summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-12 09:13:00 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-03-16 09:58:26 +0000
commit03561cae90f1d99b5c54b1ef3be69f10e882b25e (patch)
treecc5f0958e823c044e7ae51cc0117fe51432abe5e /chromium/components
parentfa98118a45f7e169f8846086dc2c22c49a8ba310 (diff)
downloadqtwebengine-chromium-03561cae90f1d99b5c54b1ef3be69f10e882b25e.tar.gz
BASELINE: Update Chromium to 88.0.4324.208
Change-Id: I3ae87d23e4eff4b4a469685658740a213600c667 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn31
-rw-r--r--chromium/components/OWNERS4
-rw-r--r--chromium/components/account_manager_core/BUILD.gn25
-rw-r--r--chromium/components/account_manager_core/DEPS3
-rw-r--r--chromium/components/account_manager_core/OWNERS1
-rw-r--r--chromium/components/account_manager_core/README.md15
-rw-r--r--chromium/components/account_manager_core/account.cc51
-rw-r--r--chromium/components/account_manager_core/account.h58
-rw-r--r--chromium/components/account_manager_core/account_manager_facade.cc12
-rw-r--r--chromium/components/account_manager_core/account_manager_facade.h33
-rw-r--r--chromium/components/account_manager_core/account_manager_util.cc70
-rw-r--r--chromium/components/account_manager_core/account_manager_util.h34
-rw-r--r--chromium/components/arc/BUILD.gn10
-rw-r--r--chromium/components/arc/DEPS2
-rw-r--r--chromium/components/arc/DIR_METADATA3
-rw-r--r--chromium/components/arc/OWNERS2
-rw-r--r--chromium/components/arc/arc_features.cc11
-rw-r--r--chromium/components/arc/arc_features.h2
-rw-r--r--chromium/components/arc/arc_prefs.cc10
-rw-r--r--chromium/components/arc/arc_prefs.h1
-rw-r--r--chromium/components/arc/clipboard/arc_clipboard_bridge.cc10
-rw-r--r--chromium/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc4
-rw-r--r--chromium/components/arc/enterprise/arc_data_snapshotd_manager.cc99
-rw-r--r--chromium/components/arc/enterprise/arc_data_snapshotd_manager.h44
-rw-r--r--chromium/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc112
-rw-r--r--chromium/components/arc/enterprise/snapshot_hours_policy_service.cc186
-rw-r--r--chromium/components/arc/enterprise/snapshot_hours_policy_service.h135
-rw-r--r--chromium/components/arc/enterprise/snapshot_hours_policy_service_unittest.cc350
-rw-r--r--chromium/components/arc/ime/DIR_METADATA3
-rw-r--r--chromium/components/arc/ime/OWNERS2
-rw-r--r--chromium/components/arc/ime/arc_ime_service_unittest.cc1
-rw-r--r--chromium/components/arc/ime/key_event_result_receiver_unittest.cc2
-rw-r--r--chromium/components/arc/intent_helper/DIR_METADATA3
-rw-r--r--chromium/components/arc/intent_helper/OWNERS1
-rw-r--r--chromium/components/arc/media_session/DIR_METADATA3
-rw-r--r--chromium/components/arc/media_session/OWNERS2
-rw-r--r--chromium/components/arc/metrics/arc_metrics_service.cc94
-rw-r--r--chromium/components/arc/metrics/arc_metrics_service.h30
-rw-r--r--chromium/components/arc/mojom/BUILD.gn4
-rw-r--r--chromium/components/arc/mojom/arc_bridge.mojom14
-rw-r--r--chromium/components/arc/mojom/bluetooth.mojom82
-rw-r--r--chromium/components/arc/mojom/digital_goods.mojom38
-rw-r--r--chromium/components/arc/mojom/file_system.mojom37
-rw-r--r--chromium/components/arc/mojom/gfx.mojom6
-rw-r--r--chromium/components/arc/mojom/intent_helper.mojom4
-rw-r--r--chromium/components/arc/mojom/metrics.mojom53
-rw-r--r--chromium/components/arc/mojom/power.mojom39
-rw-r--r--chromium/components/arc/mojom/screen_capture.mojom2
-rw-r--r--chromium/components/arc/mojom/sharesheet.mojom21
-rw-r--r--chromium/components/arc/mojom/video_common.mojom8
-rw-r--r--chromium/components/arc/mojom/video_encode_accelerator.mojom1
-rw-r--r--chromium/components/arc/mojom/video_protected_buffer_allocator.mojom1
-rw-r--r--chromium/components/arc/net/DIR_METADATA3
-rw-r--r--chromium/components/arc/net/OWNERS2
-rw-r--r--chromium/components/arc/net/always_on_vpn_manager.cc2
-rw-r--r--chromium/components/arc/pay/arc_digital_goods_bridge.cc99
-rw-r--r--chromium/components/arc/pay/arc_digital_goods_bridge.h77
-rw-r--r--chromium/components/arc/power/arc_power_bridge.cc13
-rw-r--r--chromium/components/arc/power/arc_power_bridge.h14
-rw-r--r--chromium/components/arc/power/arc_power_bridge_unittest.cc91
-rw-r--r--chromium/components/arc/session/arc_bridge_host_impl.cc16
-rw-r--r--chromium/components/arc/session/arc_bridge_host_impl.h5
-rw-r--r--chromium/components/arc/session/arc_bridge_service.cc2
-rw-r--r--chromium/components/arc/session/arc_bridge_service.h13
-rw-r--r--chromium/components/arc/session/arc_container_client_adapter.cc2
-rw-r--r--chromium/components/arc/session/arc_container_client_adapter_unittest.cc89
-rw-r--r--chromium/components/arc/session/arc_data_remover.cc5
-rw-r--r--chromium/components/arc/session/arc_session_runner.cc2
-rw-r--r--chromium/components/arc/session/arc_session_runner_unittest.cc1
-rw-r--r--chromium/components/arc/session/arc_vm_client_adapter.cc39
-rw-r--r--chromium/components/arc/session/arc_vm_client_adapter_unittest.cc242
-rw-r--r--chromium/components/arc/sharesheet/OWNERS3
-rw-r--r--chromium/components/arc/timer/arc_timer_bridge.cc5
-rw-r--r--chromium/components/arc/timer/arc_timer_bridge_unittest.cc2
-rw-r--r--chromium/components/arc/video_accelerator/arc_video_accelerator_util.cc9
-rw-r--r--chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc39
-rw-r--r--chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h22
-rw-r--r--chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc2
-rw-r--r--chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc2
-rw-r--r--chromium/components/assist_ranker/base_predictor_unittest.cc2
-rw-r--r--chromium/components/assist_ranker/binary_classifier_predictor.cc2
-rw-r--r--chromium/components/assist_ranker/binary_classifier_predictor_unittest.cc2
-rw-r--r--chromium/components/assist_ranker/classifier_predictor.cc2
-rw-r--r--chromium/components/assist_ranker/classifier_predictor_unittest.cc2
-rw-r--r--chromium/components/assist_ranker/ranker_model_loader_impl.cc2
-rw-r--r--chromium/components/assist_ranker/ranker_model_loader_impl_unittest.cc1
-rw-r--r--chromium/components/autofill/android/BUILD.gn2
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.cc35
-rw-r--r--chromium/components/autofill/android/provider/autofill_provider_android.h16
-rw-r--r--chromium/components/autofill/android/provider/form_data_android.h2
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java20
-rw-r--r--chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java12
-rw-r--r--chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java7
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc4
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h2
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc1
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc12
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc17
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_agent.mojom2
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_driver.mojom12
-rw-r--r--chromium/components/autofill/content/renderer/OWNERS9
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc24
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h6
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc1
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc6
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.cc15
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.h5
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.h2
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc84
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h23
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc1
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h1
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc17
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.h6
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn23
-rw-r--r--chromium/components/autofill/core/browser/OWNERS2
-rw-r--r--chromium/components/autofill/core/browser/address_normalization_manager.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalizer_impl.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc25
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h39
-rw-r--r--chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc34
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html1
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html1
-rw-r--r--chromium/components/autofill/core/browser/autofill_data_util.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc5
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc21
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.cc27
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.h29
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc113
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h28
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc280
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc1297
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.h3
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc (renamed from chromium/components/autofill/core/common/autofill_regex_constants.cc)26
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.h (renamed from chromium/components/autofill/core/common/autofill_regex_constants.h)6
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.cc (renamed from chromium/components/autofill/core/common/autofill_regexes.cc)10
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes.h (renamed from chromium/components/autofill/core/common/autofill_regexes.h)6
-rw-r--r--chromium/components/autofill/core/browser/autofill_regexes_unittest.cc232
-rw-r--r--chromium/components/autofill/core/browser/data_model/address.cc54
-rw-r--r--chromium/components/autofill/core/browser/data_model/address_unittest.cc83
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.cc4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.cc80
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc5
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc12
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc51
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h15
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc21
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc56
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc62
-rw-r--r--chromium/components/autofill/core/browser/data_model/contact_info.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc2
-rw-r--r--chromium/components/autofill/core/browser/data_model/data_model_utils.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc69
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h5
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc242
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.cc323
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.h62
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc127
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc29
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h8
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc125
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.h11
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc25
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.cc6
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.cc57
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.h20
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc89
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.cc127
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc21
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc53
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.h9
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc17
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc17
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.cc20
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/travel_field.h1
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc115
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h4
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc832
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc156
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.h181
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc69
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h47
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc119
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc226
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h113
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc159
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.cc17
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.h23
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/geo/country_data.cc1058
-rw-r--r--chromium/components/autofill/core/browser/geo/country_data.h27
-rw-r--r--chromium/components/autofill/core/browser/geo/subkey_requester.cc2
-rw-r--r--chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/logging/log_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc24
-rw-r--r--chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h11
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/DEPS5
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc228
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h60
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc196
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc167
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h87
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc238
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json2947
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc36
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h23
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h9
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc32
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.h1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc2
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc11
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/proto/BUILD.gn1
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto1
-rw-r--r--chromium/components/autofill/core/browser/proto/states.proto31
-rw-r--r--chromium/components/autofill/core/browser/rationalization_util_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager.h1
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.cc4
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.h3
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/ui/region_combobox_model.cc2
-rw-r--r--chromium/components/autofill/core/browser/validation.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc30
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc3
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc7
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn10
-rw-r--r--chromium/components/autofill/core/common/OWNERS4
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.cc19
-rw-r--r--chromium/components/autofill/core/common/autofill_constants.h6
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc147
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h32
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc6
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.cc8
-rw-r--r--chromium/components/autofill/core/common/autofill_regexes_unittest.cc232
-rw-r--r--chromium/components/autofill/core/common/autofill_util.cc2
-rw-r--r--chromium/components/autofill/core/common/dense_set.h278
-rw-r--r--chromium/components/autofill/core/common/dense_set_unittest.cc484
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer.cc14
-rw-r--r--chromium/components/autofill/core/common/mojom/BUILD.gn4
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types.mojom14
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc2
-rw-r--r--chromium/components/autofill/core/common/password_form.h388
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h1
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.cc44
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h17
-rw-r--r--chromium/components/autofill/core/common/password_generation_util.h4
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc4
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h2
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm16
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm2
-rw-r--r--chromium/components/autofill_assistant/browser/BUILD.gn112
-rw-r--r--chromium/components/autofill_assistant/browser/DEPS5
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action.cc36
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action.h18
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate.h137
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc293
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate_util.h114
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc186
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_test_utils.cc39
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_test_utils.h24
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_unittest.cc96
-rw-r--r--chromium/components/autofill_assistant/browser/actions/click_action.cc22
-rw-r--r--chromium/components/autofill_assistant/browser/actions/click_action.h1
-rw-r--r--chromium/components/autofill_assistant/browser/actions/click_action_unittest.cc203
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h1
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc22
-rw-r--r--chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h6
-rw-r--r--chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc180
-rw-r--r--chromium/components/autofill_assistant/browser/actions/focus_element_action.cc88
-rw-r--r--chromium/components/autofill_assistant/browser/actions/focus_element_action.h40
-rw-r--r--chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/actions/get_element_status_action.cc226
-rw-r--r--chromium/components/autofill_assistant/browser/actions/get_element_status_action.h42
-rw-r--r--chromium/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc546
-rw-r--r--chromium/components/autofill_assistant/browser/actions/highlight_element_action.cc20
-rw-r--r--chromium/components/autofill_assistant/browser/actions/highlight_element_action_unittest.cc91
-rw-r--r--chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h150
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action.cc68
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action.h17
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc166
-rw-r--r--chromium/components/autofill_assistant/browser/actions/select_option_action.cc41
-rw-r--r--chromium/components/autofill_assistant/browser/actions/select_option_action_unittest.cc6
-rw-r--r--chromium/components/autofill_assistant/browser/actions/set_attribute_action.cc11
-rw-r--r--chromium/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.cc189
-rw-r--r--chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.h31
-rw-r--r--chromium/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc346
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_cast_action.cc114
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_cast_action.h43
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_cast_action_unittest.cc152
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_form_action.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc16
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h1
-rw-r--r--chromium/components/autofill_assistant/browser/actions/stop_action.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/stopwatch.cc149
-rw-r--r--chromium/components/autofill_assistant/browser/actions/stopwatch.h94
-rw-r--r--chromium/components/autofill_assistant/browser/actions/stopwatch_unittest.cc186
-rw-r--r--chromium/components/autofill_assistant/browser/actions/upload_dom_action.cc75
-rw-r--r--chromium/components/autofill_assistant/browser/actions/upload_dom_action.h13
-rw-r--r--chromium/components/autofill_assistant/browser/actions/upload_dom_action_unittest.cc165
-rw-r--r--chromium/components/autofill_assistant/browser/actions/use_address_action.cc16
-rw-r--r--chromium/components/autofill_assistant/browser/actions/use_address_action_unittest.cc243
-rw-r--r--chromium/components/autofill_assistant/browser/actions/use_credit_card_action.cc14
-rw-r--r--chromium/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc332
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_document_action.cc77
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_document_action.h16
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc63
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc7
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc65
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc150
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h89
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc83
-rw-r--r--chromium/components/autofill_assistant/browser/basic_interactions.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/basic_interactions.h2
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker.cc33
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker.h23
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc143
-rw-r--r--chromium/components/autofill_assistant/browser/chip.h3
-rw-r--r--chromium/components/autofill_assistant/browser/client.h8
-rw-r--r--chromium/components/autofill_assistant/browser/client_settings.cc23
-rw-r--r--chromium/components/autofill_assistant/browser/client_settings.h10
-rw-r--r--chromium/components/autofill_assistant/browser/client_settings_unittest.cc33
-rw-r--r--chromium/components/autofill_assistant/browser/client_status.cc16
-rw-r--r--chromium/components/autofill_assistant/browser/client_status.h10
-rw-r--r--chromium/components/autofill_assistant/browser/controller.cc142
-rw-r--r--chromium/components/autofill_assistant/browser/controller.h29
-rw-r--r--chromium/components/autofill_assistant/browser/controller_observer.h3
-rw-r--r--chromium/components/autofill_assistant/browser/controller_unittest.cc256
-rw-r--r--chromium/components/autofill_assistant/browser/devtools/BUILD.gn5
-rw-r--r--chromium/components/autofill_assistant/browser/devtools/devtools_client.cc40
-rw-r--r--chromium/components/autofill_assistant/browser/devtools/devtools_client.h3
-rw-r--r--chromium/components/autofill_assistant/browser/element_area.cc29
-rw-r--r--chromium/components/autofill_assistant/browser/element_area.h8
-rw-r--r--chromium/components/autofill_assistant/browser/element_area_unittest.cc238
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition.cc10
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition.h4
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition_unittest.cc31
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h3
-rw-r--r--chromium/components/autofill_assistant/browser/features.cc36
-rw-r--r--chromium/components/autofill_assistant/browser/features.h7
-rw-r--r--chromium/components/autofill_assistant/browser/field_formatter.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/field_formatter_unittest.cc6
-rw-r--r--chromium/components/autofill_assistant/browser/generic_ui.proto1
-rw-r--r--chromium/components/autofill_assistant/browser/metrics.cc32
-rw-r--r--chromium/components/autofill_assistant/browser/metrics.h229
-rw-r--r--chromium/components/autofill_assistant/browser/mock_client.h3
-rw-r--r--chromium/components/autofill_assistant/browser/mock_client_context.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/mock_client_context.h27
-rw-r--r--chromium/components/autofill_assistant/browser/mock_controller_observer.h1
-rw-r--r--chromium/components/autofill_assistant/browser/model.proto22
-rw-r--r--chromium/components/autofill_assistant/browser/onboarding_result.h31
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils.cc72
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils.h18
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc100
-rw-r--r--chromium/components/autofill_assistant/browser/public/runtime_manager.cc7
-rw-r--r--chromium/components/autofill_assistant/browser/public/runtime_manager.h5
-rw-r--r--chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/public/runtime_manager_impl.h6
-rw-r--r--chromium/components/autofill_assistant/browser/retry_timer.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/retry_timer.h3
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor.cc251
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor.h106
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor_delegate.h5
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor_unittest.cc566
-rw-r--r--chromium/components/autofill_assistant/browser/script_precondition_unittest.cc16
-rw-r--r--chromium/components/autofill_assistant/browser/script_tracker_unittest.cc53
-rw-r--r--chromium/components/autofill_assistant/browser/selector.cc68
-rw-r--r--chromium/components/autofill_assistant/browser/selector_unittest.cc47
-rw-r--r--chromium/components/autofill_assistant/browser/service.proto550
-rw-r--r--chromium/components/autofill_assistant/browser/service/access_token_fetcher.h (renamed from chromium/components/autofill_assistant/browser/access_token_fetcher.h)6
-rw-r--r--chromium/components/autofill_assistant/browser/service/api_key_fetcher.cc28
-rw-r--r--chromium/components/autofill_assistant/browser/service/api_key_fetcher.h19
-rw-r--r--chromium/components/autofill_assistant/browser/service/api_key_fetcher_unittest.cc60
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service.cc (renamed from chromium/components/autofill_assistant/browser/java_service.cc)10
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service.h (renamed from chromium/components/autofill_assistant/browser/java_service.h)12
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc52
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service_request_sender.h48
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service.cc (renamed from chromium/components/autofill_assistant/browser/lite_service.cc)37
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service.h (renamed from chromium/components/autofill_assistant/browser/lite_service.h)23
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service_unittest.cc (renamed from chromium/components/autofill_assistant/browser/lite_service_unittest.cc)122
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service_util.cc (renamed from chromium/components/autofill_assistant/browser/lite_service_util.cc)3
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service_util.h (renamed from chromium/components/autofill_assistant/browser/lite_service_util.h)6
-rw-r--r--chromium/components/autofill_assistant/browser/service/lite_service_util_unittest.cc (renamed from chromium/components/autofill_assistant/browser/lite_service_util_unittest.cc)6
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.h35
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_service.cc (renamed from chromium/components/autofill_assistant/browser/mock_service.cc)12
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_service.h (renamed from chromium/components/autofill_assistant/browser/mock_service.h)15
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_service_request_sender.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h35
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h37
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_url_loader.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_url_loader.h84
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc56
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher.h33
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc49
-rw-r--r--chromium/components/autofill_assistant/browser/service/service.h (renamed from chromium/components/autofill_assistant/browser/service.h)9
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_impl.cc112
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_impl.h94
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc101
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender.h32
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc220
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h91
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc233
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc22
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h33
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc41
-rw-r--r--chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.cc17
-rw-r--r--chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.h41
-rw-r--r--chromium/components/autofill_assistant/browser/service_impl.cc321
-rw-r--r--chromium/components/autofill_assistant/browser/service_impl.h151
-rw-r--r--chromium/components/autofill_assistant/browser/string_conversions_util.cc10
-rw-r--r--chromium/components/autofill_assistant/browser/top_padding.h2
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_context.cc14
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_context.h3
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc116
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h88
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions_unittest.cc164
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h37
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h34
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.cc65
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h59
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions_unittest.cc78
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.cc90
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.h45
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_action.h27
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc555
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h220
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc1014
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_unittest.cc272
-rw-r--r--chromium/components/autofill_assistant/browser/ui_delegate.h6
-rw-r--r--chromium/components/autofill_assistant/browser/url_utils.cc42
-rw-r--r--chromium/components/autofill_assistant/browser/url_utils.h28
-rw-r--r--chromium/components/autofill_assistant/browser/url_utils_unittest.cc38
-rw-r--r--chromium/components/autofill_assistant/browser/user_data.cc1
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util.cc40
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util.h9
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util_unittest.cc80
-rw-r--r--chromium/components/autofill_assistant/browser/view_layout.proto4
-rw-r--r--chromium/components/autofill_assistant/browser/wait_for_document_operation.cc69
-rw-r--r--chromium/components/autofill_assistant/browser/wait_for_document_operation.h57
-rw-r--r--chromium/components/autofill_assistant/browser/wait_for_document_operation_unittest.cc117
-rw-r--r--chromium/components/autofill_assistant/browser/web/check_on_top_worker.cc96
-rw-r--r--chromium/components/autofill_assistant/browser/web/check_on_top_worker.h53
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_finder.cc398
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_finder.h153
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_position_getter.cc59
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_position_getter.h25
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_rect_getter.cc13
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_rect_getter.h9
-rw-r--r--chromium/components/autofill_assistant/browser/web/js_snippets.cc58
-rw-r--r--chromium/components/autofill_assistant/browser/web/js_snippets.h53
-rw-r--r--chromium/components/autofill_assistant/browser/web/mock_web_controller.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/web/mock_web_controller.h109
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller.cc1081
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller.h305
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc895
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller_util.cc9
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller_util.h6
-rw-r--r--chromium/components/autofill_assistant/browser/website_login_manager_impl.cc18
-rw-r--r--chromium/components/autofill_assistant/browser/website_login_manager_impl.h1
-rw-r--r--chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc4
-rw-r--r--chromium/components/autofill_assistant_strings.grdp3
-rw-r--r--chromium/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK.png.sha11
-rw-r--r--chromium/components/autofill_assistant_strings_grdp/OWNERS1
-rw-r--r--chromium/components/background_sync/BUILD.gn11
-rw-r--r--chromium/components/background_sync/DEPS6
-rw-r--r--chromium/components/background_sync/background_sync_controller_impl.cc414
-rw-r--r--chromium/components/background_sync/background_sync_controller_impl.h146
-rw-r--r--chromium/components/background_sync/background_sync_delegate.h78
-rw-r--r--chromium/components/background_sync/background_sync_metrics.cc151
-rw-r--r--chromium/components/background_sync/background_sync_metrics.h90
-rw-r--r--chromium/components/background_sync/background_sync_permission_context_unittest.cc2
-rw-r--r--chromium/components/background_task_scheduler/BUILD.gn1
-rw-r--r--chromium/components/background_task_scheduler/internal/BUILD.gn1
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerGcmNetworkManagerTest.java16
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerImplTest.java10
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java28
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java10
-rw-r--r--chromium/components/blocked_content/android/popup_blocked_infobar_delegate.cc2
-rw-r--r--chromium/components/blocked_content/android/popup_blocked_infobar_delegate_unittest.cc5
-rw-r--r--chromium/components/blocked_content/popup_blocker.cc3
-rw-r--r--chromium/components/blocked_content/popup_blocker_tab_helper_unittest.cc6
-rw-r--r--chromium/components/blocked_content/popup_opener_tab_helper.cc6
-rw-r--r--chromium/components/blocked_content/popup_tracker.cc17
-rw-r--r--chromium/components/blocked_content/popup_tracker.h12
-rw-r--r--chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc5
-rw-r--r--chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.h8
-rw-r--r--chromium/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc54
-rw-r--r--chromium/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc2
-rw-r--r--chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc2
-rw-r--r--chromium/components/bookmarks/browser/BUILD.gn14
-rw-r--r--chromium/components/bookmarks/browser/bookmark_index_unittest.cc565
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.cc62
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.h34
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model_unittest.cc297
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node.cc9
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node.h5
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node_data.cc4
-rw-r--r--chromium/components/bookmarks/browser/bookmark_utils.cc11
-rw-r--r--chromium/components/bookmarks/browser/model_loader.cc110
-rw-r--r--chromium/components/bookmarks/browser/model_loader.h1
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.cc186
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.h72
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index_unittest.cc675
-rw-r--r--chromium/components/bookmarks/browser/titled_url_match.h3
-rw-r--r--chromium/components/bookmarks/browser/titled_url_node.h7
-rw-r--r--chromium/components/bookmarks/browser/url_index.cc79
-rw-r--r--chromium/components/bookmarks/browser/url_index.h20
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc2
-rw-r--r--chromium/components/browser_sync/BUILD.gn33
-rw-r--r--chromium/components/browser_sync/active_devices_provider_impl.cc80
-rw-r--r--chromium/components/browser_sync/active_devices_provider_impl.h45
-rw-r--r--chromium/components/browser_sync/active_devices_provider_impl_unittest.cc91
-rw-r--r--chromium/components/browser_sync/browser_sync_client.cc19
-rw-r--r--chromium/components/browser_sync/browser_sync_client.h10
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.cc77
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.h3
-rw-r--r--chromium/components/browser_sync/test_http_bridge_factory.cc41
-rw-r--r--chromium/components/browser_sync/test_http_bridge_factory.h51
-rw-r--r--chromium/components/browser_ui/DIR_METADATA7
-rw-r--r--chromium/components/browser_ui/OWNERS4
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/DIR_METADATA7
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/OWNERS4
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java111
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java5
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java21
-rw-r--r--chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java8
-rw-r--r--chromium/components/browser_ui/client_certificate/DIR_METADATA3
-rw-r--r--chromium/components/browser_ui/client_certificate/OWNERS2
-rw-r--r--chromium/components/browser_ui/contacts_picker/android/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/contacts_picker/android/OWNERS3
-rw-r--r--chromium/components/browser_ui/display_cutout/DIR_METADATA3
-rw-r--r--chromium/components/browser_ui/display_cutout/OWNERS2
-rw-r--r--chromium/components/browser_ui/media/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/media/OWNERS3
-rw-r--r--chromium/components/browser_ui/media/android/BUILD.gn2
-rw-r--r--chromium/components/browser_ui/media/android/DEPS2
-rw-r--r--chromium/components/browser_ui/notifications/android/DIR_METADATA7
-rw-r--r--chromium/components/browser_ui/notifications/android/OWNERS4
-rw-r--r--chromium/components/browser_ui/photo_picker/android/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/photo_picker/android/OWNERS3
-rw-r--r--chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreference.java16
-rw-r--r--chromium/components/browser_ui/share/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/share/OWNERS3
-rw-r--r--chromium/components/browser_ui/site_settings/DIR_METADATA3
-rw-r--r--chromium/components/browser_ui/site_settings/OWNERS2
-rw-r--r--chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc392
-rw-r--r--chromium/components/browser_ui/sms/android/BUILD.gn6
-rw-r--r--chromium/components/browser_ui/sms/android/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/sms/android/OWNERS3
-rw-r--r--chromium/components/browser_ui/sms/android/README.md4
-rw-r--r--chromium/components/browser_ui/sms/android/sms_infobar.cc6
-rw-r--r--chromium/components/browser_ui/sms/android/sms_infobar_delegate.cc2
-rw-r--r--chromium/components/browser_ui/strings/android/BUILD.gn2
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings.grd9
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_EXPANDED.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_TRUNCATED.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings.grdp24
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_IDLE_DETECTION_PERMISSION_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_IDLE_DETECTION.png.sha12
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOWED_DSE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCKED_DSE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb130
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb28
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb28
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb14
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb14
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb16
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb58
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb28
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb72
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb16
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb34
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb10
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb38
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb8
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb8
-rw-r--r--chromium/components/browser_ui/styles/android/BUILD.gn13
-rw-r--r--chromium/components/browser_ui/webshare/DIR_METADATA5
-rw-r--r--chromium/components/browser_ui/webshare/OWNERS3
-rw-r--r--chromium/components/browser_ui/widget/android/BUILD.gn9
-rw-r--r--chromium/components/browser_ui/widget/android/DIR_METADATA7
-rw-r--r--chromium/components/browser_ui/widget/android/OWNERS4
-rw-r--r--chromium/components/browsing_data/content/BUILD.gn2
-rw-r--r--chromium/components/browsing_data/content/DEPS2
-rw-r--r--chromium/components/browsing_data/content/appcache_helper.cc2
-rw-r--r--chromium/components/browsing_data/content/appcache_helper_unittest.cc4
-rw-r--r--chromium/components/browsing_data/content/browsing_data_helper.cc2
-rw-r--r--chromium/components/browsing_data/content/cache_storage_helper_browsertest.cc2
-rw-r--r--chromium/components/browsing_data/content/cookie_helper.cc2
-rw-r--r--chromium/components/browsing_data/content/cookie_helper_unittest.cc4
-rw-r--r--chromium/components/browsing_data/content/database_helper_browsertest.cc4
-rw-r--r--chromium/components/browsing_data/content/file_system_helper_unittest.cc2
-rw-r--r--chromium/components/browsing_data/content/indexed_db_helper_browsertest.cc2
-rw-r--r--chromium/components/browsing_data/content/indexed_db_helper_unittest.cc2
-rw-r--r--chromium/components/browsing_data/content/local_storage_helper_browsertest.cc2
-rw-r--r--chromium/components/browsing_data/content/local_storage_helper_unittest.cc2
-rw-r--r--chromium/components/browsing_data/content/mock_cookie_helper.cc2
-rw-r--r--chromium/components/browsing_data/content/service_worker_helper.cc2
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils_unittest.cc2
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc2
-rw-r--r--chromium/components/browsing_data/core/counters/passwords_counter.cc11
-rw-r--r--chromium/components/browsing_data/core/features.cc2
-rw-r--r--chromium/components/browsing_data/core/features.h4
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils_unittest.cc2
-rw-r--r--chromium/components/browsing_data/core/pref_names.cc6
-rw-r--r--chromium/components/browsing_data/core/pref_names.h2
-rw-r--r--chromium/components/captive_portal/content/captive_portal_service.cc2
-rw-r--r--chromium/components/captive_portal/content/captive_portal_tab_helper_unittest.cc2
-rw-r--r--chromium/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc2
-rw-r--r--chromium/components/cast/BUILD.gn5
-rw-r--r--chromium/components/cast/api_bindings/BUILD.gn3
-rw-r--r--chromium/components/cast/api_bindings/DEPS3
-rw-r--r--chromium/components/cast/api_bindings/manager.cc7
-rw-r--r--chromium/components/cast/api_bindings/manager.h9
-rw-r--r--chromium/components/cast/api_bindings/scoped_api_binding.cc24
-rw-r--r--chromium/components/cast/api_bindings/scoped_api_binding.h14
-rw-r--r--chromium/components/cast/message_port/BUILD.gn83
-rw-r--r--chromium/components/cast/message_port/DEPS4
-rw-r--r--chromium/components/cast/message_port/message_port.cc12
-rw-r--r--chromium/components/cast/message_port/message_port.h64
-rw-r--r--chromium/components/cast/message_port/message_port_cast.cc102
-rw-r--r--chromium/components/cast/message_port/message_port_cast.h52
-rw-r--r--chromium/components/cast/message_port/message_port_fuchsia.cc344
-rw-r--r--chromium/components/cast/message_port/message_port_fuchsia.h87
-rw-r--r--chromium/components/cast/message_port/message_port_unittest.cc176
-rw-r--r--chromium/components/cast/message_port/test_message_port_receiver.cc49
-rw-r--r--chromium/components/cast/message_port/test_message_port_receiver.h57
-rw-r--r--chromium/components/cast/named_message_port_connector/BUILD.gn14
-rw-r--r--chromium/components/cast/named_message_port_connector/named_message_port_connector.cc35
-rw-r--r--chromium/components/cast/named_message_port_connector/named_message_port_connector.h27
-rw-r--r--chromium/components/cast/named_message_port_connector/named_message_port_connector.js54
-rw-r--r--chromium/components/cast_certificate/BUILD.gn42
-rw-r--r--chromium/components/cast_certificate/DEPS2
-rw-r--r--chromium/components/cast_certificate/cast_cert_reader.cc55
-rw-r--r--chromium/components/cast_certificate/cast_cert_reader.h28
-rw-r--r--chromium/components/cast_certificate/cast_cert_test_helpers.cc89
-rw-r--r--chromium/components/cast_certificate/cast_cert_test_helpers.h (renamed from chromium/components/cast_certificate/cast_cert_validator_test_helpers.h)37
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.cc80
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc107
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_unittest.cc95
-rw-r--r--chromium/components/cast_certificate/cast_crl_unittest.cc30
-rw-r--r--chromium/components/cast_certificate/switches.cc16
-rw-r--r--chromium/components/cast_certificate/switches.h16
-rw-r--r--chromium/components/cast_channel/BUILD.gn3
-rw-r--r--chromium/components/cast_channel/cast_auth_util_fuzzer.cc8
-rw-r--r--chromium/components/cast_channel/cast_auth_util_unittest.cc51
-rw-r--r--chromium/components/cast_channel/cast_message_handler.cc12
-rw-r--r--chromium/components/cast_channel/cast_message_handler_unittest.cc136
-rw-r--r--chromium/components/cast_channel/cast_socket.cc2
-rw-r--r--chromium/components/cast_channel/cast_socket.h2
-rw-r--r--chromium/components/cast_channel/cast_socket_unittest.cc5
-rw-r--r--chromium/components/cdm/common/BUILD.gn18
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc1
-rw-r--r--chromium/components/chrome_cleaner/public/constants/constants.cc1
-rw-r--r--chromium/components/chrome_cleaner/public/constants/constants.h3
-rw-r--r--chromium/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc3
-rw-r--r--chromium/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc20
-rw-r--r--chromium/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc2
-rw-r--r--chromium/components/client_hints/browser/client_hints.cc21
-rw-r--r--chromium/components/cloud_devices/common/cloud_devices_urls.cc13
-rw-r--r--chromium/components/cloud_devices/common/cloud_devices_urls.h3
-rw-r--r--chromium/components/component_updater/component_installer_unittest.cc2
-rw-r--r--chromium/components/component_updater/component_updater_service.cc2
-rw-r--r--chromium/components/component_updater/component_updater_service.h6
-rw-r--r--chromium/components/component_updater/component_updater_service_unittest.cc2
-rw-r--r--chromium/components/component_updater/installer_policies/BUILD.gn4
-rw-r--r--chromium/components/component_updater/installer_policies/DEPS1
-rw-r--r--chromium/components/component_updater/installer_policies/safety_tips_component_installer.cc147
-rw-r--r--chromium/components/component_updater/installer_policies/safety_tips_component_installer.h54
-rw-r--r--chromium/components/component_updater/timer.cc2
-rw-r--r--chromium/components/component_updater/timer.h4
-rw-r--r--chromium/components/component_updater/timer_update_scheduler.cc2
-rw-r--r--chromium/components/components_strings.grd13
-rw-r--r--chromium/components/components_strings_grd/IDS_INSTALL.png.sha11
-rw-r--r--chromium/components/components_strings_grd/IDS_UPDATE.png.sha11
-rw-r--r--chromium/components/consent_auditor/consent_auditor_impl_unittest.cc2
-rw-r--r--chromium/components/consent_auditor/consent_sync_bridge_impl.cc2
-rw-r--r--chromium/components/consent_auditor/consent_sync_bridge_impl_unittest.cc6
-rw-r--r--chromium/components/content_capture/android/BUILD.gn2
-rw-r--r--chromium/components/content_capture/android/junit/BUILD.gn25
-rw-r--r--chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java569
-rw-r--r--chromium/components/content_capture/common/content_capture_features.cc2
-rw-r--r--chromium/components/content_settings/android/cookie_controls_bridge.cc2
-rw-r--r--chromium/components/content_settings/android/cookie_controls_bridge.h4
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings.cc31
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings.h11
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc4
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_controller.cc2
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_controller.h7
-rw-r--r--chromium/components/content_settings/common/content_settings_agent.mojom3
-rw-r--r--chromium/components/content_settings/core/browser/BUILD.gn1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.cc50
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.h11
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_details.cc7
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_details.h9
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.cc46
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.h5
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_ephemeral_provider_unittest.cc45
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_global_value_map.cc6
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_global_value_map.h3
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_info.cc4
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_info.h8
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_observable_provider.cc5
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_observable_provider.h3
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_observer.h3
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc58
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h55
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.cc39
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.h3
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.cc173
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.h19
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.cc61
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.h12
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc132
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider.cc1
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider.h5
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc66
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.cc96
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.h2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_rule.h2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.cc8
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.h2
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings.cc26
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings.h9
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings_unittest.cc44
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc195
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.h94
-rw-r--r--chromium/components/content_settings/core/browser/private_network_settings.cc4
-rw-r--r--chromium/components/content_settings/core/browser/user_modifiable_provider.h3
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.cc12
-rw-r--r--chromium/components/content_settings/core/common/BUILD.gn1
-rw-r--r--chromium/components/content_settings/core/common/content_settings.cc2
-rw-r--r--chromium/components/content_settings/core/common/content_settings.h4
-rw-r--r--chromium/components/content_settings/core/common/content_settings_constraints.h (renamed from chromium/components/content_settings/core/browser/content_settings_constraints.h)11
-rw-r--r--chromium/components/content_settings/core/common/content_settings_types.h8
-rw-r--r--chromium/components/content_settings/core/common/features.cc4
-rw-r--r--chromium/components/content_settings/core/common/features.h5
-rw-r--r--chromium/components/content_settings/core/common/pref_names.cc15
-rw-r--r--chromium/components/content_settings/core/common/pref_names.h4
-rw-r--r--chromium/components/content_settings/renderer/content_settings_agent_impl.cc39
-rw-r--r--chromium/components/content_settings/renderer/content_settings_agent_impl.h22
-rw-r--r--chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc68
-rw-r--r--chromium/components/crash/content/browser/BUILD.gn41
-rw-r--r--chromium/components/crash/content/browser/child_exit_observer_android.cc2
-rw-r--r--chromium/components/crash/content/browser/child_exit_observer_android.h8
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.cc2
-rw-r--r--chromium/components/crash/content/browser/error_reporting/BUILD.gn39
-rw-r--r--chromium/components/crash/content/browser/error_reporting/DEPS2
-rw-r--r--chromium/components/crash/content/browser/error_reporting/javascript_error_report.h29
-rw-r--r--chromium/components/crash/content/browser/error_reporting/js_error_report_processor.cc29
-rw-r--r--chromium/components/crash/content/browser/error_reporting/js_error_report_processor.h47
-rw-r--r--chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc7
-rw-r--r--chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.h9
-rw-r--r--chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.cc337
-rw-r--r--chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.h44
-rw-r--r--chromium/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc230
-rw-r--r--chromium/components/crash/core/app/BUILD.gn31
-rw-r--r--chromium/components/crash/core/browser/resources/crashes.html1
-rw-r--r--chromium/components/crash/core/common/BUILD.gn1
-rw-r--r--chromium/components/crash/core/common/DEPS1
-rw-r--r--chromium/components/crash/core/common/crash_key_breakpad_ios.mm5
-rw-r--r--chromium/components/cronet/android/BUILD.gn9
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc1
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc8
-rw-r--r--chromium/components/data_reduction_proxy/proto/BUILD.gn4
-rw-r--r--chromium/components/data_reduction_proxy/proto/robots_rules.proto26
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.cc15
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc2
-rw-r--r--chromium/components/dbus/menu/BUILD.gn3
-rw-r--r--chromium/components/dbus/menu/DEPS1
-rw-r--r--chromium/components/dbus/menu/menu.cc2
-rw-r--r--chromium/components/dbus/menu/menu_property_list.cc70
-rw-r--r--chromium/components/dbus/menu/menu_property_list_unittest.cc3
-rw-r--r--chromium/components/dbus/properties/dbus_properties.h2
-rw-r--r--chromium/components/dbus/properties/types.h2
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc24
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h16
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc32
-rw-r--r--chromium/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc2
-rw-r--r--chromium/components/dom_distiller/core/distiller_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc1
-rw-r--r--chromium/components/domain_reliability/OWNERS2
-rw-r--r--chromium/components/domain_reliability/context_manager.cc2
-rw-r--r--chromium/components/domain_reliability/monitor_unittest.cc2
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.cc46
-rw-r--r--chromium/components/download/content/DEPS1
-rw-r--r--chromium/components/download/content/internal/BUILD.gn4
-rw-r--r--chromium/components/download/content/internal/context_menu_download.cc49
-rw-r--r--chromium/components/download/content/internal/download_driver_impl.cc2
-rw-r--r--chromium/components/download/content/internal/download_driver_impl_unittest.cc2
-rw-r--r--chromium/components/download/content/public/BUILD.gn4
-rw-r--r--chromium/components/download/content/public/context_menu_download.h25
-rw-r--r--chromium/components/download/internal/background_service/in_memory_download_unittest.cc2
-rw-r--r--chromium/components/download/internal/background_service/logger_impl.cc2
-rw-r--r--chromium/components/download/internal/background_service/proto/entry.proto5
-rw-r--r--chromium/components/download/internal/background_service/proto_conversions.cc4
-rw-r--r--chromium/components/download/internal/background_service/stats.cc2
-rw-r--r--chromium/components/download/internal/common/BUILD.gn17
-rw-r--r--chromium/components/download/internal/common/all_download_event_notifier_unittest.cc2
-rw-r--r--chromium/components/download/internal/common/download_item_impl_delegate.cc2
-rw-r--r--chromium/components/download/internal/common/download_item_impl_unittest.cc2
-rw-r--r--chromium/components/download/internal/common/download_job.cc2
-rw-r--r--chromium/components/download/internal/common/download_job_factory.cc42
-rw-r--r--chromium/components/download/internal/common/download_stats.cc17
-rw-r--r--chromium/components/download/internal/common/download_utils.cc2
-rw-r--r--chromium/components/download/internal/common/parallel_download_job.cc7
-rw-r--r--chromium/components/download/internal/common/parallel_download_job.h3
-rw-r--r--chromium/components/download/public/background_service/clients.h5
-rw-r--r--chromium/components/download/public/common/download_stats.h57
-rw-r--r--chromium/components/download/public/common/download_url_parameters.cc5
-rw-r--r--chromium/components/download/public/common/download_url_parameters.h12
-rw-r--r--chromium/components/embedder_support/android/BUILD.gn11
-rw-r--r--chromium/components/embedder_support/android/DEPS3
-rw-r--r--chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/util/UrlUtilitiesUnitTest.java31
-rw-r--r--chromium/components/embedder_support/android/metrics/BUILD.gn3
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc12
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc91
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client.h34
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc85
-rw-r--r--chromium/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java15
-rw-r--r--chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc2
-rw-r--r--chromium/components/embedder_support/android/util/DEPS2
-rw-r--r--chromium/components/embedder_support/android/util/cdn_utils.cc79
-rw-r--r--chromium/components/embedder_support/android/util/cdn_utils.h26
-rw-r--r--chromium/components/embedder_support/android/util/user_agent_utils.cc33
-rw-r--r--chromium/components/embedder_support/android/util/user_agent_utils.h23
-rw-r--r--chromium/components/embedder_support/origin_trials/features.cc6
-rw-r--r--chromium/components/embedder_support/origin_trials/features.h7
-rw-r--r--chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc4
-rw-r--r--chromium/components/enterprise/BUILD.gn3
-rw-r--r--chromium/components/enterprise/browser/controller/browser_dm_token_storage.cc2
-rw-r--r--chromium/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc2
-rw-r--r--chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc13
-rw-r--r--chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h8
-rw-r--r--chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc2
-rw-r--r--chromium/components/enterprise/browser/enterprise_switches.cc18
-rw-r--r--chromium/components/enterprise/browser/enterprise_switches.h21
-rw-r--r--chromium/components/enterprise/browser/reporting/browser_report_generator.cc10
-rw-r--r--chromium/components/enterprise/browser/reporting/browser_report_generator.h4
-rw-r--r--chromium/components/enterprise/browser/reporting/profile_report_generator.cc50
-rw-r--r--chromium/components/enterprise/browser/reporting/profile_report_generator.h5
-rw-r--r--chromium/components/enterprise/browser/reporting/report_generator.cc40
-rw-r--r--chromium/components/enterprise/browser/reporting/report_generator.h13
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc12
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request_queue_generator.h9
-rw-r--r--chromium/components/enterprise/browser/reporting/report_scheduler.cc72
-rw-r--r--chromium/components/enterprise/browser/reporting/report_scheduler.h18
-rw-r--r--chromium/components/enterprise/browser/reporting/report_type.h18
-rw-r--r--chromium/components/enterprise/common/proto/connectors.proto6
-rw-r--r--chromium/components/error_page/common/localized_error.cc33
-rw-r--r--chromium/components/error_page/content/browser/net_error_auto_reloader.cc5
-rw-r--r--chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc2
-rw-r--r--chromium/components/error_page_strings.grdp10
-rw-r--r--chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_GAME_INSTRUCTIONS.png.sha11
-rw-r--r--chromium/components/exo/BUILD.gn23
-rw-r--r--chromium/components/exo/DEPS4
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.cc164
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.h36
-rw-r--r--chromium/components/exo/client_controlled_shell_surface_unittest.cc150
-rw-r--r--chromium/components/exo/data_device.cc12
-rw-r--r--chromium/components/exo/data_device_delegate.h2
-rw-r--r--chromium/components/exo/data_device_unittest.cc25
-rw-r--r--chromium/components/exo/data_offer.cc259
-rw-r--r--chromium/components/exo/data_offer.h62
-rw-r--r--chromium/components/exo/data_offer_unittest.cc207
-rw-r--r--chromium/components/exo/data_source.cc12
-rw-r--r--chromium/components/exo/data_source.h6
-rw-r--r--chromium/components/exo/data_source_unittest.cc56
-rw-r--r--chromium/components/exo/display_unittest.cc25
-rw-r--r--chromium/components/exo/drag_drop_operation.cc183
-rw-r--r--chromium/components/exo/drag_drop_operation.h50
-rw-r--r--chromium/components/exo/drag_drop_operation_unittest.cc6
-rw-r--r--chromium/components/exo/extended_drag_source.cc262
-rw-r--r--chromium/components/exo/extended_drag_source.h79
-rw-r--r--chromium/components/exo/extended_drag_source_unittest.cc288
-rw-r--r--chromium/components/exo/file_helper.h64
-rw-r--r--chromium/components/exo/keyboard.cc32
-rw-r--r--chromium/components/exo/keyboard.h2
-rw-r--r--chromium/components/exo/mock_vsync_timing_observer.cc13
-rw-r--r--chromium/components/exo/mock_vsync_timing_observer.h26
-rw-r--r--chromium/components/exo/notification_unittest.cc2
-rw-r--r--chromium/components/exo/pointer.cc19
-rw-r--r--chromium/components/exo/pointer.h4
-rw-r--r--chromium/components/exo/pointer_unittest.cc5
-rw-r--r--chromium/components/exo/seat.cc21
-rw-r--r--chromium/components/exo/seat.h13
-rw-r--r--chromium/components/exo/seat_unittest.cc5
-rw-r--r--chromium/components/exo/shell_surface.cc54
-rw-r--r--chromium/components/exo/shell_surface.h6
-rw-r--r--chromium/components/exo/shell_surface_base.cc83
-rw-r--r--chromium/components/exo/shell_surface_base.h9
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc16
-rw-r--r--chromium/components/exo/shell_surface_util.cc15
-rw-r--r--chromium/components/exo/shell_surface_util.h6
-rw-r--r--chromium/components/exo/surface.cc332
-rw-r--r--chromium/components/exo/surface.h83
-rw-r--r--chromium/components/exo/surface_tree_host.cc2
-rw-r--r--chromium/components/exo/surface_unittest.cc126
-rw-r--r--chromium/components/exo/text_input.cc48
-rw-r--r--chromium/components/exo/text_input.h5
-rw-r--r--chromium/components/exo/text_input_unittest.cc7
-rw-r--r--chromium/components/exo/touch_unittest.cc5
-rw-r--r--chromium/components/exo/ui_lock_controller.cc4
-rw-r--r--chromium/components/exo/vsync_timing_manager.cc25
-rw-r--r--chromium/components/exo/vsync_timing_manager.h15
-rw-r--r--chromium/components/exo/wayland/BUILD.gn46
-rw-r--r--chromium/components/exo/wayland/clients/client_base.cc4
-rw-r--r--chromium/components/exo/wayland/compatibility_test/BUILD.gn103
-rw-r--r--chromium/components/exo/wayland/compatibility_test/client_compatibility_test.cc18
-rw-r--r--chromium/components/exo/wayland/compatibility_test/client_compatibility_test.h29
-rw-r--r--chromium/components/exo/wayland/compatibility_test/client_compatibility_test_server.cc44
-rw-r--r--chromium/components/exo/wayland/compatibility_test/template_client_event_receiver_version_tests.cc.tmpl415
-rw-r--r--chromium/components/exo/wayland/compatibility_test/template_client_helpers.cc.tmpl32
-rw-r--r--chromium/components/exo/wayland/compatibility_test/template_client_helpers.h.tmpl39
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h159
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.cc18
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.h41
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_client_registry.cc85
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_client_registry.h83
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_c_arg_handling.py85
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.gni57
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.py119
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_construction.py252
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_data_classes.py519
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_externals.py25
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_identifiers.py109
-rw-r--r--chromium/components/exo/wayland/compatibility_test/wayland_protocol_utils.py30
-rw-r--r--chromium/components/exo/wayland/protocol/aura-shell.xml32
-rw-r--r--chromium/components/exo/wayland/wl_data_device_manager.cc19
-rw-r--r--chromium/components/exo/wayland/wl_shell.cc2
-rw-r--r--chromium/components/exo/wayland/xdg_shell.cc14
-rw-r--r--chromium/components/exo/wayland/zaura_shell.cc77
-rw-r--r--chromium/components/exo/wayland/zaura_shell.h4
-rw-r--r--chromium/components/exo/wayland/zcr_extended_drag.cc10
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell.cc79
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell_unittest.cc7
-rw-r--r--chromium/components/exo/wayland/zwp_text_input_manager.cc34
-rw-r--r--chromium/components/exo/wayland/zxdg_shell.cc14
-rw-r--r--chromium/components/exo/wm_helper_chromeos.cc11
-rw-r--r--chromium/components/exo/wm_helper_chromeos.h2
-rw-r--r--chromium/components/exo/wm_helper_chromeos_unittest.cc59
-rw-r--r--chromium/components/favicon/android/BUILD.gn46
-rw-r--r--chromium/components/favicon/android/DEPS5
-rw-r--r--chromium/components/favicon/android/large_icon_bridge.cc103
-rw-r--r--chromium/components/favicon/android/large_icon_bridge.h41
-rw-r--r--chromium/components/favicon/content/BUILD.gn2
-rw-r--r--chromium/components/favicon/content/content_favicon_driver_unittest.cc2
-rw-r--r--chromium/components/favicon/content/large_favicon_provider_getter.cc30
-rw-r--r--chromium/components/favicon/content/large_favicon_provider_getter.h30
-rw-r--r--chromium/components/favicon/core/BUILD.gn3
-rw-r--r--chromium/components/favicon/core/favicon_handler.cc2
-rw-r--r--chromium/components/favicon/core/favicon_handler_unittest.cc3
-rw-r--r--chromium/components/favicon/core/favicon_service.h11
-rw-r--r--chromium/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc2
-rw-r--r--chromium/components/favicon/core/large_favicon_provider.h41
-rw-r--r--chromium/components/favicon/core/large_icon_service_impl.cc339
-rw-r--r--chromium/components/favicon/core/large_icon_service_impl.h11
-rw-r--r--chromium/components/favicon/core/large_icon_service_impl_unittest.cc117
-rw-r--r--chromium/components/favicon/core/large_icon_worker.cc197
-rw-r--r--chromium/components/favicon/core/large_icon_worker.h74
-rw-r--r--chromium/components/favicon_base/favicon_types.h2
-rw-r--r--chromium/components/favicon_base/favicon_util.cc2
-rw-r--r--chromium/components/favicon_base/select_favicon_frames.cc2
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.cc37
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.h8
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.cc2
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.h3
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl_unittest.cc2
-rw-r--r--chromium/components/feature_engagement/public/BUILD.gn16
-rw-r--r--chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc89
-rw-r--r--chromium/components/feature_engagement/public/android/wrapping_test_tracker.h44
-rw-r--r--chromium/components/feature_engagement/public/event_constants.cc6
-rw-r--r--chromium/components/feature_engagement/public/event_constants.h9
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.cc28
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.h15
-rw-r--r--chromium/components/feature_engagement/public/feature_list.cc14
-rw-r--r--chromium/components/feature_engagement/public/feature_list.h39
-rw-r--r--chromium/components/feature_engagement/public/tracker.h3
-rw-r--r--chromium/components/federated_learning/BUILD.gn9
-rw-r--r--chromium/components/federated_learning/floc_blocklist_service.cc114
-rw-r--r--chromium/components/federated_learning/floc_blocklist_service.h76
-rw-r--r--chromium/components/federated_learning/floc_blocklist_service_unittest.cc178
-rw-r--r--chromium/components/federated_learning/floc_constants.cc11
-rw-r--r--chromium/components/federated_learning/floc_constants.h9
-rw-r--r--chromium/components/federated_learning/floc_id.cc36
-rw-r--r--chromium/components/federated_learning/floc_id.h34
-rw-r--r--chromium/components/federated_learning/floc_id_unittest.cc40
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc119
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h26
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc190
-rw-r--r--chromium/components/federated_learning/proto/BUILD.gn9
-rw-r--r--chromium/components/federated_learning/proto/blocklist.proto13
-rw-r--r--chromium/components/feed/core/common/pref_names.cc6
-rw-r--r--chromium/components/feed/core/common/pref_names.h14
-rw-r--r--chromium/components/feed/core/feed_networking_host.cc8
-rw-r--r--chromium/components/feed/core/feed_networking_host.h6
-rw-r--r--chromium/components/feed/core/feed_networking_host_unittest.cc17
-rw-r--r--chromium/components/feed/core/proto/BUILD.gn3
-rw-r--r--chromium/components/feed/core/proto/v2/store.proto9
-rw-r--r--chromium/components/feed/core/proto/v2/wire/chrome_client_info.proto17
-rw-r--r--chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto1
-rw-r--r--chromium/components/feed/core/proto/v2/wire/chrome_fulfillment_info.proto17
-rw-r--r--chromium/components/feed/core/proto/v2/wire/client_info.proto5
-rw-r--r--chromium/components/feed/core/proto/v2/wire/feed_query.proto4
-rw-r--r--chromium/components/feed/core/proto/wire/chrome_fulfillment_info.proto20
-rw-r--r--chromium/components/feed/core/proto/wire/feed_query.proto5
-rw-r--r--chromium/components/feed/core/v2/BUILD.gn12
-rw-r--r--chromium/components/feed/core/v2/common_enums.h86
-rw-r--r--chromium/components/feed/core/v2/config.cc15
-rw-r--r--chromium/components/feed/core/v2/config.h6
-rw-r--r--chromium/components/feed/core/v2/feed_network.h2
-rw-r--r--chromium/components/feed/core/v2/feed_network_impl.cc11
-rw-r--r--chromium/components/feed/core/v2/feed_network_impl_unittest.cc3
-rw-r--r--chromium/components/feed/core/v2/feed_store.cc4
-rw-r--r--chromium/components/feed/core/v2/feed_store_unittest.cc2
-rw-r--r--chromium/components/feed/core/v2/feed_stream.cc118
-rw-r--r--chromium/components/feed/core/v2/feed_stream.h27
-rw-r--r--chromium/components/feed/core/v2/feed_stream_unittest.cc445
-rw-r--r--chromium/components/feed/core/v2/image_fetcher_unittest.cc2
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter.cc5
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter.h45
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter_unittest.cc3
-rw-r--r--chromium/components/feed/core/v2/notice_card_tracker.cc97
-rw-r--r--chromium/components/feed/core/v2/notice_card_tracker.h47
-rw-r--r--chromium/components/feed/core/v2/notice_card_tracker_unittest.cc151
-rw-r--r--chromium/components/feed/core/v2/prefs.cc18
-rw-r--r--chromium/components/feed/core/v2/prefs.h10
-rw-r--r--chromium/components/feed/core/v2/proto_util.cc40
-rw-r--r--chromium/components/feed/core/v2/proto_util_unittest.cc26
-rw-r--r--chromium/components/feed/core/v2/protocol_translator.cc13
-rw-r--r--chromium/components/feed/core/v2/protocol_translator.h3
-rw-r--r--chromium/components/feed/core/v2/public/feed_service.cc3
-rw-r--r--chromium/components/feed/core/v2/public/feed_service.h2
-rw-r--r--chromium/components/feed/core/v2/public/feed_stream_api.h14
-rw-r--r--chromium/components/feed/core/v2/public/types.h1
-rw-r--r--chromium/components/feed/core/v2/tasks/load_more_task.cc35
-rw-r--r--chromium/components/feed/core/v2/tasks/load_more_task.h3
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc2
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h1
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_task.cc17
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_task.h3
-rw-r--r--chromium/components/feed/core/v2/tasks/prefetch_images_task.cc100
-rw-r--r--chromium/components/feed/core/v2/tasks/prefetch_images_task.h51
-rw-r--r--chromium/components/feed/core/v2/types.h2
-rw-r--r--chromium/components/feed/features.gni16
-rw-r--r--chromium/components/feed/feed_feature_list.cc12
-rw-r--r--chromium/components/feed/feed_feature_list.h6
-rw-r--r--chromium/components/feedback/BUILD.gn8
-rw-r--r--chromium/components/feedback/feedback_uploader_dispatch_unittest.cc2
-rw-r--r--chromium/components/feedback/redaction_tool_fuzzer.cc46
-rw-r--r--chromium/components/feedback/redaction_tool_fuzzer.dict42
-rw-r--r--chromium/components/feedback/system_logs/system_logs_fetcher.cc2
-rw-r--r--chromium/components/find_in_page/find_result_observer.h1
-rw-r--r--chromium/components/find_in_page/find_tab_helper.cc29
-rw-r--r--chromium/components/flags_ui/resources/flags.html2
-rw-r--r--chromium/components/games/core/catalog_store_unittest.cc2
-rw-r--r--chromium/components/games/core/games_service_impl_unittest.cc2
-rw-r--r--chromium/components/games/core/highlighted_games_store_unittest.cc2
-rw-r--r--chromium/components/google/core/common/google_util.cc38
-rw-r--r--chromium/components/google/core/common/google_util.h13
-rw-r--r--chromium/components/google/core/common/google_util_unittest.cc17
-rw-r--r--chromium/components/grpc_support/bidirectional_stream.cc7
-rw-r--r--chromium/components/grpc_support/bidirectional_stream.h9
-rw-r--r--chromium/components/grpc_support/bidirectional_stream_c.cc13
-rw-r--r--chromium/components/guest_os/OWNERS2
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.cc17
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.h1
-rw-r--r--chromium/components/guest_view/common/guest_view_messages.h7
-rw-r--r--chromium/components/guest_view/renderer/guest_view_request.cc19
-rw-r--r--chromium/components/guest_view/renderer/guest_view_request.h17
-rw-r--r--chromium/components/gwp_asan/client/BUILD.gn12
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator.h5
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc4
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc2
-rw-r--r--chromium/components/gwp_asan/client/gwp_asan.cc2
-rw-r--r--chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc10
-rw-r--r--chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc14
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc2
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc2
-rw-r--r--chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc2
-rw-r--r--chromium/components/heap_profiling/multi_process/test_driver.cc8
-rw-r--r--chromium/components/history/README.md17
-rw-r--r--chromium/components/history/core/browser/android/android_cache_database.cc12
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.cc14
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.h14
-rw-r--r--chromium/components/history/core/browser/browsing_history_service_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/expire_history_backend_unittest.cc3
-rw-r--r--chromium/components/history/core/browser/history_backend.cc2
-rw-r--r--chromium/components/history/core/browser/history_backend_db_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/history_querying_unittest.cc4
-rw-r--r--chromium/components/history/core/browser/history_service.cc2
-rw-r--r--chromium/components/history/core/browser/history_service_unittest.cc6
-rw-r--r--chromium/components/history/core/browser/in_memory_history_backend.cc2
-rw-r--r--chromium/components/history/core/browser/in_memory_history_backend.h6
-rw-r--r--chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc4
-rw-r--r--chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc24
-rw-r--r--chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.h11
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc2
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge.h6
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc385
-rw-r--r--chromium/components/history/core/browser/top_sites_backend.cc2
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.cc7
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.h6
-rw-r--r--chromium/components/history/core/browser/url_database.h7
-rw-r--r--chromium/components/history/core/test/BUILD.gn13
-rw-r--r--chromium/components/image_fetcher/core/cache/image_cache.cc2
-rw-r--r--chromium/components/image_fetcher/core/cached_image_fetcher.cc2
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc2
-rw-r--r--chromium/components/image_fetcher/core/image_fetcher_impl_unittest.cc2
-rw-r--r--chromium/components/infobars/android/confirm_infobar.cc2
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.cc11
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.h11
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h5
-rw-r--r--chromium/components/javascript_dialogs/android/BUILD.gn1
-rw-r--r--chromium/components/keyed_service/core/keyed_service.h5
-rw-r--r--chromium/components/language/content/browser/geo_language_model_unittest.cc2
-rw-r--r--chromium/components/language/content/browser/geo_language_provider_unittest.cc2
-rw-r--r--chromium/components/language/core/browser/language_prefs_unittest.cc1
-rw-r--r--chromium/components/language/core/common/language_experiments.cc4
-rw-r--r--chromium/components/language/core/common/language_experiments.h6
-rw-r--r--chromium/components/language_usage_metrics/BUILD.gn8
-rw-r--r--chromium/components/language_usage_metrics/DEPS9
-rw-r--r--chromium/components/language_usage_metrics/language_usage_metrics.cc22
-rw-r--r--chromium/components/language_usage_metrics/language_usage_metrics.h11
-rw-r--r--chromium/components/language_usage_metrics/language_usage_metrics_unittest.cc178
-rw-r--r--chromium/components/leveldb_proto/internal/leveldb_proto_feature_list.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/proto_database_perftest.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database.h2
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/unique_proto_database_unittest.cc2
-rw-r--r--chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc4
-rw-r--r--chromium/components/leveldb_proto/public/shared_proto_database_client_list.h4
-rw-r--r--chromium/components/lookalikes/core/features.cc2
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_util.cc6
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_util_unittest.cc1
-rw-r--r--chromium/components/management/resources/management.html3
-rw-r--r--chromium/components/media_message_center/media_controls_progress_view_unittest.cc2
-rw-r--r--chromium/components/media_message_center/media_notification_background_ash_impl.cc40
-rw-r--r--chromium/components/media_message_center/media_notification_background_ash_impl.h2
-rw-r--r--chromium/components/media_message_center/media_notification_background_ash_impl_unittest.cc17
-rw-r--r--chromium/components/media_message_center/media_notification_item.h11
-rw-r--r--chromium/components/media_message_center/media_notification_view_impl.cc289
-rw-r--r--chromium/components/media_message_center/media_notification_view_impl.h36
-rw-r--r--chromium/components/media_message_center/media_notification_view_impl_unittest.cc16
-rw-r--r--chromium/components/media_message_center/media_notification_view_modern_impl.cc37
-rw-r--r--chromium/components/media_message_center/media_notification_view_modern_impl.h10
-rw-r--r--chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc9
-rw-r--r--chromium/components/media_message_center/media_session_notification_item.cc4
-rw-r--r--chromium/components/media_message_center/media_session_notification_item.h2
-rw-r--r--chromium/components/media_message_center/vector_icons/BUILD.gn2
-rw-r--r--chromium/components/media_router/OWNERS1
-rw-r--r--chromium/components/media_router/browser/android/BUILD.gn15
-rw-r--r--chromium/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java97
-rw-r--r--chromium/components/media_router/browser/android/media_router_android.cc2
-rw-r--r--chromium/components/media_router/browser/android/media_router_android_unittest.cc2
-rw-r--r--chromium/components/media_router/browser/presentation/local_presentation_manager.cc19
-rw-r--r--chromium/components/media_router/browser/presentation/local_presentation_manager.h23
-rw-r--r--chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc16
-rw-r--r--chromium/components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.cc2
-rw-r--r--chromium/components/media_router/common/BUILD.gn3
-rw-r--r--chromium/components/media_router/common/DEPS1
-rw-r--r--chromium/components/media_router/common/mojom/media_router.mojom3
-rw-r--r--chromium/components/media_router/common/mojom/media_router_mojom_traits.h7
-rw-r--r--chromium/components/media_router/common/route_request_result.h3
-rw-r--r--chromium/components/media_router/test/android/cast_emulator/BUILD.gn28
-rw-r--r--chromium/components/media_router/test/android/media_router_test_support/BUILD.gn22
-rw-r--r--chromium/components/messages/OWNERS2
-rw-r--r--chromium/components/messages/android/BUILD.gn88
-rw-r--r--chromium/components/messages/android/DEPS3
-rw-r--r--chromium/components/messages/android/internal/BUILD.gn9
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherImpl.java62
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java129
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImpl.java98
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImplTest.java123
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java230
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesFactory.java40
-rw-r--r--chromium/components/messages/android/message_dispatcher_bridge.cc43
-rw-r--r--chromium/components/messages/android/message_dispatcher_bridge.h28
-rw-r--r--chromium/components/messages/android/message_utils_bridge.cc20
-rw-r--r--chromium/components/messages/android/message_utils_bridge.h18
-rw-r--r--chromium/components/messages/android/message_wrapper.cc149
-rw-r--r--chromium/components/messages/android/message_wrapper.h71
-rw-r--r--chromium/components/messages/android/messages_feature.cc4
-rw-r--r--chromium/components/metrics/BUILD.gn39
-rw-r--r--chromium/components/metrics/DEPS3
-rw-r--r--chromium/components/metrics/call_stack_profile_builder_unittest.cc2
-rw-r--r--chromium/components/metrics/call_stack_profile_encoding.cc2
-rw-r--r--chromium/components/metrics/call_stack_profile_params.h1
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider.cc9
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider.h8
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider.cc6
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider.h7
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider_browsertest.cc20
-rw-r--r--chromium/components/metrics/demographic_metrics_provider_unittest.cc219
-rw-r--r--chromium/components/metrics/demographics/BUILD.gn67
-rw-r--r--chromium/components/metrics/demographics/DEPS8
-rw-r--r--chromium/components/metrics/demographics/demographic_metrics_provider.cc (renamed from chromium/components/metrics/demographic_metrics_provider.cc)49
-rw-r--r--chromium/components/metrics/demographics/demographic_metrics_provider.h (renamed from chromium/components/metrics/demographic_metrics_provider.h)31
-rw-r--r--chromium/components/metrics/demographics/demographic_metrics_provider_unittest.cc352
-rw-r--r--chromium/components/metrics/demographics/demographic_metrics_test_utils.cc106
-rw-r--r--chromium/components/metrics/demographics/demographic_metrics_test_utils.h76
-rw-r--r--chromium/components/metrics/demographics/user_demographics.cc253
-rw-r--r--chromium/components/metrics/demographics/user_demographics.h139
-rw-r--r--chromium/components/metrics/demographics/user_demographics_unittest.cc259
-rw-r--r--chromium/components/metrics/expired_histogram_util.cc15
-rw-r--r--chromium/components/metrics/expired_histograms_checker.cc25
-rw-r--r--chromium/components/metrics/expired_histograms_checker.h23
-rw-r--r--chromium/components/metrics/expired_histograms_checker_unittest.cc12
-rw-r--r--chromium/components/metrics/generate_expired_histograms_array.gni137
-rw-r--r--chromium/components/metrics/metrics_log.cc20
-rw-r--r--chromium/components/metrics/metrics_log.h17
-rw-r--r--chromium/components/metrics/metrics_log_manager_unittest.cc3
-rw-r--r--chromium/components/metrics/metrics_log_store.cc39
-rw-r--r--chromium/components/metrics/metrics_log_store.h32
-rw-r--r--chromium/components/metrics/metrics_log_store_unittest.cc25
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc13
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc15
-rw-r--r--chromium/components/metrics/metrics_pref_names.h3
-rw-r--r--chromium/components/metrics/metrics_reporting_service.cc25
-rw-r--r--chromium/components/metrics/metrics_reporting_service.h3
-rw-r--r--chromium/components/metrics/metrics_service.cc12
-rw-r--r--chromium/components/metrics/metrics_service.h16
-rw-r--r--chromium/components/metrics/metrics_service_client.cc37
-rw-r--r--chromium/components/metrics/metrics_service_client.h4
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc8
-rw-r--r--chromium/components/metrics/metrics_state_manager.h6
-rw-r--r--chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc2
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.cc2
-rw-r--r--chromium/components/metrics/persistent_histograms.cc2
-rw-r--r--chromium/components/metrics/reporting_service.cc6
-rw-r--r--chromium/components/metrics/reporting_service.h3
-rw-r--r--chromium/components/metrics/stability_metrics_provider.cc38
-rw-r--r--chromium/components/metrics/stability_metrics_provider.h3
-rw-r--r--chromium/components/metrics/structured/BUILD.gn4
-rw-r--r--chromium/components/metrics/ukm_demographic_metrics_provider.h2
-rw-r--r--chromium/components/metrics/unsent_log_store.cc2
-rw-r--r--chromium/components/metrics/unsent_log_store_metrics.cc4
-rw-r--r--chromium/components/metrics/unsent_log_store_metrics.h11
-rw-r--r--chromium/components/metrics/unsent_log_store_metrics_impl.cc21
-rw-r--r--chromium/components/metrics/unsent_log_store_metrics_impl_unittest.cc16
-rw-r--r--chromium/components/mirroring/service/BUILD.gn1
-rw-r--r--chromium/components/mirroring/service/message_dispatcher.cc2
-rw-r--r--chromium/components/mirroring/service/remoting_sender.cc12
-rw-r--r--chromium/components/mirroring/service/remoting_sender.h3
-rw-r--r--chromium/components/mirroring/service/remoting_sender_unittest.cc2
-rw-r--r--chromium/components/mirroring/service/rtp_stream_unittest.cc4
-rw-r--r--chromium/components/mirroring/service/session.cc20
-rw-r--r--chromium/components/mirroring/service/session.h4
-rw-r--r--chromium/components/mirroring/service/video_capture_client.cc19
-rw-r--r--chromium/components/mirroring/service/video_capture_client.h15
-rw-r--r--chromium/components/mirroring/service/video_capture_client_unittest.cc2
-rw-r--r--chromium/components/module_installer/android/module.cc6
-rw-r--r--chromium/components/nacl/browser/BUILD.gn20
-rw-r--r--chromium/components/nacl/common/BUILD.gn19
-rw-r--r--chromium/components/nacl/loader/BUILD.gn29
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc2
-rw-r--r--chromium/components/net_log/chrome_net_log.cc15
-rw-r--r--chromium/components/net_log/chrome_net_log.h14
-rw-r--r--chromium/components/net_log/net_export_file_writer.cc2
-rw-r--r--chromium/components/net_log/net_log_proxy_source_unittest.cc2
-rw-r--r--chromium/components/net_log/resources/net_export.html14
-rw-r--r--chromium/components/net_log/resources/net_export.js13
-rw-r--r--chromium/components/neterror/resources/neterror.html2
-rw-r--r--chromium/components/neterror/resources/neterror.js15
-rw-r--r--chromium/components/network_session_configurator/OWNERS1
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator.cc61
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc39
-rw-r--r--chromium/components/new_or_sad_tab_strings.grdp52
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_IN.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_OUT.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SAVED.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_IN.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_OUT.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_IN.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_OUT.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/OWNERS3
-rw-r--r--chromium/components/no_state_prefetch/OWNERS (renamed from chromium/components/prerender/OWNERS)2
-rw-r--r--chromium/components/no_state_prefetch/browser/BUILD.gn (renamed from chromium/components/prerender/browser/BUILD.gn)4
-rw-r--r--chromium/components/no_state_prefetch/browser/DEPS (renamed from chromium/components/prerender/browser/DEPS)0
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_config.cc (renamed from chromium/components/prerender/browser/prerender_config.cc)2
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_config.h (renamed from chromium/components/prerender/browser/prerender_config.h)6
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_contents.cc (renamed from chromium/components/prerender/browser/prerender_contents.cc)35
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_contents.h (renamed from chromium/components/prerender/browser/prerender_contents.h)16
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_contents_delegate.cc (renamed from chromium/components/prerender/browser/prerender_contents_delegate.cc)2
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_contents_delegate.h (renamed from chromium/components/prerender/browser/prerender_contents_delegate.h)8
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_field_trial.cc20
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_field_trial.h (renamed from chromium/components/prerender/browser/prerender_field_trial.h)14
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_handle.cc (renamed from chromium/components/prerender/browser/prerender_handle.cc)4
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_handle.h (renamed from chromium/components/prerender/browser/prerender_handle.h)8
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_histograms.cc (renamed from chromium/components/prerender/browser/prerender_histograms.cc)4
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_histograms.h (renamed from chromium/components/prerender/browser/prerender_histograms.h)10
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_history.cc (renamed from chromium/components/prerender/browser/prerender_history.cc)2
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_history.h (renamed from chromium/components/prerender/browser/prerender_history.h)10
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc (renamed from chromium/components/prerender/browser/prerender_history_unittest.cc)2
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_link_manager.cc (renamed from chromium/components/prerender/browser/prerender_link_manager.cc)13
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_link_manager.h (renamed from chromium/components/prerender/browser/prerender_link_manager.h)8
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_manager.cc (renamed from chromium/components/prerender/browser/prerender_manager.cc)133
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_manager.h (renamed from chromium/components/prerender/browser/prerender_manager.h)57
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_manager_delegate.cc (renamed from chromium/components/prerender/browser/prerender_manager_delegate.cc)2
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_manager_delegate.h (renamed from chromium/components/prerender/browser/prerender_manager_delegate.h)10
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_processor_impl.cc (renamed from chromium/components/prerender/browser/prerender_processor_impl.cc)12
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_processor_impl.h (renamed from chromium/components/prerender/browser/prerender_processor_impl.h)9
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_processor_impl_delegate.h (renamed from chromium/components/prerender/browser/prerender_processor_impl_delegate.h)6
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_util.cc (renamed from chromium/components/prerender/browser/prerender_util.cc)4
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_util.h (renamed from chromium/components/prerender/browser/prerender_util.h)12
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_util_unittest.cc (renamed from chromium/components/prerender/browser/prerender_util_unittest.cc)2
-rw-r--r--chromium/components/no_state_prefetch/common/BUILD.gn (renamed from chromium/components/prerender/common/BUILD.gn)0
-rw-r--r--chromium/components/no_state_prefetch/common/DEPS (renamed from chromium/components/prerender/common/DEPS)0
-rw-r--r--chromium/components/no_state_prefetch/common/OWNERS (renamed from chromium/components/prerender/common/OWNERS)0
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_canceler.mojom (renamed from chromium/components/prerender/common/prerender_canceler.mojom)0
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_final_status.cc (renamed from chromium/components/prerender/common/prerender_final_status.cc)4
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_final_status.h (renamed from chromium/components/prerender/common/prerender_final_status.h)10
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_origin.cc (renamed from chromium/components/prerender/common/prerender_origin.cc)2
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_origin.h (renamed from chromium/components/prerender/common/prerender_origin.h)6
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_types.mojom (renamed from chromium/components/prerender/common/prerender_types.mojom)0
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc (renamed from chromium/components/prerender/common/prerender_url_loader_throttle.cc)4
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.h (renamed from chromium/components/prerender/common/prerender_url_loader_throttle.h)10
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_util.cc (renamed from chromium/components/prerender/common/prerender_util.cc)2
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_util.h (renamed from chromium/components/prerender/common/prerender_util.h)8
-rw-r--r--chromium/components/no_state_prefetch/common/render_frame_prerender_messages.mojom (renamed from chromium/components/prerender/common/render_frame_prerender_messages.mojom)2
-rw-r--r--chromium/components/no_state_prefetch/renderer/BUILD.gn (renamed from chromium/components/prerender/renderer/BUILD.gn)4
-rw-r--r--chromium/components/no_state_prefetch/renderer/DEPS (renamed from chromium/components/prerender/renderer/DEPS)0
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_helper.cc (renamed from chromium/components/prerender/renderer/prerender_helper.cc)4
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_helper.h (renamed from chromium/components/prerender/renderer/prerender_helper.h)8
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_observer.h (renamed from chromium/components/prerender/renderer/prerender_observer.h)6
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_observer_list.cc (renamed from chromium/components/prerender/renderer/prerender_observer_list.cc)4
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_observer_list.h (renamed from chromium/components/prerender/renderer/prerender_observer_list.h)6
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.cc (renamed from chromium/components/prerender/renderer/prerender_render_frame_observer.cc)8
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.h (renamed from chromium/components/prerender/renderer/prerender_render_frame_observer.h)10
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_utils.cc (renamed from chromium/components/prerender/renderer/prerender_utils.cc)4
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerender_utils.h (renamed from chromium/components/prerender/renderer/prerender_utils.h)6
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerenderer_client.cc (renamed from chromium/components/prerender/renderer/prerenderer_client.cc)4
-rw-r--r--chromium/components/no_state_prefetch/renderer/prerenderer_client.h (renamed from chromium/components/prerender/renderer/prerenderer_client.h)6
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc9
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h12
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc5
-rw-r--r--chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h6
-rw-r--r--chromium/components/ntp_snippets/remote/cached_image_fetcher.cc2
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h2
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h2
-rw-r--r--chromium/components/ntp_snippets_strings.grdp2
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn17
-rw-r--r--chromium/components/ntp_tiles/DEPS7
-rw-r--r--chromium/components/ntp_tiles/constants.cc6
-rw-r--r--chromium/components/ntp_tiles/constants.h2
-rw-r--r--chromium/components/ntp_tiles/custom_links_manager_impl.cc6
-rw-r--r--chromium/components/ntp_tiles/custom_links_manager_impl.h7
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc2
-rw-r--r--chromium/components/ntp_tiles/metrics.cc5
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc104
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.h36
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc147
-rw-r--r--chromium/components/ntp_tiles/tile_source.h4
-rw-r--r--chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html1
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_item_visuals_bridge.cc2
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/cleanup_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/get_requests_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/reconcile_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.cc2
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_unittest.cc5
-rw-r--r--chromium/components/offline_pages/core/downloads/download_ui_adapter.cc2
-rw-r--r--chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc1
-rw-r--r--chromium/components/offline_pages/core/model/cleanup_visuals_task_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/model/get_visuals_task_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified.cc8
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc3
-rw-r--r--chromium/components/offline_pages/core/model/store_visuals_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/model/visuals_availability_task_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/offline_page_archiver.h3
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.cc5
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_test_util.cc4
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/tasks/download_archives_task_unittest.cc1
-rw-r--r--chromium/components/offline_pages/core/prefetch/tasks/get_operation_task_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_download_service.cc2
-rw-r--r--chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller_unittest.cc1
-rw-r--r--chromium/components/offline_pages/task/task_unittest.cc2
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn13
-rw-r--r--chromium/components/omnibox_strings.grdp5
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ACC_REMOVE_SUGGESTION_SUFFIX.png.sha11
-rw-r--r--chromium/components/on_load_script_injector/browser/BUILD.gn6
-rw-r--r--chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc107
-rw-r--r--chromium/components/on_load_script_injector/browser/on_load_script_injector_host.h97
-rw-r--r--chromium/components/open_from_clipboard/DEPS1
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc25
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc1
-rw-r--r--chromium/components/openscreen_platform/tls_client_connection.h2
-rw-r--r--chromium/components/openscreen_platform/tls_connection_factory.h2
-rw-r--r--chromium/components/openscreen_platform/udp_socket.h4
-rw-r--r--chromium/components/optimization_guide/hints_processing_util.cc2
-rw-r--r--chromium/components/optimization_guide/optimization_guide_store.cc2
-rw-r--r--chromium/components/optimization_guide/optimization_metadata.h17
-rw-r--r--chromium/components/optimization_guide/proto/hints.proto5
-rw-r--r--chromium/components/optimization_guide/proto/models.proto2
-rw-r--r--chromium/components/optimization_guide/proto/performance_hints_metadata.proto13
-rw-r--r--chromium/components/os_crypt/BUILD.gn9
-rw-r--r--chromium/components/os_crypt/features.gni2
-rw-r--r--chromium/components/os_crypt/keychain_password_mac.mm2
-rw-r--r--chromium/components/ownership/owner_settings_service.cc4
-rw-r--r--chromium/components/ownership/owner_settings_service.h7
-rw-r--r--chromium/components/page_info/android/BUILD.gn3
-rw-r--r--chromium/components/page_info/android/connection_info_view_android.cc11
-rw-r--r--chromium/components/page_info/android/page_info_controller_android.cc5
-rw-r--r--chromium/components/page_info/page_info.cc32
-rw-r--r--chromium/components/page_info/page_info.h5
-rw-r--r--chromium/components/page_info/page_info_ui.cc172
-rw-r--r--chromium/components/page_info/page_info_ui.h9
-rw-r--r--chromium/components/page_info_strings.grdp16
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_DESCRIPTION.png.sha1 (renamed from chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1)0
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_TYPE_IDLE_DETECTION.png.sha12
-rw-r--r--chromium/components/page_load_metrics/browser/BUILD.gn6
-rw-r--r--chromium/components/page_load_metrics/browser/layout_shift_normalization.cc191
-rw-r--r--chromium/components/page_load_metrics/browser/layout_shift_normalization.h86
-rw-r--r--chromium/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc146
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc15
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h26
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc4
-rw-r--r--chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc27
-rw-r--r--chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h2
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc32
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h4
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc18
-rw-r--r--chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc4
-rw-r--r--chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.cc2
-rw-r--r--chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc33
-rw-r--r--chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h4
-rw-r--r--chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc48
-rw-r--r--chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h40
-rw-r--r--chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer_unittest.cc124
-rw-r--r--chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc13
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc6
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_observer.h44
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h10
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc10
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h5
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc59
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h59
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_tracker.cc20
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_tracker.h4
-rw-r--r--chromium/components/page_load_metrics/common/BUILD.gn1
-rw-r--r--chromium/components/page_load_metrics/common/page_load_metrics.mojom26
-rw-r--r--chromium/components/page_load_metrics/common/page_load_metrics_constants.h5
-rw-r--r--chromium/components/page_load_metrics/renderer/OWNERS2
-rw-r--r--chromium/components/page_load_metrics/renderer/fake_page_timing_sender.cc25
-rw-r--r--chromium/components/page_load_metrics/renderer/fake_page_timing_sender.h34
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc69
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h14
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc28
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h2
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc22
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_sender.h3
-rw-r--r--chromium/components/paint_preview/README.md113
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc1
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client.cc30
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client_unittest.cc3
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc22
-rw-r--r--chromium/components/paint_preview/common/paint_preview_tracker.h4
-rw-r--r--chromium/components/paint_preview/common/serial_utils.cc48
-rw-r--r--chromium/components/paint_preview/common/serial_utils.h15
-rw-r--r--chromium/components/paint_preview/common/serial_utils_unittest.cc116
-rw-r--r--chromium/components/paint_preview/common/serialized_recording.cc3
-rw-r--r--chromium/components/paint_preview/common/serialized_recording_unittest.cc2
-rw-r--r--chromium/components/paint_preview/player/BUILD.gn3
-rw-r--r--chromium/components/paint_preview/player/android/javatests/paint_preview_test_service.cc3
-rw-r--r--chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java15
-rw-r--r--chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java543
-rw-r--r--chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc48
-rw-r--r--chromium/components/paint_preview/player/android/player_compositor_delegate_android.h12
-rw-r--r--chromium/components/paint_preview/player/bitmap_request.cc24
-rw-r--r--chromium/components/paint_preview/player/bitmap_request.h38
-rw-r--r--chromium/components/paint_preview/player/compositor_status.h2
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate.cc130
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate.h50
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc236
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc56
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc8
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc2
-rw-r--r--chromium/components/password_manager/content/browser/bad_message.cc16
-rw-r--r--chromium/components/password_manager/content/browser/bad_message.h22
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc13
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.h5
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc1
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc41
-rw-r--r--chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc3
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn56
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/android_affiliation_service.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc2
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc22
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h3
-rw-r--r--chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/credential_cache.h2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc10
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc46
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_utils.cc50
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_utils.h31
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_utils_unittest.cc (renamed from chromium/components/password_manager/core/common/credential_manager_types_unittest.cc)42
-rw-r--r--chromium/components/password_manager/core/browser/credentials_cleaner.h4
-rw-r--r--chromium/components/password_manager/core/browser/credentials_cleaner_runner.cc14
-rw-r--r--chromium/components/password_manager/core/browser/credentials_cleaner_runner.h19
-rw-r--r--chromium/components/password_manager/core/browser/credentials_cleaner_runner_unittest.cc85
-rw-r--r--chromium/components/password_manager/core/browser/credentials_filter.h2
-rw-r--r--chromium/components/password_manager/core/browser/export/password_csv_writer.h3
-rw-r--r--chromium/components/password_manager/core/browser/field_info_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher.h2
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser.cc45
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser.h5
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc20
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc30
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/password_field_prediction_unittest.cc37
-rw-r--r--chromium/components/password_manager/core/browser/form_saver.h3
-rw-r--r--chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager_impl.cc4
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager_impl.h2
-rw-r--r--chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc30
-rw-r--r--chromium/components/password_manager/core/browser/http_credentials_cleaner.cc3
-rw-r--r--chromium/components/password_manager/core/browser/http_credentials_cleaner.h3
-rw-r--r--chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.h3
-rw-r--r--chromium/components/password_manager/core/browser/import/password_importer_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/bulk_leak_check_impl_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc19
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/encryption_utils.h2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate.h2
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc37
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc7
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h5
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc13
-rw-r--r--chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc24
-rw-r--r--chromium/components/password_manager/core/browser/origin_credential_store.h3
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.cc7
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_form.cc (renamed from chromium/components/autofill/core/common/password_form.cc)107
-rw-r--r--chromium/components/password_manager/core/browser/password_form.h382
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.cc19
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.h5
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling_unittest.cc34
-rw-r--r--chromium/components/password_manager/core/browser/password_form_forward.h25
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc95
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h22
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_for_ui.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc24
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.h3
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc1
-rw-r--r--chromium/components/password_manager/core/browser/password_list_sorter.h3
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc70
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h44
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.cc11
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h22
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc45
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc16
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h23
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.h9
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc223
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc25
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.h5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/browser/password_requirements_service_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc1
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc32
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc9
-rw-r--r--chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.h6
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc25
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h34
-rw-r--r--chromium/components/password_manager/core/browser/password_store_change.cc17
-rw-r--r--chromium/components/password_manager/core/browser/password_store_change.h12
-rw-r--r--chromium/components/password_manager/core/browser/password_store_consumer.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_store_factory_util.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_store_sync.h3
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_sync_util.h5
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils.h2
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.cc7
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc72
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.cc115
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h38
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc131
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder.h2
-rw-r--r--chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/statistics_table_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter.cc27
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter.h3
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc63
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc8
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h5
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc12
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_model_type_controller.h1
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc16
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc135
-rw-r--r--chromium/components/password_manager/core/browser/sync_credentials_filter.h3
-rw-r--r--chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/sync_username_test_base.h3
-rw-r--r--chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h3
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.cc4
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.h13
-rw-r--r--chromium/components/password_manager/core/browser/ui/compromised_credentials_reader_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/ui/credential_provider_interface.h4
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc47
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h20
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc37
-rw-r--r--chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.cc71
-rw-r--r--chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.h10
-rw-r--r--chromium/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc223
-rw-r--r--chromium/components/password_manager/core/browser/ui/weak_check_utility.cc11
-rw-r--r--chromium/components/password_manager/core/browser/ui/weak_check_utility.h8
-rw-r--r--chromium/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc7
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader.cc1
-rw-r--r--chromium/components/password_manager/core/browser/well_known_change_password_state_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/common/BUILD.gn28
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.cc47
-rw-r--r--chromium/components/password_manager/core/common/credential_manager_types.h19
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc39
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h6
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.cc7
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.h9
-rw-r--r--chromium/components/password_manager/ios/js_password_manager.mm25
-rw-r--r--chromium/components/password_manager/ios/password_form_helper.mm22
-rw-r--r--chromium/components/password_manager/ios/password_form_helper_unittest.mm1
-rw-r--r--chromium/components/password_manager/ios/password_suggestion_helper.h2
-rw-r--r--chromium/components/password_manager/ios/password_suggestion_helper.mm2
-rw-r--r--chromium/components/password_manager/ios/resources/password_controller.js8
-rw-r--r--chromium/components/password_manager/ios/shared_password_controller.mm12
-rw-r--r--chromium/components/password_manager/ios/shared_password_controller_unittest.mm12
-rw-r--r--chromium/components/payments/content/BUILD.gn2
-rw-r--r--chromium/components/payments/content/DEPS1
-rw-r--r--chromium/components/payments/content/android/BUILD.gn76
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.cc6
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.h3
-rw-r--r--chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl7
-rw-r--r--chromium/components/payments/content/android/java_templates/PrefsStrings.java.tmpl17
-rw-r--r--chromium/components/payments/content/android/jni_payment_app.cc4
-rw-r--r--chromium/components/payments/content/android/journey_logger_android.cc162
-rw-r--r--chromium/components/payments/content/android/journey_logger_android.h87
-rw-r--r--chromium/components/payments/content/android/payment_handler_host.h3
-rw-r--r--chromium/components/payments/content/android/payment_request_spec.h2
-rw-r--r--chromium/components/payments/content/android/payments_java_resources.gni3
-rw-r--r--chromium/components/payments/content/android_app_communication.h2
-rw-r--r--chromium/components/payments/content/android_app_communication_chrome_os.cc25
-rw-r--r--chromium/components/payments/content/android_app_communication_stub.cc1
-rw-r--r--chromium/components/payments/content/android_app_communication_test_support_chrome_os.cc2
-rw-r--r--chromium/components/payments/content/android_app_communication_unittest.cc14
-rw-r--r--chromium/components/payments/content/android_payment_app.cc18
-rw-r--r--chromium/components/payments/content/android_payment_app.h5
-rw-r--r--chromium/components/payments/content/android_payment_app_factory.cc6
-rw-r--r--chromium/components/payments/content/android_payment_app_factory_unittest.cc18
-rw-r--r--chromium/components/payments/content/android_payment_app_unittest.cc23
-rw-r--r--chromium/components/payments/content/installable_payment_app_crawler.cc4
-rw-r--r--chromium/components/payments/content/payment_event_response_util.cc5
-rw-r--r--chromium/components/payments/content/payment_request.cc89
-rw-r--r--chromium/components/payments/content/payment_request.h7
-rw-r--r--chromium/components/payments/content/payment_request_display_manager.cc1
-rw-r--r--chromium/components/payments/content/payment_request_display_manager.h4
-rw-r--r--chromium/components/payments/content/payment_request_spec.cc8
-rw-r--r--chromium/components/payments/content/payment_request_spec.h10
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_app_factory.cc42
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_app_factory.h13
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_controller.cc2
-rw-r--r--chromium/components/payments/content/service_worker_payment_app.cc8
-rw-r--r--chromium/components/payments/content/service_worker_payment_app.h2
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc2
-rw-r--r--chromium/components/payments/core/can_make_payment_query.cc2
-rw-r--r--chromium/components/payments/core/currency_formatter.cc4
-rw-r--r--chromium/components/payments/core/currency_formatter.h4
-rw-r--r--chromium/components/payments/core/journey_logger.h2
-rw-r--r--chromium/components/payments/core/journey_logger_unittest.cc1
-rw-r--r--chromium/components/payments/core/native_error_strings.cc6
-rw-r--r--chromium/components/payments/core/native_error_strings.h6
-rw-r--r--chromium/components/payments/core/strings_util.cc2
-rw-r--r--chromium/components/payments/core/strings_util.h2
-rw-r--r--chromium/components/payments_strings_grdp/OWNERS3
-rw-r--r--chromium/components/pdf_strings.grdp3
-rw-r--r--chromium/components/pdf_strings_grdp/IDS_PDF_FULLSCREEN.png.sha11
-rw-r--r--chromium/components/performance_manager/BUILD.gn56
-rw-r--r--chromium/components/performance_manager/DEPS2
-rw-r--r--chromium/components/performance_manager/decorators/decorators_utils_unittest.cc2
-rw-r--r--chromium/components/performance_manager/decorators/frame_visibility_decorator.cc91
-rw-r--r--chromium/components/performance_manager/decorators/frame_visibility_decorator.h44
-rw-r--r--chromium/components/performance_manager/decorators/frame_visibility_decorator_unittest.cc142
-rw-r--r--chromium/components/performance_manager/decorators/site_data_recorder_unittest.cc4
-rw-r--r--chromium/components/performance_manager/embedder/performance_manager_lifetime.h4
-rw-r--r--chromium/components/performance_manager/execution_context/execution_context_attached_data_unittest.cc77
-rw-r--r--chromium/components/performance_manager/execution_context/execution_context_impl.cc21
-rw-r--r--chromium/components/performance_manager/execution_context/execution_context_registry_impl.cc57
-rw-r--r--chromium/components/performance_manager/execution_context/execution_context_registry_impl.h23
-rw-r--r--chromium/components/performance_manager/execution_context/execution_context_registry_impl_unittest.cc63
-rw-r--r--chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator.cc (renamed from chromium/components/performance_manager/frame_priority/boosting_vote_aggregator.cc)196
-rw-r--r--chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator_unittest.cc659
-rw-r--r--chromium/components/performance_manager/execution_context_priority/execution_context_priority.cc58
-rw-r--r--chromium/components/performance_manager/execution_context_priority/execution_context_priority_unittest.cc (renamed from chromium/components/performance_manager/frame_priority/frame_priority_unittest.cc)87
-rw-r--r--chromium/components/performance_manager/execution_context_priority/max_vote_aggregator.cc (renamed from chromium/components/performance_manager/frame_priority/max_vote_aggregator.cc)64
-rw-r--r--chromium/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc (renamed from chromium/components/performance_manager/frame_priority/max_vote_aggregator_unittest.cc)117
-rw-r--r--chromium/components/performance_manager/execution_context_priority/override_vote_aggregator.cc (renamed from chromium/components/performance_manager/frame_priority/override_vote_aggregator.cc)67
-rw-r--r--chromium/components/performance_manager/execution_context_priority/override_vote_aggregator_unittest.cc (renamed from chromium/components/performance_manager/frame_priority/override_vote_aggregator_unittest.cc)82
-rw-r--r--chromium/components/performance_manager/features.cc3
-rw-r--r--chromium/components/performance_manager/frame_priority/boosting_vote_aggregator_unittest.cc603
-rw-r--r--chromium/components/performance_manager/frame_priority/frame_priority.cc403
-rw-r--r--chromium/components/performance_manager/freezing/freezing_vote_aggregator.cc194
-rw-r--r--chromium/components/performance_manager/freezing/freezing_vote_aggregator.h151
-rw-r--r--chromium/components/performance_manager/freezing/freezing_vote_aggregator_unittest.cc267
-rw-r--r--chromium/components/performance_manager/graph/frame_node_impl.cc78
-rw-r--r--chromium/components/performance_manager/graph/frame_node_impl.h48
-rw-r--r--chromium/components/performance_manager/graph/frame_node_impl_describer.cc49
-rw-r--r--chromium/components/performance_manager/graph/frame_node_impl_unittest.cc49
-rw-r--r--chromium/components/performance_manager/graph/graph_impl.cc2
-rw-r--r--chromium/components/performance_manager/graph/policies/process_priority_policy_unittest.cc4
-rw-r--r--chromium/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc6
-rw-r--r--chromium/components/performance_manager/graph/process_node_impl.cc22
-rw-r--r--chromium/components/performance_manager/graph/process_node_impl.h20
-rw-r--r--chromium/components/performance_manager/graph/process_node_impl_unittest.cc2
-rw-r--r--chromium/components/performance_manager/graph/properties.h18
-rw-r--r--chromium/components/performance_manager/graph/system_node_impl.h7
-rw-r--r--chromium/components/performance_manager/graph/worker_node_impl.cc20
-rw-r--r--chromium/components/performance_manager/graph/worker_node_impl.h27
-rw-r--r--chromium/components/performance_manager/graph/worker_node_impl_describer.cc4
-rw-r--r--chromium/components/performance_manager/graph/worker_node_impl_unittest.cc51
-rw-r--r--chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc2
-rw-r--r--chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_unittest.cc2
-rw-r--r--chromium/components/performance_manager/performance_manager.cc36
-rw-r--r--chromium/components/performance_manager/performance_manager_browsertest.cc2
-rw-r--r--chromium/components/performance_manager/performance_manager_impl_unittest.cc4
-rw-r--r--chromium/components/performance_manager/performance_manager_lifetime.cc25
-rw-r--r--chromium/components/performance_manager/performance_manager_tab_helper_unittest.cc2
-rw-r--r--chromium/components/performance_manager/performance_manager_unittest.cc52
-rw-r--r--chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc13
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.h2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/unittest_utils.cc2
-rw-r--r--chromium/components/performance_manager/public/execution_context/execution_context.h15
-rw-r--r--chromium/components/performance_manager/public/execution_context/execution_context_attached_data.h106
-rw-r--r--chromium/components/performance_manager/public/execution_context/execution_context_registry.h3
-rw-r--r--chromium/components/performance_manager/public/execution_context_priority/boosting_vote_aggregator.h (renamed from chromium/components/performance_manager/public/frame_priority/boosting_vote_aggregator.h)104
-rw-r--r--chromium/components/performance_manager/public/execution_context_priority/execution_context_priority.h67
-rw-r--r--chromium/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h (renamed from chromium/components/performance_manager/public/frame_priority/max_vote_aggregator.h)53
-rw-r--r--chromium/components/performance_manager/public/execution_context_priority/override_vote_aggregator.h (renamed from chromium/components/performance_manager/public/frame_priority/override_vote_aggregator.h)48
-rw-r--r--chromium/components/performance_manager/public/features.h6
-rw-r--r--chromium/components/performance_manager/public/frame_priority/frame_priority.h432
-rw-r--r--chromium/components/performance_manager/public/graph/frame_node.h31
-rw-r--r--chromium/components/performance_manager/public/graph/node_data_describer_util.cc17
-rw-r--r--chromium/components/performance_manager/public/graph/node_data_describer_util.h9
-rw-r--r--chromium/components/performance_manager/public/graph/worker_node.h15
-rw-r--r--chromium/components/performance_manager/public/mojom/BUILD.gn10
-rw-r--r--chromium/components/performance_manager/public/mojom/coordination_unit.mojom47
-rw-r--r--chromium/components/performance_manager/public/mojom/v8_contexts.mojom57
-rw-r--r--chromium/components/performance_manager/public/mojom/web_memory.mojom65
-rw-r--r--chromium/components/performance_manager/public/performance_manager.h32
-rw-r--r--chromium/components/performance_manager/public/render_process_host_id.h24
-rw-r--r--chromium/components/performance_manager/public/v8_memory/v8_detailed_memory.h (renamed from chromium/components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h)549
-rw-r--r--chromium/components/performance_manager/public/v8_memory/web_memory.h33
-rw-r--r--chromium/components/performance_manager/public/voting/voting.h922
-rw-r--r--chromium/components/performance_manager/render_process_host_id_unittest.cc39
-rw-r--r--chromium/components/performance_manager/render_process_host_proxy_browsertest.cc5
-rw-r--r--chromium/components/performance_manager/service_worker_context_adapter.cc85
-rw-r--r--chromium/components/performance_manager/service_worker_context_adapter.h17
-rw-r--r--chromium/components/performance_manager/tab_helper_frame_node_source.cc10
-rw-r--r--chromium/components/performance_manager/tab_helper_frame_node_source.h8
-rw-r--r--chromium/components/performance_manager/test_support/BUILD.gn3
-rw-r--r--chromium/components/performance_manager/test_support/decorators_utils.h2
-rw-r--r--chromium/components/performance_manager/test_support/frame_priority.cc101
-rw-r--r--chromium/components/performance_manager/test_support/frame_priority.h77
-rw-r--r--chromium/components/performance_manager/test_support/mock_graphs.cc43
-rw-r--r--chromium/components/performance_manager/test_support/mock_graphs.h57
-rw-r--r--chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.cc15
-rw-r--r--chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.h27
-rw-r--r--chromium/components/performance_manager/test_support/voting.h279
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker.cc511
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker.h248
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc113
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc67
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h69
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers_unittest.cc135
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.cc449
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h379
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc434
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_types.cc62
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_types.h89
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_unittest.cc771
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_detailed_memory.cc (renamed from chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc)638
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc (renamed from chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc)1085
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.cc240
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.h225
-rw-r--r--chromium/components/performance_manager/v8_memory/web_memory_aggregator.cc120
-rw-r--r--chromium/components/performance_manager/v8_memory/web_memory_aggregator.h49
-rw-r--r--chromium/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc236
-rw-r--r--chromium/components/performance_manager/voting_unittest.cc201
-rw-r--r--chromium/components/performance_manager/web_contents_proxy_unittest.cc2
-rw-r--r--chromium/components/performance_manager/worker_watcher.cc169
-rw-r--r--chromium/components/performance_manager/worker_watcher.h20
-rw-r--r--chromium/components/performance_manager/worker_watcher_unittest.cc75
-rw-r--r--chromium/components/permissions/BUILD.gn13
-rw-r--r--chromium/components/permissions/android/BUILD.gn1
-rw-r--r--chromium/components/permissions/android/permission_prompt_android.cc7
-rw-r--r--chromium/components/permissions/android/permission_prompt_android.h4
-rw-r--r--chromium/components/permissions/chooser_context_base.cc10
-rw-r--r--chromium/components/permissions/chooser_context_base_unittest.cc10
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context_android.cc13
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context_android.h3
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc11
-rw-r--r--chromium/components/permissions/contexts/webxr_permission_context.cc10
-rw-r--r--chromium/components/permissions/contexts/webxr_permission_context.h3
-rw-r--r--chromium/components/permissions/features.cc26
-rw-r--r--chromium/components/permissions/features.h10
-rw-r--r--chromium/components/permissions/notification_permission_ui_selector.cc6
-rw-r--r--chromium/components/permissions/notification_permission_ui_selector.h11
-rw-r--r--chromium/components/permissions/permission_context_base.cc45
-rw-r--r--chromium/components/permissions/permission_context_base.h9
-rw-r--r--chromium/components/permissions/permission_context_base_unittest.cc2
-rw-r--r--chromium/components/permissions/permission_decision_auto_blocker.cc16
-rw-r--r--chromium/components/permissions/permission_manager.cc3
-rw-r--r--chromium/components/permissions/permission_manager.h3
-rw-r--r--chromium/components/permissions/permission_manager_unittest.cc58
-rw-r--r--chromium/components/permissions/permission_prompt.h4
-rw-r--r--chromium/components/permissions/permission_request.h62
-rw-r--r--chromium/components/permissions/permission_request_enums.h68
-rw-r--r--chromium/components/permissions/permission_request_impl.cc11
-rw-r--r--chromium/components/permissions/permission_request_impl.h5
-rw-r--r--chromium/components/permissions/permission_request_manager.cc286
-rw-r--r--chromium/components/permissions/permission_request_manager.h77
-rw-r--r--chromium/components/permissions/permission_request_manager_unittest.cc345
-rw-r--r--chromium/components/permissions/permission_uma_util.cc82
-rw-r--r--chromium/components/permissions/permission_uma_util.h55
-rw-r--r--chromium/components/permissions/permission_uma_util_unittest.cc23
-rw-r--r--chromium/components/permissions/permission_util.h1
-rw-r--r--chromium/components/permissions/permissions_client.cc6
-rw-r--r--chromium/components/permissions/permissions_client.h13
-rw-r--r--chromium/components/permissions/prediction_service/BUILD.gn42
-rw-r--r--chromium/components/permissions/prediction_service/DEPS7
-rw-r--r--chromium/components/permissions/prediction_service/prediction_request_features.h35
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service.cc269
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service.h81
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_base.h43
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_common.cc24
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_common.h25
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_messages.proto126
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_unittest.cc510
-rw-r--r--chromium/components/permissions/quota_permission_context_impl.cc5
-rw-r--r--chromium/components/permissions_strings.grdp9
-rw-r--r--chromium/components/permissions_strings_grdp/IDS_PERMISSIONS_BUBBLE_PROMPT_ONE_TIME.png.sha11
-rw-r--r--chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ALWAYS.png.sha11
-rw-r--r--chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ONCE.png.sha11
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.cc193
-rw-r--r--chromium/components/plugins/renderer/loadable_plugin_placeholder.h60
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc13
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.h13
-rw-r--r--chromium/components/policy/BUILD.gn10
-rw-r--r--chromium/components/policy/content/BUILD.gn25
-rw-r--r--chromium/components/policy/core/common/BUILD.gn9
-rw-r--r--chromium/components/policy/proto/BUILD.gn13
-rw-r--r--chromium/components/policy_strings.grdp19
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE.png.sha11
-rw-r--r--chromium/components/prefs/json_pref_store.cc2
-rw-r--r--chromium/components/prefs/pref_change_registrar.cc4
-rw-r--r--chromium/components/prefs/pref_change_registrar_unittest.cc2
-rw-r--r--chromium/components/prefs/pref_service.cc88
-rw-r--r--chromium/components/prefs/pref_service.h3
-rw-r--r--chromium/components/prefs/pref_service_factory.cc2
-rw-r--r--chromium/components/prefs/pref_service_unittest.cc2
-rw-r--r--chromium/components/prefs/pref_test_utils.cc2
-rw-r--r--chromium/components/prerender/browser/prerender_field_trial.cc35
-rw-r--r--chromium/components/previews/content/previews_decider_impl.cc2
-rw-r--r--chromium/components/previews/content/previews_decider_impl_unittest.cc2
-rw-r--r--chromium/components/previews/core/previews_block_list_unittest.cc2
-rw-r--r--chromium/components/previous_session_info/BUILD.gn32
-rw-r--r--chromium/components/previous_session_info/DEPS4
-rw-r--r--chromium/components/previous_session_info/OWNERS5
-rw-r--r--chromium/components/previous_session_info/README3
-rw-r--r--chromium/components/previous_session_info/previous_session_info.h233
-rw-r--r--chromium/components/previous_session_info/previous_session_info.mm653
-rw-r--r--chromium/components/previous_session_info/previous_session_info_private.h38
-rw-r--r--chromium/components/previous_session_info/previous_session_info_unittest.mm721
-rw-r--r--chromium/components/printing/browser/BUILD.gn1
-rw-r--r--chromium/components/printing/browser/DEPS1
-rw-r--r--chromium/components/printing/browser/print_composite_client.cc3
-rw-r--r--chromium/components/printing/browser/print_manager.cc16
-rw-r--r--chromium/components/printing/browser/print_manager.h7
-rw-r--r--chromium/components/printing/browser/print_manager_utils.cc5
-rw-r--r--chromium/components/printing/browser/printer_capabilities_unittest.cc15
-rw-r--r--chromium/components/printing/common/print.mojom7
-rw-r--r--chromium/components/printing/common/print_messages.h10
-rw-r--r--chromium/components/printing/renderer/BUILD.gn12
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.cc98
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.h1
-rw-r--r--chromium/components/profile_metrics/counts.cc2
-rw-r--r--chromium/components/profile_metrics/counts.h38
-rw-r--r--chromium/components/query_tiles/android/tile_conversion_bridge.cc11
-rw-r--r--chromium/components/query_tiles/android/tile_conversion_bridge.h4
-rw-r--r--chromium/components/query_tiles/android/tile_provider_bridge.cc24
-rw-r--r--chromium/components/query_tiles/android/tile_provider_bridge.h1
-rw-r--r--chromium/components/query_tiles/internal/BUILD.gn2
-rw-r--r--chromium/components/query_tiles/internal/image_prefetcher.cc2
-rw-r--r--chromium/components/query_tiles/internal/image_prefetcher_unittest.cc2
-rw-r--r--chromium/components/query_tiles/internal/init_aware_tile_service.cc2
-rw-r--r--chromium/components/query_tiles/internal/init_aware_tile_service_unittest.cc2
-rw-r--r--chromium/components/query_tiles/internal/stats.cc7
-rw-r--r--chromium/components/query_tiles/internal/stats.h18
-rw-r--r--chromium/components/query_tiles/internal/stats_unittest.cc9
-rw-r--r--chromium/components/query_tiles/internal/tile_config.cc26
-rw-r--r--chromium/components/query_tiles/internal/tile_config.h12
-rw-r--r--chromium/components/query_tiles/internal/tile_fetcher_unittest.cc2
-rw-r--r--chromium/components/query_tiles/internal/tile_group.cc45
-rw-r--r--chromium/components/query_tiles/internal/tile_group.h6
-rw-r--r--chromium/components/query_tiles/internal/tile_group_unittest.cc32
-rw-r--r--chromium/components/query_tiles/internal/tile_manager.cc66
-rw-r--r--chromium/components/query_tiles/internal/tile_manager_unittest.cc241
-rw-r--r--chromium/components/query_tiles/internal/tile_service_impl.cc2
-rw-r--r--chromium/components/query_tiles/internal/tile_service_impl_unittest.cc4
-rw-r--r--chromium/components/query_tiles/internal/tile_utils.cc40
-rw-r--r--chromium/components/query_tiles/internal/tile_utils.h10
-rw-r--r--chromium/components/query_tiles/internal/tile_utils_unittest.cc48
-rw-r--r--chromium/components/query_tiles/internal/trending_tile_handler.cc69
-rw-r--r--chromium/components/query_tiles/internal/trending_tile_handler.h57
-rw-r--r--chromium/components/query_tiles/switches.cc3
-rw-r--r--chromium/components/query_tiles/switches.h4
-rw-r--r--chromium/components/reading_list/core/reading_list_store_unittest.cc4
-rw-r--r--chromium/components/reading_list/features/reading_list_switches.cc16
-rw-r--r--chromium/components/reading_list/features/reading_list_switches.h11
-rw-r--r--chromium/components/remote_cocoa/app_shim/bridged_content_view.mm44
-rw-r--r--chromium/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm4
-rw-r--r--chromium/components/remote_cocoa/common/select_file_dialog.mojom3
-rw-r--r--chromium/components/renderer_context_menu/render_view_context_menu_base.cc2
-rw-r--r--chromium/components/reputation/OWNERS3
-rw-r--r--chromium/components/reputation/README9
-rw-r--r--chromium/components/reputation/core/BUILD.gn37
-rw-r--r--chromium/components/reputation/core/DEPS11
-rw-r--r--chromium/components/reputation/core/safety_tip_test_utils.cc79
-rw-r--r--chromium/components/reputation/core/safety_tip_test_utils.h44
-rw-r--r--chromium/components/reputation/core/safety_tips.proto68
-rw-r--r--chromium/components/reputation/core/safety_tips_config.cc172
-rw-r--r--chromium/components/reputation/core/safety_tips_config.h47
-rw-r--r--chromium/components/reputation/core/safety_tips_config_unittest.cc33
-rw-r--r--chromium/components/resources/BUILD.gn9
-rw-r--r--chromium/components/resources/android/DEPS3
-rw-r--r--chromium/components/resources/android/page_info_resource_id.h10
-rw-r--r--chromium/components/resources/android/theme_resources.h1
-rw-r--r--chromium/components/resources/android/webxr_resource_id.h30
-rw-r--r--chromium/components/resources/autofill_regex_resources.grdp4
-rw-r--r--chromium/components/resources/components_resources.grd1
-rw-r--r--chromium/components/resources/ssl/ssl_error_assistant/BUILD.gn5
-rw-r--r--chromium/components/safe_browsing/content/base_blocking_page.cc2
-rw-r--r--chromium/components/safe_browsing/content/base_ui_manager.h2
-rw-r--r--chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc10
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details.cc2
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_history.cc7
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_history.h7
-rw-r--r--chromium/components/safe_browsing/content/password_protection/BUILD.gn6
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_navigation_throttle_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_request.cc3
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service.cc15
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service.h7
-rw-r--r--chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc5
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn44
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/DEPS15
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.cc16
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h20
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util_unittest.cc19
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc282
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h164
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc296
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h174
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.cc481
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h147
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.cc279
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h168
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc471
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.cc116
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h50
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor_unittest.cc161
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc188
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h112
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc257
-rw-r--r--chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc2
-rw-r--r--chromium/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc1
-rw-r--r--chromium/components/safe_browsing/content/web_ui/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html2
-rw-r--r--chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js9
-rw-r--r--chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc224
-rw-r--r--chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h19
-rw-r--r--chromium/components/safe_browsing/core/BUILD.gn4
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc26
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h6
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc21
-rw-r--r--chromium/components/safe_browsing/core/common/BUILD.gn21
-rw-r--r--chromium/components/safe_browsing/core/common/DEPS3
-rw-r--r--chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc41
-rw-r--r--chromium/components/safe_browsing/core/common/safe_browsing_prefs.h107
-rw-r--r--chromium/components/safe_browsing/core/common/utils.cc28
-rw-r--r--chromium/components/safe_browsing/core/common/utils.h9
-rw-r--r--chromium/components/safe_browsing/core/common/visual_utils.cc (renamed from chromium/components/safe_browsing/content/password_protection/visual_utils.cc)2
-rw-r--r--chromium/components/safe_browsing/core/common/visual_utils.h (renamed from chromium/components/safe_browsing/content/password_protection/visual_utils.h)6
-rw-r--r--chromium/components/safe_browsing/core/common/visual_utils_unittest.cc (renamed from chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc)2
-rw-r--r--chromium/components/safe_browsing/core/db/database_manager_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/core/db/hit_report.h1
-rw-r--r--chromium/components/safe_browsing/core/db/v4_database_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/core/db/v4_local_database_manager.cc2
-rw-r--r--chromium/components/safe_browsing/core/features.cc12
-rw-r--r--chromium/components/safe_browsing/core/features.h10
-rw-r--r--chromium/components/safe_browsing/core/ping_manager.cc3
-rw-r--r--chromium/components/safe_browsing/core/ping_manager_unittest.cc20
-rw-r--r--chromium/components/safe_browsing/core/proto/csd.proto2
-rw-r--r--chromium/components/safe_browsing/core/proto/webprotect.proto140
-rw-r--r--chromium/components/safe_browsing/core/realtime/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/core/realtime/policy_engine.h1
-rw-r--r--chromium/components/safe_browsing/core/realtime/url_lookup_service_base.cc27
-rw-r--r--chromium/components/safe_browsing/core/realtime/url_lookup_service_unittest.cc11
-rw-r--r--chromium/components/safe_browsing/core/resources/BUILD.gn8
-rw-r--r--chromium/components/safe_browsing/core/verdict_cache_manager.cc43
-rw-r--r--chromium/components/safe_browsing/core/verdict_cache_manager.h8
-rw-r--r--chromium/components/safe_browsing/core/verdict_cache_manager_unittest.cc32
-rw-r--r--chromium/components/safe_browsing/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h6
-rw-r--r--chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm7
-rw-r--r--chromium/components/scheduling_metrics/thread_metrics.cc2
-rw-r--r--chromium/components/scheduling_metrics/thread_metrics.h2
-rw-r--r--chromium/components/scheduling_metrics/thread_metrics_unittest.cc27
-rw-r--r--chromium/components/schema_org/BUILD.gn4
-rw-r--r--chromium/components/schema_org/extractor_fuzzer.cc2
-rw-r--r--chromium/components/schema_org/extractor_unittest.cc2
-rw-r--r--chromium/components/search/BUILD.gn31
-rw-r--r--chromium/components/search/DEPS9
-rw-r--r--chromium/components/search/ntp_features.cc151
-rw-r--r--chromium/components/search/ntp_features.h76
-rw-r--r--chromium/components/search/repeatable_queries/repeatable_queries_service.cc487
-rw-r--r--chromium/components/search/repeatable_queries/repeatable_queries_service.h175
-rw-r--r--chromium/components/search/repeatable_queries/repeatable_queries_service_observer.h23
-rw-r--r--chromium/components/search/repeatable_queries/repeatable_queries_service_unittest.cc662
-rw-r--r--chromium/components/search/search.cc17
-rw-r--r--chromium/components/search/search.h6
-rw-r--r--chromium/components/search/search_provider_observer.cc35
-rw-r--r--chromium/components/search/search_provider_observer.h36
-rw-r--r--chromium/components/search_engines/BUILD.gn1
-rw-r--r--chromium/components/search_engines/default_search_manager.cc2
-rw-r--r--chromium/components/search_engines/search_engine_utils.h4
-rw-r--r--chromium/components/search_engines/search_terms_data.cc2
-rw-r--r--chromium/components/search_engines/search_terms_data.h3
-rw-r--r--chromium/components/search_engines/template_url.cc47
-rw-r--r--chromium/components/search_engines/template_url.h59
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.cc125
-rw-r--r--chromium/components/search_engines/template_url_service.cc318
-rw-r--r--chromium/components/search_engines/template_url_service.h94
-rw-r--r--chromium/components/search_engines/template_url_service_unittest.cc60
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc60
-rw-r--r--chromium/components/search_engines/testing_search_terms_data.cc4
-rw-r--r--chromium/components/search_engines/testing_search_terms_data.h5
-rw-r--r--chromium/components/search_provider_logos/DEPS1
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.cc51
-rw-r--r--chromium/components/search_provider_logos/logo_observer.h7
-rw-r--r--chromium/components/search_provider_logos/logo_service_impl.cc3
-rw-r--r--chromium/components/security_interstitials/content/BUILD.gn18
-rw-r--r--chromium/components/security_interstitials/content/blocked_interception_blocking_page.cc1
-rw-r--r--chromium/components/security_interstitials/content/captive_portal_metrics_recorder.cc2
-rw-r--r--chromium/components/security_interstitials/content/certificate_error_report_unittest.cc1
-rw-r--r--chromium/components/security_interstitials/content/common_name_mismatch_handler.cc7
-rw-r--r--chromium/components/security_interstitials/content/common_name_mismatch_handler.h6
-rw-r--r--chromium/components/security_interstitials/content/insecure_form_navigation_throttle.cc116
-rw-r--r--chromium/components/security_interstitials/content/insecure_form_navigation_throttle.h13
-rw-r--r--chromium/components/security_interstitials/content/legacy_tls_blocking_page.cc1
-rw-r--r--chromium/components/security_interstitials/content/resources/connection_help.html1
-rw-r--r--chromium/components/security_interstitials/content/ssl_blocking_page.cc3
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_handler.cc17
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_handler.h5
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc17
-rw-r--r--chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc17
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/enhanced_protection_message.js20
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_large.html2
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.html1
-rw-r--r--chromium/components/security_interstitials/core/common/resources/interstitial_common.js21
-rw-r--r--chromium/components/security_interstitials/core/features.cc7
-rw-r--r--chromium/components/security_interstitials/core/features.h12
-rw-r--r--chromium/components/security_state/core/features.cc6
-rw-r--r--chromium/components/security_state/core/features.h13
-rw-r--r--chromium/components/security_state/core/security_state.cc9
-rw-r--r--chromium/components/security_state/core/security_state.h4
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc9
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc82
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc32
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.h14
-rw-r--r--chromium/components/services/app_service/app_service_impl.cc14
-rw-r--r--chromium/components/services/app_service/app_service_impl.h5
-rw-r--r--chromium/components/services/app_service/public/cpp/BUILD.gn9
-rw-r--r--chromium/components/services/app_service/public/cpp/app_registry_cache.h4
-rw-r--r--chromium/components/services/app_service/public/cpp/app_update.h2
-rw-r--r--chromium/components/services/app_service/public/cpp/icon_cache_unittest.cc2
-rw-r--r--chromium/components/services/app_service/public/cpp/icon_coalescer.cc2
-rw-r--r--chromium/components/services/app_service/public/cpp/instance_registry.h3
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter_util.cc3
-rw-r--r--chromium/components/services/app_service/public/cpp/publisher_base.cc7
-rw-r--r--chromium/components/services/app_service/public/cpp/publisher_base.h4
-rw-r--r--chromium/components/services/app_service/public/cpp/url_handler_info.cc36
-rw-r--r--chromium/components/services/app_service/public/cpp/url_handler_info.h45
-rw-r--r--chromium/components/services/app_service/public/mojom/app_service.mojom15
-rw-r--r--chromium/components/services/app_service/public/mojom/types.mojom6
-rw-r--r--chromium/components/services/filesystem/directory_test_helper.cc6
-rw-r--r--chromium/components/services/font/public/mojom/font_service.mojom6
-rw-r--r--chromium/components/services/heap_profiling/json_exporter.cc4
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/profiling_client.cc1
-rw-r--r--chromium/components/services/paint_preview_compositor/DEPS1
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc10
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h11
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.cc51
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.h19
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl_unittest.cc46
-rw-r--r--chromium/components/services/patch/public/mojom/file_patcher.mojom9
-rw-r--r--chromium/components/services/print_compositor/print_compositor_impl.cc2
-rw-r--r--chromium/components/services/print_compositor/print_compositor_impl.h2
-rw-r--r--chromium/components/services/print_compositor/public/mojom/print_compositor.mojom6
-rw-r--r--chromium/components/services/quarantine/BUILD.gn37
-rw-r--r--chromium/components/services/quarantine/quarantine_win_unittest.cc1
-rw-r--r--chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/local_storage_impl.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_impl.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_impl_unittest.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_metadata_unittest.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/storage_area_impl.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc3
-rw-r--r--chromium/components/services/storage/dom_storage/storage_area_test_util.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc3
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scope_unittest.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_unittest.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/scopes_lock_manager_unittest.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc2
-rw-r--r--chromium/components/services/storage/public/mojom/service_worker_database.mojom3
-rw-r--r--chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom43
-rw-r--r--chromium/components/services/unzip/public/mojom/unzipper.mojom6
-rw-r--r--chromium/components/session_manager/session_manager_types.h4
-rw-r--r--chromium/components/sessions/BUILD.gn18
-rw-r--r--chromium/components/sessions/content/DEPS3
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_builder.cc6
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc2
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.cc8
-rw-r--r--chromium/components/sessions/core/command_storage_backend_unittest.cc2
-rw-r--r--chromium/components/sessions/core/session_command.h5
-rw-r--r--chromium/components/sessions/core/session_service_commands.cc36
-rw-r--r--chromium/components/sessions/core/snapshotting_session_backend_unittest.cc2
-rw-r--r--chromium/components/sessions/core/tab_restore_service_impl.cc5
-rw-r--r--chromium/components/shared_highlighting/OWNERS1
-rw-r--r--chromium/components/shared_highlighting/core/common/BUILD.gn4
-rw-r--r--chromium/components/shared_highlighting/core/common/DEPS1
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc62
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h66
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc300
-rw-r--r--chromium/components/signin/DEPS1
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc3
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.h3
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc32
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.h3
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_delegate.h12
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_unittest.cc76
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn10
-rw-r--r--chromium/components/signin/core/browser/android/javatests/res/drawable/test_profile_picture.xml27
-rw-r--r--chromium/components/signin/core/browser/chrome_connected_header_helper.cc15
-rw-r--r--chromium/components/signin/core/browser/chrome_connected_header_helper.h2
-rw-r--r--chromium/components/signin/core/browser/cookie_reminter.cc2
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc10
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h3
-rw-r--r--chromium/components/signin/core/browser/resources/signin_index.html1
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.cc4
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.h7
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller_unittest.cc9
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.cc5
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.h1
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc88
-rw-r--r--chromium/components/signin/core/browser/signin_status_metrics_provider.cc11
-rw-r--r--chromium/components/signin/core/browser/signin_status_metrics_provider.h7
-rw-r--r--chromium/components/signin/internal/identity_manager/account_fetcher_service.cc5
-rw-r--r--chromium/components/signin/internal/identity_manager/accounts_mutator_impl.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc4
-rw-r--r--chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/oauth_multilogin_helper.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/oauth_multilogin_helper_unittest.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h2
-rw-r--r--chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher_unittest.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager.cc35
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager.h10
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc40
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc7
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_policy_manager_impl.cc5
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc61
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h16
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc35
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.h11
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.mm120
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service_unittest.mm71
-rw-r--r--chromium/components/signin/ios/browser/features.cc4
-rw-r--r--chromium/components/signin/ios/browser/features.h3
-rw-r--r--chromium/components/signin/ios/browser/manage_accounts_delegate.h4
-rw-r--r--chromium/components/signin/public/base/persistent_repeating_timer.cc4
-rw-r--r--chromium/components/signin/public/base/persistent_repeating_timer_unittest.cc16
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_fetcher.cc7
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_fetcher.h7
-rw-r--r--chromium/components/signin/public/identity_manager/account_info.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/diagnostics_provider_unittest.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager.cc23
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager.h14
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager_unittest.cc18
-rw-r--r--chromium/components/signin/public/identity_manager/identity_test_utils.cc15
-rw-r--r--chromium/components/signin/public/identity_manager/identity_utils.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.cc7
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.h6
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc13
-rw-r--r--chromium/components/site_engagement/OWNERS6
-rw-r--r--chromium/components/site_engagement/README7
-rw-r--r--chromium/components/site_engagement/core/mojom/BUILD.gn11
-rw-r--r--chromium/components/site_engagement/core/mojom/OWNERS2
-rw-r--r--chromium/components/site_engagement/core/mojom/site_engagement_details.mojom22
-rw-r--r--chromium/components/site_isolation/BUILD.gn8
-rw-r--r--chromium/components/site_isolation/site_isolation_policy.cc15
-rw-r--r--chromium/components/site_isolation/site_isolation_policy.h4
-rw-r--r--chromium/components/site_isolation/site_isolation_policy_unittest.cc118
-rw-r--r--chromium/components/speech/BUILD.gn11
-rw-r--r--chromium/components/speech/chunked_byte_buffer.cc127
-rw-r--r--chromium/components/speech/chunked_byte_buffer.h76
-rw-r--r--chromium/components/speech/chunked_byte_buffer_unittest.cc76
-rw-r--r--chromium/components/spellcheck/browser/BUILD.gn29
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_mac.mm2
-rw-r--r--chromium/components/spellcheck/browser/windows_spell_checker.cc2
-rw-r--r--chromium/components/spellcheck/common/spellcheck.mojom4
-rw-r--r--chromium/components/spellcheck/renderer/BUILD.gn11
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_worditerator.cc2
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_utils.cc105
-rw-r--r--chromium/components/storage_monitor/BUILD.gn57
-rw-r--r--chromium/components/storage_monitor/media_storage_util_unittest.cc2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.cc2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux.cc2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_mac_unittest.mm2
-rw-r--r--chromium/components/storage_monitor/volume_mount_watcher_win.cc2
-rw-r--r--chromium/components/strings/BUILD.gn10
-rw-r--r--chromium/components/strings/components_chromium_strings_is.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_eu.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fi.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_is.xtb2
-rw-r--r--chromium/components/strings/components_strings_af.xtb54
-rw-r--r--chromium/components/strings/components_strings_am.xtb56
-rw-r--r--chromium/components/strings/components_strings_ar.xtb54
-rw-r--r--chromium/components/strings/components_strings_as.xtb56
-rw-r--r--chromium/components/strings/components_strings_az.xtb56
-rw-r--r--chromium/components/strings/components_strings_be.xtb58
-rw-r--r--chromium/components/strings/components_strings_bg.xtb54
-rw-r--r--chromium/components/strings/components_strings_bn.xtb64
-rw-r--r--chromium/components/strings/components_strings_bs.xtb54
-rw-r--r--chromium/components/strings/components_strings_ca.xtb68
-rw-r--r--chromium/components/strings/components_strings_cs.xtb54
-rw-r--r--chromium/components/strings/components_strings_da.xtb54
-rw-r--r--chromium/components/strings/components_strings_de.xtb56
-rw-r--r--chromium/components/strings/components_strings_el.xtb54
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb92
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb62
-rw-r--r--chromium/components/strings/components_strings_es.xtb150
-rw-r--r--chromium/components/strings/components_strings_et.xtb54
-rw-r--r--chromium/components/strings/components_strings_eu.xtb74
-rw-r--r--chromium/components/strings/components_strings_fa.xtb58
-rw-r--r--chromium/components/strings/components_strings_fi.xtb54
-rw-r--r--chromium/components/strings/components_strings_fil.xtb54
-rw-r--r--chromium/components/strings/components_strings_fr-CA.xtb54
-rw-r--r--chromium/components/strings/components_strings_fr.xtb64
-rw-r--r--chromium/components/strings/components_strings_gl.xtb60
-rw-r--r--chromium/components/strings/components_strings_gu.xtb64
-rw-r--r--chromium/components/strings/components_strings_hi.xtb64
-rw-r--r--chromium/components/strings/components_strings_hr.xtb54
-rw-r--r--chromium/components/strings/components_strings_hu.xtb58
-rw-r--r--chromium/components/strings/components_strings_hy.xtb60
-rw-r--r--chromium/components/strings/components_strings_id.xtb62
-rw-r--r--chromium/components/strings/components_strings_is.xtb56
-rw-r--r--chromium/components/strings/components_strings_it.xtb66
-rw-r--r--chromium/components/strings/components_strings_iw.xtb60
-rw-r--r--chromium/components/strings/components_strings_ja.xtb58
-rw-r--r--chromium/components/strings/components_strings_ka.xtb54
-rw-r--r--chromium/components/strings/components_strings_kk.xtb54
-rw-r--r--chromium/components/strings/components_strings_km.xtb54
-rw-r--r--chromium/components/strings/components_strings_kn.xtb66
-rw-r--r--chromium/components/strings/components_strings_ko.xtb64
-rw-r--r--chromium/components/strings/components_strings_ky.xtb54
-rw-r--r--chromium/components/strings/components_strings_lo.xtb54
-rw-r--r--chromium/components/strings/components_strings_lt.xtb54
-rw-r--r--chromium/components/strings/components_strings_lv.xtb54
-rw-r--r--chromium/components/strings/components_strings_mk.xtb86
-rw-r--r--chromium/components/strings/components_strings_ml.xtb64
-rw-r--r--chromium/components/strings/components_strings_mn.xtb74
-rw-r--r--chromium/components/strings/components_strings_mr.xtb70
-rw-r--r--chromium/components/strings/components_strings_ms.xtb54
-rw-r--r--chromium/components/strings/components_strings_my.xtb58
-rw-r--r--chromium/components/strings/components_strings_ne.xtb56
-rw-r--r--chromium/components/strings/components_strings_nl.xtb56
-rw-r--r--chromium/components/strings/components_strings_no.xtb54
-rw-r--r--chromium/components/strings/components_strings_or.xtb64
-rw-r--r--chromium/components/strings/components_strings_pa.xtb62
-rw-r--r--chromium/components/strings/components_strings_pl.xtb56
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb68
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb54
-rw-r--r--chromium/components/strings/components_strings_ro.xtb54
-rw-r--r--chromium/components/strings/components_strings_ru.xtb56
-rw-r--r--chromium/components/strings/components_strings_si.xtb54
-rw-r--r--chromium/components/strings/components_strings_sk.xtb62
-rw-r--r--chromium/components/strings/components_strings_sl.xtb54
-rw-r--r--chromium/components/strings/components_strings_sq.xtb56
-rw-r--r--chromium/components/strings/components_strings_sr-Latn.xtb54
-rw-r--r--chromium/components/strings/components_strings_sr.xtb54
-rw-r--r--chromium/components/strings/components_strings_sv.xtb60
-rw-r--r--chromium/components/strings/components_strings_sw.xtb54
-rw-r--r--chromium/components/strings/components_strings_ta.xtb66
-rw-r--r--chromium/components/strings/components_strings_te.xtb72
-rw-r--r--chromium/components/strings/components_strings_th.xtb54
-rw-r--r--chromium/components/strings/components_strings_tr.xtb60
-rw-r--r--chromium/components/strings/components_strings_uk.xtb56
-rw-r--r--chromium/components/strings/components_strings_ur.xtb58
-rw-r--r--chromium/components/strings/components_strings_uz.xtb54
-rw-r--r--chromium/components/strings/components_strings_vi.xtb54
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb64
-rw-r--r--chromium/components/strings/components_strings_zh-HK.xtb54
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb60
-rw-r--r--chromium/components/strings/components_strings_zu.xtb54
-rw-r--r--chromium/components/subresource_filter/android/BUILD.gn42
-rw-r--r--chromium/components/subresource_filter/android/DEPS9
-rw-r--r--chromium/components/subresource_filter/android/ads_blocked_infobar.cc46
-rw-r--r--chromium/components/subresource_filter/android/ads_blocked_infobar.h31
-rw-r--r--chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.cc90
-rw-r--r--chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.h58
-rw-r--r--chromium/components/subresource_filter/content/browser/BUILD.gn20
-rw-r--r--chromium/components/subresource_filter/content/browser/DEPS6
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc52
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc130
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_intervention_manager.h109
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_intervention_manager_unittest.cc102
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc18
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc321
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h121
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc128
-rw-r--r--chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_publisher_impl_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_service.cc25
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_service.h10
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_service_unittest.cc74
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_version.cc4
-rw-r--r--chromium/components/subresource_filter/content/browser/ruleset_version.h12
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_client.h4
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc235
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h159
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc359
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc7
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h7
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.cc34
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.h69
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc8
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc33
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/test_ruleset_publisher.cc59
-rw-r--r--chromium/components/subresource_filter/content/browser/test_ruleset_publisher.h37
-rw-r--r--chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.cc67
-rw-r--r--chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h78
-rw-r--r--chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/verified_ruleset_dealer_unittest.cc2
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_utils.cc2
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_utils.h12
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc72
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h14
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc35
-rw-r--r--chromium/components/subresource_filter_strings.grdp18
-rw-r--r--chromium/components/suggestions/suggestions_service_impl_unittest.cc1
-rw-r--r--chromium/components/sync/BUILD.gn97
-rw-r--r--chromium/components/sync/base/BUILD.gn5
-rw-r--r--chromium/components/sync/driver/BUILD.gn21
-rw-r--r--chromium/components/sync/driver/resources/BUILD.gn11
-rw-r--r--chromium/components/sync/protocol/protocol_sources.gni1
-rw-r--r--chromium/components/sync/trusted_vault/BUILD.gn3
-rw-r--r--chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_local_changes_builder.h2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_merger.cc108
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_merger.h2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_observer_impl.cc2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.cc68
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.h4
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc50
-rw-r--r--chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h2
-rw-r--r--chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc72
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.cc25
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.h10
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc132
-rw-r--r--chromium/components/sync_device_info/device_info_prefs.cc23
-rw-r--r--chromium/components/sync_device_info/device_info_prefs.h2
-rw-r--r--chromium/components/sync_device_info/device_info_prefs_unittest.cc20
-rw-r--r--chromium/components/sync_device_info/device_info_sync_bridge.cc12
-rw-r--r--chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc11
-rw-r--r--chromium/components/sync_device_info/device_info_sync_service.h3
-rw-r--r--chromium/components/sync_device_info/device_info_sync_service_impl.cc2
-rw-r--r--chromium/components/sync_device_info/device_info_sync_service_impl.h2
-rw-r--r--chromium/components/sync_device_info/fake_device_info_sync_service.h2
-rw-r--r--chromium/components/sync_device_info/local_device_info_provider_impl_unittest.cc15
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.cc2
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.h2
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_unittest.cc4
-rw-r--r--chromium/components/sync_sessions/BUILD.gn2
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl.cc23
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc31
-rw-r--r--chromium/components/sync_sessions/mock_sync_sessions_client.h23
-rw-r--r--chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc20
-rw-r--r--chromium/components/sync_sessions/proxy_tabs_data_type_controller.h7
-rw-r--r--chromium/components/sync_sessions/session_store.cc2
-rw-r--r--chromium/components/sync_sessions/session_store_unittest.cc14
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge.cc2
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge_unittest.cc10
-rw-r--r--chromium/components/sync_sessions/session_sync_service_impl.cc2
-rw-r--r--chromium/components/sync_sessions/switches.cc14
-rw-r--r--chromium/components/sync_sessions/switches.h16
-rw-r--r--chromium/components/sync_user_events/DEPS1
-rw-r--r--chromium/components/sync_user_events/fake_user_event_service.cc8
-rw-r--r--chromium/components/sync_user_events/fake_user_event_service.h12
-rw-r--r--chromium/components/sync_user_events/no_op_user_event_service.cc3
-rw-r--r--chromium/components/sync_user_events/no_op_user_event_service.h5
-rw-r--r--chromium/components/sync_user_events/user_event_service.h5
-rw-r--r--chromium/components/sync_user_events/user_event_service_impl.cc5
-rw-r--r--chromium/components/sync_user_events/user_event_service_impl.h4
-rw-r--r--chromium/components/sync_user_events/user_event_service_impl_unittest.cc4
-rw-r--r--chromium/components/sync_user_events/user_event_sync_bridge.cc2
-rw-r--r--chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/system_media_controls/linux/buildflags/buildflags.gni2
-rw-r--r--chromium/components/system_media_controls/linux/system_media_controls_linux.cc6
-rw-r--r--chromium/components/thin_webview/internal/compositor_view_impl.cc17
-rw-r--r--chromium/components/thin_webview/internal/compositor_view_impl.h3
-rw-r--r--chromium/components/thin_webview/internal/java/src/org/chromium/components/thinwebview/internal/CompositorViewImpl.java6
-rw-r--r--chromium/components/thin_webview/java/src/org/chromium/components/thinwebview/ThinWebViewConstraints.java8
-rw-r--r--chromium/components/timers/alarm_timer_chromeos.cc1
-rw-r--r--chromium/components/timers/alarm_timer_unittest.cc2
-rw-r--r--chromium/components/tracing/common/trace_startup_config.cc9
-rw-r--r--chromium/components/translate/core/browser/BUILD.gn3
-rw-r--r--chromium/components/translate/core/common/BUILD.gn15
-rw-r--r--chromium/components/ui_devtools/devtools_server.cc2
-rw-r--r--chromium/components/ui_devtools/tracing_agent.cc12
-rw-r--r--chromium/components/ui_devtools/views/element_utility.cc5
-rw-r--r--chromium/components/ui_devtools/views/view_element.cc7
-rw-r--r--chromium/components/ui_devtools/views/view_element_unittest.cc1
-rw-r--r--chromium/components/ukm/content/source_url_recorder_test.cc8
-rw-r--r--chromium/components/ukm/debug/ukm_internals.html1
-rw-r--r--chromium/components/ukm/observers/history_delete_observer.cc4
-rw-r--r--chromium/components/ukm/observers/history_delete_observer.h7
-rw-r--r--chromium/components/ukm/observers/ukm_consent_state_observer.cc7
-rw-r--r--chromium/components/ukm/observers/ukm_consent_state_observer.h7
-rw-r--r--chromium/components/ukm/ukm_recorder_impl.cc28
-rw-r--r--chromium/components/ukm/ukm_recorder_impl_unittest.cc3
-rw-r--r--chromium/components/ukm/ukm_reporting_service.cc35
-rw-r--r--chromium/components/ukm/ukm_reporting_service.h6
-rw-r--r--chromium/components/ukm/ukm_service.cc31
-rw-r--r--chromium/components/ukm/ukm_service.h9
-rw-r--r--chromium/components/ukm/ukm_service_unittest.cc3
-rw-r--r--chromium/components/unified_consent/unified_consent_service.cc2
-rw-r--r--chromium/components/update_client/component.cc66
-rw-r--r--chromium/components/update_client/component.h4
-rw-r--r--chromium/components/update_client/crx_downloader_unittest.cc2
-rw-r--r--chromium/components/update_client/net/url_loader_post_interceptor.cc2
-rw-r--r--chromium/components/update_client/ping_manager_unittest.cc2
-rw-r--r--chromium/components/update_client/request_sender.cc2
-rw-r--r--chromium/components/update_client/update_checker_unittest.cc4
-rw-r--r--chromium/components/update_client/update_client.h6
-rw-r--r--chromium/components/update_client/update_client_errors.h1
-rw-r--r--chromium/components/update_client/update_client_unittest.cc56
-rw-r--r--chromium/components/update_client/update_engine.cc84
-rw-r--r--chromium/components/update_client/update_engine.h15
-rw-r--r--chromium/components/url_formatter/android/BUILD.gn1
-rw-r--r--chromium/components/url_formatter/android/javatests/src/org/chromium/components/url_formatter/UrlFormatterUnitTest.java31
-rw-r--r--chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc4
-rw-r--r--chromium/components/url_formatter/spoof_checks/skeleton_generator.cc2
-rw-r--r--chromium/components/url_formatter/url_formatter_android.cc16
-rw-r--r--chromium/components/user_actions_ui/resources/user_actions.html1
-rw-r--r--chromium/components/user_manager/fake_user_manager.cc11
-rw-r--r--chromium/components/user_manager/fake_user_manager.h7
-rw-r--r--chromium/components/user_manager/known_user.cc18
-rw-r--r--chromium/components/user_manager/known_user.h8
-rw-r--r--chromium/components/user_manager/user_manager.h7
-rw-r--r--chromium/components/user_manager/user_manager_base.cc46
-rw-r--r--chromium/components/user_manager/user_manager_base.h15
-rw-r--r--chromium/components/variations/BUILD.gn5
-rw-r--r--chromium/components/variations/active_field_trials.h2
-rw-r--r--chromium/components/variations/net/variations_http_headers_unittest.cc2
-rw-r--r--chromium/components/variations/platform_field_trials.h5
-rw-r--r--chromium/components/variations/service/generate_ui_string_overrider.gni5
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.cc18
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.h8
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator_unittest.cc7
-rw-r--r--chromium/components/variations/service/variations_service.cc3
-rw-r--r--chromium/components/variations/service/variations_service_unittest.cc2
-rw-r--r--chromium/components/variations/study_filtering_unittest.cc2
-rw-r--r--chromium/components/variations/variations_associated_data_unittest.cc1
-rw-r--r--chromium/components/variations/variations_features.cc2
-rw-r--r--chromium/components/variations/variations_id_collection.cc2
-rw-r--r--chromium/components/variations/variations_ids_provider.cc38
-rw-r--r--chromium/components/variations/variations_ids_provider.h14
-rw-r--r--chromium/components/variations/variations_ids_provider_unittest.cc261
-rw-r--r--chromium/components/variations/variations_request_scheduler_unittest.cc2
-rw-r--r--chromium/components/variations/variations_seed_processor.cc6
-rw-r--r--chromium/components/variations/variations_seed_processor.h4
-rw-r--r--chromium/components/variations/variations_seed_processor_unittest.cc39
-rw-r--r--chromium/components/variations/variations_seed_store.cc2
-rw-r--r--chromium/components/variations/variations_seed_store_unittest.cc2
-rw-r--r--chromium/components/variations/variations_test_utils.cc52
-rw-r--r--chromium/components/variations/variations_test_utils.h30
-rw-r--r--chromium/components/vector_icons/BUILD.gn2
-rw-r--r--chromium/components/vector_icons/vector_icons.gni44
-rw-r--r--chromium/components/version_ui/resources/about_version.html7
-rw-r--r--chromium/components/version_ui/resources/about_version.js9
-rw-r--r--chromium/components/version_ui/version_ui_constants.cc5
-rw-r--r--chromium/components/version_ui/version_ui_constants.h5
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_writer.cc2
-rw-r--r--chromium/components/viz/BUILD.gn15
-rw-r--r--chromium/components/viz/OWNERS1
-rw-r--r--chromium/components/viz/client/client_resource_provider.cc19
-rw-r--r--chromium/components/viz/client/client_resource_provider.h6
-rw-r--r--chromium/components/viz/client/client_resource_provider_unittest.cc2
-rw-r--r--chromium/components/viz/common/BUILD.gn15
-rw-r--r--chromium/components/viz/common/DEPS1
-rw-r--r--chromium/components/viz/common/delegated_ink_metadata.cc5
-rw-r--r--chromium/components/viz/common/delegated_ink_metadata.h18
-rw-r--r--chromium/components/viz/common/features.cc41
-rw-r--r--chromium/components/viz/common/features.h2
-rw-r--r--chromium/components/viz/common/gl_i420_converter.h2
-rw-r--r--chromium/components/viz/common/gl_scaler.h2
-rw-r--r--chromium/components/viz/common/gpu/context_provider.cc10
-rw-r--r--chromium/components/viz/common/gpu/context_provider.h8
-rw-r--r--chromium/components/viz/common/gpu/vulkan_context_provider.h9
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc69
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h37
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider_unittest.cc75
-rw-r--r--chromium/components/viz/common/java/src/org/chromium/components/viz/common/VizFeatures.java.tmpl16
-rw-r--r--chromium/components/viz/common/quads/DEPS2
-rw-r--r--chromium/components/viz/common/quads/compositor_render_pass_unittest.cc43
-rw-r--r--chromium/components/viz/common/quads/draw_quad.h2
-rw-r--r--chromium/components/viz/common/quads/draw_quad_perftest.cc6
-rw-r--r--chromium/components/viz/common/quads/draw_quad_unittest.cc18
-rw-r--r--chromium/components/viz/common/quads/quad_list.cc13
-rw-r--r--chromium/components/viz/common/quads/quad_list.h3
-rw-r--r--chromium/components/viz/common/quads/render_pass_internal.cc21
-rw-r--r--chromium/components/viz/common/quads/render_pass_internal.h4
-rw-r--r--chromium/components/viz/common/quads/render_pass_io.cc22
-rw-r--r--chromium/components/viz/common/quads/render_pass_io_unittest.cc26
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.cc11
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.h20
-rw-r--r--chromium/components/viz/common/quads/yuv_video_draw_quad.cc4
-rw-r--r--chromium/components/viz/common/quads/yuv_video_draw_quad.h6
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc5
-rw-r--r--chromium/components/viz/common/switches.cc8
-rw-r--r--chromium/components/viz/common/switches.h7
-rw-r--r--chromium/components/viz/common/yuv_readback_unittest.cc3
-rw-r--r--chromium/components/viz/demo/BUILD.gn1
-rw-r--r--chromium/components/viz/demo/client/demo_client.cc4
-rw-r--r--chromium/components/viz/demo/demo_main.cc52
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.h5
-rw-r--r--chromium/components/viz/host/gpu_host_impl.cc5
-rw-r--r--chromium/components/viz/host/gpu_host_impl.h6
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.cc2
-rw-r--r--chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc6
-rw-r--r--chromium/components/viz/service/BUILD.gn24
-rw-r--r--chromium/components/viz/service/DEPS2
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/BUILD.gn4
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc17
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc6
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc17
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h7
-rw-r--r--chromium/components/viz/service/display/DEPS7
-rw-r--r--chromium/components/viz/service/display/aggregated_frame.h9
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.cc8
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h2
-rw-r--r--chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc4
-rw-r--r--chromium/components/viz/service/display/damage_frame_annotator.cc2
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.cc372
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.h44
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.cc91
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.h60
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc160
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_base.h41
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc159
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h62
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc103
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h15
-rw-r--r--chromium/components/viz/service/display/display.cc61
-rw-r--r--chromium/components/viz/service/display/display.h20
-rw-r--r--chromium/components/viz/service/display/display_compositor_memory_and_task_controller.cc114
-rw-r--r--chromium/components/viz/service/display/display_compositor_memory_and_task_controller.h85
-rw-r--r--chromium/components/viz/service/display/display_perftest.cc14
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc46
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h17
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_unittest.cc2
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc1076
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc259
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h10
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.cc54
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.h4
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_unittest.cc34
-rw-r--r--chromium/components/viz/service/display/gl_renderer_draw_cache.h4
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc549
-rw-r--r--chromium/components/viz/service/display/output_surface.h10
-rw-r--r--chromium/components/viz/service/display/overlay_ca_unittest.cc59
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.cc146
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.h45
-rw-r--r--chromium/components/viz/service/display/overlay_candidate_temporal_tracker.cc133
-rw-r--r--chromium/components/viz/service/display/overlay_candidate_temporal_tracker.h99
-rw-r--r--chromium/components/viz/service/display/overlay_dc_unittest.cc321
-rw-r--r--chromium/components/viz/service/display/overlay_processor_android.cc31
-rw-r--r--chromium/components/viz/service/display/overlay_processor_android.h24
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.cc83
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.h14
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.cc14
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.h6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_on_gpu.cc9
-rw-r--r--chromium/components/viz/service/display/overlay_processor_on_gpu.h10
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.cc56
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.h8
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.cc2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.h3
-rw-r--r--chromium/components/viz/service/display/overlay_processor_surface_control.cc23
-rw-r--r--chromium/components/viz/service/display/overlay_processor_surface_control.h5
-rw-r--r--chromium/components/viz/service/display/overlay_processor_surface_control_unittest.cc14
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.cc17
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.h4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.cc16
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.h6
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.cc8
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.h3
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.cc8
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.h3
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.cc11
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.h3
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc18
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.h2
-rw-r--r--chromium/components/viz/service/display/overlay_unittest.cc732
-rw-r--r--chromium/components/viz/service/display/renderer_perftest.cc63
-rw-r--r--chromium/components/viz/service/display/renderer_pixeltest.cc251
-rw-r--r--chromium/components/viz/service/display/skia_output_surface.h18
-rw-r--r--chromium/components/viz/service/display/skia_readback_pixeltest.cc7
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc281
-rw-r--r--chromium/components/viz/service/display/skia_renderer.h12
-rw-r--r--chromium/components/viz/service/display/software_output_device.cc4
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc13
-rw-r--r--chromium/components/viz/service/display/software_renderer_unittest.cc29
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc571
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h84
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_pixeltest.cc70
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc520
-rw-r--r--chromium/components/viz/service/display_embedder/DEPS2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.cc9
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.h3
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.cc16
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.h4
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc135
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h40
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.cc54
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.h3
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider.h21
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc43
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.h8
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_unified.cc9
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_unified.h3
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device.cc71
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device.h37
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc45
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h12
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc88
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc6
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.cc167
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.h19
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc6
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc11
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc135
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h58
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_webview.cc3
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_x11.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h4
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc4
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc318
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.h65
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc369
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h52
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc98
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_x11.cc3
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_x11.h2
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.cc9
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.h3
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface_unittest.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.cc28
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.h9
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc46
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc30
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc10
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc20
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc2
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc22
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h7
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl_unittest.cc5
-rw-r--r--chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc2
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.cc11
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.h2
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_deadline.cc8
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.cc8
-rw-r--r--chromium/components/web_package/mojom/web_bundle_parser.mojom4
-rw-r--r--chromium/components/web_package/web_bundle_parser.cc2
-rw-r--r--chromium/components/web_package/web_bundle_parser_factory.cc2
-rw-r--r--chromium/components/web_package/web_bundle_parser_factory_unittest.cc2
-rw-r--r--chromium/components/web_package/web_bundle_parser_unittest.cc2
-rw-r--r--chromium/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java17
-rw-r--r--chromium/components/webcrypto/OWNERS1
-rw-r--r--chromium/components/webcrypto/jwk.cc14
-rw-r--r--chromium/components/webdata/common/web_database.cc26
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper_unittest.cc2
-rw-r--r--chromium/components/webrtc/media_stream_devices_controller.cc15
-rw-r--r--chromium/components/webxr/OWNERS2
-rw-r--r--chromium/components/webxr/android/BUILD.gn127
-rw-r--r--chromium/components/webxr/android/DEPS9
-rw-r--r--chromium/components/webxr/android/ar_compositor_delegate_provider.cc27
-rw-r--r--chromium/components/webxr/android/ar_compositor_delegate_provider.h32
-rw-r--r--chromium/components/webxr/android/arcore_install_helper.cc166
-rw-r--r--chromium/components/webxr/android/arcore_install_helper.h72
-rw-r--r--chromium/components/webxr/android/arcore_java_utils.cc136
-rw-r--r--chromium/components/webxr/android/arcore_java_utils.h68
-rw-r--r--chromium/components/webxr/android/webxr_utils.cc32
-rw-r--r--chromium/components/webxr/android/webxr_utils.h28
-rw-r--r--chromium/components/webxr/android/xr_install_helper_delegate.h42
-rw-r--r--chromium/components/webxr/android/xr_install_infobar.cc64
-rw-r--r--chromium/components/webxr/android/xr_install_infobar.h57
-rw-r--r--chromium/components/webxr/mailbox_to_surface_bridge_impl.cc31
-rw-r--r--chromium/components/webxr/mailbox_to_surface_bridge_impl.h8
-rw-r--r--chromium/components/webxr_strings.grdp13
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/OWNERS2
-rw-r--r--chromium/components/webxr_strings_grdp/README.md5
-rw-r--r--chromium/components/wifi/BUILD.gn11
-rw-r--r--chromium/components/zoom/zoom_controller.cc38
-rw-r--r--chromium/components/zucchini/fuzzers/BUILD.gn7
-rw-r--r--chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc2
2918 files changed, 92796 insertions, 29454 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index 6582ce9985b..a2b91e9123b 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chrome_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//components/nacl/features.gni")
@@ -66,6 +67,7 @@ test("components_unittests") {
"//components/blocklist/opt_out_blocklist/sql:unit_tests",
"//components/bookmarks/browser:unit_tests",
"//components/bookmarks/managed:unit_tests",
+ "//components/browser_sync:unit_tests",
"//components/browsing_data/core:unit_tests",
"//components/captive_portal/core:unit_tests",
"//components/cbor:unit_tests",
@@ -106,6 +108,7 @@ test("components_unittests") {
"//components/leveldb_proto:unit_tests",
"//components/lookalikes/core:unit_tests",
"//components/metrics:unit_tests",
+ "//components/metrics/demographics:unit_tests",
"//components/navigation_metrics:unit_tests",
"//components/net_log:unit_tests",
"//components/network_session_configurator/browser:unit_tests",
@@ -118,7 +121,6 @@ test("components_unittests") {
"//components/openscreen_platform:unittests",
"//components/os_crypt:unit_tests",
"//components/password_manager/core/browser:unit_tests",
- "//components/password_manager/core/common:unit_tests",
"//components/payments/core:unit_tests",
"//components/policy/core/browser:unit_tests",
"//components/policy/core/common:unit_tests",
@@ -128,6 +130,7 @@ test("components_unittests") {
"//components/query_parser:unit_tests",
"//components/rappor:unit_tests",
"//components/reading_list/core:unit_tests",
+ "//components/reputation/core:unit_tests",
"//components/safe_search_api:unit_tests",
"//components/scheduling_metrics:unit_tests",
"//components/schema_org:unit_tests",
@@ -145,6 +148,7 @@ test("components_unittests") {
"//components/signin/public/base:unit_tests",
"//components/signin/public/identity_manager:unit_tests",
"//components/signin/public/webdata:unit_tests",
+ "//components/speech:unit_tests",
"//components/sqlite_proto:unit_tests",
"//components/ssl_errors:unit_tests",
"//components/subresource_filter/core/browser:unit_tests",
@@ -213,7 +217,9 @@ test("components_unittests") {
"//components/autofill/ios/form_util:unit_tests",
"//components/image_fetcher/ios:unit_tests",
"//components/language/ios/browser:unit_tests",
+ "//components/password_manager/core/common:unit_tests",
"//components/password_manager/ios:unit_tests",
+ "//components/previous_session_info:unit_tests",
"//components/safe_browsing/ios:unit_tests",
"//components/security_state/ios:unit_tests",
"//components/signin/ios/browser:unit_tests",
@@ -257,6 +263,7 @@ test("components_unittests") {
"//components/media_router/common:unit_tests",
"//components/navigation_interception:unit_tests",
"//components/network_hints/renderer:unit_tests",
+ "//components/no_state_prefetch/browser:unit_tests",
"//components/offline_pages:unit_tests",
"//components/optimization_guide:unit_tests",
"//components/page_image_annotation/content/renderer:unit_tests",
@@ -272,8 +279,8 @@ test("components_unittests") {
"//components/payments/content/utility:unit_tests",
"//components/performance_manager:unit_tests",
"//components/permissions:unit_tests",
+ "//components/permissions/prediction_service:unit_tests",
"//components/policy/content:unit_tests",
- "//components/prerender/browser:unit_tests",
"//components/previews/content:unit_tests",
"//components/query_tiles:unit_tests",
"//components/safe_browsing/content/password_protection:password_protection_unittest",
@@ -307,10 +314,13 @@ test("components_unittests") {
"//components/webrtc_logging/common:unit_tests",
]
+ if (!is_win) { # !iOS and !Windows
+ deps += [ "//components/cast:unit_tests" ]
+ }
+
if (!is_fuchsia) { # !iOS and !Fuchsia
deps += [
"//components/crash/content/browser:unit_tests",
- "//components/crash/content/browser/error_reporting:unit_tests",
"//components/crash/core/app:unit_tests",
"//components/data_reduction_proxy/core/browser:unit_tests",
"//components/data_reduction_proxy/core/common:unit_tests",
@@ -463,8 +473,11 @@ test("components_unittests") {
deps += [ "//components/pdf/renderer:unit_tests" ]
}
- # No components should depend on Chrome.
- assert_no_deps = [ "//chrome/*" ]
+ # On LaCrOS, tests use ash-chrome as a window manager, thus the dependency.
+ # On other platforms, no components should depend on Chrome.
+ if (!chromeos_is_browser_only) {
+ assert_no_deps = [ "//chrome/*" ]
+ }
if (is_ios) {
assert_no_deps += ios_assert_no_deps
@@ -704,7 +717,11 @@ if (!is_ios && !is_fuchsia) {
]
}
- assert_no_deps = [ "//chrome/*" ]
+ # On LaCrOS, tests use ash-chrome as a window manager, thus the dependency.
+ # On other platforms, no components should depend on Chrome.
+ if (!chromeos_is_browser_only) {
+ assert_no_deps = [ "//chrome/*" ]
+ }
}
test("components_perftests") {
@@ -780,9 +797,11 @@ if (is_android) {
"//components/browser_ui/util/android:junit",
"//components/browser_ui/webshare/android:junit",
"//components/browser_ui/widget/android:junit",
+ "//components/content_capture/android/junit:components_content_capture_junit_tests",
"//components/embedder_support/android:components_embedder_support_junit_tests",
"//components/gcm_driver/android:components_gcm_driver_junit_tests",
"//components/media_router/browser/android:junit",
+ "//components/messages/android:junit",
"//components/messages/android/internal:junit",
"//components/permissions/android:components_permissions_junit_tests",
"//components/policy/android:components_policy_junit_tests",
diff --git a/chromium/components/OWNERS b/chromium/components/OWNERS
index 88ce455f7e1..35a66c5acd2 100644
--- a/chromium/components/OWNERS
+++ b/chromium/components/OWNERS
@@ -37,12 +37,14 @@ per-file security_interstitials_strings.grdp=file://components/security_intersti
per-file security_state_strings.grdp=file://components/security_state/OWNERS
per-file send_tab_to_self_strings.grdp=file://components/send_tab_to_self/OWNERS
per-file ssl_errors_strings.grdp=file://components/ssl_errors/OWNERS
+per-file subresource_filter_strings.grdp=file://components/subresource_filter/OWNERS
per-file sync_ui_strings.grdp=file://components/sync/OWNERS
per-file tab_groups_strings.grdp=file://components/tab_groups/OWNERS
per-file translate_strings.grdp=file://components/translate/OWNERS
per-file undo_strings.grdp=file://components/undo/OWNERS
per-file version_ui_strings.grdp=file://components/version_ui/OWNERS
per-file web_contents_delegate_android_strings.grdp=file://components/embedder_support/android/delegate/OWNERS
+per-file webxr_strings.grdp=file://components/webxr/OWNERS
# For web_dev_style related changes.
per-file .eslintrc.js=file://ui/webui/PLATFORM_OWNERS
@@ -58,4 +60,4 @@ per-file BUILD.gn=*
# Service sandbox specialization must be reviewed by SECURITY_OWNERS
per-file service_sandbox_type.h=set noparent
-per-file service_sandbox_type.h=file://ipc/SECURITY_OWNERS \ No newline at end of file
+per-file service_sandbox_type.h=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/account_manager_core/BUILD.gn b/chromium/components/account_manager_core/BUILD.gn
new file mode 100644
index 00000000000..ffa07ab6ffc
--- /dev/null
+++ b/chromium/components/account_manager_core/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2020 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("//build/config/ui.gni")
+
+assert(is_chromeos || is_lacros)
+
+component("account_manager_core") {
+ sources = [
+ "account.cc",
+ "account.h",
+ "account_manager_facade.cc",
+ "account_manager_facade.h",
+ "account_manager_util.cc",
+ "account_manager_util.h",
+ ]
+
+ deps = [
+ "//base",
+ "//chromeos/crosapi/mojom",
+ ]
+
+ defines = [ "IS_ACCOUNT_MANAGER_CORE_IMPL" ]
+}
diff --git a/chromium/components/account_manager_core/DEPS b/chromium/components/account_manager_core/DEPS
new file mode 100644
index 00000000000..1b72be6bb9d
--- /dev/null
+++ b/chromium/components/account_manager_core/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+chromeos/crosapi/mojom/account_manager.mojom.h",
+]
diff --git a/chromium/components/account_manager_core/OWNERS b/chromium/components/account_manager_core/OWNERS
new file mode 100644
index 00000000000..86ecfb748bb
--- /dev/null
+++ b/chromium/components/account_manager_core/OWNERS
@@ -0,0 +1 @@
+file://chromeos/components/account_manager/OWNERS
diff --git a/chromium/components/account_manager_core/README.md b/chromium/components/account_manager_core/README.md
new file mode 100644
index 00000000000..75990f883de
--- /dev/null
+++ b/chromium/components/account_manager_core/README.md
@@ -0,0 +1,15 @@
+# //components/account_manager_core
+
+This component holds the core data structures and public facing interfaces for
+Chrome OS Account Manager.
+
+The build targets contained in this component can be depended on by Ash (Chrome
+OS) and Lacros (Chrome browser) both. Ash and Lacros's common dependencies
+must be placed here, to avoid cyclic dependencies between Ash and Lacros.
+
+Currently this component exposes an interface for a facade for Account Manager -
+`AccountManagerFacade` - and data structures for Chrome OS accounts.
+
+Also, see:
+- `//chromeos/components/account_manager/`
+- `//chrome/browser/lacros/account_manager*.*`
diff --git a/chromium/components/account_manager_core/account.cc b/chromium/components/account_manager_core/account.cc
new file mode 100644
index 00000000000..468948c9186
--- /dev/null
+++ b/chromium/components/account_manager_core/account.cc
@@ -0,0 +1,51 @@
+// Copyright 2020 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/account_manager_core/account.h"
+
+namespace account_manager {
+
+bool AccountKey::IsValid() const {
+ return !id.empty();
+}
+
+bool AccountKey::operator<(const AccountKey& other) const {
+ if (id != other.id) {
+ return id < other.id;
+ }
+
+ return account_type < other.account_type;
+}
+
+bool AccountKey::operator==(const AccountKey& other) const {
+ return id == other.id && account_type == other.account_type;
+}
+
+bool AccountKey::operator!=(const AccountKey& other) const {
+ return !(*this == other);
+}
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+std::ostream& operator<<(std::ostream& os, const AccountType& account_type) {
+ switch (account_type) {
+ case account_manager::AccountType::kGaia:
+ os << "Gaia";
+ break;
+ case account_manager::AccountType::kActiveDirectory:
+ os << "ActiveDirectory";
+ break;
+ }
+
+ return os;
+}
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+std::ostream& operator<<(std::ostream& os, const AccountKey& account_key) {
+ os << "{ id: " << account_key.id
+ << ", account_type: " << account_key.account_type << " }";
+
+ return os;
+}
+
+} // namespace account_manager
diff --git a/chromium/components/account_manager_core/account.h b/chromium/components/account_manager_core/account.h
new file mode 100644
index 00000000000..6a0d24849ba
--- /dev/null
+++ b/chromium/components/account_manager_core/account.h
@@ -0,0 +1,58 @@
+// Copyright 2020 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_ACCOUNT_MANAGER_CORE_ACCOUNT_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_H_
+
+#include <ostream>
+#include <string>
+
+#include "base/component_export.h"
+
+namespace account_manager {
+
+// Type of an account, based on the authentication backend of the account.
+// Loosely based on //chromeos/components/account_manager/tokens.proto
+enum class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountType : int {
+ // Gaia account (aka Google account) - including enterprise and consumer
+ // accounts.
+ kGaia = 1,
+ // Microsoft Active Directory accounts.
+ kActiveDirectory = 2,
+};
+
+// Uniquely identifies an account.
+struct COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountKey {
+ // |id| is obfuscated GAIA id for |AccountType::kGaia|.
+ // |id| is object GUID (|AccountId::GetObjGuid|) for
+ // |AccountType::kActiveDirectory|.
+ std::string id;
+ AccountType account_type;
+
+ bool IsValid() const;
+
+ bool operator<(const AccountKey& other) const;
+ bool operator==(const AccountKey& other) const;
+ bool operator!=(const AccountKey& other) const;
+};
+
+// Publicly viewable information about an account.
+struct COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) Account {
+ // A unique identifier for this account.
+ AccountKey key;
+
+ // The raw, un-canonicalized email id for this account.
+ std::string raw_email;
+};
+
+// For logging.
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+std::ostream& operator<<(std::ostream& os, const AccountType& account_type);
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+std::ostream& operator<<(std::ostream& os, const AccountKey& account_key);
+
+} // namespace account_manager
+
+#endif // COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_H_
diff --git a/chromium/components/account_manager_core/account_manager_facade.cc b/chromium/components/account_manager_core/account_manager_facade.cc
new file mode 100644
index 00000000000..eb8eea7eab3
--- /dev/null
+++ b/chromium/components/account_manager_core/account_manager_facade.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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/account_manager_core/account_manager_facade.h"
+
+namespace account_manager {
+
+AccountManagerFacade::AccountManagerFacade() = default;
+AccountManagerFacade::~AccountManagerFacade() = default;
+
+} // namespace account_manager
diff --git a/chromium/components/account_manager_core/account_manager_facade.h b/chromium/components/account_manager_core/account_manager_facade.h
new file mode 100644
index 00000000000..888aa8909c8
--- /dev/null
+++ b/chromium/components/account_manager_core/account_manager_facade.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_FACADE_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_FACADE_H_
+
+#include "base/component_export.h"
+
+namespace account_manager {
+
+// An interface to talk to |AccountManager|.
+// Implementations of this interface hide the in-process / out-of-process nature
+// of this communication.
+// Instances of this class are singletons, and are independent of a |Profile|.
+// Use |GetAccountManagerFacade()| to get an instance of this class.
+class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerFacade {
+ public:
+ AccountManagerFacade();
+ AccountManagerFacade(const AccountManagerFacade&) = delete;
+ AccountManagerFacade& operator=(const AccountManagerFacade&) = delete;
+ virtual ~AccountManagerFacade() = 0;
+
+ // Returns |true| if |AccountManager| is connected and has been fully
+ // initialized.
+ // Note: For out-of-process implementations, it returns |false| if the IPC
+ // pipe to |AccountManager| is disconnected.
+ virtual bool IsInitialized() = 0;
+};
+
+} // namespace account_manager
+
+#endif // COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_FACADE_H_
diff --git a/chromium/components/account_manager_core/account_manager_util.cc b/chromium/components/account_manager_core/account_manager_util.cc
new file mode 100644
index 00000000000..d2183684fb8
--- /dev/null
+++ b/chromium/components/account_manager_core/account_manager_util.cc
@@ -0,0 +1,70 @@
+// Copyright 2020 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/account_manager_core/account_manager_util.h"
+
+#include "components/account_manager_core/account.h"
+
+namespace account_manager {
+
+base::Optional<account_manager::Account> FromMojoAccount(
+ const crosapi::mojom::AccountPtr& mojom_account) {
+ const base::Optional<account_manager::AccountType> account_type =
+ FromMojoAccountType(mojom_account->key->account_type);
+ if (!account_type.has_value())
+ return base::nullopt;
+
+ account_manager::Account account;
+ account.key.id = mojom_account->key->id;
+ account.key.account_type = account_type.value();
+ account.raw_email = mojom_account->raw_email;
+ return account;
+}
+
+crosapi::mojom::AccountPtr ToMojoAccount(
+ const account_manager::Account& account) {
+ crosapi::mojom::AccountPtr mojom_account = crosapi::mojom::Account::New();
+
+ mojom_account->key = crosapi::mojom::AccountKey::New();
+ mojom_account->key->id = account.key.id;
+ mojom_account->key->account_type =
+ ToMojoAccountType(account.key.account_type);
+ mojom_account->raw_email = account.raw_email;
+
+ return mojom_account;
+}
+
+base::Optional<account_manager::AccountType> FromMojoAccountType(
+ const crosapi::mojom::AccountType& account_type) {
+ switch (account_type) {
+ case crosapi::mojom::AccountType::kGaia:
+ static_assert(static_cast<int>(crosapi::mojom::AccountType::kGaia) ==
+ static_cast<int>(account_manager::AccountType::kGaia),
+ "Underlying enum values must match");
+ return account_manager::AccountType::kGaia;
+ case crosapi::mojom::AccountType::kActiveDirectory:
+ static_assert(
+ static_cast<int>(crosapi::mojom::AccountType::kActiveDirectory) ==
+ static_cast<int>(account_manager::AccountType::kActiveDirectory),
+ "Underlying enum values must match");
+ return account_manager::AccountType::kActiveDirectory;
+ default:
+ // Don't consider this as as error to preserve forwards compatibility with
+ // lacros.
+ LOG(WARNING) << "Unknown account type: " << account_type;
+ return base::nullopt;
+ }
+}
+
+crosapi::mojom::AccountType ToMojoAccountType(
+ const account_manager::AccountType& account_type) {
+ switch (account_type) {
+ case account_manager::AccountType::kGaia:
+ return crosapi::mojom::AccountType::kGaia;
+ case account_manager::AccountType::kActiveDirectory:
+ return crosapi::mojom::AccountType::kActiveDirectory;
+ }
+}
+
+} // namespace account_manager
diff --git a/chromium/components/account_manager_core/account_manager_util.h b/chromium/components/account_manager_core/account_manager_util.h
new file mode 100644
index 00000000000..4029974575c
--- /dev/null
+++ b/chromium/components/account_manager_core/account_manager_util.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_UTIL_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_UTIL_H_
+
+#include "base/optional.h"
+#include "chromeos/crosapi/mojom/account_manager.mojom.h"
+#include "components/account_manager_core/account.h"
+
+namespace account_manager {
+
+// Returns `base::nullopt` if `mojom_account` cannot be parsed.
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+base::Optional<account_manager::Account> FromMojoAccount(
+ const crosapi::mojom::AccountPtr& mojom_account);
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+crosapi::mojom::AccountPtr ToMojoAccount(
+ const account_manager::Account& account);
+
+// Returns `base::nullopt` if `account_type` cannot be parsed.
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+base::Optional<account_manager::AccountType> FromMojoAccountType(
+ const crosapi::mojom::AccountType& account_type);
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+crosapi::mojom::AccountType ToMojoAccountType(
+ const account_manager::AccountType& account_type);
+
+} // namespace account_manager
+
+#endif // COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_UTIL_H_
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index 3bf5b92af25..6f135fbbe20 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -27,6 +27,8 @@ static_library("arc") {
"enterprise/arc_data_snapshotd_bridge.h",
"enterprise/arc_data_snapshotd_manager.cc",
"enterprise/arc_data_snapshotd_manager.h",
+ "enterprise/snapshot_hours_policy_service.cc",
+ "enterprise/snapshot_hours_policy_service.h",
"ime/arc_ime_bridge.h",
"ime/arc_ime_bridge_impl.cc",
"ime/arc_ime_bridge_impl.h",
@@ -67,6 +69,8 @@ static_library("arc") {
"net/arc_net_host_impl.h",
"obb_mounter/arc_obb_mounter_bridge.cc",
"obb_mounter/arc_obb_mounter_bridge.h",
+ "pay/arc_digital_goods_bridge.cc",
+ "pay/arc_digital_goods_bridge.h",
"pay/arc_payment_app_bridge.cc",
"pay/arc_payment_app_bridge.h",
"power/arc_power_bridge.cc",
@@ -101,6 +105,8 @@ static_library("arc") {
"//ash/keyboard/ui",
"//ash/public/cpp",
"//base",
+ "//base/util/timer",
+ "//chromeos",
"//chromeos/audio",
"//chromeos/constants",
"//chromeos/dbus",
@@ -384,6 +390,7 @@ source_set("unit_tests") {
"clipboard/arc_clipboard_bridge_unittest.cc",
"enterprise/arc_data_snapshotd_bridge_unittest.cc",
"enterprise/arc_data_snapshotd_manager_unittest.cc",
+ "enterprise/snapshot_hours_policy_service_unittest.cc",
"ime/arc_ime_service_unittest.cc",
"ime/key_event_result_receiver_unittest.cc",
"intent_helper/activity_icon_loader_unittest.cc",
@@ -397,6 +404,7 @@ source_set("unit_tests") {
"pay/arc_payment_app_bridge_unittest.cc",
"power/arc_power_bridge_unittest.cc",
"property/arc_property_bridge_unittest.cc",
+ "session/arc_container_client_adapter_unittest.cc",
"session/arc_data_remover_unittest.cc",
"session/arc_property_util_unittest.cc",
"session/arc_session_impl_unittest.cc",
@@ -414,6 +422,8 @@ source_set("unit_tests") {
"//ash/public/cpp",
"//base",
"//base/test:test_support",
+ "//base/util/timer",
+ "//chromeos",
"//chromeos/constants",
"//chromeos/cryptohome:test_support",
"//chromeos/dbus:test_support",
diff --git a/chromium/components/arc/DEPS b/chromium/components/arc/DEPS
index 3899f4e8900..fb992583b74 100644
--- a/chromium/components/arc/DEPS
+++ b/chromium/components/arc/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"+chromeos/cryptohome",
"+chromeos/dbus",
"+chromeos/memory",
+ "+chromeos/policy",
"+chromeos/system",
"+components/guest_os",
"+components/account_id",
@@ -24,6 +25,7 @@ include_rules = [
"+storage/browser/file_system",
"+third_party/re2",
"+third_party/skia",
+ "+third_party/blink/public/mojom",
"+ui/base",
"+ui/display",
"+ui/events",
diff --git a/chromium/components/arc/DIR_METADATA b/chromium/components/arc/DIR_METADATA
new file mode 100644
index 00000000000..e568bf01ba6
--- /dev/null
+++ b/chromium/components/arc/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform>Apps>ARC"
+}
diff --git a/chromium/components/arc/OWNERS b/chromium/components/arc/OWNERS
index 30b8279b7ec..f054fdeb92b 100644
--- a/chromium/components/arc/OWNERS
+++ b/chromium/components/arc/OWNERS
@@ -2,5 +2,3 @@ hidehiko@chromium.org
jhorwich@chromium.org
yhanada@chromium.org
yusukes@chromium.org
-
-# COMPONENT: Platform>Apps>ARC
diff --git a/chromium/components/arc/arc_features.cc b/chromium/components/arc/arc_features.cc
index 5cb36aa3288..05c89c5dbc7 100644
--- a/chromium/components/arc/arc_features.cc
+++ b/chromium/components/arc/arc_features.cc
@@ -6,11 +6,6 @@
namespace arc {
-// Controls whether ARC++ app runtime performance statistics collection is
-// enabled.
-const base::Feature kAppRuntimePerormanceStatistics{
- "AppRuntimePerormanceStatistics", base::FEATURE_ENABLED_BY_DEFAULT};
-
// Controls ACTION_BOOT_COMPLETED broadcast for third party applications on ARC.
// When disabled, third party apps will not receive this broadcast.
const base::Feature kBootCompletedBroadcastFeature {
@@ -25,11 +20,7 @@ const base::Feature kCleanArcDataOnRegularToChildTransitionFeature{
// Controls experimental Custom Tabs feature for ARC.
const base::Feature kCustomTabsExperimentFeature{
- "ArcCustomTabsExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether ARC applications support zoom in/out.
-const base::Feature kEnableApplicationZoomFeature{
- "ArcEnableApplicationZoomFeature", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ArcCustomTabsExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether ARC handles child->regular account transition.
const base::Feature kEnableChildToRegularTransitionFeature{
diff --git a/chromium/components/arc/arc_features.h b/chromium/components/arc/arc_features.h
index 0c935e26b4f..f4949d27cf9 100644
--- a/chromium/components/arc/arc_features.h
+++ b/chromium/components/arc/arc_features.h
@@ -12,11 +12,9 @@
namespace arc {
// Please keep alphabetized.
-extern const base::Feature kAppRuntimePerormanceStatistics;
extern const base::Feature kBootCompletedBroadcastFeature;
extern const base::Feature kCleanArcDataOnRegularToChildTransitionFeature;
extern const base::Feature kCustomTabsExperimentFeature;
-extern const base::Feature kEnableApplicationZoomFeature;
extern const base::Feature kEnableChildToRegularTransitionFeature;
extern const base::Feature kEnableDocumentsProviderInFilesAppFeature;
extern const base::Feature kEnableRegularToChildTransitionFeature;
diff --git a/chromium/components/arc/arc_prefs.cc b/chromium/components/arc/arc_prefs.cc
index fb66e9fbfd8..3dd63ff9c5d 100644
--- a/chromium/components/arc/arc_prefs.cc
+++ b/chromium/components/arc/arc_prefs.cc
@@ -103,9 +103,6 @@ const char kArcSkippedReportingNotice[] = "arc.skipped.reporting.notice";
// the user directory (i.e., the user finished required migration.)
const char kArcCompatibleFilesystemChosen[] =
"arc.compatible_filesystem.chosen";
-// Integer pref indicating the ecryptfs to ext4 migration strategy. One of
-// options: forbidden = 0, migrate = 1, wipe = 2 or minimal migrate = 4.
-const char kEcryptfsMigrationStrategy[] = "ecryptfs_migration_strategy";
// Preferences for storing engagement time data, as per
// GuestOsEngagementMetrics.
const char kEngagementPrefsPrefix[] = "arc.metrics";
@@ -129,12 +126,16 @@ const char kStabilityMetrics[] = "arc.metrics.stability";
// Android properties. Used only in ARCVM.
const char kArcSerialNumberSalt[] = "arc.serialno_salt";
+// A preference to keep time intervals when snapshotting is allowed.
+const char kArcSnapshotHours[] = "arc.snapshot_hours";
+
// A preferece to keep ARC snapshot related info in dictionary.
const char kArcSnapshotInfo[] = "arc.snapshot";
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
// Sorted in lexicographical order.
registry->RegisterStringPref(kArcSerialNumberSalt, std::string());
+ registry->RegisterDictionaryPref(kArcSnapshotHours);
registry->RegisterDictionaryPref(kArcSnapshotInfo);
registry->RegisterBooleanPref(kNativeBridge64BitSupportExperimentEnabled,
false);
@@ -156,9 +157,6 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kArcBackupRestoreEnabled, false);
registry->RegisterBooleanPref(kArcLocationServiceEnabled, false);
- // This is used to decide whether migration from ecryptfs to ext4 is allowed.
- registry->RegisterIntegerPref(prefs::kEcryptfsMigrationStrategy, 0);
-
registry->RegisterIntegerPref(
kArcSupervisionTransition,
static_cast<int>(ArcSupervisionTransition::NO_TRANSITION));
diff --git a/chromium/components/arc/arc_prefs.h b/chromium/components/arc/arc_prefs.h
index b3f5cc66489..9d496f08756 100644
--- a/chromium/components/arc/arc_prefs.h
+++ b/chromium/components/arc/arc_prefs.h
@@ -45,6 +45,7 @@ ARC_EXPORT extern const char kEngagementPrefsPrefix[];
// Local state prefs in lexicographical order.
ARC_EXPORT extern const char kArcSerialNumberSalt[];
+ARC_EXPORT extern const char kArcSnapshotHours[];
ARC_EXPORT extern const char kArcSnapshotInfo[];
ARC_EXPORT extern const char kNativeBridge64BitSupportExperimentEnabled[];
ARC_EXPORT extern const char kStabilityMetrics[];
diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
index 860b4203f2d..b5d4d3f5e17 100644
--- a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -16,9 +16,9 @@
#include "components/arc/session/arc_bridge_service.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/clipboard/clipboard_data_endpoint.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
namespace arc {
namespace {
@@ -49,7 +49,7 @@ mojom::ClipRepresentationPtr CreateHTML(const ui::Clipboard* clipboard) {
// Unused. URL is sent from CreatePlainText() by reading it from the Bookmark.
std::string url;
uint32_t fragment_start, fragment_end;
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kArc);
clipboard->ReadHTML(ui::ClipboardBuffer::kCopyPaste, &data_dst, &markup16,
&url, &fragment_start, &fragment_end);
@@ -71,7 +71,7 @@ mojom::ClipRepresentationPtr CreatePlainText(const ui::Clipboard* clipboard) {
base::string16 title;
std::string text;
std::string mime_type(ui::kMimeTypeText);
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kArc);
// Both Bookmark and AsciiText are represented by text/plain. If both are
// present, only use Bookmark.
@@ -87,7 +87,7 @@ mojom::ClipDataPtr GetClipData(const ui::Clipboard* clipboard) {
DCHECK(clipboard);
std::vector<base::string16> mime_types;
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kArc);
clipboard->ReadAvailableTypes(ui::ClipboardBuffer::kCopyPaste, &data_dst,
&mime_types);
@@ -178,7 +178,7 @@ void ArcClipboardBridge::SetClipContent(mojom::ClipDataPtr clip_data) {
base::AutoReset<bool> auto_reset(&event_originated_at_instance_, true);
ui::ScopedClipboardWriter writer(
ui::ClipboardBuffer::kCopyPaste,
- std::make_unique<ui::ClipboardDataEndpoint>(ui::EndpointType::kArc));
+ std::make_unique<ui::DataTransferEndpoint>(ui::EndpointType::kArc));
for (const auto& repr : clip_data->representations) {
const std::string& mime_type(repr->mime_type);
diff --git a/chromium/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc b/chromium/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
index 2924aa043df..002889f83bd 100644
--- a/chromium/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
+++ b/chromium/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
@@ -6,9 +6,9 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "chromeos/dbus/arc/arc_data_snapshotd_client.h"
#include "chromeos/dbus/arc/fake_arc_data_snapshotd_client.h"
diff --git a/chromium/components/arc/enterprise/arc_data_snapshotd_manager.cc b/chromium/components/arc/enterprise/arc_data_snapshotd_manager.cc
index c20c173d1d5..394cb5b8507 100644
--- a/chromium/components/arc/enterprise/arc_data_snapshotd_manager.cc
+++ b/chromium/components/arc/enterprise/arc_data_snapshotd_manager.cc
@@ -7,16 +7,19 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/dbus/upstart/upstart_client.h"
#include "components/arc/arc_prefs.h"
#include "components/arc/enterprise/arc_data_snapshotd_bridge.h"
#include "components/prefs/pref_service.h"
+#include "components/session_manager/core/session_manager.h"
+#include "components/user_manager/user_manager.h"
#include "ui/ozone/public/ozone_switches.h"
namespace arc {
@@ -34,7 +37,7 @@ constexpr char kUpdated[] = "updated";
constexpr char kPrevious[] = "previous";
constexpr char kLast[] = "last";
constexpr char kBlockedUiReboot[] = "blocked_ui_reboot";
-constexpr char kStartedDate[] = "started_date";
+constexpr char kStarted[] = "started";
bool IsSnapshotEnabled() {
// TODO(pbond): implement policy processing.
@@ -59,6 +62,9 @@ void EnableHeadlessMode() {
bool ArcDataSnapshotdManager::is_snapshot_enabled_for_testing_ = false;
+// This class is owned by ChromeBrowserMainPartsChromeos.
+static ArcDataSnapshotdManager* g_arc_data_snapshotd_manager = nullptr;
+
ArcDataSnapshotdManager::SnapshotInfo::SnapshotInfo(const base::Value* value,
bool last)
: is_last_(last) {
@@ -153,11 +159,11 @@ std::unique_ptr<ArcDataSnapshotdManager::Snapshot>
ArcDataSnapshotdManager::Snapshot::CreateForTesting(
PrefService* local_state,
bool blocked_ui_mode,
- const std::string& started_date,
+ bool started,
std::unique_ptr<SnapshotInfo> last,
std::unique_ptr<SnapshotInfo> previous) {
return base::WrapUnique(new ArcDataSnapshotdManager::Snapshot(
- local_state, blocked_ui_mode, started_date, std::move(last),
+ local_state, blocked_ui_mode, started, std::move(last),
std::move(previous)));
}
@@ -182,9 +188,9 @@ void ArcDataSnapshotdManager::Snapshot::Parse() {
blocked_ui_mode_ = found.value();
}
{
- auto* found = dict->FindStringPath(kStartedDate);
- if (found)
- started_date_ = *found;
+ auto found = dict->FindBoolPath(kStarted);
+ if (found.has_value())
+ started_ = found.value();
}
}
@@ -195,7 +201,7 @@ void ArcDataSnapshotdManager::Snapshot::Sync() {
if (last_)
last_->Sync(&dict);
dict.SetBoolKey(kBlockedUiReboot, blocked_ui_mode_);
- dict.SetStringKey(kStartedDate, started_date_);
+ dict.SetBoolKey(kStarted, started_);
local_state_->Set(arc::prefs::kArcSnapshotInfo, std::move(dict));
}
@@ -205,23 +211,42 @@ void ArcDataSnapshotdManager::Snapshot::ClearSnapshot(bool last) {
Sync();
}
+void ArcDataSnapshotdManager::Snapshot::StartNewSnapshot() {
+ previous_ = std::move(last_);
+ last_ = nullptr;
+
+ started_ = true;
+ Sync();
+}
+
ArcDataSnapshotdManager::Snapshot::Snapshot(
PrefService* local_state,
bool blocked_ui_mode,
- const std::string& started_date,
+ bool started,
std::unique_ptr<SnapshotInfo> last,
std::unique_ptr<SnapshotInfo> previous)
: local_state_(local_state),
blocked_ui_mode_(blocked_ui_mode),
- started_date_(started_date),
+ started_(started),
last_(std::move(last)),
previous_(std::move(previous)) {
DCHECK(local_state_);
}
-ArcDataSnapshotdManager::ArcDataSnapshotdManager(PrefService* local_state)
- : snapshot_{local_state} {
+// static
+ArcDataSnapshotdManager* ArcDataSnapshotdManager::Get() {
+ return g_arc_data_snapshotd_manager;
+}
+
+ArcDataSnapshotdManager::ArcDataSnapshotdManager(
+ PrefService* local_state,
+ base::OnceClosure attempt_user_exit_callback)
+ : snapshot_{local_state},
+ attempt_user_exit_callback_(std::move(attempt_user_exit_callback)) {
+ DCHECK(!g_arc_data_snapshotd_manager);
DCHECK(local_state);
+ g_arc_data_snapshotd_manager = this;
+
snapshot_.Parse();
if (IsRestoredSession()) {
@@ -237,6 +262,11 @@ ArcDataSnapshotdManager::ArcDataSnapshotdManager(PrefService* local_state)
}
ArcDataSnapshotdManager::~ArcDataSnapshotdManager() {
+ DCHECK(g_arc_data_snapshotd_manager);
+ g_arc_data_snapshotd_manager = nullptr;
+
+ session_manager::SessionManager::Get()->RemoveObserver(this);
+
snapshot_.Sync();
EnsureDaemonStopped(base::DoNothing());
}
@@ -261,6 +291,37 @@ void ArcDataSnapshotdManager::EnsureDaemonStopped(base::OnceClosure callback) {
StopDaemon(std::move(callback));
}
+bool ArcDataSnapshotdManager::IsAutoLoginConfigured() {
+ switch (state_) {
+ case ArcDataSnapshotdManager::State::kBlockedUi:
+ case ArcDataSnapshotdManager::State::kMgsToLaunch:
+ case ArcDataSnapshotdManager::State::kMgsLaunched:
+ return true;
+ case ArcDataSnapshotdManager::State::kNone:
+ case ArcDataSnapshotdManager::State::kRestored:
+ return false;
+ }
+}
+
+bool ArcDataSnapshotdManager::IsAutoLoginAllowed() {
+ switch (state_) {
+ case ArcDataSnapshotdManager::State::kBlockedUi:
+ return false;
+ case ArcDataSnapshotdManager::State::kNone:
+ case ArcDataSnapshotdManager::State::kRestored:
+ case ArcDataSnapshotdManager::State::kMgsLaunched:
+ case ArcDataSnapshotdManager::State::kMgsToLaunch:
+ return true;
+ }
+}
+
+void ArcDataSnapshotdManager::OnSessionStateChanged() {
+ if (state_ != State::kMgsToLaunch)
+ return;
+ if (user_manager::UserManager::Get()->IsLoggedInAsPublicAccount())
+ state_ = State::kMgsLaunched;
+}
+
void ArcDataSnapshotdManager::StopDaemon(base::OnceClosure callback) {
VLOG(1) << "Stopping arc-data-snapshotd";
daemon_weak_ptr_factory_.InvalidateWeakPtrs();
@@ -331,10 +392,22 @@ void ArcDataSnapshotdManager::OnSnapshotsCleared(bool success) {
void ArcDataSnapshotdManager::OnKeyPairGenerated(bool success) {
if (success) {
+ VLOG(1) << "Managed Guest Session is ready to be started with blocked UI.";
state_ = State::kMgsToLaunch;
+ session_manager::SessionManager::Get()->AddObserver(this);
+ // Move last to previous snapshot:
+ snapshot_.StartNewSnapshot();
+
+ if (!reset_autologin_callback_.is_null())
+ std::move(reset_autologin_callback_).Run();
} else {
- // TODO(pbond): restart browser to normal.
LOG(ERROR) << "Key pair generation failed. Abort snapshot creation.";
+
+ snapshot_.set_blocked_ui_mode(false);
+ snapshot_.Sync();
+
+ DCHECK(!attempt_user_exit_callback_.is_null());
+ EnsureDaemonStopped(std::move(attempt_user_exit_callback_));
}
}
diff --git a/chromium/components/arc/enterprise/arc_data_snapshotd_manager.h b/chromium/components/arc/enterprise/arc_data_snapshotd_manager.h
index 4dec65866e7..aba4e15ad5c 100644
--- a/chromium/components/arc/enterprise/arc_data_snapshotd_manager.h
+++ b/chromium/components/arc/enterprise/arc_data_snapshotd_manager.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
+#include "components/session_manager/core/session_manager_observer.h"
class PrefService;
@@ -26,7 +27,8 @@ class ArcDataSnapshotdBridge;
// This class manages ARC data/ directory snapshots and controls the lifetime of
// the arc-data-snapshotd daemon.
-class ArcDataSnapshotdManager final {
+class ArcDataSnapshotdManager final
+ : public session_manager::SessionManagerObserver {
public:
// State of the flow.
enum class State {
@@ -109,7 +111,7 @@ class ArcDataSnapshotdManager final {
static std::unique_ptr<Snapshot> CreateForTesting(
PrefService* local_state,
bool blocked_ui_mode,
- const std::string& started_date,
+ bool started,
std::unique_ptr<SnapshotInfo> last,
std::unique_ptr<SnapshotInfo> previous);
@@ -121,14 +123,22 @@ class ArcDataSnapshotdManager final {
// if |last| is true or previous otherwise.
void ClearSnapshot(bool last);
+ // Moves last snapshot to previous and updates a |start_date| to the current
+ // date.
+ void StartNewSnapshot();
+
+ void set_blocked_ui_mode(bool blocked_ui_mode) {
+ blocked_ui_mode_ = blocked_ui_mode;
+ }
bool is_blocked_ui_mode() const { return blocked_ui_mode_; }
+ bool started() const { return started_; }
SnapshotInfo* last() { return last_.get(); }
SnapshotInfo* previous() { return previous_.get(); }
private:
Snapshot(PrefService* local_state,
bool blocked_ui_mode,
- const std::string& started_date,
+ bool started,
std::unique_ptr<SnapshotInfo> last,
std::unique_ptr<SnapshotInfo> previous);
@@ -138,32 +148,49 @@ class ArcDataSnapshotdManager final {
// Values should be kept in sync with values stored in arc.snapshot
// preference.
bool blocked_ui_mode_ = false;
- std::string started_date_;
+ bool started_;
std::unique_ptr<SnapshotInfo> last_;
std::unique_ptr<SnapshotInfo> previous_;
};
- explicit ArcDataSnapshotdManager(PrefService* local_state);
+ ArcDataSnapshotdManager(PrefService* local_state,
+ base::OnceClosure attempt_user_exit_callback);
ArcDataSnapshotdManager(const ArcDataSnapshotdManager&) = delete;
ArcDataSnapshotdManager& operator=(const ArcDataSnapshotdManager&) = delete;
- ~ArcDataSnapshotdManager();
+ ~ArcDataSnapshotdManager() override;
+
+ static ArcDataSnapshotdManager* Get();
// Starts arc-data-snapshotd.
void EnsureDaemonStarted(base::OnceClosure callback);
// Stops arc-data-snapshotd.
void EnsureDaemonStopped(base::OnceClosure callback);
+ // Returns true if autologin to public account should be performed.
+ bool IsAutoLoginConfigured();
+ // Returns true if autologin is allowed to be performed and manager is not
+ // waiting for the response from arc-data-snapshotd daemon.
+ bool IsAutoLoginAllowed();
+
+ // session_manager::SessionManagerObserver:
+ void OnSessionStateChanged() override;
+
// Get |bridge_| for testing.
ArcDataSnapshotdBridge* bridge() { return bridge_.get(); }
State state() const { return state_; }
+ void set_reset_autologin_callback(base::OnceClosure callback) {
+ reset_autologin_callback_ = std::move(callback);
+ }
+
static void set_snapshot_enabled_for_testing(bool enabled) {
is_snapshot_enabled_for_testing_ = enabled;
}
static bool is_snapshot_enabled_for_testing() {
return is_snapshot_enabled_for_testing_;
}
+ void set_state_for_testing(State state) { state_ = state; }
private:
// Attempts to arc-data-snapshotd daemon regardless of state of the class.
@@ -201,6 +228,11 @@ class ArcDataSnapshotdManager final {
std::unique_ptr<ArcDataSnapshotdBridge> bridge_;
+ base::OnceClosure attempt_user_exit_callback_;
+
+ // Callback to reset an autologin timer once userless MGS is ready to start.
+ base::OnceClosure reset_autologin_callback_;
+
// Used for cancelling previously posted tasks to daemon.
base::WeakPtrFactory<ArcDataSnapshotdManager> daemon_weak_ptr_factory_{this};
// WeakPtrFactory to use for callbacks.
diff --git a/chromium/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc b/chromium/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc
index d6451614857..e088913380f 100644
--- a/chromium/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc
+++ b/chromium/components/arc/enterprise/arc_data_snapshotd_manager_unittest.cc
@@ -6,9 +6,10 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/dbus/arc/fake_arc_data_snapshotd_client.h"
@@ -17,6 +18,7 @@
#include "components/arc/arc_prefs.h"
#include "components/arc/enterprise/arc_data_snapshotd_bridge.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/session_manager/core/session_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/public/ozone_switches.h"
@@ -54,12 +56,14 @@ class ArcDataSnapshotdManagerBasicTest : public testing::Test {
chromeos::DBusThreadManager::Initialize();
EXPECT_TRUE(chromeos::DBusThreadManager::Get()->IsUsingFakes());
- arc::prefs::RegisterLocalStatePrefs(local_state_.registry());
-
upstart_client_ = std::make_unique<TestUpstartClient>();
}
- void SetUp() override { SetDBusClientAvailability(true /* is_available */); }
+ void SetUp() override {
+ SetDBusClientAvailability(true /* is_available */);
+
+ arc::prefs::RegisterLocalStatePrefs(local_state_.registry());
+ }
~ArcDataSnapshotdManagerBasicTest() override {
chromeos::DBusThreadManager::Shutdown();
@@ -99,10 +103,11 @@ class ArcDataSnapshotdManagerBasicTest : public testing::Test {
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ TestingPrefServiceSimple local_state_;
private:
- TestingPrefServiceSimple local_state_;
std::unique_ptr<TestUpstartClient> upstart_client_;
+ session_manager::SessionManager session_manager_;
};
// Tests flows in ArcDataSnapshotdManager:
@@ -114,6 +119,7 @@ class ArcDataSnapshotdManagerFlowTest
public:
void SetUp() override {
SetDBusClientAvailability(is_dbus_client_available());
+ arc::prefs::RegisterLocalStatePrefs(local_state_.registry());
}
bool is_dbus_client_available() { return GetParam(); }
@@ -125,7 +131,9 @@ class ArcDataSnapshotdManagerFlowTest
}
// Check number of snapshots in local_state.
- void CheckSnapshotsNumber(int expected_number) {
+ void CheckSnapshots(int expected_snapshots_number,
+ bool expected_blocked_ui = true,
+ bool expected_snapshot_started = false) {
ArcDataSnapshotdManager::Snapshot snapshot(local_state());
snapshot.Parse();
int actual_number = 0;
@@ -135,12 +143,14 @@ class ArcDataSnapshotdManagerFlowTest
if (snapshot.last()) {
actual_number++;
}
- EXPECT_EQ(expected_number, actual_number);
+ EXPECT_EQ(expected_snapshots_number, actual_number);
+ EXPECT_EQ(expected_blocked_ui, snapshot.is_blocked_ui_mode());
+ EXPECT_EQ(expected_snapshot_started, snapshot.started());
}
// Set up local_state with info for previous and last snapshots and blocked ui
// mode.
- void SetupLocalState() {
+ void SetupLocalState(bool blocked_ui_mode) {
auto last = ArcDataSnapshotdManager::SnapshotInfo::CreateForTesting(
"" /* os_version */, "" /* creation_date */, false /* verified */,
false /* updated */, true /* last */);
@@ -148,8 +158,8 @@ class ArcDataSnapshotdManagerFlowTest
"" /* os_version */, "" /* creation_date */, false /* verified */,
false /* updated */, false /* last */);
auto snapshot = ArcDataSnapshotdManager::Snapshot::CreateForTesting(
- local_state(), true /* blocked_ui_mode */, "" /* started_date */,
- std::move(last), std::move(previous));
+ local_state(), blocked_ui_mode, false /* started */, std::move(last),
+ std::move(previous));
snapshot->Sync();
}
@@ -170,7 +180,9 @@ class ArcDataSnapshotdManagerFlowTest
// Test basic scenario: start / stop arc-data-snapshotd.
TEST_F(ArcDataSnapshotdManagerBasicTest, Basic) {
- ArcDataSnapshotdManager manager(local_state());
+ // Daemon stopped in ctor, since no need to be running.
+ ExpectStopDaemon(false /* success */);
+ ArcDataSnapshotdManager manager(local_state(), base::DoNothing());
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kNone);
EXPECT_FALSE(manager.bridge());
@@ -186,7 +198,9 @@ TEST_F(ArcDataSnapshotdManagerBasicTest, Basic) {
// Test a double start scenario: start arc-data-snapshotd twice.
// Upstart job returns "false" if the job is already running.
TEST_F(ArcDataSnapshotdManagerBasicTest, DoubleStart) {
- ArcDataSnapshotdManager manager(local_state());
+ // Daemon stopped in ctor, since no need to be running.
+ ExpectStopDaemon(false /* success */);
+ ArcDataSnapshotdManager manager(local_state(), base::DoNothing());
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kNone);
EXPECT_FALSE(manager.bridge());
@@ -208,7 +222,11 @@ TEST_F(ArcDataSnapshotdManagerBasicTest, DoubleStart) {
// Test that arc-data-snapshotd daemon is already stopped when |manager| tries
// to stop it.
TEST_F(ArcDataSnapshotdManagerBasicTest, UpstartFailures) {
- ArcDataSnapshotdManager manager(local_state());
+ // Daemon stopped in ctor, since no need to be running.
+ ExpectStopDaemon(false /* success */);
+
+ ArcDataSnapshotdManager manager(local_state(), base::DoNothing());
+
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kNone);
EXPECT_FALSE(manager.bridge());
@@ -221,12 +239,21 @@ TEST_F(ArcDataSnapshotdManagerBasicTest, UpstartFailures) {
EXPECT_FALSE(manager.bridge());
}
-TEST_F(ArcDataSnapshotdManagerBasicTest, RestoredAfterCrash) {
+#if defined(MEMORY_SANITIZER)
+// https://crbug.com/1144452
+#define MAYBE_RestoredAfterCrash DISABLED_RestoredAfterCrash
+#else
+#define MAYBE_RestoredAfterCrash RestoredAfterCrash
+#endif
+TEST_F(ArcDataSnapshotdManagerBasicTest, MAYBE_RestoredAfterCrash) {
SetUpRestoredSessionCommandLine();
// The attempt to stop the daemon, started before crash.
ExpectStopDaemon(true /*success */);
- ArcDataSnapshotdManager manager(local_state());
+ ArcDataSnapshotdManager manager(local_state(), base::DoNothing());
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kRestored);
+ EXPECT_FALSE(manager.IsAutoLoginConfigured());
+ EXPECT_TRUE(manager.IsAutoLoginAllowed());
+
EXPECT_FALSE(manager.bridge());
ExpectStartDaemon(true /*success */);
@@ -239,8 +266,9 @@ TEST_F(ArcDataSnapshotdManagerBasicTest, RestoredAfterCrash) {
// Test clear snapshots flow.
TEST_P(ArcDataSnapshotdManagerFlowTest, ClearSnapshotsBasic) {
// Set up two snapshots (previous and last) in local_state.
- SetupLocalState();
- CheckSnapshotsNumber(2 /* expected_number */);
+ SetupLocalState(false /* blocked_ui_mode */);
+ CheckSnapshots(2 /* expected_snapshots_number */,
+ false /* expected_blocked_ui_mode */);
// Once |manager| is created, it tries to clear both snapshots, because the
// mechanism is disabled by default, and stop the daemon.
@@ -248,12 +276,15 @@ TEST_P(ArcDataSnapshotdManagerFlowTest, ClearSnapshotsBasic) {
ExpectStartDaemon(true /*success */);
// Stop once finished clearing.
ExpectStopDaemon(true /*success */);
- ArcDataSnapshotdManager manager(local_state());
+ ArcDataSnapshotdManager manager(local_state(), base::DoNothing());
RunUntilIdle();
// No snapshots in local_state either.
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kNone);
- CheckSnapshotsNumber(0 /* expected_number */);
+ EXPECT_FALSE(manager.IsAutoLoginConfigured());
+ EXPECT_TRUE(manager.IsAutoLoginAllowed());
+ CheckSnapshots(0 /* expected_snapshots_number */,
+ false /* expected_blocked_ui_mode */);
EXPECT_FALSE(manager.bridge());
}
@@ -261,8 +292,8 @@ TEST_P(ArcDataSnapshotdManagerFlowTest, ClearSnapshotsBasic) {
// Test blocked UI mode flow.
TEST_P(ArcDataSnapshotdManagerFlowTest, BlockedUiBasic) {
// Set up two snapshots (previous and last) in local_state.
- SetupLocalState();
- CheckSnapshotsNumber(2 /* expected_number */);
+ SetupLocalState(true /* blocked_ui_mode */);
+ CheckSnapshots(2 /* expected_snapshots_number */);
// Enable snapshotting mechanism for testing.
ArcDataSnapshotdManager::set_snapshot_enabled_for_testing(true /* enabled */);
@@ -272,21 +303,38 @@ TEST_P(ArcDataSnapshotdManagerFlowTest, BlockedUiBasic) {
ExpectStartDaemon(true /*success */);
// Stop once finished clearing.
ExpectStopDaemon(true /*success */);
- ArcDataSnapshotdManager manager(local_state());
+ bool is_attempt_user_exit_called = false;
+ ArcDataSnapshotdManager manager(
+ local_state(),
+ base::BindLambdaForTesting([&is_attempt_user_exit_called]() {
+ is_attempt_user_exit_called = true;
+ }));
CheckHeadlessMode();
EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kBlockedUi);
- RunUntilIdle();
-
- // Snapshots are valid, no need to clear.
- CheckSnapshotsNumber(2 /* expected_number */);
+ EXPECT_TRUE(manager.IsAutoLoginConfigured());
+ EXPECT_FALSE(manager.IsAutoLoginAllowed());
- auto expected_state = is_dbus_client_available()
- ? ArcDataSnapshotdManager::State::kMgsToLaunch
- : ArcDataSnapshotdManager::State::kBlockedUi;
+ RunUntilIdle();
- // The communication is established and MGS can be launched.
- EXPECT_EQ(manager.state(), expected_state);
- EXPECT_TRUE(manager.bridge());
+ if (is_dbus_client_available()) {
+ EXPECT_FALSE(is_attempt_user_exit_called);
+ EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kMgsToLaunch);
+ EXPECT_TRUE(manager.IsAutoLoginConfigured());
+ EXPECT_TRUE(manager.IsAutoLoginAllowed());
+
+ EXPECT_TRUE(manager.bridge());
+ // Starts a last snapshot creation. last became previous.
+ CheckSnapshots(1 /* expected_snapshots_number */,
+ true /*expected_blocked_ui */,
+ true /* expected_snapshot_started */);
+ } else {
+ EXPECT_TRUE(is_attempt_user_exit_called);
+ EXPECT_EQ(manager.state(), ArcDataSnapshotdManager::State::kBlockedUi);
+ EXPECT_FALSE(manager.bridge());
+ // Snapshots are valid. No need to clear.
+ CheckSnapshots(2 /* expected_snapshots_number */,
+ false /* expected_blocked_ui */);
+ }
}
INSTANTIATE_TEST_SUITE_P(ArcDataSnapshotdManagerFlowTest,
diff --git a/chromium/components/arc/enterprise/snapshot_hours_policy_service.cc b/chromium/components/arc/enterprise/snapshot_hours_policy_service.cc
new file mode 100644
index 00000000000..12def9f3692
--- /dev/null
+++ b/chromium/components/arc/enterprise/snapshot_hours_policy_service.cc
@@ -0,0 +1,186 @@
+// Copyright 2020 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/arc/enterprise/snapshot_hours_policy_service.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/time/default_clock.h"
+#include "base/time/tick_clock.h"
+#include "base/values.h"
+#include "chromeos/policy/weekly_time/time_utils.h"
+#include "components/arc/arc_prefs.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_manager/user_manager.h"
+
+namespace arc {
+namespace data_snapshotd {
+
+SnapshotHoursPolicyService::SnapshotHoursPolicyService(PrefService* local_state)
+ : local_state_(local_state) {
+ DCHECK(local_state_);
+ pref_change_registrar_.Init(local_state_);
+ pref_change_registrar_.Add(
+ prefs::kArcSnapshotHours,
+ base::BindRepeating(&SnapshotHoursPolicyService::UpdatePolicy,
+ weak_ptr_factory_.GetWeakPtr()));
+ UpdatePolicy();
+}
+
+SnapshotHoursPolicyService::~SnapshotHoursPolicyService() = default;
+
+void SnapshotHoursPolicyService::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void SnapshotHoursPolicyService::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void SnapshotHoursPolicyService::StartObservingPrimaryProfilePrefs(
+ PrefService* profile_prefs) {
+ if (!user_manager::UserManager::Get() ||
+ !user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
+ // Do not care about ArcEnabled policy for other than MGS.
+ return;
+ }
+ profile_prefs_ = profile_prefs;
+ profile_pref_change_registrar_.Init(profile_prefs_);
+ profile_pref_change_registrar_.Add(
+ prefs::kArcEnabled,
+ base::BindRepeating(&SnapshotHoursPolicyService::UpdatePolicy,
+ weak_ptr_factory_.GetWeakPtr()));
+ UpdatePolicy();
+}
+
+void SnapshotHoursPolicyService::StopObservingPrimaryProfilePrefs() {
+ if (!profile_prefs_)
+ return;
+ profile_pref_change_registrar_.RemoveAll();
+ profile_prefs_ = nullptr;
+ UpdatePolicy();
+}
+
+void SnapshotHoursPolicyService::UpdatePolicy() {
+ intervals_.clear();
+ base::ScopedClosureRunner snapshot_disabler(
+ base::BindOnce(&SnapshotHoursPolicyService::DisableSnapshots,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (!IsArcEnabled())
+ return;
+
+ const auto* dict = local_state_->GetDictionary(prefs::kArcSnapshotHours);
+ if (!dict)
+ return;
+
+ const auto* timezone = dict->FindStringKey("timezone");
+ if (!timezone)
+ return;
+
+ int offset;
+ if (!policy::weekly_time_utils::GetOffsetFromTimezoneToGmt(
+ *timezone, base::DefaultClock::GetInstance(), &offset)) {
+ return;
+ }
+
+ const auto* intervals = dict->FindListKey("intervals");
+ if (!intervals)
+ return;
+
+ for (const auto& entry : intervals->GetList()) {
+ if (!entry.is_dict())
+ continue;
+ auto interval =
+ policy::WeeklyTimeInterval::ExtractFromValue(&entry, -offset);
+ if (interval)
+ intervals_.push_back(*interval);
+ }
+ intervals_ = policy::weekly_time_utils::ConvertIntervalsToGmt(intervals_);
+ if (intervals_.empty())
+ return;
+
+ ignore_result(snapshot_disabler.Release());
+ EnableSnapshots();
+}
+
+void SnapshotHoursPolicyService::DisableSnapshots() {
+ if (!is_snapshot_enabled_)
+ return;
+
+ is_snapshot_enabled_ = false;
+ StopTimer();
+ SetEndTime(base::Time());
+ NotifySnapshotsDisabled();
+}
+
+void SnapshotHoursPolicyService::EnableSnapshots() {
+ if (is_snapshot_enabled_)
+ return;
+ is_snapshot_enabled_ = true;
+
+ UpdateTimer();
+ NotifySnapshotsEnabled();
+}
+
+void SnapshotHoursPolicyService::UpdateTimer() {
+ auto current_time = policy::WeeklyTime::GetCurrentGmtWeeklyTime(
+ base::DefaultClock::GetInstance());
+ for (const auto& interval : intervals_) {
+ if (interval.Contains(current_time)) {
+ auto remaining_timer_duration =
+ current_time.GetDurationTo(interval.end());
+ SetEndTime(base::Time::Now() + remaining_timer_duration);
+ StartTimer(remaining_timer_duration);
+ return;
+ }
+ }
+ StartTimer(policy::weekly_time_utils::GetDeltaTillNextTimeInterval(
+ current_time, intervals_));
+ SetEndTime(base::Time());
+}
+
+void SnapshotHoursPolicyService::StartTimer(base::TimeDelta delay) {
+ DCHECK_GT(delay, base::TimeDelta());
+ timer_.Start(FROM_HERE, base::DefaultClock::GetInstance()->Now() + delay,
+ base::BindOnce(&SnapshotHoursPolicyService::UpdateTimer,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SnapshotHoursPolicyService::StopTimer() {
+ timer_.Stop();
+}
+
+void SnapshotHoursPolicyService::SetEndTime(base::Time end_time) {
+ if (snapshot_update_end_time_ == end_time)
+ return;
+ snapshot_update_end_time_ = end_time;
+ NotifySnapshotUpdateEndTimeChanged();
+}
+
+void SnapshotHoursPolicyService::NotifySnapshotsDisabled() {
+ for (auto& observer : observers_)
+ observer.OnSnapshotsDisabled();
+}
+
+void SnapshotHoursPolicyService::NotifySnapshotsEnabled() {
+ for (auto& observer : observers_)
+ observer.OnSnapshotsEnabled();
+}
+
+void SnapshotHoursPolicyService::NotifySnapshotUpdateEndTimeChanged() {
+ for (auto& observer : observers_)
+ observer.OnSnapshotUpdateEndTimeChanged();
+}
+
+bool SnapshotHoursPolicyService::IsArcEnabled() const {
+ // Assume ARC is enabled if there is no profile prefs.
+ return !profile_prefs_ || profile_prefs_->GetBoolean(prefs::kArcEnabled);
+}
+
+} // namespace data_snapshotd
+} // namespace arc
diff --git a/chromium/components/arc/enterprise/snapshot_hours_policy_service.h b/chromium/components/arc/enterprise/snapshot_hours_policy_service.h
new file mode 100644
index 00000000000..640aa4e633c
--- /dev/null
+++ b/chromium/components/arc/enterprise/snapshot_hours_policy_service.h
@@ -0,0 +1,135 @@
+// Copyright 2020 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_ARC_ENTERPRISE_SNAPSHOT_HOURS_POLICY_SERVICE_H_
+#define COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_HOURS_POLICY_SERVICE_H_
+
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/time/time.h"
+#include "base/util/timer/wall_clock_timer.h"
+#include "chromeos/policy/weekly_time/weekly_time_interval.h"
+#include "components/prefs/pref_change_registrar.h"
+
+class PrefService;
+
+namespace arc {
+namespace data_snapshotd {
+
+// This class handles "DeviceArcDataSnapshotHours" policy, enables/disables ARC
+// data snapshot feature, handles ARC data snapshot update intervals.
+//
+// ArcDataSnapshotdManager is an owner of this object.
+class SnapshotHoursPolicyService {
+ public:
+ // Observer interface.
+ class Observer : public base::CheckedObserver {
+ public:
+ // Called once ARC data snapshot feature gets disabled by policy.
+ virtual void OnSnapshotsDisabled() {}
+ // Called once ARC data snapshot feature gets enabled by policy.
+ virtual void OnSnapshotsEnabled() {}
+ // Called once the interval for allowed ARC data snapshot update has
+ // started/finished.
+ // The observer can get an end time for started interval via
+ // snapshot_update_end_time().
+ virtual void OnSnapshotUpdateEndTimeChanged() {}
+ };
+
+ explicit SnapshotHoursPolicyService(PrefService* local_state);
+ SnapshotHoursPolicyService(const SnapshotHoursPolicyService&) = delete;
+ SnapshotHoursPolicyService& operator=(const SnapshotHoursPolicyService&) =
+ delete;
+ ~SnapshotHoursPolicyService();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Starts observing primary profile prefs only for MGS.
+ void StartObservingPrimaryProfilePrefs(PrefService* profile_prefs);
+ // Stops observing primary profile prefs.
+ void StopObservingPrimaryProfilePrefs();
+
+ // Returns the end time of the current interval when ARC data snapshot update
+ // is possible.
+ // Returns null outside of the interval.
+ base::Time snapshot_update_end_time() const {
+ return snapshot_update_end_time_;
+ }
+
+ bool is_snapshot_enabled() const { return is_snapshot_enabled_; }
+
+ const std::vector<policy::WeeklyTimeInterval>& get_intervals_for_testing()
+ const {
+ return intervals_;
+ }
+ const util::WallClockTimer* get_timer_for_testing() const { return &timer_; }
+
+ private:
+ // Processes the policy update: either ArcEnabled and
+ // DeviceArcDataSnapshotHours.
+ void UpdatePolicy();
+
+ // Disables ARC data snapshot feature and notifies observers if necessary.
+ void DisableSnapshots();
+ // Enables ARC data snaoshot feature and notifies observers if necessary.
+ void EnableSnapshots();
+
+ // Updates ARC data snapshot update timer according to the policy.
+ void UpdateTimer();
+
+ // Starts timer with |delay|.
+ void StartTimer(base::TimeDelta delay);
+ // Stops timer.
+ void StopTimer();
+ // Changes |snapshot_update_end_time_| and notifies observers if necessary.
+ void SetEndTime(base::Time end_time);
+
+ // Notifies observers about relevant events.
+ void NotifySnapshotsDisabled();
+ void NotifySnapshotsEnabled();
+ void NotifySnapshotUpdateEndTimeChanged();
+
+ // Returns false if ARC is disabled for a logged-in MGS, otherwise returns
+ // true.
+ bool IsArcEnabled() const;
+
+ // The feature is disabled when either kArcDataSnapshotHours policy is not set
+ // or ARC is disabled by policy for MGS.
+ bool is_snapshot_enabled_ = false;
+
+ // Not owned.
+ PrefService* const local_state_ = nullptr;
+
+ // Owned by primary profile.
+ PrefService* profile_prefs_ = nullptr;
+
+ // Registrar for pref changes in local_state_.
+ PrefChangeRegistrar pref_change_registrar_;
+ // Registrar for pref changes in profile_prefs_.
+ PrefChangeRegistrar profile_pref_change_registrar_;
+
+ // The end time of the current interval if ARC data snapshot update is
+ // possible. The value is null outside of all intervals.
+ base::Time snapshot_update_end_time_;
+
+ base::ObserverList<Observer> observers_;
+
+ // Current "ArcDataSnapshotHours" time intervals.
+ std::vector<policy::WeeklyTimeInterval> intervals_;
+
+ // Timer for updating ARC data snapshot at the begin of next interval or at
+ // the end of current interval.
+ util::WallClockTimer timer_;
+
+ base::WeakPtrFactory<SnapshotHoursPolicyService> weak_ptr_factory_{this};
+};
+
+} // namespace data_snapshotd
+} // namespace arc
+
+#endif // COMPONENTS_ARC_ENTERPRISE_SNAPSHOT_HOURS_POLICY_SERVICE_H_
diff --git a/chromium/components/arc/enterprise/snapshot_hours_policy_service_unittest.cc b/chromium/components/arc/enterprise/snapshot_hours_policy_service_unittest.cc
new file mode 100644
index 00000000000..5bb8cacac4a
--- /dev/null
+++ b/chromium/components/arc/enterprise/snapshot_hours_policy_service_unittest.cc
@@ -0,0 +1,350 @@
+// Copyright 2020 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/arc/enterprise/snapshot_hours_policy_service.h"
+
+#include <memory>
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/json/json_reader.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "base/values.h"
+#include "chromeos/policy/weekly_time/weekly_time_interval.h"
+#include "components/arc/arc_prefs.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/user_manager/fake_user_manager.h"
+#include "components/user_manager/scoped_user_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+namespace data_snapshotd {
+
+namespace {
+
+constexpr char kPublicAccountEmail[] = "public-session-account@localhost";
+
+// DeviceArcDataSnapshotHours policy with one correct interval.
+constexpr char kJsonPolicy[] =
+ "{"
+ "\"intervals\": ["
+ "{"
+ "\"start\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 1284000"
+ "},"
+ "\"end\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 21720000"
+ "}"
+ "}"
+ "],"
+ "\"timezone\": \"GMT\""
+ "}";
+
+// DeviceArcDataSnapshotHours incorrect policy with missing timezone.
+constexpr char kJsonPolicyNoTimezone[] =
+ "{"
+ "\"intervals\": ["
+ "{"
+ "\"start\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 1284000"
+ "},"
+ "\"end\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 21720000"
+ "}"
+ "}"
+ "]"
+ "}";
+
+// DeviceArcDataSnapshotHours incorrect policy with incorrect intervals.
+constexpr char kJsonPolicyIncorrectIntervals[] =
+ "{"
+ "\"intervals\": ["
+ "{"
+ "\"start\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 1284000"
+ "},"
+ "\"end\": {"
+ "\"day_of_week\": 0,"
+ "\"time\": 21720000"
+ "}"
+ "}"
+ "],"
+ "\"timezone\": \"GMT\""
+ "}";
+
+// DeviceArcDataSnapshotHours incorrect policy with missing intervals.
+constexpr char kJsonPolicyNoIntervals[] =
+ "{"
+ "\"timezone\": \"GMT\""
+ "}";
+
+// DeviceArcDataSnapshotHours incorrect policy with empty intervals.
+constexpr char kJsonPolicyEmptyIntervals[] =
+ "{"
+ "\"intervals\": ["
+ "],"
+ "\"timezone\": \"GMT\""
+ "}";
+
+// DeviceArcDataSnapshotHours incorrect policy with empty timezone.
+constexpr char kJsonPolicyWrongOffset[] =
+ "{"
+ "\"intervals\": ["
+ "{"
+ "\"start\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 1284000"
+ "},"
+ "\"end\": {"
+ "\"day_of_week\": 1,"
+ "\"time\": 21720000"
+ "}"
+ "}"
+ "],"
+ "\"timezone\": \"\""
+ "}";
+
+class FakeObserver : public SnapshotHoursPolicyService::Observer {
+ public:
+ FakeObserver() = default;
+ FakeObserver(const FakeObserver&) = delete;
+ FakeObserver& operator=(const FakeObserver&) = delete;
+ ~FakeObserver() override = default;
+
+ void OnSnapshotsDisabled() override { disabled_calls_num_++; }
+
+ void OnSnapshotsEnabled() override { enabled_calls_num_++; }
+
+ void OnSnapshotUpdateEndTimeChanged() override { changed_calls_num_++; }
+
+ int disabled_calls_num() const { return disabled_calls_num_; }
+ int enabled_calls_num() const { return enabled_calls_num_; }
+ int changed_calls_num() const { return changed_calls_num_; }
+
+ private:
+ int disabled_calls_num_ = 0;
+ int enabled_calls_num_ = 0;
+ int changed_calls_num_ = 0;
+};
+
+} // namespace
+
+// Tests SnapshotHoursPolicyService class instance.
+class SnapshotHoursPolicyServiceTest
+ : public testing::TestWithParam<std::string> {
+ protected:
+ SnapshotHoursPolicyServiceTest() = default;
+
+ void SetUp() override {
+ arc::prefs::RegisterLocalStatePrefs(local_state_.registry());
+ policy_service_ =
+ std::make_unique<SnapshotHoursPolicyService>(local_state());
+ observer_ = std::make_unique<FakeObserver>();
+ policy_service()->AddObserver(observer_.get());
+
+ fake_user_manager_ = new user_manager::FakeUserManager();
+ scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
+ base::WrapUnique(fake_user_manager_));
+ }
+
+ void TearDown() override {
+ policy_service()->RemoveObserver(observer_.get());
+ policy_service_.reset();
+ local_state_.ClearPref(prefs::kArcSnapshotHours);
+ }
+
+ const std::string& policy() const { return GetParam(); }
+
+ // Ensure the feature disabled.
+ void EnsureSnapshotDisabled(int disabled_calls_num = 0) {
+ EXPECT_FALSE(policy_service()->is_snapshot_enabled());
+ EXPECT_FALSE(policy_service()->get_timer_for_testing()->IsRunning());
+ EXPECT_TRUE(policy_service()->snapshot_update_end_time().is_null());
+ EXPECT_EQ(observer_->disabled_calls_num(), disabled_calls_num);
+ }
+
+ // Ensure the feature enabled.
+ void EnsureSnapshotEnabled(int enabled_calls_num = 1) {
+ EXPECT_TRUE(policy_service()->is_snapshot_enabled());
+ EXPECT_TRUE(policy_service()->get_timer_for_testing()->IsRunning());
+
+ EXPECT_EQ(policy_service()->get_intervals_for_testing().size(), 1u);
+ EXPECT_EQ(observer_->enabled_calls_num(), enabled_calls_num);
+ }
+
+ // Enable feature and check.
+ void EnableSnapshot(int enabled_calls_num = 1) {
+ base::Optional<base::Value> policy = base::JSONReader::Read(kJsonPolicy);
+ EXPECT_TRUE(policy.has_value());
+ local_state()->Set(arc::prefs::kArcSnapshotHours, policy.value());
+ EnsureSnapshotEnabled(enabled_calls_num);
+ }
+
+ // Fire the next timer.
+ void FastForwardToTimer() {
+ if (policy_service()->snapshot_update_end_time().is_null()) {
+ task_environment_.FastForwardBy(
+ policy_service()->get_timer_for_testing()->desired_run_time() -
+ base::Time::Now());
+ task_environment_.RunUntilIdle();
+ }
+ EXPECT_FALSE(policy_service()->snapshot_update_end_time().is_null());
+ }
+
+ void LoginAsPublicSession() {
+ auto account_id = AccountId::FromUserEmail(kPublicAccountEmail);
+ user_manager()->AddPublicAccountUser(account_id);
+ user_manager()->UserLoggedIn(account_id, account_id.GetUserEmail(), false,
+ false);
+ }
+
+ SnapshotHoursPolicyService* policy_service() { return policy_service_.get(); }
+ TestingPrefServiceSimple* local_state() { return &local_state_; }
+ FakeObserver* observer() { return observer_.get(); }
+ user_manager::FakeUserManager* user_manager() { return fake_user_manager_; }
+
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+ private:
+ std::unique_ptr<FakeObserver> observer_;
+ std::unique_ptr<SnapshotHoursPolicyService> policy_service_;
+ TestingPrefServiceSimple local_state_;
+ user_manager::FakeUserManager* fake_user_manager_;
+ std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
+};
+
+// Test that the feature is disabled by default.
+TEST_F(SnapshotHoursPolicyServiceTest, Disabled) {
+ EnsureSnapshotDisabled();
+}
+
+TEST_F(SnapshotHoursPolicyServiceTest, OneIntervalEnabled) {
+ EnableSnapshot();
+}
+
+TEST_F(SnapshotHoursPolicyServiceTest, DoubleDisable) {
+ EnableSnapshot();
+
+ {
+ base::Optional<base::Value> policy_value =
+ base::JSONReader::Read(kJsonPolicyEmptyIntervals);
+ EXPECT_TRUE(policy_value.has_value());
+ local_state()->Set(arc::prefs::kArcSnapshotHours, policy_value.value());
+
+ EnsureSnapshotDisabled(1 /* disabled_calls_num */);
+ }
+
+ {
+ // User a different JSON to ensure the policy value is updated.
+ base::Optional<base::Value> policy_value =
+ base::JSONReader::Read(kJsonPolicyNoIntervals);
+ EXPECT_TRUE(policy_value.has_value());
+ local_state()->Set(arc::prefs::kArcSnapshotHours, policy_value.value());
+
+ // Do not notify the second time.
+ EnsureSnapshotDisabled(1 /* disabled_calls_num */);
+ }
+}
+
+TEST_F(SnapshotHoursPolicyServiceTest, DoubleEnable) {
+ EnableSnapshot();
+ // Do not notify the second time.
+ EnableSnapshot();
+}
+
+// Test that once the feature enabled, the time is outside interval.
+TEST_F(SnapshotHoursPolicyServiceTest, OutsideInterval) {
+ EnableSnapshot();
+ EXPECT_TRUE(policy_service()->snapshot_update_end_time().is_null());
+ EXPECT_EQ(observer()->changed_calls_num(), 0);
+
+ FastForwardToTimer();
+ EXPECT_EQ(observer()->changed_calls_num(), 1);
+ EXPECT_FALSE(policy_service()->snapshot_update_end_time().is_null());
+}
+
+// Test that once the feature enabled, the time is outside interval.
+TEST_F(SnapshotHoursPolicyServiceTest, InsideInterval) {
+ EnableSnapshot();
+ EXPECT_TRUE(policy_service()->snapshot_update_end_time().is_null());
+ EXPECT_EQ(observer()->changed_calls_num(), 0);
+
+ FastForwardToTimer();
+ EXPECT_EQ(observer()->changed_calls_num(), 1);
+ EXPECT_FALSE(policy_service()->snapshot_update_end_time().is_null());
+
+ // Disable snapshots.
+ {
+ base::Optional<base::Value> policy_value =
+ base::JSONReader::Read(kJsonPolicyNoIntervals);
+ EXPECT_TRUE(policy_value.has_value());
+ local_state()->Set(arc::prefs::kArcSnapshotHours, policy_value.value());
+
+ EnsureSnapshotDisabled(1 /* disabled_calls_num */);
+ EXPECT_EQ(observer()->changed_calls_num(), 2);
+ }
+
+ EnableSnapshot(2 /* enabled_calls_num */);
+ EXPECT_EQ(observer()->changed_calls_num(), 3);
+ EXPECT_FALSE(policy_service()->snapshot_update_end_time().is_null());
+}
+
+// Test that if ARC is disabled by user policy (not for public session
+// account), it does not disable the feature.
+TEST_F(SnapshotHoursPolicyServiceTest, DisableByUserPolicyForUser) {
+ EnableSnapshot();
+
+ TestingPrefServiceSimple profile_prefs;
+ arc::prefs::RegisterProfilePrefs(profile_prefs.registry());
+ profile_prefs.SetBoolean(arc::prefs::kArcEnabled, false);
+ policy_service()->StartObservingPrimaryProfilePrefs(&profile_prefs);
+ EnsureSnapshotEnabled();
+ policy_service()->StopObservingPrimaryProfilePrefs();
+}
+
+// Test that if ARC is disabled for public session account, it disables
+// the feature.
+TEST_F(SnapshotHoursPolicyServiceTest, DisableByUserPolicyForMGS) {
+ LoginAsPublicSession();
+ EnableSnapshot();
+
+ TestingPrefServiceSimple profile_prefs;
+ arc::prefs::RegisterProfilePrefs(profile_prefs.registry());
+ profile_prefs.SetBoolean(arc::prefs::kArcEnabled, false);
+ policy_service()->StartObservingPrimaryProfilePrefs(&profile_prefs);
+ EnsureSnapshotDisabled(1 /* disabled_calls_num */);
+ policy_service()->StopObservingPrimaryProfilePrefs();
+ EnsureSnapshotEnabled(2 /* enabled_calls_num */);
+}
+
+TEST_P(SnapshotHoursPolicyServiceTest, DisabledByPolicy) {
+ EnableSnapshot();
+
+ base::Optional<base::Value> policy_value = base::JSONReader::Read(policy());
+ EXPECT_TRUE(policy_value.has_value());
+ local_state()->Set(arc::prefs::kArcSnapshotHours, policy_value.value());
+
+ EnsureSnapshotDisabled(1 /* disabled_calls_num */);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ /* no prefix */,
+ SnapshotHoursPolicyServiceTest,
+ testing::Values(kJsonPolicyNoTimezone,
+ kJsonPolicyIncorrectIntervals,
+ kJsonPolicyNoIntervals,
+ kJsonPolicyEmptyIntervals,
+ kJsonPolicyWrongOffset));
+
+} // namespace data_snapshotd
+} // namespace arc
diff --git a/chromium/components/arc/ime/DIR_METADATA b/chromium/components/arc/ime/DIR_METADATA
new file mode 100644
index 00000000000..e40e277485a
--- /dev/null
+++ b/chromium/components/arc/ime/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "UI>Input>Text>IME"
+}
diff --git a/chromium/components/arc/ime/OWNERS b/chromium/components/arc/ime/OWNERS
index 537633ab3ae..b7c37fd8a6a 100644
--- a/chromium/components/arc/ime/OWNERS
+++ b/chromium/components/arc/ime/OWNERS
@@ -1,5 +1,3 @@
kinaba@chromium.org
tetsui@chromium.org
yhanada@chromium.org
-
-# COMPONENT: UI>Input>Text>IME
diff --git a/chromium/components/arc/ime/arc_ime_service_unittest.cc b/chromium/components/arc/ime/arc_ime_service_unittest.cc
index c790b79ae69..5f8fbe636a8 100644
--- a/chromium/components/arc/ime/arc_ime_service_unittest.cc
+++ b/chromium/components/arc/ime/arc_ime_service_unittest.cc
@@ -12,7 +12,6 @@
#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/arc/mojom/ime.mojom.h"
#include "components/arc/session/arc_bridge_service.h"
diff --git a/chromium/components/arc/ime/key_event_result_receiver_unittest.cc b/chromium/components/arc/ime/key_event_result_receiver_unittest.cc
index b449fee9a42..0329866e697 100644
--- a/chromium/components/arc/ime/key_event_result_receiver_unittest.cc
+++ b/chromium/components/arc/ime/key_event_result_receiver_unittest.cc
@@ -4,7 +4,7 @@
#include "components/arc/ime/key_event_result_receiver.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
diff --git a/chromium/components/arc/intent_helper/DIR_METADATA b/chromium/components/arc/intent_helper/DIR_METADATA
new file mode 100644
index 00000000000..cf53beece28
--- /dev/null
+++ b/chromium/components/arc/intent_helper/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform>Apps>Foundation"
+}
diff --git a/chromium/components/arc/intent_helper/OWNERS b/chromium/components/arc/intent_helper/OWNERS
index d2e1c3575fe..aaa0a699d1b 100644
--- a/chromium/components/arc/intent_helper/OWNERS
+++ b/chromium/components/arc/intent_helper/OWNERS
@@ -3,4 +3,3 @@ djacobo@chromium.org
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *_mojom_traits*.*=file://components/arc/mojom/ARC_SECURITY_OWNERS
-# COMPONENT: Platform>Apps>Foundation
diff --git a/chromium/components/arc/media_session/DIR_METADATA b/chromium/components/arc/media_session/DIR_METADATA
new file mode 100644
index 00000000000..49ac631b461
--- /dev/null
+++ b/chromium/components/arc/media_session/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Media>Session"
+}
diff --git a/chromium/components/arc/media_session/OWNERS b/chromium/components/arc/media_session/OWNERS
index 162fbc21554..593ec6f5c87 100644
--- a/chromium/components/arc/media_session/OWNERS
+++ b/chromium/components/arc/media_session/OWNERS
@@ -1,3 +1 @@
file://services/media_session/OWNERS
-
-# COMPONENT: Internals>Media>Session
diff --git a/chromium/components/arc/metrics/arc_metrics_service.cc b/chromium/components/arc/metrics/arc_metrics_service.cc
index a3a2454e65b..034c70f3924 100644
--- a/chromium/components/arc/metrics/arc_metrics_service.cc
+++ b/chromium/components/arc/metrics/arc_metrics_service.cc
@@ -36,6 +36,7 @@ constexpr char kUmaPrefix[] = "Arc";
constexpr base::TimeDelta kUmaMinTime = base::TimeDelta::FromMilliseconds(1);
constexpr base::TimeDelta kUmaMaxTime = base::TimeDelta::FromSeconds(60);
constexpr int kUmaNumBuckets = 50;
+constexpr int kUmaPriAbiMigMaxFailedAttempts = 10;
constexpr base::TimeDelta kRequestProcessListPeriod =
base::TimeDelta::FromMinutes(5);
@@ -136,6 +137,12 @@ ArcMetricsService::~ArcMetricsService() {
arc_bridge_service_->RemoveObserver(&arc_bridge_service_observer_);
}
+void ArcMetricsService::Shutdown() {
+ for (auto& obs : app_kill_observers_)
+ obs.OnArcMetricsServiceDestroyed();
+ app_kill_observers_.Clear();
+}
+
void ArcMetricsService::SetHistogramNamer(HistogramNamer histogram_namer) {
histogram_namer_ = histogram_namer;
}
@@ -273,6 +280,84 @@ void ArcMetricsService::ReportCompanionLibApiUsage(
UMA_HISTOGRAM_ENUMERATION("Arc.CompanionLibraryApisCounter", api_id);
}
+void ArcMetricsService::ReportAppKill(mojom::AppKillPtr app_kill) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ switch (app_kill->type) {
+ case mojom::AppKillType::LMKD_KILL:
+ NotifyLowMemoryKill();
+ break;
+ case mojom::AppKillType::OOM_KILL:
+ NotifyOOMKillCount(app_kill->count);
+ break;
+ }
+}
+
+void ArcMetricsService::NotifyLowMemoryKill() {
+ for (auto& obs : app_kill_observers_)
+ obs.OnArcLowMemoryKill();
+}
+
+void ArcMetricsService::NotifyOOMKillCount(unsigned long count) {
+ for (auto& obs : app_kill_observers_)
+ obs.OnArcOOMKillCount(count);
+}
+
+void ArcMetricsService::ReportArcCorePriAbiMigEvent(
+ mojom::ArcCorePriAbiMigEvent event_type) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ UMA_HISTOGRAM_ENUMERATION("Arc.AbiMigration.Event", event_type);
+}
+
+void ArcMetricsService::ReportArcCorePriAbiMigFailedTries(
+ uint32_t failed_attempts) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ UMA_HISTOGRAM_EXACT_LINEAR("Arc.AbiMigration.FailedAttempts", failed_attempts,
+ kUmaPriAbiMigMaxFailedAttempts);
+}
+
+void ArcMetricsService::ReportArcCorePriAbiMigDowngradeDelay(
+ base::TimeDelta delay) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ base::UmaHistogramCustomTimes("Arc.AbiMigration.DowngradeDelay", delay,
+ kUmaMinTime, kUmaMaxTime, kUmaNumBuckets);
+}
+
+void ArcMetricsService::OnArcStartTimeForPriAbiMigration(
+ base::TimeTicks durationTicks,
+ base::Optional<base::TimeTicks> arc_start_time) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!arc_start_time.has_value()) {
+ LOG(ERROR) << "Failed to retrieve ARC start timeticks.";
+ return;
+ }
+ VLOG(2) << "ARC start for Primary Abi Migration @" << arc_start_time.value();
+
+ const base::TimeDelta elapsed_time = durationTicks - arc_start_time.value();
+ base::UmaHistogramCustomTimes("Arc.AbiMigration.BootTime", elapsed_time,
+ kUmaMinTime, kUmaMaxTime, kUmaNumBuckets);
+}
+
+void ArcMetricsService::ReportArcCorePriAbiMigBootTime(
+ base::TimeDelta duration) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ const base::TimeTicks durationTicks = duration + base::TimeTicks();
+
+ // For VM builds, do not call into session_manager since we don't use it
+ // for the builds. Using base::TimeTicks() is fine for now because 1) the
+ // clocks in host and guest are not synchronized, and 2) the guest does not
+ // support mini container.
+ // TODO(b/172266394): Guest should itself report the timing of the upgrade.
+ if(IsArcVmEnabled()) {
+ OnArcStartTimeForPriAbiMigration(std::move(durationTicks), base::TimeTicks());
+ return;
+ }
+
+ // Retrieve ARC full container's start time from session manager.
+ chromeos::SessionManagerClient::Get()->GetArcStartTime(
+ base::BindOnce(&ArcMetricsService::OnArcStartTimeForPriAbiMigration,
+ weak_ptr_factory_.GetWeakPtr(), durationTicks));
+}
+
void ArcMetricsService::OnWindowActivated(
wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
@@ -315,6 +400,15 @@ void ArcMetricsService::OnTaskDestroyed(int32_t task_id) {
guest_os_engagement_metrics_.SetBackgroundActive(!task_ids_.empty());
}
+void ArcMetricsService::AddAppKillObserver(AppKillObserver* obs) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ app_kill_observers_.AddObserver(obs);
+}
+
+void ArcMetricsService::RemoveAppKillObserver(AppKillObserver* obs) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ app_kill_observers_.RemoveObserver(obs);
+}
ArcMetricsService::ProcessObserver::ProcessObserver(
ArcMetricsService* arc_metrics_service)
: arc_metrics_service_(arc_metrics_service) {}
diff --git a/chromium/components/arc/metrics/arc_metrics_service.h b/chromium/components/arc/metrics/arc_metrics_service.h
index 736d260115d..55d58174ff4 100644
--- a/chromium/components/arc/metrics/arc_metrics_service.h
+++ b/chromium/components/arc/metrics/arc_metrics_service.h
@@ -11,6 +11,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
@@ -50,6 +52,13 @@ class ArcMetricsService : public KeyedService,
using HistogramNamer =
base::RepeatingCallback<std::string(const std::string& base_name)>;
+ class AppKillObserver : public base::CheckedObserver {
+ public:
+ virtual void OnArcLowMemoryKill() = 0;
+ virtual void OnArcOOMKillCount(unsigned long count) = 0;
+ virtual void OnArcMetricsServiceDestroyed() {}
+ };
+
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
static ArcMetricsService* GetForBrowserContext(
@@ -64,6 +73,9 @@ class ArcMetricsService : public KeyedService,
ArcBridgeService* bridge_service);
~ArcMetricsService() override;
+ // KeyedService overrides.
+ void Shutdown() override;
+
// Sets the histogram namer. Required to not have a dependency on browser
// codebase.
void SetHistogramNamer(HistogramNamer histogram_namer);
@@ -77,6 +89,12 @@ class ArcMetricsService : public KeyedService,
mojom::BootType boot_type) override;
void ReportNativeBridge(mojom::NativeBridgeType native_bridge_type) override;
void ReportCompanionLibApiUsage(mojom::CompanionLibApiId api_id) override;
+ void ReportAppKill(mojom::AppKillPtr app_kill) override;
+ void ReportArcCorePriAbiMigEvent(
+ mojom::ArcCorePriAbiMigEvent event_type) override;
+ void ReportArcCorePriAbiMigFailedTries(uint32_t failed_attempts) override;
+ void ReportArcCorePriAbiMigDowngradeDelay(base::TimeDelta delay) override;
+ void ReportArcCorePriAbiMigBootTime(base::TimeDelta duration) override;
// wm::ActivationChangeObserver overrides.
// Records to UMA when a user has interacted with an ARC app window.
@@ -95,6 +113,9 @@ class ArcMetricsService : public KeyedService,
const std::string& intent);
void OnTaskDestroyed(int32_t task_id);
+ void AddAppKillObserver(AppKillObserver* obs);
+ void RemoveAppKillObserver(AppKillObserver* obs);
+
private:
// Adapter to be able to also observe ProcessInstance events.
class ProcessObserver : public ConnectionObserver<mojom::ProcessInstance> {
@@ -169,6 +190,13 @@ class ArcMetricsService : public KeyedService,
void OnArcStartTimeRetrieved(std::vector<mojom::BootProgressEventPtr> events,
mojom::BootType boot_type,
base::Optional<base::TimeTicks> arc_start_time);
+ void OnArcStartTimeForPriAbiMigration(
+ base::TimeTicks durationTicks,
+ base::Optional<base::TimeTicks> arc_start_time);
+
+ // Notify AppKillObservers.
+ void NotifyLowMemoryKill();
+ void NotifyOOMKillCount(unsigned long count);
THREAD_CHECKER(thread_checker_);
@@ -193,6 +221,8 @@ class ArcMetricsService : public KeyedService,
bool gamepad_interaction_recorded_ = false;
+ base::ObserverList<AppKillObserver> app_kill_observers_;
+
// Always keep this the last member of this class to make sure it's the
// first thing to be destructed.
base::WeakPtrFactory<ArcMetricsService> weak_ptr_factory_{this};
diff --git a/chromium/components/arc/mojom/BUILD.gn b/chromium/components/arc/mojom/BUILD.gn
index e0e669826eb..1927977d1de 100644
--- a/chromium/components/arc/mojom/BUILD.gn
+++ b/chromium/components/arc/mojom/BUILD.gn
@@ -26,6 +26,7 @@ if (is_chromeos) {
"cert_store.mojom",
"clipboard.mojom",
"crash_collector.mojom",
+ "digital_goods.mojom",
"disk_quota.mojom",
"enterprise_reporting.mojom",
"file_system.mojom",
@@ -54,6 +55,7 @@ if (is_chromeos) {
"screen_capture.mojom",
"sensor.mojom",
"sensor_service.mojom",
+ "sharesheet.mojom",
"storage_manager.mojom",
"timer.mojom",
"tracing.mojom",
@@ -71,12 +73,14 @@ if (is_chromeos) {
":media",
":notifications",
":oemcrypto",
+ "//components/payments/mojom:mojom",
"//media/capture/video/chromeos/mojom:cros_camera",
"//mojo/public/mojom/base",
"//printing/mojom",
"//services/device/public/mojom:usb",
"//services/media_session/public/mojom",
"//services/resource_coordinator/public/mojom",
+ "//third_party/blink/public/mojom:android_mojo_bindings",
"//ui/accessibility/mojom",
"//ui/gfx/geometry/mojom",
"//url/mojom:url_mojom_gurl",
diff --git a/chromium/components/arc/mojom/arc_bridge.mojom b/chromium/components/arc/mojom/arc_bridge.mojom
index a5049339f42..3ed01bde810 100644
--- a/chromium/components/arc/mojom/arc_bridge.mojom
+++ b/chromium/components/arc/mojom/arc_bridge.mojom
@@ -18,6 +18,7 @@ import "components/arc/mojom/cast_receiver.mojom";
import "components/arc/mojom/cert_store.mojom";
import "components/arc/mojom/clipboard.mojom";
import "components/arc/mojom/crash_collector.mojom";
+import "components/arc/mojom/digital_goods.mojom";
import "components/arc/mojom/disk_quota.mojom";
import "components/arc/mojom/enterprise_reporting.mojom";
import "components/arc/mojom/file_system.mojom";
@@ -44,6 +45,7 @@ import "components/arc/mojom/property.mojom";
import "components/arc/mojom/rotation_lock.mojom";
import "components/arc/mojom/screen_capture.mojom";
import "components/arc/mojom/sensor.mojom";
+import "components/arc/mojom/sharesheet.mojom";
import "components/arc/mojom/storage_manager.mojom";
import "components/arc/mojom/timer.mojom";
import "components/arc/mojom/tracing.mojom";
@@ -56,9 +58,9 @@ import "components/arc/mojom/volume_mounter.mojom";
import "components/arc/mojom/wake_lock.mojom";
import "components/arc/mojom/wallpaper.mojom";
-// Next MinVersion: 51
+// Next MinVersion: 53
// Deprecated method IDs: 101, 105, 121
-// Next method ID: 156
+// Next method ID: 158
interface ArcBridgeHost {
// Keep the entries alphabetical. In order to do so without breaking
// compatibility with the ARC instance, explicitly assign each interface a
@@ -119,6 +121,10 @@ interface ArcBridgeHost {
[MinVersion=7] OnCrashCollectorInstanceReady@112(
pending_remote<CrashCollectorInstance> instance_remote);
+ // Notifies Chrome that the DigitalGoodsInstance interface is ready.
+ [MinVersion=51] OnDigitalGoodsInstanceReady@156(
+ pending_remote<DigitalGoodsInstance> instance_remote);
+
// Notifies Chrome that the DiskQuotaInstance interface is ready.
[MinVersion=39] OnDiskQuotaInstanceReady@144(
pending_remote<DiskQuotaInstance> instance_remote);
@@ -221,6 +227,10 @@ interface ArcBridgeHost {
[MinVersion=49] OnSensorInstanceReady@154(
pending_remote<SensorInstance> instance_ptr);
+ // Notifies Chrome that the SharesheetInstance interface is ready.
+ [MinVersion=53] OnSharesheetInstanceReady@158(
+ pending_remote<SharesheetInstance> instance_remote);
+
// Notifies Chrome that the SmartCardManagerInstance interface is ready.
[MinVersion=48] OnSmartCardManagerInstanceReady@153(
pending_remote<SmartCardManagerInstance> instance_remote);
diff --git a/chromium/components/arc/mojom/bluetooth.mojom b/chromium/components/arc/mojom/bluetooth.mojom
index 64e3f6d24f3..18515074f38 100644
--- a/chromium/components/arc/mojom/bluetooth.mojom
+++ b/chromium/components/arc/mojom/bluetooth.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 18
+// Next MinVersion: 19
module arc.mojom;
@@ -316,8 +316,56 @@ interface RfcommConnectingSocketClient {
OnConnectFailed@1();
};
-// Next Method ID: 47
-// Deprecated Method ID: 4, 5, 6, 7, 20, 21
+// Copied from Android. See android.bluetooth.BluetoothSocket.
+// Currently we only support RFCOMM and LE CoC (L2CAP_LE) sockets.
+[Extensible]
+enum BluetoothSocketType {
+ TYPE_RFCOMM = 1,
+ TYPE_L2CAP_LE = 4,
+};
+
+// Bluetooth socket security flags in Android, used in open socket requests.
+// Chrome should set the socket option based on these flags.
+struct BluetoothSocketFlags {
+ bool encrypt;
+ bool auth;
+ bool auth_mitm;
+ bool auth_16_digit;
+};
+
+// BluetoothSocketConnection contains the information for a new Bluetooth socket
+// connection. Note that |port| is either the channel number for an RFCOMM
+// socket or PSM for an L2CAP socket. Since we cannot get socket (or peer) name
+// on the transferred socket on Android side, we also need to pass the peer
+// address and port number.
+struct BluetoothSocketConnection {
+ handle sock;
+ BluetoothAddress addr;
+ int32 port;
+};
+
+// The mojo connection represents a listening socket.
+// Next Method ID: 1
+interface BluetoothListenSocketClient {
+ // Called when accept() succeeds. |port| in |connection| is the peer port
+ // number.
+ OnAccepted@0(BluetoothSocketConnection connection);
+};
+
+// The mojo connection represents a connecting (not connected yet) socket.
+// After connect() either succeeds or fails, Android is responsible for closing
+// this mojo connection.
+// Next Method ID: 2
+interface BluetoothConnectSocketClient {
+ // Called when connect() succeeds. |port| in |connection| is the port number
+ // on our side.
+ OnConnected@0(BluetoothSocketConnection connection);
+ // Called when connect() fails.
+ OnConnectFailed@1();
+};
+
+// Next Method ID: 49
+// Deprecated Method ID: 4, 5, 6, 7, 20, 21, 29, 45, 46
interface BluetoothHost {
EnableAdapter@0() => (BluetoothAdapterState state);
DisableAdapter@1() => (BluetoothAdapterState state);
@@ -375,7 +423,9 @@ interface BluetoothHost {
[MinVersion=1] ReadRemoteRssi@28(BluetoothAddress remote_addr)
=> (int32 rssi);
- [MinVersion=2] OpenBluetoothSocket@29()
+ // DEPRECATED: Use BluetoothSocketListen@47 or BluetoothSocketConnect@48
+ // instead.
+ [MinVersion=2] OpenBluetoothSocketDeprecated@29()
=> (handle sock);
// Bluetooth Gatt Server functions
@@ -430,7 +480,7 @@ interface BluetoothHost {
// we will select a channel number automatically. If this process succeeds,
// returns SUCCESS in |status|, the actual listening channel in |channel|,
// and a new mojo connection which represents the listening socket.
- [MinVersion=15] RfcommListen@45(int32 channel, int32 optval)
+ [MinVersion=15] RfcommListenDeprecated@45(int32 channel, int32 optval)
=> (BluetoothStatus status, int32 channel,
RfcommListeningSocketClient&? client);
// Opens a bluetooth socket with socket option |optval|, and then connect()
@@ -438,9 +488,27 @@ interface BluetoothHost {
// in |status| and a new mojo connection which holds the connecting socket.
// Unlike in RfcommListen(), |channel| here could not be 0, since this is the
// peer channel number.
- [MinVersion=15] RfcommConnect@46(BluetoothAddress remote_addr,
- int32 channel, int32 optval)
+ [MinVersion=15] RfcommConnectDeprecated@46(BluetoothAddress remote_addr,
+ int32 channel, int32 optval)
=> (BluetoothStatus status, RfcommConnectingSocketClient&? client);
+
+ // Bluetooth socket (RFCOMM and L2CAP LE) functions
+ // Opens a |sock_type| socket with security options in |sock_flags|, and
+ // listens on |port| (RFCOMM channel or L2CAP PSM). When |port| = 0, we will
+ // select a port number automatically. If this process succeeds, the actual
+ // listening port will be returned in |port|.
+ [MinVersion=18] BluetoothSocketListen@47(BluetoothSocketType sock_type,
+ BluetoothSocketFlags sock_flags,
+ int32 port)
+ => (BluetoothStatus status, int32 port,
+ BluetoothListenSocketClient&? client);
+ // Opens a |sock_type| socket with security options in |sock_flags|, and
+ // connects to |remote_addr| which is listening on |remote_port|.
+ [MinVersion=18] BluetoothSocketConnect@48(BluetoothSocketType sock_type,
+ BluetoothSocketFlags sock_flags,
+ BluetoothAddress remote_addr,
+ int32 remote_port)
+ => (BluetoothStatus status, BluetoothConnectSocketClient&? client);
};
// Next Method ID: 24
diff --git a/chromium/components/arc/mojom/digital_goods.mojom b/chromium/components/arc/mojom/digital_goods.mojom
new file mode 100644
index 00000000000..c07fec7f94a
--- /dev/null
+++ b/chromium/components/arc/mojom/digital_goods.mojom
@@ -0,0 +1,38 @@
+// Copyright 2020 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.
+
+// Next MinVersion: 1
+
+module arc.mojom;
+
+import "third_party/blink/public/mojom/digital_goods/digital_goods.mojom";
+
+// Allows the browser process to forward calls for the Digital Goods API to
+// ARC++
+// Next method ID: 3
+interface DigitalGoodsInstance {
+ // Queries a specific package for SKU details by item IDs.
+ [MinVersion=0] GetDetails@0(string package_name,
+ string scope,
+ array<string> item_ids)
+ => (payments.mojom.BillingResponseCode code,
+ array<payments.mojom.ItemDetails> item_details_list);
+
+ // Informs a package that the purchase identified by |purchase_token| was
+ // successfully acknowledged. If |make_available_again| is true, indicates
+ // that the purchase is repeatable (e.g. a consumable item). If it is false,
+ // indicates that the purchase is one-off (e.g. a permanent upgrade).
+ [MinVersion=0] Acknowledge@1(string package_name,
+ string scope,
+ string purchase_token,
+ bool make_available_again)
+ => (payments.mojom.BillingResponseCode code);
+
+ // Queries a package for information on all items that are currently owned by
+ // the user.
+ [MinVersion=0] ListPurchases@2(string package_name,
+ string scope)
+ => (payments.mojom.BillingResponseCode code,
+ array<payments.mojom.PurchaseDetails> purchase_details_list);
+};
diff --git a/chromium/components/arc/mojom/file_system.mojom b/chromium/components/arc/mojom/file_system.mojom
index 7a74c610d13..5d84a4f0c99 100644
--- a/chromium/components/arc/mojom/file_system.mojom
+++ b/chromium/components/arc/mojom/file_system.mojom
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 15
+// Next MinVersion: 17
module arc.mojom;
import "components/arc/mojom/bitmap.mojom";
+import "components/arc/mojom/gfx.mojom";
import "components/arc/mojom/intent_common.mojom";
+import "components/arc/mojom/video_common.mojom";
import "url/mojom/url.mojom";
// Represents a document in Android DocumentsProvider.
@@ -58,6 +60,10 @@ struct Document {
// Flag indicating that a document can be moved to another location within
// the same document provider.
[MinVersion=12] bool supports_move;
+
+ // Flag indicating that a document has a thumbnail available that can be
+ // fetched with OpenThumbnail.
+ [MinVersion=15] bool supports_thumbnail;
};
// Represents a root in Android DocumentsProvider.
@@ -167,6 +173,10 @@ struct SelectFilesRequest {
// Android task ID of the request sender.
int32 task_id;
+
+ // Search query to run when the file selector is launched.
+ // Corresponds to Intent.EXTRA_CONTENT_QUERY.
+ string? search_query;
};
// Represents a path to a document served by a DocumentsProvider.
@@ -234,9 +244,12 @@ struct FileSelectorElements {
// List of files in the right pane.
array<FileSelectorElement> file_elements;
+
+ // Query text filled in the search box.
+ string? search_query;
};
-// Next method ID: 9
+// Next method ID: 11
interface FileSystemHost {
// Returns the name of the file specified by the URL.
// When an error occurs, returns null value.
@@ -258,6 +271,14 @@ interface FileSystemHost {
// Called when the list of available roots or their metadata are changed.
[MinVersion=10] OnRootsChanged@6();
+ // Returns a unique ID to represent the file specified by the URL.
+ // The FD needs to be created by the caller itself.
+ [MinVersion=16] GetVirtualFileId@9(string url) => (string? id);
+
+ // Releases the ID generated by GetVirtualFileId() when it is no longer
+ // used.
+ [MinVersion=16] HandleIdReleased@10(string id) => (bool success);
+
// Returns an FD for reading the file specified by the URL.
[MinVersion=6] OpenFileToRead@4(string url) => (handle? fd);
@@ -278,7 +299,7 @@ interface FileSystemHost {
(FileSelectorElements elements);
};
-// Next method ID: 21
+// Next method ID: 22
interface FileSystemInstance {
// Notes about Android Documents Provider:
//
@@ -395,6 +416,11 @@ interface FileSystemInstance {
// URL.
[MinVersion=13] OpenFileToWrite@18(string url) => (handle? fd);
+ // Asks the ContentResolver to get a FD to read the thumbnail of a
+ // DocumentsProvider file specified by the URL. The thumbnail should be close
+ // in size (width and height) but not necessarily the same as |size_hint|.
+ [MinVersion=15] OpenThumbnail@21(string url, Size size_hint) => (handle? fd);
+
// Uninstalls a document watcher.
//
// After this method call returns, OnDocumentChanged() will never be called
@@ -407,6 +433,11 @@ interface FileSystemInstance {
// Requests MediaProvider to scan specified files.
// When the specified file does not exist, the corresponding entry in
// MediaProvider is removed.
+ //
+ // NOTE: We use [UnlimitedSize] here because `paths` may be arbitrarily large
+ // and there have been crash dumps indicating that it actually happens with
+ // this message. See https://crbug.com/1142019.
+ [UnlimitedSize]
RequestMediaScan@0(array<string> paths);
// Reloads and refreshes entries in MediaStore under |directory_path|.
diff --git a/chromium/components/arc/mojom/gfx.mojom b/chromium/components/arc/mojom/gfx.mojom
index aaf58a27b7e..3400f6957bf 100644
--- a/chromium/components/arc/mojom/gfx.mojom
+++ b/chromium/components/arc/mojom/gfx.mojom
@@ -26,3 +26,9 @@ struct Range {
// End offset in UTF-16 index.
uint32 end;
};
+
+// The graphics dimension. Both width and height should be non-negative.
+struct Size {
+ int32 width;
+ int32 height;
+};
diff --git a/chromium/components/arc/mojom/intent_helper.mojom b/chromium/components/arc/mojom/intent_helper.mojom
index 15a2920960b..481ff7ee044 100644
--- a/chromium/components/arc/mojom/intent_helper.mojom
+++ b/chromium/components/arc/mojom/intent_helper.mojom
@@ -197,8 +197,10 @@ enum ChromePage {
OSLANGUAGESINPUT,
OSLANGUAGESLANGUAGES,
OSLANGUAGESEDITDICTIONARY,
+ KERBEROS,
+ KERBEROSACCOUNTSV2,
- LAST = OSLANGUAGESEDITDICTIONARY
+ LAST = KERBEROSACCOUNTSV2
};
// Describes an unique chrome app.
diff --git a/chromium/components/arc/mojom/metrics.mojom b/chromium/components/arc/mojom/metrics.mojom
index 5de9ef7e617..fefbba84086 100644
--- a/chromium/components/arc/mojom/metrics.mojom
+++ b/chromium/components/arc/mojom/metrics.mojom
@@ -1,10 +1,12 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 6
+// Next MinVersion: 8
module arc.mojom;
+import "mojo/public/mojom/base/time.mojom";
+
[Extensible]
enum BootType {
// This is used only for backward compatibility reasons and the value has to
@@ -103,7 +105,39 @@ enum CompanionLibApiId {
IS_CLIPPING_TO_TASK_DISABLED = 23,
};
-// Next method ID: 3
+// Describes the type of app kill being reported.
+[Extensible]
+enum AppKillType {
+ LMKD_KILL = 0,
+ OOM_KILL = 1,
+};
+
+// Describes an app kill from ARC instance.
+struct AppKill {
+ // Type of kill being reported.
+ AppKillType type;
+ // Number of kills. For LMKD kills, this is always 1. For OOM kills, this is
+ // the total oom_kill count from /proc/vm_stat.
+ uint32 count;
+};
+
+// Outlines the various states that can arise while performing Primary ABI
+// Migration on a ChromeOS device.
+[Extensible]
+enum ArcCorePriAbiMigEvent {
+ // If an unknown event is reported, it will be recorded as UNSUPPORTED.
+ kUnsupported = 0,
+
+ kMigrationCompleted = 1,
+ kGmsNoDowngrade = 2,
+ kGmsDowngradeSuccess = 3,
+ kGmsDowngradeFailure = 4,
+ kWebviewNoDowngrade = 5,
+ kWebviewDowngradeSuccess = 6,
+ kWebviewDowngradeFailure = 7,
+};
+
+// Next method ID: 8
interface MetricsHost {
// Reports boot progress events from ARC instance.
ReportBootProgress@0(array<BootProgressEvent> events,
@@ -114,6 +148,21 @@ interface MetricsHost {
// Reports api usage by ChromeOS Companion Library.
[MinVersion=4] ReportCompanionLibApiUsage@2(CompanionLibApiId api_id);
+
+ // Reports LMKD and OOM kills from ARC.
+ [MinVersion=6] ReportAppKill@3(AppKill app_kill);
+
+ // Reports migration event by ARC Metrics Service.
+ [MinVersion=7] ReportArcCorePriAbiMigEvent@4(ArcCorePriAbiMigEvent event);
+
+ // Reports number of failed ABI Migration attempts by ARC Metrics Service.
+ [MinVersion=7] ReportArcCorePriAbiMigFailedTries@5(uint32 failed_attempts);
+
+ // Reports ABI Migration system packages downgrade delay by ArcMetricsService.
+ [MinVersion=7] ReportArcCorePriAbiMigDowngradeDelay@6(mojo_base.mojom.TimeDelta delay);
+
+ // Reports boot time during ABI Migration by ARC Metrics Service.
+ [MinVersion=7] ReportArcCorePriAbiMigBootTime@7(mojo_base.mojom.TimeDelta duration);
};
// Next method ID: 3
diff --git a/chromium/components/arc/mojom/power.mojom b/chromium/components/arc/mojom/power.mojom
index ac17a824e8c..5c39f7f8093 100644
--- a/chromium/components/arc/mojom/power.mojom
+++ b/chromium/components/arc/mojom/power.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 6
+// Next MinVersion: 7
module arc.mojom;
@@ -19,12 +19,42 @@ enum DisplayWakeLockType {
DIM = 1
};
-// Next method ID: 4
+// Enumerates the types of wakefullness modes.
+// Must match to PowerManager.WAKEFULNESS_* constants.
+[Extensible]
+enum WakefulnessMode {
+ // Device mode is unknown.
+ UNKNOWN = -1,
+
+ // The device is asleep. It can only be awoken.
+ // The device typically passes through the dozing state first.
+ ASLEEP = 0,
+
+ // The device is fully awake. It can be put to sleep.
+ // When the user activity timeout expires, the device may start dreaming
+ // or go to sleep.
+ AWAKE,
+
+ // The device is dreaming. It can be awoken which ends the dream.
+ DREAMING,
+
+ // The device is dozing. It is almost asleep but is allowing a special
+ // low-power "doze" dream to run which keeps the display on but lets the
+ // application processor be suspended. It can be awoken which ends the
+ // dream.The device fully goes to sleep if the dream cannot be started or
+ // ends on its own.
+ DOZING
+};
+
+// Next method ID: 5
interface PowerHost {
// Acquire and release wake locks on the host side.
OnAcquireDisplayWakeLock@0(DisplayWakeLockType type);
OnReleaseDisplayWakeLock@1(DisplayWakeLockType type);
+ // Notifies wakefulness mode is changed.
+ [MinVersion=6] OnWakefulnessChanged@5(WakefulnessMode mode);
+
// Checks if there is a display on.
[MinVersion=1] IsDisplayOn@2() => (bool is_on);
@@ -33,7 +63,7 @@ interface PowerHost {
[MinVersion=3] OnScreenBrightnessUpdateRequest@3(double percent);
};
-// Next method ID: 7
+// Next method ID: 8
interface PowerInstance {
// DEPRECATED: Please use Init@5 instead.
InitDeprecated@0(pending_remote<PowerHost> host_remote);
@@ -59,4 +89,7 @@ interface PowerInstance {
// TODO(b/136427446): Rearchitect ARC power info management with more
// explicit data / event passing.
[MinVersion=5] PowerSupplyInfoChanged@6();
+
+ // Requests current wakefulness mode.
+ [MinVersion=6] GetWakefulnessMode@7() => (WakefulnessMode mode);
};
diff --git a/chromium/components/arc/mojom/screen_capture.mojom b/chromium/components/arc/mojom/screen_capture.mojom
index ca72e9164f1..794b0f5bd70 100644
--- a/chromium/components/arc/mojom/screen_capture.mojom
+++ b/chromium/components/arc/mojom/screen_capture.mojom
@@ -14,7 +14,7 @@
module arc.mojom;
-// For gfx::Size.
+import "components/arc/mojom/gfx.mojom";
import "components/arc/mojom/video_common.mojom";
// Implemented by Chrome in order to allow requesting of permissions to perform
diff --git a/chromium/components/arc/mojom/sharesheet.mojom b/chromium/components/arc/mojom/sharesheet.mojom
new file mode 100644
index 00000000000..cec5a0844d4
--- /dev/null
+++ b/chromium/components/arc/mojom/sharesheet.mojom
@@ -0,0 +1,21 @@
+// Copyright 2020 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.
+//
+// Next MinVersion: 1
+
+module arc.mojom;
+
+// Used by ARC to create a new sharesheet session. A sharesheet session is used
+// to show the Chrome sharesheet initiated from an Android app
+// Next method ID: 0
+interface SharesheetHost {
+ // TODO(phshah): Add methods to open sharesheet view
+};
+
+// Next method ID: 1
+interface SharesheetInstance {
+ // Establishes full-duplex communication with the host.
+ [MinVersion=0] Init@0(pending_remote<SharesheetHost> host_remote) => ();
+};
+
diff --git a/chromium/components/arc/mojom/video_common.mojom b/chromium/components/arc/mojom/video_common.mojom
index 320789385c9..bc2df6a37a7 100644
--- a/chromium/components/arc/mojom/video_common.mojom
+++ b/chromium/components/arc/mojom/video_common.mojom
@@ -7,6 +7,8 @@
module arc.mojom;
+import "components/arc/mojom/gfx.mojom";
+
[Extensible]
enum VideoCodecProfile {
// The values must match to the values in media::VideoCodecProfile.
@@ -88,12 +90,6 @@ struct VideoFramePlane {
int32 stride;
};
-// The graphics dimension. Both width and height should be non-negative.
-struct Size {
- int32 width;
- int32 height;
-};
-
// The information of a plane of a video frame that describes how physical
// buffers are allocated.
struct ColorPlaneLayout {
diff --git a/chromium/components/arc/mojom/video_encode_accelerator.mojom b/chromium/components/arc/mojom/video_encode_accelerator.mojom
index 3bd387e88e1..dfcb0401aed 100644
--- a/chromium/components/arc/mojom/video_encode_accelerator.mojom
+++ b/chromium/components/arc/mojom/video_encode_accelerator.mojom
@@ -7,6 +7,7 @@
module arc.mojom;
+import "components/arc/mojom/gfx.mojom";
import "components/arc/mojom/video_common.mojom";
// Next MinVersion: 5
diff --git a/chromium/components/arc/mojom/video_protected_buffer_allocator.mojom b/chromium/components/arc/mojom/video_protected_buffer_allocator.mojom
index dbb9eda3ef3..b68b453c626 100644
--- a/chromium/components/arc/mojom/video_protected_buffer_allocator.mojom
+++ b/chromium/components/arc/mojom/video_protected_buffer_allocator.mojom
@@ -6,6 +6,7 @@
module arc.mojom;
+import "components/arc/mojom/gfx.mojom";
import "components/arc/mojom/video_common.mojom";
// Next method ID: 3
diff --git a/chromium/components/arc/net/DIR_METADATA b/chromium/components/arc/net/DIR_METADATA
new file mode 100644
index 00000000000..e568bf01ba6
--- /dev/null
+++ b/chromium/components/arc/net/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Platform>Apps>ARC"
+}
diff --git a/chromium/components/arc/net/OWNERS b/chromium/components/arc/net/OWNERS
index 522f9d41ab5..3b02b0680e8 100644
--- a/chromium/components/arc/net/OWNERS
+++ b/chromium/components/arc/net/OWNERS
@@ -1,3 +1 @@
hugobenichi@google.com
-
-# COMPONENT: Platform>Apps>ARC
diff --git a/chromium/components/arc/net/always_on_vpn_manager.cc b/chromium/components/arc/net/always_on_vpn_manager.cc
index 477801e6da0..e436028dfaa 100644
--- a/chromium/components/arc/net/always_on_vpn_manager.cc
+++ b/chromium/components/arc/net/always_on_vpn_manager.cc
@@ -7,7 +7,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/values.h"
#include "chromeos/network/network_configuration_handler.h"
diff --git a/chromium/components/arc/pay/arc_digital_goods_bridge.cc b/chromium/components/arc/pay/arc_digital_goods_bridge.cc
new file mode 100644
index 00000000000..c9eb0373c8d
--- /dev/null
+++ b/chromium/components/arc/pay/arc_digital_goods_bridge.cc
@@ -0,0 +1,99 @@
+// Copyright 2020 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/arc/pay/arc_digital_goods_bridge.h"
+
+#include <utility>
+
+#include "base/no_destructor.h"
+#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/session/arc_bridge_service.h"
+
+namespace arc {
+namespace {
+
+class ArcDigitalGoodsBridgeFactory
+ : public internal::ArcBrowserContextKeyedServiceFactoryBase<
+ ArcDigitalGoodsBridge,
+ ArcDigitalGoodsBridgeFactory> {
+ public:
+ // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
+ static constexpr const char* kName = "ArcDigitalGoodsBridgeFactory";
+
+ static ArcDigitalGoodsBridgeFactory* GetInstance() {
+ static base::NoDestructor<ArcDigitalGoodsBridgeFactory> factory;
+ return factory.get();
+ }
+
+ ArcDigitalGoodsBridgeFactory() = default;
+ ~ArcDigitalGoodsBridgeFactory() override = default;
+};
+
+} // namespace
+
+// static
+ArcDigitalGoodsBridge* ArcDigitalGoodsBridge::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return ArcDigitalGoodsBridgeFactory::GetForBrowserContext(context);
+}
+
+// static
+ArcDigitalGoodsBridge* ArcDigitalGoodsBridge::GetForBrowserContextForTesting(
+ content::BrowserContext* context) {
+ return ArcDigitalGoodsBridgeFactory::GetForBrowserContextForTesting(context);
+}
+
+ArcDigitalGoodsBridge::ArcDigitalGoodsBridge(
+ content::BrowserContext* browser_context,
+ ArcBridgeService* bridge_service)
+ : arc_bridge_service_(bridge_service) {}
+
+ArcDigitalGoodsBridge::~ArcDigitalGoodsBridge() = default;
+
+void ArcDigitalGoodsBridge::GetDetails(const std::string& package_name,
+ const std::string& scope,
+ const std::vector<std::string>& item_ids,
+ GetDetailsCallback callback) {
+ mojom::DigitalGoodsInstance* digital_goods = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_bridge_service_->digital_goods(), GetDetails);
+ if (!digital_goods) {
+ std::move(callback).Run(
+ payments::mojom::BillingResponseCode::kClientAppUnavailable,
+ /* item_detail_list = */ {});
+ return;
+ }
+ digital_goods->GetDetails(package_name, scope, item_ids, std::move(callback));
+}
+
+void ArcDigitalGoodsBridge::Acknowledge(const std::string& package_name,
+ const std::string& scope,
+ const std::string& purchase_token,
+ bool make_available_again,
+ AcknowledgeCallback callback) {
+ mojom::DigitalGoodsInstance* digital_goods = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_bridge_service_->digital_goods(), Acknowledge);
+ if (!digital_goods) {
+ std::move(callback).Run(
+ payments::mojom::BillingResponseCode::kClientAppUnavailable);
+ return;
+ }
+ digital_goods->Acknowledge(package_name, scope, purchase_token,
+ make_available_again, std::move(callback));
+}
+
+void ArcDigitalGoodsBridge::ListPurchases(const std::string& package_name,
+ const std::string& scope,
+ ListPurchasesCallback callback) {
+ mojom::DigitalGoodsInstance* digital_goods = ARC_GET_INSTANCE_FOR_METHOD(
+ arc_bridge_service_->digital_goods(), ListPurchases);
+ if (!digital_goods) {
+ std::move(callback).Run(
+ payments::mojom::BillingResponseCode::kClientAppUnavailable,
+ /* purchase_details_list = */ {});
+ return;
+ }
+ digital_goods->ListPurchases(package_name, scope, std::move(callback));
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/pay/arc_digital_goods_bridge.h b/chromium/components/arc/pay/arc_digital_goods_bridge.h
new file mode 100644
index 00000000000..53c46366651
--- /dev/null
+++ b/chromium/components/arc/pay/arc_digital_goods_bridge.h
@@ -0,0 +1,77 @@
+// Copyright 2020 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_ARC_PAY_ARC_DIGITAL_GOODS_BRIDGE_H_
+#define COMPONENTS_ARC_PAY_ARC_DIGITAL_GOODS_BRIDGE_H_
+
+#include <string>
+#include <vector>
+
+#include "components/arc/mojom/digital_goods.mojom.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace arc {
+
+class ArcBridgeService;
+
+// Queries a TWA's digital goods service.
+class ArcDigitalGoodsBridge : public KeyedService {
+ public:
+ using GetDetailsCallback =
+ base::OnceCallback<void(payments::mojom::BillingResponseCode,
+ std::vector<payments::mojom::ItemDetailsPtr>)>;
+ using AcknowledgeCallback =
+ base::OnceCallback<void(payments::mojom::BillingResponseCode)>;
+ using ListPurchasesCallback = base::OnceCallback<void(
+ payments::mojom::BillingResponseCode,
+ std::vector<payments::mojom::PurchaseDetailsPtr>)>;
+
+ // Returns the instance owned by the given BrowserContext, or nullptr if the
+ // browser |context| is not allowed to use ARC.
+ static ArcDigitalGoodsBridge* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ // Used only in testing with a TestBrowserContext.
+ static ArcDigitalGoodsBridge* GetForBrowserContextForTesting(
+ content::BrowserContext* context);
+
+ ArcDigitalGoodsBridge(content::BrowserContext* browser_context,
+ ArcBridgeService* bridge_service);
+ ~ArcDigitalGoodsBridge() override;
+
+ // Disallow copy and assign.
+ ArcDigitalGoodsBridge(const ArcDigitalGoodsBridge& other) = delete;
+ ArcDigitalGoodsBridge& operator=(const ArcDigitalGoodsBridge& other) = delete;
+
+ // Queries a specific package for SKU details by item IDs.
+ void GetDetails(const std::string& package_name,
+ const std::string& scope,
+ const std::vector<std::string>& item_ids,
+ GetDetailsCallback callback);
+
+ // Informs a package that the purchase identified by |purchase_token| was
+ // successfully acknowledged.
+ void Acknowledge(const std::string& package_name,
+ const std::string& scope,
+ const std::string& purchase_token,
+ bool make_available_again,
+ AcknowledgeCallback callback);
+
+ // Queries a package for information on all items that are currently owned by
+ // the user.
+ void ListPurchases(const std::string& package_name,
+ const std::string& scope,
+ ListPurchasesCallback callback);
+
+ private:
+ ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_PAY_ARC_DIGITAL_GOODS_BRIDGE_H_
diff --git a/chromium/components/arc/power/arc_power_bridge.cc b/chromium/components/arc/power/arc_power_bridge.cc
index 0ab1ebed483..f5e915aacd7 100644
--- a/chromium/components/arc/power/arc_power_bridge.cc
+++ b/chromium/components/arc/power/arc_power_bridge.cc
@@ -134,6 +134,14 @@ ArcPowerBridge::~ArcPowerBridge() {
arc_bridge_service_->power()->SetHost(nullptr);
}
+void ArcPowerBridge::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void ArcPowerBridge::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
void ArcPowerBridge::SetUserIdHash(const std::string& user_id_hash) {
user_id_hash_ = user_id_hash;
}
@@ -359,6 +367,11 @@ void ArcPowerBridge::OnGetScreenBrightnessPercent(
UpdateAndroidScreenBrightness(percent.value());
}
+void ArcPowerBridge::OnWakefulnessChanged(mojom::WakefulnessMode mode) {
+ for (auto& observer : observer_list_)
+ observer.OnWakefulnessChanged(mode);
+}
+
void ArcPowerBridge::UpdateAndroidScreenBrightness(double percent) {
mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->power(), UpdateScreenBrightnessSettings);
diff --git a/chromium/components/arc/power/arc_power_bridge.h b/chromium/components/arc/power/arc_power_bridge.h
index 328337524b5..da1b335b60f 100644
--- a/chromium/components/arc/power/arc_power_bridge.h
+++ b/chromium/components/arc/power/arc_power_bridge.h
@@ -10,6 +10,7 @@
#include <string>
#include "base/macros.h"
+#include "base/observer_list.h"
#include "base/optional.h"
#include "base/timer/timer.h"
#include "chromeos/dbus/concierge_client.h"
@@ -38,6 +39,12 @@ class ArcPowerBridge : public KeyedService,
public display::DisplayConfigurator::Observer,
public mojom::PowerHost {
public:
+ class Observer : public base::CheckedObserver {
+ public:
+ // Notifies that wakefulness mode is changed.
+ virtual void OnWakefulnessChanged(mojom::WakefulnessMode mode) = 0;
+ };
+
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
static ArcPowerBridge* GetForBrowserContext(content::BrowserContext* context);
@@ -46,6 +53,9 @@ class ArcPowerBridge : public KeyedService,
ArcBridgeService* bridge_service);
~ArcPowerBridge() override;
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
void SetUserIdHash(const std::string& user_id_hash);
// If |notify_brightness_timer_| is set, runs it and returns true. Returns
@@ -75,6 +85,7 @@ class ArcPowerBridge : public KeyedService,
void OnReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) override;
void IsDisplayOn(IsDisplayOnCallback callback) override;
void OnScreenBrightnessUpdateRequest(double percent) override;
+ void OnWakefulnessChanged(mojom::WakefulnessMode mode) override;
void SetWakeLockProviderForTesting(
mojo::Remote<device::mojom::WakeLockProvider> provider) {
@@ -127,6 +138,9 @@ class ArcPowerBridge : public KeyedService,
// about brightness changes.
base::OneShotTimer notify_brightness_timer_;
+ // List of observers.
+ base::ObserverList<Observer> observer_list_;
+
base::WeakPtrFactory<ArcPowerBridge> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ArcPowerBridge);
diff --git a/chromium/components/arc/power/arc_power_bridge_unittest.cc b/chromium/components/arc/power/arc_power_bridge_unittest.cc
index 6e90cf4719c..8aba24cdb65 100644
--- a/chromium/components/arc/power/arc_power_bridge_unittest.cc
+++ b/chromium/components/arc/power/arc_power_bridge_unittest.cc
@@ -22,6 +22,37 @@
namespace arc {
+namespace {
+
+class TestObserver : public ArcPowerBridge::Observer {
+ public:
+ TestObserver() = default;
+ ~TestObserver() override = default;
+
+ // ArcPowerBridge::Observer:
+ void OnWakefulnessChanged(mojom::WakefulnessMode mode) override {
+ last_mode_ = mode;
+ ++update_count_;
+ }
+
+ int GetUpdateCountAndReset() {
+ const int update_count = update_count_;
+ update_count_ = 0;
+ return update_count;
+ }
+
+ mojom::WakefulnessMode last_mode() const { return last_mode_; }
+
+ private:
+ int update_count_ = 0;
+ mojom::WakefulnessMode last_mode_ = mojom::WakefulnessMode::UNKNOWN;
+
+ TestObserver(TestObserver const&) = delete;
+ TestObserver& operator=(TestObserver const&) = delete;
+};
+
+} // namespace
+
using device::mojom::WakeLockType;
class ArcPowerBridgeTest : public testing::Test {
@@ -104,40 +135,43 @@ class ArcPowerBridgeTest : public testing::Test {
return chromeos::FakePowerManagerClient::Get();
}
+ FakePowerInstance* power_instance() { return power_instance_.get(); }
+ ArcPowerBridge* power_bridge() { return power_bridge_.get(); }
+
+ private:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<ArcBridgeService> bridge_service_;
std::unique_ptr<FakePowerInstance> power_instance_;
std::unique_ptr<ArcPowerBridge> power_bridge_;
- private:
std::unique_ptr<device::TestWakeLockProvider> wake_lock_provider_;
DISALLOW_COPY_AND_ASSIGN(ArcPowerBridgeTest);
};
TEST_F(ArcPowerBridgeTest, SuspendAndResume) {
- ASSERT_EQ(0, power_instance_->num_suspend());
- ASSERT_EQ(0, power_instance_->num_resume());
+ ASSERT_EQ(0, power_instance()->num_suspend());
+ ASSERT_EQ(0, power_instance()->num_resume());
// When powerd notifies Chrome that the system is about to suspend,
// ArcPowerBridge should notify Android and take a suspend readiness callback
// to defer the suspend operation.
power_manager_client()->SendSuspendImminent(
power_manager::SuspendImminent_Reason_OTHER);
- EXPECT_EQ(1, power_instance_->num_suspend());
- EXPECT_EQ(0, power_instance_->num_resume());
+ EXPECT_EQ(1, power_instance()->num_suspend());
+ EXPECT_EQ(0, power_instance()->num_resume());
EXPECT_EQ(1,
power_manager_client()->num_pending_suspend_readiness_callbacks());
// Simulate Android acknowledging that it's ready for the system to suspend.
- power_instance_->GetSuspendCallback().Run();
+ power_instance()->GetSuspendCallback().Run();
EXPECT_EQ(0,
power_manager_client()->num_pending_suspend_readiness_callbacks());
power_manager_client()->SendSuspendDone();
- EXPECT_EQ(1, power_instance_->num_suspend());
- EXPECT_EQ(1, power_instance_->num_resume());
+ EXPECT_EQ(1, power_instance()->num_suspend());
+ EXPECT_EQ(1, power_instance()->num_resume());
// We shouldn't crash if the instance isn't ready.
DestroyPowerInstance();
@@ -149,21 +183,21 @@ TEST_F(ArcPowerBridgeTest, SuspendAndResume) {
}
TEST_F(ArcPowerBridgeTest, SetInteractive) {
- power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF);
- EXPECT_FALSE(power_instance_->interactive());
+ power_bridge()->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF);
+ EXPECT_FALSE(power_instance()->interactive());
- power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_ON);
- EXPECT_TRUE(power_instance_->interactive());
+ power_bridge()->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_ON);
+ EXPECT_TRUE(power_instance()->interactive());
// We shouldn't crash if the instance isn't ready.
DestroyPowerInstance();
- power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF);
+ power_bridge()->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF);
}
TEST_F(ArcPowerBridgeTest, ScreenBrightness) {
// Let the initial GetScreenBrightnessPercent() task run.
base::RunLoop().RunUntilIdle();
- EXPECT_DOUBLE_EQ(kInitialBrightness, power_instance_->screen_brightness());
+ EXPECT_DOUBLE_EQ(kInitialBrightness, power_instance()->screen_brightness());
// Check that Chrome OS brightness changes are passed to Android.
const double kUpdatedBrightness = 45.0;
@@ -172,11 +206,11 @@ TEST_F(ArcPowerBridgeTest, ScreenBrightness) {
change.set_percent(kUpdatedBrightness);
change.set_cause(power_manager::BacklightBrightnessChange_Cause_USER_REQUEST);
power_manager_client()->SendScreenBrightnessChanged(change);
- EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance_->screen_brightness());
+ EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance()->screen_brightness());
// Requests from Android should update the Chrome OS brightness.
const double kAndroidBrightness = 70.0;
- power_bridge_->OnScreenBrightnessUpdateRequest(kAndroidBrightness);
+ power_bridge()->OnScreenBrightnessUpdateRequest(kAndroidBrightness);
EXPECT_DOUBLE_EQ(kAndroidBrightness,
power_manager_client()->screen_brightness_percent());
@@ -185,9 +219,9 @@ TEST_F(ArcPowerBridgeTest, ScreenBrightness) {
// the timer fires.
change.set_percent(kAndroidBrightness);
power_manager_client()->SendScreenBrightnessChanged(change);
- EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance_->screen_brightness());
- ASSERT_TRUE(power_bridge_->TriggerNotifyBrightnessTimerForTesting());
- EXPECT_DOUBLE_EQ(kAndroidBrightness, power_instance_->screen_brightness());
+ EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance()->screen_brightness());
+ ASSERT_TRUE(power_bridge()->TriggerNotifyBrightnessTimerForTesting());
+ EXPECT_DOUBLE_EQ(kAndroidBrightness, power_instance()->screen_brightness());
}
TEST_F(ArcPowerBridgeTest, PowerSupplyInfoChanged) {
@@ -198,10 +232,10 @@ TEST_F(ArcPowerBridgeTest, PowerSupplyInfoChanged) {
power_manager_client()->UpdatePowerProperties(prop.value());
// Check that Chrome OS power changes are passed to Android.
- const int prev_call_count = power_instance_->num_power_supply_info();
+ const int prev_call_count = power_instance()->num_power_supply_info();
prop->set_battery_state(power_manager::PowerSupplyProperties::DISCHARGING);
power_manager_client()->UpdatePowerProperties(prop.value());
- EXPECT_EQ(1 + prev_call_count, power_instance_->num_power_supply_info());
+ EXPECT_EQ(1 + prev_call_count, power_instance()->num_power_supply_info());
}
TEST_F(ArcPowerBridgeTest, DifferentWakeLocks) {
@@ -261,4 +295,19 @@ TEST_F(ArcPowerBridgeTest, ReleaseWakeLocksWhenInstanceClosed) {
EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventDisplaySleep));
}
+// Verifies that observer methods are called on power mode change.
+TEST_F(ArcPowerBridgeTest, Observer) {
+ TestObserver test_observer;
+ power_bridge()->AddObserver(&test_observer);
+ EXPECT_EQ(0, test_observer.GetUpdateCountAndReset());
+ power_bridge()->OnWakefulnessChanged(mojom::WakefulnessMode::ASLEEP);
+ EXPECT_EQ(mojom::WakefulnessMode::ASLEEP, test_observer.last_mode());
+ EXPECT_EQ(1, test_observer.GetUpdateCountAndReset());
+ // Observe is removed, no calls are expected.
+ power_bridge()->RemoveObserver(&test_observer);
+ power_bridge()->OnWakefulnessChanged(mojom::WakefulnessMode::AWAKE);
+ EXPECT_EQ(mojom::WakefulnessMode::ASLEEP, test_observer.last_mode());
+ EXPECT_EQ(0, test_observer.GetUpdateCountAndReset());
+}
+
} // namespace arc
diff --git a/chromium/components/arc/session/arc_bridge_host_impl.cc b/chromium/components/arc/session/arc_bridge_host_impl.cc
index 4767ebcd83b..9b3ca0652cb 100644
--- a/chromium/components/arc/session/arc_bridge_host_impl.cc
+++ b/chromium/components/arc/session/arc_bridge_host_impl.cc
@@ -10,7 +10,7 @@
#include "ash/public/cpp/external_arc/message_center/arc_notification_manager.h"
#include "ash/public/cpp/message_center/arc_notifications_host_initializer.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/arc/mojom/accessibility_helper.mojom.h"
#include "components/arc/mojom/app.mojom.h"
#include "components/arc/mojom/app_permissions.mojom.h"
@@ -25,6 +25,7 @@
#include "components/arc/mojom/cert_store.mojom.h"
#include "components/arc/mojom/clipboard.mojom.h"
#include "components/arc/mojom/crash_collector.mojom.h"
+#include "components/arc/mojom/digital_goods.mojom.h"
#include "components/arc/mojom/disk_quota.mojom.h"
#include "components/arc/mojom/enterprise_reporting.mojom.h"
#include "components/arc/mojom/file_system.mojom.h"
@@ -51,6 +52,7 @@
#include "components/arc/mojom/rotation_lock.mojom.h"
#include "components/arc/mojom/screen_capture.mojom.h"
#include "components/arc/mojom/sensor.mojom.h"
+#include "components/arc/mojom/sharesheet.mojom.h"
#include "components/arc/mojom/storage_manager.mojom.h"
#include "components/arc/mojom/timer.mojom.h"
#include "components/arc/mojom/tracing.mojom.h"
@@ -163,6 +165,12 @@ void ArcBridgeHostImpl::OnCrashCollectorInstanceReady(
std::move(crash_collector_remote));
}
+void ArcBridgeHostImpl::OnDigitalGoodsInstanceReady(
+ mojo::PendingRemote<mojom::DigitalGoodsInstance> digital_goods_remote) {
+ OnInstanceReady(arc_bridge_service_->digital_goods(),
+ std::move(digital_goods_remote));
+}
+
void ArcBridgeHostImpl::OnDiskQuotaInstanceReady(
mojo::PendingRemote<mojom::DiskQuotaInstance> disk_quota_remote) {
OnInstanceReady(arc_bridge_service_->disk_quota(),
@@ -320,6 +328,12 @@ void ArcBridgeHostImpl::OnSensorInstanceReady(
OnInstanceReady(arc_bridge_service_->sensor(), std::move(sensor_remote));
}
+void ArcBridgeHostImpl::OnSharesheetInstanceReady(
+ mojo::PendingRemote<mojom::SharesheetInstance> sharesheet_remote) {
+ OnInstanceReady(arc_bridge_service_->sharesheet(),
+ std::move(sharesheet_remote));
+}
+
void ArcBridgeHostImpl::OnSmartCardManagerInstanceReady(
mojo::PendingRemote<mojom::SmartCardManagerInstance>
smart_card_manager_remote) {
diff --git a/chromium/components/arc/session/arc_bridge_host_impl.h b/chromium/components/arc/session/arc_bridge_host_impl.h
index ca99fba0ede..d61dcee12e2 100644
--- a/chromium/components/arc/session/arc_bridge_host_impl.h
+++ b/chromium/components/arc/session/arc_bridge_host_impl.h
@@ -72,6 +72,9 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
void OnCrashCollectorInstanceReady(
mojo::PendingRemote<mojom::CrashCollectorInstance> crash_collector_remote)
override;
+ void OnDigitalGoodsInstanceReady(
+ mojo::PendingRemote<mojom::DigitalGoodsInstance> digital_goods_remote)
+ override;
void OnDiskQuotaInstanceReady(
mojo::PendingRemote<mojom::DiskQuotaInstance> disk_quota_remote) override;
void OnEnterpriseReportingInstanceReady(
@@ -132,6 +135,8 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
override;
void OnSensorInstanceReady(
mojo::PendingRemote<mojom::SensorInstance> sensor_ptr) override;
+ void OnSharesheetInstanceReady(mojo::PendingRemote<mojom::SharesheetInstance>
+ sharesheet_remote) override;
void OnSmartCardManagerInstanceReady(
mojo::PendingRemote<mojom::SmartCardManagerInstance>
smart_card_manager_remote) override;
diff --git a/chromium/components/arc/session/arc_bridge_service.cc b/chromium/components/arc/session/arc_bridge_service.cc
index 5c7ad62b69c..38c2010f645 100644
--- a/chromium/components/arc/session/arc_bridge_service.cc
+++ b/chromium/components/arc/session/arc_bridge_service.cc
@@ -20,6 +20,7 @@
#include "components/arc/mojom/cert_store.mojom.h"
#include "components/arc/mojom/clipboard.mojom.h"
#include "components/arc/mojom/crash_collector.mojom.h"
+#include "components/arc/mojom/digital_goods.mojom.h"
#include "components/arc/mojom/disk_quota.mojom.h"
#include "components/arc/mojom/enterprise_reporting.mojom.h"
#include "components/arc/mojom/file_system.mojom.h"
@@ -45,6 +46,7 @@
#include "components/arc/mojom/rotation_lock.mojom.h"
#include "components/arc/mojom/screen_capture.mojom.h"
#include "components/arc/mojom/sensor.mojom.h"
+#include "components/arc/mojom/sharesheet.mojom.h"
#include "components/arc/mojom/storage_manager.mojom.h"
#include "components/arc/mojom/timer.mojom.h"
#include "components/arc/mojom/tracing.mojom.h"
diff --git a/chromium/components/arc/session/arc_bridge_service.h b/chromium/components/arc/session/arc_bridge_service.h
index d47ef0b601b..51502ca975f 100644
--- a/chromium/components/arc/session/arc_bridge_service.h
+++ b/chromium/components/arc/session/arc_bridge_service.h
@@ -40,6 +40,7 @@ class ClipboardHost;
class ClipboardInstance;
class CrashCollectorHost;
class CrashCollectorInstance;
+class DigitalGoodsInstance;
class DiskQuotaHost;
class DiskQuotaInstance;
class EnterpriseReportingHost;
@@ -84,6 +85,8 @@ class ScreenCaptureHost;
class ScreenCaptureInstance;
class SensorHost;
class SensorInstance;
+class SharesheetHost;
+class SharesheetInstance;
class SmartCardManagerHost;
class SmartCardManagerInstance;
class StorageManagerInstance;
@@ -181,6 +184,9 @@ class ArcBridgeService {
crash_collector() {
return &crash_collector_;
}
+ ConnectionHolder<mojom::DigitalGoodsInstance>* digital_goods() {
+ return &digital_goods_;
+ }
ConnectionHolder<mojom::DiskQuotaInstance, mojom::DiskQuotaHost>*
disk_quota() {
return &disk_quota_;
@@ -258,6 +264,10 @@ class ArcBridgeService {
ConnectionHolder<mojom::SensorInstance, mojom::SensorHost>* sensor() {
return &sensor_;
}
+ ConnectionHolder<mojom::SharesheetInstance, mojom::SharesheetHost>*
+ sharesheet() {
+ return &sharesheet_;
+ }
ConnectionHolder<mojom::SmartCardManagerInstance,
mojom::SmartCardManagerHost>*
smart_card_manager() {
@@ -311,6 +321,7 @@ class ArcBridgeService {
ConnectionHolder<mojom::ClipboardInstance, mojom::ClipboardHost> clipboard_;
ConnectionHolder<mojom::CrashCollectorInstance, mojom::CrashCollectorHost>
crash_collector_;
+ ConnectionHolder<mojom::DigitalGoodsInstance> digital_goods_;
ConnectionHolder<mojom::DiskQuotaInstance, mojom::DiskQuotaHost> disk_quota_;
ConnectionHolder<mojom::EnterpriseReportingInstance,
mojom::EnterpriseReportingHost>
@@ -345,6 +356,8 @@ class ArcBridgeService {
ConnectionHolder<mojom::ScreenCaptureInstance, mojom::ScreenCaptureHost>
screen_capture_;
ConnectionHolder<mojom::SensorInstance, mojom::SensorHost> sensor_;
+ ConnectionHolder<mojom::SharesheetInstance, mojom::SharesheetHost>
+ sharesheet_;
ConnectionHolder<mojom::SmartCardManagerInstance, mojom::SmartCardManagerHost>
smart_card_manager_;
ConnectionHolder<mojom::StorageManagerInstance> storage_manager_;
diff --git a/chromium/components/arc/session/arc_container_client_adapter.cc b/chromium/components/arc/session/arc_container_client_adapter.cc
index 7697b24ac23..60347a5a28f 100644
--- a/chromium/components/arc/session/arc_container_client_adapter.cc
+++ b/chromium/components/arc/session/arc_container_client_adapter.cc
@@ -7,7 +7,7 @@
#include <string>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
diff --git a/chromium/components/arc/session/arc_container_client_adapter_unittest.cc b/chromium/components/arc/session/arc_container_client_adapter_unittest.cc
new file mode 100644
index 00000000000..ef41fe2e67b
--- /dev/null
+++ b/chromium/components/arc/session/arc_container_client_adapter_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2020 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 "base/callback_helpers.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "components/arc/session/arc_container_client_adapter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+class ArcContainerClientAdapterTest : public testing::Test {
+ public:
+ ArcContainerClientAdapterTest() = default;
+ ~ArcContainerClientAdapterTest() override = default;
+ ArcContainerClientAdapterTest(const ArcContainerClientAdapterTest&) = delete;
+ ArcContainerClientAdapterTest& operator=(
+ const ArcContainerClientAdapterTest&) = delete;
+
+ void SetUp() override {
+ chromeos::SessionManagerClient::InitializeFake();
+ client_adapter_ = CreateArcContainerClientAdapter();
+ }
+
+ void TearDown() override {
+ client_adapter_ = nullptr;
+ chromeos::SessionManagerClient::Shutdown();
+ }
+
+ protected:
+ ArcClientAdapter* client_adapter() { return client_adapter_.get(); }
+
+ private:
+ std::unique_ptr<ArcClientAdapter> client_adapter_;
+};
+
+// b/164816080 This test ensures that a new container instance that is
+// created while handling the shutting down of the previous instance,
+// doesn't incorrectly receive the shutdown event as well.
+TEST_F(ArcContainerClientAdapterTest,
+ DoesNotGetArcInstanceStoppedOnNestedInstance) {
+ class Observer : public ArcClientAdapter::Observer {
+ public:
+ explicit Observer(Observer* child_observer)
+ : child_observer_(child_observer) {}
+ Observer(const Observer&) = delete;
+ Observer& operator=(const Observer&) = delete;
+
+ ~Observer() override {
+ if (child_observer_ && nested_client_adapter_)
+ nested_client_adapter_->RemoveObserver(child_observer_);
+ }
+
+ bool stopped_called() const { return stopped_called_; }
+
+ // ArcClientAdapter::Observer:
+ void ArcInstanceStopped() override {
+ stopped_called_ = true;
+
+ if (child_observer_) {
+ nested_client_adapter_ = CreateArcContainerClientAdapter();
+ nested_client_adapter_->AddObserver(child_observer_);
+ }
+ }
+
+ private:
+ Observer* const child_observer_;
+ std::unique_ptr<ArcClientAdapter> nested_client_adapter_;
+ bool stopped_called_ = false;
+ };
+
+ Observer child_observer(nullptr);
+ Observer parent_observer(&child_observer);
+ client_adapter()->AddObserver(&parent_observer);
+ base::ScopedClosureRunner teardown(base::BindOnce(
+ [](ArcClientAdapter* client_adapter, Observer* parent_observer) {
+ client_adapter->RemoveObserver(parent_observer);
+ },
+ client_adapter(), &parent_observer));
+
+ chromeos::FakeSessionManagerClient::Get()->NotifyArcInstanceStopped();
+
+ EXPECT_TRUE(parent_observer.stopped_called());
+ EXPECT_FALSE(child_observer.stopped_called());
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/session/arc_data_remover.cc b/chromium/components/arc/session/arc_data_remover.cc
index 23aabe931e9..b1cc83cb809 100644
--- a/chromium/components/arc/session/arc_data_remover.cc
+++ b/chromium/components/arc/session/arc_data_remover.cc
@@ -57,9 +57,8 @@ void ArcDataRemover::Run(RunCallback callback) {
.account_id();
upstart_client->StartJob(
kArcRemoveDataUpstartJob, {"CHROMEOS_USER=" + account_id},
- base::AdaptCallbackForRepeating(
- base::BindOnce(&ArcDataRemover::OnDataRemoved,
- weak_factory_.GetWeakPtr(), std::move(callback))));
+ base::BindOnce(&ArcDataRemover::OnDataRemoved, weak_factory_.GetWeakPtr(),
+ std::move(callback)));
}
void ArcDataRemover::OnDataRemoved(RunCallback callback, bool success) {
diff --git a/chromium/components/arc/session/arc_session_runner.cc b/chromium/components/arc/session/arc_session_runner.cc
index 14da213e27d..ae998ffead3 100644
--- a/chromium/components/arc/session/arc_session_runner.cc
+++ b/chromium/components/arc/session/arc_session_runner.cc
@@ -258,8 +258,6 @@ void ArcSessionRunner::SetRestartDelayForTesting(
restart_delay_ = restart_delay;
}
-// TODO(b/164816080) add a test to ensure OnSessionStopped is not called
-// when starting ARC session after failed attempt
void ArcSessionRunner::StartArcSession() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!restart_timer_.IsRunning());
diff --git a/chromium/components/arc/session/arc_session_runner_unittest.cc b/chromium/components/arc/session/arc_session_runner_unittest.cc
index 104256e12fd..73a64132d1c 100644
--- a/chromium/components/arc/session/arc_session_runner_unittest.cc
+++ b/chromium/components/arc/session/arc_session_runner_unittest.cc
@@ -6,7 +6,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/macros.h"
diff --git a/chromium/components/arc/session/arc_vm_client_adapter.cc b/chromium/components/arc/session/arc_vm_client_adapter.cc
index aeca7d62c50..ab75026874b 100644
--- a/chromium/components/arc/session/arc_vm_client_adapter.cc
+++ b/chromium/components/arc/session/arc_vm_client_adapter.cc
@@ -14,7 +14,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -60,20 +60,18 @@ namespace {
// The "_2d" in job names below corresponds to "-". Upstart escapes characters
// that aren't valid in D-Bus object paths with underscore followed by its
// ascii code in hex. So "arc_2dcreate_2ddata" becomes "arc-create-data".
-constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
constexpr const char kArcHostClockServiceJobName[] =
"arc_2dhost_2dclock_2dservice";
constexpr const char kArcKeymasterJobName[] = "arc_2dkeymasterd";
constexpr const char kArcSensorServiceJobName[] = "arc_2dsensor_2dservice";
-constexpr const char kArcVmMountMyFilesJobName[] = "arcvm_2dmount_2dmyfiles";
-constexpr const char kArcVmMountRemovableMediaJobName[] =
- "arcvm_2dmount_2dremovable_2dmedia";
-constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
constexpr const char kArcVmAdbdJobName[] = "arcvm_2dadbd";
constexpr const char kArcVmPerBoardFeaturesJobName[] =
"arcvm_2dper_2dboard_2dfeatures";
constexpr const char kArcVmBootNotificationServerJobName[] =
"arcvm_2dboot_2dnotification_2dserver";
+// TODO(hashimoto): Introduce another job for pre-login services.
+constexpr char kArcVmPostLoginServicesJobName[] =
+ "arcvm_2dpost_2dlogin_2dservices";
constexpr const char kCrosSystemPath[] = "/usr/bin/crossystem";
constexpr const char kArcVmBootNotificationServerSocketPath[] =
@@ -547,6 +545,13 @@ class ArcVmClientAdapter : public ArcClientAdapter,
<< "StopArcInstance is called during browser shutdown. Do nothing.";
return;
}
+ if (current_cid_ == kInvalidCid) {
+ // No VM is currently running, avoid calling ConciergeClient::StopVm().
+ // TODO(wvk): Once StartMiniArc() is implemented, use a DCHECK here
+ // instead.
+ OnArcInstanceStopped();
+ return;
+ }
if (should_backup_log) {
GetDebugDaemonClient()->BackupArcBugReport(
@@ -636,10 +641,7 @@ class ArcVmClientAdapter : public ArcClientAdapter,
// exist.
JobDesc{kArcVmPerBoardFeaturesJobName, UpstartOperation::JOB_START, {}},
- JobDesc{kArcVmServerProxyJobName, UpstartOperation::JOB_STOP, {}},
- JobDesc{kArcVmMountMyFilesJobName, UpstartOperation::JOB_STOP, {}},
- JobDesc{
- kArcVmMountRemovableMediaJobName, UpstartOperation::JOB_STOP, {}},
+ JobDesc{kArcVmPostLoginServicesJobName, UpstartOperation::JOB_STOP, {}},
JobDesc{kArcKeymasterJobName, UpstartOperation::JOB_STOP_AND_START, {}},
JobDesc{
kArcSensorServiceJobName, UpstartOperation::JOB_STOP_AND_START, {}},
@@ -715,20 +717,15 @@ class ArcVmClientAdapter : public ArcClientAdapter,
return;
}
- std::vector<std::string> environment_for_create_data = {
+ std::vector<std::string> environment{
"CHROMEOS_USER=" +
- cryptohome::CreateAccountIdentifierFromIdentification(cryptohome_id_)
- .account_id()};
- std::vector<std::string> environment_for_arcvm_mount_myfiles = {
+ cryptohome::CreateAccountIdentifierFromIdentification(
+ cryptohome_id_)
+ .account_id(),
"CHROMEOS_USER_ID_HASH=" + user_id_hash_};
std::deque<JobDesc> jobs{
- JobDesc{kArcVmServerProxyJobName, UpstartOperation::JOB_START, {}},
- JobDesc{kArcCreateDataJobName, UpstartOperation::JOB_START,
- std::move(environment_for_create_data)},
- JobDesc{kArcVmMountMyFilesJobName, UpstartOperation::JOB_START,
- std::move(environment_for_arcvm_mount_myfiles)},
- JobDesc{
- kArcVmMountRemovableMediaJobName, UpstartOperation::JOB_START, {}},
+ JobDesc{kArcVmPostLoginServicesJobName, UpstartOperation::JOB_START,
+ std::move(environment)},
};
ConfigureUpstartJobs(
std::move(jobs),
diff --git a/chromium/components/arc/session/arc_vm_client_adapter_unittest.cc b/chromium/components/arc/session/arc_vm_client_adapter_unittest.cc
index 44d83087084..cb1980b9ebd 100644
--- a/chromium/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/chromium/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -14,6 +14,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -24,7 +25,7 @@
#include "base/system/sys_info.h"
#include "base/task/current_thread.h"
#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/time/time.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
@@ -42,15 +43,10 @@
namespace arc {
namespace {
-constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
constexpr const char kArcHostClockServiceJobName[] =
"arc_2dhost_2dclock_2dservice";
constexpr const char kArcKeymasterJobName[] = "arc_2dkeymasterd";
constexpr const char kArcSensorServiceJobName[] = "arc_2dsensor_2dservice";
-constexpr const char kArcVmMountMyFilesJobName[] = "arcvm_2dmount_2dmyfiles";
-constexpr const char kArcVmMountRemovableMediaJobName[] =
- "arcvm_2dmount_2dremovable_2dmedia";
-constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
constexpr const char kArcVmAdbdJobName[] = "arcvm_2dadbd";
constexpr const char kArcVmPerBoardFeaturesJobName[] =
"arcvm_2dper_2dboard_2dfeatures";
@@ -59,6 +55,8 @@ constexpr const char kArcVmBootNotificationServerJobName[] =
constexpr const size_t kUnixMaxPathLen = sizeof(sockaddr_un::sun_path);
constexpr const char kArcVmBootNotificationServerAddress[kUnixMaxPathLen] =
"\0test_arcvm_boot_notification_server";
+constexpr char kArcVmPostLoginServicesJobName[] =
+ "arcvm_2dpost_2dlogin_2dservices";
constexpr const char kUserIdHash[] = "this_is_a_valid_user_id_hash";
constexpr const char kSerialNumber[] = "AAAABBBBCCCCDDDD1234";
@@ -499,10 +497,10 @@ TEST_F(ArcVmClientAdapterTest, StartMiniArc) {
}
// Tests that StartMiniArc() still succeeds even when Upstart fails to stop
-// the arcvm-server-proxy job.
-TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopArcVmServerProxyJobFail) {
+// the arcvm-post-login-services job.
+TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopArcVmPostLoginServicesJobFail) {
// Inject failure to FakeUpstartClient.
- InjectUpstartStopJobFailure(kArcVmServerProxyJobName);
+ InjectUpstartStopJobFailure(kArcVmPostLoginServicesJobName);
StartMiniArc();
// Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
@@ -576,29 +574,6 @@ TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopArcSensorServiceJobFail) {
EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
}
-// Tests that StartMiniArc() still succeeds even when Upstart fails to stop
-// arcvm-mount-myfiles.
-TEST_F(ArcVmClientAdapterTest, StartMiniArc_StopArcVmMountMyFilesJobFail) {
- // Inject failure to FakeUpstartClient.
- InjectUpstartStopJobFailure(kArcVmMountMyFilesJobName);
-
- StartMiniArc();
- // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
- EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-}
-
-// Tests that StartMiniArc() still succeeds even when Upstart fails to stop
-// arcvm-mount-removable-media.
-TEST_F(ArcVmClientAdapterTest,
- StartMiniArc_StopArcVmMountRemovableMediaJobFail) {
- // Inject failure to FakeUpstartClient.
- InjectUpstartStopJobFailure(kArcVmMountRemovableMediaJobName);
-
- StartMiniArc();
- // Confirm that no VM is started. ARCVM doesn't support mini ARC yet.
- EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-}
-
// Tests that StartMiniArc() fails when Upstart fails to start the job.
TEST_F(ArcVmClientAdapterTest, StartMiniArc_StartArcVmPerBoardFeaturesJobFail) {
// Inject failure to FakeUpstartClient.
@@ -650,6 +625,85 @@ TEST_F(ArcVmClientAdapterTest, StopArcInstance) {
EXPECT_TRUE(arc_instance_stopped_called());
}
+// b/164816080 This test ensures that a new vm instance that is
+// created while handling the shutting down of the previous instance,
+// doesn't incorrectly receive the shutdown event as well.
+TEST_F(ArcVmClientAdapterTest, DoesNotGetArcInstanceStoppedOnNestedInstance) {
+ using RunLoopFactory = base::RepeatingCallback<base::RunLoop*()>;
+
+ class Observer : public ArcClientAdapter::Observer {
+ public:
+ Observer(RunLoopFactory run_loop_factory, Observer* child_observer)
+ : run_loop_factory_(run_loop_factory),
+ child_observer_(child_observer) {}
+ Observer(const Observer&) = delete;
+ Observer& operator=(const Observer&) = delete;
+
+ ~Observer() override {
+ if (child_observer_ && nested_adapter_)
+ nested_adapter_->RemoveObserver(child_observer_);
+ }
+
+ bool stopped_called() const { return stopped_called_; }
+
+ // ArcClientAdapter::Observer:
+ void ArcInstanceStopped() override {
+ stopped_called_ = true;
+
+ if (child_observer_) {
+ nested_adapter_ = CreateArcVmClientAdapterForTesting(base::DoNothing());
+ nested_adapter_->AddObserver(child_observer_);
+ nested_adapter_->SetUserInfo(
+ cryptohome::Identification(user_manager::StubAccountId()),
+ kUserIdHash, kSerialNumber);
+
+ base::RunLoop* run_loop = run_loop_factory_.Run();
+ nested_adapter_->StartMiniArc({}, QuitClosure(run_loop));
+ run_loop->Run();
+
+ run_loop = run_loop_factory_.Run();
+ nested_adapter_->UpgradeArc({}, QuitClosure(run_loop));
+ run_loop->Run();
+ }
+ }
+
+ private:
+ base::OnceCallback<void(bool)> QuitClosure(base::RunLoop* run_loop) {
+ return base::BindOnce(
+ [](base::RunLoop* run_loop, bool result) { run_loop->Quit(); },
+ run_loop);
+ }
+
+ base::RepeatingCallback<base::RunLoop*()> const run_loop_factory_;
+ Observer* const child_observer_;
+ std::unique_ptr<ArcClientAdapter> nested_adapter_;
+ bool stopped_called_ = false;
+ };
+
+ SetValidUserInfo();
+ StartMiniArc();
+ UpgradeArc(true);
+
+ RunLoopFactory run_loop_factory = base::BindLambdaForTesting([this]() {
+ RecreateRunLoop();
+ return run_loop();
+ });
+
+ Observer child_observer(run_loop_factory, nullptr);
+ Observer parent_observer(run_loop_factory, &child_observer);
+ adapter()->AddObserver(&parent_observer);
+ base::ScopedClosureRunner teardown(base::BindOnce(
+ [](ArcClientAdapter* adapter, Observer* parent_observer) {
+ adapter->RemoveObserver(parent_observer);
+ },
+ adapter(), &parent_observer));
+
+ SendVmStoppedSignal();
+
+ EXPECT_TRUE(parent_observer.stopped_called());
+ EXPECT_FALSE(child_observer.stopped_called());
+}
+
// Tests that StopArcInstance() initiates ARC log backup.
TEST_F(ArcVmClientAdapterTest, StopArcInstance_WithLogBackup) {
SetValidUserInfo();
@@ -710,7 +764,9 @@ TEST_F(ArcVmClientAdapterTest, StopArcInstance_OnShutdown) {
// Tests that StopArcInstance() immediately notifies the observer on failure.
TEST_F(ArcVmClientAdapterTest, StopArcInstance_Fail) {
+ SetValidUserInfo();
StartMiniArc();
+ UpgradeArc(true);
// Inject failure.
vm_tools::concierge::StopVmResponse response;
@@ -726,27 +782,24 @@ TEST_F(ArcVmClientAdapterTest, StopArcInstance_Fail) {
EXPECT_TRUE(arc_instance_stopped_called());
}
-// Tests that UpgradeArc() handles arcvm-server-proxy startup failures properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmProxyFailure) {
+// Tests that UpgradeArc() handles arcvm-post-login-services startup failures
+// properly.
+TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmPostLoginServicesFailure) {
SetValidUserInfo();
StartMiniArc();
// Inject failure to FakeUpstartClient.
- InjectUpstartStartJobFailure(kArcVmServerProxyJobName);
+ InjectUpstartStartJobFailure(kArcVmPostLoginServicesJobName);
UpgradeArc(false);
EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
EXPECT_FALSE(arc_instance_stopped_called());
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
+ // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
adapter()->StopArcInstance(/*on_shutdown=*/false,
/*should_backup_log=*/false);
run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+ EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called());
EXPECT_TRUE(arc_instance_stopped_called());
}
@@ -790,81 +843,6 @@ TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmAdbdFailure) {
EXPECT_TRUE(arc_instance_stopped_called());
}
-// Tests that UpgradeArc() handles arc-create-data startup failures properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcCreateDataFailure) {
- SetValidUserInfo();
- StartMiniArc();
-
- // Inject failure to FakeUpstartClient.
- InjectUpstartStartJobFailure(kArcCreateDataJobName);
-
- UpgradeArc(false);
- EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
- EXPECT_FALSE(arc_instance_stopped_called());
-
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
- adapter()->StopArcInstance(/*on_shutdown=*/false,
- /*should_backup_log=*/false);
- run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
- EXPECT_TRUE(arc_instance_stopped_called());
-}
-
-// Tests that UpgradeArc() handles arcvm-mount-myfiles startup failures
-// properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmMountMyFilesJobFail) {
- SetValidUserInfo();
- StartMiniArc();
-
- // Inject failure to FakeUpstartClient.
- InjectUpstartStartJobFailure(kArcVmMountMyFilesJobName);
-
- UpgradeArc(false);
- EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
- EXPECT_FALSE(arc_instance_stopped_called());
-
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
- adapter()->StopArcInstance(/*on_shutdown=*/false,
- /*should_backup_log=*/false);
- run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
- EXPECT_TRUE(arc_instance_stopped_called());
-}
-
-// Tests that UpgradeArc() handles arcvm-mount-removable-media startup failures
-// properly.
-TEST_F(ArcVmClientAdapterTest,
- UpgradeArc_StartArcVmMountRemovableMediaJobFail) {
- SetValidUserInfo();
- StartMiniArc();
-
- // Inject failure to FakeUpstartClient.
- InjectUpstartStartJobFailure(kArcVmMountRemovableMediaJobName);
-
- UpgradeArc(false);
- EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
- EXPECT_FALSE(arc_instance_stopped_called());
-
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
- adapter()->StopArcInstance(/*on_shutdown=*/false,
- /*should_backup_log=*/false);
- run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
- EXPECT_TRUE(arc_instance_stopped_called());
-}
-
// Tests that "no user ID hash" failure is handled properly.
TEST_F(ArcVmClientAdapterTest, UpgradeArc_NoUserId) {
// Don't set the user id hash. Note that we cannot call StartArcVm() without
@@ -876,15 +854,11 @@ TEST_F(ArcVmClientAdapterTest, UpgradeArc_NoUserId) {
EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
EXPECT_FALSE(arc_instance_stopped_called());
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
+ // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
adapter()->StopArcInstance(/*on_shutdown=*/false,
/*should_backup_log=*/false);
run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+ EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called());
EXPECT_TRUE(arc_instance_stopped_called());
}
@@ -899,15 +873,11 @@ TEST_F(ArcVmClientAdapterTest, UpgradeArc_NoSerial) {
EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
EXPECT_FALSE(arc_instance_stopped_called());
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
+ // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
adapter()->StopArcInstance(/*on_shutdown=*/false,
/*should_backup_log=*/false);
run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+ EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called());
EXPECT_TRUE(arc_instance_stopped_called());
}
@@ -924,15 +894,11 @@ TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmFailure) {
EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
EXPECT_FALSE(arc_instance_stopped_called());
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
+ // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
adapter()->StopArcInstance(/*on_shutdown=*/false,
/*should_backup_log=*/false);
run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+ EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called());
EXPECT_TRUE(arc_instance_stopped_called());
}
@@ -946,15 +912,11 @@ TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartArcVmFailureEmptyReply) {
EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
EXPECT_FALSE(arc_instance_stopped_called());
- // Try to stop the VM. StopVm will fail in this case because
- // no VM is running.
- vm_tools::concierge::StopVmResponse response;
- response.set_success(false);
- GetTestConciergeClient()->set_stop_vm_response(response);
+ // Try to stop the VM. No VM is running so StopVm() shouldn't be called.
adapter()->StopArcInstance(/*on_shutdown=*/false,
/*should_backup_log=*/false);
run_loop()->Run();
- EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
+ EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called());
EXPECT_TRUE(arc_instance_stopped_called());
}
diff --git a/chromium/components/arc/sharesheet/OWNERS b/chromium/components/arc/sharesheet/OWNERS
new file mode 100644
index 00000000000..81ebf5fe526
--- /dev/null
+++ b/chromium/components/arc/sharesheet/OWNERS
@@ -0,0 +1,3 @@
+melzhang@chromium.org
+mxcai@chromium.org
+phshah@chromium.org
diff --git a/chromium/components/arc/timer/arc_timer_bridge.cc b/chromium/components/arc/timer/arc_timer_bridge.cc
index ec0cc31e3fa..eb7542444be 100644
--- a/chromium/components/arc/timer/arc_timer_bridge.cc
+++ b/chromium/components/arc/timer/arc_timer_bridge.cc
@@ -40,13 +40,12 @@ void OnStartTimer(mojom::TimerHost::StartTimerCallback callback, bool result) {
// Unwraps a mojo handle to a file descriptor on the system.
base::ScopedFD UnwrapScopedHandle(mojo::ScopedHandle handle) {
- base::PlatformFile platform_file;
+ base::ScopedPlatformFile platform_file;
if (mojo::UnwrapPlatformFile(std::move(handle), &platform_file) !=
MOJO_RESULT_OK) {
LOG(ERROR) << "Failed to unwrap mojo handle";
- return base::ScopedFD();
}
- return base::ScopedFD(platform_file);
+ return platform_file;
}
// Returns true iff |arc_timer_requests| contains duplicate clock id values.
diff --git a/chromium/components/arc/timer/arc_timer_bridge_unittest.cc b/chromium/components/arc/timer/arc_timer_bridge_unittest.cc
index 0d0a485c313..c421d3baeeb 100644
--- a/chromium/components/arc/timer/arc_timer_bridge_unittest.cc
+++ b/chromium/components/arc/timer/arc_timer_bridge_unittest.cc
@@ -38,7 +38,7 @@ namespace {
// Converts a system file descriptor to a mojo handle that can be sent to the
// host.
mojo::ScopedHandle WrapPlatformFd(base::ScopedFD scoped_fd) {
- mojo::ScopedHandle handle = mojo::WrapPlatformFile(scoped_fd.release());
+ mojo::ScopedHandle handle = mojo::WrapPlatformFile(std::move(scoped_fd));
if (!handle.is_valid()) {
LOG(ERROR) << "Failed to wrap platform handle";
return mojo::ScopedHandle();
diff --git a/chromium/components/arc/video_accelerator/arc_video_accelerator_util.cc b/chromium/components/arc/video_accelerator/arc_video_accelerator_util.cc
index 0faa20accc3..73bd0042b78 100644
--- a/chromium/components/arc/video_accelerator/arc_video_accelerator_util.cc
+++ b/chromium/components/arc/video_accelerator/arc_video_accelerator_util.cc
@@ -21,15 +21,12 @@ base::ScopedFD UnwrapFdFromMojoHandle(mojo::ScopedHandle handle) {
return base::ScopedFD();
}
- base::PlatformFile platform_file;
+ base::ScopedPlatformFile platform_file;
MojoResult mojo_result =
mojo::UnwrapPlatformFile(std::move(handle), &platform_file);
- if (mojo_result != MOJO_RESULT_OK) {
+ if (mojo_result != MOJO_RESULT_OK)
VLOGF(1) << "UnwrapPlatformFile failed: " << mojo_result;
- return base::ScopedFD();
- }
-
- return base::ScopedFD(platform_file);
+ return platform_file;
}
std::vector<base::ScopedFD> DuplicateFD(base::ScopedFD fd, size_t num_fds) {
diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
index d0971465ea3..5df39cc7023 100644
--- a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
+++ b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
@@ -92,7 +92,10 @@ GpuArcVideoDecodeAccelerator::GpuArcVideoDecodeAccelerator(
GpuArcVideoDecodeAccelerator::~GpuArcVideoDecodeAccelerator() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (vda_)
+ // Normally client_count_ should always be > 0 if vda_ is set, but if it
+ // isn't and we underflow then we won't be able to create any new decoder
+ // forever (b/173700103). So let's use an extra check to avoid this...
+ if (vda_ && client_count_ > 0)
client_count_--;
}
@@ -119,6 +122,8 @@ void GpuArcVideoDecodeAccelerator::ProvidePictureBuffersWithVisibleRect(
pending_coded_size_ = dimensions;
+ decoder_state_ = DecoderState::kAwaitingAssignPictureBuffers;
+
auto pbf = mojom::PictureBufferFormat::New();
pbf->min_num_buffers = requested_num_of_buffers;
pbf->coded_size = dimensions;
@@ -348,6 +353,9 @@ void GpuArcVideoDecodeAccelerator::InitializeTask(
mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE);
}
+ client_count_++;
+ VLOGF(2) << "Number of concurrent clients: " << client_count_;
+
secure_mode_ = base::nullopt;
error_state_ = false;
pending_requests_ = {};
@@ -374,12 +382,8 @@ void GpuArcVideoDecodeAccelerator::OnInitializeDone(
DVLOGF(4);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (result == mojom::VideoDecodeAccelerator::Result::SUCCESS) {
- client_count_++;
- VLOGF(2) << "Number of concurrent clients: " << client_count_;
- } else {
+ if (result != mojom::VideoDecodeAccelerator::Result::SUCCESS)
error_state_ = true;
- }
// Report initialization status to UMA.
UMA_HISTOGRAM_ENUMERATION(
@@ -486,9 +490,9 @@ void GpuArcVideoDecodeAccelerator::AssignPictureBuffers(uint32_t count) {
mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT);
return;
}
- if (assign_picture_buffers_called_) {
- VLOGF(1) << "AssignPictureBuffers is called twice without "
- << "ImportBufferForPicture()";
+ if (decoder_state_ != DecoderState::kAwaitingAssignPictureBuffers) {
+ VLOGF(1) << "AssignPictureBuffers is not called right after "
+ << "Client::ProvidePictureBuffers()";
client_->NotifyError(
mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT);
return;
@@ -496,7 +500,7 @@ void GpuArcVideoDecodeAccelerator::AssignPictureBuffers(uint32_t count) {
coded_size_ = pending_coded_size_;
output_buffer_count_ = static_cast<size_t>(count);
- assign_picture_buffers_called_ = true;
+ decoder_state_ = DecoderState::kAwaitingFirstImport;
}
void GpuArcVideoDecodeAccelerator::ImportBufferForPicture(
@@ -510,6 +514,12 @@ void GpuArcVideoDecodeAccelerator::ImportBufferForPicture(
VLOGF(1) << "VDA not initialized.";
return;
}
+ if (decoder_state_ == DecoderState::kAwaitingAssignPictureBuffers) {
+ DVLOGF(3) << "AssignPictureBuffers() hasn't been called after calling "
+ << "Client::ProvidePictureBuffers(), ignored.";
+ return;
+ }
+
if (picture_buffer_id < 0 ||
static_cast<size_t>(picture_buffer_id) >= output_buffer_count_) {
VLOGF(1) << "Invalid picture_buffer_id=" << picture_buffer_id;
@@ -580,7 +590,7 @@ void GpuArcVideoDecodeAccelerator::ImportBufferForPicture(
// This is the first time of ImportBufferForPicture() after
// AssignPictureBuffers() is called. Call VDA::AssignPictureBuffers() here.
- if (assign_picture_buffers_called_) {
+ if (decoder_state_ == DecoderState::kAwaitingFirstImport) {
gfx::Size picture_size(gmb_handle.native_pixmap_handle.planes[0].stride,
coded_size_.height());
std::vector<media::PictureBuffer> buffers;
@@ -590,7 +600,7 @@ void GpuArcVideoDecodeAccelerator::ImportBufferForPicture(
}
vda_->AssignPictureBuffers(std::move(buffers));
- assign_picture_buffers_called_ = false;
+ decoder_state_ = DecoderState::kDecoding;
}
vda_->ImportBufferForPicture(picture_buffer_id, pixel_format,
@@ -605,6 +615,11 @@ void GpuArcVideoDecodeAccelerator::ReusePictureBuffer(
VLOGF(1) << "VDA not initialized.";
return;
}
+ if (decoder_state_ == DecoderState::kAwaitingAssignPictureBuffers) {
+ DVLOGF(3) << "AssignPictureBuffers() hasn't been called after calling "
+ << "Client::ProvidePictureBuffers(), ignored.";
+ return;
+ }
vda_->ReusePictureBuffer(picture_buffer_id);
}
diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h
index 9d5ea18115e..43894564d83 100644
--- a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h
+++ b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h
@@ -79,6 +79,25 @@ class GpuArcVideoDecodeAccelerator
void Flush(FlushCallback callback) override;
void Reset(ResetCallback callback) override;
private:
+ // The calling flow of changing resolution is:
+ // 1. VDA calls Client::ProvidePictureBuffers()
+ // 2. Client calls VDA::AssignPictureBuffers()
+ // 3. Client calls VDA::ImportBufferForPicture() for N times
+ // 4. Client calls VDA::ReusePictureBuffer() when a buffer is recycled.
+ //
+ // The enum state is used to check these two situations:
+ // 1. Client should not call VDA::AssignPictureBuffers() twice without calling
+ // VDA::ImportBufferForPicture() between them.
+ // 2. If VDA::ImportBufferForPicture() or VDA::ReusePictureBuffer() is
+ // called right after calling Client::ProvidePictureBuffers() without
+ // VDA::AssignPictureBuffers() be called, then the buffer contains previous
+ // resolution and should be ignored.
+ enum class DecoderState {
+ kAwaitingAssignPictureBuffers,
+ kAwaitingFirstImport,
+ kDecoding,
+ };
+
using PendingCallback =
base::OnceCallback<void(mojom::VideoDecodeAccelerator::Result)>;
static_assert(std::is_same<ResetCallback, PendingCallback>::value,
@@ -159,7 +178,8 @@ class GpuArcVideoDecodeAccelerator
base::Optional<bool> secure_mode_ = base::nullopt;
size_t output_buffer_count_ = 0;
- bool assign_picture_buffers_called_ = false;
+
+ DecoderState decoder_state_ = DecoderState::kDecoding;
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(GpuArcVideoDecodeAccelerator);
diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
index 04069c75c27..0fab25d90c7 100644
--- a/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
+++ b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/numerics/checked_math.h"
diff --git a/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc
index 8c5dcb9f093..b9e3dadba54 100644
--- a/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc
+++ b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc
@@ -28,7 +28,7 @@ void GpuArcProtectedBufferManagerProxy::GetProtectedSharedMemoryFromHandle(
std::move(unwrapped_fd));
// This ScopedFDPair dance is chromeos-specific.
base::subtle::ScopedFDPair fd_pair = region.PassPlatformHandle();
- std::move(callback).Run(mojo::WrapPlatformFile(fd_pair.fd.release()));
+ std::move(callback).Run(mojo::WrapPlatformFile(std::move(fd_pair.fd)));
}
} // namespace arc
diff --git a/chromium/components/assist_ranker/base_predictor_unittest.cc b/chromium/components/assist_ranker/base_predictor_unittest.cc
index 84201845051..de929a92e13 100644
--- a/chromium/components/assist_ranker/base_predictor_unittest.cc
+++ b/chromium/components/assist_ranker/base_predictor_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/assist_ranker/fake_ranker_model_loader.h"
diff --git a/chromium/components/assist_ranker/binary_classifier_predictor.cc b/chromium/components/assist_ranker/binary_classifier_predictor.cc
index 54e1eb9889f..69b88e65720 100644
--- a/chromium/components/assist_ranker/binary_classifier_predictor.cc
+++ b/chromium/components/assist_ranker/binary_classifier_predictor.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "components/assist_ranker/generic_logistic_regression_inference.h"
#include "components/assist_ranker/proto/ranker_model.pb.h"
diff --git a/chromium/components/assist_ranker/binary_classifier_predictor_unittest.cc b/chromium/components/assist_ranker/binary_classifier_predictor_unittest.cc
index 22898dcddc4..fec0fca37ae 100644
--- a/chromium/components/assist_ranker/binary_classifier_predictor_unittest.cc
+++ b/chromium/components/assist_ranker/binary_classifier_predictor_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/test/scoped_feature_list.h"
#include "components/assist_ranker/fake_ranker_model_loader.h"
diff --git a/chromium/components/assist_ranker/classifier_predictor.cc b/chromium/components/assist_ranker/classifier_predictor.cc
index 80fa065edfa..f5369a78390 100644
--- a/chromium/components/assist_ranker/classifier_predictor.cc
+++ b/chromium/components/assist_ranker/classifier_predictor.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "components/assist_ranker/example_preprocessing.h"
#include "components/assist_ranker/nn_classifier.h"
diff --git a/chromium/components/assist_ranker/classifier_predictor_unittest.cc b/chromium/components/assist_ranker/classifier_predictor_unittest.cc
index 14831b232c9..f6c55f7aad4 100644
--- a/chromium/components/assist_ranker/classifier_predictor_unittest.cc
+++ b/chromium/components/assist_ranker/classifier_predictor_unittest.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/test/scoped_feature_list.h"
#include "components/assist_ranker/example_preprocessing.h"
diff --git a/chromium/components/assist_ranker/ranker_model_loader_impl.cc b/chromium/components/assist_ranker/ranker_model_loader_impl.cc
index e098e2d1519..af4d0c630c7 100644
--- a/chromium/components/assist_ranker/ranker_model_loader_impl.cc
+++ b/chromium/components/assist_ranker/ranker_model_loader_impl.cc
@@ -9,7 +9,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
diff --git a/chromium/components/assist_ranker/ranker_model_loader_impl_unittest.cc b/chromium/components/assist_ranker/ranker_model_loader_impl_unittest.cc
index 7fdc5df3ca6..3d643c1f32c 100644
--- a/chromium/components/assist_ranker/ranker_model_loader_impl_unittest.cc
+++ b/chromium/components/assist_ranker/ranker_model_loader_impl_unittest.cc
@@ -15,7 +15,6 @@
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/assist_ranker/proto/ranker_model.pb.h"
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index 150a6db3bd8..9f15164b1a8 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
java_strings_grd("autofill_strings_grd") {
grd_file = "java/strings/autofill_strings.grd"
@@ -20,6 +21,7 @@ android_resources("autofill_java_resources") {
"java/res/layout/autofill_dropdown_item_refresh.xml",
"java/res/values/colors.xml",
"java/res/values/dimens.xml",
+ "java/res/values/styles.xml",
]
deps = [
":autofill_strings_grd",
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.cc b/chromium/components/autofill/android/provider/autofill_provider_android.cc
index a9a7099e5e0..157142cde47 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.cc
@@ -86,8 +86,7 @@ void AutofillProviderAndroid::OnQueryFormFieldAutofill(
// Focus or field value change will also trigger the query, so it should be
// ignored if the form is same.
- if (ShouldStartNewSession(handler, form))
- StartNewSession(handler, form, field, bounding_box);
+ MaybeStartNewSession(handler, form, field, bounding_box);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
@@ -105,18 +104,24 @@ void AutofillProviderAndroid::OnQueryFormFieldAutofill(
}
}
-bool AutofillProviderAndroid::ShouldStartNewSession(
+void AutofillProviderAndroid::MaybeStartNewSession(
AutofillHandlerProxy* handler,
- const FormData& form) {
- // Only start a new session when form or handler is changed, the change of
- // handler indicates query from other frame and a new session is needed.
- return !IsCurrentlyLinkedForm(form) || !IsCurrentlyLinkedHandler(handler);
-}
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box) {
+ // Don't start a new session when the new form is similar to the old form, the
+ // new handler is the same as the current handler, and the coordinates of the
+ // relevant form field haven't changed.
+ if (form_ && form_->SimilarFormAs(form) &&
+ IsCurrentlyLinkedHandler(handler)) {
+ size_t index;
+ if (form_->GetFieldIndex(field, &index) &&
+ handler->driver()->TransformBoundingBoxToViewportCoordinates(
+ form.fields[index].bounds) == form_->form().fields[index].bounds) {
+ return;
+ }
+ }
-void AutofillProviderAndroid::StartNewSession(AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
@@ -221,8 +226,7 @@ void AutofillProviderAndroid::OnSelectControlDidChange(
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) {
- if (ShouldStartNewSession(handler, form))
- StartNewSession(handler, form, field, bounding_box);
+ MaybeStartNewSession(handler, form, field, bounding_box);
FireFormFieldDidChanged(handler, form, field, bounding_box);
}
@@ -255,7 +259,8 @@ void AutofillProviderAndroid::OnFormSubmitted(AutofillHandlerProxy* handler,
}
void AutofillProviderAndroid::OnFocusNoLongerOnForm(
- AutofillHandlerProxy* handler) {
+ AutofillHandlerProxy* handler,
+ bool had_interacted_form) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!IsCurrentlyLinkedHandler(handler))
return;
diff --git a/chromium/components/autofill/android/provider/autofill_provider_android.h b/chromium/components/autofill/android/provider/autofill_provider_android.h
index 5ed22d4e6ae..618517ca585 100644
--- a/chromium/components/autofill/android/provider/autofill_provider_android.h
+++ b/chromium/components/autofill/android/provider/autofill_provider_android.h
@@ -56,7 +56,8 @@ class AutofillProviderAndroid : public AutofillProvider {
const FormData& form,
bool known_success,
mojom::SubmissionSource source) override;
- void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
+ void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) override;
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
@@ -99,13 +100,12 @@ class AutofillProviderAndroid : public AutofillProvider {
gfx::RectF ToClientAreaBound(const gfx::RectF& bounding_box);
- bool ShouldStartNewSession(AutofillHandlerProxy* handler,
- const FormData& form);
-
- void StartNewSession(AutofillHandlerProxy* handler,
- const FormData& form,
- const FormFieldData& field,
- const gfx::RectF& bounding_box);
+ // Starts a new session, but only if |form| or |handler| doesn't match the
+ // current session.
+ void MaybeStartNewSession(AutofillHandlerProxy* handler,
+ const FormData& form,
+ const FormFieldData& field,
+ const gfx::RectF& bounding_box);
void Reset();
diff --git a/chromium/components/autofill/android/provider/form_data_android.h b/chromium/components/autofill/android/provider/form_data_android.h
index 8882a788673..96002f62c94 100644
--- a/chromium/components/autofill/android/provider/form_data_android.h
+++ b/chromium/components/autofill/android/provider/form_data_android.h
@@ -54,7 +54,7 @@ class FormDataAndroid {
void ApplyHeuristicFieldType(const FormStructure& form);
- const FormData& form_for_testing() { return form_; }
+ const FormData& form() { return form_; }
private:
// Same as the form passed in from constructor, but FormFieldData's bounds is
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
index b9b4da26a6b..e92fdb19c61 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
@@ -14,11 +14,11 @@ import android.view.autofill.AutofillValue;
import androidx.annotation.VisibleForTesting;
+import org.chromium.base.CollectionUtil;
import org.chromium.base.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
/**
* The class to call Android's AutofillManager.
@@ -158,25 +158,9 @@ public class AutofillManagerWrapper {
mInputUIObservers.add(new WeakReference<InputUIObserver>(observer));
}
- public void removeInputUIObserver(InputUIObserver observer) {
- if (observer == null) return;
- for (Iterator<WeakReference<InputUIObserver>> i = mInputUIObservers.listIterator();
- i.hasNext();) {
- WeakReference<InputUIObserver> o = i.next();
- if (o.get() == null || o.get() == observer) i.remove();
- }
- }
-
@VisibleForTesting
public void notifyInputUIChange() {
- for (Iterator<WeakReference<InputUIObserver>> i = mInputUIObservers.listIterator();
- i.hasNext();) {
- WeakReference<InputUIObserver> o = i.next();
- InputUIObserver observer = o.get();
- if (observer == null) {
- i.remove();
- continue;
- }
+ for (InputUIObserver observer : CollectionUtil.strengthen(mInputUIObservers)) {
observer.onInputUIShown();
}
}
diff --git a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
index 1546b3dca28..226f0dc55a7 100644
--- a/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ b/chromium/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -29,6 +29,7 @@ import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.annotations.VerifiesOnO;
import org.chromium.base.metrics.ScopedSysTraceEvent;
import org.chromium.components.version_info.VersionConstants;
+import org.chromium.content_public.browser.RenderCoordinates;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsAccessibility;
import org.chromium.ui.DropdownItem;
@@ -715,8 +716,16 @@ public class AutofillProvider {
return mDatalistPopup;
}
+ private Rect transformToWindowBounds(RectF rect) {
+ // Refer to crbug.com/1085294 for the reason of offset.
+ // The current version of Mockito didn't support mock static method, adding extra method so
+ // the transform can be tested.
+ return transformToWindowBoundsWithOffsetY(
+ rect, RenderCoordinates.fromWebContents(mWebContents).getContentOffsetYPixInt());
+ }
+
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public Rect transformToWindowBounds(RectF rect) {
+ public Rect transformToWindowBoundsWithOffsetY(RectF rect, int offsetY) {
// Convert bounds to device pixel.
WindowAndroid windowAndroid = mWebContents.getTopLevelNativeWindow();
DisplayAndroid displayAndroid = windowAndroid.getDisplay();
@@ -726,6 +735,7 @@ public class AutofillProvider {
matrix.setScale(dipScale, dipScale);
int[] location = new int[2];
mContainerView.getLocationOnScreen(location);
+ location[1] += offsetY;
matrix.postTranslate(location[0], location[1]);
matrix.mapRect(bounds);
return new Rect(
diff --git a/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
index 7b017f0c419..5d63ae0630b 100644
--- a/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
+++ b/chromium/components/autofill/android/provider/junit/src/org/chromium/components/autofill/AutofillProviderTest.java
@@ -106,10 +106,11 @@ public class AutofillProviderTest {
@Test
public void testTransformToWindowBounds() {
RectF source = new RectF(10, 20, 300, 400);
- Rect result = mAutofillProvider.transformToWindowBounds(source);
+ final int offsetY = 10;
+ Rect result = mAutofillProvider.transformToWindowBoundsWithOffsetY(source, offsetY);
assertEquals(10 * EXPECTED_DIP_SCALE + LOCATION_X, result.left, 0);
- assertEquals(20 * EXPECTED_DIP_SCALE + LOCATION_Y, result.top, 0);
+ assertEquals(20 * EXPECTED_DIP_SCALE + LOCATION_Y + offsetY, result.top, 0);
assertEquals(300 * EXPECTED_DIP_SCALE + LOCATION_X, result.right, 0);
- assertEquals(400 * EXPECTED_DIP_SCALE + LOCATION_Y, result.bottom, 0);
+ assertEquals(400 * EXPECTED_DIP_SCALE + LOCATION_Y + offsetY, result.bottom, 0);
}
}
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index c657114d28a..3c37af33dac 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -287,8 +287,8 @@ void ContentAutofillDriver::HidePopup() {
autofill_handler_->OnHidePopup();
}
-void ContentAutofillDriver::FocusNoLongerOnForm() {
- autofill_handler_->OnFocusNoLongerOnForm();
+void ContentAutofillDriver::FocusNoLongerOnForm(bool had_interacted_form) {
+ autofill_handler_->OnFocusNoLongerOnForm(had_interacted_form);
}
void ContentAutofillDriver::FocusOnFormField(const FormData& form,
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 1a8df440236..efa287202f4 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -128,7 +128,7 @@ class ContentAutofillDriver : public AutofillDriver,
const gfx::RectF& bounding_box,
bool autoselect_first_suggestion) override;
void HidePopup() override;
- void FocusNoLongerOnForm() override;
+ void FocusNoLongerOnForm(bool had_interacted_form) override;
void FocusOnFormField(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 1906bc92438..3862c76d670 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -25,7 +25,6 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/frame_navigate_params.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index e23505a78d0..994561d81ae 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -20,7 +20,7 @@
#include "base/cpu.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
@@ -221,8 +221,9 @@ class FingerprintDataLoader : public content::GpuDataManagerObserver {
// Ensures that any observer registrations for the GPU data are cleaned up by
// the time this object is destroyed.
- ScopedObserver<content::GpuDataManager, content::GpuDataManagerObserver>
- gpu_observer_{this};
+ base::ScopedObservation<content::GpuDataManager,
+ content::GpuDataManagerObserver>
+ gpu_observation_{this};
// Data that will be passed on to the next loading phase. See the comment for
// GetFingerprint() for a description of these variables.
@@ -295,7 +296,7 @@ FingerprintDataLoader::FingerprintDataLoader(
// Load GPU data if needed.
if (gpu_data_manager_->GpuAccessAllowed(nullptr) &&
!gpu_data_manager_->IsEssentialGpuInfoAvailable()) {
- gpu_observer_.Add(gpu_data_manager_);
+ gpu_observation_.Observe(gpu_data_manager_);
OnGpuInfoUpdate();
}
@@ -326,7 +327,8 @@ void FingerprintDataLoader::OnGpuInfoUpdate() {
if (!gpu_data_manager_->IsEssentialGpuInfoAvailable())
return;
- gpu_observer_.Remove(gpu_data_manager_);
+ DCHECK(gpu_observation_.IsObservingSource(gpu_data_manager_));
+ gpu_observation_.RemoveObservation();
MaybeFillFingerprint();
}
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index 663ebeaab86..885c1d4206d 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -75,16 +75,17 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
unavailable_screen_bounds_(0, 0, 101, 11) {}
void SetUpOnMainThread() override {
- device::mojom::Geoposition position;
- position.latitude = kLatitude;
- position.longitude = kLongitude;
- position.altitude = kAltitude;
- position.accuracy = kAccuracy;
- position.timestamp = base::Time::UnixEpoch() +
- base::TimeDelta::FromMilliseconds(kGeolocationTime);
+ auto position = device::mojom::Geoposition::New();
+ position->latitude = kLatitude;
+ position->longitude = kLongitude;
+ position->altitude = kAltitude;
+ position->accuracy = kAccuracy;
+ position->timestamp = base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds(kGeolocationTime);
geolocation_overrider_ =
- std::make_unique<device::ScopedGeolocationOverrider>(position);
+ std::make_unique<device::ScopedGeolocationOverrider>(
+ std::move(position));
}
void GetFingerprintTestCallback(base::OnceClosure continuation_callback,
diff --git a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
index 28b90f991f2..28e6bd73674 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
@@ -118,7 +118,7 @@ interface PasswordGenerationAgent {
// Tells the renderer to find a focused element, and if it is a password field
// eligible for generation then to trigger generation by returning
// non-empty PasswordGenerationUIData.
- UserTriggeredGeneratePassword() => (PasswordGenerationUIData? data);
+ TriggeredGeneratePassword() => (PasswordGenerationUIData? data);
// Tells the renderer that a password can be generated on the fields
// identified by |form|.
diff --git a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
index 6807ea2b937..106f0d69d37 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -61,8 +61,12 @@ interface AutofillDriver {
// Instructs the browser to hide the Autofill popup if it is open.
HidePopup();
- // Sent when the current form is no longer focused.
- FocusNoLongerOnForm();
+ // Sent when either (a) focus moves off of any form element, or (b) focus
+ // moves off of the form that the user had previously interacted with to a
+ // different form. |had_interacted_form| indicates whether there was such a
+ // previously-interacted form.
+ // TODO(crbug.com/1140473): Remove need to pass |had_interacted_form|.
+ FocusNoLongerOnForm(bool had_interacted_form);
// Notification that a form field is focused.
FocusOnFormField(FormData form,
@@ -108,6 +112,10 @@ interface PasswordManagerDriver {
// FRAME_DETACHED.
SameDocumentNavigation(SubmissionIndicatorEvent submission_indication_event);
+ // Notification that password form was cleared. This is used as a signal of
+ // a successful submission for change password forms.
+ PasswordFormCleared(FormData form_data);
+
// Sends |log| to browser for displaying to the user. Only strings passed as
// an argument to methods overriding SavePasswordProgressLogger::SendLog may
// become |log|, because those are guaranteed to be sanitized.
diff --git a/chromium/components/autofill/content/renderer/OWNERS b/chromium/components/autofill/content/renderer/OWNERS
index 15f8279c885..39dfee96ce7 100644
--- a/chromium/components/autofill/content/renderer/OWNERS
+++ b/chromium/components/autofill/content/renderer/OWNERS
@@ -1,7 +1,2 @@
-per-file *password*=dvadym@chromium.org
-per-file *password*=kolos@chromium.org
-per-file *password*=vasilii@chromium.org
-
-per-file *username*=dvadym@chromium.org
-per-file *username*=kolos@chromium.org
-per-file *username*=vasilii@chromium.org
+per-file *password*=file://components/password_manager/OWNERS
+per-file *username*=file://components/password_manager/OWNERS
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index c7e7044d8b9..95ff56c0a45 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -40,7 +40,6 @@
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "content/public/common/content_switches.h"
@@ -217,11 +216,9 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
HidePopup();
if (element.IsNull()) {
- if (!last_interacted_form_.IsNull()) {
- // Focus moved away from the last interacted form to somewhere else on
- // the page.
- GetAutofillDriver()->FocusNoLongerOnForm();
- }
+ // Focus moved away from the last interacted form (if any) to somewhere else
+ // on the page.
+ GetAutofillDriver()->FocusNoLongerOnForm(!last_interacted_form_.IsNull());
return;
}
@@ -232,7 +229,7 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
(!input || last_interacted_form_ != input->Form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
- GetAutofillDriver()->FocusNoLongerOnForm();
+ GetAutofillDriver()->FocusNoLongerOnForm(/*had_interacted_form=*/true);
focus_moved_to_new_form = true;
}
@@ -930,6 +927,14 @@ bool AutofillAgent::ShouldSuppressKeyboard(
autofill_assistant_agent_->ShouldSuppressKeyboard());
}
+void AutofillAgent::FormElementReset(const WebFormElement& form) {
+ password_autofill_agent_->InformAboutFormClearing(form);
+}
+
+void AutofillAgent::PasswordFieldReset(const WebInputElement& element) {
+ password_autofill_agent_->InformAboutFieldClearing(element);
+}
+
void AutofillAgent::SelectWasUpdated(
const blink::WebFormControlElement& element) {
// Look for the form and field associated with the select element. If they are
@@ -1106,6 +1111,11 @@ void AutofillAgent::RemoveFormObserver(Observer* observer) {
form_tracker_.RemoveObserver(observer);
}
+void AutofillAgent::TrackAutofilledElement(
+ const blink::WebFormControlElement& element) {
+ form_tracker_.TrackAutofilledElement(element);
+}
+
base::Optional<FormData> AutofillAgent::GetSubmittedForm() const {
if (!last_interacted_form_.IsNull()) {
FormData form;
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index b88c2b490e7..a6d4cbeb9ec 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -34,6 +34,7 @@ namespace blink {
class WebNode;
class WebView;
class WebFormControlElement;
+class WebFormElement;
template <typename T>
class WebVector;
} // namespace blink
@@ -118,6 +119,9 @@ class AutofillAgent : public content::RenderFrameObserver,
void AddFormObserver(Observer* observer);
void RemoveFormObserver(Observer* observer);
+ // Instructs `form_tracker_` to track the autofilled `element`.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
FormTracker* form_tracker_for_testing() { return &form_tracker_; }
void SelectWasUpdated(const blink::WebFormControlElement& element);
@@ -191,6 +195,8 @@ class AutofillAgent : public content::RenderFrameObserver,
const blink::WebFormControlElement& element) override;
bool ShouldSuppressKeyboard(
const blink::WebFormControlElement& element) override;
+ void FormElementReset(const blink::WebFormElement& form) override;
+ void PasswordFieldReset(const blink::WebInputElement& element) override;
void HandleFocusChangeComplete();
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 2ba2414738c..f42cf808f28 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -28,7 +28,6 @@
#include "build/build_config.h"
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/field_data_manager.h"
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index a64c24aa9ae..a4aca1d571a 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -105,9 +105,9 @@ bool IsFormInteresting(const FormData& form, size_t num_editable_elements) {
// If there are no autocomplete attributes, the form needs to have at least
// the required number of editable fields for the prediction routines to be a
// candidate for autofill.
- return num_editable_elements >= MinRequiredFieldsForHeuristics() ||
- num_editable_elements >= MinRequiredFieldsForQuery() ||
- num_editable_elements >= MinRequiredFieldsForUpload() ||
+ return num_editable_elements >= kMinRequiredFieldsForHeuristics ||
+ num_editable_elements >= kMinRequiredFieldsForQuery ||
+ num_editable_elements >= kMinRequiredFieldsForUpload ||
(all_fields_are_passwords &&
num_editable_elements >=
kRequiredFieldsForFormsWithOnlyPasswordFields);
diff --git a/chromium/components/autofill/content/renderer/form_tracker.cc b/chromium/components/autofill/content/renderer/form_tracker.cc
index f4f99702c69..0afae7d2a75 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.cc
+++ b/chromium/components/autofill/content/renderer/form_tracker.cc
@@ -106,6 +106,21 @@ void FormTracker::SelectControlDidChange(const WebFormControlElement& element) {
Observer::ElementChangeSource::SELECT_CHANGED));
}
+void FormTracker::TrackAutofilledElement(const WebFormControlElement& element) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
+ DCHECK(element.IsAutofilled());
+
+ if (ignore_control_changes_)
+ return;
+
+ ResetLastInteractedElements();
+ if (element.Form().IsNull())
+ last_interacted_formless_element_ = element;
+ else
+ last_interacted_form_ = element.Form();
+ TrackElement();
+}
+
void FormTracker::FireProbablyFormSubmittedForTesting() {
FireProbablyFormSubmitted();
}
diff --git a/chromium/components/autofill/content/renderer/form_tracker.h b/chromium/components/autofill/content/renderer/form_tracker.h
index 7498871c373..ea0e7ca31aa 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.h
+++ b/chromium/components/autofill/content/renderer/form_tracker.h
@@ -73,6 +73,11 @@ class FormTracker : public content::RenderFrameObserver {
void TextFieldDidChange(const blink::WebFormControlElement& element);
void SelectControlDidChange(const blink::WebFormControlElement& element);
+ // Tells the tracker to track the autofilled `element`. Since autofilling a
+ // form or field won't trigger the regular *DidChange events, the tracker
+ // won't be notified of this `element` otherwise.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
void set_ignore_control_changes(bool ignore_control_changes) {
ignore_control_changes_ = ignore_control_changes;
}
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.h b/chromium/components/autofill/content/renderer/html_based_username_detector.h
index 5a32cb4a353..ef1c22a4b90 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.h
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.h
@@ -8,7 +8,7 @@
#include <map>
#include <vector>
-#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_input_element.h"
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index 7e4b3154b54..83a970ccad2 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -570,6 +570,11 @@ void PasswordAutofillAgent::UpdateStateForTextChange(
}
}
+void PasswordAutofillAgent::TrackAutofilledElement(
+ const blink::WebFormControlElement& element) {
+ autofill_agent_->TrackAutofilledElement(element);
+}
+
bool PasswordAutofillAgent::FillSuggestion(
const WebFormControlElement& control_element,
const base::string16& username,
@@ -640,6 +645,7 @@ void PasswordAutofillAgent::FillField(WebInputElement* input,
const FieldRendererId input_id(input->UniqueRendererFormControlId());
field_data_manager_->UpdateFieldDataMap(
input_id, credential, FieldPropertiesFlags::kAutofilledOnUserTrigger);
+ TrackAutofilledElement(*input);
}
void PasswordAutofillAgent::FillPasswordFieldAndSave(
@@ -797,19 +803,6 @@ bool PasswordAutofillAgent::ShouldSuppressKeyboard() {
bool PasswordAutofillAgent::TryToShowTouchToFill(
const WebFormControlElement& control_element) {
- // Don't show Touch To Fill if it should only be enabled for insecure origins
- // and we are currently on a potentially trustworthy origin.
- if (base::GetFieldTrialParamByFeatureAsBool(features::kAutofillTouchToFill,
- "insecure-origins-only",
- /*default_value=*/false) &&
- render_frame()
- ->GetWebFrame()
- ->GetDocument()
- .GetSecurityOrigin()
- .IsPotentiallyTrustworthy()) {
- return false;
- }
-
if (touch_to_fill_state_ != TouchToFillState::kShouldShow)
return false;
@@ -1380,6 +1373,51 @@ PasswordAutofillAgent::GetFormDataFromUnownedInputElements() {
&button_titles_cache_);
}
+void PasswordAutofillAgent::InformAboutFormClearing(
+ const WebFormElement& form) {
+ if (!FrameCanAccessPasswordManager())
+ return;
+ for (const auto& element : form.GetFormControlElements()) {
+ FieldRendererId element_id(element.UniqueRendererFormControlId());
+ // Notify PasswordManager if |form| has password fields that have user typed
+ // input or input autofilled on user trigger.
+ if (IsPasswordFieldFilledByUser(element)) {
+ NotifyPasswordManagerAboutClearedForm(form);
+ return;
+ }
+ }
+}
+
+void PasswordAutofillAgent::InformAboutFieldClearing(
+ const WebInputElement& cleared_element) {
+ if (!FrameCanAccessPasswordManager())
+ return;
+ DCHECK(cleared_element.Value().IsEmpty());
+ FieldRendererId field_id(cleared_element.UniqueRendererFormControlId());
+ // Ignore fields that had no user input or autofill on user trigger.
+ if (!field_data_manager_->DidUserType(field_id) &&
+ !field_data_manager_->WasAutofilledOnUserTrigger(field_id)) {
+ return;
+ }
+
+ WebFormElement form = cleared_element.Form();
+ if (form.IsNull()) {
+ // Process password field clearing for fields outside the <form> tag.
+ if (auto unowned_form_data = GetFormDataFromUnownedInputElements())
+ GetPasswordManagerDriver()->PasswordFormCleared(*unowned_form_data);
+ return;
+ }
+ // Process field clearing for a form under a <form> tag.
+ // Only notify PasswordManager in case all user filled password fields were
+ // cleared.
+ bool cleared_all_password_fields = base::ranges::all_of(
+ form.GetFormControlElements(), [this](const auto& el) {
+ return !IsPasswordFieldFilledByUser(el) || el.Value().IsEmpty();
+ });
+ if (cleared_all_password_fields)
+ NotifyPasswordManagerAboutClearedForm(form);
+}
+
////////////////////////////////////////////////////////////////////////////////
// PasswordAutofillAgent, private:
@@ -1868,4 +1906,24 @@ bool PasswordAutofillAgent::CanShowPopupWithoutPasswords(
IsElementEditable(password_element);
}
+bool PasswordAutofillAgent::IsPasswordFieldFilledByUser(
+ const WebFormControlElement& element) const {
+ FieldRendererId element_id(element.UniqueRendererFormControlId());
+ return element.FormControlTypeForAutofill() == "password" &&
+ (field_data_manager_->DidUserType(element_id) ||
+ field_data_manager_->WasAutofilledOnUserTrigger(element_id));
+}
+
+void PasswordAutofillAgent::NotifyPasswordManagerAboutClearedForm(
+ const WebFormElement& cleared_form) {
+ const auto extract_mask = static_cast<form_util::ExtractMask>(
+ form_util::EXTRACT_VALUE | form_util::EXTRACT_OPTIONS);
+ FormData form_data;
+ if (WebFormElementToFormData(cleared_form, WebFormControlElement(),
+ field_data_manager_.get(), extract_mask,
+ &form_data, nullptr)) {
+ GetPasswordManagerDriver()->PasswordFormCleared(form_data);
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index 3738a1fc7b2..040f7aecada 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -24,7 +24,6 @@
#include "components/autofill/content/renderer/html_based_username_detector.h"
#include "components/autofill/core/common/field_data_manager.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "content/public/renderer/render_frame_observer.h"
@@ -163,6 +162,9 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// shown.
void UpdateStateForTextChange(const blink::WebInputElement& element);
+ // Instructs `autofill_agent_` to track the autofilled `element`.
+ void TrackAutofilledElement(const blink::WebFormControlElement& element);
+
// Fills the username and password fields of this form with the given values.
// Returns true if the fields were filled, false otherwise.
bool FillSuggestion(const blink::WebFormControlElement& control_element,
@@ -221,6 +223,16 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
std::unique_ptr<FormData> GetFormDataFromUnownedInputElements();
+ // Notification that form element was cleared by HTMLFormElement::reset()
+ // method. This can be used as a signal of a successful submission for change
+ // password forms.
+ void InformAboutFormClearing(const blink::WebFormElement& form);
+
+ // Notification that input element was cleared by HTMLInputValue::SetValue()
+ // method by setting an empty value. This can be used as a signal of a
+ // successful submission for change password forms.
+ void InformAboutFieldClearing(const blink::WebInputElement& element);
+
bool logging_state_active() const { return logging_state_active_; }
// Determine whether the current frame is allowed to access the password
@@ -465,6 +477,15 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
bool CanShowPopupWithoutPasswords(
const blink::WebInputElement& password_element) const;
+ // Returns true if the element is of type 'password' and has either user typed
+ // input or input autofilled on user trigger.
+ bool IsPasswordFieldFilledByUser(
+ const blink::WebFormControlElement& element) const;
+
+ // Extracts and sends the form data of |cleared_form| to PasswordManager.
+ void NotifyPasswordManagerAboutClearedForm(
+ const blink::WebFormElement& cleared_form);
+
// The logins we have filled so far with their associated info.
WebInputToPasswordInfoMap web_input_to_password_info_;
// A (sort-of) reverse map to |web_input_to_password_info_|.
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
index 93824cae0bd..81cea7d92e2 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/base/url_util.h"
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
index 07a2ad05095..1685530ea03 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -14,7 +14,6 @@
#include "base/strings/string_piece.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
-#include "components/autofill/core/common/password_form.h"
#include "third_party/blink/public/platform/web_string.h"
#include "url/gurl.h"
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index a87d298ca38..dea5a37779b 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -19,7 +19,6 @@
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/signatures.h"
@@ -232,6 +231,7 @@ void PasswordGenerationAgent::GeneratedPasswordAccepted(
if (!render_frame())
return;
password_element.SetAutofillState(WebAutofillState::kAutofilled);
+ password_agent_->TrackAutofilledElement(password_element);
// Advance focus to the next input field. We assume password fields in
// an account creation form are always adjacent.
render_frame()->GetRenderView()->GetWebView()->AdvanceFocus(false);
@@ -290,10 +290,10 @@ void PasswordGenerationAgent::FoundFormEligibleForGeneration(
}
}
-void PasswordGenerationAgent::UserTriggeredGeneratePassword(
- UserTriggeredGeneratePasswordCallback callback) {
- if (SetUpUserTriggeredGeneration()) {
- LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP);
+void PasswordGenerationAgent::TriggeredGeneratePassword(
+ TriggeredGeneratePasswordCallback callback) {
+ if (SetUpTriggeredGeneration()) {
+ LogMessage(Logger::STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP);
// If the field is not |type=password|, the list of suggestions
// should not be populated with passwords to avoid filling them in a
// clear-text field.
@@ -320,7 +320,7 @@ void PasswordGenerationAgent::UserTriggeredGeneratePassword(
}
}
-bool PasswordGenerationAgent::SetUpUserTriggeredGeneration() {
+bool PasswordGenerationAgent::SetUpTriggeredGeneration() {
if (last_focused_password_element_.IsNull() || !render_frame())
return false;
@@ -493,6 +493,11 @@ bool PasswordGenerationAgent::TextDidChangeInTextField(
*presaved_form_data, generated_password);
}
}
+
+ // Notify `password_agent_` of text changes to the other confirmation
+ // password fields.
+ for (const auto& element : current_generation_item_->password_elements_)
+ password_agent_->UpdateStateForTextChange(element);
}
return true;
}
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.h b/chromium/components/autofill/content/renderer/password_generation_agent.h
index 2eeb0e3044e..37fb76215b0 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.h
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.h
@@ -59,8 +59,8 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
const PasswordFormGenerationData& form) override;
// Sets |generation_element_| to the focused password field and responds back
// if the generation was triggered successfully.
- void UserTriggeredGeneratePassword(
- UserTriggeredGeneratePasswordCallback callback) override;
+ void TriggeredGeneratePassword(
+ TriggeredGeneratePasswordCallback callback) override;
// Returns true if the field being changed is one where a generated password
// is being offered. Updates the state of the popup if necessary.
@@ -110,7 +110,7 @@ class PasswordGenerationAgent : public content::RenderFrameObserver,
// Helper function which takes care of the form processing and collecting the
// information which is required to show the generation popup. Returns true if
// all required information is collected.
- bool SetUpUserTriggeredGeneration();
+ bool SetUpTriggeredGeneration();
// This is called whenever automatic generation could be offered.
// If manual generation was already requested, automatic generation will
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 6c76bdbd609..a747fd5924f 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -55,6 +55,8 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
submission_indication_event) override {}
+ void PasswordFormCleared(const autofill::FormData& form_data) override {}
+
void ShowPasswordSuggestions(base::i18n::TextDirection text_direction,
const base::string16& typed_username,
int options,
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 3447ad7a303..b0dcbce1521 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -25,6 +25,8 @@ static_library("browser") {
"address_normalizer.h",
"address_normalizer_impl.cc",
"address_normalizer_impl.h",
+ "address_profiles/address_profile_save_manager.cc",
+ "address_profiles/address_profile_save_manager.h",
"address_rewriter.cc",
"address_rewriter.h",
"autocomplete_history_manager.cc",
@@ -71,6 +73,10 @@ static_library("browser") {
"autofill_profile_validator.h",
"autofill_provider.cc",
"autofill_provider.h",
+ "autofill_regex_constants.cc",
+ "autofill_regex_constants.h",
+ "autofill_regexes.cc",
+ "autofill_regexes.h",
"autofill_subject.cc",
"autofill_subject.h",
"autofill_type.cc",
@@ -151,6 +157,10 @@ static_library("browser") {
"form_types.h",
"geo/address_i18n.cc",
"geo/address_i18n.h",
+ "geo/alternative_state_name_map.cc",
+ "geo/alternative_state_name_map.h",
+ "geo/alternative_state_name_map_updater.cc",
+ "geo/alternative_state_name_map_updater.h",
"geo/autofill_country.cc",
"geo/autofill_country.h",
"geo/country_data.cc",
@@ -183,6 +193,8 @@ static_library("browser") {
"metrics/form_event_logger_base.cc",
"metrics/form_event_logger_base.h",
"metrics/form_events.h",
+ "pattern_provider/pattern_configuration_parser.cc",
+ "pattern_provider/pattern_configuration_parser.h",
"pattern_provider/pattern_provider.cc",
"pattern_provider/pattern_provider.h",
"payments/account_info_getter.h",
@@ -390,6 +402,7 @@ static_library("browser") {
"//crypto",
"//google_apis",
"//net",
+ "//services/data_decoder/public/cpp:cpp",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
@@ -440,12 +453,16 @@ static_library("test_support") {
"autofill_test_utils.h",
"data_driven_test.cc",
"data_driven_test.h",
+ "geo/alternative_state_name_map_test_utils.cc",
+ "geo/alternative_state_name_map_test_utils.h",
"geo/test_region_data_loader.cc",
"geo/test_region_data_loader.h",
"logging/stub_log_manager.cc",
"logging/stub_log_manager.h",
"mock_autocomplete_history_manager.cc",
"mock_autocomplete_history_manager.h",
+ "pattern_provider/test_pattern_provider.cc",
+ "pattern_provider/test_pattern_provider.h",
"payments/test_authentication_requester.cc",
"payments/test_authentication_requester.h",
"payments/test_credit_card_save_manager.cc",
@@ -576,6 +593,7 @@ source_set("unit_tests") {
sources = [
"address_normalization_manager_unittest.cc",
"address_normalizer_impl_unittest.cc",
+ "address_profiles/address_profile_save_manager_unittest.cc",
"address_rewriter_unittest.cc",
"autocomplete_history_manager_unittest.cc",
"autofill_address_policy_handler_unittest.cc",
@@ -591,6 +609,7 @@ source_set("unit_tests") {
"autofill_profile_sync_util_unittest.cc",
"autofill_profile_validation_util_unittest.cc",
"autofill_profile_validator_unittest.cc",
+ "autofill_regexes_unittest.cc",
"autofill_subject_unittest.cc",
"autofill_type_unittest.cc",
"data_model/address_unittest.cc",
@@ -620,6 +639,8 @@ source_set("unit_tests") {
"form_parsing/search_field_unittest.cc",
"form_structure_unittest.cc",
"geo/address_i18n_unittest.cc",
+ "geo/alternative_state_name_map_unittest.cc",
+ "geo/alternative_state_name_map_updater_unittest.cc",
"geo/autofill_country_unittest.cc",
"geo/country_names_for_locale_unittest.cc",
"geo/country_names_unittest.cc",
@@ -628,6 +649,7 @@ source_set("unit_tests") {
"logging/log_buffer_submitter_unittest.cc",
"logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc",
+ "pattern_provider/pattern_configuration_parser_unittest.cc",
"pattern_provider/pattern_provider_unittest.cc",
"payments/autofill_offer_manager_unittest.cc",
"payments/credit_card_access_manager_unittest.cc",
@@ -727,6 +749,7 @@ source_set("unit_tests") {
"//google_apis",
"//google_apis:test_support",
"//net:test_support",
+ "//services/data_decoder/public/cpp:test_support",
"//services/metrics/public/cpp:ukm_builders",
"//services/network:test_support",
"//services/network/public/cpp",
diff --git a/chromium/components/autofill/core/browser/OWNERS b/chromium/components/autofill/core/browser/OWNERS
index c23e8389686..711aa7cc667 100644
--- a/chromium/components/autofill/core/browser/OWNERS
+++ b/chromium/components/autofill/core/browser/OWNERS
@@ -1,4 +1,2 @@
-parastoog@google.com
-
per-file *type_controller*=jkrcal@chromium.org
per-file *type_controller*=file://components/sync/OWNERS
diff --git a/chromium/components/autofill/core/browser/address_normalization_manager.cc b/chromium/components/autofill/core/browser/address_normalization_manager.cc
index a83ef900e07..708572b38d4 100644
--- a/chromium/components/autofill/core/browser/address_normalization_manager.cc
+++ b/chromium/components/autofill/core/browser/address_normalization_manager.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/address_normalizer.h"
diff --git a/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
index b8a775340c2..e7f89b09415 100644
--- a/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_normalization_manager_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/autofill/core/browser/test_address_normalizer.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl.cc b/chromium/components/autofill/core/browser/address_normalizer_impl.cc
index 85ff881f2fa..335589e92bf 100644
--- a/chromium/components/autofill/core/browser/address_normalizer_impl.cc
+++ b/chromium/components/autofill/core/browser/address_normalizer_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/check_op.h"
#include "base/location.h"
diff --git a/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
index a3c5cfe306a..dc3206e2822 100644
--- a/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_normalizer_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/address_normalizer.h"
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc
new file mode 100644
index 00000000000..4081c68239a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 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/address_profiles/address_profile_save_manager.h"
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+
+namespace autofill {
+
+AddressProfileSaveManager::AddressProfileSaveManager(
+ PersonalDataManager* personal_data_manager)
+ : personal_data_manager_(personal_data_manager) {}
+
+AddressProfileSaveManager::~AddressProfileSaveManager() = default;
+
+std::string AddressProfileSaveManager::SaveProfile(
+ const AutofillProfile& profile) {
+ return personal_data_manager_
+ ? personal_data_manager_->SaveImportedProfile(profile)
+ : std::string();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h
new file mode 100644
index 00000000000..69ac2d01511
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager.h
@@ -0,0 +1,39 @@
+// Copyright 2020 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_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
+
+#include <string>
+
+namespace autofill {
+
+class AutofillProfile;
+class PersonalDataManager;
+
+// Manages logic for saving address profiles to the database. Owned by
+// FormDataImporter.
+class AddressProfileSaveManager {
+ public:
+ explicit AddressProfileSaveManager(
+ PersonalDataManager* personal_data_manager);
+ AddressProfileSaveManager(const AddressProfileSaveManager&) = delete;
+ AddressProfileSaveManager& operator=(const AddressProfileSaveManager&) =
+ delete;
+ virtual ~AddressProfileSaveManager();
+
+ // Saves `imported_profile` using the `personal_data_manager_`. Returns the
+ // guid of the new or updated profile, or the empty string if no profile was
+ // saved.
+ std::string SaveProfile(const AutofillProfile& imported_profile);
+
+ private:
+ // The personal data manager, used to save and load personal data to/from the
+ // web database.
+ PersonalDataManager* const personal_data_manager_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_ADDRESS_PROFILES_ADDRESS_PROFILE_SAVE_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc
new file mode 100644
index 00000000000..b73b0dc35e5
--- /dev/null
+++ b/chromium/components/autofill/core/browser/address_profiles/address_profile_save_manager_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 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/address_profiles/address_profile_save_manager.h"
+
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+class MockPersonalDataManager : public TestPersonalDataManager {
+ public:
+ MockPersonalDataManager() = default;
+ ~MockPersonalDataManager() override = default;
+ MOCK_METHOD(std::string,
+ SaveImportedProfile,
+ (const AutofillProfile&),
+ (override));
+};
+
+} // namespace
+
+TEST(AddressProfileSaveManager, SaveProfile) {
+ MockPersonalDataManager pdm;
+ AddressProfileSaveManager save_manager(&pdm);
+ AutofillProfile test_profile = test::GetFullProfile();
+ EXPECT_CALL(pdm, SaveImportedProfile(test_profile));
+ save_manager.SaveProfile(test_profile);
+}
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
index 2eb1f5540ac..83dbe8e0995 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -5,6 +5,7 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<meta charset="utf-8">
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="autofill_and_password_manager_internals.js"></script>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
index d48f3884ed1..918dd3bfa40 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
@@ -10,6 +10,7 @@
injected by web. -->
<script src="chrome://resources/js/ios/web_ui.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="autofill_and_password_manager_internals.js"></script>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
diff --git a/chromium/components/autofill/core/browser/autofill_data_util.cc b/chromium/components/autofill/core/browser/autofill_data_util.cc
index 21daf5d37ac..d8b5520cfc4 100644
--- a/chromium/components/autofill/core/browser/autofill_data_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_data_util.cc
@@ -185,8 +185,7 @@ bool IsHangulCharacter(UChar32 c) {
// characters or spaces. |name| should already be confirmed to be a CJK name, as
// per |IsCJKName()|.
bool IsHangulName(base::StringPiece16 name) {
- for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(name); !iter.end(); iter.Advance()) {
UChar32 c = iter.get();
if (!IsHangulCharacter(c) && !base::IsUnicodeWhitespace(c)) {
return false;
@@ -367,8 +366,7 @@ bool IsCJKName(base::StringPiece16 name) {
static const base::char16 kMiddleDot = u'\u00B7';
bool previous_was_cjk = false;
size_t word_count = 0;
- for (base::i18n::UTF16CharIterator iter(name.data(), name.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(name); !iter.end(); iter.Advance()) {
UChar32 c = iter.get();
const bool is_cjk = IsCJKCharacter(c);
if (!is_cjk && !base::IsUnicodeWhitespace(c) && c != kKatakanaMiddleDot &&
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 74b0009b7e3..923f8c9071c 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -1341,7 +1341,7 @@ class AutofillServerCommunicationTest
driver_ = std::make_unique<TestAutofillDriver>();
driver_->SetSharedURLLoaderFactory(shared_url_loader_factory_);
driver_->SetIsolationInfo(net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
url::Origin::Create(GURL("https://abc.com")),
url::Origin::Create(GURL("https://xyz.com")), net::SiteForCookies()));
@@ -2062,8 +2062,7 @@ TEST_P(AutofillUploadTest, ThrottlingDisabled) {
// Enabled.
{},
// Disabled
- {features::kAutofillUploadThrottling,
- features::kAutofillEnforceMinRequiredFieldsForUpload});
+ {features::kAutofillUploadThrottling});
FormData form;
FormData small_form;
diff --git a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
index e9f6e3c3c50..23b169a68b2 100644
--- a/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
index 47c3f1bd4a2..7e0893d3adb 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
@@ -4,7 +4,7 @@
#include "components/autofill/core/browser/autofill_experiments.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_metrics.h"
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 5cd990ebb73..6a81dc37934 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -13,7 +13,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_experiments.h"
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index 376f1b8381f..41610aa4482 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -143,6 +143,27 @@ AutofillType AutofillField::ComputedType() const {
believe_server = believe_server &&
!(AutofillType(server_type_).group() == PASSWORD_FIELD &&
heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
+
+ // For new name tokens the heuristic predictions get precedence over the
+ // server predictions.
+ // TODO(crbug.com/1098943): Remove feature check once launched.
+ believe_server =
+ believe_server &&
+ !(base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInNames) &&
+ (heuristic_type_ == NAME_LAST_SECOND ||
+ heuristic_type_ == NAME_LAST_FIRST));
+
+ // For new address tokens the heuristic predictions get precedence over the
+ // server predictions.
+ // TODO(crbug.com/1098943): Remove feature check once launched.
+ believe_server =
+ believe_server &&
+ !(base::FeatureList::IsEnabled(
+ features::kAutofillEnableSupportForMoreStructureInAddresses) &&
+ (heuristic_type_ == ADDRESS_HOME_STREET_NAME ||
+ heuristic_type_ == ADDRESS_HOME_HOUSE_NUMBER));
+
if (believe_server)
return AutofillType(server_type_);
}
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
index 177004fffb2..f8889cfce9f 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -48,6 +48,10 @@ FormFieldData CreateFieldByRole(ServerFieldType role) {
field.label = ASCIIToUTF16("E-mail address");
field.name = ASCIIToUTF16("email");
break;
+ case ServerFieldType::ADDRESS_HOME_LINE1:
+ field.label = ASCIIToUTF16("Address");
+ field.name = ASCIIToUTF16("home_line_one");
+ break;
case ServerFieldType::ADDRESS_HOME_CITY:
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
@@ -84,11 +88,19 @@ FormFieldData CreateFieldByRole(ServerFieldType role) {
return field;
}
-FormData GetFormData(const FormAttributes& form_attributes) {
+FormData GetFormData(const TestFormAttributes& test_form_attributes) {
FormData form_data;
- form_data.url = GURL(form_attributes.form_url);
- for (const FieldDataDescription& field_description : form_attributes.fields) {
+ form_data.url = GURL(test_form_attributes.url);
+ form_data.action = GURL(test_form_attributes.action);
+ form_data.name = ASCIIToUTF16(test_form_attributes.name);
+ static int field_count = 0;
+ if (test_form_attributes.unique_renderer_id)
+ form_data.unique_renderer_id = *test_form_attributes.unique_renderer_id;
+ if (test_form_attributes.main_frame_origin)
+ form_data.main_frame_origin = *test_form_attributes.main_frame_origin;
+ for (const FieldDataDescription& field_description :
+ test_form_attributes.fields) {
FormFieldData field = CreateFieldByRole(field_description.role);
field.form_control_type = field_description.form_control_type;
field.is_focusable = field_description.is_focusable;
@@ -98,11 +110,16 @@ FormData GetFormData(const FormAttributes& form_attributes) {
field.label = ASCIIToUTF16(field_description.label);
if (ASCIIToUTF16(field_description.name) != ASCIIToUTF16(kNameText))
field.name = ASCIIToUTF16(field_description.name);
+ if (field_description.value)
+ field.value = ASCIIToUTF16(*field_description.value);
+ if (field_description.is_autofilled)
+ field.is_autofilled = *field_description.is_autofilled;
+ field.unique_renderer_id = FieldRendererId(field_count++);
field.should_autocomplete = field_description.should_autocomplete;
form_data.fields.push_back(field);
}
- form_data.is_formless_checkout = form_attributes.is_formless_checkout;
- form_data.is_form_tag = form_attributes.is_form_tag;
+ form_data.is_formless_checkout = test_form_attributes.is_formless_checkout;
+ form_data.is_form_tag = test_form_attributes.is_form_tag;
return form_data;
}
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.h b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
index 6ec1180c09c..0c4c9b936c1 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
@@ -26,7 +26,10 @@ constexpr char kLabelText[] = "label";
constexpr char kNameText[] = "name";
// Default form url.
-constexpr char kFormUrl[] = "http://www.foo.com/";
+constexpr char kFormUrl[] = "http://example.com/form.html";
+
+// Default form action url.
+constexpr char kFormActionUrl[] = "http://example.com/submit.html";
} // namespace
@@ -39,17 +42,23 @@ struct FieldDataDescription {
bool is_focusable = true;
const char* label = kLabelText;
const char* name = kNameText;
+ base::Optional<const char*> value = base::nullopt;
const char* autocomplete_attribute = nullptr;
const char* form_control_type = "text";
bool should_autocomplete = true;
+ base::Optional<bool> is_autofilled = base::nullopt;
};
// Attributes provided to the test form.
template <typename = void>
-struct FormAttributes {
- const char* description_for_logging = "";
- std::vector<FieldDataDescription<>> fields = {};
- const char* form_url = kFormUrl;
+struct TestFormAttributes {
+ const char* description_for_logging;
+ std::vector<FieldDataDescription<>> fields;
+ base::Optional<FormRendererId> unique_renderer_id = base::nullopt;
+ const char* name = "TestForm";
+ const char* url = kFormUrl;
+ const char* action = kFormActionUrl;
+ base::Optional<url::Origin> main_frame_origin = base::nullopt;
bool is_formless_checkout = false;
bool is_form_tag = true;
};
@@ -57,7 +66,7 @@ struct FormAttributes {
// Flags determining whether the corresponding check should be run on the test
// form.
template <typename = void>
-struct FormFlags {
+struct TestFormFlags {
// false means the function is not to be called.
bool determine_heuristic_type = false;
bool parse_query_response = false;
@@ -90,15 +99,15 @@ struct ExpectedFieldTypeValues {
// Describes a test case for the parser.
template <typename = void>
struct FormStructureTestCase {
- FormAttributes<> form_attributes;
- FormFlags<> form_flags;
+ TestFormAttributes<> form_attributes;
+ TestFormFlags<> form_flags;
ExpectedFieldTypeValues<> expected_field_types;
};
} // namespace internal
using FieldDataDescription = internal::FieldDataDescription<>;
-using FormAttributes = internal::FormAttributes<>;
+using TestFormAttributes = internal::TestFormAttributes<>;
using FormStructureTestCase = internal::FormStructureTestCase<>;
// Describes the |form_data|. Use this in SCOPED_TRACE if other logging
@@ -109,7 +118,7 @@ testing::Message DescribeFormData(const FormData& form_data);
FormFieldData CreateFieldByRole(ServerFieldType role);
// Creates a FormData to be fed to the parser.
-FormData GetFormData(const FormAttributes& form_attributes);
+FormData GetFormData(const TestFormAttributes& test_form_attributes);
class FormStructureTest : public testing::Test {
protected:
diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc
index c7474a25dfa..b8f647955ae 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler.cc
@@ -30,6 +30,10 @@ const size_t kAutofillHandlerMaxFormCacheSize = 100;
// if not found.
AutofillField* FindAutofillFillField(const FormStructure& form,
const FormFieldData& field) {
+ for (const auto& f : form) {
+ if (field.unique_renderer_id == f->unique_renderer_id)
+ return f.get();
+ }
for (const auto& cur_field : form) {
if (cur_field->SameFieldAs(field)) {
return cur_field.get();
@@ -99,17 +103,11 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
// code would have ignored the cache hit we update the FormStructure's
// FormSignature.
// Otherwise, if the experiment disabled, we just ignore the cache hit.
- //
- // TODO(crbug.com/1100231) Clean up when experiment is complete.
- const bool kOldBehavior = !base::FeatureList::IsEnabled(
- features::kAutofillKeepInitialFormValuesInCache);
bool update_form_signature = false;
if (cached_form_structure) {
for (const FormType& form_type : cached_form_structure->GetFormTypes()) {
if (form_type != CREDIT_CARD_FORM) {
update_form_signature = true;
- if (kOldBehavior)
- cached_form_structure = nullptr;
break;
}
}
@@ -120,7 +118,7 @@ void AutofillHandler::OnFormsSeen(const std::vector<FormData>& forms,
continue;
DCHECK(form_structure);
- if (update_form_signature && !kOldBehavior)
+ if (update_form_signature)
form_structure->set_form_signature(CalculateFormSignature(form));
new_forms.push_back(&form);
diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h
index d476cd02d5a..18b7d0b42c3 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.h
+++ b/chromium/components/autofill/core/browser/autofill_handler.h
@@ -89,8 +89,9 @@ class AutofillHandler {
void OnFormsSeen(const std::vector<FormData>& forms,
const base::TimeTicks timestamp);
- // Invoked when focus is no longer on form.
- virtual void OnFocusNoLongerOnForm() = 0;
+ // Invoked when focus is no longer on form. |had_interacted_form| indicates
+ // whether focus was previously on a form with which the user had interacted.
+ virtual void OnFocusNoLongerOnForm(bool had_interacted_form) = 0;
// Invoked when |form| has been filled with the value given by
// SendFormDataToRenderer.
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
index 4a917d09f4b..41fd6d405e2 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -74,8 +74,8 @@ void AutofillHandlerProxy::OnFormsParsed(
const std::vector<const FormData*>& form_structures,
const base::TimeTicks timestamp) {}
-void AutofillHandlerProxy::OnFocusNoLongerOnForm() {
- provider_->OnFocusNoLongerOnForm(this);
+void AutofillHandlerProxy::OnFocusNoLongerOnForm(bool had_interacted_form) {
+ provider_->OnFocusNoLongerOnForm(this, had_interacted_form);
}
void AutofillHandlerProxy::OnDidFillAutofillFormData(
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
index 741b30da102..8d2f0287888 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
@@ -20,7 +20,7 @@ class AutofillHandlerProxy : public AutofillHandler {
AutofillProvider* provider);
~AutofillHandlerProxy() override;
- void OnFocusNoLongerOnForm() override;
+ void OnFocusNoLongerOnForm(bool had_interacted_form) override;
void OnDidFillAutofillFormData(const FormData& form,
const base::TimeTicks timestamp) override;
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index a9dd2e727dd..9f4f5f3688e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -451,7 +451,9 @@ AutofillManager::FillingContext::FillingContext(
*optional_credit_card,
optional_cvc ? *optional_cvc : base::string16()))
: base::nullopt),
- filled_field_name(field.unique_name()),
+ filled_field_renderer_id(field.unique_renderer_id),
+ filled_field_signature(field.GetFieldSignature()),
+ filled_field_unique_name(field.unique_name()),
original_fill_time(AutofillTickClock::NowTicks()) {
DCHECK(optional_profile || optional_credit_card);
DCHECK(optional_credit_card || !optional_cvc);
@@ -1137,7 +1139,13 @@ void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
/*query_id=*/-1, form, field, profile);
}
-void AutofillManager::OnFocusNoLongerOnForm() {
+void AutofillManager::OnFocusNoLongerOnForm(bool had_interacted_form) {
+ // For historical reasons, Chrome takes action on this message only if focus
+ // was previously on a form with which the user had interacted.
+ // TODO(crbug.com/1140473): Remove need for this short-circuit.
+ if (!had_interacted_form)
+ return;
+
ProcessPendingFormForUpload();
#if defined(OS_CHROMEOS)
@@ -1607,7 +1615,8 @@ void AutofillManager::Reset() {
credit_card_action_ = AutofillDriver::FORM_DATA_ACTION_PREVIEW;
initial_interaction_timestamp_ = TimeTicks();
external_delegate_->Reset();
- filling_contexts_map_.clear();
+ filling_context_by_renderer_id_.clear();
+ filling_context_by_unique_name_.clear();
}
AutofillManager::AutofillManager(
@@ -1739,9 +1748,9 @@ void AutofillManager::FillOrPreviewDataModelForm(
DCHECK_EQ(form_structure->field_count(), form.fields.size());
if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) {
- filling_contexts_map_[form_structure->GetIdentifierForRefill()] =
- std::make_unique<FillingContext>(*autofill_field, optional_profile,
- optional_credit_card, optional_cvc);
+ SetFillingContext(*form_structure, std::make_unique<FillingContext>(
+ *autofill_field, optional_profile,
+ optional_credit_card, optional_cvc));
}
// Only record the types that are filled for an eventual refill if all the
@@ -1750,11 +1759,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
// A form with the given name is already filled.
// A refill has not been attempted for that form yet.
// This fill is not a refill attempt.
- FillingContext* filling_context = nullptr;
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
- if (itr != filling_contexts_map_.end())
- filling_context = itr->second.get();
+ FillingContext* filling_context = GetFillingContext(*form_structure);
bool could_attempt_refill = filling_context != nullptr &&
!filling_context->attempted_refill && !is_refill;
@@ -2094,10 +2099,8 @@ void AutofillManager::OnFormsParsed(const std::vector<const FormData*>& forms,
// been a refill attempt on that form yet, start the process of triggering a
// refill.
if (ShouldTriggerRefill(*form_structure)) {
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
- DCHECK(itr != filling_contexts_map_.end());
- FillingContext* filling_context = itr->second.get();
+ FillingContext* filling_context = GetFillingContext(*form_structure);
+ DCHECK(filling_context != nullptr);
// If a timer for the refill was already running, it means the form
// changed again. Stop the timer and start it again.
@@ -2464,18 +2467,44 @@ void AutofillManager::FillFieldWithValue(AutofillField* autofill_field,
}
}
+// TODO(crbug/896689): Remove code duplication once experiment is finished.
+void AutofillManager::SetFillingContext(
+ const FormStructure& form,
+ std::unique_ptr<FillingContext> context) {
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds)) {
+ filling_context_by_renderer_id_[form.unique_renderer_id()] =
+ std::move(context);
+ } else {
+ filling_context_by_unique_name_[form.GetIdentifierForRefill()] =
+ std::move(context);
+ }
+}
+
+// TODO(crbug/896689): Remove code duplication once experiment is finished.
+AutofillManager::FillingContext* AutofillManager::GetFillingContext(
+ const FormStructure& form) {
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds)) {
+ auto it = filling_context_by_renderer_id_.find(form.unique_renderer_id());
+ return it != filling_context_by_renderer_id_.end() ? it->second.get()
+ : nullptr;
+ } else {
+ auto it =
+ filling_context_by_unique_name_.find(form.GetIdentifierForRefill());
+ return it != filling_context_by_unique_name_.end() ? it->second.get()
+ : nullptr;
+ }
+}
+
bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) {
- // Should not refill if a form with the same name has not been filled
- // before.
- auto itr =
- filling_contexts_map_.find(form_structure.GetIdentifierForRefill());
- if (itr == filling_contexts_map_.end())
+ // Should not refill if a form with the same FormRendererId has not been
+ // filled before.
+ FillingContext* filling_context = GetFillingContext(form_structure);
+ if (filling_context == nullptr)
return false;
address_form_event_logger_->OnDidSeeFillableDynamicForm(sync_state_,
form_structure);
- FillingContext* filling_context = itr->second.get();
base::TimeTicks now = AutofillTickClock::NowTicks();
base::TimeDelta delta = now - filling_context->original_fill_time;
@@ -2499,16 +2528,14 @@ void AutofillManager::TriggerRefill(const FormData& form) {
address_form_event_logger_->OnDidRefill(sync_state_, *form_structure);
- auto itr =
- filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
+ FillingContext* filling_context = GetFillingContext(*form_structure);
// Since GetIdentifierForRefill() is not stable across dynamic changes,
- // |filling_contexts_map_| may not contain the element anymore.
- if (itr == filling_contexts_map_.end())
+ // |filling_context_by_unique_name_| may not contain the element anymore.
+ // TODO(crbug/896689): Can be replaced with DCHECK once experiment is over.
+ if (filling_context == nullptr)
return;
- FillingContext* filling_context = itr->second.get();
-
// The refill attempt can happen from different paths, some of which happen
// after waiting for a while. Therefore, although this condition has been
// checked prior to calling TriggerRefill, it may not hold, when we get
@@ -2519,14 +2546,44 @@ void AutofillManager::TriggerRefill(const FormData& form) {
filling_context->attempted_refill = true;
// Try to find the field from which the original field originated.
+ // Precedence is given to look up by |filled_field_renderer_id|.
+ // If that is unsuccessful, look up is done by |filled_field_signature|.
+ // TODO(crbug/896689): Clean up after feature launch.
AutofillField* autofill_field = nullptr;
for (const std::unique_ptr<AutofillField>& field : *form_structure) {
- if (field->unique_name() == filling_context->filled_field_name) {
+ // TODO(crbug/896689): Clean up once experiment is over.
+ if ((base::FeatureList::IsEnabled(
+ features::kAutofillRefillWithRendererIds) &&
+ field->unique_renderer_id ==
+ filling_context->filled_field_renderer_id) ||
+ (!base::FeatureList::IsEnabled(
+ features::kAutofillRefillWithRendererIds) &&
+ field->unique_name() == filling_context->filled_field_unique_name)) {
autofill_field = field.get();
break;
}
}
+ // If the field was deleted, look for one with a matching signature. Prefer
+ // visible and newer fields over invisible or older ones.
+ if (base::FeatureList::IsEnabled(features::kAutofillRefillWithRendererIds) &&
+ autofill_field == nullptr) {
+ auto is_better = [](const AutofillField& f, const AutofillField& g) {
+ return std::forward_as_tuple(f.IsVisible(),
+ f.unique_renderer_id.value()) >
+ std::forward_as_tuple(g.IsVisible(), g.unique_renderer_id.value());
+ };
+
+ for (const std::unique_ptr<AutofillField>& field : *form_structure) {
+ if (field->GetFieldSignature() ==
+ filling_context->filled_field_signature) {
+ if (autofill_field == nullptr || is_better(*field, *autofill_field)) {
+ autofill_field = field.get();
+ }
+ }
+ }
+ }
+
// If it was not found cancel the refill.
if (!autofill_field)
return;
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index fc6e8bc4714..d2cecaf5e00 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -217,7 +217,7 @@ class AutofillManager : public AutofillHandler,
void DidSuppressPopup(const FormData& form, const FormFieldData& field);
// AutofillHandler:
- void OnFocusNoLongerOnForm() override;
+ void OnFocusNoLongerOnForm(bool had_interacted_form) override;
void OnFocusOnFormFieldImpl(const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
@@ -388,6 +388,9 @@ class AutofillManager : public AutofillHandler,
// Exposed for testing.
bool is_rich_query_enabled() const { return is_rich_query_enabled_; }
+ // Exposed for testing.
+ FormData* pending_form_data() { return pending_form_data_.get(); }
+
private:
// Keeps track of the filling context for a form, used to make refill attemps.
struct FillingContext {
@@ -406,8 +409,12 @@ class AutofillManager : public AutofillHandler,
// empty.
const base::Optional<AutofillProfile> profile;
const base::Optional<std::pair<CreditCard, base::string16>> credit_card;
- // The name of the field that was initially filled.
- const base::string16 filled_field_name;
+ // Possible identifiers of the field that was focused when the form was
+ // initially filled. A refill shall be triggered from the same field.
+ // TODO(crbug/896689): Remove |filled_field_unique_name|.
+ const FieldRendererId filled_field_renderer_id;
+ const FieldSignature filled_field_signature;
+ const base::string16 filled_field_unique_name;
// The time at which the initial fill occurred.
const base::TimeTicks original_fill_time;
// The timer used to trigger a refill.
@@ -582,7 +589,14 @@ class AutofillManager : public AutofillHandler,
uint32_t profile_form_bitmask,
std::string* failure_to_fill);
- // Whether there should be an attemps to refill the form. Returns true if all
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ void SetFillingContext(const FormStructure& form,
+ std::unique_ptr<FillingContext> context);
+
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ FillingContext* GetFillingContext(const FormStructure& form);
+
+ // Whether there should be an attempts to refill the form. Returns true if all
// the following are satisfied:
// There have been no refill on that page yet.
// A non empty form name was recorded in a previous fill
@@ -618,6 +632,7 @@ class AutofillManager : public AutofillHandler,
void SetDataList(const std::vector<base::string16>& values,
const std::vector<base::string16>& labels);
+
AutofillClient* const client_;
LogManager* log_manager_;
@@ -714,8 +729,11 @@ class AutofillManager : public AutofillHandler,
// A map of form names to FillingContext instances used to make refill
// attempts for dynamic forms.
+ // TODO(crbug/896689): Remove code duplication once experiment is finished.
+ std::map<FormRendererId, std::unique_ptr<FillingContext>>
+ filling_context_by_renderer_id_;
std::map<base::string16, std::unique_ptr<FillingContext>>
- filling_contexts_map_;
+ filling_context_by_unique_name_;
// Tracks whether or not rich query encoding is enabled for this client.
const bool is_rich_query_enabled_ = false;
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 7d296d95b25..d801bda0abb 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -37,6 +37,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -94,9 +95,6 @@ using testing::UnorderedElementsAre;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using features::kAutofillRestrictUnownedFieldsToFormlessCheckout;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -637,6 +635,7 @@ class AutofillManagerTest : public testing::Test {
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
base::test::ScopedFeatureList scoped_feature_list_;
TestStrikeDatabase* strike_database_;
+ TestPatternProvider test_pattern_provider_;
private:
int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
@@ -953,9 +952,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
// them have an autocomplete attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_NoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -987,9 +983,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
// suggestions are only made for the one that has the attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_WithOneAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -1018,86 +1011,11 @@ TEST_P(AutofillManagerStructuredProfileTest,
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
-// Test that suggestions are returned by default when there are less than
-// three fields and none of them have an autocomplete attribute.
-TEST_P(AutofillManagerStructuredProfileTest,
- GetProfileSuggestions_NoMinFieldsEnforced_NoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("https://myform.com/form.html");
- form.action = GURL("https://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("First Name", "firstname", "", "text", &field);
- form.fields.push_back(field);
- test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- // Ensure that autocomplete manager is called for both fields.
- EXPECT_CALL(*(autocomplete_history_manager_.get()),
- OnGetAutocompleteSuggestions)
- .Times(0);
-
- GetAutofillSuggestions(form, form.fields[0]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Charles", "Charles Hardin Holley", "", 1),
- Suggestion("Elvis", "Elvis Aaron Presley", "", 2));
-
- GetAutofillSuggestions(form, form.fields[1]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Holley", "Charles Hardin Holley", "", 1),
- Suggestion("Presley", "Elvis Aaron Presley", "", 2));
-}
-
-// Test that for form with two fields with one that has an autocomplete
-// attribute, suggestions are made for both if small form support is enabled
-// (no minimum number of fields enforced).
-TEST_P(AutofillManagerStructuredProfileTest,
- GetProfileSuggestions_NoMinFieldsEnforced_WithOneAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- form.url = GURL("https://myform.com/form.html");
- form.action = GURL("https://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("First Name", "firstname", "", "text", &field);
- field.autocomplete_attribute = "given-name";
- form.fields.push_back(field);
- test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
- field.autocomplete_attribute = "";
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- GetAutofillSuggestions(form, form.fields[0]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Charles", "Charles Hardin Holley", "", 1),
- Suggestion("Elvis", "Elvis Aaron Presley", "", 2));
-
- GetAutofillSuggestions(form, form.fields[1]);
- CheckSuggestions(kDefaultPageID,
- Suggestion("Holley", "Charles Hardin Holley", "", 1),
- Suggestion("Presley", "Elvis Aaron Presley", "", 2));
-}
-
// Test that for a form with two fields with autocomplete attributes,
// suggestions are made for both fields. This is true even if a minimum number
// of fields is enforced.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_SmallFormWithTwoAutocomplete) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForHeuristics);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
@@ -2123,6 +2041,79 @@ TEST_P(AutofillManagerStructuredProfileTest,
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
+// Test that the correct section is filled.
+TEST_F(AutofillManagerTest, FillTriggeredSection) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ size_t index_of_trigger_field = form.fields.size();
+ test::CreateTestAddressFormData(&form);
+ FormsSeen({form});
+
+ // Check that the form has been parsed into two sections.
+ ASSERT_NE(form.fields.size(), 0u);
+ ASSERT_EQ(index_of_trigger_field, form.fields.size() / 2);
+ {
+ FormStructure* form_structure;
+ AutofillField* autofill_field;
+ bool found = autofill_manager_->GetCachedFormAndField(
+ form, form.fields[index_of_trigger_field], &form_structure,
+ &autofill_field);
+ ASSERT_TRUE(found);
+ for (size_t i = 0; i < form.fields.size() / 2; ++i) {
+ size_t j = form.fields.size() / 2 + i;
+ ASSERT_EQ(form_structure->field(i)->name, form_structure->field(j)->name);
+ ASSERT_NE(form_structure->field(i)->section,
+ form_structure->field(j)->section);
+ ASSERT_TRUE(form_structure->field(i)->SameFieldAs(form.fields[j]));
+ ASSERT_TRUE(form_structure->field(j)->SameFieldAs(form.fields[i]));
+ }
+ }
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
+ ASSERT_TRUE(profile);
+ EXPECT_EQ(1U, profile->use_count());
+ EXPECT_NE(base::Time(), profile->use_date());
+
+ int response_page_id = 0;
+ FormData response_data;
+ FillAutofillFormDataAndSaveResults(
+ kDefaultPageID, form, form.fields[index_of_trigger_field],
+ MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
+ // Extract the sections into individual forms to reduce boiler plate code.
+ size_t mid = response_data.fields.size() / 2;
+ FormData section1 = response_data;
+ FormData section2 = response_data;
+ section1.fields.erase(section1.fields.begin() + mid, section1.fields.end());
+ section2.fields.erase(section2.fields.begin(), section2.fields.end() - mid);
+ // First section should be empty, second should be filled.
+ ExpectFilledForm(response_page_id, section1, kDefaultPageID, "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "", "", true, false,
+ false);
+ ExpectFilledAddressFormElvis(response_page_id, section2, kDefaultPageID,
+ false);
+}
+
+// Tests that AutofillManager ignores loss of focus events sent from the
+// renderer if the renderer did not have a previously-interacted form.
+// TODO(crbug.com/1140473): Remove this test when workaround is no longer
+// needed.
+TEST_F(AutofillManagerTest,
+ ShouldIgnoreLossOfFocusWithNoPreviouslyInteractedForm) {
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+
+ autofill_manager_->UpdatePendingForm(form);
+ ASSERT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
+
+ // Receiving a notification that focus is no longer on the form *without* the
+ // renderer having a previously-interacted form should not result in
+ // any changes to the pending form.
+ autofill_manager_->OnFocusNoLongerOnForm(/*had_interacted_form=*/false);
+ EXPECT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
+}
+
TEST_F(AutofillManagerTest,
ShouldNotShowCreditCardsSuggestionsIfCreditCardAutofillDisabled) {
DisableCreditCardAutofill();
@@ -6484,7 +6475,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
- autofill_manager_->OnFocusNoLongerOnForm();
+ autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that navigating with a filled form sends an upload with types matching
@@ -6589,7 +6580,7 @@ TEST_P(AutofillManagerStructuredProfileTest,
AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
- autofill_manager_->OnFocusNoLongerOnForm();
+ autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that suggestions are returned for credit card fields with an
@@ -7291,60 +7282,18 @@ TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
test::CreateTestFormField("Name", "name", "", "text", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Add a second field to the form.
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has less than 3 fields but has autocomplete attribute.
form.fields[0].autocomplete_attribute = "given-name";
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
- // With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has more than 3 fields, no autocomplete attribute.
form.fields[0].autocomplete_attribute = "";
@@ -7370,21 +7319,8 @@ TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
test::CreateTestFormField("Password", "password", "", "password", &field);
form.fields.push_back(field);
- // With min required fields enabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
-
// With min required fields disabled.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- features::kAutofillEnforceMinRequiredFieldsForUpload);
- EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
- }
+ EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Autofill disabled.
autofill_manager_->SetAutofillProfileEnabled(false);
@@ -7593,55 +7529,6 @@ TEST_P(AutofillManagerStructuredProfileTest,
}
}
-// Test that with small form upload enabled but heuristics and query disabled
-// we get uploads but not quality metrics.
-TEST_P(AutofillManagerStructuredProfileTest,
- SmallForm_Upload_NoHeuristicsOrQuery) {
- // Setup the feature environment.
- base::test::ScopedFeatureList features;
- features.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery},
- // Disabled.
- {kAutofillEnforceMinRequiredFieldsForUpload});
-
- // Add a local card to allow data matching for upload votes.
- CreditCard credit_card =
- autofill::test::GetRandomCreditCard(CreditCard::LOCAL_CARD);
- personal_data_.AddCreditCard(credit_card);
-
- // Set up the form.
- FormData form;
- form.url = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
- FormFieldData field;
- test::CreateTestFormField("Unknown", "unknown", "", "text", &field);
- form.fields.push_back(field);
-
- // Have the browser encounter the form.
- FormsSeen({form});
-
- // Populate the form with a credit card value.
- form.fields.back().value = credit_card.number();
-
- // Setup expectation on the test autofill manager (these are validated
- // during the simlulated submit).
- autofill_manager_->SetExpectedSubmittedFieldTypes({{CREDIT_CARD_NUMBER}});
- autofill_manager_->SetExpectedObservedSubmission(true);
- autofill_manager_->SetCallParentUploadFormData(true);
- EXPECT_CALL(*download_manager_,
- StartUploadRequest(_, false, _, std::string(), true, _));
-
- base::HistogramTester histogram_tester;
- FormSubmitted(form);
-
- EXPECT_EQ(FormStructure(form).FormSignatureAsStr(),
- autofill_manager_->GetSubmittedFormSignature());
-
- histogram_tester.ExpectTotalCount("Autofill.FieldPrediction.CreditCard", 0);
-}
-
// Test that is_all_server_suggestions is true if there are only
// full_server_card and masked_server_card on file.
TEST_P(AutofillManagerStructuredProfileTest,
@@ -8990,10 +8877,7 @@ class OnFocusOnFormFieldTest : public AutofillManagerTest,
// Enabled
{},
// Disabled
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload,
- kAutofillRestrictUnownedFieldsToFormlessCheckout});
+ {kAutofillRestrictUnownedFieldsToFormlessCheckout});
}
void TearDown() override {
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index b3d84109576..b9da1edcafb 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -26,11 +26,13 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_form_test_utils.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/metrics/address_form_event_logger.h"
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -80,9 +82,6 @@ using ::testing::UnorderedPointwise;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using mojom::SubmissionSource;
using SyncSigninState = AutofillSyncSigninState;
@@ -357,10 +356,6 @@ class AutofillMetricsTest : public testing::Test {
bool include_masked_server_credit_card,
bool include_full_server_credit_card);
- // Creates a masked server card with a nickname, and adds it to existing
- // credit card list.
- void AddMaskedServerCreditCardWithNickname();
-
void AddMaskedServerCreditCardWithOffer(std::string guid,
std::string offer_reward_amount,
GURL url,
@@ -388,6 +383,7 @@ class AutofillMetricsTest : public testing::Test {
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
std::unique_ptr<AutofillExternalDelegate> external_delegate_;
base::test::ScopedFeatureList scoped_feature_list_;
+ TestPatternProvider test_pattern_provider_;
private:
void CreateTestAutofillProfiles();
@@ -562,13 +558,6 @@ void AutofillMetricsTest::RecreateCreditCards(
personal_data_->Refresh();
}
-void AutofillMetricsTest::AddMaskedServerCreditCardWithNickname() {
- CreditCard masked_server_credit_card =
- test::GetMaskedServerCardWithNickname();
- personal_data_->AddServerCreditCard(masked_server_credit_card);
- personal_data_->Refresh();
-}
-
void AutofillMetricsTest::AddMaskedServerCreditCardWithOffer(
std::string guid,
std::string offer_reward_amount,
@@ -640,53 +629,43 @@ INSTANTIATE_TEST_SUITE_P(AutofillMetricsTest,
// Test that we log quality metrics appropriately.
TEST_F(AutofillMetricsTest, QualityMetrics) {
// Set up our form data.
- FormData form;
- form.unique_renderer_id = MakeFormRendererId();
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
- form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley",
- "text", &field);
- field.is_autofilled = true;
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FIRST);
-
- test::CreateTestFormField("Autofill Failed", "autofillfailed",
- "buddy@gmail.com", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_NUMBER);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Empty", "empty", "", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FIRST);
-
- test::CreateTestFormField("Unknown", "unknown", "garbage", "text", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_NUMBER);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Select", "select", "USA", "select-one", &field);
- field.is_autofilled = false;
- form.fields.push_back(field);
- heuristic_types.push_back(UNKNOWN_TYPE);
- server_types.push_back(NO_SERVER_DATA);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field);
- field.is_autofilled = true;
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
+ FormData form =
+ test::GetFormData({.description_for_logging = "QualityMetrics",
+ .fields = {{.label = "Autofilled",
+ .name = "autofilled",
+ .value = "Elvis Aaron Presley",
+ .is_autofilled = true},
+ {.label = "Autofill Failed",
+ .name = "autofillfailed",
+ .value = "buddy@gmail.com",
+ .is_autofilled = false},
+ {.label = "Empty",
+ .name = "empty",
+ .value = "",
+ .is_autofilled = false},
+ {.label = "Unknown",
+ .name = "unknown",
+ .value = "garbage",
+ .is_autofilled = false},
+ {.label = "Select",
+ .name = "select",
+ .value = "USA",
+ .form_control_type = "select-one",
+ .is_autofilled = false},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER,
+ .value = "2345678901",
+ .form_control_type = "tel",
+ .is_autofilled = true}},
+ .unique_renderer_id = MakeFormRendererId(),
+ .main_frame_origin = url::Origin::Create(
+ autofill_client_.form_origin())});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, PHONE_HOME_NUMBER, NAME_FULL,
+ PHONE_HOME_NUMBER, UNKNOWN_TYPE, PHONE_HOME_CITY_AND_NUMBER};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FIRST, EMAIL_ADDRESS, NAME_FIRST,
+ EMAIL_ADDRESS, NO_SERVER_DATA, PHONE_HOME_CITY_AND_NUMBER};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -829,50 +808,31 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
// Test that the ProfileImportStatus logs a no import.
TEST_F(AutofillMetricsTest, ProfileImportStatus_NoImport) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "InvalidState", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "00000000000000000", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "NoACountry", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_NoImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "Invalid State"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP,
+ .value = "00000000000000000"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY,
+ .value = "NoACountry"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -902,50 +862,28 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_NoImport) {
// Test that the ProfileImportStatus logs a regular import.
TEST_F(AutofillMetricsTest, ProfileImportStatus_RegularImport) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_RegularImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -975,54 +913,40 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_RegularImport) {
// Test that the ProfileImportStatus logs a section union mport.
TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- // Assign a specific section.
- field.autocomplete_attribute = "section-billing locality";
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- // Make the state a different section than the city.
- field.autocomplete_attribute = "section-shipping address-level1";
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportStatus_UnionImport",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY,
+ .value = "New York",
+ .autocomplete_attribute = "section-billing locality"},
+ // Add the last field of the form into a new section.
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "CA",
+ .autocomplete_attribute = "section-shipping address-level1"}}});
+
+ // Set the heuristic types.
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE};
+
+ // Set the server types.
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1034,39 +958,16 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
base::HistogramTester histogram_tester;
std::string histogram = "Autofill.AddressProfileImportStatus";
- // Disable the union import feature.
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
- // Simulate form submission.
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
+ // Verify that one profile was imported using the union of the two sections.
histogram_tester.ExpectBucketCount(
histogram,
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT, 0);
histogram_tester.ExpectBucketCount(
histogram, AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT,
- 1);
- histogram_tester.ExpectBucketCount(
- histogram,
- AutofillMetrics::AddressProfileImportStatusMetric::SECTION_UNION_IMPORT,
0);
-
- // Enable the union import feature.
- scoped_feature_list_.Reset();
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
- // Simulate form submission.
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
-
- histogram_tester.ExpectBucketCount(
- histogram,
- AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT, 0);
- histogram_tester.ExpectBucketCount(
- histogram, AutofillMetrics::AddressProfileImportStatusMetric::NO_IMPORT,
- 1);
histogram_tester.ExpectBucketCount(
histogram,
AutofillMetrics::AddressProfileImportStatusMetric::SECTION_UNION_IMPORT,
@@ -1077,50 +978,28 @@ TEST_F(AutofillMetricsTest, ProfileImportStatus_UnionImport) {
// 'perfect' profile import.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportRequirements_AllFulfilled",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1178,49 +1057,28 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_AllFulfilled) {
// ADDRESS_HOME_LINE1 is missing.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_MissingHomeLineOne) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_MissingHomeLineOne",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1280,50 +1138,30 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_MissingHomeLineOne) {
TEST_F(AutofillMetricsTest,
ProfileImportRequirements_AllFulfilledForNonStateCountry) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "Germany", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_AllFulfilledForNonStateCountry",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY,
+ .value = "Germany"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1381,56 +1219,38 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest,
ProfileImportRequirements_FilledButInvalidZipEmailAndState) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "DefNotAState", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "1234567890", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Email1", "email1", "test_noat_test.io", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_FilledButInvalidZipEmailAndState",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = "DefNotAState"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "1234567890"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::EMAIL_ADDRESS,
+ .value = "test_noat_test.io"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS};
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1488,61 +1308,41 @@ TEST_F(AutofillMetricsTest,
// profile with multiple email addresses.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_NonUniqueEmail) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "New York", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "2345678901", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "CA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "37373", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "country", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
-
- test::CreateTestFormField("Email1", "email1", "test@test.io", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
-
- test::CreateTestFormField("Email2", "email2", "not_test@test.io", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(EMAIL_ADDRESS);
- server_types.push_back(EMAIL_ADDRESS);
+ FormData form = test::GetFormData(
+ {.description_for_logging = "ProfileImportRequirements_NonUniqueEmail",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = "New York"},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = "2345678901"},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = "CA"},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = "37373"},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = "USA"},
+ {.role = ServerFieldType::EMAIL_ADDRESS,
+ .value = "test_noat_test.io"},
+ {.label = "Email1",
+ .name = ".email1",
+ .value = "not_test@test.io"}}});
+
+ std::vector<ServerFieldType> heuristic_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ EMAIL_ADDRESS};
+ std::vector<ServerFieldType> server_types = {NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ EMAIL_ADDRESS};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -1600,50 +1400,29 @@ TEST_F(AutofillMetricsTest, ProfileImportRequirements_NonUniqueEmail) {
// missing.
TEST_F(AutofillMetricsTest, ProfileImportRequirements_OnlyAddressLineOne) {
// Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
-
- std::vector<ServerFieldType> heuristic_types, server_types;
- FormFieldData field;
-
- test::CreateTestFormField("Name", "name", "Elvis Aaron Presley", "text",
- &field);
- form.fields.push_back(field);
- heuristic_types.push_back(NAME_FULL);
- server_types.push_back(NAME_FULL);
-
- test::CreateTestFormField("Address", "home_line_one",
- "3734 Elvis Presley Blvd.", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_LINE1);
- server_types.push_back(ADDRESS_HOME_LINE1);
-
- test::CreateTestFormField("City", "city", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_CITY);
- server_types.push_back(ADDRESS_HOME_CITY);
-
- test::CreateTestFormField("Phone", "phone", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
- server_types.push_back(PHONE_HOME_CITY_AND_NUMBER);
-
- test::CreateTestFormField("State", "state", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_STATE);
- server_types.push_back(ADDRESS_HOME_STATE);
-
- test::CreateTestFormField("ZIP", "zip", "", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_ZIP);
- server_types.push_back(ADDRESS_HOME_ZIP);
-
- test::CreateTestFormField("Country", "", "USA", "text", &field);
- form.fields.push_back(field);
- heuristic_types.push_back(ADDRESS_HOME_COUNTRY);
- server_types.push_back(ADDRESS_HOME_COUNTRY);
+ FormData form = test::GetFormData(
+ {.description_for_logging =
+ "ProfileImportRequirements_OnlyAddressLineOne",
+ .fields = {
+ {.role = ServerFieldType::NAME_FULL, .value = "Elvis Aaron Presley"},
+ {.role = ServerFieldType::ADDRESS_HOME_LINE1,
+ .value = "3734 Elvis Presley Blvd."},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY, .value = ""},
+ {.role = ServerFieldType::PHONE_HOME_NUMBER, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_STATE, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP, .value = ""},
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY, .value = ""}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY, PHONE_HOME_CITY_AND_NUMBER,
+ ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY};
// Simulate having seen this form on page load.
autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
@@ -3200,92 +2979,6 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
histogram_tester.ExpectTotalCount("Autofill.UserHappiness.Unknown", 0);
}
-// Verify that when a field is annotated with the autocomplete attribute, its
-// predicted type is remembered when quality metrics are logged.
-TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
- // Allow heuristics to run (and be accepted) for small forms.
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
-
- // Set up our form data. Note that the fields have default values not found
- // in the user profiles. They will be changed between the time the form is
- // seen/parsed, and the time it is submitted.
- FormData form;
- FormFieldData field;
- form.unique_renderer_id = MakeFormRendererId();
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
- form.main_frame_origin =
- url::Origin::Create(GURL("http://example_root.com/form.html"));
-
- test::CreateTestFormField("Select", "select", "USA", "select-one", &field);
- form.fields.push_back(field);
- form.fields.back().autocomplete_attribute = "country";
-
- test::CreateTestFormField("Unknown", "Unknown", "", "text", &field);
- form.fields.push_back(field);
-
- test::CreateTestFormField("Phone", "phone", "", "tel", &field);
- form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
-
- base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
-
- // We change the value of the text fields to change the default/seen values
- // (hence the values are not cleared in UpdateFromCache). The new values
- // match what is in the test profile.
- form.fields[1].value = base::ASCIIToUTF16("79401");
- form.fields[2].value = base::ASCIIToUTF16("2345678901");
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
-
- for (const std::string source : {"Heuristic", "Server", "Overall"}) {
- std::string histogram_name =
- "Autofill.FieldPredictionQuality.ByFieldType." + source;
- // First verify that country was not predicted by client or server.
- {
- SCOPED_TRACE("ADDRESS_HOME_COUNTRY");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_COUNTRY,
- source == "Overall" ? AutofillMetrics::TRUE_POSITIVE
- : AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- }
-
- // We did not predict zip code because it did not have an autocomplete
- // attribute, nor client or server predictions.
- {
- SCOPED_TRACE("ADDRESS_HOME_ZIP");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- ADDRESS_HOME_ZIP, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN),
- 1);
- }
-
- // Phone should have been predicted by the heuristics but not the server.
- {
- SCOPED_TRACE("PHONE_HOME_WHOLE_NUMBER");
- histogram_tester.ExpectBucketCount(
- histogram_name,
- GetFieldTypeGroupPredictionQualityMetric(
- PHONE_HOME_WHOLE_NUMBER,
- source == "Server" ? AutofillMetrics::FALSE_NEGATIVE_UNKNOWN
- : AutofillMetrics::TRUE_POSITIVE),
- 1);
- }
-
- // Sanity check.
- histogram_tester.ExpectTotalCount(histogram_name, 3);
- }
-}
-
// Test that we behave sanely when the cached form differs from the submitted
// one.
TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
@@ -3426,8 +3119,6 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Verify that when submitting a non-autofillable form, the stored profile
// metric is not logged.
TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(kAutofillEnforceMinRequiredFieldsForHeuristics);
// Construct a non-fillable form.
FormData form;
form.unique_renderer_id = MakeFormRendererId();
@@ -3729,19 +3420,6 @@ TEST_F(AutofillMetricsTest, DeveloperEngagement) {
histogram_tester.ExpectTotalCount("Autofill.DeveloperEngagement", 0);
}
- // Otherwise, log developer engagement for all forms.
- {
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- base::HistogramTester histogram_tester;
- autofill_manager_->OnFormsSeen(forms, TimeTicks());
- autofill_manager_->Reset();
- histogram_tester.ExpectUniqueSample(
- "Autofill.DeveloperEngagement",
- AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS, 1);
- }
-
// Add another field to the form, so that it becomes fillable.
test::CreateTestFormField("Phone", "phone", "", "text", &field);
forms.back().fields.push_back(field);
@@ -3827,9 +3505,6 @@ TEST_F(AutofillMetricsTest,
// Ensure no entries are logged when loading a non-fillable form.
{
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
autofill_manager_->Reset();
@@ -3907,14 +3582,6 @@ TEST_F(AutofillMetricsTest,
// Verify that we correctly log UKM for form parsed with type hints regarding
// developer engagement.
TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
FormData form;
form.unique_renderer_id = MakeFormRendererId();
form.name = ASCIIToUTF16("TestForm");
@@ -3930,27 +3597,11 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
test::CreateTestFormField("Payment", "payment", "", "text", &field);
field.autocomplete_attribute = "upi-vpa";
form.fields.push_back(field);
-
- std::vector<FormData> forms(1, form);
-
- // Expect the "upi-vpa hint" metric to be logged and the "form loaded" form
- // interaction event to be logged.
- {
- SCOPED_TRACE("VPA is the only hint");
- autofill_manager_->OnFormsSeen(forms, AutofillTickClock::NowTicks());
-
- VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
- /* UPI VPA has Unknown form type.*/
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
- {AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
- PurgeUKM();
- }
-
- // Add another field with an author-specified field type to the form.
test::CreateTestFormField("", "", "", "text", &field);
field.autocomplete_attribute = "address-line1";
- forms.back().fields.push_back(field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
{
SCOPED_TRACE("VPA and other autocomplete hint present");
@@ -6665,349 +6316,6 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
}
}
-// Test that we log form events for masked server card nickname.
-// TODO(crbug.com/1059087): Remove histogram logging for server nickname.
-TEST_F(AutofillMetricsTest, LogServerNicknameFormEvents) {
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
- form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- FormFieldData field;
- std::vector<ServerFieldType> field_types;
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
- test::CreateTestFormField("Year", "card_year", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_NUMBER);
-
- // Creating all kinds of cards. None of them has nicknames.
- RecreateCreditCards(true /* include_local_credit_card */,
- true /* include_masked_server_credit_card */,
- true /* include_full_server_credit_card */);
-
- // Simulate having seen this form on page load.
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- // Check that the nickname sub-histogram was not recorded.
- // ExpectBucketCount() can't be used here because it expects the histogram
- // to exist.
- EXPECT_EQ(0, histogram_tester.GetTotalCountsForPrefix(
- "Autofill.FormEvents.CreditCard")
- ["Autofill.FormEvents.CreditCard.WithServerNickname"]);
- }
-
- // Add another masked server card with nickname.
- AddMaskedServerCreditCardWithNickname();
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion. Both general
- // histogram and nickname sub-histogram are logged.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Select the local card, still log to sub-histogram because user has
- // another masked servr card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000001");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- // The general credit card form event historgram is still logged.
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- // Sub-histogratm CreditCard.WithServerNickname is also logged
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_LOCAL_SUGGESTION_FILLED, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown, selecting a masked card server suggestion and
- // submitting the form. Verify that all related form events are correctly
- // logged to nickname sub-histogram.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Select the masked server card without nickname, still log to nickname
- // sub-histogram because user has another masked server card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000002");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- OnDidGetRealPan(AutofillClient::SUCCESS, "6011000990139424");
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_INTERACTED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SELECTED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED_ONCE, 1);
- histogram_tester.ExpectBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname",
- FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, 1);
- }
-}
-
-// Test that we log suggestion selection duration for masked server card
-// nickname.
-// TODO(crbug.com/1059087): Remove histogram logging for server nickname.
-TEST_F(AutofillMetricsTest, LogServerNicknameSelectionDuration) {
- base::TimeTicks now = AutofillTickClock::NowTicks();
- TestAutofillTickClock test_clock;
- test_clock.SetNowTicks(now);
-
- // Set up our form data.
- FormData form;
- form.name = ASCIIToUTF16("TestForm");
- form.url = GURL("http://example.com/form.html");
- form.action = GURL("http://example.com/submit.html");
- form.main_frame_origin = url::Origin::Create(autofill_client_.form_origin());
-
- FormFieldData field;
- std::vector<ServerFieldType> field_types;
- test::CreateTestFormField("Month", "card_month", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_MONTH);
- test::CreateTestFormField("Year", "card_year", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_EXP_2_DIGIT_YEAR);
- test::CreateTestFormField("Credit card", "card", "", "text", &field);
- form.fields.push_back(field);
- field_types.push_back(CREDIT_CARD_NUMBER);
-
- // Creating all kinds of cards. None of them have nicknames.
- RecreateCreditCards(true /* include_local_credit_card */,
- true /* include_masked_server_credit_card */,
- true /* include_full_server_credit_card */);
-
- // Simulate having seen this form on page load.
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // No masked server card has nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- // Check that the nickname sub-histogram was not recorded.
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 0);
- }
-
- // Add another masked server card with nickname.
- AddMaskedServerCreditCardWithNickname();
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and filling a local card suggestion.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- // Select the local card, log nickname selection duration because user has
- // another masked servr card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000001");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating activating the autofill popup for the credit card field, new
- // popup being shown and selecting a masked card server suggestion.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion after 1 second.
- base::TimeDelta selection_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + selection_delta);
- // Select the masked server card without nickname, still log select
- // duration, even though GetRealPan fails afterwards, because user has
- // another masked server card with nickname.
- std::string guid("10000000-0000-0000-0000-000000000002");
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE, std::string());
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating suggestions are shown twice, then choosing a local card.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate the first popup was dismissed and the second popup is shown
- // after 1 second.
- base::TimeDelta suggestion_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + suggestion_delta);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate choosing a suggestion on the second popup after 2 seconds.
- // The overall selection duration will be 3 seconds, between the first time
- // suggestion was shown and the first card is chosen.
- base::TimeDelta total_selection_delta =
- suggestion_delta + base::TimeDelta::FromSeconds(2);
- test_clock.SetNowTicks(now + total_selection_delta);
- std::string guid("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- total_selection_delta, 1);
- }
-
- // Reset the autofill manager state.
- autofill_manager_->Reset();
- autofill_manager_->AddSeenForm(form, field_types, field_types);
-
- {
- // A masked server card with nickname.
- // Simulating suggestions being shown and selecting masked server card
- // multiple times.
- base::HistogramTester histogram_tester;
- test_clock.SetNowTicks(now);
- autofill_manager_->OnQueryFormFieldAutofill(
- 0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
- autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- // Simulate the first selection happens 1 second after suggestion is shown.
- base::TimeDelta first_suggestion_delta = base::TimeDelta::FromSeconds(1);
- test_clock.SetNowTicks(now + first_suggestion_delta);
- std::string guid1(
- "10000000-0000-0000-0000-000000000002"); // masked server card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid1, std::string()));
- // Simulate choosing another local card 2 seconds after user chooses the
- // server card.
- base::TimeDelta second_selection_delta =
- first_suggestion_delta + base::TimeDelta::FromSeconds(2);
- test_clock.SetNowTicks(now + second_selection_delta);
- std::string guid2("10000000-0000-0000-0000-000000000001"); // local card
- autofill_manager_->FillOrPreviewForm(
- AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
- autofill_manager_->MakeFrontendIDForTest(guid2, std::string()));
- // The selection duration should be only logged once.
- histogram_tester.ExpectTotalCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- 1);
- // The logged selection duration should be 1 second, between the suggestion
- // was shown and the first card is chosen.
- histogram_tester.ExpectTimeBucketCount(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- first_suggestion_delta, 1);
- }
-}
-
// Test that we log form events for masked server card with offers.
TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
scoped_feature_list_.InitAndEnableFeature(
@@ -8657,45 +7965,6 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Clear out the third field's value.
form.fields[2].value = base::string16();
forms.front() = form;
-
- // This form is non-fillable if small form support is disabled (min number
- // of fields enforced.)
- {
- base::test::ScopedFeatureList features;
- features.InitWithFeatures(
- // Enabled
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery},
- // Disabled
- {});
- base::HistogramTester histogram_tester;
- base::UserActionTester user_action_tester;
- autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION);
- histogram_tester.ExpectUniqueSample(
- "Autofill.FormSubmittedState",
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
- EXPECT_EQ(1, user_action_tester.GetActionCount(
- "Autofill_FormSubmitted_NonFillable"));
-
- expected_form_submission_ukm_metrics.push_back(
- {{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
- AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
- {UkmFormSubmittedType::kIsForCreditCardName, false},
- {UkmFormSubmittedType::kHasUpiVpaFieldName, false},
- {UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
- {UkmFormSubmittedType::kFormSignatureName,
- Collapse(CalculateFormSignature(form)).value()}});
- VerifyUkm(test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
- expected_form_submission_ukm_metrics);
-
- AppendFieldFillStatusUkm(form, &expected_field_fill_status_ukm_metrics);
- VerifyUkm(test_ukm_recorder_, form, UkmFieldFillStatusType::kEntryName,
- expected_field_fill_status_ukm_metrics);
- }
}
// Verify that we correctly log the submitted form's state with fields
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
index 267ad01698e..f82bcdf9778 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -48,6 +48,8 @@ VerificationStatus ConvertSpecificsToProfileVerificationStatus(
return VerificationStatus::kObserved;
case sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED:
return VerificationStatus::kUserVerified;
+ case sync_pb::AutofillProfileSpecifics_VerificationStatus_SERVER_PARSED:
+ return VerificationStatus::kServerParsed;
}
}
@@ -67,6 +69,8 @@ ConvertProfileToSpecificsVerificationStatus(VerificationStatus profile_status) {
return sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED;
case (VerificationStatus::kUserVerified):
return sync_pb::AutofillProfileSpecifics_VerificationStatus_USER_VERIFIED;
+ case (VerificationStatus::kServerParsed):
+ return sync_pb::AutofillProfileSpecifics_VerificationStatus_SERVER_PARSED;
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.h b/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
index c3078c34aae..a43595262bf 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.h
@@ -7,8 +7,6 @@
#include <memory>
#include <string>
-// TODO(crbug.com/904390): Remove when the investigation is over.
-#include <vector>
namespace syncer {
struct EntityData;
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.cc b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
index e175fadb0e1..898069ea87f 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_validator.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/check.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h
index 6eae4082e4b..1d9b93d8535 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.h
+++ b/chromium/components/autofill/core/browser/autofill_provider.h
@@ -52,7 +52,8 @@ class AutofillProvider {
bool known_success,
mojom::SubmissionSource source) = 0;
- virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) = 0;
+ virtual void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) = 0;
virtual void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index 97cae9baf26..60997b8bb58 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -6,7 +6,7 @@
// different compilers, we use a script to convert the UTF8 strings into
// numeric literals (\x##).
-#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
namespace autofill {
@@ -31,10 +31,16 @@ const char kCompanyRe[] =
"|شرکت" // fa
"|회사|ì§ìž¥"; // ko-KR
const char kStreetNameRe[] =
- "stra(ss|ß)e" // de
- "|street" // en
- "|rua|avenida"; // br
-const char kHouseNumberRe[] = "(house |^)number|(haus|^)nummer|^número$";
+ "stra(ss|ß)e" // de
+ "|street" // en
+ "|улица|название.?улицы" // ru
+ "|rua|avenida" // pt-PT, pt-BR
+ "|((?<!do |de )endereço)"; // pt-BR
+const char kHouseNumberRe[] =
+ "(house.?|street.?|^)number" // en
+ "|(haus|^)nummer" // de
+ "|^\\*?.?número(.?\\*?$| da residência)" // pt-BR, pt-PT
+ "|дом|номер.?дома"; // ru
const char kAddressLine1Re[] =
"^address$|address[_-]?line(one)?|address1|addr1|street"
"|(?:shipping|billing)address$"
@@ -44,7 +50,7 @@ const char kAddressLine1Re[] =
"|adresse" // fr-FR
"|indirizzo" // it-IT
"|^ä½æ‰€$|ä½æ‰€1" // ja-JP
- "|morada|((?<!identificação do )endereço)" // pt-BR, pt-PT
+ "|morada|((?<!do |de )endereço)" // pt-BR, pt-PT
"|ÐдреÑ" // ru
"|地å€" // zh-CN
"|(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)" // tr
@@ -121,8 +127,8 @@ const char kCityRe[] =
"|ville|commune" // fr-FR
"|localita" // it-IT
"|市区町æ‘" // ja-JP
- "|cidade" // pt-BR, pt-PT
- "|Город" // ru
+ "|cidade|município" // pt-BR, pt-PT
+ "|Город|ÐаÑелённый.?пункт" // ru
"|市" // zh-CN
"|分å€" // zh-TW
"|شهر" // fa
@@ -241,13 +247,13 @@ const char kExpirationYearRe[] =
// - (optional) Exactly two adjacent m's before the y's.
// - (optional) Separated by white-space and/or a dash or slash.
// - (optional) Prepended with some text similar to "Expiration Date".
-// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
+// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
const char kExpirationDate2DigitYearRe[] =
"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)";
// Used to match a expiration date field with a four digit year.
// Same requirements as |kExpirationDate2DigitYearRe| except:
// - Exactly four adjacent y's.
-// Tested in components/autofill/core/common/autofill_regexes_unittest.cc
+// Tested in components/autofill/core/browser/autofill_regexes_unittest.cc
const char kExpirationDate4DigitYearRe[] =
"(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)";
// Used to match expiration date fields that do not specify a year length.
diff --git a/chromium/components/autofill/core/common/autofill_regex_constants.h b/chromium/components/autofill/core/browser/autofill_regex_constants.h
index 407600d571c..de9ef0ecba2 100644
--- a/chromium/components/autofill/core/common/autofill_regex_constants.h
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.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 COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
-#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
namespace autofill {
@@ -96,4 +96,4 @@ extern const char kUrlSearchActionRe[];
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_
diff --git a/chromium/components/autofill/core/common/autofill_regexes.cc b/chromium/components/autofill/core/browser/autofill_regexes.cc
index 02254fa266a..4875a113f8b 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.cc
+++ b/chromium/components/autofill/core/browser/autofill_regexes.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 "components/autofill/core/common/autofill_regexes.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include <memory>
#include <unordered_map>
@@ -43,7 +43,7 @@ class AutofillRegexes {
icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) {
auto it = matchers_.find(pattern);
if (it == matchers_.end()) {
- const icu::UnicodeString icu_pattern(FALSE, pattern.data(),
+ const icu::UnicodeString icu_pattern(false, pattern.data(),
pattern.length());
UErrorCode status = U_ZERO_ERROR;
@@ -71,21 +71,21 @@ bool MatchesPattern(const base::string16& input,
base::AutoLock lock(*g_lock);
icu::RegexMatcher* matcher = g_autofill_regexes->GetMatcher(pattern);
- icu::UnicodeString icu_input(FALSE, input.data(), input.length());
+ icu::UnicodeString icu_input(false, input.data(), input.length());
matcher->reset(icu_input);
UErrorCode status = U_ZERO_ERROR;
UBool matched = matcher->find(0, status);
DCHECK(U_SUCCESS(status));
- if (matched == TRUE && match) {
+ if (matched && match) {
icu::UnicodeString match_unicode =
matcher->group(group_to_be_captured, status);
DCHECK(U_SUCCESS(status));
*match = base::i18n::UnicodeStringToString16(match_unicode);
}
- return matched == TRUE;
+ return matched;
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_regexes.h b/chromium/components/autofill/core/browser/autofill_regexes.h
index 837130b582c..585e88e20b6 100644
--- a/chromium/components/autofill/core/common/autofill_regexes.h
+++ b/chromium/components/autofill/core/browser/autofill_regexes.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 COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
-#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
#include "base/strings/string16.h"
@@ -20,4 +20,4 @@ bool MatchesPattern(const base::string16& input,
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEXES_H_
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEXES_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc b/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc
new file mode 100644
index 00000000000..2adddede044
--- /dev/null
+++ b/chromium/components/autofill/core/browser/autofill_regexes_unittest.cc
@@ -0,0 +1,232 @@
+// 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_regexes.h"
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+
+namespace autofill {
+
+struct InputPatternTestCase {
+ const char* const input;
+ const char* const pattern;
+};
+
+class PositiveSampleTest : public testing::TestWithParam<InputPatternTestCase> {
+};
+
+TEST_P(PositiveSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(test_case.pattern);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
+ ASCIIToUTF16(test_case.pattern)));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ PositiveSampleTest,
+ testing::Values(
+ // Empty pattern
+ InputPatternTestCase{"", ""},
+ InputPatternTestCase{
+ "Look, ma' -- a non-empty string!", ""},
+ // Substring
+ InputPatternTestCase{"string", "tri"},
+ // Substring at beginning
+ InputPatternTestCase{"string", "str"},
+ InputPatternTestCase{"string", "^str"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring"},
+ InputPatternTestCase{"string", "ring$"},
+ // Case-insensitive
+ InputPatternTestCase{"StRiNg", "string"}));
+
+class NegativeSampleTest : public testing::TestWithParam<InputPatternTestCase> {
+};
+
+TEST_P(NegativeSampleTest, SampleRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ SCOPED_TRACE(test_case.pattern);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
+ ASCIIToUTF16(test_case.pattern)));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ NegativeSampleTest,
+ testing::Values(
+ // Empty string
+ InputPatternTestCase{
+ "", "Look, ma' -- a non-empty pattern!"},
+ // Substring
+ InputPatternTestCase{"string", "trn"},
+ // Substring at beginning
+ InputPatternTestCase{"string", " str"},
+ InputPatternTestCase{"string", "^tri"},
+ // Substring at end
+ InputPatternTestCase{"string", "ring "},
+ InputPatternTestCase{"string", "rin$"}));
+
+struct InputTestCase {
+ const char* const input;
+};
+
+class ExpirationDate2DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearPositive,
+ testing::Values(InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+class ExpirationDate2DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
+ auto test_case = GetParam();
+ SCOPED_TRACE(test_case.input);
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate2DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+class ExpirationDate4DigitYearPositive
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
+ SCOPED_TRACE(test_case.input);
+ EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
+ ExpirationDate4DigitYearPositive,
+ testing::Values(
+ // Simple four year cases
+ InputTestCase{"mm / yyyy"},
+ InputTestCase{"mm/ yyyy"},
+ InputTestCase{"mm /yyyy"},
+ InputTestCase{"mm/yyyy"},
+ InputTestCase{"mm - yyyy"},
+ InputTestCase{"mm- yyyy"},
+ InputTestCase{"mm -yyyy"},
+ InputTestCase{"mm-yyyy"},
+ InputTestCase{"mmyyyy"},
+ // Complex four year cases
+ InputTestCase{"Expiration Date (MM / YYYY)"},
+ InputTestCase{"Expiration Date (MM/YYYY)"},
+ InputTestCase{"Expiration Date (MM - YYYY)"},
+ InputTestCase{"Expiration Date (MM-YYYY)"},
+ InputTestCase{"Expiration Date MM / YYYY"},
+ InputTestCase{"Expiration Date MM/YYYY"},
+ InputTestCase{"Expiration Date MM - YYYY"},
+ InputTestCase{"Expiration Date MM-YYYY"},
+ InputTestCase{"expiration date yyyy"},
+ InputTestCase{"Exp Date (MM / YYYY)"}));
+
+class ExpirationDate4DigitYearNegative
+ : public testing::TestWithParam<InputTestCase> {};
+
+TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
+ auto test_case = GetParam();
+ const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
+ SCOPED_TRACE(test_case.input);
+ EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ AutofillRegexes,
+ ExpirationDate4DigitYearNegative,
+ testing::Values(InputTestCase{""},
+ InputTestCase{"Look, ma' -- an invalid string!"},
+ InputTestCase{"mmfavouritewordyy"},
+ InputTestCase{"mm a yy"},
+ InputTestCase{"mm a yyyy"},
+ // Simple two year cases
+ InputTestCase{"mm / yy"},
+ InputTestCase{"mm/ yy"},
+ InputTestCase{"mm /yy"},
+ InputTestCase{"mm/yy"},
+ InputTestCase{"mm - yy"},
+ InputTestCase{"mm- yy"},
+ InputTestCase{"mm -yy"},
+ InputTestCase{"mm-yy"},
+ InputTestCase{"mmyy"},
+ // Complex two year cases
+ InputTestCase{"Expiration Date (MM / YY)"},
+ InputTestCase{"Expiration Date (MM/YY)"},
+ InputTestCase{"Expiration Date (MM - YY)"},
+ InputTestCase{"Expiration Date (MM-YY)"},
+ InputTestCase{"Expiration Date MM / YY"},
+ InputTestCase{"Expiration Date MM/YY"},
+ InputTestCase{"Expiration Date MM - YY"},
+ InputTestCase{"Expiration Date MM-YY"},
+ InputTestCase{"expiration date yy"},
+ InputTestCase{"Exp Date (MM / YY)"}));
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/address.cc b/chromium/components/autofill/core/browser/data_model/address.cc
index cd7f8e6dd57..284283981ee 100644
--- a/chromium/components/autofill/core/browser/data_model/address.cc
+++ b/chromium/components/autofill/core/browser/data_model/address.cc
@@ -65,7 +65,17 @@ bool Address::FinalizeAfterImport(bool profile_is_verified) {
// fully launched.
if (structured_address::StructuredAddressesEnabled()) {
structured_address_.MigrateLegacyStructure(profile_is_verified);
- return structured_address_.CompleteFullTree();
+ bool result = structured_address_.CompleteFullTree();
+ // If the address could not be completed, it is possible that it contains an
+ // invalid structure.
+ if (!result) {
+ if (structured_address_.WipeInvalidStructure()) {
+ // If the structure was wiped because it is invalid, try to complete the
+ // address again.
+ result = structured_address_.CompleteFullTree();
+ }
+ }
+ return result;
}
return true;
}
@@ -158,6 +168,22 @@ void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
+ // The street address has a structure that may have already been set before
+ // using the settings dialog. In case the settings dialog was used to change
+ // the address to contain different tokens, the structure must be reset.
+ if (type == ADDRESS_HOME_STREET_ADDRESS) {
+ const base::string16 current_value =
+ structured_address_.GetValueForType(type);
+ if (!current_value.empty()) {
+ bool token_equivalent = structured_address::AreStringTokenEquivalent(
+ value, structured_address_.GetValueForType(type));
+ structured_address_.SetValueForTypeIfPossible(
+ ADDRESS_HOME_STREET_ADDRESS, value, status,
+ /*invalidate_child_nodes=*/!token_equivalent);
+ return;
+ }
+ }
+
structured_address_.SetValueForTypeIfPossible(type, value, status);
return;
}
@@ -366,21 +392,17 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
std::string country_code = base::ToUpperASCII(base::UTF16ToASCII(value));
if (!data_util::IsValidCountryCode(country_code)) {
- // Some popular websites use the HTML_TYPE_COUNTRY_CODE attribute for
- // full text names (e.g. alliedelec.com). Try to convert the value to a
- // country code as a fallback.
- if (base::FeatureList::IsEnabled(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames)) {
- CountryNames* country_names =
- !value.empty() ? CountryNames::GetInstance() : nullptr;
- country_code =
- country_names
- ? country_names->GetCountryCodeForLocalizedCountryName(value,
- locale)
- : std::string();
- } else {
- country_code = std::string();
- }
+ // To counteract the misuse of autocomplete=country attribute when used
+ // with full country names, if the supplied country code is not a valid,
+ // it is tested if a country code can be derived from the value when it is
+ // interpreted as a full country name. Otherwise an empty string is
+ // assigned to |country_code|.
+ CountryNames* country_names =
+ !value.empty() ? CountryNames::GetInstance() : nullptr;
+ country_code = country_names
+ ? country_names->GetCountryCodeForLocalizedCountryName(
+ value, locale)
+ : std::string();
}
// TODO(crbug.com/1130194): Clean legacy implementation once structured
diff --git a/chromium/components/autofill/core/browser/data_model/address_unittest.cc b/chromium/components/autofill/core/browser/data_model/address_unittest.cc
index 8a3f79fe3da..ee3aed0d76c 100644
--- a/chromium/components/autofill/core/browser/data_model/address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/address_unittest.cc
@@ -84,12 +84,6 @@ TEST_P(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
- // Enable the feature that allows for full country names although the
- // field type explicitly set to HTML_TYPE_COUNTRY_CODE.
- base::test::ScopedFeatureList feature;
- feature.InitAndEnableFeature(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames);
-
// Create an autofill type from HTML_TYPE_COUNTRY_CODE.
AutofillType autofill_type(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE);
@@ -131,18 +125,6 @@ TEST_P(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
AutofillType(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE), "en-US");
EXPECT_EQ(ASCIIToUTF16("DE"), actual_country_code);
EXPECT_EQ(ASCIIToUTF16("Germany"), actual_country);
-
- // By disabling the feature, test that the country name deduction actually
- // uses the path for HTML_TYPE_COUNTRY_CODE.
- feature.Reset();
- feature.InitAndDisableFeature(
- features::kAutofillAllowHtmlTypeCountryCodesWithFullNames);
- address.SetInfo(autofill_type, ASCIIToUTF16("Germany"), "en-US");
- actual_country = address.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), "en-US");
- actual_country_code = address.GetInfo(
- AutofillType(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE), "en-US");
- EXPECT_EQ(ASCIIToUTF16(""), actual_country);
- EXPECT_EQ(ASCIIToUTF16(""), actual_country_code);
}
// Test that we properly detect country codes appropriate for each country.
@@ -687,6 +669,71 @@ TEST_P(AddressTest, TestGettingTheStructuredAddress) {
base::UTF8ToUTF16("12345"));
}
+// For structured address, test that the structured information is wiped
+// correctly when the unstructured street address changes.
+TEST_P(AddressTest, ResetStructuredTokens) {
+ // This test is only applicable for structured addresses.
+ if (!StructuredAddresses())
+ return;
+
+ Address address;
+ // Set a structured address line and call the finalization routine.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Erika-Mann-Str 12"),
+ structured_address::VerificationStatus::kUserVerified);
+ address.FinalizeAfterImport();
+
+ // Verify that structured tokens have been assigned correctly.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16("Erika-Mann-Str"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kParsed);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16("12"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kParsed);
+
+ // Lift the verification status of the house number to be |kObserved|.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("12"),
+ structured_address::VerificationStatus::kObserved);
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kObserved);
+
+ // Now, set a new unstructured street address that has the same tokens in a
+ // different order.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("12 Erika-Mann-Str"),
+ structured_address::VerificationStatus::kUserVerified);
+
+ // After this operation, the structure should be maintained including the
+ // observed status of the house number.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16("Erika-Mann-Str"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kParsed);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16("12"));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kObserved);
+
+ // Now set a different street address.
+ address.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Marienplatz"),
+ structured_address::VerificationStatus::kUserVerified);
+
+ // The set address is not parsable and the this should unset both the street
+ // name and the house number.
+ EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
+ base::ASCIIToUTF16(""));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_STREET_NAME),
+ structured_address::VerificationStatus::kNoStatus);
+ ASSERT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
+ base::ASCIIToUTF16(""));
+ EXPECT_EQ(address.GetVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER),
+ structured_address::VerificationStatus::kNoStatus);
+}
+
// Runs the suite with the feature
// |kAutofillSupportForStructuredStructuredNames| enabled and disabled.
// TODO(crbug.com/1130194): Remove parameterized test once structured addresses
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
index daf20027c29..7da13d15f85 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
@@ -72,8 +72,8 @@ double AutofillDataModel::GetFrecencyScore(base::Time time) const {
// of the profile and leveraging the properties of the logarithmic function.
// DaysSinceLastUse() and |use_count_| are offset because their minimum values
// are respectively 0 and 1 but the formula requires at least a value of 2.
- // Please update getFrecencyScore in PaymentRequestImpl.java as well if below
- // formula needs update.
+ // Please update getFrecencyScore in ChromePaymentRequestService.java as well
+ // if below formula needs update.
return -log((time - use_date_).InDays() + 2) / log(use_count_ + 1);
}
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
index 94e43c09ffa..e9668df416b 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -449,15 +449,20 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
for (ServerFieldType type : types) {
int comparison = GetRawInfo(type).compare(profile.GetRawInfo(type));
- if (comparison != 0)
+ if (comparison != 0) {
return comparison;
+ }
}
for (ServerFieldType type : types) {
- if (GetVerificationStatus(type) < profile.GetVerificationStatus(type))
+ if (structured_address::IsLessSignificantVerificationStatus(
+ GetVerificationStatus(type), profile.GetVerificationStatus(type))) {
return -1;
- if (GetVerificationStatus(type) > profile.GetVerificationStatus(type))
+ }
+ if (structured_address::IsLessSignificantVerificationStatus(
+ profile.GetVerificationStatus(type), GetVerificationStatus(type))) {
return 1;
+ }
}
// TODO(crbug.com/1130194): Remove feature check once structured addresses are
@@ -474,15 +479,22 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
};
for (ServerFieldType type : new_types) {
int comparison = GetRawInfo(type).compare(profile.GetRawInfo(type));
- if (comparison != 0)
+ if (comparison != 0) {
return comparison;
+ }
}
- for (ServerFieldType type : new_types) {
- if (GetVerificationStatus(type) < profile.GetVerificationStatus(type))
+ for (ServerFieldType type : types) {
+ if (structured_address::IsLessSignificantVerificationStatus(
+ GetVerificationStatus(type),
+ profile.GetVerificationStatus(type))) {
return -1;
- if (GetVerificationStatus(type) > profile.GetVerificationStatus(type))
+ }
+ if (structured_address::IsLessSignificantVerificationStatus(
+ profile.GetVerificationStatus(type),
+ GetVerificationStatus(type))) {
return 1;
+ }
}
}
@@ -637,35 +649,47 @@ bool AutofillProfile::MergeStructuredDataFrom(const AutofillProfile& profile,
// Should only be called if the profile is already verified.
DCHECK(IsVerified());
- // Only applicable for structured names.
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames)) {
- return false;
- }
-
AutofillProfileComparator comparator(app_locale);
- NameInfo name;
+
DVLOG(1) << "Merging profile structure information :\nSource = " << profile
<< "\nDest = " << *this;
- // It is already verified upstream that the profiles and therefore also the
- // names are mergeable.
- // However, the structure should only be merged if the full names are token
- // equivalent.
- if (!structured_address::AreStringTokenEquivalent(
- GetRawInfo(NAME_FULL), profile.GetRawInfo(NAME_FULL)))
- return false;
+ bool merged = false;
- if (!comparator.MergeNames(profile, *this, &name)) {
- NOTREACHED();
- return false;
+ // It is already verified upstream that the profiles and therefore also the
+ // names and addresses are mergeable.
+ // However, the structure should only be merged if the full names or addresses
+ // are token equivalent.
+ if (structured_address::StructuredNamesEnabled() &&
+ structured_address::AreStringTokenEquivalent(
+ GetRawInfo(NAME_FULL), profile.GetRawInfo(NAME_FULL))) {
+ NameInfo name;
+ if (!comparator.MergeNames(profile, *this, &name)) {
+ NOTREACHED();
+ return false;
+ }
+ if (name_ != name) {
+ name_ = name;
+ merged = true;
+ }
}
- if (name_ != name) {
- name_ = name;
- return true;
+ if (structured_address::StructuredAddressesEnabled() &&
+ structured_address::AreStringTokenEquivalent(
+ GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
+ profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS))) {
+ Address address;
+ if (!comparator.MergeAddresses(profile, *this, &address)) {
+ NOTREACHED();
+ return false;
+ }
+ if (address_ != address) {
+ address_ = address;
+ merged = true;
+ }
}
- return false;
+
+ return merged;
}
bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index 9c39c693e56..e24375a36eb 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -122,7 +122,7 @@ NormalizingIterator::NormalizingIterator(
: previous_was_skippable_(false),
collapse_skippable_(whitespace_spec ==
AutofillProfileComparator::RETAIN_WHITESPACE),
- iter_(base::i18n::UTF16CharIterator(text.data(), text.length())) {
+ iter_(text) {
int32_t character = iter_.get();
while (!iter_.end() && IsPunctuationOrWhitespace(u_charType(character))) {
@@ -282,8 +282,7 @@ base::string16 AutofillProfileComparator::NormalizeForComparison(
base::string16 result;
result.reserve(text.length());
bool previous_was_whitespace = (whitespace_spec == RETAIN_WHITESPACE);
- for (base::i18n::UTF16CharIterator iter(text.data(), text.length());
- !iter.end(); iter.Advance()) {
+ for (base::i18n::UTF16CharIterator iter(text); !iter.end(); iter.Advance()) {
if (IsPunctuationOrWhitespace(u_charType(iter.get()))) {
if (!previous_was_whitespace && whitespace_spec == RETAIN_WHITESPACE) {
result.push_back(' ');
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
index c745377720b..b5fa1ea03e3 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.cc
@@ -4,7 +4,6 @@
#include "components/autofill/core/browser/data_model/autofill_structured_address.h"
-#include <iostream>
#include <utility>
#include "base/i18n/case_conversion.h"
#include "base/strings/strcat.h"
@@ -136,7 +135,8 @@ void StreetAddress::ParseValueAndAssignSubcomponentsByFallbackMethod() {
bool StreetAddress::HasNewerValuePrecendenceInMerging(
const AddressComponent& newer_component) const {
// If the newer component has a better verification status, use the newer one.
- if (GetVerificationStatus() < newer_component.GetVerificationStatus())
+ if (IsLessSignificantVerificationStatus(
+ GetVerificationStatus(), newer_component.GetVerificationStatus()))
return true;
// If the verification statuses are the same, do not use the newer component
@@ -353,6 +353,13 @@ Address::Address(const Address& other) : Address() {
*this = other;
}
+bool Address::WipeInvalidStructure() {
+ // For structured addresses, currently it is sufficient to wipe the structure
+ // of the street address, because this is the only directly assignable value
+ // that has a substructure.
+ return street_address_.WipeInvalidStructure();
+}
+
// Addresses are mergeable when all of their children are mergeable.
// Reformat the address from their children after merge.
Address::Address(AddressComponent* parent)
@@ -367,7 +374,6 @@ Address::~Address() = default;
void Address::MigrateLegacyStructure(bool is_verified_profile) {
// If this component already has a verification status, no profile is regarded
// as already verified.
- std::cout << "APply migration" << std::endl;
if (GetVerificationStatus() != VerificationStatus::kNoStatus)
return;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
index 1e2c0201dbd..7e872bfc114 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address.h
@@ -226,6 +226,10 @@ class Address : public AddressComponent {
// a status.
void MigrateLegacyStructure(bool is_verified_profile);
+ // Checks if the street address contains an invalid structure and wipes it if
+ // necessary.
+ bool WipeInvalidStructure() override;
+
private:
StreetAddress street_address_{this};
PostalCode postal_code_{this};
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
index fccb0bd9725..50e6e86f2d2 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.cc
@@ -27,6 +27,28 @@ namespace autofill {
namespace structured_address {
+bool IsLessSignificantVerificationStatus(VerificationStatus left,
+ VerificationStatus right) {
+ // Both the KUserVerified and kObserved are larger then kServerParsed although
+ // the underlying integer suggests differently.
+ if (left == VerificationStatus::kServerParsed &&
+ (right == VerificationStatus::kObserved ||
+ right == VerificationStatus::kUserVerified)) {
+ return true;
+ }
+
+ if (right == VerificationStatus::kServerParsed &&
+ (left == VerificationStatus::kObserved ||
+ left == VerificationStatus::kUserVerified)) {
+ return false;
+ }
+
+ // In all other cases, it is sufficient to compare the underlying integer
+ // values.
+ return static_cast<std::underlying_type_t<VerificationStatus>>(left) <
+ static_cast<std::underlying_type_t<VerificationStatus>>(right);
+}
+
AddressComponent::AddressComponent(ServerFieldType storage_type,
AddressComponent* parent,
std::vector<AddressComponent*> subcomponents,
@@ -482,6 +504,27 @@ void AddressComponent::ParseValueAndAssignSubcomponentsByFallbackMethod() {
DCHECK(success);
}
+bool AddressComponent::WipeInvalidStructure() {
+ if (IsAtomic()) {
+ return false;
+ }
+
+ // Test that each structured token is part of the subcomponent.
+ // This is not perfect, because different components can match with an
+ // overlapping portion of the unstructured string, but it guarantees that all
+ // information in the components is contained in the unstructured
+ // representation.
+ for (const auto* component : Subcomponents()) {
+ if (GetValue().find(component->GetValue()) == base::string16::npos) {
+ // If the value of one component could not have been found, wipe the full
+ // structure.
+ RecursivelyUnsetSubcomponents();
+ return true;
+ }
+ }
+ return false;
+}
+
void AddressComponent::FormatValueFromSubcomponents() {
// Get the most suited format string.
base::string16 format_string = GetBestFormatString();
@@ -697,7 +740,7 @@ void AddressComponent::UnsetParsedAndFormattedValuesInEntireTree() {
void AddressComponent::MergeVerificationStatuses(
const AddressComponent& newer_component) {
if (IsValueAssigned() && (GetValue() == newer_component.GetValue()) &&
- (GetVerificationStatus() < newer_component.GetVerificationStatus())) {
+ HasNewerValuePrecendenceInMerging(newer_component)) {
value_verification_status_ = newer_component.GetVerificationStatus();
}
@@ -807,7 +850,7 @@ bool AddressComponent::MergeWithComponent(
// If the normalized values are the same, optimize the verification status.
if ((merge_mode_ & kUseBetterOrNewerForSameValue) && (value == value_newer)) {
- if (newer_component.GetVerificationStatus() >= GetVerificationStatus()) {
+ if (HasNewerValuePrecendenceInMerging(newer_component)) {
*this = newer_component;
}
return true;
@@ -900,7 +943,8 @@ bool AddressComponent::MergeWithComponent(
bool AddressComponent::HasNewerValuePrecendenceInMerging(
const AddressComponent& newer_component) const {
- return newer_component.GetVerificationStatus() >= GetVerificationStatus();
+ return !IsLessSignificantVerificationStatus(
+ newer_component.GetVerificationStatus(), GetVerificationStatus());
}
bool AddressComponent::MergeTokenEquivalentComponent(
@@ -1109,6 +1153,7 @@ int AddressComponent::GetStructureVerificationScore() const {
case VerificationStatus::kNoStatus:
case VerificationStatus::kParsed:
case VerificationStatus::kFormatted:
+ case VerificationStatus::kServerParsed:
break;
case VerificationStatus::kObserved:
result += 1;
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
index 9cfc4d1c310..7adba19a86e 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component.h
@@ -37,8 +37,15 @@ enum class VerificationStatus {
kObserved = 3,
// The user used the autofill settings to verify and store this token.
kUserVerified = 4,
+ // The token was parsed by the server.
+ kServerParsed = 5,
};
+// Returns true if |left| has a less significant verification status compared to
+// |right|.
+bool IsLessSignificantVerificationStatus(VerificationStatus left,
+ VerificationStatus right);
+
// The merge mode defines if and how two components are merged.
enum MergeMode {
// If one component has an empty value, use the non-empty one.
@@ -57,8 +64,7 @@ enum MergeMode {
kUseNewerIfDifferent = 1 << 5,
// If the newer component contains one token more, apply a recursive strategy
// to merge the tokens.
- kRecursivelyMergeSingleTokenSubset =
- 1 << 6 | kRecursivelyMergeTokenEquivalentValues,
+ kRecursivelyMergeSingleTokenSubset = 1 << 6,
// If one is a substring use the most recent one.
kUseMostRecentSubstring = 1 << 7,
// Merge the child nodes and reformat the node from its children after merge.
@@ -335,6 +341,11 @@ class AddressComponent {
bool* validity_status,
bool wipe_if_not = false);
+ // Deletes the stored structure if it contains strings that are not a
+ // substring of the unstructured representation.
+ // Return true if a wipe operation was performed.
+ virtual bool WipeInvalidStructure();
+
#ifdef UNIT_TEST
// Initiates the formatting of the values from the subcomponents.
void FormatValueFromSubcomponentsForTesting() {
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
index 2a4a7fd1c8f..a9356b83cd8 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_component_unittest.cc
@@ -1661,5 +1661,26 @@ TEST(AutofillStructuredAddressAddressComponent, MergeChildsAndReformatRoot) {
VerifyTestValues(&older, older_values);
}
+// Test the comparison of different Verification statuses.
+TEST(AutofillStructuredAddressAddressComponent,
+ TestIsLessSignificantVerificationStatus) {
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kParsed, VerificationStatus::kFormatted));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kParsed, VerificationStatus::kServerParsed));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kObserved));
+ EXPECT_TRUE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kUserVerified));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kFormatted));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kServerParsed, VerificationStatus::kParsed));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kObserved, VerificationStatus::kServerParsed));
+ EXPECT_FALSE(IsLessSignificantVerificationStatus(
+ VerificationStatus::kUserVerified, VerificationStatus::kServerParsed));
+}
+
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
index ed1ffa76558..ea5ba89c845 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_name_unittest.cc
@@ -11,7 +11,6 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/common/autofill_features.h"
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
index 07f58617c0e..ba400f32f08 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
@@ -267,11 +267,12 @@ std::string ParseFirstMiddleLastNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_FIRST, kSingleWordRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_MIDDLE, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_MIDDLE, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST,
{kOptionalLastNamePrefixRe, kSingleWordRe}),
kOptionalLastNameSuffixRe});
@@ -288,14 +289,15 @@ std::string ParseLastCommaFirstMiddleExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST,
{kOptionalLastNamePrefixRe, kSingleWordRe},
{.separator = "\\s*,\\s*"}),
CaptureTypeWithPattern(NAME_FIRST, kSingleWordRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_MIDDLE, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_MIDDLE, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL})});
}
// Returns an expression to parse an Hispanic/Latinx last name.
@@ -313,7 +315,7 @@ std::string ParseHispanicLastNameExpression() {
{kOptionalLastNamePrefixRe, kSingleWordRe}),
CaptureTypeWithPattern(NAME_LAST_CONJUNCTION,
kHispanicLastNameConjunctionsRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPattern(NAME_LAST_SECOND,
{kOptionalLastNamePrefixRe, kSingleWordRe})});
}
@@ -325,9 +327,10 @@ std::string ParseHispanicFullNameExpression() {
return CaptureTypeWithPattern(
NAME_FULL,
{CaptureTypeWithPattern(NAME_HONORIFIC_PREFIX, kHonorificPrefixRe,
- {.quantifier = MATCH_OPTIONAL}),
- CaptureTypeWithPattern(NAME_FIRST, kMultipleLazyWordsRe,
- {.quantifier = MATCH_LAZY_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPattern(
+ NAME_FIRST, kMultipleLazyWordsRe,
+ CaptureOptions{.quantifier = MATCH_LAZY_OPTIONAL}),
ParseHispanicLastNameExpression()});
}
@@ -358,14 +361,15 @@ std::string ParseStreetNameHouseNumberExpression() {
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_FLOOR, kFloorAffixRe,
- "(?:(\\d{0,3}\\w?))",
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPrefixedPattern(
+ ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
// Returns an expression to parse a street address into the street name, the
@@ -392,12 +396,13 @@ std::string ParseStreetNameHouseNumberExpressionSuffixedFloor() {
{
CaptureTypeWithSuffixedPattern(
ADDRESS_HOME_FLOOR, "(?:(\\d{0,3}\\w?))", kFloorAffixRe,
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
// Returns an expression to parse a street address into the street name, the
@@ -417,14 +422,15 @@ std::string ParseHouseNumberStreetNameExpression() {
CaptureTypeWithPattern(
ADDRESS_HOME_SUBPREMISE,
{
- CaptureTypeWithPrefixedPattern(ADDRESS_HOME_FLOOR, kFloorAffixRe,
- "(?:(\\d{0,3}\\w?))",
- {.quantifier = MATCH_OPTIONAL}),
+ CaptureTypeWithPrefixedPattern(
+ ADDRESS_HOME_FLOOR, kFloorAffixRe, "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
CaptureTypeWithPrefixedPattern(
ADDRESS_HOME_APT_NUM, kApartmentNumberPrefix,
- "(?:(\\d{0,3}\\w?))", {.quantifier = MATCH_OPTIONAL}),
+ "(?:(\\d{0,3}\\w?))",
+ CaptureOptions{.quantifier = MATCH_OPTIONAL}),
},
- {.quantifier = MATCH_OPTIONAL})});
+ CaptureOptions{.quantifier = MATCH_OPTIONAL})});
}
} // namespace
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
index 1a8bf503d31..c00710a40d4 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_unittest.cc
@@ -12,7 +12,6 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -482,6 +481,67 @@ TEST(AutofillStructuredAddress, TestMigrationAndFinalization_AlreadyMigrated) {
// Verify that the address was not changed by the migration.
VerifyTestValues(&address, test_values);
}
+
+// Tests that a valid address structure is not wiped.
+TEST(AutofillStructuredAddress,
+ TestWipingAnInvalidSubstructure_ValidStructure) {
+ Address address;
+ AddressComponentTestValues address_with_valid_structure = {
+ // This structure is valid because all structured components are contained
+ // in the unstructured representation.
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "123 Street name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "Street name",
+ .status = VerificationStatus::kParsed},
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "123",
+ .status = VerificationStatus::kParsed},
+ };
+
+ SetTestValues(&address, address_with_valid_structure, /*finalize=*/false);
+
+ EXPECT_FALSE(address.WipeInvalidStructure());
+ VerifyTestValues(&address, address_with_valid_structure);
+}
+
+// Tests that an invalid address structure is wiped.
+TEST(AutofillStructuredAddress,
+ TestWipingAnInvalidSubstructure_InValidStructure) {
+ Address address;
+ AddressComponentTestValues address_with_valid_structure = {
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "Some other name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "Street name",
+ .status = VerificationStatus::kParsed},
+ // The structure is invalid, because the house number is not contained in
+ // the unstructured street address.
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "123",
+ .status = VerificationStatus::kParsed},
+ };
+
+ SetTestValues(&address, address_with_valid_structure, /*finalize=*/false);
+
+ EXPECT_TRUE(address.WipeInvalidStructure());
+
+ AddressComponentTestValues address_with_wiped_structure = {
+ {.type = ADDRESS_HOME_STREET_ADDRESS,
+ .value = "Some other name",
+ .status = VerificationStatus::kObserved},
+ {.type = ADDRESS_HOME_STREET_NAME,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ {.type = ADDRESS_HOME_HOUSE_NUMBER,
+ .value = "",
+ .status = VerificationStatus::kNoStatus},
+ };
+ VerifyTestValues(&address, address_with_wiped_structure);
+}
+
} // namespace
} // namespace structured_address
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/contact_info.cc b/chromium/components/autofill/core/browser/data_model/contact_info.cc
index 8464c16d6a7..bd31bdcaa3a 100644
--- a/chromium/components/autofill/core/browser/data_model/contact_info.cc
+++ b/chromium/components/autofill/core/browser/data_model/contact_info.cc
@@ -14,12 +14,12 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_l10n_util.h"
-#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.cc b/chromium/components/autofill/core/browser/data_model/credit_card.cc
index 022464200ad..484b13711c5 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -27,6 +27,7 @@
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
#include "components/autofill/core/browser/data_model/data_model_utils.h"
@@ -35,7 +36,6 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
diff --git a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
index 518d6a7949d..023b70402cc 100644
--- a/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/data_model_utils.cc
@@ -11,9 +11,9 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "third_party/icu/source/i18n/unicode/dtfmtsym.h"
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index 203fbe516ab..37c6daaa7a4 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -19,6 +19,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/autofill/core/browser/address_profiles/address_profile_save_manager.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_type.h"
@@ -102,16 +103,13 @@ bool IsMinimumAddress(const AutofillProfile& profile,
<< "Country entry in form." << CTag{};
}
- if (base::FeatureList::IsEnabled(
- features::kAutofillUseVariationCountryCode)) {
- // As a fallback, use the finch state to get a country code.
- if (country_code.empty() && !variation_country_code.empty()) {
- country_code = variation_country_code;
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Variations service." << CTag{};
- }
+ // As a fallback, use the finch state to get a country code.
+ if (country_code.empty() && !variation_country_code.empty()) {
+ country_code = variation_country_code;
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Variations service." << CTag{};
}
}
@@ -230,6 +228,8 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
payments_client,
app_locale,
personal_data_manager)),
+ address_profile_save_manager_(
+ std::make_unique<AddressProfileSaveManager>(personal_data_manager)),
#if !defined(OS_ANDROID) && !defined(OS_IOS)
local_card_migration_manager_(
std::make_unique<LocalCardMigrationManager>(client,
@@ -470,15 +470,12 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
// And close the div of the section import log.
import_log_buffer << CTag{"div"};
}
- // TODO(crbug.com/1097125): Remove feature test.
// Run the import on the union of the section if the import was not
// successful and if there is more than one section.
if (num_saved_profiles > 0) {
AutofillMetrics::LogAddressFormImportStatustMetric(
AutofillMetrics::AddressProfileImportStatusMetric::REGULAR_IMPORT);
- } else if (base::FeatureList::IsEnabled(
- features::kAutofillProfileImportFromUnifiedSection) &&
- sections.size() > 1) {
+ } else if (sections.size() > 1) {
// Try to import by combining all sections.
if (ImportAddressProfileForSection(form, "", &import_log_buffer)) {
num_saved_profiles++;
@@ -542,14 +539,8 @@ bool FormDataImporter::ImportAddressProfileForSection(
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
// If we don't know the type of the field, or the user hasn't entered any
- // information into the field, or the field is non-focusable (hidden), then
- // skip it.
- // TODO(crbug.com/1101280): Remove |skip_unfocussable_field|
- bool skip_unfocussable_field =
- !field->is_focusable &&
- !base::FeatureList::IsEnabled(
- features::kAutofillProfileImportFromUnfocusableFields);
- if (!field->IsFieldFillable() || skip_unfocussable_field || value.empty())
+ // information into the field, then skip it.
+ if (!field->IsFieldFillable() || value.empty())
continue;
AutofillType field_type = field->Type();
@@ -591,24 +582,20 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Reject profiles with invalid country information.
if (server_field_type == ADDRESS_HOME_COUNTRY &&
candidate_profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) {
- // TODO(crbug.com/1075604): Remove branch with disabled feature.
- if (base::FeatureList::IsEnabled(
- features::kAutofillUsePageLanguageToTranslateCountryNames)) {
- // The country code was not successfully determined from the value in
- // the country field. This can be caused by a localization that does not
- // match the |app_locale|. Try setting the value again using the
- // language of the page. Note, there should be a locale associated with
- // every language code.
- std::string page_language;
- const translate::LanguageState* language_state =
- client_->GetLanguageState();
- if (language_state)
- page_language = language_state->original_language();
- // Retry to set the country of there is known page language.
- if (!page_language.empty()) {
- candidate_profile.SetInfoWithVerificationStatus(
- field_type, value, page_language, VerificationStatus::kObserved);
- }
+ // The country code was not successfully determined from the value in
+ // the country field. This can be caused by a localization that does not
+ // match the |app_locale|. Try setting the value again using the
+ // language of the page. Note, there should be a locale associated with
+ // every language code.
+ std::string page_language;
+ const translate::LanguageState* language_state =
+ client_->GetLanguageState();
+ if (language_state)
+ page_language = language_state->original_language();
+ // Retry to set the country of there is known page language.
+ if (!page_language.empty()) {
+ candidate_profile.SetInfoWithVerificationStatus(
+ field_type, value, page_language, VerificationStatus::kObserved);
}
// Check if the country code was still not determined correctly.
if (candidate_profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) {
@@ -687,7 +674,7 @@ bool FormDataImporter::ImportAddressProfileForSection(
return false;
std::string guid =
- personal_data_manager_->SaveImportedProfile(candidate_profile);
+ address_profile_save_manager_->SaveProfile(candidate_profile);
return !guid.empty();
}
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index 38d0b12fd9a..4ef28d575a6 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -24,6 +24,8 @@ class SaveCardOfferObserver;
namespace autofill {
+class AddressProfileSaveManager;
+
// Manages logic for importing address profiles and credit card information from
// web forms into the user's Autofill profile via the PersonalDataManager.
// Owned by AutofillManager.
@@ -151,6 +153,9 @@ class FormDataImporter {
// Responsible for managing credit card save flows (local or upload).
std::unique_ptr<CreditCardSaveManager> credit_card_save_manager_;
+ // Responsible for managing address profiles save flows.
+ std::unique_ptr<AddressProfileSaveManager> address_profile_save_manager_;
+
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Responsible for migrating locally saved credit cards to Google Pay.
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager_;
diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
index 31e772c644a..b15cee9ccae 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -14,7 +14,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/guid.h"
@@ -29,8 +29,10 @@
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -230,6 +232,7 @@ class FormDataImporterTestBase {
std::unique_ptr<PersonalDataManager> personal_data_manager_;
std::unique_ptr<FormDataImporter> form_data_importer_;
base::test::ScopedFeatureList scoped_feature_list_;
+ TestPatternProvider test_pattern_provider_;
};
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
@@ -580,18 +583,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfileFromUnifiedSection) {
// Assign the address field another section than the other fields.
form_structure.field(3)->section = "another_section";
- base::test::ScopedFeatureList scoped_feature;
- scoped_feature.InitAndDisableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
- // Without the feature, the import is expected to fail.
- ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
-
- // After enabled the feature, the import is expected to succeed.
- scoped_feature.Reset();
- scoped_feature.InitAndEnableFeature(
- features::kAutofillProfileImportFromUnifiedSection);
-
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -842,7 +833,9 @@ TEST_P(FormDataImporterTest,
EXPECT_EQ(0, expected.Compare(*results[0]));
}
-TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
+// Test that a form is imported correctly even if some fields are not
+// focusable.
+TEST_P(FormDataImporterTest, ImportAddressProfiles_WithUnFocussableFields) {
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -864,7 +857,8 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
form.fields.push_back(field);
test::CreateTestFormField("City:", "city", "San Francisco", "text", &field);
- // Set this field to be unfocusable.
+
+ // Set this field to be not focusable.
field.is_focusable = false;
form.fields.push_back(field);
@@ -877,18 +871,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
- // Verify the status quo that the form is not imported with the unfocusable
- // fields.
- // TODO(crbug.com/1101280): Remove once feature is launched.
- scoped_feature_list_.Reset();
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillProfileImportFromUnfocusableFields);
- ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
-
- // Activate the feature and test again.
- scoped_feature_list_.Reset();
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillProfileImportFromUnfocusableFields);
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
@@ -1605,6 +1587,181 @@ TEST_P(FormDataImporterTest,
EXPECT_EQ(0, profile.Compare(*results2[0]));
}
+TEST_P(FormDataImporterTest,
+ IncorporateStructuredNameInformationInVerifiedProfile) {
+ // This test is only applicable to structured names.
+ if (!structured_address::StructuredNamesEnabled()) {
+ return;
+ }
+
+ // Start with a verified profile.
+ AutofillProfile profile(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ EXPECT_TRUE(profile.IsVerified());
+
+ // Set the verification status for the first and middle name to parsed.
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Marion"),
+ structured_address::VerificationStatus::kParsed);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Mitchell"),
+ structured_address::VerificationStatus::kParsed);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_manager_->AddProfile(profile);
+ run_loop.Run();
+
+ // Simulate a form submission with conflicting info.
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "Marion Mitchell",
+ "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Morrison", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "johnwayne@me.xyz", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Address:", "address1", "123 Zoo St.", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "Hollywood", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "CA", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "91601", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ // The form submission should result in a change of name structure.
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_FIRST, base::ASCIIToUTF16("Marion Mitchell"),
+ structured_address::VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_MIDDLE, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ NAME_LAST, base::ASCIIToUTF16("Morrison"),
+ structured_address::VerificationStatus::kObserved);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, profile.Compare(*results[0]));
+
+ // Try the same thing, but without "Mitchell". The profiles should still match
+ // because "Marion Morrison" is a variant of the known full name.
+ test::CreateTestFormField("First name:", "first_name", "Marion", "text",
+ &field);
+ form.fields[0] = field;
+
+ FormStructure form_structure2(form);
+ form_structure2.DetermineHeuristicTypes();
+
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure2);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results2 =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results2.size());
+ EXPECT_EQ(0, profile.Compare(*results2[0]));
+}
+
+TEST_P(FormDataImporterTest,
+ IncorporateStructuredAddressInformationInVerififedProfile) {
+ // This test is only applicable to structured addresses.
+ if (!structured_address::StructuredAddressesEnabled()) {
+ return;
+ }
+
+ // Start with a verified profile.
+ AutofillProfile profile(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ EXPECT_TRUE(profile.IsVerified());
+
+ // Reset the structured address to emulate a failed parsing attempt.
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME, base::ASCIIToUTF16(""),
+ structured_address::VerificationStatus::kNoStatus);
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
+ .WillOnce(QuitMessageLoop(&run_loop));
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ personal_data_manager_->AddProfile(profile);
+ run_loop.Run();
+
+ // Simulate a form submission with conflicting info.
+ FormData form;
+ form.url = GURL("https://wwww.foo.com");
+
+ FormFieldData field;
+ test::CreateTestFormField("First name:", "first_name", "Marion Mitchell",
+ "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Last name:", "last_name", "Morrison", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Email:", "email", "johnwayne@me.xyz", "text",
+ &field);
+ form.fields.push_back(field);
+ // This forms contains structured address information.
+ test::CreateTestFormField("Street Name:", "street_name", "Zoo St.", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("House Number:", "house_number", "123", "text",
+ &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City:", "city", "Hollywood", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("State:", "state", "CA", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Zip:", "zip", "91601", "text", &field);
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.DetermineHeuristicTypes();
+ ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
+
+ // The form submission should result in a change of the address structure.
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_AND_DEPENDENT_STREET_NAME,
+ base::ASCIIToUTF16("Zoo St."),
+ structured_address::VerificationStatus::kFormatted);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("Zoo St."),
+ structured_address::VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("123"),
+ structured_address::VerificationStatus::kObserved);
+
+ // Expect that no new profile is saved.
+ const std::vector<AutofillProfile*>& results =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(1U, results.size());
+ EXPECT_EQ(0, profile.Compare(*results[0]));
+}
+
// Tests that no profile is inferred if the country is not recognized.
TEST_P(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) {
FormData form;
@@ -1690,37 +1847,6 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_LocalizedCountryName) {
// Set the page language to match the localized country value and try again.
autofill_client_->GetLanguageState()->SetOriginalLanguage("de");
- // TODO(crbug.com/1075604): Remove test with disabled feature.
- // Verify that nothing is changed if using the page language feature is not
- // enabled.
- scoped_feature_list_.Reset();
- if (StructuredNames()) {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableSupportForMoreStructureInNames},
- {features::kAutofillUsePageLanguageToTranslateCountryNames});
- } else {
- scoped_feature_list_.InitWithFeatures(
- {}, {features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillUsePageLanguageToTranslateCountryNames});
- }
- ImportAddressProfiles(/*extraction_successful=*/false, form_structure);
-
- // There should be no imported address profile.
- ASSERT_EQ(0U, personal_data_manager_->GetProfiles().size());
- ASSERT_EQ(0U, personal_data_manager_->GetCreditCards().size());
-
- // Enable the feature and to test if the profile can now be imported.
- scoped_feature_list_.Reset();
- if (StructuredNames()) {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillEnableSupportForMoreStructureInNames,
- features::kAutofillUsePageLanguageToTranslateCountryNames},
- {});
- } else {
- scoped_feature_list_.InitWithFeatures(
- {features::kAutofillUsePageLanguageToTranslateCountryNames},
- {features::kAutofillEnableSupportForMoreStructureInNames});
- }
ImportAddressProfiles(/*extraction_successful=*/true, form_structure);
// There should be one imported address profile.
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.cc b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
index 123f7878008..6ed67749e2f 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
@@ -14,10 +14,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
using base::UTF8ToUTF16;
@@ -58,9 +58,21 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
base::string16 attention_ignored = UTF8ToUTF16(kAttentionIgnoredRe);
base::string16 region_ignored = UTF8ToUTF16(kRegionIgnoredRe);
- const bool is_enabled_merged_city_state_country_zip =
- base::FeatureList::IsEnabled(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
+ // In JSON : EMAIL_ADDRESS
+ auto& patterns_email = PatternProvider::GetInstance().GetMatchPatterns(
+ "EMAIL_ADDRESS", page_language);
+ // In JSON : ADDRESS_LOOKUP
+ auto& patterns_al = PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_LOOKUP", page_language);
+ // In JSON : ADDRESS_NAME_IGNORED
+ auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_NAME_IGNORED", page_language);
+ // In JSON : ATTENTION_IGNORED
+ auto& patterns_ai = PatternProvider::GetInstance().GetMatchPatterns(
+ "ATTENTION_IGNORED", page_language);
+ // In JSON : REGION_IGNORED
+ auto& patterns_ri = PatternProvider::GetInstance().GetMatchPatterns(
+ "REGION_IGNORED", page_language);
// Allow address fields to appear in any order.
size_t begin_trailing_non_labeled_fields = 0;
@@ -68,28 +80,28 @@ std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner,
while (!scanner->IsEnd()) {
const size_t cursor = scanner->SaveCursor();
// Ignore "Address Lookup" field. http://crbug.com/427622
- if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe), nullptr,
- {log_manager, "kAddressLookupRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kAddressNameIgnoredRe), nullptr,
+ if (ParseField(scanner, base::UTF8ToUTF16(kAddressLookupRe), patterns_al,
+ nullptr, {log_manager, "kAddressLookupRe"}) ||
+ ParseField(scanner, base::UTF8ToUTF16(kAddressNameIgnoredRe),
+ patterns_ni, nullptr,
{log_manager, "kAddressNameIgnoreRe"})) {
continue;
// Ignore email addresses.
} else if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
- MATCH_DEFAULT | MATCH_TEXT_AREA, nullptr,
- {log_manager, "kEmailRe"})) {
+ MATCH_DEFAULT | MATCH_TEXT_AREA,
+ patterns_email, nullptr,
+ {log_manager, "kEmailRe"},
+ {.augment_types = MATCH_TEXT_AREA})) {
continue;
- } else if (address_field->ParseAddress(scanner) ||
- (!is_enabled_merged_city_state_country_zip &&
- (address_field->ParseCityStateZipCode(scanner) ||
- address_field->ParseCountry(scanner))) ||
- (is_enabled_merged_city_state_country_zip &&
- address_field->ParseCityStateCountryZipCode(scanner)) ||
- address_field->ParseCompany(scanner)) {
+ } else if (address_field->ParseAddress(scanner, page_language) ||
+ address_field->ParseCityStateCountryZipCode(scanner,
+ page_language) ||
+ address_field->ParseCompany(scanner, page_language)) {
has_trailing_non_labeled_fields = false;
continue;
- } else if (ParseField(scanner, attention_ignored, nullptr,
+ } else if (ParseField(scanner, attention_ignored, patterns_ai, nullptr,
{log_manager, "kAttentionIgnoredRe"}) ||
- ParseField(scanner, region_ignored, nullptr,
+ ParseField(scanner, region_ignored, patterns_ri, nullptr,
{log_manager, "kRegionIgnoredRe"})) {
// We ignore the following:
// * Attention.
@@ -170,15 +182,20 @@ void AddressField::AddClassifications(
kBaseAddressParserScore, field_candidates);
}
-bool AddressField::ParseCompany(AutofillScanner* scanner) {
+bool AddressField::ParseCompany(AutofillScanner* scanner,
+ const std::string& page_language) {
if (company_)
return false;
+ // In JSON : COMPANY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COMPANY", page_language);
- return ParseField(scanner, UTF8ToUTF16(kCompanyRe), &company_,
+ return ParseField(scanner, UTF8ToUTF16(kCompanyRe), patterns_c, &company_,
{log_manager_, "kCompanyRe"});
}
-bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner) {
+bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner,
+ const std::string& page_language) {
// Search for a sequence of a street name field followed by a house number
// field. Only if both are found in an abitrary order, the parsing is
// considered successful.
@@ -190,16 +207,24 @@ bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner) {
}
const size_t cursor_position = scanner->CursorPosition();
+ // In JSON : ---- maybe ADDRESS_LINE1(2,3)
+ auto& patterns_s = PatternProvider::GetInstance().GetMatchPatterns(
+ ADDRESS_HOME_STREET_NAME, page_language);
+ // In JSON : ----
+ auto& patterns_h = PatternProvider::GetInstance().GetMatchPatterns(
+ ADDRESS_HOME_HOUSE_NUMBER, page_language);
while (!scanner->IsEnd()) {
if (!street_name_ &&
ParseFieldSpecifics(scanner, UTF8ToUTF16(kStreetNameRe), MATCH_DEFAULT,
- &street_name_, {log_manager_, "kStreetNameRe"})) {
+ patterns_s, &street_name_,
+ {log_manager_, "kStreetNameRe"})) {
continue;
}
if (!house_number_ &&
ParseFieldSpecifics(scanner, UTF8ToUTF16(kHouseNumberRe), MATCH_DEFAULT,
- &house_number_, {log_manager_, "kHouseNumberRe"})) {
+ patterns_h, &house_number_,
+ {log_manager_, "kHouseNumberRe"})) {
continue;
}
@@ -218,14 +243,17 @@ bool AddressField::ParseAddressFieldSequence(AutofillScanner* scanner) {
return false;
}
-bool AddressField::ParseAddress(AutofillScanner* scanner) {
+bool AddressField::ParseAddress(AutofillScanner* scanner,
+ const std::string& page_language) {
if (street_name_ && house_number_) {
return false;
}
- return ParseAddressFieldSequence(scanner) || ParseAddressLines(scanner);
+ return ParseAddressFieldSequence(scanner, page_language) ||
+ ParseAddressLines(scanner, page_language);
}
-bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
+bool AddressField::ParseAddressLines(AutofillScanner* scanner,
+ const std::string& page_language) {
// We only match the string "address" in page text, not in element names,
// because sometimes every element in a group of address fields will have
// a name containing the string "address"; for example, on the page
@@ -239,17 +267,23 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
base::string16 pattern = UTF8ToUTF16(kAddressLine1Re);
base::string16 label_pattern = UTF8ToUTF16(kAddressLine1LabelRe);
- if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, &address1_,
- {log_manager_, "kAddressLine1Re"}) &&
+ // In JSON : ADDRESS_LINE_1
+ auto& patterns_l1 = PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_LINE_1", page_language);
+
+ if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, patterns_l1,
+ &address1_, {log_manager_, "kAddressLine1Re"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address1_,
+ patterns_l1, &address1_,
{log_manager_, "kAddressLine1LabelRe"}) &&
!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_TEXT_AREA,
- &street_address_,
- {log_manager_, "kAddressLine1Re"}) &&
- !ParseFieldSpecifics(scanner, label_pattern,
- MATCH_LABEL | MATCH_TEXT_AREA, &street_address_,
- {log_manager_, "kAddressLine1LabelRe"}))
+ patterns_l1, &street_address_,
+ {log_manager_, "kAddressLine1Re"},
+ {.augment_types = MATCH_TEXT_AREA}) &&
+ !ParseFieldSpecifics(
+ scanner, label_pattern, MATCH_LABEL | MATCH_TEXT_AREA, patterns_l1,
+ &street_address_, {log_manager_, "kAddressLine1LabelRe"},
+ {.augment_types = MATCH_TEXT_AREA}))
return false;
if (street_address_)
@@ -260,19 +294,33 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
// discussion on https://codereview.chromium.org/741493003/
pattern = UTF8ToUTF16(kAddressLine2Re);
label_pattern = UTF8ToUTF16(kAddressLine2LabelRe);
- if (!ParseField(scanner, pattern, &address2_,
+ // auto& patternsL2 = PatternProvider::GetInstance().GetMatchPatterns(
+ // "ADDRESS_HOME_LINE2", page_language);
+ // auto& patternsSA = PatternProvider::GetInstance().GetMatchPatterns(
+ // "ADDRESS_HOME_STREET_ADDRESS", page_language);
+
+ // In JSON : ADDRESS_LINE_2
+ auto& patterns_l2 = PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_LINE_2", page_language);
+ // In JSON : ADDRESS_LINE_EXTRA
+ auto& patterns_le = PatternProvider::GetInstance().GetMatchPatterns(
+ "ADDRESS_LINE_EXTRA", page_language);
+
+ if (!ParseField(scanner, pattern, patterns_l2, &address2_,
{log_manager_, "kAddressLine2Re"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address2_, {log_manager_, "kAddressLine2LabelRe"}))
+ patterns_l2, &address2_,
+ {log_manager_, "kAddressLine2LabelRe"}))
return true;
// Optionally parse address line 3. This uses the same label regexp as
// address 2 above.
pattern = UTF8ToUTF16(kAddressLinesExtraRe);
- if (!ParseField(scanner, pattern, &address3_,
+ if (!ParseField(scanner, pattern, patterns_le, &address3_,
{log_manager_, "kAddressLinesExtraRe"}) &&
!ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- &address3_, {log_manager_, "kAddressLine2LabelRe"}))
+ patterns_l2, &address3_,
+ {log_manager_, "kAddressLine2LabelRe"}))
return true;
// Try for surplus lines, which we will promptly discard. Some pages have 4
@@ -281,21 +329,29 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner) {
// Since these are rare, don't bother considering unlabeled lines as extra
// address lines.
pattern = UTF8ToUTF16(kAddressLinesExtraRe);
- while (ParseField(scanner, pattern, nullptr,
+ while (ParseField(scanner, pattern, patterns_le, nullptr,
{log_manager_, "kAddressLinesExtraRe"})) {
// Consumed a surplus line, try for another.
}
return true;
}
-bool AddressField::ParseCountry(AutofillScanner* scanner) {
+bool AddressField::ParseCountry(AutofillScanner* scanner,
+ const std::string& page_language) {
if (country_)
return false;
+ // In JSON : COUNTRY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
+ auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
+ "COUNTRY_LOCATION", page_language);
+
scanner->SaveCursor();
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kCountryRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- &country_, {log_manager_, "kCountryRe"})) {
+ patterns_c, &country_,
+ {log_manager_, "kCountryRe"})) {
return true;
}
@@ -304,46 +360,67 @@ bool AddressField::ParseCountry(AutofillScanner* scanner) {
scanner->Rewind();
return ParseFieldSpecifics(
scanner, UTF8ToUTF16(kCountryLocationRe),
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, &country_,
- {log_manager_, "kCountryLocationRe"});
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
+ &country_, {log_manager_, "kCountryLocationRe"});
}
-bool AddressField::ParseZipCode(AutofillScanner* scanner) {
+bool AddressField::ParseZipCode(AutofillScanner* scanner,
+ const std::string& page_language) {
if (zip_)
return false;
+ // auto& patternsZ = PatternProvider::GetInstance().GetMatchPatterns(
+ // "ADDRESS_HOME_ZIP", page_language);
+ // In JSON : ZIP_CODE
+ auto& patterns_z = PatternProvider::GetInstance().GetMatchPatterns(
+ "ZIP_CODE", page_language);
+ // In JSON : ZIP_4
+ auto& patterns_z4 =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
if (!ParseFieldSpecifics(scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType,
- &zip_, {log_manager_, "kZipCodeRe"})) {
+ patterns_z, &zip_, {log_manager_, "kZipCodeRe"})) {
return false;
}
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
- ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType, &zip4_,
- {log_manager_, "kZip4Re"});
+ ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
+ patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
return true;
}
-bool AddressField::ParseCity(AutofillScanner* scanner) {
+bool AddressField::ParseCity(AutofillScanner* scanner,
+ const std::string& page_language) {
if (city_)
return false;
+ // In JSON : CITY
+ auto& patterns_city =
+ PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kCityRe), kCityMatchType,
- &city_, {log_manager_, "kCityRe"});
+ patterns_city, &city_, {log_manager_, "kCityRe"});
}
-bool AddressField::ParseState(AutofillScanner* scanner) {
+bool AddressField::ParseState(AutofillScanner* scanner,
+ const std::string& page_language) {
if (state_)
return false;
+ // auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ // "ADDRESS_HOME_STATE", page_language);
+ // In JSON : STATE
+ auto& patterns_state =
+ PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseFieldSpecifics(scanner, UTF8ToUTF16(kStateRe), kStateMatchType,
- &state_, {log_manager_, "kStateRe"});
+ patterns_state, &state_,
+ {log_manager_, "kStateRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const base::string16& pattern,
int match_type,
+ const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging) {
if (scanner->IsEnd())
@@ -352,10 +429,12 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillField* cur_match = nullptr;
size_t saved_cursor = scanner->SaveCursor();
bool parsed_name = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_LABEL, &cur_match, logging);
+ scanner, pattern, match_type & ~MATCH_LABEL, patterns, &cur_match,
+ logging, {.restrict_attributes = MATCH_NAME});
scanner->RewindTo(saved_cursor);
bool parsed_label = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_NAME, &cur_match, logging);
+ scanner, pattern, match_type & ~MATCH_NAME, patterns, &cur_match, logging,
+ {.restrict_attributes = MATCH_LABEL});
if (parsed_name && parsed_label) {
if (match)
*match = cur_match;
@@ -370,60 +449,9 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
return RESULT_MATCH_NONE;
}
-bool AddressField::ParseCityStateZipCode(AutofillScanner* scanner) {
- // Simple cases.
- if (scanner->IsEnd())
- return false;
- if (city_ && state_ && zip_)
- return false;
- if (state_ && zip_)
- return ParseCity(scanner);
- if (city_ && zip_)
- return ParseState(scanner);
- if (city_ && state_)
- return ParseZipCode(scanner);
-
- // Check for matches to both name and label.
- ParseNameLabelResult city_result = ParseNameAndLabelForCity(scanner);
- if (city_result == RESULT_MATCH_NAME_LABEL)
- return true;
- ParseNameLabelResult state_result = ParseNameAndLabelForState(scanner);
- if (state_result == RESULT_MATCH_NAME_LABEL)
- return true;
- ParseNameLabelResult zip_result = ParseNameAndLabelForZipCode(scanner);
- if (zip_result == RESULT_MATCH_NAME_LABEL)
- return true;
-
- // Check if there is only one potential match.
- bool maybe_city = city_result != RESULT_MATCH_NONE;
- bool maybe_state = state_result != RESULT_MATCH_NONE;
- bool maybe_zip = zip_result != RESULT_MATCH_NONE;
- if (maybe_city && !maybe_state && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (maybe_state && !maybe_city && !maybe_zip)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (maybe_zip && !maybe_city && !maybe_state)
- return ParseZipCode(scanner);
-
- // Otherwise give name priority over label.
- if (city_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_NAME)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (zip_result == RESULT_MATCH_NAME)
- return ParseZipCode(scanner);
-
- if (city_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &city_);
- if (state_result == RESULT_MATCH_LABEL)
- return SetFieldAndAdvanceCursor(scanner, &state_);
- if (zip_result == RESULT_MATCH_LABEL)
- return ParseZipCode(scanner);
-
- return false;
-}
-
-bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
+bool AddressField::ParseCityStateCountryZipCode(
+ AutofillScanner* scanner,
+ const std::string& page_language) {
// The |scanner| is not pointing at a field.
if (scanner->IsEnd())
return false;
@@ -434,25 +462,29 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
// Exactly one field type is missing.
if (state_ && country_ && zip_)
- return ParseCity(scanner);
+ return ParseCity(scanner, page_language);
if (city_ && country_ && zip_)
- return ParseState(scanner);
+ return ParseState(scanner, page_language);
if (city_ && state_ && zip_)
- return ParseCountry(scanner);
+ return ParseCountry(scanner, page_language);
if (city_ && state_ && country_)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
// Check for matches to both the name and the label.
- ParseNameLabelResult city_result = ParseNameAndLabelForCity(scanner);
+ ParseNameLabelResult city_result =
+ ParseNameAndLabelForCity(scanner, page_language);
if (city_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult state_result = ParseNameAndLabelForState(scanner);
+ ParseNameLabelResult state_result =
+ ParseNameAndLabelForState(scanner, page_language);
if (state_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult country_result = ParseNameAndLabelForCountry(scanner);
+ ParseNameLabelResult country_result =
+ ParseNameAndLabelForCountry(scanner, page_language);
if (country_result == RESULT_MATCH_NAME_LABEL)
return true;
- ParseNameLabelResult zip_result = ParseNameAndLabelForZipCode(scanner);
+ ParseNameLabelResult zip_result =
+ ParseNameAndLabelForZipCode(scanner, page_language);
if (zip_result == RESULT_MATCH_NAME_LABEL)
return true;
@@ -468,7 +500,7 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
if (maybe_country && !maybe_city && !maybe_state && !maybe_zip)
return SetFieldAndAdvanceCursor(scanner, &country_);
if (maybe_zip && !maybe_city && !maybe_state && !maybe_country)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
// If there is a clash between the country and the state, set the type of
// the field to the country.
@@ -483,7 +515,7 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
if (country_result == RESULT_MATCH_NAME)
return SetFieldAndAdvanceCursor(scanner, &country_);
if (zip_result == RESULT_MATCH_NAME)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
if (city_result == RESULT_MATCH_LABEL)
return SetFieldAndAdvanceCursor(scanner, &city_);
@@ -492,30 +524,38 @@ bool AddressField::ParseCityStateCountryZipCode(AutofillScanner* scanner) {
if (country_result == RESULT_MATCH_LABEL)
return SetFieldAndAdvanceCursor(scanner, &country_);
if (zip_result == RESULT_MATCH_LABEL)
- return ParseZipCode(scanner);
+ return ParseZipCode(scanner, page_language);
return false;
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (zip_)
return RESULT_MATCH_NONE;
+ // In JSON : ZIP_CODE
+ auto& patterns_z = PatternProvider::GetInstance().GetMatchPatterns(
+ "ZIP_CODE", page_language);
+ // In JSON :
+ auto& patterns_z4 =
+ PatternProvider::GetInstance().GetMatchPatterns("ZIP_4", page_language);
+
ParseNameLabelResult result = ParseNameAndLabelSeparately(
- scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, &zip_,
+ scanner, UTF8ToUTF16(kZipCodeRe), kZipCodeMatchType, patterns_z, &zip_,
{log_manager_, "kZipCodeRe"});
if (result != RESULT_MATCH_NAME_LABEL || scanner->IsEnd())
return result;
size_t saved_cursor = scanner->SaveCursor();
- bool found_non_zip4 = ParseCity(scanner);
+ bool found_non_zip4 = ParseCity(scanner, page_language);
if (found_non_zip4)
city_ = nullptr;
scanner->RewindTo(saved_cursor);
if (!found_non_zip4) {
- found_non_zip4 = ParseState(scanner);
+ found_non_zip4 = ParseState(scanner, page_language);
if (found_non_zip4)
state_ = nullptr;
scanner->RewindTo(saved_cursor);
@@ -525,40 +565,55 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForZipCode(
// Look for a zip+4, whose field name will also often contain
// the substring "zip".
ParseFieldSpecifics(scanner, UTF8ToUTF16(kZip4Re), kZipCodeMatchType,
- &zip4_, {log_manager_, "kZip4Re"});
+ patterns_z4, &zip4_, {log_manager_, "kZip4Re"});
}
return result;
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCity(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (city_)
return RESULT_MATCH_NONE;
+ // In JSON : CITY
+ auto& patterns_city =
+ PatternProvider::GetInstance().GetMatchPatterns("CITY", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kCityRe),
- kCityMatchType, &city_,
+ kCityMatchType, patterns_city, &city_,
{log_manager_, "kCityRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForState(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (state_)
return RESULT_MATCH_NONE;
+ // In JSON : STATE
+ auto& patterns_state =
+ PatternProvider::GetInstance().GetMatchPatterns("STATE", page_language);
return ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kStateRe),
- kStateMatchType, &state_,
+ kStateMatchType, patterns_state, &state_,
{log_manager_, "kStateRe"});
}
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
- AutofillScanner* scanner) {
+ AutofillScanner* scanner,
+ const std::string& page_language) {
if (country_)
return RESULT_MATCH_NONE;
- ParseNameLabelResult country_result =
- ParseNameAndLabelSeparately(scanner, UTF8ToUTF16(kCountryRe),
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- &country_, {log_manager_, "kCountryRe"});
+ // In JSON : COUNTRY
+ auto& patterns_c =
+ PatternProvider::GetInstance().GetMatchPatterns("COUNTRY", page_language);
+ auto& patterns_cl = PatternProvider::GetInstance().GetMatchPatterns(
+ "COUNTRY_LOCATION", page_language);
+
+ ParseNameLabelResult country_result = ParseNameAndLabelSeparately(
+ scanner, UTF8ToUTF16(kCountryRe),
+ MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH, patterns_c, &country_,
+ {log_manager_, "kCountryRe"});
if (country_result != RESULT_MATCH_NONE)
return country_result;
@@ -566,8 +621,8 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
// "location". However, this only makes sense for select tags.
return ParseNameAndLabelSeparately(
scanner, UTF8ToUTF16(kCountryLocationRe),
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, &country_,
- {log_manager_, "kCountryLocationRe"});
+ MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, patterns_cl,
+ &country_, {log_manager_, "kCountryLocationRe"});
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.h b/chromium/components/autofill/core/browser/form_parsing/address_field.h
index 4fb2c6c6758..0ee62ee3853 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.h
@@ -14,6 +14,7 @@
#include "base/strings/string16.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
@@ -53,45 +54,70 @@ class AddressField : public FormField {
explicit AddressField(LogManager* log_manager);
- bool ParseCompany(AutofillScanner* scanner);
- bool ParseAddress(AutofillScanner* scanner);
- bool ParseAddressFieldSequence(AutofillScanner* scanner);
- bool ParseAddressLines(AutofillScanner* scanner);
- bool ParseCountry(AutofillScanner* scanner);
- bool ParseZipCode(AutofillScanner* scanner);
- bool ParseCity(AutofillScanner* scanner);
- bool ParseState(AutofillScanner* scanner);
+ bool ParseCompany(AutofillScanner* scanner, const std::string& page_language);
- // Parses the current field pointed to by |scanner|, if it exists, and tries
- // to figure out whether the field's type: city, state, zip, or none of those.
- // TODO(crbug.com/1073555) Delete this once experiment
- // |kAutofillUseParseCityStateCountryZipCodeInHeuristic| has been launched.
- bool ParseCityStateZipCode(AutofillScanner* scanner);
+ bool ParseAddress(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseAddressFieldSequence(AutofillScanner* scanner,
+ const std::string& page_language);
+
+ bool ParseAddressLines(AutofillScanner* scanner,
+ const std::string& page_language);
+
+ bool ParseCountry(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseZipCode(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseCity(AutofillScanner* scanner, const std::string& page_language);
+
+ bool ParseState(AutofillScanner* scanner, const std::string& page_language);
// Parses the current field pointed to by |scanner|, if it exists, and tries
// to figure out whether the field's type: city, state, country, zip, or
// none of those.
- bool ParseCityStateCountryZipCode(AutofillScanner* scanner);
+ bool ParseCityStateCountryZipCode(AutofillScanner* scanner,
+ const std::string& page_language);
// Like ParseFieldSpecifics(), but applies |pattern| against the name and
// label of the current field separately. If the return value is
// RESULT_MATCH_NAME_LABEL, then |scanner| advances and |match| is filled if
// it is non-NULL. Otherwise |scanner| does not advance and |match| does not
// change.
+ // ParseNameLabelResult ParseNameAndLabelSeparately(
+ // AutofillScanner* scanner,
+ // const base::string16& pattern,
+ // int match_type,
+ // AutofillField** match,
+ // const RegExLogging& logging);
+
+ // New version of function above using new structure MatchingPattern and
+ // PatternProvider.
ParseNameLabelResult ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const base::string16& pattern,
int match_type,
+ const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging);
// Run matches on the name and label separately. If the return result is
// RESULT_MATCH_NAME_LABEL, then |scanner| advances and the field is set.
// Otherwise |scanner| rewinds and the field is cleared.
- ParseNameLabelResult ParseNameAndLabelForZipCode(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForCity(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForCountry(AutofillScanner* scanner);
- ParseNameLabelResult ParseNameAndLabelForState(AutofillScanner* scanner);
+ ParseNameLabelResult ParseNameAndLabelForZipCode(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForCity(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForCountry(
+ AutofillScanner* scanner,
+ const std::string& page_language);
+
+ ParseNameLabelResult ParseNameAndLabelForState(
+ AutofillScanner* scanner,
+ const std::string& page_language);
LogManager* log_manager_;
AutofillField* company_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
index 9b59b7c455b..bc6e0908571 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field_unittest.cc
@@ -14,6 +14,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,13 +25,11 @@ namespace autofill {
class AddressFieldTest : public testing::Test {
public:
- AddressFieldTest() {}
+ AddressFieldTest() = default;
+ AddressFieldTest(const AddressFieldTest&) = delete;
+ AddressFieldTest& operator=(const AddressFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<AddressField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<AddressField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -41,8 +40,12 @@ class AddressFieldTest : public testing::Test {
static_cast<AddressField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(AddressFieldTest);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<AddressField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(AddressFieldTest, Empty) {
@@ -160,6 +163,104 @@ TEST_F(AddressFieldTest, ParseStreetAddressFromTextArea) {
field_candidates_map_[ASCIIToUTF16("addr")].BestHeuristicType());
}
+// Tests that fields are classified as |ADDRESS_HOME_STREET_NAME| and
+// |ADDRESS_HOME_HOUSE_NUMBER| when they are labeled accordingly and
+// both are present.
+TEST_F(AddressFieldTest, ParseStreetNameAndHouseNumber) {
+ // TODO(crbug.com/1125978): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableSupportForMoreStructureInAddresses);
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Street");
+ field.name = ASCIIToUTF16("street");
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("street")));
+
+ field.label = ASCIIToUTF16("House number");
+ field.name = ASCIIToUTF16("house-number");
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("house")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+ ASSERT_NE(nullptr, field_.get());
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("street")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(ADDRESS_HOME_STREET_NAME,
+ field_candidates_map_[ASCIIToUTF16("street")].BestHeuristicType());
+
+ ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("house")) !=
+ field_candidates_map_.end());
+ EXPECT_EQ(ADDRESS_HOME_HOUSE_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("house")].BestHeuristicType());
+}
+
+// Tests that the field is not classified as |ADDRESS_HOME_STREET_NAME| when
+// it is labeled accordingly but adjacent field classified as
+// |ADDRESS_HOME_HOUSE_NUMBER| is absent.
+TEST_F(AddressFieldTest, NotParseStreetNameWithoutHouseNumber) {
+ // TODO(crbug.com/1125978): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableSupportForMoreStructureInAddresses);
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("Street");
+ field.name = ASCIIToUTF16("street");
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("street")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+
+ if (!field_.get())
+ return;
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+ if (field_candidates_map_.empty())
+ return;
+
+ EXPECT_NE(ADDRESS_HOME_STREET_NAME,
+ field_candidates_map_[ASCIIToUTF16("street")].BestHeuristicType());
+}
+
+// Tests that the field is not classified as |ADDRESS_HOME_HOUSE_NUMBER| when
+// it is labeled accordingly but adjacent field classified as
+// |ADDRESS_HOME_STREET_NAME| is absent.
+TEST_F(AddressFieldTest, NotParseHouseNumberWithoutStreetName) {
+ // TODO(crbug.com/1125978): Remove once launched.
+ base::test::ScopedFeatureList enabled;
+ enabled.InitAndEnableFeature(
+ features::kAutofillEnableSupportForMoreStructureInAddresses);
+
+ FormFieldData field;
+ field.form_control_type = "text";
+
+ field.label = ASCIIToUTF16("House number");
+ field.name = ASCIIToUTF16("house-number");
+ list_.push_back(
+ std::make_unique<AutofillField>(field, ASCIIToUTF16("house")));
+
+ AutofillScanner scanner(list_);
+ field_ = Parse(&scanner);
+
+ if (!field_.get())
+ return;
+ field_->AddClassificationsForTesting(&field_candidates_map_);
+ if (field_candidates_map_.empty())
+ return;
+
+ EXPECT_NE(ADDRESS_HOME_HOUSE_NUMBER,
+ field_candidates_map_[ASCIIToUTF16("house")].BestHeuristicType());
+}
+
TEST_F(AddressFieldTest, ParseCity) {
FormFieldData field;
field.form_control_type = "text";
@@ -308,10 +409,6 @@ TEST_F(AddressFieldTest, ParseCityStateCountryZipcodeTogether) {
field.name = ASCIIToUTF16("zip");
list_.push_back(std::make_unique<AutofillField>(field, ASCIIToUTF16("zip1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
@@ -350,10 +447,6 @@ TEST_F(AddressFieldTest, ParseCountryLabelRegion) {
list_.push_back(
std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
@@ -377,10 +470,6 @@ TEST_F(AddressFieldTest, ParseCountryNameRegion) {
list_.push_back(
std::make_unique<AutofillField>(field, ASCIIToUTF16("country1")));
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(
- features::kAutofillUseParseCityStateCountryZipCodeInHeuristic);
-
AutofillScanner scanner(list_);
field_ = Parse(&scanner);
ASSERT_NE(nullptr, field_.get());
diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
index d9fc85afdce..ddd418eca54 100644
--- a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.cc
@@ -13,31 +13,4 @@ MatchingPattern& MatchingPattern::operator=(const MatchingPattern& mp) =
MatchingPattern::~MatchingPattern() = default;
-autofill::MatchingPattern GetCompanyPatternEn() {
- autofill::MatchingPattern m_p;
- m_p.pattern_identifier = "kCompanyPatternEn";
- m_p.positive_pattern = "company|business|organization|organisation";
- m_p.positive_score = 1.1f;
- m_p.negative_pattern = "";
- m_p.match_field_attributes = MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "en";
-
- return m_p;
-}
-
-autofill::MatchingPattern GetCompanyPatternDe() {
- autofill::MatchingPattern m_p;
-
- m_p.pattern_identifier = "kCompanyPatternDe";
- m_p.positive_pattern = "|(?<!con)firma|firmenname";
- m_p.positive_score = 1.1f;
- m_p.negative_pattern = "";
- m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
- m_p.language = "de";
-
- return m_p;
-}
-
-} // namespace autofill \ No newline at end of file
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
index 8335c216c20..b24b5b5a5d7 100644
--- a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
+++ b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_AUTOFILL_PARSING_UTILS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_AUTOFILL_PARSING_UTILS_H_
+#include <base/optional.h>
#include <string>
namespace autofill {
@@ -51,17 +52,12 @@ struct MatchingPattern {
std::string pattern_identifier;
std::string positive_pattern;
float positive_score = 1.1f;
- std::string negative_pattern;
+ base::Optional<std::string> negative_pattern;
int match_field_attributes;
int match_field_input_types;
std::string language;
};
-// Use these functions instead of storing "non standats type" constants that
-// bots might complaining over.
-MatchingPattern GetCompanyPatternEn();
-MatchingPattern GetCompanyPatternDe();
-
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_PARSING_UTILS_H_
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 766a9a00fda..27ee112a819 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -17,13 +17,13 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/field_filler.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -92,16 +92,28 @@ std::unique_ptr<FormField> CreditCardField::Parse(
size_t saved_cursor = scanner->SaveCursor();
int nb_unknown_fields = 0;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_ON_CARD", page_language);
+ // In JSON : NAME_ON_CARD_CONTEXTUAL
+ auto& patterns_cont = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_ON_CARD_CONTEXTUAL", page_language);
+ // In JSON : LAST_NAME
+ auto& patterns_nl = PatternProvider::GetInstance().GetMatchPatterns(
+ "LAST_NAME", page_language);
+ // In JSON : CARD_CVC
+ auto& patterns_cvc = PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_VERIFICATION_CODE, page_language);
+
// Credit card fields can appear in many different orders.
// We loop until no more credit card related fields are found, see |break| at
// the bottom of the loop.
for (int fields = 0; !scanner->IsEnd(); ++fields) {
// Ignore gift card fields.
- if (IsGiftCardField(scanner, log_manager))
+ if (IsGiftCardField(scanner, log_manager, page_language))
break;
if (!credit_card_field->cardholder_) {
- if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe),
+ if (ParseField(scanner, base::UTF8ToUTF16(kNameOnCardRe), patterns,
&credit_card_field->cardholder_,
{log_manager, "kNameOnCardRe"})) {
continue;
@@ -113,9 +125,10 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// fields. So we search for "name" only when we've already parsed at
// least one other credit card field and haven't yet parsed the
// expiration date (which usually appears at the end).
+
if (fields > 0 && !credit_card_field->expiration_month_ &&
ParseField(scanner, base::UTF8ToUTF16(kNameOnCardContextualRe),
- &credit_card_field->cardholder_,
+ patterns_cont, &credit_card_field->cardholder_,
{log_manager, "kNameOnCardContextualRe"})) {
continue;
}
@@ -125,7 +138,7 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// and haven't yet parsed the expiration date (which usually appears at
// the end).
if (!credit_card_field->expiration_month_ &&
- ParseField(scanner, base::UTF8ToUTF16(kLastNameRe),
+ ParseField(scanner, base::UTF8ToUTF16(kLastNameRe), patterns_nl,
&credit_card_field->cardholder_last_,
{log_manager, "kLastNameRe"})) {
continue;
@@ -150,10 +163,12 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// They also sometimes use type="password" for sensitive types.
const int kMatchNumTelAndPwd =
MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_PASSWORD;
+
if (!credit_card_field->verification_ &&
- ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kCardCvcRe), kMatchNumTelAndPwd,
- &credit_card_field->verification_, {log_manager, "kCardCvcRe"})) {
+ ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
+ kMatchNumTelAndPwd, patterns_cvc,
+ &credit_card_field->verification_,
+ {log_manager, "kCardCvcRe"})) {
// A couple of sites have multiple verification codes right after another.
// Allow the classification of these codes one by one.
AutofillField* const saved_cvv = credit_card_field->verification_;
@@ -165,8 +180,9 @@ std::unique_ptr<FormField> CreditCardField::Parse(
!credit_card_field->cardholder_ && scanner->SaveCursor() > 1) {
// Check if the previous field was a verification code.
scanner->RewindTo(scanner->SaveCursor() - 2);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardCvcRe),
- kMatchNumTelAndPwd,
+ kMatchNumTelAndPwd, patterns_cvc,
&credit_card_field->verification_,
{log_manager, "kCardCvcRe"})) {
// Reset the current cvv (The verification parse overwrote it).
@@ -189,8 +205,10 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// TODO(crbug.com/591816): Make sure parsing cc-numbers of type password
// doesn't have bad side effects.
AutofillField* current_number_field;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_NUMBER, page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kCardNumberRe),
- kMatchNumTelAndPwd, &current_number_field,
+ kMatchNumTelAndPwd, patterns, &current_number_field,
{log_manager, "kCardNumberRe"})) {
// Avoid autofilling any credit card number field having very low or high
// |start_index| on the HTML form.
@@ -215,7 +233,8 @@ std::unique_ptr<FormField> CreditCardField::Parse(
continue;
}
- if (credit_card_field->ParseExpirationDate(scanner, log_manager)) {
+ if (credit_card_field->ParseExpirationDate(scanner, log_manager,
+ page_language)) {
nb_unknown_fields = 0;
continue;
}
@@ -311,8 +330,10 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
}
// static
-bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner,
- LogManager* log_manager) {
+bool CreditCardField::LikelyCardYearSelectField(
+ AutofillScanner* scanner,
+ LogManager* log_manager,
+ const std::string& page_language) {
if (scanner->IsEnd())
return false;
@@ -331,9 +352,12 @@ bool CreditCardField::LikelyCardYearSelectField(AutofillScanner* scanner,
}
// Another way to eliminate days - filter out 'day' fields.
+ // In JSON : DAY (only in JSON)
+ auto& patterns_day =
+ PatternProvider::GetInstance().GetMatchPatterns("DAY", page_language);
if (FormField::ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDayRe),
- MATCH_DEFAULT | MATCH_SELECT, nullptr,
- {log_manager, "kDayRe"})) {
+ MATCH_DEFAULT | MATCH_SELECT, patterns_day,
+ nullptr, {log_manager, "kDayRe"})) {
return false;
}
@@ -389,28 +413,40 @@ bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
// static
bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
- LogManager* log_manager) {
+ LogManager* log_manager,
+ const std::string& page_language) {
if (scanner->IsEnd())
return false;
const int kMatchFieldTypes =
MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_SEARCH;
size_t saved_cursor = scanner->SaveCursor();
+
+ // In JSON : DEBIT_CARD (only in JSON)
+ auto& patterns_d = PatternProvider::GetInstance().GetMatchPatterns(
+ "DEBIT_CARD", page_language);
+ // In JSON : DEBIT_GIFT_CARD (only in JSON)
+ auto& patterns_dg = PatternProvider::GetInstance().GetMatchPatterns(
+ "DEBIT_GIFT_CARD", page_language);
+ // In JSON : GIFT_CARD (only in JSON)
+ auto& patterns_g = PatternProvider::GetInstance().GetMatchPatterns(
+ "GIFT_CARD", page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_d, nullptr,
{log_manager, "kDebitCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kDebitGiftCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_dg, nullptr,
{log_manager, "kDebitGiftCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kGiftCardRe),
- kMatchFieldTypes, nullptr,
+ kMatchFieldTypes, patterns_g, nullptr,
{log_manager, "kGiftCardRe"});
}
@@ -467,7 +503,8 @@ void CreditCardField::AddClassifications(
}
bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
- LogManager* log_manager) {
+ LogManager* log_manager,
+ const std::string& page_language) {
if (!expiration_date_ && base::LowerCaseEqualsASCII(
scanner->Cursor()->form_control_type, "month")) {
expiration_date_ = scanner->Cursor();
@@ -487,7 +524,7 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
if (LikelyCardMonthSelectField(scanner)) {
expiration_month_ = scanner->Cursor();
scanner->Advance();
- if (LikelyCardYearSelectField(scanner, log_manager)) {
+ if (LikelyCardYearSelectField(scanner, log_manager, page_language)) {
expiration_year_ = scanner->Cursor();
scanner->Advance();
return true;
@@ -500,11 +537,23 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
scanner->RewindTo(month_year_saved_cursor);
const int kMatchCCType = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE |
MATCH_SELECT | MATCH_SEARCH;
+
+ // In JSON : CARD_EXP_MONTH
+ auto& patterns_m = PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_EXP_MONTH, page_language);
+ // In JSON : CARD_EXP_YEAR
+ auto& patterns_y = PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_YEAR", page_language);
+ auto& patterns_mm = PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR", page_language);
+ auto& patterns_yy = PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_YEAR_AFTER_MONTH", page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationMonthRe),
- kMatchCCType, &expiration_month_,
+ kMatchCCType, patterns_m, &expiration_month_,
{log_manager_, "kExpirationMonthRe"}) &&
ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationYearRe),
- kMatchCCType, &expiration_year_,
+ kMatchCCType, patterns_y, &expiration_year_,
{log_manager_, "kExpirationYearRe"})) {
return true;
}
@@ -512,9 +561,10 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
// If that fails, look for just MM and/or YY(YY).
scanner->RewindTo(month_year_saved_cursor);
if (ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^mm$"), kMatchCCType,
- &expiration_month_, {log_manager_, "^mm$"}) &&
+ patterns_mm, &expiration_month_,
+ {log_manager_, "^mm$"}) &&
ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^(yy|yyyy)$"),
- kMatchCCType, &expiration_year_,
+ kMatchCCType, patterns_yy, &expiration_year_,
{log_manager_, "^(yy|yyyy)$"})) {
return true;
}
@@ -530,17 +580,23 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
return false;
// Try to look for a 2-digit year expiration date.
- if (ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kExpirationDate2DigitYearRe), kMatchCCType,
- &expiration_date_, {log_manager_, "kExpirationDate2DigitYearRe"})) {
+ // In JSON : CARD_EXP_DATE_2_DIGIT_YEAR
+ auto& patterns_2dy = PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, page_language);
+ if (ParseFieldSpecifics(scanner,
+ base::UTF8ToUTF16(kExpirationDate2DigitYearRe),
+ kMatchCCType, patterns_2dy, &expiration_date_,
+ {log_manager_, "kExpirationDate2DigitYearRe"})) {
exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
expiration_month_ = nullptr;
return true;
}
// Try to look for a generic expiration date field. (2 or 4 digit year)
+ auto& patterns_exp_d = PatternProvider::GetInstance().GetMatchPatterns(
+ "CREDIT_CARD_EXP_DATE", page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDateRe),
- kMatchCCType, &expiration_date_,
+ kMatchCCType, patterns_exp_d, &expiration_date_,
{log_manager_, "kExpirationDateRe"})) {
// If such a field exists, but it cannot fit a 4-digit year expiration
// date, then the likely possibility is that it is a 2-digit year expiration
@@ -554,11 +610,14 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
}
// Try to look for a 4-digit year expiration date.
+ auto& patterns_4dy = PatternProvider::GetInstance().GetMatchPatterns(
+ CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, page_language);
if (FieldCanFitDataForFieldType(current_field_max_length,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
- ParseFieldSpecifics(
- scanner, base::UTF8ToUTF16(kExpirationDate4DigitYearRe), kMatchCCType,
- &expiration_date_, {log_manager_, "kExpirationDate4DigitYearRe"})) {
+ ParseFieldSpecifics(scanner,
+ base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
+ kMatchCCType, patterns_4dy, &expiration_date_,
+ {log_manager_, "kExpirationDate4DigitYearRe"})) {
expiration_month_ = nullptr;
return true;
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
index 974219ba87e..a3aa409c065 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
@@ -42,7 +43,8 @@ class CreditCardField : public FormField {
// the next few years. |log_manager| is used to log any parsing details
// to chrome://autofill-internals
static bool LikelyCardYearSelectField(AutofillScanner* scanner,
- LogManager* log_manager);
+ LogManager* log_manager,
+ const std::string& page_language);
// Returns true if |scanner| points to a <select> field that contains credit
// card type options.
@@ -53,11 +55,14 @@ class CreditCardField : public FormField {
// Prepaid debit cards do not count as gift cards, since they can be used like
// a credit card.
static bool IsGiftCardField(AutofillScanner* scanner,
- LogManager* log_manager);
+ LogManager* log_manager,
+ const std::string& page_language);
// Parses the expiration month/year/date fields. Returns true if it finds
// something new.
- bool ParseExpirationDate(AutofillScanner* scanner, LogManager* log_manager);
+ bool ParseExpirationDate(AutofillScanner* scanner,
+ LogManager* log_manager,
+ const std::string& page_language);
// For the combined expiration field we return |exp_year_type_|; otherwise if
// |expiration_year_| is having year with |max_length| of 2-digits we return
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
index f5e0aab5013..9d9815c4269 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,14 +24,11 @@ namespace autofill {
class CreditCardFieldTestBase {
public:
- CreditCardFieldTestBase() {}
- ~CreditCardFieldTestBase() {}
+ CreditCardFieldTestBase() = default;
+ CreditCardFieldTestBase(const CreditCardFieldTestBase&) = delete;
+ CreditCardFieldTestBase& operator=(const CreditCardFieldTestBase&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<const CreditCardField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Parses the contents of |list_| as a form, and stores the result into
// |field_|.
void Parse() {
@@ -67,17 +65,20 @@ class CreditCardFieldTestBase {
return field_->AddClassifications(&field_candidates_map_);
}
- private:
- DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTestBase);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<const CreditCardField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
class CreditCardFieldTest : public CreditCardFieldTestBase,
public testing::Test {
public:
- CreditCardFieldTest() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CreditCardFieldTest);
+ CreditCardFieldTest() = default;
+ CreditCardFieldTest(const CreditCardFieldTest&) = delete;
+ CreditCardFieldTest& operator=(const CreditCardFieldTest&) = delete;
};
TEST_F(CreditCardFieldTest, Empty) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.cc b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
index ad2b95f68b4..99d87e8fc17 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
@@ -5,8 +5,8 @@
#include "components/autofill/core/browser/form_parsing/email_field.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -15,8 +15,10 @@ std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ "EMAIL_ADDRESS", page_language);
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kEmailRe),
- MATCH_DEFAULT | MATCH_EMAIL, &field,
+ MATCH_DEFAULT | MATCH_EMAIL, patterns, &field,
{log_manager, "kEmailRe"})) {
return std::make_unique<EmailField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.h b/chromium/components/autofill/core/browser/form_parsing/email_field.h
index ffcf2dda7a9..3765457f766 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.cc b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
index 10cbb1f9966..4b5f80e3ca8 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/address_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
@@ -33,7 +34,6 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
namespace autofill {
@@ -122,7 +122,7 @@ FieldCandidatesMap FormField::ParseFormFields(
// For <form> tags, make an exception for email fields, which are commonly
// the only recognized field on account registration sites.
const bool accept_parsing =
- fillable_fields >= MinRequiredFieldsForHeuristics() ||
+ fillable_fields >= kMinRequiredFieldsForHeuristics ||
(is_form_tag && email_count > 0);
if (!accept_parsing) {
@@ -168,6 +168,22 @@ bool FormField::ParseField(AutofillScanner* scanner,
return ParseFieldSpecifics(scanner, patterns, match, logging);
}
+bool FormField::ParseField(AutofillScanner* scanner,
+ const base::string16& pattern,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ return ParseField(scanner, patterns, match, logging);
+ } else {
+ return ParseField(scanner, pattern, match, logging);
+ }
+}
+
bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
const base::string16& pattern,
int match_field_attributes,
@@ -207,7 +223,9 @@ bool FormField::ParseFieldSpecifics(
if (base::FeatureList::IsEnabled(
features::
kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
- if (FormField::Match(field, base::UTF8ToUTF16(pattern.negative_pattern),
+ if (pattern.negative_pattern.has_value() &&
+ FormField::Match(field,
+ base::UTF8ToUTF16(pattern.negative_pattern.value()),
pattern.match_field_attributes,
pattern.match_field_input_types, logging)) {
continue;
@@ -220,7 +238,6 @@ bool FormField::ParseFieldSpecifics(
return true;
}
}
-
return false;
}
@@ -237,6 +254,38 @@ bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
match_field_types, match, logging);
}
+bool FormField::ParseFieldSpecifics(
+ AutofillScanner* scanner,
+ const base::string16& pattern,
+ int match_type,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging,
+ MatchFieldBitmasks match_field_bitmasks) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ // TODO(crbug/1142936): This hack is to allow
+ // AddressField::ParseNameAndLabelSeparately().
+ if (match_field_bitmasks.restrict_attributes != ~0 ||
+ match_field_bitmasks.augment_types != 0) {
+ std::vector<MatchingPattern> patterns_with_restricted_match_type =
+ patterns;
+ for (MatchingPattern& mp : patterns_with_restricted_match_type) {
+ mp.match_field_attributes &= match_field_bitmasks.restrict_attributes;
+ mp.match_field_input_types |= match_field_bitmasks.augment_types;
+ }
+ return ParseFieldSpecifics(scanner, patterns_with_restricted_match_type,
+ match, logging);
+ }
+ return ParseFieldSpecifics(scanner, patterns, match, logging);
+ } else {
+ return ParseFieldSpecifics(scanner, pattern, match_type, match, logging);
+ }
+}
+
// static
bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
AutofillField** match) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.h b/chromium/components/autofill/core/browser/form_parsing/form_field.h
index f2c17a629c5..7eca61ab200 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.h
@@ -72,6 +72,12 @@ class FormField {
AutofillField** match,
const RegExLogging& logging = {});
+ static bool ParseField(AutofillScanner* scanner,
+ const base::string16& pattern,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging = {});
+
// Parses the stream of fields in |scanner| with regular expression |pattern|
// as specified in the |match_type| bit field (see |MatchType|). If |match|
// is non-NULL and the pattern matches, |match| will be set to the matched
@@ -96,6 +102,20 @@ class FormField {
int match_field_input_types,
AutofillField** match,
const RegExLogging& logging = {});
+ struct MatchFieldBitmasks {
+ int restrict_attributes = ~0;
+ int augment_types = 0;
+ };
+
+ static bool ParseFieldSpecifics(AutofillScanner* scanner,
+ const base::string16& pattern,
+ int match_type,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging,
+ MatchFieldBitmasks match_field_bitmasks = {
+ .restrict_attributes = ~0,
+ .augment_types = 0});
// Attempts to parse a field with an empty label. Returns true
// on success and fills |match| with a pointer to the field.
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index 771275d5ecf..ed5baa21072 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -10,10 +10,10 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
-using autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics;
using autofill::features::kAutofillFixFillableFieldTypes;
using base::ASCIIToUTF16;
@@ -112,6 +112,8 @@ TEST(FormFieldTest, Match) {
// Test that we ignore checkable elements.
TEST(FormFieldTest, ParseFormFields) {
+ TestPatternProvider test_pattern_provider_;
+
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
@@ -135,66 +137,27 @@ TEST(FormFieldTest, ParseFormFields) {
std::make_unique<AutofillField>(field_data, field_data.label));
// Parse a single address line 1 field.
- {
- base::test::ScopedFeatureList enforce_min_fields;
- enforce_min_fields.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- ASSERT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
- }
- {
- base::test::ScopedFeatureList do_not_enforce_min_fields;
- do_not_enforce_min_fields.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- const FieldCandidatesMap field_candidates_map =
- FormField::ParseFormFields(fields, /*page_language=*/"", true);
- ASSERT_EQ(1u, field_candidates_map.size());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map.find(ASCIIToUTF16("Address line1"))
- ->second.BestHeuristicType());
- }
+ ASSERT_EQ(
+ 0u,
+ FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
// Parses address line 1 and 2.
field_data.label = ASCIIToUTF16("Address line2");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
- {
- base::test::ScopedFeatureList enforce_min_fields;
- enforce_min_fields.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- ASSERT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
- }
- {
- base::test::ScopedFeatureList do_not_enforce_min_fields;
- do_not_enforce_min_fields.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- const FieldCandidatesMap field_candidates_map =
- FormField::ParseFormFields(fields, /*page_language=*/"", true);
- ASSERT_EQ(2u, field_candidates_map.size());
- EXPECT_EQ(ADDRESS_HOME_LINE1,
- field_candidates_map.find(ASCIIToUTF16("Address line1"))
- ->second.BestHeuristicType());
- EXPECT_EQ(ADDRESS_HOME_LINE2,
- field_candidates_map.find(ASCIIToUTF16("Address line2"))
- ->second.BestHeuristicType());
- }
+ // An empty page_language means the language is unknown and patterns of
+ // all languages are used.
+ ASSERT_EQ(
+ 0u,
+ FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
}
// Test that the minimum number of required fields for the heuristics considers
// whether a field is actually fillable.
TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
+ TestPatternProvider test_pattern_provider_;
+
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
@@ -208,16 +171,11 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
std::make_unique<AutofillField>(field_data, field_data.label));
// Don't parse forms with 2 fields.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- // An empty page_language means the language is unknown and patterns of all
- // languages are used.
- EXPECT_EQ(
- 0u,
- FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
- }
+ // An empty page_language means the language is unknown and patterns of all
+ // languages are used.
+ EXPECT_EQ(
+ 0u,
+ FormField::ParseFormFields(fields, /*page_language=*/"", true).size());
field_data.label = ASCIIToUTF16("Search");
fields.push_back(
@@ -227,10 +185,7 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// now, although a search field is not fillable.
{
base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/
- {kAutofillEnforceMinRequiredFieldsForHeuristics},
- /*disabled_features=*/{kAutofillFixFillableFieldTypes});
+ feature_list.InitAndDisableFeature(kAutofillFixFillableFieldTypes);
// An empty page_language means the language is unknown and patterns of all
// languages are used.
EXPECT_EQ(
@@ -242,11 +197,7 @@ TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
// fillable (therefore, the form has only 2 fillable fields).
{
base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillFixFillableFieldTypes},
- /*disabled_features=*/{});
+ feature_list.InitAndEnableFeature(kAutofillFixFillableFieldTypes);
// An empty page_language means the language is unknown and patterns of all
// languages are used.
const FieldCandidatesMap field_candidates_map =
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.cc b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
index 0db9bd926fc..0fd65aa87c9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
@@ -10,10 +10,10 @@
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
using base::UTF8ToUTF16;
@@ -24,6 +24,7 @@ namespace {
class FullNameField : public NameField {
public:
static std::unique_ptr<FullNameField> Parse(AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
explicit FullNameField(AutofillField* field);
@@ -42,9 +43,12 @@ class FirstTwoLastNamesField : public NameField {
public:
static std::unique_ptr<FirstTwoLastNamesField> ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager);
+ static std::unique_ptr<FirstTwoLastNamesField> Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
- static std::unique_ptr<FirstTwoLastNamesField> Parse(AutofillScanner* scanner,
- LogManager* log_manager);
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
@@ -67,12 +71,16 @@ class FirstLastNameField : public NameField {
public:
static std::unique_ptr<FirstLastNameField> ParseSpecificName(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
static std::unique_ptr<FirstLastNameField> ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager);
+ static std::unique_ptr<FirstLastNameField> Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager);
- static std::unique_ptr<FirstLastNameField> Parse(AutofillScanner* scanner,
- LogManager* log_manager);
protected:
void AddClassifications(FieldCandidatesMap* field_candidates) const override;
@@ -103,11 +111,11 @@ std::unique_ptr<FormField> NameField::Parse(AutofillScanner* scanner,
std::unique_ptr<FormField> field;
if (!field && base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames))
- field = FirstTwoLastNamesField::Parse(scanner, log_manager);
+ field = FirstTwoLastNamesField::Parse(scanner, page_language, log_manager);
if (!field)
- field = FirstLastNameField::Parse(scanner, log_manager);
+ field = FirstLastNameField::Parse(scanner, page_language, log_manager);
if (!field)
- field = FullNameField::Parse(scanner, log_manager);
+ field = FullNameField::Parse(scanner, page_language, log_manager);
return field;
}
@@ -116,12 +124,17 @@ void NameField::AddClassifications(FieldCandidatesMap* field_candidates) const {
}
// static
-std::unique_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner,
- LogManager* log_manager) {
+std::unique_ptr<FullNameField> FullNameField::Parse(
+ AutofillScanner* scanner,
+ const std::string& page_language,
+ LogManager* log_manager) {
// Exclude e.g. "username" or "nickname" fields.
scanner->SaveCursor();
- bool should_ignore = ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), nullptr,
- {log_manager, "kNameIgnoredRe"});
+ auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_IGNORED", page_language);
+ bool should_ignore =
+ ParseField(scanner, UTF8ToUTF16(kNameIgnoredRe), patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"});
scanner->Rewind();
if (should_ignore)
return nullptr;
@@ -130,7 +143,10 @@ std::unique_ptr<FullNameField> FullNameField::Parse(AutofillScanner* scanner,
// for example, Travelocity_Edit travel profile.html contains a field
// "Travel Profile Name".
AutofillField* field = nullptr;
- if (ParseField(scanner, UTF8ToUTF16(kNameRe), &field,
+ // In JSON : FULL_NAME (closest vatiant)
+ auto& patterns_name = PatternProvider::GetInstance().GetMatchPatterns(
+ "FULL_NAME", page_language);
+ if (ParseField(scanner, UTF8ToUTF16(kNameRe), patterns_name, &field,
{log_manager, "kNameRe"}))
return std::make_unique<FullNameField>(field);
@@ -149,17 +165,32 @@ FirstTwoLastNamesField::FirstTwoLastNamesField() = default;
// static
std::unique_ptr<FirstTwoLastNamesField> FirstTwoLastNamesField::Parse(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
- return ParseComponentNames(scanner, log_manager);
+ return ParseComponentNames(scanner, page_language, log_manager);
}
// static
std::unique_ptr<FirstTwoLastNamesField>
FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstTwoLastNamesField> v(new FirstTwoLastNamesField);
scanner->SaveCursor();
+ auto& patterns_hp = PatternProvider::GetInstance().GetMatchPatterns(
+ "HONORIFIC_PREFIX", page_language);
+ auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_IGNORED", page_language);
+ auto& patterns_fn = PatternProvider::GetInstance().GetMatchPatterns(
+ "FIRST_NAME", page_language);
+ auto& patterns_mn = PatternProvider::GetInstance().GetMatchPatterns(
+ "MIDDLE_NAME", page_language);
+ auto& patterns_ln1 = PatternProvider::GetInstance().GetMatchPatterns(
+ "LAST_NAME_FIRST", page_language);
+ auto& patterns_ln2 = PatternProvider::GetInstance().GetMatchPatterns(
+ "LAST_NAME_SECOND", page_language);
+
// Allow name fields to appear in any order.
while (!scanner->IsEnd()) {
// Scan for the honorific prefix before checking for unrelated name fields
@@ -168,7 +199,7 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
// TODO(crbug.com/1098943): Remove check once feature is launched or
// removed.
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
&v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
@@ -177,30 +208,31 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
// Skip over any unrelated fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- nullptr, {log_manager, "kNameIgnoredRe"})) {
+ patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), &v->first_name_,
- {log_manager, "kFirstNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ &v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), &v->middle_name_,
- {log_manager, "kMiddleNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ &v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->first_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe), &v->first_last_name_,
- {log_manager, "kNameLastFirstRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kNameLastFirstRe), patterns_ln1,
+ &v->first_last_name_, {log_manager, "kNameLastFirstRe"})) {
continue;
}
if (!v->second_last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe),
+ ParseField(scanner, UTF8ToUTF16(kNameLastSecondRe), patterns_ln2,
&v->second_last_name_,
{log_manager, "kNameLastSecondtRe"})) {
continue;
@@ -235,6 +267,7 @@ void FirstTwoLastNamesField::AddClassifications(
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
// Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html)
// have the label "Name" followed by two or three text fields.
@@ -242,8 +275,11 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
scanner->SaveCursor();
AutofillField* next = nullptr;
- if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), &v->first_name_,
- {log_manager, "kNameSpecificRe"}) &&
+ auto& patterns_ns = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_SPECIFIC", page_language);
+
+ if (ParseField(scanner, UTF8ToUTF16(kNameSpecificRe), patterns_ns,
+ &v->first_name_, {log_manager, "kNameSpecificRe"}) &&
ParseEmptyLabel(scanner, &next)) {
if (ParseEmptyLabel(scanner, &v->last_name_)) {
// There are three name fields; assume that the middle one is a
@@ -264,6 +300,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseSpecificName(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> v(new FirstLastNameField);
scanner->SaveCursor();
@@ -279,6 +316,20 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// The ".*last$" matches fields ending in "last" (example in sample8.html).
// Allow name fields to appear in any order.
+
+ auto& patterns_hp = PatternProvider::GetInstance().GetMatchPatterns(
+ "HONORIFIC_PREFIX", page_language);
+ auto& patterns_ni = PatternProvider::GetInstance().GetMatchPatterns(
+ "NAME_IGNORED", page_language);
+ auto& patterns_fn = PatternProvider::GetInstance().GetMatchPatterns(
+ "FIRST_NAME", page_language);
+ auto& patterns_mi = PatternProvider::GetInstance().GetMatchPatterns(
+ "MIDDLE_INITIAL", page_language);
+ auto& patterns_mn = PatternProvider::GetInstance().GetMatchPatterns(
+ "MIDDLE_NAME", page_language);
+ auto& patterns_ln = PatternProvider::GetInstance().GetMatchPatterns(
+ "LAST_NAME", page_language);
+
while (!scanner->IsEnd()) {
// Scan for the honorific prefix before checking for unrelated fields
// because a honorific prefix field is expected to have very specific labels
@@ -288,7 +339,7 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames)) {
if (!v->honorific_prefix_ &&
- ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe),
+ ParseField(scanner, UTF8ToUTF16(kHonorificPrefixRe), patterns_hp,
&v->honorific_prefix_,
{log_manager, "kHonorificPrefixRe"})) {
continue;
@@ -298,13 +349,14 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// Skip over any unrelated name fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- nullptr, {log_manager, "kNameIgnoredRe"})) {
+ patterns_ni, nullptr,
+ {log_manager, "kNameIgnoredRe"})) {
continue;
}
if (!v->first_name_ &&
- ParseField(scanner, UTF8ToUTF16(kFirstNameRe), &v->first_name_,
- {log_manager, "kFirstNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kFirstNameRe), patterns_fn,
+ &v->first_name_, {log_manager, "kFirstNameRe"})) {
continue;
}
@@ -314,21 +366,21 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// "txtmiddlename"); such a field probably actually represents a
// middle initial.
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe), &v->middle_name_,
- {log_manager, "kMiddleInitialRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleInitialRe), patterns_mi,
+ &v->middle_name_, {log_manager, "kMiddleInitialRe"})) {
v->middle_initial_ = true;
continue;
}
if (!v->middle_name_ &&
- ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), &v->middle_name_,
- {log_manager, "kMiddleNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kMiddleNameRe), patterns_mn,
+ &v->middle_name_, {log_manager, "kMiddleNameRe"})) {
continue;
}
if (!v->last_name_ &&
- ParseField(scanner, UTF8ToUTF16(kLastNameRe), &v->last_name_,
- {log_manager, "kLastNameRe"})) {
+ ParseField(scanner, UTF8ToUTF16(kLastNameRe), patterns_ln,
+ &v->last_name_, {log_manager, "kLastNameRe"})) {
continue;
}
@@ -347,11 +399,12 @@ std::unique_ptr<FirstLastNameField> FirstLastNameField::ParseComponentNames(
// static
std::unique_ptr<FirstLastNameField> FirstLastNameField::Parse(
AutofillScanner* scanner,
+ const std::string& page_language,
LogManager* log_manager) {
std::unique_ptr<FirstLastNameField> field =
- ParseSpecificName(scanner, log_manager);
+ ParseSpecificName(scanner, page_language, log_manager);
if (!field)
- field = ParseComponentNames(scanner, log_manager);
+ field = ParseComponentNames(scanner, page_language, log_manager);
return field;
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.h b/chromium/components/autofill/core/browser/form_parsing/name_field.h
index 26048b596bb..7298fbdb7d5 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
index 2931c9028d5..e83e8187b8c 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field_unittest.cc
@@ -12,10 +12,11 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,13 +26,11 @@ namespace autofill {
class NameFieldTest : public testing::Test {
public:
- NameFieldTest() {}
+ NameFieldTest() = default;
+ NameFieldTest(const NameFieldTest&) = delete;
+ NameFieldTest& operator=(const NameFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<NameField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<NameField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -41,8 +40,12 @@ class NameFieldTest : public testing::Test {
return std::unique_ptr<NameField>(static_cast<NameField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(NameFieldTest);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<NameField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(NameFieldTest, FirstMiddleLast) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
index 82d6294891a..b50388208be 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -16,10 +16,10 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
namespace autofill {
namespace {
@@ -246,7 +246,8 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
scanner, GetRegExp(kPhoneFieldGrammars[i].regex),
&parsed_fields[kPhoneFieldGrammars[i].phone_part],
{log_manager, GetRegExpName(kPhoneFieldGrammars[i].regex)},
- is_country_code_field))
+ is_country_code_field,
+ GetJSONFieldType(kPhoneFieldGrammars[i].regex), page_language))
break;
if (kPhoneFieldGrammars[i].max_size &&
(!parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length ||
@@ -291,11 +292,13 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
if (!ParsePhoneField(scanner, kPhoneSuffixRe,
&phone_field->parsed_phone_fields_[FIELD_SUFFIX],
{log_manager, "kPhoneSuffixRe"},
- /*is_country_code_field=*/false)) {
+ /*is_country_code_field=*/false, "PHONE_SUFFIX",
+ page_language)) {
ParsePhoneField(scanner, kPhoneSuffixSeparatorRe,
&phone_field->parsed_phone_fields_[FIELD_SUFFIX],
{log_manager, "kPhoneSuffixSeparatorRe"},
- /*is_country_code_field=*/false);
+ /*is_country_code_field=*/false, "PHONE_SUFFIX_SEPARATOR",
+ page_language);
}
}
@@ -305,7 +308,8 @@ std::unique_ptr<FormField> PhoneField::Parse(AutofillScanner* scanner,
ParsePhoneField(scanner, kPhoneExtensionRe,
&phone_field->parsed_phone_fields_[FIELD_EXTENSION],
{log_manager, "kPhoneExtensionRe"},
- /*is_country_code_field=*/false);
+ /*is_country_code_field=*/false, "PHONE_EXTENSION",
+ page_language);
return std::move(phone_field);
}
@@ -416,19 +420,52 @@ const char* PhoneField::GetRegExpName(RegexType regex_id) {
return "";
}
+//
+std::string PhoneField::GetJSONFieldType(RegexType phonetype_id) {
+ switch (phonetype_id) {
+ case REGEX_COUNTRY:
+ return "PHONE_COUNTRY_CODE";
+ case REGEX_AREA:
+ return "PHONE_AREA_CODE";
+ case REGEX_AREA_NOTEXT:
+ return "PHONE_AREA_CODE_NO_TEXT";
+ case REGEX_PHONE:
+ return "PHONE";
+ case REGEX_PREFIX_SEPARATOR:
+ return "PHONE_PREFIX_SEPARATOR";
+ case REGEX_PREFIX:
+ return "PHONE_PREFIX";
+ case REGEX_SUFFIX_SEPARATOR:
+ return "PHONE_SUFFIX_SEPARATOR";
+ case REGEX_SUFFIX:
+ return "PHONE_SUFFIX";
+ case REGEX_EXTENSION:
+ return "PHONE_EXTENSION";
+ default:
+ NOTREACHED();
+ break;
+ }
+ return std::string();
+}
+
// static
bool PhoneField::ParsePhoneField(AutofillScanner* scanner,
const std::string& regex,
AutofillField** field,
const RegExLogging& logging,
- const bool is_country_code_field) {
+ const bool is_country_code_field,
+ const std::string& json_field_type,
+ const std::string& page_language) {
int match_type = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
// Include the selection boxes too for the matching of the phone country code.
if (is_country_code_field)
match_type |= MATCH_SELECT;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ json_field_type, page_language);
+
return ParseFieldSpecifics(scanner, base::UTF8ToUTF16(regex), match_type,
- field, logging);
+ patterns, field, logging);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.h b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
index f0f39a3928f..6ac25f26693 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.h
@@ -17,6 +17,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/phone_number.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
@@ -96,12 +97,18 @@ class PhoneField : public FormField {
// This is useful for logging purposes.
static const char* GetRegExpName(RegexType regex_id);
+ // Returns the name of field type which indicated in JSON corresponding to
+ // |regex_id|.
+ static std::string GetJSONFieldType(RegexType phonetype_id);
+
// Convenient wrapper for ParseFieldSpecifics().
static bool ParsePhoneField(AutofillScanner* scanner,
const std::string& regex,
AutofillField** field,
const RegExLogging& logging,
- const bool is_country_code_field);
+ const bool is_country_code_field,
+ const std::string& json_field_type,
+ const std::string& page_language);
// Returns true if |scanner| points to a <select> field that appears to be the
// phone country code by looking at its option contents.
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
index 72469564fd3..71e0cf605c4 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field_unittest.cc
@@ -16,6 +16,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -83,6 +84,9 @@ class PhoneFieldTest : public testing::Test {
std::vector<std::unique_ptr<AutofillField>> list_;
std::unique_ptr<PhoneField> field_;
FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(PhoneFieldTest, Empty) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.cc b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
index 58079a2800f..595b759ad00 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
@@ -6,8 +6,8 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -16,10 +16,13 @@ std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns =
+ PatternProvider::GetInstance().GetMatchPatterns("PRICE", page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kPriceRe),
MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT |
MATCH_TEXT_AREA | MATCH_SEARCH,
- &field, {log_manager, kPriceRe})) {
+ patterns, &field, {log_manager, kPriceRe})) {
return std::make_unique<PriceField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.h b/chromium/components/autofill/core/browser/form_parsing/price_field.h
index b3023982b57..7d05f460dae 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
index 9f6110de258..464830b2852 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,13 +23,11 @@ namespace autofill {
class PriceFieldTest : public testing::Test {
public:
- PriceFieldTest() {}
+ PriceFieldTest() = default;
+ PriceFieldTest(const PriceFieldTest&) = delete;
+ PriceFieldTest& operator=(const PriceFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<PriceField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<PriceField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -39,8 +38,12 @@ class PriceFieldTest : public testing::Test {
static_cast<PriceField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(PriceFieldTest);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<PriceField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(PriceFieldTest, ParsePrice) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.cc b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
index a2065dc0c30..a7564839f06 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
@@ -6,8 +6,8 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
namespace autofill {
@@ -16,9 +16,12 @@ std::unique_ptr<FormField> SearchField::Parse(AutofillScanner* scanner,
const std::string& page_language,
LogManager* log_manager) {
AutofillField* field;
+ auto& patterns = PatternProvider::GetInstance().GetMatchPatterns(
+ SEARCH_TERM, page_language);
+
if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kSearchTermRe),
MATCH_DEFAULT | MATCH_SEARCH | MATCH_TEXT_AREA,
- &field, {log_manager, "kSearchTermRe"})) {
+ patterns, &field, {log_manager, "kSearchTermRe"})) {
return std::make_unique<SearchField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.h b/chromium/components/autofill/core/browser/form_parsing/search_field.h
index 71b2f70bb48..99e70eb9a2c 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
index 09148d51010..a6be80cc7e0 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/common/form_field_data.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,13 +23,11 @@ namespace autofill {
class SearchFieldTest : public testing::Test {
public:
- SearchFieldTest() {}
+ SearchFieldTest() = default;
+ SearchFieldTest(const SearchFieldTest&) = delete;
+ SearchFieldTest& operator=(const SearchFieldTest&) = delete;
protected:
- std::vector<std::unique_ptr<AutofillField>> list_;
- std::unique_ptr<SearchField> field_;
- FieldCandidatesMap field_candidates_map_;
-
// Downcast for tests.
static std::unique_ptr<SearchField> Parse(AutofillScanner* scanner) {
// An empty page_language means the language is unknown and patterns of all
@@ -39,8 +38,12 @@ class SearchFieldTest : public testing::Test {
static_cast<SearchField*>(field.release()));
}
- private:
- DISALLOW_COPY_AND_ASSIGN(SearchFieldTest);
+ std::vector<std::unique_ptr<AutofillField>> list_;
+ std::unique_ptr<SearchField> field_;
+ FieldCandidatesMap field_candidates_map_;
+
+ // RAII object to mock the the PatternProvider.
+ TestPatternProvider test_pattern_provider_;
};
TEST_F(SearchFieldTest, ParseSearchTerm) {
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
index cf90e229903..2e1dc92a836 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
namespace autofill {
@@ -21,17 +21,25 @@ std::unique_ptr<FormField> TravelField::Parse(AutofillScanner* scanner,
if (!scanner || scanner->IsEnd()) {
return nullptr;
}
+ auto& patternsP = PatternProvider::GetInstance().GetMatchPatterns(
+ "PASSPORT", page_language);
+ auto& patternsTO = PatternProvider::GetInstance().GetMatchPatterns(
+ "TRAVEL_ORIGIN", page_language);
+ auto& patternsTD = PatternProvider::GetInstance().GetMatchPatterns(
+ "TRAVEL_DESTINATION", page_language);
+ auto& patternsF =
+ PatternProvider::GetInstance().GetMatchPatterns("FLIGHT", page_language);
auto travel_field = std::make_unique<TravelField>();
- if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe),
+ if (ParseField(scanner, base::UTF8ToUTF16(kPassportRe), patternsP,
&travel_field->passport_, {log_manager, "kPassportRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe),
+ ParseField(scanner, base::UTF8ToUTF16(kTravelOriginRe), patternsTO,
&travel_field->origin_, {log_manager, "kTravelOriginRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe),
+ ParseField(scanner, base::UTF8ToUTF16(kTravelDestinationRe), patternsTD,
&travel_field->destination_,
{log_manager, "kTravelDestinationRe"}) ||
- ParseField(scanner, base::UTF8ToUTF16(kFlightRe), &travel_field->flight_,
- {log_manager, "kFlightRe"})) {
+ ParseField(scanner, base::UTF8ToUTF16(kFlightRe), patternsF,
+ &travel_field->flight_, {log_manager, "kFlightRe"})) {
// If any regex matches, then we found a travel field.
return std::move(travel_field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/travel_field.h b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
index 8ac09a00df3..9b2d2e5e891 100644
--- a/chromium/components/autofill/core/browser/form_parsing/travel_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/travel_field.h
@@ -9,6 +9,7 @@
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index ff7993d82e2..9bd72190efa 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -32,6 +32,8 @@
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/field_candidates.h"
@@ -45,8 +47,6 @@
#include "components/autofill/core/common/autofill_internals/log_message.h"
#include "components/autofill/core/common/autofill_internals/logging_scope.h"
#include "components/autofill/core/common/autofill_payments_features.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
@@ -56,6 +56,7 @@
#include "components/autofill/core/common/logging/log_buffer.h"
#include "components/autofill/core/common/signatures.h"
#include "components/security_state/core/security_state.h"
+#include "components/version_info/version_info.h"
#include "url/origin.h"
namespace autofill {
@@ -64,8 +65,6 @@ using mojom::SubmissionIndicatorEvent;
namespace {
-// Version of the client sent to the server.
-constexpr char kClientVersion[] = "6.1.1715.1442/en (GGLL)";
constexpr char kBillingMode[] = "billing";
constexpr char kShippingMode[] = "shipping";
@@ -705,7 +704,8 @@ bool FormStructure::EncodeUploadRequest(
encoded_signatures->clear();
upload->set_submission(observed_submission);
- upload->set_client_version(kClientVersion);
+ upload->set_client_version(
+ version_info::GetProductNameAndVersionForUserAgent());
upload->set_form_signature(form_signature().value());
upload->set_autofill_used(form_was_autofilled);
upload->set_data_present(EncodeFieldTypes(available_field_types));
@@ -763,7 +763,8 @@ bool FormStructure::EncodeQueryRequest(
queried_form_signatures->clear();
queried_form_signatures->reserve(forms.size());
- query->set_client_version(kClientVersion);
+ query->set_client_version(
+ version_info::GetProductNameAndVersionForUserAgent());
// If a page contains repeated forms, detect that and encode only one form as
// the returned data would be the same for all the repeated forms.
@@ -889,7 +890,6 @@ void FormStructure::ProcessQueryResponse(
form->UpdateAutofillCount();
form->RationalizeRepeatedFields(form_interactions_ukm_logger);
form->RationalizeFieldTypePredictions();
- form->OverrideServerPredictionsWithHeuristics();
form->IdentifySections(false);
}
@@ -956,8 +956,8 @@ std::string FormStructure::FormSignatureAsStr() const {
bool FormStructure::IsAutofillable() const {
size_t min_required_fields =
- std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(),
- MinRequiredFieldsForUpload()});
+ std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+ kMinRequiredFieldsForUpload});
if (autofill_count() < min_required_fields)
return false;
@@ -999,8 +999,8 @@ bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
}
size_t min_required_fields =
- std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(),
- MinRequiredFieldsForUpload()});
+ std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+ kMinRequiredFieldsForUpload});
if (active_field_count() < min_required_fields &&
(!all_fields_are_passwords() ||
active_field_count() < kRequiredFieldsForFormsWithOnlyPasswordFields) &&
@@ -1040,7 +1040,7 @@ bool FormStructure::ShouldBeParsed(LogManager* log_manager) const {
}
bool FormStructure::ShouldRunHeuristics() const {
- return active_field_count() >= MinRequiredFieldsForHeuristics() &&
+ return active_field_count() >= kMinRequiredFieldsForHeuristics &&
HasAllowedScheme(source_url_) &&
(is_form_tag_ || is_formless_checkout_ ||
!base::FeatureList::IsEnabled(
@@ -1049,12 +1049,12 @@ bool FormStructure::ShouldRunHeuristics() const {
bool FormStructure::ShouldBeQueried() const {
return (has_password_field_ ||
- active_field_count() >= MinRequiredFieldsForQuery()) &&
+ active_field_count() >= kMinRequiredFieldsForQuery) &&
ShouldBeParsed();
}
bool FormStructure::ShouldBeUploaded() const {
- return active_field_count() >= MinRequiredFieldsForUpload() &&
+ return active_field_count() >= kMinRequiredFieldsForUpload &&
ShouldBeParsed();
}
@@ -1062,37 +1062,21 @@ void FormStructure::RetrieveFromCache(
const FormStructure& cached_form,
const bool should_keep_cached_value,
const bool only_server_and_autofill_state) {
- // TODO(crbug/1101631) Clean up once the experiment is over.
- const bool kUseRendererIds = base::FeatureList::IsEnabled(
- features::kAutofillRetrieveFromCacheWithRendererIds);
- std::map<base::string16, const AutofillField*> cached_fields_by_name;
std::map<FieldRendererId, const AutofillField*> cached_fields_by_id;
for (size_t i = 0; i < cached_form.field_count(); ++i) {
auto* const field = cached_form.field(i);
- if (kUseRendererIds)
- cached_fields_by_id[field->unique_renderer_id] = field;
- else
- cached_fields_by_name[field->unique_name()] = field;
+ cached_fields_by_id[field->unique_renderer_id] = field;
}
for (auto& field : *this) {
const AutofillField* cached_field = nullptr;
- if (kUseRendererIds) {
- const auto& it = cached_fields_by_id.find(field->unique_renderer_id);
- if (it != cached_fields_by_id.end())
- cached_field = it->second;
- } else {
- const auto& it = cached_fields_by_name.find(field->unique_name());
- if (it != cached_fields_by_name.end())
- cached_field = it->second;
- }
+ const auto& it = cached_fields_by_id.find(field->unique_renderer_id);
+ if (it != cached_fields_by_id.end())
+ cached_field = it->second;
// If the unique renderer id (or the name) is not stable due to some Java
// Script magic in the website, use the field signature as a fallback
// solution to find the field in the cached form.
- // TODO(crbug.com/1125624): Remove feature check once trial ended.
- if (!cached_field &&
- base::FeatureList::IsEnabled(
- features::kAutofillRetrieveFromCacheWithFieldSignatureAsFallback)) {
+ if (!cached_field) {
// Iterates over the fields to find the field with the same form
// signature.
for (size_t i = 0; i < cached_form.field_count(); ++i) {
@@ -1125,24 +1109,16 @@ void FormStructure::RetrieveFromCache(
field->is_autofilled = cached_field->is_autofilled;
}
if (field->form_control_type != "select-one") {
- bool is_credit_card_field =
- AutofillType(cached_field->Type().GetStorableType()).group() ==
- CREDIT_CARD;
- if (should_keep_cached_value &&
- (is_credit_card_field ||
- base::FeatureList::IsEnabled(
- features::kAutofillKeepInitialFormValuesInCache))) {
+ if (should_keep_cached_value) {
field->value = cached_field->value;
value_from_dynamic_change_form_ = true;
} else if (field->value == cached_field->value &&
- (!base::FeatureList::IsEnabled(
- features::
- kAutofillImportPrefilledCountryAndStateValues) ||
- (field->server_type() != ADDRESS_HOME_COUNTRY &&
- field->server_type() != ADDRESS_HOME_STATE))) {
- // TODO(crbug.com/1100231): Remove feature check once launched.
+ (field->server_type() != ADDRESS_HOME_COUNTRY &&
+ field->server_type() != ADDRESS_HOME_STATE)) {
// From the perspective of learning user data, text fields containing
// default values are equivalent to empty fields.
+ // Since a website can prefill country and state values basedw on
+ // GeoIp, the mechanism is deactivated for state and country fields.
field->value = base::string16();
}
}
@@ -1242,8 +1218,8 @@ void FormStructure::LogQualityMetrics(
// submission event.
if (observed_submission) {
AutofillMetrics::AutofillFormSubmittedState state;
- if (num_detected_field_types < MinRequiredFieldsForHeuristics() &&
- num_detected_field_types < MinRequiredFieldsForQuery()) {
+ if (num_detected_field_types < kMinRequiredFieldsForHeuristics &&
+ num_detected_field_types < kMinRequiredFieldsForQuery) {
state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA;
} else {
if (did_autofill_all_possible_fields) {
@@ -1871,27 +1847,6 @@ void FormStructure::RationalizeAddressStateCountry(
}
}
-void FormStructure::OverrideServerPredictionsWithHeuristics() {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames) &&
- !base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInAddresses)) {
- return;
- }
- for (const auto& field : fields_) {
- switch (field->heuristic_type()) {
- case NAME_LAST_SECOND:
- case NAME_LAST_FIRST:
- case ADDRESS_HOME_STREET_NAME:
- case ADDRESS_HOME_HOUSE_NUMBER:
- field->SetTypeTo(AutofillType(field->heuristic_type()));
- break;
- default: {
- };
- }
- }
-}
-
void FormStructure::RationalizeRepeatedFields(
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
// The type of every field whose index is in
@@ -2090,9 +2045,21 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
base::FeatureList::IsEnabled(
features::kAutofillSectionUponRedundantNameInfo);
+ // Creates a unique name for the section that starts with |field|.
+ // TODO(crbug/896689): Cleanup once experiment is launched.
+ auto get_section_name = [](const AutofillField& field) {
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillNameSectionsWithRendererIds)) {
+ return base::StrCat(
+ {field.name, base::ASCIIToUTF16("_"),
+ base::NumberToString16(field.unique_renderer_id.value())});
+ } else {
+ return field.unique_name();
+ }
+ };
+
if (!has_author_specified_sections || is_enabled_autofill_new_sectioning) {
- // Name sections after the first field in the section.
- base::string16 current_section = fields_.front()->unique_name();
+ base::string16 current_section = get_section_name(*fields_.front());
// Keep track of the types we've seen in this section.
std::set<ServerFieldType> seen_types;
@@ -2214,7 +2181,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
}
// The end of a section, so start a new section.
- current_section = field->unique_name();
+ current_section = get_section_name(*field);
if (is_enabled_autofill_new_sectioning) {
// The section described in the autocomplete section attribute
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index a18c4d9b581..58a8a8d48dc 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -25,7 +25,6 @@
#include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -399,11 +398,12 @@ class FormStructure {
private:
friend class AutofillMergeTest;
friend class FormStructureTestImpl;
+ friend class ParameterizedFormStructureTest;
FRIEND_TEST_ALL_PREFIXES(AutofillDownloadTest, QueryAndUploadTest);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, FindLongestCommonPrefix);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, FindLongestCommonAffixLength);
FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl, IsValidParseableName);
- FRIEND_TEST_ALL_PREFIXES(FormStructureTestImpl,
+ FRIEND_TEST_ALL_PREFIXES(ParameterizedFormStructureTest,
RationalizePhoneNumber_RunsOncePerSection);
class SectionedFieldsIndexes {
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 6125363ecb2..4e894075277 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -19,27 +19,26 @@
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_form_test_utils.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/proto/api_v1.pb.h"
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/signatures.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/version_info/version_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using base::ASCIIToUTF16;
+using version_info::GetProductNameAndVersionForUserAgent;
namespace autofill {
-using features::kAutofillEnforceMinRequiredFieldsForHeuristics;
-using features::kAutofillEnforceMinRequiredFieldsForQuery;
-using features::kAutofillEnforceMinRequiredFieldsForUpload;
using features::kAutofillLabelAffixRemoval;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
@@ -90,74 +89,22 @@ class FormStructureTestImpl : public test::FormStructureTest {
feature_list->InitAndDisableFeature(feature);
}
- // Single field forms are not parseable iff all of the minimum required field
- // values are enforced.
- void CheckFormShouldBeParsed(const char* trace_message,
- const FormData form,
- bool expected_if_all_enforced,
- bool expected_if_not_all_enforced) {
- SCOPED_TRACE(trace_message);
- for (bool enforce_min_for_heuristics : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&heuristics, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_for_heuristics);
- for (bool enforce_min_for_query : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&query, kAutofillEnforceMinRequiredFieldsForQuery,
- enforce_min_for_query);
- for (bool enforce_min_for_upload : {true, false}) {
- base::test::ScopedFeatureList heuristics, query, upload;
- InitFeature(&upload, kAutofillEnforceMinRequiredFieldsForUpload,
- enforce_min_for_upload);
- bool all_enforced = enforce_min_for_heuristics &&
- enforce_min_for_query && enforce_min_for_upload;
- FormStructure form_structure(form);
- if (all_enforced) {
- EXPECT_EQ(expected_if_all_enforced,
- form_structure.ShouldBeParsed());
- } else {
- EXPECT_EQ(expected_if_not_all_enforced,
- form_structure.ShouldBeParsed())
- << "heuristics:" << enforce_min_for_heuristics << "; "
- << "query:" << enforce_min_for_query << "; "
- << "upload:" << enforce_min_for_upload;
- }
- }
- }
- }
+ bool FormShouldBeParsed(const FormData form) {
+ return FormStructure(form).ShouldBeParsed();
}
- bool FormIsAutofillable(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_fields);
+ bool FormIsAutofillable(const FormData& form) {
FormStructure form_structure(form);
form_structure.DetermineHeuristicTypes();
return form_structure.IsAutofillable();
}
- bool FormShouldRunHeuristics(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForHeuristics,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldRunHeuristics();
+ bool FormShouldRunHeuristics(const FormData& form) {
+ return FormStructure(form).ShouldRunHeuristics();
}
- bool FormShouldBeQueried(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForQuery,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldBeQueried();
- }
-
- bool FormShouldBeUploaded(const FormData& form, bool enforce_min_fields) {
- base::test::ScopedFeatureList feature_list;
- InitFeature(&feature_list, kAutofillEnforceMinRequiredFieldsForUpload,
- enforce_min_fields);
- FormStructure form_structure(form);
- return form_structure.ShouldBeUploaded();
+ bool FormShouldBeQueried(const FormData& form) {
+ return FormStructure(form).ShouldBeQueried();
}
void DisableAutofillMetadataFieldTrial() {
@@ -175,6 +122,13 @@ class FormStructureTestImpl : public test::FormStructureTest {
{});
}
+ FieldRendererId MakeFieldRendererId() {
+ return FieldRendererId(++id_counter_);
+ }
+
+ protected:
+ TestPatternProvider test_pattern_provider_;
+
private:
void EnableAutofillMetadataFieldTrial() {
scoped_feature_list_.Reset();
@@ -184,6 +138,7 @@ class FormStructureTestImpl : public test::FormStructureTest {
field_trial_->group();
}
+ uint32_t id_counter_ = 10;
base::test::ScopedFeatureList scoped_feature_list_;
scoped_refptr<base::FieldTrial> field_trial_;
};
@@ -277,62 +232,60 @@ TEST_F(FormStructureTestImpl, IsAutofillable) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// With min required fields enabled.
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add a password field. The form should be picked up by the password but
// not by autofill.
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add an auto-fillable fields. With just one auto-fillable field, this should
// be picked up by autofill only if there is no minimum field enforcement.
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// Add an auto-fillable fields. With just one auto-fillable field, this should
// be picked up by autofill only if there is no minimum field enforcement.
field.label = ASCIIToUTF16("Address Line 1");
field.name = ASCIIToUTF16("address1");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// We now have three auto-fillable fields. It's always autofillable.
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_TRUE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_TRUE(FormIsAutofillable(form));
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
- EXPECT_FALSE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_FALSE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormIsAutofillable(form));
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
- EXPECT_TRUE(FormIsAutofillable(form, true)); // Min enforced.
- EXPECT_TRUE(FormIsAutofillable(form, false)); // Min not enforced.
+ EXPECT_TRUE(FormIsAutofillable(form));
}
TEST_F(FormStructureTestImpl, ShouldBeParsed) {
@@ -345,51 +298,56 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed) {
FormFieldData::CheckStatus::kCheckableButUnchecked;
checkable_field.name = ASCIIToUTF16("radiobtn");
checkable_field.form_control_type = "radio";
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
// A form with a single checkable field isn't interesting.
- CheckFormShouldBeParsed("one checkable", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "one checkable";
// Add a second checkable field.
checkable_field.name = ASCIIToUTF16("checkbox");
checkable_field.form_control_type = "checkbox";
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
// A form with a only checkable fields isn't interesting.
- CheckFormShouldBeParsed("two checkable", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "two checkable";
// Add a text field.
FormFieldData field;
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Single text field forms shouldn't be parsed if all of the minimums are
// enforced but should be parsed if ANY of the minimums is not enforced.
- CheckFormShouldBeParsed("username", form, false, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "username";
// We now have three text fields, though only two are auto-fillable.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Three text field forms should always be parsed.
- CheckFormShouldBeParsed("three field", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "three field";
// The target cannot include http(s)://*/search...
form.action = GURL("http://google.com/search?q=hello");
- CheckFormShouldBeParsed("search path", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "search path";
// But search can be in the URL.
form.action = GURL("http://search.com/?q=hello");
- CheckFormShouldBeParsed("search domain", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "search domain";
// The form need only have three fields, but at least one must be a text
// field.
@@ -398,38 +356,43 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed) {
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
field.form_control_type = "select-one";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.form_control_type = "select-one";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("text + selects", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "text + selects";
// Now, no text fields.
form.fields[0].form_control_type = "select-one";
- CheckFormShouldBeParsed("only selects", form, false, false);
+ EXPECT_FALSE(FormShouldBeParsed(form)) << "only selects";
// We have only one field, which is password.
form.fields.clear();
field.label = ASCIIToUTF16("Password");
field.name = ASCIIToUTF16("pw");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("password", form, false, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "password";
// We have two fields, which are passwords, should be parsed.
field.label = ASCIIToUTF16("New password");
field.name = ASCIIToUTF16("new_pw");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- CheckFormShouldBeParsed("new password", form, true, true);
+ EXPECT_TRUE(FormShouldBeParsed(form)) << "new password";
}
TEST_F(FormStructureTestImpl, ShouldBeParsed_BadScheme) {
@@ -441,18 +404,21 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed_BadScheme) {
field.name = ASCIIToUTF16("name");
field.form_control_type = "text";
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Baseline, HTTP should work.
@@ -522,12 +488,14 @@ TEST_F(FormStructureTestImpl, ShouldBeParsed_TwoFields_HasAutocomplete) {
field.name = ASCIIToUTF16("name");
field.form_control_type = "name";
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("Address");
field.form_control_type = "select-one";
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1115,39 +1083,20 @@ TEST_F(FormStructureTestImpl,
FormFieldData field;
field.form_control_type = "text";
+
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormShouldRunHeuristics(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldRunHeuristics(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormShouldRunHeuristics(form));
- EXPECT_FALSE(FormShouldBeQueried(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldBeQueried(form, false)); // Min not enforced.
-
- // Status Quo (Q3/2017) - Small forms not supported.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(0U, form_structure.autofill_count());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_FALSE(form_structure.IsAutofillable());
- }
+ EXPECT_TRUE(FormShouldBeQueried(form));
// Default configuration.
{
@@ -1161,22 +1110,6 @@ TEST_F(FormStructureTestImpl,
EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_FALSE(form_structure.IsAutofillable());
}
-
- // Enable small form heuristics.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(2U, form_structure.autofill_count());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_TRUE(form_structure.IsAutofillable());
- }
}
// Tests the heuristics and server predictions are not run for forms with less
@@ -1194,65 +1127,23 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
- EXPECT_FALSE(FormShouldRunHeuristics(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldRunHeuristics(form, false)); // Min not enforced.
+ EXPECT_FALSE(FormShouldRunHeuristics(form));
- EXPECT_FALSE(FormShouldBeQueried(form, true)); // Min enforced.
- EXPECT_TRUE(FormShouldBeQueried(form, false)); // Min not enforced.
-
- // Status Quo (Q3/2017) - Small forms not supported.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // Enabled.
- {kAutofillEnforceMinRequiredFieldsForHeuristics,
- kAutofillEnforceMinRequiredFieldsForQuery,
- kAutofillEnforceMinRequiredFieldsForUpload},
- // Disabled.
- {});
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(1U, form_structure.autofill_count());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_FALSE(form_structure.IsAutofillable());
- }
-
- // Enable small form heuristics.
- {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForHeuristics);
- FormStructure form_structure(form);
- form_structure.DetermineHeuristicTypes();
- ASSERT_EQ(2U, form_structure.field_count());
- ASSERT_EQ(2U, form_structure.autofill_count());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
- EXPECT_EQ(NAME_FIRST, form_structure.field(0)->Type().GetStorableType());
- EXPECT_EQ(NAME_LAST, form_structure.field(1)->Type().GetStorableType());
- EXPECT_TRUE(form_structure.IsAutofillable());
- }
+ EXPECT_TRUE(FormShouldBeQueried(form));
// As a side effect of parsing small forms (if any of the heuristics, query,
// or upload minimmums are disabled, we'll autofill fields with an
// autocomplete attribute, even if its the only field in the form.
{
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(
- kAutofillEnforceMinRequiredFieldsForUpload);
FormData form_copy = form;
form_copy.fields.pop_back();
FormStructure form_structure(form_copy);
@@ -1280,20 +1171,24 @@ TEST_F(FormStructureTestImpl, PasswordFormShouldBeQueried) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.autocomplete_attribute = "username";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Password");
field.name = ASCIIToUTF16("Password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1315,28 +1210,37 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
// Some fields will have no section specified. These fall into the default
// section.
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// We allow arbitrary section names.
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping" and "billing" are special section tokens that don't require the
// "section-" prefix.
field.autocomplete_attribute = "shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping" and "billing" can be combined with other section names.
field.autocomplete_attribute = "section-foo shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "section-foo billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// We don't do anything clever to try to coalesce sections; it's up to site
// authors to avoid typos.
field.autocomplete_attribute = "section--foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// "shipping email" and "section--shipping" email should be parsed as
@@ -1344,10 +1248,12 @@ TEST_F(FormStructureTestImpl, HeuristicsAutocompleteAttributeWithSections) {
// implement implicit section names from attributes like "shipping email"; see
// the implementation for more details.
field.autocomplete_attribute = "section--shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Credit card fields are implicitly in a separate section from other fields.
field.autocomplete_attribute = "section-foo cc-number";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1380,20 +1286,29 @@ TEST_F(FormStructureTestImpl,
// Some fields will have no section specified. These fall into the default
// section.
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Specifying "section-" is equivalent to not specifying a section.
field.autocomplete_attribute = "section- email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Invalid tokens should prevent us from setting a section name.
field.autocomplete_attribute = "garbage section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage section-bar email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage shipping email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "garbage billing email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1423,8 +1338,11 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "text";
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.autocomplete_attribute = "section-foo address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1455,15 +1373,22 @@ TEST_F(FormStructureTestImpl,
field.name = ASCIIToUTF16("one");
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = base::string16();
field.autocomplete_attribute = "section-foo email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = base::string16();
field.autocomplete_attribute = "name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.name = ASCIIToUTF16("two");
field.autocomplete_attribute = "address-line1";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -1491,43 +1416,53 @@ TEST_F(FormStructureTestImpl, HeuristicsSample8) {
field.label = ASCIIToUTF16("Your First Name:");
field.name = ASCIIToUTF16("bill.first");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Your Last Name:");
field.name = ASCIIToUTF16("bill.last");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street Address Line 1:");
field.name = ASCIIToUTF16("bill.street1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street Address Line 2:");
field.name = ASCIIToUTF16("bill.street2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("bill.city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State (U.S.):");
field.name = ASCIIToUTF16("bill.state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip/Postal Code:");
field.name = ASCIIToUTF16("BillTo.PostalCode");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country:");
field.name = ASCIIToUTF16("bill.country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone Number:");
field.name = ASCIIToUTF16("BillTo.Phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1569,32 +1504,39 @@ TEST_F(FormStructureTestImpl, HeuristicsSample6) {
field.label = ASCIIToUTF16("E-mail address");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full name");
field.name = ASCIIToUTF16("name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Company");
field.name = ASCIIToUTF16("company");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip Code");
field.name = ASCIIToUTF16("Home.PostalCode");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.value = ASCIIToUTF16("continue");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1632,35 +1574,43 @@ TEST_F(FormStructureTestImpl, HeuristicsLabelsOnly) {
field.label = ASCIIToUTF16("First Name");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Zip code");
field.name = base::string16();
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1698,27 +1648,33 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfo) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Month");
field.name = ASCIIToUTF16("ccmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Year");
field.name = ASCIIToUTF16("ccyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Verification");
field.name = ASCIIToUTF16("verification");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1753,33 +1709,40 @@ TEST_F(FormStructureTestImpl, HeuristicsCreditCardInfoWithUnknownCardField) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// This is not a field we know how to process. But we should skip over it
// and process the other fields in the card block.
field.label = ASCIIToUTF16("Card image");
field.name = ASCIIToUTF16("card_image");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Month");
field.name = ASCIIToUTF16("ccmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Exp Year");
field.name = ASCIIToUTF16("ccyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Verification");
field.name = ASCIIToUTF16("verification");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1816,18 +1779,22 @@ TEST_F(FormStructureTestImpl, ThreeAddressLines) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line3");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1857,18 +1824,22 @@ TEST_F(FormStructureTestImpl, SurplusAddressLinesIgnored) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("shipping.address.addressLine1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("shipping.address.addressLine2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line3");
field.name = ASCIIToUTF16("billing.address.addressLine3");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line4");
field.name = ASCIIToUTF16("billing.address.addressLine4");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1901,18 +1872,22 @@ TEST_F(FormStructureTestImpl, ThreeAddressLinesExpedia) {
field.label = ASCIIToUTF16("Street:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Suite or Apt:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adap");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Street address second line");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City:");
field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adct");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1944,14 +1919,17 @@ TEST_F(FormStructureTestImpl, TwoAddressLinesEbay) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("address1");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Floor number, suite number, etc");
field.name = ASCIIToUTF16("address2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City:");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -1978,14 +1956,17 @@ TEST_F(FormStructureTestImpl, HeuristicsStateWithProvince) {
field.label = ASCIIToUTF16("Address Line1");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address Line2");
field.name = ASCIIToUTF16("Address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State/Province/Region");
field.name = ASCIIToUTF16("State");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2013,46 +1994,57 @@ TEST_F(FormStructureTestImpl, HeuristicsWithBilling) {
field.label = ASCIIToUTF16("First Name*:");
field.name = ASCIIToUTF16("editBillingAddress$firstNameBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name*:");
field.name = ASCIIToUTF16("editBillingAddress$lastNameBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Company Name:");
field.name = ASCIIToUTF16("editBillingAddress$companyBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address*:");
field.name = ASCIIToUTF16("editBillingAddress$addressLine1Box");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Apt/Suite :");
field.name = ASCIIToUTF16("editBillingAddress$addressLine2Box");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City*:");
field.name = ASCIIToUTF16("editBillingAddress$cityBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State/Province*:");
field.name = ASCIIToUTF16("editBillingAddress$stateDropDown");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country*:");
field.name = ASCIIToUTF16("editBillingAddress$countryDropDown");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Postal Code*:");
field.name = ASCIIToUTF16("editBillingAddress$zipCodeBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone*:");
field.name = ASCIIToUTF16("editBillingAddress$phoneBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email Address*:");
field.name = ASCIIToUTF16("email$emailBox");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2086,11 +2078,13 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
field.label = ASCIIToUTF16("Phone:");
field.name = ASCIIToUTF16("dayphone1");
field.max_length = 0;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("-");
field.name = ASCIIToUTF16("dayphone2");
field.max_length = 3; // Size of prefix is 3.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("-");
@@ -2098,11 +2092,13 @@ TEST_F(FormStructureTestImpl, ThreePartPhoneNumber) {
field.max_length = 4; // Size of suffix is 4. If unlimited size is
// passed, phone will be parsed as
// <country code> - <area code> - <phone>.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("ext.:");
field.name = ASCIIToUTF16("dayphone4");
field.max_length = 0;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2131,22 +2127,27 @@ TEST_F(FormStructureTestImpl, HeuristicsInfernoCC) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("billing_address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("expiration_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Year");
field.name = ASCIIToUTF16("expiration_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2182,26 +2183,32 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesNotFirst) {
field.label = ASCIIToUTF16("Card number");
field.name = ASCIIToUTF16("ccnumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("First name");
field.name = ASCIIToUTF16("first_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last name");
field.name = ASCIIToUTF16("last_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration date");
field.name = ASCIIToUTF16("ccexpiresmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("ccexpiresyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("cvc number");
field.name = ASCIIToUTF16("csc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2241,26 +2248,32 @@ TEST_F(FormStructureTestImpl, HeuristicsInferCCNames_NamesFirst) {
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("cc_first_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last name");
field.name = ASCIIToUTF16("last_name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card number");
field.name = ASCIIToUTF16("ccnumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration date");
field.name = ASCIIToUTF16("ccexpiresmonth");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("ccexpiresyear");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("cvc number");
field.name = ASCIIToUTF16("csc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2296,22 +2309,27 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
field.label = ASCIIToUTF16("Name on Card");
field.name = ASCIIToUTF16("name_on_card");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("billing_address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("card_number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("expiration_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Year");
field.name = ASCIIToUTF16("expiration_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2320,7 +2338,9 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
FormFieldData::CheckStatus::kCheckableButUnchecked;
checkable_field.label = ASCIIToUTF16("Checkable1");
checkable_field.name = ASCIIToUTF16("Checkable1");
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
+
FormStructure form_structure(form);
std::vector<FormStructure*> forms;
@@ -2331,7 +2351,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
// Prepare the expected proto string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -2379,6 +2399,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
for (size_t i = 0; i < 5; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
@@ -2441,6 +2462,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
for (size_t i = 0; i < 300; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
malformed_form.fields.push_back(field);
}
@@ -2568,6 +2590,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2575,6 +2598,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2583,6 +2607,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2591,6 +2616,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER}, {AutofillProfile::EMPTY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2599,6 +2625,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2610,6 +2637,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2640,7 +2668,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -2699,6 +2727,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMatchingValidities) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -2767,6 +2796,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2774,6 +2804,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2782,6 +2813,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2790,6 +2822,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER}, {AutofillProfile::EMPTY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2798,6 +2831,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2809,6 +2843,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2839,7 +2874,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithNonMatchingValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -2899,6 +2934,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST},
{AutofillProfile::UNVALIDATED, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
@@ -2906,6 +2942,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST},
{AutofillProfile::UNVALIDATED, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -2914,6 +2951,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS},
{AutofillProfile::INVALID, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -2923,6 +2961,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
possible_field_types, possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER},
{AutofillProfile::EMPTY, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -2931,6 +2970,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID, AutofillProfile::VALID});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -2942,6 +2982,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
{ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID, AutofillProfile::VALID});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -2972,7 +3013,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithMultipleValidities) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -3030,12 +3071,14 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.name = ASCIIToUTF16("firstname");
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
@@ -3043,6 +3086,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.form_control_type = "email";
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
@@ -3051,6 +3095,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{PHONE_HOME_WHOLE_NUMBER});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
@@ -3059,6 +3104,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ADDRESS_HOME_COUNTRY});
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add checkable field.
@@ -3070,6 +3116,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ADDRESS_HOME_COUNTRY});
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
form_structure = std::make_unique<FormStructure>(form);
@@ -3106,7 +3153,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
AutofillUploadContents upload;
upload.set_submission(true);
upload.set_submission_event(AutofillUploadContents::HTML_FORM_SUBMISSION);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
@@ -3159,6 +3206,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -3216,6 +3264,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities,
@@ -3254,35 +3303,45 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {USERNAME});
+
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
{ACCOUNT_CREATION_PASSWORD});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3316,7 +3375,7 @@ TEST_F(FormStructureTestImpl,
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440000000000000000802");
@@ -3383,22 +3442,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.autocomplete_attribute = "given-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3419,7 +3484,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithAutocomplete) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3473,9 +3538,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.autocomplete_attribute = "given-name";
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask = FieldPropertiesFlags::kHadFocus;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
@@ -3484,9 +3551,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask =
FieldPropertiesFlags::kHadFocus | FieldPropertiesFlags::kUserTyped;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
@@ -3496,9 +3565,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
field.css_classes = ASCIIToUTF16("class1 class2");
field.properties_mask =
FieldPropertiesFlags::kHadFocus | FieldPropertiesFlags::kUserTyped;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3519,7 +3590,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestWithPropertiesMask) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3571,22 +3642,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstname");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
field.form_control_type = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3607,7 +3684,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_ObservedSubmissionFalse) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(false);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3653,17 +3730,23 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
field.form_control_type = "text";
// No label for the first field.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3684,7 +3767,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithLabels) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3725,19 +3808,25 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
FormFieldData field;
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.css_classes = ASCIIToUTF16("last_name_field");
field.id_attribute = ASCIIToUTF16("lastname_id");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.css_classes = ASCIIToUTF16("email_field required_field");
field.id_attribute = ASCIIToUTF16("email_id");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3758,7 +3847,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithCssClassesAndIds) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3814,12 +3903,17 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
FormFieldData field;
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
@@ -3845,7 +3939,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_WithFormName) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3894,22 +3988,28 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
// Some fields don't have "name" or "autocomplete" attributes, and some have
// neither.
// No label.
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
field.autocomplete_attribute = "family-name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.form_control_type = "email";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -3930,7 +4030,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequestPartialMetadata) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -3984,18 +4084,22 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
field.id_attribute = ASCIIToUTF16("first_name");
field.autocomplete_attribute = "given-name";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastname");
field.name_attribute = field.name;
field.id_attribute = ASCIIToUTF16("last_name");
field.autocomplete_attribute = "family-name";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
+
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
@@ -4003,9 +4107,11 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
field.form_control_type = "email";
field.autocomplete_attribute = "email";
field.css_classes = ASCIIToUTF16("class1 class2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
+
form_structure = std::make_unique<FormStructure>(form);
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
@@ -4026,7 +4132,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_DisabledMetadataTrial) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(true);
upload.set_data_present("1440");
@@ -4069,16 +4175,19 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4103,7 +4212,7 @@ TEST_F(FormStructureTestImpl, CheckDataPresence) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure.form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("");
@@ -4355,6 +4464,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS});
@@ -4362,6 +4472,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_FIRST});
@@ -4369,6 +4480,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(
possible_field_types, possible_field_types_validities, {NAME_LAST});
@@ -4376,6 +4488,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
test::InitializePossibleTypesAndValidities(possible_field_types,
possible_field_types_validities,
@@ -4392,7 +4505,7 @@ TEST_F(FormStructureTestImpl, CheckMultipleTypes) {
// Prepare the expected proto string.
AutofillUploadContents upload;
upload.set_submission(true);
- upload.set_client_version("6.1.1715.1442/en (GGLL)");
+ upload.set_client_version(GetProductNameAndVersionForUserAgent());
upload.set_form_signature(form_structure->form_signature().value());
upload.set_autofill_used(false);
upload.set_data_present("1440000360000008");
@@ -4500,14 +4613,17 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_PasswordsRevealed) {
FormFieldData field;
field.name = ASCIIToUTF16("email");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.name = ASCIIToUTF16("first");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.name = ASCIIToUTF16("last");
field.name_attribute = field.name;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4529,6 +4645,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_IsFormTag) {
form.url = GURL("http://www.foo.com/");
FormFieldData field;
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form.is_form_tag = is_form_tag;
@@ -4581,6 +4698,7 @@ TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) {
field.aria_label = ASCIIToUTF16(f.aria_label);
field.aria_description = ASCIIToUTF16(f.aria_description);
field.css_classes = ASCIIToUTF16(f.css_classes);
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
RandomizedEncoder encoder("seed for testing",
@@ -4722,6 +4840,7 @@ TEST_F(FormStructureTestImpl, Metadata_OnlySendFullUrlWithUserConsent) {
field.form_control_type = "text";
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
TestingPrefServiceSimple prefs;
@@ -4755,10 +4874,12 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("first");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Checkable fields shouldn't affect the signature.
@@ -4766,6 +4887,7 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.name = ASCIIToUTF16("Select");
field.form_control_type = "checkbox";
field.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
form_structure = std::make_unique<FormStructure>(form);
@@ -4796,16 +4918,24 @@ TEST_F(FormStructureTestImpl, CheckFormSignature) {
field.label = ASCIIToUTF16("Random Field label");
field.name = ASCIIToUTF16("random1234");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label2");
field.name = ASCIIToUTF16("random12345");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label3");
field.name = ASCIIToUTF16("1ran12dom12345678");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Random Field label3");
field.name = ASCIIToUTF16("12345ran123456dom123");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
form_structure = std::make_unique<FormStructure>(form);
EXPECT_EQ(FormStructureTestImpl::Hash64Bit(
std::string("https://login.facebook.com&login_form&email&first&"
@@ -4823,16 +4953,19 @@ TEST_F(FormStructureTestImpl, ToFormData) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
EXPECT_TRUE(form.SameFormAs(FormStructure(form).ToFormData()));
@@ -4848,18 +4981,21 @@ TEST_F(FormStructureTestImpl, SkipFieldTest) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("select");
field.name = ASCIIToUTF16("select");
field.form_control_type = "checkbox";
field.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
field.check_status = FormFieldData::CheckStatus::kNotCheckable;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4870,7 +5006,7 @@ TEST_F(FormStructureTestImpl, SkipFieldTest) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -4903,16 +5039,19 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLabels) {
// No label on the first field.
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Email address");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
std::vector<FormStructure*> forms;
@@ -4923,7 +5062,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLabels) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -4954,6 +5093,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
// No label on the first field.
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// This label will be truncated in the XML request.
@@ -4964,11 +5104,13 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
"Exceeding A Certain Number Of Characters...");
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Enter your Password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -4979,7 +5121,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_WithLongLabels) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5011,6 +5153,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
@@ -5018,6 +5161,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
field.name = ASCIIToUTF16("");
field.form_control_type = "text";
field.check_status = FormFieldData::CheckStatus::kNotCheckable;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5029,7 +5173,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_MissingNames) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5065,12 +5209,14 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) {
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = base::string16();
field.name = ASCIIToUTF16("country");
field.form_control_type = "text";
field.check_status = FormFieldData::CheckStatus::kNotCheckable;
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5081,7 +5227,7 @@ TEST_F(FormStructureTestImpl, EncodeQueryRequest_DisabledMetadataTrial) {
// Create the expected query and serialize it to a string.
AutofillPageQueryRequest query;
- query.set_client_version("6.1.1715.1442/en (GGLL)");
+ query.set_client_version(GetProductNameAndVersionForUserAgent());
AutofillPageQueryRequest::Form* query_form = query.add_forms();
query_form->set_signature(form_structure.form_signature().value());
@@ -5115,7 +5261,9 @@ TEST_F(FormStructureTestImpl, PossibleValues) {
field.option_values.push_back(ASCIIToUTF16(""));
field.option_contents.push_back(ASCIIToUTF16("Germany"));
field.option_values.push_back(ASCIIToUTF16("GRMNY"));
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
+
FormStructure form_structure(form_data);
form_structure.ParseFieldTypesFromAutocompleteAttributes();
@@ -5138,7 +5286,9 @@ TEST_F(FormStructureTestImpl, PossibleValues) {
// A freeform input (<input>) allows any value (overriding other <select>s).
FormFieldData freeform_field;
freeform_field.autocomplete_attribute = "billing country";
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(freeform_field);
+
FormStructure form_structure2(form_data);
form_structure2.ParseFieldTypesFromAutocompleteAttributes();
EXPECT_EQ(0U, form_structure2.PossibleValues(ADDRESS_BILLING_COUNTRY).size());
@@ -5395,15 +5545,18 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_UnknownType) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("fname");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lname");
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
field.autocomplete_attribute = "address-level2";
+ field.unique_renderer_id = MakeFieldRendererId();
form_data.fields.push_back(field);
FormStructure form(form_data);
@@ -5454,10 +5607,12 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
field.label = ASCIIToUTF16("fullname");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Checkable fields should be ignored in parsing
@@ -5466,6 +5621,7 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
checkable_field.form_control_type = "radio";
checkable_field.check_status =
FormFieldData::CheckStatus::kCheckableButUnchecked;
+ checkable_field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(checkable_field);
FormStructure form_structure(form);
@@ -5476,11 +5632,13 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponse) {
FormData form2;
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form2.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form2.fields.push_back(field);
FormStructure form_structure2(form2);
@@ -5545,6 +5703,7 @@ TEST_F(FormStructureTestImpl,
field.form_control_type = "email";
field.label = ASCIIToUTF16("emailaddress");
field.name = ASCIIToUTF16("emailaddress");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add form to the vector needed by the response parsing function.
@@ -5574,6 +5733,7 @@ TEST_F(FormStructureTestImpl, ParseApiQueryResponseWhenPayloadNotBase64) {
field.form_control_type = "email";
field.label = ASCIIToUTF16("emailaddress");
field.name = ASCIIToUTF16("emailaddress");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Add form to the vector needed by the response parsing function.
@@ -5615,12 +5775,14 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_AuthorDefinedTypes) {
field.name = ASCIIToUTF16("email");
field.form_control_type = "text";
field.autocomplete_attribute = "email";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
field.autocomplete_attribute = "new-password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5656,18 +5818,22 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeLoneField) {
field.label = ASCIIToUTF16("fullname");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("height");
field.name = ASCIIToUTF16("height");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5703,14 +5869,17 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeCCName) {
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("fname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("email");
field.name = ASCIIToUTF16("email");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5745,22 +5914,27 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeMultiMonth_1) {
field.label = ASCIIToUTF16("Cardholder");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Month)");
field.name = ASCIIToUTF16("expiry_month");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Year");
field.name = ASCIIToUTF16("expiry_year");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Quantity");
field.name = ASCIIToUTF16("quantity");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5804,18 +5978,22 @@ TEST_F(FormStructureTestImpl, ParseQueryResponse_RationalizeMultiMonth_2) {
field.label = ASCIIToUTF16("Cardholder");
field.name = ASCIIToUTF16("fullname");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Card Number");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiry Date (MMYY)");
field.name = ASCIIToUTF16("expiry");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Quantity");
field.name = ASCIIToUTF16("quantity");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -5981,7 +6159,16 @@ TEST_F(FormStructureTestImpl, FindLongestCommonPrefix) {
EXPECT_EQ(ASCIIToUTF16(""), prefix);
}
-TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
+TEST_P(ParameterizedFormStructureTest,
+ RationalizePhoneNumber_RunsOncePerSection) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
+
FormData form;
form.url = GURL("http://foo.com");
FormFieldData field;
@@ -5990,18 +6177,22 @@ TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Home Phone");
field.name = ASCIIToUTF16("homePhoneNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Cell Phone");
field.name = ASCIIToUTF16("cellPhoneNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6022,9 +6213,15 @@ TEST_F(FormStructureTestImpl, RationalizePhoneNumber_RunsOncePerSection) {
FormStructure::ParseApiQueryResponse(
response_string, forms, test::GetEncodedSignatures(forms), nullptr);
- EXPECT_FALSE(form_structure.phone_rationalized_["fullName_1-default"]);
- form_structure.RationalizePhoneNumbersInSection("fullName_1-default");
- EXPECT_TRUE(form_structure.phone_rationalized_["fullName_1-default"]);
+ if (section_with_renderer_ids) {
+ EXPECT_FALSE(form_structure.phone_rationalized_["fullName_11-default"]);
+ form_structure.RationalizePhoneNumbersInSection("fullName_11-default");
+ EXPECT_TRUE(form_structure.phone_rationalized_["fullName_11-default"]);
+ } else {
+ EXPECT_FALSE(form_structure.phone_rationalized_["fullName_1-default"]);
+ form_structure.RationalizePhoneNumbersInSection("fullName_1-default");
+ EXPECT_TRUE(form_structure.phone_rationalized_["fullName_1-default"]);
+ }
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
@@ -6048,14 +6245,17 @@ TEST_F(FormStructureTestImpl, RationalizeRepeatedFields_OneAddress) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6095,18 +6295,22 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_TwoAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6148,22 +6352,27 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_ThreeAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6209,26 +6418,32 @@ TEST_F(FormStructureTestImpl, RationalizeRepreatedFields_FourAddresses) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6281,31 +6496,37 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6361,78 +6582,93 @@ TEST_F(
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Shipping";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Billing
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Billing";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Work address (not realistic)
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.section = "Work";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -6513,26 +6749,32 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6588,39 +6830,48 @@ TEST_F(
// Shipping
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Billing
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6677,45 +6928,55 @@ TEST_F(FormStructureTestImpl,
// First Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Second Section
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Third Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Fourth Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6779,18 +7040,22 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.section = "billing";
@@ -6799,54 +7064,64 @@ TEST_F(FormStructureTestImpl,
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.section = "billing-2";
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -6912,74 +7187,88 @@ TEST_F(FormStructureTestImpl,
// First Section
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.form_control_type = "select-one";
field.role = FormFieldData::RoleAttribute::kPresentation; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.role = FormFieldData::RoleAttribute::kOther; // visible
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Second Section
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Third Section
field.label = ASCIIToUTF16("city");
field.name = ASCIIToUTF16("City");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.form_control_type = "select-one";
field.role = FormFieldData::RoleAttribute::kPresentation; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.role = FormFieldData::RoleAttribute::kOther; // visible
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7057,28 +7346,33 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country3");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7121,34 +7415,40 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country2");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country3");
field.form_control_type = "select-one";
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.is_focusable = true; // visible
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state");
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("State");
field.name = ASCIIToUTF16("state2");
field.is_focusable = true; // visible
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7208,22 +7508,26 @@ TEST_P(ParameterizedFormStructureTest,
// Autocomplete Off, with server data.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete Off, without server data.
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete On, with server data.
field.should_autocomplete = true;
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
// Autocomplete On, without server data.
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7277,18 +7581,22 @@ TEST_P(ParameterizedFormStructureTest, NoServerDataCCFields_CVC_NoOverwrite) {
// All fields with autocomplete off and no server data.
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Credit Card Number");
field.name = ASCIIToUTF16("cc-number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("exp-date");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("CVC");
field.name = ASCIIToUTF16("cvc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7352,18 +7660,22 @@ TEST_P(ParameterizedFormStructureTest, WithServerDataCCFields_CVC_NoOverwrite) {
// All fields with autocomplete off and no server data.
field.label = ASCIIToUTF16("Cardholder Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Credit Card Number");
field.name = ASCIIToUTF16("cc-number");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Expiration Date");
field.name = ASCIIToUTF16("exp-date");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("CVC");
field.name = ASCIIToUTF16("cvc");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7443,16 +7755,22 @@ TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) {
// Just adding >=3 random fields to trigger rationalization.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Something under test");
field.name = ASCIIToUTF16("tested-thing");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7503,17 +7821,22 @@ TEST_P(RationalizationFieldTypeRelationshipsTest,
// Just adding >=3 random fields to trigger rationalization.
field.label = ASCIIToUTF16("First Name");
field.name = ASCIIToUTF16("firstName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
+
field.label = ASCIIToUTF16("Last Name");
field.name = ASCIIToUTF16("lastName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Some field with required type");
field.name = ASCIIToUTF16("some-name");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Something under test");
field.name = ASCIIToUTF16("tested-thing");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
AutofillQueryResponse response;
@@ -7560,6 +7883,7 @@ TEST_F(FormStructureTestImpl, AllowBigForms) {
for (size_t i = 0; i < 250; ++i) {
field.form_control_type = "text";
field.name = ASCIIToUTF16("text") + base::NumberToString16(i);
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
}
@@ -7578,14 +7902,11 @@ TEST_F(FormStructureTestImpl, AllowBigForms) {
// Tests that an Autofill upload for password form with 1 field should not be
// uploaded.
TEST_F(FormStructureTestImpl, OneFieldPasswordFormShouldNotBeUpload) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /* enabled features */ {kAutofillEnforceMinRequiredFieldsForUpload},
- /* disabled features */ {kAutofillEnforceMinRequiredFieldsForQuery});
FormData form;
FormFieldData field;
field.name = ASCIIToUTF16("Password");
field.form_control_type = "password";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
EXPECT_FALSE(FormStructure(form).ShouldBeUploaded());
@@ -7611,9 +7932,15 @@ TEST_F(FormStructureTestImpl, CreateForPasswordManagerUpload) {
// Tests if a new logical form is started with the second appearance of a field
// of type |NAME|.
-TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+TEST_P(ParameterizedFormStructureTest, NoAutocompleteSectionNames) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7623,26 +7950,32 @@ TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7661,12 +7994,21 @@ TEST_F(FormStructureTestImpl, NoAutocompleteSectionNames) {
// Assert the correct number of fields.
ASSERT_EQ(6U, form_structure.field_count());
- EXPECT_EQ("fullName_1-default", form_structure.field(0)->section);
- EXPECT_EQ("fullName_1-default", form_structure.field(1)->section);
- EXPECT_EQ("fullName_1-default", form_structure.field(2)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(3)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(4)->section);
- EXPECT_EQ("fullName_2-default", form_structure.field(5)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("fullName_11-default", form_structure.field(0)->section);
+ EXPECT_EQ("fullName_11-default", form_structure.field(1)->section);
+ EXPECT_EQ("fullName_11-default", form_structure.field(2)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(3)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(4)->section);
+ EXPECT_EQ("fullName_14-default", form_structure.field(5)->section);
+ } else {
+ EXPECT_EQ("fullName_1-default", form_structure.field(0)->section);
+ EXPECT_EQ("fullName_1-default", form_structure.field(1)->section);
+ EXPECT_EQ("fullName_1-default", form_structure.field(2)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(3)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(4)->section);
+ EXPECT_EQ("fullName_2-default", form_structure.field(5)->section);
+ }
}
// Tests that the immediate recurrence of the |PHONE_HOME_NUMBER| type does not
@@ -7683,33 +8025,40 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Mobile Number");
field.name = ASCIIToUTF16("mobileNumber");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
field.autocomplete_attribute = "section-blue billing tel";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Mobile Number");
field.name = ASCIIToUTF16("mobileNumber");
field.autocomplete_attribute = "section-blue billing tel";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7740,9 +8089,15 @@ TEST_F(FormStructureTestImpl, NoSplitByRecurringPhoneFieldType) {
// Tests if a new logical form is started with the second appearance of a field
// of type |ADDRESS_HOME_COUNTRY|.
-TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+TEST_P(ParameterizedFormStructureTest, SplitByRecurringFieldType) {
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7753,21 +8108,25 @@ TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7787,16 +8146,26 @@ TEST_F(FormStructureTestImpl, SplitByRecurringFieldType) {
EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
EXPECT_EQ("blue-shipping-default", form_structure.field(1)->section);
EXPECT_EQ("blue-shipping-default", form_structure.field(2)->section);
- EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("country_14-default", form_structure.field(3)->section);
+ } else {
+ EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ }
}
// Tests if a new logical form is started with the second appearance of a field
// of type |NAME_FULL| and another with the second appearance of a field of
// type |ADDRESS_HOME_COUNTRY|.
-TEST_F(FormStructureTestImpl,
+TEST_P(ParameterizedFormStructureTest,
SplitByNewAutocompleteSectionNameAndRecurringType) {
- base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseNewSectioningMethod);
+ bool section_with_renderer_ids = GetParam();
+ base::test::ScopedFeatureList scoped_features;
+ std::vector<base::Feature> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(features::kAutofillUseNewSectioningMethod);
+ (section_with_renderer_ids ? &enabled : &disabled)
+ ->push_back(features::kAutofillNameSectionsWithRendererIds);
+ scoped_features.InitWithFeatures(enabled, disabled);
FormData form;
form.url = GURL("http://foo.com");
@@ -7807,21 +8176,25 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue billing country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7842,7 +8215,11 @@ TEST_F(FormStructureTestImpl,
EXPECT_EQ("blue-shipping-default", form_structure.field(0)->section);
EXPECT_EQ("blue-billing-default", form_structure.field(1)->section);
EXPECT_EQ("blue-billing-default", form_structure.field(2)->section);
- EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ if (section_with_renderer_ids) {
+ EXPECT_EQ("country_14-default", form_structure.field(3)->section);
+ } else {
+ EXPECT_EQ("country_2-default", form_structure.field(3)->section);
+ }
}
// Tests if a new logical form is started with the second appearance of a field
@@ -7860,21 +8237,25 @@ TEST_F(FormStructureTestImpl, SplitByNewAutocompleteSectionName) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7914,21 +8295,25 @@ TEST_F(
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-blue billing name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("City");
field.name = ASCIIToUTF16("city");
field.autocomplete_attribute = "";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -7966,11 +8351,13 @@ TEST_F(FormStructureTestImpl, FromEmptyAutocompleteSectionToDefinedOne) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -8005,17 +8392,20 @@ TEST_F(FormStructureTestImpl,
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Phone");
field.name = ASCIIToUTF16("phone");
field.is_focusable = false; // hidden
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("FullName");
field.name = ASCIIToUTF16("fullName");
field.is_focusable = true; // visible
field.autocomplete_attribute = "shipping name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
@@ -8052,11 +8442,13 @@ TEST_F(FormStructureTestImpl, IgnoreAribtraryAutocompleteSectionName) {
field.label = ASCIIToUTF16("Full Name");
field.name = ASCIIToUTF16("fullName");
field.autocomplete_attribute = "section-red ship name";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
field.label = ASCIIToUTF16("Country");
field.name = ASCIIToUTF16("country");
field.autocomplete_attribute = "section-blue shipping country";
+ field.unique_renderer_id = MakeFieldRendererId();
form.fields.push_back(field);
FormStructure form_structure(form);
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
new file mode 100644
index 00000000000..1e5ed929936
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
@@ -0,0 +1,156 @@
+// Copyright 2020 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/geo/alternative_state_name_map.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace autofill {
+
+namespace {
+
+// Assuming a user can have maximum 500 profiles each containing a different
+// state string in the worst case scenario.
+constexpr int kMaxMapSize = 500;
+
+// The characters to be removed from the state strings before the comparison.
+constexpr char kCharsToStrip[] = ".- ";
+
+} // namespace
+
+// static
+AlternativeStateNameMap* AlternativeStateNameMap::GetInstance() {
+ static base::NoDestructor<AlternativeStateNameMap>
+ g_alternative_state_name_map;
+ return g_alternative_state_name_map.get();
+}
+
+AlternativeStateNameMap::AlternativeStateNameMap() = default;
+
+// static
+AlternativeStateNameMap::StateName AlternativeStateNameMap::NormalizeStateName(
+ const StateName& text) {
+ base::string16 normalized_text;
+ base::RemoveChars(text.value(), base::ASCIIToUTF16(kCharsToStrip),
+ &normalized_text);
+ return StateName(normalized_text);
+}
+
+base::Optional<AlternativeStateNameMap::CanonicalStateName>
+AlternativeStateNameMap::GetCanonicalStateName(
+ const CountryCode& country_code,
+ const StateName& state_name,
+ bool is_state_name_normalized) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ // Example:
+ // Entries in |localized_state_names_map_| are:
+ // ("DE", "Bavaria") -> {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }
+ // Entries in |localized_state_names_reverse_lookup_map_| are:
+ // ("DE", "Bayern") -> "Bayern"
+ // ("DE", "BY") -> "Bayern"
+ // ("DE", "Bavaria") -> "Bayern"
+ // then, AlternativeStateNameMap::GetCanonicalStateName("DE", "Bayern") =
+ // AlternativeStateNameMap::GetCanonicalStateName("DE", "BY") =
+ // AlternativeStateNameMap::GetCanonicalStateName("DE", "Bavaria") =
+ // CanonicalStateName("Bayern")
+ StateName normalized_state_name = state_name;
+ if (!is_state_name_normalized)
+ normalized_state_name = NormalizeStateName(state_name);
+
+ auto it = localized_state_names_reverse_lookup_map_.find(
+ {country_code, normalized_state_name});
+ if (it != localized_state_names_reverse_lookup_map_.end())
+ return it->second;
+
+ return base::nullopt;
+}
+
+base::Optional<StateEntry> AlternativeStateNameMap::GetEntry(
+ const CountryCode& country_code,
+ const StateName& state_string_from_profile) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+
+ StateName normalized_state_string_from_profile =
+ NormalizeStateName(state_string_from_profile);
+ base::Optional<CanonicalStateName> canonical_state_name =
+ GetCanonicalStateName(country_code, normalized_state_string_from_profile,
+ /*is_state_name_normalized=*/true);
+
+ if (!canonical_state_name) {
+ canonical_state_name =
+ CanonicalStateName(normalized_state_string_from_profile.value());
+ }
+
+ DCHECK(canonical_state_name);
+ auto it = localized_state_names_map_.find(
+ {country_code, canonical_state_name.value()});
+ if (it != localized_state_names_map_.end())
+ return it->second;
+
+ return base::nullopt;
+}
+
+void AlternativeStateNameMap::AddEntry(
+ const CountryCode& country_code,
+ const StateName& normalized_state_value_from_profile,
+ const StateEntry& state_entry,
+ const std::vector<StateName>& normalized_alternative_state_names,
+ CanonicalStateName* normalized_canonical_state_name) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+
+ // Example:
+ // AddEntry("DE", "Bavaria", {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }, {"Bavaria", "BY", "Bayern"}, "Bayern")
+ // Then entry added to |localized_state_names_map_| is:
+ // ("DE", "Bayern") -> {
+ // "canonical_name": "Bayern",
+ // "abbreviations": "BY",
+ // "alternative_names": "Bavaria"
+ // }
+ // Entries added to |localized_state_names_reverse_lookup_map_| are:
+ // ("DE", "Bayern") -> "Bayern"
+ // ("DE", "BY") -> "Bayern"
+ // ("DE", "Bavaria") -> "Bayern"
+
+ if (localized_state_names_map_.size() == kMaxMapSize ||
+ GetCanonicalStateName(country_code, normalized_state_value_from_profile,
+ /*is_state_name_normalized=*/true)) {
+ return;
+ }
+
+ if (normalized_canonical_state_name) {
+ localized_state_names_map_[{
+ country_code, *normalized_canonical_state_name}] = state_entry;
+ for (const auto& alternative_name : normalized_alternative_state_names) {
+ localized_state_names_reverse_lookup_map_[{
+ country_code, alternative_name}] = *normalized_canonical_state_name;
+ }
+ } else {
+ localized_state_names_map_[{
+ country_code,
+ CanonicalStateName(normalized_state_value_from_profile.value())}] =
+ state_entry;
+ }
+}
+
+bool AlternativeStateNameMap::IsLocalisedStateNamesMapEmpty() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ return localized_state_names_map_.empty();
+}
+
+void AlternativeStateNameMap::ClearAlternativeStateNameMap() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(alternative_state_name_map_sequence_checker_);
+ localized_state_names_map_.clear();
+ localized_state_names_reverse_lookup_map_.clear();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
new file mode 100644
index 00000000000..1ed11eaa6c6
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.h
@@ -0,0 +1,181 @@
+// Copyright 2020 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_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
+
+#include "components/autofill/core/browser/proto/states.pb.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/no_destructor.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string16.h"
+#include "base/util/type_safety/strong_alias.h"
+
+namespace autofill {
+// AlternativeStateNameMap encapsulates mappings from state names in the
+// profiles to their localized and the abbreviated names.
+//
+// AlternativeStateNameMap is used for the filling of state fields, comparison
+// of profiles, determining mergeability of the address profiles and required
+// |ADDRESS_HOME_STATE| votes to be sent to the server.
+//
+// AlternativeStateNameMap can provide the following data for the states:
+// 1. The state string stored in the address profile denoted by
+// state_string_from_profile in this class.
+// 2. The canonical state name (StateEntry::canonical_name) which acts as the
+// unique identifier representing the state (unique within a country).
+// 3. The abbreviations of the state (StateEntry::abbreviations).
+// 4. The alternative names of the state (StateEntry::alternative_names).
+//
+// StateEntry holds the information about the abbreviations and the
+// alternative names of the state which is determined after comparison with the
+// state values saved in the address profiles if they match.
+//
+// The main map |localized_state_names_map_| maps the tuple
+// (country_code, canonical state name) as the key to the corresponding
+// StateEntry object (with the information about the abbreviations and the
+// alternative names) as the value.
+//
+// The |localized_state_names_reverse_lookup_map_| takes in the
+// country_code and StateEntry::name, StateEntry::abbreviations or
+// ::alternative_names as the key and the canonical state name as the value.
+//
+// Example: Considering "California" as the state_string_from_profile and
+// the corresponding StateEntry object:
+// {
+// 'canonical_name': 'California',
+// 'abbreviations': ['CA'],
+// 'alternate_names': ['The Golden State']
+// }
+//
+// 1. StateEntry::canonical_name (i.e "California" in this case) acts
+// as the canonical state name.
+// 2. ("US", "California") acts as the key and the above StateEntry
+// object is added as the value in the
+// |localized_state_names_map_|.
+// 3. Entries added to |localized_state_names_reverse_lookup_map_|
+// are:
+// a. ("US", "California") -> "California"
+// b. ("US", "CA") -> "California"
+// c. ("US", "TheGoldenState") -> "California"
+//
+// Example: Assuming the user creates an unknown state in the profile
+// "Random State".
+// 1. Entries added to the |localized_state_names_map_| are:
+// ("RandomState", Empty StateEntry object)
+// 2. Nothing is added to the
+// |localized_state_names_reverse_lookup_map_| in this case
+class AlternativeStateNameMap {
+ public:
+ // Represents ISO 3166-1 alpha-2 codes (always uppercase ASCII).
+ using CountryCode = util::StrongAlias<class CountryCodeTag, std::string>;
+
+ // Represents either a canonical state name, or an abbreviation, or an
+ // alternative name or normalized state name from the profile.
+ using StateName = util::StrongAlias<class StateNameTag, base::string16>;
+
+ // States can be represented as different strings (different spellings,
+ // translations, abbreviations). All representations of a single state in a
+ // single country are mapped to the same canonical name.
+ using CanonicalStateName =
+ util::StrongAlias<class CanonicalStateNameTag, base::string16>;
+
+ static AlternativeStateNameMap* GetInstance();
+
+ ~AlternativeStateNameMap() = delete;
+ AlternativeStateNameMap(const AlternativeStateNameMap&) = delete;
+ AlternativeStateNameMap& operator=(const AlternativeStateNameMap&) = delete;
+
+ // Removes |kCharsToStrip| from |text| and returns the normalized text.
+ static StateName NormalizeStateName(const StateName& text);
+
+ // Returns the canonical name (StateEntry::canonical_name) from the
+ // |localized_state_names_map_| based on
+ // (|country_code|, |state_name|).
+ base::Optional<CanonicalStateName> GetCanonicalStateName(
+ const CountryCode& country_code,
+ const StateName& state_name,
+ bool is_state_name_normalized = false) const;
+
+ // Returns the value present in |localized_state_names_map_| corresponding
+ // to (|country_code|, |state_string_from_profile|). In case, the entry does
+ // not exist in the map, base::nullopt is returned.
+ base::Optional<StateEntry> GetEntry(
+ const CountryCode& country_code,
+ const StateName& state_string_from_profile) const;
+
+ // Adds ((|country_code|, state key), |state_entry|) to the
+ // |localized_state_names_map_|, where state key corresponds to
+ // |normalized_canonical_state_name| if it is not null, or to
+ // |normalized_state_value_from_profile| otherwise.
+ // If |normalized_canonical_state_name| is not null, each entry from
+ // |normalized_alternative_state_names| is added as a tuple
+ // ((|country_code|, entry), |normalized_canonical_state_name|) to the
+ // |localized_state_names_reverse_lookup_map_|.
+ void AddEntry(
+ const CountryCode& country_code,
+ const StateName& normalized_state_value_from_profile,
+ const StateEntry& state_entry,
+ const std::vector<StateName>& normalized_alternative_state_names,
+ CanonicalStateName* normalized_canonical_state_name);
+
+ // Returns true if the |localized_state_names_map_| is empty.
+ bool IsLocalisedStateNamesMapEmpty() const;
+
+#if defined(UNIT_TEST)
+ // Clears the map for testing purposes.
+ void ClearAlternativeStateNameMapForTesting() {
+ ClearAlternativeStateNameMap();
+ }
+#endif
+
+ private:
+ AlternativeStateNameMap();
+
+ // Clears the |localized_state_names_map_| and
+ // |localized_state_names_reverse_lookup_map_|.
+ // Used only for testing purposes.
+ void ClearAlternativeStateNameMap();
+
+ // A custom comparator for the
+ // |localized_state_names_reverse_lookup_map_| that ignores the case
+ // of the string on comparisons.
+ struct CaseInsensitiveLessComparator {
+ bool operator()(const std::pair<CountryCode, StateName>& lhs,
+ const std::pair<CountryCode, StateName>& rhs) const {
+ // Compares the country codes that are always uppercase ASCII.
+ if (lhs.first != rhs.first)
+ return lhs.first.value() < rhs.first.value();
+
+ return base::i18n::ToLower(lhs.second.value()) <
+ base::i18n::ToLower(rhs.second.value());
+ }
+ };
+
+ // Since the constructor is private, |base::NoDestructor| must be friend to be
+ // allowed to construct the class.
+ friend class base::NoDestructor<AlternativeStateNameMap>;
+
+ // A map that stores the alternative state names. The map is keyed
+ // by the country_code and the canonical state name (or
+ // normalized_state_value_from_profile in case no canonical state name is
+ // known) while the value is the StateEntry object.
+ std::map<std::pair<CountryCode, CanonicalStateName>, StateEntry>
+ localized_state_names_map_;
+
+ // The map is keyed by the country_code and the abbreviation or
+ // canonical name or the alternative name of the state.
+ std::map<std::pair<CountryCode, StateName>,
+ CanonicalStateName,
+ CaseInsensitiveLessComparator>
+ localized_state_names_reverse_lookup_map_;
+
+ SEQUENCE_CHECKER(alternative_state_name_map_sequence_checker_);
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_H_
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
new file mode 100644
index 00000000000..9435c583dbf
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.cc
@@ -0,0 +1,69 @@
+// Copyright 2020 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/geo/alternative_state_name_map_test_utils.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+
+namespace autofill {
+
+namespace test {
+
+void PopulateStateEntry(const TestStateEntry& test_state_entry,
+ StateEntry* state_entry) {
+ state_entry->set_canonical_name(test_state_entry.canonical_name);
+ for (const auto& abbr : test_state_entry.abbreviations)
+ state_entry->add_abbreviations(abbr);
+ for (const auto& alternative_name : test_state_entry.alternative_names)
+ state_entry->add_alternative_names(alternative_name);
+}
+
+void ClearAlternativeStateNameMapForTesting() {
+ AlternativeStateNameMap::GetInstance()
+ ->ClearAlternativeStateNameMapForTesting();
+}
+
+void PopulateAlternativeStateNameMapForTesting(
+ const std::string& country_code,
+ const std::string& key,
+ const std::vector<TestStateEntry>& test_state_entries) {
+ for (const auto& test_state_entry : test_state_entries) {
+ StateEntry state_entry;
+ PopulateStateEntry(test_state_entry, &state_entry);
+ std::vector<AlternativeStateNameMap::StateName> alternatives;
+ AlternativeStateNameMap::CanonicalStateName canonical_state_name =
+ AlternativeStateNameMap::CanonicalStateName(
+ base::ASCIIToUTF16(test_state_entry.canonical_name));
+ alternatives.emplace_back(
+ AlternativeStateNameMap::StateName(canonical_state_name.value()));
+ for (const auto& abbr : test_state_entry.abbreviations)
+ alternatives.emplace_back(
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(abbr)));
+ for (const auto& alternative_name : test_state_entry.alternative_names)
+ alternatives.emplace_back(AlternativeStateNameMap::StateName(
+ base::ASCIIToUTF16(alternative_name)));
+
+ AlternativeStateNameMap::GetInstance()->AddEntry(
+ AlternativeStateNameMap::CountryCode(country_code),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(key)),
+ state_entry, alternatives, &canonical_state_name);
+ }
+}
+
+std::string CreateStatesProtoAsString(const std::string& country_code,
+ const TestStateEntry& test_state_entry) {
+ StatesInCountry states_data;
+ states_data.set_country_code(std::move(country_code));
+ StateEntry* entry = states_data.add_states();
+ PopulateStateEntry(test_state_entry, entry);
+
+ std::string serialized_output;
+ bool proto_is_serialized = states_data.SerializeToString(&serialized_output);
+ DCHECK(proto_is_serialized);
+ return serialized_output;
+}
+
+} // namespace test
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
new file mode 100644
index 00000000000..0c86be629a8
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
+
+#include "base/optional.h"
+#include "components/autofill/core/browser/proto/states.pb.h"
+
+namespace autofill {
+
+namespace test {
+
+namespace internal {
+template <typename = void>
+struct TestStateEntry {
+ std::string canonical_name = "Bavaria";
+ std::vector<std::string> abbreviations = {"BY"};
+ std::vector<std::string> alternative_names = {"Bayern"};
+};
+} // namespace internal
+
+using TestStateEntry = internal::TestStateEntry<>;
+
+// Populates |state_entry| with the data in |test_state_entry|.
+void PopulateStateEntry(const TestStateEntry& test_state_entry,
+ StateEntry* state_entry);
+
+// Clears the map for testing purposes.
+void ClearAlternativeStateNameMapForTesting();
+
+// Inserts a StateEntry instance into AlternativeStateNameMap for testing.
+void PopulateAlternativeStateNameMapForTesting(
+ const std::string& country_code = "DE",
+ const std::string& key = "Bavaria",
+ const std::vector<TestStateEntry>& test_state_entries = {TestStateEntry()});
+
+// Returns a StateEntry instance serialized as string.
+std::string CreateStatesProtoAsString(
+ const std::string& country_code = "DE",
+ const TestStateEntry& test_state_entry = TestStateEntry());
+
+} // namespace test
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_TEST_UTILS_H_
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
new file mode 100644
index 00000000000..268b41cec02
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_unittest.cc
@@ -0,0 +1,119 @@
+// Copyright 2020 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/geo/alternative_state_name_map.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace test {
+
+// Tests that map is not empty when an entry has been added to it.
+TEST(AlternativeStateNameMapTest, IsEntryAddedToMap) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ EXPECT_FALSE(
+ AlternativeStateNameMap::GetInstance()->IsLocalisedStateNamesMapEmpty());
+}
+
+// Tests that the state canonical name is present when an entry is added to
+// the map.
+TEST(AlternativeStateNameMapTest, StateCanonicalString) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+ const char* const kValidMatches[] = {"Bavaria", "BY", "Bayern", "by",
+ "BAVARIA", "B.Y", "BAYern", "B-Y"};
+ for (const char* valid_match : kValidMatches) {
+ SCOPED_TRACE(valid_match);
+ EXPECT_NE(alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(
+ base::ASCIIToUTF16(valid_match))),
+ base::nullopt);
+ }
+ EXPECT_EQ(
+ alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("US"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
+ base::nullopt);
+ EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(""))),
+ base::nullopt);
+ EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode(""),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16(""))),
+ base::nullopt);
+}
+
+// Tests that the separate entries are created in the map for the different
+// country codes.
+TEST(AlternativeStateNameMapTest, SeparateEntryForDifferentCounties) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting("DE");
+ test::PopulateAlternativeStateNameMapForTesting("US");
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+ EXPECT_NE(
+ alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
+ base::nullopt);
+ EXPECT_NE(
+ alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("US"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
+ base::nullopt);
+}
+
+// Tests that |AlternativeStateNameMap::NormalizeStateName()| removes "-", " "
+// and "." from the text.
+TEST(AlternativeStateNameMapTest, StripText) {
+ struct {
+ const char* test_string;
+ const char* expected;
+ } test_cases[] = {{"B.Y", "BY"},
+ {"The Golden Sun", "TheGoldenSun"},
+ {"Bavaria - BY", "BavariaBY"}};
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(testing::Message() << "test_string: " << test_case.test_string
+ << " | expected: " << test_case.expected);
+ AlternativeStateNameMap::StateName text =
+ AlternativeStateNameMap::StateName(
+ base::ASCIIToUTF16(test_case.test_string));
+ EXPECT_EQ(AlternativeStateNameMap::NormalizeStateName(text).value(),
+ base::ASCIIToUTF16(test_case.expected));
+ }
+}
+
+// Tests that the correct entries are returned when the maps in
+// AlternativeStateNameMap are queried.
+TEST(AlternativeStateNameMapTest, GetEntry) {
+ test::ClearAlternativeStateNameMapForTesting();
+ test::PopulateAlternativeStateNameMapForTesting();
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+ EXPECT_EQ(
+ alternative_state_name_map->GetEntry(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Random"))),
+ base::nullopt);
+ auto entry = alternative_state_name_map->GetEntry(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")));
+ EXPECT_NE(entry, base::nullopt);
+ ASSERT_TRUE(entry->has_canonical_name());
+ EXPECT_EQ(entry->canonical_name(), "Bavaria");
+ EXPECT_THAT(entry->abbreviations(),
+ testing::UnorderedElementsAreArray({"BY"}));
+ EXPECT_THAT(entry->alternative_names(),
+ testing::UnorderedElementsAreArray({"Bayern"}));
+}
+
+} // namespace test
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
new file mode 100644
index 00000000000..3c85158b61e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.cc
@@ -0,0 +1,226 @@
+// Copyright 2020 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/geo/alternative_state_name_map_updater.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/ranges/algorithm.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task_runner_util.h"
+#include "components/autofill/core/browser/geo/country_data.h"
+#include "components/autofill/core/common/autofill_l10n_util.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/prefs/pref_service.h"
+
+namespace autofill {
+
+namespace {
+
+// Returns data read from the file specified in |file|.
+std::string LoadDataFromFile(const base::FilePath& file) {
+ DCHECK(!file.empty());
+
+ std::string data;
+ if (!base::PathExists(file)) {
+ VLOG(1) << "File does not exist: " << file;
+ return std::string();
+ }
+
+ if (!base::ReadFileToString(file, &data)) {
+ VLOG(1) << "Failed reading from file: " << file;
+ return std::string();
+ }
+
+ return data;
+}
+
+} // namespace
+
+AlternativeStateNameMapUpdater::AlternativeStateNameMapUpdater()
+ : task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {}
+
+AlternativeStateNameMapUpdater::~AlternativeStateNameMapUpdater() = default;
+
+// static
+bool AlternativeStateNameMapUpdater::ContainsState(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile) {
+ l10n::CaseInsensitiveCompare compare;
+
+ // Returns true if |str1| is same as |str2| in a case-insensitive comparison.
+ return base::ranges::any_of(
+ stripped_alternative_state_names,
+ [&](const AlternativeStateNameMap::StateName& text) {
+ return compare.StringsEqual(text.value(),
+ stripped_state_values_from_profile.value());
+ });
+}
+
+void AlternativeStateNameMapUpdater::LoadStatesData(
+ const CountryToStateNamesListMapping& country_to_state_names_map,
+ PrefService* pref_service,
+ base::OnceClosure done_callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Get the states data installation path from |pref_service|.
+ const std::string data_download_path =
+ pref_service->GetString(prefs::kAutofillStatesDataDir);
+
+ // If the installed directory path is empty, it means that the component is
+ // not ready for use yet.
+ if (data_download_path.empty()) {
+ std::move(done_callback).Run();
+ return;
+ }
+
+ const std::vector<std::string>& country_codes =
+ CountryDataMap::GetInstance()->country_codes();
+
+ // The |country_to_state_names_map| maps country_code names to a vector of
+ // state names that are associated with this corresponding country.
+ for (const auto& entry : country_to_state_names_map) {
+ const AlternativeStateNameMap::CountryCode& country_code = entry.first;
+ const std::vector<AlternativeStateNameMap::StateName>& states =
+ entry.second;
+
+ // This is a security check to ensure that we only attempt to read files
+ // that match to known countries.
+ if (!base::Contains(country_codes, country_code.value()))
+ continue;
+
+ // country_code is used as the filename.
+ // Example -> File "DE" contains the geographical states data of Germany.
+ // |data_download_path| is set by the component updater once it downloads
+ // the states data and should be safe to use.
+ const base::FilePath file_path =
+ base::FilePath::FromUTF8Unsafe(data_download_path)
+ .AppendASCII(country_code.value());
+
+ ++number_pending_init_tasks_;
+ pending_init_done_callbacks_.push_back(std::move(done_callback));
+
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE,
+ base::BindOnce(&LoadDataFromFile, file_path),
+ base::BindOnce(
+ &AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent,
+ weak_ptr_factory_.GetWeakPtr(), states));
+ }
+}
+
+void AlternativeStateNameMapUpdater::ProcessLoadedStateFileContent(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_state_values_from_profiles,
+ const std::string& data) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ DCHECK_GT(number_pending_init_tasks_, 0);
+ --number_pending_init_tasks_;
+
+ StatesInCountry states_data;
+
+ if (!data.empty() && states_data.ParseFromString(data)) {
+ DCHECK(states_data.has_country_code());
+ AlternativeStateNameMap::CountryCode country_code =
+ AlternativeStateNameMap::CountryCode(states_data.country_code());
+
+ // Boolean flags that denote in |match_found[i]| whether the match has been
+ // found for |stripped_state_values_from_profiles[i]|.
+ std::vector<bool> match_found(stripped_state_values_from_profiles.size(),
+ false);
+
+ // Iterates over the states data loaded from the file and builds a list of
+ // the state names and its variations. For each value v in
+ // |stripped_state_values_from_profiles|, v is compared with the values in
+ // the above created states list (if a match is not found for v yet). If the
+ // comparison results in a match, the corresponding entry is added to the
+ // |AlternativeStateNameMap|.
+ for (const auto& state_entry : states_data.states()) {
+ DCHECK(state_entry.has_canonical_name());
+ AlternativeStateNameMap::CanonicalStateName state_canonical_name =
+ AlternativeStateNameMap::CanonicalStateName(
+ base::UTF8ToUTF16(state_entry.canonical_name()));
+
+ // Build a list of all the names of the state (including its
+ // abbreviations) in |state_names|.
+ const std::vector<AlternativeStateNameMap::StateName> state_names =
+ ExtractAllStateNames(state_entry);
+
+ for (size_t i = 0; i < stripped_state_values_from_profiles.size(); i++) {
+ if (match_found[i])
+ continue;
+
+ // If |stripped_state_values_from_profile[i] is in the set of names of
+ // the state under consideration, add it to the AlternativeStateNameMap.
+ if (ContainsState(state_names,
+ stripped_state_values_from_profiles[i])) {
+ AlternativeStateNameMap::GetInstance()->AddEntry(
+ country_code, stripped_state_values_from_profiles[i], state_entry,
+ state_names, &state_canonical_name);
+ match_found[i] = true;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < stripped_state_values_from_profiles.size(); i++) {
+ // In case, no match is found, insert an |empty_state_entry| object
+ // to the map.
+ if (!match_found[i]) {
+ StateEntry empty_state_entry;
+ AlternativeStateNameMap::GetInstance()->AddEntry(
+ country_code, stripped_state_values_from_profiles[i],
+ empty_state_entry, {}, nullptr);
+ }
+ }
+ }
+
+ // When all pending tasks are completed, trigger and clear the pending
+ // callbacks.
+ if (number_pending_init_tasks_ == 0) {
+ for (auto& callback : std::exchange(pending_init_done_callbacks_, {}))
+ std::move(callback).Run();
+ }
+}
+
+std::vector<AlternativeStateNameMap::StateName>
+AlternativeStateNameMapUpdater::ExtractAllStateNames(
+ const StateEntry& state_entry) {
+ DCHECK(state_entry.has_canonical_name());
+
+ std::vector<AlternativeStateNameMap::StateName> state_names;
+ state_names.reserve(1u + state_entry.abbreviations_size() +
+ state_entry.alternative_names_size());
+
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(
+ base::UTF8ToUTF16(state_entry.canonical_name()))));
+ for (const auto& abbr : state_entry.abbreviations()) {
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16(abbr))));
+ }
+ for (const auto& alternative_name : state_entry.alternative_names()) {
+ state_names.emplace_back(AlternativeStateNameMap::NormalizeStateName(
+ AlternativeStateNameMap::StateName(
+ base::UTF8ToUTF16(alternative_name))));
+ }
+
+ return state_names;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
new file mode 100644
index 00000000000..ab1caabaf66
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater.h
@@ -0,0 +1,113 @@
+// Copyright 2020 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_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+
+class PrefService;
+
+namespace autofill {
+
+using CountryToStateNamesListMapping =
+ std::map<AlternativeStateNameMap::CountryCode,
+ std::vector<AlternativeStateNameMap::StateName>>;
+
+// The AlternativeStateNameMap is a singleton to map between canonical state
+// names and alternative representations. This class encapsulates all aspects
+// about loading state data from disk and adding it to the
+// AlternativeStateNameMap.
+class AlternativeStateNameMapUpdater {
+ public:
+ AlternativeStateNameMapUpdater();
+ ~AlternativeStateNameMapUpdater();
+ AlternativeStateNameMapUpdater(const AlternativeStateNameMapUpdater&) =
+ delete;
+ AlternativeStateNameMapUpdater& operator=(
+ const AlternativeStateNameMapUpdater&) = delete;
+
+ // Creates and posts jobs to the |task_runner_| for reading the state data
+ // files and populating AlternativeStateNameMap. Once all files are read and
+ // the data is incorporated into AlternativeStateNameMap, |done_callback| is
+ // fired. |country_to_state_names_map| specifies which state data of which
+ // countries to load.
+ // Each call to LoadStatesData triggers loading state data files, so requests
+ // should be batched up.
+ void LoadStatesData(
+ const CountryToStateNamesListMapping& country_to_state_names_map,
+ PrefService* pref_service,
+ base::OnceClosure done_callback);
+
+#if defined(UNIT_TEST)
+ // A wrapper around |ProcessLoadedStateFileContent| used for testing purposes.
+ void ProcessLoadedStateFileContentForTesting(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ state_values_from_profiles,
+ const std::string& data,
+ base::OnceClosure callback) {
+ ++number_pending_init_tasks_;
+ pending_init_done_callbacks_.push_back(std::move(callback));
+ ProcessLoadedStateFileContent(state_values_from_profiles, data);
+ }
+
+ // A wrapper around |ContainsState| used for testing purposes.
+ static bool ContainsStateForTesting(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile) {
+ return ContainsState(stripped_alternative_state_names,
+ stripped_state_values_from_profile);
+ }
+#endif
+
+ private:
+ // Compares |stripped_state_value_from_profile| with the entries in
+ // |stripped_state_alternative_names| and returns true if a match is found.
+ static bool ContainsState(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ stripped_alternative_state_names,
+ const AlternativeStateNameMap::StateName&
+ stripped_state_values_from_profile);
+
+ // Each entry in |state_values_from_profiles| is compared with the states
+ // |data| read from the files and then inserted into the
+ // AlternativeStateNameMap.
+ void ProcessLoadedStateFileContent(
+ const std::vector<AlternativeStateNameMap::StateName>&
+ state_values_from_profiles,
+ const std::string& data);
+
+ // Builds and returns a list of all the names of the state (including its
+ // abbreviations) from the |state_entry| into |state_names|.
+ std::vector<AlternativeStateNameMap::StateName> ExtractAllStateNames(
+ const StateEntry& state_entry);
+
+ // TaskRunner for reading files from disk.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ // In case of concurrent requests to load states data, the callbacks are
+ // queued in |pending_init_done_callbacks_| and triggered once the
+ // |number_pending_init_tasks_| returns to 0.
+ std::vector<base::OnceClosure> pending_init_done_callbacks_;
+ int number_pending_init_tasks_ = 0;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // base::WeakPtr ensures that the callback bound to the object is canceled
+ // when that object is destroyed.
+ base::WeakPtrFactory<AlternativeStateNameMapUpdater> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_ALTERNATIVE_STATE_NAME_MAP_UPDATER_H_
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
new file mode 100644
index 00000000000..97a6eb1038a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2020 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/geo/alternative_state_name_map_updater.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/optional.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+
+namespace autofill {
+
+class AlternativeStateNameMapUpdaterTest : public ::testing::Test {
+ public:
+ AlternativeStateNameMapUpdaterTest()
+ : pref_service_(test::PrefServiceForTesting()) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(data_install_dir_.CreateUniqueTempDir());
+ }
+
+ const base::FilePath& GetPath() const { return data_install_dir_.GetPath(); }
+
+ void WritePathToPref(const base::FilePath& file_path) {
+ pref_service_->SetFilePath(autofill::prefs::kAutofillStatesDataDir,
+ file_path);
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ AlternativeStateNameMapUpdater alternative_state_name_map_updater;
+ std::unique_ptr<PrefService> pref_service_;
+ base::ScopedTempDir data_install_dir_;
+};
+
+// Tests that the states data is added to AlternativeStateNameMap.
+TEST_F(AlternativeStateNameMapUpdaterTest, EntryAddedToStateMap) {
+ test::ClearAlternativeStateNameMapForTesting();
+ std::string states_data = test::CreateStatesProtoAsString();
+ std::vector<AlternativeStateNameMap::StateName> test_strings = {
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("B.Y")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bav-aria")),
+ AlternativeStateNameMap::StateName(UTF8ToUTF16("amapá")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Broen")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria is in Germany")),
+ AlternativeStateNameMap::StateName(ASCIIToUTF16("BA is in Germany"))};
+ std::vector<bool> state_data_present = {true, true, true, true,
+ false, false, false, false};
+
+ alternative_state_name_map_updater.ProcessLoadedStateFileContentForTesting(
+ test_strings, states_data, base::DoNothing());
+ AlternativeStateNameMap* alternative_state_name_map =
+ AlternativeStateNameMap::GetInstance();
+ DCHECK(!alternative_state_name_map->IsLocalisedStateNamesMapEmpty());
+
+ for (size_t i = 0; i < test_strings.size(); i++) {
+ SCOPED_TRACE(test_strings[i]);
+ EXPECT_EQ(alternative_state_name_map->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ test_strings[i]) != base::nullopt,
+ state_data_present[i]);
+ }
+}
+
+// Tests that the AlternativeStateNameMap is populated when
+// |StateNameMapUpdater::LoadStatesData()| is called.
+TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesData) {
+ test::ClearAlternativeStateNameMapForTesting();
+
+ base::WriteFile(GetPath().AppendASCII("DE"),
+ test::CreateStatesProtoAsString());
+ WritePathToPref(GetPath());
+
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater.LoadStatesData(
+ {{AlternativeStateNameMap::CountryCode("DE"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Bavaria"))}}},
+ pref_service_.get(), run_loop.QuitClosure());
+ run_loop.Run();
+
+ EXPECT_NE(
+ AlternativeStateNameMap::GetInstance()->GetCanonicalStateName(
+ AlternativeStateNameMap::CountryCode("DE"),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))),
+ base::nullopt);
+}
+
+// Tests that the AlternativeStateNameMap is populated when
+// |StateNameMapUpdater::LoadStatesData()| is called and there are UTF8 strings.
+TEST_F(AlternativeStateNameMapUpdaterTest, TestLoadStatesDataUTF8) {
+ test::ClearAlternativeStateNameMapForTesting();
+
+ base::WriteFile(
+ GetPath().AppendASCII("ES"),
+ test::CreateStatesProtoAsString(
+ "ES", {.canonical_name = "Paraná",
+ .abbreviations = {"PR"},
+ .alternative_names = {"Parana", "State of Parana"}}));
+ WritePathToPref(GetPath());
+
+ base::RunLoop run_loop;
+ alternative_state_name_map_updater.LoadStatesData(
+ {{AlternativeStateNameMap::CountryCode("ES"),
+ {AlternativeStateNameMap::StateName(ASCIIToUTF16("Parana"))}}},
+ pref_service_.get(), run_loop.QuitClosure());
+ run_loop.Run();
+
+ base::Optional<StateEntry> entry1 =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode("ES"),
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16("Paraná")));
+ EXPECT_NE(entry1, base::nullopt);
+ EXPECT_EQ(entry1->canonical_name(), "Paraná");
+ EXPECT_THAT(entry1->abbreviations(),
+ testing::UnorderedElementsAreArray({"PR"}));
+ EXPECT_THAT(entry1->alternative_names(), testing::UnorderedElementsAreArray(
+ {"Parana", "State of Parana"}));
+
+ base::Optional<StateEntry> entry2 =
+ AlternativeStateNameMap::GetInstance()->GetEntry(
+ AlternativeStateNameMap::CountryCode("ES"),
+ AlternativeStateNameMap::StateName(base::UTF8ToUTF16("Parana")));
+ EXPECT_NE(entry2, base::nullopt);
+ EXPECT_EQ(entry2->canonical_name(), "Paraná");
+ EXPECT_THAT(entry2->abbreviations(),
+ testing::UnorderedElementsAreArray({"PR"}));
+ EXPECT_THAT(entry2->alternative_names(), testing::UnorderedElementsAreArray(
+ {"Parana", "State of Parana"}));
+}
+
+// Tests the |StateNameMapUpdater::ContainsState()| functionality.
+TEST_F(AlternativeStateNameMapUpdaterTest, ContainsState) {
+ EXPECT_TRUE(AlternativeStateNameMapUpdater::ContainsStateForTesting(
+ {AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("BY"))},
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria"))));
+ EXPECT_FALSE(AlternativeStateNameMapUpdater::ContainsStateForTesting(
+ {AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bavaria")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("Bayern")),
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("BY"))},
+ AlternativeStateNameMap::StateName(base::ASCIIToUTF16("California"))));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.cc b/chromium/components/autofill/core/browser/geo/autofill_country.cc
index 43a02de277f..121868e521a 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.cc
@@ -37,20 +37,16 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
// If there is no entry in the |CountryDataMap| for the
// |country_code_for_country_data| use the country code derived from the
// locale. This reverts to US.
- country_data_map->HasCountryData(country_code_)
+ country_data_map->HasRequiredFieldsForAddressImport(country_code_)
? country_code_
: CountryCodeForLocale(locale);
// Acquire the country address data.
- const CountryData& data = country_data_map->GetCountryData(country_code_);
+ required_fields_for_address_import_ =
+ country_data_map->GetRequiredFieldsForAddressImport(country_code_);
// Translate the country name by the supplied local.
name_ = l10n_util::GetDisplayNameForCountry(country_code_, locale);
-
- // Get the localized strings associate with the address fields.
- postal_code_label_ = l10n_util::GetStringUTF16(data.postal_code_label_id);
- state_label_ = l10n_util::GetStringUTF16(data.state_label_id);
- address_required_fields_ = data.address_required_fields;
}
AutofillCountry::~AutofillCountry() {}
@@ -82,10 +78,7 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
const base::string16& name,
const base::string16& postal_code_label,
const base::string16& state_label)
- : country_code_(country_code),
- name_(name),
- postal_code_label_(postal_code_label),
- state_label_(state_label) {}
+ : country_code_(country_code), name_(name) {}
// Prints a formatted log of a |AutofillCountry| to a |LogBuffer|.
LogBuffer& operator<<(LogBuffer& buffer, const AutofillCountry& country) {
@@ -97,8 +90,6 @@ LogBuffer& operator<<(LogBuffer& buffer, const AutofillCountry& country) {
buffer << Tr{} << "State required:" << country.requires_state();
buffer << Tr{} << "Zip required:" << country.requires_zip();
buffer << Tr{} << "City required:" << country.requires_city();
- buffer << Tr{} << "State label:" << country.state_label();
- buffer << Tr{} << "Postal code label:" << country.postal_code_label();
buffer << CTag{"table"};
buffer << CTag{"div"};
buffer << CTag{};
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.h b/chromium/components/autofill/core/browser/geo/autofill_country.h
index fc16ef008d3..c1d3a3eb1b7 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.h
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.h
@@ -31,33 +31,32 @@ class AutofillCountry {
const std::string& country_code() const { return country_code_; }
const base::string16& name() const { return name_; }
- const base::string16& postal_code_label() const { return postal_code_label_; }
- const base::string16& state_label() const { return state_label_; }
// City is expected in a complete address for this country.
bool requires_city() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_CITY) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_CITY) != 0;
}
// State is expected in a complete address for this country.
bool requires_state() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_STATE) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_STATE) != 0;
}
// Zip is expected in a complete address for this country.
bool requires_zip() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_ZIP) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_ZIP) != 0;
}
// An address line1 is expected in a complete address for this country.
bool requires_line1() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_LINE1) != 0;
+ return (required_fields_for_address_import_ & ADDRESS_REQUIRES_LINE1) != 0;
}
// True if a complete address is expected to either contain a state or a ZIP
// code. Not true if the address explicitly needs both.
bool requires_zip_or_state() const {
- return (address_required_fields_ & ADDRESS_REQUIRES_ZIP_OR_STATE) != 0;
+ return (required_fields_for_address_import_ &
+ ADDRESS_REQUIRES_ZIP_OR_STATE) != 0;
}
private:
@@ -72,14 +71,8 @@ class AutofillCountry {
// The country's name, localized to the app locale.
base::string16 name_;
- // The localized label for the postal code (or zip code) field.
- base::string16 postal_code_label_;
-
- // The localized label for the state (or province, district, etc.) field.
- base::string16 state_label_;
-
- // Address requirement field codes for the country.
- AddressRequiredFields address_required_fields_;
+ // Required fields for an address import for the country.
+ RequiredFieldsForAddressImport required_fields_for_address_import_;
DISALLOW_COPY_AND_ASSIGN(AutofillCountry);
};
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
index 655c9e1777a..487d46e1990 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -24,8 +24,6 @@ TEST(AutofillCountryTest, AutofillCountry) {
AutofillCountry united_states_en("US", "en_US");
EXPECT_EQ("US", united_states_en.country_code());
EXPECT_EQ(ASCIIToUTF16("United States"), united_states_en.name());
- EXPECT_EQ(ASCIIToUTF16("ZIP code"), united_states_en.postal_code_label());
- EXPECT_EQ(ASCIIToUTF16("State"), united_states_en.state_label());
AutofillCountry united_states_es("US", "es");
EXPECT_EQ("US", united_states_es.country_code());
@@ -39,8 +37,6 @@ TEST(AutofillCountryTest, AutofillCountry) {
AutofillCountry canada_en("CA", "en_US");
EXPECT_EQ("CA", canada_en.country_code());
EXPECT_EQ(ASCIIToUTF16("Canada"), canada_en.name());
- EXPECT_EQ(ASCIIToUTF16("Postal code"), canada_en.postal_code_label());
- EXPECT_EQ(ASCIIToUTF16("Province"), canada_en.state_label());
AutofillCountry canada_hu("CA", "hu");
EXPECT_EQ("CA", canada_hu.country_code());
@@ -124,7 +120,7 @@ TEST(AutofillCountryTest, AliasMappingsForCountryData) {
CountryDataMap* country_data_map = CountryDataMap::GetInstance();
// There should be country data for the "GB".
- EXPECT_TRUE(country_data_map->HasCountryData("GB"));
+ EXPECT_TRUE(country_data_map->HasRequiredFieldsForAddressImport("GB"));
// Check the correctness of the alias definitions.
EXPECT_TRUE(country_data_map->HasCountryCodeAlias("UK"));
diff --git a/chromium/components/autofill/core/browser/geo/country_data.cc b/chromium/components/autofill/core/browser/geo/country_data.cc
index a85fba5a745..545179c09d8 100644
--- a/chromium/components/autofill/core/browser/geo/country_data.cc
+++ b/chromium/components/autofill/core/browser/geo/country_data.cc
@@ -14,9 +14,9 @@
namespace autofill {
namespace {
-struct StaticCountryData {
+struct StaticCountryAddressImportRequirementsData {
char country_code[3];
- CountryData country_data;
+ RequiredFieldsForAddressImport address_import_field_requirements;
};
// Alias definitions record for CountryData requests. A request for
@@ -30,783 +30,284 @@ struct StaticCountryCodeAliasData {
// Alias definitions.
const StaticCountryCodeAliasData kCountryCodeAliases[] = {{"UK", "GB"}};
-// Maps country codes to localized label string identifiers. Keep this sorted
+// Maps country codes to address import requirements. Keep this sorted
// by country code.
// This list is comprized of countries appearing in both
// //third_party/icu/source/data/region/en.txt and
// //third_party/libaddressinput/src/cpp/src/region_data_constants.cc.
-const StaticCountryData kCountryData[] = {
- // clang-format off
- {"AC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1 } },
- {"AE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_EMIRATE,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"AF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"AI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AS", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"AW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"AX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"AZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"BT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"BV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"BY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"BZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"CI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"CV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"CX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"CY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"CZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"DK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"DO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"DZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"EG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"EH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ER", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ES", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"ET", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"FK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FM", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"FO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"FR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"GL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"GR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GU", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"GY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"HK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_AREA,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"HM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"HN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"HR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"HT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"HU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ID", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"IR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"IS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"IT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"JE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"JM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PARISH,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"JO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"JP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PREFECTURE,
- ADDRESS_REQUIRES_LINE1_STATE_ZIP } },
- {"KE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"KM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"KN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"KP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"KR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"KW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"KY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"KZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"LA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"LI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"LY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ME", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MH", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ML", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"MP", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"MQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"MX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"MZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_DEPARTMENT,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"NL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NP", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"NR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_DISTRICT,
- ADDRESS_REQUIRES_LINE1_STATE } },
- {"NU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"NZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"OM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"PE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"PH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"PK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PR", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"PT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"PW", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"PY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"QA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"RE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"RW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SB", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_ZIP } },
- {"SH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SI", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_ZIP } },
- {"SN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"SO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ST", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"SX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"SZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TD", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TH", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"TJ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TL", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"TO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"TT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"TV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_ISLAND,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"TW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_COUNTY,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"TZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"UA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"UM", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"US", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UY", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"UZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"VA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"VC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"VE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE } },
- {"VG", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1 } },
- {"VI", { IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE,
- IDS_AUTOFILL_FIELD_LABEL_STATE,
- ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP } },
- {"VN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"VU", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"WF", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"WS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"XK", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"YE", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"YT", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ZA", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY_ZIP } },
- {"ZM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- {"ZW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE,
- ADDRESS_REQUIRES_LINE1_CITY } },
- // clang-format on
+const StaticCountryAddressImportRequirementsData
+ kCountryAddressImportRequirementsData[] = {
+ {"AC", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AD", ADDRESS_REQUIRES_LINE1},
+ {"AE", ADDRESS_REQUIRES_LINE1_STATE},
+ {"AF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AG", ADDRESS_REQUIRES_LINE1},
+ {"AI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AS", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AU", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"AW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"AX", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"AZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BB", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"BD", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BI", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"BS", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"BT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"BV", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"BZ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CA", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CC", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"CI", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CL", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CO", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CS", ADDRESS_REQUIRES_LINE1},
+ {"CV", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"CX", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"CY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"CZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"DK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"DO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"DZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"EG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"EH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ER", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ES", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"ET", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FJ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"FK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"FO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"FR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GB", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GH", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GI", ADDRESS_REQUIRES_LINE1},
+ {"GL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GP", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GQ", ADDRESS_REQUIRES_LINE1_CITY},
+ {"GR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GW", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"GY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"HK", ADDRESS_REQUIRES_LINE1_STATE},
+ {"HM", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"HN", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"HR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"HT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"HU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ID", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IE", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IQ", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"IR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"IS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"IT", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"JE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"JM", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"JO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"JP", ADDRESS_REQUIRES_LINE1_STATE_ZIP},
+ {"KE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KI", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"KM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"KN", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"KP", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"KR", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"KW", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"KY", ADDRESS_REQUIRES_LINE1_STATE},
+ {"KZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"LA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LB", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LC", ADDRESS_REQUIRES_LINE1_CITY},
+ {"LI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LV", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"LY", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MD", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ME", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MG", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MH", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ML", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MN", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MO", ADDRESS_REQUIRES_LINE1},
+ {"MP", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"MQ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MR", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MU", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MV", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"MX", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"MZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NF", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NG", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NI", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"NL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NP", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"NR", ADDRESS_REQUIRES_LINE1_STATE},
+ {"NU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"NZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"OM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PA", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"PE", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PF", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PG", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"PH", ADDRESS_REQUIRES_LINE1_CITY},
+ {"PK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PL", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PR", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"PT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"PW", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"PY", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"QA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"RE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RO", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RS", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"RU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"RW", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SB", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SC", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SE", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SG", ADDRESS_REQUIRES_LINE1_ZIP},
+ {"SH", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SI", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SJ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SK", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SL", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SM", ADDRESS_REQUIRES_LINE1_ZIP},
+ {"SN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"SO", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SR", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ST", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SV", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"SX", ADDRESS_REQUIRES_LINE1_CITY},
+ {"SZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TD", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TF", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TH", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"TJ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TL", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TM", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TN", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"TO", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TR", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"TT", ADDRESS_REQUIRES_LINE1_CITY},
+ {"TV", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"TW", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"TZ", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"UA", ADDRESS_REQUIRES_LINE1_CITY},
+ {"UG", ADDRESS_REQUIRES_LINE1_CITY},
+ {"UM", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"US", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"UY", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"UZ", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"VA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"VC", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"VE", ADDRESS_REQUIRES_LINE1_CITY_STATE},
+ {"VG", ADDRESS_REQUIRES_LINE1},
+ {"VI", ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP},
+ {"VN", ADDRESS_REQUIRES_LINE1_CITY},
+ {"VU", ADDRESS_REQUIRES_LINE1_CITY},
+ {"WF", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"WS", ADDRESS_REQUIRES_LINE1_CITY},
+ {"XK", ADDRESS_REQUIRES_LINE1_CITY},
+ {"YE", ADDRESS_REQUIRES_LINE1_CITY},
+ {"YT", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ZA", ADDRESS_REQUIRES_LINE1_CITY_ZIP},
+ {"ZM", ADDRESS_REQUIRES_LINE1_CITY},
+ {"ZW", ADDRESS_REQUIRES_LINE1_CITY},
};
// GetCountryCodes and GetCountryData compute the data for CountryDataMap
-// based on |kCountryData|.
+// based on |kCountryAddressImportRequirementsData|.
std::vector<std::string> GetCountryCodes() {
std::vector<std::string> country_codes;
- country_codes.reserve(base::size(kCountryData));
- for (const auto& static_data : kCountryData) {
+ country_codes.reserve(base::size(kCountryAddressImportRequirementsData));
+ for (const auto& static_data : kCountryAddressImportRequirementsData) {
country_codes.push_back(static_data.country_code);
}
return country_codes;
}
-std::map<std::string, CountryData> GetCountryDataMap() {
- std::map<std::string, CountryData> country_data;
+std::map<std::string, RequiredFieldsForAddressImport> GetCountryDataMap() {
+ std::map<std::string, RequiredFieldsForAddressImport> import_requirements;
// Add all the countries we have explicit data for.
- for (const auto& static_data : kCountryData) {
- country_data.insert(
- std::make_pair(static_data.country_code, static_data.country_data));
+ for (const auto& static_data : kCountryAddressImportRequirementsData) {
+ import_requirements.insert(
+ import_requirements.end(),
+ std::make_pair(static_data.country_code,
+ static_data.address_import_field_requirements));
}
// Add any other countries that ICU knows about, falling back to default data
@@ -814,14 +315,13 @@ std::map<std::string, CountryData> GetCountryDataMap() {
for (const char* const* country_pointer = icu::Locale::getISOCountries();
*country_pointer; ++country_pointer) {
std::string country_code = *country_pointer;
- if (!country_data.count(country_code)) {
- CountryData data = {IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE,
- IDS_AUTOFILL_FIELD_LABEL_PROVINCE};
- country_data.insert(
- std::make_pair(std::move(country_code), std::move(data)));
+ if (!import_requirements.count(country_code)) {
+ import_requirements.insert(std::make_pair(
+ std::move(country_code),
+ RequiredFieldsForAddressImport::ADDRESS_REQUIREMENTS_UNKNOWN));
}
}
- return country_data;
+ return import_requirements;
}
std::map<std::string, std::string> GetCountryCodeAliasMap() {
@@ -844,23 +344,25 @@ CountryDataMap* CountryDataMap::GetInstance() {
}
CountryDataMap::CountryDataMap()
- : country_data_(GetCountryDataMap()),
+ : required_fields_for_address_import_map_(GetCountryDataMap()),
country_code_aliases_(GetCountryCodeAliasMap()),
country_codes_(GetCountryCodes()) {}
CountryDataMap::~CountryDataMap() = default;
-bool CountryDataMap::HasCountryData(const std::string& country_code) const {
- return country_data_.count(country_code) > 0;
+bool CountryDataMap::HasRequiredFieldsForAddressImport(
+ const std::string& country_code) const {
+ return required_fields_for_address_import_map_.count(country_code) > 0;
}
-const CountryData& CountryDataMap::GetCountryData(
+RequiredFieldsForAddressImport
+CountryDataMap::GetRequiredFieldsForAddressImport(
const std::string& country_code) const {
- auto lookup = country_data_.find(country_code);
- if (lookup != country_data_.end())
+ auto lookup = required_fields_for_address_import_map_.find(country_code);
+ if (lookup != required_fields_for_address_import_map_.end())
return lookup->second;
// If there is no entry for country_code return the entry for the US.
- return country_data_.find("US")->second;
+ return required_fields_for_address_import_map_.find("US")->second;
}
bool CountryDataMap::HasCountryCodeAlias(
@@ -872,7 +374,7 @@ const std::string CountryDataMap::GetCountryCodeForAlias(
const std::string& country_code_alias) const {
auto lookup = country_code_aliases_.find(country_code_alias);
if (lookup != country_code_aliases_.end()) {
- DCHECK(HasCountryData(lookup->second));
+ DCHECK(HasRequiredFieldsForAddressImport(lookup->second));
return lookup->second;
}
return std::string();
diff --git a/chromium/components/autofill/core/browser/geo/country_data.h b/chromium/components/autofill/core/browser/geo/country_data.h
index d30783a6276..12ae5f8cf17 100644
--- a/chromium/components/autofill/core/browser/geo/country_data.h
+++ b/chromium/components/autofill/core/browser/geo/country_data.h
@@ -20,7 +20,7 @@ namespace autofill {
// The minimal required fields for an address to be complete for a given
// country.
-enum AddressRequiredFields {
+enum RequiredFieldsForAddressImport {
ADDRESS_REQUIRES_CITY = 1 << 0,
ADDRESS_REQUIRES_STATE = 1 << 1,
ADDRESS_REQUIRES_ZIP = 1 << 2,
@@ -52,19 +52,6 @@ enum AddressRequiredFields {
ADDRESS_REQUIREMENTS_UNKNOWN = ADDRESS_REQUIRES_LINE1_CITY_STATE_ZIP,
};
-// This struct describes the address format typical for a particular country.
-struct CountryData {
- // Resource identifier for the string used to denote postal codes.
- int postal_code_label_id;
-
- // Resource identifier for the string used to denote the major subdivision
- // below the "country" level.
- int state_label_id;
-
- // The required parts of the address.
- AddressRequiredFields address_required_fields;
-};
-
// A singleton class that encapsulates a map from country codes to country data.
class CountryDataMap {
public:
@@ -72,7 +59,7 @@ class CountryDataMap {
// Returns true if a |CountryData| entry for the supplied |country_code|
// exists.
- bool HasCountryData(const std::string& country_code) const;
+ bool HasRequiredFieldsForAddressImport(const std::string& country_code) const;
// Returns true if there is a country code alias for |country_code|.
bool HasCountryCodeAlias(const std::string& country_code_alias) const;
@@ -82,9 +69,10 @@ class CountryDataMap {
const std::string GetCountryCodeForAlias(
const std::string& country_code_alias) const;
- // Lookup the |CountryData| for the supplied |country_code|. If no entry
- // exists, return the data for the US as a best guess.
- const CountryData& GetCountryData(const std::string& country_code) const;
+ // Lookup the |RequiredFieldForAddressImport| for the supplied |country_code|.
+ // If no entry exists, return requirements for the US as a best guess.
+ RequiredFieldsForAddressImport GetRequiredFieldsForAddressImport(
+ const std::string& country_code) const;
// Return a constant reference to a vector of all country codes.
const std::vector<std::string>& country_codes() { return country_codes_; }
@@ -94,7 +82,8 @@ class CountryDataMap {
~CountryDataMap();
friend struct base::DefaultSingletonTraits<CountryDataMap>;
- const std::map<std::string, CountryData> country_data_;
+ const std::map<std::string, RequiredFieldsForAddressImport>
+ required_fields_for_address_import_map_;
const std::map<std::string, std::string> country_code_aliases_;
const std::vector<std::string> country_codes_;
diff --git a/chromium/components/autofill/core/browser/geo/subkey_requester.cc b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
index 5bbc0dda70f..0eb5da274bc 100644
--- a/chromium/components/autofill/core/browser/geo/subkey_requester.cc
+++ b/chromium/components/autofill/core/browser/geo/subkey_requester.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
index b167d01018f..506fadb82f0 100644
--- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
@@ -4,8 +4,8 @@
#include "components/autofill/core/browser/logging/log_buffer_submitter.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/values.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
diff --git a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
index e9c2ab752f4..19806be5c00 100644
--- a/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_manager_unittest.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/logging/log_manager.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
#include "components/autofill/core/browser/logging/log_router.h"
diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
index 95e479a4740..ecae251fd12 100644
--- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
+++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.cc
@@ -13,7 +13,6 @@
#include "components/autofill/core/browser/form_data_importer.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_tick_clock.h"
namespace autofill {
@@ -50,19 +49,6 @@ void CreditCardFormEventLogger::OnDidSelectCardSuggestion(
AutofillSyncSigninState sync_state) {
sync_state_ = sync_state;
- // When server nicknames are available, if any card is selected, log the
- // selection duration.
- if (has_server_nickname_ && !has_logged_suggestion_selected_timestamp_) {
- has_logged_suggestion_selected_timestamp_ = true;
- base::TimeTicks now = AutofillTickClock::NowTicks();
- // Suggestion selection should always chronologically follow suggestion
- // shown.
- DCHECK(now > first_suggestion_shown_timestamp_);
- base::UmaHistogramMediumTimes(
- "Autofill.FormEvents.CreditCard.WithServerNickname.SelectionDuration",
- now - first_suggestion_shown_timestamp_);
- }
-
if (has_eligible_offer_) {
card_selected_has_offer_ = DoesCardHaveOffer(credit_card);
base::UmaHistogramBoolean("Autofill.Offer.SelectedCardHasOffer",
@@ -189,8 +175,6 @@ void CreditCardFormEventLogger::LogUkmInteractedWithForm(
}
void CreditCardFormEventLogger::OnSuggestionsShownOnce() {
- // Record the timestamp of the first suggestion shown.
- first_suggestion_shown_timestamp_ = AutofillTickClock::NowTicks();
base::UmaHistogramBoolean("Autofill.Offer.SuggestedCardsHaveOffer",
has_eligible_offer_);
}
@@ -214,14 +198,6 @@ void CreditCardFormEventLogger::OnLog(const std::string& name,
NUM_FORM_EVENTS);
}
- // Log a different histogram for credit card forms with server nickname
- // available so that selection rate with server nickname can be compared on
- // their own.
- if (has_server_nickname_) {
- base::UmaHistogramEnumeration(name + ".WithServerNickname", event,
- NUM_FORM_EVENTS);
- }
-
// Log a different histogram for credit card forms with credit card offers
// available so that selection rate with offers and rewards can be compared on
// their own.
diff --git a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
index a84566a1b3f..4fb93962afc 100644
--- a/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
+++ b/chromium/components/autofill/core/browser/metrics/credit_card_form_event_logger.h
@@ -46,10 +46,6 @@ class CreditCardFormEventLogger : public FormEventLoggerBase {
is_context_secure_ = is_context_secure;
}
- void set_has_server_nickname(bool has_server_nickname) {
- has_server_nickname_ = has_server_nickname;
- }
-
void set_suggestions(std::vector<Suggestion> suggestions);
void OnDidSelectCardSuggestion(const CreditCard& credit_card,
@@ -97,18 +93,11 @@ class CreditCardFormEventLogger : public FormEventLoggerBase {
bool is_context_secure_ = false;
UnmaskAuthFlowType current_authentication_flow_;
bool has_logged_masked_server_card_suggestion_selected_ = false;
- bool has_logged_suggestion_selected_timestamp_ = false;
bool logged_suggestion_filled_was_masked_server_card_ = false;
- base::TimeTicks first_suggestion_shown_timestamp_;
std::vector<Suggestion> suggestions_;
bool has_eligible_offer_ = false;
bool card_selected_has_offer_ = false;
- // True when ANY of the masked server cards has a nickname. Note that,
- // depending on the experimental setup, the user may not be shown the
- // nickname.
- bool has_server_nickname_ = false;
-
// Weak references.
PersonalDataManager* personal_data_manager_;
AutofillClient* client_;
diff --git a/chromium/components/autofill/core/browser/pattern_provider/DEPS b/chromium/components/autofill/core/browser/pattern_provider/DEPS
new file mode 100644
index 00000000000..89e4cd8553f
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/grit/components_resources.h",
+ "+services/data_decoder/public/cpp:cpp",
+ "+services/data_decoder/public",
+]
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
new file mode 100644
index 00000000000..3aaeb3d97a9
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
@@ -0,0 +1,228 @@
+// Copyright 2020 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/pattern_provider/pattern_configuration_parser.h"
+
+#include "base/bind.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/grit/components_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace autofill {
+
+namespace field_type_parsing {
+
+namespace {
+
+const char kPatternIdentifierKey[] = "pattern_identifier";
+const char kPositivePatternKey[] = "positive_pattern";
+const char kNegativePatternKey[] = "negative_pattern";
+const char kPositiveScoreKey[] = "positive_score";
+const char kMatchFieldAttributesKey[] = "match_field_attributes";
+const char kMatchFieldInputTypesKey[] = "match_field_input_types";
+const char kVersionKey[] = "version";
+
+bool ParseMatchingPattern(PatternProvider::Map& patterns,
+ const std::string& field_type,
+ const std::string& language,
+ const base::Value& value) {
+ if (!value.is_dict())
+ return false;
+
+ const std::string* pattern_identifier =
+ value.FindStringKey(kPatternIdentifierKey);
+ const std::string* positive_pattern =
+ value.FindStringKey(kPositivePatternKey);
+ const std::string* negative_pattern =
+ value.FindStringKey(kNegativePatternKey);
+ base::Optional<double> positive_score =
+ value.FindDoubleKey(kPositiveScoreKey);
+ base::Optional<int> match_field_attributes =
+ value.FindIntKey(kMatchFieldAttributesKey);
+ base::Optional<int> match_field_input_types =
+ value.FindIntKey(kMatchFieldInputTypesKey);
+
+ if (!pattern_identifier || !positive_pattern || !positive_score ||
+ !match_field_attributes || !match_field_input_types)
+ return false;
+
+ autofill::MatchingPattern new_pattern;
+ new_pattern.pattern_identifier = *pattern_identifier;
+ new_pattern.positive_pattern = *positive_pattern;
+ new_pattern.positive_score = *positive_score;
+ if (negative_pattern != nullptr) {
+ new_pattern.negative_pattern = *negative_pattern;
+ } else {
+ new_pattern.negative_pattern = base::nullopt;
+ }
+ new_pattern.match_field_attributes = match_field_attributes.value();
+ new_pattern.match_field_input_types = match_field_input_types.value();
+ new_pattern.language = language;
+
+ // Shift to the right to match the MatchFieldTypes enum, which temporarily
+ // starts at 1<<2 instead of 1<<0.
+ new_pattern.match_field_input_types <<= 2;
+
+ std::vector<MatchingPattern>* pattern_list = &patterns[field_type][language];
+ pattern_list->push_back(new_pattern);
+
+ DVLOG(2) << "Correctly parsed MatchingPattern with identifier |"
+ << new_pattern.pattern_identifier << "|.";
+
+ return true;
+}
+
+// Callback which is used once the JSON is parsed.
+// |overwrite_equal_version| should be true when loading a remote
+// configuration. If the configuration versions are equal or
+// both unspecified (i.e. set to 0) this prioritizes the remote
+// configuration over the local one.
+void OnJsonParsed(bool overwrite_equal_version,
+ base::OnceClosure done_callback,
+ data_decoder::DataDecoder::ValueOrError result) {
+ // Skip any processing in case of an error.
+ if (!result.value) {
+ DVLOG(1) << "Failed to parse PatternProvider configuration JSON string.";
+ std::move(done_callback).Run();
+ return;
+ }
+
+ base::Version version = ExtractVersionFromJsonObject(result.value.value());
+ base::Optional<PatternProvider::Map> patterns =
+ GetConfigurationFromJsonObject(result.value.value());
+
+ if (patterns && version.IsValid()) {
+ DVLOG(1) << "Successfully parsed PatternProvider configuration.";
+
+ PatternProvider& pattern_provider = PatternProvider::GetInstance();
+ pattern_provider.SetPatterns(std::move(patterns.value()),
+ std::move(version), overwrite_equal_version);
+ } else {
+ DVLOG(1) << "Failed to parse PatternProvider configuration JSON object.";
+ }
+
+ std::move(done_callback).Run();
+}
+
+} // namespace
+
+base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
+ const base::Value& root) {
+ PatternProvider::Map patterns;
+
+ if (!root.is_dict()) {
+ DVLOG(1) << "JSON object is not a dictionary.";
+ return base::nullopt;
+ }
+
+ for (const auto& kv : root.DictItems()) {
+ const std::string& field_type = kv.first;
+ const base::Value* field_type_dict = &kv.second;
+
+ if (!field_type_dict->is_dict()) {
+ DVLOG(1) << "|" << field_type << "| does not contain a dictionary.";
+ return base::nullopt;
+ }
+
+ for (const auto& value : field_type_dict->DictItems()) {
+ const std::string& language = value.first;
+ const base::Value* inner_list = &value.second;
+
+ if (!inner_list->is_list()) {
+ DVLOG(1) << "Language |" << language << "| in |" << field_type
+ << "| does not contain a list.";
+ return base::nullopt;
+ }
+
+ for (const auto& matchingPatternObj : inner_list->GetList()) {
+ bool success = ParseMatchingPattern(patterns, field_type, language,
+ matchingPatternObj);
+ if (!success) {
+ DVLOG(1) << "Found incorrect |MatchingPattern| object in list |"
+ << field_type << "|, language |" << language << "|.";
+ return base::nullopt;
+ }
+ }
+ }
+ }
+
+ return base::make_optional(patterns);
+}
+
+base::Version ExtractVersionFromJsonObject(base::Value& root) {
+ if (!root.is_dict())
+ return base::Version("0");
+
+ base::Optional<base::Value> version_str = root.ExtractKey(kVersionKey);
+ if (!version_str || !version_str.value().is_string())
+ return base::Version("0");
+
+ base::Version version = base::Version(version_str.value().GetString());
+ if (!version.IsValid())
+ return base::Version("0");
+
+ return version;
+}
+
+void PopulateFromJsonString(std::string json_string) {
+ data_decoder::DataDecoder::ParseJsonIsolated(
+ std::move(json_string),
+ base::BindOnce(&OnJsonParsed, true, base::DoNothing::Once()));
+}
+
+void PopulateFromResourceBundle(base::OnceClosure done_callback) {
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ VLOG(1) << "Resource Bundle unavailable to load Autofill Matching Pattern "
+ "definitions.";
+ std::move(done_callback).Run();
+ return;
+ }
+
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+
+ // Load the string from the Resource Bundle on a worker thread, then
+ // securely parse the JSON in a separate process and call |OnJsonParsed|
+ // with the result.
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock()},
+ base::BindOnce(&ui::ResourceBundle::LoadDataResourceString,
+ base::Unretained(&bundle), IDR_AUTOFILL_REGEX_JSON),
+ base::BindOnce(
+ [](base::OnceClosure done_callback, std::string resource_string) {
+ data_decoder::DataDecoder::ParseJsonIsolated(
+ std::move(resource_string),
+ base::BindOnce(&OnJsonParsed, false, std::move(done_callback)));
+ },
+ std::move(done_callback)));
+}
+
+base::Optional<PatternProvider::Map>
+GetPatternsFromResourceBundleSynchronously() {
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ VLOG(1) << "Resource Bundle unavailable to load Autofill Matching Pattern "
+ "definitions.";
+ return base::nullopt;
+ }
+
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ std::string resource_string =
+ bundle.LoadDataResourceString(IDR_AUTOFILL_REGEX_JSON);
+ base::Optional<base::Value> json_object =
+ base::JSONReader::Read(resource_string);
+
+ // Discard version, since this is the only getter used in unit tests.
+ base::Version version = ExtractVersionFromJsonObject(json_object.value());
+ base::Optional<PatternProvider::Map> configuration_map =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ return configuration_map;
+}
+
+} // namespace field_type_parsing
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h
new file mode 100644
index 00000000000..8f72b18bf31
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h
@@ -0,0 +1,60 @@
+// Copyright 2020 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_PATTERN_PROVIDER_PATTERN_CONFIGURATION_PARSER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_CONFIGURATION_PARSER_H_
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/version.h"
+#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+namespace autofill {
+
+namespace field_type_parsing {
+
+// Tries to extract the configuration version from the JSON base::Value tree.
+// This removes the key if found, so that validation is easier later on.
+// If not found, default to version 0.
+base::Version ExtractVersionFromJsonObject(base::Value& root);
+
+// Transforms the parsed JSON base::Value tree into the map used in
+// |PatternProvider|. Requires the version key to already be extracted.
+// The root is expected to be a dictionary with keys corresponding to
+// strings representing |ServerFieldType|. Then there should be
+// second level dictionaries with keys describing the language. These
+// should point to a list of objects representing |MatchingPattern|.
+// {
+// "FIELD_NAME": {
+// "language":[
+// {MatchingPatternFields}
+// ]
+// }
+// }
+// An example can be found in the relative resources folder.
+base::Optional<PatternProvider::Map> GetConfigurationFromJsonObject(
+ const base::Value& root);
+
+// Tries to get and parse the default configuration in the resource bundle
+// into a valid map used in |PatternProvider| and swap it in for further use.
+// The callback is used as a signal for testing.
+void PopulateFromResourceBundle(
+ base::OnceClosure done_callback = base::DoNothing::Once());
+
+// Tries to parse the given JSON string into a valid map used in the
+// |PatternProvider| and swap it in for further use.
+void PopulateFromJsonString(std::string json_string);
+
+// Synchronous getter used to set up a test fixture.
+base::Optional<PatternProvider::Map>
+GetPatternsFromResourceBundleSynchronously();
+
+} // namespace field_type_parsing
+
+} // namespace autofill
+
+#endif
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
new file mode 100644
index 00000000000..a9cd570a644
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
@@ -0,0 +1,196 @@
+// Copyright 2020 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/pattern_provider/pattern_configuration_parser.h"
+
+#include <stddef.h>
+
+#include "base/json/json_reader.h"
+#include "base/test/gtest_util.h"
+#include "base/version.h"
+#include "components/grit/components_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace autofill {
+
+namespace field_type_parsing {
+
+// Test that the |base::Value| object of the configuration is
+// parsed to the map structure used by |PatternProvider| as
+// expected, given the input is valid.
+TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
+ std::string JSON_message = R"(
+ {
+ "version": "1.0",
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "Name_fr",
+ "positive_pattern": "nom|prenom",
+ "positive_score": 2.0,
+ "negative_pattern": "compagne",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ },
+ "ADDRESS": {
+ "en_us": [
+ {
+ "pattern_identifier": "Address",
+ "positive_pattern": "address",
+ "positive_score": 2.0,
+ "negative_pattern": "email",
+ "match_field_attributes": 4,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_TRUE(version.IsValid());
+ ASSERT_TRUE(optional_patterns);
+
+ ASSERT_EQ(base::Version("1.0"), version);
+
+ PatternProvider::Map patterns = optional_patterns.value();
+
+ ASSERT_EQ(2U, patterns.size());
+ ASSERT_TRUE(patterns.count("FULL_NAME"));
+ ASSERT_EQ(2U, patterns["FULL_NAME"].size());
+ ASSERT_TRUE(patterns["FULL_NAME"].count("en_us"));
+ ASSERT_TRUE(patterns["FULL_NAME"].count("fr"));
+
+ ASSERT_TRUE(patterns.count("ADDRESS"));
+ ASSERT_EQ(1U, patterns["ADDRESS"].size());
+ ASSERT_TRUE(patterns["ADDRESS"].count("en_us"));
+
+ // Test one |MatchingPattern| to check that they are parsed correctly.
+ MatchingPattern* pattern = &patterns["FULL_NAME"]["fr"][0];
+
+ ASSERT_EQ("Name_fr", pattern->pattern_identifier);
+ ASSERT_EQ("nom|prenom", pattern->positive_pattern);
+ ASSERT_EQ("compagne", pattern->negative_pattern);
+ ASSERT_EQ("fr", pattern->language);
+ ASSERT_NEAR(2.0, pattern->positive_score, 1e-6);
+ ASSERT_EQ(2, pattern->match_field_attributes);
+ ASSERT_EQ(3 << 2, pattern->match_field_input_types);
+}
+
+// Test that the parser does not return anything if some |MatchingPattern|
+// object is missing a property.
+TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
+ std::string JSON_message = R"(
+ {
+ "version": "1.0",
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "Name_fr",
+ "positive_pattern": "nom|prenom",
+ "negative_pattern": "compagne",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// Test that the parser correctly sets the default version if
+// it is not present in the configuration.
+TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
+ std::string JSON_message = R"(
+ {
+ "FULL_NAME": {
+ "en_us": [
+ {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ ]
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Version version = ExtractVersionFromJsonObject(JSON_object.value());
+
+ ASSERT_EQ(base::Version("0"), version);
+}
+
+// Test that the parser does not return anything if the inner key points
+// to a single object instead of a list.
+TEST(PatternConfigurationParserTest, MalformedNotList) {
+ std::string JSON_message = R"(
+ {
+ "FULL_NAME": {
+ "en_us": {
+ "pattern_identifier": "Name_en",
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 2,
+ "match_field_input_types": 3
+ }
+ }
+ })";
+ base::Optional<base::Value> JSON_object =
+ base::JSONReader::Read(JSON_message);
+
+ ASSERT_TRUE(JSON_object) << "Incorrectly formatted JSON string.";
+
+ base::Optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(JSON_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+} // namespace field_type_parsing
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
index 04a2d48bac1..349c0d8c39a 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
@@ -8,42 +8,171 @@
#include <iostream>
#include <string>
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/no_destructor.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
+#include "components/autofill/core/common/autofill_features.h"
namespace autofill {
-PatternProvider::PatternProvider() {
- auto& company_patterns = patterns_[AutofillType(COMPANY_NAME).ToString()];
- company_patterns["EN"].push_back(GetCompanyPatternEn());
- company_patterns["DE"].push_back(GetCompanyPatternDe());
+
+namespace {
+const char* kSourceCodeLanguage = "en";
+
+// Adds the English patterns, restricted to MatchFieldType MATCH_NAME, to
+// every other language.
+void EnrichPatternsWithEnVersion(
+ PatternProvider::Map* type_and_lang_to_patterns) {
+ DCHECK(type_and_lang_to_patterns);
+ for (auto& p : *type_and_lang_to_patterns) {
+ std::map<std::string, std::vector<MatchingPattern>>& lang_to_patterns =
+ p.second;
+
+ auto it = lang_to_patterns.find(kSourceCodeLanguage);
+ if (it == lang_to_patterns.end())
+ continue;
+ std::vector<MatchingPattern> en_patterns = it->second;
+ for (MatchingPattern& en_pattern : en_patterns) {
+ en_pattern.match_field_attributes = MATCH_NAME;
+ }
+
+ for (auto& q : lang_to_patterns) {
+ const std::string& page_language = q.first;
+ std::vector<MatchingPattern>& patterns = q.second;
+
+ if (page_language != kSourceCodeLanguage) {
+ patterns.insert(patterns.end(), en_patterns.begin(), en_patterns.end());
+ }
+ }
+ }
}
-PatternProvider::~PatternProvider() {
- patterns_.clear();
+// Sorts patterns in descending order by their score.
+void SortPatternsByScore(PatternProvider::Map* type_and_lang_to_patterns) {
+ for (auto& p : *type_and_lang_to_patterns) {
+ std::map<std::string, std::vector<MatchingPattern>>& lang_to_patterns =
+ p.second;
+ for (auto& q : lang_to_patterns) {
+ std::vector<MatchingPattern>& patterns = q.second;
+ std::sort(patterns.begin(), patterns.end(),
+ [](const MatchingPattern& mp1, const MatchingPattern& mp2) {
+ return mp1.positive_score > mp2.positive_score;
+ });
+ }
+ }
+}
+}
+
+PatternProvider* PatternProvider::g_pattern_provider = nullptr;
+
+// static
+PatternProvider& PatternProvider::GetInstance() {
+ if (!g_pattern_provider) {
+ static base::NoDestructor<PatternProvider> instance;
+ g_pattern_provider = instance.get();
+ // TODO(crbug/1147608) This is an ugly hack to avoid loading the JSON. The
+ // motivation is that some Android unit tests fail because a dependency is
+ // missing. Instead of fixing this dependency, we'll go for an alternative
+ // solution that avoids the whole async/sync problem.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ field_type_parsing::PopulateFromResourceBundle();
+ }
+ }
+ return *g_pattern_provider;
}
-void PatternProvider::SetPatterns(
- const std::map<std::string,
- std::map<std::string, std::vector<MatchingPattern>>>&
- patterns) {
- patterns_ = patterns;
+// static
+void PatternProvider::ResetPatternProvider() {
+ g_pattern_provider = nullptr;
}
-const std::vector<MatchingPattern>& PatternProvider::GetMatchPatterns(
+PatternProvider::PatternProvider() = default;
+PatternProvider::~PatternProvider() = default;
+
+void PatternProvider::SetPatterns(PatternProvider::Map patterns,
+ const base::Version version,
+ const bool overwrite_equal_version) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!pattern_version_.IsValid() || pattern_version_ < version ||
+ (overwrite_equal_version && pattern_version_ == version)) {
+ patterns_ = patterns;
+ pattern_version_ = version;
+ EnrichPatternsWithEnVersion(&patterns_);
+ SortPatternsByScore(&patterns_);
+ }
+}
+
+const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
const std::string& pattern_name,
- const std::string& page_language) {
- return patterns_[pattern_name][page_language];
+ const std::string& page_language) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ // TODO(crbug.com/1134496): Remove feature check once launched.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns)) {
+ auto outer_it = patterns_.find(pattern_name);
+ if (outer_it != patterns_.end()) {
+ const std::map<std::string, std::vector<MatchingPattern>>&
+ lang_to_pattern = outer_it->second;
+ auto inner_it = lang_to_pattern.find(page_language);
+ if (inner_it != lang_to_pattern.end()) {
+ const std::vector<MatchingPattern>& patterns = inner_it->second;
+ if (!patterns.empty()) {
+ return patterns;
+ }
+ }
+ }
+ return GetAllPatternsByType(pattern_name);
+ } else if (
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ return GetAllPatternsByType(pattern_name);
+ } else {
+ return {};
+ }
}
-const std::vector<MatchingPattern>& PatternProvider::GetMatchPatterns(
+const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
ServerFieldType type,
- const std::string& page_language) {
+ const std::string& page_language) const {
std::string pattern_name = AutofillType(type).ToString();
return GetMatchPatterns(pattern_name, page_language);
}
-PatternProvider* PatternProvider::getInstance() {
- static base::NoDestructor<PatternProvider> instance;
- return instance.get();
+const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
+ ServerFieldType type) const {
+ std::string type_str = AutofillType(type).ToString();
+ return GetAllPatternsByType(type_str);
+}
+
+const std::vector<MatchingPattern> PatternProvider::GetAllPatternsByType(
+ const std::string& type) const {
+ auto it = patterns_.find(type);
+ if (it == patterns_.end())
+ return {};
+ const std::map<std::string, std::vector<MatchingPattern>>& type_patterns =
+ it->second;
+
+ std::vector<MatchingPattern> all_language_patterns;
+ for (const auto& p : type_patterns) {
+ const std::string& page_language = p.first;
+ const std::vector<MatchingPattern>& language_patterns = p.second;
+ for (const MatchingPattern& mp : language_patterns) {
+ if (page_language == kSourceCodeLanguage ||
+ mp.language != kSourceCodeLanguage) {
+ all_language_patterns.push_back(mp);
+ }
+ }
+ }
+ return all_language_patterns;
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
index 2cb7422023b..4ddd9cf6469 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
@@ -7,52 +7,91 @@
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/no_destructor.h"
+#include "base/sequence_checker.h"
+#include "base/version.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "third_party/re2/src/re2/re2.h"
namespace autofill {
+// Base class for the Pattern Provider. This class contains the implementation
+// for providing the matching patterns. Different subclasses provide different
+// ways to load the data in for further use.
class PatternProvider {
public:
- static PatternProvider* getInstance();
+ // The outer keys are field types or other pattern names. The inner keys are
+ // page languages in lower case.
+ // TODO(crbug/1142413): decide on uppercase or lowercase.
+ using Map = std::map<std::string,
+ std::map<std::string, std::vector<MatchingPattern>>>;
- // Setter for loaded patterns from external storage.
- void SetPatterns(
- const std::map<std::string,
- std::map<std::string, std::vector<MatchingPattern>>>&
- patterns);
+ // Returns a reference to the global Pattern Provider.
+ static PatternProvider& GetInstance();
- // Provides us with all patterns that can match our field type and page
- // language.
- const std::vector<MatchingPattern>& GetMatchPatterns(
+ // Setter for loading patterns from external storage.
+ void SetPatterns(const Map patterns,
+ const base::Version version,
+ const bool overwrite_equal_version);
+
+ // Find the patterns for a given ServerFieldType and for a given
+ // |page_language|.
+ const std::vector<MatchingPattern> GetMatchPatterns(
ServerFieldType type,
- const std::string& page_language);
+ const std::string& page_language) const;
- const std::vector<MatchingPattern>& GetMatchPatterns(
+ // Find the patterns for a given |pattern_name| and a given |page_language|.
+ const std::vector<MatchingPattern> GetMatchPatterns(
const std::string& pattern_name,
- const std::string& page_language);
+ const std::string& page_language) const;
- // Provides us with all patterns that can match our field type.
- const std::vector<MatchingPattern>& GetAllPatternsBaseOnType(
- ServerFieldType type);
+ // Find all patterns, across all languages, for a given server field |type|.
+ const std::vector<MatchingPattern> GetAllPatternsByType(
+ ServerFieldType type) const;
+
+ // Find all patterns, across all languages, for a given server field |type|.
+ const std::vector<MatchingPattern> GetAllPatternsByType(
+ const std::string& type) const;
+
+ protected:
+ // Sets a provider to be used for tests.
+ static void SetPatternProviderForTesting(PatternProvider* pattern_provider) {
+ DCHECK(pattern_provider);
+ g_pattern_provider = pattern_provider;
+ }
+
+ // Resets the provider pointer if the object behind it gets deleted.
+ static void ResetPatternProvider();
- private:
PatternProvider();
~PatternProvider();
- // Func to sort the incoming map by score.
- void SortPatternsByScore(std::vector<MatchingPattern>& patterns);
+ const Map& patterns() const { return patterns_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
+ TestParsingEquivalent);
+ FRIEND_TEST_ALL_PREFIXES(AutofillPatternProviderPipelineTest,
+ DefaultPatternProviderLoads);
+
+ friend class base::NoDestructor<PatternProvider>;
+
+ static PatternProvider* g_pattern_provider;
+
+ // Sequence checker to ensure thread-safety for pattern swapping.
+ // All functions accessing the |patterns_| member variable are
+ // expected to be called from the UI thread.
+ SEQUENCE_CHECKER(sequence_checker_);
// Local map to store a vector of patterns keyed by field type and
// page language.
- std::map<std::string, std::map<std::string, std::vector<MatchingPattern>>>
- patterns_;
+ Map patterns_;
- friend class base::NoDestructor<PatternProvider>;
+ // Version for keeping track which pattern set is currently used.
+ base::Version pattern_version_;
};
} // namespace autofill
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_PROVIDER_H_ \ No newline at end of file
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_PATTERN_PROVIDER_H_
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
index 7259a75d56e..5222b67d903 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
@@ -2,8 +2,6 @@
// 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/pattern_provider/pattern_provider.h"
-
#include <stddef.h>
#include <map>
@@ -11,10 +9,83 @@
#include <vector>
#include "base/test/gtest_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
+namespace {
+
+MatchingPattern GetCompanyPatternEn() {
+ autofill::MatchingPattern m_p;
+ m_p.pattern_identifier = "kCompanyPatternEn";
+ m_p.positive_pattern = "company|business|organization|organisation";
+ m_p.positive_score = 1.1f;
+ m_p.negative_pattern = "";
+ m_p.match_field_attributes = MATCH_NAME;
+ m_p.match_field_input_types = MATCH_TEXT;
+ m_p.language = "en";
+ return m_p;
+}
+
+MatchingPattern GetCompanyPatternDe() {
+ autofill::MatchingPattern m_p;
+ m_p.pattern_identifier = "kCompanyPatternDe";
+ m_p.positive_pattern = "|(?<!con)firma|firmenname";
+ m_p.positive_score = 1.1f;
+ m_p.negative_pattern = "";
+ m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
+ m_p.match_field_input_types = MATCH_TEXT;
+ m_p.language = "de";
+ return m_p;
+}
+
+// Pattern Provider with custom values set for testing.
+class UnitTestPatternProvider : public PatternProvider {
+ public:
+ UnitTestPatternProvider();
+ UnitTestPatternProvider(const std::vector<MatchingPattern>& de_patterns,
+ const std::vector<MatchingPattern>& en_patterns);
+ ~UnitTestPatternProvider();
+};
+
+UnitTestPatternProvider::UnitTestPatternProvider()
+ : UnitTestPatternProvider({GetCompanyPatternDe()},
+ {GetCompanyPatternEn()}) {}
+
+UnitTestPatternProvider::UnitTestPatternProvider(
+ const std::vector<MatchingPattern>& de_patterns,
+ const std::vector<MatchingPattern>& en_patterns) {
+ PatternProvider::SetPatternProviderForTesting(this);
+ Map patterns;
+ auto& company_patterns = patterns[AutofillType(COMPANY_NAME).ToString()];
+ company_patterns["de"] = de_patterns;
+ company_patterns["en"] = en_patterns;
+ SetPatterns(patterns, base::Version(), true);
+}
+
+UnitTestPatternProvider::~UnitTestPatternProvider() {
+ PatternProvider::ResetPatternProvider();
+}
+
+} // namespace
+
+class AutofillPatternProviderTest : public testing::Test {
+ protected:
+ UnitTestPatternProvider pattern_provider_;
+
+ ~AutofillPatternProviderTest() override = default;
+};
+
bool operator==(const MatchingPattern& mp1, const MatchingPattern& mp2) {
return (mp1.language == mp2.language &&
mp1.match_field_attributes == mp2.match_field_attributes &&
@@ -26,14 +97,165 @@ bool operator==(const MatchingPattern& mp1, const MatchingPattern& mp2) {
}
TEST(AutofillPatternProvider, Single_Match) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+
MatchingPattern kCompanyPatternEn = GetCompanyPatternEn();
MatchingPattern kCompanyPatternDe = GetCompanyPatternDe();
- PatternProvider* pattern_provider = PatternProvider::getInstance();
+ UnitTestPatternProvider* pattern_provider = new UnitTestPatternProvider();
+ auto pattern_store = pattern_provider->GetMatchPatterns("COMPANY_NAME", "en");
+
+ ASSERT_EQ(pattern_store.size(), 1u);
+ EXPECT_EQ(pattern_store[0], kCompanyPatternEn);
+}
+
+// Test that the default pattern provider loads without crashing.
+TEST(AutofillPatternProviderPipelineTest, DefaultPatternProviderLoads) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ // Enable so that PatternProvider::GetInstance() actually does load the JSON.
+ scoped_feature_list.InitAndEnableFeature(
+ autofill::features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+
+ base::test::TaskEnvironment task_environment_;
+ data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
+
+ base::RunLoop run_loop;
+ field_type_parsing::PopulateFromResourceBundle(run_loop.QuitClosure());
+ run_loop.Run();
+ PatternProvider& default_pattern_provider = PatternProvider::GetInstance();
+
+ EXPECT_FALSE(default_pattern_provider.patterns().empty());
+
+ // Call the getter to ensure sequence checks work correctly.
+ default_pattern_provider.GetMatchPatterns("EMAIL_ADDRESS", "en");
+}
+
+// Test that the TestPatternProvider class uses a PatternProvider::Map
+// equivalent to the DefaultPatternProvider. This is also an example of what is
+// needed to test the DefaultPatternProvider. Warning: If this crashes, check
+// that no state carried over from other tests using the singleton.
+TEST(AutofillPatternProviderPipelineTest, TestParsingEquivalent) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ // Enable so that PatternProvider::GetInstance() actually does load the JSON.
+ scoped_feature_list.InitAndEnableFeature(
+ autofill::features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+
+ base::test::TaskEnvironment task_environment_;
+ data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
+
+ base::RunLoop run_loop;
+ field_type_parsing::PopulateFromResourceBundle(run_loop.QuitClosure());
+ run_loop.Run();
+ PatternProvider& default_pattern_provider = PatternProvider::GetInstance();
+
+ TestPatternProvider test_pattern_provider;
+
+ EXPECT_EQ(default_pattern_provider.patterns(),
+ test_pattern_provider.patterns());
+}
+
+TEST(AutofillPatternProvider, BasedOnMatchType) {
+ UnitTestPatternProvider p;
+ ASSERT_GT(p.GetAllPatternsByType("COMPANY_NAME").size(), 0u);
+ EXPECT_EQ(p.GetAllPatternsByType("COMPANY_NAME"),
+ std::vector<MatchingPattern>(
+ {GetCompanyPatternDe(), GetCompanyPatternEn()}));
+ EXPECT_EQ(p.GetAllPatternsByType("COMPANY_NAME").size(), 2u);
+}
+
+TEST(AutofillPatternProvider, UnknownLanguages) {
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ // disabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ }
+
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", ""),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "blabla"),
+ p.GetAllPatternsByType("COMPANY_NAME"));
+ }
+}
+
+TEST(AutofillPatternProvider, EnrichPatternsWithEnVersion) {
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+ // disabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "en"),
+ std::vector<MatchingPattern>{GetCompanyPatternEn()});
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "de"),
+ std::vector<MatchingPattern>(
+ {GetCompanyPatternDe(), GetCompanyPatternEn()}));
+ }
+
+ {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+ UnitTestPatternProvider p;
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "en"),
+ std::vector<MatchingPattern>({GetCompanyPatternDe(),
+ GetCompanyPatternEn()}));
+ EXPECT_EQ(p.GetMatchPatterns("COMPANY_NAME", "de"),
+ std::vector<MatchingPattern>({GetCompanyPatternDe(),
+ GetCompanyPatternEn()}));
+ }
+}
- ASSERT_TRUE(pattern_provider->GetMatchPatterns("COMPANY_NAME", "EN").size() >
- 0);
- EXPECT_EQ(pattern_provider->GetMatchPatterns("COMPANY_NAME", "EN")[0],
- kCompanyPatternEn);
+TEST(AutofillPatternProvider, SortPatternsByScore) {
+ base::test::ScopedFeatureList feature;
+ feature.InitWithFeatures(
+ // enabled
+ {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns,
+ features::kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+ // disabled
+ {});
+ std::vector<MatchingPattern> de_input_patterns;
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns.push_back(GetCompanyPatternDe());
+ de_input_patterns[0].positive_score = 3.0;
+ de_input_patterns[1].positive_score = 1.0;
+ de_input_patterns[2].positive_score = 5.0;
+ de_input_patterns[3].positive_score = 3.0;
+ UnitTestPatternProvider p(de_input_patterns, {});
+ const std::vector<MatchingPattern>& de_patterns =
+ p.GetMatchPatterns(COMPANY_NAME, "de");
+ ASSERT_EQ(de_patterns.size(), de_input_patterns.size());
+ EXPECT_EQ(de_patterns[0].positive_score, 5.0);
+ EXPECT_EQ(de_patterns[1].positive_score, 3.0);
+ EXPECT_EQ(de_patterns[2].positive_score, 3.0);
+ EXPECT_EQ(de_patterns[3].positive_score, 1.0);
}
-} // namespace autofill \ No newline at end of file
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
new file mode 100644
index 00000000000..16778eac24e
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -0,0 +1,2947 @@
+{
+ "ADDRESS_HOME_STREET_NAME": {
+ "en" : [
+ {
+ "pattern_identifier": "en_street_name",
+ "positive_pattern": "street",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de" : [
+ {
+ "pattern_identifier": "de_street_name",
+ "positive_pattern": "stra(ss|ß)e",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru" : [
+ {
+ "pattern_identifier": "ru_street_name",
+ "positive_pattern": "улица|название.?улицы",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt" : [
+ {
+ "pattern_identifier": "pt_street_name",
+ "positive_pattern": "rua|avenida|((?<!do |de )endereço)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_HOME_HOUSE_NUMBER":{
+ "en": [
+ {
+ "pattern_identifier": "en_house_number",
+ "positive_pattern": "(house.?|street.?|^)number",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_house_number",
+ "positive_pattern": "(haus|^)nummer",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_house_number",
+ "positive_pattern": "^\\*?.?número(.?\\*?$| da residência)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_house_number",
+ "positive_pattern": "дом|номер.?дома",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ATTENTION_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_attention_ignored_preserving",
+ "positive_pattern": "attention|attn",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "REGION_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_region_ignored_preserving",
+ "positive_pattern": "province|region|other",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_region_ignored_preserving",
+ "positive_pattern": "provincia",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_region_ignored_preserving",
+ "positive_pattern": "bairro|suburb",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_NAME_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_name_ignored_preserving",
+ "positive_pattern": "address.*nickname|address.*label",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "COMPANY": {
+ "en": [
+ {
+ "pattern_identifier": "en_company_preserving",
+ "positive_pattern": "company|business|organization|organisation",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_company_preserving",
+ "positive_pattern": "(?<!con)firma|firmenname",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_company_preserving",
+ "positive_pattern": "empresa",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_company_preserving",
+ "positive_pattern": "societe|société",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_company_preserving",
+ "positive_pattern": "ragione.?sociale",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_company_preserving",
+ "positive_pattern": "会社",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_company_preserving",
+ "positive_pattern": "название.?компании",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_company_preserving",
+ "positive_pattern": "å•ä½|å…¬å¸",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_company_preserving",
+ "positive_pattern": "شرکت",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_company_preserving",
+ "positive_pattern": "회사|ì§ìž¥",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_1": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_1_preserving",
+ "positive_pattern": "^address$|address[_-]?line(one)?|address1|addr1|street|(?:shipping|billing)address$|house.?name",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "en_address_line_1_label_preserving",
+ "positive_pattern": "(^\\W*address)|(address\\W*$)|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|recipient|home|work|office|school|business|mail)[\\s\\-]+address|address\\s+(of|for|to|from)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_address_line_1_preserving",
+ "positive_pattern": "strasse|straße",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_1_preserving",
+ "positive_pattern": "direccion|dirección",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_1_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "fr_address_line_1_label_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_1_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "it_address_line_1_label_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_address_line_1_preserving",
+ "positive_pattern": "^ä½æ‰€$|ä½æ‰€1",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "ja_address_line_1_label_preserving",
+ "positive_pattern": "ä½æ‰€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_address_line_1_preserving",
+ "positive_pattern": "morada|((?<!do |de )endereço)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_address_line_1_preserving",
+ "positive_pattern": "ÐдреÑ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_address_line_1_preserving",
+ "positive_pattern": "地å€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "zh_address_line_1_label_preserving",
+ "positive_pattern": "地å€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_address_line_1_preserving",
+ "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "tr_address_line_1_label_preserving",
+ "positive_pattern": "(\\b|_)adres(?! (başlığı(nız)?|tarifi))(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_address_line_1_preserving",
+ "positive_pattern": "^주소.?$|주소.?1",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ,
+ {
+ "pattern_identifier": "ko_address_line_1_label_preserving",
+ "positive_pattern": "주소",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_2": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_2_preserving",
+ "positive_pattern": "address[_-]?line(2|two)|address2|addr2|street|suite|unit",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "en_address_line_2_label_preserving",
+ "positive_pattern": "address|line",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_address_line_2_preserving",
+ "positive_pattern": "adresszusatz|ergänzende.?angaben",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_2_preserving",
+ "positive_pattern": "direccion2|colonia|adicional",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_2_preserving",
+ "positive_pattern": "addresssuppl|complementnom|appartement",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "fr_address_line_2_label_preserving",
+ "positive_pattern": "adresse",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_2_preserving",
+ "positive_pattern": "indirizzo2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "it_address_line_2_label_preserving",
+ "positive_pattern": "indirizzo",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_address_line_2_preserving",
+ "positive_pattern": "ä½æ‰€2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_address_line_2_preserving",
+ "positive_pattern": "complemento|addrcomplement",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_address_line_2_preserving",
+ "positive_pattern": "Улица",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_address_line_2_preserving",
+ "positive_pattern": "地å€2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "zh_address_line_2_label_preserving",
+ "positive_pattern": "地å€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_address_line_2_preserving",
+ "positive_pattern": "주소.?2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "ko_address_line_2_label_preserving",
+ "positive_pattern": "주소",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 1,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LINE_EXTRA": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_line_extra_preserving",
+ "positive_pattern": "address.*line[3-9]|address[3-9]|addr[3-9]|street|line[3-9]",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_address_line_extra_preserving",
+ "positive_pattern": "municipio",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_address_line_extra_preserving",
+ "positive_pattern": "batiment|residence",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_address_line_extra_preserving",
+ "positive_pattern": "indirizzo[3-9]",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ADDRESS_LOOKUP": {
+ "en": [
+ {
+ "pattern_identifier": "en_address_lookup_preserving",
+ "positive_pattern": "lookup",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "COUNTRY": {
+ "en": [
+ {
+ "pattern_identifier": "en_country_preserving",
+ "positive_pattern": "country|countries",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_country_preserving",
+ "positive_pattern": "país|pais",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_country_preserving",
+ "positive_pattern": "(\\b|_)land(\\b|_)(?!.*(mark.*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_country_preserving",
+ "positive_pattern": "(?<!(入|出))国",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_country_preserving",
+ "positive_pattern": "国家",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_country_preserving",
+ "positive_pattern": "êµ­ê°€|나ë¼",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_country_preserving",
+ "positive_pattern": "(\\b|_)(ülke|ulce|ulke)(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_country_preserving",
+ "positive_pattern": "کشور",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "COUNTRY_LOCATION": {
+ "en": [
+ {
+ "pattern_identifier": "en_country_location_preserving",
+ "positive_pattern": "location",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 136
+ }
+ ]
+ },
+ "ZIP_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_zip_code_preserving",
+ "positive_pattern": "zip|postal|post.*code|pcode|pin.?code",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_zip_code_preserving",
+ "positive_pattern": "postleitzahl",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_zip_code_preserving",
+ "positive_pattern": "\\bcp\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_zip_code_preserving",
+ "positive_pattern": "\\bcdp\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_zip_code_preserving",
+ "positive_pattern": "\\bcap\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_zip_code_preserving",
+ "positive_pattern": "郵便番å·",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_zip_code_preserving",
+ "positive_pattern": "codigo|codpos|\\bcep\\b",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_zip_code_preserving",
+ "positive_pattern": "Почтовый.?ИндекÑ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_zip_code_preserving",
+ "positive_pattern": "पिन.?कोड",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_zip_code_preserving",
+ "positive_pattern": "പിനàµâ€à´•àµ‹à´¡àµ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_zip_code_preserving",
+ "positive_pattern": "邮政编ç |邮编|郵éžå€è™Ÿ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_zip_code_preserving",
+ "positive_pattern": "(\\b|_)posta kodu(\\b|_)",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_zip_code_preserving",
+ "positive_pattern": "우편.?번호",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "ZIP_4": {
+ "en": [
+ {
+ "pattern_identifier": "en_zip_4_preserving",
+ "positive_pattern": "zip|^-$|post2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_zip_4_preserving",
+ "positive_pattern": "codpos2",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "CITY": {
+ "en": [
+ {
+ "pattern_identifier": "en_city_preserving",
+ "positive_pattern": "city|town|suburb",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_city_preserving",
+ "positive_pattern": "\\bort\\b|stadt",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_city_preserving",
+ "positive_pattern": "ciudad|provincia|localidad|poblacion",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_city_preserving",
+ "positive_pattern": "ville|commune",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_city_preserving",
+ "positive_pattern": "localita",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_city_preserving",
+ "positive_pattern": "市区町æ‘",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_city_preserving",
+ "positive_pattern": "cidade|município",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_city_preserving",
+ "positive_pattern": "Город|ÐаÑелённый.?пункт",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_city_preserving",
+ "positive_pattern": "市|分å€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_city_preserving",
+ "positive_pattern": "شهر",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_city_preserving",
+ "positive_pattern": "शहर|गà¥à¤°à¤¾à¤®|गाà¤à¤µ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_city_preserving",
+ "positive_pattern": "നഗരം|à´—àµà´°à´¾à´®à´‚",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_city_preserving",
+ "positive_pattern": "((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_city_preserving",
+ "positive_pattern": "^ì‹œ[^ë„·・]|ì‹œ[·・]?êµ°[·・]?구",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "STATE": {
+ "en": [
+ {
+ "pattern_identifier": "en_state_preserving",
+ "positive_pattern": "(?<!(united|hist|history).?)state|county|region|province|county|principality",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_state_preserving",
+ "positive_pattern": "都é“府県",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_state_preserving",
+ "positive_pattern": "estado|provincia",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_state_preserving",
+ "positive_pattern": "облаÑÑ‚ÑŒ",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_state_preserving",
+ "positive_pattern": "çœ|地å€",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_state_preserving",
+ "positive_pattern": "സംസàµà´¥à´¾à´¨à´‚",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_state_preserving",
+ "positive_pattern": "استان",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_state_preserving",
+ "positive_pattern": "राजà¥à¤¯",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_state_preserving",
+ "positive_pattern": "((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_state_preserving",
+ "positive_pattern": "^ì‹œ[·・]?ë„",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "SEARCH_TERM": {
+ "en": [
+ {
+ "pattern_identifier": "en_search_term_preserving",
+ "positive_pattern": "^q$|search|query|qry",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_search_term_preserving",
+ "positive_pattern": "suche.*",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_search_term_preserving",
+ "positive_pattern": "æœç´¢",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_search_term_preserving",
+ "positive_pattern": "探ã™|検索",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_search_term_preserving",
+ "positive_pattern": "recherch.*",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_search_term_preserving",
+ "positive_pattern": "busca",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_search_term_preserving",
+ "positive_pattern": "جستجو",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_search_term_preserving",
+ "positive_pattern": "иÑкать|найти|поиÑк",
+ "positive_score": 0.8,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 145
+ }
+ ]
+ },
+ "PRICE": {
+ "en": [
+ {
+ "pattern_identifier": "en_price_preserving",
+ "positive_pattern": "\\bprice\\b|\\brate\\b|\\bcost\\b",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "ar": [
+ {
+ "pattern_identifier": "ar_price_preserving",
+ "positive_pattern": "قیمة‎|سعر‎",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_price_preserving",
+ "positive_pattern": "قیمت",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_price_preserving",
+ "positive_pattern": "\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b",
+ "positive_score": 0.95,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 217
+ }
+ ]
+ },
+ "NAME_ON_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_on_card_preserving",
+ "positive_pattern": "card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card|(?:card|cc).?name|cc.?full.?name",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_name_on_card_preserving",
+ "positive_pattern": "karteninhaber",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_name_on_card_preserving",
+ "positive_pattern": "nombre.*tarjeta",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_name_on_card_preserving",
+ "positive_pattern": "nom.*carte",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_name_on_card_preserving",
+ "positive_pattern": "nome.*cart",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_name_on_card_preserving",
+ "positive_pattern": "åå‰",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_name_on_card_preserving",
+ "positive_pattern": "ИмÑ.*карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_name_on_card_preserving",
+ "positive_pattern": "信用å¡å¼€æˆ·å|开户å|æŒå¡äººå§“å|æŒå¡äººå§“å",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "NAME_ON_CARD_CONTEXTUAL": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_on_card_contextual_preserving",
+ "positive_pattern": "name",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "CREDIT_CARD_NUMBER": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_number_preserving",
+ "positive_pattern": "(add)?(?:card|cc|acct).?(?:number|#|no|num|field)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_number_preserving",
+ "positive_pattern": "(?<!telefon|haus|person|fødsels)nummer",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_number_preserving",
+ "positive_pattern": "カード番å·",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_number_preserving",
+ "positive_pattern": "Ðомер.*карты",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_number_preserving",
+ "positive_pattern": "信用å¡å·|信用å¡å·ç |信用å¡å¡è™Ÿ",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_card_number_preserving",
+ "positive_pattern": "카드",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_number_preserving",
+ "positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ]
+ },
+ "CREDIT_CARD_VERIFICATION_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_cvc_preserving",
+ "positive_pattern": "verification|card.?identification|security.?code|card.?code|security.?value|security.?number|card.?pin|c-v-v|(cvn|cvv|cvc|csc|cvd|cid|ccv)(field)?|\\bcid\\b",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 101
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_MONTH": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_month_preserving",
+ "positive_pattern": "expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_month_preserving",
+ "positive_pattern": "gueltig|gültig|monat",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_month_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_exp_month_preserving",
+ "positive_pattern": "date.*exp",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_month_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_month_preserving",
+ "positive_pattern": "有効期é™",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_month_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_month_preserving",
+ "positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_exp_month_preserving",
+ "positive_pattern": "月",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_year_preserving",
+ "positive_pattern": "exp|^/|(add)?year",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_year_preserving",
+ "positive_pattern": "ablaufdatum|gueltig|gültig|jahr",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_year_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_year_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_year_preserving",
+ "positive_pattern": "有効期é™",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_year_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_year_preserving",
+ "positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_card_exp_year_preserving",
+ "positive_pattern": "年|有效期",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_2_digit_year_preserving",
+ "positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_4_digit_year_preserving",
+ "positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_DATE": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_date_preserving",
+ "positive_pattern": "expir|exp.*date|^expfield$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_card_exp_date_preserving",
+ "positive_pattern": "gueltig|gültig",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_card_exp_date_preserving",
+ "positive_pattern": "fecha",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_card_exp_date_preserving",
+ "positive_pattern": "date.*exp",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_card_exp_date_preserving",
+ "positive_pattern": "scadenza",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_card_exp_date_preserving",
+ "positive_pattern": "有効期é™",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_card_exp_date_preserving",
+ "positive_pattern": "validade",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_card_exp_date_preserving",
+ "positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_month_before_year_preserving",
+ "positive_pattern": "^mm$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "CREDIT_CARD_EXP_YEAR_AFTER_MONTH": {
+ "en": [
+ {
+ "pattern_identifier": "en_card_exp_year_after_month_preserving",
+ "positive_pattern": "^(yy|yyyy)$",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 205
+ }
+ ]
+ },
+ "GIFT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_gift_card_preserving",
+ "positive_pattern": "gift.?(card|cert)",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DEBIT_GIFT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_debit_gift_card_preserving",
+ "positive_pattern": "(?:visa|mastercard|discover|amex|american express).*gift.?card",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DEBIT_CARD": {
+ "en": [
+ {
+ "pattern_identifier": "en_debit_card_preserving",
+ "positive_pattern": "debit.*card",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 197
+ }
+ ]
+ },
+ "DAY": {
+ "en": [
+ {
+ "pattern_identifier": "en_day_preserving",
+ "positive_pattern": "day",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 9
+ }
+ ]
+ },
+ "EMAIL_ADDRESS": {
+ "en": [
+ {
+ "pattern_identifier": "en_email_preserving",
+ "positive_pattern": "e.?mail",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_email_preserving",
+ "positive_pattern": "courriel",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_email_preserving",
+ "positive_pattern": "correo.*electr(o|ó)nico",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_email_preserving",
+ "positive_pattern": "メールアドレス",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_email_preserving",
+ "positive_pattern": "Электронной.?Почты",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_email_preserving",
+ "positive_pattern": "邮件|邮箱|電郵地å€",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_email_preserving",
+ "positive_pattern": "à´‡-മെയിലàµâ€|ഇലകàµà´Ÿàµà´°àµ‹à´£à´¿à´•àµ.?മെയിൽ",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_email_preserving",
+ "positive_pattern": "ایمیل|پست.*الکترونیک",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_email_preserving",
+ "positive_pattern": "ईमेल|इलॅकà¥à¤Ÿà¥à¤°à¥‰à¤¨à¤¿à¤•.?मेल",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_email_preserving",
+ "positive_pattern": "(\\b|_)eposta(\\b|_)",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_email_preserving",
+ "positive_pattern": "(?:ì´ë©”ì¼|ì „ìž.?우편|[Ee]-?mail)(.?주소)?",
+ "positive_score": 1.4,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 3
+ }
+ ]
+ },
+ "NAME_IGNORED": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_ignored_preserving",
+ "positive_pattern": "user.?name|user.?id|nickname|maiden name|title|prefix|suffix",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_name_ignored_preserving",
+ "positive_pattern": "adres başlığınız",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_name_ignored_preserving",
+ "positive_pattern": "vollständiger.?name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_name_ignored_preserving",
+ "positive_pattern": "用户å",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_name_ignored_preserving",
+ "positive_pattern": "(?:사용ìž.?)?ì•„ì´ë””|사용ìž.?ID",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 137
+ }
+ ]
+ },
+ "FULL_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_full_name_preserving",
+ "positive_pattern": "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name|name.*first.*last|firstandlastname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_full_name_preserving",
+ "positive_pattern": "nombre.*y.*apellidos",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_full_name_preserving",
+ "positive_pattern": "^nom(?!bre)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_full_name_preserving",
+ "positive_pattern": "ãŠåå‰|æ°å",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_full_name_preserving",
+ "positive_pattern": "^nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_full_name_preserving",
+ "positive_pattern": "نام.*نام.*خانوادگی",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_full_name_preserving",
+ "positive_pattern": "姓å",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_full_name_preserving",
+ "positive_pattern": "(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_full_name_preserving",
+ "positive_pattern": "성명",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "NAME_SPECIFIC": {
+ "en": [
+ {
+ "pattern_identifier": "en_name_specific_preserving",
+ "positive_pattern": "^name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_name_specific_preserving",
+ "positive_pattern": "^nom",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_name_specific_preserving",
+ "positive_pattern": "^nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "FIRST_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_first_name_preserving",
+ "positive_pattern": "first.*name|initials|fname|first$|given.*name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_first_name_preserving",
+ "positive_pattern": "vorname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_first_name_preserving",
+ "positive_pattern": "nombre",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_first_name_preserving",
+ "positive_pattern": "forename|prénom|prenom",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_first_name_preserving",
+ "positive_pattern": "å",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_first_name_preserving",
+ "positive_pattern": "nome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_first_name_preserving",
+ "positive_pattern": "ИмÑ",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_first_name_preserving",
+ "positive_pattern": "نام",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_first_name_preserving",
+ "positive_pattern": "ì´ë¦„",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_first_name_preserving",
+ "positive_pattern": "പേരàµ",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_first_name_preserving",
+ "positive_pattern": "(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_first_name_preserving",
+ "positive_pattern": "नाम",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "MIDDLE_INITIAL": {
+ "en": [
+ {
+ "pattern_identifier": "en_middle_initial_preserving",
+ "positive_pattern": "middle.*initial|m\\.i\\.|mi$|\\bmi\\b",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "MIDDLE_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_middle_name_preserving",
+ "positive_pattern": "middle.*name|mname|middle$",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME": {
+ "en": [
+ {
+ "pattern_identifier": "en_last_name_preserving",
+ "positive_pattern": "last.*name|lname|surname(?!\\d)|last$|secondname|family.*name",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_last_name_preserving",
+ "positive_pattern": "nachname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_preserving",
+ "positive_pattern": "apellidos?",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_last_name_preserving",
+ "positive_pattern": "famille|^nom(?!bre)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_last_name_preserving",
+ "positive_pattern": "cognome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_last_name_preserving",
+ "positive_pattern": "姓",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_last_name_preserving",
+ "positive_pattern": "apelidos|surename|sobrenome",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_last_name_preserving",
+ "positive_pattern": "ФамилиÑ",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fa": [
+ {
+ "pattern_identifier": "fa_last_name_preserving",
+ "positive_pattern": "نام.*خانوادگی",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_last_name_preserving",
+ "positive_pattern": "उपनाम",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_last_name_preserving",
+ "positive_pattern": "മറàµà´ªàµ‡à´°àµ",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_last_name_preserving",
+ "positive_pattern": "(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_last_name_preserving",
+ "positive_pattern": "\\b성(?:[^명]|\\b)",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME_FIRST": {
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_first_preserving",
+ "positive_pattern": "(primer.*apellido)|(apellido1)|(apellido.*paterno)|surname_?1|first(\\s|_)?surname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "LAST_NAME_SECOND": {
+ "es": [
+ {
+ "pattern_identifier": "es_last_name_second_preserving",
+ "positive_pattern": "(segund.*apellido)|(apellido2)|(apellido.*materno)|surname_?2|second(\\s|_)?surname",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "HONORIFIC_PREFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_honorific_prefix_preserving",
+ "positive_pattern": "^title:?$|(salutation(?! and given name))",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_honorific_prefix_preserving",
+ "positive_pattern": "anrede|titel",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_honorific_prefix_preserving",
+ "positive_pattern": "tratamiento|encabezamiento",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "it": [
+ {
+ "pattern_identifier": "it_honorific_prefix_preserving",
+ "positive_pattern": "titolo",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_honorific_prefix_preserving",
+ "positive_pattern": "titre",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_honorific_prefix_preserving",
+ "positive_pattern": "обращеÍние|зваÍние",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "el": [
+ {
+ "pattern_identifier": "el_honorific_prefix_preserving",
+ "positive_pattern": "Ï€Ïοσφώνηση",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_honorific_prefix_preserving",
+ "positive_pattern": "hitap",
+ "positive_score": 0.9,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "PHONE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_preserving",
+ "positive_pattern": "phone|mobile|contact.?number",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "de": [
+ {
+ "pattern_identifier": "de_phone_preserving",
+ "positive_pattern": "telefonnummer",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_phone_preserving",
+ "positive_pattern": "telefono|teléfono",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_phone_preserving",
+ "positive_pattern": "telfixe",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_phone_preserving",
+ "positive_pattern": "電話",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_preserving",
+ "positive_pattern": "telefone|telemovel",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ru": [
+ {
+ "pattern_identifier": "ru_phone_preserving",
+ "positive_pattern": "телефон",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "hi": [
+ {
+ "pattern_identifier": "hi_phone_preserving",
+ "positive_pattern": "मोबाइल",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "tr": [
+ {
+ "pattern_identifier": "tr_phone_preserving",
+ "positive_pattern": "(\\b|_|\\*)telefon(\\b|_|\\*)",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "zh": [
+ {
+ "pattern_identifier": "zh_phone_preserving",
+ "positive_pattern": "电è¯",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ml": [
+ {
+ "pattern_identifier": "ml_phone_preserving",
+ "positive_pattern": "മൊബൈലàµâ€",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_phone_preserving",
+ "positive_pattern": "(?:ì „í™”|핸드í°|휴대í°|휴대전화)(?:.?번호)?",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "AUGMENTED_PHONE_COUNTRY_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_augmented_phone_country_code_preserving",
+ "positive_pattern": "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "PHONE_COUNTRY_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_country_code_preserving",
+ "positive_pattern": "country.*code|ccode|_cc|phone.*code|user.*phone.*code",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 77
+ }
+ ]
+ },
+ "PHONE_AREA_CODE_NO_TEXT": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_area_code_no_text_preserving",
+ "positive_pattern": "^\\($",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_AREA_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_area_code_preserving",
+ "positive_pattern": "area.*code|acode|area",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "ko": [
+ {
+ "pattern_identifier": "ko_phone_area_code_preserving",
+ "positive_pattern": "지역.?번호",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_PREFIX_SEPARATOR": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_prefix_separator_preserving",
+ "positive_pattern": "^-$|^\\)$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_SUFFIX_SEPARATOR": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_suffix_separator_preserving",
+ "positive_pattern": "^-$",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_PREFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_prefix_preserving",
+ "positive_pattern": "prefix|exchange",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_phone_prefix_preserving",
+ "positive_pattern": "preselection",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_prefix_preserving",
+ "positive_pattern": "ddd",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_SUFFIX": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_suffix_preserving",
+ "positive_pattern": "suffix",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PHONE_EXTENSION": {
+ "en": [
+ {
+ "pattern_identifier": "en_phone_extension_preserving",
+ "positive_pattern": "\\bext|ext\\b|extension",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ],
+ "pt": [
+ {
+ "pattern_identifier": "pt_phone_extension_preserving",
+ "positive_pattern": "ramal",
+ "positive_score": 1.3,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 69
+ }
+ ]
+ },
+ "PASSPORT": {
+ "en": [
+ {
+ "pattern_identifier": "en_passport_preserving",
+ "positive_pattern": "document.*number|passport",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "fr": [
+ {
+ "pattern_identifier": "fr_passport_preserving",
+ "positive_pattern": "passeport",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_passport_preserving",
+ "positive_pattern": "numero.*documento|pasaporte",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_passport_preserving",
+ "positive_pattern": "書類",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "TRAVEL_ORIGIN": {
+ "en": [
+ {
+ "pattern_identifier": "en_travel_origin_preserving",
+ "positive_pattern": "point.*of.*entry|arrival",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_travel_origin_preserving",
+ "positive_pattern": "punto.*internaci(o|ó)n|fecha.*llegada",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_travel_origin_preserving",
+ "positive_pattern": "入国",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "TRAVEL_DESTINATION": {
+ "en": [
+ {
+ "pattern_identifier": "en_travel_destination_preserving",
+ "positive_pattern": "departure",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_travel_destination_preserving",
+ "positive_pattern": "fecha.*salida|destino",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_travel_destination_preserving",
+ "positive_pattern": "出国",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "FLIGHT": {
+ "en": [
+ {
+ "pattern_identifier": "en_flight_preserving",
+ "positive_pattern": "airline|flight",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "es": [
+ {
+ "pattern_identifier": "es_flight_preserving",
+ "positive_pattern": "aerol(i|í)nea|n(u|ú)mero.*vuelo",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ],
+ "ja": [
+ {
+ "pattern_identifier": "ja_flight_preserving",
+ "positive_pattern": "便å|航空会社",
+ "positive_score": 1.2,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "UPI_VIRTUAL_PAYMENT_ADDRESS": {
+ "en": [
+ {
+ "pattern_identifier": "en_upi_virtual_payment_address_user@(IFSC/Aadhaar/Mobile/RuPay)_preserving",
+ "positive_pattern": "^[\\w.+-_]+@(\\w+\\.ifsc\\.npci|aadhaar\\.npci|mobile\\.npci|rupay\\.npci)$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ },
+ {
+ "pattern_identifier": "en_upi_virtual_payment_address_user@(bank_list)_preserving",
+ "positive_pattern": "^[\\w.+-_]+@(airtel|airtelpaymentsbank|albk|allahabadbank|allbank|andb|apb|apl|axis|axisbank|axisgo|bandhan|barodampay|birla|boi|cbin|cboi|centralbank|cmsidfc|cnrb|csbcash|csbpay|cub|dbs|dcb|dcbbank|denabank|dlb|eazypay|equitas|ezeepay|fbl|federal|finobank|hdfcbank|hsbc|icici|idbi|idbibank|idfc|idfcbank|idfcnetc|ikwik|imobile|indbank|indianbank|indianbk|indus|iob|jkb|jsb|jsbp|karb|karurvysyabank|kaypay|kbl|kbl052|kmb|kmbl|kotak|kvb|kvbank|lime|lvb|lvbank|mahb|obc|okaxis|okbizaxis|okhdfcbank|okicici|oksbi|paytm|payzapp|pingpay|pnb|pockets|psb|purz|rajgovhdfcbank|rbl|sbi|sc|scb|scbl|scmobile|sib|srcb|synd|syndbank|syndicate|tjsb|tjsp|ubi|uboi|uco|unionbank|unionbankofindia|united|upi|utbi|vijayabank|vijb|vjb|ybl|yesbank|yesbankltd)$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "INTERNATIONAL_BANK_ACCOUNT_NUMBER": {
+ "en": [
+ {
+ "pattern_identifier": "en_international_bank_account_number_preserving",
+ "positive_pattern": "^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "VALIDATION_CREDIT_CARD_VERIFICATION_CODE": {
+ "en": [
+ {
+ "pattern_identifier": "en_credit_card_cvc_preserving",
+ "positive_pattern": "^\\d{3,4}$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "VALIDATION_CREDIT_CARD_EXP_YEAR": {
+ "en": [
+ {
+ "pattern_identifier": "en_credit_card_exp_year_preserving",
+ "positive_pattern": "^[2][0][1-9][0-9]$",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "URL_SEARCH_ACTION": {
+ "en": [
+ {
+ "pattern_identifier": "en_url_search_action_preserving",
+ "positive_pattern": "/search(/|((\\w*\\.\\w+)?$))",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "SOCIAL_SECURITY": {
+ "en": [
+ {
+ "pattern_identifier": "en_social_security_preserving",
+ "positive_pattern": "ssn|social.?security.?(num(ber)?|#)*",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ },
+ "ONE_TIME_PASSWORD": {
+ "en": [
+ {
+ "pattern_identifier": "en_one_time_password_preserving",
+ "positive_pattern": "one.?time|sms.?(code|token|password|pwd|pass)",
+ "positive_score": 0,
+ "negative_pattern": null,
+ "match_field_attributes": 3,
+ "match_field_input_types": 1
+ }
+ ]
+ }
+}
diff --git a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc
new file mode 100644
index 00000000000..e6e1a075863
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 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/pattern_provider/test_pattern_provider.h"
+
+#include "base/feature_list.h"
+#include "components/autofill/core/browser/pattern_provider/pattern_configuration_parser.h"
+#include "components/autofill/core/common/autofill_features.h"
+
+namespace autofill {
+
+TestPatternProvider::TestPatternProvider() {
+ // TODO(crbug/1147608) This is an ugly hack to avoid loading the JSON. The
+ // motivation is that some Android unit tests fail because a dependency is
+ // missing. Instead of fixing this dependency, we'll go for an alternative
+ // solution that avoids the whole async/sync problem.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+ base::Optional<PatternProvider::Map> patterns =
+ field_type_parsing::GetPatternsFromResourceBundleSynchronously();
+ if (patterns)
+ SetPatterns(patterns.value(), base::Version(), true);
+
+ PatternProvider::SetPatternProviderForTesting(this);
+ }
+}
+
+TestPatternProvider::~TestPatternProvider() {
+ PatternProvider::ResetPatternProvider();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h
new file mode 100644
index 00000000000..dc923237777
--- /dev/null
+++ b/chromium/components/autofill/core/browser/pattern_provider/test_pattern_provider.h
@@ -0,0 +1,23 @@
+// Copyright 2020 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_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
+
+#include "components/autofill/core/browser/pattern_provider/pattern_provider.h"
+
+namespace autofill {
+
+// The pattern provider to be used in tests. Loads the MatchingPattern
+// configuration synchronously from the Resource Bundle and sets itself as the
+// global PatternProvider.
+class TestPatternProvider : public PatternProvider {
+ public:
+ TestPatternProvider();
+ ~TestPatternProvider();
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PATTERN_PROVIDER_TEST_PATTERN_PROVIDER_H_
diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
index 969131b3a1e..99d93d80d3e 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h
@@ -7,6 +7,8 @@
#include <memory>
+#include "components/signin/public/identity_manager/account_info.h"
+
namespace infobars {
class InfoBar;
}
@@ -15,9 +17,12 @@ namespace autofill {
class AutofillSaveCardInfoBarDelegateMobile;
-// Creates an infobar for saving a credit card on a mobile device.
+// Creates an Infobar for saving a credit card on a mobile device. If
+// AccountInfo contains the user's data, an account indication footer will be
+// shown at the bottom of the Infobar.
std::unique_ptr<infobars::InfoBar> CreateSaveCardInfoBarMobile(
- std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile> delegate);
+ std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile> delegate,
+ base::Optional<AccountInfo> accountInfo);
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
index 7267cfdfd1a..25ea9af5ec7 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
@@ -7,25 +7,18 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/sync_auth_util.h"
+#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "google_apis/gaia/google_service_auth_error.h"
-namespace {
-
-#if defined(OS_ANDROID)
-constexpr base::Feature kWalletRequiresFirstSyncSetupComplete{
- "WalletRequiresFirstSyncSetupComplete", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
-
-} // namespace
-
namespace browser_sync {
AutofillWalletModelTypeController::AutofillWalletModelTypeController(
@@ -102,7 +95,8 @@ AutofillWalletModelTypeController::GetPreconditionState() const {
pref_service_->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled) &&
!sync_service_->GetAuthError().IsPersistentError();
#if defined(OS_ANDROID)
- if (base::FeatureList::IsEnabled(kWalletRequiresFirstSyncSetupComplete)) {
+ if (base::FeatureList::IsEnabled(
+ autofill::features::kWalletRequiresFirstSyncSetupComplete)) {
// On Android, it's also required that the initial Sync setup is complete
// (i.e. the user has previously opted in to Sync-the-feature, even if it's
// not enabled right now).
@@ -114,6 +108,22 @@ AutofillWalletModelTypeController::GetPreconditionState() const {
: PreconditionState::kMustStopAndClearData;
}
+bool AutofillWalletModelTypeController::ShouldRunInTransportOnlyMode() const {
+ if (type() != syncer::AUTOFILL_WALLET_DATA) {
+ return false;
+ }
+ if (!base::FeatureList::IsEnabled(
+ autofill::features::kAutofillEnableAccountWalletStorage)) {
+ return false;
+ }
+ if (sync_service_->GetUserSettings()->IsUsingSecondaryPassphrase() &&
+ !base::FeatureList::IsEnabled(
+ switches::kSyncAllowWalletDataInTransportModeWithCustomPassphrase)) {
+ return false;
+ }
+ return true;
+}
+
void AutofillWalletModelTypeController::OnUserPrefChanged() {
DCHECK(CalledOnValidThread());
sync_service_->DataTypePreconditionChanged(type());
diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
index 03d0312c094..8a016e00805 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h
@@ -47,6 +47,7 @@ class AutofillWalletModelTypeController : public syncer::ModelTypeController,
void Stop(syncer::ShutdownReason shutdown_reason,
StopCallback callback) override;
PreconditionState GetPreconditionState() const override;
+ bool ShouldRunInTransportOnlyMode() const override;
// syncer::SyncServiceObserver implementation.
void OnStateChanged(syncer::SyncService* sync) override;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
index cbd1018b3dd..9b38d40a594 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -79,21 +79,12 @@ void CreditCardAccessManager::UpdateCreditCardFormEventLogger() {
size_t server_record_type_count = 0;
size_t local_record_type_count = 0;
- bool has_server_nickname = false;
for (CreditCard* credit_card : credit_cards) {
- // If any masked server card has valid nickname, we will set to true no
- // matter the flag is enabled or not.
- if (credit_card->record_type() == CreditCard::MASKED_SERVER_CARD &&
- credit_card->HasNonEmptyValidNickname()) {
- has_server_nickname = true;
- }
-
if (credit_card->record_type() == CreditCard::LOCAL_CARD)
local_record_type_count++;
else
server_record_type_count++;
}
- form_event_logger_->set_has_server_nickname(has_server_nickname);
form_event_logger_->set_server_record_type_count(server_record_type_count);
form_event_logger_->set_local_record_type_count(local_record_type_count);
form_event_logger_->set_is_context_secure(client_->IsContextSecure());
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
index e9e8c203a20..2addf2ad08f 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -15,7 +15,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string16.h"
@@ -486,6 +486,8 @@ void CreditCardSaveManager::OfferCardUploadSave() {
// should not display the offer-to-save infobar at all.
if (!is_mobile_build || show_save_prompt_.value_or(true)) {
user_did_accept_upload_prompt_ = false;
+ if (observer_for_testing_)
+ observer_for_testing_->OnOfferUploadSave();
client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, legal_message_lines_,
AutofillClient::SaveCreditCardOptions()
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
index cc5131c2956..a1e77140599 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -84,6 +84,7 @@ class CreditCardSaveManager {
public:
virtual ~ObserverForTest() {}
virtual void OnOfferLocalSave() {}
+ virtual void OnOfferUploadSave() {}
virtual void OnDecideToRequestUploadSave() {}
virtual void OnReceivedGetUploadDetailsResponse() {}
virtual void OnSentUploadCardRequest() {}
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index d6dbaf29876..1868db7fc2b 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -31,6 +31,7 @@
#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/mock_autocomplete_history_manager.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
@@ -349,6 +350,7 @@ class CreditCardSaveManagerTest : public testing::Test {
MockAutocompleteHistoryManager autocomplete_history_manager_;
syncer::TestSyncService sync_service_;
base::test::ScopedFeatureList scoped_feature_list_;
+ TestPatternProvider test_pattern_provider_;
// Ends up getting owned (and destroyed) by TestFormDataImporter:
TestCreditCardSaveManager* credit_card_save_manager_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
index 5843d193507..a7286883894 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
@@ -28,6 +28,7 @@
#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/mock_autocomplete_history_manager.h"
+#include "components/autofill/core/browser/pattern_provider/test_pattern_provider.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_local_card_migration_manager.h"
@@ -313,6 +314,7 @@ class LocalCardMigrationManagerTest : public testing::Test {
MockAutocompleteHistoryManager autocomplete_history_manager_;
syncer::TestSyncService sync_service_;
base::test::ScopedFeatureList scoped_feature_list_;
+ TestPatternProvider test_pattern_provider_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
TestStrikeDatabase* strike_database_;
// Ends up getting owned (and destroyed) by TestFormDataImporter:
diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index 1faf3fad213..d96c2f31f4b 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/autofill/core/browser/payments/strike_database.cc b/chromium/components/autofill/core/browser/payments/strike_database.cc
index d373314931e..a4acdfcbdb8 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
diff --git a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
index 1d0f11324dd..039ea214d05 100644
--- a/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
+++ b/chromium/components/autofill/core/browser/payments/strike_database_integrator_base.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/time/time.h"
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 0a6960bbd43..11d891b1282 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -1523,12 +1523,9 @@ const std::string& PersonalDataManager::GetDefaultCountryCodeForNewAddress()
if (default_country_code_.empty())
default_country_code_ = MostCommonCountryCodeFromProfiles();
- if (base::FeatureList::IsEnabled(
- features::kAutofillUseVariationCountryCode)) {
- // Failing that, use the country code from variations service.
- if (default_country_code_.empty())
- default_country_code_ = variations_country_code_;
- }
+ // Failing that, use the country code from variations service.
+ if (default_country_code_.empty())
+ default_country_code_ = variations_country_code_;
// Failing that, guess based on system timezone.
if (default_country_code_.empty())
@@ -1984,7 +1981,7 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
return !is_opted_in;
#else
return false;
-#endif // #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
+#endif // #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) || \
// defined(OS_APPLE)
}
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
index c930dbc16a4..99b095478df 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -15,7 +15,7 @@
#include <vector>
#include "base/base64.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/guid.h"
#include "base/i18n/time_formatting.h"
@@ -2035,7 +2035,6 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) {
TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromVariations) {
base::test::ScopedFeatureList enabled;
- enabled.InitAndEnableFeature(features::kAutofillUseVariationCountryCode);
const std::string expected_country_code = "DE";
const std::string unepected_country_code = "FR";
diff --git a/chromium/components/autofill/core/browser/proto/BUILD.gn b/chromium/components/autofill/core/browser/proto/BUILD.gn
index eb779aaae07..0aac1b74f7f 100644
--- a/chromium/components/autofill/core/browser/proto/BUILD.gn
+++ b/chromium/components/autofill/core/browser/proto/BUILD.gn
@@ -11,6 +11,7 @@ fuzzable_proto_library("proto") {
"password_requirements.proto",
"password_requirements_shard.proto",
"server.proto",
+ "states.proto",
"strike_data.proto",
]
}
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 1bc923e9f25..ea2d2a5f4b8 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -407,6 +407,7 @@ message AutofillUploadContents {
DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD = 8; // unused
DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD = 9; // unused
PROBABLE_FORM_SUBMISSION = 10;
+ CHANGE_PASSWORD_FORM_CLEARED = 11;
}
// The type of the event that was taken as an indication that the form has
diff --git a/chromium/components/autofill/core/browser/proto/states.proto b/chromium/components/autofill/core/browser/proto/states.proto
new file mode 100644
index 00000000000..3253823616b
--- /dev/null
+++ b/chromium/components/autofill/core/browser/proto/states.proto
@@ -0,0 +1,31 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package autofill;
+
+option optimize_for = LITE_RUNTIME;
+
+message StateEntry {
+ // Full name representing the state entry unique within a country.
+ // Example:
+ // "California" for "CA", "California", "The Golden State".
+ // "Bavaria" for "BY", "Bavaria", "Bayern".
+ optional string canonical_name = 1;
+
+ // Abbreviations corresponding to the state entry.
+ repeated string abbreviations = 2;
+
+ // Alternative names of the state.
+ repeated string alternative_names = 3;
+}
+
+message StatesInCountry {
+ // Two digit country code.
+ optional string country_code = 1;
+
+ // All the states belonging to the country.
+ repeated StateEntry states = 2;
+}
diff --git a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
index 67ebfbe0af9..8ec974c7a65 100644
--- a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.h b/chromium/components/autofill/core/browser/test_autofill_manager.h
index 51989ace0e5..2a5b103953c 100644
--- a/chromium/components/autofill/core/browser/test_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/test_autofill_manager.h
@@ -72,6 +72,7 @@ class TestAutofillManager : public AutofillManager {
void SetCallParentUploadFormData(bool value);
using AutofillManager::is_rich_query_enabled;
+ using AutofillManager::pending_form_data;
private:
TestPersonalDataManager* personal_data_; // Weak reference.
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
index ed92eae2fcf..7bdb471b44a 100644
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.cc b/chromium/components/autofill/core/browser/test_autofill_provider.cc
index 2102a1974f9..ac9248b8d08 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.cc
@@ -33,8 +33,8 @@ void TestAutofillProvider::OnSelectControlDidChange(
const FormFieldData& field,
const gfx::RectF& bounding_box) {}
-void TestAutofillProvider::OnFocusNoLongerOnForm(
- AutofillHandlerProxy* handler) {}
+void TestAutofillProvider::OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) {}
void TestAutofillProvider::OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h
index 7a21e59c6bb..db7234195fa 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.h
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.h
@@ -37,7 +37,8 @@ class TestAutofillProvider : public AutofillProvider {
const FormData& form,
bool known_success,
mojom::SubmissionSource source) override {}
- void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
+ void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler,
+ bool had_interacted_form) override;
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
const FormFieldData& field,
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
index 03455605c04..49a051467f7 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl_unittest.cc
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
diff --git a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
index 4779ab5f6c5..144e523b838 100644
--- a/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/region_combobox_model.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/geo/region_data_loader.h"
#include "components/strings/grit/components_strings.h"
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index 33f0aa6dbde..deee50f2db7 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -14,12 +14,12 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/geo/state_names.h"
#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 557cbac1485..9cda0484f05 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/proto/autofill_sync.pb.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -287,7 +288,7 @@ void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutocompleteSyncBridge>(
web_data_backend,
std::make_unique<ClientTagBasedModelTypeProcessor>(
- syncer::AUTOFILL, /*dump_stack=*/base::RepeatingClosure())));
+ syncer::AUTOFILL, /*dump_stack=*/base::DoNothing())));
}
// static
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index d559076a9a4..4c580c90dc0 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -10,13 +10,13 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -27,9 +27,9 @@
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/metadata_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
index 627a0aac521..d6f098f58b0 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -60,7 +61,7 @@ void AutofillProfileSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillProfileSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_PROFILE,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
app_locale, web_data_backend));
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
index f977b702cad..171f079d9f8 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
@@ -18,7 +18,7 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
@@ -35,12 +35,12 @@
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/entity_data.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/model/sync_error_factory_mock.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/sync_error_factory_mock.h"
#include "components/webdata/common/web_database.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
index 403f270afec..03f8b7baef7 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
@@ -4,7 +4,7 @@
#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_callback.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index 4f639a23d22..aa3324298db 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1044,9 +1044,10 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
AutofillProfile profile;
profile.set_origin(std::string());
- profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("Street Address"),
- VerificationStatus::kUserVerified);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("Street Name House Number Premise Subpremise"),
+ VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
ASCIIToUTF16("Street Name"),
VerificationStatus::kFormatted);
@@ -1070,9 +1071,9 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
profile.SetRawInfoWithVerificationStatus(
ADDRESS_HOME_COUNTRY, ASCIIToUTF16("DE"), VerificationStatus::kObserved);
- profile.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, ASCIIToUTF16("Dependent Street Name"),
- VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ASCIIToUTF16(""),
+ VerificationStatus::kObserved);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER,
ASCIIToUTF16("House Number"),
@@ -1131,7 +1132,7 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredAddresses) {
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_STREET_NAME),
ASCIIToUTF16("Street Name"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
- ASCIIToUTF16("Dependent Street Name"));
+ ASCIIToUTF16(""));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
ASCIIToUTF16("House Number"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_SUBPREMISE),
@@ -1162,15 +1163,16 @@ TEST_F(AutofillTableTest,
AutofillProfile profile;
profile.set_origin(std::string());
- profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_ADDRESS,
- ASCIIToUTF16("Street Address"),
- VerificationStatus::kUserVerified);
+ profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_STREET_ADDRESS,
+ ASCIIToUTF16("Street Name House Number Premise Subpremise"),
+ VerificationStatus::kUserVerified);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_STREET_NAME,
ASCIIToUTF16("Street Name"),
VerificationStatus::kFormatted);
- profile.SetRawInfoWithVerificationStatus(
- ADDRESS_HOME_DEPENDENT_STREET_NAME, ASCIIToUTF16("Dependent Street Name"),
- VerificationStatus::kObserved);
+ profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_DEPENDENT_STREET_NAME,
+ ASCIIToUTF16(""),
+ VerificationStatus::kObserved);
profile.SetRawInfoWithVerificationStatus(ADDRESS_HOME_HOUSE_NUMBER,
ASCIIToUTF16("House Number"),
VerificationStatus::kUserVerified);
@@ -1196,7 +1198,7 @@ TEST_F(AutofillTableTest,
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_STREET_NAME),
ASCIIToUTF16("Street Name"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
- ASCIIToUTF16("Dependent Street Name"));
+ ASCIIToUTF16(""));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
ASCIIToUTF16("House Number"));
EXPECT_EQ(db_profile->GetRawInfo(ADDRESS_HOME_SUBPREMISE),
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index e43c36f6c40..c89d012e159 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -10,6 +10,7 @@
#include <vector>
#include "base/base64.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/optional.h"
@@ -310,7 +311,7 @@ void AutofillWalletMetadataSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletMetadataSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_METADATA,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
index 0cae0cf6b6d..f646c276c19 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -13,10 +13,10 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/data_model/autofill_metadata.h"
@@ -32,9 +32,9 @@
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/entity_data.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
index c95389dba6d..bc4c93b79ba 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
@@ -47,7 +48,7 @@ void AutofillWalletOfferSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletOfferSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_OFFER,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
index 3132670cb95..5658421d159 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
@@ -12,7 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
@@ -26,12 +26,12 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/hash_util.h"
#include "components/sync/model/entity_data.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index 8cafefa1abb..47f257894e1 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/base64.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
@@ -146,7 +147,7 @@ void AutofillWalletSyncBridge::CreateForWebDataServiceAndBackend(
std::make_unique<AutofillWalletSyncBridge>(
std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
syncer::AUTOFILL_WALLET_DATA,
- /*dump_stack=*/base::RepeatingClosure()),
+ /*dump_stack=*/base::DoNothing()),
web_data_backend));
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index 540f2b9376b..ce186b41372 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -10,13 +10,12 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
@@ -36,12 +35,12 @@
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/model/entity_data.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/test_matchers.h"
#include "components/webdata/common/web_database.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
index 6487f6bb507..de0083a0599 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -5,7 +5,7 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index dce7abdaf4a..b637f09bf1d 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -7,7 +7,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index 44d8b901795..948b48e1485 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -22,16 +22,13 @@ static_library("common") {
"autofill_payments_features.h",
"autofill_prefs.cc",
"autofill_prefs.h",
- "autofill_regex_constants.cc",
- "autofill_regex_constants.h",
- "autofill_regexes.cc",
- "autofill_regexes.h",
"autofill_switches.cc",
"autofill_switches.h",
"autofill_tick_clock.cc",
"autofill_tick_clock.h",
"autofill_util.cc",
"autofill_util.h",
+ "dense_set.h",
"field_data_manager.cc",
"field_data_manager.h",
"form_data.cc",
@@ -46,11 +43,8 @@ static_library("common") {
"gaia_id_hash.h",
"logging/log_buffer.cc",
"logging/log_buffer.h",
- "password_form.cc",
- "password_form.h",
"password_form_fill_data.cc",
"password_form_fill_data.h",
- "password_form_generation_data.cc",
"password_form_generation_data.h",
"password_generation_util.cc",
"password_generation_util.h",
@@ -87,8 +81,8 @@ source_set("unit_tests") {
"autofill_internals/logging_scope_unittest.cc",
"autofill_l10n_util_unittest.cc",
"autofill_prefs_unittest.cc",
- "autofill_regexes_unittest.cc",
"autofill_util_unittest.cc",
+ "dense_set_unittest.cc",
"field_data_manager_unittest.cc",
"form_data_unittest.cc",
"form_field_data_unittest.cc",
diff --git a/chromium/components/autofill/core/common/OWNERS b/chromium/components/autofill/core/common/OWNERS
index 219017c1704..04e7201eab4 100644
--- a/chromium/components/autofill/core/common/OWNERS
+++ b/chromium/components/autofill/core/common/OWNERS
@@ -1,5 +1,3 @@
-per-file *password*=dvadym@chromium.org
-per-file *password*=kolos@chromium.org
-per-file *password*=vasilii@chromium.org
+per-file *password*=file://components/password_manager/OWNERS
per-file autofill_payments_features.*=file://components/autofill/core/browser/payments/OWNERS
diff --git a/chromium/components/autofill/core/common/autofill_constants.cc b/chromium/components/autofill/core/common/autofill_constants.cc
index f67d797bed9..5f9f040624a 100644
--- a/chromium/components/autofill/core/common/autofill_constants.cc
+++ b/chromium/components/autofill/core/common/autofill_constants.cc
@@ -12,25 +12,6 @@ namespace autofill {
const char kSettingsOrigin[] = "Chrome settings";
-size_t MinRequiredFieldsForHeuristics() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics)
- ? 3
- : 1;
-}
-size_t MinRequiredFieldsForQuery() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForQuery)
- ? 3
- : 1;
-}
-size_t MinRequiredFieldsForUpload() {
- return base::FeatureList::IsEnabled(
- autofill::features::kAutofillEnforceMinRequiredFieldsForUpload)
- ? 3
- : 1;
-}
-
bool IsAutofillEntryWithUseDateDeletable(const base::Time& use_date) {
return use_date < AutofillClock::Now() - kDisusedDataModelDeletionTimeDelta;
}
diff --git a/chromium/components/autofill/core/common/autofill_constants.h b/chromium/components/autofill/core/common/autofill_constants.h
index 84c5b916b03..07428810cc3 100644
--- a/chromium/components/autofill/core/common/autofill_constants.h
+++ b/chromium/components/autofill/core/common/autofill_constants.h
@@ -18,9 +18,9 @@ extern const char kSettingsOrigin[];
// The number of fields required by Autofill to execute its heuristic and
// crowd-sourcing query/upload routines.
-size_t MinRequiredFieldsForHeuristics();
-size_t MinRequiredFieldsForQuery();
-size_t MinRequiredFieldsForUpload();
+constexpr size_t kMinRequiredFieldsForHeuristics = 3;
+constexpr size_t kMinRequiredFieldsForQuery = 1;
+constexpr size_t kMinRequiredFieldsForUpload = 1;
// The maximum number of form fields we are willing to parse, due to
// computational costs. Several examples of forms with lots of fields that are
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index 50444cf12c2..349361c1c7b 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -24,6 +24,13 @@ namespace features {
const base::Feature kAutofillAddressEnhancementVotes{
"kAutofillAddressEnhancementVotes", base::FEATURE_DISABLED_BY_DEFAULT};
+// TODO(crbug.com/1135188): Remove this feature flag after the explicit save
+// prompts for address profiles is complete.
+// When enabled, a save prompt will be shown to user upon form submission before
+// storing any detected address profile.
+const base::Feature kAutofillAddressProfileSavePrompt{
+ "AutofillAddressProfileSavePrompt", base::FEATURE_DISABLED_BY_DEFAULT};
+
// By default, AutofillAgent and, if |kAutofillProbableFormSubmissionInBrowser|
// is enabled, also ContentAutofillDriver omit duplicate form submissions, even
// though the form's data may have changed substantially. If enabled, the
@@ -32,13 +39,6 @@ const base::Feature kAutofillAddressEnhancementVotes{
const base::Feature kAutofillAllowDuplicateFormSubmissions{
"AutofillAllowDuplicateFormSubmissions", base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls if a full country name instead of a country code in a field with a
-// type derived from HTML_TYPE_COUNTRY_CODE can be used to set the profile
-// country.
-const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames{
- "AutofillAllowHtmlTypeCountryCodesWithFullNames",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether autofill activates on non-HTTP(S) pages. Useful for
// automated with data URLS in cases where it's too difficult to use the
// embedded test server. Generally avoid using.
@@ -86,6 +86,28 @@ const base::Feature kAutofillEnableAugmentedPhoneCountryCode{
const base::Feature kAutofillEnableHideSuggestionsUI{
"AutofillEnableHideSuggestionsUI", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled and user has single account, a footer indicating user's e-mail
+// address and profile picture will appear at the bottom of InfoBars which has
+// corresponding account indication footer flags on.
+const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers{
+ "AutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled and user is syncing, a footer indicating user's e-mail address
+// and profile picture will appear at the bottom of InfoBars which has
+// corresponding account indication footer flags on.
+const base::Feature kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers{
+ "AutofillEnableInfoBarAccountIndicationFooterForSyncUsers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled and user is signed in, a footer indicating user's e-mail address
+// and profile picture will appear at the bottom of corresponding password
+// InfoBars.
+const base::Feature kAutofillEnablePasswordInfoBarAccountIndicationFooter{
+ "AutofillEnablePasswordInfoBarAccountIndicationFooter",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls if Autofill supports new structure in names.
// TODO(crbug.com/1098943): Remove once launched.
const base::Feature kAutofillEnableSupportForMoreStructureInNames{
@@ -104,23 +126,12 @@ const base::Feature kAutofillEnableSupportForMergingSubsetNames{
"AutofillEnableSupportForMergingSubsetNames",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether or not a minimum number of fields is required before
-// heuristic field type prediction is run for a form.
-const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics{
- "AutofillEnforceMinRequiredFieldsForHeuristics",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether or not a minimum number of fields is required before
-// crowd-sourced field type predictions are queried for a form.
-const base::Feature kAutofillEnforceMinRequiredFieldsForQuery{
- "AutofillEnforceMinRequiredFieldsForQuery",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls whether or not a minimum number of fields is required before
-// field type votes are uploaded to the crowd-sourcing server.
-const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
- "AutofillEnforceMinRequiredFieldsForUpload",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether honorific prefix is shown and editable in Autofill Settings
+// on Android, iOS and Desktop.
+// TODO(crbug.com/1141460): Remove once launched.
+const base::Feature kAutofillEnableUIForHonorificPrefixesInSettings{
+ "AutofillEnableUIForHonorificPrefixesInSettings",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether or not all datalist shall be extracted into FormFieldData.
// This feature is enabled in both WebView and WebLayer where all datalists
@@ -137,30 +148,17 @@ const base::Feature kAutofillExtractAllDatalists{
const base::Feature kAutofillFixFillableFieldTypes{
"AutofillFixFillableFieldTypes", base::FEATURE_DISABLED_BY_DEFAULT};
-// If enabled, prefilled country and state values are not reset before
-// an address profile import.
-// TODO(crbug.com/1100231): Remove once fix is tested.
-const base::Feature kAutofillImportPrefilledCountryAndStateValues{
- "AutofillImportPrefilledCountryAndStateValues",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// When enabled, Autofill keeps the initial field values in the |FormStructure|
-// cache for all field types.
-const base::Feature kAutofillKeepInitialFormValuesInCache{
- "AutofillKeepCachedFormValues", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// When enabled, Autofill will use FieldRendererIds instead of unique_names
-// to align forms in FormStructure::RetrieveFromCache().
-const base::Feature kAutofillRetrieveFromCacheWithRendererIds{
- "AutofillRetrieveFromCacheWithRendererIds",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will use FormRendererIds instead of
+// GetIdentifierForRefill() to identify forms during refills.
+// TODO(crbug/896689): Remove once experiment is finished.
+const base::Feature kAutofillRefillWithRendererIds{
+ "AutofillRefillWithRendererIds", base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, Autofill will try to retrieve cached fields by signatures as a
-// fallback that is useful if unique renderer ids are unstable.
-// TODO(crbug.com/1125624): Remove experiment once trial ended.
-const base::Feature kAutofillRetrieveFromCacheWithFieldSignatureAsFallback{
- "AutofillRetrieveFromCacheWithFieldSignatureAsFallback",
- base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, Autofill will use FormRendererIds instead of
+// unique_name() to create unique section names.
+// TODO(crbug/896689): Remove once experiment is finished.
+const base::Feature kAutofillNameSectionsWithRendererIds{
+ "AutofillNameSectionsWithRendererIds", base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, autofill suggestions are displayed in the keyboard accessory
// instead of the regular popup.
@@ -196,15 +194,6 @@ const base::Feature kAutofillProbableFormSubmissionInBrowser{
const base::Feature kAutofillProfileClientValidation{
"AutofillProfileClientValidation", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillProfileImportFromUnifiedSection{
- "AutofillProfileImportFromUnifiedSection",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// TODO(crbug.com/1101280): Remove once feature is tested.
-const base::Feature kAutofillProfileImportFromUnfocusableFields{
- "AutofillProfileImportFromUnfocusableFields",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether Autofill uses server-side validation to ensure that fields
// with invalid data are not suggested.
const base::Feature kAutofillProfileServerValidation{
@@ -263,14 +252,17 @@ const base::Feature kAutofillSkipFillingFieldsWithChangedValues{
const base::Feature kAutofillTokenPrefixMatching{
"AutofillTokenPrefixMatching", base::FEATURE_DISABLED_BY_DEFAULT};
-// Enables the touch to fill feature for Android.
-const base::Feature kAutofillTouchToFill = {"TouchToFillAndroid",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Autofill upload throttling is used for testing.
const base::Feature kAutofillUploadThrottling{"AutofillUploadThrottling",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether to use the AutofillUseAlternativeStateNameMap for filling
+// of state selection fields, comparison of profiles and sending state votes to
+// the server.
+// TODO(crbug.com/1143516): Remove the feature when the experiment is completed.
+const base::Feature kAutofillUseAlternativeStateNameMap{
+ "AutofillUseAlternativeStateNameMap", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether suggestions' labels use the improved label disambiguation
// format.
const base::Feature kAutofillUseImprovedLabelDisambiguation{
@@ -282,31 +274,12 @@ const base::Feature kAutofillUseImprovedLabelDisambiguation{
const base::Feature kAutofillUseNewSectioningMethod{
"AutofillUseNewSectioningMethod", base::FEATURE_DISABLED_BY_DEFAULT};
-// TODO(crbug.com/1075604): Remove once launched.
-// Controls whether the page language is used as a fall-back locale to translate
-// the country name when a profile is imported from a form.
-const base::Feature kAutofillUsePageLanguageToTranslateCountryNames{
- "AutofillUsePageLanguageToTranslateCountryNames",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Controls whether to use the |ParseCityStateCountryZipCode| or not for
-// predicting the heuristic type.
-// |ParseCityStateCountryZipCode| is intended to prevent the misclassification
-// of the country field into |ADDRESS_HOME_STATE| while determining the
-// heuristic type. The misclassification happens sometimes because the regular
-// expression for |ADDRESS_HOME_STATE| contains the term "region" which is also
-// used for country selectors.
-const base::Feature kAutofillUseParseCityStateCountryZipCodeInHeuristic{
- "AutofillUseParseCityStateCountryZipCodeInHeuristic",
+// Controls whether page language is used to match patterns.
+// TODO(crbug.com/1134496): Remove once launched.
+const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns{
+ "AutofillUsePageLanguageToSelectFieldParsingPatterns",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether or not autofill utilizes the country code from the Chrome
-// variation service. The country code is used for determining the address
-// requirements for address profile creation and as source for a default country
-// used in a new address profile.
-const base::Feature kAutofillUseVariationCountryCode{
- "AutofillUseVariationCountryCode", base::FEATURE_DISABLED_BY_DEFAULT};
-
#if defined(OS_ANDROID)
// Controls whether the Autofill manual fallback for Addresses and Payments is
// present on Android.
@@ -335,5 +308,13 @@ const base::Feature kAutofillUseUniqueRendererIDsOnIOS{
"AutofillUseUniqueRendererIDsOnIOS", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
+#if defined(OS_ANDROID)
+// Controls whether the Wallet (GPay) integration requires first-sync-setup to
+// be complete.
+// TODO(crbug.com/1134564): Clean up after launch.
+const base::Feature kWalletRequiresFirstSyncSetupComplete{
+ "WalletRequiresFirstSyncSetupComplete", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 1bbf23972e7..8209085714b 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -22,8 +22,8 @@ namespace features {
// All features in alphabetical order.
extern const base::Feature kAutofillAddressEnhancementVotes;
+extern const base::Feature kAutofillAddressProfileSavePrompt;
extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
-extern const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames;
extern const base::Feature kAutofillAllowNonHttpActivation;
extern const base::Feature kAutofillAlwaysFillAddresses;
extern const base::Feature
@@ -33,20 +33,20 @@ extern const base::Feature kAutofillCreateDataForTest;
extern const base::Feature kAutofillEnableAccountWalletStorage;
extern const base::Feature kAutofillEnableAugmentedPhoneCountryCode;
extern const base::Feature kAutofillEnableHideSuggestionsUI;
+extern const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSingleAccountUsers;
+extern const base::Feature
+ kAutofillEnableInfoBarAccountIndicationFooterForSyncUsers;
+extern const base::Feature
+ kAutofillEnablePasswordInfoBarAccountIndicationFooter;
extern const base::Feature kAutofillEnableSupportForMoreStructureInNames;
extern const base::Feature kAutofillEnableSupportForMoreStructureInAddresses;
extern const base::Feature kAutofillEnableSupportForMergingSubsetNames;
-extern const base::Feature kAutofillEnableSupportForHouseNumbers;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
-extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
+extern const base::Feature kAutofillEnableUIForHonorificPrefixesInSettings;
extern const base::Feature kAutofillExtractAllDatalists;
extern const base::Feature kAutofillFixFillableFieldTypes;
-extern const base::Feature kAutofillImportPrefilledCountryAndStateValues;
-extern const base::Feature kAutofillKeepInitialFormValuesInCache;
-extern const base::Feature kAutofillRetrieveFromCacheWithRendererIds;
-extern const base::Feature
- kAutofillRetrieveFromCacheWithFieldSignatureAsFallback;
+extern const base::Feature kAutofillRefillWithRendererIds;
+extern const base::Feature kAutofillNameSectionsWithRendererIds;
extern const base::Feature kAutofillKeyboardAccessory;
extern const base::Feature kAutofillLabelAffixRemoval;
extern const base::Feature kAutofillPruneSuggestions;
@@ -55,8 +55,6 @@ extern const base::Feature kAutofillOffNoServerData;
extern const base::Feature kAutofillPreventMixedFormsFilling;
extern const base::Feature kAutofillProbableFormSubmissionInBrowser;
extern const base::Feature kAutofillProfileClientValidation;
-extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
-extern const base::Feature kAutofillProfileImportFromUnifiedSection;
extern const base::Feature kAutofillProfileServerValidation;
extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
extern const base::Feature kAutofillRichMetadataQueries;
@@ -67,13 +65,11 @@ extern const base::Feature kAutofillShowTypePredictions;
extern const base::Feature kAutofillSkipComparingInferredLabels;
extern const base::Feature kAutofillSkipFillingFieldsWithChangedValues;
extern const base::Feature kAutofillTokenPrefixMatching;
-extern const base::Feature kAutofillTouchToFill;
extern const base::Feature kAutofillUploadThrottling;
+extern const base::Feature kAutofillUseAlternativeStateNameMap;
extern const base::Feature kAutofillUseImprovedLabelDisambiguation;
extern const base::Feature kAutofillUseNewSectioningMethod;
-extern const base::Feature kAutofillUsePageLanguageToTranslateCountryNames;
-extern const base::Feature kAutofillUseParseCityStateCountryZipCodeInHeuristic;
-extern const base::Feature kAutofillUseVariationCountryCode;
+extern const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns;
#if defined(OS_ANDROID)
extern const base::Feature kAutofillManualFallbackAndroid;
@@ -97,6 +93,10 @@ bool IsMacViewsAutofillPopupExperimentEnabled();
extern const base::Feature kAutofillUseUniqueRendererIDsOnIOS;
#endif // OS_IOS
+#if defined(OS_ANDROID)
+extern const base::Feature kWalletRequiresFirstSyncSetupComplete;
+#endif
+
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc
index 5d89d6e7431..8d74f541c6c 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -84,6 +84,12 @@ const base::Feature kAutofillEnableGoogleIssuedCard{
const base::Feature kAutofillEnableOffersInDownstream{
"kAutofillEnableOffersInDownstream", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled and user is signed in, a footer indicating user's e-mail address
+// and profile picture will appear at the bottom of SaveCardInfoBar.
+const base::Feature kAutofillEnableSaveCardInfoBarAccountIndicationFooter{
+ "AutofillEnableSaveCardInfoBarAccountIndicationFooter",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, all payments related bubbles will not be dismissed upon page
// navigation.
const base::Feature kAutofillEnableStickyPaymentsBubble{
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 29ab241633c..4cadf5421ad 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -30,6 +30,8 @@ extern const base::Feature kAutofillEnableCardNicknameUpstream;
extern const base::Feature kAutofillEnableFixedPaymentsBubbleLogging;
extern const base::Feature kAutofillEnableGoogleIssuedCard;
extern const base::Feature kAutofillEnableOffersInDownstream;
+extern const base::Feature
+ kAutofillEnableSaveCardInfoBarAccountIndicationFooter;
extern const base::Feature kAutofillEnableStickyPaymentsBubble;
extern const base::Feature kAutofillEnableToolbarStatusChip;
extern const base::Feature kAutofillEnableVirtualCard;
diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc
index c31f2e3c56b..23a0ce36f01 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs.cc
@@ -185,11 +185,12 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterTimePref(prefs::kAutofillUploadEventsLastResetTimestamp,
base::Time());
registry->RegisterDictionaryPref(prefs::kAutofillSyncTransportOptIn);
- registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
// Deprecated prefs registered for migration.
registry->RegisterBooleanPref(kAutofillJapanCityFieldMigratedDeprecated,
false);
+ // Deprecated in profile prefs.
+ registry->RegisterStringPref(prefs::kAutofillStatesDataDir, "");
}
void MigrateDeprecatedAutofillPrefs(PrefService* prefs) {
@@ -223,6 +224,11 @@ void MigrateDeprecatedAutofillPrefs(PrefService* prefs) {
// Added 10/2019.
prefs->ClearPref(kAutofillJapanCityFieldMigratedDeprecated);
+
+ // Added 11/2020
+ // TODO(crbug.com/1147852): Remove deprecated kAutofillStatesDataDir from
+ // autofill profile prefs.
+ prefs->ClearPref(kAutofillStatesDataDir);
}
bool IsAutocompleteEnabled(const PrefService* prefs) {
diff --git a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc b/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
deleted file mode 100644
index 4201bceef30..00000000000
--- a/chromium/components/autofill/core/common/autofill_regexes_unittest.cc
+++ /dev/null
@@ -1,232 +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/common/autofill_regexes.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
-
-namespace autofill {
-
-struct InputPatternTestCase {
- const char* const input;
- const char* const pattern;
- };
-
- class PositiveSampleTest
- : public testing::TestWithParam<InputPatternTestCase> {};
-
- TEST_P(PositiveSampleTest, SampleRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input),
- ASCIIToUTF16(test_case.pattern)));
- }
-
- INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- PositiveSampleTest,
- testing::Values(
- // Empty pattern
- InputPatternTestCase{"", ""},
- InputPatternTestCase{
- "Look, ma' -- a non-empty string!", ""},
- // Substring
- InputPatternTestCase{"string", "tri"},
- // Substring at beginning
- InputPatternTestCase{"string", "str"},
- InputPatternTestCase{"string", "^str"},
- // Substring at end
- InputPatternTestCase{"string", "ring"},
- InputPatternTestCase{"string", "ring$"},
- // Case-insensitive
- InputPatternTestCase{"StRiNg", "string"}));
-
- class NegativeSampleTest
- : public testing::TestWithParam<InputPatternTestCase> {};
-
- TEST_P(NegativeSampleTest, SampleRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- SCOPED_TRACE(test_case.pattern);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input),
- ASCIIToUTF16(test_case.pattern)));
-}
-
-INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- NegativeSampleTest,
- testing::Values(
- // Empty string
- InputPatternTestCase{
- "", "Look, ma' -- a non-empty pattern!"},
- // Substring
- InputPatternTestCase{"string", "trn"},
- // Substring at beginning
- InputPatternTestCase{"string", " str"},
- InputPatternTestCase{"string", "^tri"},
- // Substring at end
- InputPatternTestCase{"string", "ring "},
- InputPatternTestCase{"string", "rin$"}));
-
-struct InputTestCase {
- const char* const input;
- };
-
- class ExpirationDate2DigitYearPositive
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate2DigitYearPositive, ExpirationDate2DigitYearRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate2DigitYearPositive,
- testing::Values(InputTestCase{"mm / yy"},
- InputTestCase{"mm/ yy"},
- InputTestCase{"mm /yy"},
- InputTestCase{"mm/yy"},
- InputTestCase{"mm - yy"},
- InputTestCase{"mm- yy"},
- InputTestCase{"mm -yy"},
- InputTestCase{"mm-yy"},
- InputTestCase{"mmyy"},
- // Complex two year cases
- InputTestCase{"Expiration Date (MM / YY)"},
- InputTestCase{"Expiration Date (MM/YY)"},
- InputTestCase{"Expiration Date (MM - YY)"},
- InputTestCase{"Expiration Date (MM-YY)"},
- InputTestCase{"Expiration Date MM / YY"},
- InputTestCase{"Expiration Date MM/YY"},
- InputTestCase{"Expiration Date MM - YY"},
- InputTestCase{"Expiration Date MM-YY"},
- InputTestCase{"expiration date yy"},
- InputTestCase{"Exp Date (MM / YY)"}));
-
- class ExpirationDate2DigitYearNegative
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate2DigitYearNegative, ExpirationDate2DigitYearRegexes) {
- auto test_case = GetParam();
- SCOPED_TRACE(test_case.input);
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate2DigitYearRe);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate2DigitYearNegative,
- testing::Values(InputTestCase{""},
- InputTestCase{"Look, ma' -- an invalid string!"},
- InputTestCase{"mmfavouritewordyy"},
- InputTestCase{"mm a yy"},
- InputTestCase{"mm a yyyy"},
- // Simple four year cases
- InputTestCase{"mm / yyyy"},
- InputTestCase{"mm/ yyyy"},
- InputTestCase{"mm /yyyy"},
- InputTestCase{"mm/yyyy"},
- InputTestCase{"mm - yyyy"},
- InputTestCase{"mm- yyyy"},
- InputTestCase{"mm -yyyy"},
- InputTestCase{"mm-yyyy"},
- InputTestCase{"mmyyyy"},
- // Complex four year cases
- InputTestCase{"Expiration Date (MM / YYYY)"},
- InputTestCase{"Expiration Date (MM/YYYY)"},
- InputTestCase{"Expiration Date (MM - YYYY)"},
- InputTestCase{"Expiration Date (MM-YYYY)"},
- InputTestCase{"Expiration Date MM / YYYY"},
- InputTestCase{"Expiration Date MM/YYYY"},
- InputTestCase{"Expiration Date MM - YYYY"},
- InputTestCase{"Expiration Date MM-YYYY"},
- InputTestCase{"expiration date yyyy"},
- InputTestCase{"Exp Date (MM / YYYY)"}));
-
- class ExpirationDate4DigitYearPositive
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate4DigitYearPositive, ExpirationDate4DigitYearRegexes) {
- auto test_case = GetParam();
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
- SCOPED_TRACE(test_case.input);
- EXPECT_TRUE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
- }
-
- INSTANTIATE_TEST_SUITE_P(AutofillRegexes,
- ExpirationDate4DigitYearPositive,
- testing::Values(
- // Simple four year cases
- InputTestCase{"mm / yyyy"},
- InputTestCase{"mm/ yyyy"},
- InputTestCase{"mm /yyyy"},
- InputTestCase{"mm/yyyy"},
- InputTestCase{"mm - yyyy"},
- InputTestCase{"mm- yyyy"},
- InputTestCase{"mm -yyyy"},
- InputTestCase{"mm-yyyy"},
- InputTestCase{"mmyyyy"},
- // Complex four year cases
- InputTestCase{"Expiration Date (MM / YYYY)"},
- InputTestCase{"Expiration Date (MM/YYYY)"},
- InputTestCase{"Expiration Date (MM - YYYY)"},
- InputTestCase{"Expiration Date (MM-YYYY)"},
- InputTestCase{"Expiration Date MM / YYYY"},
- InputTestCase{"Expiration Date MM/YYYY"},
- InputTestCase{"Expiration Date MM - YYYY"},
- InputTestCase{"Expiration Date MM-YYYY"},
- InputTestCase{"expiration date yyyy"},
- InputTestCase{"Exp Date (MM / YYYY)"}));
-
- class ExpirationDate4DigitYearNegative
- : public testing::TestWithParam<InputTestCase> {};
-
- TEST_P(ExpirationDate4DigitYearNegative, ExpirationDate4DigitYearRegexes) {
- auto test_case = GetParam();
- const base::string16 pattern = ASCIIToUTF16(kExpirationDate4DigitYearRe);
- SCOPED_TRACE(test_case.input);
- EXPECT_FALSE(MatchesPattern(ASCIIToUTF16(test_case.input), pattern));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- AutofillRegexes,
- ExpirationDate4DigitYearNegative,
- testing::Values(InputTestCase{""},
- InputTestCase{"Look, ma' -- an invalid string!"},
- InputTestCase{"mmfavouritewordyy"},
- InputTestCase{"mm a yy"},
- InputTestCase{"mm a yyyy"},
- // Simple two year cases
- InputTestCase{"mm / yy"},
- InputTestCase{"mm/ yy"},
- InputTestCase{"mm /yy"},
- InputTestCase{"mm/yy"},
- InputTestCase{"mm - yy"},
- InputTestCase{"mm- yy"},
- InputTestCase{"mm -yy"},
- InputTestCase{"mm-yy"},
- InputTestCase{"mmyy"},
- // Complex two year cases
- InputTestCase{"Expiration Date (MM / YY)"},
- InputTestCase{"Expiration Date (MM/YY)"},
- InputTestCase{"Expiration Date (MM - YY)"},
- InputTestCase{"Expiration Date (MM-YY)"},
- InputTestCase{"Expiration Date MM / YY"},
- InputTestCase{"Expiration Date MM/YY"},
- InputTestCase{"Expiration Date MM - YY"},
- InputTestCase{"Expiration Date MM-YY"},
- InputTestCase{"expiration date yy"},
- InputTestCase{"Exp Date (MM / YY)"}));
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc
index f738895aa7f..d9a17f403a6 100644
--- a/chromium/components/autofill/core/common/autofill_util.cc
+++ b/chromium/components/autofill/core/common/autofill_util.cc
@@ -65,7 +65,7 @@ bool IsKeyboardAccessoryEnabled() {
bool IsTouchToFillEnabled() {
#if defined(OS_ANDROID)
- return base::FeatureList::IsEnabled(features::kAutofillTouchToFill);
+ return true;
#else // !defined(OS_ANDROID)
return false;
#endif
diff --git a/chromium/components/autofill/core/common/dense_set.h b/chromium/components/autofill/core/common/dense_set.h
new file mode 100644
index 00000000000..cd52b04a025
--- /dev/null
+++ b/chromium/components/autofill/core/common/dense_set.h
@@ -0,0 +1,278 @@
+// Copyright 2020 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_COMMON_DENSE_SET_H_
+#define COMPONENTS_AUTOFILL_CORE_COMMON_DENSE_SET_H_
+
+#include <bitset>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace autofill {
+
+// A set container with a std::set<T>-like interface for integral or enum types
+// T that have a dense and small representation as unsigned integers.
+//
+// The order of the elements in the container corresponds to their integer
+// representation.
+//
+// The lower and upper bounds of elements storable in a container are
+// [T(0), kEnd).
+//
+// Internally, the set is represented as a std::bitset.
+//
+// Time and space complexity depend on std::bitset:
+// - insert(), erase(), contains() should run in time O(1)
+// - empty(), size(), iteration should run in time O(kEnd)
+// - sizeof(DenseSet) should be ceil(kEnd / 8) bytes.
+//
+// Iterators are invalidated when the owning container is destructed or moved,
+// or when the element the iterator points to is erased from the container.
+template <typename T, T kEnd>
+class DenseSet {
+ private:
+ using Index = std::make_unsigned_t<T>;
+
+ public:
+ // A bidirectional iterator for the DenseSet.
+ class Iterator {
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = T;
+ using difference_type = std::ptrdiff_t;
+ using pointer = void;
+ using reference = T;
+
+ constexpr Iterator() = default;
+
+ friend bool operator==(const Iterator& a, const Iterator& b) {
+ DCHECK(a.owner_);
+ DCHECK_EQ(a.owner_, b.owner_);
+ return a.index_ == b.index_;
+ }
+
+ friend bool operator!=(const Iterator& a, const Iterator& b) {
+ return !(a == b);
+ }
+
+ T operator*() const {
+ DCHECK(derefenceable());
+ return index_to_value(index_);
+ }
+
+ Iterator& operator++() {
+ ++index_;
+ Skip(kForward);
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ auto that = *this;
+ operator++();
+ return that;
+ }
+
+ Iterator& operator--() {
+ --index_;
+ Skip(kBackward);
+ return *this;
+ }
+
+ Iterator operator--(int) {
+ auto that = *this;
+ operator--();
+ return that;
+ }
+
+ private:
+ friend DenseSet;
+
+ enum Direction { kBackward = -1, kForward = 1 };
+
+ constexpr Iterator(const DenseSet* owner, Index index)
+ : owner_(owner), index_(index) {}
+
+ // Advances the index, starting from the current position, to the next
+ // non-empty one. std::bitset does not offer a find-next-set operation.
+ void Skip(Direction direction) {
+ DCHECK_LE(index_, owner_->max_size());
+ while (index_ < owner_->max_size() && !derefenceable()) {
+ index_ += direction;
+ }
+ }
+
+ bool derefenceable() const {
+ DCHECK_LT(index_, owner_->max_size());
+ return owner_->bitset_.test(index_);
+ }
+
+ const DenseSet* owner_ = nullptr;
+
+ // The current index is in the interval [0, owner_->max_size()].
+ Index index_ = 0;
+ };
+
+ using value_type = T;
+ using iterator = Iterator;
+ using const_iterator = Iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ constexpr DenseSet() = default;
+
+ DenseSet(std::initializer_list<T> init) {
+ for (const auto& x : init) {
+ insert(x);
+ }
+ }
+
+ template <typename InputIt>
+ DenseSet(InputIt first, InputIt last) {
+ for (auto it = first; it != last; ++it) {
+ insert(*it);
+ }
+ }
+
+ friend bool operator==(const DenseSet& a, const DenseSet& b) {
+ return a.bitset_ == b.bitset_;
+ }
+
+ friend bool operator!=(const DenseSet& a, const DenseSet& b) {
+ return !(a == b);
+ }
+
+ // Iterators.
+
+ // Returns an iterator to the beginning.
+ iterator begin() const {
+ const_iterator it(this, 0);
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+ const_iterator cbegin() const { return begin(); }
+
+ // Returns an iterator to the end.
+ iterator end() const { return iterator(this, max_size()); }
+ const_iterator cend() const { return end(); }
+
+ // Returns a reverse iterator to the beginning.
+ reverse_iterator rbegin() const { return reverse_iterator(end()); }
+ const_reverse_iterator crbegin() const { return rbegin(); }
+
+ // Returns a reverse iterator to the end.
+ reverse_iterator rend() const { return reverse_iterator(begin()); }
+ const_reverse_iterator crend() const { return rend(); }
+
+ // Capacity.
+
+ // Returns true if the set is empty, otherwise false.
+ bool empty() const { return bitset_.none(); }
+
+ // Returns the number of elements the set has.
+ size_t size() const { return bitset_.count(); }
+
+ // Returns the maximum number of elements the set can have.
+ size_t max_size() const { return bitset_.size(); }
+
+ // Modifiers.
+
+ // Clears the contents.
+ void clear() { bitset_.reset(); }
+
+ // Inserts value |x| if it is not present yet, and returns an iterator to the
+ // inserted or existing element and a boolean that indicates whether the
+ // insertion took place.
+ std::pair<iterator, bool> insert(T x) {
+ bool contained = contains(x);
+ bitset_.set(value_to_index(x));
+ return {find(x), !contained};
+ }
+
+ // Erases the element whose index matches the index of |x| and returns the
+ // number of erased elements (0 or 1).
+ size_t erase(T x) {
+ bool contained = contains(x);
+ bitset_.reset(value_to_index(x));
+ return contained ? 1 : 0;
+ }
+
+ // Erases the element |*it| and returns an iterator to its successor.
+ iterator erase(const_iterator it) {
+ DCHECK(it.owner_ == this && it.derefenceable());
+ bitset_.reset(it.index_);
+ it.Skip(const_iterator::kForward);
+ return it;
+ }
+
+ // Erases the elements [first,last) and returns |last|.
+ iterator erase(const_iterator first, const_iterator last) {
+ DCHECK(first.owner_ == this && last.owner_ == this);
+ while (first != last) {
+ bitset_.reset(first.index_);
+ ++first;
+ }
+ return last;
+ }
+
+ // Lookup.
+
+ // Returns 1 if |x| is an element, otherwise 0.
+ size_t count(T x) const { return contains(x) ? 1 : 0; }
+
+ // Returns an iterator to the element |x| if it exists, otherwise end().
+ const_iterator find(T x) const {
+ return contains(x) ? const_iterator(this, value_to_index(x)) : cend();
+ }
+
+ // Returns true if |x| is an element, else |false|.
+ bool contains(T x) const { return bitset_.test(value_to_index(x)); }
+
+ // Returns an iterator to the first element not less than the |x|, or end().
+ const_iterator lower_bound(T x) const {
+ const_iterator it(this, value_to_index(x));
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+
+ // Returns an iterator to the first element greater than |x|, or end().
+ const_iterator upper_bound(T x) const {
+ const_iterator it(this, value_to_index(x) + 1);
+ it.Skip(Iterator::kForward);
+ return it;
+ }
+
+ private:
+ friend Iterator;
+
+ struct Wrapper {
+ using type = T;
+ };
+
+ static constexpr Index value_to_index(T x) {
+ DCHECK(index_to_value(0) <= x && x < kEnd);
+ return base::checked_cast<Index>(x);
+ }
+
+ static constexpr T index_to_value(Index i) {
+ DCHECK_LT(i, base::checked_cast<Index>(kEnd));
+ using UnderlyingType =
+ typename std::conditional_t<std::is_enum<T>::value,
+ std::underlying_type<T>, Wrapper>::type;
+ return static_cast<T>(base::checked_cast<UnderlyingType>(i));
+ }
+
+ static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
+ static_assert(index_to_value(0) <= kEnd, "");
+
+ std::bitset<base::checked_cast<Index>(kEnd)> bitset_{};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_COMMON_BITSET_H_
diff --git a/chromium/components/autofill/core/common/dense_set_unittest.cc b/chromium/components/autofill/core/common/dense_set_unittest.cc
new file mode 100644
index 00000000000..c6df3972962
--- /dev/null
+++ b/chromium/components/autofill/core/common/dense_set_unittest.cc
@@ -0,0 +1,484 @@
+// Copyright 2020 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/common/dense_set.h"
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TEST(DenseSet, initialization) {
+ enum class T : size_t {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(s.size(), 0u);
+ EXPECT_EQ(DS(s.begin(), s.end()), s);
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(DS(s.begin(), s.end()), s);
+ EXPECT_EQ(DS(s.cbegin(), s.cend()), s);
+ EXPECT_EQ(DS(s.rbegin(), s.rend()), s);
+ EXPECT_EQ(DS(s.crbegin(), s.crend()), s);
+ EXPECT_EQ(DS({T::Four, T::Two, T::One}), s);
+}
+
+TEST(DenseSet, iterators_begin_end) {
+ enum class T : int {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(std::distance(s.begin(), s.end()), 3);
+
+ {
+ auto it = s.begin();
+ auto x1 = *it++;
+ auto x2 = *it++;
+ auto x3 = *it++;
+ EXPECT_EQ(it, s.end());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.begin();
+ auto x1 = *it;
+ auto x2 = *++it;
+ auto x3 = *++it;
+ EXPECT_NE(it, s.end());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_THAT(s, ::testing::ElementsAre(T::One, T::Two, T::Four));
+}
+
+TEST(DenseSet, iterators_begin_end_reverse) {
+ enum class T : char {
+ One = 1,
+ Two = 2,
+ Three = 3,
+ Four = 4,
+ Five = 5,
+ kEnd = 6
+ };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+
+ {
+ auto it = s.end();
+ it--;
+ auto x3 = *it--;
+ auto x2 = *it--;
+ auto x1 = *it;
+ EXPECT_EQ(it, s.begin());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.end();
+ auto x3 = *--it;
+ auto x2 = *--it;
+ auto x1 = *--it;
+ EXPECT_EQ(it, s.begin());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+}
+
+TEST(DenseSet, iterators_rbegin_rend) {
+ enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(std::distance(s.rbegin(), s.rend()), 3);
+
+ {
+ auto it = s.rbegin();
+ auto x3 = *it++;
+ auto x2 = *it++;
+ auto x1 = *it++;
+ EXPECT_EQ(it, s.rend());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.rbegin();
+ auto x3 = *it;
+ auto x2 = *++it;
+ auto x1 = *++it;
+ EXPECT_NE(it, s.rend());
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_THAT(std::vector<T>(s.rbegin(), s.rend()),
+ ::testing::ElementsAre(T::Four, T::Two, T::One));
+}
+
+TEST(DenseSet, lookup) {
+ enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+
+ EXPECT_FALSE(s.contains(static_cast<T>(0)));
+ EXPECT_TRUE(s.contains(T::One));
+ EXPECT_TRUE(s.contains(T::Two));
+ EXPECT_FALSE(s.contains(T::Three));
+ EXPECT_TRUE(s.contains(T::Four));
+ EXPECT_FALSE(s.contains(T::Five));
+
+ EXPECT_EQ(s.contains(static_cast<T>(0)), 0u);
+ EXPECT_EQ(s.contains(T::One), 1u);
+ EXPECT_EQ(s.contains(T::Two), 1u);
+ EXPECT_EQ(s.contains(T::Three), 0u);
+ EXPECT_EQ(s.contains(T::Four), 1u);
+ EXPECT_EQ(s.contains(T::Five), 0u);
+
+ EXPECT_EQ(s.find(static_cast<T>(0)), s.end());
+ EXPECT_NE(s.find(T::One), s.end());
+ EXPECT_NE(s.find(T::Two), s.end());
+ EXPECT_EQ(s.find(T::Three), s.end());
+ EXPECT_NE(s.find(T::Four), s.end());
+ EXPECT_EQ(s.find(T::Five), s.end());
+
+ EXPECT_EQ(*s.find(T::One), T::One);
+ EXPECT_EQ(*s.find(T::Two), T::Two);
+ EXPECT_EQ(*s.find(T::Four), T::Four);
+
+ EXPECT_NE(s.find(static_cast<T>(0)), s.lower_bound(static_cast<T>(0)));
+ EXPECT_EQ(s.find(T::One), s.lower_bound(T::One));
+ EXPECT_EQ(s.find(T::Two), s.lower_bound(T::Two));
+ EXPECT_NE(s.find(T::Three), s.lower_bound(T::Three));
+ EXPECT_EQ(s.find(T::Four), s.lower_bound(T::Four));
+ EXPECT_EQ(s.find(T::Five), s.lower_bound(T::Five));
+}
+
+TEST(DenseSet, iterators_lower_upper_bound) {
+ enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5, kEnd = 6 };
+ using DS = DenseSet<T, T::kEnd>;
+
+ DS s;
+ s.insert(T::Two);
+ s.insert(T::Four);
+ s.insert(T::One);
+ EXPECT_EQ(s.size(), 3u);
+
+ EXPECT_EQ(s.lower_bound(static_cast<T>(0)), s.begin());
+ EXPECT_EQ(s.lower_bound(T::One), s.begin());
+
+ EXPECT_EQ(s.upper_bound(T::Four), s.end());
+ EXPECT_EQ(s.upper_bound(T::Five), s.end());
+
+ {
+ auto it = s.lower_bound(static_cast<T>(0));
+ auto jt = s.upper_bound(static_cast<T>(0));
+ EXPECT_EQ(it, jt);
+ }
+
+ {
+ auto it = s.lower_bound(T::One);
+ auto jt = s.upper_bound(T::One);
+ auto x1 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x1, T::One);
+ }
+
+ {
+ auto it = s.lower_bound(T::Four);
+ auto jt = s.upper_bound(T::Four);
+ auto x3 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.lower_bound(T::Five);
+ auto jt = s.upper_bound(T::Five);
+ EXPECT_EQ(it, jt);
+ }
+
+ {
+ auto it = s.lower_bound(T::One);
+ auto jt = s.upper_bound(T::Five);
+ auto x1 = *it++;
+ auto x2 = *it++;
+ auto x3 = *it++;
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x1, T::One);
+ EXPECT_EQ(x2, T::Two);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ {
+ auto it = s.lower_bound(T::Three);
+ auto jt = s.upper_bound(T::Four);
+ auto x3 = *it++;
+ EXPECT_EQ(jt, s.end());
+ EXPECT_EQ(it, jt);
+ EXPECT_EQ(x3, T::Four);
+ }
+
+ EXPECT_EQ(static_cast<size_t>(std::distance(s.begin(), s.end())), s.size());
+ EXPECT_EQ(std::next(std::next(std::next(s.begin()))), s.end());
+}
+
+TEST(DenseSet, max_size) {
+ const int One = 1;
+ const int Two = 2;
+ // const int Three = 3;
+ const int Four = 4;
+ // const int Five = 5;
+ const int kEnd = 6;
+ using DS = DenseSet<int, kEnd>;
+
+ DS s;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(s.size(), 0u);
+ EXPECT_EQ(s.max_size(), 6u);
+ s.insert(Two);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 1u);
+ s.insert(Four);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 2u);
+ s.insert(One);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(s.max_size(), 6u);
+}
+
+TEST(DenseSet, modifiers) {
+ const size_t One = 1;
+ const size_t Two = 2;
+ const size_t Three = 3;
+ const size_t Four = 4;
+ // const size_t Five = 5;
+ const size_t kEnd = 6;
+ using DS = DenseSet<size_t, kEnd>;
+
+ DS s;
+ s.insert(Two);
+ s.insert(Four);
+ s.insert(One);
+ EXPECT_EQ(s.size(), 3u);
+
+ auto EXPECT_INSERTION = [](auto& set, auto value, bool took_place) {
+ auto it = set.insert(value);
+ EXPECT_EQ(it, std::make_pair(set.find(value), took_place));
+ };
+
+ DS t;
+ EXPECT_NE(s, t);
+ EXPECT_INSERTION(t, Two, true);
+ EXPECT_INSERTION(t, Two, false);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_INSERTION(t, Four, false);
+ EXPECT_INSERTION(t, One, true);
+ EXPECT_INSERTION(t, One, false);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_INSERTION(t, Three, true);
+ EXPECT_INSERTION(t, Three, false);
+ EXPECT_EQ(t.erase(Three), 1u);
+ EXPECT_EQ(t.erase(Three), 0u);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(One), 1u);
+ EXPECT_EQ(t.erase(Four), 1u);
+ EXPECT_NE(s, t);
+ EXPECT_EQ(s.size(), 2u);
+ EXPECT_EQ(t.size(), 2u);
+
+ EXPECT_INSERTION(s, One, true);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(s.find(One)), s.find(Two));
+ EXPECT_EQ(t.erase(t.lower_bound(One), t.upper_bound(One)), t.find(Two));
+ EXPECT_FALSE(s.contains(One));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 2u);
+ EXPECT_EQ(t.size(), 2u);
+
+ EXPECT_INSERTION(s, One, true);
+ EXPECT_INSERTION(t, One, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ EXPECT_EQ(s.erase(s.find(Two), s.end()), s.end());
+ EXPECT_EQ(t.erase(t.lower_bound(Two), t.upper_bound(Four)), t.end());
+ EXPECT_TRUE(s.contains(One));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 1u);
+ EXPECT_EQ(t.size(), 1u);
+
+ EXPECT_INSERTION(s, Two, true);
+ EXPECT_INSERTION(t, Two, true);
+ EXPECT_INSERTION(s, Four, true);
+ EXPECT_INSERTION(t, Four, true);
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+
+ s.clear();
+ EXPECT_EQ(s, DS());
+ EXPECT_EQ(s.size(), 0u);
+
+ EXPECT_INSERTION(s, *t.begin(), true);
+ EXPECT_TRUE(s.contains(One));
+ EXPECT_INSERTION(s, *std::next(t.begin()), true);
+ EXPECT_TRUE(s.contains(Two));
+ EXPECT_INSERTION(s, *std::prev(t.end()), true);
+ EXPECT_TRUE(s.contains(Four));
+ EXPECT_EQ(s, t);
+ EXPECT_EQ(s.size(), 3u);
+ EXPECT_EQ(t.size(), 3u);
+}
+
+TEST(DenseSet, std_set) {
+ constexpr size_t kEnd = 50;
+ DenseSet<size_t, kEnd> dense_set;
+ std::set<size_t> std_set;
+
+ auto expect_equivalence = [&] {
+ EXPECT_EQ(dense_set.empty(), std_set.empty());
+ EXPECT_EQ(dense_set.size(), std_set.size());
+ EXPECT_TRUE(base::ranges::equal(dense_set, std_set));
+ };
+
+ auto random_insert = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ auto p = dense_set.insert(value);
+ auto q = std_set.insert(value);
+ EXPECT_EQ(p.second, q.second);
+ EXPECT_EQ(p.first == dense_set.end(), q.first == std_set.end());
+ EXPECT_TRUE(!p.second || p.first == dense_set.find(value));
+ EXPECT_TRUE(!q.second || q.first == std_set.find(value));
+ };
+
+ auto random_erase = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ EXPECT_EQ(dense_set.erase(value), std_set.erase(value));
+ };
+
+ auto random_erase_iterator = [&] {
+ expect_equivalence();
+ size_t value = base::RandUint64() % kEnd;
+ auto it = dense_set.find(value);
+ auto jt = std_set.find(value);
+ EXPECT_EQ(it == dense_set.end(), jt == std_set.end());
+ if (it == dense_set.end() || jt == std_set.end())
+ return;
+ auto succ_it = dense_set.erase(it);
+ auto succ_jt = std_set.erase(jt);
+ EXPECT_EQ(succ_it == dense_set.end(), succ_jt == std_set.end());
+ EXPECT_TRUE(succ_it == dense_set.upper_bound(value));
+ EXPECT_TRUE(succ_jt == std_set.upper_bound(value));
+ EXPECT_TRUE(succ_it == dense_set.end() || *succ_it == *succ_jt);
+ };
+
+ auto random_erase_range = [&] {
+ expect_equivalence();
+ size_t min_value = base::RandUint64() % kEnd;
+ size_t max_value = base::RandUint64() % kEnd;
+ min_value = std::min(min_value, max_value);
+ max_value = std::max(min_value, max_value);
+ dense_set.erase(dense_set.lower_bound(min_value),
+ dense_set.upper_bound(max_value));
+ std_set.erase(std_set.lower_bound(min_value),
+ std_set.upper_bound(max_value));
+ };
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd / 2; ++i) {
+ random_erase();
+ }
+
+ expect_equivalence();
+ dense_set.clear();
+ std_set.clear();
+ expect_equivalence();
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_erase_iterator();
+ }
+
+ expect_equivalence();
+ dense_set.clear();
+ std_set.clear();
+ expect_equivalence();
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_insert();
+ }
+
+ for (size_t i = 0; i < kEnd; ++i) {
+ random_erase_range();
+ }
+
+ expect_equivalence();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc
index 0f9e6c349d5..961e66e457b 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer.cc
+++ b/chromium/components/autofill/core/common/logging/log_buffer.cc
@@ -76,7 +76,7 @@ bool TryCoalesceString(std::vector<base::Value>* buffer,
base::Value CreateEmptyFragment() {
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("fragment"));
+ storage.try_emplace("type", "fragment");
return base::Value(storage);
}
@@ -115,9 +115,8 @@ LogBuffer& operator<<(LogBuffer& buf, Tag&& tag) {
return buf;
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("element"));
- storage.try_emplace("value",
- std::make_unique<base::Value>(std::move(tag.name)));
+ storage.try_emplace("type", "element");
+ storage.try_emplace("value", std::move(tag.name));
buf.buffer_.emplace_back(std::move(storage));
return buf;
}
@@ -148,8 +147,7 @@ LogBuffer& operator<<(LogBuffer& buf, Attrib&& attrib) {
base::Value(std::move(attrib.value)));
} else {
base::Value::DictStorage dict;
- dict.try_emplace(std::move(attrib.name),
- std::make_unique<base::Value>(std::move(attrib.value)));
+ dict.try_emplace(std::move(attrib.name), std::move(attrib.value));
node.SetKey("attributes", base::Value(std::move(dict)));
}
@@ -173,10 +171,10 @@ LogBuffer& operator<<(LogBuffer& buf, base::StringPiece text) {
return buf;
base::Value::DictStorage storage;
- storage.try_emplace("type", std::make_unique<base::Value>("text"));
+ storage.try_emplace("type", "text");
// This text is not HTML escaped because the rest of the frame work takes care
// of that and it must not be escaped twice.
- storage.try_emplace("value", std::make_unique<base::Value>(text));
+ storage.try_emplace("value", text);
base::Value node_to_add(std::move(storage));
AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
return buf;
diff --git a/chromium/components/autofill/core/common/mojom/BUILD.gn b/chromium/components/autofill/core/common/mojom/BUILD.gn
index 4c3ab8abd86..12cc7be0213 100644
--- a/chromium/components/autofill/core/common/mojom/BUILD.gn
+++ b/chromium/components/autofill/core/common/mojom/BUILD.gn
@@ -72,10 +72,6 @@ mojom("mojo_types") {
mojom = "autofill.mojom.PasswordGenerationUIData"
cpp = "::autofill::password_generation::PasswordGenerationUIData"
},
- {
- mojom = "autofill.mojom.ValueElementPair"
- cpp = "::autofill::ValueElementPair"
- },
]
traits_headers = [ "autofill_types_mojom_traits.h" ]
traits_sources = [ "autofill_types_mojom_traits.cc" ]
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types.mojom b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
index 6ad1a8fc233..4c35cd75787 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/chromium/components/autofill/core/common/mojom/autofill_types.mojom
@@ -27,19 +27,7 @@ enum SubmissionIndicatorEvent {
// DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD,
// DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD,
PROBABLE_FORM_SUBMISSION = 10,
-};
-
-// This enum lists form field types as understood by the password manager,
-// essentially a digest of |autofill::ServerFieldType|. Note that we cannot
-// simply reuse |autofill::ServerFieldType| as it is defined in the browser,
-// while this enum will be used by both the browser and renderer.
-// TODO(https://crbug.com/1067347): move this enum to browser code. It is not
-// used in Mojo anymore.
-enum PasswordFormFieldPredictionType {
- kUsername,
- kCurrentPassword,
- kNewPassword,
- kNotPassword,
+ CHANGE_PASSWORD_FORM_CLEARED = 11,
};
enum SubmissionSource {
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
index bc85d1db9f7..5b9b8780e67 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
@@ -23,8 +23,6 @@
namespace autofill {
-using mojom::PasswordFormFieldPredictionType;
-
const std::vector<const char*> kOptions = {"Option1", "Option2", "Option3",
"Option4"};
namespace {
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
deleted file mode 100644
index 3d3e786a73a..00000000000
--- a/chromium/components/autofill/core/common/password_form.h
+++ /dev/null
@@ -1,388 +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_COMMON_PASSWORD_FORM_H__
-#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/time/time.h"
-#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/gaia_id_hash.h"
-#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
-#include "components/autofill/core/common/renderer_id.h"
-#include "url/gurl.h"
-#include "url/origin.h"
-
-namespace autofill {
-
-// Pair of a value and the name of the element that contained this value.
-using ValueElementPair = std::pair<base::string16, base::string16>;
-
-// Vector of possible username values and corresponding field names.
-using ValueElementVector = std::vector<ValueElementPair>;
-
-// The PasswordForm struct encapsulates information about a login form,
-// which can be an HTML form or a dialog with username/password text fields.
-//
-// The Web Data database stores saved username/passwords and associated form
-// metdata using a PasswordForm struct, typically one that was created from
-// a parsed HTMLFormElement or LoginDialog, but the saved entries could have
-// also been created by imported data from another browser.
-//
-// The PasswordManager implements a fuzzy-matching algorithm to compare saved
-// PasswordForm entries against PasswordForms that were created from a parsed
-// HTML or dialog form. As one might expect, the more data contained in one
-// of the saved PasswordForms, the better the job the PasswordManager can do
-// in matching it against the actual form it was saved on, and autofill
-// accurately. But it is not always possible, especially when importing from
-// other browsers with different data models, to copy over all the information
-// about a particular "saved password entry" to our PasswordForm
-// representation.
-//
-// The field descriptions in the struct specification below are intended to
-// describe which fields are not strictly required when adding a saved password
-// entry to the database and how they can affect the matching process.
-//
-// TODO(crbug.com/1067347): Move complete class to password_manager namespace.
-struct PasswordForm {
- // Enum to differentiate between HTML form based authentication, and dialogs
- // using basic or digest schemes. Default is kHtml. Only PasswordForms of the
- // same Scheme will be matched/autofilled against each other.
- enum class Scheme {
- kHtml,
- kBasic,
- kDigest,
- kOther,
- kUsernameOnly,
- kMinValue = kHtml,
- kMaxValue = kUsernameOnly,
- };
-
- // Enum to differentiate between manually filled forms, forms with auto-
- // generated passwords, and forms generated from the DOM API.
- //
- // Always append new types at the end. This enum is converted to int and
- // stored in password store backends, so it is important to keep each
- // value assigned to the same integer.
- enum class Type {
- kManual,
- kGenerated,
- kApi,
- kMinValue = kManual,
- kMaxValue = kApi,
- };
-
- // Enum to keep track of what information has been sent to the server about
- // this form regarding password generation.
- enum class GenerationUploadStatus {
- kNoSignalSent,
- kPositiveSignalSent,
- kNegativeSignalSent,
- kMinValue = kNoSignalSent,
- kMaxValue = kNegativeSignalSent,
- };
-
- Scheme scheme = Scheme::kHtml;
-
- // The "Realm" for the sign-on. This is scheme, host, port for SCHEME_HTML.
- // Dialog based forms also contain the HTTP realm. Android based forms will
- // contain a string of the form "android://<hash of cert>@<package name>"
- //
- // The signon_realm is effectively the primary key used for retrieving
- // data from the database, so it must not be empty.
- std::string signon_realm;
-
- // An URL consists of the scheme, host, port and path; the rest is stripped.
- // This is the primary data used by the PasswordManager to decide (in longest
- // matching prefix fashion) whether or not a given PasswordForm result from
- // the database is a good fit for a particular form on a page.
- //
- // This should not be empty except for Android based credentials.
- GURL url;
-
- // The action target of the form; like |origin| URL consists of the scheme,
- // host, port and path; the rest is stripped. This is the primary data used by
- // the PasswordManager for form autofill; that is, the action of the saved
- // credentials must match the action of the form on the page to be autofilled.
- // If this is empty / not available, it will result in a "restricted" IE-like
- // autofill policy, where we wait for the user to type in their username
- // before autofilling the password. In these cases, after successful login the
- // action URL will automatically be assigned by the PasswordManager.
- //
- // When parsing an HTML form, this must always be set.
- GURL action;
-
- // The web realm affiliated with the Android application, if the form is an
- // Android credential. Otherwise, the string is empty. If there are several
- // realms affiliated with the application, an arbitrary realm is chosen. The
- // field is filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the string is empty.
- std::string affiliated_web_realm;
-
- // The display name (e.g. Play Store name) of the Android application if the
- // form is an Android credential. Otherwise, the string is empty. The field is
- // filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the string is empty.
- std::string app_display_name;
-
- // The icon URL (e.g. Play Store icon URL) of the Android application if the
- // form is an Android credential. Otherwise, the URL is empty. The field is
- // filled out when the PasswordStore injects affiliation and branding
- // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
- // no prior call to this method, the URL is empty.
- GURL app_icon_url;
-
- // The name of the submit button used. Optional; only used in scoring
- // of PasswordForm results from the database to make matches as tight as
- // possible.
- base::string16 submit_element;
-
- // The name of the username input element.
- base::string16 username_element;
-
- // The renderer id of the username input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId username_element_renderer_id;
-
- // True if the server-side classification was successful.
- bool server_side_classification_successful = false;
-
- // True if the server-side classification believes that the field may be
- // pre-filled with a placeholder in the value attribute. It is set during
- // form parsing and not persisted.
- bool username_may_use_prefilled_placeholder = false;
-
- // When parsing an HTML form, this is typically empty unless the site
- // has implemented some form of autofill.
- base::string16 username_value;
-
- // This member is populated in cases where we there are multiple input
- // elements that could possibly be the username. Used when our heuristics for
- // determining the username are incorrect. Optional.
- ValueElementVector all_possible_usernames;
-
- // This member is populated in cases where we there are multiple possible
- // password values. Used in pending password state, to populate a dropdown
- // for possible passwords. Contains all possible passwords. Optional.
- ValueElementVector all_possible_passwords;
-
- // True if |all_possible_passwords| have autofilled value or its part.
- bool form_has_autofilled_value = false;
-
- // The name of the input element corresponding to the current password.
- // Optional (improves scoring).
- //
- // When parsing an HTML form, this will always be set, unless it is a sign-up
- // form or a change password form that does not ask for the current password.
- // In these two cases the |new_password_element| will always be set.
- base::string16 password_element;
-
- // The renderer id of the password input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId password_element_renderer_id;
-
- // The current password. Must be non-empty for PasswordForm instances that are
- // meant to be persisted to the password store.
- //
- // When parsing an HTML form, this is typically empty.
- base::string16 password_value;
-
- // The current encrypted password. Must be non-empty for PasswordForm
- // instances retrieved from the password store or coming in a
- // PasswordStoreChange that is not of type REMOVE.
- std::string encrypted_password;
-
- // If the form was a sign-up or a change password form, the name of the input
- // element corresponding to the new password. Optional, and not persisted.
- base::string16 new_password_element;
-
- // The renderer id of the new password input element. It is set during the new
- // form parsing and not persisted.
- FieldRendererId new_password_element_renderer_id;
-
- // The confirmation password element. Optional, only set on form parsing, and
- // not persisted.
- base::string16 confirmation_password_element;
-
- // The renderer id of the confirmation password input element. It is set
- // during the new form parsing and not persisted.
- FieldRendererId confirmation_password_element_renderer_id;
-
- // The new password. Optional, and not persisted.
- base::string16 new_password_value;
-
- // When the login was last used by the user to login to the site. Defaults to
- // |date_created|, except for passwords that were migrated from the now
- // deprecated |preferred| flag. Their default is set when migrating the login
- // database to have the "date_last_used" column.
- //
- // When parsing an HTML form, this is not used.
- base::Time date_last_used;
-
- // When the login was saved (by chrome).
- //
- // When parsing an HTML form, this is not used.
- base::Time date_created;
-
- // When the login was downloaded from the sync server. For local passwords is
- // not used.
- //
- // When parsing an HTML form, this is not used.
- base::Time date_synced;
-
- // Tracks if the user opted to never remember passwords for this form. Default
- // to false.
- //
- // When parsing an HTML form, this is not used.
- bool blocked_by_user = false;
-
- // The form type.
- Type type = Type::kManual;
-
- // The number of times that this username/password has been used to
- // authenticate the user.
- //
- // When parsing an HTML form, this is not used.
- int times_used = 0;
-
- // Autofill representation of this form. Used to communicate with the
- // Autofill servers if necessary. Currently this is only used to help
- // determine forms where we can trigger password generation.
- //
- // When parsing an HTML form, this is normally set.
- FormData form_data;
-
- // What information has been sent to the Autofill server about this form.
- GenerationUploadStatus generation_upload_status =
- GenerationUploadStatus::kNoSignalSent;
-
- // These following fields are set by a website using the Credential Manager
- // API. They will be empty and remain unused for sites which do not use that
- // API.
- //
- // User friendly name to show in the UI.
- base::string16 display_name;
-
- // The URL of this credential's icon, such as the user's avatar, to display
- // in the UI.
- GURL icon_url;
-
- // The origin of identity provider used for federated login.
- url::Origin federation_origin;
-
- // If true, Chrome will not return this credential to a site in response to
- // 'navigator.credentials.request()' without user interaction.
- // Once user selects this credential the flag is reseted.
- bool skip_zero_click = false;
-
- // If true, this form was parsed using Autofill predictions.
- bool was_parsed_using_autofill_predictions = false;
-
- // If true, this match was found using public suffix matching.
- bool is_public_suffix_match = false;
-
- // If true, this is a credential saved through an Android application, and
- // found using affiliation-based match.
- bool is_affiliation_based_match = false;
-
- // The type of the event that was taken as an indication that this form is
- // being or has already been submitted. This field is not persisted and filled
- // out only for submitted forms.
- mojom::SubmissionIndicatorEvent submission_event =
- mojom::SubmissionIndicatorEvent::NONE;
-
- // True iff heuristics declined this form for normal saving or filling (e.g.
- // only credit card fields were found). But this form can be saved or filled
- // only with the fallback.
- bool only_for_fallback = false;
-
- // True iff the new password field was found with server hints or autocomplete
- // attributes. Only set on form parsing for filling, and not persisted. Used
- // as signal for password generation eligibility.
- bool is_new_password_reliable = false;
-
- // Serialized to prefs, so don't change numeric values!
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
- enum class Store {
- // Default value.
- kNotSet = 0,
- // Credential came from the profile (i.e. local) storage.
- kProfileStore = 1,
- // Credential came from the Gaia-account-scoped storage.
- kAccountStore = 2,
- kMaxValue = kAccountStore
- };
- Store in_store = Store::kNotSet;
-
- // Vector of hashes of the gaia id for users who prefer not to move this
- // password form to their account. This list is used to suppress the move
- // prompt for those users.
- std::vector<GaiaIdHash> moving_blocked_for_list;
-
- // Return true if we consider this form to be a change password form.
- // We use only client heuristics, so it could include signup forms.
- bool IsPossibleChangePasswordForm() const;
-
- // Return true if we consider this form to be a change password form
- // without username field. We use only client heuristics, so it could
- // include signup forms.
- bool IsPossibleChangePasswordFormWithoutUsername() const;
-
- // Returns true if current password element is set.
- bool HasUsernameElement() const;
-
- // Returns true if current password element is set.
- bool HasPasswordElement() const;
-
- // Returns true if current password element is set.
- bool HasNewPasswordElement() const;
-
- // True iff |federation_origin| isn't empty.
- bool IsFederatedCredential() const;
-
- // True if username element is set and password and new password elements are
- // not set.
- bool IsSingleUsername() const;
-
- // Returns whether this form is stored in the account-scoped store, i.e.
- // whether |in_store == Store::kAccountStore|.
- bool IsUsingAccountStore() const;
-
- // Returns true when |password_value| or |new_password_value| are non-empty.
- bool HasNonEmptyPasswordValue() const;
-
- // Equality operators for testing.
- bool operator==(const PasswordForm& form) const;
- bool operator!=(const PasswordForm& form) const;
-
- PasswordForm();
- PasswordForm(const PasswordForm& other);
- PasswordForm(PasswordForm&& other);
- ~PasswordForm();
-
- PasswordForm& operator=(const PasswordForm& form);
- PasswordForm& operator=(PasswordForm&& form);
-};
-
-// True if the unique keys for the forms are the same. The unique key is
-// (origin, username_element, username_value, password_element, signon_realm).
-bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
- const PasswordForm& right);
-
-// For testing.
-std::ostream& operator<<(std::ostream& os, PasswordForm::Scheme scheme);
-std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
-std::ostream& operator<<(std::ostream& os, PasswordForm* form);
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index 36f83ca6b03..93081879d5d 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -9,7 +9,6 @@
#include <vector>
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/renderer_id.h"
namespace autofill {
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.cc b/chromium/components/autofill/core/common/password_form_generation_data.cc
deleted file mode 100644
index 04cccb19fbb..00000000000
--- a/chromium/components/autofill/core/common/password_form_generation_data.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 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.
-
-#include "components/autofill/core/common/password_form_generation_data.h"
-
-#include <utility>
-
-namespace autofill {
-
-PasswordFormGenerationData::PasswordFormGenerationData() = default;
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id)
- : new_password_renderer_id(new_password_renderer_id),
- confirmation_password_renderer_id(confirmation_password_renderer_id) {}
-
-#if defined(OS_IOS)
-PasswordFormGenerationData::PasswordFormGenerationData(
- FormRendererId form_renderer_id,
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id)
- : form_renderer_id(form_renderer_id),
- new_password_renderer_id(new_password_renderer_id),
- confirmation_password_renderer_id(confirmation_password_renderer_id) {}
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- const PasswordFormGenerationData&) = default;
-
-PasswordFormGenerationData& PasswordFormGenerationData::operator=(
- const PasswordFormGenerationData&) = default;
-
-PasswordFormGenerationData::PasswordFormGenerationData(
- PasswordFormGenerationData&&) = default;
-
-PasswordFormGenerationData& PasswordFormGenerationData::operator=(
- PasswordFormGenerationData&&) = default;
-
-PasswordFormGenerationData::~PasswordFormGenerationData() = default;
-
-#endif
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h
index 2618629d47a..7c22909ac82 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -5,32 +5,15 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_GENERATION_DATA_H_
-#include <stdint.h>
-
-#include "base/optional.h"
#include "build/build_config.h"
#include "components/autofill/core/common/renderer_id.h"
-#include "url/gurl.h"
namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
- PasswordFormGenerationData();
- PasswordFormGenerationData(FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id);
#if defined(OS_IOS)
- PasswordFormGenerationData(FormRendererId form_renderer_id,
- FieldRendererId new_password_renderer_id,
- FieldRendererId confirmation_password_renderer_id);
-
- PasswordFormGenerationData(const PasswordFormGenerationData&);
- PasswordFormGenerationData& operator=(const PasswordFormGenerationData&);
- PasswordFormGenerationData(PasswordFormGenerationData&&);
- PasswordFormGenerationData& operator=(PasswordFormGenerationData&&);
- ~PasswordFormGenerationData();
-
FormRendererId form_renderer_id;
#endif
FieldRendererId new_password_renderer_id;
diff --git a/chromium/components/autofill/core/common/password_generation_util.h b/chromium/components/autofill/core/common/password_generation_util.h
index 43115bfaae3..abcee73daae 100644
--- a/chromium/components/autofill/core/common/password_generation_util.h
+++ b/chromium/components/autofill/core/common/password_generation_util.h
@@ -5,7 +5,9 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_GENERATION_UTIL_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_GENERATION_UTIL_H_
-#include "components/autofill/core/common/password_form.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "ui/gfx/geometry/rect_f.h"
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index cc87fcd332e..4890a9be31a 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -353,8 +353,8 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Generation disabled: no sync";
case STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE:
return "Generation: automatic generation is available";
- case STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP:
- return "Show generation popup triggered manually";
+ case STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP:
+ return "Show generation popup triggered";
case STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED:
return "Generated password accepted";
case STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT:
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index 2c23c2e54f4..aea961ea912 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -120,7 +120,7 @@ class SavePasswordProgressLogger {
STRING_GENERATION_DISABLED_SAVING_DISABLED,
STRING_GENERATION_DISABLED_NO_SYNC,
STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE,
- STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP,
+ STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP,
STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED,
STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT,
STRING_MAIN_FRAME_ORIGIN,
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
index bce8f456d66..550f2e9479a 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger_unittest.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/password_form.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index 1fcafb96c9f..c33daac5902 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -15,6 +15,7 @@
#include "base/mac/foundation_util.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
@@ -107,7 +108,8 @@ void GetFormField(autofill::FormFieldData* field,
void UpdateFieldManagerWithFillingResults(
scoped_refptr<FieldDataManager> fieldDataManager,
- NSString* jsonString) {
+ NSString* jsonString,
+ size_t numFieldsInFormData) {
std::map<uint32_t, base::string16> fillingResults;
if (autofill::ExtractFillingResults(jsonString, &fillingResults)) {
for (auto& fillData : fillingResults) {
@@ -116,6 +118,8 @@ void UpdateFieldManagerWithFillingResults(
kAutofilledOnUserTrigger);
}
}
+ // TODO(crbug/1131038): Remove once the experiment is over.
+ UMA_HISTOGRAM_BOOLEAN("Autofill.FormFillSuccessIOS", !fillingResults.empty());
}
void UpdateFieldManagerForClearedIDs(
@@ -759,9 +763,9 @@ autofillManagerFromWebState:(web::WebState*)webState
};
// The document has now been fully loaded. Scan for forms to be extracted.
size_t min_required_fields =
- MIN(autofill::MinRequiredFieldsForUpload(),
- MIN(autofill::MinRequiredFieldsForHeuristics(),
- autofill::MinRequiredFieldsForQuery()));
+ MIN(autofill::kMinRequiredFieldsForUpload,
+ MIN(autofill::kMinRequiredFieldsForHeuristics,
+ autofill::kMinRequiredFieldsForQuery));
[self fetchFormsFiltered:NO
withName:base::string16()
minimumRequiredFieldsCount:min_required_fields
@@ -944,6 +948,7 @@ autofillManagerFromWebState:(web::WebState*)webState
SuggestionHandledCompletion suggestionHandledCompletionCopy =
[_suggestionHandledCompletion copy];
_suggestionHandledCompletion = nil;
+ size_t numFieldsInFormData = data->FindPath("fields")->DictSize();
[_jsAutofillManager fillForm:std::move(data)
forceFillFieldIdentifier:SysUTF16ToNSString(_pendingAutocompleteField)
forceFillFieldUniqueID:_pendingAutocompleteFieldID
@@ -953,7 +958,8 @@ autofillManagerFromWebState:(web::WebState*)webState
if (!strongSelf)
return;
UpdateFieldManagerWithFillingResults(
- strongSelf->_fieldDataManager, jsonString);
+ strongSelf->_fieldDataManager, jsonString,
+ numFieldsInFormData);
// It is possible that the fill was not initiated by selecting
// a suggestion in this case the callback is nil.
if (suggestionHandledCompletionCopy)
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index 9948c219d46..f72958bede1 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -175,7 +175,7 @@ net::IsolationInfo AutofillDriverIOS::IsolationInfo() {
return net::IsolationInfo();
return net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
url::Origin::Create(main_web_frame->GetSecurityOrigin()),
url::Origin::Create(web_frame->GetSecurityOrigin()),
net::SiteForCookies());
diff --git a/chromium/components/autofill_assistant/browser/BUILD.gn b/chromium/components/autofill_assistant/browser/BUILD.gn
index 182791b6cbb..81b694594e1 100644
--- a/chromium/components/autofill_assistant/browser/BUILD.gn
+++ b/chromium/components/autofill_assistant/browser/BUILD.gn
@@ -19,7 +19,6 @@ proto_library("proto") {
static_library("browser") {
sources = [
- "access_token_fetcher.h",
"actions/action.cc",
"actions/action.h",
"actions/action_delegate.h",
@@ -39,10 +38,10 @@ static_library("browser") {
"actions/fallback_handler/required_field.h",
"actions/fallback_handler/required_fields_fallback_handler.cc",
"actions/fallback_handler/required_fields_fallback_handler.h",
- "actions/focus_element_action.cc",
- "actions/focus_element_action.h",
"actions/generate_password_for_form_field_action.cc",
"actions/generate_password_for_form_field_action.h",
+ "actions/get_element_status_action.cc",
+ "actions/get_element_status_action.h",
"actions/highlight_element_action.cc",
"actions/highlight_element_action.h",
"actions/navigate_action.cc",
@@ -61,6 +60,8 @@ static_library("browser") {
"actions/set_attribute_action.h",
"actions/set_form_field_value_action.cc",
"actions/set_form_field_value_action.h",
+ "actions/show_cast_action.cc",
+ "actions/show_cast_action.h",
"actions/show_details_action.cc",
"actions/show_details_action.h",
"actions/show_form_action.cc",
@@ -73,6 +74,8 @@ static_library("browser") {
"actions/show_progress_bar_action.h",
"actions/stop_action.cc",
"actions/stop_action.h",
+ "actions/stopwatch.cc",
+ "actions/stopwatch.h",
"actions/tell_action.cc",
"actions/tell_action.h",
"actions/unsupported_action.cc",
@@ -89,6 +92,8 @@ static_library("browser") {
"actions/wait_for_dom_action.h",
"actions/wait_for_navigation_action.cc",
"actions/wait_for_navigation_action.h",
+ "autofill_assistant_onboarding_fetcher.cc",
+ "autofill_assistant_onboarding_fetcher.h",
"basic_interactions.cc",
"basic_interactions.h",
"batch_element_checker.cc",
@@ -129,12 +134,9 @@ static_library("browser") {
"generic_ui_replace_placeholders.h",
"info_box.cc",
"info_box.h",
- "lite_service.cc",
- "lite_service.h",
- "lite_service_util.cc",
- "lite_service_util.h",
"metrics.cc",
"metrics.h",
+ "onboarding_result.h",
"overlay_state.h",
"protocol_utils.cc",
"protocol_utils.h",
@@ -157,9 +159,26 @@ static_library("browser") {
"selector.h",
"self_delete_full_card_requester.cc",
"self_delete_full_card_requester.h",
- "service.h",
- "service_impl.cc",
- "service_impl.h",
+ "service/access_token_fetcher.h",
+ "service/api_key_fetcher.cc",
+ "service/api_key_fetcher.h",
+ "service/lite_service.cc",
+ "service/lite_service.h",
+ "service/lite_service_util.cc",
+ "service/lite_service_util.h",
+ "service/server_url_fetcher.cc",
+ "service/server_url_fetcher.h",
+ "service/service.h",
+ "service/service_impl.cc",
+ "service/service_impl.h",
+ "service/service_request_sender.cc",
+ "service/service_request_sender.h",
+ "service/service_request_sender_impl.cc",
+ "service/service_request_sender_impl.h",
+ "service/service_request_sender_local_impl.cc",
+ "service/service_request_sender_local_impl.h",
+ "service/simple_url_loader_factory.cc",
+ "service/simple_url_loader_factory.h",
"state.h",
"string_conversions_util.cc",
"string_conversions_util.h",
@@ -169,7 +188,17 @@ static_library("browser") {
"top_padding.h",
"trigger_context.cc",
"trigger_context.h",
+ "trigger_scripts/dynamic_trigger_conditions.cc",
+ "trigger_scripts/dynamic_trigger_conditions.h",
+ "trigger_scripts/static_trigger_conditions.cc",
+ "trigger_scripts/static_trigger_conditions.h",
+ "trigger_scripts/trigger_script.cc",
+ "trigger_scripts/trigger_script.h",
+ "trigger_scripts/trigger_script_coordinator.cc",
+ "trigger_scripts/trigger_script_coordinator.h",
"ui_delegate.h",
+ "url_utils.cc",
+ "url_utils.h",
"user_action.cc",
"user_action.h",
"user_data.cc",
@@ -181,12 +210,18 @@ static_library("browser") {
"value_util.cc",
"value_util.h",
"viewport_mode.h",
+ "wait_for_document_operation.cc",
+ "wait_for_document_operation.h",
+ "web/check_on_top_worker.cc",
+ "web/check_on_top_worker.h",
"web/element_finder.cc",
"web/element_finder.h",
"web/element_position_getter.cc",
"web/element_position_getter.h",
"web/element_rect_getter.cc",
"web/element_rect_getter.h",
+ "web/js_snippets.cc",
+ "web/js_snippets.h",
"web/web_controller.cc",
"web/web_controller.h",
"web/web_controller_util.cc",
@@ -207,15 +242,19 @@ static_library("browser") {
"//components/autofill_assistant/browser/devtools",
"//components/autofill_assistant/browser/public:public",
"//components/google/core/common:common",
+ "//components/keyed_service/core",
"//components/password_manager/content/browser:browser",
"//components/password_manager/core/browser:browser",
"//components/password_manager/core/browser/form_parsing:form_parsing",
"//components/signin/public/identity_manager",
"//components/strings:components_strings_grit",
+ "//components/ukm/content:content",
"//components/version_info",
"//content/public/browser",
"//google_apis",
"//net",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//third_party/re2",
]
}
@@ -233,12 +272,12 @@ static_library("unit_test_support") {
"mock_controller_observer.h",
"mock_personal_data_manager.cc",
"mock_personal_data_manager.h",
- "mock_service.cc",
- "mock_service.h",
"mock_user_model_observer.cc",
"mock_user_model_observer.h",
"mock_website_login_manager.cc",
"mock_website_login_manager.h",
+ "service/mock_service.cc",
+ "service/mock_service.h",
"web/mock_web_controller.cc",
"web/mock_web_controller.h",
]
@@ -261,11 +300,14 @@ source_set("unit_tests") {
"actions/action_delegate_util_unittest.cc",
"actions/action_test_utils.cc",
"actions/action_test_utils.h",
+ "actions/action_unittest.cc",
"actions/click_action_unittest.cc",
"actions/collect_user_data_action_unittest.cc",
"actions/configure_bottom_sheet_action_unittest.cc",
"actions/fallback_handler/required_fields_fallback_handler_unittest.cc",
"actions/generate_password_for_form_field_action_unittest.cc",
+ "actions/get_element_status_action_unittest.cc",
+ "actions/highlight_element_action_unittest.cc",
"actions/popup_message_action_unittest.cc",
"actions/presave_generated_password_action_unittest.cc",
"actions/prompt_action_unittest.cc",
@@ -273,17 +315,22 @@ source_set("unit_tests") {
"actions/select_option_action_unittest.cc",
"actions/set_attribute_action_unittest.cc",
"actions/set_form_field_value_action_unittest.cc",
+ "actions/show_cast_action_unittest.cc",
"actions/show_details_action_unittest.cc",
"actions/show_generic_ui_action_unittest.cc",
"actions/show_progress_bar_action_unittest.cc",
+ "actions/stopwatch_unittest.cc",
"actions/tell_action_unittest.cc",
+ "actions/upload_dom_action_unittest.cc",
"actions/use_address_action_unittest.cc",
"actions/use_credit_card_action_unittest.cc",
"actions/wait_for_document_action_unittest.cc",
"actions/wait_for_dom_action_unittest.cc",
+ "autofill_assistant_onboarding_fetcher_unittest.cc",
"basic_interactions_unittest.cc",
"batch_element_checker_unittest.cc",
"client_context_unittest.cc",
+ "client_settings_unittest.cc",
"controller_unittest.cc",
"details_unittest.cc",
"element_area_unittest.cc",
@@ -291,8 +338,8 @@ source_set("unit_tests") {
"event_handler_unittest.cc",
"field_formatter_unittest.cc",
"generic_ui_replace_placeholders_unittest.cc",
- "lite_service_unittest.cc",
- "lite_service_util_unittest.cc",
+ "mock_client_context.cc",
+ "mock_client_context.h",
"protocol_utils_unittest.cc",
"radio_button_controller_unittest.cc",
"retry_timer_unittest.cc",
@@ -300,13 +347,38 @@ source_set("unit_tests") {
"script_precondition_unittest.cc",
"script_tracker_unittest.cc",
"selector_unittest.cc",
+ "service/api_key_fetcher_unittest.cc",
+ "service/lite_service_unittest.cc",
+ "service/lite_service_util_unittest.cc",
+ "service/mock_access_token_fetcher.cc",
+ "service/mock_access_token_fetcher.h",
+ "service/mock_service_request_sender.cc",
+ "service/mock_service_request_sender.h",
+ "service/mock_simple_url_loader_factory.cc",
+ "service/mock_simple_url_loader_factory.h",
+ "service/mock_url_loader.cc",
+ "service/mock_url_loader.h",
+ "service/server_url_fetcher_unittest.cc",
+ "service/service_impl_unittest.cc",
+ "service/service_request_sender_impl_unittest.cc",
+ "service/service_request_sender_local_impl_unittest.cc",
"string_conversions_util_unittest.cc",
"test_util.cc",
"test_util.h",
"trigger_context_unittest.cc",
+ "trigger_scripts/dynamic_trigger_conditions_unittest.cc",
+ "trigger_scripts/mock_dynamic_trigger_conditions.cc",
+ "trigger_scripts/mock_dynamic_trigger_conditions.h",
+ "trigger_scripts/mock_static_trigger_conditions.cc",
+ "trigger_scripts/mock_static_trigger_conditions.h",
+ "trigger_scripts/static_trigger_conditions_unittest.cc",
+ "trigger_scripts/trigger_script_coordinator_unittest.cc",
+ "trigger_scripts/trigger_script_unittest.cc",
+ "url_utils_unittest.cc",
"user_data_util_unittest.cc",
"user_model_unittest.cc",
"value_util_unittest.cc",
+ "wait_for_document_operation_unittest.cc",
"website_login_manager_impl_unittest.cc",
]
@@ -321,8 +393,11 @@ source_set("unit_tests") {
"//components/password_manager/core/browser:test_support",
"//components/password_manager/core/common",
"//components/strings:components_strings_grit",
+ "//components/ukm:test_support",
+ "//components/ukm/content:content",
"//components/version_info",
"//content/test:test_support",
+ "//services/network:test_support",
"//testing/gmock",
"//testing/gtest",
"//third_party/re2",
@@ -357,7 +432,9 @@ if (is_android) {
sources = [
"generic_ui_java_generated_enums.h",
"metrics.h",
+ "onboarding_result.h",
"overlay_state.h",
+ "trigger_scripts/trigger_script_action.h",
"user_data.h",
"viewport_mode.h",
]
@@ -366,8 +443,10 @@ if (is_android) {
static_library("test_support") {
testonly = true
sources = [
- "java_service.cc",
- "java_service.h",
+ "service/java_service.cc",
+ "service/java_service.h",
+ "service/java_service_request_sender.cc",
+ "service/java_service_request_sender.h",
]
deps = [
@@ -375,6 +454,7 @@ if (is_android) {
":proto",
"//base",
"//chrome/android/features/autofill_assistant:test_support_jni_headers",
+ "//net",
"//url:url",
]
}
diff --git a/chromium/components/autofill_assistant/browser/DEPS b/chromium/components/autofill_assistant/browser/DEPS
index ff90e40566d..17e690dd23e 100644
--- a/chromium/components/autofill_assistant/browser/DEPS
+++ b/chromium/components/autofill_assistant/browser/DEPS
@@ -2,9 +2,11 @@ include_rules = [
"+chrome/android/features/autofill_assistant/test_support_jni_headers",
"+components/autofill",
"+components/google/core/common",
+ "+components/keyed_service/core",
"+components/password_manager/content/browser",
"+components/password_manager/core/browser",
"+components/password_manager/core/common",
+ "+components/ukm",
"+components/version_info",
"+content/public/browser",
"+content/public/test",
@@ -14,7 +16,10 @@ include_rules = [
"+crypto",
"+google_apis",
"+net",
+ "+services/metrics/public",
"+services/network/public/cpp",
+ "+services/network/public/mojom",
+ "+services/network/test",
"+third_party/blink/public/mojom/payments/payment_request.mojom.h",
"+third_party/icu/source/common/unicode",
"+third_party/libaddressinput/chromium/addressinput_util.h",
diff --git a/chromium/components/autofill_assistant/browser/actions/action.cc b/chromium/components/autofill_assistant/browser/actions/action.cc
index 6b4ce0ff8fb..c2a842a1b54 100644
--- a/chromium/components/autofill_assistant/browser/actions/action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action.cc
@@ -17,8 +17,27 @@ Action::Action(ActionDelegate* delegate, const ActionProto& proto)
Action::~Action() {}
void Action::ProcessAction(ProcessActionCallback callback) {
+ action_stopwatch_.StartActiveTime();
processed_action_proto_ = std::make_unique<ProcessedActionProto>();
- InternalProcessAction(std::move(callback));
+ InternalProcessAction(base::BindOnce(&Action::RecordActionTimes,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback)));
+}
+
+void Action::RecordActionTimes(
+ ProcessActionCallback callback,
+ std::unique_ptr<ProcessedActionProto> processed_action_proto) {
+ // Record times.
+ action_stopwatch_.Stop();
+
+ processed_action_proto->mutable_timing_stats()->set_delay_ms(
+ proto_.action_delay_ms());
+ processed_action_proto->mutable_timing_stats()->set_active_time_ms(
+ action_stopwatch_.TotalActiveTime().InMilliseconds());
+ processed_action_proto->mutable_timing_stats()->set_wait_time_ms(
+ action_stopwatch_.TotalWaitTime().InMilliseconds());
+
+ std::move(callback).Run(std::move(processed_action_proto));
}
void Action::UpdateProcessedAction(ProcessedActionStatusProto status_proto) {
@@ -31,6 +50,14 @@ void Action::UpdateProcessedAction(const ClientStatus& status) {
status.FillProto(processed_action_proto_.get());
}
+void Action::OnWaitForElementTimed(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& element_status,
+ base::TimeDelta wait_time) {
+ action_stopwatch_.TransferToWaitTime(wait_time);
+ std::move(callback).Run(element_status);
+}
+
// static
std::vector<std::string> Action::ExtractVector(
const google::protobuf::RepeatedPtrField<std::string>& repeated_strings) {
@@ -71,8 +98,8 @@ std::ostream& operator<<(std::ostream& out,
case ActionProto::ActionInfoCase::kTell:
out << "Tell";
break;
- case ActionProto::ActionInfoCase::kFocusElement:
- out << "FocusElement";
+ case ActionProto::ActionInfoCase::kShowCast:
+ out << "ShowCast";
break;
case ActionProto::ActionInfoCase::kWaitForDom:
out << "WaitForDom";
@@ -140,6 +167,9 @@ std::ostream& operator<<(std::ostream& out,
case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
out << "PresaveGeneratedPassword";
break;
+ case ActionProto::ActionInfoCase::kGetElementStatus:
+ out << "GetElementStatus";
+ break;
case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
out << "ACTION_INFO_NOT_SET";
break;
diff --git a/chromium/components/autofill_assistant/browser/actions/action.h b/chromium/components/autofill_assistant/browser/actions/action.h
index 85adb3724e2..4675bf2ea5b 100644
--- a/chromium/components/autofill_assistant/browser/actions/action.h
+++ b/chromium/components/autofill_assistant/browser/actions/action.h
@@ -11,6 +11,8 @@
#include <vector>
#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/stopwatch.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
@@ -48,6 +50,18 @@ class Action {
void UpdateProcessedAction(ProcessedActionStatusProto status);
void UpdateProcessedAction(const ClientStatus& status);
+ // Wraps the `ProcesseActionCallback` to also fill the relevant timing stat
+ // fields.
+ void RecordActionTimes(ProcessActionCallback callback,
+ std::unique_ptr<ProcessedActionProto>);
+
+ // Wraps `callback` to record the wait in the action stopwatch for wait for
+ // dom and short wait for element operations.
+ void OnWaitForElementTimed(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& element_status,
+ base::TimeDelta wait_time);
+
// Intended for debugging. Writes a string representation of |action| to
// |out|.
friend std::ostream& operator<<(std::ostream& out, const Action& action);
@@ -59,6 +73,10 @@ class Action {
std::unique_ptr<ProcessedActionProto> processed_action_proto_;
// Reference to the delegate that owns this action.
ActionDelegate* delegate_;
+ // Used to record active and wait times in the action execution.
+ ActionStopwatch action_stopwatch_;
+
+ base::WeakPtrFactory<Action> weak_ptr_factory_{this};
};
// Intended for debugging. Writes a string representation of |action_case| to
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate.h b/chromium/components/autofill_assistant/browser/actions/action_delegate.h
index ceb100f823c..e39d0bb8540 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback_forward.h"
+#include "base/time/time.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/details.h"
#include "components/autofill_assistant/browser/info_box.h"
@@ -78,7 +79,8 @@ class ActionDelegate {
// WebController and eliminate double-lookup.
virtual void ShortWaitForElement(
const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>
+ callback) = 0;
// Wait for up to |max_wait_time| for element conditions to match on the page,
// then call |callback| with the last status.
@@ -94,11 +96,17 @@ class ActionDelegate {
base::RepeatingCallback<
void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)> check_elements,
- base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>
+ callback) = 0;
// Find an element specified by |selector| on the web page.
virtual void FindElement(const Selector&,
- ElementFinder::Callback callback) = 0;
+ ElementFinder::Callback callback) const = 0;
+
+ // Find all elements matching |selector|. If there are no matches, the status
+ // will be ELEMENT_RESOLUTION_FAILED.
+ virtual void FindAllElements(const Selector& selector,
+ ElementFinder::Callback callback) const = 0;
// Click or tap the |element|.
virtual void ClickOrTapElement(
@@ -106,13 +114,22 @@ class ActionDelegate {
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Wait for the |element|'s document to become interactive.
- virtual void WaitForDocumentToBecomeInteractive(
+ // Scroll the |element| into view.
+ virtual void ScrollIntoView(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Scroll the |element| into view.
- virtual void ScrollIntoView(
+ // Wait for the |element| to stop moving on the page. Fails with
+ // ELEMENT_UNSTABLE.
+ virtual void WaitUntilElementIsStable(
+ int max_rounds,
+ base::TimeDelta check_interval,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+
+ // Make sure that |element| is the topmost element at its center. Fails with
+ // ELEMENT_NOT_ON_TOP.
+ virtual void CheckOnTop(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
@@ -136,10 +153,10 @@ class ActionDelegate {
// Have the UI leave the prompt state and go back to its previous state.
virtual void CleanUpAfterPrompt() = 0;
- // Set the list of whitelisted domains to be used when we enter a browse
- // state. This list is used to determine whether a user initiated navigation
- // to a different domain or subdomain is allowed.
- virtual void SetBrowseDomainsWhitelist(std::vector<std::string> domains) = 0;
+ // Set the list of allowed domains to be used when we enter a browse state.
+ // This list is used to determine whether a user initiated navigation to a
+ // different domain or subdomain is allowed.
+ virtual void SetBrowseDomainsAllowlist(std::vector<std::string> domains) = 0;
// Asks the user to provide the requested user data.
virtual void CollectUserData(
@@ -199,11 +216,16 @@ class ActionDelegate {
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Focus on element given by |selector|. |top_padding| specifies the padding
- // between focused element and the top.
- virtual void FocusElement(
+ // Scroll to an |element|'s position. |top_padding| specifies the padding
+ // between the focused element and the top.
+ // TODO(b/168107066): The selector is only used for storing the previously
+ // selected element and is not being used to resolve it. This is required for
+ // the current implementation of |ScriptExecutor| that repeats the focus
+ // after an interrupt. This dependency should be removed from the signature.
+ virtual void ScrollToElementPosition(
const Selector& selector,
const TopPadding& top_padding,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
// Sets selector of areas that can be manipulated:
@@ -213,37 +235,52 @@ class ActionDelegate {
virtual void SetTouchableElementArea(
const ElementAreaProto& touchable_element_area) = 0;
- // Highlight the element given by |selector|.
+ // Highlight the |element|.
virtual void HighlightElement(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Get the value of |selector| and return the result through |callback|. The
- // returned value might be false, if the element cannot be found, true and the
- // empty string in case of error or empty value.
+ // Get the value attribute of an |element| and return the result through
+ // |callback|. If the lookup fails, the value will be empty. An empty result
+ // does not mean an error.
virtual void GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) = 0;
- // Set the |value| of field |element| and return the result through
- // |callback|. If |simulate_key_presses| is true, the value will be set by
- // clicking the field and then simulating key presses, otherwise the `value`
- // attribute will be set directly.
- virtual void SetFieldValue(
+ // Get the value of a nested |attribute| from an |element| and return the
+ // result through |callback|. If the lookup fails, the value will be empty.
+ // An empty result does not mean an error.
+ virtual void GetStringAttribute(
+ const std::vector<std::string>& attributes,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback) = 0;
+
+ // Set the value attribute of an |element| to the specified |value| and
+ // trigger an onchange event.
+ virtual void SetValueAttribute(
const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Set the |value| of all the |attributes| of the |element|.
+ // Set the nested |attributes| of an |element| to the specified |value|.
virtual void SetAttribute(
const std::vector<std::string>& attributes,
const std::string& value,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+ // Select the current value in a text |element|.
+ virtual void SelectFieldValue(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+
+ // Focus the current |element|.
+ virtual void FocusField(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) = 0;
+
// Sets the keyboard focus to |element| and inputs the specified codepoints.
// Returns the result through |callback|.
virtual void SendKeyboardInput(
@@ -252,12 +289,19 @@ class ActionDelegate {
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Return the outerHTML of an element given by |selector|.
+ // Return the outerHTML of an |element|.
virtual void GetOuterHtml(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) = 0;
+ // Return the outerHTML of each element in |elements|. |elements| must contain
+ // the object ID of a JS array containing the elements.
+ virtual void GetOuterHtmls(
+ const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback) = 0;
+
// Return the tag of the |element|. In case of an error, returns an empty
// string.
virtual void GetElementTag(
@@ -285,18 +329,29 @@ class ActionDelegate {
base::OnceCallback<void(bool)> on_navigation_done) = 0;
// Waits for the value of Document.readyState to reach at least
- // |min_ready_state| in |optional_frame| or, if it is empty, in the main
- // document.
+ // |min_ready_state| in |optional_frame_element| or, if it is empty, in the
+ // main document.
virtual void WaitForDocumentReadyState(
- const Selector& optional_frame,
+ base::TimeDelta max_wait_time,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) = 0;
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) = 0;
+
+ // Wait until the defined |min_ready_state| in |optional_frame_element| is
+ // reached or time out. If the |optional_frame_element| is empty, check the
+ // main document.
+ virtual void WaitUntilDocumentIsInReadyState(
+ base::TimeDelta max_wait_time,
+ DocumentReadyState min_ready_state,
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&)> callback) = 0;
- // Gets the value of Document.readyState in |optional_frame| or, if it is
- // empty, in the main document.
+ // Gets the value of Document.readyState in |optional_frame_element| or, if
+ // it is empty, in the main document.
virtual void GetDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) = 0;
@@ -305,7 +360,7 @@ class ActionDelegate {
virtual void LoadURL(const GURL& url) = 0;
// Shut down Autofill Assistant at the end of the current script.
- virtual void Shutdown() = 0;
+ virtual void Shutdown(bool show_feedback_chip) = 0;
// Shut down Autofill Assistant and closes Chrome.
virtual void Close() = 0;
@@ -382,7 +437,7 @@ class ActionDelegate {
base::OnceCallback<void(const ClientStatus&)> callback) = 0;
// Returns the current client settings.
- virtual const ClientSettings& GetSettings() = 0;
+ virtual const ClientSettings& GetSettings() const = 0;
// Show a form to the user and call |changed_callback| with its values
// whenever there is a change. |changed_callback| will be called directly with
@@ -425,7 +480,7 @@ class ActionDelegate {
virtual void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) = 0;
- virtual base::WeakPtr<ActionDelegate> GetWeakPtr() = 0;
+ virtual base::WeakPtr<ActionDelegate> GetWeakPtr() const = 0;
protected:
ActionDelegate() = default;
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
index 430e91c41f1..498f5f7f183 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
@@ -6,12 +6,14 @@
#include "base/callback.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
-namespace ActionDelegateUtil {
+namespace action_delegate_util {
namespace {
void RetainElementAndExecuteCallback(
@@ -22,30 +24,34 @@ void RetainElementAndExecuteCallback(
std::move(callback).Run(status);
}
-void RecursivePerformActions(
- const ElementFinder::Result& element,
+void PerformActionsSequentially(
std::unique_ptr<ElementActionVector> perform_actions,
+ std::unique_ptr<ProcessedActionStatusDetailsProto> status_details,
size_t action_index,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> done,
const ClientStatus& status) {
+ status_details->MergeFrom(status.details());
+
if (!status.ok()) {
VLOG(1) << __func__ << "Web-Action failed with status " << status;
- std::move(done).Run(status);
+ std::move(done).Run(ClientStatus(status.proto_status(), *status_details));
return;
}
if (action_index >= perform_actions->size()) {
- std::move(done).Run(status);
+ std::move(done).Run(ClientStatus(status.proto_status(), *status_details));
return;
}
std::move((*perform_actions)[action_index])
- .Run(element, base::BindOnce(&RecursivePerformActions, element,
- std::move(perform_actions), action_index + 1,
- std::move(done)));
+ .Run(element,
+ base::BindOnce(&PerformActionsSequentially,
+ std::move(perform_actions), std::move(status_details),
+ action_index + 1, element, std::move(done)));
}
-void OnFindElement(std::unique_ptr<ElementActionVector> perform_actions,
+void OnFindElement(ElementActionCallback perform,
base::OnceCallback<void(const ClientStatus&)> done,
const ClientStatus& element_status,
std::unique_ptr<ElementFinder::Result> element_result) {
@@ -55,93 +61,252 @@ void OnFindElement(std::unique_ptr<ElementActionVector> perform_actions,
return;
}
- DCHECK(!perform_actions->empty());
- RecursivePerformActions(
- *element_result, std::move(perform_actions), 0,
+ std::move(perform).Run(
+ *element_result,
base::BindOnce(&RetainElementAndExecuteCallback,
- std::move(element_result), std::move(done)),
- OkClientStatus());
+ std::move(element_result), std::move(done)));
+}
+
+void FindElementAndPerformImpl(
+ const ActionDelegate* delegate,
+ const Selector& selector,
+ ElementActionCallback perform,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ delegate->FindElement(
+ selector,
+ base::BindOnce(&OnFindElement, std::move(perform), std::move(done)));
+}
+
+// Call |done| with a successful status, no matter what |status|.
+//
+// Note that the status details, if any, filled in |status| are conserved.
+void IgnoreErrorStatus(base::OnceCallback<void(const ClientStatus&)> done,
+ const ClientStatus& status) {
+ if (status.ok()) {
+ std::move(done).Run(status);
+ return;
+ }
+ std::move(done).Run(status.WithStatusOverride(ACTION_APPLIED));
+}
+
+// Execute [action] but skip any failures by transforming failed ClientStatus
+// into successes.
+//
+// Note that the status details filled by the failed action are conserved.
+void SkipIfFail(ElementActionCallback action,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ std::move(action).Run(element,
+ base::BindOnce(&IgnoreErrorStatus, std::move(done)));
+}
+
+// Adds a sequence of actions that execute a click.
+void AddClickOrTapSequence(const ActionDelegate* delegate,
+ ClickType click_type,
+ OptionalStep on_top,
+ ElementActionVector* actions) {
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::WaitUntilDocumentIsInReadyState, delegate->GetWeakPtr(),
+ delegate->GetSettings().document_ready_check_timeout,
+ DOCUMENT_INTERACTIVE));
+ actions->emplace_back(
+ base::BindOnce(&ActionDelegate::ScrollIntoView, delegate->GetWeakPtr()));
+ if (click_type != ClickType::JAVASCRIPT) {
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::WaitUntilElementIsStable, delegate->GetWeakPtr(),
+ delegate->GetSettings().box_model_check_count,
+ delegate->GetSettings().box_model_check_interval));
+ AddOptionalStep(
+ on_top,
+ base::BindOnce(&ActionDelegate::CheckOnTop, delegate->GetWeakPtr()),
+ actions);
+ }
+ actions->emplace_back(base::BindOnce(&ActionDelegate::ClickOrTapElement,
+ delegate->GetWeakPtr(), click_type));
}
} // namespace
-void FindElementAndPerform(ActionDelegate* delegate,
- const Selector& selector,
- ElementActionCallback perform,
- base::OnceCallback<void(const ClientStatus&)> done) {
- auto actions = std::make_unique<ElementActionVector>();
- actions->emplace_back(std::move(perform));
+void PerformAll(std::unique_ptr<ElementActionVector> perform_actions,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ PerformActionsSequentially(
+ std::move(perform_actions),
+ std::make_unique<ProcessedActionStatusDetailsProto>(), 0, element,
+ std::move(done), OkClientStatus());
+}
+
+void AddOptionalStep(OptionalStep optional_step,
+ ElementActionCallback step,
+ ElementActionVector* actions) {
+ switch (optional_step) {
+ case STEP_UNSPECIFIED:
+ NOTREACHED() << __func__ << " unspecified optional_step";
+ FALLTHROUGH;
- FindElementAndPerform(delegate, selector, std::move(actions),
- std::move(done));
+ case SKIP_STEP:
+ break;
+
+ case REPORT_STEP_RESULT:
+ actions->emplace_back(base::BindOnce(&SkipIfFail, std::move(step)));
+ break;
+
+ case REQUIRE_STEP_SUCCESS:
+ actions->emplace_back(std::move(step));
+ break;
+ }
}
-void FindElementAndPerform(ActionDelegate* delegate,
+void FindElementAndPerform(const ActionDelegate* delegate,
const Selector& selector,
- std::unique_ptr<ElementActionVector> perform_actions,
+ ElementActionCallback perform,
base::OnceCallback<void(const ClientStatus&)> done) {
- DCHECK(!selector.empty());
- VLOG(3) << __func__ << " " << selector;
- delegate->FindElement(
- selector, base::BindOnce(&OnFindElement, std::move(perform_actions),
- std::move(done)));
+ FindElementAndPerformImpl(delegate, selector, std::move(perform),
+ std::move(done));
+}
+
+void TakeElementAndPerform(ElementActionCallback perform,
+ base::OnceCallback<void(const ClientStatus&)> done,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element) {
+ OnFindElement(std::move(perform), std::move(done), element_status,
+ std::move(element));
}
-void ClickOrTapElement(ActionDelegate* delegate,
+void ClickOrTapElement(const ActionDelegate* delegate,
const Selector& selector,
ClickType click_type,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- auto actions = std::make_unique<ElementActionVector>();
- actions->emplace_back(
- base::BindOnce(&ActionDelegate::WaitForDocumentToBecomeInteractive,
- delegate->GetWeakPtr()));
- actions->emplace_back(
- base::BindOnce(&ActionDelegate::ScrollIntoView, delegate->GetWeakPtr()));
- actions->emplace_back(base::BindOnce(&ActionDelegate::ClickOrTapElement,
- delegate->GetWeakPtr(), click_type));
+ OptionalStep on_top,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ FindElementAndPerformImpl(
+ delegate, selector,
+ base::BindOnce(&PerformClickOrTapElement, delegate, click_type, on_top),
+ std::move(done));
+}
- FindElementAndPerform(delegate, selector, std::move(actions),
- std::move(callback));
+void PerformClickOrTapElement(
+ const ActionDelegate* delegate,
+ ClickType click_type,
+ OptionalStep on_top,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ VLOG(3) << __func__ << " click_type=" << click_type << " on_top=" << on_top;
+
+ auto actions = std::make_unique<ElementActionVector>();
+ AddClickOrTapSequence(delegate, click_type, on_top, actions.get());
+ PerformAll(std::move(actions), element, std::move(done));
}
-void SendKeyboardInput(ActionDelegate* delegate,
+void SendKeyboardInput(const ActionDelegate* delegate,
const Selector& selector,
const std::vector<UChar32> codepoints,
int delay_in_millis,
- base::OnceCallback<void(const ClientStatus&)> callback) {
+ bool use_focus,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ FindElementAndPerformImpl(
+ delegate, selector,
+ base::BindOnce(&PerformSendKeyboardInput, delegate, codepoints,
+ delay_in_millis, use_focus),
+ std::move(done));
+}
+
+void PerformSendKeyboardInput(
+ const ActionDelegate* delegate,
+ const std::vector<UChar32> codepoints,
+ int delay_in_millis,
+ bool use_focus,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ VLOG(3) << __func__ << " focus: " << use_focus;
+
auto actions = std::make_unique<ElementActionVector>();
- actions->emplace_back(
- base::BindOnce(&ActionDelegate::WaitForDocumentToBecomeInteractive,
- delegate->GetWeakPtr()));
- actions->emplace_back(
- base::BindOnce(&ActionDelegate::ScrollIntoView, delegate->GetWeakPtr()));
- actions->emplace_back(base::BindOnce(&ActionDelegate::ClickOrTapElement,
- delegate->GetWeakPtr(),
- ClickType::CLICK));
+ if (use_focus) {
+ actions->emplace_back(
+ base::BindOnce(&ActionDelegate::FocusField, delegate->GetWeakPtr()));
+ } else {
+ AddClickOrTapSequence(delegate, ClickType::CLICK, /* on_top=*/SKIP_STEP,
+ actions.get());
+ }
actions->emplace_back(base::BindOnce(&ActionDelegate::SendKeyboardInput,
delegate->GetWeakPtr(), codepoints,
delay_in_millis));
- FindElementAndPerform(delegate, selector, std::move(actions),
- std::move(callback));
+ PerformAll(std::move(actions), element, std::move(done));
}
-void SetFieldValue(ActionDelegate* delegate,
+void SetFieldValue(const ActionDelegate* delegate,
const Selector& selector,
const std::string& value,
KeyboardValueFillStrategy fill_strategy,
int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- // TODO(b/158153191): This should reuse the callback chains in the util
- // instead of relying on the |WebController| to properly implement it.
- // This requires to extract more methods and some internal logic of
- // |SetFieldValue|.
- FindElementAndPerform(
+ base::OnceCallback<void(const ClientStatus&)> done) {
+ FindElementAndPerformImpl(
delegate, selector,
- base::BindOnce(&ActionDelegate::SetFieldValue, delegate->GetWeakPtr(),
- value, fill_strategy, key_press_delay_in_millisecond),
- std::move(callback));
+ base::BindOnce(&PerformSetFieldValue, delegate, value, fill_strategy,
+ key_press_delay_in_millisecond),
+ std::move(done));
+}
+void PerformSetFieldValue(const ActionDelegate* delegate,
+ const std::string& value,
+ KeyboardValueFillStrategy fill_strategy,
+ int key_press_delay_in_millisecond,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done) {
+#ifdef NDEBUG
+ VLOG(3) << __func__ << " value=(redacted)"
+ << ", strategy=" << fill_strategy;
+#else
+ DVLOG(3) << __func__ << " value=" << value << ", strategy=" << fill_strategy;
+#endif
+
+ auto actions = std::make_unique<ElementActionVector>();
+ if (value.empty()) {
+ actions->emplace_back(base::BindOnce(&ActionDelegate::SetValueAttribute,
+ delegate->GetWeakPtr(),
+ std::string()));
+ } else {
+ switch (fill_strategy) {
+ case UNSPECIFIED_KEYBAORD_STRATEGY:
+ case SET_VALUE:
+ actions->emplace_back(base::BindOnce(&ActionDelegate::SetValueAttribute,
+ delegate->GetWeakPtr(), value));
+ break;
+ case SIMULATE_KEY_PRESSES:
+ actions->emplace_back(base::BindOnce(&ActionDelegate::SetValueAttribute,
+ delegate->GetWeakPtr(),
+ std::string()));
+ AddClickOrTapSequence(delegate, ClickType::CLICK,
+ /* on_top= */ SKIP_STEP, actions.get());
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::SendKeyboardInput, delegate->GetWeakPtr(),
+ UTF8ToUnicode(value), key_press_delay_in_millisecond));
+ break;
+ case SIMULATE_KEY_PRESSES_SELECT_VALUE:
+ // TODO(b/149004036): In case of empty, send a backspace (i.e. code 8),
+ // instead of falling back to SetValueAttribute(""). This currently
+ // fails in WebControllerBrowserTest.GetAndSetFieldValue. Fixing this
+ // might fix b/148001624 as well.
+ actions->emplace_back(base::BindOnce(&ActionDelegate::SelectFieldValue,
+ delegate->GetWeakPtr()));
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::SendKeyboardInput, delegate->GetWeakPtr(),
+ UTF8ToUnicode(value), key_press_delay_in_millisecond));
+ break;
+ case SIMULATE_KEY_PRESSES_FOCUS:
+ actions->emplace_back(base::BindOnce(&ActionDelegate::SetValueAttribute,
+ delegate->GetWeakPtr(),
+ std::string()));
+ actions->emplace_back(base::BindOnce(&ActionDelegate::FocusField,
+ delegate->GetWeakPtr()));
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::SendKeyboardInput, delegate->GetWeakPtr(),
+ UTF8ToUnicode(value), key_press_delay_in_millisecond));
+ break;
+ }
+ }
+
+ PerformAll(std::move(actions), element, std::move(done));
}
-} // namespace ActionDelegateUtil
+} // namespace action_delegate_util
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.h b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.h
index 9a13ea328a3..4e2c4dcfe6f 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.h
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.h
@@ -9,9 +9,23 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
-namespace ActionDelegateUtil {
+namespace action_delegate_util {
+namespace {
+
+template <typename R>
+void RetainElementAndExecuteGetCallback(
+ std::unique_ptr<ElementFinder::Result> element,
+ base::OnceCallback<void(const ClientStatus&, const R&)> callback,
+ const ClientStatus& status,
+ const R& result) {
+ DCHECK(element != nullptr);
+ std::move(callback).Run(status, result);
+}
+
+} // namespace
using ElementActionCallback =
base::OnceCallback<void(const ElementFinder::Result&,
@@ -19,46 +33,102 @@ using ElementActionCallback =
using ElementActionVector = std::vector<ElementActionCallback>;
+template <typename R>
+using ElementActionGetCallback = base::OnceCallback<void(
+ const ElementFinder::Result&,
+ base::OnceCallback<void(const ClientStatus&, const R&)>)>;
+
// Finds the element given by the selector. If the resolution fails, it
// immediately executes the |done| callback. If the resolution succeeds, it
// executes the |perform| callback with the element and the |done| callback as
// arguments, while retaining the element.
-void FindElementAndPerform(
- /* const */ ActionDelegate* delegate,
- const Selector& selector,
- ElementActionCallback perform,
- base::OnceCallback<void(const ClientStatus&)> done);
+void FindElementAndPerform(const ActionDelegate* delegate,
+ const Selector& selector,
+ ElementActionCallback perform,
+ base::OnceCallback<void(const ClientStatus&)> done);
-// Finds the element given by the selector. If the resolution fails, it
-// immediately executes the |done| callback. If the resolution succeeds, it
-// executes the |perform_actions| callbacks in sequence with the element and
-// the |done| callback as arguments, while retaining the element.
-void FindElementAndPerform(
- /* const */ ActionDelegate* delegate,
- const Selector& selector,
- std::unique_ptr<ElementActionVector> perform_actions,
- base::OnceCallback<void(const ClientStatus&)> done);
-
-void ClickOrTapElement(
- /* const */ ActionDelegate* delegate,
- const Selector& selector,
+// Take ownership of the |element| and execute the |perform| callback with the
+// element and the |done| callback as arguments, while retaining the element.
+// If the initial status is not ok, execute the |done| callback immediately.
+void TakeElementAndPerform(ElementActionCallback perform,
+ base::OnceCallback<void(const ClientStatus&)> done,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element);
+
+// Take ownership of the |element| and execute the |perform| callback with the
+// element and the |done| callback as arguments, while retaining the element.
+// If the initial status is not ok, execute the |done| callback with the default
+// value immediately.
+template <typename R>
+void TakeElementAndGetProperty(
+ ElementActionGetCallback<R> perform_and_get,
+ base::OnceCallback<void(const ClientStatus&, const R&)> done,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!element_status.ok()) {
+ VLOG(1) << __func__ << " Failed to find element.";
+ std::move(done).Run(element_status, R());
+ return;
+ }
+
+ std::move(perform_and_get)
+ .Run(*element_result,
+ base::BindOnce(&RetainElementAndExecuteGetCallback<R>,
+ std::move(element_result), std::move(done)));
+}
+
+void PerformAll(std::unique_ptr<ElementActionVector> perform_actions,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> done);
+
+// Adds an optional step to the |actions|. If the step is |SKIP_STEP|, it does
+// not add it. For |REPORT_STEP_RESULT| it adds the step ignoring a potential
+// failure. For |REQUIRE_STEP_SUCCESS| it binds the step as is.
+void AddOptionalStep(OptionalStep optional_step,
+ ElementActionCallback step,
+ ElementActionVector* actions);
+
+void ClickOrTapElement(const ActionDelegate* delegate,
+ const Selector& selector,
+ ClickType click_type,
+ OptionalStep on_top,
+ base::OnceCallback<void(const ClientStatus&)> callback);
+void PerformClickOrTapElement(
+ const ActionDelegate* delegate,
ClickType click_type,
+ OptionalStep on_top,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback);
-void SendKeyboardInput(/* const */ ActionDelegate* delegate,
+void SendKeyboardInput(const ActionDelegate* delegate,
const Selector& selector,
const std::vector<UChar32> codepoints,
int delay_in_millis,
+ bool use_focus,
base::OnceCallback<void(const ClientStatus&)> callback);
+void PerformSendKeyboardInput(
+ const ActionDelegate* delegate,
+ const std::vector<UChar32> codepoints,
+ int delay_in_millis,
+ bool use_focus,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback);
-void SetFieldValue(/* const */ ActionDelegate* delegate,
+void SetFieldValue(const ActionDelegate* delegate,
const Selector& selector,
const std::string& value,
KeyboardValueFillStrategy fill_strategy,
int key_press_delay_in_millisecond,
base::OnceCallback<void(const ClientStatus&)> callback);
+void PerformSetFieldValue(
+ const ActionDelegate* delegate,
+ const std::string& value,
+ KeyboardValueFillStrategy fill_strategy,
+ int key_press_delay_in_millisecond,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback);
-} // namespace ActionDelegateUtil
+} // namespace action_delegate_util
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ACTION_DELEGATE_UTIL_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc b/chromium/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
index 169394c00f1..0c155addcf1 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
@@ -4,14 +4,16 @@
#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
+#include "base/time/time.h"
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/selector.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
+namespace action_delegate_util {
namespace {
using ::base::test::RunOnceCallback;
@@ -33,6 +35,16 @@ class ActionDelegateUtilTest : public testing::Test {
const ElementFinder::Result&,
base::OnceCallback<void(const ClientStatus&)> done));
+ MOCK_METHOD1(MockDone, void(const ClientStatus& status));
+
+ MOCK_METHOD2(MockGetAction,
+ void(const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::string&)> done));
+
+ MOCK_METHOD2(MockDoneGet,
+ void(const ClientStatus& status, const std::string& value));
+
protected:
MockActionDelegate mock_action_delegate_;
};
@@ -41,12 +53,15 @@ TEST_F(ActionDelegateUtilTest, FindElementFails) {
EXPECT_CALL(mock_action_delegate_, FindElement(_, _))
.WillOnce(
RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
-
- ActionDelegateUtil::FindElementAndPerform(
- &mock_action_delegate_, Selector({"#nothing"}), base::DoNothing(),
- base::BindOnce([](const ClientStatus& status) {
- EXPECT_EQ(status.proto_status(), ELEMENT_RESOLUTION_FAILED);
- }));
+ EXPECT_CALL(*this, MockAction(_, _)).Times(0);
+ EXPECT_CALL(*this,
+ MockDone(EqualsStatus(ClientStatus(ELEMENT_RESOLUTION_FAILED))));
+
+ FindElementAndPerform(&mock_action_delegate_, Selector({"#nothing"}),
+ base::BindOnce(&ActionDelegateUtilTest::MockAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone,
+ base::Unretained(this)));
}
TEST_F(ActionDelegateUtilTest, FindElementAndExecuteSingleAction) {
@@ -55,15 +70,14 @@ TEST_F(ActionDelegateUtilTest, FindElementAndExecuteSingleAction) {
test_util::MockFindElement(mock_action_delegate_, expected_selector);
EXPECT_CALL(*this, MockAction(EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ACTION_APPLIED)));
-
- ActionDelegateUtil::FindElementAndPerform(
- &mock_action_delegate_, expected_selector,
- base::BindOnce(&ActionDelegateUtilTest::MockAction,
- base::Unretained(this)),
- base::BindOnce([](const ClientStatus& status) {
- EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
- }));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(*this, MockDone(EqualsStatus(OkClientStatus())));
+
+ FindElementAndPerform(&mock_action_delegate_, expected_selector,
+ base::BindOnce(&ActionDelegateUtilTest::MockAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone,
+ base::Unretained(this)));
}
TEST_F(ActionDelegateUtilTest, FindElementAndExecuteMultipleActions) {
@@ -74,13 +88,44 @@ TEST_F(ActionDelegateUtilTest, FindElementAndExecuteMultipleActions) {
test_util::MockFindElement(mock_action_delegate_, expected_selector);
EXPECT_CALL(*this, MockIndexedAction(1, EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<2>(ClientStatus(ACTION_APPLIED)));
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(*this, MockIndexedAction(2, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(*this, MockIndexedAction(3, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(*this, MockDone(EqualsStatus(OkClientStatus())));
+
+ auto actions = std::make_unique<ElementActionVector>();
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 1));
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 2));
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 3));
+
+ FindElementAndPerform(&mock_action_delegate_, expected_selector,
+ base::BindOnce(&PerformAll, std::move(actions)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone,
+ base::Unretained(this)));
+}
+
+TEST_F(ActionDelegateUtilTest,
+ FindElementAndExecuteMultipleActionsAbortsOnError) {
+ InSequence sequence;
+
+ Selector expected_selector({"#element"});
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ EXPECT_CALL(*this, MockIndexedAction(1, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(*this, MockIndexedAction(2, EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<2>(ClientStatus(ACTION_APPLIED)));
+ .WillOnce(RunOnceCallback<2>(ClientStatus(UNEXPECTED_JS_ERROR)));
EXPECT_CALL(*this, MockIndexedAction(3, EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<2>(ClientStatus(ACTION_APPLIED)));
+ .Times(0);
+ EXPECT_CALL(*this, MockDone(EqualsStatus(ClientStatus(UNEXPECTED_JS_ERROR))));
- auto actions = std::make_unique<ActionDelegateUtil::ElementActionVector>();
+ auto actions = std::make_unique<ElementActionVector>();
actions->emplace_back(base::BindOnce(
&ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 1));
actions->emplace_back(base::BindOnce(
@@ -88,11 +133,10 @@ TEST_F(ActionDelegateUtilTest, FindElementAndExecuteMultipleActions) {
actions->emplace_back(base::BindOnce(
&ActionDelegateUtilTest::MockIndexedAction, base::Unretained(this), 3));
- ActionDelegateUtil::FindElementAndPerform(
- &mock_action_delegate_, expected_selector, std::move(actions),
- base::BindOnce([](const ClientStatus& status) {
- EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
- }));
+ FindElementAndPerform(&mock_action_delegate_, expected_selector,
+ base::BindOnce(&PerformAll, std::move(actions)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone,
+ base::Unretained(this)));
}
TEST_F(ActionDelegateUtilTest, ActionDelegateDeletedDuringExecution) {
@@ -104,30 +148,100 @@ TEST_F(ActionDelegateUtilTest, ActionDelegateDeletedDuringExecution) {
auto expected_element =
test_util::MockFindElement(*mock_delegate, expected_selector);
- EXPECT_CALL(*mock_delegate, WaitForDocumentToBecomeInteractive(
- EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ACTION_APPLIED)));
+ EXPECT_CALL(*mock_delegate, WaitUntilElementIsStable(
+ _, _, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(*mock_delegate, ScrollIntoView(_, _)).Times(0);
+ EXPECT_CALL(*this, MockDone(_)).Times(0);
- auto actions = std::make_unique<ActionDelegateUtil::ElementActionVector>();
- actions->emplace_back(
- base::BindOnce(&ActionDelegate::WaitForDocumentToBecomeInteractive,
- mock_delegate->GetWeakPtr()));
+ auto actions = std::make_unique<ElementActionVector>();
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::WaitUntilElementIsStable, mock_delegate->GetWeakPtr(), 1,
+ base::TimeDelta::FromMilliseconds(0)));
actions->emplace_back(base::BindOnce(
[](base::OnceCallback<void()> destroy_delegate,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> done) {
std::move(destroy_delegate).Run();
- std::move(done).Run(ClientStatus(ACTION_APPLIED));
+ std::move(done).Run(OkClientStatus());
},
base::BindLambdaForTesting([&]() { mock_delegate.reset(); })));
actions->emplace_back(base::BindOnce(&ActionDelegate::ScrollIntoView,
mock_delegate->GetWeakPtr()));
- ActionDelegateUtil::FindElementAndPerform(
- mock_delegate.get(), expected_selector, std::move(actions),
- base::BindOnce([](const ClientStatus& status) {}));
+ FindElementAndPerform(mock_delegate.get(), expected_selector,
+ base::BindOnce(&PerformAll, std::move(actions)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone,
+ base::Unretained(this)));
+}
+
+TEST_F(ActionDelegateUtilTest, TakeElementAndPerform) {
+ auto expected_element = std::make_unique<ElementFinder::Result>();
+
+ EXPECT_CALL(mock_action_delegate_, FindElement(_, _)).Times(0);
+
+ EXPECT_CALL(*this, MockAction(EqualsElement(*expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(*this, MockDone(EqualsStatus(OkClientStatus())));
+
+ TakeElementAndPerform(
+ base::BindOnce(&ActionDelegateUtilTest::MockAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone, base::Unretained(this)),
+ OkClientStatus(), std::move(expected_element));
+}
+
+TEST_F(ActionDelegateUtilTest, TakeElementAndPerformWithFailedStatus) {
+ auto expected_element = std::make_unique<ElementFinder::Result>();
+
+ EXPECT_CALL(mock_action_delegate_, FindElement(_, _)).Times(0);
+
+ EXPECT_CALL(*this, MockAction(_, _)).Times(0);
+ EXPECT_CALL(*this,
+ MockDone(EqualsStatus(ClientStatus(ELEMENT_RESOLUTION_FAILED))));
+
+ TakeElementAndPerform(
+ base::BindOnce(&ActionDelegateUtilTest::MockAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDone, base::Unretained(this)),
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), std::move(expected_element));
+}
+
+TEST_F(ActionDelegateUtilTest, TakeElementAndGetProperty) {
+ auto expected_element = std::make_unique<ElementFinder::Result>();
+
+ EXPECT_CALL(mock_action_delegate_, FindElement(_, _)).Times(0);
+
+ EXPECT_CALL(*this, MockGetAction(EqualsElement(*expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "value"));
+ EXPECT_CALL(*this, MockDoneGet(EqualsStatus(OkClientStatus()), "value"));
+
+ TakeElementAndGetProperty<std::string>(
+ base::BindOnce(&ActionDelegateUtilTest::MockGetAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDoneGet,
+ base::Unretained(this)),
+ OkClientStatus(), std::move(expected_element));
+}
+
+TEST_F(ActionDelegateUtilTest, TakeElementAndGetPropertyWithFailedStatus) {
+ auto expected_element = std::make_unique<ElementFinder::Result>();
+
+ EXPECT_CALL(mock_action_delegate_, FindElement(_, _)).Times(0);
+
+ EXPECT_CALL(*this, MockGetAction(_, _)).Times(0);
+ EXPECT_CALL(*this,
+ MockDoneGet(EqualsStatus(ClientStatus(ELEMENT_RESOLUTION_FAILED)),
+ std::string()));
+
+ TakeElementAndGetProperty<std::string>(
+ base::BindOnce(&ActionDelegateUtilTest::MockGetAction,
+ base::Unretained(this)),
+ base::BindOnce(&ActionDelegateUtilTest::MockDoneGet,
+ base::Unretained(this)),
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), std::move(expected_element));
}
} // namespace
+} // namespace action_delegate_util
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/action_test_utils.cc b/chromium/components/autofill_assistant/browser/actions/action_test_utils.cc
index 95f68d89e3f..5773316f1a4 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_test_utils.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action_test_utils.cc
@@ -8,6 +8,7 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -16,10 +17,44 @@ namespace test_util {
using ::testing::_;
using ::testing::WithArgs;
+void MockFindAnyElement(MockActionDelegate& delegate) {
+ ON_CALL(delegate, FindElement(_, _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+}
+
ElementFinder::Result MockFindElement(MockActionDelegate& delegate,
- const Selector& selector) {
+ const Selector& selector,
+ int times) {
EXPECT_CALL(delegate, FindElement(selector, _))
- .WillOnce(WithArgs<1>([&selector](auto&& callback) {
+ .Times(times)
+ .WillRepeatedly(WithArgs<1>([&selector](auto&& callback) {
+ auto element_result = std::make_unique<ElementFinder::Result>();
+ element_result->object_id = selector.proto.filters(0).css_selector();
+ std::move(callback).Run(OkClientStatus(), std::move(element_result));
+ }));
+
+ ElementFinder::Result expected_result;
+ expected_result.object_id = selector.proto.filters(0).css_selector();
+ return expected_result;
+}
+
+void MockFindAnyElement(MockWebController& web_controller) {
+ ON_CALL(web_controller, OnFindElement(_, _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+}
+
+ElementFinder::Result MockFindElement(MockWebController& web_controller,
+ const Selector& selector,
+ int times) {
+ EXPECT_CALL(web_controller, OnFindElement(selector, _))
+ .Times(times)
+ .WillRepeatedly(WithArgs<1>([&selector](auto&& callback) {
auto element_result = std::make_unique<ElementFinder::Result>();
element_result->object_id = selector.proto.filters(0).css_selector();
std::move(callback).Run(OkClientStatus(), std::move(element_result));
diff --git a/chromium/components/autofill_assistant/browser/actions/action_test_utils.h b/chromium/components/autofill_assistant/browser/actions/action_test_utils.h
index b0aa9c77917..caaaff49390 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_test_utils.h
+++ b/chromium/components/autofill_assistant/browser/actions/action_test_utils.h
@@ -8,6 +8,7 @@
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -16,10 +17,31 @@ MATCHER_P(EqualsElement, element, "") {
return arg.object_id == element.object_id;
}
+MATCHER_P(EqualsStatus, status, "") {
+ return arg.proto_status() == status.proto_status();
+}
+
namespace test_util {
+// Mock |ActionDelegate::FindElement| an unspecified amount of times for any
+// selector.
+void MockFindAnyElement(MockActionDelegate& delegate);
+
+// Expect |ActionDelegate::FindElement| being called a specified amount of
+// times for the given |Selector|.
ElementFinder::Result MockFindElement(MockActionDelegate& delegate,
- const Selector& selector);
+ const Selector& selector,
+ int times = 1);
+
+// Mock |WebController::FindElement| an unspecified amount of times for any
+// selector.
+void MockFindAnyElement(MockWebController& web_controller);
+
+// Expect |WebController::FindElement| being called a specified amount of times
+// for the given |Selector|.
+ElementFinder::Result MockFindElement(MockWebController& web_controller,
+ const Selector& selector,
+ int times = 1);
} // namespace test_util
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/action_unittest.cc
new file mode 100644
index 00000000000..5c9082ae7dd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/action_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright 2020 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_assistant/browser/actions/action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::SaveArgPointee;
+
+class TimeTicksOverride {
+ public:
+ static base::TimeTicks Now() { return now_ticks_; }
+
+ static base::TimeTicks now_ticks_;
+};
+
+// static
+base::TimeTicks TimeTicksOverride::now_ticks_ = base::TimeTicks::Now();
+
+class FakeAction : public Action {
+ public:
+ FakeAction(ActionDelegate* delegate, const ActionProto& proto)
+ : Action(delegate, proto) {}
+
+ private:
+ void InternalProcessAction(ProcessActionCallback callback) override {
+ Selector selector;
+ delegate_->ShortWaitForElement(
+ selector,
+ base::BindOnce(
+ &FakeAction::OnWaitForElementTimed, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&FakeAction::OnWaitForElement,
+ base::Unretained(this), std::move(callback))));
+ }
+
+ void OnWaitForElement(ProcessActionCallback callback,
+ const ClientStatus& element_status) {
+ std::move(callback).Run(std::move(processed_action_proto_));
+ }
+};
+
+class FakeActionTest : public testing::Test {
+ public:
+ void SetUp() override {}
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ action_proto.set_action_delay_ms(1000);
+ FakeAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+};
+
+ACTION_P(Delay, delay) {
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(delay);
+}
+
+TEST_F(FakeActionTest, WaitForDomActionTest) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ InSequence sequence;
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+ .WillOnce(DoAll(Delay(2), RunOnceCallback<1>(
+ OkClientStatus(),
+ base::TimeDelta::FromMilliseconds(500))));
+
+ ProcessedActionProto processed_proto;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(SaveArgPointee<0>(&processed_proto));
+ Run();
+
+ EXPECT_EQ(processed_proto.timing_stats().delay_ms(), 1000);
+ EXPECT_EQ(processed_proto.timing_stats().active_time_ms(), 1500);
+ EXPECT_EQ(processed_proto.timing_stats().wait_time_ms(), 500);
+}
+
+} // namespace
+} // namespace autofill_assistant \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/browser/actions/click_action.cc b/chromium/components/autofill_assistant/browser/actions/click_action.cc
index 962c48c0354..6413c02ce8b 100644
--- a/chromium/components/autofill_assistant/browser/actions/click_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/click_action.cc
@@ -23,23 +23,29 @@ ClickAction::ClickAction(ActionDelegate* delegate, const ActionProto& proto)
// default: TAP
click_type_ = ClickType::TAP;
}
+ on_top_ = proto.click().on_top();
+ if (on_top_ == STEP_UNSPECIFIED) {
+ on_top_ = SKIP_STEP;
+ }
}
ClickAction::~ClickAction() {}
void ClickAction::InternalProcessAction(ProcessActionCallback callback) {
- Selector selector =
- Selector(proto_.click().element_to_click()).MustBeVisible();
+ Selector selector = Selector(proto_.click().element_to_click());
if (selector.empty()) {
VLOG(1) << __func__ << ": empty selector";
UpdateProcessedAction(INVALID_SELECTOR);
std::move(callback).Run(std::move(processed_action_proto_));
return;
}
- delegate_->ShortWaitForElement(selector,
- base::BindOnce(&ClickAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(callback), selector));
+
+ delegate_->ShortWaitForElement(
+ selector, base::BindOnce(&ClickAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&ClickAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), selector)));
}
void ClickAction::OnWaitForElement(ProcessActionCallback callback,
@@ -51,8 +57,8 @@ void ClickAction::OnWaitForElement(ProcessActionCallback callback,
return;
}
- ActionDelegateUtil::ClickOrTapElement(
- delegate_, selector, click_type_,
+ action_delegate_util::ClickOrTapElement(
+ delegate_, selector, click_type_, on_top_,
base::BindOnce(&::autofill_assistant::ClickAction::OnClick,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
diff --git a/chromium/components/autofill_assistant/browser/actions/click_action.h b/chromium/components/autofill_assistant/browser/actions/click_action.h
index 20bb9f8bc75..e5809fafb8f 100644
--- a/chromium/components/autofill_assistant/browser/actions/click_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/click_action.h
@@ -31,6 +31,7 @@ class ClickAction : public Action {
void OnClick(ProcessActionCallback callback, const ClientStatus& status);
ClickType click_type_;
+ OptionalStep on_top_;
base::WeakPtrFactory<ClickAction> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ClickAction);
diff --git a/chromium/components/autofill_assistant/browser/actions/click_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/click_action_unittest.cc
index 6ac491db4ae..cff529519e2 100644
--- a/chromium/components/autofill_assistant/browser/actions/click_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/click_action_unittest.cc
@@ -25,7 +25,21 @@ class ClickActionTest : public testing::Test {
public:
ClickActionTest() {}
- void SetUp() override {}
+ void SetUp() override {
+ ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ ON_CALL(mock_action_delegate_, WaitUntilDocumentIsInReadyState(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, ScrollIntoView(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, CheckOnTop(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, ClickOrTapElement(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus()));
+ }
protected:
void Run() {
@@ -35,6 +49,16 @@ class ClickActionTest : public testing::Test {
action.ProcessAction(callback_.Get());
}
+ // Return an error status with details as created by
+ // WebController::CheckOnTop.
+ ClientStatus NotOnTopStatus() {
+ ClientStatus not_on_top(ELEMENT_NOT_ON_TOP);
+ not_on_top.mutable_details()
+ ->mutable_web_controller_error_info()
+ ->set_failed_web_action(WebControllerErrorInfoProto::ON_TOP);
+ return not_on_top;
+ }
+
MockActionDelegate mock_action_delegate_;
base::MockCallback<Action::ProcessActionCallback> callback_;
ClickProto proto_;
@@ -48,29 +72,72 @@ TEST_F(ClickActionTest, EmptySelectorFails) {
}
TEST_F(ClickActionTest, CheckExpectedCallChain) {
- InSequence sequence;
-
- Selector selector({"#click"});
- *proto_.mutable_element_to_click() = selector.proto;
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
proto_.set_click_type(ClickType::CLICK);
- Selector expected_selector = selector;
- expected_selector.MustBeVisible();
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ InSequence seq;
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- auto expected_element =
- test_util::MockFindElement(mock_action_delegate_, expected_selector);
- EXPECT_CALL(mock_action_delegate_, WaitForDocumentToBecomeInteractive(
- EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
ScrollIntoView(EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus()));
EXPECT_CALL(
mock_action_delegate_,
+ WaitUntilElementIsStable(_, _, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
ClickOrTapElement(ClickType::CLICK, EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ Run();
+}
+
+TEST_F(ClickActionTest, JavaScriptClickSkipsWaitForElementStable) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::JAVASCRIPT);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ EXPECT_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
+ .Times(0);
+ EXPECT_CALL(mock_action_delegate_, CheckOnTop(_, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_,
+ ClickOrTapElement(ClickType::JAVASCRIPT,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+TEST_F(ClickActionTest, SkipCheckOnTop) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::TAP);
+ proto_.set_on_top(SKIP_STEP);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ EXPECT_CALL(mock_action_delegate_, CheckOnTop(_, _)).Times(0);
EXPECT_CALL(
callback_,
@@ -78,5 +145,115 @@ TEST_F(ClickActionTest, CheckExpectedCallChain) {
Run();
}
+TEST_F(ClickActionTest, RequireCheckOnTop) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::TAP);
+ proto_.set_on_top(REQUIRE_STEP_SUCCESS);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ InSequence seq;
+ EXPECT_CALL(
+ mock_action_delegate_,
+ WaitUntilElementIsStable(_, _, EqualsElement(expected_element), _));
+ EXPECT_CALL(mock_action_delegate_,
+ CheckOnTop(EqualsElement(expected_element), _));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::TAP, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+TEST_F(ClickActionTest, OptionalCheckOnTop) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::TAP);
+ proto_.set_on_top(REPORT_STEP_RESULT);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ InSequence seq;
+ EXPECT_CALL(
+ mock_action_delegate_,
+ WaitUntilElementIsStable(_, _, EqualsElement(expected_element), _));
+ EXPECT_CALL(mock_action_delegate_,
+ CheckOnTop(EqualsElement(expected_element), _));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::TAP, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+TEST_F(ClickActionTest, RequiredCheckOnTopFails) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::TAP);
+ proto_.set_on_top(REQUIRE_STEP_SUCCESS);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ // CheckOnTop fails.
+ EXPECT_CALL(mock_action_delegate_,
+ CheckOnTop(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(NotOnTopStatus()));
+
+ // The action must not tap.
+ EXPECT_CALL(mock_action_delegate_, ClickOrTapElement(_, _, _)).Times(0);
+
+ ProcessedActionProto result;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(testing::SaveArgPointee<0>(&result));
+ Run();
+
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, result.status());
+ EXPECT_EQ(
+ WebControllerErrorInfoProto::ON_TOP,
+ result.status_details().web_controller_error_info().failed_web_action());
+}
+
+TEST_F(ClickActionTest, OptionalCheckOnTopFails) {
+ Selector expected_selector({"#click"});
+ *proto_.mutable_element_to_click() = expected_selector.proto;
+ proto_.set_click_type(ClickType::TAP);
+ proto_.set_on_top(REPORT_STEP_RESULT);
+
+ ElementFinder::Result expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+
+ // CheckOnTop fails.
+ EXPECT_CALL(mock_action_delegate_,
+ CheckOnTop(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(NotOnTopStatus()));
+
+ // The action must tap anyway.
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::TAP, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ ProcessedActionProto result;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(testing::SaveArgPointee<0>(&result));
+ Run();
+
+ EXPECT_EQ(ACTION_APPLIED, result.status());
+ EXPECT_EQ(
+ WebControllerErrorInfoProto::ON_TOP,
+ result.status_details().web_controller_error_info().failed_web_action());
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, result.status_details().original_status());
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index d9d3b1e48ed..e322c7c2922 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -481,6 +481,7 @@ void CollectUserDataAction::InternalProcessAction(
} else {
ShowToUser();
}
+ action_stopwatch_.StartWaitTime();
}
void CollectUserDataAction::EndAction(const ClientStatus& status) {
@@ -628,6 +629,7 @@ void CollectUserDataAction::OnGetUserData(
const UserModel* user_model) {
if (!callback_)
return;
+ action_stopwatch_.StartActiveTime();
delegate_->GetPersonalDataManager()->RemoveObserver(this);
WriteProcessedAction(user_data, user_model);
@@ -642,6 +644,7 @@ void CollectUserDataAction::OnAdditionalActionTriggered(
const UserModel* user_model) {
if (!callback_)
return;
+ action_stopwatch_.StartActiveTime();
delegate_->GetPersonalDataManager()->RemoveObserver(this);
processed_action_proto_->mutable_collect_user_data_result()
@@ -656,6 +659,7 @@ void CollectUserDataAction::OnTermsAndConditionsLinkClicked(
const UserModel* user_model) {
if (!callback_)
return;
+ action_stopwatch_.StartActiveTime();
delegate_->GetPersonalDataManager()->RemoveObserver(this);
processed_action_proto_->mutable_collect_user_data_result()->set_terms_link(
@@ -1247,7 +1251,7 @@ void CollectUserDataAction::UpdatePersonalDataManagerProfiles(
for (const auto* profile :
delegate_->GetPersonalDataManager()->GetProfilesToSuggest()) {
user_data->available_profiles_.emplace_back(
- std::make_unique<autofill::AutofillProfile>(*profile));
+ MakeUniqueFromProfile(*profile));
if (selected_profile != nullptr &&
CompareContactDetails(*collect_user_data_options_, profile,
@@ -1279,7 +1283,7 @@ void CollectUserDataAction::UpdatePersonalDataManagerProfiles(
if (default_selection != -1) {
user_data->selected_addresses_.emplace(
collect_user_data_options_->contact_details_name,
- std::make_unique<autofill::AutofillProfile>(
+ MakeUniqueFromProfile(
*(user_data->available_profiles_[default_selection])));
}
}
@@ -1299,7 +1303,7 @@ void CollectUserDataAction::UpdatePersonalDataManagerProfiles(
if (default_selection != -1) {
user_data->selected_addresses_.emplace(
collect_user_data_options_->shipping_address_name,
- std::make_unique<autofill::AutofillProfile>(
+ MakeUniqueFromProfile(
*(user_data->available_profiles_[default_selection])));
}
}
@@ -1334,7 +1338,7 @@ void CollectUserDataAction::UpdatePersonalDataManagerCards(
card->billing_address_id());
if (billing_address != nullptr) {
payment_instrument->billing_address =
- std::make_unique<autofill::AutofillProfile>(*billing_address);
+ MakeUniqueFromProfile(*billing_address);
}
}
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
index 5a7fac9636a..d5e75b7f782 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
@@ -14,7 +14,6 @@
#include "base/optional.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill_assistant/browser/actions/action.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/user_model.h"
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index ac0136f8dbd..60afcf9e22d 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -17,6 +17,7 @@
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/mock_personal_data_manager.h"
#include "components/autofill_assistant/browser/mock_website_login_manager.h"
+#include "components/autofill_assistant/browser/test_util.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/test/test_renderer_host.h"
@@ -41,13 +42,6 @@ void SetDateProto(DateProto* proto, int year, int month, int day) {
proto->set_day(day);
}
-MATCHER_P(EqualsProto, message, "") {
- std::string expected_serialized, actual_serialized;
- message.SerializeToString(&expected_serialized);
- arg.SerializeToString(&actual_serialized);
- return expected_serialized == actual_serialized;
-}
-
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
@@ -1189,14 +1183,14 @@ TEST_F(CollectUserDataActionTest, SelectDateTimeRange) {
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_range_start_date,
- EqualsProto(actual_pickup_date))),
+ Eq(actual_pickup_date))),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_range_start_timeslot,
Eq(actual_pickup_time))),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_range_end_date,
- EqualsProto(actual_return_date))),
+ Eq(actual_return_date))),
Property(
&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::date_range_end_timeslot,
diff --git a/chromium/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
index 65fde663519..c4f0e50cd20 100644
--- a/chromium/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
diff --git a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
index c7bf0533394..dcc6e6b30e4 100644
--- a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
+++ b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.cc
@@ -225,7 +225,7 @@ void RequiredFieldsFallbackHandler::SetFallbackFieldValuesSequentially(
const RequiredField& required_field = required_fields_[required_fields_index];
if (required_field.value_expression.empty()) {
- ActionDelegateUtil::SetFieldValue(
+ action_delegate_util::SetFieldValue(
action_delegate_, required_field.selector, "",
required_field.fill_strategy, required_field.delay_in_millisecond,
base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
@@ -249,8 +249,9 @@ void RequiredFieldsFallbackHandler::SetFallbackFieldValuesSequentially(
// default: TAP
click_type = ClickType::TAP;
}
- ActionDelegateUtil::ClickOrTapElement(
+ action_delegate_util::ClickOrTapElement(
action_delegate_, required_field.selector, click_type,
+ /* on_top= */ SKIP_STEP,
base::BindOnce(
&RequiredFieldsFallbackHandler::OnClickOrTapFallbackElement,
weak_ptr_factory_.GetWeakPtr(), fallback_value.value(),
@@ -319,9 +320,9 @@ void RequiredFieldsFallbackHandler::OnGetFallbackFieldElementTag(
return;
}
- action_delegate_->SetFieldValue(
- value, required_field.fill_strategy, required_field.delay_in_millisecond,
- *element,
+ action_delegate_util::PerformSetFieldValue(
+ action_delegate_, value, required_field.fill_strategy,
+ required_field.delay_in_millisecond, *element,
base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
weak_ptr_factory_.GetWeakPtr(), required_fields_index,
std::move(element)));
@@ -344,7 +345,7 @@ void RequiredFieldsFallbackHandler::OnClickOrTapFallbackElement(
DCHECK(required_field.fallback_click_element.has_value());
Selector value_selector = required_field.fallback_click_element.value();
- value_selector.MatchingInnerText(value).MustBeVisible();
+ value_selector.MatchingInnerText(value);
action_delegate_->ShortWaitForElement(
value_selector,
@@ -356,8 +357,9 @@ void RequiredFieldsFallbackHandler::OnClickOrTapFallbackElement(
void RequiredFieldsFallbackHandler::OnShortWaitForElement(
const Selector& selector_to_click,
size_t required_fields_index,
-
- const ClientStatus& find_element_status) {
+ const ClientStatus& find_element_status,
+ base::TimeDelta wait_time) {
+ total_wait_time_ += wait_time;
const RequiredField& required_field = required_fields_[required_fields_index];
if (!find_element_status.ok()) {
FillStatusDetailsWithError(
@@ -374,8 +376,8 @@ void RequiredFieldsFallbackHandler::OnShortWaitForElement(
// default: TAP
click_type = ClickType::TAP;
}
- ActionDelegateUtil::ClickOrTapElement(
- action_delegate_, selector_to_click, click_type,
+ action_delegate_util::ClickOrTapElement(
+ action_delegate_, selector_to_click, click_type, /* on_top= */ SKIP_STEP,
base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
weak_ptr_factory_.GetWeakPtr(), required_fields_index,
/* element= */ nullptr));
diff --git a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h
index 0d0e86288e0..ff036830fa9 100644
--- a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h
+++ b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h
@@ -43,6 +43,8 @@ class RequiredFieldsFallbackHandler {
const base::Optional<ClientStatus>&)>
status_update_callback);
+ base::TimeDelta TotalWaitTime() { return total_wait_time_; }
+
private:
// Check whether all required fields have a non-empty value. If it is the
// case, update the status to success. If it's not and |apply_fallback|
@@ -87,7 +89,8 @@ class RequiredFieldsFallbackHandler {
// Called after waiting for option element to appear before clicking it.
void OnShortWaitForElement(const Selector& selector_to_click,
size_t required_fields_index,
- const ClientStatus& find_element_status);
+ const ClientStatus& find_element_status,
+ base::TimeDelta wait_time);
// Called after trying to set form values without Autofill in case of
// fallback after failed validation.
@@ -104,6 +107,7 @@ class RequiredFieldsFallbackHandler {
status_update_callback_;
ActionDelegate* action_delegate_;
std::unique_ptr<BatchElementChecker> batch_element_checker_;
+ base::TimeDelta total_wait_time_ = base::TimeDelta::FromSeconds(0);
base::WeakPtrFactory<RequiredFieldsFallbackHandler> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(RequiredFieldsFallbackHandler);
diff --git a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
index 06f8de60daa..688cc8cd305 100644
--- a/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler_unittest.cc
@@ -27,6 +27,7 @@ namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::Expectation;
+using ::testing::InSequence;
using ::testing::Invoke;
RequiredField CreateRequiredField(const std::string& value_expression,
@@ -45,14 +46,17 @@ class RequiredFieldsFallbackHandlerTest : public testing::Test {
.WillByDefault(Invoke([this](BatchElementChecker* checker) {
checker->Run(&mock_web_controller_);
}));
+ test_util::MockFindAnyElement(mock_web_controller_);
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
- ON_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _))
+ ON_CALL(mock_action_delegate_, SetValueAttribute(_, _, _))
.WillByDefault(RunOnceCallback<2>(OkClientStatus()));
- ON_CALL(mock_action_delegate_, WaitForDocumentToBecomeInteractive(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, WaitUntilDocumentIsInReadyState(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
ON_CALL(mock_action_delegate_, ScrollIntoView(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
}
protected:
@@ -156,7 +160,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
TEST_F(RequiredFieldsFallbackHandlerTest, AddsFirstFieldFillingError) {
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), ""));
- ON_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _))
+ ON_CALL(mock_action_delegate_, SetValueAttribute(_, _, _))
.WillByDefault(RunOnceCallback<2>(ClientStatus(OTHER_ACTION_STATUS)));
std::vector<RequiredField> required_fields = {
@@ -260,7 +264,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
TEST_F(RequiredFieldsFallbackHandlerTest, DoesNotFallbackIfFieldsAreFilled) {
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "value"));
- EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_, SetValueAttribute(_, _, _)).Times(0);
std::vector<RequiredField> required_fields = {
CreateRequiredField("${51}", {"#card_name"})};
@@ -282,10 +286,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FillsEmptyRequiredField) {
Expectation set_value =
EXPECT_CALL(
mock_action_delegate_,
- OnSetFieldValue("John Doe",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expected_selector)),
- _))
+ SetValueAttribute("John Doe",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.After(set_value)
@@ -314,10 +318,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FallsBackForForcedFilledField) {
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "value"));
Selector expected_selector({"#card_name"});
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("John Doe",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expected_selector)),
- _))
+ SetValueAttribute("John Doe",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
std::vector<RequiredField> required_fields = {
@@ -342,7 +346,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FallsBackForForcedFilledField) {
TEST_F(RequiredFieldsFallbackHandlerTest, FailsIfForcedFieldDidNotGetFilled) {
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "value"));
- EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_, SetValueAttribute(_, _, _)).Times(0);
std::vector<RequiredField> required_fields = {
CreateRequiredField("${51}", {"#card_name"})};
@@ -389,10 +393,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, FillsFieldWithPattern) {
Expectation set_value =
EXPECT_CALL(
mock_action_delegate_,
- OnSetFieldValue("08/2050",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expected_selector)),
- _))
+ SetValueAttribute("08/2050",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.After(set_value)
@@ -424,7 +428,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.Times(2)
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_, SetValueAttribute(_, _, _)).Times(0);
std::vector<RequiredField> required_fields = {
CreateRequiredField("${53}", {"#card_expiry"}),
@@ -481,22 +485,33 @@ TEST_F(RequiredFieldsFallbackHandlerTest,
}
TEST_F(RequiredFieldsFallbackHandlerTest, UsesSelectOptionForDropdowns) {
+ InSequence sequence;
+
Selector expected_selector({"#year"});
+
+ // First validation fails.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ // Fill field.
const ElementFinder::Result& expected_element =
test_util::MockFindElement(mock_action_delegate_, expected_selector);
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expected_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
EXPECT_CALL(mock_action_delegate_,
GetElementTag(EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "SELECT"));
- Expectation select_option =
- EXPECT_CALL(
- mock_action_delegate_,
- SelectOption("2050", DropdownSelectStrategy::LABEL_STARTS_WITH,
- EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<3>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expected_selector, _))
- .After(select_option)
+ EXPECT_CALL(mock_action_delegate_,
+ SelectOption("2050", DropdownSelectStrategy::LABEL_STARTS_WITH,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ // Second validation succeeds.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "2050"));
std::vector<RequiredField> required_fields = {
@@ -519,7 +534,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest, UsesSelectOptionForDropdowns) {
TEST_F(RequiredFieldsFallbackHandlerTest, ClicksOnCustomDropdown) {
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
- EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_, SetValueAttribute(_, _, _)).Times(0);
Selector expected_main_selector({"#card_expiry"});
EXPECT_CALL(
mock_action_delegate_,
@@ -530,10 +545,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, ClicksOnCustomDropdown) {
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
Selector expected_option_selector({".option"});
expected_option_selector.MatchingInnerText("08");
- expected_option_selector.MustBeVisible();
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_option_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
EXPECT_CALL(
mock_action_delegate_,
ClickOrTapElement(ClickType::TAP,
@@ -563,7 +578,7 @@ TEST_F(RequiredFieldsFallbackHandlerTest, ClicksOnCustomDropdown) {
TEST_F(RequiredFieldsFallbackHandlerTest, CustomDropdownClicksStopOnError) {
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
- EXPECT_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _)).Times(0);
+ EXPECT_CALL(mock_action_delegate_, SetValueAttribute(_, _, _)).Times(0);
Selector expected_main_selector({"#card_expiry"});
Expectation main_click =
EXPECT_CALL(
@@ -575,10 +590,10 @@ TEST_F(RequiredFieldsFallbackHandlerTest, CustomDropdownClicksStopOnError) {
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
Selector expected_option_selector({".option"});
expected_option_selector.MatchingInnerText("08");
- expected_option_selector.MustBeVisible();
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_option_selector, _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ base::TimeDelta::FromSeconds(0)));
EXPECT_CALL(mock_action_delegate_, FindElement(_, _))
.Times(0)
.After(main_click);
@@ -605,41 +620,74 @@ TEST_F(RequiredFieldsFallbackHandlerTest, CustomDropdownClicksStopOnError) {
}));
}
-TEST_F(RequiredFieldsFallbackHandlerTest, ClearsFilledFields) {
- Selector full_field_selector({"#full_field"});
- Selector empty_field_selector({"#empty_field"});
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(full_field_selector, _))
+TEST_F(RequiredFieldsFallbackHandlerTest, ClearsFilledField) {
+ InSequence sequence;
+
+ Selector expected_selector({"#field"});
+
+ // First validation fails
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "value"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(empty_field_selector, _))
- .Times(0);
- Expectation clear_full_value =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, full_field_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(full_field_selector, _))
- .After(clear_full_value)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- Expectation clear_empty_value =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, empty_field_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(empty_field_selector, _))
- .After(clear_empty_value)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
+ // Clears field.
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(std::string(),
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ // Second validation succeeds.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ std::vector<RequiredField> required_fields = {
+ CreateRequiredField(std::string(), {"#field"})};
+ std::map<std::string, std::string> fallback_values;
+
+ RequiredFieldsFallbackHandler fallback_handler(
+ required_fields, fallback_values, &mock_action_delegate_);
+ fallback_handler.CheckAndFallbackRequiredFields(
+ OkClientStatus(),
+ base::BindOnce([](const ClientStatus& status,
+ const base::Optional<ClientStatus>& detail_status) {
+ EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
+ }));
+}
+
+TEST_F(RequiredFieldsFallbackHandlerTest, SkipsForcedFieldCheckOnFirstRun) {
+ InSequence sequence;
+
+ Selector forced_field_selector({"#forced_field"});
+
+ // First validation skips forced fields.
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
+
+ // Fills field.
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("value",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, forced_field_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+
+ // Second validation checks the field.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, forced_field_selector)),
+ _))
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "value"));
- auto non_forced_field = CreateRequiredField("", {"#full_field"});
- auto forced_field = CreateRequiredField("", {"#empty_field"});
+ auto forced_field = CreateRequiredField("value", {"#forced_field"});
forced_field.forced = true;
- std::vector<RequiredField> required_fields = {non_forced_field, forced_field};
+ std::vector<RequiredField> required_fields = {forced_field};
std::map<std::string, std::string> fallback_values;
diff --git a/chromium/components/autofill_assistant/browser/actions/focus_element_action.cc b/chromium/components/autofill_assistant/browser/actions/focus_element_action.cc
deleted file mode 100644
index 126fe3917e6..00000000000
--- a/chromium/components/autofill_assistant/browser/actions/focus_element_action.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2018 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_assistant/browser/actions/focus_element_action.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "components/autofill_assistant/browser/actions/action_delegate.h"
-#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/service.pb.h"
-
-namespace autofill_assistant {
-
-FocusElementAction::FocusElementAction(ActionDelegate* delegate,
- const ActionProto& proto)
- : Action(delegate, proto) {
- DCHECK(proto_.has_focus_element());
-}
-
-FocusElementAction::~FocusElementAction() {}
-
-void FocusElementAction::InternalProcessAction(ProcessActionCallback callback) {
- const FocusElementProto& focus_element = proto_.focus_element();
- if (focus_element.has_title()) {
- // TODO(crbug.com/806868): Deprecate and remove message from this action and
- // use tell instead.
- delegate_->SetStatusMessage(focus_element.title());
- }
- Selector selector = Selector(focus_element.element()).MustBeVisible();
- if (selector.empty()) {
- VLOG(1) << __func__ << ": empty selector";
- UpdateProcessedAction(INVALID_SELECTOR);
- std::move(callback).Run(std::move(processed_action_proto_));
- return;
- }
-
- // Default value of 25%. This value should always be overriden
- // by backend.
- TopPadding top_padding{0.25, TopPadding::Unit::RATIO};
- switch (focus_element.top_padding().top_padding_case()) {
- case FocusElementProto::TopPadding::kPixels:
- top_padding = TopPadding(focus_element.top_padding().pixels(),
- TopPadding::Unit::PIXELS);
- break;
- case FocusElementProto::TopPadding::kRatio:
- top_padding = TopPadding(focus_element.top_padding().ratio(),
- TopPadding::Unit::RATIO);
- break;
- case FocusElementProto::TopPadding::TOP_PADDING_NOT_SET:
- // Default value set before switch.
- break;
- }
-
- delegate_->ShortWaitForElement(
- selector, base::BindOnce(&FocusElementAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(callback), selector, top_padding));
-}
-
-void FocusElementAction::OnWaitForElement(ProcessActionCallback callback,
- const Selector& selector,
- const TopPadding& top_padding,
- const ClientStatus& element_status) {
- if (!element_status.ok()) {
- UpdateProcessedAction(element_status.proto_status());
- std::move(callback).Run(std::move(processed_action_proto_));
- return;
- }
-
- delegate_->FocusElement(
- selector, top_padding,
- base::BindOnce(&FocusElementAction::OnFocusElement,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void FocusElementAction::OnFocusElement(ProcessActionCallback callback,
- const ClientStatus& status) {
- delegate_->SetTouchableElementArea(
- proto().focus_element().touchable_element_area());
- UpdateProcessedAction(status);
- std::move(callback).Run(std::move(processed_action_proto_));
-}
-
-} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/focus_element_action.h b/chromium/components/autofill_assistant/browser/actions/focus_element_action.h
deleted file mode 100644
index cc7b665509c..00000000000
--- a/chromium/components/autofill_assistant/browser/actions/focus_element_action.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 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_ASSISTANT_BROWSER_ACTIONS_FOCUS_ELEMENT_ACTION_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_FOCUS_ELEMENT_ACTION_H_
-
-#include "components/autofill_assistant/browser/actions/action.h"
-#include "components/autofill_assistant/browser/top_padding.h"
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-namespace autofill_assistant {
-
-// An action to focus a given element on Web. Scrolling to it first if required.
-class FocusElementAction : public Action {
- public:
- explicit FocusElementAction(ActionDelegate* delegate,
- const ActionProto& proto);
- ~FocusElementAction() override;
-
- private:
- // Overrides Action:
- void InternalProcessAction(ProcessActionCallback callback) override;
-
- void OnWaitForElement(ProcessActionCallback callback,
- const Selector& selector,
- const TopPadding& top_padding,
- const ClientStatus& element_status);
- void OnFocusElement(ProcessActionCallback callback,
- const ClientStatus& status);
-
- base::WeakPtrFactory<FocusElementAction> weak_ptr_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(FocusElementAction);
-};
-
-} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_FOCUS_ELEMENT_ACTION_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc b/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
index 0205448d797..aaecfbba1be 100644
--- a/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action.cc
@@ -29,9 +29,7 @@ void GeneratePasswordForFormFieldAction::InternalProcessAction(
ProcessActionCallback callback) {
callback_ = std::move(callback);
- selector_ = Selector(proto_.generate_password_for_form_field().element())
- .MustBeVisible();
-
+ selector_ = Selector(proto_.generate_password_for_form_field().element());
if (selector_.empty()) {
VLOG(1) << __func__ << ": empty selector";
EndAction(ClientStatus(INVALID_SELECTOR));
diff --git a/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
index 4880d7d33f2..05d07313573 100644
--- a/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/generate_password_for_form_field_action_unittest.cc
@@ -66,8 +66,7 @@ TEST_F(GeneratePasswordForFormFieldActionTest, GeneratedPassword) {
autofill::FormFieldData()));
GeneratePasswordForFormFieldProto* generate_password_proto =
proto_.mutable_generate_password_for_form_field();
- *generate_password_proto->mutable_element() =
- Selector({kFakeSelector}).MustBeVisible().proto;
+ *generate_password_proto->mutable_element() = Selector({kFakeSelector}).proto;
generate_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
GeneratePasswordForFormFieldAction action(&mock_action_delegate_, proto_);
diff --git a/chromium/components/autofill_assistant/browser/actions/get_element_status_action.cc b/chromium/components/autofill_assistant/browser/actions/get_element_status_action.cc
new file mode 100644
index 00000000000..eded04bac2a
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/get_element_status_action.cc
@@ -0,0 +1,226 @@
+// Copyright 2020 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_assistant/browser/actions/get_element_status_action.h"
+
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
+#include "third_party/re2/src/re2/re2.h"
+
+namespace autofill_assistant {
+namespace {
+
+struct MaybeRe2 {
+ std::string value;
+ bool is_re2 = false;
+};
+
+std::string RemoveWhitespace(const std::string& value) {
+ std::string copy = value;
+ base::EraseIf(copy, base::IsUnicodeWhitespace);
+ return copy;
+}
+
+GetElementStatusProto::ComparisonReport CreateComparisonReport(
+ const std::string& actual,
+ const MaybeRe2& re2,
+ bool case_sensitive,
+ bool remove_space) {
+ GetElementStatusProto::ComparisonReport report;
+ report.mutable_match_options()->set_case_sensitive(case_sensitive);
+ report.mutable_match_options()->set_remove_space(remove_space);
+
+ std::string actual_for_match =
+ remove_space ? RemoveWhitespace(actual) : actual;
+ report.set_empty(actual_for_match.empty());
+
+ std::string value_for_match =
+ !re2.is_re2 && remove_space ? RemoveWhitespace(re2.value) : re2.value;
+
+ if (!re2.is_re2 && value_for_match.empty()) {
+ if (actual_for_match.empty()) {
+ report.set_expected_empty_match(true);
+ report.set_full_match(true);
+ report.set_contains(true);
+ report.set_starts_with(true);
+ report.set_ends_with(true);
+ }
+ return report;
+ }
+
+ std::string re2_for_match =
+ re2.is_re2 ? re2.value : re2::RE2::QuoteMeta(value_for_match);
+
+ re2::RE2::Options options;
+ options.set_case_sensitive(case_sensitive);
+ re2::RE2 regexp(re2_for_match, options);
+ std::string match;
+ bool found_match = RE2::Extract(actual_for_match, regexp, "\\0", &match);
+
+ if (!found_match) {
+ return report;
+ }
+
+ report.set_expected_empty_match(match.empty());
+ report.set_full_match(actual_for_match == match);
+ size_t pos = actual_for_match.find(match);
+ report.set_contains(pos != std::string::npos);
+ report.set_starts_with(pos != std::string::npos && pos == 0);
+ report.set_ends_with(pos != std::string::npos &&
+ pos == actual_for_match.size() - match.size());
+ return report;
+}
+
+} // namespace
+
+GetElementStatusAction::GetElementStatusAction(ActionDelegate* delegate,
+ const ActionProto& proto)
+ : Action(delegate, proto) {
+ DCHECK(proto_.has_get_element_status());
+}
+
+GetElementStatusAction::~GetElementStatusAction() = default;
+
+void GetElementStatusAction::InternalProcessAction(
+ ProcessActionCallback callback) {
+ callback_ = std::move(callback);
+ selector_ = Selector(proto_.get_element_status().element());
+
+ if (selector_.empty()) {
+ VLOG(1) << __func__ << ": empty selector";
+ EndAction(ClientStatus(INVALID_SELECTOR));
+ return;
+ }
+
+ delegate_->ShortWaitForElement(
+ selector_,
+ base::BindOnce(&GetElementStatusAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&GetElementStatusAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void GetElementStatusAction::OnWaitForElement(
+ const ClientStatus& element_status) {
+ if (!element_status.ok()) {
+ EndAction(element_status);
+ return;
+ }
+
+ std::vector<std::string> attribute_list;
+ switch (proto_.get_element_status().value_source()) {
+ case GetElementStatusProto::VALUE:
+ attribute_list.emplace_back("value");
+ break;
+ case GetElementStatusProto::INNER_TEXT:
+ attribute_list.emplace_back("innerText");
+ break;
+ case GetElementStatusProto::NOT_SET:
+ EndAction(ClientStatus(INVALID_ACTION));
+ return;
+ }
+
+ delegate_->FindElement(
+ selector_,
+ base::BindOnce(
+ &action_delegate_util::TakeElementAndGetProperty<std::string>,
+ base::BindOnce(&ActionDelegate::GetStringAttribute,
+ delegate_->GetWeakPtr(), attribute_list),
+ base::BindOnce(&GetElementStatusAction::OnGetStringAttribute,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void GetElementStatusAction::OnGetStringAttribute(const ClientStatus& status,
+ const std::string& text) {
+ if (!status.ok()) {
+ EndAction(status);
+ return;
+ }
+
+ const auto& expected_match =
+ proto_.get_element_status().expected_value_match().text_match();
+ MaybeRe2 expected_re2;
+ switch (expected_match.value_source_case()) {
+ case GetElementStatusProto::TextMatch::kValue:
+ expected_re2.value = expected_match.value();
+ break;
+ case GetElementStatusProto::TextMatch::kAutofillValue: {
+ ClientStatus autofill_status = GetFormattedAutofillValue(
+ expected_match.autofill_value(), delegate_->GetUserData(),
+ &expected_re2.value);
+ if (!autofill_status.ok()) {
+ EndAction(autofill_status);
+ return;
+ }
+ break;
+ }
+ case GetElementStatusProto::TextMatch::kRe2:
+ expected_re2.value = expected_match.re2();
+ expected_re2.is_re2 = true;
+ break;
+ case GetElementStatusProto::TextMatch::VALUE_SOURCE_NOT_SET:
+ EndAction(ClientStatus(INVALID_ACTION));
+ return;
+ }
+
+ auto* result = processed_action_proto_->mutable_get_element_status_result();
+ result->set_not_empty(!text.empty());
+
+ bool success = true;
+ *result->add_reports() = CreateComparisonReport(
+ text, expected_re2, /* case_sensitive= */ true, /* remove_space= */ true);
+ *result->add_reports() =
+ CreateComparisonReport(text, expected_re2, /* case_sensitive= */ true,
+ /* remove_space= */ false);
+ *result->add_reports() =
+ CreateComparisonReport(text, expected_re2, /* case_sensitive= */ false,
+ /* remove_space= */ true);
+ *result->add_reports() =
+ CreateComparisonReport(text, expected_re2, /* case_sensitive= */ false,
+ /* remove_space= */ false);
+
+ if (expected_match.has_match_expectation()) {
+ const auto& expectation = expected_match.match_expectation();
+ auto report = CreateComparisonReport(
+ text, expected_re2, expectation.match_options().case_sensitive(),
+ expectation.match_options().remove_space());
+
+ switch (expectation.match_level_case()) {
+ case GetElementStatusProto::MatchExpectation::MATCH_LEVEL_NOT_SET:
+ case GetElementStatusProto::MatchExpectation::kFullMatch:
+ success = report.full_match();
+ break;
+ case GetElementStatusProto::MatchExpectation::kContains:
+ success = report.contains();
+ break;
+ case GetElementStatusProto::MatchExpectation::kStartsWith:
+ success = report.starts_with();
+ break;
+ case GetElementStatusProto::MatchExpectation::kEndsWith:
+ success = report.ends_with();
+ break;
+ }
+
+ result->set_expected_empty_match(report.expected_empty_match());
+ result->set_match_success(success);
+ }
+
+ EndAction(!success && proto_.get_element_status().mismatch_should_fail()
+ ? ClientStatus(ELEMENT_MISMATCH)
+ : OkClientStatus());
+}
+
+void GetElementStatusAction::EndAction(const ClientStatus& status) {
+ UpdateProcessedAction(status);
+ std::move(callback_).Run(std::move(processed_action_proto_));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/get_element_status_action.h b/chromium/components/autofill_assistant/browser/actions/get_element_status_action.h
new file mode 100644
index 00000000000..f4f54f318a7
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/get_element_status_action.h
@@ -0,0 +1,42 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_ACTIONS_GET_ELEMENT_STATUS_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_GET_ELEMENT_STATUS_ACTION_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+
+namespace autofill_assistant {
+
+// Action to get an element's status.
+class GetElementStatusAction : public Action {
+ public:
+ explicit GetElementStatusAction(ActionDelegate* delegate,
+ const ActionProto& proto);
+ ~GetElementStatusAction() override;
+
+ GetElementStatusAction(const GetElementStatusAction&) = delete;
+ GetElementStatusAction& operator=(const GetElementStatusAction&) = delete;
+
+ private:
+ // Overrides Action:
+ void InternalProcessAction(ProcessActionCallback callback) override;
+
+ void OnWaitForElement(const ClientStatus& element_status);
+ void OnGetStringAttribute(const ClientStatus& status,
+ const std::string& text);
+
+ void EndAction(const ClientStatus& status);
+
+ Selector selector_;
+ ProcessActionCallback callback_;
+ base::WeakPtrFactory<GetElementStatusAction> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_GET_ELEMENT_STATUS_ACTION_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
new file mode 100644
index 00000000000..5a98281cf49
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
@@ -0,0 +1,546 @@
+// Copyright 2020 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_assistant/browser/actions/get_element_status_action.h"
+
+#include "base/guid.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Pointee;
+using ::testing::Property;
+using ::testing::Return;
+using ::testing::SizeIs;
+using ::testing::UnorderedElementsAre;
+
+const char kValue[] = "Some Value";
+
+class GetElementStatusActionTest : public testing::Test {
+ public:
+ GetElementStatusActionTest() {}
+
+ void SetUp() override {
+ ON_CALL(mock_action_delegate_, GetUserData)
+ .WillByDefault(Return(&user_data_));
+ ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ test_util::MockFindAnyElement(mock_action_delegate_);
+ ON_CALL(mock_action_delegate_, GetStringAttribute(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), kValue));
+
+ proto_.set_value_source(GetElementStatusProto::VALUE);
+ }
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_get_element_status() = proto_;
+ GetElementStatusAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ GetElementStatusProto proto_;
+ UserData user_data_;
+};
+
+TEST_F(GetElementStatusActionTest, EmptySelectorFails) {
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionFailsForNonExistentElement) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ kValue);
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(selector, _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(TIMED_OUT),
+ base::TimeDelta::FromSeconds(0)));
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, TIMED_OUT))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionReportsAllVariations) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ kValue);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::reports,
+ SizeIs(4))))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionFailsForMismatchIfRequired) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "other");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ELEMENT_MISMATCH),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ false)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForMismatchIfAllowed) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "other");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ false)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForNoExpectation) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "other");
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(&ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForCaseSensitiveFullMatch) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ kValue);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, selector);
+ EXPECT_CALL(mock_action_delegate_,
+ GetStringAttribute(ElementsAre("value"),
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus(), kValue));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForCaseSensitiveContains) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "me Va");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_contains(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForCaseSensitiveStartsWith) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "Some");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_starts_with(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForCaseSensitiveEndsWith) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "Value");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_ends_with(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForCaseInsensitiveFullMatch) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "sOmE vAlUe");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(false);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionSucceedsForFullMatchWithoutSpaces) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ "S o m eV a l u e");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_remove_space(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, EmptyTextForEmptyValueIsSuccess) {
+ ON_CALL(mock_action_delegate_, GetStringAttribute(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), std::string()));
+
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ std::string());
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(
+ Property(&GetElementStatusProto::Result::not_empty, false),
+ Property(&GetElementStatusProto::Result::match_success, true),
+ Property(&GetElementStatusProto::Result::expected_empty_match,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, InnerTextLookupSuccess) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(
+ kValue);
+ proto_.set_value_source(GetElementStatusProto::INNER_TEXT);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, selector);
+ EXPECT_CALL(mock_action_delegate_,
+ GetStringAttribute(ElementsAre("innerText"),
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus(), kValue));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, MatchingValueWithRegexpCaseSensitive) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_re2("Valu.");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_ends_with(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, MatchingValueWithRegexpCaseInsensitive) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_re2("vAlU.");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_case_sensitive(false);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_ends_with(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, ActionFailsForRegexMismatchIfRequired) {
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_re2("none");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ELEMENT_MISMATCH),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success,
+ false)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, EmptyRegexpForEmptyValueIsSuccess) {
+ ON_CALL(mock_action_delegate_, GetStringAttribute(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), std::string()));
+
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_re2("^$");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(
+ Property(&GetElementStatusProto::Result::not_empty, false),
+ Property(&GetElementStatusProto::Result::match_success, true),
+ Property(&GetElementStatusProto::Result::expected_empty_match,
+ true)))))));
+ Run();
+}
+
+TEST_F(GetElementStatusActionTest, BlankTextWithRemovingSpacesIsExpectedEmpty) {
+ ON_CALL(mock_action_delegate_, GetStringAttribute(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), " "));
+
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+ proto_.mutable_expected_value_match()->mutable_text_match()->set_value(" ");
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->mutable_match_options()
+ ->set_remove_space(true);
+ proto_.mutable_expected_value_match()
+ ->mutable_text_match()
+ ->mutable_match_expectation()
+ ->set_full_match(true);
+ proto_.set_mismatch_should_fail(true);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(
+ &ProcessedActionProto::get_element_status_result,
+ AllOf(
+ // The field is not empty (it is blank), but the match is
+ // still a success and expects to be empty given the
+ // configuration.
+ Property(&GetElementStatusProto::Result::not_empty, true),
+ Property(&GetElementStatusProto::Result::match_success, true),
+ Property(&GetElementStatusProto::Result::expected_empty_match,
+ true)))))));
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/highlight_element_action.cc b/chromium/components/autofill_assistant/browser/actions/highlight_element_action.cc
index a685f343db3..2b6c5698a5d 100644
--- a/chromium/components/autofill_assistant/browser/actions/highlight_element_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/highlight_element_action.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/client_status.h"
namespace autofill_assistant {
@@ -23,18 +24,21 @@ HighlightElementAction::~HighlightElementAction() {}
void HighlightElementAction::InternalProcessAction(
ProcessActionCallback callback) {
- Selector selector =
- Selector(proto_.highlight_element().element()).MustBeVisible();
+ Selector selector = Selector(proto_.highlight_element().element());
if (selector.empty()) {
VLOG(1) << __func__ << ": empty selector";
UpdateProcessedAction(INVALID_SELECTOR);
std::move(callback).Run(std::move(processed_action_proto_));
return;
}
+
delegate_->ShortWaitForElement(
- selector, base::BindOnce(&HighlightElementAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(callback), selector));
+ selector,
+ base::BindOnce(&HighlightElementAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&HighlightElementAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), selector)));
}
void HighlightElementAction::OnWaitForElement(
@@ -47,8 +51,10 @@ void HighlightElementAction::OnWaitForElement(
return;
}
- delegate_->HighlightElement(
- selector,
+ action_delegate_util::FindElementAndPerform(
+ delegate_, selector,
+ base::BindOnce(&ActionDelegate::HighlightElement,
+ delegate_->GetWeakPtr()),
base::BindOnce(&HighlightElementAction::OnHighlightElement,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
diff --git a/chromium/components/autofill_assistant/browser/actions/highlight_element_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/highlight_element_action_unittest.cc
new file mode 100644
index 00000000000..d22c3e026fd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/highlight_element_action_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 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_assistant/browser/actions/highlight_element_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Pointee;
+using ::testing::Property;
+
+class HighlightElementActionTest : public testing::Test {
+ public:
+ HighlightElementActionTest() {}
+
+ void SetUp() override {}
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_highlight_element() = proto_;
+ HighlightElementAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ HighlightElementProto proto_;
+};
+
+TEST_F(HighlightElementActionTest, EmptySelectorFails) {
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR))));
+ Run();
+}
+
+TEST_F(HighlightElementActionTest, ActionFailsForNonExistentElement) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+
+ Selector expected_selector = selector;
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(expected_selector, _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(TIMED_OUT),
+ base::TimeDelta::FromSeconds(0)));
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, TIMED_OUT))));
+ Run();
+}
+
+TEST_F(HighlightElementActionTest, CheckExpectedCallChain) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_element() = selector.proto;
+
+ Selector expected_selector = selector;
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(expected_selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+ EXPECT_CALL(mock_action_delegate_,
+ HighlightElement(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h b/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
index e02175a3d2c..00e901e3c39 100644
--- a/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/time/time.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
@@ -34,12 +35,14 @@ class MockActionDelegate : public ActionDelegate {
void ShortWaitForElement(
const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)> callback) override {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback)
+ override {
OnShortWaitForElement(selector, callback);
}
- MOCK_METHOD2(OnShortWaitForElement,
- void(const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)>&));
+ MOCK_METHOD2(
+ OnShortWaitForElement,
+ void(const Selector& selector,
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>&));
void WaitForDom(
base::TimeDelta max_wait_time,
@@ -47,16 +50,18 @@ class MockActionDelegate : public ActionDelegate {
base::RepeatingCallback<
void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)> check_elements,
- base::OnceCallback<void(const ClientStatus&)> callback) override {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback)
+ override {
OnWaitForDom(max_wait_time, allow_interrupt, check_elements, callback);
}
- MOCK_METHOD4(OnWaitForDom,
- void(base::TimeDelta,
- bool,
- base::RepeatingCallback<
- void(BatchElementChecker*,
- base::OnceCallback<void(const ClientStatus&)>)>&,
- base::OnceCallback<void(const ClientStatus&)>&));
+ MOCK_METHOD4(
+ OnWaitForDom,
+ void(base::TimeDelta,
+ bool,
+ base::RepeatingCallback<
+ void(BatchElementChecker*,
+ base::OnceCallback<void(const ClientStatus&)>)>&,
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>&));
MOCK_METHOD1(SetStatusMessage, void(const std::string& message));
@@ -66,19 +71,29 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD0(GetBubbleMessage, std::string());
- MOCK_METHOD2(FindElement,
- void(const Selector& selector, ElementFinder::Callback));
+ MOCK_CONST_METHOD2(FindElement,
+ void(const Selector& selector, ElementFinder::Callback));
+
+ MOCK_CONST_METHOD2(FindAllElements,
+ void(const Selector& selector,
+ ElementFinder::Callback callback));
MOCK_METHOD3(ClickOrTapElement,
void(ClickType click_type,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
- MOCK_METHOD2(WaitForDocumentToBecomeInteractive,
+ MOCK_METHOD2(ScrollIntoView,
void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
- MOCK_METHOD2(ScrollIntoView,
+ MOCK_METHOD4(WaitUntilElementIsStable,
+ void(int,
+ base::TimeDelta,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback));
+
+ MOCK_METHOD2(CheckOnTop,
void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
@@ -91,7 +106,7 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD0(CleanUpAfterPrompt, void());
- MOCK_METHOD1(SetBrowseDomainsWhitelist,
+ MOCK_METHOD1(SetBrowseDomainsAllowlist,
void(std::vector<std::string> domains));
void FillAddressForm(
@@ -141,16 +156,17 @@ class MockActionDelegate : public ActionDelegate {
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
- MOCK_METHOD3(FocusElement,
+ MOCK_METHOD4(ScrollToElementPosition,
void(const Selector& selector,
const TopPadding& top_padding,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
MOCK_METHOD1(SetTouchableElementArea,
void(const ElementAreaProto& touchable_element_area));
MOCK_METHOD2(HighlightElement,
- void(const Selector& selector,
+ void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
MOCK_METHOD1(CollectUserData,
@@ -178,37 +194,21 @@ class MockActionDelegate : public ActionDelegate {
base::OnceCallback<void(std::unique_ptr<autofill::CreditCard> card,
const base::string16& cvc)>& callback));
- void GetFieldValue(const Selector& selector,
- base::OnceCallback<void(const ClientStatus&,
- const std::string&)> callback) {
- OnGetFieldValue(selector, callback);
- }
- MOCK_METHOD2(OnGetFieldValue,
- void(const Selector& selector,
+ MOCK_METHOD2(GetFieldValue,
+ void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&,
- const std::string&)>& callback));
-
- void SetFieldValue(const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
- const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- OnSetFieldValue(value, element, callback);
- OnSetFieldValue(value,
- fill_strategy == SIMULATE_KEY_PRESSES ||
- fill_strategy == SIMULATE_KEY_PRESSES_SELECT_VALUE,
- key_press_delay_in_millisecond, element, callback);
- }
- MOCK_METHOD3(OnSetFieldValue,
- void(const std::string& value,
+ const std::string&)> callback));
+
+ MOCK_METHOD3(GetStringAttribute,
+ void(const std::vector<std::string>& attributes,
const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)>& callback));
- MOCK_METHOD5(OnSetFieldValue,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::string&)> callback));
+
+ MOCK_METHOD3(SetValueAttribute,
void(const std::string& value,
- bool simulate_key_presses,
- int delay_in_millisecond,
const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)>& callback));
+ base::OnceCallback<void(const ClientStatus&)> callback));
MOCK_METHOD4(SetAttribute,
void(const std::vector<std::string>& attribute,
@@ -216,6 +216,14 @@ class MockActionDelegate : public ActionDelegate {
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback));
+ MOCK_METHOD2(SelectFieldValue,
+ void(const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback));
+
+ MOCK_METHOD2(FocusField,
+ void(const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback));
+
void SendKeyboardInput(
const std::vector<UChar32>& codepoints,
int delay_in_millisecond,
@@ -230,10 +238,16 @@ class MockActionDelegate : public ActionDelegate {
base::OnceCallback<void(const ClientStatus&)>& callback));
MOCK_METHOD2(GetOuterHtml,
- void(const Selector& selector,
+ void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback));
+ MOCK_METHOD2(
+ GetOuterHtmls,
+ void(const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback));
+
MOCK_METHOD2(GetElementTag,
void(const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&,
@@ -244,7 +258,7 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD1(WaitForNavigation,
bool(base::OnceCallback<void(bool)> callback));
MOCK_METHOD1(LoadURL, void(const GURL& url));
- MOCK_METHOD0(Shutdown, void());
+ MOCK_METHOD1(Shutdown, void(bool show_feedback_chip));
MOCK_METHOD0(Close, void());
MOCK_METHOD0(Restart, void());
MOCK_CONST_METHOD0(GetUserData, UserData*());
@@ -293,30 +307,40 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD2(
OnGetDocumentReadyState,
- void(const Selector&,
+ void(const ElementFinder::Result&,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>&));
void GetDocumentReadyState(
- const Selector& frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) override {
- OnGetDocumentReadyState(frame, callback);
+ OnGetDocumentReadyState(optional_frame_element, callback);
}
- MOCK_METHOD3(
- OnWaitForDocumentReadyState,
- void(const Selector&,
- DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>&));
+ MOCK_METHOD3(OnWaitForDocumentReadyState,
+ void(DocumentReadyState,
+ const ElementFinder::Result&,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)>&));
void WaitForDocumentReadyState(
- const Selector& frame,
+ base::TimeDelta max_wait_time,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) override {
- OnWaitForDocumentReadyState(frame, min_ready_state, callback);
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) override {
+ OnWaitForDocumentReadyState(min_ready_state, optional_frame_element,
+ callback);
}
+ MOCK_METHOD4(WaitUntilDocumentIsInReadyState,
+ void(base::TimeDelta,
+ DocumentReadyState,
+ const ElementFinder::Result&,
+ base::OnceCallback<void(const ClientStatus&)>));
+
MOCK_METHOD0(RequireUI, void());
MOCK_METHOD0(SetExpandSheetForPromptAction, bool());
@@ -339,11 +363,13 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD1(SetOverlayBehavior,
void(ConfigureUiStateProto::OverlayBehavior));
- base::WeakPtr<ActionDelegate> GetWeakPtr() override {
+ base::WeakPtr<ActionDelegate> GetWeakPtr() const override {
return weak_ptr_factory_.GetWeakPtr();
}
- const ClientSettings& GetSettings() override { return client_settings_; }
+ const ClientSettings& GetSettings() const override {
+ return client_settings_;
+ }
ClientSettings client_settings_;
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action.cc b/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
index d58874a585d..4980a7837cd 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
@@ -13,7 +13,6 @@
#include "base/callback.h"
#include "base/strings/string_number_conversions.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
-#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/element_precondition.h"
#include "url/gurl.h"
@@ -40,28 +39,34 @@ void PromptAction::InternalProcessAction(ProcessActionCallback callback) {
}
if (proto_.prompt().browse_mode()) {
- delegate_->SetBrowseDomainsWhitelist(
- {proto_.prompt().browse_domains_whitelist().begin(),
- proto_.prompt().browse_domains_whitelist().end()});
+ delegate_->SetBrowseDomainsAllowlist(
+ {proto_.prompt().browse_domains_allowlist().begin(),
+ proto_.prompt().browse_domains_allowlist().end()});
}
SetupConditions();
UpdateUserActions();
+ wait_time_stopwatch_.Start();
if (HasNonemptyPreconditions() || auto_select_ ||
proto_.prompt().allow_interrupt()) {
- delegate_->WaitForDom(base::TimeDelta::Max(),
- proto_.prompt().allow_interrupt(),
- base::BindRepeating(&PromptAction::RegisterChecks,
- weak_ptr_factory_.GetWeakPtr()),
- base::BindOnce(&PromptAction::OnDoneWaitForDom,
- weak_ptr_factory_.GetWeakPtr()));
+ delegate_->WaitForDom(
+ base::TimeDelta::Max(), proto_.prompt().allow_interrupt(),
+ base::BindRepeating(&PromptAction::RegisterChecks,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&PromptAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&PromptAction::OnDoneWaitForDom,
+ weak_ptr_factory_.GetWeakPtr())));
}
}
void PromptAction::RegisterChecks(
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> wait_for_dom_callback) {
+ last_period_stopwatch_.Stop();
+ last_checks_stopwatch_.Reset();
+ last_checks_stopwatch_.Start();
if (!callback_) {
// Action is done; checks aren't necessary anymore.
std::move(wait_for_dom_callback).Run(OkClientStatus());
@@ -90,12 +95,15 @@ void PromptAction::SetupConditions() {
int choice_count = proto_.prompt().choices_size();
preconditions_.resize(choice_count);
precondition_results_.resize(choice_count);
+ positive_precondition_changes_.resize(choice_count);
+ precondition_stopwatches_.resize(choice_count);
for (int i = 0; i < choice_count; i++) {
auto& choice_proto = proto_.prompt().choices(i);
preconditions_[i] =
std::make_unique<ElementPrecondition>(choice_proto.show_only_when());
precondition_results_[i] = preconditions_[i]->empty();
+ positive_precondition_changes_[i] = false;
}
ElementConditionsProto auto_select;
@@ -131,6 +139,7 @@ void PromptAction::OnPreconditionResult(
return;
precondition_results_[choice_index] = precondition_is_met;
+ positive_precondition_changes_[choice_index] = precondition_is_met;
precondition_changed_ = true;
}
@@ -167,6 +176,23 @@ void PromptAction::UpdateUserActions() {
precondition_changed_ = false;
}
+void PromptAction::UpdateTimings() {
+ for (int i = 0; i < proto_.prompt().choices_size(); i++) {
+ if (!precondition_results_[i]) {
+ precondition_stopwatches_[i].Reset();
+ } else if (positive_precondition_changes_[i]) {
+ positive_precondition_changes_[i] = false;
+ // The precondition now contains the duration of the wait for dom
+ // operation retry period plus the time that it took to perform the actual
+ // checks. We want to instead record only half of the period plus the
+ // checks.
+ precondition_stopwatches_[i].AddTime(last_checks_stopwatch_);
+ precondition_stopwatches_[i].AddTime(
+ last_period_stopwatch_.TotalElapsed() / 2);
+ }
+ }
+}
+
void PromptAction::OnAutoSelectCondition(
const ClientStatus& status,
const std::vector<std::string>& payloads) {
@@ -184,8 +210,14 @@ void PromptAction::OnAutoSelectCondition(
void PromptAction::OnElementChecksDone(
base::OnceCallback<void(const ClientStatus&)> wait_for_dom_callback) {
- if (precondition_changed_)
+ last_checks_stopwatch_.Stop();
+ if (precondition_changed_) {
UpdateUserActions();
+ }
+
+ UpdateTimings();
+ last_period_stopwatch_.Reset();
+ last_period_stopwatch_.Start();
// Calling wait_for_dom_callback with successful status is a way of asking the
// WaitForDom to end gracefully and call OnDoneWaitForDom with the status.
@@ -220,6 +252,14 @@ void PromptAction::OnSuggestionChosen(int choice_index) {
NOTREACHED();
return;
}
+
+ if (auto_select_choice_index_ < 0) {
+ wait_time_stopwatch_.Stop();
+ action_stopwatch_.TransferToWaitTime(wait_time_stopwatch_.TotalElapsed());
+ action_stopwatch_.TransferToActiveTime(
+ precondition_stopwatches_[choice_index].TotalElapsed());
+ }
+
DCHECK(choice_index >= 0 && choice_index <= proto_.prompt().choices_size());
processed_action_proto_->mutable_prompt_choice()->set_server_payload(
@@ -232,15 +272,17 @@ void PromptAction::OnNavigationEnded() {
NOTREACHED();
return;
}
+ action_stopwatch_.TransferToWaitTime(wait_time_stopwatch_.TotalElapsed());
+
processed_action_proto_->mutable_prompt_choice()->set_navigation_ended(true);
EndAction(ClientStatus(ACTION_APPLIED));
}
void PromptAction::EndAction(const ClientStatus& status) {
delegate_->CleanUpAfterPrompt();
- // Clear the whitelist when a browse action is done.
+ // Clear the allowlist when a browse action is done.
if (proto_.prompt().browse_mode()) {
- delegate_->SetBrowseDomainsWhitelist({});
+ delegate_->SetBrowseDomainsAllowlist({});
}
UpdateProcessedAction(status);
std::move(callback_).Run(std::move(processed_action_proto_));
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action.h b/chromium/components/autofill_assistant/browser/actions/prompt_action.h
index 99af3291bdb..89afe7c075f 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action.h
@@ -47,6 +47,7 @@ class PromptAction : public Action {
void OnSuggestionChosen(int choice_index);
void OnNavigationEnded();
void EndAction(const ClientStatus& status);
+ void UpdateTimings();
ProcessActionCallback callback_;
@@ -57,6 +58,14 @@ class PromptAction : public Action {
// precondition_results_[i] contains the last result reported by
// preconditions_[i].
std::vector<bool> precondition_results_;
+ // positive_precondition_changes_[i] contains true only when the corresponding
+ // preconditions_[i] changed from false to true in the last periodic checks.
+ std::vector<bool> positive_precondition_changes_;
+ // precondition_stopwatches_[i] contains a stopwatch with the active time for
+ // preconditions_[i]. This will be 0 as long as preconditions_[i] is false
+ // and will contain the sum of the time that the precondition checks required
+ // to complete plus half the duration of the retry period.
+ std::vector<Stopwatch> precondition_stopwatches_;
// true if something in precondition_results_ has changed, which means that
// the set of user actions must be updated.
@@ -73,6 +82,14 @@ class PromptAction : public Action {
// Batch element checker for preconditions and auto-selection.
std::unique_ptr<BatchElementChecker> element_checker_;
+ // This stopwatch contains the total wait time, needed all exit criteria
+ // except the autoselect one.
+ Stopwatch wait_time_stopwatch_;
+ // Contains the duration of the last retry period.
+ Stopwatch last_period_stopwatch_;
+ // Contains the duration of the last precondition checks.
+ Stopwatch last_checks_stopwatch_;
+
base::WeakPtrFactory<PromptAction> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(PromptAction);
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index 3e66b265f79..8d8153f0bf1 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -8,9 +8,11 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "base/test/test_simple_task_runner.h"
#include "base/timer/timer.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
@@ -22,15 +24,16 @@ namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
-using ::testing::Eq;
using ::testing::Invoke;
using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::Pointee;
using ::testing::Property;
+using ::testing::SaveArgPointee;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
+using ::testing::WithArgs;
class PromptActionTest : public testing::Test {
public:
@@ -38,11 +41,9 @@ class PromptActionTest : public testing::Test {
: task_env_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
- ON_CALL(mock_web_controller_, OnElementCheck(_, _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus()));
- ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus(), ""));
-
+ ON_CALL(mock_web_controller_, OnFindElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
EXPECT_CALL(mock_action_delegate_, OnWaitForDom(_, _, _, _))
.WillRepeatedly(Invoke(this, &PromptActionTest::FakeWaitForDom));
ON_CALL(mock_action_delegate_, Prompt(_, _, _, _, _))
@@ -67,7 +68,8 @@ class PromptActionTest : public testing::Test {
base::RepeatingCallback<
void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)>& check_elements,
- base::OnceCallback<void(const ClientStatus&)>& done_waiting_callback) {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>&
+ done_waiting_callback) {
fake_wait_for_dom_done_ = std::move(done_waiting_callback);
RunFakeWaitForDom(check_elements);
}
@@ -84,6 +86,8 @@ class PromptActionTest : public testing::Test {
check_elements.Run(checker_.get(),
base::BindOnce(&PromptActionTest::OnCheckElementsDone,
base::Unretained(this)));
+ task_env_.FastForwardBy(
+ base::TimeDelta::FromMilliseconds(fake_check_time_));
checker_->AddAllDoneCallback(
base::BindOnce(&PromptActionTest::OnWaitForDomDone,
base::Unretained(this), check_elements));
@@ -110,7 +114,9 @@ class PromptActionTest : public testing::Test {
return;
if (check_elements_result_.ok()) {
- std::move(fake_wait_for_dom_done_).Run(check_elements_result_);
+ std::move(fake_wait_for_dom_done_)
+ .Run(check_elements_result_,
+ base::TimeDelta::FromMilliseconds(fake_wait_time_));
} else {
wait_for_dom_timer_ = std::make_unique<base::OneShotTimer>();
wait_for_dom_timer_->Start(
@@ -127,7 +133,8 @@ class PromptActionTest : public testing::Test {
MockActionDelegate mock_action_delegate_;
MockWebController mock_web_controller_;
base::MockCallback<Action::ProcessActionCallback> callback_;
- base::OnceCallback<void(const ClientStatus&)> fake_wait_for_dom_done_;
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>
+ fake_wait_for_dom_done_;
ActionProto proto_;
PromptProto* prompt_proto_;
std::unique_ptr<std::vector<UserAction>> user_actions_;
@@ -135,6 +142,8 @@ class PromptActionTest : public testing::Test {
bool has_check_elements_result_ = false;
ClientStatus check_elements_result_;
std::unique_ptr<base::OneShotTimer> wait_for_dom_timer_;
+ int fake_wait_time_ = 0;
+ int fake_check_time_ = 0;
};
TEST_F(PromptActionTest, ChoicesMissing) {
@@ -218,19 +227,58 @@ TEST_F(PromptActionTest, ShowOnlyIfElementExists) {
ASSERT_THAT(user_actions_, Pointee(IsEmpty()));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_THAT(user_actions_, Pointee(IsEmpty()));
}
+TEST_F(PromptActionTest, TimingStatsUserAction) {
+ auto* ok_proto = prompt_proto_->add_choices();
+ ok_proto->mutable_chip()->set_text("Ok");
+ ok_proto->mutable_chip()->set_type(HIGHLIGHTED_ACTION);
+ ok_proto->set_server_payload("ok");
+ *ok_proto->mutable_show_only_when()->mutable_match() =
+ ToSelectorProto("element");
+
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ std::make_unique<ElementFinder::Result>());
+ }))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ std::make_unique<ElementFinder::Result>());
+ }))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+
+ fake_check_time_ = 200;
+ PromptAction action(&mock_action_delegate_, proto_);
+ action.ProcessAction(callback_.Get());
+
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(3));
+ ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
+
+ ProcessedActionProto capture;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(SaveArgPointee<0>(&capture));
+ EXPECT_TRUE((*user_actions_)[0].HasCallback());
+ (*user_actions_)[0].Call(TriggerContext::CreateEmpty());
+ EXPECT_EQ(capture.timing_stats().active_time_ms(), 700);
+ EXPECT_EQ(capture.timing_stats().wait_time_ms(), 2500);
+}
+
TEST_F(PromptActionTest, DisabledUnlessElementExists) {
auto* ok_proto = prompt_proto_->add_choices();
ok_proto->mutable_chip()->set_text("Ok");
@@ -243,16 +291,18 @@ TEST_F(PromptActionTest, DisabledUnlessElementExists) {
PromptAction action(&mock_action_delegate_, proto_);
action.ProcessAction(callback_.Get());
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
EXPECT_TRUE((*user_actions_)[0].enabled());
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
EXPECT_FALSE((*user_actions_)[0].enabled());
@@ -269,9 +319,11 @@ TEST_F(PromptActionTest, AutoSelectWhenElementExists) {
action.ProcessAction(callback_.Get());
EXPECT_THAT(user_actions_, Pointee(SizeIs(0)));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
EXPECT_CALL(mock_action_delegate_, CleanUpAfterPrompt());
EXPECT_CALL(
@@ -283,6 +335,31 @@ TEST_F(PromptActionTest, AutoSelectWhenElementExists) {
task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
}
+TEST_F(PromptActionTest, TimingStatsAutoSelect) {
+ auto* choice_proto = prompt_proto_->add_choices();
+ choice_proto->set_server_payload("auto-select");
+ *choice_proto->mutable_auto_select_when()->mutable_match() =
+ ToSelectorProto("element");
+
+ fake_wait_time_ = 500;
+ PromptAction action(&mock_action_delegate_, proto_);
+ action.ProcessAction(callback_.Get());
+ EXPECT_THAT(user_actions_, Pointee(SizeIs(0)));
+
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+
+ EXPECT_CALL(mock_action_delegate_, CleanUpAfterPrompt());
+ ProcessedActionProto capture;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(SaveArgPointee<0>(&capture));
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(capture.timing_stats().active_time_ms(), 500);
+ EXPECT_EQ(capture.timing_stats().wait_time_ms(), 500);
+}
+
TEST_F(PromptActionTest, AutoSelectWithButton) {
auto* ok_proto = prompt_proto_->add_choices();
ok_proto->mutable_chip()->set_text("Ok");
@@ -299,9 +376,11 @@ TEST_F(PromptActionTest, AutoSelectWithButton) {
ASSERT_THAT(user_actions_, Pointee(SizeIs(1)));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
@@ -437,7 +516,8 @@ TEST_F(PromptActionTest, ForwardInterruptFailure) {
Property(&ProcessedActionProto::prompt_choice,
Property(&PromptProto::Result::server_payload, ""))))));
ASSERT_TRUE(fake_wait_for_dom_done_);
- std::move(fake_wait_for_dom_done_).Run(ClientStatus(INTERRUPT_FAILED));
+ std::move(fake_wait_for_dom_done_)
+ .Run(ClientStatus(INTERRUPT_FAILED), base::TimeDelta::FromSeconds(0));
}
TEST_F(PromptActionTest, EndActionOnNavigation) {
@@ -467,5 +547,35 @@ TEST_F(PromptActionTest, EndActionOnNavigation) {
action.ProcessAction(callback_.Get());
}
+TEST_F(PromptActionTest, TimingStatsEndActionOnNavigation) {
+ auto timer = std::make_unique<base::OneShotTimer>();
+ EXPECT_CALL(mock_action_delegate_, Prompt(_, _, _, _, _))
+ .WillOnce(
+ [this, &timer](std::unique_ptr<std::vector<UserAction>> user_actions,
+ bool disable_force_expand_sheet,
+ base::OnceCallback<void()> callback, bool browse_mode,
+ bool browse_mode_invisible) {
+ user_actions_ = std::move(user_actions);
+ timer->Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
+ std::move(callback));
+ });
+
+ prompt_proto_->set_end_on_navigation(true);
+ PromptProto_Choice* ok_proto = prompt_proto_->add_choices();
+ ok_proto->mutable_chip()->set_text("ok");
+
+ PromptAction action(&mock_action_delegate_, proto_);
+
+ // Set new expectations for when the navigation event arrives.
+ EXPECT_CALL(mock_action_delegate_, CleanUpAfterPrompt());
+ ProcessedActionProto capture;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(SaveArgPointee<0>(&capture));
+ action.ProcessAction(callback_.Get());
+ EXPECT_TRUE(task_env_.NextTaskIsDelayed());
+ task_env_.DescribePendingMainThreadTasks();
+ task_env_.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(capture.timing_stats().wait_time_ms(), 1000);
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/select_option_action.cc b/chromium/components/autofill_assistant/browser/actions/select_option_action.cc
index 2a4fdfb0cfc..5e157696c0a 100644
--- a/chromium/components/autofill_assistant/browser/actions/select_option_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -12,7 +12,7 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/field_formatter.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
namespace autofill_assistant {
@@ -46,34 +46,12 @@ void SelectOptionAction::InternalProcessAction(ProcessActionCallback callback) {
value_ = select_option.selected_option();
break;
case SelectOptionProto::kAutofillValue: {
- if (select_option.autofill_value().profile().identifier().empty() ||
- select_option.autofill_value().value_expression().empty()) {
- VLOG(1) << "SelectOptionAction: |autofill_value| with empty "
- "|profile.identifier| or |value_expression|";
- EndAction(ClientStatus(INVALID_ACTION));
- return;
- }
-
- const autofill::AutofillProfile* address =
- delegate_->GetUserData()->selected_address(
- select_option.autofill_value().profile().identifier());
- if (address == nullptr) {
- VLOG(1) << "SelectOptionAction: requested unknown address '"
- << select_option.autofill_value().profile().identifier() << "'";
- EndAction(ClientStatus(PRECONDITION_FAILED));
+ ClientStatus autofill_status = GetFormattedAutofillValue(
+ select_option.autofill_value(), delegate_->GetUserData(), &value_);
+ if (!autofill_status.ok()) {
+ EndAction(autofill_status);
return;
}
-
- auto value = field_formatter::FormatString(
- select_option.autofill_value().value_expression(),
- field_formatter::CreateAutofillMappings(*address,
- /* locale= */ "en-US"));
- if (!value.has_value()) {
- EndAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE));
- return;
- }
-
- value_ = *value;
break;
}
default:
@@ -83,8 +61,11 @@ void SelectOptionAction::InternalProcessAction(ProcessActionCallback callback) {
}
delegate_->ShortWaitForElement(
- selector, base::BindOnce(&SelectOptionAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(), selector));
+ selector,
+ base::BindOnce(&SelectOptionAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&SelectOptionAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(), selector)));
}
void SelectOptionAction::OnWaitForElement(const Selector& selector,
@@ -94,7 +75,7 @@ void SelectOptionAction::OnWaitForElement(const Selector& selector,
return;
}
- ActionDelegateUtil::FindElementAndPerform(
+ action_delegate_util::FindElementAndPerform(
delegate_, selector,
base::BindOnce(&ActionDelegate::SelectOption, delegate_->GetWeakPtr(),
value_, proto_.select_option().select_strategy()),
diff --git a/chromium/components/autofill_assistant/browser/actions/select_option_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
index 3470225b81a..23067342ef7 100644
--- a/chromium/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
@@ -99,7 +99,8 @@ TEST_F(SelectOptionActionTest, CheckExpectedCallChain) {
Selector expected_selector = selector;
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
auto expected_element =
test_util::MockFindElement(mock_action_delegate_, expected_selector);
EXPECT_CALL(mock_action_delegate_,
@@ -171,7 +172,8 @@ TEST_F(SelectOptionActionTest, SelectOptionFromProfileValue) {
Selector expected_selector = selector;
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
EXPECT_CALL(mock_action_delegate_,
SelectOption("John", _,
EqualsElement(test_util::MockFindElement(
diff --git a/chromium/components/autofill_assistant/browser/actions/set_attribute_action.cc b/chromium/components/autofill_assistant/browser/actions/set_attribute_action.cc
index 7a7c8c9bed6..aeb6d49ad42 100644
--- a/chromium/components/autofill_assistant/browser/actions/set_attribute_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/set_attribute_action.cc
@@ -32,9 +32,12 @@ void SetAttributeAction::InternalProcessAction(ProcessActionCallback callback) {
return;
}
delegate_->ShortWaitForElement(
- selector, base::BindOnce(&SetAttributeAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(callback), selector));
+ selector,
+ base::BindOnce(&SetAttributeAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&SetAttributeAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), selector)));
}
void SetAttributeAction::OnWaitForElement(ProcessActionCallback callback,
@@ -46,7 +49,7 @@ void SetAttributeAction::OnWaitForElement(ProcessActionCallback callback,
return;
}
- ActionDelegateUtil::FindElementAndPerform(
+ action_delegate_util::FindElementAndPerform(
delegate_, selector,
base::BindOnce(&ActionDelegate::SetAttribute, delegate_->GetWeakPtr(),
ExtractVector(proto_.set_attribute().attribute()),
diff --git a/chromium/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc
index 7cbffa1df17..aa75800d23a 100644
--- a/chromium/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc
@@ -59,7 +59,8 @@ TEST_F(SetAttributeActionTest, CheckExpectedCallChain) {
Selector expected_selector = selector;
EXPECT_CALL(mock_action_delegate_,
OnShortWaitForElement(expected_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
auto expected_element =
test_util::MockFindElement(mock_action_delegate_, expected_selector);
std::vector<std::string> expected_attributes = {"value"};
diff --git a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.cc b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
index 92d47a862c1..6719bdd719d 100644
--- a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
@@ -12,14 +12,16 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/field_formatter.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
namespace {
bool IsSimulatingKeyPresses(KeyboardValueFillStrategy fill_strategy) {
return fill_strategy == SIMULATE_KEY_PRESSES ||
- fill_strategy == SIMULATE_KEY_PRESSES_SELECT_VALUE;
+ fill_strategy == SIMULATE_KEY_PRESSES_SELECT_VALUE ||
+ fill_strategy == SIMULATE_KEY_PRESSES_FOCUS;
}
} // namespace
@@ -51,7 +53,7 @@ SetFormFieldValueAction::~SetFormFieldValueAction() {}
void SetFormFieldValueAction::InternalProcessAction(
ProcessActionCallback callback) {
process_action_callback_ = std::move(callback);
- selector_ = Selector(proto_.set_form_value().element()).MustBeVisible();
+ selector_ = Selector(proto_.set_form_value().element());
if (selector_.empty()) {
VLOG(1) << __func__ << ": empty selector";
EndAction(ClientStatus(INVALID_SELECTOR));
@@ -138,34 +140,15 @@ void SetFormFieldValueAction::InternalProcessAction(
.values(0));
break;
case SetFormFieldValueProto_KeyPress::kAutofillValue: {
- if (keypress.autofill_value().profile().identifier().empty() ||
- keypress.autofill_value().value_expression().empty()) {
- VLOG(1) << "SetFormFieldValueAction: |autofill_value| with empty "
- "|profile.identifier| or |value_expression|";
- FailAction(ClientStatus(INVALID_ACTION), keypress_index);
- return;
- }
-
- const autofill::AutofillProfile* address =
- delegate_->GetUserData()->selected_address(
- keypress.autofill_value().profile().identifier());
- if (address == nullptr) {
- VLOG(1) << "SetFormFieldValueAction: requested unknown address '"
- << keypress.autofill_value().profile().identifier() << "'";
- FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
+ std::string value;
+ ClientStatus autofill_status = GetFormattedAutofillValue(
+ keypress.autofill_value(), delegate_->GetUserData(), &value);
+ if (!autofill_status.ok()) {
+ FailAction(autofill_status, keypress_index);
return;
}
- auto value = field_formatter::FormatString(
- keypress.autofill_value().value_expression(),
- field_formatter::CreateAutofillMappings(*address,
- /* locale= */ "en-US"));
- if (!value.has_value()) {
- FailAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE), keypress_index);
- return;
- }
-
- field_inputs_.emplace_back(*value);
+ field_inputs_.emplace_back(value);
break;
}
default:
@@ -177,36 +160,55 @@ void SetFormFieldValueAction::InternalProcessAction(
}
delegate_->ShortWaitForElement(
- selector_, base::BindOnce(&SetFormFieldValueAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr()));
+ selector_,
+ base::BindOnce(&SetFormFieldValueAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&SetFormFieldValueAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr())));
}
void SetFormFieldValueAction::OnWaitForElement(
const ClientStatus& element_status) {
if (!element_status.ok()) {
- EndAction(ClientStatus(element_status.proto_status()));
+ EndAction(element_status);
+ return;
+ }
+ delegate_->FindElement(selector_,
+ base::BindOnce(&SetFormFieldValueAction::OnFindElement,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SetFormFieldValueAction::OnFindElement(
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!element_status.ok()) {
+ EndAction(element_status);
return;
}
- // Start with first value, then call OnSetFieldValue() recursively until done.
- OnSetFieldValue(/* next = */ 0, OkClientStatus());
+
+ element_ = std::move(element_result);
+ SetFieldValueSequentially(/* field_index = */ 0, OkClientStatus());
}
-void SetFormFieldValueAction::OnSetFieldValue(int next,
- const ClientStatus& status) {
- // If something went wrong or we are out of values: finish
- if (!status.ok() || next >= proto_.set_form_value().value_size()) {
+void SetFormFieldValueAction::SetFieldValueSequentially(
+ int field_index,
+ const ClientStatus& status) {
+ // If something went wrong or we are out of values: finish.
+ if (!status.ok() || field_index >= proto_.set_form_value().value_size()) {
EndAction(status);
return;
}
int delay_in_millisecond = proto_.set_form_value().delay_in_millisecond();
- auto next_field_callback = base::BindOnce(
- &SetFormFieldValueAction::OnSetFieldValue, weak_ptr_factory_.GetWeakPtr(),
- /* next = */ next + 1);
- const auto& field_input = field_inputs_[next];
+ auto fill_strategy = proto_.set_form_value().fill_strategy();
+ auto next_field_callback =
+ base::BindOnce(&SetFormFieldValueAction::SetFieldValueSequentially,
+ weak_ptr_factory_.GetWeakPtr(), field_index + 1);
+ const auto& field_input = field_inputs_[field_index];
if (field_input.keyboard_input) {
- ActionDelegateUtil::SendKeyboardInput(
- delegate_, selector_, *field_input.keyboard_input, delay_in_millisecond,
+ action_delegate_util::PerformSendKeyboardInput(
+ delegate_, *field_input.keyboard_input, delay_in_millisecond,
+ fill_strategy == SIMULATE_KEY_PRESSES_FOCUS, *element_,
std::move(next_field_callback));
} else if (field_input.password_type != PasswordValueType::NOT_SET) {
switch (field_input.password_type) {
@@ -218,30 +220,46 @@ void SetFormFieldValueAction::OnSetFieldValue(int next,
*delegate_->GetUserData()->selected_login_,
base::BindOnce(&SetFormFieldValueAction::OnGetStoredPassword,
weak_ptr_factory_.GetWeakPtr(),
- /* field_index = */ next));
+ std::move(next_field_callback)));
break;
}
} else {
auto fill_strategy = proto_.set_form_value().fill_strategy();
- if (IsSimulatingKeyPresses(fill_strategy)) {
- ActionDelegateUtil::SetFieldValue(delegate_, selector_, field_input.value,
- fill_strategy, delay_in_millisecond,
- std::move(next_field_callback));
- } else {
- ActionDelegateUtil::SetFieldValue(
- delegate_, selector_, field_input.value, fill_strategy,
- delay_in_millisecond,
- base::BindOnce(
- &SetFormFieldValueAction::OnSetFieldValueAndCheckFallback,
- weak_ptr_factory_.GetWeakPtr(),
- /* field_index = */ next,
- /* requested_value = */ field_input.value));
- }
+ action_delegate_util::PerformSetFieldValue(
+ delegate_, field_input.value, fill_strategy, delay_in_millisecond,
+ *element_,
+ IsSimulatingKeyPresses(fill_strategy)
+ ? std::move(next_field_callback)
+ : base::BindOnce(
+ &SetFormFieldValueAction::OnSetFieldValueAndCheckFallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(next_field_callback),
+ /* requested_value = */ field_input.value));
}
}
+void SetFormFieldValueAction::OnGetStoredPassword(
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
+ bool success,
+ std::string password) {
+ if (!success) {
+ EndAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE));
+ return;
+ }
+ auto fill_strategy = proto_.set_form_value().fill_strategy();
+ action_delegate_util::PerformSetFieldValue(
+ delegate_, password, fill_strategy,
+ proto_.set_form_value().delay_in_millisecond(), *element_,
+ IsSimulatingKeyPresses(fill_strategy)
+ ? std::move(next_field_callback)
+ : base::BindOnce(
+ &SetFormFieldValueAction::OnSetFieldValueAndCheckFallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(next_field_callback),
+ /* requested_value = */ password));
+}
+
void SetFormFieldValueAction::OnSetFieldValueAndCheckFallback(
- int field_index,
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
const std::string& requested_value,
const ClientStatus& status) {
if (!status.ok()) {
@@ -249,19 +267,20 @@ void SetFormFieldValueAction::OnSetFieldValueAndCheckFallback(
return;
}
delegate_->GetFieldValue(
- selector_, base::BindOnce(&SetFormFieldValueAction::OnGetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), field_index,
- requested_value));
+ *element_,
+ base::BindOnce(&SetFormFieldValueAction::OnGetFieldValue,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(next_field_callback), requested_value));
}
void SetFormFieldValueAction::OnGetFieldValue(
- int field_index,
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
const std::string& requested_value,
const ClientStatus& element_status,
const std::string& actual_value) {
// Move to next value if |GetFieldValue| failed.
if (!element_status.ok()) {
- OnSetFieldValue(field_index + 1, OkClientStatus());
+ std::move(next_field_callback).Run(OkClientStatus());
return;
}
@@ -269,48 +288,20 @@ void SetFormFieldValueAction::OnGetFieldValue(
// simulation fallback.
if (!requested_value.empty() && actual_value.empty()) {
// Report a key press simulation fallback has happened.
- auto result = SetFormFieldValueProto::Result();
- result.set_fallback_to_simulate_key_presses(true);
- *processed_action_proto_->mutable_set_form_field_value_result() = result;
+ processed_action_proto_->mutable_set_form_field_value_result()
+ ->set_fallback_to_simulate_key_presses(true);
// Run |SetFieldValue| with keyboard simulation on and move on to next value
// afterwards.
- ActionDelegateUtil::SetFieldValue(
- delegate_, selector_, requested_value, SIMULATE_KEY_PRESSES,
- proto_.set_form_value().delay_in_millisecond(),
- base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(),
- /* next = */ field_index + 1));
+ action_delegate_util::PerformSetFieldValue(
+ delegate_, requested_value, SIMULATE_KEY_PRESSES,
+ proto_.set_form_value().delay_in_millisecond(), *element_,
+ std::move(next_field_callback));
return;
}
// Move to next value in all other cases.
- OnSetFieldValue(field_index + 1, OkClientStatus());
-}
-
-void SetFormFieldValueAction::OnGetStoredPassword(int field_index,
- bool success,
- std::string password) {
- if (!success) {
- EndAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE));
- return;
- }
- auto fill_strategy = proto_.set_form_value().fill_strategy();
- int delay_in_millisecond = proto_.set_form_value().delay_in_millisecond();
- if (IsSimulatingKeyPresses(fill_strategy)) {
- ActionDelegateUtil::SetFieldValue(
- delegate_, selector_, password, fill_strategy, delay_in_millisecond,
- base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(),
- /* next = */ field_index + 1));
- } else {
- ActionDelegateUtil::SetFieldValue(
- delegate_, selector_, password, fill_strategy, delay_in_millisecond,
- base::BindOnce(
- &SetFormFieldValueAction::OnSetFieldValueAndCheckFallback,
- weak_ptr_factory_.GetWeakPtr(),
- /* next = */ field_index, /* requested_value = */ password));
- }
+ std::move(next_field_callback).Run(OkClientStatus());
}
void SetFormFieldValueAction::FailAction(const ClientStatus& status,
diff --git a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.h b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.h
index ccdf3ab53b4..748cf4e81d9 100644
--- a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action.h
@@ -15,6 +15,7 @@
#include "components/autofill_assistant/browser/actions/action.h"
#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
@@ -56,24 +57,28 @@ class SetFormFieldValueAction : public Action {
void InternalProcessAction(ProcessActionCallback callback) override;
void OnWaitForElement(const ClientStatus& element_status);
-
- void OnGetFieldValue(int field_index,
- const std::string& requested_value,
- const ClientStatus& element_status,
- const std::string& actual_value);
-
- void OnSetFieldValue(int next, const ClientStatus& status);
-
- void OnSetFieldValueAndCheckFallback(int field_index,
- const std::string& requested_value,
- const ClientStatus& status);
-
- void OnGetStoredPassword(int field_index, bool success, std::string password);
+ void OnFindElement(const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result);
+ void SetFieldValueSequentially(int field_index, const ClientStatus& status);
+ void OnGetStoredPassword(
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
+ bool success,
+ std::string password);
+ void OnSetFieldValueAndCheckFallback(
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
+ const std::string& requested_value,
+ const ClientStatus& status);
+ void OnGetFieldValue(
+ base::OnceCallback<void(const ClientStatus&)> next_field_callback,
+ const std::string& requested_value,
+ const ClientStatus& element_status,
+ const std::string& actual_value);
void FailAction(const ClientStatus& status, int keypress_index);
void EndAction(const ClientStatus& status);
Selector selector_;
+ std::unique_ptr<ElementFinder::Result> element_;
std::vector<FieldInput> field_inputs_;
ProcessActionCallback process_action_callback_;
base::WeakPtrFactory<SetFormFieldValueAction> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
index 74f221df322..ba59d068758 100644
--- a/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
@@ -45,8 +45,7 @@ class SetFormFieldValueActionTest : public testing::Test {
public:
void SetUp() override {
set_form_field_proto_ = proto_.mutable_set_form_value();
- *set_form_field_proto_->mutable_element() =
- Selector({kFakeSelector}).MustBeVisible().proto;
+ *set_form_field_proto_->mutable_element() = Selector({kFakeSelector}).proto;
ON_CALL(mock_action_delegate_, GetUserData)
.WillByDefault(Return(&user_data_));
ON_CALL(mock_action_delegate_, WriteUserData)
@@ -54,32 +53,37 @@ class SetFormFieldValueActionTest : public testing::Test {
RunOnceCallback<0>(&user_data_, /* field_change = */ nullptr));
ON_CALL(mock_action_delegate_, GetWebsiteLoginManager)
.WillByDefault(Return(&mock_website_login_manager_));
+ ON_CALL(mock_website_login_manager_, OnGetLoginsForUrl(_, _))
+ .WillByDefault(
+ RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{
+ WebsiteLoginManager::Login(GURL(kFakeUrl), kFakeUsername)}));
+ ON_CALL(mock_website_login_manager_, OnGetPasswordForLogin(_, _))
+ .WillByDefault(RunOnceCallback<1>(true, kFakePassword));
ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ ON_CALL(mock_action_delegate_, GetFieldValue(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(), ""));
+ test_util::MockFindAnyElement(mock_action_delegate_);
+ ON_CALL(mock_action_delegate_, SetValueAttribute(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, SelectFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus()));
- ON_CALL(mock_action_delegate_, OnSetFieldValue(_, _, _, _, _))
- .WillByDefault(RunOnceCallback<4>(OkClientStatus()));
- ON_CALL(mock_action_delegate_, FindElement(_, _))
- .WillByDefault(WithArgs<1>([&](auto&& callback) {
- auto element_result = std::make_unique<ElementFinder::Result>();
- std::move(callback).Run(OkClientStatus(), std::move(element_result));
- }));
- ON_CALL(mock_action_delegate_, WaitForDocumentToBecomeInteractive(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, WaitUntilDocumentIsInReadyState(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
ON_CALL(mock_action_delegate_, ScrollIntoView(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
ON_CALL(mock_action_delegate_, ClickOrTapElement(_, _, _))
.WillByDefault(RunOnceCallback<2>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, OnSendKeyboardInput(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
- ON_CALL(mock_website_login_manager_, OnGetLoginsForUrl(_, _))
- .WillByDefault(
- RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{
- WebsiteLoginManager::Login(GURL(kFakeUrl), kFakeUsername)}));
- ON_CALL(mock_website_login_manager_, OnGetPasswordForLogin(_, _))
- .WillByDefault(RunOnceCallback<1>(true, kFakePassword));
user_data_.selected_login_ =
base::make_optional<WebsiteLoginManager::Login>(GURL(kFakeUrl),
kFakeUsername);
- fake_selector_ = Selector({kFakeSelector}).MustBeVisible();
+ fake_selector_ = Selector({kFakeSelector});
}
protected:
@@ -141,14 +145,16 @@ TEST_F(SetFormFieldValueActionTest, Username) {
auto* value = set_form_field_proto_->add_value();
value->set_use_username(true);
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), kFakeUsername));
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFakeUsername, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakeUsername, _, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), kFakeUsername));
EXPECT_CALL(
callback_,
@@ -160,14 +166,16 @@ TEST_F(SetFormFieldValueActionTest, PasswordToFill) {
auto* value = set_form_field_proto_->add_value();
value->set_use_password(true);
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), kFakePassword));
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFakePassword, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakePassword, _, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), kFakePassword));
EXPECT_CALL(
callback_,
@@ -175,6 +183,16 @@ TEST_F(SetFormFieldValueActionTest, PasswordToFill) {
action.ProcessAction(callback_.Get());
}
+TEST_F(SetFormFieldValueActionTest, PasswordIsClearedFromMemory) {
+ auto* value = set_form_field_proto_->add_value();
+ value->set_use_password(true);
+ SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+ ON_CALL(mock_action_delegate_, GetFieldValue(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(), kFakePassword));
+ action.ProcessAction(callback_.Get());
+ EXPECT_TRUE(action.field_inputs_.empty());
+}
+
TEST_F(SetFormFieldValueActionTest, Keycode) {
auto* value = set_form_field_proto_->add_value();
value->set_keycode(13); // carriage return
@@ -219,12 +237,14 @@ TEST_F(SetFormFieldValueActionTest, KeyboardInputHasExpectedCallChain) {
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(fake_selector_, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
auto expected_element =
test_util::MockFindElement(mock_action_delegate_, fake_selector_);
- EXPECT_CALL(mock_action_delegate_, WaitForDocumentToBecomeInteractive(
- EqualsElement(expected_element), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
ScrollIntoView(EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<1>(OkClientStatus()));
@@ -247,14 +267,84 @@ TEST_F(SetFormFieldValueActionTest, Text) {
auto* value = set_form_field_proto_->add_value();
value->set_text("SomeText𠜎");
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "SomeText𠜎"));
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("SomeText𠜎", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "SomeText𠜎"));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest, TextWithKeystrokeHasExpectedCallChain) {
+ InSequence sequence;
+
+ auto* value = set_form_field_proto_->add_value();
+ std::string keyboard_input = "SomeQuery";
+ value->set_text(keyboard_input);
+ set_form_field_proto_->set_fill_strategy(SIMULATE_KEY_PRESSES);
+ SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(fake_selector_, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ ScrollIntoView(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::CLICK, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode(keyboard_input), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest,
+ TextWithKeystrokeAndSelectHasExpectedCallChain) {
+ InSequence sequence;
+
+ auto* value = set_form_field_proto_->add_value();
+ std::string keyboard_input = "SomeQuery";
+ value->set_text(keyboard_input);
+ set_form_field_proto_->set_fill_strategy(SIMULATE_KEY_PRESSES_SELECT_VALUE);
+ SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(fake_selector_, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(mock_action_delegate_,
+ SelectFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("SomeText𠜎", _, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ OnSendKeyboardInput(UTF8ToUnicode(keyboard_input), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(
callback_,
@@ -270,14 +360,17 @@ TEST_F(SetFormFieldValueActionTest, MultipleValuesAndSimulateKeypress) {
set_form_field_proto_->set_fill_strategy(SIMULATE_KEY_PRESSES);
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("SomeText", /* simulate_key_presses = */ true, _, _, _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode("SomeText"), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
// The second entry, a deprecated keycode is transformed into a
// field_input.keyboard_input.
EXPECT_CALL(mock_action_delegate_,
- OnSendKeyboardInput(std::vector<int>{13}, _, _, _))
+ OnSendKeyboardInput(std::vector<int>{13}, _,
+ EqualsElement(expected_element), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(
@@ -293,14 +386,16 @@ TEST_F(SetFormFieldValueActionTest, ClientMemoryKey) {
value_proto.mutable_strings()->add_values("SomeText𠜎");
user_data_.additional_values_["key"] = value_proto;
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "SomeText𠜎"));
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("SomeText𠜎", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("SomeText𠜎", _, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "SomeText𠜎"));
EXPECT_CALL(
callback_,
@@ -318,29 +413,29 @@ TEST_F(SetFormFieldValueActionTest, ClientMemoryKeyFailsIfNotInClientMemory) {
action.ProcessAction(callback_.Get());
}
-// Test that automatic fallback to simulate keystrokes works.
-TEST_F(SetFormFieldValueActionTest, Fallback) {
+TEST_F(SetFormFieldValueActionTest, FallbackToSimulateKeystrokes) {
+ InSequence sequence;
+
auto* value = set_form_field_proto_->add_value();
value->set_text("123");
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), ""));
- {
- InSequence seq;
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("123",
- /* simulate_key_presses = */ false, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _));
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("123",
- /* simulate_key_presses = */ true, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _));
- }
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("123", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode("123"), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_CALL(callback_,
Run(Pointee(AllOf(
@@ -349,18 +444,97 @@ TEST_F(SetFormFieldValueActionTest, Fallback) {
Property(&SetFormFieldValueProto::Result::
fallback_to_simulate_key_presses,
true))))));
-
action.ProcessAction(callback_.Get());
}
-TEST_F(SetFormFieldValueActionTest, PasswordIsClearedFromMemory) {
+TEST_F(SetFormFieldValueActionTest, FallbackForPassword) {
+ InSequence sequence;
+
auto* value = set_form_field_proto_->add_value();
value->set_use_password(true);
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), kFakePassword));
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFakePassword, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode(kFakePassword), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(&ProcessedActionProto::set_form_field_value_result,
+ Property(&SetFormFieldValueProto::Result::
+ fallback_to_simulate_key_presses,
+ true))))));
+ action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest, FallbackForMultipleValues) {
+ InSequence sequence;
+
+ auto* value = set_form_field_proto_->add_value();
+ value->set_text("SomeText");
+ auto* enter = set_form_field_proto_->add_value();
+ enter->set_text("SomeOtherText");
+ SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+
+ // First value.
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("SomeText", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode("SomeText"), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ // Second value.
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("SomeOtherText", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode("SomeOtherText"), _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(&ProcessedActionProto::set_form_field_value_result,
+ Property(&SetFormFieldValueProto::Result::
+ fallback_to_simulate_key_presses,
+ true))))));
action.ProcessAction(callback_.Get());
- EXPECT_TRUE(action.field_inputs_.empty());
}
TEST_F(SetFormFieldValueActionTest, EmptyProfileValueFails) {
@@ -424,14 +598,14 @@ TEST_F(SetFormFieldValueActionTest, SetFieldFromProfileValue) {
"}"}));
SetFormFieldValueAction action(&mock_action_delegate_, proto_);
- ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+ const ElementFinder::Result& expected_element =
+ test_util::MockFindElement(mock_action_delegate_, fake_selector_);
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("John", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("John", _, _,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, fake_selector_)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ GetFieldValue(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_CALL(
callback_,
diff --git a/chromium/components/autofill_assistant/browser/actions/show_cast_action.cc b/chromium/components/autofill_assistant/browser/actions/show_cast_action.cc
new file mode 100644
index 00000000000..eccce518211
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/show_cast_action.cc
@@ -0,0 +1,114 @@
+// Copyright 2018 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_assistant/browser/actions/show_cast_action.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
+#include "components/autofill_assistant/browser/client_settings.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+
+namespace autofill_assistant {
+
+ShowCastAction::ShowCastAction(ActionDelegate* delegate,
+ const ActionProto& proto)
+ : Action(delegate, proto) {
+ DCHECK(proto_.has_show_cast());
+}
+
+ShowCastAction::~ShowCastAction() {}
+
+void ShowCastAction::InternalProcessAction(ProcessActionCallback callback) {
+ process_action_callback_ = std::move(callback);
+
+ const ShowCastProto& show_cast = proto_.show_cast();
+ if (show_cast.has_title()) {
+ // TODO(crbug.com/806868): Deprecate and remove message from this action and
+ // use tell instead.
+ delegate_->SetStatusMessage(show_cast.title());
+ }
+ Selector selector = Selector(show_cast.element_to_present());
+ if (selector.empty()) {
+ VLOG(1) << __func__ << ": empty selector";
+ EndAction(ClientStatus(INVALID_SELECTOR));
+ return;
+ }
+
+ // Default value of 25%. This value should always be overridden by backend.
+ TopPadding top_padding{0.25, TopPadding::Unit::RATIO};
+ switch (show_cast.top_padding().top_padding_case()) {
+ case ShowCastProto::TopPadding::kPixels:
+ top_padding = TopPadding(show_cast.top_padding().pixels(),
+ TopPadding::Unit::PIXELS);
+ break;
+ case ShowCastProto::TopPadding::kRatio:
+ top_padding =
+ TopPadding(show_cast.top_padding().ratio(), TopPadding::Unit::RATIO);
+ break;
+ case ShowCastProto::TopPadding::TOP_PADDING_NOT_SET:
+ // Default value set before switch.
+ break;
+ }
+
+ delegate_->ShortWaitForElement(
+ selector, base::BindOnce(&ShowCastAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&ShowCastAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(),
+ selector, top_padding)));
+}
+
+void ShowCastAction::OnWaitForElement(const Selector& selector,
+ const TopPadding& top_padding,
+ const ClientStatus& element_status) {
+ if (!element_status.ok()) {
+ EndAction(element_status);
+ return;
+ }
+
+ auto actions = std::make_unique<action_delegate_util::ElementActionVector>();
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::WaitUntilDocumentIsInReadyState, delegate_->GetWeakPtr(),
+ delegate_->GetSettings().document_ready_check_timeout,
+ DOCUMENT_INTERACTIVE));
+ auto wait_for_stable_element = proto_.show_cast().wait_for_stable_element();
+ if (wait_for_stable_element == STEP_UNSPECIFIED) {
+ wait_for_stable_element = SKIP_STEP;
+ }
+ action_delegate_util::AddOptionalStep(
+ wait_for_stable_element,
+ base::BindOnce(&ActionDelegate::WaitUntilElementIsStable,
+ delegate_->GetWeakPtr(),
+ proto_.show_cast().stable_check_max_rounds(),
+ base::TimeDelta::FromMilliseconds(
+ proto_.show_cast().stable_check_interval_ms())),
+ actions.get());
+ actions->emplace_back(base::BindOnce(&ActionDelegate::ScrollToElementPosition,
+ delegate_->GetWeakPtr(), selector,
+ top_padding));
+ action_delegate_util::FindElementAndPerform(
+ delegate_, selector,
+ base::BindOnce(&action_delegate_util::PerformAll, std::move(actions)),
+ base::BindOnce(&ShowCastAction::OnScrollToElementPosition,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ShowCastAction::OnScrollToElementPosition(const ClientStatus& status) {
+ delegate_->SetTouchableElementArea(
+ proto().show_cast().touchable_element_area());
+ EndAction(status);
+}
+
+void ShowCastAction::EndAction(const ClientStatus& status) {
+ UpdateProcessedAction(status);
+ std::move(process_action_callback_).Run(std::move(processed_action_proto_));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/show_cast_action.h b/chromium/components/autofill_assistant/browser/actions/show_cast_action.h
new file mode 100644
index 00000000000..7ed6e6a33a8
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/show_cast_action.h
@@ -0,0 +1,43 @@
+// Copyright 2018 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_ASSISTANT_BROWSER_ACTIONS_SHOW_CAST_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SHOW_CAST_ACTION_H_
+
+#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/top_padding.h"
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace autofill_assistant {
+
+// An action to show cast a given element on Web. Scrolling to it first if
+// required.
+class ShowCastAction : public Action {
+ public:
+ explicit ShowCastAction(ActionDelegate* delegate, const ActionProto& proto);
+ ~ShowCastAction() override;
+
+ private:
+ // Overrides Action:
+ void InternalProcessAction(ProcessActionCallback callback) override;
+
+ void OnWaitForElement(const Selector& selector,
+ const TopPadding& top_padding,
+ const ClientStatus& element_status);
+ void OnScrollToElementPosition(const ClientStatus& status);
+
+ void EndAction(const ClientStatus& status);
+
+ ProcessActionCallback process_action_callback_;
+
+ base::WeakPtrFactory<ShowCastAction> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(ShowCastAction);
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SHOW_CAST_ACTION_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/show_cast_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/show_cast_action_unittest.cc
new file mode 100644
index 00000000000..49517a25da2
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/show_cast_action_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright 2020 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_assistant/browser/actions/show_cast_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Pointee;
+using ::testing::Property;
+
+class ShowCastActionTest : public testing::Test {
+ public:
+ ShowCastActionTest() {}
+
+ void SetUp() override {}
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_show_cast() = proto_;
+ ShowCastAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ ShowCastProto proto_;
+};
+
+TEST_F(ShowCastActionTest, EmptySelectorFails) {
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR))));
+ Run();
+}
+
+TEST_F(ShowCastActionTest, ActionFailsForNonExistentElement) {
+ InSequence sequence;
+
+ Selector selector({"#focus"});
+ *proto_.mutable_element_to_present() = selector.proto;
+
+ Selector expected_selector = selector;
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(expected_selector, _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(TIMED_OUT),
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_action_delegate_, SetTouchableElementArea(_)).Times(0);
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, TIMED_OUT))));
+ Run();
+}
+
+TEST_F(ShowCastActionTest, CheckExpectedCallChain) {
+ InSequence sequence;
+
+ Selector expected_selector({"#focus"});
+ *proto_.mutable_element_to_present() = expected_selector.proto;
+
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(expected_selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ ScrollToElementPosition(expected_selector, _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_, SetTouchableElementArea(_));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+TEST_F(ShowCastActionTest, WaitsForStableElementIfSpecified) {
+ InSequence sequence;
+
+ Selector expected_selector({"#focus"});
+ *proto_.mutable_element_to_present() = expected_selector.proto;
+ proto_.set_wait_for_stable_element(REQUIRE_STEP_SUCCESS);
+
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(expected_selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, expected_selector);
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ WaitUntilElementIsStable(_, _, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ ScrollToElementPosition(expected_selector, _,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_, SetTouchableElementArea(_));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+TEST_F(ShowCastActionTest, SetsTitleIfSpecified) {
+ ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ test_util::MockFindAnyElement(mock_action_delegate_);
+ ON_CALL(mock_action_delegate_, WaitUntilDocumentIsInReadyState(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
+ ON_CALL(mock_action_delegate_, ScrollToElementPosition(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
+
+ Selector selector({"#focus"});
+ *proto_.mutable_element_to_present() = selector.proto;
+ proto_.set_title("Title");
+
+ EXPECT_CALL(mock_action_delegate_, SetStatusMessage("Title"));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/show_form_action.cc b/chromium/components/autofill_assistant/browser/actions/show_form_action.cc
index ca6897ea60a..a0c142f029a 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_form_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/show_form_action.cc
@@ -7,8 +7,8 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/user_action.h"
#include "components/strings/grit/components_strings.h"
diff --git a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
index accb907b1b5..5cc2cfc64f7 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
@@ -9,6 +9,7 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "content/public/browser/web_contents.h"
@@ -194,16 +195,22 @@ void ShowGenericUiAction::OnViewInflationFinished(const ClientStatus& status) {
preconditions_.begin(), preconditions_.end(),
[&](const auto& precondition) { return !precondition->empty(); })) {
has_pending_wait_for_dom_ = true;
+
delegate_->WaitForDom(
base::TimeDelta::Max(), proto_.show_generic_ui().allow_interrupt(),
base::BindRepeating(&ShowGenericUiAction::RegisterChecks,
weak_ptr_factory_.GetWeakPtr()),
- base::BindOnce(&ShowGenericUiAction::OnDoneWaitForDom,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&ShowGenericUiAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&ShowGenericUiAction::OnDoneWaitForDom,
+ weak_ptr_factory_.GetWeakPtr())));
}
+ wait_time_start_ = base::TimeTicks::Now();
}
void ShowGenericUiAction::OnNavigationEnded() {
+ action_stopwatch_.TransferToWaitTime(base::TimeTicks::Now() -
+ wait_time_start_);
processed_action_proto_->mutable_show_generic_ui_result()
->set_navigation_ended(true);
OnEndActionInteraction(ClientStatus(ACTION_APPLIED));
@@ -272,6 +279,8 @@ void ShowGenericUiAction::OnEndActionInteraction(const ClientStatus& status) {
should_end_action_ = true;
return;
}
+ action_stopwatch_.TransferToWaitTime(base::TimeTicks::Now() -
+ wait_time_start_);
EndAction(status);
}
@@ -314,8 +323,7 @@ void ShowGenericUiAction::OnPersonalDataChanged() {
std::vector<std::unique_ptr<autofill::AutofillProfile>>>();
for (const auto* profile :
delegate_->GetPersonalDataManager()->GetProfilesToSuggest()) {
- profiles->emplace_back(
- std::make_unique<autofill::AutofillProfile>(*profile));
+ profiles->emplace_back(MakeUniqueFromProfile(*profile));
}
WriteProfilesToUserModel(std::move(profiles),
proto_.show_generic_ui().request_profiles(),
diff --git a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
index f57505a02f7..86b7ca4485c 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
@@ -51,6 +51,7 @@ class ShowGenericUiAction : public Action,
// From autofill::PersonalDataManagerObserver.
void OnPersonalDataChanged() override;
+ base::TimeTicks wait_time_start_;
bool has_pending_wait_for_dom_ = false;
bool should_end_action_ = false;
std::vector<std::unique_ptr<ElementPrecondition>> preconditions_;
diff --git a/chromium/components/autofill_assistant/browser/actions/stop_action.cc b/chromium/components/autofill_assistant/browser/actions/stop_action.cc
index edcb2ad52d2..44a673d98f9 100644
--- a/chromium/components/autofill_assistant/browser/actions/stop_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/stop_action.cc
@@ -23,7 +23,7 @@ void StopAction::InternalProcessAction(ProcessActionCallback callback) {
if (proto_.stop().close_cct()) {
delegate_->Close();
} else {
- delegate_->Shutdown();
+ delegate_->Shutdown(proto_.stop().show_feedback_chip());
}
UpdateProcessedAction(ACTION_APPLIED);
std::move(callback).Run(std::move(processed_action_proto_));
diff --git a/chromium/components/autofill_assistant/browser/actions/stopwatch.cc b/chromium/components/autofill_assistant/browser/actions/stopwatch.cc
new file mode 100644
index 00000000000..2863b4a6038
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/stopwatch.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 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_assistant/browser/actions/stopwatch.h"
+
+#include <ostream>
+#include <string>
+
+#include "base/logging.h"
+
+namespace autofill_assistant {
+
+Stopwatch::Stopwatch() {
+ elapsed_time_.FromMilliseconds(0);
+}
+
+bool Stopwatch::Start() {
+ if (running_) {
+ return false;
+ }
+ running_ = true;
+ start_time_ = base::TimeTicks::Now();
+ return true;
+}
+
+void Stopwatch::StartAt(base::TimeTicks start_time) {
+ running_ = true;
+ start_time_ = start_time;
+}
+
+bool Stopwatch::Stop() {
+ if (!running_) {
+ return false;
+ }
+ elapsed_time_ += LastElapsedAt(base::TimeTicks::Now());
+ running_ = false;
+ return true;
+}
+
+bool Stopwatch::StopAt(base::TimeTicks stop_time) {
+ if (!running_) {
+ return false;
+ }
+ elapsed_time_ += LastElapsedAt(stop_time);
+ running_ = false;
+ return true;
+}
+
+void Stopwatch::AddTime(base::TimeDelta time) {
+ elapsed_time_ += time;
+}
+
+void Stopwatch::AddTime(const Stopwatch& other) {
+ AddTime(other.TotalElapsed());
+}
+
+void Stopwatch::RemoveTime(base::TimeDelta time) {
+ if (elapsed_time_ > time) {
+ elapsed_time_ -= time;
+ } else {
+ elapsed_time_ = base::TimeDelta::FromMilliseconds(0);
+ if (running_) {
+ start_time_ += (time - elapsed_time_);
+ }
+ }
+}
+
+void Stopwatch::RemoveTime(const Stopwatch& other) {
+ RemoveTime(other.TotalElapsed());
+}
+
+void Stopwatch::Reset() {
+ Stop();
+ elapsed_time_ = base::TimeDelta::FromMilliseconds(0);
+}
+
+base::TimeDelta Stopwatch::TotalElapsed() const {
+ return elapsed_time_ + LastElapsedAt(base::TimeTicks::Now());
+}
+
+base::TimeDelta Stopwatch::LastElapsedAt(base::TimeTicks time) const {
+ if (!running_) {
+ return base::TimeDelta::FromMilliseconds(0);
+ }
+ return time > start_time_ ? time - start_time_
+ : base::TimeDelta::FromMilliseconds(0);
+}
+
+bool Stopwatch::IsRunning() const {
+ return running_;
+}
+
+std::ostream& operator<<(std::ostream& out, const Stopwatch& stopwatch) {
+ out << (stopwatch.elapsed_time_ + stopwatch.LastElapsedAt(base::TimeTicks()))
+ .InMilliseconds()
+ << " (currently " << (stopwatch.running_ ? "" : "not ") << "running)";
+ return out;
+}
+
+void ActionStopwatch::TransferToActiveTime(base::TimeDelta time) {
+ active_time_stopwatch_.AddTime(time);
+ wait_time_stopwatch_.RemoveTime(time);
+}
+
+void ActionStopwatch::TransferToWaitTime(base::TimeDelta time) {
+ wait_time_stopwatch_.AddTime(time);
+ active_time_stopwatch_.RemoveTime(time);
+}
+
+void ActionStopwatch::StartActiveTime() {
+ wait_time_stopwatch_.Stop();
+ active_time_stopwatch_.Start();
+}
+void ActionStopwatch::StartActiveTimeAt(base::TimeTicks start_time) {
+ wait_time_stopwatch_.StopAt(start_time);
+ active_time_stopwatch_.StartAt(start_time);
+}
+void ActionStopwatch::StartWaitTime() {
+ active_time_stopwatch_.Stop();
+ wait_time_stopwatch_.Start();
+}
+
+void ActionStopwatch::StartWaitTimeAt(base::TimeTicks start_time) {
+ active_time_stopwatch_.StopAt(start_time);
+ wait_time_stopwatch_.StartAt(start_time);
+}
+
+void ActionStopwatch::Stop() {
+ active_time_stopwatch_.Stop();
+ wait_time_stopwatch_.Stop();
+}
+
+base::TimeDelta ActionStopwatch::TotalActiveTime() {
+ return active_time_stopwatch_.TotalElapsed();
+}
+
+base::TimeDelta ActionStopwatch::TotalWaitTime() {
+ return wait_time_stopwatch_.TotalElapsed();
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const ActionStopwatch& action_stopwatch) {
+ out << "Active time: " << action_stopwatch.active_time_stopwatch_
+ << " Wait time: " << action_stopwatch.wait_time_stopwatch_;
+ return out;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/stopwatch.h b/chromium/components/autofill_assistant/browser/actions/stopwatch.h
new file mode 100644
index 00000000000..403ba4c0243
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/stopwatch.h
@@ -0,0 +1,94 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_ACTIONS_STOPWATCH_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_STOPWATCH_H_
+
+#include <ostream>
+#include <string>
+
+#include "base/time/time.h"
+
+namespace autofill_assistant {
+
+// A simple stopwatch to measure cumulative times.
+class Stopwatch {
+ public:
+ Stopwatch();
+ // Start measuring the time when the method is called.
+ // Returns true if the stopwatch was not already running.
+ bool Start();
+ // Starts measuring the time from `start_time`, if the stopwatch was already
+ // running, it simply updates the recorded start time of the current run.
+ void StartAt(base::TimeTicks start_time);
+ // Stops the stopwatch and, if it was running, adds to the cumulative elapsed
+ // time. If the stopwatch was not running, it has no effect and returns false.
+ bool Stop();
+ // Stops the stopwatch at `stop_time` and, if it was running, adds to the
+ // cumulative elapsed time. If the stopwatch was not running, it has no effect
+ // and returns false.
+ bool StopAt(base::TimeTicks stop_time);
+ // Adds `time` to the cumulative elapsed time held by this stopwatch.
+ void AddTime(base::TimeDelta time);
+ // Add `other`'s `TotalElapsed` to the cumulative elapsed time held by this
+ // stopwatch.
+ void AddTime(const Stopwatch& other);
+ // Remove `time` from the cumulative elapsed time held by this stopwatch.
+ void RemoveTime(base::TimeDelta time);
+ // Remove up to `other`'s `TotalElapsed` from the cumulative elapsed time held
+ // by this stopwatch.
+ void RemoveTime(const Stopwatch& other);
+ // Resets the stopwatch and doesn't start it again.
+ void Reset();
+ // Returns the total time accumulated by this stopwatch.
+ base::TimeDelta TotalElapsed() const;
+
+ // Whether the stopwatch is running or not.
+ bool IsRunning() const;
+
+ friend std::ostream& operator<<(std::ostream& out, const Stopwatch& action);
+
+ private:
+ base::TimeDelta LastElapsedAt(base::TimeTicks time) const;
+
+ bool running_ = false;
+ base::TimeTicks start_time_;
+ base::TimeDelta elapsed_time_;
+};
+
+// This class holds two stopwatches: one for active and one for wait time (e.g.
+// wait on preconditions or user action) spent while executing the action.
+class ActionStopwatch {
+ public:
+ // Removes `time` from the total wait time and adds it to the active time.
+ void TransferToActiveTime(base::TimeDelta time);
+ // Removes `time` from the total active time and adds it to the wait time.
+ void TransferToWaitTime(base::TimeDelta time);
+ // Starts the active time stopwatch, stopping the wait time one if it was
+ // running.
+ void StartActiveTime();
+ // Starts the active time and stops the wait time stopwatch at `start_time`,
+ // which can be a time in the past or the future.
+ void StartActiveTimeAt(base::TimeTicks start_time);
+ // Starts the wait time stopwatch, stopping the active time one if it was
+ // running.
+ void StartWaitTime();
+ // Starts the wait time and stops the active time stopwatch at `start_time`,
+ // which can be a time in the past or the future.
+ void StartWaitTimeAt(base::TimeTicks start_time);
+ // Stops both stopwatches.
+ void Stop();
+
+ base::TimeDelta TotalActiveTime();
+ base::TimeDelta TotalWaitTime();
+ friend std::ostream& operator<<(std::ostream& out,
+ const ActionStopwatch& action);
+
+ private:
+ Stopwatch active_time_stopwatch_;
+ Stopwatch wait_time_stopwatch_;
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_ACTION_TIMER_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/stopwatch_unittest.cc b/chromium/components/autofill_assistant/browser/actions/stopwatch_unittest.cc
new file mode 100644
index 00000000000..ffa8d2c9128
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/stopwatch_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2020 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_assistant/browser/actions/stopwatch.h"
+
+#include "base/logging.h"
+#include "base/time/time_override.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+class TimeTicksOverride {
+ public:
+ static base::TimeTicks Now() { return now_ticks_; }
+
+ static base::TimeTicks now_ticks_;
+};
+
+// static
+base::TimeTicks TimeTicksOverride::now_ticks_ = base::TimeTicks::Now();
+
+class StopwatchTest : public testing::Test {
+ protected:
+ Stopwatch stopwatch_;
+};
+
+TEST_F(StopwatchTest, SimpleRun) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ EXPECT_TRUE(stopwatch_.Start());
+ EXPECT_FALSE(stopwatch_.Start());
+ EXPECT_TRUE(stopwatch_.IsRunning());
+
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1), stopwatch_.TotalElapsed());
+
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(stopwatch_.Stop());
+ EXPECT_FALSE(stopwatch_.Stop());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(3), stopwatch_.TotalElapsed());
+
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(stopwatch_.Start());
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(4), stopwatch_.TotalElapsed());
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(stopwatch_.Stop());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(5), stopwatch_.TotalElapsed());
+}
+
+TEST_F(StopwatchTest, AddTime) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ stopwatch_.Start();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ stopwatch_.Stop();
+ stopwatch_.AddTime(base::TimeDelta::FromSeconds(2));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(3), stopwatch_.TotalElapsed());
+}
+
+TEST_F(StopwatchTest, RemoveTime) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ stopwatch_.Start();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ stopwatch_.Stop();
+ stopwatch_.RemoveTime(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1), stopwatch_.TotalElapsed());
+}
+
+TEST_F(StopwatchTest, RemoveGreaterThanElapsed) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ stopwatch_.Start();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ stopwatch_.Stop();
+ stopwatch_.RemoveTime(base::TimeDelta::FromSeconds(2));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(0), stopwatch_.TotalElapsed());
+}
+
+// This parameterized test uses 4 parameters: time to start at, time to stop at,
+// expected time before the stop is invoked and expected time at the end.
+// If start at or stop at times are 0, the regular Start() and Stop() methods
+// are used instead of the StartAt(time) or StopAt(time).
+class StopwatchStartStopTest
+ : public StopwatchTest,
+ public testing::WithParamInterface<std::tuple<long, long, long, long>> {};
+
+INSTANTIATE_TEST_SUITE_P(ParametrizedTests,
+ StopwatchStartStopTest,
+ testing::Values(std::make_tuple(-1, 1, 1, 2),
+ std::make_tuple(1, 2, 0, 1),
+ std::make_tuple(2, 1, 0, 0),
+ std::make_tuple(-1, 0, 1, 1),
+ std::make_tuple(1, 0, 0, 0),
+ std::make_tuple(0, 1, 0, 1)));
+
+TEST_P(StopwatchStartStopTest, StartAndStopAt) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ long start_at = std::get<0>(GetParam());
+ long stop_at = std::get<1>(GetParam());
+ long expected_while_running = std::get<2>(GetParam());
+ long expected = std::get<3>(GetParam());
+ if (start_at) {
+ stopwatch_.StartAt(TimeTicksOverride::now_ticks_ +
+ base::TimeDelta::FromSeconds(start_at));
+ } else {
+ stopwatch_.Start();
+ }
+ EXPECT_EQ(base::TimeDelta::FromSeconds(expected_while_running),
+ stopwatch_.TotalElapsed());
+ if (stop_at) {
+ stopwatch_.StopAt(TimeTicksOverride::now_ticks_ +
+ base::TimeDelta::FromSeconds(stop_at));
+ } else {
+ stopwatch_.Stop();
+ }
+ EXPECT_EQ(base::TimeDelta::FromSeconds(expected), stopwatch_.TotalElapsed());
+}
+
+class ActionStopwatchTest : public testing::Test {
+ protected:
+ ActionStopwatch action_stopwatch_;
+};
+
+TEST_F(ActionStopwatchTest, SimpleRun) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ action_stopwatch_.StartActiveTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(1);
+ action_stopwatch_.StartWaitTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ action_stopwatch_.Stop();
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1),
+ action_stopwatch_.TotalActiveTime());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(2), action_stopwatch_.TotalWaitTime());
+}
+
+TEST_F(ActionStopwatchTest, TransferToActive) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ action_stopwatch_.StartActiveTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(4);
+ action_stopwatch_.StartWaitTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ action_stopwatch_.Stop();
+ action_stopwatch_.TransferToActiveTime(base::TimeDelta::FromSeconds(3));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(7),
+ action_stopwatch_.TotalActiveTime());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(0), action_stopwatch_.TotalWaitTime());
+}
+
+TEST_F(ActionStopwatchTest, TransferToWait) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ action_stopwatch_.StartActiveTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ action_stopwatch_.StartWaitTime();
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(4);
+ action_stopwatch_.Stop();
+ action_stopwatch_.TransferToWaitTime(base::TimeDelta::FromSeconds(3));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(0),
+ action_stopwatch_.TotalActiveTime());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(7), action_stopwatch_.TotalWaitTime());
+}
+
+TEST_F(ActionStopwatchTest, StartTimesAt) {
+ base::subtle::ScopedTimeClockOverrides overrides(
+ nullptr, &TimeTicksOverride::Now, nullptr);
+ action_stopwatch_.StartActiveTimeAt(TimeTicksOverride::now_ticks_ +
+ base::TimeDelta::FromSeconds(1));
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(5);
+ action_stopwatch_.StartWaitTimeAt(TimeTicksOverride::now_ticks_ -
+ base::TimeDelta::FromSeconds(1));
+ TimeTicksOverride::now_ticks_ += base::TimeDelta::FromSeconds(2);
+ action_stopwatch_.Stop();
+ EXPECT_EQ(base::TimeDelta::FromSeconds(3),
+ action_stopwatch_.TotalActiveTime());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(3), action_stopwatch_.TotalWaitTime());
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/upload_dom_action.cc b/chromium/components/autofill_assistant/browser/actions/upload_dom_action.cc
index 7d6f558e243..43552a809be 100644
--- a/chromium/components/autofill_assistant/browser/actions/upload_dom_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/upload_dom_action.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/client_status.h"
namespace autofill_assistant {
@@ -22,45 +23,79 @@ UploadDomAction::UploadDomAction(ActionDelegate* delegate,
UploadDomAction::~UploadDomAction() {}
void UploadDomAction::InternalProcessAction(ProcessActionCallback callback) {
+ process_action_callback_ = std::move(callback);
+
Selector selector = Selector(proto_.upload_dom().tree_root());
if (selector.empty()) {
VLOG(1) << __func__ << ": empty selector";
- UpdateProcessedAction(INVALID_SELECTOR);
+ EndAction(ClientStatus(INVALID_SELECTOR));
return;
}
delegate_->ShortWaitForElement(
- selector, base::BindOnce(&UploadDomAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(callback), selector));
+ selector,
+ base::BindOnce(
+ &UploadDomAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&UploadDomAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(), selector,
+ proto_.upload_dom().can_match_multiple_elements())));
}
-void UploadDomAction::OnWaitForElement(ProcessActionCallback callback,
- const Selector& selector,
+void UploadDomAction::OnWaitForElement(const Selector& selector,
+ bool can_match_multiple_elements,
const ClientStatus& element_status) {
if (!element_status.ok()) {
- UpdateProcessedAction(element_status.proto_status());
- std::move(callback).Run(std::move(processed_action_proto_));
+ EndAction(element_status);
+ return;
+ }
+
+ if (can_match_multiple_elements) {
+ delegate_->FindAllElements(
+ selector,
+ base::BindOnce(&action_delegate_util::TakeElementAndGetProperty<
+ std::vector<std::string>>,
+ base::BindOnce(&ActionDelegate::GetOuterHtmls,
+ delegate_->GetWeakPtr()),
+ base::BindOnce(&UploadDomAction::OnGetOuterHtmls,
+ weak_ptr_factory_.GetWeakPtr())));
return;
}
- delegate_->GetOuterHtml(
+ delegate_->FindElement(
selector,
- base::BindOnce(&UploadDomAction::OnGetOuterHtml,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ base::BindOnce(
+ &action_delegate_util::TakeElementAndGetProperty<std::string>,
+ base::BindOnce(&ActionDelegate::GetOuterHtml,
+ delegate_->GetWeakPtr()),
+ base::BindOnce(&UploadDomAction::OnGetOuterHtml,
+ weak_ptr_factory_.GetWeakPtr())));
}
-void UploadDomAction::OnGetOuterHtml(ProcessActionCallback callback,
- const ClientStatus& status,
+void UploadDomAction::OnGetOuterHtml(const ClientStatus& status,
const std::string& outer_html) {
- if (!status.ok()) {
- UpdateProcessedAction(status);
- std::move(callback).Run(std::move(processed_action_proto_));
- return;
+ if (status.ok()) {
+ processed_action_proto_->mutable_upload_dom_result()->add_outer_htmls(
+ outer_html);
}
+ EndAction(status);
+}
+
+void UploadDomAction::OnGetOuterHtmls(
+ const ClientStatus& status,
+ const std::vector<std::string>& outer_htmls) {
+ if (status.ok()) {
+ auto* result = processed_action_proto_->mutable_upload_dom_result();
+ for (const auto& outer_html : outer_htmls) {
+ result->add_outer_htmls(outer_html);
+ }
+ }
+
+ EndAction(status);
+}
- processed_action_proto_->set_html_source(outer_html);
- UpdateProcessedAction(ACTION_APPLIED);
- std::move(callback).Run(std::move(processed_action_proto_));
+void UploadDomAction::EndAction(const ClientStatus& status) {
+ UpdateProcessedAction(status);
+ std::move(process_action_callback_).Run(std::move(processed_action_proto_));
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/upload_dom_action.h b/chromium/components/autofill_assistant/browser/actions/upload_dom_action.h
index 1d0cc50eed5..9e42b9a504b 100644
--- a/chromium/components/autofill_assistant/browser/actions/upload_dom_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/upload_dom_action.h
@@ -7,9 +7,11 @@
#include <string>
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
@@ -22,13 +24,16 @@ class UploadDomAction : public Action {
// Overrides Action:
void InternalProcessAction(ProcessActionCallback callback) override;
- void OnWaitForElement(ProcessActionCallback callback,
- const Selector& selector,
+ void OnWaitForElement(const Selector& selector,
+ bool can_match_multiple_elements,
const ClientStatus& element_status);
- void OnGetOuterHtml(ProcessActionCallback callback,
- const ClientStatus& status,
+ void OnGetOuterHtml(const ClientStatus& status,
const std::string& outer_html);
+ void OnGetOuterHtmls(const ClientStatus& status,
+ const std::vector<std::string>& outer_htmls);
+ void EndAction(const ClientStatus& status);
+ ProcessActionCallback process_action_callback_;
base::WeakPtrFactory<UploadDomAction> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(UploadDomAction);
diff --git a/chromium/components/autofill_assistant/browser/actions/upload_dom_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/upload_dom_action_unittest.cc
new file mode 100644
index 00000000000..352f0ede12a
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/upload_dom_action_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2020 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_assistant/browser/actions/upload_dom_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::Eq;
+using ::testing::InSequence;
+using ::testing::Pointee;
+using ::testing::Property;
+
+class UploadDomActionTest : public testing::Test {
+ public:
+ UploadDomActionTest() {}
+
+ void SetUp() override {}
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_upload_dom() = proto_;
+ UploadDomAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ UploadDomProto::Result UploadDomResult(
+ const std::vector<std::string>& outer_htmls) {
+ UploadDomProto::Result result;
+ for (const auto& outer_html : outer_htmls) {
+ result.add_outer_htmls(outer_html);
+ }
+ return result;
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ UploadDomProto proto_;
+};
+
+TEST_F(UploadDomActionTest, EmptySelectorFails) {
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR))));
+ Run();
+}
+
+TEST_F(UploadDomActionTest, ActionFailsForNonExistentElement) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_tree_root() = selector.proto;
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(selector, _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(TIMED_OUT),
+ base::TimeDelta::FromSeconds(0)));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(Property(&ProcessedActionProto::status, TIMED_OUT),
+ Property(&ProcessedActionProto::upload_dom_result,
+ Eq(UploadDomResult({})))))));
+ Run();
+}
+
+TEST_F(UploadDomActionTest, CheckExpectedCallChain) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_tree_root() = selector.proto;
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, selector);
+ EXPECT_CALL(mock_action_delegate_,
+ GetOuterHtml(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "<html></html>"));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(&ProcessedActionProto::upload_dom_result,
+ Eq(UploadDomResult({"<html></html>"})))))));
+ Run();
+}
+
+TEST_F(UploadDomActionTest, ReturnsEmptyStringForNotFoundElement) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_tree_root() = selector.proto;
+
+ // Unlikely scenario, if ShortWaitForElement succeeds, the FindElement will
+ // too. Failing FindElement is however the more interesting test than failing
+ // GetOuterHtml.
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_action_delegate_, FindElement(selector, _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ EXPECT_CALL(mock_action_delegate_, GetOuterHtml(_, _)).Times(0);
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ELEMENT_RESOLUTION_FAILED),
+ Property(&ProcessedActionProto::upload_dom_result,
+ Eq(UploadDomResult({})))))));
+ Run();
+}
+
+TEST_F(UploadDomActionTest, MultipleDomUpload) {
+ InSequence sequence;
+
+ Selector selector({"#element"});
+ *proto_.mutable_tree_root() = selector.proto;
+ proto_.set_can_match_multiple_elements(true);
+
+ EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(selector, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+
+ EXPECT_CALL(mock_action_delegate_, FindAllElements(selector, _))
+ .WillOnce(testing::WithArgs<1>([](auto&& callback) {
+ auto element_result = std::make_unique<ElementFinder::Result>();
+ element_result->object_id = "fake_object_id";
+ std::move(callback).Run(OkClientStatus(), std::move(element_result));
+ }));
+
+ ElementFinder::Result expected_result;
+ expected_result.object_id = "fake_object_id";
+
+ std::vector<std::string> fake_htmls{"<div></div>", "<span></span>"};
+ EXPECT_CALL(mock_action_delegate_,
+ GetOuterHtmls(EqualsElement(expected_result), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), fake_htmls));
+
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(AllOf(
+ Property(&ProcessedActionProto::status, ACTION_APPLIED),
+ Property(&ProcessedActionProto::upload_dom_result,
+ Eq(UploadDomResult({"<div></div>", "<span></span>"})))))));
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/use_address_action.cc b/chromium/components/autofill_assistant/browser/actions/use_address_action.cc
index 938cab87309..37a73beca5f 100644
--- a/chromium/components/autofill_assistant/browser/actions/use_address_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/use_address_action.cc
@@ -17,6 +17,7 @@
#include "components/autofill_assistant/browser/actions/fallback_handler/required_fields_fallback_handler.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/field_formatter.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/value_util.h"
@@ -27,7 +28,6 @@ UseAddressAction::UseAddressAction(ActionDelegate* delegate,
: Action(delegate, proto) {
DCHECK(proto.has_use_address());
selector_ = Selector(proto.use_address().form_field_element());
- selector_.MustBeVisible();
}
UseAddressAction::~UseAddressAction() = default;
@@ -70,7 +70,7 @@ void UseAddressAction::InternalProcessAction(
EndAction(ClientStatus(PRECONDITION_FAILED));
return;
}
- profile_ = std::make_unique<autofill::AutofillProfile>(*profile);
+ profile_ = MakeUniqueFromProfile(*profile);
break;
}
case UseAddressProto::kModelIdentifier: {
@@ -103,7 +103,7 @@ void UseAddressAction::InternalProcessAction(
EndAction(ClientStatus(PRECONDITION_FAILED));
return;
}
- profile_ = std::make_unique<autofill::AutofillProfile>(*profile);
+ profile_ = MakeUniqueFromProfile(*profile);
break;
}
case UseAddressProto::ADDRESS_SOURCE_NOT_SET:
@@ -118,6 +118,9 @@ void UseAddressAction::InternalProcessAction(
void UseAddressAction::EndAction(
const ClientStatus& final_status,
const base::Optional<ClientStatus>& optional_details_status) {
+ if (fallback_handler_)
+ action_stopwatch_.TransferToWaitTime(fallback_handler_->TotalWaitTime());
+
UpdateProcessedAction(final_status);
if (optional_details_status.has_value() && !optional_details_status->ok()) {
processed_action_proto_->mutable_status_details()->MergeFrom(
@@ -134,8 +137,11 @@ void UseAddressAction::FillFormWithData() {
}
delegate_->ShortWaitForElement(
- selector_, base::BindOnce(&UseAddressAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr()));
+ selector_,
+ base::BindOnce(&UseAddressAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&UseAddressAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr())));
}
void UseAddressAction::OnWaitForElement(const ClientStatus& element_status) {
diff --git a/chromium/components/autofill_assistant/browser/actions/use_address_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
index 1681d7b7ccd..7ee586f3cf5 100644
--- a/chromium/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
@@ -18,6 +18,7 @@
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/mock_personal_data_manager.h"
+#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
@@ -72,7 +73,9 @@ class UseAddressActionTest : public testing::Test {
checker->Run(&mock_web_controller_);
}));
ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
+ test_util::MockFindAnyElement(mock_web_controller_);
}
protected:
@@ -158,8 +161,9 @@ TEST_F(UseAddressActionTest, PreconditionFailedNoProfileForName) {
TEST_F(UseAddressActionTest, ResolveProfileByNameSucceeds) {
ON_CALL(mock_action_delegate_,
- OnShortWaitForElement(Selector({kFakeSelector}).MustBeVisible(), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ OnShortWaitForElement(Selector({kFakeSelector}), _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
@@ -192,8 +196,9 @@ TEST_F(UseAddressActionTest, PreconditionFailedNoProfileForModelIdentifier) {
TEST_F(UseAddressActionTest, ResolveProfileByModelIdentifierSucceeds) {
ON_CALL(mock_action_delegate_,
- OnShortWaitForElement(Selector({kFakeSelector}).MustBeVisible(), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ OnShortWaitForElement(Selector({kFakeSelector}), _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
@@ -231,10 +236,10 @@ TEST_F(UseAddressActionTest, PreconditionFailedPopulatesUnexpectedErrorInfo) {
}
TEST_F(UseAddressActionTest, ShortWaitForElementVisible) {
- EXPECT_CALL(
- mock_action_delegate_,
- OnShortWaitForElement(Selector({kFakeSelector}).MustBeVisible(), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnShortWaitForElement(Selector({kFakeSelector}), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ActionProto action_proto = CreateUseAddressAction();
// Autofill succeeds.
@@ -274,8 +279,7 @@ TEST_F(UseAddressActionTest, ValidationSucceeds) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Validation succeeds.
@@ -316,24 +320,33 @@ TEST_F(UseAddressActionTest, FallbackFails) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Validation fails when getting FIRST_NAME.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(email_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, email_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(last_name_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, last_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
// Fallback fails.
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFirstName,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, first_name_selector)),
- _))
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFirstName,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<2>(ClientStatus(OTHER_ACTION_STATUS)));
ProcessedActionProto processed_action;
@@ -355,7 +368,9 @@ TEST_F(UseAddressActionTest, FallbackFails) {
.status());
}
-TEST_F(UseAddressActionTest, FallbackSucceeds) {
+TEST_F(UseAddressActionTest, FillAddressWithFallback) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -379,37 +394,44 @@ TEST_F(UseAddressActionTest, FallbackSucceeds) {
"}"}),
"#email");
- Selector email_selector({"#email"});
Selector first_name_selector({"#first_name"});
Selector last_name_selector({"#last_name"});
+ Selector email_selector({"#email"});
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
- // Validation fails when getting FIRST_NAME.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(email_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(last_name_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+ // First validation fails with an empty value, called once for each field.
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
+ .Times(3)
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), std::string()));
- // Fallback succeeds.
- Expectation set_first_name =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue(kFirstName,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, first_name_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ // Expect fields to be filled
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFirstName,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, first_name_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(kLastName,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, last_name_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(kEmail,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, email_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
- .After(set_first_name)
+ .Times(3)
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
@@ -420,8 +442,7 @@ TEST_F(UseAddressActionTest, AutofillFailureWithoutRequiredFieldsIsFatal) {
ActionProto action_proto = CreateUseAddressAction();
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(ClientStatus(OTHER_ACTION_STATUS)));
ProcessedActionProto processed_action;
@@ -437,6 +458,8 @@ TEST_F(UseAddressActionTest, AutofillFailureWithoutRequiredFieldsIsFatal) {
TEST_F(UseAddressActionTest,
AutofillFailureWithRequiredFieldsLaunchesFallback) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -451,26 +474,29 @@ TEST_F(UseAddressActionTest,
Selector first_name_selector({"#first_name"});
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(
FillAutofillErrorStatus(ClientStatus(OTHER_ACTION_STATUS))));
// First validation fails.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fill first name.
- Expectation set_first_name =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue(kFirstName,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, first_name_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFirstName,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, first_name_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
- .After(set_first_name)
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
ProcessedActionProto processed_action;
@@ -488,6 +514,8 @@ TEST_F(UseAddressActionTest,
}
TEST_F(UseAddressActionTest, FallbackForPhoneSucceeds) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -498,27 +526,30 @@ TEST_F(UseAddressActionTest, FallbackForPhoneSucceeds) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Validation fails when getting phone number.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(phone_number_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, phone_number_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fallback succeeds.
- Expectation set_phone_number_name =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("(+41) (79) 1234567",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, phone_number_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("(+41) (79) 1234567",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, phone_number_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(phone_number_selector, _))
- .After(set_phone_number_name)
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, phone_number_selector)),
+ _))
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
@@ -526,6 +557,8 @@ TEST_F(UseAddressActionTest, FallbackForPhoneSucceeds) {
}
TEST_F(UseAddressActionTest, ForcedFallbackWithKeystrokes) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -545,28 +578,50 @@ TEST_F(UseAddressActionTest, ForcedFallbackWithKeystrokes) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
- OnFillAddressForm(
- NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
+ OnFillAddressForm(NotNull(), Eq(Selector({kFakeSelector})), _))
.WillOnce(RunOnceCallback<2>(OkClientStatus()));
- // The field is not empty.
- ON_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+ // Do not check required field.
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
- // But we still want the first name filled, with
- // simulated keypresses.
+ // But we still want the first name filled, with simulated keypresses.
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, first_name_selector);
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ ScrollIntoView(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::CLICK, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFirstName, true, 1000,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, first_name_selector)),
+ OnSendKeyboardInput(UTF8ToUnicode(kFirstName), 1000,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ // The field is only checked afterwards and is not empty.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
_))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
ProcessAction(action_proto));
}
TEST_F(UseAddressActionTest, SkippingAutofill) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -586,20 +641,24 @@ TEST_F(UseAddressActionTest, SkippingAutofill) {
EXPECT_CALL(mock_action_delegate_, OnFillAddressForm(_, _, _)).Times(0);
// First validation fails.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fill first name.
- Expectation set_first_name =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue(kFirstName,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, first_name_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute(kFirstName,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, first_name_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(first_name_selector, _))
- .After(set_first_name)
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, first_name_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
ProcessedActionProto processed_action;
diff --git a/chromium/components/autofill_assistant/browser/actions/use_credit_card_action.cc b/chromium/components/autofill_assistant/browser/actions/use_credit_card_action.cc
index 717f02e68a2..38b3691927c 100644
--- a/chromium/components/autofill_assistant/browser/actions/use_credit_card_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/use_credit_card_action.cc
@@ -32,7 +32,6 @@ UseCreditCardAction::UseCreditCardAction(ActionDelegate* delegate,
: Action(delegate, proto) {
DCHECK(proto.has_use_card());
selector_ = Selector(proto.use_card().form_field_element());
- selector_.MustBeVisible();
}
UseCreditCardAction::~UseCreditCardAction() = default;
@@ -100,6 +99,9 @@ void UseCreditCardAction::InternalProcessAction(
void UseCreditCardAction::EndAction(
const ClientStatus& final_status,
const base::Optional<ClientStatus>& optional_details_status) {
+ if (fallback_handler_)
+ action_stopwatch_.TransferToWaitTime(fallback_handler_->TotalWaitTime());
+
UpdateProcessedAction(final_status);
if (optional_details_status.has_value() && !optional_details_status->ok()) {
processed_action_proto_->mutable_status_details()->MergeFrom(
@@ -116,8 +118,11 @@ void UseCreditCardAction::FillFormWithData() {
}
delegate_->ShortWaitForElement(
- selector_, base::BindOnce(&UseCreditCardAction::OnWaitForElement,
- weak_ptr_factory_.GetWeakPtr()));
+ selector_,
+ base::BindOnce(&UseCreditCardAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&UseCreditCardAction::OnWaitForElement,
+ weak_ptr_factory_.GetWeakPtr())));
}
void UseCreditCardAction::OnWaitForElement(const ClientStatus& element_status) {
@@ -130,11 +135,13 @@ void UseCreditCardAction::OnWaitForElement(const ClientStatus& element_status) {
delegate_->GetFullCard(credit_card_.get(),
base::BindOnce(&UseCreditCardAction::OnGetFullCard,
weak_ptr_factory_.GetWeakPtr()));
+ action_stopwatch_.StartWaitTime();
}
void UseCreditCardAction::OnGetFullCard(
std::unique_ptr<autofill::CreditCard> card,
const base::string16& cvc) {
+ action_stopwatch_.StartActiveTime();
if (!card) {
EndAction(ClientStatus(GET_FULL_CARD_FAILED));
return;
@@ -180,6 +187,7 @@ void UseCreditCardAction::OnGetFullCard(
void UseCreditCardAction::ExecuteFallback(const ClientStatus& status) {
DCHECK(fallback_handler_ != nullptr);
+ action_stopwatch_.TransferToWaitTime(fallback_handler_->TotalWaitTime());
fallback_handler_->CheckAndFallbackRequiredFields(
status, base::BindOnce(&UseCreditCardAction::EndAction,
weak_ptr_factory_.GetWeakPtr()));
diff --git a/chromium/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
index 9fd9626efb9..97f65becd27 100644
--- a/chromium/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
@@ -16,6 +16,7 @@
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/mock_personal_data_manager.h"
+#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
@@ -72,7 +73,8 @@ class UseCreditCardActionTest : public testing::Test {
checker->Run(&mock_web_controller_);
}));
ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ON_CALL(mock_action_delegate_, OnGetFullCard)
.WillByDefault(Invoke([](const autofill::CreditCard* credit_card,
base::OnceCallback<void(
@@ -83,6 +85,7 @@ class UseCreditCardActionTest : public testing::Test {
: nullptr,
base::UTF8ToUTF16(kFakeCvc));
}));
+ test_util::MockFindAnyElement(mock_web_controller_);
}
protected:
@@ -153,8 +156,9 @@ TEST_F(UseCreditCardActionTest, PreconditionFailedNoCreditCardInUserData) {
TEST_F(UseCreditCardActionTest, CreditCardInUserDataSucceeds) {
ON_CALL(mock_action_delegate_,
- OnShortWaitForElement(Selector({kFakeSelector}).MustBeVisible(), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ OnShortWaitForElement(Selector({kFakeSelector}), _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
ActionProto action;
@@ -163,7 +167,7 @@ TEST_F(UseCreditCardActionTest, CreditCardInUserDataSucceeds) {
EXPECT_CALL(
mock_action_delegate_,
OnFillCardForm(Pointee(Eq(credit_card_)), base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
}
@@ -188,8 +192,9 @@ TEST_F(UseCreditCardActionTest,
TEST_F(UseCreditCardActionTest, CreditCardInUserModelSucceeds) {
ON_CALL(mock_action_delegate_,
- OnShortWaitForElement(Selector({kFakeSelector}).MustBeVisible(), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ OnShortWaitForElement(Selector({kFakeSelector}), _))
+ .WillByDefault(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
ActionProto action;
@@ -199,7 +204,7 @@ TEST_F(UseCreditCardActionTest, CreditCardInUserModelSucceeds) {
EXPECT_CALL(
mock_action_delegate_,
OnFillCardForm(Pointee(Eq(credit_card_)), base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
}
@@ -210,7 +215,7 @@ TEST_F(UseCreditCardActionTest, FillCreditCard) {
user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
@@ -234,13 +239,15 @@ TEST_F(UseCreditCardActionTest, FillCreditCardRequiredFieldsFilled) {
user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
}
TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -296,6 +303,11 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
"}"}),
"#network");
+ EXPECT_CALL(mock_action_delegate_,
+ OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
+ Selector({kFakeSelector}), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
Selector cvc_selector({"#cvc"});
Selector expiry_month_selector({"#expmonth"});
Selector expiry_year2_selector({"#expyear2"});
@@ -304,110 +316,70 @@ TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
Selector card_number_selector({"#card_number"});
Selector network_selector({"#network"});
- // First validation fails.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_month_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_year2_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_year4_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(card_name_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(card_number_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(network_selector, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
+ // First validation fails with an empty value, called once for each field.
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
+ .Times(7)
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), std::string()));
// Expect fields to be filled
- Expectation set_cvc =
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakeCvc,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, cvc_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_expmonth =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("09",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expiry_month_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_expyear2 =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("50",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expiry_year2_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_expyear4 =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("2050",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expiry_year4_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_cardholder_name =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("Adam West",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, card_name_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_card_number =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("4111111111111111",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, card_number_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
- Expectation set_card_network =
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue("visa",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, network_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(kFakeCvc,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, cvc_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("09",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expiry_month_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("50",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expiry_year2_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("2050",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expiry_year4_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("Adam West",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, card_name_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("4111111111111111",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, card_number_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute("visa",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, network_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// After fallback, second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
- .After(set_cvc)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_month_selector, _))
- .After(set_expmonth)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_year2_selector, _))
- .After(set_expyear2)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(expiry_year4_selector, _))
- .After(set_expyear4)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(card_name_selector, _))
- .After(set_expyear4)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(card_number_selector, _))
- .After(set_expyear4)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(network_selector, _))
- .After(set_card_network)
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
-
- EXPECT_CALL(mock_action_delegate_,
- OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
- .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
+ .Times(7)
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
}
TEST_F(UseCreditCardActionTest, ForcedFallbackWithKeystrokes) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -423,29 +395,53 @@ TEST_F(UseCreditCardActionTest, ForcedFallbackWithKeystrokes) {
cvc_required->set_fill_strategy(SIMULATE_KEY_PRESSES);
cvc_required->set_delay_in_millisecond(1000);
- // No field is ever empty
- ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+ user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
+ EXPECT_CALL(mock_action_delegate_,
+ OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
+ Selector({kFakeSelector}), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ // Do not check required field.
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
// But we still want the CVC filled, with simulated keypresses.
Selector cvc_selector({"#cvc"});
+ auto expected_element =
+ test_util::MockFindElement(mock_action_delegate_, cvc_selector);
EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakeCvc, true, 1000,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, cvc_selector)),
- _))
- .WillOnce(RunOnceCallback<4>(OkClientStatus()));
-
- user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
+ SetValueAttribute("", EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
EXPECT_CALL(mock_action_delegate_,
- OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ WaitUntilDocumentIsInReadyState(
+ _, DOCUMENT_INTERACTIVE, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ ScrollIntoView(EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_, WaitUntilElementIsStable(_, _, _, _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ ClickOrTapElement(ClickType::CLICK, EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ OnSendKeyboardInput(UTF8ToUnicode(kFakeCvc), 1000,
+ EqualsElement(expected_element), _))
+ .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+ // The field is only checked afterwards and is not empty.
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, cvc_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
}
TEST_F(UseCreditCardActionTest, SkippingAutofill) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -465,19 +461,23 @@ TEST_F(UseCreditCardActionTest, SkippingAutofill) {
EXPECT_CALL(mock_action_delegate_, OnFillCardForm(_, _, _, _)).Times(0);
// First validation fails.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, cvc_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fill cvc.
- Expectation set_cvc =
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakeCvc,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, cvc_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(kFakeCvc,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, cvc_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
- .After(set_cvc)
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, cvc_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED, ProcessAction(action));
@@ -489,7 +489,7 @@ TEST_F(UseCreditCardActionTest, AutofillFailureWithoutRequiredFieldsIsFatal) {
user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(ClientStatus(OTHER_ACTION_STATUS)));
ProcessedActionProto processed_action;
@@ -505,6 +505,8 @@ TEST_F(UseCreditCardActionTest, AutofillFailureWithoutRequiredFieldsIsFatal) {
TEST_F(UseCreditCardActionTest,
AutofillFailureWithRequiredFieldsLaunchesFallback) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -522,24 +524,28 @@ TEST_F(UseCreditCardActionTest,
user_data_.selected_card_ = std::make_unique<autofill::CreditCard>();
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(
FillAutofillErrorStatus(ClientStatus(OTHER_ACTION_STATUS))));
// First validation fails.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, cvc_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fill CVC.
- Expectation set_cvc =
- EXPECT_CALL(mock_action_delegate_,
- OnSetFieldValue(kFakeCvc,
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, cvc_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(mock_action_delegate_,
+ SetValueAttribute(kFakeCvc,
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, cvc_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(cvc_selector, _))
- .After(set_cvc)
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, cvc_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
ProcessedActionProto processed_action;
@@ -557,6 +563,8 @@ TEST_F(UseCreditCardActionTest,
}
TEST_F(UseCreditCardActionTest, FallbackForCardExpirationSucceeds) {
+ InSequence sequence;
+
ON_CALL(mock_action_delegate_, GetElementTag(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
@@ -568,27 +576,32 @@ TEST_F(UseCreditCardActionTest, FallbackForCardExpirationSucceeds) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
// Validation fails when getting expiration date.
- EXPECT_CALL(mock_web_controller_,
- OnGetFieldValue(expiration_date_selector, _))
+ EXPECT_CALL(
+ mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expiration_date_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fallback succeeds.
- Expectation set_expiration_date =
- EXPECT_CALL(
- mock_action_delegate_,
- OnSetFieldValue("09 - 2050",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expiration_date_selector)),
- _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ mock_action_delegate_,
+ SetValueAttribute("09 - 2050",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expiration_date_selector)),
+ _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
// Second validation succeeds.
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
- .After(set_expiration_date)
+ EXPECT_CALL(
+ mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expiration_date_selector)),
+ _))
.WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
@@ -607,21 +620,24 @@ TEST_F(UseCreditCardActionTest, FallbackFails) {
// Autofill succeeds.
EXPECT_CALL(mock_action_delegate_,
OnFillCardForm(_, base::UTF8ToUTF16(kFakeCvc),
- Selector({kFakeSelector}).MustBeVisible(), _))
+ Selector({kFakeSelector}), _))
.WillOnce(RunOnceCallback<3>(OkClientStatus()));
// Validation fails when getting expiration date.
- EXPECT_CALL(mock_web_controller_,
- OnGetFieldValue(expiration_date_selector, _))
+ EXPECT_CALL(
+ mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expiration_date_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
// Fallback fails.
EXPECT_CALL(
mock_action_delegate_,
- OnSetFieldValue("09/2050",
- EqualsElement(test_util::MockFindElement(
- mock_action_delegate_, expiration_date_selector)),
- _))
+ SetValueAttribute("09/2050",
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expiration_date_selector)),
+ _))
.WillOnce(RunOnceCallback<2>(ClientStatus(OTHER_ACTION_STATUS)));
ProcessedActionProto processed_action;
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.cc
index 976ad325ade..8a7b28942bb 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.cc
@@ -6,6 +6,7 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
@@ -21,25 +22,50 @@ void WaitForDocumentAction::InternalProcessAction(
ProcessActionCallback callback) {
callback_ = std::move(callback);
- Selector selector(proto_.wait_for_document().frame());
- if (selector.empty()) {
+ Selector frame_selector(proto_.wait_for_document().frame());
+ if (frame_selector.empty()) {
// No element to wait for.
- OnShortWaitForElement(ClientStatus(ACTION_APPLIED));
+ WaitForReadyState();
return;
}
delegate_->ShortWaitForElement(
- selector, base::BindOnce(&WaitForDocumentAction::OnShortWaitForElement,
- weak_ptr_factory_.GetWeakPtr()));
+ frame_selector,
+ base::BindOnce(
+ &WaitForDocumentAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&WaitForDocumentAction::OnShortWaitForElement,
+ weak_ptr_factory_.GetWeakPtr(), frame_selector)));
}
void WaitForDocumentAction::OnShortWaitForElement(
+ const Selector& frame_selector,
const ClientStatus& element_status) {
if (!element_status.ok()) {
SendResult(element_status, DOCUMENT_UNKNOWN_READY_STATE);
return;
}
+
+ delegate_->FindElement(frame_selector,
+ base::BindOnce(&WaitForDocumentAction::OnFindElement,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WaitForDocumentAction::OnFindElement(
+ const ClientStatus& status,
+ std::unique_ptr<ElementFinder::Result> element) {
+ if (!status.ok()) {
+ SendResult(status, DOCUMENT_UNKNOWN_READY_STATE);
+ return;
+ }
+
+ optional_frame_element_ = std::move(element);
+ WaitForReadyState();
+}
+
+void WaitForDocumentAction::WaitForReadyState() {
delegate_->GetDocumentReadyState(
- Selector(proto_.wait_for_document().frame()),
+ optional_frame_element_ ? *optional_frame_element_
+ : ElementFinder::Result(),
base::BindOnce(&WaitForDocumentAction::OnGetStartState,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -66,38 +92,39 @@ void WaitForDocumentAction::OnGetStartState(const ClientStatus& status,
return;
}
- timer_.Start(FROM_HERE, timeout,
- base::BindOnce(&WaitForDocumentAction::OnTimeout,
- weak_ptr_factory_.GetWeakPtr()));
delegate_->WaitForDocumentReadyState(
- Selector(proto_.wait_for_document().frame()),
- proto_.wait_for_document().min_ready_state(),
+ timeout, proto_.wait_for_document().min_ready_state(),
+ optional_frame_element_ ? *optional_frame_element_
+ : ElementFinder::Result(),
base::BindOnce(&WaitForDocumentAction::OnWaitForStartState,
weak_ptr_factory_.GetWeakPtr()));
}
void WaitForDocumentAction::OnWaitForStartState(
const ClientStatus& status,
- DocumentReadyState current_state) {
- SendResult(status, current_state);
-}
-
-void WaitForDocumentAction::OnTimeout() {
- // We've already returned successfully.
- if (!callback_)
+ DocumentReadyState current_state,
+ base::TimeDelta wait_time) {
+ action_stopwatch_.TransferToWaitTime(wait_time);
+
+ if (status.proto_status() == TIMED_OUT) {
+ delegate_->GetDocumentReadyState(
+ optional_frame_element_ ? *optional_frame_element_
+ : ElementFinder::Result(),
+ base::BindOnce(&WaitForDocumentAction::OnTimeoutInState,
+ weak_ptr_factory_.GetWeakPtr(), status));
return;
+ }
- delegate_->GetDocumentReadyState(
- Selector(proto_.wait_for_document().frame()),
- base::BindOnce(&WaitForDocumentAction::OnTimeoutInState,
- weak_ptr_factory_.GetWeakPtr()));
+ SendResult(status, current_state);
}
-void WaitForDocumentAction::OnTimeoutInState(const ClientStatus& status,
- DocumentReadyState end_state) {
+void WaitForDocumentAction::OnTimeoutInState(
+ const ClientStatus& original_status,
+ const ClientStatus& status,
+ DocumentReadyState end_state) {
DVLOG_IF(1, !status.ok())
<< __func__ << ": cannot report end_state because of " << status;
- SendResult(ClientStatus(TIMED_OUT), end_state);
+ SendResult(original_status, end_state);
}
void WaitForDocumentAction::SendResult(const ClientStatus& status,
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.h b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.h
index a8179934221..3c73060fea0 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action.h
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
@@ -22,19 +23,24 @@ class WaitForDocumentAction : public Action {
// Overrides Action:
void InternalProcessAction(ProcessActionCallback callback) override;
- void OnShortWaitForElement(const ClientStatus& status);
+ void OnShortWaitForElement(const Selector& frame_selector,
+ const ClientStatus& status);
+ void OnFindElement(const ClientStatus& status,
+ std::unique_ptr<ElementFinder::Result> element);
+ void WaitForReadyState();
void OnGetStartState(const ClientStatus& status,
DocumentReadyState start_state);
void OnWaitForStartState(const ClientStatus& status,
- DocumentReadyState end_state);
- void OnTimeout();
- void OnTimeoutInState(const ClientStatus& status,
+ DocumentReadyState current_state,
+ base::TimeDelta wait_time);
+ void OnTimeoutInState(const ClientStatus& original_status,
+ const ClientStatus& status,
DocumentReadyState end_state);
void SendResult(const ClientStatus& status, DocumentReadyState end_state);
ProcessActionCallback callback_;
- base::OneShotTimer timer_;
+ std::unique_ptr<ElementFinder::Result> optional_frame_element_;
base::WeakPtrFactory<WaitForDocumentAction> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(WaitForDocumentAction);
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
index 3ae75c0a587..310145170d6 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
@@ -8,10 +8,11 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -23,6 +24,7 @@ using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Eq;
+using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::IsEmpty;
using ::testing::IsNull;
@@ -32,12 +34,12 @@ using ::testing::SizeIs;
class WaitForDocumentActionTest : public testing::Test {
public:
- WaitForDocumentActionTest()
- : task_env_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+ WaitForDocumentActionTest() {}
void SetUp() override {
ON_CALL(mock_action_delegate_, OnWaitForDocumentReadyState(_, _, _))
- .WillByDefault(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_COMPLETE));
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_COMPLETE,
+ base::TimeDelta::FromSeconds(0)));
}
// Runs the action defined in |proto_| and reports the result to
@@ -59,10 +61,6 @@ class WaitForDocumentActionTest : public testing::Test {
}
protected:
- // task_env_ must be first to guarantee other field
- // creation run in that environment.
- base::test::TaskEnvironment task_env_;
-
MockActionDelegate mock_action_delegate_;
WaitForDocumentProto proto_;
ProcessedActionProto processed_action_;
@@ -135,8 +133,9 @@ TEST_F(WaitForDocumentActionTest, WaitForDocumentInteractive) {
EXPECT_CALL(mock_action_delegate_, OnGetDocumentReadyState(_, _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), DOCUMENT_LOADING));
EXPECT_CALL(mock_action_delegate_,
- OnWaitForDocumentReadyState(_, DOCUMENT_INTERACTIVE, _))
- .WillOnce(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_INTERACTIVE));
+ OnWaitForDocumentReadyState(DOCUMENT_INTERACTIVE, _, _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_INTERACTIVE,
+ base::TimeDelta::FromSeconds(0)));
proto_.set_timeout_ms(1000);
Run();
EXPECT_EQ(ACTION_APPLIED, processed_action_.status());
@@ -147,48 +146,41 @@ TEST_F(WaitForDocumentActionTest, WaitForDocumentInteractive) {
}
TEST_F(WaitForDocumentActionTest, WaitForDocumentInteractiveTimesOut) {
+ InSequence sequence;
+
// The first time the document is reported as loading.
EXPECT_CALL(mock_action_delegate_, OnGetDocumentReadyState(_, _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), DOCUMENT_LOADING));
-
- // The document doesn't become complete right away.
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- captured_callback;
EXPECT_CALL(mock_action_delegate_,
- OnWaitForDocumentReadyState(_, DOCUMENT_COMPLETE, _))
- .WillOnce(Invoke(
- [&captured_callback](
- const Selector& frame, DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>&
- callback) { captured_callback = std::move(callback); }));
+ OnWaitForDocumentReadyState(DOCUMENT_COMPLETE, _, _))
+ .WillOnce(RunOnceCallback<2>(ClientStatus(TIMED_OUT),
+ DOCUMENT_UNKNOWN_READY_STATE,
+ base::TimeDelta::FromSeconds(0)));
+ // The second time the document is reported interactive.
+ EXPECT_CALL(mock_action_delegate_, OnGetDocumentReadyState(_, _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), DOCUMENT_INTERACTIVE));
proto_.set_timeout_ms(1000);
proto_.set_min_ready_state(DOCUMENT_COMPLETE);
Run();
-
- // 1s afterwards, the document has become interactive, but not complete. The
- // action times out and reports that.
- EXPECT_CALL(mock_action_delegate_, OnGetDocumentReadyState(_, _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), DOCUMENT_INTERACTIVE));
- task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-
EXPECT_EQ(TIMED_OUT, processed_action_.status());
EXPECT_EQ(DOCUMENT_LOADING,
processed_action_.wait_for_document_result().start_ready_state());
EXPECT_EQ(DOCUMENT_INTERACTIVE,
processed_action_.wait_for_document_result().end_ready_state());
-
- // This callback should be ignored. It's too late. This should not crash.
- std::move(captured_callback).Run(OkClientStatus(), DOCUMENT_COMPLETE);
}
TEST_F(WaitForDocumentActionTest, CheckDocumentInFrame) {
+ Selector expected_frame_selector({"#frame"});
EXPECT_CALL(mock_action_delegate_,
- OnShortWaitForElement(Selector({"#frame"}), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
-
+ OnShortWaitForElement(expected_frame_selector, _))
+ .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(),
+ base::TimeDelta::FromSeconds(0)));
EXPECT_CALL(mock_action_delegate_,
- OnGetDocumentReadyState(Selector({"#frame"}), _))
+ OnGetDocumentReadyState(
+ EqualsElement(test_util::MockFindElement(
+ mock_action_delegate_, expected_frame_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), DOCUMENT_COMPLETE));
proto_.set_timeout_ms(0);
@@ -200,7 +192,8 @@ TEST_F(WaitForDocumentActionTest, CheckDocumentInFrame) {
TEST_F(WaitForDocumentActionTest, CheckFrameElementNotFound) {
EXPECT_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
.WillRepeatedly(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ base::TimeDelta::FromSeconds(0)));
proto_.set_timeout_ms(0);
*proto_.mutable_frame() = ToSelectorProto("#frame");
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
index 17728c3bb70..aa85aa7ae03 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -43,8 +43,11 @@ void WaitForDomAction::InternalProcessAction(ProcessActionCallback callback) {
max_wait_time, proto_.wait_for_dom().allow_interrupt(),
base::BindRepeating(&WaitForDomAction::CheckElements,
weak_ptr_factory_.GetWeakPtr()),
- base::BindOnce(&WaitForDomAction::ReportActionResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ base::BindOnce(
+ &WaitForDomAction::OnWaitForElementTimed,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&WaitForDomAction::ReportActionResult,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
void WaitForDomAction::CheckElements(
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
index 4f496d18a68..82bba7f79a8 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
@@ -23,15 +23,16 @@ using ::testing::ElementsAre;
using ::testing::Invoke;
using ::testing::Pointee;
using ::testing::Property;
+using ::testing::WithArgs;
class WaitForDomActionTest : public testing::Test {
public:
WaitForDomActionTest() {}
void SetUp() override {
- ON_CALL(mock_web_controller_, OnElementCheck(_, _))
- .WillByDefault(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ ON_CALL(mock_web_controller_, OnFindElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
EXPECT_CALL(mock_action_delegate_, OnWaitForDom(_, _, _, _))
.WillRepeatedly(Invoke(this, &WaitForDomActionTest::FakeWaitForDom));
@@ -45,7 +46,8 @@ class WaitForDomActionTest : public testing::Test {
base::RepeatingCallback<
void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)>& check_elements,
- base::OnceCallback<void(const ClientStatus&)>& callback) {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>&
+ callback) {
checker_ = std::make_unique<BatchElementChecker>();
has_check_elements_result_ = false;
check_elements.Run(
@@ -68,10 +70,11 @@ class WaitForDomActionTest : public testing::Test {
// Called by |checker_| once it's done. This ends the call to
// FakeWaitForDom().
void OnWaitForDomDone(
- base::OnceCallback<void(const ClientStatus&)> callback) {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
ASSERT_TRUE(
has_check_elements_result_); // OnCheckElementsDone() not called
- std::move(callback).Run(check_elements_result_);
+ std::move(callback).Run(check_elements_result_,
+ base::TimeDelta::FromMilliseconds(fake_wait_time_));
}
// Runs the action defined in |proto_| and reports the result to |callback_|.
@@ -89,6 +92,7 @@ class WaitForDomActionTest : public testing::Test {
std::unique_ptr<BatchElementChecker> checker_;
bool has_check_elements_result_ = false;
ClientStatus check_elements_result_;
+ int fake_wait_time_ = 0;
};
TEST_F(WaitForDomActionTest, NoSelectors) {
@@ -99,8 +103,11 @@ TEST_F(WaitForDomActionTest, NoSelectors) {
}
TEST_F(WaitForDomActionTest, ConditionMet) {
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Selector({"#element"}), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
*proto_.mutable_wait_condition()->mutable_match() =
ToSelectorProto("#element");
@@ -110,6 +117,24 @@ TEST_F(WaitForDomActionTest, ConditionMet) {
Run();
}
+TEST_F(WaitForDomActionTest, TimingStatsConditionMet) {
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+
+ fake_wait_time_ = 500;
+ *proto_.mutable_wait_condition()->mutable_match() =
+ ToSelectorProto("#element");
+
+ ProcessedActionProto capture;
+ EXPECT_CALL(callback_, Run(_)).WillOnce(testing::SaveArgPointee<0>(&capture));
+ Run();
+
+ EXPECT_EQ(capture.timing_stats().wait_time_ms(), 500);
+}
+
TEST_F(WaitForDomActionTest, ConditionNotMet) {
*proto_.mutable_wait_condition()->mutable_match() =
ToSelectorProto("#element");
@@ -119,14 +144,22 @@ TEST_F(WaitForDomActionTest, ConditionNotMet) {
}
TEST_F(WaitForDomActionTest, ReportMatchesToServer) {
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Selector({"#element1"}), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Selector({"#element2"}), _))
- .WillRepeatedly(RunOnceCallback<1>(ClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Selector({"#element3"}), _))
- .WillRepeatedly(RunOnceCallback<1>(ClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Selector({"#element4"}), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element1"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element2"}), _))
+ .WillRepeatedly(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element3"}), _))
+ .WillRepeatedly(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"#element4"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
auto* any_of = proto_.mutable_wait_condition()->mutable_any_of();
auto* condition1 = any_of->add_conditions();
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc
new file mode 100644
index 00000000000..83025ae3891
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc
@@ -0,0 +1,150 @@
+// Copyright 2020 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_assistant/browser/autofill_assistant_onboarding_fetcher.h"
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/json/json_reader.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+namespace {
+
+bool ExtractStrings(const base::Value& json,
+ AutofillAssistantOnboardingFetcher::StringMap& string_map) {
+ for (const auto& intent_it : json.DictItems()) {
+ const auto& intent = intent_it.first;
+ if (!intent_it.second.is_dict()) {
+ return false;
+ }
+ base::flat_map<std::string, std::string> strings;
+ for (const auto& string_it : intent_it.second.DictItems()) {
+ const auto& string_id = string_it.first;
+ if (!string_it.second.is_string()) {
+ return false;
+ }
+ strings[string_id] = string_it.second.GetString();
+ }
+ string_map[intent] = strings;
+ }
+ return true;
+}
+
+} // namespace
+
+constexpr char kDefaultOnboardingDataUrlPattern[] =
+ "https://www.gstatic.com/autofill_assistant/$1/onboarding_definition.json";
+
+constexpr int kMaxDownloadSizeInBytes = 10 * 1024;
+constexpr char kTrafficAnnotationId[] = "gstatic_onboarding_definition";
+constexpr char kTrafficAnnotationDefinition[] = R"(
+ semantics {
+ sender: "Autofill Assistant"
+ description:
+ "A JSON file hosted by gstatic containing a definition of "
+ "content for onboarding."
+ trigger:
+ "When Autofill Assistant starts for a user that has not previously "
+ "accepted the onboarding."
+ data:
+ "The request body is empty. No user data is included."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ })";
+
+AutofillAssistantOnboardingFetcher::AutofillAssistantOnboardingFetcher(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+ : url_loader_factory_(std::move(url_loader_factory)) {}
+
+AutofillAssistantOnboardingFetcher::~AutofillAssistantOnboardingFetcher() =
+ default;
+
+void AutofillAssistantOnboardingFetcher::FetchOnboardingDefinition(
+ const std::string& intent,
+ const std::string& locale,
+ int timeout_ms,
+ ResponseCallback callback) {
+ pending_callbacks_.emplace_back(
+ base::BindOnce(&AutofillAssistantOnboardingFetcher::RunCallback,
+ base::Unretained(this), intent, std::move(callback)));
+ StartFetch(locale, timeout_ms);
+}
+
+void AutofillAssistantOnboardingFetcher::StartFetch(const std::string& locale,
+ int timeout_ms) {
+ static const base::NoDestructor<base::TimeDelta> kFetchTimeout(
+ base::TimeDelta::FromMilliseconds(timeout_ms));
+ if (url_loader_) {
+ return;
+ }
+
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->url = GURL(base::ReplaceStringPlaceholders(
+ kDefaultOnboardingDataUrlPattern, {locale}, /* offset= */ nullptr));
+ resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation(kTrafficAnnotationId,
+ kTrafficAnnotationDefinition);
+ url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+ traffic_annotation);
+ url_loader_->SetTimeoutDuration(*kFetchTimeout);
+ url_loader_->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(&AutofillAssistantOnboardingFetcher::OnFetchComplete,
+ base::Unretained(this)),
+ kMaxDownloadSizeInBytes);
+}
+
+void AutofillAssistantOnboardingFetcher::OnFetchComplete(
+ std::unique_ptr<std::string> response_body) {
+ url_loader_.reset();
+ ResultStatus result_status = ParseResponse(std::move(response_body));
+ base::UmaHistogramEnumeration(
+ "AutofillAssistant.AutofillAssistantOnboardingFetcher.ResultStatus",
+ result_status);
+ for (auto& callback : pending_callbacks_) {
+ std::move(callback).Run();
+ }
+ pending_callbacks_.clear();
+}
+
+AutofillAssistantOnboardingFetcher::ResultStatus
+AutofillAssistantOnboardingFetcher::ParseResponse(
+ std::unique_ptr<std::string> response_body) {
+ onboarding_strings_.clear();
+
+ if (!response_body) {
+ return ResultStatus::kNoBody;
+ }
+
+ base::JSONReader::ValueWithError data =
+ base::JSONReader::ReadAndReturnValueWithError(*response_body);
+
+ if (data.value == base::nullopt) {
+ DVLOG(1) << "Parse error: " << data.error_message;
+ return ResultStatus::kInvalidJson;
+ }
+ if (!data.value->is_dict()) {
+ return ResultStatus::kInvalidData;
+ }
+ return ExtractStrings(*data.value, onboarding_strings_)
+ ? ResultStatus::kOk
+ : ResultStatus::kInvalidData;
+}
+
+void AutofillAssistantOnboardingFetcher::RunCallback(
+ const std::string& intent,
+ ResponseCallback callback) {
+ std::move(callback).Run(onboarding_strings_[intent]);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h
new file mode 100644
index 00000000000..a313bd84f51
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h
@@ -0,0 +1,89 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_ONBOARDING_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_ONBOARDING_FETCHER_H_
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}
+
+namespace autofill_assistant {
+
+extern const char kDefaultOnboardingDataUrlPattern[];
+
+// Used to fetch the configuration for the onboarding screen to be shown on the
+// user's first run of Autofill Assistant.
+class AutofillAssistantOnboardingFetcher : public KeyedService {
+ public:
+ using ResponseCallback =
+ base::OnceCallback<void(const base::flat_map<std::string, std::string>&)>;
+
+ using StringMap =
+ base::flat_map<std::string, base::flat_map<std::string, std::string>>;
+
+ // This enum is used in histograms, do not remove/renumber entries. Only add
+ // at the end and update kMaxValue. Also remember to update the
+ // AutofillAssistantOnboardingFetcherResultStatus enum listing in
+ // tools/metrics/histograms/enums.xml.
+ enum class ResultStatus {
+ kOk = 0,
+ // No body was received from the server.
+ kNoBody = 1,
+ // Parsing the JSON failed.
+ kInvalidJson = 1,
+ // The JSON was not in the form we expected it to be.
+ kInvalidData = 2,
+ kMaxValue = kInvalidData
+ };
+
+ AutofillAssistantOnboardingFetcher(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+ ~AutofillAssistantOnboardingFetcher() override;
+
+ void FetchOnboardingDefinition(const std::string& intent,
+ const std::string& locale,
+ int timeout_ms,
+ ResponseCallback callback);
+
+ private:
+ // Sends new request to gstatic.
+ void StartFetch(const std::string& locale, int timeout_ms);
+
+ // Callback for the request to gstatic.
+ void OnFetchComplete(std::unique_ptr<std::string> response_body);
+
+ // Parses the response body. Returns a result status.
+ ResultStatus ParseResponse(std::unique_ptr<std::string> response_body);
+
+ // Extracts the requested data and runs the callback.
+ void RunCallback(const std::string& intent, ResponseCallback callback);
+
+ std::vector<base::OnceClosure> pending_callbacks_;
+
+ // Contains the onboarding data as a map of:
+ // {
+ // "intent": {
+ // "string-id": "string-value"
+ // }
+ // }
+ StringMap onboarding_strings_;
+
+ // URL loader object for the gstatic request. If |url_loader_| is not
+ // null, a request is currently in flight.
+ std::unique_ptr<network::SimpleURLLoader> url_loader_;
+
+ // Used for the gstatic requests.
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_ONBOARDING_FETCHER_H_
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc
new file mode 100644
index 00000000000..0d51602c013
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright 2020 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_assistant/browser/autofill_assistant_onboarding_fetcher.h"
+
+#include "base/android/locale_utils.h"
+#include "base/containers/flat_map.h"
+#include "base/test/task_environment.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill_assistant {
+namespace {
+
+constexpr char kTestResponseContent[] =
+ R"json(
+{
+ "BUY_MOVIE_TICKETS": {
+ "onboarding_title": "Title",
+ "onboarding_text": "Text"
+ }
+}
+ )json";
+
+constexpr char kExpectedUrl[] =
+ "https://www.gstatic.com/autofill_assistant/en-US/"
+ "onboarding_definition.json";
+
+class AutofillAssistantOnboardingFetcherTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ test_url_loader_factory_ =
+ std::make_unique<network::TestURLLoaderFactory>();
+ test_shared_loader_factory_ =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ test_url_loader_factory_.get());
+ fetcher_ = std::make_unique<AutofillAssistantOnboardingFetcher>(
+ test_shared_loader_factory_);
+ }
+
+ void TearDown() override { EXPECT_EQ(0, GetNumberOfPendingRequests()); }
+
+ int GetNumberOfPendingRequests() {
+ return test_url_loader_factory_->NumPending();
+ }
+
+ AutofillAssistantOnboardingFetcher* fetcher() { return fetcher_.get(); }
+
+ void SimulateResponse() { SimulateResponseWithContent(kTestResponseContent); }
+
+ void SimulateResponseWithContent(const std::string& content) {
+ EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest(
+ kExpectedUrl, content));
+ }
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ std::unique_ptr<AutofillAssistantOnboardingFetcher> fetcher_;
+ std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+};
+
+TEST_F(AutofillAssistantOnboardingFetcherTest, FetchOnboardingStrings) {
+ AutofillAssistantOnboardingFetcher::ResponseCallback callback =
+ base::BindOnce([](const base::flat_map<std::string, std::string>& map) {
+ EXPECT_EQ(map.at("onboarding_title"), "Title");
+ EXPECT_EQ(map.at("onboarding_text"), "Text");
+ });
+
+ fetcher()->FetchOnboardingDefinition("BUY_MOVIE_TICKETS",
+ base::android::GetDefaultLocaleString(),
+ 300, std::move(callback));
+ EXPECT_EQ(1, GetNumberOfPendingRequests());
+ SimulateResponse();
+ EXPECT_EQ(0, GetNumberOfPendingRequests());
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/basic_interactions.cc b/chromium/components/autofill_assistant/browser/basic_interactions.cc
index b9e9ce27826..3598dd46414 100644
--- a/chromium/components/autofill_assistant/browser/basic_interactions.cc
+++ b/chromium/components/autofill_assistant/browser/basic_interactions.cc
@@ -4,7 +4,7 @@
#include "components/autofill_assistant/browser/basic_interactions.h"
#include <algorithm>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/autofill_assistant/browser/basic_interactions.h b/chromium/components/autofill_assistant/browser/basic_interactions.h
index 69e256e15db..fc14adf85f4 100644
--- a/chromium/components/autofill_assistant/browser/basic_interactions.h
+++ b/chromium/components/autofill_assistant/browser/basic_interactions.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BASIC_INTERACTIONS_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BASIC_INTERACTIONS_H_
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/generic_ui.pb.h"
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker.cc b/chromium/components/autofill_assistant/browser/batch_element_checker.cc
index b8aa97589f4..bea60f332d5 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker.cc
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker.cc
@@ -10,6 +10,8 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
namespace autofill_assistant {
@@ -50,7 +52,7 @@ void BatchElementChecker::Run(WebController* web_controller) {
element_check_callbacks_.size() + get_field_value_callbacks_.size() + 1;
for (auto& entry : element_check_callbacks_) {
- web_controller->ElementCheck(
+ web_controller->FindElement(
entry.first, /* strict= */ false,
base::BindOnce(
&BatchElementChecker::OnElementChecked,
@@ -61,14 +63,18 @@ void BatchElementChecker::Run(WebController* web_controller) {
}
for (auto& entry : get_field_value_callbacks_) {
- web_controller->GetFieldValue(
- entry.first,
+ web_controller->FindElement(
+ entry.first, /* strict= */ true,
base::BindOnce(
- &BatchElementChecker::OnGetFieldValue,
- weak_ptr_factory_.GetWeakPtr(),
- // Guaranteed to exist for the lifetime of this instance, because
- // the map isn't modified after Run has been called.
- base::Unretained(&entry.second)));
+ &action_delegate_util::TakeElementAndGetProperty<std::string>,
+ base::BindOnce(&WebController::GetFieldValue,
+ web_controller->GetWeakPtr()),
+ base::BindOnce(&BatchElementChecker::OnFieldValueChecked,
+ weak_ptr_factory_.GetWeakPtr(),
+ // Guaranteed to exist for the lifetime of
+ // this instance, because the map isn't
+ // modified after Run has been called.
+ base::Unretained(&entry.second))));
}
// The extra +1 of pending_check_count and this check happening last
@@ -84,20 +90,21 @@ void BatchElementChecker::Run(WebController* web_controller) {
void BatchElementChecker::OnElementChecked(
std::vector<ElementCheckCallback>* callbacks,
- const ClientStatus& element_status) {
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
for (auto& callback : *callbacks) {
- std::move(callback).Run(element_status);
+ std::move(callback).Run(element_status, *element_result);
}
callbacks->clear();
CheckDone();
}
-void BatchElementChecker::OnGetFieldValue(
+void BatchElementChecker::OnFieldValueChecked(
std::vector<GetFieldValueCallback>* callbacks,
- const ClientStatus& element_status,
+ const ClientStatus& status,
const std::string& value) {
for (auto& callback : *callbacks) {
- std::move(callback).Run(element_status, value);
+ std::move(callback).Run(status, value);
}
callbacks->clear();
CheckDone();
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker.h b/chromium/components/autofill_assistant/browser/batch_element_checker.h
index 23670ec6354..8b153efef06 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker.h
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker.h
@@ -11,12 +11,13 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
class WebController;
@@ -28,10 +29,13 @@ class BatchElementChecker {
explicit BatchElementChecker();
virtual ~BatchElementChecker();
- // Callback for AddElementCheck. Argument is true if the check passed.
+ // Callback for AddElementCheck. Arguments are an ok client status if the
+ // check passed and an |ElementFinder::Result|.
//
// An ElementCheckCallback must not delete its calling BatchElementChecker.
- using ElementCheckCallback = base::OnceCallback<void(const ClientStatus&)>;
+ using ElementCheckCallback =
+ base::OnceCallback<void(const ClientStatus&,
+ const ElementFinder::Result&)>;
// Callback for AddFieldValueCheck. Argument is true is the element exists.
// The string contains the field value, or an empty string if accessing the
@@ -68,11 +72,16 @@ class BatchElementChecker {
void Run(WebController* web_controller);
private:
+ // Gets called for each ElementCheck.
void OnElementChecked(std::vector<ElementCheckCallback>* callbacks,
- const ClientStatus& element_status);
- void OnGetFieldValue(std::vector<GetFieldValueCallback>* callbacks,
- const ClientStatus& element_status,
- const std::string& value);
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result);
+
+ // Gets called for each FieldValueCheck.
+ void OnFieldValueChecked(std::vector<GetFieldValueCallback>* callbacks,
+ const ClientStatus& status,
+ const std::string& value);
+
void CheckDone();
// A map of ElementCheck arguments (check_type, selector) to callbacks that
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc b/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
index dd72e03f02a..ee1f6d9a27a 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
@@ -8,10 +8,12 @@
#include <set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -33,15 +35,11 @@ class BatchElementCheckerTest : public testing::Test {
protected:
BatchElementCheckerTest() : checks_() {}
- void SetUp() override {
- ON_CALL(mock_web_controller_, OnElementCheck(_, _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus()));
- ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus(), ""));
- }
+ void SetUp() override { test_util::MockFindAnyElement(mock_web_controller_); }
void OnElementExistenceCheck(const std::string& name,
- const ClientStatus& result) {
+ const ClientStatus& result,
+ const ElementFinder::Result& ignored_element) {
element_exists_results_[name] = result.ok();
}
@@ -51,8 +49,10 @@ class BatchElementCheckerTest : public testing::Test {
base::Unretained(this), name);
}
- void OnVisibilityRequirementCheck(const std::string& name,
- const ClientStatus& result) {
+ void OnVisibilityRequirementCheck(
+ const std::string& name,
+ const ClientStatus& result,
+ const ElementFinder::Result& ignored_element) {
element_visible_results_[name] = result.ok();
}
@@ -105,9 +105,9 @@ TEST_F(BatchElementCheckerTest, Empty) {
}
TEST_F(BatchElementCheckerTest, OneElementFound) {
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- checks_.AddElementCheck(Selector({"exists"}),
+ Selector expected_selector({"exists"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector);
+ checks_.AddElementCheck(expected_selector,
ElementExistenceCallback("exists"));
Run("was_run");
@@ -116,10 +116,12 @@ TEST_F(BatchElementCheckerTest, OneElementFound) {
}
TEST_F(BatchElementCheckerTest, OneElementNotFound) {
+ Selector expected_notexists_selector({"does_not_exist"});
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"does_not_exist"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
- checks_.AddElementCheck(Selector({"does_not_exist"}),
+ OnFindElement(expected_notexists_selector, _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ checks_.AddElementCheck(expected_notexists_selector,
ElementExistenceCallback("does_not_exist"));
Run("was_run");
@@ -128,9 +130,13 @@ TEST_F(BatchElementCheckerTest, OneElementNotFound) {
}
TEST_F(BatchElementCheckerTest, OneFieldValueFound) {
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"field"})), _))
+ Selector expected_selector({"field"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "some value"));
- checks_.AddFieldValueCheck(Selector({"field"}), FieldValueCallback("field"));
+ checks_.AddFieldValueCheck(expected_selector, FieldValueCallback("field"));
Run("was_run");
EXPECT_THAT(get_field_value_results_, Contains(Pair("field", "some value")));
@@ -138,9 +144,12 @@ TEST_F(BatchElementCheckerTest, OneFieldValueFound) {
}
TEST_F(BatchElementCheckerTest, OneFieldValueNotFound) {
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"field"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(), ""));
- checks_.AddFieldValueCheck(Selector({"field"}), FieldValueCallback("field"));
+ Selector expected_selector({"field"});
+ EXPECT_CALL(mock_web_controller_, OnFindElement(expected_selector, _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _)).Times(0);
+ checks_.AddFieldValueCheck(expected_selector, FieldValueCallback("field"));
Run("was_run");
EXPECT_THAT(get_field_value_results_, Contains(Pair("field", "")));
@@ -148,52 +157,68 @@ TEST_F(BatchElementCheckerTest, OneFieldValueNotFound) {
}
TEST_F(BatchElementCheckerTest, OneFieldValueEmpty) {
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"field"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
- checks_.AddFieldValueCheck(Selector({"field"}), FieldValueCallback("field"));
+ Selector expected_selector({"field"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), std::string()));
+ checks_.AddFieldValueCheck(expected_selector, FieldValueCallback("field"));
Run("was_run");
- EXPECT_THAT(get_field_value_results_, Contains(Pair("field", "")));
+ EXPECT_THAT(get_field_value_results_, Contains(Pair("field", std::string())));
EXPECT_THAT(all_done_, Contains("was_run"));
}
TEST_F(BatchElementCheckerTest, MultipleElements) {
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"1"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"2"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"3"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"4"})), _))
+ Selector expected_selector_1({"1"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_1);
+ Selector expected_selector_2({"2"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_2);
+ Selector expected_selector_3({"3"});
+ EXPECT_CALL(mock_web_controller_, OnFindElement(expected_selector_3, _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ Selector expected_selector_4({"4"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_4)),
+ _))
.WillOnce(RunOnceCallback<1>(OkClientStatus(), "value"));
- EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"5"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(), ""));
-
- checks_.AddElementCheck(Selector({"1"}), ElementExistenceCallback("1"));
- checks_.AddElementCheck(Selector({"2"}), ElementExistenceCallback("2"));
- checks_.AddElementCheck(Selector({"3"}), ElementExistenceCallback("3"));
- checks_.AddFieldValueCheck(Selector({"4"}), FieldValueCallback("4"));
- checks_.AddFieldValueCheck(Selector({"5"}), FieldValueCallback("5"));
+ Selector expected_selector_5({"5"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetFieldValue(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_5)),
+ _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ std::string()));
+
+ checks_.AddElementCheck(expected_selector_1, ElementExistenceCallback("1"));
+ checks_.AddElementCheck(expected_selector_2, ElementExistenceCallback("2"));
+ checks_.AddElementCheck(expected_selector_3, ElementExistenceCallback("3"));
+ checks_.AddFieldValueCheck(expected_selector_4, FieldValueCallback("4"));
+ checks_.AddFieldValueCheck(expected_selector_5, FieldValueCallback("5"));
Run("was_run");
EXPECT_THAT(element_exists_results_, Contains(Pair("1", true)));
EXPECT_THAT(element_exists_results_, Contains(Pair("2", true)));
EXPECT_THAT(element_exists_results_, Contains(Pair("3", false)));
EXPECT_THAT(get_field_value_results_, Contains(Pair("4", "value")));
- EXPECT_THAT(get_field_value_results_, Contains(Pair("5", "")));
+ EXPECT_THAT(get_field_value_results_, Contains(Pair("5", std::string())));
EXPECT_THAT(all_done_, Contains("was_run"));
}
TEST_F(BatchElementCheckerTest, DeduplicateElementExists) {
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"1"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"2"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
-
- checks_.AddElementCheck(Selector({"1"}), ElementExistenceCallback("first 1"));
- checks_.AddElementCheck(Selector({"1"}),
+ Selector expected_selector_1({"1"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_1);
+ Selector expected_selector_2({"2"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_2);
+
+ checks_.AddElementCheck(expected_selector_1,
+ ElementExistenceCallback("first 1"));
+ checks_.AddElementCheck(expected_selector_1,
ElementExistenceCallback("second 1"));
- checks_.AddElementCheck(Selector({"2"}), ElementExistenceCallback("2"));
+ checks_.AddElementCheck(expected_selector_2, ElementExistenceCallback("2"));
Run("was_run");
@@ -204,18 +229,16 @@ TEST_F(BatchElementCheckerTest, DeduplicateElementExists) {
}
TEST_F(BatchElementCheckerTest, DeduplicateElementVisible) {
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"2"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ Selector expected_selector_1({"1"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_1);
+ Selector expected_selector_2({"2"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector_2);
- checks_.AddElementCheck(Selector({"1"}).MustBeVisible(),
+ checks_.AddElementCheck(expected_selector_1,
VisibilityRequirementCallback("first 1"));
- checks_.AddElementCheck(Selector({"1"}).MustBeVisible(),
+ checks_.AddElementCheck(expected_selector_1,
VisibilityRequirementCallback("second 1"));
- checks_.AddElementCheck(Selector({"2"}).MustBeVisible(),
+ checks_.AddElementCheck(expected_selector_2,
VisibilityRequirementCallback("2"));
Run("was_run");
@@ -227,7 +250,9 @@ TEST_F(BatchElementCheckerTest, DeduplicateElementVisible) {
}
TEST_F(BatchElementCheckerTest, CallMultipleAllDoneCallbacks) {
- checks_.AddElementCheck(Selector({"exists"}),
+ Selector expected_selector({"exists"});
+ test_util::MockFindElement(mock_web_controller_, expected_selector);
+ checks_.AddElementCheck(expected_selector,
ElementExistenceCallback("exists"));
checks_.AddAllDoneCallback(DoneCallback("1"));
checks_.AddAllDoneCallback(DoneCallback("2"));
diff --git a/chromium/components/autofill_assistant/browser/chip.h b/chromium/components/autofill_assistant/browser/chip.h
index 650935d0f58..965915bfe5d 100644
--- a/chromium/components/autofill_assistant/browser/chip.h
+++ b/chromium/components/autofill_assistant/browser/chip.h
@@ -34,6 +34,9 @@ struct Chip {
// Whether this chip is sticky. A sticky chip will be a candidate to be
// displayed in the header if the peek mode of the sheet is HANDLE_HEADER.
bool sticky = false;
+
+ // Whether this chip should be displayed in the carousel.
+ bool visible = true;
};
// Guarantees that the Chip.type of all chips is set to a sensible value.
diff --git a/chromium/components/autofill_assistant/browser/client.h b/chromium/components/autofill_assistant/browser/client.h
index 5398ef83ad0..0d932cdeeda 100644
--- a/chromium/components/autofill_assistant/browser/client.h
+++ b/chromium/components/autofill_assistant/browser/client.h
@@ -15,10 +15,6 @@ namespace autofill {
class PersonalDataManager;
} // namespace autofill
-namespace password_manager {
-class PasswordManagerClient;
-} // namespace password_manager
-
namespace version_info {
enum class Channel;
} // namespace version_info
@@ -60,10 +56,6 @@ class Client {
// Returns the current active personal data manager.
virtual autofill::PersonalDataManager* GetPersonalDataManager() const = 0;
- // Return the password manager client for the current WebContents.
- virtual password_manager::PasswordManagerClient* GetPasswordManagerClient()
- const = 0;
-
// Returns the currently active login fetcher.
virtual WebsiteLoginManager* GetWebsiteLoginManager() const = 0;
diff --git a/chromium/components/autofill_assistant/browser/client_settings.cc b/chromium/components/autofill_assistant/browser/client_settings.cc
index 89afa01a284..620586a57f2 100644
--- a/chromium/components/autofill_assistant/browser/client_settings.cc
+++ b/chromium/components/autofill_assistant/browser/client_settings.cc
@@ -4,12 +4,14 @@
#include "components/autofill_assistant/browser/client_settings.h"
#include "base/logging.h"
+#include "components/autofill_assistant/browser/view_layout.pb.h"
namespace {
bool IsValidOverlayImageProto(
const autofill_assistant::OverlayImageProto& proto) {
- if (!proto.image_url().empty() && !proto.has_image_size()) {
+ if ((proto.has_image_drawable() || !proto.image_url().empty()) &&
+ !proto.has_image_size()) {
VLOG(1) << __func__ << ": Missing image_size in overlay_image, ignoring";
return false;
}
@@ -57,12 +59,9 @@ void ClientSettings::UpdateFromProto(const ClientSettingsProto& proto) {
if (proto.has_box_model_check_count()) {
box_model_check_count = proto.box_model_check_count();
}
- if (proto.has_document_ready_check_interval_ms()) {
- document_ready_check_interval = base::TimeDelta::FromMilliseconds(
- proto.document_ready_check_interval_ms());
- }
- if (proto.has_document_ready_check_count()) {
- document_ready_check_count = proto.document_ready_check_count();
+ if (proto.has_document_ready_check_timeout_ms()) {
+ document_ready_check_timeout = base::TimeDelta::FromMilliseconds(
+ proto.document_ready_check_timeout_ms());
}
if (proto.has_cancel_delay_ms()) {
cancel_delay = base::TimeDelta::FromMilliseconds(proto.cancel_delay_ms());
@@ -79,8 +78,18 @@ void ClientSettings::UpdateFromProto(const ClientSettingsProto& proto) {
base::TimeDelta::FromMilliseconds(proto.tap_shutdown_delay_ms());
}
if (proto.has_overlay_image()) {
+ // TODO(b/170202574): Add integration test and remove legacy |image_url|.
if (IsValidOverlayImageProto(proto.overlay_image())) {
overlay_image = proto.overlay_image();
+ // Legacy treatment for |image_url|.
+ if (!overlay_image->image_url().empty()) {
+ std::string url = overlay_image->image_url();
+ auto* bitmap_proto =
+ overlay_image->mutable_image_drawable()->mutable_bitmap();
+ bitmap_proto->set_url(url);
+ *bitmap_proto->mutable_width() = overlay_image->image_size();
+ *bitmap_proto->mutable_height() = overlay_image->image_size();
+ }
} else {
overlay_image.reset();
}
diff --git a/chromium/components/autofill_assistant/browser/client_settings.h b/chromium/components/autofill_assistant/browser/client_settings.h
index a280170b3f9..25d50c929ad 100644
--- a/chromium/components/autofill_assistant/browser/client_settings.h
+++ b/chromium/components/autofill_assistant/browser/client_settings.h
@@ -56,14 +56,10 @@ struct ClientSettings {
// become stable.
int box_model_check_count = 50;
- // Time to wait between two checks of the document state, when waiting for the
+ // Time to wait while checking the document state, when waiting for the
// document to become ready.
- base::TimeDelta document_ready_check_interval =
- base::TimeDelta::FromMilliseconds(200);
-
- // Maximum number of checks to run while waiting for the document to become
- // ready.
- int document_ready_check_count = 50;
+ base::TimeDelta document_ready_check_timeout =
+ base::TimeDelta::FromSeconds(10);
// How much time to give users to tap undo when they tap a cancel button.
base::TimeDelta cancel_delay = base::TimeDelta::FromSeconds(5);
diff --git a/chromium/components/autofill_assistant/browser/client_settings_unittest.cc b/chromium/components/autofill_assistant/browser/client_settings_unittest.cc
new file mode 100644
index 00000000000..18fd67adcbc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/client_settings_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 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_assistant/browser/client_settings.h"
+#include "components/autofill_assistant/browser/mock_client.h"
+
+namespace autofill_assistant {
+
+namespace {
+
+class ClientSettingsTest : public testing::Test {
+ protected:
+ ClientSettingsTest() {}
+ ~ClientSettingsTest() override {}
+};
+
+TEST_F(ClientSettingsTest, CheckLegacyOverlayImage) {
+ ClientSettingsProto proto;
+ proto.mutable_overlay_image()->set_image_url(
+ "https://www.example.com/favicon.ico");
+ proto.mutable_overlay_image()->mutable_image_size()->set_dp(32);
+
+ ClientSettings settings;
+ settings.UpdateFromProto(proto);
+
+ ASSERT_TRUE(settings.overlay_image.has_value());
+ EXPECT_EQ(settings.overlay_image->image_drawable().bitmap().url(),
+ "https://www.example.com/favicon.ico");
+}
+
+} // namespace
+} // namespace autofill_assistant \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/browser/client_status.cc b/chromium/components/autofill_assistant/browser/client_status.cc
index c3b4ad9cd54..37686115643 100644
--- a/chromium/components/autofill_assistant/browser/client_status.cc
+++ b/chromium/components/autofill_assistant/browser/client_status.cc
@@ -13,6 +13,16 @@ ClientStatus::ClientStatus(ProcessedActionStatusProto status)
: status_(status) {}
ClientStatus::~ClientStatus() = default;
+ClientStatus ClientStatus::WithStatusOverride(
+ ProcessedActionStatusProto new_status) const {
+ ClientStatus other = *this;
+ if (status_ != new_status) {
+ other.set_proto_status(new_status);
+ other.mutable_details()->set_original_status(status_);
+ }
+ return other;
+}
+
void ClientStatus::FillProto(ProcessedActionProto* proto) const {
proto->set_status(status_);
if (has_details_)
@@ -122,6 +132,12 @@ std::ostream& operator<<(std::ostream& out,
case ProcessedActionStatusProto::TOO_MANY_CANDIDATES:
out << "TOO_MANY_CANDIDATES";
break;
+ case ProcessedActionStatusProto::ELEMENT_MISMATCH:
+ out << "ELEMENT_MISMATCH";
+ break;
+ case ProcessedActionStatusProto::ELEMENT_NOT_ON_TOP:
+ out << "ELEMENT_NOT_ON_TOP";
+ break;
// Intentionally no default case to make compilation fail if a new value
// was added to the enum but not to this list.
diff --git a/chromium/components/autofill_assistant/browser/client_status.h b/chromium/components/autofill_assistant/browser/client_status.h
index a17f182f483..f659a02117d 100644
--- a/chromium/components/autofill_assistant/browser/client_status.h
+++ b/chromium/components/autofill_assistant/browser/client_status.h
@@ -18,6 +18,12 @@ class ClientStatus {
explicit ClientStatus(ProcessedActionStatusProto status);
~ClientStatus();
+ ClientStatus(ProcessedActionStatusProto status,
+ const ProcessedActionStatusDetailsProto& details)
+ : ClientStatus(status) {
+ mutable_details()->MergeFrom(details);
+ }
+
// Returns true if this is an OK status.
bool ok() const { return status_ == ACTION_APPLIED; }
@@ -30,6 +36,10 @@ class ClientStatus {
// Modifies the corresponding proto status.
void set_proto_status(ProcessedActionStatusProto status) { status_ = status; }
+ // Returns a copy of the current ClientStatus instance with the status set to
+ // |new_status| and the original status saved in original_status.
+ ClientStatus WithStatusOverride(ProcessedActionStatusProto new_status) const;
+
// Returns a mutable version of status details, creates one if necessary.
ProcessedActionStatusDetailsProto* mutable_details() {
has_details_ = true;
diff --git a/chromium/components/autofill_assistant/browser/controller.cc b/chromium/components/autofill_assistant/browser/controller.cc
index 834ea20281d..9b09e93ebff 100644
--- a/chromium/components/autofill_assistant/browser/controller.cc
+++ b/chromium/components/autofill_assistant/browser/controller.cc
@@ -19,8 +19,9 @@
#include "components/autofill_assistant/browser/features.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/protocol_utils.h"
-#include "components/autofill_assistant/browser/service_impl.h"
+#include "components/autofill_assistant/browser/service/service_impl.h"
#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/url_utils.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/view_layout.pb.h"
#include "components/google/core/common/google_util.h"
@@ -31,6 +32,7 @@
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "net/http/http_status_code.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
@@ -88,37 +90,12 @@ bool StateNeedsUiInLiteScript(AutofillAssistantState state) {
}
}
-// Check whether a domain is a subdomain of another domain.
-bool IsSubdomainOf(const std::string& subdomain,
- const std::string& parent_domain) {
- return base::EndsWith(base::StringPiece(subdomain),
- base::StringPiece("." + parent_domain),
- base::CompareCase::INSENSITIVE_ASCII);
-}
-
-// Check whether two URLs have the same domain.
-bool HasSameDomainAs(const GURL& a, const GURL& b) {
- return a.host() == b.host();
-}
-
-// Check whether |subdomain| is a subdomain of a set of domains in |whitelist|.
-bool IsInWhitelist(const std::string& subdomain,
- const std::vector<std::string> whitelist) {
- const GURL subdomain_gurl = GURL(subdomain);
- for (const std::string& parent_domain : whitelist) {
- if (HasSameDomainAs(subdomain_gurl, GURL(parent_domain)) ||
- IsSubdomainOf(subdomain, parent_domain))
- return true;
- }
- return false;
-}
-
} // namespace
Controller::Controller(content::WebContents* web_contents,
Client* client,
const base::TickClock* tick_clock,
- RuntimeManagerImpl* runtime_manager,
+ base::WeakPtr<RuntimeManagerImpl> runtime_manager,
std::unique_ptr<Service> service)
: content::WebContentsObserver(web_contents),
client_(client),
@@ -162,8 +139,7 @@ Service* Controller::GetService() {
WebController* Controller::GetWebController() {
if (!web_controller_) {
- web_controller_ =
- WebController::CreateForWebContents(web_contents(), &settings_);
+ web_controller_ = WebController::CreateForWebContents(web_contents());
}
return web_controller_.get();
}
@@ -379,6 +355,19 @@ void Controller::SetUserActions(
SetDefaultChipType(user_actions.get());
}
user_actions_ = std::move(user_actions);
+ SetVisibilityAndUpdateUserActions();
+}
+
+void Controller::SetVisibilityAndUpdateUserActions() {
+ // All non-cancel chips should be hidden while the keyboard is showing.
+ if (user_actions_) {
+ for (UserAction& user_action : *user_actions_) {
+ if (user_action.chip().type != CANCEL_ACTION) {
+ user_action.chip().visible = !is_keyboard_showing_;
+ }
+ }
+ }
+
for (ControllerObserver& observer : observers_) {
observer.OnUserActionsChanged(GetUserActions());
}
@@ -402,7 +391,9 @@ void Controller::RequireUI() {
void Controller::SetUiShown(bool shown) {
ui_shown_ = shown;
- runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
+ if (runtime_manager_) {
+ runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
+ }
}
void Controller::SetGenericUi(
@@ -431,6 +422,10 @@ void Controller::SetBrowseModeInvisible(bool invisible) {
browse_mode_invisible_ = invisible;
}
+void Controller::SetShowFeedbackChip(bool show_feedback_chip) {
+ show_feedback_chip_on_graceful_shutdown_ = show_feedback_chip;
+}
+
void Controller::AddNavigationListener(
ScriptExecutorDelegate::NavigationListener* listener) {
navigation_listeners_.AddObserver(listener);
@@ -453,8 +448,8 @@ void Controller::SetExpandSheetForPromptAction(bool expand) {
expand_sheet_for_prompt_action_ = expand;
}
-void Controller::SetBrowseDomainsWhitelist(std::vector<std::string> domains) {
- browse_domains_whitelist_ = std::move(domains);
+void Controller::SetBrowseDomainsAllowlist(std::vector<std::string> domains) {
+ browse_domains_allowlist_ = std::move(domains);
}
bool Controller::PerformUserActionWithContext(
@@ -731,13 +726,28 @@ void Controller::ReportNavigationStateChanged() {
}
}
-void Controller::EnterStoppedState() {
+void Controller::EnterStoppedState(bool show_feedback_chip) {
if (script_tracker_)
script_tracker_->StopScript();
+ std::unique_ptr<std::vector<UserAction>> final_actions;
+ if (base::FeatureList::IsEnabled(features::kAutofillAssistantFeedbackChip) &&
+ show_feedback_chip) {
+ final_actions = std::make_unique<std::vector<UserAction>>();
+ UserAction feedback_action;
+ Chip feedback_chip;
+ feedback_chip.type = FEEDBACK_ACTION;
+ feedback_chip.text =
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK);
+ feedback_action.SetCallback(base::BindOnce(&Controller::ShutdownIfNecessary,
+ weak_ptr_factory_.GetWeakPtr()));
+ feedback_action.chip() = feedback_chip;
+ final_actions->emplace_back(std::move(feedback_action));
+ }
+
ClearInfoBox();
SetDetails(nullptr);
- SetUserActions(nullptr);
+ SetUserActions(std::move(final_actions));
SetCollectUserDataOptions(nullptr);
SetForm(nullptr, base::DoNothing(), base::DoNothing());
EnterState(AutofillAssistantState::STOPPED);
@@ -818,7 +828,7 @@ void Controller::GetOrCheckScripts() {
return;
const GURL& url = GetCurrentURL();
- if (!HasSameDomainAs(script_url_, url)) {
+ if (script_url_.host() != url.host()) {
StopPeriodicScriptChecks();
script_url_ = url;
#ifdef NDEBUG
@@ -885,23 +895,26 @@ void Controller::OnPeriodicScriptCheck() {
}
void Controller::OnGetScripts(const GURL& url,
- bool result,
+ int http_status,
const std::string& response) {
if (state_ == AutofillAssistantState::STOPPED)
return;
// If the domain of the current URL changed since the request was sent, the
// response is not relevant anymore and can be safely discarded.
- if (!HasSameDomainAs(script_url_, url))
+ if (script_url_.host() != url.host())
return;
- if (!result) {
+ if (http_status != net::HTTP_OK) {
#ifdef NDEBUG
- VLOG(1) << "Failed to get assistant scripts for <redacted>";
+ VLOG(1) << "Failed to get assistant scripts for <redacted>, http-status="
+ << http_status;
#else
- VLOG(1) << "Failed to get assistant scripts for " << script_url_.host();
+ VLOG(1) << "Failed to get assistant scripts for " << script_url_.host()
+ << ", http-status=" << http_status;
#endif
OnFatalError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
+ /*show_feedback_chip=*/true,
Metrics::DropOutReason::GET_SCRIPTS_FAILED);
return;
}
@@ -915,6 +928,7 @@ void Controller::OnGetScripts(const GURL& url,
<< "unparseable response";
#endif
OnFatalError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
+ /*show_feedback_chip=*/true,
Metrics::DropOutReason::GET_SCRIPTS_UNPARSABLE);
return;
}
@@ -964,7 +978,7 @@ void Controller::OnGetScripts(const GURL& url,
if (state_ == AutofillAssistantState::TRACKING) {
OnFatalError(
l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
- Metrics::DropOutReason::NO_SCRIPTS);
+ /*show_feedback_chip=*/false, Metrics::DropOutReason::NO_SCRIPTS);
return;
}
OnNoRunnableScriptsForPage();
@@ -1034,7 +1048,8 @@ void Controller::OnScriptExecuted(const std::string& script_path,
case ScriptExecutor::SHUTDOWN_GRACEFULLY:
if (!tracking_) {
- EnterStoppedState();
+ EnterStoppedState(
+ /*show_feedback_chip=*/show_feedback_chip_on_graceful_shutdown_);
RecordDropOutOrShutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
return;
}
@@ -1186,18 +1201,27 @@ bool Controller::Start(const GURL& deeplink_url,
}
void Controller::ShowFirstMessageAndStart() {
- // Only show default status message if necessary. Scripts started by lite
- // scripts that also showed the onboarding do not show the loading message.
- if (status_message_.empty() &&
- !(GetTriggerContext()->is_onboarding_shown() &&
- GetTriggerContext()->WasStartedByTriggerScript())) {
+ if (!status_message_.empty()) {
+ // A status message may have been set prior to calling |Start|.
+ SetStatusMessage(status_message_);
+ } else if (!(GetTriggerContext()->is_onboarding_shown() &&
+ GetTriggerContext()->WasStartedByLegacyTriggerScript())) {
SetStatusMessage(
l10n_util::GetStringFUTF8(IDS_AUTOFILL_ASSISTANT_LOADING,
base::UTF8ToUTF16(GetCurrentURL().host())));
+ } else {
+ // Only show default status message if necessary. Scripts started by lite
+ // scripts that also showed the onboarding do not show the loading message.
}
if (step_progress_bar_configuration_.has_value() &&
step_progress_bar_configuration_->use_step_progress_bar()) {
- SetProgressActiveStep(0);
+ if (!progress_active_step_.has_value()) {
+ // Set default progress unless already specified in
+ // |progress_active_step_|.
+ progress_active_step_ = 0;
+ }
+ SetStepProgressBarConfiguration(*step_progress_bar_configuration_);
+ SetProgressActiveStep(*progress_active_step_);
} else {
SetProgress(kAutostartInitialProgress);
}
@@ -1594,7 +1618,7 @@ void Controller::OnScriptError(const std::string& error_message,
SetProgressBarErrorState(true);
}
- EnterStoppedState();
+ EnterStoppedState(/*show_feedback_chip=*/true);
if (tracking_) {
EnterState(AutofillAssistantState::TRACKING);
@@ -1605,6 +1629,7 @@ void Controller::OnScriptError(const std::string& error_message,
}
void Controller::OnFatalError(const std::string& error_message,
+ bool show_feedback_chip,
Metrics::DropOutReason reason) {
LOG(ERROR) << "Autofill Assistant has encountered a fatal error and is "
"shutting down, reason="
@@ -1614,13 +1639,13 @@ void Controller::OnFatalError(const std::string& error_message,
SetStatusMessage(error_message);
SetProgressBarErrorState(true);
- EnterStoppedState();
+ EnterStoppedState(show_feedback_chip);
// If we haven't managed to check the set of scripts yet at this point, we
// never will.
MaybeReportFirstCheckDone();
- if (tracking_ && HasSameDomainAs(script_url_, GetCurrentURL())) {
+ if (tracking_ && script_url_.host() == GetCurrentURL().host()) {
// When tracking the controller should stays until the browser has navigated
// away from the last domain that was checked to be able to tell callers
// that the set of user actions is empty.
@@ -1657,7 +1682,7 @@ void Controller::OnStop(const std::string& message,
void Controller::PerformDelayedShutdownIfNecessary() {
if (delayed_shutdown_reason_ &&
- !HasSameDomainAs(script_url_, GetCurrentURL())) {
+ script_url_.host() != GetCurrentURL().host()) {
Metrics::DropOutReason reason = delayed_shutdown_reason_.value();
delayed_shutdown_reason_ = base::nullopt;
tracking_ = false;
@@ -1881,11 +1906,9 @@ void Controller::DidFinishNavigation(
// from the original assisted domain. Subdomains of the original domain are
// supported.
if (state_ == AutofillAssistantState::BROWSE) {
- auto current_host = web_contents()->GetLastCommittedURL().host();
- auto script_host = script_url_.host();
- if (current_host != script_host &&
- !IsSubdomainOf(current_host, script_host) &&
- !IsInWhitelist(current_host, browse_domains_whitelist_)) {
+ if (!url_utils::IsInDomainOrSubDomain(GetCurrentURL(), script_url_) &&
+ !url_utils::IsInDomainOrSubDomain(GetCurrentURL(),
+ browse_domains_allowlist_)) {
OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE);
}
@@ -2003,6 +2026,11 @@ bool Controller::IsRunningLiteScript() const {
return service_ ? service_->IsLiteService() : false;
}
+void Controller::OnKeyboardVisibilityChanged(bool visible) {
+ is_keyboard_showing_ = visible;
+ SetVisibilityAndUpdateUserActions();
+}
+
ElementArea* Controller::touchable_element_area() {
if (!touchable_element_area_) {
touchable_element_area_ = std::make_unique<ElementArea>(this);
diff --git a/chromium/components/autofill_assistant/browser/controller.h b/chromium/components/autofill_assistant/browser/controller.h
index 8b6a87d5724..0c0bcca1853 100644
--- a/chromium/components/autofill_assistant/browser/controller.h
+++ b/chromium/components/autofill_assistant/browser/controller.h
@@ -10,7 +10,7 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/optional.h"
#include "components/autofill_assistant/browser/basic_interactions.h"
@@ -24,8 +24,8 @@
#include "components/autofill_assistant/browser/script.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/script_tracker.h"
-#include "components/autofill_assistant/browser/service.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/state.h"
#include "components/autofill_assistant/browser/trigger_context.h"
#include "components/autofill_assistant/browser/ui_delegate.h"
@@ -63,7 +63,7 @@ class Controller : public ScriptExecutorDelegate,
Controller(content::WebContents* web_contents,
Client* client,
const base::TickClock* tick_clock,
- RuntimeManagerImpl* runtime_manager,
+ base::WeakPtr<RuntimeManagerImpl> runtime_manager,
std::unique_ptr<Service> service);
~Controller() override;
@@ -150,6 +150,7 @@ class Controller : public ScriptExecutorDelegate,
view_inflation_finished_callback) override;
void ClearGenericUi() override;
void SetBrowseModeInvisible(bool invisible) override;
+ void SetShowFeedbackChip(bool show_feedback_chip) override;
// Show the UI if it's not already shown. This is only meaningful while in
// states where showing the UI is optional, such as RUNNING, in tracking mode.
@@ -164,7 +165,7 @@ class Controller : public ScriptExecutorDelegate,
void RemoveListener(ScriptExecutorDelegate::Listener* listener) override;
void SetExpandSheetForPromptAction(bool expand) override;
- void SetBrowseDomainsWhitelist(std::vector<std::string> domains) override;
+ void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
bool EnterState(AutofillAssistantState state) override;
void SetOverlayBehavior(
@@ -222,6 +223,7 @@ class Controller : public ScriptExecutorDelegate,
void GetRestrictedArea(std::vector<RectF>* area) const override;
void GetVisualViewport(RectF* visual_viewport) const override;
void OnFatalError(const std::string& error_message,
+ bool show_feedback_chip,
Metrics::DropOutReason reason) override;
void OnStop(const std::string& message,
const std::string& button_label) override;
@@ -251,6 +253,7 @@ class Controller : public ScriptExecutorDelegate,
bool ShouldShowOverlay() const override;
void ShutdownIfNecessary() override;
bool IsRunningLiteScript() const override;
+ void OnKeyboardVisibilityChanged(bool visible) override;
private:
friend ControllerTest;
@@ -268,7 +271,9 @@ class Controller : public ScriptExecutorDelegate,
// once right now and schedule regular checks. Otherwise, do nothing.
void GetOrCheckScripts();
- void OnGetScripts(const GURL& url, bool result, const std::string& response);
+ void OnGetScripts(const GURL& url,
+ int http_status,
+ const std::string& response);
// Execute |script_path| and, if execution succeeds, enter |end_state| and
// call |on_success|.
@@ -341,7 +346,11 @@ class Controller : public ScriptExecutorDelegate,
void ShowFirstMessageAndStart();
// Clear out visible state and enter the stopped state.
- void EnterStoppedState();
+ // If |show_feedback_chip| is true, a "Send feedback" chip will be added to
+ // the bottom sheet.
+ void EnterStoppedState(bool show_feedback_chip);
+
+ void OnFeedbackChipClicked();
ElementArea* touchable_element_area();
ScriptTracker* script_tracker();
@@ -352,10 +361,12 @@ class Controller : public ScriptExecutorDelegate,
bool StateNeedsUI(AutofillAssistantState state);
+ void SetVisibilityAndUpdateUserActions();
+
ClientSettings settings_;
Client* const client_;
const base::TickClock* const tick_clock_;
- RuntimeManagerImpl* const runtime_manager_;
+ base::WeakPtr<RuntimeManagerImpl> runtime_manager_;
// Lazily instantiate in GetWebController().
std::unique_ptr<WebController> web_controller_;
@@ -517,8 +528,10 @@ class Controller : public ScriptExecutorDelegate,
BasicInteractions basic_interactions_{this};
bool expand_sheet_for_prompt_action_ = true;
- std::vector<std::string> browse_domains_whitelist_;
+ std::vector<std::string> browse_domains_allowlist_;
bool browse_mode_invisible_ = false;
+ bool is_keyboard_showing_ = false;
+ bool show_feedback_chip_on_graceful_shutdown_ = false;
// Only set during a ShowGenericUiAction.
std::unique_ptr<GenericUserInterfaceProto> generic_user_interface_;
diff --git a/chromium/components/autofill_assistant/browser/controller_observer.h b/chromium/components/autofill_assistant/browser/controller_observer.h
index 68472744648..1419891769b 100644
--- a/chromium/components/autofill_assistant/browser/controller_observer.h
+++ b/chromium/components/autofill_assistant/browser/controller_observer.h
@@ -131,6 +131,9 @@ class ControllerObserver : public base::CheckedObserver {
// Called when the desired overlay behavior has changed.
virtual void OnShouldShowOverlayChanged(bool should_show) = 0;
+
+ // Called when the feedback form has been requested.
+ virtual void OnFeedbackFormRequested() = 0;
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_CONTROLLER_OBSERVER_H_
diff --git a/chromium/components/autofill_assistant/browser/controller_unittest.cc b/chromium/components/autofill_assistant/browser/controller_unittest.cc
index e5b94798b29..96bd1bb4a57 100644
--- a/chromium/components/autofill_assistant/browser/controller_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/controller_unittest.cc
@@ -7,10 +7,10 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/gtest_util.h"
#include "base/test/mock_callback.h"
@@ -21,9 +21,10 @@
#include "components/autofill_assistant/browser/mock_client.h"
#include "components/autofill_assistant/browser/mock_controller_observer.h"
#include "components/autofill_assistant/browser/mock_personal_data_manager.h"
-#include "components/autofill_assistant/browser/mock_service.h"
#include "components/autofill_assistant/browser/public/mock_runtime_manager.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/mock_service.h"
+#include "components/autofill_assistant/browser/service/service.h"
+#include "components/autofill_assistant/browser/test_util.h"
#include "components/autofill_assistant/browser/trigger_context.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "components/strings/grit/components_strings.h"
@@ -31,6 +32,7 @@
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
+#include "net/http/http_status_code.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/l10n/l10n_util.h"
@@ -62,6 +64,7 @@ using ::testing::Sequence;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
+using ::testing::WithArgs;
namespace {
@@ -103,9 +106,10 @@ class ControllerTest : public content::RenderViewHostTestHarness {
ON_CALL(mock_client_, GetWebContents).WillByDefault(Return(web_contents()));
ON_CALL(mock_client_, HasHadUI()).WillByDefault(Return(true));
+ mock_runtime_manager_ = std::make_unique<MockRuntimeManager>();
controller_ = std::make_unique<Controller>(
web_contents(), &mock_client_, task_environment()->GetMockTickClock(),
- &mock_runtime_manager_, std::move(service));
+ mock_runtime_manager_->GetWeakPtr(), std::move(service));
controller_->SetWebControllerForTest(std::move(web_controller));
ON_CALL(mock_client_, AttachUI()).WillByDefault(Invoke([this]() {
@@ -118,19 +122,19 @@ class ControllerTest : public content::RenderViewHostTestHarness {
// Fetching scripts succeeds for all URLs, but return nothing.
ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
- .WillByDefault(RunOnceCallback<2>(true, ""));
+ .WillByDefault(RunOnceCallback<2>(net::HTTP_OK, ""));
// Scripts run, but have no actions.
ON_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillByDefault(RunOnceCallback<5>(true, ""));
+ .WillByDefault(RunOnceCallback<5>(net::HTTP_OK, ""));
- ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillByDefault(RunOnceCallback<4>(true, ""));
+ ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillByDefault(RunOnceCallback<5>(net::HTTP_OK, ""));
ON_CALL(*mock_service_, IsLiteService).WillByDefault(Return(false));
- ON_CALL(*mock_web_controller_, OnElementCheck(_, _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus()));
+ ON_CALL(*mock_web_controller_, OnFindElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(ClientStatus(), nullptr));
ON_CALL(mock_observer_, OnStateChanged(_))
.WillByDefault(Invoke([this](AutofillAssistantState state) {
@@ -163,7 +167,7 @@ class ControllerTest : public content::RenderViewHostTestHarness {
std::string scripts_str;
scripts.SerializeToString(&scripts_str);
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
- .WillOnce(RunOnceCallback<2>(true, scripts_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str));
}
void SetupActionsForScript(const std::string& path,
@@ -171,7 +175,7 @@ class ControllerTest : public content::RenderViewHostTestHarness {
std::string actions_response_str;
actions_response.SerializeToString(&actions_response_str);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, actions_response_str));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str));
}
void Start() { Start("http://initialurl.com"); }
@@ -209,7 +213,7 @@ class ControllerTest : public content::RenderViewHostTestHarness {
response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
}
// Sets up all calls to the service for scripts to return |response|.
@@ -218,7 +222,7 @@ class ControllerTest : public content::RenderViewHostTestHarness {
response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
- .WillRepeatedly(RunOnceCallback<2>(true, response_str));
+ .WillRepeatedly(RunOnceCallback<2>(net::HTTP_OK, response_str));
}
UserData* GetUserData() { return controller_->user_data_.get(); }
@@ -237,7 +241,7 @@ class ControllerTest : public content::RenderViewHostTestHarness {
MockService* mock_service_;
MockWebController* mock_web_controller_;
NiceMock<MockClient> mock_client_;
- NiceMock<MockRuntimeManager> mock_runtime_manager_;
+ std::unique_ptr<MockRuntimeManager> mock_runtime_manager_;
NiceMock<MockControllerObserver> mock_observer_;
std::unique_ptr<Controller> controller_;
};
@@ -325,7 +329,7 @@ TEST_F(ControllerTest, FetchAndRunScriptsWithChip) {
// Choose script2 and run it successfully.
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("script2"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_TRUE(controller_->PerformUserAction(1));
// Offering the remaining choice: script1 as script2 can only run once.
@@ -548,7 +552,7 @@ TEST_F(ControllerTest, Stop) {
std::string actions_response_str;
actions_response.SerializeToString(&actions_response_str);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, actions_response_str));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str));
Start();
ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
@@ -568,7 +572,7 @@ TEST_F(ControllerTest, CloseCustomTab) {
std::string actions_response_str;
actions_response.SerializeToString(&actions_response_str);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, actions_response_str));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str));
Start();
ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
@@ -580,6 +584,30 @@ TEST_F(ControllerTest, CloseCustomTab) {
EXPECT_TRUE(controller_->PerformUserAction(0));
}
+TEST_F(ControllerTest, StopWithFeedbackChip) {
+ SupportsScriptResponseProto script_response;
+ AddRunnableScript(&script_response, "stop");
+ SetNextScriptResponse(script_response);
+
+ ActionsResponseProto actions_response;
+ actions_response.add_actions()->mutable_tell()->set_message("I give up");
+ actions_response.add_actions()->mutable_stop()->set_show_feedback_chip(true);
+ std::string actions_response_str;
+ actions_response.SerializeToString(&actions_response_str);
+ EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, actions_response_str));
+
+ Start();
+ ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
+
+ testing::InSequence seq;
+ EXPECT_CALL(mock_client_,
+ RecordDropOut(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
+ EXPECT_TRUE(controller_->PerformUserAction(0));
+ ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
+ EXPECT_EQ(FEEDBACK_ACTION, controller_->GetUserActions().at(0).chip().type);
+}
+
TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "script");
@@ -588,10 +616,10 @@ TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(Eq(GURL("http://a.example.com/path1")), _, _))
- .WillOnce(RunOnceCallback<2>(true, scripts_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str));
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(Eq(GURL("http://b.example.com/path1")), _, _))
- .WillOnce(RunOnceCallback<2>(true, scripts_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, scripts_str));
Start("http://a.example.com/path1");
SimulateNavigateToUrl(GURL("http://a.example.com/path2"));
@@ -608,7 +636,7 @@ TEST_F(ControllerTest, Autostart) {
SetNextScriptResponse(script_response);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("autostart"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(mock_client_, AttachUI());
Start("http://a.example.com/path");
@@ -633,7 +661,26 @@ TEST_F(ControllerTest, Autostart) {
AutofillAssistantState::STOPPED));
}
-TEST_F(ControllerTest, AutostartIsNotPassedToTheUi) {
+TEST_F(ControllerTest,
+ AutostartFallbackWithNoRunnableScriptsShowsFeedbackChip) {
+ SupportsScriptResponseProto script_response;
+ auto* autostart = AddRunnableScript(&script_response, "runnable");
+ autostart->mutable_presentation()->set_autostart(true);
+ RunOnce(autostart);
+ SetRepeatedScriptResponse(script_response);
+
+ Start("http://a.example.com/path");
+ ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
+ EXPECT_EQ(FEEDBACK_ACTION, controller_->GetUserActions().at(0).chip().type);
+}
+
+TEST_F(ControllerTest,
+ AutostartErrorDoesNotShowFeedbackChipWithFeatureFlagDisabled) {
+ // Disable the feedback chip feature.
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillAssistantFeedbackChip);
+
SupportsScriptResponseProto script_response;
auto* autostart = AddRunnableScript(&script_response, "runnable");
autostart->mutable_presentation()->set_autostart(true);
@@ -651,7 +698,7 @@ TEST_F(ControllerTest, AutostartIsNotPassedToTheUi) {
TEST_F(ControllerTest, InitialUrlLoads) {
GURL initialUrl("http://a.example.com/path");
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
- .WillOnce(RunOnceCallback<2>(true, ""));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
controller_->Start(initialUrl, TriggerContext::CreateEmpty());
}
@@ -827,8 +874,9 @@ TEST_F(ControllerTest, StateChanges) {
AutofillAssistantState::PROMPT,
AutofillAssistantState::STOPPED));
- // The cancel button is removed.
- EXPECT_TRUE(controller_->GetUserActions().empty());
+ // The cancel button is removed and the feedback chip is displayed.
+ ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
+ EXPECT_EQ(FEEDBACK_ACTION, controller_->GetUserActions().at(0).chip().type);
}
TEST_F(ControllerTest, AttachUIWhenStarting) {
@@ -851,7 +899,8 @@ TEST_F(ControllerTest, AttachUIWhenContentsFocused) {
SimulateWebContentsFocused(); // must call AttachUI
EXPECT_CALL(mock_client_, AttachUI());
- controller_->OnFatalError("test", Metrics::DropOutReason::TAB_CHANGED);
+ controller_->OnFatalError("test", /*show_feedback_chip= */ false,
+ Metrics::DropOutReason::TAB_CHANGED);
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
SimulateWebContentsFocused(); // must call AttachUI
}
@@ -874,8 +923,11 @@ TEST_F(ControllerTest, KeepCheckingForElement) {
EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
}
- EXPECT_CALL(*mock_web_controller_, OnElementCheck(_, _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(*mock_web_controller_, OnFindElement(_, _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT,
@@ -904,7 +956,7 @@ TEST_F(ControllerTest, ScriptTimeoutError) {
on_timeout_error.SerializeToString(&on_timeout_error_str);
EXPECT_CALL(*mock_service_,
OnGetActions(StrEq("on_timeout_error"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, on_timeout_error_str));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, on_timeout_error_str));
Start("http://a.example.com/path");
for (int i = 0; i < 30; i++) {
@@ -936,7 +988,7 @@ TEST_F(ControllerTest, ScriptTimeoutWarning) {
on_timeout_error.SerializeToString(&on_timeout_error_str);
EXPECT_CALL(*mock_service_,
OnGetActions(StrEq("on_timeout_error"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, on_timeout_error_str));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, on_timeout_error_str));
Start("http://a.example.com/path");
@@ -1098,9 +1150,9 @@ TEST_F(ControllerTest, WaitForNavigationActionTimesOut) {
SetupActionsForScript("script", actions_response);
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
Start("http://a.example.com/path");
EXPECT_THAT(controller_->GetUserActions(), SizeIs(1));
@@ -1131,9 +1183,9 @@ TEST_F(ControllerTest, WaitForNavigationActionStartWithinTimeout) {
SetupActionsForScript("script", actions_response);
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
Start("http://a.example.com/path");
EXPECT_THAT(controller_->GetUserActions(), SizeIs(1));
@@ -1179,11 +1231,11 @@ TEST_F(ControllerTest, Track) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://b.example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, ""));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
// Start tracking at example.com, with one script matching
SetLastCommittedUrl(GURL("http://example.com/"));
@@ -1287,7 +1339,7 @@ TEST_F(ControllerTest, TrackScriptShowUIOnError) {
// Running the script fails, due to a backend issue. The error message should
// be shown.
EXPECT_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(false, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
// Start tracking at example.com, with one script matching
SetLastCommittedUrl(GURL("http://example.com/"));
@@ -1317,7 +1369,7 @@ TEST_F(ControllerTest, TrackContinuesAfterScriptError) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
// Start tracking at example.com, with one script matching
SetLastCommittedUrl(GURL("http://example.com/"));
@@ -1327,7 +1379,7 @@ TEST_F(ControllerTest, TrackContinuesAfterScriptError) {
ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("runnable"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(false, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
// When the script fails, the controller transitions to STOPPED state, then
// right away back to TRACKING state.
@@ -1373,7 +1425,7 @@ TEST_F(ControllerTest, TrackReportsFirstSetOfScripts) {
AddRunnableScript(&script_response, "runnable");
std::string response_str;
script_response.SerializeToString(&response_str);
- std::move(get_scripts_callback).Run(true, response_str);
+ std::move(get_scripts_callback).Run(net::HTTP_OK, response_str);
EXPECT_TRUE(first_check_done);
EXPECT_TRUE(controller_->HasRunFirstCheck());
@@ -1451,7 +1503,7 @@ TEST_F(ControllerTest, TrackThenAutostart) {
EXPECT_THAT(controller_->GetUserActions(), SizeIs(1));
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("autostart"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
ActionsResponseProto runnable_script;
runnable_script.add_actions()->mutable_tell()->set_message("runnable");
@@ -1491,7 +1543,7 @@ TEST_F(ControllerTest, BrowseStateStopsOnDifferentDomain) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://b.example.com/"), _, _))
.Times(0);
@@ -1520,7 +1572,7 @@ TEST_F(ControllerTest, BrowseStateStopsOnDifferentDomain) {
SimulateNavigateToUrl(GURL("http://other-example.com/"));
}
-TEST_F(ControllerTest, BrowseStateWithDomainWhitelist) {
+TEST_F(ControllerTest, BrowseStateWithDomainAllowlist) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "runnable")
->mutable_presentation()
@@ -1528,15 +1580,15 @@ TEST_F(ControllerTest, BrowseStateWithDomainWhitelist) {
ActionsResponseProto runnable_script;
auto* prompt = runnable_script.add_actions()->mutable_prompt();
prompt->set_browse_mode(true);
- *prompt->add_browse_domains_whitelist() = "example.com";
- *prompt->add_browse_domains_whitelist() = "other-example.com";
+ *prompt->add_browse_domains_allowlist() = "example.com";
+ *prompt->add_browse_domains_allowlist() = "other-example.com";
prompt->add_choices()->mutable_chip()->set_text("continue");
SetupActionsForScript("runnable", runnable_script);
std::string response_str;
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
Start("http://a.example.com/");
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
@@ -1552,13 +1604,13 @@ TEST_F(ControllerTest, BrowseStateWithDomainWhitelist) {
content::NavigationSimulator::GoBack(web_contents());
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
- // Same domain navigations as one of the whitelisted domains should not
- // shutdown AA.
+ // Same domain navigations as one of the allowed domains should not shut down
+ // AA.
SimulateNavigateToUrl(GURL("http://other-example.com/"));
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
}
-TEST_F(ControllerTest, BrowseStateWithDomainWhitelistCleanup) {
+TEST_F(ControllerTest, BrowseStateWithDomainAllowlistCleanup) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "runnable")
->mutable_presentation()
@@ -1566,10 +1618,10 @@ TEST_F(ControllerTest, BrowseStateWithDomainWhitelistCleanup) {
ActionsResponseProto runnable_script;
auto* prompt = runnable_script.add_actions()->mutable_prompt();
prompt->set_browse_mode(true);
- *prompt->add_browse_domains_whitelist() = "example.com";
+ *prompt->add_browse_domains_allowlist() = "example.com";
prompt->add_choices()->mutable_chip()->set_text("continue");
- // Second browse action without a whitelist.
+ // Second browse action without an allowlist.
auto* prompt2 = runnable_script.add_actions()->mutable_prompt();
prompt2->set_browse_mode(true);
prompt2->add_choices()->mutable_chip()->set_text("done");
@@ -1579,7 +1631,7 @@ TEST_F(ControllerTest, BrowseStateWithDomainWhitelistCleanup) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
Start("http://a.example.com/");
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
@@ -1593,7 +1645,7 @@ TEST_F(ControllerTest, BrowseStateWithDomainWhitelistCleanup) {
EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "done");
- // Make sure the whitelist got reset with the second prompt action.
+ // Make sure the allowlist got reset with the second prompt action.
EXPECT_CALL(
mock_client_,
RecordDropOut(Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE));
@@ -1614,7 +1666,7 @@ TEST_F(ControllerTest, PromptStateStopsOnGoBack) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
Start("http://example.com/");
EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
@@ -1934,7 +1986,7 @@ TEST_F(ControllerTest, DomainChangeToGooglePropertyDuringBrowseDestroysUI) {
script_response.SerializeToString(&response_str);
EXPECT_CALL(*mock_service_,
OnGetScriptsForUrl(GURL("http://a.example.com/"), _, _))
- .WillOnce(RunOnceCallback<2>(true, response_str));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, response_str));
Start("http://a.example.com/");
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
@@ -2624,7 +2676,7 @@ TEST_F(ControllerTest, SetGenericUi) {
TEST_F(ControllerTest, StartPasswordChangeFlow) {
GURL initialUrl("http://example.com/password");
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
- .WillOnce(RunOnceCallback<2>(true, ""));
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
std::map<std::string, std::string> parameters;
std::string username = "test_username";
parameters["PASSWORD_CHANGE_USERNAME"] = username;
@@ -2656,9 +2708,9 @@ TEST_F(ControllerTest, EndPromptWithOnEndNavigation) {
SetupActionsForScript("script", actions_response);
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
Start("http://a.example.com/path");
@@ -2850,11 +2902,93 @@ TEST_F(ControllerTest, RegularScriptShowsDefaultInitialStatusMessage) {
Start("http://a.example.com/path");
}
+TEST_F(ControllerTest, NotifyObserversOfInitialStatusMessageAndProgressBar) {
+ SupportsScriptResponseProto script_response;
+ AddRunnableScript(&script_response, "script")
+ ->mutable_presentation()
+ ->set_autostart(true);
+ SetupScripts(script_response);
+
+ ActionsResponseProto actions_response;
+ actions_response.add_actions()->mutable_tell()->set_message("script message");
+ SetupActionsForScript("script", actions_response);
+
+ ShowProgressBarProto::StepProgressBarConfiguration progress_bar_configuration;
+ progress_bar_configuration.set_use_step_progress_bar(true);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_INITIAL_STEP);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_DATA_COLLECTION);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_PAYMENT);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_FINAL_STEP);
+
+ // When setting UI state of the controller before calling |Start|, observers
+ // will be notified immediately after |Start|.
+ controller_->SetStatusMessage("startup message");
+ controller_->SetStepProgressBarConfiguration(progress_bar_configuration);
+ controller_->SetProgressActiveStep(1);
+
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(
+ progress_bar_configuration));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
+ testing::Sequence s1;
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged("startup message"))
+ .InSequence(s1);
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged("script message"))
+ .InSequence(s1);
+ Start("http://a.example.com/path");
+}
+
TEST_F(ControllerTest, NotifyRuntimeManagerOnUiStateChange) {
- EXPECT_CALL(mock_runtime_manager_, SetUIState(UIState::kShown)).Times(1);
+ EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kShown)).Times(1);
controller_->SetUiShown(true);
- EXPECT_CALL(mock_runtime_manager_, SetUIState(UIState::kNotShown)).Times(1);
+ EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kNotShown)).Times(1);
controller_->SetUiShown(false);
}
+
+TEST_F(ControllerTest, RuntimeManagerDestroyed) {
+ mock_runtime_manager_.reset();
+ // This method should not crash.
+ controller_->SetUiShown(true);
+}
+
+TEST_F(ControllerTest, OnGetScriptsFailedWillShutdown) {
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged(l10n_util::GetStringFUTF8(
+ IDS_AUTOFILL_ASSISTANT_LOADING,
+ base::UTF8ToUTF16("initialurl.com"))))
+ .Times(1);
+ EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_NOT_FOUND, ""));
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged(l10n_util::GetStringUTF8(
+ IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR)))
+ .Times(1);
+ EXPECT_CALL(mock_client_, HasHadUI()).WillOnce(Return(false));
+ EXPECT_CALL(mock_client_,
+ Shutdown(Metrics::DropOutReason::GET_SCRIPTS_FAILED))
+ .Times(1);
+
+ Start();
+ EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
+}
+
+TEST_F(ControllerTest, OnScriptErrorWillAppendVanishingFeedbackChip) {
+ // A script error should show the feedback chip.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(1)));
+ EXPECT_CALL(mock_client_, RecordDropOut(Metrics::DropOutReason::NAVIGATION));
+ controller_->OnScriptError("Error", Metrics::DropOutReason::NAVIGATION);
+ EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
+
+ // The chip should vanish once clicked.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ EXPECT_CALL(mock_client_,
+ Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY));
+ EXPECT_TRUE(controller_->PerformUserAction(0));
+}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/devtools/BUILD.gn b/chromium/components/autofill_assistant/browser/devtools/BUILD.gn
index dcc65ba033e..08a398a1b12 100644
--- a/chromium/components/autofill_assistant/browser/devtools/BUILD.gn
+++ b/chromium/components/autofill_assistant/browser/devtools/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
+
devtools_domains = [
"accessibility",
"animation",
@@ -51,7 +53,8 @@ foreach(domain, devtools_domains) {
]
}
-action("gen_devtools_client_api") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("gen_devtools_client_api") {
script = "devtools_api/client_api_generator.py"
deps = [ "//third_party/blink/public/devtools_protocol:protocol_version" ]
inputs = [
diff --git a/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc b/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
index 6698d957966..b997f81f074 100644
--- a/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
+++ b/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
@@ -13,10 +13,13 @@
#include "base/callback_forward.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/strings/strcat.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace autofill_assistant {
+// Error code indicating that a session-id lookup has failed.
+constexpr long kSessionIdLookupFailedError = -10;
DevtoolsClient::DevtoolsClient(
scoped_refptr<content::DevToolsAgentHost> agent_host)
@@ -26,7 +29,6 @@ DevtoolsClient::DevtoolsClient(
runtime_domain_(this),
network_domain_(this),
target_domain_(this),
- renderer_crashed_(false),
next_message_id_(0),
frame_tracker_(this) {
browser_main_thread_ = content::GetUIThreadTaskRunner({});
@@ -64,7 +66,22 @@ void DevtoolsClient::SendMessage(
std::unique_ptr<base::Value> params,
const std::string& optional_node_frame_id,
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback) {
- SendMessageWithParams(method, std::move(params), optional_node_frame_id,
+ std::string optional_session_id =
+ GetSessionIdForFrame(optional_node_frame_id);
+ if (!optional_node_frame_id.empty() && optional_session_id.empty()) {
+ // Early-fail now to avoid sending the message to the main frame instead.
+ ReplyStatus status;
+ status.error_code = kSessionIdLookupFailedError;
+ status.error_message =
+ base::StrCat({"Failed to look up session-id for node-frame-id ",
+ optional_node_frame_id,
+ ". This indicates either that the frame crashed, or a "
+ "bug in session handling."});
+ std::move(callback).Run(status, base::Value());
+ return;
+ }
+
+ SendMessageWithParams(method, std::move(params), optional_session_id,
std::move(callback));
}
@@ -72,7 +89,15 @@ void DevtoolsClient::SendMessage(const char* method,
std::unique_ptr<base::Value> params,
const std::string& optional_node_frame_id,
base::OnceClosure callback) {
- SendMessageWithParams(method, std::move(params), optional_node_frame_id,
+ std::string optional_session_id =
+ GetSessionIdForFrame(optional_node_frame_id);
+ if (!optional_node_frame_id.empty() && optional_session_id.empty()) {
+ // Early-fail now to avoid sending the message to the main frame instead.
+ std::move(callback).Run();
+ return;
+ }
+
+ SendMessageWithParams(method, std::move(params), optional_session_id,
std::move(callback));
}
@@ -80,20 +105,16 @@ template <typename CallbackType>
void DevtoolsClient::SendMessageWithParams(
const char* method,
std::unique_ptr<base::Value> params,
- const std::string& optional_node_frame_id,
+ const std::string& optional_session_id,
CallbackType callback) {
base::DictionaryValue message;
message.SetString("method", method);
message.Set("params", std::move(params));
- std::string optional_session_id =
- GetSessionIdForFrame(optional_node_frame_id);
if (!optional_session_id.empty()) {
message.SetString("sessionId", optional_session_id);
}
- if (renderer_crashed_)
- return;
int id = next_message_id_;
next_message_id_ += 2; // We only send even numbered messages.
message.SetInteger("id", id);
@@ -220,8 +241,6 @@ bool DevtoolsClient::DispatchEvent(std::unique_ptr<base::Value> owning_message,
if (!method_value)
return false;
const std::string& method = method_value->GetString();
- if (method == "Inspector.targetCrashed")
- renderer_crashed_ = true;
EventHandlerMap::const_iterator it = event_handlers_.find(method);
if (it == event_handlers_.end()) {
if (method != "Inspector.targetCrashed")
@@ -276,7 +295,6 @@ void DevtoolsClient::FillReplyStatusFromErrorDict(
void DevtoolsClient::AgentHostClosed(content::DevToolsAgentHost* agent_host) {
// Agent host is not expected to be closed when this object is alive.
- renderer_crashed_ = true;
}
std::string DevtoolsClient::GetSessionIdForFrame(
diff --git a/chromium/components/autofill_assistant/browser/devtools/devtools_client.h b/chromium/components/autofill_assistant/browser/devtools/devtools_client.h
index 38aee6d5dea..960bc175029 100644
--- a/chromium/components/autofill_assistant/browser/devtools/devtools_client.h
+++ b/chromium/components/autofill_assistant/browser/devtools/devtools_client.h
@@ -126,7 +126,7 @@ class DevtoolsClient : public MessageDispatcher,
template <typename CallbackType>
void SendMessageWithParams(const char* method,
std::unique_ptr<base::Value> params,
- const std::string& optional_node_frame_id,
+ const std::string& optional_session_id,
CallbackType callback);
bool DispatchMessageReply(std::unique_ptr<base::Value> owning_message,
const base::DictionaryValue& message_dict);
@@ -156,7 +156,6 @@ class DevtoolsClient : public MessageDispatcher,
target::ExperimentalDomain target_domain_;
std::unordered_map<int, Callback> pending_messages_;
EventHandlerMap event_handlers_;
- bool renderer_crashed_;
int next_message_id_;
FrameTracker frame_tracker_;
diff --git a/chromium/components/autofill_assistant/browser/element_area.cc b/chromium/components/autofill_assistant/browser/element_area.cc
index 0b513492506..10450a21bbf 100644
--- a/chromium/components/autofill_assistant/browser/element_area.cc
+++ b/chromium/components/autofill_assistant/browser/element_area.cc
@@ -12,6 +12,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
@@ -88,7 +89,7 @@ void ElementArea::AddRectangles(
for (const auto& element_proto : rectangle_proto.elements()) {
rectangle.positions.emplace_back();
ElementPosition& position = rectangle.positions.back();
- position.selector = Selector(element_proto).MustBeVisible();
+ position.selector = Selector(element_proto);
DVLOG(3) << " " << position.selector;
}
}
@@ -128,10 +129,15 @@ void ElementArea::Update() {
for (auto& rectangle : rectangles_) {
for (auto& position : rectangle.positions) {
- delegate_->GetWebController()->GetElementPosition(
- position.selector,
- base::BindOnce(&ElementArea::OnGetElementPosition,
- weak_ptr_factory_.GetWeakPtr(), position.selector));
+ delegate_->GetWebController()->FindElement(
+ position.selector, /* strict= */ true,
+ base::BindOnce(
+ &action_delegate_util::TakeElementAndGetProperty<RectF>,
+ base::BindOnce(&WebController::GetElementRect,
+ delegate_->GetWebController()->GetWeakPtr()),
+ base::BindOnce(&ElementArea::OnGetElementRect,
+ weak_ptr_factory_.GetWeakPtr(),
+ position.selector)));
}
}
}
@@ -205,10 +211,10 @@ void ElementArea::Rectangle::FillRect(RectF* rect,
return;
}
-void ElementArea::OnGetElementPosition(const Selector& selector,
- bool found,
- const RectF& rect) {
- // found == false, has all coordinates set to 0.0, which clears the area.
+void ElementArea::OnGetElementRect(const Selector& selector,
+ const ClientStatus& rect_status,
+ const RectF& rect) {
+ // !rect_status.ok() has all coordinates set to 0.0, which clears the area.
bool updated = false;
for (auto& rectangle : rectangles_) {
for (auto& position : rectangle.positions) {
@@ -227,12 +233,13 @@ void ElementArea::OnGetElementPosition(const Selector& selector,
// rectangles_. This is fine.
}
-void ElementArea::OnGetVisualViewport(bool success, const RectF& rect) {
+void ElementArea::OnGetVisualViewport(const ClientStatus& rect_status,
+ const RectF& rect) {
if (!visual_viewport_pending_update_)
return;
visual_viewport_pending_update_ = false;
- if (!success)
+ if (!rect_status.ok())
return;
visual_viewport_ = rect;
diff --git a/chromium/components/autofill_assistant/browser/element_area.h b/chromium/components/autofill_assistant/browser/element_area.h
index 4ff578ee1f0..01c78e11c96 100644
--- a/chromium/components/autofill_assistant/browser/element_area.h
+++ b/chromium/components/autofill_assistant/browser/element_area.h
@@ -121,10 +121,10 @@ class ElementArea {
void AddRectangles(const ::google::protobuf::RepeatedPtrField<
ElementAreaProto::Rectangle>& rectangles_proto,
bool restricted);
- void OnGetElementPosition(const Selector& selector,
- bool found,
- const RectF& rect);
- void OnGetVisualViewport(bool success, const RectF& rect);
+ void OnGetElementRect(const Selector& selector,
+ const ClientStatus& rect_status,
+ const RectF& rect);
+ void OnGetVisualViewport(const ClientStatus& status, const RectF& rect);
void ReportUpdate();
ScriptExecutorDelegate* const delegate_;
diff --git a/chromium/components/autofill_assistant/browser/element_area_unittest.cc b/chromium/components/autofill_assistant/browser/element_area_unittest.cc
index 3ccde28d42f..30c1cd68e1c 100644
--- a/chromium/components/autofill_assistant/browser/element_area_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/element_area_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
@@ -70,10 +71,13 @@ class ElementAreaTest : public testing::Test {
delegate_.GetMutableSettings()->element_position_update_interval =
base::TimeDelta::FromMilliseconds(100);
- ON_CALL(mock_web_controller_, OnGetElementPosition(_, _))
- .WillByDefault(RunOnceCallback<1>(false, RectF()));
+ test_util::MockFindAnyElement(mock_web_controller_);
+ ON_CALL(mock_web_controller_, OnGetElementRect(_, _))
+ .WillByDefault(
+ RunOnceCallback<1>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
ON_CALL(mock_web_controller_, OnGetVisualViewport(_))
- .WillByDefault(RunOnceCallback<0>(true, RectF(0, 0, 200, 400)));
+ .WillByDefault(
+ RunOnceCallback<0>(OkClientStatus(), RectF(0, 0, 200, 400)));
element_area_.SetOnUpdate(base::BindRepeating(&ElementAreaTest::OnUpdate,
base::Unretained(this)));
@@ -143,9 +147,12 @@ TEST_F(ElementAreaTest, GetVisualViewport) {
}
TEST_F(ElementAreaTest, OneRectangle) {
+ Selector expected_selector({"#found"});
EXPECT_CALL(mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
SetElement("#found");
std::vector<RectF> rectangles;
@@ -154,9 +161,12 @@ TEST_F(ElementAreaTest, OneRectangle) {
}
TEST_F(ElementAreaTest, CallOnUpdate) {
+ Selector expected_selector({"#found"});
EXPECT_CALL(mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
SetElement("#found");
EXPECT_EQ(on_update_call_count_, 1);
@@ -165,9 +175,14 @@ TEST_F(ElementAreaTest, CallOnUpdate) {
}
TEST_F(ElementAreaTest, CallOnUpdateAfterSetFromProto) {
+ Selector expected_selector({"#found"});
EXPECT_CALL(mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
- .WillRepeatedly(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector, 2)),
+ _))
+ .Times(2)
+ .WillRepeatedly(
+ RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
SetElement("#found");
EXPECT_EQ(on_update_call_count_, 1);
@@ -176,13 +191,17 @@ TEST_F(ElementAreaTest, CallOnUpdateAfterSetFromProto) {
}
TEST_F(ElementAreaTest, DontCallOnUpdateWhenViewportMissing) {
+ Selector expected_selector({"#found"});
+
// Swallowing calls to OnGetVisualViewport guarantees that the viewport
// position will never be known.
EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
.WillOnce(DoNothing());
EXPECT_CALL(mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
SetElement("#found");
EXPECT_EQ(on_update_call_count_, 0);
@@ -190,7 +209,8 @@ TEST_F(ElementAreaTest, DontCallOnUpdateWhenViewportMissing) {
TEST_F(ElementAreaTest, CallOnUpdateWhenViewportMissingAndEmptyRect) {
EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
- .WillRepeatedly(RunOnceCallback<0>(false, RectF()));
+ .WillRepeatedly(
+ RunOnceCallback<0>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
SetElement("#found");
@@ -204,14 +224,21 @@ TEST_F(ElementAreaTest, CallOnUpdateWhenViewportMissingAndEmptyRect) {
}
TEST_F(ElementAreaTest, TwoRectangles) {
+ Selector expected_selector_top_left({"#top_left"});
+ Selector expected_selector_bottom_right({"#bottom_right"});
+
EXPECT_CALL(
mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#top_left"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 0, 25, 25)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#bottom_right"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 100, 100)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_top_left)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 0, 25, 25)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(
+ EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_bottom_right)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 100, 100)));
ElementAreaProto area_proto;
*area_proto.add_touchable()->add_elements() = ToSelectorProto("#top_left");
@@ -226,14 +253,19 @@ TEST_F(ElementAreaTest, TwoRectangles) {
}
TEST_F(ElementAreaTest, OneRectangleTwoElements) {
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(5, 2, 6, 5)));
+ Selector expected_selector_1({"#element1"});
+ Selector expected_selector_2({"#element2"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_1)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_2)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(5, 2, 6, 5)));
ElementAreaProto area_proto;
auto* rectangle_proto = area_proto.add_touchable();
@@ -247,16 +279,20 @@ TEST_F(ElementAreaTest, OneRectangleTwoElements) {
}
TEST_F(ElementAreaTest, DoNotReportIncompleteRectangles) {
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
+ Selector expected_selector_1({"#element1"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_1)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
// Getting the position of #element2 neither succeeds nor fails, simulating an
// intermediate state which shouldn't be reported to the callback.
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
+ Selector expected_selector_2({"#element2"});
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_2)),
+ _))
.WillOnce(DoNothing()); // overrides default action
ElementAreaProto area_proto;
@@ -273,22 +309,31 @@ TEST_F(ElementAreaTest, DoNotReportIncompleteRectangles) {
}
TEST_F(ElementAreaTest, OneRectangleFourElements) {
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 0, 1, 1)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(9, 9, 100, 100)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element3"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 9, 1, 100)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element4"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(9, 0, 100, 1)));
+ Selector expected_selector_1({"#element1"});
+ Selector expected_selector_2({"#element2"});
+ Selector expected_selector_3({"#element3"});
+ Selector expected_selector_4({"#element4"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_1)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 0, 1, 1)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_2)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(9, 9, 100, 100)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_3)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 9, 1, 100)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_4)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(9, 0, 100, 1)));
ElementAreaProto area_proto;
auto* rectangle_proto = area_proto.add_touchable();
@@ -304,14 +349,19 @@ TEST_F(ElementAreaTest, OneRectangleFourElements) {
}
TEST_F(ElementAreaTest, OneRectangleMissingElementsReported) {
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(1, 1, 2, 2)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(false, RectF()));
+ Selector expected_selector_1({"#element1"});
+ Selector expected_selector_2({"#element2"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_1)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 1, 2, 2)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_2)),
+ _))
+ .WillOnce(RunOnceCallback<1>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
ElementAreaProto area_proto;
auto* rectangle_proto = area_proto.add_touchable();
@@ -327,16 +377,22 @@ TEST_F(ElementAreaTest, OneRectangleMissingElementsReported) {
}
TEST_F(ElementAreaTest, FullWidthRectangle) {
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(5, 7, 6, 8)));
+ Selector expected_selector_1({"#element1"});
+ Selector expected_selector_2({"#element2"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_1)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector_2)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(5, 7, 6, 8)));
EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
- .WillRepeatedly(RunOnceCallback<0>(true, RectF(100, 0, 200, 400)));
+ .WillRepeatedly(
+ RunOnceCallback<0>(OkClientStatus(), RectF(100, 0, 200, 400)));
ElementAreaProto area_proto;
auto* rectangle_proto = area_proto.add_touchable();
@@ -355,11 +411,19 @@ TEST_F(ElementAreaTest, FullWidthRectangle) {
TEST_F(ElementAreaTest, ElementMovesAfterUpdate) {
testing::InSequence seq;
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 25, 100, 50)))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 50, 100, 75)));
+
+ Selector expected_selector({"#element"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 25, 100, 50)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 50, 100, 75)));
SetElement("#element");
@@ -381,11 +445,24 @@ TEST_F(ElementAreaTest, ElementMovesAfterUpdate) {
TEST_F(ElementAreaTest, ElementMovesWithTime) {
testing::InSequence seq;
- EXPECT_CALL(
- mock_web_controller_,
- OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(0, 25, 100, 50)))
- .WillRepeatedly(RunOnceCallback<1>(true, RectF(0, 50, 100, 75)));
+
+ Selector expected_selector({"#element"});
+
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 25, 100, 50)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 50, 100, 75)));
+ EXPECT_CALL(mock_web_controller_,
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 50, 100, 75)));
SetElement("#element");
@@ -408,10 +485,13 @@ TEST_F(ElementAreaTest, ElementMovesWithTime) {
}
TEST_F(ElementAreaTest, RestrictedElement) {
+ Selector expected_selector({"#restricted_element"});
+
EXPECT_CALL(mock_web_controller_,
- OnGetElementPosition(
- Eq(Selector({"#restricted_element"}).MustBeVisible()), _))
- .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+ OnGetElementRect(EqualsElement(test_util::MockFindElement(
+ mock_web_controller_, expected_selector)),
+ _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
SetElement("#restricted_element", /* restricted= */ true);
diff --git a/chromium/components/autofill_assistant/browser/element_precondition.cc b/chromium/components/autofill_assistant/browser/element_precondition.cc
index 3af6be558aa..38a92e94af5 100644
--- a/chromium/components/autofill_assistant/browser/element_precondition.cc
+++ b/chromium/components/autofill_assistant/browser/element_precondition.cc
@@ -34,10 +34,10 @@ void ElementPrecondition::Check(
// Empty selectors never match.
continue;
}
- base::OnceCallback<void(const ClientStatus&)> callback =
+ batch_checks->AddElementCheck(
+ result.selector,
base::BindOnce(&ElementPrecondition::OnCheckElementExists,
- weak_ptr_factory_.GetWeakPtr(), i);
- batch_checks->AddElementCheck(result.selector, std::move(callback));
+ weak_ptr_factory_.GetWeakPtr(), i));
}
batch_checks->AddAllDoneCallback(
base::BindOnce(&ElementPrecondition::OnAllElementChecksDone,
@@ -46,7 +46,8 @@ void ElementPrecondition::Check(
void ElementPrecondition::OnCheckElementExists(
size_t result_index,
- const ClientStatus& element_status) {
+ const ClientStatus& element_status,
+ const ElementFinder::Result& element_reference) {
if (result_index >= results_.size()) {
NOTREACHED();
return;
@@ -55,6 +56,7 @@ void ElementPrecondition::OnCheckElementExists(
result.match = element_status.ok();
// TODO(szermatt): Consider reporting element_status as an unexpected error
// right away if it is neither success nor ELEMENT_RESOLUTION_FAILED.
+ // TODO(b/171782156): Store the element, if the status is ok.
}
void ElementPrecondition::OnAllElementChecksDone(
diff --git a/chromium/components/autofill_assistant/browser/element_precondition.h b/chromium/components/autofill_assistant/browser/element_precondition.h
index 1a2c2718054..04e93c281df 100644
--- a/chromium/components/autofill_assistant/browser/element_precondition.h
+++ b/chromium/components/autofill_assistant/browser/element_precondition.h
@@ -14,6 +14,7 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
namespace autofill_assistant {
class BatchElementChecker;
@@ -53,7 +54,8 @@ class ElementPrecondition {
void AddResults(const ElementConditionProto& proto);
void OnCheckElementExists(size_t result_index,
- const ClientStatus& element_status);
+ const ClientStatus& element_status,
+ const ElementFinder::Result& element_reference);
void OnAllElementChecksDone(
base::OnceCallback<void(const ClientStatus&,
diff --git a/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc b/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc
index b9f1058c92a..598453402c7 100644
--- a/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc
@@ -5,8 +5,8 @@
#include "components/autofill_assistant/browser/script_precondition.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
@@ -23,25 +23,30 @@ namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
-using ::testing::Eq;
using ::testing::Property;
+using ::testing::WithArgs;
class ElementPreconditionTest : public testing::Test {
public:
void SetUp() override {
- ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_web_controller_, OnFindElement(Selector({"exists"}), _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
+ ON_CALL(mock_web_controller_, OnFindElement(Selector({"exists_too"}), _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
ON_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"exists_too"})), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ OnFindElement(Selector({"does_not_exist"}), _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
ON_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"does_not_exist"})), _))
- .WillByDefault(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
- ON_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"does_not_exist_either"})), _))
- .WillByDefault(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ OnFindElement(Selector({"does_not_exist_either"}), _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
}
protected:
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 4621f61729f..0d33bc828da 100644
--- a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -213,7 +213,7 @@ void FakeScriptExecutorDelegate::SetExpandSheetForPromptAction(bool expand) {
expand_sheet_for_prompt_ = expand;
}
-void FakeScriptExecutorDelegate::SetBrowseDomainsWhitelist(
+void FakeScriptExecutorDelegate::SetBrowseDomainsAllowlist(
std::vector<std::string> domains) {
browse_domains_ = std::move(domains);
}
@@ -246,4 +246,6 @@ void FakeScriptExecutorDelegate::SetOverlayBehavior(
void FakeScriptExecutorDelegate::SetBrowseModeInvisible(bool invisible) {}
+void FakeScriptExecutorDelegate::SetShowFeedbackChip(bool show_feedback_chip) {}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 00866a2dd8d..9773525cce6 100644
--- a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -86,7 +86,7 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
void AddListener(ScriptExecutorDelegate::Listener* listener) override;
void RemoveListener(ScriptExecutorDelegate::Listener* listener) override;
void SetExpandSheetForPromptAction(bool expand) override;
- void SetBrowseDomainsWhitelist(std::vector<std::string> domains) override;
+ void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
void SetGenericUi(
std::unique_ptr<GenericUserInterfaceProto> generic_ui,
base::OnceCallback<void(const ClientStatus&)> end_action_callback,
@@ -96,6 +96,7 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
void SetBrowseModeInvisible(bool invisible) override;
+ void SetShowFeedbackChip(bool show_feedback_chip) override;
ClientSettings* GetMutableSettings() { return &client_settings_; }
diff --git a/chromium/components/autofill_assistant/browser/features.cc b/chromium/components/autofill_assistant/browser/features.cc
index 943ab632ad6..8a93f1fbd01 100644
--- a/chromium/components/autofill_assistant/browser/features.cc
+++ b/chromium/components/autofill_assistant/browser/features.cc
@@ -16,8 +16,44 @@ const base::Feature kAutofillAssistant{"AutofillAssistant",
const base::Feature kAutofillAssistantChromeEntry{
"AutofillAssistantChromeEntry", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether to enable dialog onboarding for Autofill Assistant
+const base::Feature kAutofillAssistantDialogOnboarding{
+ "AutofillAssistantDialogOnboarding", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kAutofillAssistantDirectActions{
"AutofillAssistantDirectActions", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether to disable onboarding flow for Autofill Assistant
+const base::Feature kAutofillAssistantDisableOnboardingFlow{
+ "AutofillAssistantDisableOnboardingFlow",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether to show the "Send feedback" chip while in an error state.
+const base::Feature kAutofillAssistantFeedbackChip{
+ "AutofillAssistantFeedbackChip", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kAutofillAssistantProactiveHelp{
+ "AutofillAssistantProactiveHelp", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Use Chrome's TabHelper system to deal with the life cycle of WebContent's
+// depending Autofill Assistant objects.
+const base::Feature kAutofillAssistantWithTabHelper{
+ "AutofillAssistantWithTabHelper", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// By default, proactive help is only offered if MSBB is turned on. This feature
+// flag allows disabling the link. Proactive help can still be offered to users
+// so long as no communication to a remote backend is required. Specifically,
+// base64-injected trigger scripts can be shown even in the absence of MSBB.
+const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB{
+ "AutofillAssistantDisableProactiveHelpTiedToMSBB",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Whether autofill assistant should load the DFM for trigger scripts when
+// necessary. Without this feature, trigger scripts will exit if the DFM is not
+// available.
+const base::Feature kAutofillAssistantLoadDFMForTriggerScripts{
+ "AutofillAssistantLoadDFMForTriggerScripts",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/features.h b/chromium/components/autofill_assistant/browser/features.h
index 0bd543a3a26..d22f5808df0 100644
--- a/chromium/components/autofill_assistant/browser/features.h
+++ b/chromium/components/autofill_assistant/browser/features.h
@@ -15,7 +15,14 @@ namespace features {
// All features in alphabetical order.
extern const base::Feature kAutofillAssistant;
extern const base::Feature kAutofillAssistantChromeEntry;
+extern const base::Feature kAutofillAssistantDialogOnboarding;
extern const base::Feature kAutofillAssistantDirectActions;
+extern const base::Feature kAutofillAssistantDisableOnboardingFlow;
+extern const base::Feature kAutofillAssistantDisableProactiveHelpTiedToMSBB;
+extern const base::Feature kAutofillAssistantFeedbackChip;
+extern const base::Feature kAutofillAssistantLoadDFMForTriggerScripts;
+extern const base::Feature kAutofillAssistantProactiveHelp;
+extern const base::Feature kAutofillAssistantWithTabHelper;
} // namespace features
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/field_formatter.cc b/chromium/components/autofill_assistant/browser/field_formatter.cc
index 3f46888daac..4f93ef39b85 100644
--- a/chromium/components/autofill_assistant/browser/field_formatter.cc
+++ b/chromium/components/autofill_assistant/browser/field_formatter.cc
@@ -133,6 +133,14 @@ std::map<std::string, std::string> CreateAutofillMappings<autofill::CreditCard>(
AutofillFormatProto::CREDIT_CARD_NUMBER_LAST_FOUR_DIGITS))] =
last_four_digits;
}
+ int month;
+ if (base::StringToInt(
+ credit_card.GetInfo(autofill::CREDIT_CARD_EXP_MONTH, locale),
+ &month)) {
+ mappings[base::NumberToString(static_cast<int>(
+ AutofillFormatProto::CREDIT_CARD_NON_PADDED_EXP_MONTH))] =
+ base::NumberToString(month);
+ }
return mappings;
}
diff --git a/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc b/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
index 54fb90b2368..a59f5313f9b 100644
--- a/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
@@ -108,6 +108,11 @@ TEST(FieldFormatterTest, CreditCard) {
EXPECT_EQ(*FormatString("${-2} ${-5}",
CreateAutofillMappings(credit_card, "en-US")),
"visa Visa");
+
+ // CREDIT_CARD_NON_PADDED_EXP_MONTH
+ EXPECT_EQ(
+ *FormatString("${-7}", CreateAutofillMappings(credit_card, "en-US")),
+ "1");
}
TEST(FieldFormatterTest, SpecialCases) {
@@ -189,6 +194,7 @@ TEST(FieldFormatterTest, AddsAllProfileFields) {
TEST(FieldFormatterTest, AddsAllCreditCardFields) {
std::map<std::string, std::string> expected_values = {
+ {"-7", "8"},
{"-5", "Visa"},
{"-4", "1111"},
{"-2", "visa"},
diff --git a/chromium/components/autofill_assistant/browser/generic_ui.proto b/chromium/components/autofill_assistant/browser/generic_ui.proto
index 9334e057110..954033acdde 100644
--- a/chromium/components/autofill_assistant/browser/generic_ui.proto
+++ b/chromium/components/autofill_assistant/browser/generic_ui.proto
@@ -199,6 +199,7 @@ message AutofillFormatProto {
CREDIT_CARD_NETWORK_FOR_DISPLAY = -5;
// Currently only US states are supported. The state name is in lower case.
ADDRESS_HOME_STATE_NAME = -6;
+ CREDIT_CARD_NON_PADDED_EXP_MONTH = -7;
}
// The format string to use. May contain one or multiple "${key}"
// placeholders, where the key is an integer corresponding to
diff --git a/chromium/components/autofill_assistant/browser/metrics.cc b/chromium/components/autofill_assistant/browser/metrics.cc
index eb9bf9dccdc..09265d8673c 100644
--- a/chromium/components/autofill_assistant/browser/metrics.cc
+++ b/chromium/components/autofill_assistant/browser/metrics.cc
@@ -6,6 +6,8 @@
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
namespace autofill_assistant {
@@ -108,4 +110,34 @@ void Metrics::RecordPaymentRequestMandatoryPostalCode(bool required,
mandatory_postal_code);
}
+// static
+void Metrics::RecordLiteScriptFinished(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptFinishedState event) {
+ ukm::builders::AutofillAssistant_LiteScriptFinished(
+ ukm::GetSourceIdForWebContentsDocument(web_contents))
+ .SetLiteScriptFinished(static_cast<int64_t>(event))
+ .Record(ukm_recorder);
+}
+
+// static
+void Metrics::RecordLiteScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptShownToUser event) {
+ ukm::builders::AutofillAssistant_LiteScriptShownToUser(
+ ukm::GetSourceIdForWebContentsDocument(web_contents))
+ .SetLiteScriptShownToUser(static_cast<int64_t>(event))
+ .Record(ukm_recorder);
+}
+
+// static
+void Metrics::RecordLiteScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptOnboarding event) {
+ ukm::builders::AutofillAssistant_LiteScriptOnboarding(
+ ukm::GetSourceIdForWebContentsDocument(web_contents))
+ .SetLiteScriptOnboarding(static_cast<int64_t>(event))
+ .Record(ukm_recorder);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/metrics.h b/chromium/components/autofill_assistant/browser/metrics.h
index e73ec44b11b..acd5afc277e 100644
--- a/chromium/components/autofill_assistant/browser/metrics.h
+++ b/chromium/components/autofill_assistant/browser/metrics.h
@@ -6,10 +6,12 @@
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
#include <ostream>
+#include "content/public/browser/web_contents.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
namespace autofill_assistant {
-// A class to generate Autofill Assistant related histograms.
+// A class to generate Autofill Assistant metrics.
class Metrics {
public:
// The different ways that autofill assistant can stop.
@@ -49,11 +51,15 @@ class Metrics {
ONBOARDING_BACK_BUTTON_CLICKED = 23,
NAVIGATION_WHILE_RUNNING = 24,
UI_CLOSED_UNEXPECTEDLY = 25, // This is a "should never happen" entry.
+ ONBOARDING_NAVIGATION = 26,
+ ONBOARDING_DIALOG_DISMISSED = 27,
- kMaxValue = UI_CLOSED_UNEXPECTEDLY
+ kMaxValue = ONBOARDING_DIALOG_DISMISSED
};
- // The different ways that autofill assistant can stop.
+ // The different ways that autofill assistant can stop. Note that this only
+ // covers regular onboarding. Trigger script onboarding is covered by
+ // LiteScriptOnboarding.
//
// GENERATED_JAVA_ENUM_PACKAGE: (
// org.chromium.chrome.browser.autofill_assistant.metrics)
@@ -155,12 +161,23 @@ class Metrics {
// tools/metrics/ukm/ukm.xml as necessary.
enum class LiteScriptShownToUser {
// The number of times a lite script was successfully fetched and started.
+ // Can happen multiple times per run (in case of tab switch).
LITE_SCRIPT_RUNNING = 0,
- // The subset of |LITE_SCRIPT_RUNNING| where the lite script prompt was
- // shown.
+ // The number of times a lite script was shown to the user. Can happen
+ // multiple times per run.
LITE_SCRIPT_SHOWN_TO_USER = 1,
+ // Since Chrome M-88. The user tapped the 'not now' button. Can happen
+ // multiple times per run.
+ LITE_SCRIPT_NOT_NOW = 2,
+ // Since Chrome M-88. The lite script was automatically hidden due to the
+ // trigger condition no longer being true. Can happen multiple times per
+ // run.
+ LITE_SCRIPT_HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE = 3,
+ // Since Chrome M-88. The user swipe-dismissed the bottom sheet. Depending
+ // on configuration, this may happen multiple times per run.
+ LITE_SCRIPT_SWIPE_DISMISSED = 4,
- kMaxValue = LITE_SCRIPT_SHOWN_TO_USER
+ kMaxValue = LITE_SCRIPT_SWIPE_DISMISSED
};
// The different ways a user might have opted out of the lite script
@@ -178,19 +195,30 @@ class Metrics {
enum class LiteScriptStarted {
// Device did not have DFM downloaded.
LITE_SCRIPT_DFM_UNAVAILABLE = 0,
- // User has explicitly rejected the lite script two times and thus opted
- // out of the experience.
- LITE_SCRIPT_CANCELED_TWO_TIMES = 1,
- // User has rejected the onboarding and thus opted out of the experience.
- LITE_SCRIPT_ONBOARDING_REJECTED = 2,
// User has not seen the lite script before and will see first time
// experience.
LITE_SCRIPT_FIRST_TIME_USER = 3,
// User has seen the first-time experience before and will see returning
// user experience.
LITE_SCRIPT_RETURNING_USER = 4,
+ // Since Chrome M-88. The proactive trigger setting is disabled. The user
+ // has either chosen 'never show again' in the prompt or manually disabled
+ // the setting in Chrome settings.
+ LITE_SCRIPT_PROACTIVE_TRIGGERING_DISABLED = 5,
+ // Since Chrome M-88. Intended as a catch-all. This is reported as soon as a
+ // lite-script intent is received (of course, only for people with MSBB
+ // enabled).
+ LITE_SCRIPT_INTENT_RECEIVED = 6,
+
+ // DEPRECATED, only sent by Chrome M-86 and M-87.
+ //
+ // User has explicitly rejected the lite script two times and thus opted
+ // out of the experience.
+ LITE_SCRIPT_CANCELED_TWO_TIMES = 1,
+ // User has rejected the onboarding and thus opted out of the experience.
+ LITE_SCRIPT_ONBOARDING_REJECTED = 2,
- kMaxValue = LITE_SCRIPT_RETURNING_USER
+ kMaxValue = LITE_SCRIPT_INTENT_RECEIVED
};
// The different ways in which a lite script may finish.
@@ -205,31 +233,65 @@ class Metrics {
// tools/metrics/histograms/enums.xml and the description in
// tools/metrics/ukm/ukm.xml as necessary.
enum class LiteScriptFinishedState {
+ // Communication with backend failed.
+ LITE_SCRIPT_GET_ACTIONS_FAILED = 3,
+ // Failed to parse the proto sent by the backend.
+ LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR = 4,
+ // Lite script failed due to a navigation event to a non-allowed domain.
+ LITE_SCRIPT_PROMPT_FAILED_NAVIGATE = 9,
+ // Lite script succeeded. The user accepted the prompt.
+ LITE_SCRIPT_PROMPT_SUCCEEDED = 13,
+ // Since Chrome M-88. The user tapped the 'cancel for this session' button.
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION = 14,
+ // Since Chrome M-88. The user tapped the 'never show again' button.
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER = 15,
+ // Since Chrome M-88. The trigger script has timed out. This indicates that
+ // trigger conditions were evaluated for >= timeout without success. Time is
+ // only counted while the tab is visible and the lite script is invisible.
+ // The timeout resets on tab change.
+ LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT = 17,
+ // Since Chrome M-88. A navigation error occurred, leading to Chrome showing
+ // an error page.
+ LITE_SCRIPT_NAVIGATION_ERROR = 18,
+ // Since Chrome M-88. The tab was closed while the prompt was visible.
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE = 19,
+ // Since Chrome M-88. The tab was closed while the prompt was invisible.
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE = 20,
+ // Since Chrome M-88. The RPC to fetch the trigger scripts returned with an
+ // empty response.
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE = 21,
+ // Since Chrome M-88. The trigger script failed to show. This can happen,
+ // for example, if the activity was changed after triggering (e.g.,
+ // switching from CCT to regular tab).
+ LITE_SCRIPT_FAILED_TO_SHOW = 22,
+ // Since Chrome M-88. The proactive help switch was enabled at start, but
+ // then manually disabled in the Chrome settings.
+ LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING = 23,
+ // Since Chrome M-88. The client failed to base64-decode the trigger script
+ // specified in the script parameters.
+ LITE_SCRIPT_BASE64_DECODING_ERROR = 24,
+ // The user rejected the bottom sheet onboarding
+ LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED = 25,
+
+ // NOTE: All values in this block are DEPRECATED and will only be sent by
+ // Chrome M-86 and M-87.
+ //
// The lite script failed for an unknown reason.
LITE_SCRIPT_UNKNOWN_FAILURE = 0,
// Can happen when users close the tab or similar.
LITE_SCRIPT_SERVICE_DELETED = 1,
// |GetActions| was asked to retrieve a wrong script path.
LITE_SCRIPT_PATH_MISMATCH = 2,
- // Communication with backend failed.
- LITE_SCRIPT_GET_ACTIONS_FAILED = 3,
- // Failed to parse the proto response to |GetActions|.
- LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR = 4,
// One or multiple unsafe actions were contained in script.
LITE_SCRIPT_UNSAFE_ACTIONS = 5,
// The mini script is invalid. A valid script must contain a prompt
// (browse=true) action and end in a prompt(browse=false) action.
LITE_SCRIPT_INVALID_SCRIPT = 6,
-
// The prompt(browse) action failed due to a navigation event to a
- // non-whitelisted domain.
+ // non-allowed domain.
LITE_SCRIPT_BROWSE_FAILED_NAVIGATE = 7,
// The prompt(browse) action failed for an unknown reason.
LITE_SCRIPT_BROWSE_FAILED_OTHER = 8,
-
- // The prompt(regular) action failed due to a navigation event to a
- // non-whitelisted domain.
- LITE_SCRIPT_PROMPT_FAILED_NAVIGATE = 9,
// The prompt(regular) action failed because the condition to show it was no
// longer true.
LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE = 10,
@@ -237,11 +299,10 @@ class Metrics {
LITE_SCRIPT_PROMPT_FAILED_CLOSE = 11,
// The prompt(regular) action failed for an unknown reason.
LITE_SCRIPT_PROMPT_FAILED_OTHER = 12,
- // The prompt(regular) action succeeded because the user tapped the continue
- // chip.
- LITE_SCRIPT_PROMPT_SUCCEEDED = 13,
+ // Since Chrome M-88. The bottom sheet was swipe-dismissed by the user.
+ LITE_SCRIPT_PROMPT_SWIPE_DISMISSED = 16,
- kMaxValue = LITE_SCRIPT_PROMPT_SUCCEEDED
+ kMaxValue = LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED
};
// The different ways a user who has successfully completed a light script may
@@ -263,8 +324,12 @@ class Metrics {
LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED = 1,
// The user has already accepted the onboarding in the past.
LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED = 2,
+ // The user has seen and dismissed the onboarding.
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_DISMISSED = 3,
+ // The onboarding was interrupted by a website navigation.
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION = 4,
- kMaxValue = LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED
+ kMaxValue = LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION
};
static void RecordDropOut(DropOutReason reason);
@@ -275,6 +340,15 @@ class Metrics {
static void RecordPaymentRequestMandatoryPostalCode(bool required,
bool initially_right,
bool success);
+ static void RecordLiteScriptFinished(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptFinishedState event);
+ static void RecordLiteScriptShownToUser(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptShownToUser event);
+ static void RecordLiteScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+ content::WebContents* web_contents,
+ LiteScriptOnboarding event);
// Intended for debugging: writes string representation of |reason| to |out|.
friend std::ostream& operator<<(std::ostream& out,
@@ -364,6 +438,12 @@ class Metrics {
case DropOutReason::UI_CLOSED_UNEXPECTEDLY:
out << "UI_CLOSED_UNEXPECTEDLY";
break;
+ case DropOutReason::ONBOARDING_NAVIGATION:
+ out << "ONBOARDING_NAVIGATION";
+ break;
+ case DropOutReason::ONBOARDING_DIALOG_DISMISSED:
+ out << "ONBOARDING_DIALOG_DISMISSED";
+ break;
// Do not add default case to force compilation error for new values.
}
return out;
@@ -399,6 +479,101 @@ class Metrics {
return out;
#endif // NDEBUG
}
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const LiteScriptFinishedState& state) {
+#ifdef NDEBUG
+ // Non-debugging builds write the enum number.
+ out << static_cast<int>(state);
+ return out;
+#else
+ // Debugging builds write a string representation of |state|.
+ switch (state) {
+ case LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED:
+ out << "LITE_SCRIPT_GET_ACTIONS_FAILED";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR:
+ out << "LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE:
+ out << "LITE_SCRIPT_PROMPT_FAILED_NAVIGATE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED:
+ out << "LITE_SCRIPT_PROMPT_SUCCEEDED";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION:
+ out << "LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER:
+ out << "LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT:
+ out << "LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_NAVIGATION_ERROR:
+ out << "LITE_SCRIPT_NAVIGATION_ERROR";
+ break;
+ case LiteScriptFinishedState::
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE:
+ out << "LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE";
+ break;
+ case LiteScriptFinishedState::
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE:
+ out << "LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE:
+ out << "LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW:
+ out << "LITE_SCRIPT_FAILED_TO_SHOW";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING:
+ out << "LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_BASE64_DECODING_ERROR:
+ out << "LITE_SCRIPT_BASE64_DECODING_ERROR";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED:
+ out << "LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_UNKNOWN_FAILURE:
+ out << "LITE_SCRIPT_UNKNOWN_FAILURE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_SERVICE_DELETED:
+ out << "LITE_SCRIPT_SERVICE_DELETED";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PATH_MISMATCH:
+ out << "LITE_SCRIPT_PATH_MISMATCH";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_UNSAFE_ACTIONS:
+ out << "LITE_SCRIPT_UNSAFE_ACTIONS";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_INVALID_SCRIPT:
+ out << "LITE_SCRIPT_INVALID_SCRIPT";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_BROWSE_FAILED_NAVIGATE:
+ out << "LITE_SCRIPT_BROWSE_FAILED_NAVIGATE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_BROWSE_FAILED_OTHER:
+ out << "LITE_SCRIPT_BROWSE_FAILED_OTHER";
+ break;
+ case LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE:
+ out << "LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CLOSE:
+ out << "LITE_SCRIPT_PROMPT_FAILED_CLOSE";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_OTHER:
+ out << "LITE_SCRIPT_PROMPT_FAILED_OTHER";
+ break;
+ case LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SWIPE_DISMISSED:
+ out << "LITE_SCRIPT_PROMPT_SWIPE_DISMISSED";
+ // Do not add default case to force compilation error for new values.
+ }
+ return out;
+#endif // NDEBUG
+ }
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_client.h b/chromium/components/autofill_assistant/browser/mock_client.h
index 31b21538b55..9406e952d5a 100644
--- a/chromium/components/autofill_assistant/browser/mock_client.h
+++ b/chromium/components/autofill_assistant/browser/mock_client.h
@@ -31,14 +31,13 @@ class MockClient : public Client {
MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
MOCK_CONST_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
MOCK_CONST_METHOD0(GetWebsiteLoginManager, WebsiteLoginManager*());
- MOCK_CONST_METHOD0(GetPasswordManagerClient,
- password_manager::PasswordManagerClient*());
MOCK_METHOD0(GetAccessTokenFetcher, AccessTokenFetcher*());
MOCK_METHOD1(Shutdown, void(Metrics::DropOutReason reason));
MOCK_METHOD1(RecordDropOut, void(Metrics::DropOutReason reason));
MOCK_METHOD0(AttachUI, void());
MOCK_METHOD0(DestroyUI, void());
MOCK_CONST_METHOD0(HasHadUI, bool());
+ MOCK_CONST_METHOD0(IsFirstTimeTriggerScriptUser, bool());
private:
std::unique_ptr<MockPersonalDataManager> mock_personal_data_manager_;
diff --git a/chromium/components/autofill_assistant/browser/mock_client_context.cc b/chromium/components/autofill_assistant/browser/mock_client_context.cc
new file mode 100644
index 00000000000..1c989ab0867
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_client_context.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/mock_client_context.h"
+
+namespace autofill_assistant {
+
+MockClientContext::MockClientContext() = default;
+MockClientContext::~MockClientContext() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_client_context.h b/chromium/components/autofill_assistant/browser/mock_client_context.h
new file mode 100644
index 00000000000..cc9a593c55b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_client_context.h
@@ -0,0 +1,27 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_MOCK_CLIENT_CONTEXT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_CLIENT_CONTEXT_H_
+
+#include "components/autofill_assistant/browser/client_context.h"
+
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockClientContext : public ClientContext {
+ public:
+ MockClientContext();
+ ~MockClientContext() override;
+
+ MOCK_METHOD1(Update, void(const TriggerContext& trigger_context));
+ MOCK_CONST_METHOD0(AsProto, ClientContextProto());
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_CLIENT_CONTEXT_H_
diff --git a/chromium/components/autofill_assistant/browser/mock_controller_observer.h b/chromium/components/autofill_assistant/browser/mock_controller_observer.h
index cad2c442515..befc3ee9c4d 100644
--- a/chromium/components/autofill_assistant/browser/mock_controller_observer.h
+++ b/chromium/components/autofill_assistant/browser/mock_controller_observer.h
@@ -62,6 +62,7 @@ class MockControllerObserver : public ControllerObserver {
MOCK_METHOD1(OnGenericUserInterfaceChanged,
void(const GenericUserInterfaceProto* generic_ui));
MOCK_METHOD1(OnShouldShowOverlayChanged, void(bool should_show));
+ MOCK_METHOD0(OnFeedbackFormRequested, void());
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/model.proto b/chromium/components/autofill_assistant/browser/model.proto
index 7e3547ed105..e75b02ed96d 100644
--- a/chromium/components/autofill_assistant/browser/model.proto
+++ b/chromium/components/autofill_assistant/browser/model.proto
@@ -198,6 +198,13 @@ enum ProcessedActionStatusProto {
// generate more specific selectors. See SelectorProto::ProximityFilter.
TOO_MANY_CANDIDATES = 25;
+ // Evaluating the element did report an unexpected mismatch in either value
+ // or text.
+ ELEMENT_MISMATCH = 26;
+
+ // Another element covered the targeted element, when trying to click.
+ ELEMENT_NOT_ON_TOP = 27;
+
reserved 15, 23;
}
@@ -251,20 +258,29 @@ enum ChipType {
// HIGHLIGHTED_ACTION.
DONE_ACTION = 6;
+ // A "Send feedback" chip, which will show the feedback form when clicked.
+ //
+ // Note that when this is used inside a script, we will continue the script
+ // normally once the user has clicked the chip.
+ FEEDBACK_ACTION = 7;
+
reserved 2;
}
enum ChipIcon {
NO_ICON = 0;
- // https://icons.googleplex.com/#icon=ic_clear
+ // https://icons.googleplex.com/#icon=clear
ICON_CLEAR = 1;
- // https://icons.googleplex.com/#icon=ic_done
+ // https://icons.googleplex.com/#icon=done
ICON_DONE = 2;
- // https://icons.googleplex.com/#icon=ic_refresh
+ // https://icons.googleplex.com/#icon=refresh
ICON_REFRESH = 3;
+
+ // https://icons.googleplex.com/#icon=more_vert
+ ICON_OVERFLOW = 4;
}
// Defines a mapping to an Android Q direct action.
diff --git a/chromium/components/autofill_assistant/browser/onboarding_result.h b/chromium/components/autofill_assistant/browser/onboarding_result.h
new file mode 100644
index 00000000000..2db2c296546
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/onboarding_result.h
@@ -0,0 +1,31 @@
+// Copyright 2021 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_ASSISTANT_BROWSER_ONBOARDING_RESULT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ONBOARDING_RESULT_H_
+
+#include <string>
+
+namespace autofill_assistant {
+
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.chrome.browser.autofill_assistant)
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: AssistantOnboardingResult
+enum class OnboardingResult {
+ // The onboarding was dismissed. No explicit choice was made.
+ DISMISSED = 0,
+
+ // The onboarding was explicitly rejected.
+ REJECTED = 1,
+
+ // The onboarding was interrupted by a website navigation.
+ NAVIGATION = 2,
+
+ // THe onboarding was explicitly accepted.
+ ACCEPTED = 3,
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ONBOARDING_RESULT_H_
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils.cc b/chromium/components/autofill_assistant/browser/protocol_utils.cc
index aeda795e6e2..5ac0d397b97 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils.cc
+++ b/chromium/components/autofill_assistant/browser/protocol_utils.cc
@@ -13,8 +13,8 @@
#include "components/autofill_assistant/browser/actions/configure_bottom_sheet_action.h"
#include "components/autofill_assistant/browser/actions/configure_ui_state_action.h"
#include "components/autofill_assistant/browser/actions/expect_navigation_action.h"
-#include "components/autofill_assistant/browser/actions/focus_element_action.h"
#include "components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h"
+#include "components/autofill_assistant/browser/actions/get_element_status_action.h"
#include "components/autofill_assistant/browser/actions/highlight_element_action.h"
#include "components/autofill_assistant/browser/actions/navigate_action.h"
#include "components/autofill_assistant/browser/actions/popup_message_action.h"
@@ -24,6 +24,7 @@
#include "components/autofill_assistant/browser/actions/select_option_action.h"
#include "components/autofill_assistant/browser/actions/set_attribute_action.h"
#include "components/autofill_assistant/browser/actions/set_form_field_value_action.h"
+#include "components/autofill_assistant/browser/actions/show_cast_action.h"
#include "components/autofill_assistant/browser/actions/show_details_action.h"
#include "components/autofill_assistant/browser/actions/show_form_action.h"
#include "components/autofill_assistant/browser/actions/show_generic_ui_action.h"
@@ -149,6 +150,7 @@ std::string ProtocolUtils::CreateNextScriptActionsRequest(
const std::string& global_payload,
const std::string& script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
const ClientContextProto& client_context) {
ScriptActionRequestProto request_proto;
request_proto.set_global_payload(global_payload);
@@ -158,6 +160,7 @@ std::string ProtocolUtils::CreateNextScriptActionsRequest(
for (const auto& processed_action : processed_actions) {
next_request->add_processed_actions()->MergeFrom(processed_action);
}
+ *next_request->mutable_timing_stats() = timing_stats;
*request_proto.mutable_client_context() = client_context;
std::string serialized_request_proto;
bool success = request_proto.SerializeToString(&serialized_request_proto);
@@ -173,8 +176,8 @@ std::unique_ptr<Action> ProtocolUtils::CreateAction(ActionDelegate* delegate,
return std::make_unique<ClickAction>(delegate, action);
case ActionProto::ActionInfoCase::kTell:
return std::make_unique<TellAction>(delegate, action);
- case ActionProto::ActionInfoCase::kFocusElement:
- return std::make_unique<FocusElementAction>(delegate, action);
+ case ActionProto::ActionInfoCase::kShowCast:
+ return std::make_unique<ShowCastAction>(delegate, action);
case ActionProto::ActionInfoCase::kUseAddress:
return std::make_unique<UseAddressAction>(delegate, action);
case ActionProto::ActionInfoCase::kUseCard:
@@ -228,6 +231,8 @@ std::unique_ptr<Action> ProtocolUtils::CreateAction(ActionDelegate* delegate,
return std::make_unique<ConfigureUiStateAction>(delegate, action);
case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
return std::make_unique<PresaveGeneratedPasswordAction>(delegate, action);
+ case ActionProto::ActionInfoCase::kGetElementStatus:
+ return std::make_unique<GetElementStatusAction>(delegate, action);
case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
VLOG(1) << "Encountered action with ACTION_INFO_NOT_SET";
return std::make_unique<UnsupportedAction>(delegate, action);
@@ -281,4 +286,65 @@ bool ProtocolUtils::ParseActions(ActionDelegate* delegate,
return true;
}
+// static
+std::string ProtocolUtils::CreateGetTriggerScriptsRequest(
+ const GURL& url,
+ const ClientContextProto& client_context,
+ const std::map<std::string, std::string>& script_parameters) {
+ GetTriggerScriptsRequestProto request_proto;
+ request_proto.set_url(url.spec());
+ *request_proto.mutable_client_context() = client_context;
+ if (!script_parameters.empty()) {
+ AppendScriptParametersToRepeatedField(
+ script_parameters, request_proto.mutable_debug_script_parameters());
+ }
+
+ std::string serialized_request_proto;
+ bool success = request_proto.SerializeToString(&serialized_request_proto);
+ DCHECK(success);
+ return serialized_request_proto;
+}
+
+// static
+bool ProtocolUtils::ParseTriggerScripts(
+ const std::string& response,
+ std::vector<std::unique_ptr<TriggerScript>>* trigger_scripts,
+ std::vector<std::string>* additional_allowed_domains,
+ int* trigger_condition_check_interval_ms,
+ base::Optional<int>* timeout_ms) {
+ DCHECK(trigger_scripts);
+ DCHECK(additional_allowed_domains);
+ DCHECK(trigger_condition_check_interval_ms);
+ DCHECK(timeout_ms);
+
+ GetTriggerScriptsResponseProto response_proto;
+ if (!response_proto.ParseFromString(response)) {
+ LOG(ERROR) << "Failed to parse trigger scripts response";
+ return false;
+ }
+
+ for (auto& trigger_script_proto : *response_proto.mutable_trigger_scripts()) {
+ if (trigger_script_proto.user_interface().scroll_to_hide()) {
+ // Turn off viewport resizing when scroll to hide is on as it causes
+ // issues.
+ trigger_script_proto.mutable_user_interface()->set_resize_visual_viewport(
+ false);
+ }
+ trigger_scripts->emplace_back(
+ std::make_unique<TriggerScript>(trigger_script_proto));
+ }
+
+ for (const auto& allowed_domain :
+ response_proto.additional_allowed_domains()) {
+ additional_allowed_domains->emplace_back(allowed_domain);
+ }
+
+ *trigger_condition_check_interval_ms =
+ response_proto.trigger_condition_check_interval_ms();
+ if (response_proto.has_timeout_ms()) {
+ *timeout_ms = response_proto.timeout_ms();
+ }
+ return true;
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils.h b/chromium/components/autofill_assistant/browser/protocol_utils.h
index 11af7daa502..7642f1f7dc0 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils.h
+++ b/chromium/components/autofill_assistant/browser/protocol_utils.h
@@ -11,9 +11,11 @@
#include <string>
#include <vector>
+#include "base/optional.h"
#include "components/autofill_assistant/browser/actions/action.h"
#include "components/autofill_assistant/browser/script.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_scripts/trigger_script.h"
class GURL;
@@ -50,8 +52,15 @@ class ProtocolUtils {
const std::string& global_payload,
const std::string& script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
const ClientContextProto& client_context);
+ // Create request to get the available trigger scripts for |url|.
+ static std::string CreateGetTriggerScriptsRequest(
+ const GURL& url,
+ const ClientContextProto& client_context,
+ const std::map<std::string, std::string>& script_parameters);
+
// Create an action from the |action|.
static std::unique_ptr<Action> CreateAction(ActionDelegate* delegate,
const ActionProto& action);
@@ -73,6 +82,15 @@ class ProtocolUtils {
std::vector<std::unique_ptr<Script>>* scripts,
bool* should_update_scripts);
+ // Parse trigger scripts from the given |response| and insert them into
+ // |trigger_scripts|. Returns false if parsing failed, else true.
+ static bool ParseTriggerScripts(
+ const std::string& response,
+ std::vector<std::unique_ptr<TriggerScript>>* trigger_scripts,
+ std::vector<std::string>* additional_allowed_domains,
+ int* trigger_condition_check_interval_ms,
+ base::Optional<int>* timeout_ms);
+
private:
// To avoid instantiate this class by accident.
ProtocolUtils() = delete;
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc b/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
index 481d1377369..68e8b355f04 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -5,7 +5,10 @@
#include "components/autofill_assistant/browser/protocol_utils.h"
#include "base/macros.h"
+#include "base/optional.h"
+#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "url/gurl.h"
@@ -17,6 +20,8 @@ using ::testing::Eq;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::Pair;
+using ::testing::Pointee;
+using ::testing::Property;
using ::testing::SizeIs;
using ::testing::UnorderedElementsAreArray;
@@ -143,7 +148,7 @@ TEST_F(ProtocolUtilsTest, CreateNextScriptActionsRequest) {
EXPECT_TRUE(
request.ParseFromString(ProtocolUtils::CreateNextScriptActionsRequest(
"global_payload", "script_payload", processed_actions,
- client_context_proto_)));
+ RoundtripTimingStats(), client_context_proto_)));
AssertClientContext(request.client_context());
EXPECT_EQ(1, request.next_request().processed_actions().size());
@@ -321,5 +326,98 @@ TEST_F(ProtocolUtilsTest, ParseActionsUpdateScriptListFullFeatured) {
EXPECT_THAT("name", Eq(scripts[0]->handle.chip.text));
}
+TEST_F(ProtocolUtilsTest, ParseTriggerScriptsParseError) {
+ std::vector<std::unique_ptr<TriggerScript>> trigger_scripts;
+ std::vector<std::string> additional_allowed_domains;
+ int interval_ms;
+ base::Optional<int> timeout_ms;
+ EXPECT_FALSE(ProtocolUtils::ParseTriggerScripts("invalid", &trigger_scripts,
+ &additional_allowed_domains,
+ &interval_ms, &timeout_ms));
+ EXPECT_TRUE(trigger_scripts.empty());
+}
+
+TEST_F(ProtocolUtilsTest, CreateGetTriggerScriptsRequest) {
+ std::map<std::string, std::string> parameters = {{"key_a", "value_a"},
+ {"key_b", "value_b"}};
+
+ GetTriggerScriptsRequestProto request;
+ EXPECT_TRUE(
+ request.ParseFromString(ProtocolUtils::CreateGetTriggerScriptsRequest(
+ GURL("http://example.com/"), client_context_proto_, parameters)));
+
+ AssertClientContext(request.client_context());
+ AssertScriptParameters(request.debug_script_parameters(), parameters);
+ EXPECT_EQ("http://example.com/", request.url());
+}
+
+TEST_F(ProtocolUtilsTest, ParseTriggerScriptsValid) {
+ GetTriggerScriptsResponseProto proto;
+ proto.add_additional_allowed_domains("example.com");
+ proto.add_additional_allowed_domains("other-example.com");
+
+ proto.set_trigger_condition_check_interval_ms(2000);
+ proto.set_timeout_ms(500000);
+
+ TriggerScriptProto trigger_script_1;
+ *trigger_script_1.mutable_trigger_condition()->mutable_selector() =
+ ToSelectorProto("fake_element_1");
+ TriggerScriptProto trigger_script_2;
+
+ *proto.add_trigger_scripts() = trigger_script_1;
+ *proto.add_trigger_scripts() = trigger_script_2;
+
+ std::string proto_str;
+ proto.SerializeToString(&proto_str);
+
+ std::vector<std::unique_ptr<TriggerScript>> trigger_scripts;
+ std::vector<std::string> additional_allowed_domains;
+ int interval_ms;
+ base::Optional<int> timeout_ms;
+ EXPECT_TRUE(ProtocolUtils::ParseTriggerScripts(proto_str, &trigger_scripts,
+ &additional_allowed_domains,
+ &interval_ms, &timeout_ms));
+ EXPECT_THAT(
+ trigger_scripts,
+ ElementsAre(
+ Pointee(Property(&TriggerScript::AsProto, Eq(trigger_script_1))),
+ Pointee(Property(&TriggerScript::AsProto, Eq(trigger_script_2)))));
+ EXPECT_THAT(additional_allowed_domains,
+ ElementsAre("example.com", "other-example.com"));
+ EXPECT_EQ(interval_ms, 2000);
+ EXPECT_EQ(timeout_ms, 500000);
+}
+
+TEST_F(ProtocolUtilsTest, TurnOffResizeVisualViewport) {
+ GetTriggerScriptsResponseProto proto;
+
+ auto* script1 = proto.add_trigger_scripts();
+ script1->mutable_user_interface()->set_scroll_to_hide(true);
+ script1->mutable_user_interface()->set_resize_visual_viewport(true);
+
+ auto* script2 = proto.add_trigger_scripts();
+ script2->mutable_user_interface()->set_resize_visual_viewport(true);
+
+ std::string proto_str;
+ proto.SerializeToString(&proto_str);
+
+ std::vector<std::unique_ptr<TriggerScript>> trigger_scripts;
+ std::vector<std::string> additional_allowed_domains;
+ int interval_ms;
+ base::Optional<int> timeout_ms;
+ EXPECT_TRUE(ProtocolUtils::ParseTriggerScripts(proto_str, &trigger_scripts,
+ &additional_allowed_domains,
+ &interval_ms, &timeout_ms));
+ ASSERT_THAT(trigger_scripts, SizeIs(2));
+
+ EXPECT_TRUE(trigger_scripts[0]->AsProto().user_interface().scroll_to_hide());
+ EXPECT_FALSE(
+ trigger_scripts[0]->AsProto().user_interface().resize_visual_viewport());
+
+ EXPECT_FALSE(trigger_scripts[1]->AsProto().user_interface().scroll_to_hide());
+ EXPECT_TRUE(
+ trigger_scripts[1]->AsProto().user_interface().resize_visual_viewport());
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/public/runtime_manager.cc b/chromium/components/autofill_assistant/browser/public/runtime_manager.cc
index f86997d9e2c..75431db15d3 100644
--- a/chromium/components/autofill_assistant/browser/public/runtime_manager.cc
+++ b/chromium/components/autofill_assistant/browser/public/runtime_manager.cc
@@ -8,9 +8,14 @@
namespace autofill_assistant {
// static
-RuntimeManager* RuntimeManager::GetForWebContents(
+RuntimeManager* RuntimeManager::GetOrCreateForWebContents(
content::WebContents* contents) {
return RuntimeManagerImpl::GetForWebContents(contents);
}
+RuntimeManager* RuntimeManager::GetForWebContents(
+ content::WebContents* contents) {
+ return RuntimeManagerImpl::FromWebContents(contents);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/public/runtime_manager.h b/chromium/components/autofill_assistant/browser/public/runtime_manager.h
index 00dcd3e35bb..7eb9d25123c 100644
--- a/chromium/components/autofill_assistant/browser/public/runtime_manager.h
+++ b/chromium/components/autofill_assistant/browser/public/runtime_manager.h
@@ -18,6 +18,11 @@ class RuntimeManager {
// Returns the instance of RuntimeManager that was attached to the
// specified WebContents. Creates a new instance if no instance was attached
// to |contents| yet.
+ static RuntimeManager* GetOrCreateForWebContents(
+ content::WebContents* contents);
+
+ // Returns the instance of RuntimeManager that was attached to the
+ // specified WebContents. If no instance is attached method will return null.
static RuntimeManager* GetForWebContents(content::WebContents* contents);
// Add/Remove observers
diff --git a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
index 1cce94e137d..81c02dac7df 100644
--- a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
+++ b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
@@ -41,5 +41,9 @@ void RuntimeManagerImpl::SetUIState(UIState state) {
}
}
+base::WeakPtr<RuntimeManagerImpl> RuntimeManagerImpl::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
WEB_CONTENTS_USER_DATA_KEY_IMPL(RuntimeManagerImpl)
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.h b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.h
index 374ad28beec..8980d30b5af 100644
--- a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.h
+++ b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_IMPL_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_RUNTIME_MANAGER_IMPL_H_
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/autofill_assistant/browser/public/runtime_manager.h"
#include "components/autofill_assistant/browser/public/runtime_observer.h"
@@ -23,6 +24,8 @@ class RuntimeManagerImpl
static RuntimeManagerImpl* GetForWebContents(content::WebContents* contents);
~RuntimeManagerImpl() override;
+ RuntimeManagerImpl(const RuntimeManagerImpl&) = delete;
+ RuntimeManagerImpl& operator=(const RuntimeManagerImpl&) = delete;
// From RuntimeManager:
void AddObserver(RuntimeObserver* observer) override;
@@ -31,6 +34,8 @@ class RuntimeManagerImpl
virtual void SetUIState(UIState state);
+ base::WeakPtr<RuntimeManagerImpl> GetWeakPtr();
+
private:
friend class content::WebContentsUserData<RuntimeManagerImpl>;
friend class MockRuntimeManager;
@@ -43,6 +48,7 @@ class RuntimeManagerImpl
// Observers of Autofill Assistant's state.
base::ObserverList<RuntimeObserver> observers_;
+ base::WeakPtrFactory<RuntimeManagerImpl> weak_ptr_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
diff --git a/chromium/components/autofill_assistant/browser/retry_timer.cc b/chromium/components/autofill_assistant/browser/retry_timer.cc
index b28f418e16d..d63cc48412d 100644
--- a/chromium/components/autofill_assistant/browser/retry_timer.cc
+++ b/chromium/components/autofill_assistant/browser/retry_timer.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/numerics/clamped_math.h"
#include "components/autofill_assistant/browser/client_status.h"
diff --git a/chromium/components/autofill_assistant/browser/retry_timer.h b/chromium/components/autofill_assistant/browser/retry_timer.h
index 40b964040b5..dd86566a22f 100644
--- a/chromium/components/autofill_assistant/browser/retry_timer.h
+++ b/chromium/components/autofill_assistant/browser/retry_timer.h
@@ -51,7 +51,8 @@ class RetryTimer {
void Cancel();
// Returns true if the timer was started but did not report any results yet.
- bool running() { return on_done_ ? true : false; }
+ bool running() const { return on_done_ ? true : false; }
+ base::TimeDelta period() const { return period_; }
private:
void Reset();
diff --git a/chromium/components/autofill_assistant/browser/script_executor.cc b/chromium/components/autofill_assistant/browser/script_executor.cc
index ac8399cf5f7..0b3cd016c8a 100644
--- a/chromium/components/autofill_assistant/browser/script_executor.cc
+++ b/chromium/components/autofill_assistant/browser/script_executor.cc
@@ -10,22 +10,25 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/actions/action_delegate_util.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/protocol_utils.h"
#include "components/autofill_assistant/browser/self_delete_full_card_requester.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/wait_for_document_operation.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
#include "components/strings/grit/components_strings.h"
+#include "net/http/http_status_code.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill_assistant {
@@ -119,7 +122,7 @@ void ScriptExecutor::Run(const UserData* user_data,
{delegate_->GetTriggerContext(), additional_context_.get()}),
last_global_payload_, last_script_payload_,
base::BindOnce(&ScriptExecutor::OnGetActions,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
}
const UserData* ScriptExecutor::GetUserData() const {
@@ -186,7 +189,7 @@ bool ScriptExecutor::ShouldInterruptOnPause(const ActionProto& proto) {
return true;
case ActionProto::ActionInfoCase::kClick:
case ActionProto::ActionInfoCase::kTell:
- case ActionProto::ActionInfoCase::kFocusElement:
+ case ActionProto::ActionInfoCase::kShowCast:
case ActionProto::ActionInfoCase::kUseAddress:
case ActionProto::ActionInfoCase::kUseCard:
case ActionProto::ActionInfoCase::kWaitForDom:
@@ -210,6 +213,7 @@ bool ScriptExecutor::ShouldInterruptOnPause(const ActionProto& proto) {
case ActionProto::ActionInfoCase::kSaveGeneratedPassword:
case ActionProto::ActionInfoCase::kConfigureUiState:
case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
+ case ActionProto::ActionInfoCase::kGetElementStatus:
case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
return false;
}
@@ -269,7 +273,7 @@ void ScriptExecutor::RunElementChecks(BatchElementChecker* checker) {
void ScriptExecutor::ShortWaitForElement(
const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)> callback) {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
this, delegate_, delegate_->GetSettings().short_wait_for_element_deadline,
/* allow_interrupt= */ false,
@@ -286,7 +290,7 @@ void ScriptExecutor::WaitForDom(
base::RepeatingCallback<void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)>
check_elements,
- base::OnceCallback<void(const ClientStatus&)> callback) {
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
this, delegate_, max_wait_time, allow_interrupt, check_elements,
base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleWithInterrupts,
@@ -311,16 +315,18 @@ std::string ScriptExecutor::GetBubbleMessage() {
}
void ScriptExecutor::FindElement(const Selector& selector,
- ElementFinder::Callback callback) {
+ ElementFinder::Callback callback) const {
+ DCHECK(!selector.empty());
+ VLOG(3) << __func__ << " " << selector;
delegate_->GetWebController()->FindElement(selector, /* strict_mode= */ true,
std::move(callback));
}
-void ScriptExecutor::WaitForDocumentToBecomeInteractive(
- const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- delegate_->GetWebController()->WaitForDocumentToBecomeInteractive(
- element, std::move(callback));
+void ScriptExecutor::FindAllElements(const Selector& selector,
+ ElementFinder::Callback callback) const {
+ DCHECK(!selector.empty());
+ VLOG(3) << __func__ << " " << selector;
+ delegate_->GetWebController()->FindAllElements(selector, std::move(callback));
}
void ScriptExecutor::ScrollIntoView(
@@ -329,6 +335,21 @@ void ScriptExecutor::ScrollIntoView(
delegate_->GetWebController()->ScrollIntoView(element, std::move(callback));
}
+void ScriptExecutor::WaitUntilElementIsStable(
+ int max_rounds,
+ base::TimeDelta check_interval,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ delegate_->GetWebController()->WaitUntilElementIsStable(
+ element, max_rounds, check_interval, std::move(callback));
+}
+
+void ScriptExecutor::CheckOnTop(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ delegate_->GetWebController()->CheckOnTop(element, std::move(callback));
+}
+
void ScriptExecutor::ClickOrTapElement(
ClickType click_type,
const ElementFinder::Result& element,
@@ -477,9 +498,9 @@ void ScriptExecutor::CleanUpAfterPrompt() {
delegate_->EnterState(AutofillAssistantState::RUNNING);
}
-void ScriptExecutor::SetBrowseDomainsWhitelist(
+void ScriptExecutor::SetBrowseDomainsAllowlist(
std::vector<std::string> domains) {
- delegate_->SetBrowseDomainsWhitelist(std::move(domains));
+ delegate_->SetBrowseDomainsAllowlist(std::move(domains));
}
void ScriptExecutor::OnChosen(UserAction::Callback callback,
@@ -526,20 +547,20 @@ void ScriptExecutor::SelectOption(
}
void ScriptExecutor::HighlightElement(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- delegate_->GetWebController()->HighlightElement(selector,
- std::move(callback));
+ delegate_->GetWebController()->HighlightElement(element, std::move(callback));
}
-void ScriptExecutor::FocusElement(
+void ScriptExecutor::ScrollToElementPosition(
const Selector& selector,
const TopPadding& top_padding,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
last_focused_element_selector_ = selector;
last_focused_element_top_padding_ = top_padding;
- delegate_->GetWebController()->FocusElement(selector, top_padding,
- std::move(callback));
+ delegate_->GetWebController()->ScrollToElementPosition(element, top_padding,
+ std::move(callback));
}
void ScriptExecutor::SetTouchableElementArea(
@@ -575,21 +596,27 @@ void ScriptExecutor::SetStepProgressBarConfiguration(
}
void ScriptExecutor::GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback) {
+ delegate_->GetWebController()->GetFieldValue(element, std::move(callback));
+}
+
+void ScriptExecutor::GetStringAttribute(
+ const std::vector<std::string>& attributes,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
- delegate_->GetWebController()->GetFieldValue(selector, std::move(callback));
+ delegate_->GetWebController()->GetStringAttribute(element, attributes,
+ std::move(callback));
}
-void ScriptExecutor::SetFieldValue(
+void ScriptExecutor::SetValueAttribute(
const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- delegate_->GetWebController()->SetFieldValue(element, value, fill_strategy,
- key_press_delay_in_millisecond,
- std::move(callback));
+ delegate_->GetWebController()->SetValueAttribute(element, value,
+ std::move(callback));
}
void ScriptExecutor::SetAttribute(
@@ -601,6 +628,18 @@ void ScriptExecutor::SetAttribute(
std::move(callback));
}
+void ScriptExecutor::SelectFieldValue(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ delegate_->GetWebController()->SelectFieldValue(element, std::move(callback));
+}
+
+void ScriptExecutor::FocusField(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ delegate_->GetWebController()->FocusField(element, std::move(callback));
+}
+
void ScriptExecutor::SendKeyboardInput(
const std::vector<UChar32>& codepoints,
int key_press_delay_in_millisecond,
@@ -611,10 +650,17 @@ void ScriptExecutor::SendKeyboardInput(
}
void ScriptExecutor::GetOuterHtml(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
- delegate_->GetWebController()->GetOuterHtml(selector, std::move(callback));
+ delegate_->GetWebController()->GetOuterHtml(element, std::move(callback));
+}
+
+void ScriptExecutor::GetOuterHtmls(
+ const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback) {
+ delegate_->GetWebController()->GetOuterHtmls(elements, std::move(callback));
}
void ScriptExecutor::GetElementTag(
@@ -656,31 +702,56 @@ bool ScriptExecutor::WaitForNavigation(
}
void ScriptExecutor::GetDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) {
- delegate_->GetWebController()->GetDocumentReadyState(optional_frame,
+ delegate_->GetWebController()->GetDocumentReadyState(optional_frame_element,
std::move(callback));
}
void ScriptExecutor::WaitForDocumentReadyState(
- const Selector& optional_frame,
+ base::TimeDelta max_wait_time,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) {
- delegate_->GetWebController()->WaitForDocumentReadyState(
- optional_frame, min_ready_state, std::move(callback));
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) {
+ current_action_data_.wait_for_document =
+ std::make_unique<WaitForDocumentOperation>(
+ delegate_, max_wait_time, min_ready_state, optional_frame_element,
+ std::move(callback));
+ current_action_data_.wait_for_document->Run();
+}
+
+void ScriptExecutor::WaitUntilDocumentIsInReadyState(
+ base::TimeDelta max_wait_time,
+ DocumentReadyState min_ready_state,
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ WaitForDocumentReadyState(
+ max_wait_time, min_ready_state, optional_frame_element,
+ base::BindOnce(&ScriptExecutor::OnWaitForDocumentReadyState,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void ScriptExecutor::OnWaitForDocumentReadyState(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status,
+ DocumentReadyState ready_state,
+ base::TimeDelta wait_time) {
+ std::move(callback).Run(status);
}
void ScriptExecutor::LoadURL(const GURL& url) {
delegate_->GetWebController()->LoadURL(url);
}
-void ScriptExecutor::Shutdown() {
+void ScriptExecutor::Shutdown(bool show_feedback_chip) {
// The following handles the case where scripts end with tell + stop
// differently from just stop. TODO(b/806868): Make that difference explicit:
// add an optional message to stop and update the scripts to use that.
if (previous_action_type_ == ActionProto::kTell) {
+ delegate_->SetShowFeedbackChip(show_feedback_chip);
at_end_ = SHUTDOWN_GRACEFULLY;
} else {
at_end_ = SHUTDOWN;
@@ -754,7 +825,7 @@ void ScriptExecutor::WaitForWindowHeightChange(
delegate_->GetWebController()->WaitForWindowHeightChange(std::move(callback));
}
-const ClientSettings& ScriptExecutor::GetSettings() {
+const ClientSettings& ScriptExecutor::GetSettings() const {
return delegate_->GetSettings();
}
@@ -788,13 +859,19 @@ void ScriptExecutor::SetOverlayBehavior(
delegate_->SetOverlayBehavior(overlay_behavior);
}
-base::WeakPtr<ActionDelegate> ScriptExecutor::GetWeakPtr() {
+base::WeakPtr<ActionDelegate> ScriptExecutor::GetWeakPtr() const {
return weak_ptr_factory_.GetWeakPtr();
}
-void ScriptExecutor::OnGetActions(bool result, const std::string& response) {
- bool success = result && ProcessNextActionResponse(response);
- VLOG(2) << __func__ << " result=" << result;
+void ScriptExecutor::OnGetActions(base::TimeTicks start_time,
+ int http_status,
+ const std::string& response) {
+ VLOG(2) << __func__ << " http-status=" << http_status;
+ batch_start_time_ = base::TimeTicks::Now();
+ roundtrip_timing_stats_.set_roundtrip_time_ms(
+ (batch_start_time_ - start_time).InMilliseconds());
+ bool success =
+ http_status == net::HTTP_OK && ProcessNextActionResponse(response);
if (should_stop_script_) {
// The last action forced the script to stop. Sending the result of the
// action is considered best effort in this situation. Report a successful
@@ -917,12 +994,20 @@ void ScriptExecutor::ProcessAction(Action* action) {
}
void ScriptExecutor::GetNextActions() {
+ base::TimeTicks get_next_actions_start = base::TimeTicks::Now();
+ roundtrip_timing_stats_.set_client_time_ms(
+ (get_next_actions_start - batch_start_time_).InMilliseconds());
+ VLOG(2) << "Batch timing stats";
+ VLOG(2) << "Roundtrip time: " << roundtrip_timing_stats_.roundtrip_time_ms();
+ VLOG(2) << "Client execution time: "
+ << roundtrip_timing_stats_.client_time_ms();
delegate_->GetService()->GetNextActions(
MergedTriggerContext(
{delegate_->GetTriggerContext(), additional_context_.get()}),
last_global_payload_, last_script_payload_, processed_actions_,
+ roundtrip_timing_stats_,
base::BindOnce(&ScriptExecutor::OnGetActions,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), get_next_actions_start));
}
void ScriptExecutor::OnProcessedAction(
@@ -932,6 +1017,18 @@ void ScriptExecutor::OnProcessedAction(
previous_action_type_ = processed_action_proto->action().action_info_case();
processed_actions_.emplace_back(*processed_action_proto);
+#ifdef NDEBUG
+ VLOG(2) << "Action completed";
+#else
+ VLOG(2) << "Requested delay ms: "
+ << processed_action_proto->timing_stats().delay_ms();
+ VLOG(2) << "Active time ms: "
+ << processed_action_proto->timing_stats().active_time_ms();
+ VLOG(2) << "Wait time ms: "
+ << processed_action_proto->timing_stats().wait_time_ms();
+ VLOG(2) << "Run time: " << run_time;
+#endif
+
auto& processed_action = processed_actions_.back();
processed_action.set_run_time_ms(run_time.InMilliseconds());
processed_action.set_direct_action(current_action_data_.direct_action);
@@ -939,13 +1036,6 @@ void ScriptExecutor::OnProcessedAction(
current_action_data_.navigation_info;
if (processed_action.status() != ProcessedActionStatusProto::ACTION_APPLIED) {
- if (delegate_->HasNavigationError()) {
- // Overwrite the original error, as the root cause is most likely a
- // navigation error.
- processed_action.mutable_status_details()->set_original_status(
- processed_action.status());
- processed_action.set_status(ProcessedActionStatusProto::NAVIGATION_ERROR);
- }
VLOG(1) << "Action failed: " << processed_action.status();
// Remove unexecuted actions, this will cause the |ProcessNextActions| call
// to immediately ask for new actions.
@@ -958,36 +1048,48 @@ void ScriptExecutor::CheckElementMatches(
const Selector& selector,
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> callback) {
- checker->AddElementCheck(selector, std::move(callback));
+ checker->AddElementCheck(
+ selector,
+ base::BindOnce(&ScriptExecutor::CheckElementMatchesCallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
-void ScriptExecutor::OnShortWaitForElement(
+void ScriptExecutor::CheckElementMatchesCallback(
base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status,
+ const ElementFinder::Result& ignored_element) {
+ std::move(callback).Run(status);
+}
+
+void ScriptExecutor::OnShortWaitForElement(
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback,
const ClientStatus& element_status,
- const Result* interrupt_result) {
+ const Result* interrupt_result,
+ base::TimeDelta wait_time) {
// Interrupts cannot run, so should never be reported.
DCHECK(!interrupt_result);
- std::move(callback).Run(element_status);
+ std::move(callback).Run(element_status, wait_time);
}
void ScriptExecutor::OnWaitForElementVisibleWithInterrupts(
- base::OnceCallback<void(const ClientStatus&)> callback,
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback,
const ClientStatus& element_status,
- const Result* interrupt_result) {
+ const Result* interrupt_result,
+ base::TimeDelta wait_time) {
if (interrupt_result) {
if (!interrupt_result->success) {
- std::move(callback).Run(ClientStatus(INTERRUPT_FAILED));
+ std::move(callback).Run(ClientStatus(INTERRUPT_FAILED), wait_time);
return;
}
if (interrupt_result->at_end != CONTINUE) {
at_end_ = interrupt_result->at_end;
should_stop_script_ = true;
- std::move(callback).Run(ClientStatus(MANUAL_FALLBACK));
+ std::move(callback).Run(ClientStatus(MANUAL_FALLBACK), wait_time);
return;
}
}
- std::move(callback).Run(element_status);
+ std::move(callback).Run(element_status, wait_time);
}
ScriptExecutor::WaitForDomOperation::WaitForDomOperation(
@@ -1014,6 +1116,7 @@ ScriptExecutor::WaitForDomOperation::~WaitForDomOperation() {
void ScriptExecutor::WaitForDomOperation::Run() {
delegate_->AddNavigationListener(this);
+ wait_time_stopwatch_.Start();
Start();
}
@@ -1066,6 +1169,16 @@ void ScriptExecutor::WaitForDomOperation::OnScriptListChanged(
void ScriptExecutor::WaitForDomOperation::RunChecks(
base::OnceCallback<void(const ClientStatus&)> report_attempt_result) {
+ wait_time_total_ =
+ (wait_time_stopwatch_.TotalElapsed() < retry_timer_.period())
+ // It's the first run of the checks, set the total time waited to 0.
+ ? base::TimeDelta::FromSeconds(0)
+ // If this is not the first run of the checks, in order to estimate
+ // the real cost of periodic checks, half the duration of the retry
+ // timer period is removed from the total wait time. This is to
+ // account for the fact that the conditions could have been satisfied
+ // at any point between the two consecutive checks.
+ : wait_time_stopwatch_.TotalElapsed() - retry_timer_.period() / 2;
// Reset state possibly left over from previous runs.
element_check_result_ = ClientStatus();
runnable_interrupts_.clear();
@@ -1185,7 +1298,7 @@ void ScriptExecutor::WaitForDomOperation::RunCallbackWithResult(
if (!callback_)
return;
- std::move(callback_).Run(element_status, result);
+ std::move(callback_).Run(element_status, result, wait_time_total_);
}
void ScriptExecutor::WaitForDomOperation::SavePreInterruptState() {
@@ -1208,9 +1321,21 @@ void ScriptExecutor::WaitForDomOperation::RestorePreInterruptScroll() {
return;
if (!main_script_->last_focused_element_selector_.empty()) {
- delegate_->GetWebController()->FocusElement(
+ auto actions =
+ std::make_unique<action_delegate_util::ElementActionVector>();
+ actions->emplace_back(
+ base::BindOnce(&ActionDelegate::WaitUntilDocumentIsInReadyState,
+ main_script_->GetWeakPtr(),
+ delegate_->GetSettings().document_ready_check_timeout,
+ DOCUMENT_INTERACTIVE));
+ actions->emplace_back(base::BindOnce(
+ &ActionDelegate::ScrollToElementPosition, main_script_->GetWeakPtr(),
main_script_->last_focused_element_selector_,
- main_script_->last_focused_element_top_padding_, base::DoNothing());
+ main_script_->last_focused_element_top_padding_));
+ action_delegate_util::FindElementAndPerform(
+ main_script_, main_script_->last_focused_element_selector_,
+ base::BindOnce(&action_delegate_util::PerformAll, std::move(actions)),
+ base::DoNothing());
}
}
diff --git a/chromium/components/autofill_assistant/browser/script_executor.h b/chromium/components/autofill_assistant/browser/script_executor.h
index 4746e821c8d..69dfe8d7170 100644
--- a/chromium/components/autofill_assistant/browser/script_executor.h
+++ b/chromium/components/autofill_assistant/browser/script_executor.h
@@ -29,6 +29,7 @@
namespace autofill_assistant {
class UserModel;
+class WaitForDocumentOperation;
// Class to execute an assistant script.
class ScriptExecutor : public ActionDelegate,
@@ -74,7 +75,7 @@ class ScriptExecutor : public ActionDelegate,
// Shut down Autofill Assistant.
SHUTDOWN,
- // Shut down Autofill Assistant after a delay.
+ // Stop Autofill Assistant but keep showing the UI.
SHUTDOWN_GRACEFULLY,
// Shut down Autofill Assistant and CCT.
@@ -110,24 +111,33 @@ class ScriptExecutor : public ActionDelegate,
void RunElementChecks(BatchElementChecker* checker) override;
void ShortWaitForElement(
const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)> callback) override;
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback)
+ override;
void WaitForDom(
base::TimeDelta max_wait_time,
bool allow_interrupt,
base::RepeatingCallback<
void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)> check_elements,
- base::OnceCallback<void(const ClientStatus&)> callback) override;
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback)
+ override;
void SetStatusMessage(const std::string& message) override;
std::string GetStatusMessage() override;
void SetBubbleMessage(const std::string& message) override;
std::string GetBubbleMessage() override;
void FindElement(const Selector& selector,
- ElementFinder::Callback callback) override;
- void WaitForDocumentToBecomeInteractive(
+ ElementFinder::Callback callback) const override;
+ void FindAllElements(const Selector& selector,
+ ElementFinder::Callback callback) const override;
+ void ScrollIntoView(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
- void ScrollIntoView(
+ void WaitUntilElementIsStable(
+ int max_rounds,
+ base::TimeDelta check_interval,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) override;
+ void CheckOnTop(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
void ClickOrTapElement(
@@ -150,7 +160,7 @@ class ScriptExecutor : public ActionDelegate,
bool browse_mode,
bool browse_mode_invisible) override;
void CleanUpAfterPrompt() override;
- void SetBrowseDomainsWhitelist(std::vector<std::string> domains) override;
+ void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
void FillAddressForm(
const autofill::AutofillProfile* profile,
const Selector& selector,
@@ -172,22 +182,26 @@ class ScriptExecutor : public ActionDelegate,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
void HighlightElement(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
- void FocusElement(
+ void ScrollToElementPosition(
const Selector& selector,
const TopPadding& top_padding,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
void SetTouchableElementArea(
const ElementAreaProto& touchable_element_area) override;
void GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override;
- void SetFieldValue(
+ void GetStringAttribute(
+ const std::vector<std::string>& attributes,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback) override;
+ void SetValueAttribute(
const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
void SetAttribute(
@@ -195,15 +209,25 @@ class ScriptExecutor : public ActionDelegate,
const std::string& value,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
+ void SelectFieldValue(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) override;
+ void FocusField(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) override;
void SendKeyboardInput(
const std::vector<UChar32>& codepoints,
int key_press_delay_in_millisecond,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) override;
void GetOuterHtml(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override;
+ void GetOuterHtmls(const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)>
+ callback) override;
void GetElementTag(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
@@ -212,17 +236,24 @@ class ScriptExecutor : public ActionDelegate,
bool ExpectedNavigationHasStarted() override;
bool WaitForNavigation(base::OnceCallback<void(bool)> callback) override;
void GetDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) override;
void WaitForDocumentReadyState(
- const Selector& optional_frame,
+ base::TimeDelta max_wait_time,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) override;
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) override;
+ void WaitUntilDocumentIsInReadyState(
+ base::TimeDelta max_wait_time,
+ DocumentReadyState min_ready_state,
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&)> callback) override;
void LoadURL(const GURL& url) override;
- void Shutdown() override;
+ void Shutdown(bool show_feedback_chip) override;
void Close() override;
autofill::PersonalDataManager* GetPersonalDataManager() override;
WebsiteLoginManager* GetWebsiteLoginManager() override;
@@ -249,7 +280,7 @@ class ScriptExecutor : public ActionDelegate,
void CollapseBottomSheet() override;
void WaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback) override;
- const ClientSettings& GetSettings() override;
+ const ClientSettings& GetSettings() const override;
bool SetForm(
std::unique_ptr<FormProto> form,
base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
@@ -263,7 +294,7 @@ class ScriptExecutor : public ActionDelegate,
void ClearGenericUi() override;
void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
- base::WeakPtr<ActionDelegate> GetWeakPtr() override;
+ base::WeakPtr<ActionDelegate> GetWeakPtr() const override;
private:
// Helper for WaitForElementVisible that keeps track of the state required to
@@ -277,7 +308,8 @@ class ScriptExecutor : public ActionDelegate,
// If the given result is non-null, it should be forwarded as the result of
// the main script.
using Callback = base::OnceCallback<void(const ClientStatus&,
- const ScriptExecutor::Result*)>;
+ const ScriptExecutor::Result*,
+ base::TimeDelta)>;
// |main_script_| must not be null and outlive this instance.
WaitForDomOperation(
@@ -350,6 +382,9 @@ class ScriptExecutor : public ActionDelegate,
// An empty vector of interrupts that can be passed to interrupt_executor_
// and outlives it. Interrupts must not run interrupts.
const std::vector<std::unique_ptr<Script>> no_interrupts_;
+ Stopwatch wait_time_stopwatch_;
+ Stopwatch period_stopwatch_;
+ base::TimeDelta wait_time_total_;
// The interrupt that's currently running.
std::unique_ptr<ScriptExecutor> interrupt_executor_;
@@ -372,7 +407,9 @@ class ScriptExecutor : public ActionDelegate,
DISALLOW_COPY_AND_ASSIGN(WaitForDomOperation);
};
- void OnGetActions(bool result, const std::string& response);
+ void OnGetActions(base::TimeTicks start_time,
+ int http_status,
+ const std::string& response);
bool ProcessNextActionResponse(const std::string& response);
void ReportPayloadsToListener();
void ReportScriptsUpdateToListener(
@@ -388,14 +425,20 @@ class ScriptExecutor : public ActionDelegate,
const Selector& selector,
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> callback);
- void OnShortWaitForElement(
+ void CheckElementMatchesCallback(
base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status,
+ const ElementFinder::Result& ignored_element);
+ void OnShortWaitForElement(
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback,
const ClientStatus& element_status,
- const Result* interrupt_result);
+ const Result* interrupt_result,
+ base::TimeDelta wait_time);
void OnWaitForElementVisibleWithInterrupts(
- base::OnceCallback<void(const ClientStatus&)> callback,
+ base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback,
const ClientStatus& element_status,
- const Result* interrupt_result);
+ const Result* interrupt_result,
+ base::TimeDelta wait_time);
void OnGetUserData(
base::OnceCallback<void(UserData*, const UserModel*)> callback,
UserData* user_data,
@@ -415,6 +458,11 @@ class ScriptExecutor : public ActionDelegate,
const base::string16& cvc);
void OnChosen(UserAction::Callback callback,
std::unique_ptr<TriggerContext> context);
+ void OnWaitForDocumentReadyState(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status,
+ DocumentReadyState ready_state,
+ base::TimeDelta wait_time);
void OnResume();
// Actions that can manipulate the UserActions should be interrupted, such
@@ -476,6 +524,7 @@ class ScriptExecutor : public ActionDelegate,
NavigationInfoProto navigation_info;
std::unique_ptr<WaitForDomOperation> wait_for_dom;
+ std::unique_ptr<WaitForDocumentOperation> wait_for_document;
// Set to true when a direct action was used to trigger a UserAction within
// a prompt. This is reported to the backend.
@@ -493,6 +542,9 @@ class ScriptExecutor : public ActionDelegate,
bool is_paused_ = false;
std::string last_status_message_;
+ base::TimeTicks batch_start_time_;
+ RoundtripTimingStats roundtrip_timing_stats_;
+
base::WeakPtrFactory<ScriptExecutor> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ScriptExecutor);
};
diff --git a/chromium/components/autofill_assistant/browser/script_executor_delegate.h b/chromium/components/autofill_assistant/browser/script_executor_delegate.h
index 1375e3b9c90..0d4b0786a12 100644
--- a/chromium/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/chromium/components/autofill_assistant/browser/script_executor_delegate.h
@@ -115,6 +115,7 @@ class ScriptExecutorDelegate {
base::OnceCallback<void(const ClientStatus&)> cancel_callback) = 0;
virtual UserModel* GetUserModel() = 0;
virtual EventHandler* GetEventHandler() = 0;
+ virtual void SetShowFeedbackChip(bool show_feedback_chip) = 0;
// Makes no area of the screen touchable.
void ClearTouchableElementArea() {
@@ -170,8 +171,8 @@ class ScriptExecutorDelegate {
// Set how the sheet should behave when entering a prompt state.
virtual void SetExpandSheetForPromptAction(bool expand) = 0;
- // Set the domains whitelist for browse mode.
- virtual void SetBrowseDomainsWhitelist(std::vector<std::string> domains) = 0;
+ // Set the domains allowlist for browse mode.
+ virtual void SetBrowseDomainsAllowlist(std::vector<std::string> domains) = 0;
// Sets the generic UI to show to the user.
virtual void SetGenericUi(
diff --git a/chromium/components/autofill_assistant/browser/script_executor_unittest.cc b/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
index 77fdaa0e495..a383d2e7c7e 100644
--- a/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -11,10 +11,12 @@
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
-#include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/mock_service.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "net/http/http_status_code.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -41,6 +43,7 @@ using ::testing::SaveArg;
using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::StrictMock;
+using ::testing::WithArgs;
const char* kScriptPath = "script_path";
@@ -62,17 +65,19 @@ class ScriptExecutorTest : public testing::Test,
/* listener= */ this, &scripts_state_, &ordered_interrupts_,
/* delegate= */ &delegate_);
- // In this test, "tell" actions always succeed and "click" actions,
- // preceded by finding the element, always fail. The following makes a
- // click action fail immediately
- ON_CALL(mock_web_controller_, OnFindElement(_, _))
- .WillByDefault(RunOnceCallback<1>(
- ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ test_util::MockFindAnyElement(mock_web_controller_);
- ON_CALL(mock_web_controller_, OnElementCheck(_, _))
+ // In this test, "tell" actions always succeed and "click" actions,
+ // always fail. The following makes a click action fail.
+ ON_CALL(mock_web_controller_, OnWaitForDocumentReadyState(_, _, _))
+ .WillByDefault(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_COMPLETE,
+ base::TimeDelta::FromSeconds(0)));
+ ON_CALL(mock_web_controller_, OnScrollIntoView(_, _))
.WillByDefault(RunOnceCallback<1>(OkClientStatus()));
- ON_CALL(mock_web_controller_, OnFocusElement(_, _, _))
- .WillByDefault(RunOnceCallback<2>(OkClientStatus()));
+ ON_CALL(mock_web_controller_, WaitUntilElementIsStable(_, _, _, _))
+ .WillByDefault(RunOnceCallback<3>(OkClientStatus()));
+ ON_CALL(mock_web_controller_, OnClickOrTapElement(_, _))
+ .WillByDefault(RunOnceCallback<1>(ClientStatus(UNEXPECTED_JS_ERROR)));
}
protected:
@@ -112,7 +117,8 @@ class ScriptExecutorTest : public testing::Test,
wait_action->set_allow_interrupt(true);
interruptible.add_actions()->mutable_tell()->set_message(path);
EXPECT_CALL(mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
}
// Creates an interrupt that contains a tell. It will always succeed.
@@ -122,7 +128,8 @@ class ScriptExecutorTest : public testing::Test,
ActionsResponseProto interrupt_actions;
InitInterruptActions(&interrupt_actions, path);
EXPECT_CALL(mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)));
}
void InitInterruptActions(ActionsResponseProto* interrupt_actions,
@@ -170,7 +177,7 @@ class ScriptExecutorTest : public testing::Test,
TEST_F(ScriptExecutorTest, GetActionsFails) {
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(false, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_,
Run(AllOf(Field(&ScriptExecutor::Result::success, false),
Field(&ScriptExecutor::Result::at_end,
@@ -198,7 +205,7 @@ TEST_F(ScriptExecutorTest, ForwardParameters) {
EXPECT_THAT("value",
trigger_context.GetParameter("param").value_or(""));
- std::move(callback).Run(true, "");
+ std::move(callback).Run(net::HTTP_OK, "");
}));
EXPECT_CALL(executor_callback_,
@@ -212,12 +219,12 @@ TEST_F(ScriptExecutorTest, RunOneActionReportAndReturn) {
ToSelectorProto("will fail");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_,
Run(AllOf(Field(&ScriptExecutor::Result::success, true),
Field(&ScriptExecutor::Result::at_end,
@@ -225,7 +232,7 @@ TEST_F(ScriptExecutorTest, RunOneActionReportAndReturn) {
executor_->Run(&user_data_, executor_callback_.Get());
ASSERT_EQ(1u, processed_actions_capture.size());
- EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, processed_actions_capture[0].status());
+ EXPECT_EQ(UNEXPECTED_JS_ERROR, processed_actions_capture[0].status());
EXPECT_TRUE(processed_actions_capture[0].has_run_time_ms());
EXPECT_GE(processed_actions_capture[0].run_time_ms(), 0);
}
@@ -235,18 +242,19 @@ TEST_F(ScriptExecutorTest, RunMultipleActions) {
initial_actions_response.add_actions()->mutable_tell()->set_message("1");
initial_actions_response.add_actions()->mutable_tell()->set_message("2");
EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(initial_actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(initial_actions_response)));
ActionsResponseProto next_actions_response;
next_actions_response.add_actions()->mutable_tell()->set_message("3");
std::vector<ProcessedActionProto> processed_actions1_capture;
std::vector<ProcessedActionProto> processed_actions2_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(
- DoAll(SaveArg<3>(&processed_actions1_capture),
- RunOnceCallback<4>(true, Serialize(next_actions_response))))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(DoAll(
+ SaveArg<3>(&processed_actions1_capture),
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response))))
.WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -260,12 +268,12 @@ TEST_F(ScriptExecutorTest, UnsupportedAction) {
actions_response.add_actions(); // action definition missing
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -279,10 +287,10 @@ TEST_F(ScriptExecutorTest, StopAfterEnd) {
actions_response.add_actions()->mutable_stop();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(AllOf(Field(&ScriptExecutor::Result::success, true),
Field(&ScriptExecutor::Result::at_end,
@@ -301,26 +309,27 @@ TEST_F(ScriptExecutorTest, InterruptActionListOnError) {
"never run");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(initial_actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(initial_actions_response)));
ActionsResponseProto next_actions_response;
next_actions_response.add_actions()->mutable_tell()->set_message(
"will run after error");
std::vector<ProcessedActionProto> processed_actions1_capture;
std::vector<ProcessedActionProto> processed_actions2_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(
- DoAll(SaveArg<3>(&processed_actions1_capture),
- RunOnceCallback<4>(true, Serialize(next_actions_response))))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(DoAll(
+ SaveArg<3>(&processed_actions1_capture),
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response))))
.WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
ASSERT_EQ(2u, processed_actions1_capture.size());
EXPECT_EQ(ACTION_APPLIED, processed_actions1_capture[0].status());
- EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, processed_actions1_capture[1].status());
+ EXPECT_EQ(UNEXPECTED_JS_ERROR, processed_actions1_capture[1].status());
ASSERT_EQ(1u, processed_actions2_capture.size());
EXPECT_EQ(ACTION_APPLIED, processed_actions2_capture[0].status());
@@ -336,12 +345,12 @@ TEST_F(ScriptExecutorTest, RunDelayedAction) {
action->set_action_delay_ms(1000);
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// executor_callback_.Run() not expected to be run just yet, as the action is
// delayed.
@@ -364,9 +373,9 @@ TEST_F(ScriptExecutorTest, ClearDetailsWhenFinished) {
*actions_response.add_actions() = click_with_clean_contextual_ui;
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -384,9 +393,9 @@ TEST_F(ScriptExecutorTest, DontClearDetailsIfOtherActionsAreLeft) {
actions_response.add_actions()->mutable_tell()->set_message("Wait no!");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -399,9 +408,9 @@ TEST_F(ScriptExecutorTest, ClearDetailsOnError) {
ActionsResponseProto actions_response;
actions_response.add_actions()->mutable_tell()->set_message("Hello");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, false)));
delegate_.SetDetails(std::make_unique<Details>()); // empty, but not null
@@ -422,7 +431,7 @@ TEST_F(ScriptExecutorTest, UpdateScriptStateWhileRunning) {
TEST_F(ScriptExecutorTest, UpdateScriptStateOnError) {
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(false, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, false)));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -435,9 +444,10 @@ TEST_F(ScriptExecutorTest, UpdateScriptStateOnSuccess) {
ActionsResponseProto initial_actions_response;
initial_actions_response.add_actions()->mutable_tell()->set_message("ok");
EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(initial_actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(initial_actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -454,14 +464,15 @@ TEST_F(ScriptExecutorTest, ForwardLastPayloadOnSuccess) {
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, "initial global payload",
"initial payload", _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
ActionsResponseProto next_actions_response;
next_actions_response.set_global_payload("last global payload");
next_actions_response.set_script_payload("last payload");
EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
- "actions payload", _, _))
- .WillOnce(RunOnceCallback<4>(true, Serialize(next_actions_response)));
+ "actions payload", _, _, _))
+ .WillOnce(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response)));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -478,11 +489,11 @@ TEST_F(ScriptExecutorTest, ForwardLastPayloadOnError) {
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, "initial global payload",
"initial payload", _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
- "actions payload", _, _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ "actions payload", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -498,22 +509,24 @@ TEST_F(ScriptExecutorTest, WaitForDomWaitUntil) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// First check does not find the element, wait for dom waits 1s, then the
// element is found, and the action succeeds.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
EXPECT_CALL(executor_callback_, Run(_));
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
@@ -530,11 +543,11 @@ TEST_F(ScriptExecutorTest, RunInterrupt) {
// Both scripts ends after the first set of actions. Capture the results.
std::vector<ProcessedActionProto> processed_actions1_capture;
std::vector<ProcessedActionProto> processed_actions2_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions1_capture),
- RunOnceCallback<4>(true, "")))
+ RunOnceCallback<5>(net::HTTP_OK, "")))
.WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -570,14 +583,14 @@ TEST_F(ScriptExecutorTest, RunMultipleInterruptInOrder) {
{
testing::InSequence seq;
EXPECT_CALL(mock_service_,
- OnGetNextActions(_, _, "payload for interrupt1", _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ OnGetNextActions(_, _, "payload for interrupt1", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(mock_service_,
- OnGetNextActions(_, _, "payload for interrupt2", _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ OnGetNextActions(_, _, "payload for interrupt2", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(mock_service_,
- OnGetNextActions(_, _, "main script payload", _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ OnGetNextActions(_, _, "main script payload", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
}
EXPECT_CALL(executor_callback_,
@@ -602,7 +615,8 @@ TEST_F(ScriptExecutorTest, RunSameInterruptMultipleTimes) {
wait_action->set_allow_interrupt(true);
}
EXPECT_CALL(mock_service_, OnGetActions(StrEq("script_path"), _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
// 'interrupt' with matching preconditions runs exactly three times.
RegisterInterrupt("interrupt", "interrupt_trigger");
@@ -610,11 +624,12 @@ TEST_F(ScriptExecutorTest, RunSameInterruptMultipleTimes) {
InitInterruptActions(&interrupt_actions, "interrupt");
EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
.Times(3)
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)));
// All scripts succeed with no more actions.
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -631,9 +646,9 @@ TEST_F(ScriptExecutorTest, ForwardMainScriptPayloadWhenInterruptRuns) {
next_interrupt_actions_response.set_script_payload(
"last payload from interrupt");
EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
- "payload for interrupt", _, _))
- .WillOnce(
- RunOnceCallback<4>(true, Serialize(next_interrupt_actions_response)));
+ "payload for interrupt", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(next_interrupt_actions_response)));
ActionsResponseProto next_main_actions_response;
next_main_actions_response.set_global_payload(
@@ -641,9 +656,9 @@ TEST_F(ScriptExecutorTest, ForwardMainScriptPayloadWhenInterruptRuns) {
next_main_actions_response.set_script_payload("last payload from main");
EXPECT_CALL(mock_service_,
OnGetNextActions(_, "last global payload from interrupt",
- "main script payload", _, _))
- .WillOnce(
- RunOnceCallback<4>(true, Serialize(next_main_actions_response)));
+ "main script payload", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(next_main_actions_response)));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -658,12 +673,12 @@ TEST_F(ScriptExecutorTest, ForwardMainScriptPayloadWhenInterruptFails) {
SetupInterrupt("interrupt", "interrupt_trigger");
EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
- "payload for interrupt", _, _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ "payload for interrupt", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
- "main script payload", _, _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ "main script payload", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -678,15 +693,18 @@ TEST_F(ScriptExecutorTest, DoNotRunInterruptIfPreconditionsDontMatch) {
SetupInterruptibleScript(kScriptPath, "element");
SetupInterrupt("interrupt", "interrupt_trigger");
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"interrupt_trigger"})), _))
- .WillRepeatedly(RunOnceCallback<1>(ClientStatus()));
+ OnFindElement(Selector({"interrupt_trigger"}), _))
+ .WillRepeatedly(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -705,14 +723,14 @@ TEST_F(ScriptExecutorTest, DoNotRunInterruptIfNotInterruptible) {
ToSelectorProto("element");
// allow_interrupt is not set
EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
// The interrupt would trigger, since interrupt_trigger exits, but it's not
// given an opportunity to.
SetupInterrupt("interrupt", "interrupt_trigger");
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -730,8 +748,8 @@ TEST_F(ScriptExecutorTest, InterruptFailsMainScript) {
// The interrupt fails.
EXPECT_CALL(mock_service_,
- OnGetNextActions(_, _, "payload for interrupt", _, _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ OnGetNextActions(_, _, "payload for interrupt", _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
// The main script gets a report of the failure from the interrupt, and fails
// in turn.
@@ -741,8 +759,8 @@ TEST_F(ScriptExecutorTest, InterruptFailsMainScript) {
_, _, "main script payload",
ElementsAre(Property(&ProcessedActionProto::status,
ProcessedActionStatusProto::INTERRUPT_FAILED)),
- _))
- .WillOnce(RunOnceCallback<4>(false, ""));
+ _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, false)));
@@ -765,13 +783,14 @@ TEST_F(ScriptExecutorTest, InterruptReturnsShutdown) {
// Get interrupt actions
EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)));
// We expect to get result of interrupt action, then result of the main script
// action.
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.Times(2)
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(AllOf(Field(&ScriptExecutor::Result::success, true),
@@ -798,20 +817,26 @@ TEST_F(ScriptExecutorTest, RunInterruptDuringPrompt) {
ToSelectorProto("end_prompt");
interruptible.add_actions()->mutable_tell()->set_message("done");
EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"interrupt_trigger"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()))
+ OnFindElement(Selector({"interrupt_trigger"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }))
.WillRepeatedly(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"end_prompt"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"end_prompt"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -845,7 +870,7 @@ TEST_F(ScriptExecutorTest, RunPromptInBrowseMode) {
prompt->set_browse_mode(true);
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ(AutofillAssistantState::BROWSE, delegate_.GetState());
@@ -857,7 +882,7 @@ TEST_F(ScriptExecutorTest, RunPromptInPromptMode) {
prompt->add_choices()->mutable_chip()->set_text("done");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
@@ -875,30 +900,44 @@ TEST_F(ScriptExecutorTest, RunInterruptMultipleTimesDuringPrompt) {
*prompt_action->add_choices()->mutable_auto_select_when()->mutable_match() =
ToSelectorProto("end_prompt");
EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
// interrupt_trigger goes away and come back, which means that the interrupt
// will be run twice.
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"interrupt_trigger"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()))
+ OnFindElement(Selector({"interrupt_trigger"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }))
.WillRepeatedly(
- RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)));
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
// It takes a several rounds for end_prompt to appear, which gives time for
// the interrupt to run.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"end_prompt"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)))
- .WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED)))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"end_prompt"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -929,7 +968,8 @@ TEST_F(ScriptExecutorTest, UpdateScriptListGetNext) {
ActionsResponseProto initial_actions_response;
initial_actions_response.add_actions()->mutable_tell()->set_message("1");
EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(initial_actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
+ Serialize(initial_actions_response)));
ActionsResponseProto next_actions_response;
next_actions_response.add_actions()->mutable_tell()->set_message("2");
@@ -940,9 +980,10 @@ TEST_F(ScriptExecutorTest, UpdateScriptListGetNext) {
presentation->mutable_chip()->set_text("name");
presentation->mutable_precondition();
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, Serialize(next_actions_response)))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response)))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -969,12 +1010,12 @@ TEST_F(ScriptExecutorTest, UpdateScriptListShouldNotifyMultipleTimes) {
presentation->mutable_precondition();
EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
script->set_path("path2");
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, Serialize(actions_response)))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -998,7 +1039,7 @@ TEST_F(ScriptExecutorTest, UpdateScriptListFromInterrupt) {
interrupt_actions.add_actions()->mutable_tell()->set_message("abc");
EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)));
auto* script = interrupt_actions.mutable_update_script_list()->add_scripts();
script->set_path("path");
@@ -1009,10 +1050,10 @@ TEST_F(ScriptExecutorTest, UpdateScriptListFromInterrupt) {
// We expect a call from the interrupt which will update the script list and a
// second call from the interrupt to terminate. Then a call from the main
// script which will finish without running any actions.
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.Times(3)
- .WillOnce(RunOnceCallback<4>(true, Serialize(interrupt_actions)))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -1039,17 +1080,19 @@ TEST_F(ScriptExecutorTest, RestorePreInterruptStatusMessage) {
ToSelectorProto("element");
wait_action->set_allow_interrupt(true);
EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
RegisterInterrupt("interrupt", "interrupt_trigger");
ActionsResponseProto interrupt_actions;
interrupt_actions.add_actions()->mutable_tell()->set_message(
"interrupt status");
EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -1068,10 +1111,11 @@ TEST_F(ScriptExecutorTest, KeepStatusMessageWhenNotInterrupted) {
ToSelectorProto("element");
wait_action->set_allow_interrupt(true);
EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
+ .WillRepeatedly(
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interruptible)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
@@ -1089,16 +1133,16 @@ TEST_F(ScriptExecutorTest, PauseWaitForDomWhileNavigating) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// First check does not find the element, wait for dom waits 1s.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
executor_->Run(&user_data_, executor_callback_.Get());
// Navigation starts while WaitForDom is waiting. The action doesn't fail,
@@ -1110,9 +1154,11 @@ TEST_F(ScriptExecutorTest, PauseWaitForDomWhileNavigating) {
}
// The end of navigation un-pauses WaitForDom.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
EXPECT_CALL(executor_callback_, Run(_));
delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ false);
@@ -1128,11 +1174,11 @@ TEST_F(ScriptExecutorTest, StartWaitForDomWhileNavigating) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// Navigation starts before WaitForDom starts. WaitForDom does not wait and
// completes successfully.
@@ -1149,30 +1195,6 @@ TEST_F(ScriptExecutorTest, StartWaitForDomWhileNavigating) {
EXPECT_FALSE(processed_actions_capture[0].navigation_info().ended());
}
-TEST_F(ScriptExecutorTest, ReportErrorAsNavigationError) {
- ActionsResponseProto actions_response;
- *actions_response.add_actions()->mutable_click()->mutable_element_to_click() =
- ToSelectorProto("will fail");
-
- EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
-
- delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ true);
- EXPECT_CALL(executor_callback_, Run(_));
- executor_->Run(&user_data_, executor_callback_.Get());
-
- ASSERT_EQ(1u, processed_actions_capture.size());
-
- // The original error is overwritten; a navigation error is reported.
- EXPECT_EQ(NAVIGATION_ERROR, processed_actions_capture[0].status());
- EXPECT_EQ(ELEMENT_RESOLUTION_FAILED,
- processed_actions_capture[0].status_details().original_status());
-}
-
TEST_F(ScriptExecutorTest, NavigateWhileRunningInterrupt) {
SetupInterruptibleScript(kScriptPath, "element");
RegisterInterrupt("interrupt", "interrupt_trigger");
@@ -1187,18 +1209,18 @@ TEST_F(ScriptExecutorTest, NavigateWhileRunningInterrupt) {
.WillRepeatedly(
DoAll(InvokeWithoutArgs(
[this]() { delegate_.UpdateNavigationState(true, false); }),
- RunOnceCallback<5>(true, Serialize(interrupt_actions)),
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(interrupt_actions)),
InvokeWithoutArgs([this]() {
delegate_.UpdateNavigationState(false, false);
})));
std::vector<ProcessedActionProto> processed_actions1_capture;
std::vector<ProcessedActionProto> processed_actions2_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions1_capture),
- RunOnceCallback<4>(true, "")))
+ RunOnceCallback<5>(net::HTTP_OK, "")))
.WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
@@ -1213,11 +1235,11 @@ TEST_F(ScriptExecutorTest, ReportNavigationErrors) {
actions_response.add_actions()->mutable_tell()->set_message("b");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ true);
EXPECT_CALL(executor_callback_, Run(_));
@@ -1237,17 +1259,17 @@ TEST_F(ScriptExecutorTest, ReportNavigationEnd) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// WaitForDom does NOT wait for navigation to end, it immediately checks for
// the element, which fails.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
// Navigation starts before the script is run.
delegate_.UpdateNavigationState(/* navigating= */ true, /* error= */ false);
@@ -1256,9 +1278,11 @@ TEST_F(ScriptExecutorTest, ReportNavigationEnd) {
delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ false);
// Checking for the element succeeds on the second try.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
ASSERT_THAT(processed_actions_capture, SizeIs(1));
@@ -1274,25 +1298,27 @@ TEST_F(ScriptExecutorTest, ReportUnexpectedNavigationStart) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// As the element doesn't exist, WaitForDom returns and waits for 1s.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
delegate_.UpdateNavigationState(/* navigating= */ true, /* error= */ false);
// Navigation end forces a re-check, which succeeds
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ false);
ASSERT_THAT(processed_actions_capture, SizeIs(1));
@@ -1309,25 +1335,27 @@ TEST_F(ScriptExecutorTest, ReportExpectedNavigationStart) {
ToSelectorProto("element");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// As the element doesn't exist, WaitForDom returns and waits for 1s.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
EXPECT_CALL(executor_callback_, Run(_));
executor_->Run(&user_data_, executor_callback_.Get());
delegate_.UpdateNavigationState(/* navigating= */ true, /* error= */ false);
// Navigation end forces a re-check, which succeeds
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillRepeatedly(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillRepeatedly(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
delegate_.UpdateNavigationState(/* navigating= */ false, /* error= */ false);
ASSERT_THAT(processed_actions_capture, SizeIs(2));
@@ -1342,11 +1370,11 @@ TEST_F(ScriptExecutorTest, WaitForNavigationWithoutExpectation) {
actions_response.add_actions()->mutable_wait_for_navigation();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// WaitForNavigation returns immediately
EXPECT_CALL(executor_callback_, Run(_));
@@ -1362,11 +1390,11 @@ TEST_F(ScriptExecutorTest, ExpectNavigation) {
actions_response.add_actions()->mutable_wait_for_navigation();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// WaitForNavigation waits for navigation to start after expect_navigation
EXPECT_CALL(executor_callback_, Run(_));
@@ -1387,11 +1415,11 @@ TEST_F(ScriptExecutorTest, MultipleWaitForNavigation) {
actions_response.add_actions()->mutable_wait_for_navigation();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// The first wait_for_navigation waits for the navigation to happen. After
// that, the other wait_for_navigation return immediately.
@@ -1413,11 +1441,11 @@ TEST_F(ScriptExecutorTest, ExpectLaterNavigationIgnoringNavigationInProgress) {
actions_response.add_actions()->mutable_wait_for_navigation();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
delegate_.UpdateNavigationState(/* navigating= */ true, /* error= */ false);
@@ -1447,11 +1475,11 @@ TEST_F(ScriptExecutorTest, WaitForNavigationReportsError) {
actions_response.add_actions()->mutable_wait_for_navigation();
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
- RunOnceCallback<4>(true, "")));
+ RunOnceCallback<5>(net::HTTP_OK, "")));
// WaitForNavigation waits for navigation to start after expect_navigation
EXPECT_CALL(executor_callback_, Run(_));
@@ -1473,7 +1501,7 @@ TEST_F(ScriptExecutorTest, InterceptUserActions) {
->set_text("done");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
@@ -1482,7 +1510,7 @@ TEST_F(ScriptExecutorTest, InterceptUserActions) {
// The prompt action must finish. We don't bother continuing with the script
// in this test.
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _));
(*delegate_.GetUserActions())[0].Call(TriggerContext::CreateEmpty());
EXPECT_EQ(AutofillAssistantState::RUNNING, delegate_.GetState());
@@ -1497,10 +1525,10 @@ TEST_F(ScriptExecutorTest, ReportDirectActionsChoices) {
->add_names("done");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
std::vector<ProcessedActionProto> processed_actions_capture;
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
.WillOnce(SaveArg<3>(&processed_actions_capture));
auto context = std::make_unique<TriggerContextImpl>();
@@ -1525,7 +1553,7 @@ TEST_F(ScriptExecutorTest, PauseAndResume) {
->set_text("Chip");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ("Tell", delegate_.GetStatusMessage());
@@ -1563,12 +1591,12 @@ TEST_F(ScriptExecutorTest, PauseAndResumeWithOngoingAction) {
actions_response.add_actions()->mutable_tell()->set_message("Finished");
EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
// At first we don't find the element, to keep the |WaitForDomAction| running.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ("Tell", delegate_.GetStatusMessage());
@@ -1587,19 +1615,53 @@ TEST_F(ScriptExecutorTest, PauseAndResumeWithOngoingAction) {
// Resume, this should not restart the |WaitForDomAction|, it should also
// not advance to the next action (i.e. |PromptAction|), so the status
// status message is the one from |TellAction|.
- EXPECT_CALL(mock_web_controller_, OnElementCheck(_, _)).Times(0);
+ EXPECT_CALL(mock_web_controller_, OnFindElement(_, _)).Times(0);
(*delegate_.GetUserActions())[0].Call(TriggerContext::CreateEmpty());
EXPECT_EQ("Tell", delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::RUNNING, delegate_.GetState());
// We have resumed, the |WaitForDom| should now finish and advance the script.
- EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"element"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ EXPECT_CALL(mock_web_controller_, OnFindElement(Selector({"element"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
EXPECT_EQ("Prompt", delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
}
+ACTION_P2(Delay, env, delay) {
+ env->FastForwardBy(base::TimeDelta::FromMilliseconds(delay));
+}
+
+TEST_F(ScriptExecutorTest, RoundtripTimingStats) {
+ ActionsResponseProto actions_response;
+ ActionProto* action = actions_response.add_actions();
+ action->mutable_tell()->set_message("1");
+ action->set_action_delay_ms(1000);
+ EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
+ .WillOnce(
+ DoAll(Delay(&task_environment_, 200),
+ RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response))));
+
+ ActionsResponseProto next_actions_response;
+ next_actions_response.add_actions()->mutable_tell()->set_message("3");
+ RoundtripTimingStats timing_stats;
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<4>(&timing_stats),
+ RunOnceCallback<5>(net::HTTP_OK, "")));
+ executor_->Run(&user_data_, executor_callback_.Get());
+ EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
+
+ EXPECT_CALL(executor_callback_,
+ Run(Field(&ScriptExecutor::Result::success, true)));
+ task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+ // Moving forward in time triggers action execution.
+
+ EXPECT_EQ(200, timing_stats.roundtrip_time_ms());
+ EXPECT_EQ(1000, timing_stats.client_time_ms());
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/script_precondition_unittest.cc b/chromium/components/autofill_assistant/browser/script_precondition_unittest.cc
index 2bfd4611c38..0bacd818f31 100644
--- a/chromium/components/autofill_assistant/browser/script_precondition_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -5,8 +5,8 @@
#include "components/autofill_assistant/browser/script_precondition.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
@@ -22,8 +22,8 @@ namespace {
using ::base::test::RunOnceCallback;
using ::testing::_;
-using ::testing::Eq;
using ::testing::Invoke;
+using ::testing::WithArgs;
// A callback that expects to be called immediately.
//
@@ -57,11 +57,15 @@ class DirectCallback {
class ScriptPreconditionTest : public testing::Test {
public:
void SetUp() override {
- ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_web_controller_, OnFindElement(Selector({"exists"}), _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
ON_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"does_not_exist"})), _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus()));
+ OnFindElement(Selector({"does_not_exist"}), _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
SetUrl("http://www.example.com/path");
diff --git a/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc b/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
index 90d8c7afd61..fc358c5e58a 100644
--- a/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -9,18 +9,18 @@
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
-#include "components/autofill_assistant/browser/mock_service.h"
#include "components/autofill_assistant/browser/protocol_utils.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/mock_service.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "net/http/http_status_code.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::ElementsAre;
-using ::testing::Eq;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::NiceMock;
@@ -29,21 +29,26 @@ using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::StrictMock;
using ::testing::UnorderedElementsAre;
+using ::testing::WithArgs;
class ScriptTrackerTest : public testing::Test, public ScriptTracker::Listener {
public:
void SetUp() override {
delegate_.SetCurrentURL(GURL("http://www.example.com/"));
- ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
- .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
+ ON_CALL(mock_web_controller_, OnFindElement(Selector({"exists"}), _))
+ .WillByDefault(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
ON_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"does_not_exist"})), _))
- .WillByDefault(RunOnceCallback<1>(ClientStatus()));
+ OnFindElement(Selector({"does_not_exist"}), _))
+ .WillByDefault(RunOnceCallback<1>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
// Scripts run, but have no actions.
ON_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
- .WillByDefault(RunOnceCallback<5>(true, ""));
+ .WillByDefault(RunOnceCallback<5>(net::HTTP_OK, ""));
}
protected:
@@ -263,8 +268,9 @@ TEST_F(ScriptTrackerTest, CheckScriptsAgainAfterScriptEnd) {
TEST_F(ScriptTrackerTest, CheckScriptsAfterDOMChange) {
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"maybe_exists"})), _))
- .WillOnce(RunOnceCallback<1>(ClientStatus()));
+ OnFindElement(Selector({"maybe_exists"}), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
InitScriptProto(AddScript(), "script name", "script path", "maybe_exists");
SetAndCheckScripts();
@@ -274,8 +280,11 @@ TEST_F(ScriptTrackerTest, CheckScriptsAfterDOMChange) {
// DOM has changed; OnElementExists now returns truthy.
EXPECT_CALL(mock_web_controller_,
- OnElementCheck(Eq(Selector({"maybe_exists"})), _))
- .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+ OnFindElement(Selector({"maybe_exists"}), _))
+ .WillOnce(WithArgs<1>([](auto&& callback) {
+ std::move(callback).Run(OkClientStatus(),
+ std::make_unique<ElementFinder::Result>());
+ }));
tracker_.CheckScripts();
// The script can now run
@@ -303,9 +312,9 @@ TEST_F(ScriptTrackerTest, UpdateScriptList) {
EXPECT_CALL(mock_service_,
OnGetActions(StrEq("runnable name"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
EXPECT_CALL(execute_callback,
@@ -345,9 +354,9 @@ TEST_F(ScriptTrackerTest, UpdateScriptListFromInterrupt) {
EXPECT_CALL(mock_service_,
OnGetActions(StrEq("runnable name"), _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillOnce(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
EXPECT_CALL(execute_callback,
@@ -384,16 +393,16 @@ TEST_F(ScriptTrackerTest, UpdateInterruptList) {
interrupt_proto->mutable_presentation()->set_interrupt(true);
EXPECT_CALL(mock_service_, OnGetActions("main", _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
- EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
- .WillRepeatedly(RunOnceCallback<4>(true, ""));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
+ EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
+ .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
ActionsResponseProto actions_interrupt;
actions_response.set_script_payload("from interrupt");
actions_response.add_actions()->mutable_tell()->set_message("interrupt");
EXPECT_CALL(mock_service_, OnGetActions("interrupt", _, _, _, _, _))
- .WillOnce(RunOnceCallback<5>(true, Serialize(actions_interrupt)));
+ .WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_interrupt)));
base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
EXPECT_CALL(execute_callback,
diff --git a/chromium/components/autofill_assistant/browser/selector.cc b/chromium/components/autofill_assistant/browser/selector.cc
index e460622cc42..72652c7196a 100644
--- a/chromium/components/autofill_assistant/browser/selector.cc
+++ b/chromium/components/autofill_assistant/browser/selector.cc
@@ -55,9 +55,25 @@ bool operator<(const SelectorProto::Filter& a, const SelectorProto::Filter& b) {
std::make_tuple(b.pseudo_element_content().pseudo_type(),
b.pseudo_element_content().content());
+ case SelectorProto::Filter::kCssStyle:
+ return std::make_tuple(a.css_style().property(),
+ a.css_style().pseudo_element(),
+ a.css_style().value()) <
+ std::make_tuple(b.css_style().property(),
+ b.css_style().pseudo_element(),
+ b.css_style().value());
+
+ case SelectorProto::Filter::kOnTop:
+ return std::make_tuple(a.on_top().scroll_into_view_if_needed(),
+ a.on_top().accept_element_if_not_in_view()) <
+ std::make_tuple(b.on_top().scroll_into_view_if_needed(),
+ b.on_top().accept_element_if_not_in_view());
+
case SelectorProto::Filter::kBoundingBox:
+ return a.bounding_box().require_nonempty() <
+ b.bounding_box().require_nonempty();
+
case SelectorProto::Filter::kEnterFrame:
- case SelectorProto::Filter::kPickOne:
case SelectorProto::Filter::kLabelled:
return false;
@@ -68,6 +84,12 @@ bool operator<(const SelectorProto::Filter& a, const SelectorProto::Filter& b) {
b.closest().relative_position());
}
+ case SelectorProto::Filter::kMatchCssSelector:
+ return a.match_css_selector() < b.match_css_selector();
+
+ case SelectorProto::Filter::kNthMatch:
+ return a.nth_match().index() < b.nth_match().index();
+
case SelectorProto::Filter::FILTER_NOT_SET:
return false;
}
@@ -83,7 +105,7 @@ SelectorProto ToSelectorProto(const std::vector<std::string>& s) {
if (!s.empty()) {
for (size_t i = 0; i < s.size(); i++) {
if (i > 0) {
- proto.add_filters()->mutable_pick_one();
+ proto.add_filters()->mutable_nth_match()->set_index(0);
proto.add_filters()->mutable_enter_frame();
}
proto.add_filters()->set_css_selector(s[i]);
@@ -209,16 +231,20 @@ base::Optional<std::string> Selector::ExtractSingleCssSelectorForAutofill()
break;
case SelectorProto::Filter::kBoundingBox:
- case SelectorProto::Filter::kPickOne:
- // Ignore these; they're not relevant for the autofill use-case
- break;
+ case SelectorProto::Filter::kNthMatch:
+ if (filter.nth_match().index() == 0)
+ break;
+ FALLTHROUGH;
case SelectorProto::Filter::kInnerText:
case SelectorProto::Filter::kValue:
case SelectorProto::Filter::kPseudoType:
case SelectorProto::Filter::kPseudoElementContent:
+ case SelectorProto::Filter::kCssStyle:
case SelectorProto::Filter::kLabelled:
case SelectorProto::Filter::kClosest:
+ case SelectorProto::Filter::kMatchCssSelector:
+ case SelectorProto::Filter::kOnTop:
VLOG(1) << __func__
<< " Selector feature not supported by autofill: " << *this;
return base::nullopt;
@@ -319,12 +345,24 @@ std::ostream& operator<<(std::ostream& out, const SelectorProto::Filter& f) {
<< "~=" << f.pseudo_element_content().content();
return out;
+ case SelectorProto::Filter::kCssStyle:
+ if (!f.css_style().pseudo_element().empty()) {
+ out << f.css_style().pseudo_element() << " ";
+ }
+ out << "style." << f.css_style().property()
+ << "~=" << f.css_style().value();
+ return out;
+
case SelectorProto::Filter::kBoundingBox:
- out << "bounding_box";
+ if (f.bounding_box().require_nonempty()) {
+ out << "bounding_box (nonempty)";
+ } else {
+ out << "bounding_box (any)";
+ }
return out;
- case SelectorProto::Filter::kPickOne:
- out << "pick_one";
+ case SelectorProto::Filter::kNthMatch:
+ out << "nth_match[" << f.nth_match().index() << "]";
return out;
case SelectorProto::Filter::kLabelled:
@@ -354,6 +392,20 @@ std::ostream& operator<<(std::ostream& out, const SelectorProto::Filter& f) {
}
return out;
+ case SelectorProto::Filter::kMatchCssSelector:
+ out << "matches: " << f.css_selector();
+ return out;
+
+ case SelectorProto::Filter::kOnTop:
+ out << "on_top";
+ if (!f.on_top().scroll_into_view_if_needed()) {
+ out << "(no scroll)";
+ }
+ if (f.on_top().accept_element_if_not_in_view()) {
+ out << "(accept not in view)";
+ }
+ return out;
+
case SelectorProto::Filter::FILTER_NOT_SET:
// Either unset or set to an unsupported value. Let's assume the worse.
out << "INVALID";
diff --git a/chromium/components/autofill_assistant/browser/selector_unittest.cc b/chromium/components/autofill_assistant/browser/selector_unittest.cc
index 08639296f6b..7e8f1848080 100644
--- a/chromium/components/autofill_assistant/browser/selector_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/selector_unittest.cc
@@ -23,10 +23,11 @@ TEST(SelectorTest, Constructor_WithIframe) {
Selector selector({"#frame", "#test"});
ASSERT_EQ(4, selector.proto.filters().size());
EXPECT_EQ("#frame", selector.proto.filters(0).css_selector());
- EXPECT_EQ(selector.proto.filters(1).filter_case(),
- SelectorProto::Filter::kPickOne);
- EXPECT_EQ(selector.proto.filters(2).filter_case(),
- SelectorProto::Filter::kEnterFrame);
+ EXPECT_EQ(SelectorProto::Filter::kNthMatch,
+ selector.proto.filters(1).filter_case());
+ EXPECT_EQ(0, selector.proto.filters(1).nth_match().index());
+ EXPECT_EQ(SelectorProto::Filter::kEnterFrame,
+ selector.proto.filters(2).filter_case());
EXPECT_EQ("#test", selector.proto.filters(3).css_selector());
}
@@ -75,6 +76,25 @@ TEST(SelectorTest, Comparison_Visibility) {
Selector({"a"}).MustBeVisible());
}
+TEST(SelectorTest, Comparison_NonEmptyBoundingBox) {
+ Selector has_bounding_box_default = Selector({"a"});
+ has_bounding_box_default.proto.add_filters()->mutable_bounding_box();
+
+ Selector has_bounding_box_explicit = Selector({"a"});
+ has_bounding_box_explicit.proto.add_filters()
+ ->mutable_bounding_box()
+ ->set_require_nonempty(false);
+
+ Selector has_nonempty_bounding_box = Selector({"a"});
+ has_nonempty_bounding_box.proto.add_filters()
+ ->mutable_bounding_box()
+ ->set_require_nonempty(true);
+
+ EXPECT_FALSE(has_bounding_box_default == has_nonempty_bounding_box);
+ EXPECT_FALSE(has_bounding_box_explicit == has_nonempty_bounding_box);
+ EXPECT_TRUE(has_bounding_box_default == has_bounding_box_explicit);
+}
+
TEST(SelectorTest, Comparison_InnerText) {
EXPECT_FALSE(Selector({"a"}).MatchingInnerText("a") ==
Selector({"a"}).MatchingInnerText("b"));
@@ -138,6 +158,25 @@ TEST(SelectorTest, Comparison_Proximity) {
EXPECT_FALSE(Selector(selector) == Selector(label2));
}
+TEST(SelectorTest, Comparison_MatchCssSelector) {
+ Selector a = Selector({"button"});
+ a.proto.add_filters()->set_match_css_selector(".class1");
+ Selector b = Selector({"button"});
+ b.proto.add_filters()->set_match_css_selector(".class2");
+
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a == a);
+}
+
+TEST(SelectorTest, Comparison_OnTop) {
+ Selector a = Selector({"button"});
+ a.proto.add_filters()->mutable_on_top();
+ Selector b = Selector({"button"});
+
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a == a);
+}
+
TEST(SelectorTest, Comparison_Frames) {
Selector ab({"a", "b"});
EXPECT_EQ(ab, ab);
diff --git a/chromium/components/autofill_assistant/browser/service.proto b/chromium/components/autofill_assistant/browser/service.proto
index c107d71e69b..2f670aa3cf8 100644
--- a/chromium/components/autofill_assistant/browser/service.proto
+++ b/chromium/components/autofill_assistant/browser/service.proto
@@ -124,8 +124,14 @@ message SupportsScriptResponseProto {
// Overlay image to be drawn on top of full overlays.
message OverlayImageProto {
- // The image to display. If set, |image_size| is mandatory.
- optional string image_url = 1;
+ // TODO(b/170202574): Remove legacy |image_url|.
+ // If set, |image_size| is mandatory.
+ oneof image {
+ // Deprecated, but currently still supported. The image to display.
+ string image_url = 1;
+ // The image to display.
+ DrawableProto image_drawable = 8;
+ }
// The size of the image to display.
optional ClientDimensionProto image_size = 2;
// The margin between the top of the page (anchor) and the image.
@@ -142,7 +148,6 @@ message OverlayImageProto {
}
message ClientSettingsProto {
- reserved 10, 11;
message IntegrationTestSettings {
// Disables animations for the poodle and the progress bar.
optional bool disable_header_animations = 1;
@@ -176,13 +181,8 @@ message ClientSettingsProto {
// become stable.
optional int32 box_model_check_count = 7;
- // Time to wait between two checks of the document state, when waiting for the
- // document to become ready.
- optional int32 document_ready_check_interval_ms = 8;
-
- // Maximum number of checks to run while waiting for the document to become
- // ready.
- optional int32 document_ready_check_count = 9;
+ // Maximum time to wait until document has reached "ready" state.
+ optional int32 document_ready_check_timeout_ms = 20;
// How much time to give users to tap undo when they tap a cancel button.
optional int32 cancel_delay_ms = 12;
@@ -222,6 +222,8 @@ message ClientSettingsProto {
optional string undo_label = 2;
}
optional BackButtonSettings back_button_settings = 19;
+
+ reserved 8 to 11;
}
message ScriptTimeoutError {
@@ -381,12 +383,22 @@ message InitialScriptActionsRequestProto {
repeated ScriptParameterProto script_parameters = 2;
}
+message RoundtripTimingStats {
+ // Reports how long it took for the previous roundtrip to the backend to
+ // complete.
+ optional int64 roundtrip_time_ms = 1;
+ // Reports the total client processing time for the executed batch of actions.
+ optional int64 client_time_ms = 2;
+}
+
// Next request to get a script's actions.
message NextScriptActionsRequestProto {
// The result of processing each ActionProto from the previous response. This
// field must be in the same order as the actions in the original response.
// It may have less actions in case of failure.
repeated ProcessedActionProto processed_actions = 1;
+ // Contains all roundtrip level (as opposed to action level) timing stats.
+ optional RoundtripTimingStats timing_stats = 2;
}
// Response of a script's actions.
@@ -416,21 +428,181 @@ message ActionsResponseProto {
optional UpdateScriptListProto update_script_list = 5;
}
+// Can be used to indicate the presence of a field, without the ambiguity that
+// a boolean field would have.
+message Empty {}
+
+// RPC request to fetch the available trigger scripts for a particular domain.
+message GetTriggerScriptsRequestProto {
+ // The exact url for which to fetch the trigger scripts.
+ optional string url = 1;
+ // The client context.
+ // NOTE: Currently, this will only contain the Chrome version number for
+ // privacy reasons.
+ optional ClientContextProto client_context = 2;
+ // Optional debug script parameters.
+ repeated ScriptParameterProto debug_script_parameters = 3;
+}
+
+// The RPC response to a |GetTriggerScriptsRequestProto|.
+message GetTriggerScriptsResponseProto {
+ // The available trigger scripts, if any.
+ repeated TriggerScriptProto trigger_scripts = 1;
+
+ // A list of additional domains and subdomains. Trigger scripts will
+ // automatically cancel the ongoing session if the user navigates away from
+ // the original domain or any of the additional domains.
+ repeated string additional_allowed_domains = 2;
+
+ // The amount of time a trigger script may evaluate trigger conditions while
+ // invisible. If a trigger script is invisible for this amount of time, it
+ // will automatically finish with LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT.
+ // If not specified, there is no automatic timeout.
+ //
+ // This is only counted while no trigger script is shown, and the time is
+ // reset on tab switch and whenever a trigger script is hidden. Note that this
+ // only counts the time in-between checks, so the actual timeout will be
+ // slightly longer.
+ optional int32 timeout_ms = 3;
+
+ // The amount of time between consecutive checks of trigger conditions. Should
+ // not be too small to limit performance impact.
+ optional int32 trigger_condition_check_interval_ms = 4 [default = 1000];
+}
+
+// A trigger script contains the full specification for a trigger script that is
+// run when a specific condition is true, prior to the full run.
+message TriggerScriptProto {
+ enum TriggerScriptAction {
+ UNDEFINED = 0;
+ // The current trigger script is cancelled. If the prompt is not currently
+ // being shown, this has no effect. If the prompt is currently being shown,
+ // the prompt is hidden and the trigger script is restarted once the trigger
+ // condition has become false again.
+ NOT_NOW = 1;
+ // Cancels the current trigger script and does not restart it for this
+ // session.
+ CANCEL_SESSION = 2;
+ // Cancels the current trigger script and prevents trigger scripts from ever
+ // running again. TODO(b/172039582): allow a per-domain opt-out.
+ CANCEL_FOREVER = 3;
+ // Displays a popup to give users additional cancel options.
+ SHOW_CANCEL_POPUP = 4;
+ // Stop the trigger script and start the regular script.
+ ACCEPT = 5;
+ }
+
+ // The |trigger_condition| must be true for the script to trigger.
+ optional TriggerScriptConditionProto trigger_condition = 1;
+
+ // The user interface to show.
+ optional TriggerScriptUIProto user_interface = 3;
+
+ // What should happen if the user swipe-dismisses the bottom sheet.
+ optional TriggerScriptAction on_swipe_to_dismiss = 4
+ [default = CANCEL_SESSION];
+
+ reserved 2;
+}
+
+message TriggerScriptConditionProto {
+ oneof type {
+ // The condition matches if all of these conditions match.
+ TriggerScriptConditionsProto all_of = 1;
+ // The condition matches if at least one of these conditions matches.
+ TriggerScriptConditionsProto any_of = 2;
+ // The condition matches if none of these conditions match.
+ TriggerScriptConditionsProto none_of = 3;
+
+ // The condition matches if the specified selector matches the current DOM..
+ SelectorProto selector = 8;
+ // The condition matches if the user has stored login credentials for the
+ // domain.
+ Empty stored_login_credentials = 5;
+ // The condition matches if the user has never seen a trigger script before.
+ Empty is_first_time_user = 6;
+ // The condition matches if the client is in the specified experiment.
+ int32 experiment_id = 7;
+ // The condition matches if the keyboard is hidden.
+ Empty keyboard_hidden = 9;
+ }
+
+ reserved 4;
+}
+
+message TriggerScriptConditionsProto {
+ repeated TriggerScriptConditionProto conditions = 1;
+}
+
+message TriggerScriptUIProto {
+ message ProgressBar {
+ repeated DrawableProto step_icons = 1;
+ optional int32 active_step = 2;
+ }
+
+ message TriggerChip {
+ optional ChipProto chip = 1;
+ optional TriggerScriptProto.TriggerScriptAction action = 2;
+ }
+ message Popup {
+ message Choice {
+ // The text to display.
+ optional string text = 1;
+ // The action to execute if this popup item is selected.
+ optional TriggerScriptProto.TriggerScriptAction action = 2;
+ }
+ // The available popup items.
+ repeated Choice choices = 1;
+ }
+
+ // The status message to display.
+ optional string status_message = 1;
+ // The callout to display. If not specified, no callout will be shown.
+ optional string callout_message = 2;
+ // The progress bar to display. If not specified, no progress bar will be
+ // shown.
+ optional ProgressBar progress_bar = 3;
+ // The cancel popup, usually associated with a particular chip.
+ optional Popup cancel_popup = 4;
+ // The available left-aligned chips, specified in order from left to right.
+ repeated TriggerChip left_aligned_chips = 5;
+ // The available right-aligned chips, specified in order from left to right.
+ repeated TriggerChip right_aligned_chips = 6;
+ // The status message to display when transitioning from this trigger script
+ // to the regular script.
+ optional string regular_script_loading_status_message = 7;
+ // Whether the visual viewport should be resized to allow scrolling to the
+ // bottom of the page while the trigger script is being displayed.
+ optional bool resize_visual_viewport = 8;
+ // Whether the bottom sheet should temporarily disappear when scrolling down
+ // the website, to move out of the way.
+ //
+ // The value of resize_visual_viewport is ignored when scroll_to_hide is true.
+ // This allows the backend setting both to true and letting chrome choose
+ // scroll_to_hide if it is supported.
+ optional bool scroll_to_hide = 9;
+}
+
enum KeyboardValueFillStrategy {
UNSPECIFIED_KEYBAORD_STRATEGY = 0;
// Send a `node.value = "<value>"` JS command.
SET_VALUE = 1;
- // Send a `node.value = ""` JS command to clear the field, then send single
- // key strokes.
+ // Send a `node.value = ""` JS command to clear the field, then click the
+ // field to focus it and send single key strokes.
SIMULATE_KEY_PRESSES = 2;
// Send a `node.select()` JS command to select the current field value, then
// send single key strokes overwriting the current value.
SIMULATE_KEY_PRESSES_SELECT_VALUE = 3;
+
+ // Send a `node.value = ""` JS command to clear the field, then send a
+ // `node.focus()` JS command to focus the field and send single key strokes.
+ SIMULATE_KEY_PRESSES_FOCUS = 4;
}
+// Note: On multiple matches, the first one will be selected.
enum DropdownSelectStrategy {
UNSPECIFIED_SELECT_STRATEGY = 0;
@@ -490,7 +662,7 @@ message ActionProto {
NavigateProto navigate = 9;
PromptProto prompt = 10;
TellProto tell = 11;
- FocusElementProto focus_element = 12;
+ ShowCastProto show_cast = 12;
WaitForDomProto wait_for_dom = 19;
UseCreditCardProto use_card = 28;
UseAddressProto use_address = 29;
@@ -513,6 +685,7 @@ message ActionProto {
SaveGeneratedPasswordProto save_generated_password = 53;
ConfigureUiStateProto configure_ui_state = 54;
PresaveGeneratedPasswordProto presave_generated_password = 55;
+ GetElementStatusProto get_element_status = 56;
}
// Set to true to make the client remove any contextual information if the
@@ -570,6 +743,16 @@ message CollectUserDataResultProto {
reserved 7, 8;
}
+message ActionTimingStats {
+ // Requested delay before executing the action.
+ optional int64 delay_ms = 1;
+ // Time actively spent by the client to execute the action.
+ optional int64 active_time_ms = 2;
+ // Time spent waiting for users to complete a task and/or for website
+ // loading/navigation.
+ optional int64 wait_time_ms = 3;
+}
+
message ProcessedActionProto {
// The action that was processed.
optional ActionProto action = 1;
@@ -580,7 +763,6 @@ message ProcessedActionProto {
oneof result_data {
PromptProto.Result prompt_choice = 5;
- string html_source = 12;
// Should be set as a result of CollectUserDataAction.
CollectUserDataResultProto collect_user_data_result = 15;
// Should be set as a result of SetFormFieldValueAction.
@@ -589,10 +771,13 @@ message ProcessedActionProto {
WaitForDomProto.Result wait_for_dom_result = 22;
// Should be set as a result of FormAction.
FormProto.Result form_result = 21;
-
WaitForDocumentProto.Result wait_for_document_result = 25;
// Should be set as a result of ShowGenericUiProto.
ShowGenericUiProto.Result show_generic_ui_result = 28;
+ // Should be set as a result of GetElementStatusProto.
+ GetElementStatusProto.Result get_element_status_result = 31;
+ // Should be set as a result of UploadDomProto.
+ UploadDomProto.Result upload_dom_result = 33;
}
// Reports information about navigation that happened while
@@ -603,12 +788,15 @@ message ProcessedActionProto {
// include the delay specified in action.delay_ms.
optional int64 run_time_ms = 23;
+ // Collects the timing stats related to the action execution.
+ optional ActionTimingStats timing_stats = 32;
+
// If true, the user triggered, during the client action, at least one user
// action, such as a prompt choice, through a direct action instead of
// selecting a chip on the UI. This is meant for monitoring and debugging.
optional bool direct_action = 24;
- reserved 26, 27;
+ reserved 3, 4, 6 to 14, 16, 18, 26, 27, 29, 30;
}
// Extended information about the action status, which provides more details
@@ -631,6 +819,9 @@ message ProcessedActionStatusDetailsProto {
// More information included for |SetFormFieldValueProto| related errors.
optional SetFormFieldErrorInfoProto form_field_error_info = 4;
+
+ // Additional information from the |WebController|.
+ optional WebControllerErrorInfoProto web_controller_error_info = 5;
}
message NavigationInfoProto {
@@ -742,6 +933,77 @@ message SetFormFieldErrorInfoProto {
optional int32 invalid_keypress_index = 1;
}
+// Message to report errors related to WebController execution.
+message WebControllerErrorInfoProto {
+ enum WebAction {
+ UNSPECIFIED_WEB_ACTION = 0;
+
+ // Scroll an element into view by centering it on the page. This uses
+ // native JS functionality.
+ SCROLL_INTO_VIEW = 1;
+
+ // Waiting for the document ready state to be interactive.
+ WAIT_FOR_DOCUMENT_TO_BECOME_INTERACTIVE = 2;
+
+ // Send a click or tap event to an element.
+ CLICK_OR_TAP_ELEMENT = 3;
+
+ // Select an option from an HTML dropdown.
+ SELECT_OPTION = 4;
+
+ // Set the element's style to be highlighted by adding a BoxShadow to the
+ // element.
+ HIGHLIGHT_ELEMENT = 5;
+
+ // Scroll the element into view with padding. This does not use native JS
+ // functionality but calculates the scrolling manually.
+ SCROLL_INTO_VIEW_WITH_PADDING = 6;
+
+ // Get the |value| attribute of an element.
+ GET_FIELD_VALUE = 7;
+
+ // Get any attribute of an element.
+ GET_STRING_ATTRIBUTE = 8;
+
+ // Select an element's value. This does only work for text elements.
+ SELECT_FIELD_VALUE = 9;
+
+ // Set the |value| attribute of an element.
+ SET_VALUE_ATTRIBUTE = 10;
+
+ // Set any attribute of an element.
+ SET_ATTRIBUTE = 11;
+
+ // Send a series of keystroke inputs. This requires an element to have
+ // focus to receive them.
+ SEND_KEYBOARD_INPUT = 12;
+
+ // Get the outer HTML of an element.
+ GET_OUTER_HTML = 13;
+
+ // Get the tag of an element.
+ GET_ELEMENT_TAG = 14;
+
+ // Set active focus on a field.
+ FOCUS_FIELD = 15;
+
+ // Wait for an element position to stabilize before clicking or a tapping.
+ // Fails with ELEMENT_UNSTABLE.
+ WAIT_UNTIL_ELEMENT_IS_STABLE = 16;
+
+ // Check that the element is on top, usually as part of clicking.
+ // Fails with ELEMENT_NOT_ON_TOP.
+ ON_TOP = 17;
+
+ // Waiting for a certain document ready state failed.
+ WAIT_FOR_DOCUMENT_READY_STATE = 18;
+ }
+
+ // The web-action that failed. This is usually a step in an execution chain
+ // for an action.
+ optional WebAction failed_web_action = 1;
+}
+
// The pseudo type values come from
// https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType.
enum PseudoType {
@@ -772,6 +1034,10 @@ message SelectorProto {
// A filter that starts with one or more elements and returns one on more
// elements. Filters are meant to be applied sequentially.
+ //
+ // The returned elements will be sorted by their order in the document.
+ // Elements that were matched via the labelled filter will have the same order
+ // as their label.
message Filter {
oneof filter {
// Enter the document of an iframe or shadow root. The next filters apply
@@ -802,13 +1068,11 @@ message SelectorProto {
//
// This is the equivalent of the old MUST_BE_VISIBLE flag. It's been
// renamed as having a bounding box is not enough to imply visibility.
- EmptyFilter bounding_box = 6;
+ BoundingBoxFilter bounding_box = 6;
- // Pick just one match and continue. Ignore all other matches.
- //
- // For backward-compatibility with older element references, pick_one can
- // be put before enter_frame.
- EmptyFilter pick_one = 7;
+ // Take the nth match. Fails with ELEMENT_RESOLUTION_FAILED if there are
+ // not enough matches.
+ NthMatchFilter nth_match = 7;
// Only keep elements that have a pseudo-element with the given content.
//
@@ -816,6 +1080,8 @@ message SelectorProto {
//
// Note that this just filters out elements. It doesn't select the
// pseudo-element; use pseudo_type for that.
+ //
+ // Deprecated: prefer css_style. This should be removed in Chrome M89.
PseudoElementContent pseudo_element_content = 8;
// Go from label to the labelled control. Only works starting with current
@@ -842,6 +1108,44 @@ message SelectorProto {
// always 0. If there are multiple elements at exactly the same distance,
// an arbitrary one is returned.
ProximityFilter closest = 10;
+
+ // Only keep results that match the given CSS selector.
+ string match_css_selector = 11;
+
+ // Only keep elements whose computed style match the given filter. This is
+ // based on Window.computedStyle()
+ CssStyleFilter css_style = 12;
+
+ // Filter out elements whose center point are covered by another element.
+ //
+ // This first calls Element.scrollIntoViewIfNeeded to make sure the
+ // element can be moved to the viewport, then calls
+ // DocumentOrShadowDom.getElementFromPoint and compares the result with
+ // the expected element. If the element at point is not the element, a
+ // descendant of the element or a label of the element, there is an
+ // overlay.
+ //
+ // Note that:
+ //
+ // - this filter will also weed out elements with no bounding box. Check
+ // with bounding_box { } first.
+ //
+ // - this filter will also weed out elements that cannot be scrolled into
+ // the viewport.
+ //
+ // - an element might be covered by an overlay and still be visible if the
+ // overlay is transparent. An element might be covered by an overlay and
+ // still be clickable, if the overlay intercepts and forwards events.
+ // Overlays with pointer-events set to none are ignored.
+ //
+ // - an element might be only partially covered by an overlay. This filter
+ // only checks the center of the element, since this is where the click
+ // action sends its clicks or taps.
+ //
+ // - this filter only detects overlays in the current frame. To detect
+ // overlays that cover the frame element itself, apply this filter on the
+ // frame element before calling enter_frame.
+ OnTopFilter on_top = 13;
}
}
@@ -863,6 +1167,35 @@ message SelectorProto {
optional TextFilter content = 2;
}
+ // Only keep elements whose computed style match the given filter. This is
+ // based on Window.computedStyle()
+ //
+ // See
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
+ message CssStyleFilter {
+ // CSS property name.
+ optional string property = 3;
+
+ // Name of the pseudo-element whose style should be checked. Leave it unset
+ // or set to the empty string to check the style of the real element.
+ //
+ // This is the pseudoElt argument of JavaScript's
+ // window.getComputedStyle(element, [, pseudoElt]).
+ optional string pseudo_element = 4;
+
+ // By default the text filter in |value| must match. Set this to false to
+ // require the text condition not to match.
+ optional bool should_match = 5 [default = true];
+
+ // CSS property value match.
+ //
+ // Valid computed CSS properties always have a value, even if it's a default
+ // value. The default value depends on the property.
+ optional TextFilter value = 6;
+
+ reserved 1, 2;
+ }
+
// Filter elements by their position on the page, relative to a given target
// element.
message ProximityFilter {
@@ -929,8 +1262,43 @@ message SelectorProto {
optional int32 max_pairs = 5 [default = 50];
}
+ // Only keep elements that have a bounding box.
+ message BoundingBoxFilter {
+ // If require_nonempty=false, which is the default, require elements to have
+ // at least one bounding rect returned by Element.getClientRects()
+ //
+ // If require_nonempty=true, additionally require the element's bounding
+ // client rect to have a nonzero width and height.
+ optional bool require_nonempty = 1;
+ }
+
+ // Filter out elements covered by other elements, such as overlays.
+ message OnTopFilter {
+ // If true, scroll the element into view before checking whether
+ // it's on top.
+ //
+ // The logic for checking whether an element is on top only works on
+ // elements that are positioned within the current viewport. Setting it to
+ // false turns off automatic scrolling to make the element visible, so the
+ // caller must make sure it's already the case.
+ optional bool scroll_into_view_if_needed = 1 [default = true];
+
+ // If true and the element cannot be scrolled into view, so the filter
+ // cannot check whether the element is on top, keep the element in the match
+ // set.
+ //
+ // This can be combined with scroll_into_view_if_needed=false to make
+ // this filter best effort and only check elements that are already in view.
+ optional bool accept_element_if_not_in_view = 2;
+ }
+
message EmptyFilter {}
+ message NthMatchFilter {
+ // Take the match at the given |index|.
+ optional int32 index = 1;
+ }
+
reserved 1 to 8;
}
@@ -938,6 +1306,19 @@ message SelectorProto {
message ClickProto {
optional SelectorProto element_to_click = 1;
optional ClickType click_type = 2;
+
+ // Configure whether click should check whether the element is the topmost
+ // element before clicking on it.
+ //
+ // If set to REQUIRE_STEP_SUCCESS, click might fail with ELEMENT_NOT_ON_TOP.
+ optional OptionalStep on_top = 3;
+}
+
+enum OptionalStep {
+ STEP_UNSPECIFIED = 0;
+ SKIP_STEP = 1;
+ REPORT_STEP_RESULT = 2;
+ REQUIRE_STEP_SUCCESS = 3;
}
// Contain all arguments to perform a select option action.
@@ -975,8 +1356,8 @@ message TellProto {
optional bool needs_ui = 2 [default = true];
}
-// Contain all arguments to focus on an element.
-message FocusElementProto {
+// Contain all arguments to show cast on an element.
+message ShowCastProto {
message TopPadding {
oneof top_padding {
// Padding in CSS pixels. Eg. 20.
@@ -985,8 +1366,9 @@ message FocusElementProto {
float ratio = 2;
}
}
- // Element to focus on.
- optional SelectorProto element = 1;
+
+ // Element to scroll to.
+ optional SelectorProto element_to_present = 1;
// Optional title to show in the status bar.
optional string title = 2;
@@ -1002,6 +1384,20 @@ message FocusElementProto {
// The padding that will be added between the focused element and the top.
optional TopPadding top_padding = 7;
+
+ // Configure whether the scrolling should wait for the element to be stable
+ // before scrolling.
+ //
+ // If set to REQUIRE_STEP_SUCCESS, scrolling may fail with ELEMENT_UNSTABLE.
+ optional OptionalStep wait_for_stable_element = 9;
+
+ // Maximum rounds to stable check.
+ optional int32 stable_check_max_rounds = 10 [default = 50];
+
+ // Interval for stable check in ms.
+ optional int32 stable_check_interval_ms = 11 [default = 200];
+
+ reserved 3, 4, 8;
}
// An area made up of rectangles whole border are made defined by the position
@@ -1205,9 +1601,18 @@ message ElementConditionsProto {
// Volatile upload of a portion of the dom for backend analysis, does not store
// anything.
message UploadDomProto {
+ message Result {
+ // The outer HTML of the element(s) matched by |tree_root|.
+ repeated string outer_htmls = 1;
+ }
+
// The element that should be a root of uploaded DOM. If empty then the whole
// page is returned.
optional SelectorProto tree_root = 1;
+
+ // Whether |tree_root| can match multiple elements. If false and multiple
+ // elements are matched, this action will fail with TOO_MANY_MATCHES.
+ optional bool can_match_multiple_elements = 2;
}
// Shows the progress bar.
@@ -1460,7 +1865,7 @@ message ShowGenericUiProto {
reserved 10;
}
-// Allow choosing one or more possibility. If FocusElement was called just
+// Allow choosing one or more possibility. If ShowCast was called just
// before, allow interaction with the touchable element area, otherwise don't
// allow any interactions.
message PromptProto {
@@ -1530,7 +1935,7 @@ message PromptProto {
// A list of domains and subdomains to allow users to navigate to when in
// browse mode.
- repeated string browse_domains_whitelist = 9;
+ repeated string browse_domains_allowlist = 9;
// Result to pass to ProcessedActionProto.
message Result {
@@ -1839,6 +2244,13 @@ message StopProto {
// Assistant.
optional bool close_cct = 2;
+ // Whether to show the feedback chip once Autofill Assistant has stopped.
+ // Note that this is only relevant if the UI is still being shown after the
+ // stop, which happens only if:
+ // - close_cct is false.
+ // - The action preceding this one is a Tell action.
+ optional bool show_feedback_chip = 3;
+
reserved 1; // stop_action_type
}
@@ -2352,3 +2764,85 @@ message PopupMessageProto {
// Message to show in the popup.
optional string message = 1;
}
+
+// Action to get an element's status.
+message GetElementStatusProto {
+ optional SelectorProto element = 1;
+
+ optional ValueMatch expected_value_match = 2;
+ optional ValueSource value_source = 4;
+
+ // If set and a mismatch happens, the action will report an failure status
+ // with |ELEMENT_MISMATCH|. If this flag is set to false, the action will not
+ // fail and simply report the result.
+ optional bool mismatch_should_fail = 3;
+
+ // The result that gets sent as part of |ProcessedActionProto.result_data|.
+ message Result {
+ // The field is considered not empty.
+ optional bool not_empty = 1;
+ // The field matches the expected input.
+ optional bool match_success = 2;
+ // The field was expected to match an empty expectation. For a value this
+ // means an empty expected value, for a RegExp this means the extracted
+ // match was empty.
+ optional bool expected_empty_match = 4;
+
+ // For logging and debugging.
+ repeated ComparisonReport reports = 3;
+ }
+
+ enum ValueSource {
+ NOT_SET = 0;
+ // Compare the element's |value| attribute against this expected match.
+ VALUE = 1;
+ // Compare the element's |innerText| attribute against this expected match.
+ INNER_TEXT = 2;
+ }
+
+ message MatchOptions {
+ optional bool case_sensitive = 1;
+ optional bool remove_space = 2;
+ }
+
+ message MatchExpectation {
+ optional MatchOptions match_options = 1;
+
+ oneof match_level {
+ bool full_match = 2;
+ bool contains = 3;
+ bool starts_with = 4;
+ bool ends_with = 5;
+ }
+ }
+
+ message TextMatch {
+ oneof value_source {
+ // The value to check against.
+ string value = 1;
+ // A value from an Autofill source. Note that this must be proceeded by a
+ // |CollectUserDataAction|.
+ AutofillValue autofill_value = 2;
+ // A regular expression.
+ string re2 = 4;
+ }
+
+ // Optional. The expectations to declare this as a matching success. If
+ // left empty, the action will always be treated as successful.
+ optional MatchExpectation match_expectation = 3;
+ }
+
+ message ValueMatch { optional TextMatch text_match = 1; }
+
+ message ComparisonReport {
+ optional MatchOptions match_options = 1;
+
+ optional bool full_match = 2;
+ optional bool contains = 3;
+ optional bool starts_with = 4;
+ optional bool ends_with = 5;
+
+ optional bool empty = 6;
+ optional bool expected_empty_match = 7;
+ }
+}
diff --git a/chromium/components/autofill_assistant/browser/access_token_fetcher.h b/chromium/components/autofill_assistant/browser/service/access_token_fetcher.h
index c8759f78045..e13d45fd362 100644
--- a/chromium/components/autofill_assistant/browser/access_token_fetcher.h
+++ b/chromium/components/autofill_assistant/browser/service/access_token_fetcher.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_ACCESS_TOKEN_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_ACCESS_TOKEN_FETCHER_H_
#include <string>
@@ -30,4 +30,4 @@ class AccessTokenFetcher {
AccessTokenFetcher() = default;
};
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_ACCESS_TOKEN_FETCHER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/api_key_fetcher.cc b/chromium/components/autofill_assistant/browser/service/api_key_fetcher.cc
new file mode 100644
index 00000000000..36d4bbb6fc7
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/api_key_fetcher.cc
@@ -0,0 +1,28 @@
+// Copyright 2020 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_assistant/browser/service/api_key_fetcher.h"
+
+#include "base/command_line.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "google_apis/google_api_keys.h"
+
+namespace autofill_assistant {
+
+std::string ApiKeyFetcher::GetAPIKey(version_info::Channel channel) {
+ const auto* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kAutofillAssistantServerKey)) {
+ return command_line->GetSwitchValueASCII(
+ switches::kAutofillAssistantServerKey);
+ }
+
+ if (google_apis::IsGoogleChromeAPIKeyUsed()) {
+ return channel == version_info::Channel::STABLE
+ ? google_apis::GetAPIKey()
+ : google_apis::GetNonStableAPIKey();
+ }
+ return "";
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/api_key_fetcher.h b/chromium/components/autofill_assistant/browser/service/api_key_fetcher.h
new file mode 100644
index 00000000000..e457d5b1654
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/api_key_fetcher.h
@@ -0,0 +1,19 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_API_KEY_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_API_KEY_FETCHER_H_
+
+#include <string>
+#include "components/version_info/version_info.h"
+
+namespace autofill_assistant {
+
+// Wrapper interface to allow mocking this in unit tests.
+struct ApiKeyFetcher {
+ virtual std::string GetAPIKey(version_info::Channel channel);
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_API_KEY_FETCHER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/api_key_fetcher_unittest.cc b/chromium/components/autofill_assistant/browser/service/api_key_fetcher_unittest.cc
new file mode 100644
index 00000000000..fc4ab44e648
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/api_key_fetcher_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 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_assistant/browser/service/api_key_fetcher.h"
+
+#include "base/command_line.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "components/version_info/version_info.h"
+#include "google_apis/google_api_keys.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::Eq;
+
+TEST(ApiKeyFetcherTest, GetAPIKeyCommandLineOverride) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kAutofillAssistantServerKey, "fake_key");
+
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::STABLE),
+ Eq("fake_key"));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::UNKNOWN),
+ Eq("fake_key"));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::CANARY),
+ Eq("fake_key"));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::DEV),
+ Eq("fake_key"));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::BETA),
+ Eq("fake_key"));
+}
+
+TEST(ApiKeyFetcherTest, GetAPIKeyReturnsStableAndNonstableKeys) {
+ base::CommandLine::ForCurrentProcess()->RemoveSwitch(
+ switches::kAutofillAssistantServerKey);
+ // Only run tests on Google Chrome builds. This intentionally does not gate
+ // the test with a precompiler definition, because a change to
+ // |IsGoogleChromeAPIKeyUsed| would go unnoticed by us.
+ if (!google_apis::IsGoogleChromeAPIKeyUsed()) {
+ return;
+ }
+
+ std::string api_key_stable = google_apis::GetAPIKey();
+ std::string api_key_nonstable = google_apis::GetNonStableAPIKey();
+
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::STABLE),
+ Eq(api_key_stable));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::UNKNOWN),
+ Eq(api_key_nonstable));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::CANARY),
+ Eq(api_key_nonstable));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::DEV),
+ Eq(api_key_nonstable));
+ EXPECT_THAT(ApiKeyFetcher().GetAPIKey(version_info::Channel::BETA),
+ Eq(api_key_nonstable));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/java_service.cc b/chromium/components/autofill_assistant/browser/service/java_service.cc
index 358f2f77071..63c54611ca0 100644
--- a/chromium/components/autofill_assistant/browser/java_service.cc
+++ b/chromium/components/autofill_assistant/browser/service/java_service.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 "components/autofill_assistant/browser/java_service.h"
+#include "components/autofill_assistant/browser/service/java_service.h"
#include <string>
#include <vector>
@@ -12,6 +12,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
+#include "net/http/http_status_code.h"
namespace autofill_assistant {
@@ -41,7 +42,7 @@ void JavaService::GetScriptsForUrl(const GURL& url,
base::android::ConvertUTF8ToJavaString(env, url.spec()));
std::string response;
base::android::JavaByteArrayToString(env, jresponse, &response);
- std::move(callback).Run(true, response);
+ std::move(callback).Run(net::HTTP_OK, response);
}
void JavaService::GetActions(const std::string& script_path,
@@ -59,7 +60,7 @@ void JavaService::GetActions(const std::string& script_path,
base::android::ToJavaByteArray(env, script_payload));
std::string response;
base::android::JavaByteArrayToString(env, jresponse, &response);
- std::move(callback).Run(true, response);
+ std::move(callback).Run(net::HTTP_OK, response);
}
void JavaService::GetNextActions(
@@ -67,6 +68,7 @@ void JavaService::GetNextActions(
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) {
JNIEnv* env = base::android::AttachCurrentThread();
auto jprocessed_actions =
@@ -86,7 +88,7 @@ void JavaService::GetNextActions(
jprocessed_actions);
std::string response;
base::android::JavaByteArrayToString(env, jresponse, &response);
- std::move(callback).Run(true, response);
+ std::move(callback).Run(net::HTTP_OK, response);
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/java_service.h b/chromium/components/autofill_assistant/browser/service/java_service.h
index eb5d81c79f5..a06827aff4c 100644
--- a/chromium/components/autofill_assistant/browser/java_service.h
+++ b/chromium/components/autofill_assistant/browser/service/java_service.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JAVA_SERVICE_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JAVA_SERVICE_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_H_
#include <memory>
#include <string>
@@ -11,11 +11,14 @@
#include "base/android/scoped_java_ref.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "url/gurl.h"
namespace autofill_assistant {
+// TODO(arbesser) Move this to chrome/browser/android, it does not belong into
+// components/autofill_assistant. This interface should be callback-based only.
+//
// Thin C++ wrapper around a service implemented in Java. Intended for use in
// Java UI tests to inject a Java service as a substitute to the native service.
class JavaService : public Service {
@@ -46,6 +49,7 @@ class JavaService : public Service {
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) override;
private:
@@ -56,4 +60,4 @@ class JavaService : public Service {
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JAVA_SERVICE_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_H_
diff --git a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc
new file mode 100644
index 00000000000..7fa568dea8b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc
@@ -0,0 +1,52 @@
+// Copyright 2020 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_assistant/browser/service/java_service_request_sender.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "chrome/android/features/autofill_assistant/test_support_jni_headers/AutofillAssistantTestServiceRequestSender_jni.h"
+
+namespace autofill_assistant {
+
+static jlong JNI_AutofillAssistantTestServiceRequestSender_CreateNative(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& java_service_request_sender) {
+ return reinterpret_cast<jlong>(
+ new JavaServiceRequestSender(java_service_request_sender));
+}
+
+JavaServiceRequestSender::JavaServiceRequestSender(
+ const base::android::JavaParamRef<jobject>& jservice_request_sender)
+ : jservice_request_sender_(jservice_request_sender) {}
+JavaServiceRequestSender::~JavaServiceRequestSender() = default;
+
+void JavaServiceRequestSender::SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) {
+ DCHECK(!callback_)
+ << __func__
+ << " invoked while still waiting for response to previous request";
+ callback_ = std::move(callback);
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_AutofillAssistantTestServiceRequestSender_sendRequest(
+ env, jservice_request_sender_,
+ base::android::ConvertUTF8ToJavaString(env, url.spec()),
+ base::android::ToJavaByteArray(env, request_body));
+}
+
+void JavaServiceRequestSender::OnResponse(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint http_status,
+ const base::android::JavaParamRef<jbyteArray>& jresponse) {
+ DCHECK(callback_);
+ std::string response;
+ if (jresponse) {
+ base::android::JavaByteArrayToString(env, jresponse, &response);
+ }
+ std::move(callback_).Run(http_status, response);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h
new file mode 100644
index 00000000000..b602aa61812
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h
@@ -0,0 +1,48 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_REQUEST_SENDER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_REQUEST_SENDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/android/jni_array.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+// TODO(arbesser): Move this to chrome/browser/android, it does not belong into
+// components/autofill_assistant.
+//
+// Thin C++ wrapper around a service request sender implemented in Java.
+// Intended for use in integration tests to inject as a mock backend.
+class JavaServiceRequestSender : public ServiceRequestSender {
+ public:
+ JavaServiceRequestSender(
+ const base::android::JavaParamRef<jobject>& jservice_request_sender);
+ ~JavaServiceRequestSender() override;
+ JavaServiceRequestSender(const JavaServiceRequestSender&) = delete;
+ JavaServiceRequestSender& operator=(const JavaServiceRequestSender&) = delete;
+
+ void SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) override;
+
+ void OnResponse(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint http_status,
+ const base::android::JavaParamRef<jbyteArray>& jresponse);
+
+ private:
+ ResponseCallback callback_;
+ base::android::ScopedJavaGlobalRef<jobject> jservice_request_sender_;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_JAVA_SERVICE_REQUEST_SENDER_H_
diff --git a/chromium/components/autofill_assistant/browser/lite_service.cc b/chromium/components/autofill_assistant/browser/service/lite_service.cc
index aac5a068fa9..f0722149149 100644
--- a/chromium/components/autofill_assistant/browser/lite_service.cc
+++ b/chromium/components/autofill_assistant/browser/service/lite_service.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill_assistant/browser/lite_service.h"
-#include "components/autofill_assistant/browser/lite_service_util.h"
+#include "components/autofill_assistant/browser/service/lite_service.h"
+#include "components/autofill_assistant/browser/service/lite_service_util.h"
#include <algorithm>
#include <string>
@@ -12,16 +12,20 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "components/autofill_assistant/browser/protocol_utils.h"
+#include "net/http/http_status_code.h"
namespace autofill_assistant {
LiteService::LiteService(
- std::unique_ptr<Service> service_impl,
+ std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& get_actions_server_url,
const std::string& trigger_script_path,
base::OnceCallback<void(Metrics::LiteScriptFinishedState)>
notify_finished_callback,
base::RepeatingCallback<void(bool)> notify_script_running_callback)
- : service_impl_(std::move(service_impl)),
+ : request_sender_(std::move(request_sender)),
+ get_actions_server_url_(get_actions_server_url),
trigger_script_path_(trigger_script_path),
notify_finished_callback_(std::move(notify_finished_callback)),
notify_script_running_callback_(
@@ -50,7 +54,7 @@ void LiteService::GetScriptsForUrl(const GURL& url,
std::string serialized_response;
response.SerializeToString(&serialized_response);
- std::move(callback).Run(true, serialized_response);
+ std::move(callback).Run(net::HTTP_OK, serialized_response);
}
void LiteService::GetActions(const std::string& script_path,
@@ -69,18 +73,20 @@ void LiteService::GetActions(const std::string& script_path,
// Note: trigger context and payloads should not be sent to the backend for
// privacy reasons.
- service_impl_->GetActions(
- trigger_script_path_, GURL(), TriggerContextImpl(),
- /* global_payload = */ std::string(),
- /* script_payload = */ std::string(),
+ request_sender_->SendRequest(
+ get_actions_server_url_,
+ ProtocolUtils::CreateInitialScriptActionsRequest(
+ trigger_script_path_, GURL(), /* global_payload = */ std::string(),
+ /* script_payload = */ std::string(), EmptyClientContext().AsProto(),
+ /* script_parameters = */ {}),
base::BindOnce(&LiteService::OnGetActions, weak_ptr_factory_.GetWeakPtr(),
std::move(callback)));
}
void LiteService::OnGetActions(ResponseCallback callback,
- bool result,
+ int http_status,
const std::string& response) {
- if (!result) {
+ if (http_status != net::HTTP_OK) {
StopWithoutErrorMessage(
std::move(callback),
Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
@@ -131,7 +137,7 @@ void LiteService::OnGetActions(ResponseCallback callback,
std::string serialized_first_part;
split_actions->first.SerializeToString(&serialized_first_part);
- std::move(callback).Run(result, serialized_first_part);
+ std::move(callback).Run(http_status, serialized_first_part);
notify_script_running_callback_.Run(/*ui_shown = */ false);
}
@@ -140,12 +146,13 @@ void LiteService::GetNextActions(
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) {
if (!notify_finished_callback_) {
// The lite script has already terminated. We need to run |callback| with
// |success|=true and an empty response to ensure a graceful stop of the
// script (i.e., without error message).
- std::move(callback).Run(true, std::string());
+ std::move(callback).Run(net::HTTP_OK, std::string());
return;
}
@@ -178,7 +185,7 @@ void LiteService::GetNextActions(
std::string serialized_second_part;
trigger_script_second_part_->SerializeToString(&serialized_second_part);
trigger_script_second_part_.reset();
- std::move(callback).Run(true, serialized_second_part);
+ std::move(callback).Run(net::HTTP_OK, serialized_second_part);
notify_script_running_callback_.Run(/*ui_shown = */ true);
return;
}
@@ -233,7 +240,7 @@ void LiteService::StopWithoutErrorMessage(
response.add_actions()->mutable_stop();
std::string serialized_response;
response.SerializeToString(&serialized_response);
- std::move(callback).Run(true, serialized_response);
+ std::move(callback).Run(net::HTTP_OK, serialized_response);
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/lite_service.h b/chromium/components/autofill_assistant/browser/service/lite_service.h
index cc813386874..7072ae90f78 100644
--- a/chromium/components/autofill_assistant/browser/lite_service.h
+++ b/chromium/components/autofill_assistant/browser/service/lite_service.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_H_
#include <memory>
#include <string>
@@ -12,7 +12,8 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/metrics.h"
-#include "components/autofill_assistant/browser/service_impl.h"
+#include "components/autofill_assistant/browser/service/service_impl.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
#include "components/version_info/version_info.h"
#include "url/gurl.h"
@@ -25,7 +26,8 @@ namespace autofill_assistant {
class LiteService : public Service {
public:
explicit LiteService(
- std::unique_ptr<Service> service_impl,
+ std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& get_actions_server_url,
const std::string& trigger_script_path,
base::OnceCallback<void(Metrics::LiteScriptFinishedState)>
notify_finished_callback,
@@ -62,13 +64,14 @@ class LiteService : public Service {
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) override;
private:
friend class LiteServiceTest;
void OnGetActions(ResponseCallback callback,
- bool result,
+ int http_status,
const std::string& response);
// Stops the script and closes autofill assistant without showing an error
@@ -77,8 +80,12 @@ class LiteService : public Service {
void StopWithoutErrorMessage(ResponseCallback callback,
Metrics::LiteScriptFinishedState state);
- // The actual service that communicates with the backend.
- std::unique_ptr<Service> service_impl_;
+ // The request sender that communicates with the backend.
+ std::unique_ptr<ServiceRequestSender> request_sender_;
+
+ // The GURL of the GetActions/GetNextActions rpc handler.
+ GURL get_actions_server_url_;
+
// The script path to fetch actions from.
std::string trigger_script_path_;
@@ -109,4 +116,4 @@ class LiteService : public Service {
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_H_
diff --git a/chromium/components/autofill_assistant/browser/lite_service_unittest.cc b/chromium/components/autofill_assistant/browser/service/lite_service_unittest.cc
index 64e34d7e3f7..7ad2f451440 100644
--- a/chromium/components/autofill_assistant/browser/lite_service_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/lite_service_unittest.cc
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill_assistant/browser/lite_service.h"
-#include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/service/lite_service.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/mock_service.h"
+#include "components/autofill_assistant/browser/service/mock_service_request_sender.h"
+#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/test_util.h"
#include "components/autofill_assistant/browser/trigger_context.h"
@@ -13,48 +14,49 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/notreached.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/gtest_util.h"
#include "base/test/mock_callback.h"
+#include "net/http/http_status_code.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
namespace {
const char kFakeScriptPath[] = "localhost/chrome/test";
const char kFakeUrl[] = "https://www.example.com";
+const char kGetActionsServerUrl[] =
+ "https://www.fake.backend.com/action_server";
} // namespace
using ::testing::_;
using ::testing::AtMost;
using ::testing::Eq;
+using ::testing::NiceMock;
class LiteServiceTest : public testing::Test {
protected:
LiteServiceTest() {
- auto service_impl = std::make_unique<MockService>();
- mock_native_service_ = service_impl.get();
+ auto mock_request_sender =
+ std::make_unique<NiceMock<MockServiceRequestSender>>();
+ mock_request_sender_ = mock_request_sender.get();
lite_service_ = std::make_unique<LiteService>(
- std::move(service_impl), kFakeScriptPath, mock_finished_callback_.Get(),
+ std::move(mock_request_sender), GURL(kGetActionsServerUrl),
+ kFakeScriptPath, mock_finished_callback_.Get(),
mock_script_running_callback_.Get());
- EXPECT_CALL(*mock_native_service_, OnGetScriptsForUrl).Times(0);
- EXPECT_CALL(*mock_native_service_, OnGetNextActions).Times(0);
- EXPECT_CALL(*mock_native_service_,
- OnGetActions(kFakeScriptPath, _, _, _, _, _))
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kGetActionsServerUrl), _, _))
.Times(AtMost(1))
- .WillOnce([&](const std::string& script_path, const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
+ .WillOnce([&](const GURL& url, const std::string& request_body,
Service::ResponseCallback& callback) {
std::string serialized_response;
get_actions_response_.SerializeToString(&serialized_response);
- std::move(callback).Run(true, serialized_response);
+ std::move(callback).Run(net::HTTP_OK, serialized_response);
});
}
~LiteServiceTest() override {}
@@ -72,17 +74,18 @@ class LiteServiceTest : public testing::Test {
stop.add_actions()->mutable_stop();
std::string serialized_stop;
stop.SerializeToString(&serialized_stop);
- EXPECT_CALL(mock_response_callback_, Run(true, serialized_stop)).Times(1);
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, serialized_stop))
+ .Times(1);
EXPECT_CALL(mock_finished_callback_, Run(state));
}
+ NiceMock<MockServiceRequestSender>* mock_request_sender_;
base::MockCallback<base::OnceCallback<void(Metrics::LiteScriptFinishedState)>>
mock_finished_callback_;
base::MockCallback<base::RepeatingCallback<void(bool)>>
mock_script_running_callback_;
- base::MockCallback<base::OnceCallback<void(bool, const std::string&)>>
+ base::MockCallback<base::OnceCallback<void(int, const std::string&)>>
mock_response_callback_;
- MockService* mock_native_service_ = nullptr;
std::unique_ptr<LiteService> lite_service_;
ActionsResponseProto get_actions_response_;
};
@@ -96,16 +99,17 @@ TEST_F(LiteServiceTest, RunsNotificationOnDelete) {
notification_callback,
Run(Metrics::LiteScriptFinishedState::LITE_SCRIPT_SERVICE_DELETED));
{
- LiteService lite_service(std::make_unique<MockService>(), kFakeScriptPath,
- notification_callback.Get(),
- script_running_callback.Get());
+ LiteService lite_service(
+ std::make_unique<NiceMock<MockServiceRequestSender>>(),
+ GURL(kGetActionsServerUrl), kFakeScriptPath,
+ notification_callback.Get(), script_running_callback.Get());
}
}
TEST_F(LiteServiceTest, GetScriptsForUrl) {
- EXPECT_CALL(mock_response_callback_, Run(true, _))
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, _))
.Times(1)
- .WillOnce([](bool success, const std::string& response) {
+ .WillOnce([](int http_status, const std::string& response) {
SupportsScriptResponseProto proto;
ASSERT_TRUE(proto.ParseFromString(response));
@@ -123,20 +127,20 @@ TEST_F(LiteServiceTest, GetActionsOnlySendsScriptPath) {
TriggerContextImpl non_empty_context;
non_empty_context.SetCallerAccountHash("something");
- EXPECT_CALL(*mock_native_service_,
- OnGetActions(kFakeScriptPath, _, _, _, _, _))
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kGetActionsServerUrl), _, _))
.Times(1)
- .WillOnce([&](const std::string& script_path, const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
+ .WillOnce([&](const GURL& url, const std::string& request_body,
Service::ResponseCallback& callback) {
- EXPECT_THAT(script_path, Eq(kFakeScriptPath));
+ ScriptActionRequestProto rpc_proto;
+ ASSERT_TRUE(rpc_proto.ParseFromString(request_body));
+
+ EXPECT_THAT(rpc_proto.initial_request().query().script_path(0),
+ Eq(kFakeScriptPath));
// All other information has been cleared.
- EXPECT_THAT(url, Eq(GURL()));
- EXPECT_THAT(trigger_context.get_caller_account_hash(), Eq(""));
- EXPECT_THAT(global_payload, Eq(""));
- EXPECT_THAT(script_payload, Eq(""));
+ EXPECT_THAT(rpc_proto.global_payload(), Eq(""));
+ EXPECT_THAT(rpc_proto.script_payload(), Eq(""));
+ EXPECT_THAT(rpc_proto.client_context(), Eq(ClientContextProto()));
});
lite_service_->GetActions(kFakeScriptPath, GURL(kFakeUrl), non_empty_context,
@@ -155,15 +159,12 @@ TEST_F(LiteServiceTest, GetActionsOnlyFetchesFromScriptPath) {
TEST_F(LiteServiceTest, StopsOnGetActionsFailed) {
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
- EXPECT_CALL(*mock_native_service_,
- OnGetActions(kFakeScriptPath, _, _, _, _, _))
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kGetActionsServerUrl), _, _))
.Times(1)
- .WillOnce([&](const std::string& script_path, const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
+ .WillOnce([&](const GURL& url, const std::string& request_body,
Service::ResponseCallback& callback) {
- std::move(callback).Run(false, std::string());
+ std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
});
EXPECT_CALL(mock_script_running_callback_, Run).Times(0);
@@ -175,15 +176,12 @@ TEST_F(LiteServiceTest, StopsOnGetActionsFailed) {
TEST_F(LiteServiceTest, StopsOnGetActionsParsingError) {
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR);
- EXPECT_CALL(*mock_native_service_,
- OnGetActions(kFakeScriptPath, _, _, _, _, _))
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kGetActionsServerUrl), _, _))
.Times(1)
- .WillOnce([&](const std::string& script_path, const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
+ .WillOnce([&](const GURL& url, const std::string& request_body,
Service::ResponseCallback& callback) {
- std::move(callback).Run(true, std::string("invalid proto"));
+ std::move(callback).Run(net::HTTP_OK, std::string("invalid proto"));
});
EXPECT_CALL(mock_script_running_callback_, Run).Times(0);
lite_service_->GetActions(kFakeScriptPath, GURL(kFakeUrl),
@@ -206,7 +204,7 @@ TEST_F(LiteServiceTest, StopsOnGetActionsContainsUnsafeActions) {
TEST_F(LiteServiceTest, GetActionsSucceedsForMinimalViableScript) {
get_actions_response_.add_actions()->mutable_prompt()->set_browse_mode(true);
get_actions_response_.add_actions()->mutable_prompt();
- EXPECT_CALL(mock_response_callback_, Run(true, _));
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, _));
EXPECT_CALL(mock_script_running_callback_, Run(/*ui_shown =*/false)).Times(1);
lite_service_->GetActions(kFakeScriptPath, GURL(kFakeUrl),
TriggerContextImpl(), "", "",
@@ -233,9 +231,9 @@ TEST_F(LiteServiceTest, GetActionsSplitsActionsResponseAtLastBrowse) {
}
std::vector<ProcessedActionProto> processed_actions;
- EXPECT_CALL(mock_response_callback_, Run(true, _))
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, _))
.Times(1)
- .WillOnce([&](bool result, const std::string& response) {
+ .WillOnce([&](int http_status, const std::string& response) {
// Can't directly compare the protos here, because the lite service
// will have automatically assigned unique payloads to prompts.
ActionsResponseProto proto;
@@ -269,9 +267,9 @@ TEST_F(LiteServiceTest, GetActionsSplitsActionsResponseAtLastBrowse) {
TriggerContextImpl(), "", "",
mock_response_callback_.Get());
- EXPECT_CALL(mock_response_callback_, Run(true, _))
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, _))
.Times(1)
- .WillOnce([&](bool result, const std::string& response) {
+ .WillOnce([&](int http_result, const std::string& response) {
ActionsResponseProto proto;
ASSERT_TRUE(proto.ParseFromString(response));
ASSERT_TRUE(proto.actions().size() == 1);
@@ -282,6 +280,7 @@ TEST_F(LiteServiceTest, GetActionsSplitsActionsResponseAtLastBrowse) {
EXPECT_CALL(mock_script_running_callback_, Run(/*ui_shown =*/true)).Times(1);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -296,6 +295,7 @@ TEST_F(LiteServiceTest, GetNextActionsFirstPartStopsOnUserNavigateAway) {
Metrics::LiteScriptFinishedState::LITE_SCRIPT_BROWSE_FAILED_NAVIGATE);
EXPECT_CALL(mock_script_running_callback_, Run(/*ui_shown =*/true)).Times(0);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -312,9 +312,10 @@ TEST_F(LiteServiceTest, GetNextActionsFirstPartSucceedsOnAutoSelectChoice) {
processed_actions.back().mutable_prompt_choice()->set_server_payload(
"payload");
- EXPECT_CALL(mock_response_callback_, Run(true, ""));
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, ""));
EXPECT_CALL(mock_script_running_callback_, Run(/*ui_shown =*/true)).Times(1);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -331,14 +332,16 @@ TEST_F(LiteServiceTest, GetNextActionsSecondPartOnlyServedOnce) {
processed_actions.back().mutable_prompt_choice()->set_server_payload(
"payload");
- EXPECT_CALL(mock_response_callback_, Run(true, "")).Times(1);
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "")).Times(1);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::
LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -357,6 +360,7 @@ TEST_F(LiteServiceTest, GetNextActionsSecondPartStopsWhenUserCancels) {
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_CLOSE);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -376,6 +380,7 @@ TEST_F(LiteServiceTest, GetNextActionsSecondPartStopsWhenUserNavigatesBack) {
Metrics::LiteScriptFinishedState::
LITE_SCRIPT_PROMPT_FAILED_CONDITION_NO_LONGER_TRUE);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -388,6 +393,7 @@ TEST_F(LiteServiceTest, GetNextActionsSecondPartStopsWhenUserNavigatesAway) {
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
@@ -402,10 +408,10 @@ TEST_F(LiteServiceTest, GetNextActionsSecondPartStopsWhenUserAgrees) {
processed_actions.back().set_status(ACTION_APPLIED);
processed_actions.back().mutable_prompt_choice()->set_server_payload(
"payload");
-
ExpectStopWithFinishedState(
Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
lite_service_->GetNextActions(TriggerContextImpl(), "", "", processed_actions,
+ RoundtripTimingStats(),
mock_response_callback_.Get());
}
diff --git a/chromium/components/autofill_assistant/browser/lite_service_util.cc b/chromium/components/autofill_assistant/browser/service/lite_service_util.cc
index 51bcc218c22..18aec34f210 100644
--- a/chromium/components/autofill_assistant/browser/lite_service_util.cc
+++ b/chromium/components/autofill_assistant/browser/service/lite_service_util.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 "components/autofill_assistant/browser/lite_service_util.h"
+#include "components/autofill_assistant/browser/service/lite_service_util.h"
#include <algorithm>
#include <memory>
@@ -117,6 +117,7 @@ ActionResponseType GetActionResponseType(const ProcessedActionProto& proto) {
case HIGHLIGHTED_ACTION:
case NORMAL_ACTION:
case CANCEL_ACTION:
+ case FEEDBACK_ACTION:
return ActionResponseType::UNKNOWN;
case CLOSE_ACTION:
return ActionResponseType::PROMPT_CLOSE;
diff --git a/chromium/components/autofill_assistant/browser/lite_service_util.h b/chromium/components/autofill_assistant/browser/service/lite_service_util.h
index 8590d04b594..2af431f7e18 100644
--- a/chromium/components/autofill_assistant/browser/lite_service_util.h
+++ b/chromium/components/autofill_assistant/browser/service/lite_service_util.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_UTIL_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_UTIL_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_UTIL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_UTIL_H_
#include <string>
#include "base/optional.h"
@@ -43,4 +43,4 @@ void AssignUniquePayloadsToPrompts(ActionsResponseProto* proto);
} // namespace lite_service_util
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_LITE_SERVICE_UTIL_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_LITE_SERVICE_UTIL_H_
diff --git a/chromium/components/autofill_assistant/browser/lite_service_util_unittest.cc b/chromium/components/autofill_assistant/browser/service/lite_service_util_unittest.cc
index 3aa602e5cdb..594796a8124 100644
--- a/chromium/components/autofill_assistant/browser/lite_service_util_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/lite_service_util_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 "components/autofill_assistant/browser/lite_service_util.h"
+#include "components/autofill_assistant/browser/service/lite_service_util.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/test_util.h"
@@ -111,7 +111,7 @@ TEST(LiteServiceUtilTest, ContainsOnlySafeActions) {
unsafe_actions.add_actions()->mutable_set_form_value();
unsafe_actions.add_actions()->mutable_select_option();
unsafe_actions.add_actions()->mutable_navigate();
- unsafe_actions.add_actions()->mutable_focus_element();
+ unsafe_actions.add_actions()->mutable_show_cast();
unsafe_actions.add_actions()->mutable_use_card();
unsafe_actions.add_actions()->mutable_use_address();
unsafe_actions.add_actions()->mutable_upload_dom();
@@ -137,7 +137,7 @@ TEST(LiteServiceUtilTest, GetActionResponseType) {
proto.set_status(ACTION_APPLIED);
EXPECT_EQ(GetActionResponseType(proto), ActionResponseType::UNKNOWN);
- proto.mutable_html_source();
+ proto.mutable_upload_dom_result();
EXPECT_EQ(GetActionResponseType(proto), ActionResponseType::UNKNOWN);
proto.mutable_collect_user_data_result();
EXPECT_EQ(GetActionResponseType(proto), ActionResponseType::UNKNOWN);
diff --git a/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.cc b/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.cc
new file mode 100644
index 00000000000..a724f6b564f
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/service/mock_access_token_fetcher.h"
+
+namespace autofill_assistant {
+
+MockAccessTokenFetcher::MockAccessTokenFetcher() = default;
+MockAccessTokenFetcher::~MockAccessTokenFetcher() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.h b/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.h
new file mode 100644
index 00000000000..7f3b640c5d2
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_access_token_fetcher.h
@@ -0,0 +1,35 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_MOCK_ACCESS_TOKEN_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_ACCESS_TOKEN_FETCHER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockAccessTokenFetcher : public AccessTokenFetcher {
+ public:
+ MockAccessTokenFetcher();
+ ~MockAccessTokenFetcher() override;
+
+ void FetchAccessToken(
+ base::OnceCallback<void(bool, const std::string&)> callback) override {
+ OnFetchAccessToken(callback);
+ }
+
+ MOCK_METHOD1(
+ OnFetchAccessToken,
+ void(base::OnceCallback<void(bool, const std::string&)>& callback));
+
+ MOCK_METHOD1(InvalidateAccessToken, void(const std::string& access_token));
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_ACCESS_TOKEN_FETCHER_H_
diff --git a/chromium/components/autofill_assistant/browser/mock_service.cc b/chromium/components/autofill_assistant/browser/service/mock_service.cc
index c6803744565..0b6ce7b7849 100644
--- a/chromium/components/autofill_assistant/browser/mock_service.cc
+++ b/chromium/components/autofill_assistant/browser/service/mock_service.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 "components/autofill_assistant/browser/mock_service.h"
+#include "components/autofill_assistant/browser/service/mock_service.h"
#include "components/autofill_assistant/browser/device_context.h"
#include "components/autofill_assistant/browser/trigger_context.h"
@@ -11,12 +11,10 @@
namespace autofill_assistant {
MockService::MockService()
- : ServiceImpl(std::string("api_key"),
- GURL("http://fake"),
- nullptr,
- nullptr,
- nullptr,
- true) {}
+ : ServiceImpl(/* request_sender = */ nullptr,
+ /* script_server_url = */ GURL("http://fake"),
+ /* action_server_url = */ GURL("http://fake"),
+ /* client_context = */ nullptr) {}
MockService::~MockService() {}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_service.h b/chromium/components/autofill_assistant/browser/service/mock_service.h
index edb2abbcc9c..05d1a388186 100644
--- a/chromium/components/autofill_assistant/browser/mock_service.h
+++ b/chromium/components/autofill_assistant/browser/service/mock_service.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_SERVICE_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_SERVICE_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_H_
#include <map>
#include <string>
#include <vector>
-#include "components/autofill_assistant/browser/service_impl.h"
+#include "components/autofill_assistant/browser/service/service_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -55,15 +55,18 @@ class MockService : public ServiceImpl {
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) override {
OnGetNextActions(trigger_context, previous_global_payload,
- previous_script_payload, processed_actions, callback);
+ previous_script_payload, processed_actions, timing_stats,
+ callback);
}
- MOCK_METHOD5(OnGetNextActions,
+ MOCK_METHOD6(OnGetNextActions,
void(const TriggerContext& trigger_contexts,
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback& callback));
MOCK_CONST_METHOD0(IsLiteService, bool());
@@ -71,4 +74,4 @@ class MockService : public ServiceImpl {
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_SERVICE_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_H_
diff --git a/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.cc b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.cc
new file mode 100644
index 00000000000..2dbf70f89d4
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/service/mock_service_request_sender.h"
+
+namespace autofill_assistant {
+
+MockServiceRequestSender::MockServiceRequestSender() = default;
+MockServiceRequestSender::~MockServiceRequestSender() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h
new file mode 100644
index 00000000000..2911f6f92b6
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h
@@ -0,0 +1,35 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_REQUEST_SENDER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_REQUEST_SENDER_H_
+
+#include <string>
+
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+class MockServiceRequestSender : public ServiceRequestSender {
+ public:
+ MockServiceRequestSender();
+ ~MockServiceRequestSender() override;
+
+ void SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) override {
+ OnSendRequest(url, request_body, callback);
+ }
+
+ MOCK_METHOD3(OnSendRequest,
+ void(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback& callback));
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SERVICE_REQUEST_SENDER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.cc b/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.cc
new file mode 100644
index 00000000000..10fd7fb82b1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/service/mock_simple_url_loader_factory.h"
+
+namespace autofill_assistant {
+
+MockSimpleURLLoaderFactory::MockSimpleURLLoaderFactory() = default;
+MockSimpleURLLoaderFactory::~MockSimpleURLLoaderFactory() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h b/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h
new file mode 100644
index 00000000000..9890af3c4cf
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h
@@ -0,0 +1,37 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_MOCK_SIMPLE_URL_LOADER_FACTORY_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SIMPLE_URL_LOADER_FACTORY_H_
+
+#include <memory>
+
+#include "components/autofill_assistant/browser/service/simple_url_loader_factory.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockSimpleURLLoaderFactory : public SimpleURLLoaderFactory {
+ public:
+ MockSimpleURLLoaderFactory();
+ ~MockSimpleURLLoaderFactory() override;
+
+ std::unique_ptr<::network::SimpleURLLoader> CreateLoader(
+ std::unique_ptr<::network::ResourceRequest> resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) const override {
+ return OnCreateLoader(resource_request.get(), annotation_tag);
+ }
+
+ MOCK_CONST_METHOD2(
+ OnCreateLoader,
+ std::unique_ptr<::network::SimpleURLLoader>(
+ ::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag));
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_SIMPLE_URL_LOADER_FACTORY_H_
diff --git a/chromium/components/autofill_assistant/browser/service/mock_url_loader.cc b/chromium/components/autofill_assistant/browser/service/mock_url_loader.cc
new file mode 100644
index 00000000000..5d5bd0fa279
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_url_loader.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/service/mock_url_loader.h"
+
+namespace autofill_assistant {
+
+MockURLLoader::MockURLLoader() = default;
+MockURLLoader::~MockURLLoader() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_url_loader.h b/chromium/components/autofill_assistant/browser/service/mock_url_loader.h
new file mode 100644
index 00000000000..7dd7fea0323
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_url_loader.h
@@ -0,0 +1,84 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_MOCK_URL_LOADER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_URL_LOADER_H_
+
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+} // namespace mojom
+} // namespace network
+
+namespace autofill_assistant {
+
+// TODO(arbesser): Remove this once we pass in the mojom interface to our
+// service, instead of the SimpleURLLoader.
+class MockURLLoader : public ::network::SimpleURLLoader {
+ public:
+ MockURLLoader();
+ ~MockURLLoader() override;
+ MOCK_METHOD3(DownloadToString,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback,
+ size_t max_body_size));
+ MOCK_METHOD2(DownloadToStringOfUnboundedSizeUntilCrashAndDie,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback));
+ MOCK_METHOD2(DownloadHeadersOnly,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ HeadersOnlyCallback headers_only_callback));
+ MOCK_METHOD4(
+ DownloadToFile,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ const base::FilePath& file_path,
+ int64_t max_body_size));
+ MOCK_METHOD3(
+ DownloadToTempFile,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ int64_t max_body_size));
+ MOCK_METHOD2(DownloadAsStream,
+ void(::network::mojom::URLLoaderFactory* url_loader_factory,
+ ::network::SimpleURLLoaderStreamConsumer* stream_consumer));
+ MOCK_METHOD1(SetOnRedirectCallback,
+ void(const OnRedirectCallback& on_redirect_callback));
+ MOCK_METHOD1(SetOnResponseStartedCallback,
+ void(OnResponseStartedCallback on_response_started_callback));
+ MOCK_METHOD1(SetOnUploadProgressCallback,
+ void(UploadProgressCallback on_upload_progress_callback));
+ MOCK_METHOD1(SetOnDownloadProgressCallback,
+ void(DownloadProgressCallback on_download_progress_callback));
+ MOCK_METHOD1(SetAllowPartialResults, void(bool allow_partial_results));
+ MOCK_METHOD1(SetAllowHttpErrorResults, void(bool allow_http_error_results));
+ MOCK_METHOD2(AttachStringForUpload,
+ void(const std::string& upload_data,
+ const std::string& upload_content_type));
+ MOCK_METHOD4(AttachFileForUpload,
+ void(const base::FilePath& upload_file_path,
+ const std::string& upload_content_type,
+ uint64_t offset,
+ uint64_t length));
+ MOCK_METHOD2(SetRetryOptions, void(int max_retries, int retry_mode));
+ MOCK_METHOD1(SetURLLoaderFactoryOptions, void(uint32_t options));
+ MOCK_METHOD1(SetRequestID, void(int32_t request_id));
+ MOCK_METHOD1(SetTimeoutDuration, void(base::TimeDelta timeout_duration));
+ MOCK_CONST_METHOD0(NetError, int());
+ MOCK_CONST_METHOD0(ResponseInfo, const ::network::mojom::URLResponseHead*());
+ MOCK_CONST_METHOD0(CompletionStatus,
+ base::Optional<::network::URLLoaderCompletionStatus>&());
+ MOCK_CONST_METHOD0(GetFinalURL, const GURL&());
+ MOCK_CONST_METHOD0(LoadedFromCache, bool());
+ MOCK_CONST_METHOD0(GetContentSize, int64_t());
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_URL_LOADER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc
new file mode 100644
index 00000000000..4f05df3bb23
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc
@@ -0,0 +1,56 @@
+// Copyright 2020 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_assistant/browser/service/server_url_fetcher.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "url/url_canon_stdstring.h"
+
+namespace {
+const char kDefaultAutofillAssistantServerUrl[] =
+ "https://automate-pa.googleapis.com";
+const char kScriptEndpoint[] = "/v1/supportsSite2";
+const char kActionEndpoint[] = "/v1/actions2";
+const char kTriggersEndpoint[] = "/v1/triggers";
+} // namespace
+
+namespace autofill_assistant {
+
+ServerUrlFetcher::ServerUrlFetcher(const GURL& server_url)
+ : server_url_(server_url) {}
+ServerUrlFetcher::~ServerUrlFetcher() = default;
+
+// static
+GURL ServerUrlFetcher::GetDefaultServerUrl() {
+ std::string server_url =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAutofillAssistantUrl);
+ if (server_url.empty()) {
+ return GURL(kDefaultAutofillAssistantServerUrl);
+ }
+ return GURL(server_url);
+}
+
+GURL ServerUrlFetcher::GetSupportsScriptEndpoint() {
+ url::StringPieceReplacements<std::string> script_replacements;
+ script_replacements.SetPathStr(kScriptEndpoint);
+ return server_url_.ReplaceComponents(script_replacements);
+}
+
+GURL ServerUrlFetcher::GetNextActionsEndpoint() {
+ url::StringPieceReplacements<std::string> action_replacements;
+ action_replacements.SetPathStr(kActionEndpoint);
+ return server_url_.ReplaceComponents(action_replacements);
+}
+
+GURL ServerUrlFetcher::GetTriggerScriptsEndpoint() {
+ url::StringPieceReplacements<std::string> trigger_replacements;
+ trigger_replacements.SetPathStr(kTriggersEndpoint);
+ return server_url_.ReplaceComponents(trigger_replacements);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h
new file mode 100644
index 00000000000..0f2c6900e9d
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_SERVER_URL_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVER_URL_FETCHER_H_
+
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+class ServerUrlFetcher {
+ public:
+ ServerUrlFetcher(const GURL& server_url);
+ virtual ~ServerUrlFetcher();
+
+ // Returns the default server url. This is either the hard-coded constant or,
+ // if applicable, the one provided via command-line argument.
+ static GURL GetDefaultServerUrl();
+
+ // Returns the endpoint to send the SupportsScript RPC to.
+ virtual GURL GetSupportsScriptEndpoint();
+ // Returns the endpoint to send the GetNextActions RPC to.
+ virtual GURL GetNextActionsEndpoint();
+ // Returns the endpoint to send the GetTriggerScripts RPC to.
+ virtual GURL GetTriggerScriptsEndpoint();
+
+ private:
+ GURL server_url_;
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVER_URL_FETCHER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc b/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
new file mode 100644
index 00000000000..9371f2b87af
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 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_assistant/browser/service/server_url_fetcher.h"
+
+#include "base/command_line.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::Eq;
+
+TEST(ServerUrlFetcherTest, GetDefaultServerUrl) {
+ base::CommandLine::ForCurrentProcess()->RemoveSwitch(
+ switches::kAutofillAssistantUrl);
+ EXPECT_THAT(ServerUrlFetcher::GetDefaultServerUrl(),
+ Eq(GURL("https://automate-pa.googleapis.com")));
+}
+
+TEST(ServerUrlFetcherTest, GetDefaultServerUrlCommandLineOverride) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kAutofillAssistantUrl, "https://www.example.com");
+ EXPECT_THAT(ServerUrlFetcher::GetDefaultServerUrl(),
+ Eq(GURL("https://www.example.com")));
+}
+
+TEST(ServerUrlFetcherTest, GetScriptsEndpoint) {
+ EXPECT_THAT(ServerUrlFetcher(GURL("https://www.example.com"))
+ .GetSupportsScriptEndpoint(),
+ Eq(GURL("https://www.example.com/v1/supportsSite2")));
+}
+
+TEST(ServerUrlFetcherTest, GetActionsEndpoint) {
+ EXPECT_THAT(ServerUrlFetcher(GURL("https://www.example.com"))
+ .GetNextActionsEndpoint(),
+ Eq(GURL("https://www.example.com/v1/actions2")));
+}
+
+TEST(ServerUrlFetcherTest, GetTriggerScriptsEndpoint) {
+ EXPECT_THAT(ServerUrlFetcher(GURL("https://www.example.com"))
+ .GetTriggerScriptsEndpoint(),
+ Eq(GURL("https://www.example.com/v1/triggers")));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service.h b/chromium/components/autofill_assistant/browser/service/service.h
index 02baead0dbf..ca413cfdfa8 100644
--- a/chromium/components/autofill_assistant/browser/service.h
+++ b/chromium/components/autofill_assistant/browser/service/service.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_H_
#include <string>
#include <vector>
@@ -27,7 +27,7 @@ class Service {
virtual bool IsLiteService() const = 0;
using ResponseCallback =
- base::OnceCallback<void(bool result, const std::string&)>;
+ base::OnceCallback<void(int http_status, const std::string&)>;
// Get scripts for a given |url|, which should be a valid URL.
virtual void GetScriptsForUrl(const GURL& url,
const TriggerContext& trigger_context,
@@ -48,6 +48,7 @@ class Service {
const std::string& previous_global_payload,
const std::string& previous_script_payload,
const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
ResponseCallback callback) = 0;
protected:
@@ -56,4 +57,4 @@ class Service {
} // namespace autofill_assistant
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_H_
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_H_
diff --git a/chromium/components/autofill_assistant/browser/service/service_impl.cc b/chromium/components/autofill_assistant/browser/service/service_impl.cc
new file mode 100644
index 00000000000..1aa89eae49a
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_impl.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 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_assistant/browser/service/service_impl.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/strcat.h"
+#include "components/autofill_assistant/browser/client.h"
+#include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/service/api_key_fetcher.h"
+#include "components/autofill_assistant/browser/service/server_url_fetcher.h"
+#include "components/autofill_assistant/browser/service/service_request_sender_impl.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace autofill_assistant {
+
+// static
+std::unique_ptr<ServiceImpl> ServiceImpl::Create(
+ content::BrowserContext* context,
+ Client* client) {
+ ServerUrlFetcher url_fetcher{ServerUrlFetcher::GetDefaultServerUrl()};
+ auto request_sender = std::make_unique<ServiceRequestSenderImpl>(
+ context, client->GetAccessTokenFetcher(),
+ std::make_unique<NativeURLLoaderFactory>(),
+ ApiKeyFetcher().GetAPIKey(client->GetChannel()),
+ /* auth_enabled = */ "false" !=
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAutofillAssistantAuth),
+ /* disable_auth_if_no_access_token = */ true);
+
+ return std::make_unique<ServiceImpl>(
+ std::move(request_sender), url_fetcher.GetSupportsScriptEndpoint(),
+ url_fetcher.GetNextActionsEndpoint(),
+ std::make_unique<ClientContextImpl>(client));
+}
+
+ServiceImpl::ServiceImpl(std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& script_server_url,
+ const GURL& action_server_url,
+ std::unique_ptr<ClientContext> client_context)
+ : request_sender_(std::move(request_sender)),
+ script_server_url_(script_server_url),
+ script_action_server_url_(action_server_url),
+ client_context_(std::move(client_context)) {
+ DCHECK(script_server_url.is_valid());
+ DCHECK(action_server_url.is_valid());
+}
+
+ServiceImpl::~ServiceImpl() {}
+
+void ServiceImpl::GetScriptsForUrl(const GURL& url,
+ const TriggerContext& trigger_context,
+ ResponseCallback callback) {
+ DCHECK(url.is_valid());
+ client_context_->Update(trigger_context);
+ request_sender_->SendRequest(
+ script_server_url_,
+ ProtocolUtils::CreateGetScriptsRequest(url, client_context_->AsProto(),
+ trigger_context.GetParameters()),
+ std::move(callback));
+}
+
+bool ServiceImpl::IsLiteService() const {
+ return false;
+}
+
+void ServiceImpl::GetActions(const std::string& script_path,
+ const GURL& url,
+ const TriggerContext& trigger_context,
+ const std::string& global_payload,
+ const std::string& script_payload,
+ ResponseCallback callback) {
+ DCHECK(!script_path.empty());
+ client_context_->Update(trigger_context);
+ request_sender_->SendRequest(
+ script_action_server_url_,
+ ProtocolUtils::CreateInitialScriptActionsRequest(
+ script_path, url, global_payload, script_payload,
+ client_context_->AsProto(), trigger_context.GetParameters()),
+ std::move(callback));
+}
+
+void ServiceImpl::GetNextActions(
+ const TriggerContext& trigger_context,
+ const std::string& previous_global_payload,
+ const std::string& previous_script_payload,
+ const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
+ ResponseCallback callback) {
+ client_context_->Update(trigger_context);
+ request_sender_->SendRequest(
+ script_action_server_url_,
+ ProtocolUtils::CreateNextScriptActionsRequest(
+ previous_global_payload, previous_script_payload, processed_actions,
+ timing_stats, client_context_->AsProto()),
+ std::move(callback));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_impl.h b/chromium/components/autofill_assistant/browser/service/service_impl.h
new file mode 100644
index 00000000000..64b53f218b5
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_impl.h
@@ -0,0 +1,94 @@
+// Copyright 2018 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_ASSISTANT_BROWSER_SERVICE_SERVICE_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/client_context.h"
+#include "components/autofill_assistant/browser/device_context.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/service.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "components/signin/public/identity_manager/access_token_fetcher.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace autofill_assistant {
+class Client;
+
+// Native autofill assistant service which communicates with the server to get
+// scripts and client actions.
+// TODO(b/158998456): Add unit tests.
+class ServiceImpl : public Service {
+ public:
+ // Convenience method for creating a service. |context| and |client| must
+ // remain valid for the lifetime of the service instance. Will enable
+ // authentication unless disabled via the autofill-assistant-auth command line
+ // flag.
+ static std::unique_ptr<ServiceImpl> Create(content::BrowserContext* context,
+ Client* client);
+
+ bool IsLiteService() const override;
+
+ ServiceImpl(std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& script_server_url,
+ const GURL& action_server_url,
+ std::unique_ptr<ClientContext> client_context);
+ ServiceImpl(const ServiceImpl&) = delete;
+ ServiceImpl& operator=(const ServiceImpl&) = delete;
+ ~ServiceImpl() override;
+
+ // Get scripts for a given |url|, which should be a valid URL.
+ void GetScriptsForUrl(const GURL& url,
+ const TriggerContext& trigger_context,
+ ResponseCallback callback) override;
+
+ // Get actions.
+ void GetActions(const std::string& script_path,
+ const GURL& url,
+ const TriggerContext& trigger_context,
+ const std::string& global_payload,
+ const std::string& script_payload,
+ ResponseCallback callback) override;
+
+ // Get next sequence of actions according to server payloads in previous
+ // response.
+ void GetNextActions(
+ const TriggerContext& trigger_context,
+ const std::string& previous_global_payload,
+ const std::string& previous_script_payload,
+ const std::vector<ProcessedActionProto>& processed_actions,
+ const RoundtripTimingStats& timing_stats,
+ ResponseCallback callback) override;
+
+ private:
+ // The request sender responsible for communicating with a remote endpoint.
+ std::unique_ptr<ServiceRequestSender> request_sender_;
+
+ // The RPC endpoints to send requests to.
+ GURL script_server_url_;
+ GURL script_action_server_url_;
+
+ // The client context to send to the backend.
+ std::unique_ptr<ClientContext> client_context_;
+
+ base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc
new file mode 100644
index 00000000000..c95f463722f
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2020 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_assistant/browser/service/service_impl.h"
+
+#include "components/autofill_assistant/browser/mock_client_context.h"
+#include "components/autofill_assistant/browser/service/mock_service_request_sender.h"
+#include "components/autofill_assistant/browser/service/service.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace {
+
+const char kScriptServerUrl[] = "https://www.fake.backend.com/script_server";
+const char kActionServerUrl[] = "https://www.fake.backend.com/action_server";
+
+class ServiceImplTest : public testing::Test {
+ public:
+ ServiceImplTest() {
+ auto mock_client_context = std::make_unique<NiceMock<MockClientContext>>();
+ mock_client_context_ = mock_client_context.get();
+
+ auto mock_request_sender =
+ std::make_unique<NiceMock<MockServiceRequestSender>>();
+ mock_request_sender_ = mock_request_sender.get();
+
+ service_ = std::make_unique<ServiceImpl>(
+ std::move(mock_request_sender), GURL(kScriptServerUrl),
+ GURL(kActionServerUrl), std::move(mock_client_context));
+ }
+ ~ServiceImplTest() override = default;
+
+ protected:
+ base::MockCallback<Service::ResponseCallback> mock_response_callback_;
+ NiceMock<MockClientContext>* mock_client_context_;
+ NiceMock<MockServiceRequestSender>* mock_request_sender_;
+ std::unique_ptr<ServiceImpl> service_;
+};
+
+TEST_F(ServiceImplTest, GetScriptsForUrl) {
+ EXPECT_CALL(*mock_client_context_, Update).Times(1);
+ // TODO(b/158998456), here and in other tests of service_impl: check that
+ // protocol utils is called with the correct parameters.
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kScriptServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
+ EXPECT_CALL(mock_response_callback_,
+ Run(net::HTTP_OK, std::string("response")))
+ .Times(1);
+
+ TriggerContextImpl trigger_context;
+ service_->GetScriptsForUrl(GURL("https://www.example.com"), trigger_context,
+ mock_response_callback_.Get());
+}
+
+TEST_F(ServiceImplTest, GetActions) {
+ EXPECT_CALL(*mock_client_context_, Update).Times(1);
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kActionServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
+ EXPECT_CALL(mock_response_callback_,
+ Run(net::HTTP_OK, std::string("response")))
+ .Times(1);
+
+ TriggerContextImpl trigger_context;
+ service_->GetActions(
+ std::string("fake_script_path"), GURL("https://www.example.com"),
+ trigger_context, std::string("fake_global_payload"),
+ std::string("fake_script_payload"), mock_response_callback_.Get());
+}
+
+TEST_F(ServiceImplTest, GetNextActions) {
+ EXPECT_CALL(*mock_client_context_, Update).Times(1);
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kActionServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
+ EXPECT_CALL(mock_response_callback_,
+ Run(net::HTTP_OK, std::string("response")))
+ .Times(1);
+
+ TriggerContextImpl trigger_context;
+ service_->GetNextActions(
+ trigger_context, std::string("fake_previous_global_payload"),
+ std::string("fake_previous_script_payload"), /* processed_actions = */ {},
+ /* timing_stats = */ RoundtripTimingStats(),
+ mock_response_callback_.Get());
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender.cc
new file mode 100644
index 00000000000..8a90cfca6f9
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/service/service_request_sender.h"
+
+namespace autofill_assistant {
+
+ServiceRequestSender::ServiceRequestSender() = default;
+ServiceRequestSender::~ServiceRequestSender() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender.h b/chromium/components/autofill_assistant/browser/service/service_request_sender.h
new file mode 100644
index 00000000000..865e9ddd2fd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender.h
@@ -0,0 +1,32 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+class ServiceRequestSender {
+ public:
+ using ResponseCallback =
+ base::OnceCallback<void(int http_status, const std::string& response)>;
+
+ ServiceRequestSender();
+ virtual ~ServiceRequestSender();
+
+ // Sends |request_body| to |url|. Returns the http status code and the
+ // response itself.
+ virtual void SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) = 0;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_H_
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc
new file mode 100644
index 00000000000..eabeb73a0d1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc
@@ -0,0 +1,220 @@
+// Copyright 2020 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_assistant/browser/service/service_request_sender_impl.h"
+
+#include "base/strings/strcat.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace {
+
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+ net::DefineNetworkTrafficAnnotation("autofill_service", R"(
+ semantics {
+ sender: "Autofill Assistant"
+ description:
+ "Chromium posts requests to autofill assistant server to get
+ scripts for a URL."
+ trigger:
+ "Matching URL."
+ data: "None."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This feature can be disabled in settings."
+ policy_exception_justification: "Not implemented."
+ })");
+
+void OnURLLoaderComplete(
+ autofill_assistant::ServiceRequestSender::ResponseCallback callback,
+ std::unique_ptr<::network::SimpleURLLoader> loader,
+ std::unique_ptr<std::string> response_body) {
+ std::string response_str;
+ if (response_body != nullptr) {
+ response_str = std::move(*response_body);
+ }
+
+ int response_code = 0;
+ if (loader->ResponseInfo() && loader->ResponseInfo()->headers) {
+ response_code = loader->ResponseInfo()->headers->response_code();
+ }
+ VLOG(3) << "Received response: status=" << response_code << ", "
+ << response_str.length() << " bytes";
+ std::move(callback).Run(response_code, response_str);
+}
+
+std::unique_ptr<::network::ResourceRequest> CreateResourceRequest(GURL url) {
+ auto resource_request = std::make_unique<::network::ResourceRequest>();
+ resource_request->url = url;
+ resource_request->method = "POST";
+ resource_request->redirect_mode = ::network::mojom::RedirectMode::kError;
+ resource_request->credentials_mode = ::network::mojom::CredentialsMode::kOmit;
+ return resource_request;
+}
+
+void SendRequestImpl(
+ std::unique_ptr<::network::ResourceRequest> request,
+ const std::string& request_body,
+ content::BrowserContext* context,
+ autofill_assistant::SimpleURLLoaderFactory* loader_factory,
+ autofill_assistant::ServiceRequestSender::ResponseCallback callback) {
+ auto loader =
+ loader_factory->CreateLoader(std::move(request), kTrafficAnnotation);
+ loader->AttachStringForUpload(request_body, "application/x-protobuffer");
+#ifdef DEBUG
+ loader->SetAllowHttpErrorResults(true);
+#endif
+ auto* const loader_ptr = loader.get();
+ loader_ptr->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ content::BrowserContext::GetDefaultStoragePartition(context)
+ ->GetURLLoaderFactoryForBrowserProcess()
+ .get(),
+ base::BindOnce(&OnURLLoaderComplete, std::move(callback),
+ std::move(loader)));
+}
+
+void SendRequestNoAuth(
+ const GURL& url,
+ const std::string& request_body,
+ content::BrowserContext* context,
+ autofill_assistant::SimpleURLLoaderFactory* loader_factory,
+ const std::string& api_key,
+ autofill_assistant::ServiceRequestSender::ResponseCallback callback) {
+ if (callback.IsCancelled()) {
+ return;
+ }
+ if (api_key.empty()) {
+ LOG(ERROR) << "no api key provided";
+ std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
+ return;
+ }
+
+ std::string query_str = base::StrCat({"key=", api_key});
+ // query_str must remain valid until ReplaceComponents() has returned.
+ url::StringPieceReplacements<std::string> add_key;
+ add_key.SetQueryStr(query_str);
+ GURL modified_url = url.ReplaceComponents(add_key);
+
+ VLOG(2) << "Sending request with api key to backend";
+ SendRequestImpl(CreateResourceRequest(modified_url), request_body, context,
+ loader_factory, std::move(callback));
+}
+
+} // namespace
+
+namespace autofill_assistant {
+
+ServiceRequestSenderImpl::ServiceRequestSenderImpl(
+ content::BrowserContext* context,
+ AccessTokenFetcher* access_token_fetcher,
+ std::unique_ptr<SimpleURLLoaderFactory> loader_factory,
+ const std::string& api_key,
+ bool auth_enabled,
+ bool disable_auth_if_no_access_token)
+ : context_(context),
+ access_token_fetcher_(access_token_fetcher),
+ loader_factory_(std::move(loader_factory)),
+ api_key_(api_key),
+ auth_enabled_(auth_enabled),
+ disable_auth_if_no_access_token_(disable_auth_if_no_access_token) {
+ DCHECK(!auth_enabled || access_token_fetcher != nullptr);
+ DCHECK(auth_enabled || !api_key.empty());
+}
+ServiceRequestSenderImpl::~ServiceRequestSenderImpl() = default;
+
+void ServiceRequestSenderImpl::SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) {
+ if (auth_enabled_ && access_token_fetcher_ == nullptr) {
+ LOG(ERROR) << "auth requested, but no access token fetcher provided";
+ std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
+ return;
+ }
+ if (auth_enabled_) {
+ access_token_fetcher_->FetchAccessToken(
+ base::BindOnce(&ServiceRequestSenderImpl::OnFetchAccessToken,
+ weak_ptr_factory_.GetWeakPtr(), url, request_body,
+ std::move(callback)));
+ return;
+ }
+
+ SendRequestNoAuth(url, request_body, context_, loader_factory_.get(),
+ api_key_, std::move(callback));
+}
+
+void ServiceRequestSenderImpl::OnFetchAccessToken(
+ GURL url,
+ std::string request_body,
+ ResponseCallback callback,
+ bool access_token_fetched,
+ const std::string& access_token) {
+ if (!access_token_fetched || access_token.empty()) {
+ if (disable_auth_if_no_access_token_) {
+ // Give up on authentication for this run. Without access token, requests
+ // might be successful or rejected, depending on the server configuration.
+ auth_enabled_ = false;
+ VLOG(1) << "No access token, falling back to api key";
+ SendRequestNoAuth(url, request_body, context_, loader_factory_.get(),
+ api_key_, std::move(callback));
+ return;
+ }
+ VLOG(1) << "No access token, but disable_auth_if_no_access_token not set";
+ std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
+ return;
+ }
+
+ SendRequestAuth(url, request_body, access_token, std::move(callback));
+}
+
+void ServiceRequestSenderImpl::SendRequestAuth(const GURL& url,
+ const std::string& request_body,
+ const std::string& access_token,
+ ResponseCallback callback) {
+ if (callback.IsCancelled()) {
+ return;
+ }
+ auto resource_request = CreateResourceRequest(url);
+ resource_request->headers.SetHeader("Authorization",
+ base::StrCat({"Bearer ", access_token}));
+
+ if (!retried_with_fresh_access_token_) {
+ callback = base::BindOnce(&ServiceRequestSenderImpl::RetryIfUnauthorized,
+ weak_ptr_factory_.GetWeakPtr(), url, access_token,
+ request_body, std::move(callback));
+ }
+ VLOG(2) << "Sending request with access token to backend";
+ SendRequestImpl(std::move(resource_request), request_body, context_,
+ loader_factory_.get(), std::move(callback));
+}
+
+void ServiceRequestSenderImpl::RetryIfUnauthorized(
+ const GURL& url,
+ const std::string& access_token,
+ const std::string& request_body,
+ ResponseCallback callback,
+ int http_status,
+ const std::string& response) {
+ // On first UNAUTHORIZED error, invalidate access token and try again.
+ if (auth_enabled_ && http_status == net::HTTP_UNAUTHORIZED) {
+ VLOG(1) << "Request with access token returned with 401 UNAUTHORIZED, "
+ "fetching a fresh access token and trying again";
+ DCHECK(!retried_with_fresh_access_token_);
+ retried_with_fresh_access_token_ = true;
+ access_token_fetcher_->InvalidateAccessToken(access_token);
+ SendRequest(url, request_body, std::move(callback));
+ return;
+ }
+ std::move(callback).Run(http_status, response);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h
new file mode 100644
index 00000000000..467a011055b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h
@@ -0,0 +1,91 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "components/autofill_assistant/browser/service/simple_url_loader_factory.h"
+#include "content/public/browser/browser_context.h"
+#include "url/gurl.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace autofill_assistant {
+
+class ServiceRequestSenderImpl : public ServiceRequestSender {
+ public:
+ // Constructor. |access_token_fetcher| is optional if |auth_enabled| is false.
+ // Pointers to |context| and, if provided, |access_token_fetcher| must remain
+ // valid during the lifetime of this instance.
+ // If |disable_auth_if_no_access_token| is true, authentication will
+ // automatically be disabled in case fetching the access token fails.
+ ServiceRequestSenderImpl(
+ content::BrowserContext* context,
+ AccessTokenFetcher* access_token_fetcher,
+ std::unique_ptr<SimpleURLLoaderFactory> loader_factory,
+ const std::string& api_key,
+ bool auth_enabled,
+ bool disable_auth_if_no_access_token);
+ ~ServiceRequestSenderImpl() override;
+ ServiceRequestSenderImpl(const ServiceRequestSenderImpl&) = delete;
+ ServiceRequestSenderImpl& operator=(const ServiceRequestSenderImpl&) = delete;
+
+ // Sends |request_body| to |url|. Depending on configuration, the request
+ // will be authenticated either with an Oauth access token or the api key.
+ // Returns the http status code and the response itself. If the returned http
+ // headers could not be parsed, the http code will be 0.
+ //
+ // When an auth-request first fails with a 401, the access token is
+ // invalidated and fetched again. If the request fails again, the request
+ // is considered failed and the callback is invoked.
+ void SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) override;
+
+ private:
+ void SendRequestAuth(const GURL& url,
+ const std::string& request_body,
+ const std::string& access_token,
+ ResponseCallback callback);
+
+ void RetryIfUnauthorized(const GURL& url,
+ const std::string& access_token,
+ const std::string& request_body,
+ ResponseCallback callback,
+ int http_status,
+ const std::string& response);
+
+ void OnFetchAccessToken(GURL url,
+ std::string request_body,
+ ResponseCallback callback,
+ bool access_token_fetched,
+ const std::string& access_token);
+
+ content::BrowserContext* context_ = nullptr;
+ AccessTokenFetcher* access_token_fetcher_ = nullptr;
+ std::unique_ptr<SimpleURLLoaderFactory> loader_factory_;
+
+ // API key to add to the URL of unauthenticated requests.
+ std::string api_key_;
+
+ // Whether requests should be authenticated.
+ bool auth_enabled_ = true;
+
+ bool disable_auth_if_no_access_token_ = true;
+ bool retried_with_fresh_access_token_ = false;
+ base::WeakPtrFactory<ServiceRequestSenderImpl> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
new file mode 100644
index 00000000000..7b4314ca433
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright 2020 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_assistant/browser/service/service_request_sender_impl.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/mock_access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h"
+#include "components/autofill_assistant/browser/service/mock_url_loader.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::WithArgs;
+
+namespace {
+
+std::unique_ptr<::network::mojom::URLResponseHead> CreateResponseInfo(
+ int status_code,
+ const std::string& status) {
+ auto response = std::make_unique<::network::mojom::URLResponseHead>();
+ response->headers =
+ base::MakeRefCounted<::net::HttpResponseHeaders>(base::StrCat(
+ {"HTTP/1.1 ", base::NumberToString(status_code), " ", status}));
+ return response;
+}
+
+class ServiceRequestSenderImplTest : public testing::Test {
+ public:
+ ServiceRequestSenderImplTest() = default;
+ ~ServiceRequestSenderImplTest() override = default;
+
+ protected:
+ base::MockCallback<base::OnceCallback<void(int, const std::string&)>>
+ mock_response_callback_;
+ // Note: |task_environment_| must be created before |context_|, else creation
+ // of |context_| will fail (see content/public/test/test_browser_context.cc).
+ content::BrowserTaskEnvironment task_environment_;
+ content::TestBrowserContext context_;
+ NiceMock<MockAccessTokenFetcher> mock_access_token_fetcher_;
+};
+
+TEST_F(ServiceRequestSenderImplTest, SendUnauthenticatedRequest) {
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ nullptr,
+ std::move(loader_factory),
+ std::string("fake_api_key"),
+ /* auth_enabled = */ false,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(GURL("https://www.example.com"),
+ std::string("request"),
+ mock_response_callback_.Get());
+}
+
+TEST_F(ServiceRequestSenderImplTest, SendAuthenticatedRequest) {
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ std::string authorization;
+ EXPECT_TRUE(resource_request->headers.GetHeader("Authorization",
+ &authorization));
+ EXPECT_EQ(authorization, "Bearer access_token");
+ EXPECT_EQ(resource_request->url, GURL("https://www.example.com"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+ EXPECT_CALL(mock_access_token_fetcher_, OnFetchAccessToken)
+ .Times(1)
+ .WillOnce(RunOnceCallback<0>(true, "access_token"));
+ EXPECT_CALL(mock_access_token_fetcher_, InvalidateAccessToken).Times(0);
+
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(loader_factory),
+ /* api_key = */ std::string(""),
+ /* auth_enabled = */ true,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(GURL("https://www.example.com"),
+ std::string("request"),
+ mock_response_callback_.Get());
+}
+
+TEST_F(ServiceRequestSenderImplTest,
+ AuthRequestFallsBackToApiKeyOnEmptyAccessToken) {
+ EXPECT_CALL(mock_access_token_fetcher_, OnFetchAccessToken)
+ .Times(1)
+ .WillOnce(RunOnceCallback<0>(true, /*access_token = */ ""));
+
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(loader_factory),
+ /* api_key = */ std::string("fake_api_key"),
+ /* auth_enabled = */ true,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(GURL("https://www.example.com"),
+ std::string("request"),
+ mock_response_callback_.Get());
+}
+
+TEST_F(ServiceRequestSenderImplTest,
+ AuthRequestFallsBackToApiKeyIfFetchingAccessTokenFails) {
+ EXPECT_CALL(mock_access_token_fetcher_, OnFetchAccessToken)
+ .Times(1)
+ .WillOnce(
+ RunOnceCallback<0>(/*success = */ false, /*access_token = */ ""));
+
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(loader_factory),
+ /* api_key = */ std::string("fake_api_key"),
+ /* auth_enabled = */ true,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(GURL("https://www.example.com"),
+ std::string("request"),
+ mock_response_callback_.Get());
+}
+
+// TODO(b/170934170): Add tests for full unit test coverage of
+// service_request_sender.
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc
new file mode 100644
index 00000000000..8c4b7a18b84
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc
@@ -0,0 +1,22 @@
+// Copyright 2020 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_assistant/browser/service/service_request_sender_local_impl.h"
+
+#include "net/http/http_status_code.h"
+
+namespace autofill_assistant {
+
+ServiceRequestSenderLocalImpl::ServiceRequestSenderLocalImpl(
+ const std::string& response)
+ : response_(response) {}
+ServiceRequestSenderLocalImpl::~ServiceRequestSenderLocalImpl() = default;
+
+void ServiceRequestSenderLocalImpl::SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) {
+ std::move(callback).Run(net::HTTP_OK, response_);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h
new file mode 100644
index 00000000000..a7cd8fd47d1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_LOCAL_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_LOCAL_IMPL_H_
+
+#include <string>
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+
+namespace autofill_assistant {
+
+// Implementation of a service request sender that serves a pre-configured,
+// local response.
+class ServiceRequestSenderLocalImpl : public ServiceRequestSender {
+ public:
+ ServiceRequestSenderLocalImpl(const std::string& response);
+ ~ServiceRequestSenderLocalImpl() override;
+
+ // This will always return status 200 and the response specified in the
+ // constructor.
+ // TODO(arbesser): Make this more flexible.
+ void SendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) override;
+
+ private:
+ std::string response_;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SERVICE_REQUEST_SENDER_LOCAL_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc
new file mode 100644
index 00000000000..a2b47db77e8
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 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_assistant/browser/service/service_request_sender_local_impl.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace {
+
+class ServiceRequestSenderLocalImplTest : public testing::Test {
+ public:
+ ServiceRequestSenderLocalImplTest() = default;
+ ~ServiceRequestSenderLocalImplTest() override = default;
+
+ protected:
+ base::MockCallback<ServiceRequestSender::ResponseCallback>
+ mock_response_callback_;
+};
+
+TEST_F(ServiceRequestSenderLocalImplTest, SendRequestAlwaysReturnsResponse) {
+ ServiceRequestSenderLocalImpl service_request_sender = {"response"};
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")).Times(2);
+ service_request_sender.SendRequest(GURL(), "request_1",
+ mock_response_callback_.Get());
+ service_request_sender.SendRequest(GURL(), "request_2",
+ mock_response_callback_.Get());
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.cc b/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.cc
new file mode 100644
index 00000000000..00a4c05bf8a
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 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_assistant/browser/service/simple_url_loader_factory.h"
+
+namespace autofill_assistant {
+
+std::unique_ptr<::network::SimpleURLLoader>
+NativeURLLoaderFactory::CreateLoader(
+ std::unique_ptr<::network::ResourceRequest> resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) const {
+ return ::network::SimpleURLLoader::Create(std::move(resource_request),
+ annotation_tag);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.h b/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.h
new file mode 100644
index 00000000000..b23ce8b4962
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/simple_url_loader_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_SERVICE_SIMPLE_URL_LOADER_FACTORY_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SIMPLE_URL_LOADER_FACTORY_H_
+
+#include <memory>
+
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace autofill_assistant {
+
+// Base interface for creators of URL loaders.
+class SimpleURLLoaderFactory {
+ public:
+ virtual ~SimpleURLLoaderFactory() = default;
+
+ virtual std::unique_ptr<::network::SimpleURLLoader> CreateLoader(
+ std::unique_ptr<::network::ResourceRequest> resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) const = 0;
+};
+
+// The native implementation of |SimpleURLLoaderFactory|.
+class NativeURLLoaderFactory : public SimpleURLLoaderFactory {
+ public:
+ NativeURLLoaderFactory() = default;
+ ~NativeURLLoaderFactory() override = default;
+ NativeURLLoaderFactory(const NativeURLLoaderFactory&) = delete;
+ NativeURLLoaderFactory& operator=(const NativeURLLoaderFactory&) = delete;
+
+ std::unique_ptr<::network::SimpleURLLoader> CreateLoader(
+ std::unique_ptr<::network::ResourceRequest> resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) const override;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_SIMPLE_URL_LOADER_FACTORY_H_
diff --git a/chromium/components/autofill_assistant/browser/service_impl.cc b/chromium/components/autofill_assistant/browser/service_impl.cc
deleted file mode 100644
index 8dcc2c85036..00000000000
--- a/chromium/components/autofill_assistant/browser/service_impl.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2018 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_assistant/browser/service_impl.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/strings/strcat.h"
-#include "base/strings/stringprintf.h"
-#include "components/autofill_assistant/browser/client.h"
-#include "components/autofill_assistant/browser/protocol_utils.h"
-#include "components/autofill_assistant/browser/switches.h"
-#include "components/autofill_assistant/browser/trigger_context.h"
-#include "components/version_info/version_info.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/storage_partition.h"
-#include "google_apis/google_api_keys.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "url/url_canon_stdstring.h"
-
-namespace autofill_assistant {
-namespace {
-
-const char* const kDefaultAutofillAssistantServerUrl =
- "https://automate-pa.googleapis.com";
-const char* const kScriptEndpoint = "/v1/supportsSite2";
-const char* const kActionEndpoint = "/v1/actions2";
-
-net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation("autofill_service", R"(
- semantics {
- sender: "Autofill Assistant"
- description:
- "Chromium posts requests to autofill assistant server to get
- scripts for a URL."
- trigger:
- "Matching URL."
- data: "None."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: NO
- setting:
- "This feature can be disabled in settings."
- policy_exception_justification: "Not implemented."
- })");
-
-std::string GetAPIKey(version_info::Channel channel) {
- const auto* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kAutofillAssistantServerKey)) {
- return command_line->GetSwitchValueASCII(
- switches::kAutofillAssistantServerKey);
- }
-
- if (google_apis::IsGoogleChromeAPIKeyUsed()) {
- return channel == version_info::Channel::STABLE
- ? google_apis::GetAPIKey()
- : google_apis::GetNonStableAPIKey();
- }
- return "";
-}
-
-std::string GetServerUrl() {
- std::string server_url =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kAutofillAssistantUrl);
- if (server_url.empty()) {
- server_url = kDefaultAutofillAssistantServerUrl;
- }
- return server_url;
-}
-
-} // namespace
-
-// static
-std::unique_ptr<ServiceImpl> ServiceImpl::Create(
- content::BrowserContext* context,
- Client* client) {
- GURL server_url(GetServerUrl());
- DCHECK(server_url.is_valid());
-
- return std::make_unique<ServiceImpl>(
- GetAPIKey(client->GetChannel()), GURL(GetServerUrl()), context,
- std::make_unique<ClientContextImpl>(client),
- client->GetAccessTokenFetcher(),
- /* auth_enabled = */ "false" !=
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kAutofillAssistantAuth));
-}
-
-ServiceImpl::ServiceImpl(const std::string& api_key,
- const GURL& server_url,
- content::BrowserContext* context,
- std::unique_ptr<ClientContext> client_context,
- AccessTokenFetcher* access_token_fetcher,
- bool auth_enabled)
- : context_(context),
- api_key_(api_key),
- client_context_(std::move(client_context)),
- access_token_fetcher_(access_token_fetcher),
- fetching_token_(false),
- auth_enabled_(auth_enabled),
- weak_ptr_factory_(this) {
- DCHECK(server_url.is_valid());
-
- url::StringPieceReplacements<std::string> script_replacements;
- script_replacements.SetPathStr(kScriptEndpoint);
- script_server_url_ = server_url.ReplaceComponents(script_replacements);
-
- url::StringPieceReplacements<std::string> action_replacements;
- action_replacements.SetPathStr(kActionEndpoint);
- script_action_server_url_ = server_url.ReplaceComponents(action_replacements);
- VLOG(1) << "Using script domain " << script_action_server_url_.host();
-}
-
-ServiceImpl::ServiceImpl(content::BrowserContext* context,
- version_info::Channel channel,
- std::unique_ptr<ClientContext> client_context,
- AccessTokenFetcher* access_token_fetcher,
- bool auth_enabled)
- : ServiceImpl(GetAPIKey(channel),
- GURL(GetServerUrl()),
- context,
- std::move(client_context),
- access_token_fetcher,
- auth_enabled) {}
-
-ServiceImpl::~ServiceImpl() {}
-
-void ServiceImpl::GetScriptsForUrl(const GURL& url,
- const TriggerContext& trigger_context,
- ResponseCallback callback) {
- DCHECK(url.is_valid());
-
- client_context_->Update(trigger_context);
- SendRequest(AddLoader(
- script_server_url_,
- ProtocolUtils::CreateGetScriptsRequest(url, client_context_->AsProto(),
- trigger_context.GetParameters()),
- std::move(callback)));
-}
-
-bool ServiceImpl::IsLiteService() const {
- return false;
-}
-
-void ServiceImpl::GetActions(const std::string& script_path,
- const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
- ResponseCallback callback) {
- DCHECK(!script_path.empty());
-
- client_context_->Update(trigger_context);
- SendRequest(AddLoader(
- script_action_server_url_,
- ProtocolUtils::CreateInitialScriptActionsRequest(
- script_path, url, global_payload, script_payload,
- client_context_->AsProto(), trigger_context.GetParameters()),
- std::move(callback)));
-}
-
-void ServiceImpl::GetNextActions(
- const TriggerContext& trigger_context,
- const std::string& previous_global_payload,
- const std::string& previous_script_payload,
- const std::vector<ProcessedActionProto>& processed_actions,
- ResponseCallback callback) {
- client_context_->Update(trigger_context);
- SendRequest(AddLoader(script_action_server_url_,
- ProtocolUtils::CreateNextScriptActionsRequest(
- previous_global_payload, previous_script_payload,
- processed_actions, client_context_->AsProto()),
- std::move(callback)));
-}
-
-void ServiceImpl::SendRequest(Loader* loader) {
- if (access_token_.empty() && auth_enabled_) {
- // Trigger a fetch of the access token. All loaders in loaders_ will be
- // started later on, the access token is available.
- FetchAccessToken();
- return;
- }
-
- StartLoader(loader);
-}
-
-ServiceImpl::Loader::Loader() : retried_with_fresh_access_token(false) {}
-ServiceImpl::Loader::~Loader() {}
-
-ServiceImpl::Loader* ServiceImpl::AddLoader(const GURL& url,
- const std::string& request_body,
- ResponseCallback callback) {
- std::unique_ptr<Loader> loader = std::make_unique<Loader>();
- loader->url = url;
- loader->request_body = request_body;
- loader->callback = std::move(callback);
- Loader* loader_ptr = loader.get();
- loaders_[loader_ptr] = std::move(loader);
- return loader_ptr;
-}
-
-void ServiceImpl::StartLoader(Loader* loader) {
- if (loader->loader)
- return;
-
- auto resource_request = std::make_unique<::network::ResourceRequest>();
- resource_request->method = "POST";
- resource_request->redirect_mode = ::network::mojom::RedirectMode::kError;
- resource_request->credentials_mode = ::network::mojom::CredentialsMode::kOmit;
- if (access_token_.empty()) {
- std::string query_str = base::StrCat({"key=", api_key_});
- // query_str must remain valid until ReplaceComponents() has returned.
- url::StringPieceReplacements<std::string> add_key;
- add_key.SetQueryStr(query_str);
- resource_request->url = loader->url.ReplaceComponents(add_key);
- } else {
- resource_request->url = loader->url;
- resource_request->headers.SetHeader(
- "Authorization", base::StrCat({"Bearer ", access_token_}));
- }
-
- loader->loader = ::network::SimpleURLLoader::Create(
- std::move(resource_request), traffic_annotation);
- loader->loader->AttachStringForUpload(loader->request_body,
- "application/x-protobuffer");
-#ifdef DEBUG
- loader->loader->SetAllowHttpErrorResults(true);
-#endif
- loader->loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
- content::BrowserContext::GetDefaultStoragePartition(context_)
- ->GetURLLoaderFactoryForBrowserProcess()
- .get(),
- base::BindOnce(&ServiceImpl::OnURLLoaderComplete, base::Unretained(this),
- loader));
-}
-
-void ServiceImpl::OnURLLoaderComplete(
- Loader* loader,
- std::unique_ptr<std::string> response_body) {
- auto loader_it = loaders_.find(loader);
- DCHECK(loader_it != loaders_.end());
-
- int response_code = 0;
- if (loader->loader->ResponseInfo() &&
- loader->loader->ResponseInfo()->headers) {
- response_code = loader->loader->ResponseInfo()->headers->response_code();
- }
-
- // When getting a 401, refresh the auth token - but only try this once.
- if (response_code == 401 && auth_enabled_ && !access_token_.empty() &&
- !loader->retried_with_fresh_access_token) {
- loader->retried_with_fresh_access_token = true;
- loader->loader.reset();
- // Invalidate access token and load a new one.
- access_token_fetcher_->InvalidateAccessToken(access_token_);
- access_token_.clear();
- SendRequest(loader);
- return;
- }
-
- // Take ownership of loader.
- std::unique_ptr<Loader> loader_instance = std::move(loader_it->second);
- loaders_.erase(loader_it);
- DCHECK(loader_instance);
-
- std::string response_body_str;
- if (loader_instance->loader->NetError() != net::OK || response_code != 200) {
- LOG(ERROR) << "Communicating with autofill assistant server error NetError="
- << loader_instance->loader->NetError()
- << " response_code=" << response_code << " message="
- << (response_body == nullptr ? "" : *response_body);
- // TODO(crbug.com/806868): Pass an enum to be able to distinguish errors
- // downstream. Also introduce a metric for this.
- std::move(loader_instance->callback).Run(false, response_body_str);
- return;
- }
-
- if (response_body)
- response_body_str = std::move(*response_body);
- std::move(loader_instance->callback).Run(true, response_body_str);
-}
-
-void ServiceImpl::FetchAccessToken() {
- if (fetching_token_)
- return;
-
- fetching_token_ = true;
- access_token_fetcher_->FetchAccessToken(base::BindOnce(
- &ServiceImpl::OnFetchAccessToken, weak_ptr_factory_.GetWeakPtr()));
-}
-
-void ServiceImpl::OnFetchAccessToken(bool success,
- const std::string& access_token) {
- fetching_token_ = false;
-
- if (!success) {
- auth_enabled_ = false;
- // Give up on authentication for this run. Let the pending requests through,
- // which might be rejected, depending on the server configuration.
- return;
- }
-
- access_token_ = access_token;
-
- // Start any pending requests with the access token.
- for (const auto& entry : loaders_) {
- StartLoader(entry.first);
- }
-}
-
-} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service_impl.h b/chromium/components/autofill_assistant/browser/service_impl.h
deleted file mode 100644
index fe6718b7a18..00000000000
--- a/chromium/components/autofill_assistant/browser/service_impl.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2018 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_ASSISTANT_BROWSER_SERVICE_IMPL_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_IMPL_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/access_token_fetcher.h"
-#include "components/autofill_assistant/browser/client_context.h"
-#include "components/autofill_assistant/browser/device_context.h"
-#include "components/autofill_assistant/browser/service.h"
-#include "components/autofill_assistant/browser/service.pb.h"
-#include "components/signin/public/identity_manager/access_token_fetcher.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "url/gurl.h"
-
-namespace content {
-class BrowserContext;
-} // namespace content
-
-namespace autofill_assistant {
-class Client;
-
-// Native autofill assistant service which communicates with the server to get
-// scripts and client actions.
-// TODO(b/158998456): Add unit tests.
-class ServiceImpl : public Service {
- public:
- // Convenience method for creating a service. |context| and |client| must
- // remain valid for the lifetime of the service instance. Will enable
- // authentication unless disabled via the autofill-assistant-auth command line
- // flag.
- static std::unique_ptr<ServiceImpl> Create(content::BrowserContext* context,
- Client* client);
-
- bool IsLiteService() const override;
-
- // |context| and |access_token_fetcher| must remain valid for the lifetime of
- // the service instance.
- ServiceImpl(content::BrowserContext* context,
- version_info::Channel channel,
- std::unique_ptr<ClientContext> client_context,
- AccessTokenFetcher* access_token_fetcher,
- bool auth_enabled);
- ServiceImpl(const std::string& api_key,
- const GURL& server_url,
- content::BrowserContext* context,
- std::unique_ptr<ClientContext> client_context,
- AccessTokenFetcher* access_token_fetcher,
- bool auth_enabled);
- ~ServiceImpl() override;
-
- // Get scripts for a given |url|, which should be a valid URL.
- void GetScriptsForUrl(const GURL& url,
- const TriggerContext& trigger_context,
- ResponseCallback callback) override;
-
- // Get actions.
- void GetActions(const std::string& script_path,
- const GURL& url,
- const TriggerContext& trigger_context,
- const std::string& global_payload,
- const std::string& script_payload,
- ResponseCallback callback) override;
-
- // Get next sequence of actions according to server payloads in previous
- // response.
- void GetNextActions(
- const TriggerContext& trigger_context,
- const std::string& previous_global_payload,
- const std::string& previous_script_payload,
- const std::vector<ProcessedActionProto>& processed_actions,
- ResponseCallback callback) override;
-
- private:
- friend class ServiceImplTest;
-
- // Struct to store scripts and actions request.
- struct Loader {
- Loader();
- ~Loader();
-
- GURL url;
- std::string request_body;
- ResponseCallback callback;
- std::unique_ptr<::network::SimpleURLLoader> loader;
- bool retried_with_fresh_access_token;
- };
-
- void SendRequest(Loader* loader);
-
- // Creates a loader and adds it to |loaders_|.
- Loader* AddLoader(const GURL& url,
- const std::string& request_body,
- ResponseCallback callback);
-
- // Sends a request with the given loader, using the current auth token, if one
- // is available.
- void StartLoader(Loader* loader);
- void OnURLLoaderComplete(Loader* loader,
- std::unique_ptr<std::string> response_body);
-
- // Fetches the access token and, once this is done, starts all pending loaders
- // in |loaders_|.
- void FetchAccessToken();
- void OnFetchAccessToken(bool success, const std::string& access_token);
-
- content::BrowserContext* context_;
- GURL script_server_url_;
- GURL script_action_server_url_;
-
- // Destroying this object will cancel ongoing requests.
- std::map<Loader*, std::unique_ptr<Loader>> loaders_;
-
- // API key to add to the URL of unauthenticated requests.
- std::string api_key_;
-
- // The client context to send to the backend.
- std::unique_ptr<ClientContext> client_context_;
-
- // Pointer must remain valid for the lifetime of the Service instance.
- AccessTokenFetcher* access_token_fetcher_;
-
- // True while waiting for a response from AccessTokenFetcher.
- bool fetching_token_;
-
- // Whether requests should be authenticated.
- bool auth_enabled_;
-
- // An OAuth 2 token. Empty if not fetched yet or if the token has been
- // invalidated.
- std::string access_token_;
-
- base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_;
-
- FRIEND_TEST_ALL_PREFIXES(ServiceImplTestSignedInStatus, SetsSignedInStatus);
-
- DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
-};
-
-} // namespace autofill_assistant
-
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/string_conversions_util.cc b/chromium/components/autofill_assistant/browser/string_conversions_util.cc
index 212bafa6372..8c27beae6c6 100644
--- a/chromium/components/autofill_assistant/browser/string_conversions_util.cc
+++ b/chromium/components/autofill_assistant/browser/string_conversions_util.cc
@@ -15,10 +15,8 @@ namespace autofill_assistant {
std::vector<UChar32> UTF8ToUnicode(const std::string& text) {
std::vector<UChar32> codepoints;
codepoints.reserve(text.length()); // upper bound
- base::i18n::UTF8CharIterator iter(&text);
- while (!iter.end()) {
+ for (base::i18n::UTF8CharIterator iter(text); !iter.end(); iter.Advance()) {
codepoints.emplace_back(iter.get());
- iter.Advance();
}
return codepoints;
}
@@ -39,13 +37,13 @@ bool UnicodeToUTF8(const std::vector<UChar32>& source, std::string* target) {
// |target|.
bool AppendUnicodeToUTF8(const UChar32 source, std::string* target) {
char bytes[4];
- UBool error = FALSE;
+ UBool error = false;
size_t offset = 0;
U8_APPEND(bytes, offset, base::size(bytes), source, error);
- if (error == FALSE) {
+ if (error == false) {
target->append(bytes, offset);
}
- return error == FALSE;
+ return !error;
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/top_padding.h b/chromium/components/autofill_assistant/browser/top_padding.h
index 472c4c56006..1c69a9a3601 100644
--- a/chromium/components/autofill_assistant/browser/top_padding.h
+++ b/chromium/components/autofill_assistant/browser/top_padding.h
@@ -8,7 +8,7 @@
namespace autofill_assistant {
// A simple structure that holds information about the top padding.
-// This structure is used by WebController.FocusElement.
+// This structure is used by WebController.ScrollToElementPosition.
//
// Only one type of value can be set (pixels or ratio). If one is
// set, other returns 0.
diff --git a/chromium/components/autofill_assistant/browser/trigger_context.cc b/chromium/components/autofill_assistant/browser/trigger_context.cc
index 2e1e9c751ef..92276066001 100644
--- a/chromium/components/autofill_assistant/browser/trigger_context.cc
+++ b/chromium/components/autofill_assistant/browser/trigger_context.cc
@@ -16,10 +16,17 @@ const char kOverlayColorParameterName[] = "OVERLAY_COLORS";
// TODO(b/151401974): Eliminate duplicate parameter definitions.
const char kPasswordChangeUsernameParameterName[] = "PASSWORD_CHANGE_USERNAME";
+// Legacy, remove as soon as possible.
// Parameter that contains the path of the lite script that was used to trigger
// this flow (may be empty).
const char kLiteScriptPathParamaterName[] = "TRIGGER_SCRIPT_USED";
+// Parameter that contains a base64-encoded GetTriggerScriptsResponseProto
+// message. This allows callers to directly inject trigger scripts, rather than
+// fetching them from a remote backend.
+const char kBase64TriggerScriptsResponseProtoParameterName[] =
+ "TRIGGER_SCRIPTS_BASE64";
+
// static
std::unique_ptr<TriggerContext> TriggerContext::CreateEmpty() {
return std::make_unique<TriggerContextImpl>();
@@ -49,10 +56,15 @@ base::Optional<std::string> TriggerContext::GetPasswordChangeUsername() const {
return GetParameter(kPasswordChangeUsernameParameterName);
}
-bool TriggerContext::WasStartedByTriggerScript() const {
+bool TriggerContext::WasStartedByLegacyTriggerScript() const {
return GetParameter(kLiteScriptPathParamaterName).has_value();
}
+base::Optional<std::string>
+TriggerContext::GetBase64TriggerScriptsResponseProto() const {
+ return GetParameter(kBase64TriggerScriptsResponseProtoParameterName);
+}
+
TriggerContextImpl::TriggerContextImpl() {}
TriggerContextImpl::TriggerContextImpl(
diff --git a/chromium/components/autofill_assistant/browser/trigger_context.h b/chromium/components/autofill_assistant/browser/trigger_context.h
index 833982d71f4..a8b2074c028 100644
--- a/chromium/components/autofill_assistant/browser/trigger_context.h
+++ b/chromium/components/autofill_assistant/browser/trigger_context.h
@@ -47,7 +47,8 @@ class TriggerContext {
// Getters for specific parameters.
base::Optional<std::string> GetOverlayColors() const;
base::Optional<std::string> GetPasswordChangeUsername() const;
- bool WasStartedByTriggerScript() const;
+ bool WasStartedByLegacyTriggerScript() const;
+ base::Optional<std::string> GetBase64TriggerScriptsResponseProto() const;
// Returns a comma-separated set of experiment ids.
virtual std::string experiment_ids() const = 0;
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc
new file mode 100644
index 00000000000..20ed26ddb50
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.cc
@@ -0,0 +1,116 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+
+namespace autofill_assistant {
+
+namespace {
+
+// Extracts all selectors from the condition tree in |proto| and writes them to
+// |results|.
+void ExtractSelectors(const TriggerScriptConditionProto& proto,
+ std::set<Selector>* results) {
+ switch (proto.type_case()) {
+ case TriggerScriptConditionProto::kAllOf:
+ for (const auto& condition : proto.all_of().conditions()) {
+ ExtractSelectors(condition, results);
+ }
+ return;
+ case TriggerScriptConditionProto::kAnyOf:
+ for (const auto& condition : proto.any_of().conditions()) {
+ ExtractSelectors(condition, results);
+ }
+ return;
+ case TriggerScriptConditionProto::kNoneOf:
+ for (const auto& condition : proto.none_of().conditions()) {
+ ExtractSelectors(condition, results);
+ }
+ return;
+ case TriggerScriptConditionProto::kStoredLoginCredentials:
+ case TriggerScriptConditionProto::kIsFirstTimeUser:
+ case TriggerScriptConditionProto::kExperimentId:
+ case TriggerScriptConditionProto::kKeyboardHidden:
+ case TriggerScriptConditionProto::TYPE_NOT_SET:
+ return;
+ case TriggerScriptConditionProto::kSelector:
+ results->insert(Selector(proto.selector()));
+ return;
+ }
+}
+
+} // namespace
+
+DynamicTriggerConditions::DynamicTriggerConditions() = default;
+DynamicTriggerConditions::~DynamicTriggerConditions() = default;
+
+void DynamicTriggerConditions::AddSelectorsFromTriggerScript(
+ const TriggerScriptProto& proto) {
+ ExtractSelectors(proto.trigger_condition(), &selectors_);
+}
+
+void DynamicTriggerConditions::ClearSelectors() {
+ selectors_.clear();
+}
+
+base::Optional<bool> DynamicTriggerConditions::GetSelectorMatches(
+ const Selector& selector) const {
+ auto it = selector_matches_.find(selector);
+ if (it == selector_matches_.end()) {
+ return base::nullopt;
+ }
+ return it->second;
+}
+
+void DynamicTriggerConditions::SetKeyboardVisible(bool visible) {
+ keyboard_visible_ = visible;
+}
+
+bool DynamicTriggerConditions::GetKeyboardVisible() const {
+ return keyboard_visible_;
+}
+
+void DynamicTriggerConditions::Update(WebController* web_controller,
+ base::OnceCallback<void(void)> callback) {
+ DCHECK(!callback_) << "Update called while already in progress";
+ if (callback_) {
+ return;
+ }
+
+ temporary_selector_matches_.clear();
+ if (selectors_.empty()) {
+ selector_matches_ = temporary_selector_matches_;
+ std::move(callback).Run();
+ return;
+ }
+
+ callback_ = std::move(callback);
+ for (const auto& selector : selectors_) {
+ web_controller->FindElement(
+ selector, /* strict = */ false,
+ base::BindOnce(&DynamicTriggerConditions::OnFindElement,
+ weak_ptr_factory_.GetWeakPtr(), selector));
+ }
+}
+
+bool DynamicTriggerConditions::HasResults() const {
+ return selector_matches_.size() == selectors_.size();
+}
+
+void DynamicTriggerConditions::OnFindElement(
+ const Selector& selector,
+ const ClientStatus& client_status,
+ std::unique_ptr<ElementFinder::Result> element) {
+ temporary_selector_matches_.emplace(
+ std::make_pair(selector, client_status.ok()));
+ if (temporary_selector_matches_.size() == selectors_.size()) {
+ selector_matches_ = temporary_selector_matches_;
+ std::move(callback_).Run();
+ }
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h
new file mode 100644
index 00000000000..ecab235eaef
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h
@@ -0,0 +1,88 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
+
+#include <map>
+#include <set>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+
+namespace autofill_assistant {
+
+// Provides easy access to the values of dynamic trigger conditions. Dynamic
+// trigger conditions depend on the current state of the DOM tree and need to be
+// repeatedly re-evaluated.
+class DynamicTriggerConditions {
+ public:
+ DynamicTriggerConditions();
+ virtual ~DynamicTriggerConditions();
+
+ // Adds the selector trigger conditions specified in |proto| to the list of
+ // selectors to be queried in |Update|.
+ virtual void AddSelectorsFromTriggerScript(const TriggerScriptProto& proto);
+
+ // Clears all selectors from the list of selectors to be queried in |Update|.
+ virtual void ClearSelectors();
+
+ // Returns whether |selector| currently matches the DOM tree. |Update| must
+ // be called prior to this method. Only selectors that have previously been
+ // added via |AddSelectorsFromTriggerScript| can be queried.
+ virtual base::Optional<bool> GetSelectorMatches(
+ const Selector& selector) const;
+
+ // Sets whether the keyboard is currently visible.
+ virtual void SetKeyboardVisible(bool visible);
+
+ // Returns whether the keyboard is currently visible.
+ virtual bool GetKeyboardVisible() const;
+
+ // Matches all previously added selectors with the current DOM tree and caches
+ // the results to be available via |GetSelectorMatches|. Invokes |callback|
+ // when done.
+ //
+ // NOTE: this class is not thread-safe. Don't invoke any of its methods while
+ // |Update| is running.
+ virtual void Update(WebController* web_controller,
+ base::OnceCallback<void(void)> callback);
+
+ // If true, all values have been evaluated. They may be out-of-date by one
+ // cycle in case an update is currently scheduled.
+ virtual bool HasResults() const;
+
+ private:
+ friend class DynamicTriggerConditionsTest;
+
+ // Writes the result of the element lookup to |selector_matches_|. When all
+ // |selectors_| have been evaluated, i.e., when the size of
+ // |selector_matches_| is equal to the size of |selectors_|, invokes
+ // |callback_|.
+ void OnFindElement(const Selector& selector,
+ const ClientStatus& client_status,
+ std::unique_ptr<ElementFinder::Result> element);
+
+ // Whether the keyboard is currently visible.
+ bool keyboard_visible_ = false;
+ // Lookup cache for selector matches. Must be updated by invoking |Update|.
+ std::map<Selector, bool> selector_matches_;
+ // Temporary store for selector matches, used during |Update| as results
+ // trickle in. Once all results have been gathered, this becomes the new
+ // |selector_matches_|.
+ std::map<Selector, bool> temporary_selector_matches_;
+ // The list of selectors to look up on |Update|.
+ std::set<Selector> selectors_;
+ // The callback to invoke after |Update| is finished. Only set during
+ // |Update|.
+ base::OnceCallback<void(void)> callback_;
+ base::WeakPtrFactory<DynamicTriggerConditions> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions_unittest.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions_unittest.cc
new file mode 100644
index 00000000000..57af5b5e3bc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
+
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/gtest_util.h"
+#include "base/test/mock_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
+
+class DynamicTriggerConditionsTest : public testing::Test {
+ public:
+ DynamicTriggerConditionsTest() = default;
+ ~DynamicTriggerConditionsTest() override = default;
+
+ protected:
+ std::set<Selector>* GetSelectorsForTest() {
+ return &dynamic_trigger_conditions_.selectors_;
+ }
+
+ base::MockCallback<base::OnceCallback<void(void)>> mock_callback_;
+ DynamicTriggerConditions dynamic_trigger_conditions_;
+ NiceMock<MockWebController> mock_web_controller_;
+};
+
+TEST_F(DynamicTriggerConditionsTest, UpdateWithoutSelectorsDoesNothing) {
+ EXPECT_CALL(mock_web_controller_, OnFindElement).Times(0);
+ EXPECT_CALL(mock_callback_, Run).Times(1);
+ dynamic_trigger_conditions_.Update(&mock_web_controller_,
+ mock_callback_.Get());
+}
+
+TEST_F(DynamicTriggerConditionsTest, LookupInvalidSelectorsFails) {
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("not_evaluated"))),
+ base::nullopt);
+}
+
+TEST_F(DynamicTriggerConditionsTest, AddSelectorsFromTriggerScript) {
+ TriggerScriptProto proto_1;
+ auto* all_of = proto_1.mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ auto* any_of = all_of->add_conditions()->mutable_any_of();
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ auto* none_of = any_of->add_conditions()->mutable_none_of();
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ TriggerScriptProto proto_2;
+ *proto_2.mutable_trigger_condition()->mutable_selector() =
+ ToSelectorProto("d");
+
+ TriggerScriptProto proto_3;
+ all_of = proto_3.mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("e");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("f");
+
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto_1);
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto_2);
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto_3);
+ EXPECT_THAT(
+ *GetSelectorsForTest(),
+ UnorderedElementsAre(
+ Selector(ToSelectorProto("a")), Selector(ToSelectorProto("b")),
+ Selector(ToSelectorProto("c")), Selector(ToSelectorProto("d")),
+ Selector(ToSelectorProto("e")), Selector(ToSelectorProto("f"))));
+}
+
+TEST_F(DynamicTriggerConditionsTest, Update) {
+ TriggerScriptProto proto;
+ auto* all_of = proto.mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_web_controller_,
+ OnFindElement(Selector(ToSelectorProto("a")), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), nullptr));
+ EXPECT_CALL(mock_web_controller_,
+ OnFindElement(Selector(ToSelectorProto("b")), _))
+ .WillOnce(
+ RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ EXPECT_CALL(mock_web_controller_,
+ OnFindElement(Selector(ToSelectorProto("c")), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), nullptr));
+
+ EXPECT_CALL(mock_callback_, Run).Times(1);
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto);
+ dynamic_trigger_conditions_.Update(&mock_web_controller_,
+ mock_callback_.Get());
+
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("a"))),
+ base::make_optional(true));
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("b"))),
+ base::make_optional(false));
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("c"))),
+ base::make_optional(true));
+}
+
+TEST_F(DynamicTriggerConditionsTest, ClearSelectors) {
+ TriggerScriptProto proto;
+ *proto.mutable_trigger_condition()->mutable_selector() = ToSelectorProto("a");
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto);
+ EXPECT_EQ(GetSelectorsForTest()->size(), 1u);
+ dynamic_trigger_conditions_.ClearSelectors();
+ EXPECT_EQ(GetSelectorsForTest()->size(), 0u);
+}
+
+TEST_F(DynamicTriggerConditionsTest, HasResults) {
+ // Since no selectors were added to the evaluation, the result is valid.
+ EXPECT_TRUE(dynamic_trigger_conditions_.HasResults());
+
+ TriggerScriptProto proto;
+ *proto.mutable_trigger_condition()->mutable_selector() = ToSelectorProto("a");
+ dynamic_trigger_conditions_.AddSelectorsFromTriggerScript(proto);
+ EXPECT_FALSE(dynamic_trigger_conditions_.HasResults());
+
+ EXPECT_CALL(mock_web_controller_,
+ OnFindElement(Selector(ToSelectorProto("a")), _))
+ .WillOnce(RunOnceCallback<1>(OkClientStatus(), nullptr));
+ dynamic_trigger_conditions_.Update(&mock_web_controller_,
+ mock_callback_.Get());
+ EXPECT_TRUE(dynamic_trigger_conditions_.HasResults());
+
+ EXPECT_CALL(mock_web_controller_,
+ OnFindElement(Selector(ToSelectorProto("a")), _))
+ .WillOnce(
+ [&](const Selector& selector, ElementFinder::Callback& callback) {
+ // While Update is running, GetSelectorMatches should return the
+ // previous results.
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("a"))),
+ base::make_optional(true));
+ std::move(callback).Run(ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ nullptr);
+ });
+ dynamic_trigger_conditions_.Update(&mock_web_controller_,
+ mock_callback_.Get());
+
+ // After the update, the new result is returned.
+ EXPECT_EQ(dynamic_trigger_conditions_.GetSelectorMatches(
+ Selector(ToSelectorProto("a"))),
+ base::make_optional(false));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.cc
new file mode 100644
index 00000000000..21f8d794560
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h"
+
+namespace autofill_assistant {
+
+MockDynamicTriggerConditions::MockDynamicTriggerConditions() = default;
+MockDynamicTriggerConditions::~MockDynamicTriggerConditions() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h
new file mode 100644
index 00000000000..79ecb8170fd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h
@@ -0,0 +1,37 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_DYNAMIC_TRIGGER_CONDITIONS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_DYNAMIC_TRIGGER_CONDITIONS_H_
+
+#include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockDynamicTriggerConditions : public DynamicTriggerConditions {
+ public:
+ MockDynamicTriggerConditions();
+ ~MockDynamicTriggerConditions() override;
+
+ MOCK_CONST_METHOD1(GetSelectorMatches,
+ base::Optional<bool>(const Selector& selector));
+
+ void Update(WebController* web_controller,
+ base::OnceCallback<void(void)> callback) override {
+ OnUpdate(web_controller, callback);
+ }
+ MOCK_METHOD2(OnUpdate,
+ void(WebController* web_controller,
+ base::OnceCallback<void(void)>& callback));
+
+ MOCK_METHOD1(AddSelectorsFromTriggerScript,
+ void(const TriggerScriptProto& proto));
+ MOCK_METHOD0(ClearSelectors, void(void));
+ MOCK_CONST_METHOD0(HasResults, bool(void));
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_DYNAMIC_TRIGGER_CONDITIONS_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.cc
new file mode 100644
index 00000000000..c9a3d1b57d0
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h"
+
+namespace autofill_assistant {
+
+MockStaticTriggerConditions::MockStaticTriggerConditions() = default;
+MockStaticTriggerConditions::~MockStaticTriggerConditions() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h
new file mode 100644
index 00000000000..46603dc8d15
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_STATIC_TRIGGER_CONDITIONS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_STATIC_TRIGGER_CONDITIONS_H_
+
+#include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockStaticTriggerConditions : public StaticTriggerConditions {
+ public:
+ MockStaticTriggerConditions();
+ ~MockStaticTriggerConditions() override;
+
+ MOCK_METHOD5(
+ Init,
+ void(WebsiteLoginManager* website_login_manager,
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback,
+ const GURL& url,
+ TriggerContext* trigger_context,
+ base::OnceCallback<void(void)> callback));
+ MOCK_METHOD1(set_is_first_time_user, void(bool));
+ MOCK_CONST_METHOD0(is_first_time_user, bool());
+ MOCK_CONST_METHOD0(has_stored_login_credentials, bool());
+ MOCK_CONST_METHOD1(is_in_experiment, bool(int experiment_id));
+ MOCK_CONST_METHOD0(has_results, bool());
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_MOCK_STATIC_TRIGGER_CONDITIONS_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.cc
new file mode 100644
index 00000000000..4551e4a8305
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.cc
@@ -0,0 +1,65 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+
+#include "base/callback.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace autofill_assistant {
+
+StaticTriggerConditions::StaticTriggerConditions() = default;
+StaticTriggerConditions::~StaticTriggerConditions() = default;
+
+void StaticTriggerConditions::Init(
+ WebsiteLoginManager* website_login_manager,
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback,
+ const GURL& url,
+ TriggerContext* trigger_context,
+ base::OnceCallback<void(void)> callback) {
+ DCHECK(!callback_)
+ << "Call to Init while another call to Init was still pending";
+ if (callback_) {
+ return;
+ }
+ is_first_time_user_ = is_first_time_user_callback.Run();
+ trigger_context_ = trigger_context;
+ has_stored_login_credentials_ = false;
+
+ callback_ = std::move(callback);
+ website_login_manager->GetLoginsForUrl(
+ url, base::BindOnce(&StaticTriggerConditions::OnGetLogins,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void StaticTriggerConditions::set_is_first_time_user(bool first_time_user) {
+ is_first_time_user_ = first_time_user;
+}
+
+bool StaticTriggerConditions::is_first_time_user() const {
+ return is_first_time_user_;
+}
+
+bool StaticTriggerConditions::has_stored_login_credentials() const {
+ return has_stored_login_credentials_;
+}
+
+bool StaticTriggerConditions::is_in_experiment(int experiment_id) const {
+ DCHECK(trigger_context_);
+ return trigger_context_->HasExperimentId(base::NumberToString(experiment_id));
+}
+
+bool StaticTriggerConditions::has_results() const {
+ return has_results_;
+}
+
+void StaticTriggerConditions::OnGetLogins(
+ std::vector<WebsiteLoginManager::Login> logins) {
+ has_stored_login_credentials_ = !logins.empty();
+ has_results_ = true;
+ DCHECK(callback_);
+ std::move(callback_).Run();
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h
new file mode 100644
index 00000000000..0721699e2f5
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h
@@ -0,0 +1,59 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/website_login_manager.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+// Provides easy access to the values of static trigger conditions. Static
+// trigger conditions do not depend on the current state of the DOM, as opposed
+// to dynamic element conditions.
+class StaticTriggerConditions {
+ public:
+ StaticTriggerConditions();
+ virtual ~StaticTriggerConditions();
+
+ // Initializes the field values using |website_login_manager| and
+ // |is_first_time_user_callback|. Invokes |callback| when done. All parameters
+ // must outlive this call.
+ virtual void Init(
+ WebsiteLoginManager* website_login_manager,
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback,
+ const GURL& url,
+ TriggerContext* trigger_context,
+ base::OnceCallback<void(void)> callback);
+ virtual void set_is_first_time_user(bool first_time_user);
+ virtual bool is_first_time_user() const;
+ virtual bool has_stored_login_credentials() const;
+ virtual bool is_in_experiment(int experiment_id) const;
+
+ // If true, all values have been evaluated. They may be out-of-date by one
+ // cycle in case an update is currently scheduled.
+ virtual bool has_results() const;
+
+ private:
+ void OnGetLogins(std::vector<WebsiteLoginManager::Login> logins);
+
+ // The callback to invoke once all information requested in |Init| has been
+ // collected. Only valid during calls of |Init|.
+ base::OnceCallback<void(void)> callback_;
+ bool has_results_ = false;
+ bool is_first_time_user_ = true;
+ bool has_stored_login_credentials_ = false;
+ TriggerContext* trigger_context_;
+ base::WeakPtrFactory<StaticTriggerConditions> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions_unittest.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions_unittest.cc
new file mode 100644
index 00000000000..d016a22c1db
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+
+#include "components/autofill_assistant/browser/mock_website_login_manager.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace {
+
+const char kFakeUrl[] = "https://www.example.com";
+
+class StaticTriggerConditionsTest : public testing::Test {
+ public:
+ StaticTriggerConditionsTest() = default;
+ ~StaticTriggerConditionsTest() override = default;
+
+ protected:
+ StaticTriggerConditions static_trigger_conditions_;
+ base::MockCallback<base::RepeatingCallback<bool(void)>>
+ mock_is_first_time_user_callback_;
+ base::MockCallback<base::OnceCallback<void(void)>> mock_callback_;
+ NiceMock<MockWebsiteLoginManager> mock_website_login_manager_;
+};
+
+TEST_F(StaticTriggerConditionsTest, Init) {
+ TriggerContextImpl trigger_context(/* params = */ {}, /* exp = */ "1,2,4");
+ EXPECT_CALL(mock_is_first_time_user_callback_, Run).WillOnce(Return(true));
+ EXPECT_CALL(mock_website_login_manager_, OnGetLoginsForUrl(GURL(kFakeUrl), _))
+ .WillOnce(RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{
+ WebsiteLoginManager::Login(GURL(kFakeUrl), "fake_username")}));
+ EXPECT_CALL(mock_callback_, Run).Times(1);
+ static_trigger_conditions_.Init(
+ &mock_website_login_manager_, mock_is_first_time_user_callback_.Get(),
+ GURL(kFakeUrl), &trigger_context, mock_callback_.Get());
+
+ EXPECT_TRUE(static_trigger_conditions_.is_first_time_user());
+ EXPECT_TRUE(static_trigger_conditions_.has_stored_login_credentials());
+ EXPECT_TRUE(static_trigger_conditions_.is_in_experiment(1));
+ EXPECT_TRUE(static_trigger_conditions_.is_in_experiment(2));
+ EXPECT_FALSE(static_trigger_conditions_.is_in_experiment(3));
+ EXPECT_TRUE(static_trigger_conditions_.is_in_experiment(4));
+}
+
+TEST_F(StaticTriggerConditionsTest, SetIsFirstTimeUser) {
+ EXPECT_TRUE(static_trigger_conditions_.is_first_time_user());
+ static_trigger_conditions_.set_is_first_time_user(false);
+ EXPECT_FALSE(static_trigger_conditions_.is_first_time_user());
+}
+
+TEST_F(StaticTriggerConditionsTest, HasResults) {
+ EXPECT_FALSE(static_trigger_conditions_.has_results());
+
+ TriggerContextImpl trigger_context(/* params = */ {}, /* exp = */ "1,2,4");
+ EXPECT_CALL(mock_is_first_time_user_callback_, Run).WillOnce(Return(true));
+ EXPECT_CALL(mock_website_login_manager_, OnGetLoginsForUrl(GURL(kFakeUrl), _))
+ .WillOnce(RunOnceCallback<1>(std::vector<WebsiteLoginManager::Login>{
+ WebsiteLoginManager::Login(GURL(kFakeUrl), "fake_username")}));
+ EXPECT_CALL(mock_callback_, Run).Times(1);
+ static_trigger_conditions_.Init(
+ &mock_website_login_manager_, mock_is_first_time_user_callback_.Get(),
+ GURL(kFakeUrl), &trigger_context, mock_callback_.Get());
+ EXPECT_TRUE(static_trigger_conditions_.has_results());
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.cc
new file mode 100644
index 00000000000..dec651c4e77
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.cc
@@ -0,0 +1,90 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script.h"
+
+namespace autofill_assistant {
+
+namespace {
+
+bool EvaluateTriggerCondition(
+ const TriggerScriptConditionProto& proto,
+ const StaticTriggerConditions& static_trigger_conditions,
+ const DynamicTriggerConditions& dynamic_trigger_conditions) {
+ switch (proto.type_case()) {
+ case TriggerScriptConditionProto::kAllOf: {
+ for (const auto& condition : proto.all_of().conditions()) {
+ if (!EvaluateTriggerCondition(condition, static_trigger_conditions,
+ dynamic_trigger_conditions)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ case TriggerScriptConditionProto::kAnyOf: {
+ for (const auto& condition : proto.any_of().conditions()) {
+ if (EvaluateTriggerCondition(condition, static_trigger_conditions,
+ dynamic_trigger_conditions)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ case TriggerScriptConditionProto::kNoneOf: {
+ for (const auto& condition : proto.none_of().conditions()) {
+ if (EvaluateTriggerCondition(condition, static_trigger_conditions,
+ dynamic_trigger_conditions)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ case TriggerScriptConditionProto::kSelector: {
+ auto selector_matches = dynamic_trigger_conditions.GetSelectorMatches(
+ Selector(proto.selector()));
+ DCHECK(selector_matches.has_value());
+ return selector_matches.value();
+ }
+ case TriggerScriptConditionProto::kStoredLoginCredentials:
+ return static_trigger_conditions.has_stored_login_credentials();
+ case TriggerScriptConditionProto::kIsFirstTimeUser:
+ return static_trigger_conditions.is_first_time_user();
+ case TriggerScriptConditionProto::kExperimentId:
+ return static_trigger_conditions.is_in_experiment(proto.experiment_id());
+ case TriggerScriptConditionProto::kKeyboardHidden:
+ return !dynamic_trigger_conditions.GetKeyboardVisible();
+ case TriggerScriptConditionProto::TYPE_NOT_SET:
+ return true;
+ }
+}
+
+} // namespace
+
+TriggerScript::TriggerScript(const TriggerScriptProto& proto) : proto_(proto) {}
+TriggerScript::~TriggerScript() = default;
+
+bool TriggerScript::EvaluateTriggerConditions(
+ const StaticTriggerConditions& static_trigger_conditions,
+ const DynamicTriggerConditions& dynamic_trigger_conditions) const {
+ if (!proto_.has_trigger_condition()) {
+ return true;
+ }
+ return EvaluateTriggerCondition(proto_.trigger_condition(),
+ static_trigger_conditions,
+ dynamic_trigger_conditions);
+}
+
+TriggerScriptProto TriggerScript::AsProto() const {
+ return proto_;
+}
+
+bool TriggerScript::waiting_for_precondition_no_longer_true() const {
+ return waiting_for_precondition_no_longer_true_;
+}
+
+void TriggerScript::waiting_for_precondition_no_longer_true(bool waiting) {
+ waiting_for_precondition_no_longer_true_ = waiting;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.h b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.h
new file mode 100644
index 00000000000..748996a1029
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script.h
@@ -0,0 +1,45 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
+
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+
+namespace autofill_assistant {
+
+// C++ class for a particular proto instance of |TriggerScriptProto|.
+class TriggerScript {
+ public:
+ TriggerScript(const TriggerScriptProto& proto);
+ ~TriggerScript();
+ TriggerScript(const TriggerScript&) = delete;
+ TriggerScript& operator=(const TriggerScript&) = delete;
+
+ // Evaluates the trigger conditions of this trigger script. Expects all
+ // trigger conditions to already be evaluated and cached in
+ // |static_trigger_conditions| and |dynamic_trigger_conditions|.
+ bool EvaluateTriggerConditions(
+ const StaticTriggerConditions& static_trigger_conditions,
+ const DynamicTriggerConditions& dynamic_trigger_conditions) const;
+
+ TriggerScriptProto AsProto() const;
+
+ // Whether the trigger script is currently waiting for its precondition to be
+ // fulfilled or for its precondition to stop being fulfilled.
+ bool waiting_for_precondition_no_longer_true() const;
+ void waiting_for_precondition_no_longer_true(bool waiting);
+
+ private:
+ friend class TriggerScriptTest;
+
+ TriggerScriptProto proto_;
+ bool waiting_for_precondition_no_longer_true_ = false;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_action.h b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_action.h
new file mode 100644
index 00000000000..c48e0d44ee5
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_action.h
@@ -0,0 +1,27 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_ACTION_H_
+
+namespace autofill_assistant {
+
+// C++ enum corresponding to the TriggerScriptProto::TriggerScriptAction enum
+// defined in proto.
+//
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.chrome.browser.autofill_assistant.trigger_scripts)
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: TriggerScriptAction
+enum class TriggerScriptAction {
+ UNDEFINED = 0,
+ NOT_NOW = 1,
+ CANCEL_SESSION = 2,
+ CANCEL_FOREVER = 3,
+ SHOW_CANCEL_POPUP = 4,
+ ACCEPT = 5
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_ACTION_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
new file mode 100644
index 00000000000..bc32b7b57cb
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -0,0 +1,555 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
+
+#include <map>
+
+#include "base/numerics/clamped_math.h"
+#include "components/autofill_assistant/browser/client_context.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/url_utils.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "components/version_info/version_info.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_controller.h"
+#include "net/http/http_status_code.h"
+
+namespace {
+
+const char kScriptParameterDebugBundleId[] = "DEBUG_BUNDLE_ID";
+const char kScriptParameterDebugBundleVersion[] = "DEBUG_BUNDLE_VERSION";
+const char kScriptParameterDebugSocketId[] = "DEBUG_SOCKET_ID";
+
+std::map<std::string, std::string> ExtractDebugScriptParameters(
+ const autofill_assistant::TriggerContext& trigger_context) {
+ std::map<std::string, std::string> debug_script_parameters;
+ auto debug_bundle_id =
+ trigger_context.GetParameter(kScriptParameterDebugBundleId);
+ auto debug_bundle_version =
+ trigger_context.GetParameter(kScriptParameterDebugBundleVersion);
+ auto debug_socket_id =
+ trigger_context.GetParameter(kScriptParameterDebugSocketId);
+
+ if (debug_bundle_id) {
+ debug_script_parameters.insert(
+ {kScriptParameterDebugBundleId, *debug_bundle_id});
+ }
+ if (debug_bundle_version) {
+ debug_script_parameters.insert(
+ {kScriptParameterDebugBundleVersion, *debug_bundle_version});
+ }
+ if (debug_socket_id) {
+ debug_script_parameters.insert(
+ {kScriptParameterDebugSocketId, *debug_socket_id});
+ }
+ return debug_script_parameters;
+}
+
+bool IsDialogOnboardingEnabled() {
+ return base::FeatureList::IsEnabled(
+ autofill_assistant::features::kAutofillAssistantDialogOnboarding);
+}
+
+} // namespace
+
+namespace autofill_assistant {
+
+TriggerScriptCoordinator::TriggerScriptCoordinator(
+ content::WebContents* web_contents,
+ WebsiteLoginManager* website_login_manager,
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback,
+ std::unique_ptr<WebController> web_controller,
+ std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& get_trigger_scripts_server,
+ std::unique_ptr<StaticTriggerConditions> static_trigger_conditions,
+ std::unique_ptr<DynamicTriggerConditions> dynamic_trigger_conditions,
+ ukm::UkmRecorder* ukm_recorder)
+ : content::WebContentsObserver(web_contents),
+ website_login_manager_(website_login_manager),
+ is_first_time_user_callback_(std::move(is_first_time_user_callback)),
+ request_sender_(std::move(request_sender)),
+ get_trigger_scripts_server_(get_trigger_scripts_server),
+ web_controller_(std::move(web_controller)),
+ static_trigger_conditions_(std::move(static_trigger_conditions)),
+ dynamic_trigger_conditions_(std::move(dynamic_trigger_conditions)),
+ ukm_recorder_(ukm_recorder) {}
+
+TriggerScriptCoordinator::~TriggerScriptCoordinator() = default;
+
+void TriggerScriptCoordinator::Start(
+ const GURL& deeplink_url,
+ std::unique_ptr<TriggerContext> trigger_context) {
+ deeplink_url_ = deeplink_url;
+ trigger_context_ = std::make_unique<TriggerContextImpl>(
+ ExtractDebugScriptParameters(*trigger_context),
+ trigger_context->experiment_ids());
+ ClientContextProto client_context;
+ client_context.mutable_chrome()->set_chrome_version(
+ version_info::GetProductNameAndVersionForUserAgent());
+
+ request_sender_->SendRequest(
+ get_trigger_scripts_server_,
+ ProtocolUtils::CreateGetTriggerScriptsRequest(
+ deeplink_url_, client_context, trigger_context_->GetParameters()),
+ base::BindOnce(&TriggerScriptCoordinator::OnGetTriggerScripts,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void TriggerScriptCoordinator::OnGetTriggerScripts(
+ int http_status,
+ const std::string& response) {
+ if (http_status != net::HTTP_OK) {
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
+ return;
+ }
+
+ trigger_scripts_.clear();
+ additional_allowed_domains_.clear();
+ base::Optional<int> timeout_ms;
+ int check_interval_ms;
+ if (!ProtocolUtils::ParseTriggerScripts(response, &trigger_scripts_,
+ &additional_allowed_domains_,
+ &check_interval_ms, &timeout_ms)) {
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR);
+ return;
+ }
+ if (trigger_scripts_.empty()) {
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+ return;
+ }
+ trigger_condition_check_interval_ =
+ base::TimeDelta::FromMilliseconds(check_interval_ms);
+ if (timeout_ms.has_value()) {
+ // Note: add 1 for the initial, not-delayed check.
+ initial_trigger_condition_evaluations_ =
+ 1 + base::ClampCeil<int64_t>(
+ base::TimeDelta::FromMilliseconds(*timeout_ms) /
+ trigger_condition_check_interval_);
+ } else {
+ initial_trigger_condition_evaluations_ = -1;
+ }
+ remaining_trigger_condition_evaluations_ =
+ initial_trigger_condition_evaluations_;
+
+ Metrics::RecordLiteScriptShownToUser(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptShownToUser::LITE_SCRIPT_RUNNING);
+ StartCheckingTriggerConditions();
+}
+
+void TriggerScriptCoordinator::PerformTriggerScriptAction(
+ TriggerScriptProto::TriggerScriptAction action) {
+ switch (action) {
+ case TriggerScriptProto::NOT_NOW:
+ if (visible_trigger_script_ != -1) {
+ Metrics::RecordLiteScriptShownToUser(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptShownToUser::LITE_SCRIPT_NOT_NOW);
+ trigger_scripts_[visible_trigger_script_]
+ ->waiting_for_precondition_no_longer_true(true);
+ HideTriggerScript();
+ }
+ return;
+ case TriggerScriptProto::CANCEL_SESSION:
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION);
+ return;
+ case TriggerScriptProto::CANCEL_FOREVER:
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER);
+ return;
+ case TriggerScriptProto::SHOW_CANCEL_POPUP:
+ NOTREACHED();
+ return;
+ case TriggerScriptProto::ACCEPT:
+ if (visible_trigger_script_ == -1) {
+ NOTREACHED();
+ return;
+ }
+ for (Observer& observer : observers_) {
+ observer.OnOnboardingRequested(IsDialogOnboardingEnabled());
+ }
+ return;
+ case TriggerScriptProto::UNDEFINED:
+ return;
+ }
+}
+
+void TriggerScriptCoordinator::OnOnboardingFinished(bool onboardingShown,
+ OnboardingResult result) {
+ // TODO(b/174445633): Replace -1 with a constant like kTriggerScriptNotVisible
+ // at all relevant places
+ if (visible_trigger_script_ != -1) {
+ if (onboardingShown) {
+ switch (result) {
+ case OnboardingResult::DISMISSED:
+ Metrics::RecordLiteScriptOnboarding(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_DISMISSED);
+ break;
+ case OnboardingResult::REJECTED:
+ Metrics::RecordLiteScriptOnboarding(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED);
+ break;
+ case OnboardingResult::NAVIGATION:
+ Metrics::RecordLiteScriptOnboarding(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION);
+ break;
+ case OnboardingResult::ACCEPTED:
+ Metrics::RecordLiteScriptOnboarding(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED);
+ break;
+ }
+ } else {
+ Metrics::RecordLiteScriptOnboarding(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED);
+ }
+
+ if (result == OnboardingResult::ACCEPTED) {
+ // Do not hide the trigger script here, to facilitate a smooth
+ // transition to the regular flow.
+ StopCheckingTriggerConditions();
+ NotifyOnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+ } else if (!IsDialogOnboardingEnabled()) {
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED);
+ }
+ }
+}
+
+void TriggerScriptCoordinator::OnBottomSheetClosedWithSwipe() {
+ if (visible_trigger_script_ == -1) {
+ NOTREACHED();
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_UNKNOWN_FAILURE);
+ return;
+ }
+ Metrics::RecordLiteScriptShownToUser(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptShownToUser::LITE_SCRIPT_SWIPE_DISMISSED);
+ PerformTriggerScriptAction(trigger_scripts_[visible_trigger_script_]
+ ->AsProto()
+ .on_swipe_to_dismiss());
+}
+
+bool TriggerScriptCoordinator::OnBackButtonPressed() {
+ if (visible_trigger_script_ == -1) {
+ return false;
+ }
+ if (web_contents()->GetController().CanGoBack()) {
+ web_contents()->GetController().GoBack();
+ }
+ // We need to handle this event, because by default the bottom sheet will
+ // close when the back button is pressed.
+ return true;
+}
+
+void TriggerScriptCoordinator::OnKeyboardVisibilityChanged(bool visible) {
+ dynamic_trigger_conditions_->SetKeyboardVisible(visible);
+ RunOutOfScheduleTriggerConditionCheck();
+}
+
+void TriggerScriptCoordinator::OnTriggerScriptShown(bool success) {
+ if (!success) {
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW);
+ return;
+ }
+}
+
+void TriggerScriptCoordinator::OnProactiveHelpSettingChanged(
+ bool proactive_help_enabled) {
+ if (!proactive_help_enabled) {
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING);
+ return;
+ }
+}
+
+void TriggerScriptCoordinator::Stop(Metrics::LiteScriptFinishedState state) {
+ VLOG(2) << "Stopping with status " << state;
+ HideTriggerScript();
+ StopCheckingTriggerConditions();
+ NotifyOnTriggerScriptFinished(state);
+}
+
+void TriggerScriptCoordinator::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void TriggerScriptCoordinator::RemoveObserver(const Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void TriggerScriptCoordinator::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ // Ignore navigation events if any of the following is true:
+ // - not currently checking for preconditions (i.e., not yet started).
+ // - not in the main frame.
+ // - document does not change (e.g., same page history navigation).
+ // - WebContents stays at the existing URL (e.g., downloads).
+ if (!is_checking_trigger_conditions_ || !navigation_handle->IsInMainFrame() ||
+ navigation_handle->IsSameDocument() ||
+ !navigation_handle->HasCommitted()) {
+ return;
+ }
+
+ // Chrome has encountered an error and is now displaying an error message
+ // (e.g., network connection lost). This will cancel the current trigger
+ // script session.
+ if (navigation_handle->IsErrorPage()) {
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_NAVIGATION_ERROR);
+ return;
+ }
+
+ // The user has navigated away from the target domain. This will cancel the
+ // current trigger script session.
+ if (!url_utils::IsInDomainOrSubDomain(GetCurrentURL(), deeplink_url_) &&
+ !url_utils::IsInDomainOrSubDomain(GetCurrentURL(),
+ additional_allowed_domains_)) {
+#ifndef NDEBUG
+ VLOG(2) << "Unexpected navigation to " << GetCurrentURL();
+ VLOG(2) << "List of allowed domains:";
+ VLOG(2) << "\t" << deeplink_url_.host();
+ for (const auto& domain : additional_allowed_domains_) {
+ VLOG(2) << "\t" << domain;
+ }
+#endif
+ Stop(Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE);
+ return;
+ }
+}
+
+void TriggerScriptCoordinator::OnVisibilityChanged(
+ content::Visibility visibility) {
+ bool visible = visibility == content::Visibility::VISIBLE;
+ if (web_contents_visible_ == visible) {
+ return;
+ }
+ web_contents_visible_ = visible;
+ OnEffectiveVisibilityChanged();
+}
+
+void TriggerScriptCoordinator::OnTabInteractabilityChanged(bool interactable) {
+ if (web_contents_interactable_ == interactable) {
+ return;
+ }
+ web_contents_interactable_ = interactable;
+ OnEffectiveVisibilityChanged();
+}
+
+void TriggerScriptCoordinator::OnEffectiveVisibilityChanged() {
+ bool visible = web_contents_visible_ && web_contents_interactable_;
+ if (visible) {
+ // Restore UI on tab switch. NOTE: an arbitrary amount of time can pass
+ // between tab-hide and tab-show. It is not guaranteed that the trigger
+ // script that was shown before is still available, hence we need to fetch
+ // it again.
+ DCHECK(visible_trigger_script_ == -1);
+ VLOG(2) << "Restarting after tab became visible again";
+ Start(deeplink_url_, std::move(trigger_context_));
+ } else {
+ // Hide UI on tab switch.
+ VLOG(2) << "Pausing after tab became invisible or non-interactable";
+ StopCheckingTriggerConditions();
+ HideTriggerScript();
+ }
+
+ for (Observer& observer : observers_) {
+ observer.OnVisibilityChanged(visible);
+ }
+}
+
+void TriggerScriptCoordinator::WebContentsDestroyed() {
+ if (!finished_state_recorded_) {
+ Metrics::RecordLiteScriptFinished(
+ ukm_recorder_, web_contents(),
+ visible_trigger_script_ == -1
+ ? Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_INVISIBLE
+ : Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_WEB_CONTENTS_DESTROYED_WHILE_VISIBLE);
+ finished_state_recorded_ = true;
+ }
+}
+
+void TriggerScriptCoordinator::StartCheckingTriggerConditions() {
+ is_checking_trigger_conditions_ = true;
+ dynamic_trigger_conditions_->ClearSelectors();
+ for (const auto& trigger_script : trigger_scripts_) {
+ dynamic_trigger_conditions_->AddSelectorsFromTriggerScript(
+ trigger_script->AsProto());
+ }
+ static_trigger_conditions_->Init(
+ website_login_manager_, is_first_time_user_callback_, deeplink_url_,
+ trigger_context_.get(),
+ base::BindOnce(&TriggerScriptCoordinator::CheckDynamicTriggerConditions,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void TriggerScriptCoordinator::CheckDynamicTriggerConditions() {
+ dynamic_trigger_conditions_->Update(
+ web_controller_.get(),
+ base::BindOnce(
+ &TriggerScriptCoordinator::OnDynamicTriggerConditionsEvaluated,
+ weak_ptr_factory_.GetWeakPtr(),
+ /* is_out_of_schedule = */ false));
+}
+
+void TriggerScriptCoordinator::StopCheckingTriggerConditions() {
+ is_checking_trigger_conditions_ = false;
+}
+
+void TriggerScriptCoordinator::ShowTriggerScript(int index) {
+ if (visible_trigger_script_ == index) {
+ return;
+ }
+
+ Metrics::RecordLiteScriptShownToUser(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptShownToUser::LITE_SCRIPT_SHOWN_TO_USER);
+ visible_trigger_script_ = index;
+ auto proto = trigger_scripts_[index]->AsProto().user_interface();
+ for (Observer& observer : observers_) {
+ observer.OnTriggerScriptShown(proto);
+ }
+}
+
+void TriggerScriptCoordinator::HideTriggerScript() {
+ if (visible_trigger_script_ == -1) {
+ return;
+ }
+
+ // Since the trigger script is now hidden, the timer to track the amount of
+ // time a script was invisible is reset.
+ remaining_trigger_condition_evaluations_ =
+ initial_trigger_condition_evaluations_;
+ static_trigger_conditions_->set_is_first_time_user(false);
+ visible_trigger_script_ = -1;
+ for (Observer& observer : observers_) {
+ observer.OnTriggerScriptHidden();
+ }
+}
+
+void TriggerScriptCoordinator::OnDynamicTriggerConditionsEvaluated(
+ bool is_out_of_schedule) {
+ if (!web_contents_visible_ || !is_checking_trigger_conditions_) {
+ return;
+ }
+ if (!static_trigger_conditions_->has_results() ||
+ !dynamic_trigger_conditions_->HasResults()) {
+ DCHECK(is_out_of_schedule);
+ return;
+ }
+
+ VLOG(3) << "Evaluating trigger conditions...";
+ std::vector<bool> evaluated_trigger_conditions;
+ for (const auto& trigger_script : trigger_scripts_) {
+ evaluated_trigger_conditions.emplace_back(
+ trigger_script->EvaluateTriggerConditions(
+ *static_trigger_conditions_, *dynamic_trigger_conditions_));
+ }
+
+ // Trigger condition for the currently shown trigger script is no longer true.
+ if (visible_trigger_script_ != -1 &&
+ !evaluated_trigger_conditions[visible_trigger_script_]) {
+ Metrics::RecordLiteScriptShownToUser(
+ ukm_recorder_, web_contents(),
+ Metrics::LiteScriptShownToUser::
+ LITE_SCRIPT_HIDE_ON_TRIGGER_CONDITION_NO_LONGER_TRUE);
+ HideTriggerScript();
+ // Do not return here: a different trigger script may have become eligible
+ // at the same time.
+ }
+
+ for (size_t i = 0; i < trigger_scripts_.size(); ++i) {
+ // The currently visible trigger script is still visible, nothing to do.
+ if (visible_trigger_script_ != -1 &&
+ i == static_cast<size_t>(visible_trigger_script_) &&
+ evaluated_trigger_conditions[i]) {
+ DCHECK(!trigger_scripts_[i]->waiting_for_precondition_no_longer_true());
+ continue;
+ }
+
+ // The script was waiting for the precondition to no longer be true.
+ // It can now resume regular precondition checking.
+ if (!evaluated_trigger_conditions[i] &&
+ trigger_scripts_[i]->waiting_for_precondition_no_longer_true()) {
+ trigger_scripts_[i]->waiting_for_precondition_no_longer_true(false);
+ continue;
+ }
+
+ if (evaluated_trigger_conditions[i] && visible_trigger_script_ != -1 &&
+ i != static_cast<size_t>(visible_trigger_script_)) {
+ // Should not happen, as trigger script conditions should be mutually
+ // exclusive. If it happens, we just ignore it. This is essentially
+ // first-come-first-serve, prioritizing scripts w.r.t. occurrence in the
+ // proto.
+ continue;
+ }
+
+ // A new trigger script has become eligible for showing.
+ if (evaluated_trigger_conditions[i] &&
+ !trigger_scripts_[i]->waiting_for_precondition_no_longer_true()) {
+ ShowTriggerScript(i);
+ }
+ }
+
+ if (is_out_of_schedule) {
+ // Out-of-schedule checks do not count towards the timeout.
+ return;
+ }
+ if (visible_trigger_script_ == -1 &&
+ remaining_trigger_condition_evaluations_ > 0) {
+ remaining_trigger_condition_evaluations_--;
+ }
+ if (remaining_trigger_condition_evaluations_ == 0) {
+ Stop(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+ return;
+ }
+ content::GetUIThreadTaskRunner({})->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&TriggerScriptCoordinator::CheckDynamicTriggerConditions,
+ weak_ptr_factory_.GetWeakPtr()),
+ trigger_condition_check_interval_);
+}
+
+void TriggerScriptCoordinator::RunOutOfScheduleTriggerConditionCheck() {
+ OnDynamicTriggerConditionsEvaluated(/* is_out_of_schedule = */ true);
+}
+
+void TriggerScriptCoordinator::NotifyOnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState state) {
+ if (!finished_state_recorded_) {
+ finished_state_recorded_ = true;
+ Metrics::RecordLiteScriptFinished(ukm_recorder_, web_contents(), state);
+ }
+
+ for (Observer& observer : observers_) {
+ observer.OnTriggerScriptFinished(state);
+ }
+}
+
+GURL TriggerScriptCoordinator::GetCurrentURL() const {
+ GURL current_url = web_contents()->GetLastCommittedURL();
+ if (current_url.is_empty()) {
+ return deeplink_url_;
+ }
+ return current_url;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
new file mode 100644
index 00000000000..8550c787647
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h
@@ -0,0 +1,220 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/client.h"
+#include "components/autofill_assistant/browser/metrics.h"
+#include "components/autofill_assistant/browser/onboarding_result.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/trigger_script.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+// Fetches and coordinates trigger scripts for a specific url. Similar in scope
+// and responsibility to a regular |controller|, but for trigger scripts instead
+// of regular scripts.
+class TriggerScriptCoordinator : public content::WebContentsObserver {
+ public:
+ // Observer interface for listeners interested in status updates of this
+ // coordinator.
+ class Observer : public base::CheckedObserver {
+ public:
+ Observer() = default;
+ ~Observer() override = default;
+
+ virtual void OnTriggerScriptShown(const TriggerScriptUIProto& proto) = 0;
+ virtual void OnTriggerScriptHidden() = 0;
+ virtual void OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState state) = 0;
+ virtual void OnVisibilityChanged(bool visible) = 0;
+ virtual void OnOnboardingRequested(bool use_dialog_onboarding) = 0;
+ };
+
+ // |web_contents| must outlive this instance.
+ TriggerScriptCoordinator(
+ content::WebContents* web_contents,
+ WebsiteLoginManager* website_login_manager,
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback,
+ std::unique_ptr<WebController> web_controller,
+ std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& get_trigger_scripts_server,
+ std::unique_ptr<StaticTriggerConditions> static_trigger_conditions,
+ std::unique_ptr<DynamicTriggerConditions> dynamic_trigger_conditions,
+ ukm::UkmRecorder* ukm_recorder);
+ ~TriggerScriptCoordinator() override;
+ TriggerScriptCoordinator(const TriggerScriptCoordinator&) = delete;
+ TriggerScriptCoordinator& operator=(const TriggerScriptCoordinator&) = delete;
+
+ // Retrieves all trigger scripts for |deeplink_url| and starts evaluating
+ // their trigger conditions. Observers will be notified of all relevant status
+ // updates.
+ void Start(const GURL& deeplink_url,
+ std::unique_ptr<TriggerContext> trigger_context);
+
+ // Performs |action|. This is usually invoked by the UI as a result of user
+ // interactions.
+ void PerformTriggerScriptAction(
+ TriggerScriptProto::TriggerScriptAction action);
+
+ // Called when the user swipe-dismisses the bottom sheet.
+ void OnBottomSheetClosedWithSwipe();
+
+ // Called when the back button is pressed. Returns whether the event was
+ // handled or not.
+ bool OnBackButtonPressed();
+
+ // Called when the keyboard was shown or hidden.
+ void OnKeyboardVisibilityChanged(bool visible);
+
+ // Called when a trigger script was attempted to be shown on screen. This may
+ // have failed, for example when trying to show a trigger script after
+ // switching from CCT to regular tab.
+ void OnTriggerScriptShown(bool success);
+
+ // Called when the tab's interactability has changed. A tab may be
+ // non-interactable while invisible and/or while the user is in the
+ // tab-switcher.
+ void OnTabInteractabilityChanged(bool interactable);
+
+ // Called when the proactive help Chrome setting has changed.
+ void OnProactiveHelpSettingChanged(bool proactive_help_enabled);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(const Observer* observer);
+
+ // Called when onboarding for trigger script is finished.
+ void OnOnboardingFinished(bool onboardingShown, OnboardingResult result);
+
+ private:
+ friend class TriggerScriptCoordinatorTest;
+
+ // From content::WebContentsObserver.
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void OnVisibilityChanged(content::Visibility visibility) override;
+ void WebContentsDestroyed() override;
+
+ void StartCheckingTriggerConditions();
+ void StopCheckingTriggerConditions();
+ void ShowTriggerScript(int index);
+ void HideTriggerScript();
+ void CheckDynamicTriggerConditions();
+ void OnDynamicTriggerConditionsEvaluated(bool is_out_of_schedule);
+ void OnGetTriggerScripts(int http_status, const std::string& response);
+ void Stop(Metrics::LiteScriptFinishedState state);
+ GURL GetCurrentURL() const;
+ void OnEffectiveVisibilityChanged();
+ void OnboardingRequested();
+
+ // Can be invoked to trigger an immediate check of the trigger condition,
+ // reusing the dynamic results of the last time. Does nothing if there are no
+ // previous results to reuse.
+ void RunOutOfScheduleTriggerConditionCheck();
+
+ void NotifyOnTriggerScriptFinished(Metrics::LiteScriptFinishedState state);
+
+ // Used to query login information for the current webcontents.
+ WebsiteLoginManager* website_login_manager_;
+
+ // Callback that can be used to query whether a user has seen the trigger
+ // script UI at least once or not.
+ base::RepeatingCallback<bool(void)> is_first_time_user_callback_;
+
+ // The original deeplink to request trigger scripts for.
+ GURL deeplink_url_;
+
+ // List of additional domains. If the user leaves the (sub)domain of
+ // |deeplink_url_| or |additional_allowed_domains_|, the session stops.
+ std::vector<std::string> additional_allowed_domains_;
+
+ // The trigger context for the most recent |Start|. This is stored as a member
+ // to allow pausing and resuming the same trigger flow.
+ std::unique_ptr<TriggerContext> trigger_context_;
+
+ // Whether the tab is currently visible or not. While invisible or
+ // non-interactable (e.g., during tab switching), trigger scripts are hidden
+ // and condition evaluation is suspended (see also
+ // |web_contents_interactable_|).
+ bool web_contents_visible_ = true;
+
+ // Whether the tab is currently interactable or not. While invisible or
+ // non-interactable (e.g., during tab switching), trigger scripts are hidden
+ // and condition evaluation is suspended (see also |web_contents_visible_|).
+ bool web_contents_interactable_ = true;
+
+ // Whether the coordinator is currently checking trigger conditions.
+ bool is_checking_trigger_conditions_ = false;
+
+ // Index of the trigger script that is currently being shown. -1 if no script
+ // is being shown.
+ int visible_trigger_script_ = -1;
+
+ // Used to request trigger scripts from the backend.
+ std::unique_ptr<ServiceRequestSender> request_sender_;
+
+ // The URL of the server that should be contacted by |request_sender_|.
+ GURL get_trigger_scripts_server_;
+
+ // The web controller to evaluate element conditions.
+ std::unique_ptr<WebController> web_controller_;
+
+ // The list of currently registered observers.
+ base::ObserverList<Observer> observers_;
+
+ // The list of trigger scripts that were fetched from the backend.
+ std::vector<std::unique_ptr<TriggerScript>> trigger_scripts_;
+
+ // Evaluate and cache the results for static and dynamic trigger conditions.
+ std::unique_ptr<StaticTriggerConditions> static_trigger_conditions_;
+ std::unique_ptr<DynamicTriggerConditions> dynamic_trigger_conditions_;
+
+ // The time between consecutive evaluations of dynamic trigger conditions.
+ base::TimeDelta trigger_condition_check_interval_ =
+ base::TimeDelta::FromMilliseconds(1000);
+
+ // The number of times the trigger condition may be evaluated. If this reaches
+ // 0, the trigger script stops with |LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT|.
+ // -1 means no limit.
+ //
+ // This number is defined by the timeout (specified in proto) divided by
+ // |trigger_condition_check_interval_|. It resets on tab resume and on UI
+ // hidden. While the UI is visible, the number does not decrease.
+ int64_t remaining_trigger_condition_evaluations_ = -1;
+
+ // The initial number of evaluations. Used to store the reset value. See
+ // |remaining_trigger_condition_evaluations_|.
+ int64_t initial_trigger_condition_evaluations_ = -1;
+
+ // The UKM recorder used for metrics.
+ ukm::UkmRecorder* const ukm_recorder_;
+
+ // Flag to ensure that we only get one LiteScriptFinished event per run.
+ bool finished_state_recorded_ = false;
+
+ base::WeakPtrFactory<TriggerScriptCoordinator> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
new file mode 100644
index 00000000000..b2b6624b75c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -0,0 +1,1014 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/mock_website_login_manager.h"
+#include "components/autofill_assistant/browser/service/mock_service_request_sender.h"
+#include "components/autofill_assistant/browser/test_util.h"
+#include "components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "components/version_info/version_info.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::NaggyMock;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::UnorderedElementsAreArray;
+
+std::unique_ptr<base::test::ScopedFeatureList> CreateScopedFeatureList(
+ bool dialog_onboarding) {
+ auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
+ scoped_feature_list->InitWithFeatureState(
+ autofill_assistant::features::kAutofillAssistantDialogOnboarding,
+ dialog_onboarding);
+ return scoped_feature_list;
+}
+
+class MockObserver : public TriggerScriptCoordinator::Observer {
+ public:
+ MOCK_METHOD1(OnTriggerScriptShown, void(const TriggerScriptUIProto& proto));
+ MOCK_METHOD0(OnTriggerScriptHidden, void());
+ MOCK_METHOD1(OnTriggerScriptFinished,
+ void(Metrics::LiteScriptFinishedState state));
+ MOCK_METHOD1(OnVisibilityChanged, void(bool visible));
+ MOCK_METHOD1(OnOnboardingRequested, void(bool use_dialog_onboarding));
+};
+
+const char kFakeDeepLink[] = "https://example.com/q?data=test";
+const char kFakeServerUrl[] =
+ "https://www.fake.backend.com/trigger_script_server";
+
+class TriggerScriptCoordinatorTest : public content::RenderViewHostTestHarness {
+ public:
+ TriggerScriptCoordinatorTest()
+ : content::RenderViewHostTestHarness(
+ base::test::TaskEnvironment::MainThreadType::UI,
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+ ~TriggerScriptCoordinatorTest() override = default;
+
+ void SetUp() override {
+ RenderViewHostTestHarness::SetUp();
+ ukm::InitializeSourceUrlRecorderForWebContents(web_contents());
+
+ auto mock_request_sender =
+ std::make_unique<NiceMock<MockServiceRequestSender>>();
+ mock_request_sender_ = mock_request_sender.get();
+
+ auto mock_web_controller = std::make_unique<NiceMock<MockWebController>>();
+ mock_web_controller_ = mock_web_controller.get();
+
+ auto mock_static_trigger_conditions =
+ std::make_unique<NiceMock<MockStaticTriggerConditions>>();
+ mock_static_trigger_conditions_ = mock_static_trigger_conditions.get();
+ auto mock_dynamic_trigger_conditions =
+ std::make_unique<NiceMock<MockDynamicTriggerConditions>>();
+ mock_dynamic_trigger_conditions_ = mock_dynamic_trigger_conditions.get();
+
+ ON_CALL(*mock_static_trigger_conditions, has_results)
+ .WillByDefault(Return(true));
+ ON_CALL(*mock_dynamic_trigger_conditions, HasResults)
+ .WillByDefault(Return(true));
+
+ coordinator_ = std::make_unique<TriggerScriptCoordinator>(
+ web_contents(), &mock_website_login_manager_,
+ mock_is_first_time_user_callback_.Get(), std::move(mock_web_controller),
+ std::move(mock_request_sender), GURL(kFakeServerUrl),
+ std::move(mock_static_trigger_conditions),
+ std::move(mock_dynamic_trigger_conditions), &ukm_recorder_);
+ coordinator_->AddObserver(&mock_observer_);
+
+ SimulateNavigateToUrl(GURL(kFakeDeepLink));
+ }
+
+ void TearDown() override { coordinator_->RemoveObserver(&mock_observer_); }
+
+ void SimulateWebContentsVisibilityChanged(content::Visibility visibility) {
+ coordinator_->OnVisibilityChanged(visibility);
+ }
+
+ void SimulateWebContentsInteractabilityChanged(bool interactable) {
+ coordinator_->OnTabInteractabilityChanged(interactable);
+ }
+
+ void SimulateNavigateToUrl(const GURL& url) {
+ content::WebContentsTester::For(web_contents())->SetLastCommittedURL(url);
+ content::NavigationSimulator::NavigateAndCommitFromDocument(
+ url, web_contents()->GetMainFrame());
+ content::WebContentsTester::For(web_contents())->TestSetIsLoading(false);
+ }
+
+ void AssertRecordedFinishedState(Metrics::LiteScriptFinishedState state) {
+ auto entries =
+ ukm_recorder_.GetEntriesByName("AutofillAssistant.LiteScriptFinished");
+ ASSERT_THAT(entries.size(), Eq(1u));
+ ukm_recorder_.ExpectEntrySourceHasUrl(
+ entries[0], web_contents()->GetLastCommittedURL());
+ EXPECT_EQ(*ukm_recorder_.GetEntryMetric(entries[0], "LiteScriptFinished"),
+ static_cast<int64_t>(state));
+ }
+
+ void AssertRecordedShownToUserState(Metrics::LiteScriptShownToUser state,
+ int expected_times) {
+ auto entries = ukm_recorder_.GetEntriesByName(
+ "AutofillAssistant.LiteScriptShownToUser");
+ ukm_recorder_.ExpectEntrySourceHasUrl(
+ entries[0], web_contents()->GetLastCommittedURL());
+ int actual_times = 0;
+ for (const auto* entry : entries) {
+ if (*ukm_recorder_.GetEntryMetric(entry, "LiteScriptShownToUser") ==
+ static_cast<int64_t>(state)) {
+ actual_times++;
+ }
+ }
+ EXPECT_EQ(expected_times, actual_times);
+ }
+
+ void AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding state,
+ int expected_times) {
+ auto entries = ukm_recorder_.GetEntriesByName(
+ "AutofillAssistant.LiteScriptOnboarding");
+ ukm_recorder_.ExpectEntrySourceHasUrl(
+ entries[0], web_contents()->GetLastCommittedURL());
+ int actual_times = 0;
+ for (const auto* entry : entries) {
+ if (*ukm_recorder_.GetEntryMetric(entry, "LiteScriptOnboarding") ==
+ static_cast<int64_t>(state)) {
+ actual_times++;
+ }
+ }
+ EXPECT_EQ(expected_times, actual_times);
+ }
+
+ protected:
+ ukm::TestAutoSetUkmRecorder ukm_recorder_;
+ NiceMock<MockServiceRequestSender>* mock_request_sender_;
+ NiceMock<MockWebController>* mock_web_controller_;
+ NiceMock<MockWebsiteLoginManager> mock_website_login_manager_;
+ base::MockCallback<base::RepeatingCallback<bool(void)>>
+ mock_is_first_time_user_callback_;
+ NaggyMock<MockObserver> mock_observer_;
+ std::unique_ptr<TriggerScriptCoordinator> coordinator_;
+ NiceMock<MockStaticTriggerConditions>* mock_static_trigger_conditions_;
+ NiceMock<MockDynamicTriggerConditions>* mock_dynamic_trigger_conditions_;
+};
+
+TEST_F(TriggerScriptCoordinatorTest, StartSendsOnlyApprovedFields) {
+ std::map<std::string, std::string> input_script_params{
+ {"keyA", "valueA"},
+ {"DEBUG_BUNDLE_ID", "bundle_id"},
+ {"DEBUG_SOCKET_ID", "socket_id"},
+ {"keyB", "valueB"},
+ {"DEBUG_BUNDLE_VERSION", "socket_version"}};
+
+ std::map<std::string, std::string> expected_script_params{
+ {"DEBUG_BUNDLE_ID", "bundle_id"},
+ {"DEBUG_SOCKET_ID", "socket_id"},
+ {"DEBUG_BUNDLE_VERSION", "socket_version"}};
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce([&](const GURL& url, const std::string& request_body,
+ ServiceRequestSender::ResponseCallback& callback) {
+ GetTriggerScriptsRequestProto request;
+ ASSERT_TRUE(request.ParseFromString(request_body));
+ EXPECT_THAT(request.url(), Eq(kFakeDeepLink));
+
+ std::map<std::string, std::string> params;
+ for (const auto& param : request.debug_script_parameters()) {
+ params[param.name()] = param.value();
+ }
+ EXPECT_THAT(params, UnorderedElementsAreArray(expected_script_params));
+
+ ClientContextProto expected_client_context;
+ expected_client_context.mutable_chrome()->set_chrome_version(
+ version_info::GetProductNameAndVersionForUserAgent());
+ EXPECT_THAT(request.client_context(), Eq(expected_client_context));
+ });
+
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>(
+ /* params = */ input_script_params,
+ /* exp = */ "1,2,4"));
+}
+
+TEST_F(TriggerScriptCoordinatorTest, StopOnBackendRequestFailed) {
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, ""));
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_FAILED);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, StopOnParsingError) {
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "invalid"));
+ EXPECT_CALL(mock_observer_,
+ OnTriggerScriptFinished(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_GET_ACTIONS_PARSE_ERROR);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, StopOnNoTriggerScriptsAvailable) {
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, StartChecksStaticAndDynamicConditions) {
+ GetTriggerScriptsResponseProto response;
+ auto* trigger_condition_all_of = response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_all_of();
+ *trigger_condition_all_of->add_conditions()->mutable_selector() =
+ ToSelectorProto("#selector");
+ trigger_condition_all_of->add_conditions()->mutable_is_first_time_user();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, ClearSelectors).Times(1);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ AddSelectorsFromTriggerScript(response.trigger_scripts(0)))
+ .Times(1);
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillByDefault(Return(false));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TriggerScriptCoordinatorTest, ShowAndHideTriggerScript) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillByDefault(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // Condition stays true, no further notification should be sent to observers.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // Condition turns false, trigger script is hidden.
+ ON_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillByDefault(Return(false));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // Condition is true again, trigger script is shown again.
+ ON_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillByDefault(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabVisibilityChange) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // When a tab becomes invisible, the trigger script is hidden and trigger
+ // condition evaluation is suspended.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ EXPECT_CALL(mock_observer_, OnVisibilityChanged(false)).Times(1);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .Times(0);
+ SimulateWebContentsVisibilityChanged(content::Visibility::HIDDEN);
+
+ // When a hidden tab becomes visible again, the trigger scripts must be
+ // fetched again.
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ EXPECT_CALL(mock_observer_, OnVisibilityChanged(true)).Times(1);
+ SimulateWebContentsVisibilityChanged(content::Visibility::VISIBLE);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionNotNow) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ coordinator_->PerformTriggerScriptAction(TriggerScriptProto::NOT_NOW);
+
+ // Despite the trigger condition still being true, the trigger script is not
+ // shown again until the condition has become first false and then true again.
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(0);
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(false));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionCancelSession) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ coordinator_->PerformTriggerScriptAction(TriggerScriptProto::CANCEL_SESSION);
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_SESSION);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionCancelForever) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ coordinator_->PerformTriggerScriptAction(TriggerScriptProto::CANCEL_FOREVER);
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_PROMPT_FAILED_CANCEL_FOREVER);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionAccept) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ coordinator_->PerformTriggerScriptAction(TriggerScriptProto::ACCEPT);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, CancelOnNavigateAway) {
+ GetTriggerScriptsResponseProto response;
+ response.add_additional_allowed_domains("other-example.com");
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // Same-domain navigation is ok.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(_)).Times(0);
+ SimulateNavigateToUrl(GURL("https://example.com/cart"));
+
+ // Navigating to sub-domain of original domain is ok.
+ SimulateNavigateToUrl(GURL("https://subdomain.example.com/test"));
+
+ // Navigating to whitelisted domain is ok.
+ SimulateNavigateToUrl(GURL("https://other-example.com/page"));
+
+ // Navigating to subdomain of whitelisted domain is ok.
+ SimulateNavigateToUrl(GURL("https://other-example.com/page"));
+
+ // Navigating to non-whitelisted domain is not ok.
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE))
+ .Times(1);
+ SimulateNavigateToUrl(GURL("https://example.different.com/page"));
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_FAILED_NAVIGATE);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, IgnoreNavigationEventsWhileNotStarted) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // When a tab becomes invisible, navigation events are disregarded.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished).Times(0);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .Times(0);
+ SimulateWebContentsVisibilityChanged(content::Visibility::HIDDEN);
+ // Note: in reality, it should be impossible to navigate on hidden tabs.
+ SimulateNavigateToUrl(GURL("https://example.different.com"));
+ SimulateNavigateToUrl(GURL("https://also-not-supported.com"));
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, /* response = */ ""));
+ // However, when the tab becomes visible again, the trigger script is
+ // restarted and thus fails if the tab is still on an unsupported domain.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE))
+ .Times(1);
+ SimulateWebContentsVisibilityChanged(content::Visibility::VISIBLE);
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_NO_TRIGGER_SCRIPT_AVAILABLE);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, BottomSheetClosedWithSwipe) {
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts()->set_on_swipe_to_dismiss(
+ TriggerScriptProto::NOT_NOW);
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ ON_CALL(*mock_dynamic_trigger_conditions_, OnUpdate(mock_web_controller_, _))
+ .WillByDefault(RunOnceCallback<1>());
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ coordinator_->OnBottomSheetClosedWithSwipe();
+ AssertRecordedShownToUserState(
+ Metrics::LiteScriptShownToUser::LITE_SCRIPT_SWIPE_DISMISSED, 1);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, TimeoutAfterInvisibleForTooLong) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ response.set_timeout_ms(3000);
+ response.set_trigger_condition_check_interval_ms(1000);
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+
+ // Note: expect 4 calls: 1 initial plus 3 until timeout.
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .Times(4)
+ .WillRepeatedly(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .Times(4)
+ .WillRepeatedly(Return(false));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, TimeoutResetsAfterTriggerScriptShown) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ response.set_timeout_ms(3000);
+ response.set_trigger_condition_check_interval_ms(1000);
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+
+ // While the trigger script is shown, the timeout is ignored.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillRepeatedly(Return(true));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ // When the trigger script is hidden, the timeout resets.
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillRepeatedly(Return(false));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, NoTimeoutByDefault) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished).Times(0);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillRepeatedly(Return(false));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ for (int i = 0; i < 10; ++i) {
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ }
+}
+
+TEST_F(TriggerScriptCoordinatorTest, KeyboardEventTriggersOutOfScheduleCheck) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ response.set_timeout_ms(3000);
+ response.set_trigger_condition_check_interval_ms(1000);
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(false));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // While the next call to Update is pending, a keyboard visibility event will
+ // immediately trigger an out-of-schedule update (which does not count towards
+ // the timeout).
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(false));
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, OnUpdate).Times(0);
+ coordinator_->OnKeyboardVisibilityChanged(true);
+ }
+
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .Times(3)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .Times(3)
+ .WillRepeatedly(RunOnceCallback<1>());
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT));
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_TRIGGER_CONDITION_TIMEOUT);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, OnTriggerScriptFailedToShow) {
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).WillOnce([&]() {
+ coordinator_->OnTriggerScriptShown(/* success = */ false);
+ });
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW));
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_FAILED_TO_SHOW);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, OnProactiveHelpSettingDisabled) {
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING));
+ coordinator_->OnProactiveHelpSettingChanged(
+ /* proactive_help_enabled = */ false);
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_DISABLED_PROACTIVE_HELP_SETTING);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabSwitch) {
+ GetTriggerScriptsResponseProto response;
+ *response.add_trigger_scripts()
+ ->mutable_trigger_condition()
+ ->mutable_selector() = ToSelectorProto("#selector");
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ // During tab switching, the tab becomes non-interactive. In this test, the
+ // same tab is then re-selected (otherwise, the original tab's visibility
+ // would change).
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ EXPECT_CALL(mock_observer_, OnVisibilityChanged(false)).Times(1);
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .Times(0);
+ SimulateWebContentsInteractabilityChanged(/* interactable = */ false);
+
+ // When a non-interactable tab becomes interactable again, the trigger scripts
+ // must be fetched again.
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillOnce(RunOnceCallback<1>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_, GetSelectorMatches)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ EXPECT_CALL(mock_observer_, OnVisibilityChanged(true)).Times(1);
+ SimulateWebContentsInteractabilityChanged(/* interactable = */ true);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, OnboardingShownAndAccepted) {
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(0);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ true,
+ /* result= */ OnboardingResult::ACCEPTED);
+
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED,
+ 1);
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+}
+
+TEST_F(TriggerScriptCoordinatorTest,
+ CancellingDialogOnboardingDoesNotStopTriggerScript) {
+ auto feature_list = CreateScopedFeatureList(/* dialog_onboarding= */ true);
+
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(mock_observer_, OnTriggerScriptFinished).Times(0);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ true,
+ /* result= */ OnboardingResult::REJECTED);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ true,
+ /* result= */ OnboardingResult::DISMISSED);
+ coordinator_->OnOnboardingFinished(
+ /* onboardingShown= */ true,
+ /* result= */ OnboardingResult::NAVIGATION);
+
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(0);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ true,
+ /* result= */ OnboardingResult::ACCEPTED);
+
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED,
+ 1);
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_ACCEPTED,
+ 1);
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::
+ LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION,
+ 1);
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+}
+
+TEST_F(TriggerScriptCoordinatorTest,
+ RejectingBottomSheetOnboardingStopsTriggerScript) {
+ auto feature_list = CreateScopedFeatureList(/* dialog_onboarding= */ false);
+
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptHidden).Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(0);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ true,
+ /* result= */ OnboardingResult::REJECTED);
+
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_SEEN_AND_REJECTED,
+ 1);
+ AssertRecordedFinishedState(Metrics::LiteScriptFinishedState::
+ LITE_SCRIPT_BOTTOMSHEET_ONBOARDING_REJECTED);
+}
+
+TEST_F(TriggerScriptCoordinatorTest, OnboardingNotShown) {
+ GetTriggerScriptsResponseProto response;
+ response.add_trigger_scripts();
+ std::string serialized_response;
+ response.SerializeToString(&serialized_response);
+
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
+ EXPECT_CALL(*mock_static_trigger_conditions_, Init)
+ .WillOnce(RunOnceCallback<4>());
+ EXPECT_CALL(*mock_dynamic_trigger_conditions_,
+ OnUpdate(mock_web_controller_, _))
+ .WillRepeatedly(RunOnceCallback<1>());
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(1);
+ coordinator_->Start(GURL(kFakeDeepLink),
+ std::make_unique<TriggerContextImpl>());
+
+ EXPECT_CALL(
+ mock_observer_,
+ OnTriggerScriptFinished(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED))
+ .Times(1);
+ EXPECT_CALL(mock_observer_, OnTriggerScriptShown).Times(0);
+ coordinator_->OnOnboardingFinished(/* onboardingShown= */ false,
+ /* result= */ OnboardingResult::ACCEPTED);
+
+ AssertRecordedLiteScriptOnboardingState(
+ Metrics::LiteScriptOnboarding::LITE_SCRIPT_ONBOARDING_ALREADY_ACCEPTED,
+ 1);
+ AssertRecordedFinishedState(
+ Metrics::LiteScriptFinishedState::LITE_SCRIPT_PROMPT_SUCCEEDED);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_unittest.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_unittest.cc
new file mode 100644
index 00000000000..619334a944c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/mock_dynamic_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/mock_static_trigger_conditions.h"
+#include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+using ::testing::NiceMock;
+using ::testing::Return;
+
+class TriggerScriptTest : public testing::Test {
+ public:
+ TriggerScriptTest() : trigger_script_(TriggerScriptProto()) {}
+ ~TriggerScriptTest() override = default;
+
+ TriggerScriptProto* GetProtoForTest() { return &trigger_script_.proto_; }
+
+ protected:
+ TriggerScript trigger_script_;
+ NiceMock<MockStaticTriggerConditions> mock_static_trigger_conditions_;
+ NiceMock<MockDynamicTriggerConditions> mock_dynamic_trigger_conditions_;
+};
+
+TEST_F(TriggerScriptTest, NoTriggerConditionSucceeds) {
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, EmptyTriggerConditionSucceeds) {
+ GetProtoForTest()->mutable_trigger_condition();
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AllOfSucceedsIfEmpty) {
+ GetProtoForTest()->mutable_trigger_condition()->mutable_all_of();
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AllOfFailsIfOnlySomeConditionsAreTrue) {
+ auto* all_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(false));
+ // "b" already fails, "c" does not need to be evaluated.
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .Times(0);
+
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AllOfSucceedsIfAllConditionsAreTrue) {
+ auto* all_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AnyOfFailsIfEmpty) {
+ GetProtoForTest()->mutable_trigger_condition()->mutable_any_of();
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AnyOfSucceedsIfSomeConditionsAreTrue) {
+ auto* any_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_any_of();
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(true));
+ // "b" already succeeds, "c" does not need to be evaluated.
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .Times(0);
+
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, AnyOfFailsIfAllConditionsAreFalse) {
+ auto* any_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_any_of();
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .WillOnce(Return(false));
+
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, NoneOfSucceedsIfEmpty) {
+ GetProtoForTest()->mutable_trigger_condition()->mutable_none_of();
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, NoneOfFailsIfSomeConditionsAreTrue) {
+ auto* none_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_none_of();
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(true));
+ // "b" already succeeds, "c" does not need to be evaluated.
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .Times(0);
+
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, NoneOfSucceedsIfAllConditionsAreFalse) {
+ auto* none_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_none_of();
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .WillOnce(Return(false));
+
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, ComplexConditions) {
+ // Tests the condition a && (b || !(c)).
+ auto* all_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_all_of();
+ *all_of->add_conditions()->mutable_selector() = ToSelectorProto("a");
+ auto* any_of = all_of->add_conditions()->mutable_any_of();
+ *any_of->add_conditions()->mutable_selector() = ToSelectorProto("b");
+ auto* none_of = any_of->add_conditions()->mutable_none_of();
+ *none_of->add_conditions()->mutable_selector() = ToSelectorProto("c");
+
+ // a == false, b == *, c == * -> false
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .Times(0);
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .Times(0);
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+
+ // a == true, b == true, c == * -> true
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .Times(0);
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+
+ // a == true, b == false, c == true -> false
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .WillOnce(Return(true));
+ EXPECT_FALSE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+
+ // a == true, b == false, c == false -> true
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("a"))))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("b"))))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_dynamic_trigger_conditions_,
+ GetSelectorMatches(Selector(ToSelectorProto("c"))))
+ .WillOnce(Return(false));
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+TEST_F(TriggerScriptTest, StaticTriggerConditions) {
+ auto* all_of =
+ GetProtoForTest()->mutable_trigger_condition()->mutable_all_of();
+ all_of->add_conditions()->mutable_stored_login_credentials();
+ all_of->add_conditions()->mutable_is_first_time_user();
+ all_of->add_conditions()->set_experiment_id(12);
+
+ EXPECT_CALL(mock_static_trigger_conditions_, is_first_time_user)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_static_trigger_conditions_, has_stored_login_credentials)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_static_trigger_conditions_, is_in_experiment(12))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(trigger_script_.EvaluateTriggerConditions(
+ mock_static_trigger_conditions_, mock_dynamic_trigger_conditions_));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/ui_delegate.h b/chromium/components/autofill_assistant/browser/ui_delegate.h
index cbe589f4873..a03bc0d12c8 100644
--- a/chromium/components/autofill_assistant/browser/ui_delegate.h
+++ b/chromium/components/autofill_assistant/browser/ui_delegate.h
@@ -11,6 +11,7 @@
#include "base/optional.h"
#include "bottom_sheet_state.h"
+#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/event_handler.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/rectf.h"
@@ -24,7 +25,6 @@ class ControllerObserver;
class Details;
class InfoBox;
class BasicInteractions;
-struct ClientSettings;
// UI delegate called for script executions.
class UiDelegate {
@@ -179,6 +179,7 @@ class UiDelegate {
// Reports a fatal error to Autofill Assistant, which should then stop.
virtual void OnFatalError(const std::string& error_message,
+ bool show_feedback_chip,
Metrics::DropOutReason reason) = 0;
// Reports that Autofill Assistant should be Stopped.
@@ -263,6 +264,9 @@ class UiDelegate {
// Returns whether the UI delegate is currently running a lite script or not.
virtual bool IsRunningLiteScript() const = 0;
+ // Called when the visibility of the keyboard has changed.
+ virtual void OnKeyboardVisibilityChanged(bool visible) = 0;
+
protected:
UiDelegate() = default;
};
diff --git a/chromium/components/autofill_assistant/browser/url_utils.cc b/chromium/components/autofill_assistant/browser/url_utils.cc
new file mode 100644
index 00000000000..4a9129b5010
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/url_utils.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 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_assistant/browser/url_utils.h"
+
+#include <algorithm>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+
+namespace {
+
+bool IsInSubDomain(const GURL& url, const std::string& domain) {
+ return base::EndsWith(base::StringPiece(url.host()),
+ base::StringPiece("." + domain),
+ base::CompareCase::INSENSITIVE_ASCII);
+}
+} // namespace
+
+namespace autofill_assistant {
+namespace url_utils {
+
+bool IsInDomainOrSubDomain(const GURL& url, const GURL& domain) {
+ if (url.host() == domain.host()) {
+ return true;
+ }
+
+ return IsInSubDomain(url, domain.host());
+}
+
+bool IsInDomainOrSubDomain(const GURL& url,
+ const std::vector<std::string>& allowed_domains) {
+ return std::find_if(allowed_domains.begin(), allowed_domains.end(),
+ [url](const std::string& allowed_domain) {
+ return url.host() == allowed_domain ||
+ IsInSubDomain(url, allowed_domain);
+ }) != allowed_domains.end();
+}
+
+} // namespace url_utils
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/url_utils.h b/chromium/components/autofill_assistant/browser/url_utils.h
new file mode 100644
index 00000000000..f143fac5acb
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/url_utils.h
@@ -0,0 +1,28 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_URL_UTILS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_URL_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+namespace url_utils {
+
+// Check whether |url| is in |domain| or in a subdomain of |domain|.
+bool IsInDomainOrSubDomain(const GURL& url, const GURL& domain);
+
+// Same as above, but checks against a vector of domains instead. Returns true
+// if |url| is in |allowed_domains| or a subdomain of |allowed_domains|.
+// NOTE: Domains should be specified without leading spec, e.g., "example.com".
+bool IsInDomainOrSubDomain(const GURL& url,
+ const std::vector<std::string>& allowed_domains);
+
+} // namespace url_utils
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_URL_UTILS_H_
diff --git a/chromium/components/autofill_assistant/browser/url_utils_unittest.cc b/chromium/components/autofill_assistant/browser/url_utils_unittest.cc
new file mode 100644
index 00000000000..fc10006503c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/url_utils_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright 2020 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_assistant/browser/url_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace url_utils {
+namespace {
+
+TEST(UrlUtilsTest, IsInDomainOrSubDomain) {
+ std::vector<std::string> allowed_domains = {"example.com",
+ "other-example.com"};
+ EXPECT_TRUE(IsInDomainOrSubDomain(GURL("http://a.example.com/"),
+ GURL("http://example.com")));
+ EXPECT_TRUE(
+ IsInDomainOrSubDomain(GURL("http://a.example.com/"), allowed_domains));
+
+ EXPECT_FALSE(IsInDomainOrSubDomain(GURL("http://other-example.com/"),
+ GURL("http://example.com")));
+ EXPECT_TRUE(IsInDomainOrSubDomain(GURL("http://other-example.com/"),
+ allowed_domains));
+
+ EXPECT_FALSE(IsInDomainOrSubDomain(GURL("http://sub.other-example.com/"),
+ GURL("http://example.com")));
+ EXPECT_TRUE(IsInDomainOrSubDomain(GURL("http://sub.other-example.com/"),
+ allowed_domains));
+
+ EXPECT_FALSE(IsInDomainOrSubDomain(GURL("http://example.different.com/"),
+ GURL("http://example.com")));
+ EXPECT_FALSE(IsInDomainOrSubDomain(GURL("http://example.different.com/"),
+ allowed_domains));
+}
+
+} // namespace
+} // namespace url_utils
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/user_data.cc b/chromium/components/autofill_assistant/browser/user_data.cc
index d973009eef8..9e9c18eca70 100644
--- a/chromium/components/autofill_assistant/browser/user_data.cc
+++ b/chromium/components/autofill_assistant/browser/user_data.cc
@@ -6,7 +6,6 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/common/password_form.h"
namespace autofill_assistant {
diff --git a/chromium/components/autofill_assistant/browser/user_data_util.cc b/chromium/components/autofill_assistant/browser/user_data_util.cc
index 1b7da34007f..02308bb6320 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util.cc
+++ b/chromium/components/autofill_assistant/browser/user_data_util.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
+#include "components/autofill_assistant/browser/field_formatter.h"
#include "third_party/libaddressinput/chromium/addressinput_util.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
@@ -155,6 +156,15 @@ bool IsCompleteAddress(const autofill::AutofillProfile* profile,
} // namespace
+std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
+ const autofill::AutofillProfile& profile) {
+ auto unique_profile = std::make_unique<autofill::AutofillProfile>(profile);
+ // Temporary workaround so that fields like first/last name a properly
+ // populated.
+ unique_profile->FinalizeAfterImport();
+ return unique_profile;
+}
+
std::vector<int> SortContactsByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles) {
@@ -353,4 +363,34 @@ bool IsCompleteCreditCard(
return true;
}
+ClientStatus GetFormattedAutofillValue(const AutofillValue& autofill_value,
+ const UserData* user_data,
+ std::string* out_value) {
+ if (autofill_value.profile().identifier().empty() ||
+ autofill_value.value_expression().empty()) {
+ VLOG(1) << "|autofill_value| with empty "
+ "|profile.identifier| or |value_expression|";
+ return ClientStatus(INVALID_ACTION);
+ }
+
+ const autofill::AutofillProfile* address =
+ user_data->selected_address(autofill_value.profile().identifier());
+ if (address == nullptr) {
+ VLOG(1) << "Requested unknown address '"
+ << autofill_value.profile().identifier() << "'";
+ return ClientStatus(PRECONDITION_FAILED);
+ }
+
+ auto value = field_formatter::FormatString(
+ autofill_value.value_expression(),
+ field_formatter::CreateAutofillMappings(*address,
+ /* locale= */ "en-US"));
+ if (!value.has_value()) {
+ return ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE);
+ }
+
+ out_value->assign(*value);
+ return OkClientStatus();
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/user_data_util.h b/chromium/components/autofill_assistant/browser/user_data_util.h
index e5fa363aa72..82b9312e7a2 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util.h
+++ b/chromium/components/autofill_assistant/browser/user_data_util.h
@@ -8,10 +8,15 @@
#include <vector>
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/user_data.h"
namespace autofill_assistant {
+std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
+ const autofill::AutofillProfile& profile);
+
// Sorts the given autofill profiles based on completeness, and returns a
// vector of profile indices in sorted order. Full profiles will be ordered
// before empty ones, and for equally complete profiles, this falls back to
@@ -74,6 +79,10 @@ bool IsCompleteCreditCard(
const autofill::AutofillProfile* billing_profile,
const CollectUserDataOptions& collect_user_data_options);
+ClientStatus GetFormattedAutofillValue(const AutofillValue& autofill_value,
+ const UserData* user_data,
+ std::string* out_value);
+
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_USER_DATA_UTIL_H_
diff --git a/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc b/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
index 0cf04fd4560..f5613c68025 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
@@ -4,10 +4,16 @@
#include "components/autofill_assistant/browser/user_data_util.h"
+#include "base/guid.h"
+#include "base/strings/strcat.h"
#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_data.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -671,5 +677,79 @@ TEST(UserDataUtilTest, CompleteCreditCardWithBadNetwork) {
EXPECT_TRUE(IsCompleteCreditCard(&card, &address, payment_options_visa));
}
+TEST(UserDataUtilTest, RequestEmptyAutofillValue) {
+ UserData user_data;
+ AutofillValue autofill_value;
+ std::string result;
+
+ EXPECT_EQ(GetFormattedAutofillValue(autofill_value, &user_data, &result)
+ .proto_status(),
+ INVALID_ACTION);
+ EXPECT_EQ(result, "");
+}
+
+TEST(UserDataUtilTest, RequestDataFromUnknownProfile) {
+ UserData user_data;
+ AutofillValue autofill_value;
+ autofill_value.mutable_profile()->set_identifier("none");
+ autofill_value.set_value_expression("value");
+ std::string result;
+
+ EXPECT_EQ(GetFormattedAutofillValue(autofill_value, &user_data, &result)
+ .proto_status(),
+ PRECONDITION_FAILED);
+ EXPECT_EQ(result, "");
+}
+
+TEST(UserDataUtilTest, RequestUnknownDataFromKnownProfile) {
+ UserData user_data;
+ autofill::AutofillProfile contact(base::GenerateGUID(),
+ autofill::test::kEmptyOrigin);
+ // Middle name is expected to be empty.
+ autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
+ "", "", "", "", "", "", "", "", "");
+ user_data.selected_addresses_["contact"] =
+ std::make_unique<autofill::AutofillProfile>(contact);
+
+ AutofillValue autofill_value;
+ autofill_value.mutable_profile()->set_identifier("contact");
+ autofill_value.set_value_expression(
+ base::StrCat({"${",
+ base::NumberToString(static_cast<int>(
+ autofill::ServerFieldType::NAME_MIDDLE)),
+ "}"}));
+
+ std::string result;
+
+ EXPECT_EQ(GetFormattedAutofillValue(autofill_value, &user_data, &result)
+ .proto_status(),
+ AUTOFILL_INFO_NOT_AVAILABLE);
+ EXPECT_EQ(result, "");
+}
+
+TEST(UserDataUtilTest, RequestKnownDataFromKnownProfile) {
+ UserData user_data;
+ autofill::AutofillProfile contact(base::GenerateGUID(),
+ autofill::test::kEmptyOrigin);
+ autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
+ "", "", "", "", "", "", "", "", "");
+ user_data.selected_addresses_["contact"] =
+ std::make_unique<autofill::AutofillProfile>(contact);
+
+ AutofillValue autofill_value;
+ autofill_value.mutable_profile()->set_identifier("contact");
+ autofill_value.set_value_expression(
+ base::StrCat({"${",
+ base::NumberToString(static_cast<int>(
+ autofill::ServerFieldType::NAME_FIRST)),
+ "}"}));
+
+ std::string result;
+
+ EXPECT_TRUE(
+ GetFormattedAutofillValue(autofill_value, &user_data, &result).ok());
+ EXPECT_EQ(result, "John");
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/view_layout.proto b/chromium/components/autofill_assistant/browser/view_layout.proto
index 2981e6563e0..1815ce42a76 100644
--- a/chromium/components/autofill_assistant/browser/view_layout.proto
+++ b/chromium/components/autofill_assistant/browser/view_layout.proto
@@ -54,6 +54,7 @@ message ClientDimensionProto {
float width_factor = 2;
// Factor to multiply with the client's total height.
float height_factor = 3;
+ int32 size_in_pixel = 4;
}
}
@@ -76,6 +77,9 @@ message FaviconDrawableProto {
optional ClientDimensionProto diameter_size = 1;
// If true, we always use the monogram, even if the favicon is available.
optional bool force_monogram = 2;
+ // If set, this url is used to fetch favicon, otherwise current url is used to
+ // fetch favicon.
+ optional string website_url = 3;
}
// A drawable for use in backgrounds or in image views.
diff --git a/chromium/components/autofill_assistant/browser/wait_for_document_operation.cc b/chromium/components/autofill_assistant/browser/wait_for_document_operation.cc
new file mode 100644
index 00000000000..f2b303ad41b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/wait_for_document_operation.cc
@@ -0,0 +1,69 @@
+// Copyright 2020 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_assistant/browser/wait_for_document_operation.h"
+
+#include "base/callback.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/script_executor_delegate.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+
+namespace autofill_assistant {
+
+WaitForDocumentOperation::WaitForDocumentOperation(
+ ScriptExecutorDelegate* script_executor_delegate,
+ base::TimeDelta max_wait_time,
+ DocumentReadyState min_ready_state,
+ const ElementFinder::Result& optional_frame_element,
+ WaitForDocumentOperation::Callback callback)
+ : script_executor_delegate_(script_executor_delegate),
+ max_wait_time_(max_wait_time),
+ min_ready_state_(min_ready_state),
+ optional_frame_element_(optional_frame_element),
+ callback_(std::move(callback)) {}
+
+WaitForDocumentOperation::~WaitForDocumentOperation() = default;
+
+void WaitForDocumentOperation::Run() {
+ timer_.Start(
+ FROM_HERE, max_wait_time_,
+ base::BindOnce(&WaitForDocumentOperation::OnTimeout,
+ weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
+ script_executor_delegate_->GetWebController()->WaitForDocumentReadyState(
+ optional_frame_element_, min_ready_state_,
+ base::BindOnce(&WaitForDocumentOperation::OnWaitForState,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WaitForDocumentOperation::OnTimeout(base::TimeTicks wait_time_start) {
+ if (!callback_) {
+ // Callback already ran successfully.
+ return;
+ }
+
+ ClientStatus timed_out(TIMED_OUT);
+ timed_out.mutable_details()
+ ->mutable_web_controller_error_info()
+ ->set_failed_web_action(
+ WebControllerErrorInfoProto::WAIT_FOR_DOCUMENT_READY_STATE);
+ std::move(callback_).Run(timed_out, DOCUMENT_UNKNOWN_READY_STATE,
+ base::TimeTicks::Now() - wait_time_start);
+}
+
+void WaitForDocumentOperation::OnWaitForState(const ClientStatus& status,
+ DocumentReadyState current_state,
+ base::TimeDelta wait_time) {
+ if (!callback_) {
+ // Callback already ran through timeout.
+ return;
+ }
+
+ std::move(callback_).Run(status, current_state, wait_time);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/wait_for_document_operation.h b/chromium/components/autofill_assistant/browser/wait_for_document_operation.h
new file mode 100644
index 00000000000..0799339f751
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/wait_for_document_operation.h
@@ -0,0 +1,57 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_WAIT_FOR_DOCUMENT_OPERATION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WAIT_FOR_DOCUMENT_OPERATION_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/script_executor_delegate.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
+
+namespace autofill_assistant {
+
+// Waits for a minimal state of the document or times out if the state is not
+// reached in time.
+class WaitForDocumentOperation {
+ public:
+ using Callback = base::OnceCallback<
+ void(const ClientStatus&, DocumentReadyState, base::TimeDelta)>;
+
+ // |script_executor_delegate| must outlive this instance.
+ WaitForDocumentOperation(ScriptExecutorDelegate* script_executor_delegate,
+ base::TimeDelta max_wait_time,
+ DocumentReadyState min_ready_state,
+ const ElementFinder::Result& optional_frame_element,
+ Callback callback);
+ ~WaitForDocumentOperation();
+
+ WaitForDocumentOperation(const WaitForDocumentOperation&) = delete;
+ WaitForDocumentOperation& operator=(const WaitForDocumentOperation&) = delete;
+
+ void Run();
+
+ private:
+ void OnTimeout(base::TimeTicks wait_time_start);
+ void OnWaitForState(const ClientStatus& status,
+ DocumentReadyState current_state,
+ base::TimeDelta wait_time);
+
+ ScriptExecutorDelegate* script_executor_delegate_;
+ base::TimeDelta max_wait_time_;
+ DocumentReadyState min_ready_state_;
+ const ElementFinder::Result& optional_frame_element_;
+ Callback callback_;
+ base::OneShotTimer timer_;
+
+ base::WeakPtrFactory<WaitForDocumentOperation> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WAIT_FOR_DOCUMENT_OPERATION_H_
diff --git a/chromium/components/autofill_assistant/browser/wait_for_document_operation_unittest.cc b/chromium/components/autofill_assistant/browser/wait_for_document_operation_unittest.cc
new file mode 100644
index 00000000000..6ebafd82ea0
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/wait_for_document_operation_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright 2020 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_assistant/browser/wait_for_document_operation.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Property;
+using ::testing::Return;
+
+class WaitForDocumentOperationTest : public testing::Test {
+ public:
+ WaitForDocumentOperationTest()
+ : task_env_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+ void SetUp() override {
+ fake_script_executor_delegate_.SetWebController(&mock_web_controller_);
+
+ wait_for_document_operation_ = std::make_unique<WaitForDocumentOperation>(
+ &fake_script_executor_delegate_, base::TimeDelta::FromSeconds(1),
+ DOCUMENT_COMPLETE, ElementFinder::Result(), mock_callback_.Get());
+ }
+
+ protected:
+ // task_env_ must be first to guarantee other field
+ // creation run in that environment.
+ base::test::TaskEnvironment task_env_;
+
+ FakeScriptExecutorDelegate fake_script_executor_delegate_;
+ MockWebController mock_web_controller_;
+ base::MockCallback<WaitForDocumentOperation::Callback> mock_callback_;
+ std::unique_ptr<WaitForDocumentOperation> wait_for_document_operation_;
+};
+
+TEST_F(WaitForDocumentOperationTest, ReportsSuccess) {
+ EXPECT_CALL(mock_web_controller_,
+ OnWaitForDocumentReadyState(_, DOCUMENT_COMPLETE, _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_COMPLETE,
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
+
+ wait_for_document_operation_->Run();
+}
+
+TEST_F(WaitForDocumentOperationTest, ReportsFailure) {
+ EXPECT_CALL(mock_web_controller_,
+ OnWaitForDocumentReadyState(_, DOCUMENT_COMPLETE, _))
+ .WillOnce(RunOnceCallback<2>(ClientStatus(TIMED_OUT),
+ DOCUMENT_UNKNOWN_READY_STATE,
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, TIMED_OUT), _, _));
+
+ wait_for_document_operation_->Run();
+}
+
+TEST_F(WaitForDocumentOperationTest, TimesOutAfterWaiting) {
+ // Capture the call without answering it.
+ WaitForDocumentOperation::Callback captured_callback;
+ EXPECT_CALL(mock_web_controller_,
+ OnWaitForDocumentReadyState(_, DOCUMENT_COMPLETE, _))
+ .WillOnce(Invoke([&captured_callback](
+ const ElementFinder::Result& optional_frame_element,
+ DocumentReadyState min_ready_state,
+ WaitForDocumentOperation::Callback& callback) {
+ captured_callback = std::move(callback);
+ }));
+ EXPECT_CALL(mock_callback_, Run(_, _, _)).Times(0);
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, TIMED_OUT), _, _));
+
+ wait_for_document_operation_->Run();
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+ // This callback should be ignored, it's too late. This should not report a
+ // success or crash.
+ std::move(captured_callback)
+ .Run(OkClientStatus(), DOCUMENT_COMPLETE,
+ base::TimeDelta::FromSeconds(2));
+}
+
+TEST_F(WaitForDocumentOperationTest, TimeoutIsIgnoredAfterSuccess) {
+ EXPECT_CALL(mock_web_controller_,
+ OnWaitForDocumentReadyState(_, DOCUMENT_COMPLETE, _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus(), DOCUMENT_COMPLETE,
+ base::TimeDelta::FromSeconds(0)));
+ EXPECT_CALL(mock_callback_, Run(_, _, _)).Times(0);
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
+
+ wait_for_document_operation_->Run();
+
+ // Moving forward in time causes the timer to expire. This should not report
+ // a failure or crash.
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/check_on_top_worker.cc b/chromium/components/autofill_assistant/browser/web/check_on_top_worker.cc
new file mode 100644
index 00000000000..e6210ddbcbe
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/check_on_top_worker.cc
@@ -0,0 +1,96 @@
+// Copyright 2020 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_assistant/browser/web/check_on_top_worker.h"
+
+#include "base/logging.h"
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
+
+namespace autofill_assistant {
+
+CheckOnTopWorker::CheckOnTopWorker(DevtoolsClient* devtools_client)
+ : devtools_client_(devtools_client) {}
+
+CheckOnTopWorker::~CheckOnTopWorker() {}
+
+void CheckOnTopWorker::Start(const ElementFinder::Result& element,
+ Callback callback) {
+ callback_ = std::move(callback);
+
+ // Each containing iframe must be checked to detect the case where an iframe
+ // element is covered by another element. The snippets might be run in
+ // parallel, if iframes run in different JavaScript contexts.
+
+ JsSnippet js_snippet;
+ js_snippet.AddLine("function(element) {");
+ AddReturnIfOnTop(&js_snippet, "element",
+ /* on_top= */ "true",
+ /* not_on_top= */ "false",
+ /* not_in_view= */ "false");
+ js_snippet.AddLine("}");
+ std::string function = js_snippet.ToString();
+
+ pending_result_count_ = element.frame_stack.size() + 1;
+ for (const auto& frame : element.frame_stack) {
+ CallFunctionOn(function, frame.node_frame_id, frame.object_id);
+ }
+ CallFunctionOn(function, element.node_frame_id, element.object_id);
+}
+
+void CheckOnTopWorker::CallFunctionOn(const std::string& function,
+ const std::string& frame_id,
+ const std::string& object_id) {
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ AddRuntimeCallArgumentObjectId(object_id, &arguments);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(object_id)
+ .SetArguments(std::move(arguments))
+ .SetFunctionDeclaration(function)
+ .SetReturnByValue(true)
+ .Build(),
+ frame_id,
+ base::BindOnce(&CheckOnTopWorker::OnReply,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CheckOnTopWorker::OnReply(
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ if (!callback_) {
+ // Already answered.
+ return;
+ }
+
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+ if (!status.ok()) {
+ VLOG(1) << __func__ << " Failed JavaScript with status: " << status;
+ std::move(callback_).Run(status);
+ return;
+ }
+
+ bool onTop = false;
+ if (!SafeGetBool(result->GetResult(), &onTop)) {
+ VLOG(1) << __func__ << " JavaScript function failed to return a boolean.";
+ std::move(callback_).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+
+ if (!onTop) {
+ std::move(callback_).Run(ClientStatus(ELEMENT_NOT_ON_TOP));
+ return;
+ }
+
+ if (pending_result_count_ == 1) {
+ std::move(callback_).Run(OkClientStatus());
+ return;
+ }
+
+ // Wait for a result from other frames.
+ DCHECK_GT(pending_result_count_, 1u);
+ pending_result_count_--;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/check_on_top_worker.h b/chromium/components/autofill_assistant/browser/web/check_on_top_worker.h
new file mode 100644
index 00000000000..f133f0a23cc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/check_on_top_worker.h
@@ -0,0 +1,53 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_WEB_CHECK_ON_TOP_WORKER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CHECK_ON_TOP_WORKER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+
+namespace autofill_assistant {
+
+// Worker class to check whether an element is on top, in all frames.
+class CheckOnTopWorker : public WebControllerWorker {
+ public:
+ // |devtools_client| must be valid for the lifetime of the instance.
+ CheckOnTopWorker(DevtoolsClient* devtools_client);
+ ~CheckOnTopWorker() override;
+
+ // Callback called when the worker is done.
+ using Callback = base::OnceCallback<void(const ClientStatus&)>;
+
+ // Have the worker check |element| and report the result to |callback|.
+ void Start(const ElementFinder::Result& element, Callback callback);
+
+ private:
+ void CallFunctionOn(const std::string& function,
+ const std::string& frame_id,
+ const std::string& object_id);
+ void OnReply(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+ DevtoolsClient* const devtools_client_;
+ Callback callback_;
+
+ // The number of successful results that are still expected before the check
+ // can be reported as successful. Note that an unsuccessful result is reported
+ // right away.
+ size_t pending_result_count_;
+
+ base::WeakPtrFactory<CheckOnTopWorker> weak_ptr_factory_{this};
+};
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CHECK_ON_TOP_WORKER_H_
diff --git a/chromium/components/autofill_assistant/browser/web/element_finder.cc b/chromium/components/autofill_assistant/browser/web/element_finder.cc
index add03320a31..7c4464a2f6f 100644
--- a/chromium/components/autofill_assistant/browser/web/element_finder.cc
+++ b/chromium/components/autofill_assistant/browser/web/element_finder.cc
@@ -97,7 +97,7 @@ std::string ElementFinder::JsFilterBuilder::BuildFunction() const {
function(args) {
let elements = [this];
)",
- base::JoinString(lines_, "\n"),
+ snippet_.ToString(),
R"(
if (elements.length == 0) return null;
if (elements.length == 1) { return elements[0] }
@@ -111,20 +111,12 @@ bool ElementFinder::JsFilterBuilder::AddFilter(
const SelectorProto::Filter& filter) {
switch (filter.filter_case()) {
case SelectorProto::Filter::kCssSelector:
- // clang-format off
- AddLine({
- "elements = elements.flatMap((e) => Array.from(e.querySelectorAll(",
- AddArgument(filter.css_selector()),
- ")));"
- });
-
- // Elements are temporarily put into a set to get rid of duplicates, which
+ // We querySelectorAll the current elements and remove duplicates, which
// are likely when using inner text before CSS selector filters. We must
// not return duplicates as they cause incorrect TOO_MANY_ELEMENTS errors.
- AddLine(R"(if (elements.length > 1) {
- elements = Array.from(new Set(elements));
- })");
- // clang-format on
+ DefineQueryAllDeduplicated();
+ AddLine({"elements = queryAllDeduplicated(elements, ",
+ AddArgument(filter.css_selector()), ");"});
return true;
case SelectorProto::Filter::kInnerText:
@@ -136,8 +128,16 @@ bool ElementFinder::JsFilterBuilder::AddFilter(
return true;
case SelectorProto::Filter::kBoundingBox:
- AddLine(
- "elements = elements.filter((e) => e.getClientRects().length > 0);");
+ if (filter.bounding_box().require_nonempty()) {
+ AddLine("elements = elements.filter((e) => {");
+ AddLine(" const rect = e.getBoundingClientRect();");
+ AddLine(" return rect.width != 0 && rect.height != 0;");
+ AddLine("});");
+ } else {
+ AddLine(
+ "elements = elements.filter((e) => e.getClientRects().length > "
+ "0);");
+ }
return true;
case SelectorProto::Filter::kPseudoElementContent: {
@@ -158,31 +158,52 @@ bool ElementFinder::JsFilterBuilder::AddFilter(
return true;
}
+ case SelectorProto::Filter::kCssStyle: {
+ std::string re_var = AddRegexpInstance(filter.css_style().value());
+ std::string property = AddArgument(filter.css_style().property());
+ std::string element = AddArgument(filter.css_style().pseudo_element());
+ AddLine("elements = elements.filter((e) => {");
+ AddLine(" const s = window.getComputedStyle(e, ");
+ AddLine({" ", element, " === '' ? null : ", element, ");"});
+ AddLine({" const match = ", re_var, ".test(s[", property, "]);"});
+ if (filter.css_style().should_match()) {
+ AddLine(" return match;");
+ } else {
+ AddLine(" return !match;");
+ }
+ AddLine("});");
+ return true;
+ }
+
case SelectorProto::Filter::kLabelled:
- AddLine(R"(elements = elements.flatMap((e) => {
- if (e.tagName != 'LABEL') return [];
- let element = null;
- const id = e.getAttribute('for');
- if (id) {
- element = document.getElementById(id)
- }
- if (!element) {
- element = e.querySelector(
- 'button,input,keygen,meter,output,progress,select,textarea');
- }
- if (element) return [element];
- return [];
-});
-)");
- // The selector above for the case where there's no "for" corresponds to
- // the list of labelable elements listed on "W3C's HTML5: Edition for Web
- // Authors":
- // https://www.w3.org/TR/2011/WD-html5-author-20110809/forms.html#category-label
+ AddLine("elements = elements.flatMap((e) => {");
+ AddLine(
+ " return e.tagName === 'LABEL' && e.control ? [e.control] : [];");
+ AddLine("});");
+ return true;
+
+ case SelectorProto::Filter::kMatchCssSelector:
+ AddLine({"elements = elements.filter((e) => e.webkitMatchesSelector(",
+ AddArgument(filter.match_css_selector()), "));"});
+ return true;
+
+ case SelectorProto::Filter::kOnTop:
+ AddLine("elements = elements.filter((e) => {");
+ AddLine("if (e.getClientRects().length == 0) return false;");
+ if (filter.on_top().scroll_into_view_if_needed()) {
+ AddLine("e.scrollIntoViewIfNeeded(false);");
+ }
+ AddReturnIfOnTop(
+ &snippet_, "e", /* on_top= */ "true", /* not_on_top= */ "false",
+ /* not_in_view= */ filter.on_top().accept_element_if_not_in_view()
+ ? "true"
+ : "false");
+ AddLine("});");
return true;
case SelectorProto::Filter::kEnterFrame:
case SelectorProto::Filter::kPseudoType:
- case SelectorProto::Filter::kPickOne:
+ case SelectorProto::Filter::kNthMatch:
case SelectorProto::Filter::kClosest:
case SelectorProto::Filter::FILTER_NOT_SET:
return false;
@@ -217,6 +238,34 @@ std::string ElementFinder::JsFilterBuilder::AddArgument(
return base::StrCat({"args[", base::NumberToString(index), "]"});
}
+void ElementFinder::JsFilterBuilder::DefineQueryAllDeduplicated() {
+ // Ensure that we don't define the function more than once.
+ if (defined_query_all_deduplicated_)
+ return;
+
+ defined_query_all_deduplicated_ = true;
+
+ AddLine(R"(
+ const queryAllDeduplicated = function(roots, selector) {
+ if (roots.length == 0) {
+ return [];
+ }
+
+ const matchesSet = new Set();
+ const matches = [];
+ roots.forEach((root) => {
+ root.querySelectorAll(selector).forEach((elem) => {
+ if (!matchesSet.has(elem)) {
+ matchesSet.add(elem);
+ matches.push(elem);
+ }
+ });
+ });
+ return matches;
+ }
+ )");
+}
+
ElementFinder::Result::Result() = default;
ElementFinder::Result::~Result() = default;
@@ -300,7 +349,7 @@ void ElementFinder::ExecuteNextTask() {
break;
case ResultType::kAnyMatch:
- if (!ConsumeAnyMatchOrFail(object_id)) {
+ if (!ConsumeMatchAtOrFail(0, object_id)) {
return;
}
break;
@@ -342,9 +391,9 @@ void ElementFinder::ExecuteNextTask() {
return;
}
- case SelectorProto::Filter::kPickOne: {
+ case SelectorProto::Filter::kNthMatch: {
std::string object_id;
- if (!ConsumeAnyMatchOrFail(object_id))
+ if (!ConsumeMatchAtOrFail(filter.nth_match().index(), object_id))
return;
next_filter_index_++;
@@ -358,7 +407,10 @@ void ElementFinder::ExecuteNextTask() {
case SelectorProto::Filter::kValue:
case SelectorProto::Filter::kBoundingBox:
case SelectorProto::Filter::kPseudoElementContent:
- case SelectorProto::Filter::kLabelled: {
+ case SelectorProto::Filter::kMatchCssSelector:
+ case SelectorProto::Filter::kCssStyle:
+ case SelectorProto::Filter::kLabelled:
+ case SelectorProto::Filter::kOnTop: {
std::vector<std::string> matches;
if (!ConsumeAllMatchesOrFail(matches))
return;
@@ -392,18 +444,6 @@ void ElementFinder::ExecuteNextTask() {
}
bool ElementFinder::ConsumeOneMatchOrFail(std::string& object_id_out) {
- // This logic relies on JsFilterBuilder::BuildFunction guaranteeing that
- // arrays contain at least 2 elements to avoid having to fetch all matching
- // elements in the common case where we just want to know whether there is at
- // least one match.
-
- if (!current_match_arrays_.empty()) {
- VLOG(1) << __func__ << " Got " << current_match_arrays_.size()
- << " arrays of 2 or more matches for " << selector_
- << ", when only 1 match was expected.";
- SendResult(ClientStatus(TOO_MANY_ELEMENTS));
- return false;
- }
if (current_matches_.size() > 1) {
VLOG(1) << __func__ << " Got " << current_matches_.size() << " matches for "
<< selector_ << ", when only 1 was expected.";
@@ -420,35 +460,20 @@ bool ElementFinder::ConsumeOneMatchOrFail(std::string& object_id_out) {
return true;
}
-bool ElementFinder::ConsumeAnyMatchOrFail(std::string& object_id_out) {
- // This logic relies on ApplyJsFilters guaranteeing that arrays contain at
- // least 2 elements to avoid having to fetch all matching elements in the
- // common case where we just want one match.
-
- if (current_matches_.size() > 0) {
- object_id_out = current_matches_[0];
+bool ElementFinder::ConsumeMatchAtOrFail(size_t index,
+ std::string& object_id_out) {
+ if (index < current_matches_.size()) {
+ object_id_out = current_matches_[index];
current_matches_.clear();
- current_match_arrays_.clear();
return true;
}
- if (!current_match_arrays_.empty()) {
- std::string array_object_id = current_match_arrays_[0];
- current_match_arrays_.clear();
- ResolveMatchArrays({array_object_id}, /* max_count= */ 1);
- return false; // Caller should call again to check
- }
+
SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
bool ElementFinder::ConsumeAllMatchesOrFail(
std::vector<std::string>& matches_out) {
- if (!current_match_arrays_.empty()) {
- std::vector<std::string> array_object_ids =
- std::move(current_match_arrays_);
- ResolveMatchArrays(array_object_ids, /* max_count= */ -1);
- return false; // Caller should call again to check
- }
if (!current_matches_.empty()) {
matches_out = std::move(current_matches_);
current_matches_.clear();
@@ -459,68 +484,74 @@ bool ElementFinder::ConsumeAllMatchesOrFail(
}
bool ElementFinder::ConsumeMatchArrayOrFail(std::string& array_object_id) {
- if (current_matches_.empty() && current_match_arrays_.empty()) {
+ if (!current_matches_js_array_.empty()) {
+ array_object_id = current_matches_js_array_;
+ current_matches_js_array_.clear();
+ return true;
+ }
+
+ if (current_matches_.empty()) {
SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
- if (current_matches_.empty() && current_match_arrays_.size() == 1) {
- array_object_id = current_match_arrays_[0];
- current_match_arrays_.clear();
- return true;
+ MoveMatchesToJSArrayRecursive(/* index= */ 0);
+ return false;
+}
+
+void ElementFinder::MoveMatchesToJSArrayRecursive(size_t index) {
+ if (index >= current_matches_.size()) {
+ current_matches_.clear();
+ ExecuteNextTask();
+ return;
}
- std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
- std::string object_id; // Will be "this" in Javascript.
+ // Push the value at |current_matches_[index]| to |current_matches_js_array_|.
std::string function;
- if (current_match_arrays_.size() > 1) {
- object_id = current_match_arrays_.back();
- current_match_arrays_.pop_back();
- // Merge both arrays into current_match_arrays_[0]
- function = "function(dest) { dest.push(...this); }";
- AddRuntimeCallArgumentObjectId(current_match_arrays_[0], &arguments);
- } else if (!current_matches_.empty()) {
- object_id = current_matches_.back();
- current_matches_.pop_back();
- if (current_match_arrays_.empty()) {
- // Create an array containing a single element.
- function = "function() { return [this]; }";
- } else {
- // Add an element to an existing array.
- function = "function(dest) { dest.push(this); }";
- AddRuntimeCallArgumentObjectId(current_match_arrays_[0], &arguments);
- }
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ if (index == 0) {
+ // Create an array containing a single element.
+ function = "function() { return [this]; }";
+ } else {
+ // Add an element to an existing array.
+ function = "function(dest) { dest.push(this); }";
+ AddRuntimeCallArgumentObjectId(current_matches_js_array_, &arguments);
}
+
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
- .SetObjectId(object_id)
+ .SetObjectId(current_matches_[index])
.SetArguments(std::move(arguments))
.SetFunctionDeclaration(function)
.Build(),
current_frame_id_,
- base::BindOnce(&ElementFinder::OnConsumeMatchArray,
- weak_ptr_factory_.GetWeakPtr()));
- return false;
+ base::BindOnce(&ElementFinder::OnMoveMatchesToJSArrayRecursive,
+ weak_ptr_factory_.GetWeakPtr(), index));
}
-void ElementFinder::OnConsumeMatchArray(
+void ElementFinder::OnMoveMatchesToJSArrayRecursive(
+ size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
- VLOG(1) << __func__ << ": Failed to get element from array for "
- << selector_;
+ VLOG(1) << __func__ << ": Failed to push value to JS array.";
SendResult(status);
return;
}
- if (current_match_arrays_.empty()) {
- std::string returned_object_id;
- if (SafeGetObjectId(result->GetResult(), &returned_object_id)) {
- current_match_arrays_.push_back(returned_object_id);
- }
+
+ // We just created an array which contains the first element. We store its ID
+ // in |current_matches_js_array_|.
+ if (index == 0 &&
+ !SafeGetObjectId(result->GetResult(), &current_matches_js_array_)) {
+ VLOG(1) << __func__ << " Failed to get array ID.";
+ SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ return;
}
- ExecuteNextTask();
+
+ // Continue the recursion to push the other values into the array.
+ MoveMatchesToJSArrayRecursive(index + 1);
}
void ElementFinder::GetDocumentElement() {
@@ -551,28 +582,29 @@ void ElementFinder::OnGetDocumentElement(
// Use the node as root for the rest of the evaluation.
current_matches_.emplace_back(object_id);
- DecrementResponseCountAndContinue();
+ ExecuteNextTask();
}
void ElementFinder::ApplyJsFilters(const JsFilterBuilder& builder,
const std::vector<std::string>& object_ids) {
DCHECK(!object_ids.empty()); // Guaranteed by ExecuteNextTask()
- pending_response_count_ = object_ids.size();
+ PrepareBatchTasks(object_ids.size());
std::string function = builder.BuildFunction();
- for (const std::string& object_id : object_ids) {
+ for (size_t task_id = 0; task_id < object_ids.size(); task_id++) {
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
- .SetObjectId(object_id)
+ .SetObjectId(object_ids[task_id])
.SetArguments(builder.BuildArgumentList())
.SetFunctionDeclaration(function)
.Build(),
current_frame_id_,
base::BindOnce(&ElementFinder::OnApplyJsFilters,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), task_id));
}
}
void ElementFinder::OnApplyJsFilters(
+ size_t task_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
if (!result) {
@@ -594,19 +626,22 @@ void ElementFinder::OnApplyJsFilters(
return;
}
- // The result can be empty (nothing found), a an array (multiple matches
+ // The result can be empty (nothing found), an array (multiple matches
// found) or a single node.
std::string object_id;
- if (SafeGetObjectId(result->GetResult(), &object_id)) {
- if (result->GetResult()->HasSubtype() &&
- result->GetResult()->GetSubtype() ==
- runtime::RemoteObjectSubtype::ARRAY) {
- current_match_arrays_.emplace_back(object_id);
- } else {
- current_matches_.emplace_back(object_id);
- }
+ if (!SafeGetObjectId(result->GetResult(), &object_id)) {
+ ReportNoMatchingElement(task_id);
+ return;
+ }
+
+ if (result->GetResult()->HasSubtype() &&
+ result->GetResult()->GetSubtype() ==
+ runtime::RemoteObjectSubtype::ARRAY) {
+ ReportMatchingElementsArray(task_id, object_id);
+ return;
}
- DecrementResponseCountAndContinue();
+
+ ReportMatchingElement(task_id, object_id);
}
void ElementFinder::ResolvePseudoElement(
@@ -621,18 +656,21 @@ void ElementFinder::ResolvePseudoElement(
}
DCHECK(!object_ids.empty()); // Guaranteed by ExecuteNextTask()
- pending_response_count_ = object_ids.size();
- for (const std::string& object_id : object_ids) {
+ PrepareBatchTasks(object_ids.size());
+ for (size_t task_id = 0; task_id < object_ids.size(); task_id++) {
devtools_client_->GetDOM()->DescribeNode(
- dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
+ dom::DescribeNodeParams::Builder()
+ .SetObjectId(object_ids[task_id])
+ .Build(),
current_frame_id_,
base::BindOnce(&ElementFinder::OnDescribeNodeForPseudoElement,
- weak_ptr_factory_.GetWeakPtr(), pseudo_type));
+ weak_ptr_factory_.GetWeakPtr(), pseudo_type, task_id));
}
}
void ElementFinder::OnDescribeNodeForPseudoElement(
dom::PseudoType pseudo_type,
+ size_t task_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result) {
if (!result || !result->GetNode()) {
@@ -652,21 +690,25 @@ void ElementFinder::OnDescribeNodeForPseudoElement(
.Build(),
current_frame_id_,
base::BindOnce(&ElementFinder::OnResolveNodeForPseudoElement,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), task_id));
return;
}
}
}
- DecrementResponseCountAndContinue();
+
+ ReportNoMatchingElement(task_id);
}
void ElementFinder::OnResolveNodeForPseudoElement(
+ size_t task_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result) {
if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
- current_matches_.emplace_back(result->GetObject()->GetObjectId());
+ ReportMatchingElement(task_id, result->GetObject()->GetObjectId());
+ return;
}
- DecrementResponseCountAndContinue();
+
+ ReportNoMatchingElement(task_id);
}
void ElementFinder::EnterFrame(const std::string& object_id) {
@@ -738,7 +780,7 @@ void ElementFinder::OnDescribeNodeForFrame(
// to remain backward compatible, don't complain and just continue filtering
// with the current element as root.
current_matches_.emplace_back(object_id);
- DecrementResponseCountAndContinue();
+ ExecuteNextTask();
}
void ElementFinder::OnResolveNode(
@@ -756,7 +798,7 @@ void ElementFinder::OnResolveNode(
}
// Use the node as root for the rest of the evaluation.
current_matches_.emplace_back(object_id);
- DecrementResponseCountAndContinue();
+ ExecuteNextTask();
}
content::RenderFrameHost* ElementFinder::FindCorrespondingRenderFrameHost(
@@ -927,24 +969,38 @@ void ElementFinder::OnProximityFilterJs(
ExecuteNextTask();
}
-void ElementFinder::ResolveMatchArrays(
- const std::vector<std::string>& array_object_ids,
- int max_count) {
- if (array_object_ids.empty()) {
- // Nothing to do
- ExecuteNextTask();
- return;
- }
- pending_response_count_ = array_object_ids.size();
- for (const std::string& array_object_id : array_object_ids) {
- ResolveMatchArrayRecursive(array_object_id, 0, max_count);
- }
+void ElementFinder::PrepareBatchTasks(int n) {
+ tasks_results_.clear();
+ tasks_results_.resize(n);
+}
+
+void ElementFinder::ReportMatchingElement(size_t task_id,
+ const std::string& object_id) {
+ tasks_results_[task_id] =
+ std::make_unique<std::vector<std::string>>(1, object_id);
+ MaybeFinalizeBatchTasks();
+}
+
+void ElementFinder::ReportNoMatchingElement(size_t task_id) {
+ tasks_results_[task_id] = std::make_unique<std::vector<std::string>>();
+ MaybeFinalizeBatchTasks();
}
-void ElementFinder::ResolveMatchArrayRecursive(
+void ElementFinder::ReportMatchingElementsArray(
+ size_t task_id,
+ const std::string& array_object_id) {
+ // Recursively add each element ID to a vector then report it as this task
+ // result.
+ ReportMatchingElementsArrayRecursive(
+ task_id, array_object_id, std::make_unique<std::vector<std::string>>(),
+ /* index= */ 0);
+}
+
+void ElementFinder::ReportMatchingElementsArrayRecursive(
+ size_t task_id,
const std::string& array_object_id,
- int index,
- int max_count) {
+ std::unique_ptr<std::vector<std::string>> acc,
+ int index) {
std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
AddRuntimeCallArgument(index, &arguments);
devtools_client_->GetRuntime()->CallFunctionOn(
@@ -954,15 +1010,16 @@ void ElementFinder::ResolveMatchArrayRecursive(
.SetFunctionDeclaration(std::string(kGetArrayElement))
.Build(),
current_frame_id_,
- base::BindOnce(&ElementFinder::OnResolveMatchArray,
- weak_ptr_factory_.GetWeakPtr(), array_object_id, index,
- max_count));
+ base::BindOnce(&ElementFinder::OnReportMatchingElementsArrayRecursive,
+ weak_ptr_factory_.GetWeakPtr(), task_id, array_object_id,
+ std::move(acc), index));
}
-void ElementFinder::OnResolveMatchArray(
+void ElementFinder::OnReportMatchingElementsArrayRecursive(
+ size_t task_id,
const std::string& array_object_id,
+ std::unique_ptr<std::vector<std::string>> acc,
int index,
- int max_count,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status =
@@ -973,33 +1030,38 @@ void ElementFinder::OnResolveMatchArray(
SendResult(status);
return;
}
+
std::string object_id;
if (!SafeGetObjectId(result->GetResult(), &object_id)) {
- // We've reached the end of the array
- DecrementResponseCountAndContinue();
+ // We've reached the end of the array.
+ tasks_results_[task_id] = std::move(acc);
+ MaybeFinalizeBatchTasks();
return;
}
- current_matches_.emplace_back(object_id);
- int next_index = index + 1;
- if (max_count != -1 && next_index >= max_count) {
- DecrementResponseCountAndContinue();
- return;
- }
+ acc->emplace_back(object_id);
// Fetch the next element.
- ResolveMatchArrayRecursive(array_object_id, next_index, max_count);
+ ReportMatchingElementsArrayRecursive(task_id, array_object_id, std::move(acc),
+ index + 1);
}
-void ElementFinder::DecrementResponseCountAndContinue() {
- if (pending_response_count_ > 1) {
- pending_response_count_--;
- return;
+void ElementFinder::MaybeFinalizeBatchTasks() {
+ // Return early if one of the tasks is still pending.
+ for (const auto& result : tasks_results_) {
+ if (!result) {
+ return;
+ }
+ }
+
+ // Add all matching elements to current_matches_.
+ for (const auto& result : tasks_results_) {
+ current_matches_.insert(current_matches_.end(), result->begin(),
+ result->end());
}
+ tasks_results_.clear();
- pending_response_count_ = 0;
ExecuteNextTask();
- return;
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/element_finder.h b/chromium/components/autofill_assistant/browser/web/element_finder.h
index a783f77945d..3103ec2051e 100644
--- a/chromium/components/autofill_assistant/browser/web/element_finder.h
+++ b/chromium/components/autofill_assistant/browser/web/element_finder.h
@@ -17,6 +17,7 @@
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/js_snippets.h"
#include "components/autofill_assistant/browser/web/web_controller_worker.h"
namespace content {
@@ -102,7 +103,8 @@ class ElementFinder : public WebControllerWorker {
private:
std::vector<std::string> arguments_;
- std::vector<std::string> lines_;
+ JsSnippet snippet_;
+ bool defined_query_all_deduplicated_ = false;
// A number that's increased by each call to DeclareVariable() to make sure
// we generate unique variables.
@@ -130,11 +132,26 @@ class ElementFinder : public WebControllerWorker {
// footer. At that point, the variable "elements" contains the current set
// of matches, as an array of nodes. It should be updated to contain the new
// set of matches.
- void AddLine(const std::string& line) { lines_.emplace_back(line); }
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to
+ // this method.
+ void AddLine(const std::string& line) { snippet_.AddLine(line); }
+ // Adds a line of JavaScript code to the function that's made up of multiple
+ // parts to be concatenated together.
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to
+ // this method.
void AddLine(const std::vector<std::string>& line) {
- lines_.emplace_back(base::StrCat(line));
+ snippet_.AddLine(line);
}
+
+ // Define a |queryAllDeduplicated(roots, selector)| JS function that calls
+ // querySelectorAll(selector) on all |roots| (in order) and returns a
+ // deduplicated list of the matching elements.
+ // Calling this function a second time does not do anything; the function
+ // will be defined only once.
+ void DefineQueryAllDeduplicated();
};
// Finds the element, starting at |frame| and calls |callback|.
@@ -159,10 +176,48 @@ class ElementFinder : public WebControllerWorker {
// Figures out what to do next given the current state.
//
// Most background operations in this worker end by updating the state and
- // calling ExecuteNextTask() again either directly or through
- // DecrementResponseCountAndContinue().
+ // calling ExecuteNextTask() again either directly or through Report*().
void ExecuteNextTask();
+ // Prepare a batch of |n| tasks that are sent at the same time to compute one
+ // or more matching elements.
+ //
+ // After calling this, Report*(i, ...) should be called *exactly once* for all
+ // 0 <= i < n to report the tasks results.
+ //
+ // Once all tasks reported their result, the object ID of all matching
+ // elements will be added to |current_matches_| and ExecuteNextTask() will be
+ // called.
+ void PrepareBatchTasks(int n);
+
+ // Report that task with ID |task_id| didn't match any element.
+ void ReportNoMatchingElement(size_t task_id);
+
+ // Report that task with ID |task_id| matched a single element with ID
+ // |object_id|.
+ void ReportMatchingElement(size_t task_id, const std::string& object_id);
+
+ // Report that task with ID |task_id| matched multiple elements that are
+ // stored in the JS array with ID |object_id|.
+ void ReportMatchingElementsArray(size_t task_id,
+ const std::string& array_object_id);
+ void ReportMatchingElementsArrayRecursive(
+ size_t task_id,
+ const std::string& array_object_id,
+ std::unique_ptr<std::vector<std::string>> acc,
+ int index);
+ void OnReportMatchingElementsArrayRecursive(
+ size_t task_id,
+ const std::string& array_object_id,
+ std::unique_ptr<std::vector<std::string>> acc,
+ int index,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+ // If all batch tasks reported their result, add all tasks results to
+ // |current_matches_| then call ExecuteNextTask().
+ void MaybeFinalizeBatchTasks();
+
// Make sure there's exactly one match, set it |object_id_out| then return
// true.
//
@@ -174,17 +229,11 @@ class ElementFinder : public WebControllerWorker {
// required data is available.
bool ConsumeOneMatchOrFail(std::string& object_id_out);
- // Make sure there's at least one match, take one and put it in
- // |object_id_out|, then return true.
- //
- // If there are no matches, send an error response and return false.
- // If there are not enough matches yet, fetch them in the background and
- // return false. This calls ExecuteNextTask() once matches have been fetched.
+ // Make sure there's at least |index + 1| matches, take the one at that index
+ // and put it in |object_id_out|, then return true.
//
- // If this returns true, continue processing. If this returns false, return
- // from ExecuteNextTask(). ExecuteNextTask() will be called again once the
- // required data is available.
- bool ConsumeAnyMatchOrFail(std::string& object_id_out);
+ // If there are not enough matches, send an error response and return false.
+ bool ConsumeMatchAtOrFail(size_t index, std::string& object_id_out);
// Make sure there's at least one match and move them all into
// |matches_out|.
@@ -200,10 +249,12 @@ class ElementFinder : public WebControllerWorker {
// Make sure there's at least one match and move them all into a single array.
//
- // If there are no matches, call SendResult() return false. If there are
- // matches, but they're not in a single array, move the element into the array
- // in the background and return false. ExecuteNextTask() is called again once
- // the background tasks have executed.
+ // If there are no matches, call SendResult() and return false.
+ //
+ // If there are matches, return false directly and move the matches into
+ // an JS array in the background. ExecuteNextTask() is called again
+ // once the background tasks have executed, and calling this will return true
+ // and write the JS array id to |array_object_id_out|.
bool ConsumeMatchArrayOrFail(std::string& array_object_id_out);
void OnConsumeMatchArray(
@@ -211,7 +262,7 @@ class ElementFinder : public WebControllerWorker {
std::unique_ptr<runtime::CallFunctionOnResult> result);
// Gets a document element from the current frame and us it as root for the
- // rest of the tasks.
+ // rest of the tasks, then call ExecuteNextTask().
void GetDocumentElement();
void OnGetDocumentElement(const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
@@ -219,7 +270,8 @@ class ElementFinder : public WebControllerWorker {
// Handle Javascript filters
void ApplyJsFilters(const JsFilterBuilder& builder,
const std::vector<std::string>& object_ids);
- void OnApplyJsFilters(const DevtoolsClient::ReplyStatus& reply_status,
+ void OnApplyJsFilters(size_t task_id,
+ const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
// Handle PSEUDO_TYPE
@@ -227,9 +279,11 @@ class ElementFinder : public WebControllerWorker {
const std::vector<std::string>& object_ids);
void OnDescribeNodeForPseudoElement(
dom::PseudoType pseudo_type,
+ size_t task_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result);
void OnResolveNodeForPseudoElement(
+ size_t task_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result);
@@ -254,34 +308,16 @@ class ElementFinder : public WebControllerWorker {
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
- // Get elements from |array_object_ids|, and put the result into
- // |element_matches_|.
- //
- // This calls ExecuteNextTask() once all the elements of all the arrays are in
- // |element_matches_|. If |max_count| is -1, fetch until the end of the array,
- // otherwise fetch |max_count| elements at most in each array.
- void ResolveMatchArrays(const std::vector<std::string>& array_object_ids,
- int max_count);
-
- // ResolveMatchArrayRecursive calls itself recursively, incrementing |index|,
- // as long as there are elements. The chain of calls end with
- // DecrementResponseCountAndContinue() as there can be more than one such
- // chains executing at a time.
- void ResolveMatchArrayRecursive(const std::string& array_object_ids,
- int index,
- int max_count);
-
- void OnResolveMatchArray(
- const std::string& array_object_id,
- int index,
- int max_count,
+ // Fill |current_matches_js_array_| with the values in |current_matches_|
+ // starting from |index|, then clear |current_matches_| and call
+ // ExecuteNextTask().
+ void MoveMatchesToJSArrayRecursive(size_t index);
+
+ void OnMoveMatchesToJSArrayRecursive(
+ size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
- // Tracks pending_response_count_ and call ExecuteNextTask() once the count
- // has reached 0.
- void DecrementResponseCountAndContinue();
-
content::WebContents* const web_contents_;
DevtoolsClient* const devtools_client_;
const Selector selector_;
@@ -304,30 +340,19 @@ class ElementFinder : public WebControllerWorker {
// Object IDs of the current set matching elements. Cleared once it's used to
// query or filter.
- //
- // More matches can be found in |current_match_arrays_|. Use one of the
- // Consume*Match() function to current matches.
std::vector<std::string> current_matches_;
- // Object ID of arrays of at least 2 matching elements.
- //
- // More matches can be found in |current_matches_|. Use one of the
- // Consume*Match() function to current matches.
- std::vector<std::string> current_match_arrays_;
+ // Object ID of the JavaScript array of the currently matching elements. In
+ // practice, this is used by ConsumeMatchArrayOrFail() to convert
+ // |current_matches_| to a JavaScript array.
+ std::string current_matches_js_array_;
// True if current_matches are pseudo-elements.
bool matching_pseudo_elements_ = false;
- // Number of responses still pending.
- //
- // Before starting several background operations in parallel, set this counter
- // to the number of operations and make sure that
- // DecrementResponseCountAndContinue() is called once the result of the
- // operation has been processed and the state of ElementFinder updated.
- // DecrementResponseCountAndContinue() will then make sure to call
- // ExecuteNextTask() again once this counter has reached 0 to continue the
- // work.
- size_t pending_response_count_ = 0;
+ // The result of the background tasks. |tasks_results_[i]| contains the
+ // elements matched by task i, or nullptr if the task is still running.
+ std::vector<std::unique_ptr<std::vector<std::string>>> tasks_results_;
std::vector<Result> frame_stack_;
diff --git a/chromium/components/autofill_assistant/browser/web/element_position_getter.cc b/chromium/components/autofill_assistant/browser/web/element_position_getter.cc
index b1321964135..864f9025f29 100644
--- a/chromium/components/autofill_assistant/browser/web/element_position_getter.cc
+++ b/chromium/components/autofill_assistant/browser/web/element_position_getter.cc
@@ -25,10 +25,11 @@ namespace autofill_assistant {
ElementPositionGetter::ElementPositionGetter(
DevtoolsClient* devtools_client,
- const ClientSettings& settings,
+ int max_rounds,
+ base::TimeDelta check_interval,
const std::string& optional_node_frame_id)
- : check_interval_(settings.box_model_check_interval),
- max_rounds_(settings.box_model_check_count),
+ : check_interval_(check_interval),
+ max_rounds_(max_rounds),
devtools_client_(devtools_client),
node_frame_id_(optional_node_frame_id),
weak_ptr_factory_(this) {}
@@ -37,7 +38,7 @@ ElementPositionGetter::~ElementPositionGetter() = default;
void ElementPositionGetter::Start(content::RenderFrameHost* frame_host,
std::string element_object_id,
- ElementPositionCallback callback) {
+ Callback callback) {
object_id_ = element_object_id;
callback_ = std::move(callback);
remaining_rounds_ = max_rounds_;
@@ -83,25 +84,31 @@ void ElementPositionGetter::OnGetBoxModelForStableCheck(
// Return the center of the element.
const std::vector<double>* content_box = result->GetModel()->GetContent();
DCHECK_EQ(content_box->size(), 8u);
- int new_point_x =
- round((round((*content_box)[0]) + round((*content_box)[2])) * 0.5);
- int new_point_y =
- round((round((*content_box)[3]) + round((*content_box)[5])) * 0.5);
-
- // Wait for at least three rounds (~600ms = 3*check_interval_) for visual
- // state update callback since it might take longer time to return or never
- // return if no updates.
- DCHECK(max_rounds_ > 2 && max_rounds_ >= remaining_rounds_);
- if (has_point_ && new_point_x == point_x_ && new_point_y == point_y_ &&
- (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) {
- // Note that there is still a chance that the element's position has been
- // changed after the last call of GetBoxModel, however, it might be safe to
- // assume the element's position will not be changed before issuing click or
- // tap event after stable for check_interval_. In addition, checking again
- // after issuing click or tap event doesn't help since the change may be
- // expected.
- OnResult(new_point_x, new_point_y);
- return;
+ int new_point_x = round(((*content_box)[0] + (*content_box)[2]) * 0.5);
+ int new_point_y = round(((*content_box)[3] + (*content_box)[5]) * 0.5);
+
+ DCHECK(max_rounds_ >= remaining_rounds_);
+
+ if (has_point_) {
+ if (max_rounds_ <= 2) {
+ OnResult(new_point_x, new_point_y);
+ return;
+ }
+
+ // If there are enough rounds, wait for at least three rounds (~600ms =
+ // 3*check_interval_) for visual state update callback since it might take
+ // longer time to return or never return if no updates.
+ if (new_point_x == point_x_ && new_point_y == point_y_ &&
+ (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) {
+ // Note that there is still a chance that the element's position has been
+ // changed after the last call of GetBoxModel, however, it might be safe
+ // to assume the element's position will not be changed before issuing
+ // click or tap event after stable for check_interval_. In addition,
+ // checking again after issuing click or tap event doesn't help since the
+ // change may be expected.
+ OnResult(new_point_x, new_point_y);
+ return;
+ }
}
if (remaining_rounds_ <= 0) {
@@ -161,13 +168,15 @@ void ElementPositionGetter::OnScrollIntoView(
void ElementPositionGetter::OnResult(int x, int y) {
if (callback_) {
- std::move(callback_).Run(/* success= */ true, x, y);
+ point_x_ = x;
+ point_y_ = y;
+ std::move(callback_).Run(OkClientStatus());
}
}
void ElementPositionGetter::OnError() {
if (callback_) {
- std::move(callback_).Run(/* success= */ false, /* x= */ 0, /* y= */ 0);
+ std::move(callback_).Run(ClientStatus(ELEMENT_UNSTABLE));
}
}
diff --git a/chromium/components/autofill_assistant/browser/web/element_position_getter.h b/chromium/components/autofill_assistant/browser/web/element_position_getter.h
index 8ed19691250..2d9531e15e9 100644
--- a/chromium/components/autofill_assistant/browser/web/element_position_getter.h
+++ b/chromium/components/autofill_assistant/browser/web/element_position_getter.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
@@ -30,21 +29,29 @@ class ElementPositionGetter : public WebControllerWorker {
public:
// |devtools_client| must be valid for the lifetime of the instance.
ElementPositionGetter(DevtoolsClient* devtools_client,
- const ClientSettings& settings,
+ int max_rounds,
+ base::TimeDelta check_interval,
const std::string& optional_node_frame_id);
~ElementPositionGetter() override;
// Callback that receives the position that corresponds to the center
// of an element.
//
- // If the first element is false, the call failed. Otherwise, the second
- // element contains the x position and the third the y position of the center
- // of the element in viewport coordinates.
- using ElementPositionCallback = base::OnceCallback<void(bool, int, int)>;
+ // If the operation failed, the status is ELEMENT_UNSTABLE.
+ // If the operation succeeded, check the coordinate in the getter.
+ using Callback = base::OnceCallback<void(const ClientStatus&)>;
+
+ // The X coordinate of the center of the element, only valid after getting a
+ // successful callback.
+ int x() { return point_x_; }
+
+ // The Y coordinate of the center of the element, only valid after getting a
+ // successful callback.
+ int y() { return point_y_; }
void Start(content::RenderFrameHost* frame_host,
std::string element_object_id,
- ElementPositionCallback callback);
+ Callback callback);
private:
void OnVisualStateUpdatedCallback(bool success);
@@ -60,12 +67,12 @@ class ElementPositionGetter : public WebControllerWorker {
// Time to wait between two box model checks.
const base::TimeDelta check_interval_;
// Maximum number of checks to run.
- const int max_rounds_;
+ int max_rounds_;
DevtoolsClient* devtools_client_ = nullptr;
std::string object_id_;
int remaining_rounds_ = 0;
- ElementPositionCallback callback_;
+ Callback callback_;
bool visual_state_updated_ = false;
// If |has_point_| is true, |point_x_| and |point_y_| contain the last
diff --git a/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc b/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
index e9154125be4..155ff658ac6 100644
--- a/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
+++ b/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
@@ -86,7 +86,9 @@ void ElementRectGetter::OnGetClientRectResult(
!result->GetResult()->GetValue()->is_list() ||
result->GetResult()->GetValue()->GetList().size() != 4u) {
VLOG(2) << __func__ << " Failed to get element rect: " << status;
- std::move(callback).Run(false, RectF());
+ std::move(callback).Run(
+ JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
+ RectF());
return;
}
@@ -108,11 +110,12 @@ void ElementRectGetter::OnGetClientRectResult(
}
if (index >= element->frame_stack.size()) {
- std::move(callback).Run(true, rect);
- } else {
- GetBoundingClientRect(std::move(element), index + 1, rect,
- std::move(callback));
+ std::move(callback).Run(OkClientStatus(), rect);
+ return;
}
+
+ GetBoundingClientRect(std::move(element), index + 1, rect,
+ std::move(callback));
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/element_rect_getter.h b/chromium/components/autofill_assistant/browser/web/element_rect_getter.h
index 6a8ba05df04..f38b763ef56 100644
--- a/chromium/components/autofill_assistant/browser/web/element_rect_getter.h
+++ b/chromium/components/autofill_assistant/browser/web/element_rect_getter.h
@@ -37,9 +37,12 @@ class ElementRectGetter : public WebControllerWorker {
// Callback that receives the bounding rect of the element.
//
- // If the first element is false, the call failed. Otherwise, the second
- // element contains the rect.
- using ElementRectCallback = base::OnceCallback<void(bool, const RectF&)>;
+ // If the first argument is a failure status, the call failed and will
+ // send an empty rectangle as the second argument. Otherwise, if the first
+ // argument is a success status the second argumnt will contain the element's
+ // bounding box in global CSS coordinates.
+ using ElementRectCallback =
+ base::OnceCallback<void(const ClientStatus&, const RectF&)>;
void Start(std::unique_ptr<ElementFinder::Result> element,
ElementRectCallback callback);
diff --git a/chromium/components/autofill_assistant/browser/web/js_snippets.cc b/chromium/components/autofill_assistant/browser/web/js_snippets.cc
new file mode 100644
index 00000000000..3bae3cbff60
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/js_snippets.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 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_assistant/browser/web/js_snippets.h"
+
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+
+namespace autofill_assistant {
+
+JsSnippet::JsSnippet() = default;
+JsSnippet::~JsSnippet() = default;
+std::string JsSnippet::ToString() const {
+ return base::JoinString(lines_, "\n");
+}
+
+void JsSnippet::AddLine(const std::string& line) {
+ lines_.emplace_back(line);
+}
+
+void JsSnippet::AddLine(const std::vector<std::string>& line) {
+ lines_.emplace_back(base::StrCat(line));
+}
+
+void AddReturnIfOnTop(JsSnippet* out,
+ const std::string& element_var,
+ const std::string& on_top,
+ const std::string& not_on_top,
+ const std::string& not_in_view) {
+ // clang-format off
+ out->AddLine({"const bounds = ", element_var, R"(.getBoundingClientRect();
+ const x = bounds.x + bounds.width / 2;
+ const y = bounds.y + bounds.height / 2;
+ const targets = [)", element_var, R"(];
+ const labels = )", element_var, R"(.labels;
+ if (labels) {
+ for (let i = 0; i < labels.length; i++) {
+ targets.push(labels[i]);
+ }
+ }
+ let root = document;
+ while (root) {
+ const atPoint = root.elementFromPoint(x, y);
+ if (!atPoint) {
+ return )", not_in_view, R"(;
+ }
+ for (const target of targets) {
+ if (target === atPoint || target.contains(atPoint)) {
+ return )", on_top , R"(;
+ }
+ }
+ root = atPoint.shadowRoot;
+ }
+ return )", not_on_top, ";"});
+ // clang-format on
+}
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/js_snippets.h b/chromium/components/autofill_assistant/browser/web/js_snippets.h
new file mode 100644
index 00000000000..78bf826add5
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/js_snippets.h
@@ -0,0 +1,53 @@
+// Copyright 2020 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_ASSISTANT_BROWSER_WEB_JS_SNIPPETS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_JS_SNIPPETS_H_
+
+#include <string>
+#include <vector>
+
+namespace autofill_assistant {
+
+// A piece of JavaScript code that might by generated dynamically.
+class JsSnippet {
+ public:
+ JsSnippet();
+ ~JsSnippet();
+
+ // Return the JavaScript snippet as a string
+ std::string ToString() const;
+
+ // Adds a line of JavaScript code to snippet.
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to this
+ // method.
+ void AddLine(const std::string& line);
+
+ // Adds a single line of Javascript code to snippet.
+ //
+ // The line can be built from multiple string pieces; they'll be concatenated
+ // together.
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to this
+ // method.
+ void AddLine(const std::vector<std::string>& line);
+
+ private:
+ std::vector<std::string> lines_;
+};
+
+// Append JavaScript code to |snippet| that checks if |element_var| is on top.
+//
+// The JavaScript snippet returns |on_top| if the element is on top,
+// |not_on_top| if its center is covered by some other element, or |not_in_view|
+// if the element is not in the viewport.
+void AddReturnIfOnTop(JsSnippet* out,
+ const std::string& element_var,
+ const std::string& on_top,
+ const std::string& not_on_top,
+ const std::string& not_in_view);
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_JS_SNIPPETS_H_
diff --git a/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc b/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
index b3046aa2309..de2083c3069 100644
--- a/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
+++ b/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
@@ -6,8 +6,7 @@
namespace autofill_assistant {
-MockWebController::MockWebController()
- : WebController(nullptr, nullptr, nullptr) {}
+MockWebController::MockWebController() : WebController(nullptr, nullptr) {}
MockWebController::~MockWebController() {}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/mock_web_controller.h b/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
index f3ff5b47885..114cb46fcce 100644
--- a/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
+++ b/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
@@ -9,8 +9,10 @@
#include <vector>
#include "base/callback.h"
+#include "base/time/time.h"
#include "components/autofill_assistant/browser/top_padding.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/element_rect_getter.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -33,6 +35,21 @@ class MockWebController : public WebController {
void(const Selector& selector,
ElementFinder::Callback& callback));
+ void ScrollIntoView(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) override {
+ OnScrollIntoView(element, callback);
+ }
+ MOCK_METHOD2(OnScrollIntoView,
+ void(const ElementFinder::Result&,
+ base::OnceCallback<void(const ClientStatus&)>&));
+
+ MOCK_METHOD4(WaitUntilElementIsStable,
+ void(const ElementFinder::Result& element,
+ int,
+ base::TimeDelta,
+ base::OnceCallback<void(const ClientStatus&)> callback));
+
void ClickOrTapElement(
const ElementFinder::Result& element,
ClickType click_type,
@@ -45,53 +62,58 @@ class MockWebController : public WebController {
void(const ElementFinder::Result&,
base::OnceCallback<void(const ClientStatus&)>& callback));
- void FocusElement(
- const Selector& selector,
+ void ScrollToElementPosition(
+ const ElementFinder::Result& element,
const TopPadding& top_padding,
base::OnceCallback<void(const ClientStatus&)> callback) override {
- OnFocusElement(selector, top_padding, callback);
+ OnScrollToElementPosition(element, top_padding, callback);
}
- MOCK_METHOD3(OnFocusElement,
- void(const Selector& selector,
+ MOCK_METHOD3(OnScrollToElementPosition,
+ void(const ElementFinder::Result& element,
const TopPadding& top_padding,
base::OnceCallback<void(const ClientStatus&)>& callback));
- void ElementCheck(
- const Selector& selector,
- bool strict,
- base::OnceCallback<void(const ClientStatus&)> callback) override {
- OnElementCheck(selector, callback);
- }
- MOCK_METHOD2(OnElementCheck,
- void(const Selector& selector,
- base::OnceCallback<void(const ClientStatus&)>& callback));
-
void GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) override {
- OnGetFieldValue(selector, callback);
+ OnGetFieldValue(element, callback);
}
MOCK_METHOD2(OnGetFieldValue,
- void(const Selector& selector,
+ void(const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::string&)>& callback));
+
+ void GetStringAttribute(
+ const ElementFinder::Result& element,
+ const std::vector<std::string>& attributes,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback) override {
+ OnGetStringAttribute(element, attributes, callback);
+ }
+ MOCK_METHOD3(OnGetStringAttribute,
+ void(const ElementFinder::Result& element,
+ const std::vector<std::string>& attributes,
base::OnceCallback<void(const ClientStatus&,
const std::string&)>& callback));
void GetVisualViewport(
- base::OnceCallback<void(bool, const RectF&)> callback) override {
+ base::OnceCallback<void(const ClientStatus&, const RectF&)> callback)
+ override {
OnGetVisualViewport(callback);
}
MOCK_METHOD1(OnGetVisualViewport,
- void(base::OnceCallback<void(bool, const RectF&)>& callback));
+ void(base::OnceCallback<void(const ClientStatus&, const RectF&)>&
+ callback));
- void GetElementPosition(
- const Selector& selector,
- base::OnceCallback<void(bool, const RectF&)> callback) override {
- OnGetElementPosition(selector, callback);
+ void GetElementRect(
+ const ElementFinder::Result& element,
+ ElementRectGetter::ElementRectCallback callback) override {
+ OnGetElementRect(element, callback);
}
- MOCK_METHOD2(OnGetElementPosition,
- void(const Selector& selector,
- base::OnceCallback<void(bool, const RectF&)>& callback));
+ MOCK_METHOD2(OnGetElementRect,
+ void(const ElementFinder::Result& element,
+ ElementRectGetter::ElementRectCallback& callback));
void WaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback) {
@@ -103,29 +125,38 @@ class MockWebController : public WebController {
MOCK_METHOD2(
OnGetDocumentReadyState,
- void(const Selector&,
+ void(const ElementFinder::Result&,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>&));
void GetDocumentReadyState(
- const Selector& frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) override {
- OnGetDocumentReadyState(frame, callback);
+ OnGetDocumentReadyState(optional_frame_element, callback);
}
- MOCK_METHOD3(
- OnWaitForDocumentReadyState,
- void(const Selector&,
- DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>&));
+ MOCK_METHOD3(OnWaitForDocumentReadyState,
+ void(const ElementFinder::Result&,
+ DocumentReadyState,
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)>&));
void WaitForDocumentReadyState(
- const Selector& frame,
+ const ElementFinder::Result& optional_frame_element,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) override {
- OnWaitForDocumentReadyState(frame, min_ready_state, callback);
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) override {
+ OnWaitForDocumentReadyState(optional_frame_element, min_ready_state,
+ callback);
+ }
+
+ base::WeakPtr<WebController> GetWeakPtr() const override {
+ return weak_ptr_factory_.GetWeakPtr();
}
+
+ base::WeakPtrFactory<MockWebController> weak_ptr_factory_{this};
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller.cc b/chromium/components/autofill_assistant/browser/web/web_controller.cc
index c571255e3f8..f5d5b1a5733 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller.cc
+++ b/chromium/components/autofill_assistant/browser/web/web_controller.cc
@@ -10,8 +10,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/strcat.h"
@@ -23,10 +23,10 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/rectf.h"
#include "components/autofill_assistant/browser/string_conversions_util.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -40,12 +40,14 @@ using autofill::ContentAutofillDriver;
namespace {
+// Get the visual viewport as a list of values to fill into RectF, that is:
+// left, top, right, bottom.
const char* const kGetVisualViewport =
R"({ const v = window.visualViewport;
[v.pageLeft,
v.pageTop,
- v.width,
- v.height] })";
+ v.pageLeft + v.width,
+ v.pageTop + v.height] })";
// Scrolls to the specified node with top padding. The top padding can
// be specified through pixels or ratio. Pixels take precedence.
@@ -112,8 +114,23 @@ const char* const kHighlightElementScript =
const char* const kGetValueAttributeScript =
"function () { return this.value; }";
+// Javascript code to retrieve the nested |attribute| of a node.
+// The function intentionally has no "has value" check, such that a bad access
+// will return an error.
+const char* const kGetElementAttributeScript =
+ R"(function (attributes) {
+ let it = this;
+ for (let i = 0; i < attributes.length; ++i) {
+ it = it[attributes[i]];
+ }
+ return it;
+ })";
+
// Javascript code to select the current value.
-const char* const kSelectFieldValue = "function() { this.select(); }";
+const char* const kSelectFieldValueScript = "function() { this.select(); }";
+
+// Javascript code to focus a field.
+const char* const kFocusFieldScript = "function() { this.focus(); }";
// Javascript code to set the 'value' attribute of a node and then fire a
// "change" event to trigger any listeners.
@@ -126,6 +143,8 @@ const char* const kSetValueAttributeScript =
})";
// Javascript code to set an attribute of a node to a given value.
+// The function intentionally has no "has value" check, such that a bad access
+// will return an error.
const char* const kSetAttributeScript =
R"(function (attribute, value) {
let receiver = this;
@@ -141,17 +160,14 @@ const char* const kSetAttributeScript =
const char* const kGetOuterHtmlScript =
"function () { return this.outerHTML; }";
-const char* const kGetElementTagScript = "function () { return this.tagName; }";
+// Javascript code to get the outerHTML of each node in a list.
+const char* const kGetOuterHtmlsScript =
+ "function () { return this.map((e) => e.outerHTML); }";
-// Javascript code to query whether the document is ready for interact.
-const char* const kIsDocumentReadyForInteract =
- R"(function () {
- return document.readyState == 'interactive'
- || document.readyState == 'complete';
- })";
+const char* const kGetElementTagScript = "function () { return this.tagName; }";
// Javascript code to click on an element.
-const char* const kClickElement =
+const char* const kClickElementScript =
R"(function (selector) {
selector.click();
})";
@@ -204,18 +220,20 @@ std::string DocumentReadyStateToQuotedJsString(int state) {
// Appends to |out| the definition of a function that'll wait for a
// ready state, expressed as a DocumentReadyState enum value.
-void AppendWaitForDocumentReadyStateFunction(std::string* out) {
+void AppendWaitForDocumentReadyStateFunction(DocumentReadyState min_ready_state,
+ std::string* out) {
// quoted_names covers all possible DocumentReadyState values.
std::vector<std::string> quoted_names(DOCUMENT_MAX_READY_STATE + 1);
for (int i = 0; i <= DOCUMENT_MAX_READY_STATE; i++) {
quoted_names[i] = DocumentReadyStateToQuotedJsString(i);
}
- base::StrAppend(out, {R"(function (minReadyStateNum) {
+ base::StrAppend(
+ out, {R"((function (minReadyStateNum) {
return new Promise((fulfill, reject) => {
let handler = function(event) {
let readyState = document.readyState;
let readyStates = [)",
- base::JoinString(quoted_names, ", "), R"(];
+ base::JoinString(quoted_names, ", "), R"(];
let readyStateNum = readyStates.indexOf(readyState);
if (readyStateNum == -1) readyStateNum = 0;
if (readyStateNum >= minReadyStateNum) {
@@ -226,44 +244,59 @@ void AppendWaitForDocumentReadyStateFunction(std::string* out) {
document.addEventListener('readystatechange', handler)
handler();
})
-})"});
+}))",
+ base::StringPrintf("(%d)", static_cast<int>(min_ready_state))});
}
-// Forward the result of WaitForDocumentReadyState to the callback. The same
-// code work on both EvaluateResult and CallFunctionOnResult.
-template <typename T>
-void OnWaitForDocumentReadyState(
+void WrapCallbackNoWait(
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<T> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- VLOG_IF(1, !status.ok()) << __func__
- << " Failed to get document ready state.";
- int ready_state;
- SafeGetIntValue(result->GetResult(), &ready_state);
- std::move(callback).Run(status, static_cast<DocumentReadyState>(ready_state));
+ const ClientStatus& status,
+ DocumentReadyState state,
+ base::TimeDelta ignored_time) {
+ std::move(callback).Run(status, state);
+}
+
+void DecorateWebControllerStatus(
+ WebControllerErrorInfoProto::WebAction web_action,
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status) {
+ ClientStatus copy = status;
+ if (!status.ok()) {
+ VLOG(1) << web_action << " failed with status: " << status;
+ FillWebControllerErrorInfo(web_action, &copy);
+ }
+ std::move(callback).Run(copy);
+}
+
+template <typename T>
+void DecorateControllerStatusWithValue(
+ WebControllerErrorInfoProto::WebAction web_action,
+ base::OnceCallback<void(const ClientStatus&, const T&)> callback,
+ const ClientStatus& status,
+ const T& result) {
+ ClientStatus copy = status;
+ if (!status.ok()) {
+ VLOG(1) << web_action << " failed with status: " << status;
+ FillWebControllerErrorInfo(web_action, &copy);
+ }
+ std::move(callback).Run(copy, result);
}
} // namespace
// static
std::unique_ptr<WebController> WebController::CreateForWebContents(
- content::WebContents* web_contents,
- const ClientSettings* settings) {
+ content::WebContents* web_contents) {
return std::make_unique<WebController>(
web_contents,
std::make_unique<DevtoolsClient>(
- content::DevToolsAgentHost::GetOrCreateFor(web_contents)),
- settings);
+ content::DevToolsAgentHost::GetOrCreateFor(web_contents)));
}
WebController::WebController(content::WebContents* web_contents,
- std::unique_ptr<DevtoolsClient> devtools_client,
- const ClientSettings* settings)
+ std::unique_ptr<DevtoolsClient> devtools_client)
: web_contents_(web_contents),
- devtools_client_(std::move(devtools_client)),
- settings_(settings) {}
+ devtools_client_(std::move(devtools_client)) {}
WebController::~WebController() {}
@@ -288,11 +321,68 @@ void WebController::OnJavaScriptResult(
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
- VLOG(1) << __func__ << " Failed JavaScript.";
+ VLOG(1) << __func__ << " Failed JavaScript with status: " << status;
}
std::move(callback).Run(status);
}
+void WebController::OnJavaScriptResultForString(
+ base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ std::string value;
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+ if (!status.ok()) {
+ VLOG(1) << __func__ << "Failed JavaScript with status: " << status;
+ }
+ SafeGetStringValue(result->GetResult(), &value);
+ std::move(callback).Run(status, value);
+}
+
+void WebController::OnJavaScriptResultForStringArray(
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+ if (!status.ok()) {
+ VLOG(1) << __func__ << "Failed JavaScript with status: " << status;
+ std::move(callback).Run(status, {});
+ return;
+ }
+
+ auto* remote_object = result->GetResult();
+ if (!remote_object || !remote_object->HasValue() ||
+ !remote_object->GetValue()->is_list()) {
+ VLOG(1) << __func__ << "JavaScript result is not an array.";
+ std::move(callback).Run(
+ JavaScriptErrorStatus(reply_status, __FILE__, __LINE__,
+ /* exception= */ nullptr),
+ {});
+ return;
+ }
+
+ auto values = remote_object->GetValue()->GetList();
+ std::vector<std::string> v;
+ for (const base::Value& value : values) {
+ if (!value.is_string()) {
+ VLOG(1) << __func__
+ << "JavaScript array content is not a string: " << value.type();
+ std::move(callback).Run(
+ JavaScriptErrorStatus(reply_status, __FILE__, __LINE__,
+ /* exception= */ nullptr),
+ {});
+ return;
+ }
+
+ v.push_back(value.GetString());
+ }
+
+ std::move(callback).Run(status, v);
+}
+
void WebController::ScrollIntoView(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
@@ -306,28 +396,75 @@ void WebController::ScrollIntoView(
.SetReturnByValue(true)
.Build(),
element.node_frame_id,
- base::BindOnce(&WebController::OnJavaScriptResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ base::BindOnce(
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SCROLL_INTO_VIEW,
+ std::move(callback))));
}
-void WebController::WaitForDocumentToBecomeInteractive(
+void WebController::CheckOnTop(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- InternalWaitForDocumentToBecomeInteractive(
- settings_->document_ready_check_count, element.object_id,
- element.node_frame_id,
- base::BindOnce(&WebController::OnWaitForDocumentToBecomeInteractive,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ auto worker = std::make_unique<CheckOnTopWorker>(devtools_client_.get());
+ auto* ptr = worker.get();
+ pending_workers_.emplace_back(std::move(worker));
+ ptr->Start(element,
+ base::BindOnce(&WebController::OnCheckOnTop,
+ weak_ptr_factory_.GetWeakPtr(), ptr,
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::ON_TOP,
+ std::move(callback))));
}
-void WebController::OnWaitForDocumentToBecomeInteractive(
+void WebController::OnCheckOnTop(
+ CheckOnTopWorker* worker_to_release,
base::OnceCallback<void(const ClientStatus&)> callback,
- bool result) {
- if (!result) {
- std::move(callback).Run(ClientStatus(TIMED_OUT));
- return;
+ const ClientStatus& status) {
+ base::EraseIf(pending_workers_, [worker_to_release](const auto& worker) {
+ return worker.get() == worker_to_release;
+ });
+ if (!status.ok()) {
+ VLOG(1) << __func__ << " Element is not on top: " << status;
}
- std::move(callback).Run(OkClientStatus());
+ std::move(callback).Run(status);
+}
+
+void WebController::WaitUntilElementIsStable(
+ const ElementFinder::Result& element,
+ int max_rounds,
+ base::TimeDelta check_interval,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ auto wrapped_callback = GetAssistantActionRunningStateRetainingCallback(
+ element, std::move(callback));
+
+ std::unique_ptr<ElementPositionGetter> getter =
+ std::make_unique<ElementPositionGetter>(devtools_client_.get(),
+ max_rounds, check_interval,
+ element.node_frame_id);
+ auto* ptr = getter.get();
+ pending_workers_.emplace_back(std::move(getter));
+ ptr->Start(element.container_frame_host, element.object_id,
+ base::BindOnce(
+ &WebController::OnWaitUntilElementIsStable,
+ weak_ptr_factory_.GetWeakPtr(), ptr,
+ base::BindOnce(
+ &DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::WAIT_UNTIL_ELEMENT_IS_STABLE,
+ std::move(wrapped_callback))));
+}
+
+void WebController::OnWaitUntilElementIsStable(
+ ElementPositionGetter* getter_to_release,
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status) {
+ base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) {
+ return worker.get() == getter_to_release;
+ });
+ if (!status.ok()) {
+ VLOG(1) << __func__ << " Element unstable.";
+ }
+ std::move(callback).Run(status);
}
void WebController::ClickOrTapElement(
@@ -344,25 +481,33 @@ void WebController::ClickOrTapElement(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
.SetArguments(std::move(argument))
- .SetFunctionDeclaration(kClickElement)
+ .SetFunctionDeclaration(kClickElementScript)
.Build(),
element.node_frame_id,
- base::BindOnce(&WebController::OnJavaScriptResult,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(wrapped_callback)));
+ base::BindOnce(
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::CLICK_OR_TAP_ELEMENT,
+ std::move(wrapped_callback))));
return;
}
std::unique_ptr<ElementPositionGetter> getter =
std::make_unique<ElementPositionGetter>(
- devtools_client_.get(), *settings_, element.node_frame_id);
+ devtools_client_.get(), /* max_rounds= */ 1,
+ /* check_interval= */ base::TimeDelta::FromMilliseconds(0),
+ element.node_frame_id);
auto* ptr = getter.get();
pending_workers_.emplace_back(std::move(getter));
ptr->Start(
element.container_frame_host, element.object_id,
- base::BindOnce(&WebController::TapOrClickOnCoordinates,
- weak_ptr_factory_.GetWeakPtr(), ptr, element.node_frame_id,
- click_type, std::move(wrapped_callback)));
+ base::BindOnce(
+ &WebController::TapOrClickOnCoordinates,
+ weak_ptr_factory_.GetWeakPtr(), ptr, element.node_frame_id,
+ click_type,
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::CLICK_OR_TAP_ELEMENT,
+ std::move(wrapped_callback))));
}
void WebController::TapOrClickOnCoordinates(
@@ -370,16 +515,16 @@ void WebController::TapOrClickOnCoordinates(
const std::string& node_frame_id,
ClickType click_type,
base::OnceCallback<void(const ClientStatus&)> callback,
- bool has_coordinates,
- int x,
- int y) {
+ const ClientStatus& status) {
+ int x = getter_to_release->x();
+ int y = getter_to_release->y();
base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) {
return worker.get() == getter_to_release;
});
- if (!has_coordinates) {
+ if (!status.ok()) {
VLOG(1) << __func__ << " Failed to get element position.";
- std::move(callback).Run(ClientStatus(ELEMENT_UNSTABLE));
+ std::move(callback).Run(status);
return;
}
@@ -493,26 +638,6 @@ void WebController::OnDispatchTouchEventEnd(
std::move(callback).Run(OkClientStatus());
}
-void WebController::ElementCheck(
- const Selector& selector,
- bool strict,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- DCHECK(!selector.empty());
- FindElement(
- selector, strict,
- base::BindOnce(&WebController::OnFindElementForCheck,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnFindElementForCheck(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> result) {
- VLOG_IF(1, !status.ok() && status.proto_status() != ELEMENT_RESOLUTION_FAILED)
- << __func__ << ": " << status;
- std::move(callback).Run(status);
-}
-
void WebController::WaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback) {
devtools_client_->GetRuntime()->Evaluate(
@@ -534,78 +659,78 @@ void WebController::OnWaitForWindowHeightChange(
}
void WebController::GetDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
callback) {
- WaitForDocumentReadyState(optional_frame, DOCUMENT_UNKNOWN_READY_STATE,
- std::move(callback));
+ WaitForDocumentReadyState(
+ optional_frame_element, DOCUMENT_UNKNOWN_READY_STATE,
+ base::BindOnce(&WrapCallbackNoWait, std::move(callback)));
}
void WebController::WaitForDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback) {
- if (optional_frame.empty()) {
- std::string expression;
- expression.append("(");
- AppendWaitForDocumentReadyStateFunction(&expression);
- base::StringAppendF(&expression, ")(%d)",
- static_cast<int>(min_ready_state));
- devtools_client_->GetRuntime()->Evaluate(
- runtime::EvaluateParams::Builder()
- .SetExpression(expression)
- .SetReturnByValue(true)
- .SetAwaitPromise(true)
- .Build(),
- /* node_frame_id= */ std::string(),
- base::BindOnce(&OnWaitForDocumentReadyState<runtime::EvaluateResult>,
- std::move(callback)));
- return;
- }
- FindElement(
- optional_frame, /* strict= */ false,
- base::BindOnce(&WebController::OnFindElementForWaitForDocumentReadyState,
- weak_ptr_factory_.GetWeakPtr(), min_ready_state,
- std::move(callback)));
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback) {
+ // Note: An optional frame element will have an empty node_frame_id which
+ // will be considered as operating in the main frame.
+ std::string expression;
+ AppendWaitForDocumentReadyStateFunction(min_ready_state, &expression);
+ devtools_client_->GetRuntime()->Evaluate(
+ runtime::EvaluateParams::Builder()
+ .SetExpression(expression)
+ .SetReturnByValue(true)
+ .SetAwaitPromise(true)
+ .Build(),
+ optional_frame_element.node_frame_id,
+ base::BindOnce(&WebController::OnWaitForDocumentReadyState,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ base::TimeTicks::Now()));
}
-void WebController::OnFindElementForWaitForDocumentReadyState(
- DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element) {
+void WebController::OnWaitForDocumentReadyState(
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback,
+ base::TimeTicks wait_start_time,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::EvaluateResult> result) {
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
- std::move(callback).Run(status, DOCUMENT_UNKNOWN_READY_STATE);
- return;
+ VLOG(1) << __func__ << " Failed to get document ready state.";
+ FillWebControllerErrorInfo(
+ WebControllerErrorInfoProto::WAIT_FOR_DOCUMENT_READY_STATE, &status);
}
- std::string function_declaration;
- AppendWaitForDocumentReadyStateFunction(&function_declaration);
-
- std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
- AddRuntimeCallArgument(static_cast<int>(min_ready_state), &arguments);
- devtools_client_->GetRuntime()->CallFunctionOn(
- runtime::CallFunctionOnParams::Builder()
- .SetObjectId(element ? element->object_id : "")
- .SetFunctionDeclaration(function_declaration)
- .SetArguments(std::move(arguments))
- .SetReturnByValue(true)
- .SetAwaitPromise(true)
- .Build(),
- element->node_frame_id,
- base::BindOnce(
- &OnWaitForDocumentReadyState<runtime::CallFunctionOnResult>,
- std::move(callback)));
+ int ready_state;
+ SafeGetIntValue(result->GetResult(), &ready_state);
+ std::move(callback).Run(status, static_cast<DocumentReadyState>(ready_state),
+ base::TimeTicks::Now() - wait_start_time);
}
void WebController::FindElement(const Selector& selector,
bool strict_mode,
ElementFinder::Callback callback) {
+ RunElementFinder(selector,
+ strict_mode ? ElementFinder::ResultType::kExactlyOneMatch
+ : ElementFinder::ResultType::kAnyMatch,
+ std::move(callback));
+}
+
+void WebController::FindAllElements(const Selector& selector,
+ ElementFinder::Callback callback) {
+ RunElementFinder(selector, ElementFinder::ResultType::kMatchArray,
+ std::move(callback));
+}
+
+void WebController::RunElementFinder(const Selector& selector,
+ ElementFinder::ResultType result_type,
+ ElementFinder::Callback callback) {
auto finder = std::make_unique<ElementFinder>(
- web_contents_, devtools_client_.get(), selector,
- strict_mode ? ElementFinder::ResultType::kExactlyOneMatch
- : ElementFinder::ResultType::kAnyMatch);
+ web_contents_, devtools_client_.get(), selector, result_type);
+
auto* ptr = finder.get();
pending_workers_.emplace_back(std::move(finder));
ptr->Start(base::BindOnce(&WebController::OnFindElementResult,
@@ -624,71 +749,13 @@ void WebController::OnFindElementResult(
std::move(callback).Run(status, std::move(result));
}
-void WebController::OnFindElementForFocusElement(
- const TopPadding& top_padding,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result) {
- if (!status.ok()) {
- VLOG(1) << __func__ << " Failed to find the element to focus on.";
- std::move(callback).Run(status);
- return;
- }
-
- std::string element_object_id = element_result->object_id;
- InternalWaitForDocumentToBecomeInteractive(
- settings_->document_ready_check_count, element_object_id,
- element_result->node_frame_id,
- base::BindOnce(
- &WebController::OnWaitDocumentToBecomeInteractiveForFocusElement,
- weak_ptr_factory_.GetWeakPtr(), top_padding, std::move(callback),
- std::move(element_result)));
-}
-
-void WebController::OnWaitDocumentToBecomeInteractiveForFocusElement(
- const TopPadding& top_padding,
- base::OnceCallback<void(const ClientStatus&)> callback,
- std::unique_ptr<ElementFinder::Result> target_element,
- bool result) {
- if (!result) {
- std::move(callback).Run(ClientStatus(ELEMENT_UNSTABLE));
- return;
- }
-
- std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
- AddRuntimeCallArgumentObjectId(target_element->object_id, &arguments);
- AddRuntimeCallArgument(top_padding.pixels(), &arguments);
- AddRuntimeCallArgument(top_padding.ratio(), &arguments);
- devtools_client_->GetRuntime()->CallFunctionOn(
- runtime::CallFunctionOnParams::Builder()
- .SetObjectId(target_element->object_id)
- .SetArguments(std::move(arguments))
- .SetFunctionDeclaration(std::string(kScrollIntoViewWithPaddingScript))
- .SetReturnByValue(true)
- .Build(),
- target_element->node_frame_id,
- base::BindOnce(&WebController::OnFocusElement,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnFocusElement(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- VLOG_IF(1, !status.ok()) << __func__ << " Failed to focus on element.";
- std::move(callback).Run(status);
-}
-
void WebController::FillAddressForm(
const autofill::AutofillProfile* profile,
const Selector& selector,
base::OnceCallback<void(const ClientStatus&)> callback) {
VLOG(3) << __func__ << " " << selector;
auto data_to_autofill = std::make_unique<FillFormInputData>();
- data_to_autofill->profile =
- std::make_unique<autofill::AutofillProfile>(*profile);
+ data_to_autofill->profile = MakeUniqueFromProfile(*profile);
FindElement(selector,
/* strict_mode= */ true,
base::BindOnce(&WebController::OnFindElementForFillingForm,
@@ -878,7 +945,10 @@ void WebController::SelectOption(
.Build(),
element.node_frame_id,
base::BindOnce(&WebController::OnSelectOption,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SELECT_OPTION,
+ std::move(callback))));
}
void WebController::OnSelectOption(
@@ -907,27 +977,9 @@ void WebController::OnSelectOption(
}
void WebController::HighlightElement(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- VLOG(3) << __func__ << " " << selector;
- FindElement(
- selector,
- /* strict_mode= */ true,
- base::BindOnce(&WebController::OnFindElementForHighlightElement,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnFindElementForHighlightElement(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result) {
- if (!status.ok()) {
- VLOG(1) << __func__ << " Failed to find the element to highlight.";
- std::move(callback).Run(status);
- return;
- }
-
- const std::string& object_id = element_result->object_id;
+ const std::string& object_id = element.object_id;
std::vector<std::unique_ptr<runtime::CallArgument>> argument;
AddRuntimeCallArgumentObjectId(object_id, &argument);
devtools_client_->GetRuntime()->CallFunctionOn(
@@ -937,233 +989,210 @@ void WebController::OnFindElementForHighlightElement(
.SetFunctionDeclaration(std::string(kHighlightElementScript))
.SetReturnByValue(true)
.Build(),
- element_result->node_frame_id,
- base::BindOnce(&WebController::OnHighlightElement,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnHighlightElement(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- VLOG_IF(1, !status.ok()) << __func__ << " Failed to highlight element.";
- std::move(callback).Run(status);
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::HIGHLIGHT_ELEMENT,
+ std::move(callback))));
}
-void WebController::FocusElement(
- const Selector& selector,
+void WebController::ScrollToElementPosition(
+ const ElementFinder::Result& element,
const TopPadding& top_padding,
base::OnceCallback<void(const ClientStatus&)> callback) {
- VLOG(3) << __func__ << " " << selector;
- DCHECK(!selector.empty());
- FindElement(selector,
- /* strict_mode= */ false,
- base::BindOnce(&WebController::OnFindElementForFocusElement,
- weak_ptr_factory_.GetWeakPtr(), top_padding,
- std::move(callback)));
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ AddRuntimeCallArgumentObjectId(element.object_id, &arguments);
+ AddRuntimeCallArgument(top_padding.pixels(), &arguments);
+ AddRuntimeCallArgument(top_padding.ratio(), &arguments);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(element.object_id)
+ .SetArguments(std::move(arguments))
+ .SetFunctionDeclaration(std::string(kScrollIntoViewWithPaddingScript))
+ .SetReturnByValue(true)
+ .Build(),
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SCROLL_INTO_VIEW_WITH_PADDING,
+ std::move(callback))));
}
void WebController::GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
- FindElement(
- selector,
- /* strict_mode= */ true,
- base::BindOnce(&WebController::OnFindElementForGetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(element.object_id)
+ .SetFunctionDeclaration(std::string(kGetValueAttributeScript))
+ .SetReturnByValue(true)
+ .Build(),
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResultForString,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
+ WebControllerErrorInfoProto::GET_FIELD_VALUE,
+ std::move(callback))));
}
-void WebController::OnFindElementForGetFieldValue(
- base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result) {
- const std::string object_id = element_result->object_id;
- if (!status.ok()) {
- std::move(callback).Run(status, "");
+void WebController::GetStringAttribute(
+ const ElementFinder::Result& element,
+ const std::vector<std::string>& attributes,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback) {
+ VLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
+ << "]";
+
+ if (attributes.empty()) {
+ ClientStatus error_status = UnexpectedErrorStatus(__FILE__, __LINE__);
+ FillWebControllerErrorInfo(
+ WebControllerErrorInfoProto::GET_STRING_ATTRIBUTE, &error_status);
+ std::move(callback).Run(error_status, "");
return;
}
+ base::Value::ListStorage attribute_values;
+ for (const std::string& attribute : attributes) {
+ attribute_values.emplace_back(base::Value(attribute));
+ }
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ AddRuntimeCallArgument(attribute_values, &arguments);
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
- .SetObjectId(object_id)
- .SetFunctionDeclaration(std::string(kGetValueAttributeScript))
+ .SetObjectId(element.object_id)
+ .SetArguments(std::move(arguments))
+ .SetFunctionDeclaration(std::string(kGetElementAttributeScript))
.SetReturnByValue(true)
.Build(),
- element_result->node_frame_id,
- base::BindOnce(&WebController::OnGetValueAttribute,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnGetValueAttribute(
- base::OnceCallback<void(const ClientStatus& element_status,
- const std::string&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- std::string value;
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- // Read the result returned from Javascript code.
- VLOG_IF(1, !status.ok()) << __func__
- << "Failed to get attribute value: " << status;
- SafeGetStringValue(result->GetResult(), &value);
- std::move(callback).Run(status, value);
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResultForString,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
+ WebControllerErrorInfoProto::GET_STRING_ATTRIBUTE,
+ std::move(callback))));
}
-void WebController::SetFieldValue(
+void WebController::SelectFieldValue(
const ElementFinder::Result& element,
- const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
base::OnceCallback<void(const ClientStatus&)> callback) {
-#ifdef NDEBUG
- VLOG(3) << __func__ << " value=(redacted)"
- << ", strategy=" << fill_strategy;
-#else
- DVLOG(3) << __func__ << " value=" << value << ", strategy=" << fill_strategy;
-#endif
-
- if ((fill_strategy == SIMULATE_KEY_PRESSES ||
- fill_strategy == SIMULATE_KEY_PRESSES_SELECT_VALUE) &&
- !value.empty()) {
- // We first select the field value, and then simulate the key presses. This
- // will clear / overwrite the previous value.
- // TODO(crbug.com/806868): Disable keyboard during this action and then
- // reset to previous state.
- if (fill_strategy == SIMULATE_KEY_PRESSES_SELECT_VALUE) {
- // TODO(b/149004036): In case of empty, send a backspace (i.e. code 8),
- // instead of falling back to SetValueAttribute(""). This currently
- // fails in WebControllerBrowserTest.GetAndSetFieldValue. Fixing this
- // might fix b/148001624 as well.
- SelectFieldValueForReplace(
- element,
- base::BindOnce(&WebController::OnFieldValueSelectedSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), element,
- UTF8ToUnicode(value), key_press_delay_in_millisecond,
- std::move(callback)));
- } else {
- SetValueAttribute(
- element, "",
- base::BindOnce(&WebController::OnClearFieldForSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), element,
- UTF8ToUnicode(value), key_press_delay_in_millisecond,
- std::move(callback)));
- }
- return;
- }
- SetValueAttribute(element, value, std::move(callback));
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(element.object_id)
+ .SetFunctionDeclaration(std::string(kSelectFieldValueScript))
+ .Build(),
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SELECT_FIELD_VALUE,
+ std::move(callback))));
}
-void WebController::OnClearFieldForSetFieldValue(
+void WebController::SetValueAttribute(
const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& clear_status) {
- if (!clear_status.ok()) {
- std::move(callback).Run(clear_status);
- return;
- }
-
- // TODO(b/158153191): Move this chain out of |WebController|. This performs
- // what used to be part of |SendKeyboardInput|.
- WaitForDocumentToBecomeInteractive(
- element,
+ const std::string& value,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ std::vector<std::unique_ptr<runtime::CallArgument>> argument;
+ AddRuntimeCallArgument(value, &argument);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(element.object_id)
+ .SetArguments(std::move(argument))
+ .SetFunctionDeclaration(std::string(kSetValueAttributeScript))
+ .Build(),
+ element.node_frame_id,
base::BindOnce(
- &WebController::OnWaitForDocumentToBecomeInteractiveForSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), element, codepoints,
- key_press_delay_in_millisecond, std::move(callback)));
+ &WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SET_VALUE_ATTRIBUTE,
+ std::move(callback))));
}
-void WebController::OnWaitForDocumentToBecomeInteractiveForSetFieldValue(
+void WebController::SetAttribute(
const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& wait_status) {
- if (!wait_status.ok()) {
- std::move(callback).Run(wait_status);
- return;
- }
-
- ScrollIntoView(
- element,
- base::BindOnce(&WebController::OnScrollIntoViewForSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), element, codepoints,
- key_press_delay_in_millisecond, std::move(callback)));
-}
+ const std::vector<std::string>& attributes,
+ const std::string& value,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
+ << "], value=" << value;
-void WebController::OnScrollIntoViewForSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& scroll_status) {
- if (!scroll_status.ok()) {
- std::move(callback).Run(scroll_status);
+ if (attributes.empty()) {
+ ClientStatus error_status = UnexpectedErrorStatus(__FILE__, __LINE__);
+ FillWebControllerErrorInfo(WebControllerErrorInfoProto::SET_ATTRIBUTE,
+ &error_status);
+ std::move(callback).Run(error_status);
return;
}
+ base::Value::ListStorage attribute_values;
+ for (const std::string& attribute : attributes) {
+ attribute_values.emplace_back(base::Value(attribute));
+ }
- ClickOrTapElement(
- element, ClickType::CLICK,
- base::BindOnce(&WebController::OnClickOrTapElementForSetFieldValue,
- weak_ptr_factory_.GetWeakPtr(), element, codepoints,
- key_press_delay_in_millisecond, std::move(callback)));
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ AddRuntimeCallArgument(attribute_values, &arguments);
+ AddRuntimeCallArgument(value, &arguments);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(element.object_id)
+ .SetArguments(std::move(arguments))
+ .SetFunctionDeclaration(std::string(kSetAttributeScript))
+ .Build(),
+ element.node_frame_id,
+ base::BindOnce(&WebController::OnJavaScriptResult,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SET_ATTRIBUTE,
+ std::move(callback))));
}
-void WebController::OnClickOrTapElementForSetFieldValue(
+void WebController::SendKeyboardInput(
const ElementFinder::Result& element,
const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& click_status) {
- if (!click_status.ok()) {
- std::move(callback).Run(click_status);
- return;
+ const int delay_in_millisecond,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ if (VLOG_IS_ON(3)) {
+ std::string input_str;
+ if (!UnicodeToUTF8(codepoints, &input_str)) {
+ input_str.assign("<invalid input>");
+ }
+#ifdef NDEBUG
+ VLOG(3) << __func__ << " input=(redacted)";
+#else
+ DVLOG(3) << __func__ << " input=" << input_str;
+#endif
}
- SendKeyboardInput(element, codepoints, key_press_delay_in_millisecond,
- std::move(callback));
+ DispatchKeyboardTextDownEvent(
+ element.node_frame_id, codepoints, 0,
+ /* delay= */ false, delay_in_millisecond,
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::SEND_KEYBOARD_INPUT,
+ std::move(callback)));
}
-void WebController::SelectFieldValueForReplace(
+void WebController::FocusField(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
+ auto wrapped_callback = GetAssistantActionRunningStateRetainingCallback(
+ element, std::move(callback));
+
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id)
- .SetFunctionDeclaration(std::string(kSelectFieldValue))
+ .SetFunctionDeclaration(std::string(kFocusFieldScript))
.Build(),
element.node_frame_id,
- base::BindOnce(&WebController::OnSelectFieldValueForReplace,
- weak_ptr_factory_.GetWeakPtr(), element,
- std::move(callback)));
-}
-
-void WebController::OnSelectFieldValueForReplace(
- const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- std::move(callback).Run(
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
-}
-
-void WebController::OnFieldValueSelectedSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& select_status) {
- if (!select_status.ok()) {
- std::move(callback).Run(select_status);
- return;
- }
- DispatchKeyboardTextDownEvent(
- element.node_frame_id, codepoints, 0,
- /* delay= */ false, key_press_delay_in_millisecond, std::move(callback));
+ base::BindOnce(&WebController::OnJavaScriptResult,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateWebControllerStatus,
+ WebControllerErrorInfoProto::FOCUS_FIELD,
+ std::move(wrapped_callback))));
}
void WebController::DispatchKeyboardTextDownEvent(
@@ -1249,79 +1278,8 @@ auto WebController::CreateKeyEventParamsForCharacter(
return params;
}
-void WebController::SetValueAttribute(
- const ElementFinder::Result& element,
- const std::string& value,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- std::vector<std::unique_ptr<runtime::CallArgument>> argument;
- AddRuntimeCallArgument(value, &argument);
- devtools_client_->GetRuntime()->CallFunctionOn(
- runtime::CallFunctionOnParams::Builder()
- .SetObjectId(element.object_id)
- .SetArguments(std::move(argument))
- .SetFunctionDeclaration(std::string(kSetValueAttributeScript))
- .Build(),
- element.node_frame_id,
- base::BindOnce(&WebController::OnJavaScriptResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::SetAttribute(
- const ElementFinder::Result& element,
- const std::vector<std::string>& attributes,
- const std::string& value,
- base::OnceCallback<void(const ClientStatus&)> callback) {
-#ifdef NDEBUG
- VLOG(3) << __func__ << " attributes=(redacted), value=(redacted)";
-#else
- DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",")
- << "], value=" << value;
-#endif
-
- DCHECK_GT(attributes.size(), 0u);
- base::Value::ListStorage attribute_values;
- for (const std::string& string : attributes) {
- attribute_values.emplace_back(base::Value(string));
- }
-
- std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
- AddRuntimeCallArgument(attribute_values, &arguments);
- AddRuntimeCallArgument(value, &arguments);
- devtools_client_->GetRuntime()->CallFunctionOn(
- runtime::CallFunctionOnParams::Builder()
- .SetObjectId(element.object_id)
- .SetArguments(std::move(arguments))
- .SetFunctionDeclaration(std::string(kSetAttributeScript))
- .Build(),
- element.node_frame_id,
- base::BindOnce(&WebController::OnJavaScriptResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::SendKeyboardInput(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- const int delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback) {
- if (VLOG_IS_ON(3)) {
- std::string input_str;
- if (!UnicodeToUTF8(codepoints, &input_str)) {
- input_str.assign("<invalid input>");
- }
-#ifdef NDEBUG
- VLOG(3) << __func__ << " input=(redacted)";
-#else
- DVLOG(3) << __func__ << " input=" << input_str;
-#endif
- }
-
- DispatchKeyboardTextDownEvent(element.node_frame_id, codepoints, 0,
- /* delay= */ false, delay_in_millisecond,
- std::move(callback));
-}
-
void WebController::GetVisualViewport(
- base::OnceCallback<void(bool, const RectF&)> callback) {
+ base::OnceCallback<void(const ClientStatus&, const RectF&)> callback) {
devtools_client_->GetRuntime()->Evaluate(
runtime::EvaluateParams::Builder()
.SetExpression(std::string(kGetVisualViewport))
@@ -1333,7 +1291,7 @@ void WebController::GetVisualViewport(
}
void WebController::OnGetVisualViewport(
- base::OnceCallback<void(bool, const RectF&)> callback,
+ base::OnceCallback<void(const ClientStatus&, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
ClientStatus status =
@@ -1342,8 +1300,9 @@ void WebController::OnGetVisualViewport(
!result->GetResult()->GetValue()->is_list() ||
result->GetResult()->GetValue()->GetList().size() != 4u) {
VLOG(1) << __func__ << " Failed to get visual viewport: " << status;
- RectF empty;
- std::move(callback).Run(false, empty);
+ std::move(callback).Run(
+ JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
+ RectF());
return;
}
const auto& list = result->GetResult()->GetValue()->GetList();
@@ -1361,95 +1320,71 @@ void WebController::OnGetVisualViewport(
rect.right = left + width;
rect.bottom = top + height;
- std::move(callback).Run(true, rect);
+ std::move(callback).Run(OkClientStatus(), rect);
}
-void WebController::GetElementPosition(
- const Selector& selector,
- base::OnceCallback<void(bool, const RectF&)> callback) {
- FindElement(
- selector, /* strict_mode= */ true,
- base::BindOnce(&WebController::OnFindElementForPosition,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnFindElementForPosition(
- base::OnceCallback<void(bool, const RectF&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> result) {
- if (!status.ok()) {
- RectF empty;
- std::move(callback).Run(false, empty);
- return;
- }
+void WebController::GetElementRect(
+ const ElementFinder::Result& element,
+ ElementRectGetter::ElementRectCallback callback) {
std::unique_ptr<ElementRectGetter> getter =
std::make_unique<ElementRectGetter>(devtools_client_.get());
auto* ptr = getter.get();
pending_workers_.emplace_back(std::move(getter));
ptr->Start(
- std::move(result),
- base::BindOnce(&WebController::OnGetElementRectResult,
+ // TODO(b/172041811): Ownership of element.
+ std::make_unique<ElementFinder::Result>(element),
+ base::BindOnce(&WebController::OnGetElementRect,
weak_ptr_factory_.GetWeakPtr(), ptr, std::move(callback)));
}
-void WebController::OnGetElementRectResult(
+void WebController::OnGetElementRect(
ElementRectGetter* getter_to_release,
- base::OnceCallback<void(bool, const RectF&)> callback,
- bool has_rect,
+ ElementRectGetter::ElementRectCallback callback,
+ const ClientStatus& rect_status,
const RectF& element_rect) {
base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) {
return worker.get() == getter_to_release;
});
- std::move(callback).Run(has_rect, element_rect);
+ std::move(callback).Run(rect_status, element_rect);
}
void WebController::GetOuterHtml(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback) {
- VLOG(3) << __func__ << " " << selector;
- FindElement(
- selector,
- /* strict_mode= */ true,
- base::BindOnce(&WebController::OnFindElementForGetOuterHtml,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnFindElementForGetOuterHtml(
- base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result) {
- if (!status.ok()) {
- VLOG(2) << __func__ << " Failed to find element for GetOuterHtml";
- std::move(callback).Run(status, "");
- return;
- }
-
devtools_client_->GetRuntime()->CallFunctionOn(
runtime::CallFunctionOnParams::Builder()
- .SetObjectId(element_result->object_id)
+ .SetObjectId(element.object_id)
.SetFunctionDeclaration(std::string(kGetOuterHtmlScript))
.SetReturnByValue(true)
.Build(),
- element_result->node_frame_id,
- base::BindOnce(&WebController::OnGetOuterHtml,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ element.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResultForString,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
+ WebControllerErrorInfoProto::GET_OUTER_HTML,
+ std::move(callback))));
}
-void WebController::OnGetOuterHtml(
- base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- if (!status.ok()) {
- VLOG(2) << __func__ << " Failed to get HTML content for GetOuterHtml";
- std::move(callback).Run(status, "");
- return;
- }
- std::string value;
- SafeGetStringValue(result->GetResult(), &value);
- std::move(callback).Run(OkClientStatus(), value);
+void WebController::GetOuterHtmls(
+ const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback) {
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetObjectId(elements.object_id)
+ .SetFunctionDeclaration(std::string(kGetOuterHtmlsScript))
+ .SetReturnByValue(true)
+ .Build(),
+ elements.node_frame_id,
+ base::BindOnce(
+ &WebController::OnJavaScriptResultForStringArray,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &DecorateControllerStatusWithValue<std::vector<std::string>>,
+ WebControllerErrorInfoProto::GET_OUTER_HTML,
+ std::move(callback))));
}
void WebController::GetElementTag(
@@ -1463,74 +1398,16 @@ void WebController::GetElementTag(
.SetReturnByValue(true)
.Build(),
element.node_frame_id,
- base::BindOnce(&WebController::OnGetElementTag,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void WebController::OnGetElementTag(
- base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- if (!status.ok()) {
- VLOG(2) << __func__ << " Failed to get element tag for GetElementTag";
- std::move(callback).Run(status, "");
- return;
- }
- std::string value;
- SafeGetStringValue(result->GetResult(), &value);
- std::move(callback).Run(OkClientStatus(), value);
-}
-
-void WebController::InternalWaitForDocumentToBecomeInteractive(
- int remaining_rounds,
- const std::string& object_id,
- const std::string& node_frame_id,
- base::OnceCallback<void(bool)> callback) {
- devtools_client_->GetRuntime()->CallFunctionOn(
- runtime::CallFunctionOnParams::Builder()
- .SetObjectId(object_id)
- .SetFunctionDeclaration(std::string(kIsDocumentReadyForInteract))
- .SetReturnByValue(true)
- .Build(),
- node_frame_id,
base::BindOnce(
- &WebController::OnInternalWaitForDocumentToBecomeInteractive,
- weak_ptr_factory_.GetWeakPtr(), remaining_rounds, object_id,
- node_frame_id, std::move(callback)));
+ &WebController::OnJavaScriptResultForString,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(&DecorateControllerStatusWithValue<std::string>,
+ WebControllerErrorInfoProto::GET_ELEMENT_TAG,
+ std::move(callback))));
}
-void WebController::OnInternalWaitForDocumentToBecomeInteractive(
- int remaining_rounds,
- const std::string& object_id,
- const std::string& node_frame_id,
- base::OnceCallback<void(bool)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
- if (!status.ok() || remaining_rounds <= 0) {
- VLOG(1) << __func__
- << " Failed to wait for the document to become interactive with "
- "remaining_rounds: "
- << remaining_rounds;
- std::move(callback).Run(false);
- return;
- }
-
- bool ready;
- if (SafeGetBool(result->GetResult(), &ready) && ready) {
- std::move(callback).Run(true);
- return;
- }
-
- content::GetUIThreadTaskRunner({})->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&WebController::InternalWaitForDocumentToBecomeInteractive,
- weak_ptr_factory_.GetWeakPtr(), --remaining_rounds,
- object_id, node_frame_id, std::move(callback)),
- settings_->document_ready_check_interval);
+base::WeakPtr<WebController> WebController::GetWeakPtr() const {
+ return weak_ptr_factory_.GetWeakPtr();
}
WebController::ScopedAssistantActionStateRunning::
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller.h b/chromium/components/autofill_assistant/browser/web/web_controller.h
index 8a62a157cfd..406eb168e51 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller.h
+++ b/chromium/components/autofill_assistant/browser/web/web_controller.h
@@ -12,7 +12,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/actions/click_action.h"
+#include "base/time/time.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
@@ -23,6 +23,7 @@
#include "components/autofill_assistant/browser/rectf.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/top_padding.h"
+#include "components/autofill_assistant/browser/web/check_on_top_worker.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/element_position_getter.h"
#include "components/autofill_assistant/browser/web/element_rect_getter.h"
@@ -44,7 +45,6 @@ class RenderFrameHost;
} // namespace content
namespace autofill_assistant {
-struct ClientSettings;
// Controller to interact with the web pages.
//
@@ -60,13 +60,11 @@ class WebController {
// Create web controller for a given |web_contents|. |settings| must be valid
// for the lifetime of the controller.
static std::unique_ptr<WebController> CreateForWebContents(
- content::WebContents* web_contents,
- const ClientSettings* settings);
+ content::WebContents* web_contents);
// |web_contents| and |settings| must outlive this web controller.
WebController(content::WebContents* web_contents,
- std::unique_ptr<DevtoolsClient> devtools_client,
- const ClientSettings* settings);
+ std::unique_ptr<DevtoolsClient> devtools_client);
virtual ~WebController();
// Load |url| in the current tab. Returns immediately, before the new page has
@@ -76,26 +74,41 @@ class WebController {
// Find the element given by |selector|. If multiple elements match
// |selector| and if |strict_mode| is false, return the first one that is
// found. Otherwise if |strict-mode| is true, do not return any.
+ //
+ // To check multiple elements, use a BatchElementChecker.
virtual void FindElement(const Selector& selector,
bool strict_mode,
ElementFinder::Callback callback);
+ // Find all elements matching |selector|. If there are no matches, the status
+ // will be ELEMENT_RESOLUTION_FAILED.
+ virtual void FindAllElements(const Selector& selector,
+ ElementFinder::Callback callback);
+
// Scroll the |element| into view.
virtual void ScrollIntoView(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Wait for the |element|'s document to become interactive. This runs for
- // a predefined number of turns.
- virtual void WaitForDocumentToBecomeInteractive(
+ // Perform a mouse left button click or a touch tap on the |element|
+ // return the result through callback.
+ virtual void ClickOrTapElement(
const ElementFinder::Result& element,
+ ClickType click_type,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Perform a mouse left button click or a touch tap on the element given by
- // |selector| and return the result through callback.
- virtual void ClickOrTapElement(
+ // Get a stable position of the given element. Fail with ELEMENT_UNSTABLE if
+ // the element position doesn't stabilize quickly enough.
+ virtual void WaitUntilElementIsStable(
+ const ElementFinder::Result& element,
+ int max_rounds,
+ base::TimeDelta check_interval,
+ base::OnceCallback<void(const ClientStatus&)> callback);
+
+ // Check whether the center given element is on top. Fail with
+ // ELEMENT_NOT_ON_TOP if the center of the element is covered.
+ virtual void CheckOnTop(
const ElementFinder::Result& element,
- ClickType click_type,
base::OnceCallback<void(const ClientStatus&)> callback);
// Fill the address form given by |selector| with the given address
@@ -122,53 +135,68 @@ class WebController {
const autofill::FormFieldData& field_data)>
callback);
- // Select the option given by |selector| and the value of the option to be
- // picked.
+ // Select the option to be picked given by the |value| in the |element|.
virtual void SelectOption(
const ElementFinder::Result& element,
const std::string& value,
DropdownSelectStrategy select_strategy,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Highlight an element given by |selector|.
+ // Highlight an |element|.
virtual void HighlightElement(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Focus on element given by |selector|. |top_padding| specifies the padding
- // between focused element and the top.
- virtual void FocusElement(
- const Selector& selector,
+ // Scroll to an |element|'s position. |top_padding| specifies the padding
+ // between the focused element and the top.
+ virtual void ScrollToElementPosition(
+ const ElementFinder::Result& element,
const TopPadding& top_padding,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Get the value of |selector| and return the result through |callback|. The
- // returned value might be false, if the element cannot be found, true and the
- // empty string in case of error or empty value.
+ // Get the value attribute of an |element| and return the result through
+ // |callback|. If the lookup fails, the value will be empty. An empty result
+ // does not mean an error.
//
// Normally done through BatchElementChecker.
virtual void GetFieldValue(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback);
- // Set the |value| of field |element| and return the result through
- // |callback|. The strategy used to fill the value is defined by
- // |fill_strategy|, see the proto for further explanation.
- virtual void SetFieldValue(
+ // Get the value of a nested |attribute| from an |element| and return the
+ // result through |callback|. If the lookup fails, the value will be empty.
+ // An empty result does not mean an error.
+ virtual void GetStringAttribute(
+ const ElementFinder::Result& element,
+ const std::vector<std::string>& attributes,
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback);
+
+ // Set the value attribute of an |element| to the specified |value| and
+ // trigger an onchange event.
+ virtual void SetValueAttribute(
const ElementFinder::Result& element,
const std::string& value,
- KeyboardValueFillStrategy fill_strategy,
- int key_press_delay_in_millisecond,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Set the |value| of all the |attributes| of the |element|.
+ // Set the nested |attributes| of an |element| to the specified |value|.
virtual void SetAttribute(
const ElementFinder::Result& element,
const std::vector<std::string>& attributes,
const std::string& value,
base::OnceCallback<void(const ClientStatus&)> callback);
+ // Select the current value in a text |element|.
+ virtual void SelectFieldValue(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback);
+
+ // Focus the current |element|.
+ virtual void FocusField(
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback);
+
// Sets the keyboard focus to |element| and inputs |codepoints|, one
// character at a time. Key presses will have a delay of |delay_in_milli|
// between them.
@@ -179,12 +207,19 @@ class WebController {
int delay_in_milli,
base::OnceCallback<void(const ClientStatus&)> callback);
- // Return the outerHTML of |selector|.
+ // Return the outerHTML of |element|.
virtual void GetOuterHtml(
- const Selector& selector,
+ const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&, const std::string&)>
callback);
+ // Return the outerHTML of each element in |elements|. |elements| must contain
+ // the object ID of a JS array containing the elements.
+ virtual void GetOuterHtmls(
+ const ElementFinder::Result& elements,
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback);
+
// Return the tag of the |element|. In case of an error, will return an empty
// string.
virtual void GetElementTag(
@@ -196,47 +231,39 @@ class WebController {
//
// The rectangle is expressed in absolute CSS coordinates.
virtual void GetVisualViewport(
- base::OnceCallback<void(bool, const RectF&)> callback);
+ base::OnceCallback<void(const ClientStatus&, const RectF&)> callback);
- // Gets the position of the element identified by the selector.
+ // Gets the position of the |element|.
//
- // If unsuccessful, the callback gets (false, 0, 0, 0, 0).
+ // If unsuccessful, the callback gets the failure status with an empty rect.
//
- // If successful, the callback gets (true, left, top, right, bottom), with
- // coordinates expressed in absolute CSS coordinates.
- virtual void GetElementPosition(
- const Selector& selector,
- base::OnceCallback<void(bool, const RectF&)> callback);
-
- // Checks whether an element matches the given selector.
- //
- // If strict, there must be exactly one matching element for the check to
- // pass. Otherwise, there must be at least one.
- //
- // To check multiple elements, use a BatchElementChecker.
- virtual void ElementCheck(
- const Selector& selector,
- bool strict,
- base::OnceCallback<void(const ClientStatus&)> callback);
+ // If successful, the callback gets a success status with a set of
+ // (left, top, right, bottom) coordinates rect, expressed in absolute CSS
+ // coordinates.
+ virtual void GetElementRect(const ElementFinder::Result& element,
+ ElementRectGetter::ElementRectCallback callback);
// Calls the callback once the main document window has been resized.
virtual void WaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback);
- // Gets the value of document.readyState for |optional_frame| or, if it is
- // empty, in the main document.
+ // Gets the value of document.readyState for |optional_frame_element| or, if
+ // it is empty, in the main document.
virtual void GetDocumentReadyState(
- const Selector& optional_frame,
- base::OnceCallback<void(const ClientStatus&,
- DocumentReadyState end_state)> callback);
+ const ElementFinder::Result& optional_frame_element,
+ base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
+ callback);
// Waits for the value of Document.readyState to satisfy |min_ready_state| in
- // |optional_frame| or, if it is empty, in the main document.
+ // |optional_frame_element| or, if it is empty, in the main document.
virtual void WaitForDocumentReadyState(
- const Selector& optional_frame,
+ const ElementFinder::Result& optional_frame_element,
DocumentReadyState min_ready_state,
base::OnceCallback<void(const ClientStatus&,
- DocumentReadyState end_state)> callback);
+ DocumentReadyState,
+ base::TimeDelta)> callback);
+
+ virtual base::WeakPtr<WebController> GetWeakPtr() const;
private:
friend class WebControllerBrowserTest;
@@ -282,17 +309,29 @@ class WebController {
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnWaitForDocumentToBecomeInteractive(
+ void OnJavaScriptResultForString(
+ base::OnceCallback<void(const ClientStatus&, const std::string&)>
+ callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void OnJavaScriptResultForStringArray(
+ base::OnceCallback<void(const ClientStatus&,
+ const std::vector<std::string>&)> callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void OnCheckOnTop(CheckOnTopWorker* worker,
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status);
+ void OnWaitUntilElementIsStable(
+ ElementPositionGetter* getter_to_release,
base::OnceCallback<void(const ClientStatus&)> callback,
- bool result);
+ const ClientStatus& status);
void TapOrClickOnCoordinates(
ElementPositionGetter* getter_to_release,
const std::string& node_frame_id,
ClickType click_type,
base::OnceCallback<void(const ClientStatus&)> callback,
- bool has_coordinates,
- int x,
- int y);
+ const ClientStatus& status);
void OnDispatchPressMouseEvent(
const std::string& node_frame_id,
base::OnceCallback<void(const ClientStatus&)> callback,
@@ -313,15 +352,13 @@ class WebController {
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchTouchEventResult> result);
- void OnFindElementForCheck(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> result);
void OnWaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
-
+ void RunElementFinder(const Selector& selector,
+ ElementFinder::ResultType result_type,
+ ElementFinder::Callback callback);
void OnFindElementResult(ElementFinder* finder_to_release,
ElementFinder::Callback callback,
const ClientStatus& status,
@@ -353,78 +390,9 @@ class WebController {
callback,
const autofill::FormData& form_data,
const autofill::FormFieldData& form_field);
- void OnFindElementForFocusElement(
- const TopPadding& top_padding,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result);
- void OnWaitDocumentToBecomeInteractiveForFocusElement(
- const TopPadding& top_padding,
- base::OnceCallback<void(const ClientStatus&)> callback,
- std::unique_ptr<ElementFinder::Result> target_element,
- bool result);
- void OnFocusElement(base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnSelectOption(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFindElementForHighlightElement(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result);
- void OnHighlightElement(
- base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFindElementForGetFieldValue(
- base::OnceCallback<void(const ClientStatus&, const std::string&)>
- callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result);
- void OnGetValueAttribute(
- base::OnceCallback<void(const ClientStatus&, const std::string&)>
- callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnClearFieldForSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& clear_status);
- void OnWaitForDocumentToBecomeInteractiveForSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& wait_status);
- void OnScrollIntoViewForSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& scroll_status);
- void OnClickOrTapElementForSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& click_status);
- void SelectFieldValueForReplace(
- const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)> callback);
- void OnSelectFieldValueForReplace(
- const ElementFinder::Result& element,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFieldValueSelectedSetFieldValue(
- const ElementFinder::Result& element,
- const std::vector<UChar32>& codepoints,
- int key_press_delay_in_millisecond,
- base::OnceCallback<void(const ClientStatus&)> callback,
- const ClientStatus& select_status);
void DispatchKeyboardTextDownEvent(
const std::string& node_frame_id,
const std::vector<UChar32>& codepoints,
@@ -438,36 +406,14 @@ class WebController {
size_t index,
int delay_in_milli,
base::OnceCallback<void(const ClientStatus&)> callback);
- void SetValueAttribute(
- const ElementFinder::Result& element,
- const std::string& value,
- base::OnceCallback<void(const ClientStatus&)> callback);
- void OnFindElementForGetOuterHtml(
- base::OnceCallback<void(const ClientStatus&, const std::string&)>
- callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element_result);
- void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&,
- const std::string&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnGetElementTag(base::OnceCallback<void(const ClientStatus&,
- const std::string&)> callback,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFindElementForPosition(
- base::OnceCallback<void(bool, const RectF&)> callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> result);
+ void OnGetElementRect(ElementRectGetter* getter_to_release,
+ ElementRectGetter::ElementRectCallback callback,
+ const ClientStatus& rect_status,
+ const RectF& element_rect);
void OnGetVisualViewport(
- base::OnceCallback<void(bool, const RectF&)> callback,
+ base::OnceCallback<void(const ClientStatus&, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
- void OnGetElementRectResult(
- ElementRectGetter* getter_to_release,
- base::OnceCallback<void(bool, const RectF&)> callback,
- bool has_rect,
- const RectF& element_rect);
// Creates a new instance of DispatchKeyEventParams for the specified type and
// unicode codepoint.
@@ -477,25 +423,13 @@ class WebController {
autofill_assistant::input::DispatchKeyEventType type,
const UChar32 codepoint);
- // Waits for the document.readyState to be 'interactive' or 'complete'.
- void InternalWaitForDocumentToBecomeInteractive(
- int remaining_rounds,
- const std::string& object_id,
- const std::string& node_frame_id,
- base::OnceCallback<void(bool)> callback);
- void OnInternalWaitForDocumentToBecomeInteractive(
- int remaining_rounds,
- const std::string& object_id,
- const std::string& node_frame_id,
- base::OnceCallback<void(bool)> callback,
+ void OnWaitForDocumentReadyState(
+ base::OnceCallback<void(const ClientStatus&,
+ DocumentReadyState,
+ base::TimeDelta)> callback,
+ base::TimeTicks wait_start_time,
const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFindElementForWaitForDocumentReadyState(
- DocumentReadyState min_ready_state,
- base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
- callback,
- const ClientStatus& status,
- std::unique_ptr<ElementFinder::Result> element);
+ std::unique_ptr<runtime::EvaluateResult> result);
// Wrapper for calling the |callback| after re-enabling the keyboard by
// setting the assistant action state to "not running".
@@ -516,7 +450,6 @@ class WebController {
// is guaranteed by the owner of this object.
content::WebContents* web_contents_;
std::unique_ptr<DevtoolsClient> devtools_client_;
- const ClientSettings* const settings_;
// Currently running workers.
std::vector<std::unique_ptr<WebControllerWorker>> pending_workers_;
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index c36ea7b2e81..1f0f2b1c927 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/strings/strcat.h"
-#include "components/autofill_assistant/browser/client_settings.h"
+#include "base/test/bind.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/top_padding.h"
@@ -58,8 +58,8 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ASSERT_TRUE(http_server_->Start(8080));
ASSERT_TRUE(
NavigateToURL(shell(), http_server_->GetURL(kTargetWebsitePath)));
- web_controller_ = WebController::CreateForWebContents(
- shell()->web_contents(), &settings_);
+ web_controller_ =
+ WebController::CreateForWebContents(shell()->web_contents());
Observe(shell()->web_contents());
}
@@ -117,20 +117,22 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ASSERT_EQ(selectors.size(), results.size());
size_t pending_number_of_checks = selectors.size();
for (size_t i = 0; i < selectors.size(); i++) {
- web_controller_->ElementCheck(
+ web_controller_->FindElement(
selectors[i], strict,
- base::BindOnce(&WebControllerBrowserTest::CheckElementVisibleCallback,
+ base::BindOnce(&WebControllerBrowserTest::ElementCheckCallback,
base::Unretained(this), run_loop.QuitClosure(),
selectors[i], &pending_number_of_checks, results[i]));
}
run_loop.Run();
}
- void CheckElementVisibleCallback(base::OnceClosure done_callback,
- const Selector& selector,
- size_t* pending_number_of_checks_output,
- bool expected_result,
- const ClientStatus& result) {
+ void ElementCheckCallback(
+ base::OnceClosure done_callback,
+ const Selector& selector,
+ size_t* pending_number_of_checks_output,
+ bool expected_result,
+ const ClientStatus& result,
+ std::unique_ptr<ElementFinder::Result> ignored_element) {
EXPECT_EQ(expected_result, result.ok())
<< "selector: " << selector << " status: " << result;
*pending_number_of_checks_output -= 1;
@@ -148,6 +150,19 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
std::move(done_callback).Run();
}
+ void ElementRetainingStringCallback(
+ std::unique_ptr<ElementFinder::Result> element,
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ std::string* result,
+ const ClientStatus& status,
+ const std::string& value) {
+ EXPECT_TRUE(element != nullptr);
+ *result_output = status;
+ result->assign(value);
+ std::move(done_callback).Run();
+ }
+
void ClickOrTapElement(const Selector& selector, ClickType click_type) {
base::RunLoop run_loop;
ClientStatus result_output;
@@ -204,7 +219,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
void WaitForElementRemove(const Selector& selector) {
base::RunLoop run_loop;
- web_controller_->ElementCheck(
+ web_controller_->FindElement(
selector, /* strict= */ false,
base::BindOnce(&WebControllerBrowserTest::OnWaitForElementRemove,
base::Unretained(this), run_loop.QuitClosure(),
@@ -212,28 +227,51 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
run_loop.Run();
}
- void OnWaitForElementRemove(base::OnceClosure done_callback,
- const Selector& selector,
- const ClientStatus& result) {
+ void OnWaitForElementRemove(
+ base::OnceClosure done_callback,
+ const Selector& selector,
+ const ClientStatus& result,
+ std::unique_ptr<ElementFinder::Result> ignored_element) {
std::move(done_callback).Run();
if (result.ok()) {
WaitForElementRemove(selector);
}
}
- void FocusElement(const Selector& selector, const TopPadding top_padding) {
+ void ScrollToElementPosition(const Selector& selector,
+ const TopPadding& top_padding) {
base::RunLoop run_loop;
- web_controller_->FocusElement(
- selector, top_padding,
- base::BindOnce(&WebControllerBrowserTest::OnFocusElement,
- base::Unretained(this), run_loop.QuitClosure()));
+ ClientStatus result;
+
+ web_controller_->FindElement(
+ selector, /* strict_mode= */ true,
+ base::BindOnce(
+ &WebControllerBrowserTest::FindScrollToElementPositionCallback,
+ base::Unretained(this), top_padding, run_loop.QuitClosure(),
+ &result));
+
run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, result.proto_status());
}
- void OnFocusElement(base::OnceClosure done_callback,
- const ClientStatus& status) {
- EXPECT_EQ(ACTION_APPLIED, status.proto_status());
- std::move(done_callback).Run();
+ void FindScrollToElementPositionCallback(
+ const TopPadding& top_padding,
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ const ClientStatus& status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!status.ok()) {
+ *result_output = status;
+ std::move(done_callback).Run();
+ return;
+ }
+
+ ASSERT_TRUE(element_result != nullptr);
+ web_controller_->ScrollToElementPosition(
+ *element_result, top_padding,
+ base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output));
}
ClientStatus SelectOption(const Selector& selector,
@@ -285,7 +323,8 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ClientStatus* result_output,
DocumentReadyState* ready_state_out,
const ClientStatus& status,
- DocumentReadyState ready_state) {
+ DocumentReadyState ready_state,
+ base::TimeDelta) {
*result_output = status;
*ready_state_out = ready_state;
std::move(done_callback).Run();
@@ -294,34 +333,106 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ClientStatus HighlightElement(const Selector& selector) {
base::RunLoop run_loop;
ClientStatus result;
- web_controller_->HighlightElement(
- selector, base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
- base::Unretained(this), run_loop.QuitClosure(),
- &result));
+
+ web_controller_->FindElement(
+ selector, /* strict_mode= */ true,
+ base::BindOnce(&WebControllerBrowserTest::FindHighlightElementCallback,
+ base::Unretained(this), run_loop.QuitClosure(),
+ &result));
+
run_loop.Run();
return result;
}
+ void FindHighlightElementCallback(
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ const ClientStatus& status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!status.ok()) {
+ *result_output = status;
+ std::move(done_callback).Run();
+ return;
+ }
+
+ ASSERT_TRUE(element_result != nullptr);
+ web_controller_->HighlightElement(
+ *element_result,
+ base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output));
+ }
+
ClientStatus GetOuterHtml(const Selector& selector,
std::string* html_output) {
base::RunLoop run_loop;
ClientStatus result;
+
+ web_controller_->FindElement(
+ selector, /* strict= */ true,
+ base::BindOnce(
+ &WebControllerBrowserTest::FindGetOuterHtmlElementCallback,
+ base::Unretained(this), run_loop.QuitClosure(), &result,
+ html_output));
+
+ run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, result.proto_status());
+ return result;
+ }
+
+ void FindGetOuterHtmlElementCallback(
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ std::string* html_output,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+ ASSERT_TRUE(element_result != nullptr);
web_controller_->GetOuterHtml(
- selector, base::BindOnce(&WebControllerBrowserTest::OnGetOuterHtml,
+ *element_result,
+ base::BindOnce(
+ &WebControllerBrowserTest::ElementRetainingStringCallback,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output, html_output));
+ }
+
+ ClientStatus GetOuterHtmls(const Selector& selector,
+ std::vector<std::string>* htmls_output) {
+ base::RunLoop run_loop;
+ ClientStatus result;
+
+ web_controller_->FindAllElements(
+ selector, base::BindOnce(&WebControllerBrowserTest::OnFindAllElements,
base::Unretained(this), run_loop.QuitClosure(),
- &result, html_output));
+ &result, htmls_output));
+
run_loop.Run();
return result;
}
- void OnGetOuterHtml(base::OnceClosure done_callback,
- ClientStatus* successful_output,
- std::string* html_output,
- const ClientStatus& status,
- const std::string& html) {
- EXPECT_EQ(ACTION_APPLIED, status.proto_status());
- *successful_output = status;
- *html_output = html;
+ void OnFindAllElements(base::OnceClosure done_callback,
+ ClientStatus* client_status_output,
+ std::vector<std::string>* htmls_output,
+ const ClientStatus& client_status,
+ std::unique_ptr<ElementFinder::Result> elements) {
+ EXPECT_EQ(ACTION_APPLIED, client_status.proto_status());
+ ASSERT_TRUE(elements);
+
+ web_controller_->GetOuterHtmls(
+ *elements, base::BindOnce(&WebControllerBrowserTest::OnGetOuterHtmls,
+ base::Unretained(this), std::move(elements),
+ std::move(done_callback),
+ client_status_output, htmls_output));
+ }
+
+ void OnGetOuterHtmls(std::unique_ptr<ElementFinder::Result> elements,
+ base::OnceClosure done_callback,
+ ClientStatus* client_status_output,
+ std::vector<std::string>* htmls_output,
+ const ClientStatus& client_status,
+ const std::vector<std::string>& htmls) {
+ *client_status_output = client_status;
+ *htmls_output = htmls;
std::move(done_callback).Run();
}
@@ -338,6 +449,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
element_tag_output));
run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, result.proto_status());
return result;
}
@@ -351,23 +463,23 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ASSERT_TRUE(element_result != nullptr);
web_controller_->GetElementTag(
*element_result,
- base::BindOnce(&WebControllerBrowserTest::OnGetElementTag,
- base::Unretained(this), std::move(done_callback),
- result_output, element_tag_output,
- std::move(element_result)));
+ base::BindOnce(
+ &WebControllerBrowserTest::ElementRetainingStringCallback,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output, element_tag_output));
}
- void OnGetElementTag(base::OnceClosure done_callback,
- ClientStatus* successful_output,
- std::string* element_tag_output,
- std::unique_ptr<ElementFinder::Result> element,
- const ClientStatus& status,
- const std::string& element_tag) {
- EXPECT_EQ(ACTION_APPLIED, status.proto_status());
- ASSERT_TRUE(element != nullptr);
- *successful_output = status;
- *element_tag_output = element_tag;
- std::move(done_callback).Run();
+ ClientStatus CheckOnTop(const ElementFinder::Result& element) {
+ ClientStatus captured_status;
+ base::RunLoop run_loop;
+ web_controller_->CheckOnTop(
+ element, base::BindLambdaForTesting(
+ [&captured_status, &run_loop](const ClientStatus& status) {
+ captured_status = status;
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+ return captured_status;
}
void FindElement(const Selector& selector,
@@ -429,28 +541,84 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
EXPECT_FALSE(result.object_id.empty());
}
+ ClientStatus GetStringAttribute(const Selector& selector,
+ const std::vector<std::string>& attributes,
+ std::string* value) {
+ base::RunLoop run_loop;
+ ClientStatus result;
+
+ web_controller_->FindElement(
+ selector, /* strict= */ true,
+ base::BindOnce(
+ &WebControllerBrowserTest::FindGetStringAttributeElementCallback,
+ base::Unretained(this), attributes, run_loop.QuitClosure(), &result,
+ value));
+
+ run_loop.Run();
+ return result;
+ }
+
+ void FindGetStringAttributeElementCallback(
+ const std::vector<std::string>& attributes,
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ std::string* value,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+ ASSERT_TRUE(element_result != nullptr);
+ web_controller_->GetStringAttribute(
+ *element_result, attributes,
+ base::BindOnce(
+ &WebControllerBrowserTest::ElementRetainingStringCallback,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output, value));
+ }
+
void GetFieldsValue(const std::vector<Selector>& selectors,
const std::vector<std::string>& expected_values) {
base::RunLoop run_loop;
ASSERT_EQ(selectors.size(), expected_values.size());
size_t pending_number_of_checks = selectors.size();
for (size_t i = 0; i < selectors.size(); i++) {
- web_controller_->GetFieldValue(
- selectors[i],
- base::BindOnce(&WebControllerBrowserTest::OnGetFieldValue,
- base::Unretained(this), run_loop.QuitClosure(),
- &pending_number_of_checks, expected_values[i]));
+ web_controller_->FindElement(
+ selectors[i], /* strict= */ true,
+ base::BindOnce(
+ &WebControllerBrowserTest::GetFieldValueElementCallback,
+ base::Unretained(this), run_loop.QuitClosure(),
+ &pending_number_of_checks, expected_values[i]));
}
run_loop.Run();
}
- void OnGetFieldValue(base::OnceClosure done_callback,
+ void GetFieldValueElementCallback(
+ base::OnceClosure done_callback,
+ size_t* pending_number_of_checks_output,
+ const std::string& expected_value,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!element_status.ok()) {
+ OnGetFieldValue(nullptr, std::move(done_callback),
+ pending_number_of_checks_output, expected_value,
+ element_status, std::string());
+ return;
+ }
+ web_controller_->GetFieldValue(
+ *element_result,
+ base::BindOnce(&WebControllerBrowserTest::OnGetFieldValue,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback),
+ pending_number_of_checks_output, expected_value));
+ }
+
+ void OnGetFieldValue(std::unique_ptr<ElementFinder::Result> element,
+ base::OnceClosure done_callback,
size_t* pending_number_of_checks_output,
const std::string& expected_value,
const ClientStatus& status,
const std::string& value) {
- // Don't use ASSERT_EQ here: if the check fails, this would result in
- // an endless loop without meaningful test results.
+ // Don't use ASSERT: If the check fails, this would result in an endless
+ // loop without meaningful test results.
EXPECT_EQ(expected_value, value);
*pending_number_of_checks_output -= 1;
if (*pending_number_of_checks_output == 0) {
@@ -488,26 +656,87 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
ASSERT_TRUE(element_result != nullptr);
- web_controller_->SetFieldValue(
- *element_result, value, fill_strategy,
- /* key_press_delay_in_millisecond= */ 0,
- base::BindOnce(&WebControllerBrowserTest::SetFieldValueCallback,
+ PerformSetFieldValue(
+ value, fill_strategy, *element_result,
+ base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback,
base::Unretained(this), std::move(element_result),
std::move(done_callback), result_output));
}
- void SetFieldValueCallback(std::unique_ptr<ElementFinder::Result> element,
- base::OnceClosure done_callback,
- ClientStatus* result_output,
- const ClientStatus& status) {
- EXPECT_TRUE(element != nullptr);
- *result_output = status;
- std::move(done_callback).Run();
+ void PerformSetFieldValue(
+ const std::string& value,
+ KeyboardValueFillStrategy fill_strategy,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ if (value.empty()) {
+ web_controller_->SetValueAttribute(element, value, std::move(callback));
+ return;
+ }
+
+ switch (fill_strategy) {
+ case SET_VALUE:
+ web_controller_->SetValueAttribute(element, value, std::move(callback));
+ return;
+ case SIMULATE_KEY_PRESSES:
+ web_controller_->SetValueAttribute(
+ element, /* value= */ std::string(),
+ base::BindOnce(
+ &WebControllerBrowserTest::OnSetValueAttributeForSetFieldValue,
+ base::Unretained(this), value, false, element,
+ std::move(callback)));
+ return;
+ case SIMULATE_KEY_PRESSES_SELECT_VALUE:
+ web_controller_->SelectFieldValue(
+ element,
+ base::BindOnce(
+ &WebControllerBrowserTest::OnSelectFieldValueForSetFieldValue,
+ base::Unretained(this), value, element, std::move(callback)));
+ return;
+ case SIMULATE_KEY_PRESSES_FOCUS:
+ web_controller_->SetValueAttribute(
+ element, /* value= */ std::string(),
+ base::BindOnce(
+ &WebControllerBrowserTest::OnSetValueAttributeForSetFieldValue,
+ base::Unretained(this), value, true, element,
+ std::move(callback)));
+ return;
+ case UNSPECIFIED_KEYBAORD_STRATEGY:
+ std::move(callback).Run(ClientStatus(INVALID_ACTION));
+ }
+ }
+
+ void OnSetValueAttributeForSetFieldValue(
+ const std::string& value,
+ bool use_js_focus,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status) {
+ if (!status.ok()) {
+ std::move(callback).Run(status);
+ return;
+ }
+ PerformSendKeyboardInput(UTF8ToUnicode(value), /* delay_in_milli= */ 0,
+ use_js_focus, element, std::move(callback));
+ }
+
+ void OnSelectFieldValueForSetFieldValue(
+ const std::string& value,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const ClientStatus& status) {
+ if (!status.ok()) {
+ std::move(callback).Run(status);
+ return;
+ }
+ web_controller_->SendKeyboardInput(element, UTF8ToUnicode(value),
+ /* delay_in_milli= */ 0,
+ std::move(callback));
}
ClientStatus SendKeyboardInput(const Selector& selector,
const std::vector<UChar32>& codepoints,
- int delay_in_milli) {
+ int delay_in_milli,
+ bool use_js_focus) {
base::RunLoop run_loop;
ClientStatus result;
@@ -515,7 +744,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
selector, /* strict_mode= */ true,
base::BindOnce(
&WebControllerBrowserTest::FindSendKeyboardInputElementCallback,
- base::Unretained(this), codepoints, delay_in_milli,
+ base::Unretained(this), codepoints, delay_in_milli, use_js_focus,
run_loop.QuitClosure(), &result));
run_loop.Run();
@@ -524,12 +753,13 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ClientStatus SendKeyboardInput(const Selector& selector,
const std::vector<UChar32>& codepoints) {
- return SendKeyboardInput(selector, codepoints, -1);
+ return SendKeyboardInput(selector, codepoints, -1, false);
}
void FindSendKeyboardInputElementCallback(
const std::vector<UChar32>& codepoints,
int delay_in_milli,
+ bool use_js_focus,
base::OnceClosure done_callback,
ClientStatus* result_output,
const ClientStatus& element_status,
@@ -537,7 +767,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
ASSERT_TRUE(element_result != nullptr);
PerformSendKeyboardInput(
- codepoints, delay_in_milli, *element_result,
+ codepoints, delay_in_milli, use_js_focus, *element_result,
base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback,
base::Unretained(this), std::move(element_result),
std::move(done_callback), result_output));
@@ -546,17 +776,28 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
void PerformSendKeyboardInput(
const std::vector<UChar32>& codepoints,
int delay_in_milli,
+ bool use_js_focus,
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
+ if (use_js_focus) {
+ web_controller_->FocusField(
+ element,
+ base::BindOnce(
+ &WebControllerBrowserTest::OnFieldFocussedForSendKeyboardInput,
+ base::Unretained(this), codepoints, delay_in_milli, element,
+ std::move(callback)));
+ return;
+ }
+
PerformClickOrTap(
ClickType::CLICK, element,
base::BindOnce(
- &WebControllerBrowserTest::OnClickOrTapForSendKeyboardInput,
+ &WebControllerBrowserTest::OnFieldFocussedForSendKeyboardInput,
base::Unretained(this), codepoints, delay_in_milli, element,
std::move(callback)));
}
- void OnClickOrTapForSendKeyboardInput(
+ void OnFieldFocussedForSendKeyboardInput(
const std::vector<UChar32>& codepoints,
int delay_in_milli,
const ElementFinder::Result& element,
@@ -609,30 +850,86 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
std::move(done_callback), result_output));
}
- bool GetElementPosition(const Selector& selector, RectF* rect_output) {
+ ClientStatus GetElementRect(const Selector& selector, RectF* rect_output) {
base::RunLoop run_loop;
- bool result;
- web_controller_->GetElementPosition(
- selector,
- base::BindOnce(&WebControllerBrowserTest::OnGetElementPosition,
+ ClientStatus result;
+
+ web_controller_->FindElement(
+ selector, /* strict= */ true,
+ base::BindOnce(&WebControllerBrowserTest::GetElementRectElementCallback,
base::Unretained(this), run_loop.QuitClosure(), &result,
rect_output));
+
run_loop.Run();
return result;
}
- void OnGetElementPosition(base::OnceClosure done_callback,
- bool* result_output,
- RectF* rect_output,
- bool non_empty,
- const RectF& rect) {
- if (non_empty) {
+ void GetElementRectElementCallback(
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ RectF* rect_output,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result) {
+ if (!element_status.ok()) {
+ *result_output = element_status;
+ std::move(done_callback).Run();
+ return;
+ }
+
+ ASSERT_TRUE(element_result != nullptr);
+ web_controller_->GetElementRect(
+ *element_result,
+ base::BindOnce(&WebControllerBrowserTest::OnGetElementRect,
+ base::Unretained(this), std::move(element_result),
+ std::move(done_callback), result_output, rect_output));
+ }
+
+ void OnGetElementRect(std::unique_ptr<ElementFinder::Result> element,
+ base::OnceClosure done_callback,
+ ClientStatus* result_output,
+ RectF* rect_output,
+ const ClientStatus& rect_status,
+ const RectF& rect) {
+ if (rect_status.ok()) {
*rect_output = rect;
}
- *result_output = non_empty;
+ *result_output = rect_status;
std::move(done_callback).Run();
}
+ // Show the overlay in the main page, which covers everything.
+ void ShowOverlay() {
+ EXPECT_TRUE(ExecJs(shell(),
+ R"(
+document.getElementById("overlay").style.visibility='visible';
+)"));
+ }
+
+ // Show the overlay in the first iframe, which covers the content
+ // of that frame.
+ void ShowOverlayInFrame() {
+ EXPECT_TRUE(ExecJs(shell()->web_contents()->GetAllFrames()[1],
+ R"(
+document.getElementById("overlay_in_frame").style.visibility='visible';
+)"));
+ }
+
+ // Hide the overlay in the main page.
+ void HideOverlay() {
+ EXPECT_TRUE(ExecJs(shell(),
+ R"(
+document.getElementById("overlay").style.visibility='hidden';
+)"));
+ }
+
+ // Hide the overlay in the first iframe.
+ void HideOverlayInFrame() {
+ EXPECT_TRUE(ExecJs(shell()->web_contents()->GetAllFrames()[1],
+ R"(
+document.getElementById("overlay_in_frame").style.visibility='hidden';
+)"));
+ }
+
// Make sure scrolling is necessary for #scroll_container , no matter the
// screen height
void SetupScrollContainerHeights() {
@@ -671,7 +968,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
ScrollContainerTo(initial_window_scroll_y);
TopPadding top_padding{0.25, TopPadding::Unit::RATIO};
- FocusElement(selector, top_padding);
+ ScrollToElementPosition(selector, top_padding);
base::ListValue eval_result = content::EvalJs(shell(), R"(
let item = document.querySelector("#scroll_item_5");
let itemRect = item.getBoundingClientRect();
@@ -687,7 +984,7 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
double container_bottom = eval_result.GetList()[4].GetDouble();
// Element is at the desired position. (top is relative to the viewport)
- EXPECT_NEAR(top, window_height * 0.25, 0.5);
+ EXPECT_NEAR(top, window_height * 0.25, 1);
// Element is within the visible portion of its container.
EXPECT_GT(bottom, container_top);
@@ -705,7 +1002,6 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
protected:
std::unique_ptr<WebController> web_controller_;
- ClientSettings settings_;
private:
std::unique_ptr<net::EmbeddedTestServer> http_server_;
@@ -798,6 +1094,32 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, VisibilityRequirementCheck) {
true);
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, RequireNonemptyBoundingBox) {
+ Selector button = Selector({"#button"});
+ button.proto.add_filters()->mutable_bounding_box()->set_require_nonempty(
+ true);
+ RunLaxElementCheck(button, true);
+
+ Selector hidden = Selector({"#hidden"});
+ RunLaxElementCheck(hidden, true);
+ hidden.proto.add_filters()->mutable_bounding_box()->set_require_nonempty(
+ true);
+ RunLaxElementCheck(hidden, false);
+
+ Selector emptydiv = Selector({"#emptydiv"});
+ RunLaxElementCheck(emptydiv, true);
+ auto* emptydiv_box = emptydiv.proto.add_filters()->mutable_bounding_box();
+ emptydiv_box->set_require_nonempty(true);
+ RunLaxElementCheck(emptydiv, false);
+ emptydiv_box->set_require_nonempty(false);
+ RunLaxElementCheck(emptydiv, true);
+
+ EXPECT_TRUE(content::ExecJs(shell(), R"(
+ document.getElementById("emptydiv").style.height = '100px';
+)"));
+ RunLaxElementCheck(emptydiv, true);
+}
+
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, MultipleVisibleElementCheck) {
// both visible
RunLaxElementCheck(Selector({"#button,#select"}).MustBeVisible(), true);
@@ -919,7 +1241,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenBoundingBox) {
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeThenPickOne) {
Selector selector({"span"});
selector.SetPseudoType(PseudoType::BEFORE);
- selector.proto.add_filters()->mutable_pick_one();
+ selector.proto.add_filters()->mutable_nth_match()->set_index(0);
RunStrictElementCheck(selector, true);
}
@@ -957,6 +1279,41 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, PseudoTypeContent) {
RunLaxElementCheck(selector, false);
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
+ PseudoElementContentWithCssStyle) {
+ Selector selector({"#with_inner_text span"});
+ auto* style = selector.proto.add_filters()->mutable_css_style();
+ style->set_property("content");
+ style->set_pseudo_element("before");
+ style->mutable_value()->set_re2("\"before\"");
+ RunLaxElementCheck(selector, true);
+
+ style->mutable_value()->set_re2("\"nomatch\"");
+ RunLaxElementCheck(selector, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, CssVisibility) {
+ Selector selector({"#button"});
+ auto* style = selector.proto.add_filters()->mutable_css_style();
+ style->set_property("visibility");
+ style->mutable_value()->set_re2("visible");
+
+ EXPECT_TRUE(content::ExecJs(shell(), R"(
+ document.getElementById("button").style.visibility = 'hidden';
+)"));
+ RunLaxElementCheck(selector, false);
+ style->set_should_match(false);
+ RunLaxElementCheck(selector, true);
+
+ EXPECT_TRUE(content::ExecJs(shell(), R"(
+ document.getElementById("button").style.visibility = 'visible';
+)"));
+ style->set_should_match(true);
+ RunLaxElementCheck(selector, true);
+ style->set_should_match(false);
+ RunLaxElementCheck(selector, false);
+}
+
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, InnerTextThenCss) {
// There are two divs containing "Section with text", but only one has a
// button, which removes #button.
@@ -1017,6 +1374,28 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindFormInputByLabel) {
EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, MatchCssSelectorFilter) {
+ Selector selector({"label"});
+ selector.MatchingInnerText("terms and conditions");
+ selector.proto.add_filters()->mutable_labelled();
+
+ RunStrictElementCheck(selector, true);
+
+ auto* last_filter = selector.proto.add_filters();
+
+ last_filter->set_match_css_selector("input[type='checkbox']");
+ RunStrictElementCheck(selector, true);
+
+ last_filter->set_match_css_selector("input[type='text']");
+ RunStrictElementCheck(selector, false);
+
+ last_filter->set_match_css_selector(":checked");
+ RunStrictElementCheck(selector, false);
+
+ last_filter->set_match_css_selector(":not(:checked)");
+ RunStrictElementCheck(selector, true);
+}
+
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ValueCondition) {
// One match
RunLaxElementCheck(Selector({"#input1"}).MatchingValue("helloworld1"), true);
@@ -1296,7 +1675,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindElementErrorStatus) {
EXPECT_EQ(TOO_MANY_ELEMENTS, status.proto_status());
}
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusElement) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ScrollToElementPosition) {
Selector selector({"#iframe", "#focus"});
const std::string checkVisibleScript = R"(
@@ -1308,24 +1687,24 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusElement) {
)";
EXPECT_EQ(false, content::EvalJs(shell(), checkVisibleScript));
TopPadding top_padding;
- FocusElement(selector, top_padding);
+ ScrollToElementPosition(selector, top_padding);
EXPECT_EQ(true, content::EvalJs(shell(), checkVisibleScript));
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
- FocusElementWithScrollIntoViewNeeded) {
+ ScrollToElementPosition_WithScrollIntoViewNeeded) {
TestScrollIntoView(/* initial_window_scroll_y= */ 0,
/* initial_container_scroll_y=*/0);
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
- FocusElementWithScrollIntoViewNotNeeded) {
+ ScrollToElementPosition_WithScrollIntoViewNotNeeded) {
TestScrollIntoView(/* initial_window_scroll_y= */ 0,
/* initial_container_scroll_y=*/200);
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
- FocusElement_WithPaddingInPixels) {
+ ScrollToElementPosition_WithPaddingInPixels) {
Selector selector({"#scroll-me"});
const std::string checkScrollDifferentThanTargetScript = R"(
@@ -1340,7 +1719,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
// Scroll 360px from the top.
TopPadding top_padding{/* value= */ 360, TopPadding::Unit::PIXELS};
- FocusElement(selector, top_padding);
+ ScrollToElementPosition(selector, top_padding);
double eval_result = content::EvalJs(shell(), R"(
let scrollTarget = document.querySelector("#scroll-me");
@@ -1353,7 +1732,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
- FocusElement_WithPaddingInRatio) {
+ ScrollToElementPosition_WithPaddingInRatio) {
Selector selector({"#scroll-me"});
const std::string checkScrollDifferentThanTargetScript = R"(
@@ -1369,7 +1748,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
// Scroll 70% from the top.
TopPadding top_padding{/* value= */ 0.7, TopPadding::Unit::RATIO};
- FocusElement(selector, top_padding);
+ ScrollToElementPosition(selector, top_padding);
base::ListValue eval_result = content::EvalJs(shell(), R"(
let scrollTarget = document.querySelector("#scroll-me");
@@ -1465,6 +1844,18 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetOuterHtml) {
EXPECT_EQ(R"(<div id="divToRemove">Text</div>)", html);
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetOuterHtmls) {
+ std::vector<std::string> htmls;
+
+ Selector div_selector({".label"});
+ ASSERT_EQ(ACTION_APPLIED, GetOuterHtmls(div_selector, &htmls).proto_status());
+
+ EXPECT_THAT(htmls,
+ testing::ElementsAre(R"(<div class="label">Label 1</div>)",
+ R"(<div class="label">Label 2</div>)",
+ R"(<div class="label">Label 3</div>)"));
+}
+
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementTag) {
std::string element_tag;
@@ -1524,9 +1915,9 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetFieldValue) {
expected_values.clear();
expected_values.emplace_back("helloworld2");
GetFieldsValue(selectors, expected_values);
- EXPECT_EQ(ACTION_APPLIED,
- SetFieldValue(a_selector, /* value= */ "", SIMULATE_KEY_PRESSES)
- .proto_status());
+ EXPECT_EQ(
+ ACTION_APPLIED,
+ SetFieldValue(a_selector, /* value= */ "", SET_VALUE).proto_status());
expected_values.clear();
expected_values.emplace_back("");
GetFieldsValue(selectors, expected_values);
@@ -1537,11 +1928,37 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetFieldValue) {
expected_values.clear();
expected_values.emplace_back("helloworld3");
GetFieldsValue(selectors, expected_values);
- EXPECT_EQ(ACTION_APPLIED, SetFieldValue(a_selector, /* value= */ "",
+ EXPECT_EQ(ACTION_APPLIED,
+ SetFieldValue(a_selector, "new value", SIMULATE_KEY_PRESSES)
+ .proto_status());
+ expected_values.clear();
+ expected_values.emplace_back("new value");
+ GetFieldsValue(selectors, expected_values);
+
+ selectors.clear();
+ a_selector = Selector({"#input4"});
+ selectors.emplace_back(a_selector);
+ expected_values.clear();
+ expected_values.emplace_back("helloworld4");
+ GetFieldsValue(selectors, expected_values);
+ EXPECT_EQ(ACTION_APPLIED, SetFieldValue(a_selector, "new value",
SIMULATE_KEY_PRESSES_SELECT_VALUE)
.proto_status());
expected_values.clear();
- expected_values.emplace_back("");
+ expected_values.emplace_back("new value");
+ GetFieldsValue(selectors, expected_values);
+
+ selectors.clear();
+ a_selector = Selector({"#input5"});
+ selectors.emplace_back(a_selector);
+ expected_values.clear();
+ expected_values.emplace_back("helloworld5");
+ GetFieldsValue(selectors, expected_values);
+ EXPECT_EQ(ACTION_APPLIED,
+ SetFieldValue(a_selector, "new value", SIMULATE_KEY_PRESSES_FOCUS)
+ .proto_status());
+ expected_values.clear();
+ expected_values.emplace_back("new value");
GetFieldsValue(selectors, expected_values);
selectors.clear();
@@ -1550,7 +1967,6 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetFieldValue) {
expected_values.clear();
expected_values.emplace_back("");
GetFieldsValue(selectors, expected_values);
-
EXPECT_EQ(ELEMENT_RESOLUTION_FAILED,
SetFieldValue(a_selector, "foobar", SET_VALUE).proto_status());
}
@@ -1578,7 +1994,13 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, SendKeyboardInput) {
selectors.emplace_back(a_selector);
EXPECT_EQ(ACTION_APPLIED,
SendKeyboardInput(a_selector, input).proto_status());
- GetFieldsValue(selectors, {expected_output});
+ Selector b_selector({"#input7"});
+ selectors.emplace_back(b_selector);
+ EXPECT_EQ(ACTION_APPLIED,
+ SendKeyboardInput(b_selector, input, /* delay_in_milli= */ -1,
+ /* use_js_focus= */ true)
+ .proto_status());
+ GetFieldsValue(selectors, {expected_output, expected_output});
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
@@ -1607,7 +2029,8 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
Selector a_selector({"#input_js_event_with_timeout"});
selectors.emplace_back(a_selector);
EXPECT_EQ(ACTION_APPLIED,
- SendKeyboardInput(a_selector, input, /*delay_in_milli*/ 100)
+ SendKeyboardInput(a_selector, input, /* delay_in_milli= */ 100,
+ /* use_js_focus= */ false)
.proto_status());
GetFieldsValue(selectors, {expected_output});
}
@@ -1696,7 +2119,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
DocumentReadyState end_state;
base::RunLoop run_loop;
web_controller_->WaitForDocumentReadyState(
- Selector(), DOCUMENT_INTERACTIVE,
+ ElementFinder::Result(), DOCUMENT_INTERACTIVE,
base::BindOnce(&WebControllerBrowserTest::OnClientStatusAndReadyState,
base::Unretained(this), run_loop.QuitClosure(), &status,
&end_state));
@@ -1712,7 +2135,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
DocumentReadyState end_state;
base::RunLoop run_loop;
web_controller_->WaitForDocumentReadyState(
- Selector(), DOCUMENT_COMPLETE,
+ ElementFinder::Result(), DOCUMENT_COMPLETE,
base::BindOnce(&WebControllerBrowserTest::OnClientStatusAndReadyState,
base::Unretained(this), run_loop.QuitClosure(), &status,
&end_state));
@@ -1723,39 +2146,69 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
- WaitFrameDocumentReadyStateLoaded) {
+ WaitFrameDocumentReadyStateComplete) {
ClientStatus status;
+
+ ElementFinder::Result iframe_element;
+ FindElement(Selector({"#iframe"}), &status, &iframe_element);
+ ASSERT_EQ(ACTION_APPLIED, status.proto_status());
+
DocumentReadyState end_state;
base::RunLoop run_loop;
web_controller_->WaitForDocumentReadyState(
- Selector({"#iframe"}), DOCUMENT_LOADED,
+ iframe_element, DOCUMENT_COMPLETE,
base::BindOnce(&WebControllerBrowserTest::OnClientStatusAndReadyState,
base::Unretained(this), run_loop.QuitClosure(), &status,
&end_state));
run_loop.Run();
EXPECT_EQ(ACTION_APPLIED, status.proto_status()) << "Status: " << status;
- EXPECT_THAT(end_state,
- AnyOf(DOCUMENT_LOADED, DOCUMENT_INTERACTIVE, DOCUMENT_COMPLETE));
+ EXPECT_THAT(end_state, DOCUMENT_COMPLETE);
}
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementPosition) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
+ WaitExternalFrameDocumentReadyStateComplete) {
+ ClientStatus status;
+
+ ElementFinder::Result iframe_element;
+ FindElement(Selector({"#iframeExternal"}), &status, &iframe_element);
+ ASSERT_EQ(ACTION_APPLIED, status.proto_status());
+
+ DocumentReadyState end_state;
+ base::RunLoop run_loop;
+ web_controller_->WaitForDocumentReadyState(
+ iframe_element, DOCUMENT_COMPLETE,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatusAndReadyState,
+ base::Unretained(this), run_loop.QuitClosure(), &status,
+ &end_state));
+ run_loop.Run();
+
+ EXPECT_EQ(ACTION_APPLIED, status.proto_status()) << "Status: " << status;
+ EXPECT_THAT(end_state, DOCUMENT_COMPLETE);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementRect) {
RectF document_element_rect;
Selector document_element({"#full_height_section"});
- EXPECT_TRUE(GetElementPosition(document_element, &document_element_rect));
+ EXPECT_EQ(
+ ACTION_APPLIED,
+ GetElementRect(document_element, &document_element_rect).proto_status());
// The iFrame must be after the #full_height_section element to check that
// the resulting rect is global.
RectF iframe_element_rect;
Selector iframe_element({"#iframe", "#touch_area_1"});
- EXPECT_TRUE(GetElementPosition(iframe_element, &iframe_element_rect));
+ EXPECT_EQ(
+ ACTION_APPLIED,
+ GetElementRect(iframe_element, &iframe_element_rect).proto_status());
EXPECT_GT(iframe_element_rect.top, document_element_rect.bottom);
// Make sure the element is within the iframe.
RectF iframe_rect;
Selector iframe({"#iframe"});
- EXPECT_TRUE(GetElementPosition(iframe, &iframe_rect));
+ EXPECT_EQ(ACTION_APPLIED,
+ GetElementRect(iframe, &iframe_rect).proto_status());
EXPECT_GT(iframe_element_rect.left, iframe_rect.left);
EXPECT_LT(iframe_element_rect.right, iframe_rect.right);
@@ -1969,7 +2422,7 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
Selector selector({"input"});
auto* closest = selector.proto.add_filters()->mutable_closest();
closest->add_target()->set_css_selector("#iframe");
- closest->add_target()->mutable_pick_one();
+ closest->add_target()->mutable_nth_match()->set_index(0);
closest->add_target()->mutable_enter_frame();
closest->add_target()->set_css_selector("div");
@@ -1992,4 +2445,204 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
GetFieldsValue({selector}, {"email@example.com"});
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetStringAttribute) {
+ std::string value;
+
+ std::vector<std::string> inner_text_attribute = {"innerText"};
+ ASSERT_EQ(ACTION_APPLIED, GetStringAttribute(Selector({"#testOuterHtml p"}),
+ inner_text_attribute, &value)
+ .proto_status());
+ EXPECT_EQ("Paragraph", value);
+
+ std::vector<std::string> option_label_attribute = {"options", "2", "label"};
+ ASSERT_EQ(ACTION_APPLIED, GetStringAttribute(Selector({"#select"}),
+ option_label_attribute, &value)
+ .proto_status());
+ EXPECT_EQ("Three", value);
+
+ std::vector<std::string> bad_access = {"none", "none"};
+ ASSERT_EQ(UNEXPECTED_JS_ERROR,
+ GetStringAttribute(Selector({"#button"}), bad_access, &value)
+ .proto_status());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, OnTop) {
+ Selector button({"#button"});
+ RunLaxElementCheck(button, true);
+
+ button.proto.add_filters()->mutable_on_top();
+ RunLaxElementCheck(button, true);
+
+ ShowOverlay();
+ RunLaxElementCheck(button, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, OnTopNeedsScrolling) {
+ // Scroll button out of the viewport.
+ double target_bottom = content::EvalJs(shell(),
+ R"(
+const target = document.getElementById("touch_area_one");
+const box = target.getBoundingClientRect();
+window.scrollBy(0, box.bottom + 10);
+target.getBoundingClientRect().bottom
+)")
+ .ExtractDouble();
+
+ // Before running the test, verify that the target is outside of the viewport,
+ // as we wanted. full_height_section guarantees that this is never a problem.
+ ASSERT_LE(target_bottom, 0);
+
+ Selector target({"#touch_area_one"});
+ RunLaxElementCheck(target, true);
+
+ auto* on_top = target.proto.add_filters()->mutable_on_top();
+
+ // Apply on_top without scrolling.
+ on_top->set_scroll_into_view_if_needed(false);
+ RunLaxElementCheck(target, false);
+ on_top->set_accept_element_if_not_in_view(true);
+ RunLaxElementCheck(target, true);
+
+ // Allow on_top to scroll.
+ on_top->set_scroll_into_view_if_needed(true);
+ on_top->set_accept_element_if_not_in_view(false);
+ RunLaxElementCheck(target, true);
+
+ ASSERT_GE(content::EvalJs(shell(),
+ R"(
+document.getElementById("touch_area_one").getBoundingClientRect().bottom
+)")
+ .ExtractDouble(),
+ 0);
+
+ ShowOverlay();
+ RunLaxElementCheck(target, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ALabelIsNotAnOverlay) {
+ Selector input({"#input1"});
+ RunLaxElementCheck(input, true);
+
+ input.proto.add_filters()->mutable_on_top();
+ RunLaxElementCheck(input, true);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, OnTopFindsOverlayInFrame) {
+ Selector button;
+ button.proto.add_filters()->set_css_selector("#iframe");
+ button.proto.add_filters()->mutable_enter_frame();
+ button.proto.add_filters()->set_css_selector("button");
+ button.proto.add_filters()->mutable_on_top();
+ RunLaxElementCheck(button, true);
+
+ ShowOverlayInFrame();
+ RunLaxElementCheck(button, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, OnTopFindsOverlayOverFrame) {
+ Selector button;
+ button.proto.add_filters()->set_css_selector("#iframe");
+ button.proto.add_filters()->mutable_on_top();
+ button.proto.add_filters()->mutable_enter_frame();
+ button.proto.add_filters()->set_css_selector("button");
+ RunLaxElementCheck(button, true);
+
+ ShowOverlay();
+ RunLaxElementCheck(button, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, OnTopFindsElementInShadow) {
+ Selector button;
+ button.proto.add_filters()->set_css_selector("#iframe");
+ button.proto.add_filters()->mutable_enter_frame();
+ button.proto.add_filters()->set_css_selector("#shadowsection");
+ button.proto.add_filters()->mutable_enter_frame();
+ button.proto.add_filters()->set_css_selector("#shadowbutton");
+ RunLaxElementCheck(button, true);
+ button.proto.add_filters()->mutable_on_top();
+ RunLaxElementCheck(button, true);
+
+ ShowOverlayInFrame();
+ RunLaxElementCheck(button, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, CheckOnTop) {
+ ClientStatus status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#button"}), &status, &element);
+ ASSERT_TRUE(status.ok());
+
+ // Make sure the button is visible.
+ EXPECT_TRUE(ExecJs(
+ shell(), "document.getElementById('button').scrollIntoViewIfNeeded();"));
+
+ // The button is the topmost element.
+ status = CheckOnTop(element);
+ EXPECT_EQ(ACTION_APPLIED, status.proto_status());
+ EXPECT_EQ(WebControllerErrorInfoProto::UNSPECIFIED_WEB_ACTION,
+ status.details().web_controller_error_info().failed_web_action());
+
+ // The button is not the topmost element.
+ ShowOverlay();
+ status = CheckOnTop(element);
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, status.proto_status());
+ EXPECT_EQ(WebControllerErrorInfoProto::ON_TOP,
+ status.details().web_controller_error_info().failed_web_action());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, CheckOnTopInFrame) {
+ ClientStatus status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#iframe", "#button"}), &status, &element);
+ ASSERT_TRUE(status.ok());
+
+ // Make sure the button is visible.
+ EXPECT_TRUE(
+ ExecJs(shell()->web_contents()->GetAllFrames()[1],
+ "document.getElementById('button').scrollIntoViewIfNeeded();"));
+
+ // The button is covered by an overlay in the main frame
+ ShowOverlay();
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, CheckOnTop(element).proto_status());
+
+ // The button is covered by an overlay in the iframe
+ HideOverlay();
+ ShowOverlayInFrame();
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, CheckOnTop(element).proto_status());
+
+ // The button is not covered by any overlay
+ HideOverlayInFrame();
+ EXPECT_EQ(ACTION_APPLIED, CheckOnTop(element).proto_status());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, NthMatch) {
+ Selector selector;
+ selector.proto.add_filters()->set_css_selector(".nth_match_parent");
+ selector.proto.add_filters()->mutable_nth_match()->set_index(1);
+ selector.proto.add_filters()->set_css_selector(".nth_match_child");
+
+ auto* pick_at_filter = selector.proto.add_filters();
+ std::string element_tag;
+
+ pick_at_filter->mutable_nth_match()->set_index(0);
+ ASSERT_EQ(ACTION_APPLIED,
+ GetElementTag(selector, &element_tag).proto_status());
+ EXPECT_EQ("P", element_tag);
+
+ pick_at_filter->mutable_nth_match()->set_index(1);
+ ASSERT_EQ(ACTION_APPLIED,
+ GetElementTag(selector, &element_tag).proto_status());
+ EXPECT_EQ("UL", element_tag);
+
+ pick_at_filter->mutable_nth_match()->set_index(2);
+ ASSERT_EQ(ACTION_APPLIED,
+ GetElementTag(selector, &element_tag).proto_status());
+ EXPECT_EQ("LI", element_tag);
+
+ pick_at_filter->mutable_nth_match()->set_index(3);
+ ASSERT_EQ(ACTION_APPLIED,
+ GetElementTag(selector, &element_tag).proto_status());
+ EXPECT_EQ("STRONG", element_tag);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller_util.cc b/chromium/components/autofill_assistant/browser/web/web_controller_util.cc
index aadf965ec4e..d25d6284abc 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller_util.cc
+++ b/chromium/components/autofill_assistant/browser/web/web_controller_util.cc
@@ -5,6 +5,7 @@
#include "components/autofill_assistant/browser/web/web_controller_util.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/service.pb.h"
namespace autofill_assistant {
@@ -56,6 +57,14 @@ ClientStatus FillAutofillErrorStatus(ClientStatus status) {
return status;
}
+void FillWebControllerErrorInfo(
+ WebControllerErrorInfoProto::WebAction failed_web_action,
+ ClientStatus* status) {
+ status->mutable_details()
+ ->mutable_web_controller_error_info()
+ ->set_failed_web_action(failed_web_action);
+}
+
bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) {
if (result && result->HasObjectId()) {
*out = result->GetObjectId();
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller_util.h b/chromium/components/autofill_assistant/browser/web/web_controller_util.h
index dda9a43b6d9..c81437bfd23 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller_util.h
+++ b/chromium/components/autofill_assistant/browser/web/web_controller_util.h
@@ -10,6 +10,7 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/service.pb.h"
namespace autofill_assistant {
@@ -57,6 +58,11 @@ ClientStatus CheckJavaScriptResult(
// Fills a ClientStatus with appropriate details for a Chrome Autofill error.
ClientStatus FillAutofillErrorStatus(ClientStatus status);
+// Fills a ClientStatus with appropriate details from the
+void FillWebControllerErrorInfo(
+ WebControllerErrorInfoProto::WebAction failed_web_action,
+ ClientStatus* status);
+
// Safely gets an object id from a RemoteObject
bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out);
diff --git a/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc b/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
index d3d1ff871eb..682553b9151 100644
--- a/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
+++ b/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
@@ -24,10 +24,10 @@ namespace {
// Creates a |PasswordForm| with minimal initialization (origin, username,
// password).
-autofill::PasswordForm CreatePasswordForm(
+password_manager::PasswordForm CreatePasswordForm(
const WebsiteLoginManager::Login& login,
const std::string& password) {
- autofill::PasswordForm form;
+ password_manager::PasswordForm form;
form.url = login.origin.GetOrigin();
form.signon_realm = password_manager::GetSignonRealm(form.url);
form.username_value = base::UTF8ToUTF16(login.username);
@@ -141,7 +141,7 @@ class WebsiteLoginManagerImpl::PendingFetchPasswordRequest
protected:
// From PendingRequest:
void OnFetchCompleted() override {
- std::vector<const autofill::PasswordForm*> matches =
+ std::vector<const password_manager::PasswordForm*> matches =
form_fetcher_->GetNonFederatedMatches();
for (const auto* match : matches) {
if (base::UTF16ToUTF8(match->username_value) == login_.username) {
@@ -184,8 +184,8 @@ class WebsiteLoginManagerImpl::UpdatePasswordRequest
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest(
- autofill::PasswordForm::Scheme::kHtml, password_form_.signon_realm,
- password_form_.url);
+ password_manager::PasswordForm::Scheme::kHtml,
+ password_form_.signon_realm, password_form_.url);
form_fetcher_ = std::make_unique<password_manager::FormFetcherImpl>(
digest, client, true);
}
@@ -217,7 +217,7 @@ class WebsiteLoginManagerImpl::UpdatePasswordRequest
}
private:
- const autofill::PasswordForm password_form_;
+ const password_manager::PasswordForm password_form_;
const autofill::FormData form_data_;
password_manager::PasswordManagerClient* const client_ = nullptr;
// This callback will execute when presaving is completed.
@@ -242,7 +242,8 @@ void WebsiteLoginManagerImpl::GetLoginsForUrl(
base::OnceCallback<void(std::vector<Login>)> callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest(
- autofill::PasswordForm::Scheme::kHtml, url.GetOrigin().spec(), GURL());
+ password_manager::PasswordForm::Scheme::kHtml, url.GetOrigin().spec(),
+ GURL());
pending_requests_.emplace_back(std::make_unique<PendingFetchLoginsRequest>(
digest, client_, std::move(callback),
base::BindOnce(&WebsiteLoginManagerImpl::OnRequestFinished,
@@ -255,7 +256,8 @@ void WebsiteLoginManagerImpl::GetPasswordForLogin(
base::OnceCallback<void(bool, std::string)> callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest(
- autofill::PasswordForm::Scheme::kHtml, login.origin.spec(), GURL());
+ password_manager::PasswordForm::Scheme::kHtml, login.origin.spec(),
+ GURL());
pending_requests_.emplace_back(std::make_unique<PendingFetchPasswordRequest>(
digest, client_, login, std::move(callback),
base::BindOnce(&WebsiteLoginManagerImpl::OnRequestFinished,
diff --git a/chromium/components/autofill_assistant/browser/website_login_manager_impl.h b/chromium/components/autofill_assistant/browser/website_login_manager_impl.h
index a365d981baf..b8656e29414 100644
--- a/chromium/components/autofill_assistant/browser/website_login_manager_impl.h
+++ b/chromium/components/autofill_assistant/browser/website_login_manager_impl.h
@@ -7,7 +7,6 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill_assistant/browser/website_login_manager.h"
#include "content/public/browser/web_contents.h"
diff --git a/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc b/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
index c6438d9d264..3e73e11ccc4 100644
--- a/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
@@ -20,8 +20,8 @@
using autofill::FormData;
using autofill::FormFieldData;
-using autofill::PasswordForm;
using base::ASCIIToUTF16;
+using password_manager::PasswordForm;
using testing::_;
using testing::Invoke;
using testing::Mock;
@@ -163,7 +163,7 @@ TEST_F(WebsiteLoginManagerImplTest, SaveGeneratedPassword) {
})));
password_manager::PasswordStore::FormDigest form_digest(
- autofill::PasswordForm::Scheme::kHtml, kFakeUrl, GURL(kFakeUrl));
+ password_manager::PasswordForm::Scheme::kHtml, kFakeUrl, GURL(kFakeUrl));
// Presave generated password. Form with empty username is presaved.
EXPECT_CALL(*store(), GetLogins(form_digest, _));
EXPECT_CALL(*store(),
diff --git a/chromium/components/autofill_assistant_strings.grdp b/chromium/components/autofill_assistant_strings.grdp
index e34248cd0dd..264972ede12 100644
--- a/chromium/components/autofill_assistant_strings.grdp
+++ b/chromium/components/autofill_assistant_strings.grdp
@@ -27,5 +27,8 @@
<message name="IDS_AUTOFILL_ASSISTANT_STOPPED" desc="Text label that is shown when stopping the Autofill Assistant.">
Google Assistant in Chrome stopping
</message>
+ <message name="IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK" desc="Option shown in the menu when clicking the Autofill Assistant profile icon. Clicking this option will open a feedback sharing dialog.">
+ Send feedback
+ </message>
</if>
</grit-part>
diff --git a/chromium/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK.png.sha1 b/chromium/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK.png.sha1
new file mode 100644
index 00000000000..83f7afa6944
--- /dev/null
+++ b/chromium/components/autofill_assistant_strings_grdp/IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK.png.sha1
@@ -0,0 +1 @@
+65dfd26a9666766181fca7942b31e3c40d42b675 \ No newline at end of file
diff --git a/chromium/components/autofill_assistant_strings_grdp/OWNERS b/chromium/components/autofill_assistant_strings_grdp/OWNERS
new file mode 100644
index 00000000000..ed6d5f01bfd
--- /dev/null
+++ b/chromium/components/autofill_assistant_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/autofill_assistant/OWNERS
diff --git a/chromium/components/background_sync/BUILD.gn b/chromium/components/background_sync/BUILD.gn
index 30728a5f241..6a3f3309848 100644
--- a/chromium/components/background_sync/BUILD.gn
+++ b/chromium/components/background_sync/BUILD.gn
@@ -4,6 +4,11 @@
static_library("background_sync") {
sources = [
+ "background_sync_controller_impl.cc",
+ "background_sync_controller_impl.h",
+ "background_sync_delegate.h",
+ "background_sync_metrics.cc",
+ "background_sync_metrics.h",
"background_sync_permission_context.cc",
"background_sync_permission_context.h",
]
@@ -12,8 +17,14 @@ static_library("background_sync") {
"//components/content_settings/core/browser",
"//components/content_settings/core/common",
"//components/permissions",
+ "//components/variations",
+ "//content/public/browser",
+ "//services/metrics/public/cpp:ukm_builders",
"//third_party/blink/public/common:headers",
]
+ if (!is_android) {
+ deps += [ "//components/keep_alive_registry" ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/background_sync/DEPS b/chromium/components/background_sync/DEPS
index d703f09535f..189c93cd0ed 100644
--- a/chromium/components/background_sync/DEPS
+++ b/chromium/components/background_sync/DEPS
@@ -1,7 +1,11 @@
include_rules = [
"+components/content_settings/core",
+ "+components/keep_alive_registry",
+ "+components/keyed_service/core",
+ "+components/variations",
"+components/permissions",
"+content/public/browser",
"+content/public/test",
- "+third_party/blink/public/mojom",
+ "+services/metrics/public",
+ "+third_party/blink/public",
]
diff --git a/chromium/components/background_sync/background_sync_controller_impl.cc b/chromium/components/background_sync/background_sync_controller_impl.cc
new file mode 100644
index 00000000000..040a8b6db3d
--- /dev/null
+++ b/chromium/components/background_sync/background_sync_controller_impl.cc
@@ -0,0 +1,414 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/background_sync/background_sync_controller_impl.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/keep_alive_registry/keep_alive_registry.h"
+#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/background_sync_context.h"
+#include "content/public/browser/background_sync_controller.h"
+#include "content/public/browser/background_sync_parameters.h"
+#include "content/public/browser/background_sync_registration.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/storage_partition.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+// static
+const char BackgroundSyncControllerImpl::kFieldTrialName[] = "BackgroundSync";
+const char BackgroundSyncControllerImpl::kDisabledParameterName[] = "disabled";
+#if defined(OS_ANDROID)
+const char BackgroundSyncControllerImpl::kRelyOnAndroidNetworkDetection[] =
+ "rely_on_android_network_detection";
+#endif
+const char BackgroundSyncControllerImpl::kKeepBrowserAwakeParameterName[] =
+ "keep_browser_awake_till_events_complete";
+const char BackgroundSyncControllerImpl::kSkipPermissionsCheckParameterName[] =
+ "skip_permissions_check_for_testing";
+const char BackgroundSyncControllerImpl::kMaxAttemptsParameterName[] =
+ "max_sync_attempts";
+const char BackgroundSyncControllerImpl::
+ kMaxAttemptsWithNotificationPermissionParameterName[] =
+ "max_sync_attempts_with_notification_permission";
+const char BackgroundSyncControllerImpl::kInitialRetryParameterName[] =
+ "initial_retry_delay_sec";
+const char BackgroundSyncControllerImpl::kRetryDelayFactorParameterName[] =
+ "retry_delay_factor";
+const char BackgroundSyncControllerImpl::kMinSyncRecoveryTimeName[] =
+ "min_recovery_time_sec";
+const char BackgroundSyncControllerImpl::kMaxSyncEventDurationName[] =
+ "max_sync_event_duration_sec";
+const char BackgroundSyncControllerImpl::kMinPeriodicSyncEventsInterval[] =
+ "min_periodic_sync_events_interval_sec";
+
+BackgroundSyncControllerImpl::BackgroundSyncControllerImpl(
+ content::BrowserContext* browser_context,
+ std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate)
+ : browser_context_(browser_context), delegate_(std::move(delegate)) {
+ DCHECK(browser_context_);
+ DCHECK(delegate_);
+
+ background_sync_metrics_ =
+ std::make_unique<BackgroundSyncMetrics>(delegate_.get());
+ delegate_->GetHostContentSettingsMap()->AddObserver(this);
+}
+
+BackgroundSyncControllerImpl::~BackgroundSyncControllerImpl() = default;
+
+void BackgroundSyncControllerImpl::OnContentSettingChanged(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (content_type != ContentSettingsType::BACKGROUND_SYNC &&
+ content_type != ContentSettingsType::PERIODIC_BACKGROUND_SYNC) {
+ return;
+ }
+
+ std::vector<url::Origin> affected_origins;
+ for (const auto& origin : periodic_sync_origins_) {
+ if (!IsContentSettingBlocked(origin))
+ continue;
+
+ auto* storage_partition =
+ content::BrowserContext::GetStoragePartitionForSite(
+ browser_context_, origin.GetURL(), /* can_create= */ false);
+ if (!storage_partition)
+ continue;
+
+ auto* background_sync_context =
+ storage_partition->GetBackgroundSyncContext();
+ if (!background_sync_context)
+ continue;
+
+ background_sync_context->UnregisterPeriodicSyncForOrigin(origin);
+ affected_origins.push_back(origin);
+ }
+
+ // Stop tracking affected origins.
+ for (const auto& origin : affected_origins) {
+ periodic_sync_origins_.erase(origin);
+ }
+}
+
+void BackgroundSyncControllerImpl::GetParameterOverrides(
+ content::BackgroundSyncParameters* parameters) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+#if defined(OS_ANDROID)
+ if (delegate_->ShouldDisableBackgroundSync())
+ parameters->disable = true;
+#endif
+
+ std::map<std::string, std::string> field_params;
+ if (!variations::GetVariationParams(kFieldTrialName, &field_params))
+ return;
+
+ if (base::LowerCaseEqualsASCII(field_params[kDisabledParameterName],
+ "true")) {
+ parameters->disable = true;
+ }
+
+ if (base::LowerCaseEqualsASCII(field_params[kKeepBrowserAwakeParameterName],
+ "true")) {
+ parameters->keep_browser_awake_till_events_complete = true;
+ }
+
+ if (base::LowerCaseEqualsASCII(
+ field_params[kSkipPermissionsCheckParameterName], "true")) {
+ parameters->skip_permissions_check_for_testing = true;
+ }
+
+ if (base::Contains(field_params,
+ kMaxAttemptsWithNotificationPermissionParameterName)) {
+ int max_attempts;
+ if (base::StringToInt(
+ field_params[kMaxAttemptsWithNotificationPermissionParameterName],
+ &max_attempts)) {
+ parameters->max_sync_attempts_with_notification_permission = max_attempts;
+ }
+ }
+
+ if (base::Contains(field_params, kMaxAttemptsParameterName)) {
+ int max_attempts;
+ if (base::StringToInt(field_params[kMaxAttemptsParameterName],
+ &max_attempts)) {
+ parameters->max_sync_attempts = max_attempts;
+ }
+ }
+
+ if (base::Contains(field_params, kInitialRetryParameterName)) {
+ int initial_retry_delay_sec;
+ if (base::StringToInt(field_params[kInitialRetryParameterName],
+ &initial_retry_delay_sec)) {
+ parameters->initial_retry_delay =
+ base::TimeDelta::FromSeconds(initial_retry_delay_sec);
+ }
+ }
+
+ if (base::Contains(field_params, kRetryDelayFactorParameterName)) {
+ int retry_delay_factor;
+ if (base::StringToInt(field_params[kRetryDelayFactorParameterName],
+ &retry_delay_factor)) {
+ parameters->retry_delay_factor = retry_delay_factor;
+ }
+ }
+
+ if (base::Contains(field_params, kMinSyncRecoveryTimeName)) {
+ int min_sync_recovery_time_sec;
+ if (base::StringToInt(field_params[kMinSyncRecoveryTimeName],
+ &min_sync_recovery_time_sec)) {
+ parameters->min_sync_recovery_time =
+ base::TimeDelta::FromSeconds(min_sync_recovery_time_sec);
+ }
+ }
+
+ if (base::Contains(field_params, kMaxSyncEventDurationName)) {
+ int max_sync_event_duration_sec;
+ if (base::StringToInt(field_params[kMaxSyncEventDurationName],
+ &max_sync_event_duration_sec)) {
+ parameters->max_sync_event_duration =
+ base::TimeDelta::FromSeconds(max_sync_event_duration_sec);
+ }
+ }
+
+ if (base::Contains(field_params, kMinPeriodicSyncEventsInterval)) {
+ int min_periodic_sync_events_interval_sec;
+ if (base::StringToInt(field_params[kMinPeriodicSyncEventsInterval],
+ &min_periodic_sync_events_interval_sec)) {
+ parameters->min_periodic_sync_events_interval =
+ base::TimeDelta::FromSeconds(min_periodic_sync_events_interval_sec);
+ }
+ }
+
+#if defined(OS_ANDROID)
+ // Check if the delegate explicitly disabled this feature.
+ if (delegate_->ShouldDisableAndroidNetworkDetection()) {
+ parameters->rely_on_android_network_detection = false;
+ } else if (base::Contains(field_params, kRelyOnAndroidNetworkDetection)) {
+ if (base::LowerCaseEqualsASCII(field_params[kRelyOnAndroidNetworkDetection],
+ "true")) {
+ parameters->rely_on_android_network_detection = true;
+ }
+ }
+#endif
+
+ return;
+}
+
+void BackgroundSyncControllerImpl::NotifyOneShotBackgroundSyncRegistered(
+ const url::Origin& origin,
+ bool can_fire,
+ bool is_reregistered) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ background_sync_metrics_->MaybeRecordOneShotSyncRegistrationEvent(
+ origin, can_fire, is_reregistered);
+}
+
+void BackgroundSyncControllerImpl::NotifyPeriodicBackgroundSyncRegistered(
+ const url::Origin& origin,
+ int min_interval,
+ bool is_reregistered) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ background_sync_metrics_->MaybeRecordPeriodicSyncRegistrationEvent(
+ origin, min_interval, is_reregistered);
+}
+
+void BackgroundSyncControllerImpl::NotifyOneShotBackgroundSyncCompleted(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ background_sync_metrics_->MaybeRecordOneShotSyncCompletionEvent(
+ origin, status_code, num_attempts, max_attempts);
+}
+
+void BackgroundSyncControllerImpl::NotifyPeriodicBackgroundSyncCompleted(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ background_sync_metrics_->MaybeRecordPeriodicSyncEventCompletion(
+ origin, status_code, num_attempts, max_attempts);
+}
+
+void BackgroundSyncControllerImpl::ScheduleBrowserWakeUpWithDelay(
+ blink::mojom::BackgroundSyncType sync_type,
+ base::TimeDelta delay) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (delegate_->IsProfileOffTheRecord())
+ return;
+
+#if defined(OS_ANDROID)
+ delegate_->ScheduleBrowserWakeUpWithDelay(sync_type, delay);
+#endif
+}
+
+void BackgroundSyncControllerImpl::CancelBrowserWakeup(
+ blink::mojom::BackgroundSyncType sync_type) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (delegate_->IsProfileOffTheRecord())
+ return;
+
+#if defined(OS_ANDROID)
+ delegate_->CancelBrowserWakeup(sync_type);
+#endif
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::SnapToMaxOriginFrequency(
+ int64_t min_interval,
+ int64_t min_gap_for_origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ DCHECK_GE(min_gap_for_origin, 0);
+ DCHECK_GE(min_interval, 0);
+
+ if (min_interval < min_gap_for_origin)
+ return base::TimeDelta::FromMilliseconds(min_gap_for_origin);
+ if (min_interval % min_gap_for_origin == 0)
+ return base::TimeDelta::FromMilliseconds(min_interval);
+ return base::TimeDelta::FromMilliseconds(
+ (min_interval / min_gap_for_origin + 1) * min_gap_for_origin);
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::ApplyMinGapForOrigin(
+ base::TimeDelta delay,
+ base::TimeDelta time_till_next_scheduled_event_for_origin,
+ base::TimeDelta min_gap_for_origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ if (time_till_next_scheduled_event_for_origin.is_max())
+ return delay;
+
+ if (delay <= time_till_next_scheduled_event_for_origin - min_gap_for_origin)
+ return delay;
+
+ if (delay <= time_till_next_scheduled_event_for_origin)
+ return time_till_next_scheduled_event_for_origin;
+
+ if (delay <= time_till_next_scheduled_event_for_origin + min_gap_for_origin)
+ return time_till_next_scheduled_event_for_origin + min_gap_for_origin;
+
+ return delay;
+}
+
+bool BackgroundSyncControllerImpl::IsContentSettingBlocked(
+ const url::Origin& origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ auto* host_content_settings_map = delegate_->GetHostContentSettingsMap();
+ DCHECK(host_content_settings_map);
+
+ auto url = origin.GetURL();
+ return CONTENT_SETTING_ALLOW != host_content_settings_map->GetContentSetting(
+ /* primary_url= */ url,
+ /* secondary_url= */ url,
+ ContentSettingsType::BACKGROUND_SYNC);
+}
+
+void BackgroundSyncControllerImpl::Shutdown() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ delegate_->GetHostContentSettingsMap()->RemoveObserver(this);
+ delegate_->Shutdown();
+}
+
+base::TimeDelta BackgroundSyncControllerImpl::GetNextEventDelay(
+ const content::BackgroundSyncRegistration& registration,
+ content::BackgroundSyncParameters* parameters,
+ base::TimeDelta time_till_soonest_scheduled_event_for_origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(parameters);
+
+ int num_attempts = registration.num_attempts();
+
+ if (!num_attempts) {
+ // First attempt.
+ switch (registration.sync_type()) {
+ case blink::mojom::BackgroundSyncType::ONE_SHOT:
+ return base::TimeDelta();
+ case blink::mojom::BackgroundSyncType::PERIODIC:
+ int site_engagement_factor =
+ delegate_->GetSiteEngagementPenalty(registration.origin().GetURL());
+ if (!site_engagement_factor)
+ return base::TimeDelta::Max();
+
+ int64_t effective_gap_ms =
+ site_engagement_factor *
+ parameters->min_periodic_sync_events_interval.InMilliseconds();
+ return ApplyMinGapForOrigin(
+ SnapToMaxOriginFrequency(registration.options()->min_interval,
+ effective_gap_ms),
+ time_till_soonest_scheduled_event_for_origin,
+ parameters->min_periodic_sync_events_interval);
+ }
+ }
+
+ // After a sync event has been fired.
+ DCHECK_LT(num_attempts, parameters->max_sync_attempts);
+ return parameters->initial_retry_delay *
+ pow(parameters->retry_delay_factor, num_attempts - 1);
+}
+
+std::unique_ptr<content::BackgroundSyncController::BackgroundSyncEventKeepAlive>
+BackgroundSyncControllerImpl::CreateBackgroundSyncEventKeepAlive() {
+#if !defined(OS_ANDROID)
+ if (!KeepAliveRegistry::GetInstance()->IsShuttingDown())
+ return std::make_unique<BackgroundSyncEventKeepAliveImpl>();
+#endif
+ return nullptr;
+}
+
+#if !defined(OS_ANDROID)
+BackgroundSyncControllerImpl::BackgroundSyncEventKeepAliveImpl::
+ BackgroundSyncEventKeepAliveImpl() {
+ keepalive_ = std::unique_ptr<ScopedKeepAlive,
+ content::BrowserThread::DeleteOnUIThread>(
+ new ScopedKeepAlive(KeepAliveOrigin::BACKGROUND_SYNC,
+ KeepAliveRestartOption::DISABLED));
+}
+
+BackgroundSyncControllerImpl::BackgroundSyncEventKeepAliveImpl::
+ ~BackgroundSyncEventKeepAliveImpl() = default;
+#endif
+
+void BackgroundSyncControllerImpl::NoteSuspendedPeriodicSyncOrigins(
+ std::set<url::Origin> suspended_origins) {
+ delegate_->NoteSuspendedPeriodicSyncOrigins(std::move(suspended_origins));
+}
+
+void BackgroundSyncControllerImpl::NoteRegisteredPeriodicSyncOrigins(
+ std::set<url::Origin> registered_origins) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ for (auto& origin : registered_origins)
+ periodic_sync_origins_.insert(std::move(origin));
+}
+
+void BackgroundSyncControllerImpl::AddToTrackedOrigins(
+ const url::Origin& origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ periodic_sync_origins_.insert(origin);
+}
+
+void BackgroundSyncControllerImpl::RemoveFromTrackedOrigins(
+ const url::Origin& origin) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ periodic_sync_origins_.erase(origin);
+}
diff --git a/chromium/components/background_sync/background_sync_controller_impl.h b/chromium/components/background_sync/background_sync_controller_impl.h
new file mode 100644
index 00000000000..d06e0459be6
--- /dev/null
+++ b/chromium/components/background_sync/background_sync_controller_impl.h
@@ -0,0 +1,146 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_
+#define COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_
+
+#include "content/public/browser/background_sync_controller.h"
+
+#include <stdint.h>
+
+#include <set>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/background_sync/background_sync_delegate.h"
+#include "components/background_sync/background_sync_metrics.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/background_sync_registration.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/mojom/background_sync/background_sync.mojom-forward.h"
+
+namespace content {
+struct BackgroundSyncParameters;
+class BrowserContext;
+} // namespace content
+
+namespace url {
+class Origin;
+} // namespace url
+
+class BackgroundSyncControllerImpl : public content::BackgroundSyncController,
+ public KeyedService,
+ public content_settings::Observer {
+ public:
+ static const char kFieldTrialName[];
+ static const char kDisabledParameterName[];
+ static const char kKeepBrowserAwakeParameterName[];
+ static const char kSkipPermissionsCheckParameterName[];
+ static const char kMaxAttemptsParameterName[];
+ static const char kRelyOnAndroidNetworkDetection[];
+ static const char kMaxAttemptsWithNotificationPermissionParameterName[];
+ static const char kInitialRetryParameterName[];
+ static const char kRetryDelayFactorParameterName[];
+ static const char kMinSyncRecoveryTimeName[];
+ static const char kMaxSyncEventDurationName[];
+ static const char kMinPeriodicSyncEventsInterval[];
+
+#if !defined(OS_ANDROID)
+ class BackgroundSyncEventKeepAliveImpl : public BackgroundSyncEventKeepAlive {
+ public:
+ ~BackgroundSyncEventKeepAliveImpl() override;
+ BackgroundSyncEventKeepAliveImpl();
+
+ private:
+ std::unique_ptr<ScopedKeepAlive, content::BrowserThread::DeleteOnUIThread>
+ keepalive_ = nullptr;
+ };
+#endif
+
+ BackgroundSyncControllerImpl(
+ content::BrowserContext* browser_context,
+ std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate);
+ ~BackgroundSyncControllerImpl() override;
+
+ // content::BackgroundSyncController overrides.
+ void GetParameterOverrides(
+ content::BackgroundSyncParameters* parameters) override;
+ void NotifyOneShotBackgroundSyncRegistered(const url::Origin& origin,
+ bool can_fire,
+ bool is_reregistered) override;
+ void NotifyPeriodicBackgroundSyncRegistered(const url::Origin& origin,
+ int min_interval,
+ bool is_reregistered) override;
+ void NotifyOneShotBackgroundSyncCompleted(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) override;
+ void NotifyPeriodicBackgroundSyncCompleted(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) override;
+ void ScheduleBrowserWakeUpWithDelay(
+ blink::mojom::BackgroundSyncType sync_type,
+ base::TimeDelta delay) override;
+ void CancelBrowserWakeup(blink::mojom::BackgroundSyncType sync_type) override;
+
+ base::TimeDelta GetNextEventDelay(
+ const content::BackgroundSyncRegistration& registration,
+ content::BackgroundSyncParameters* parameters,
+ base::TimeDelta time_till_soonest_scheduled_event_for_origin) override;
+
+ std::unique_ptr<BackgroundSyncEventKeepAlive>
+ CreateBackgroundSyncEventKeepAlive() override;
+ void NoteSuspendedPeriodicSyncOrigins(
+ std::set<url::Origin> suspended_origins) override;
+ void NoteRegisteredPeriodicSyncOrigins(
+ std::set<url::Origin> registered_origins) override;
+ void AddToTrackedOrigins(const url::Origin& origin) override;
+ void RemoveFromTrackedOrigins(const url::Origin& origin) override;
+
+ // content_settings::Observer overrides.
+ void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) override;
+
+ bool IsOriginTracked(const url::Origin& origin) {
+ return periodic_sync_origins_.find(origin) != periodic_sync_origins_.end();
+ }
+
+ private:
+ // Once we've identified the minimum number of hours between each periodicsync
+ // event for an origin, every delay calculated for the origin should be a
+ // multiple of the same.
+ base::TimeDelta SnapToMaxOriginFrequency(int64_t min_interval,
+ int64_t min_gap_for_origin);
+
+ // Returns an updated delay for a Periodic Background Sync registration -- one
+ // that ensures the |min_gap_for_origin|.
+ base::TimeDelta ApplyMinGapForOrigin(
+ base::TimeDelta delay,
+ base::TimeDelta time_till_next_scheduled_event_for_origin,
+ base::TimeDelta min_gap_for_origin);
+
+ bool IsContentSettingBlocked(const url::Origin& origin);
+
+ // KeyedService implementation.
+ void Shutdown() override;
+
+ content::BrowserContext* browser_context_;
+
+ std::unique_ptr<background_sync::BackgroundSyncDelegate> delegate_;
+ std::unique_ptr<BackgroundSyncMetrics> background_sync_metrics_;
+
+ std::set<url::Origin> periodic_sync_origins_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncControllerImpl);
+};
+
+#endif // COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_IMPL_H_
diff --git a/chromium/components/background_sync/background_sync_delegate.h b/chromium/components/background_sync/background_sync_delegate.h
new file mode 100644
index 00000000000..fcaa77d5767
--- /dev/null
+++ b/chromium/components/background_sync/background_sync_delegate.h
@@ -0,0 +1,78 @@
+// Copyright 2020 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_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_H_
+#define COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_H_
+
+#include <set>
+
+#include "base/callback.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "third_party/blink/public/mojom/background_sync/background_sync.mojom-forward.h"
+#include "url/origin.h"
+
+class HostContentSettingsMap;
+
+class GURL;
+
+namespace background_sync {
+
+// Allows the component embedder to override the behavior of Background Sync
+// component.
+class BackgroundSyncDelegate {
+ public:
+ virtual ~BackgroundSyncDelegate() = default;
+
+ // Gets the source_ID to log the UKM event for, and calls |callback| with that
+ // source_id, or with base::nullopt if UKM recording is not allowed.
+ virtual void GetUkmSourceId(
+ const url::Origin& origin,
+ base::OnceCallback<void(base::Optional<ukm::SourceId>)> callback) = 0;
+
+ // Handles browser shutdown.
+ virtual void Shutdown() = 0;
+
+ // Returns the content settings map.
+ virtual HostContentSettingsMap* GetHostContentSettingsMap() = 0;
+
+ // Returns true if the profile associated with the delegate is off-the-record.
+ virtual bool IsProfileOffTheRecord() = 0;
+
+ // Notes the origins for which Periodic Background Sync is suspended.
+ virtual void NoteSuspendedPeriodicSyncOrigins(
+ std::set<url::Origin> suspended_origins) = 0;
+
+ // Gets the site engagement penalty to add to the Periodic Background Sync
+ // interval for the origin corresponding to |url|.
+ // The site engagement penalty is inversely proportional to the engagement
+ // level. The lower the engagement levels with the site, the less often
+ // periodic sync events will be fired.
+ // Returns 0 if the engagement level is blink::mojom::EngagementLevel::NONE.
+ virtual int GetSiteEngagementPenalty(const GURL& url) = 0;
+
+#if defined(OS_ANDROID)
+ // Schedules the browser to be woken up when the device is online to process
+ // registrations of type |sync| after a minimum delay |delay|.
+ virtual void ScheduleBrowserWakeUpWithDelay(
+ blink::mojom::BackgroundSyncType sync_type,
+ base::TimeDelta delay) = 0;
+
+ // Cancels browser wakeup for registrations of type |sync_type|.
+ virtual void CancelBrowserWakeup(
+ blink::mojom::BackgroundSyncType sync_type) = 0;
+
+ // Whether Background Sync should be disabled.
+ virtual bool ShouldDisableBackgroundSync() = 0;
+
+ // Whether to disable Android network detection for connectivity checks.
+ virtual bool ShouldDisableAndroidNetworkDetection() = 0;
+#endif
+};
+
+} // namespace background_sync
+
+#endif // COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_H_
diff --git a/chromium/components/background_sync/background_sync_metrics.cc b/chromium/components/background_sync/background_sync_metrics.cc
new file mode 100644
index 00000000000..b61e26bece3
--- /dev/null
+++ b/chromium/components/background_sync/background_sync_metrics.cc
@@ -0,0 +1,151 @@
+// 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 "components/background_sync/background_sync_metrics.h"
+
+#include "base/bind.h"
+#include "components/background_sync/background_sync_delegate.h"
+#include "services/metrics/public/cpp/metrics_utils.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/origin.h"
+
+BackgroundSyncMetrics::BackgroundSyncMetrics(
+ background_sync::BackgroundSyncDelegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate_);
+}
+
+BackgroundSyncMetrics::~BackgroundSyncMetrics() = default;
+
+void BackgroundSyncMetrics::MaybeRecordOneShotSyncRegistrationEvent(
+ const url::Origin& origin,
+ bool can_fire,
+ bool is_reregistered) {
+ DCHECK(delegate_);
+ delegate_->GetUkmSourceId(
+ origin,
+ base::BindOnce(
+ &BackgroundSyncMetrics::DidGetBackgroundSourceId,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &BackgroundSyncMetrics::RecordOneShotSyncRegistrationEvent,
+ weak_ptr_factory_.GetWeakPtr(), can_fire, is_reregistered)));
+}
+
+void BackgroundSyncMetrics::MaybeRecordPeriodicSyncRegistrationEvent(
+ const url::Origin& origin,
+ int min_interval,
+ bool is_reregistered) {
+ DCHECK(delegate_);
+ delegate_->GetUkmSourceId(
+ origin,
+ base::BindOnce(
+ &BackgroundSyncMetrics::DidGetBackgroundSourceId,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &BackgroundSyncMetrics::RecordPeriodicSyncRegistrationEvent,
+ weak_ptr_factory_.GetWeakPtr(), min_interval, is_reregistered)));
+}
+
+void BackgroundSyncMetrics::MaybeRecordOneShotSyncCompletionEvent(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) {
+ DCHECK(delegate_);
+ delegate_->GetUkmSourceId(
+ origin, base::BindOnce(
+ &BackgroundSyncMetrics::DidGetBackgroundSourceId,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &BackgroundSyncMetrics::RecordOneShotSyncCompletionEvent,
+ weak_ptr_factory_.GetWeakPtr(), status_code, num_attempts,
+ max_attempts)));
+}
+
+void BackgroundSyncMetrics::MaybeRecordPeriodicSyncEventCompletion(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts) {
+ DCHECK(delegate_);
+ delegate_->GetUkmSourceId(
+ origin, base::BindOnce(
+ &BackgroundSyncMetrics::DidGetBackgroundSourceId,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::BindOnce(
+ &BackgroundSyncMetrics::RecordPeriodicSyncEventCompletion,
+ weak_ptr_factory_.GetWeakPtr(), status_code, num_attempts,
+ max_attempts)));
+}
+
+void BackgroundSyncMetrics::DidGetBackgroundSourceId(
+ RecordCallback record_callback,
+ base::Optional<ukm::SourceId> source_id) {
+ // This background event did not meet the requirements for the UKM service.
+ if (!source_id)
+ return;
+
+ std::move(record_callback).Run(*source_id);
+ if (ukm_event_recorded_for_testing_)
+ std::move(ukm_event_recorded_for_testing_).Run();
+}
+
+void BackgroundSyncMetrics::RecordOneShotSyncRegistrationEvent(
+ bool can_fire,
+ bool is_reregistered,
+ ukm::SourceId source_id) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+ DCHECK(recorder);
+
+ ukm::builders::BackgroundSyncRegistered(source_id)
+ .SetCanFire(can_fire)
+ .SetIsReregistered(is_reregistered)
+ .Record(recorder);
+}
+
+void BackgroundSyncMetrics::RecordPeriodicSyncRegistrationEvent(
+ int min_interval,
+ bool is_reregistered,
+ ukm::SourceId source_id) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+ DCHECK(recorder);
+
+ ukm::builders::PeriodicBackgroundSyncRegistered(source_id)
+ .SetMinIntervalMs(ukm::GetExponentialBucketMin(
+ min_interval, kUkmEventDataBucketSpacing))
+ .SetIsReregistered(is_reregistered)
+ .Record(recorder);
+}
+
+void BackgroundSyncMetrics::RecordOneShotSyncCompletionEvent(
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts,
+ ukm::SourceId source_id) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+ DCHECK(recorder);
+
+ ukm::builders::BackgroundSyncCompleted(source_id)
+ .SetStatus(static_cast<int>(status_code))
+ .SetNumAttempts(num_attempts)
+ .SetMaxAttempts(max_attempts)
+ .Record(recorder);
+}
+
+void BackgroundSyncMetrics::RecordPeriodicSyncEventCompletion(
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts,
+ ukm::SourceId source_id) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+ DCHECK(recorder);
+
+ ukm::builders::PeriodicBackgroundSyncEventCompleted(source_id)
+ .SetStatus(static_cast<int>(status_code))
+ .SetNumAttempts(num_attempts)
+ .SetMaxAttempts(max_attempts)
+ .Record(recorder);
+}
diff --git a/chromium/components/background_sync/background_sync_metrics.h b/chromium/components/background_sync/background_sync_metrics.h
new file mode 100644
index 00000000000..fe5f9ff95e1
--- /dev/null
+++ b/chromium/components/background_sync/background_sync_metrics.h
@@ -0,0 +1,90 @@
+// 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 COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_
+#define COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+
+namespace {
+// Exponential bucket spacing for UKM event data.
+constexpr double kUkmEventDataBucketSpacing = 2.0;
+} // namespace
+
+namespace background_sync {
+class BackgroundSyncDelegate;
+} // namespace background_sync
+
+namespace url {
+class Origin;
+} // namespace url
+
+// Lives entirely on the UI thread.
+class BackgroundSyncMetrics {
+ public:
+ using RecordCallback = base::OnceCallback<void(ukm::SourceId)>;
+
+ explicit BackgroundSyncMetrics(
+ background_sync::BackgroundSyncDelegate* delegate);
+ ~BackgroundSyncMetrics();
+
+ void MaybeRecordOneShotSyncRegistrationEvent(const url::Origin& origin,
+ bool can_fire,
+ bool is_reregistered);
+
+ void MaybeRecordPeriodicSyncRegistrationEvent(const url::Origin& origin,
+ int min_interval,
+ bool is_reregistered);
+
+ void MaybeRecordOneShotSyncCompletionEvent(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts);
+
+ void MaybeRecordPeriodicSyncEventCompletion(
+ const url::Origin& origin,
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts);
+
+ private:
+ friend class BackgroundSyncMetricsBrowserTest;
+
+ void DidGetBackgroundSourceId(RecordCallback record_callback,
+ base::Optional<ukm::SourceId> source_id);
+
+ void RecordOneShotSyncRegistrationEvent(bool can_fire,
+ bool is_reregistered,
+ ukm::SourceId source_id);
+ void RecordPeriodicSyncRegistrationEvent(int min_interval,
+ bool is_reregistered,
+ ukm::SourceId source_id);
+
+ void RecordOneShotSyncCompletionEvent(
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts,
+ ukm::SourceId source_id);
+ void RecordPeriodicSyncEventCompletion(
+ blink::ServiceWorkerStatusCode status_code,
+ int num_attempts,
+ int max_attempts,
+ ukm::SourceId source_id);
+
+ background_sync::BackgroundSyncDelegate* delegate_;
+
+ // Used to signal tests that a UKM event has been recorded.
+ base::OnceClosure ukm_event_recorded_for_testing_;
+
+ base::WeakPtrFactory<BackgroundSyncMetrics> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundSyncMetrics);
+};
+
+#endif // COMPONENTS_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_
diff --git a/chromium/components/background_sync/background_sync_permission_context_unittest.cc b/chromium/components/background_sync/background_sync_permission_context_unittest.cc
index 2fe06a1af13..d7b24c29eee 100644
--- a/chromium/components/background_sync/background_sync_permission_context_unittest.cc
+++ b/chromium/components/background_sync/background_sync_permission_context_unittest.cc
@@ -95,7 +95,7 @@ TEST_F(BackgroundSyncPermissionContextTest, TestBlockOrigin) {
->GetSettingsMap(browser_context())
->SetContentSettingDefaultScope(url1, GURL(),
ContentSettingsType::BACKGROUND_SYNC,
- std::string(), CONTENT_SETTING_BLOCK);
+ CONTENT_SETTING_BLOCK);
NavigateAndRequestPermission(url1, &permission_context);
diff --git a/chromium/components/background_task_scheduler/BUILD.gn b/chromium/components/background_task_scheduler/BUILD.gn
index a98456fa561..a24e667918e 100644
--- a/chromium/components/background_task_scheduler/BUILD.gn
+++ b/chromium/components/background_task_scheduler/BUILD.gn
@@ -132,6 +132,7 @@ if (is_android) {
"//base:base_java_test_support",
"//base:base_junit_test_support",
"//components/background_task_scheduler:public_java",
+ "//third_party/android_deps:chromium_play_services_availability_shadows_java",
"//third_party/android_deps:robolectric_all_java",
"//third_party/junit",
"//third_party/mockito:mockito_java",
diff --git a/chromium/components/background_task_scheduler/internal/BUILD.gn b/chromium/components/background_task_scheduler/internal/BUILD.gn
index 1ce3ec4bf86..3bbe8e393d3 100644
--- a/chromium/components/background_task_scheduler/internal/BUILD.gn
+++ b/chromium/components/background_task_scheduler/internal/BUILD.gn
@@ -36,6 +36,7 @@ if (is_android) {
"//components/background_task_scheduler:public_java",
"//content/public/android:content_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:chromium_play_services_availability_java",
"//third_party/android_deps:protobuf_lite_runtime_java",
]
}
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerGcmNetworkManagerTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerGcmNetworkManagerTest.java
index 43b014e6c73..823b8028d27 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerGcmNetworkManagerTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerGcmNetworkManagerTest.java
@@ -12,8 +12,6 @@ import static org.junit.Assert.assertTrue;
import android.os.Bundle;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.gcm.GcmNetworkManager;
import com.google.android.gms.gcm.OneoffTask;
import com.google.android.gms.gcm.PeriodicTask;
@@ -25,8 +23,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.gms.Shadows;
-import org.robolectric.shadows.gms.common.ShadowGoogleApiAvailability;
import org.chromium.base.ContextUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -35,13 +31,14 @@ import org.chromium.components.background_task_scheduler.BackgroundTask;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;
import org.chromium.components.background_task_scheduler.TaskParameters;
+import org.chromium.gms.shadows.ShadowChromiumPlayServicesAvailability;
import java.util.concurrent.TimeUnit;
/** Unit tests for {@link BackgroundTaskSchedulerGcmNetworkManager}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE,
- shadows = {ShadowGcmNetworkManager.class, ShadowGoogleApiAvailability.class})
+ shadows = {ShadowGcmNetworkManager.class, ShadowChromiumPlayServicesAvailability.class})
public class BackgroundTaskSchedulerGcmNetworkManagerTest {
ShadowGcmNetworkManager mGcmNetworkManager;
@@ -59,8 +56,7 @@ public class BackgroundTaskSchedulerGcmNetworkManagerTest {
@Before
public void setUp() {
- Shadows.shadowOf(GoogleApiAvailability.getInstance())
- .setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
+ ShadowChromiumPlayServicesAvailability.setIsGooglePlayServicesAvailable(true);
mGcmNetworkManager = (ShadowGcmNetworkManager) Shadow.extract(
GcmNetworkManager.getInstance(ContextUtils.getApplicationContext()));
BackgroundTaskSchedulerGcmNetworkManager.setClockForTesting(mClock);
@@ -301,8 +297,7 @@ public class BackgroundTaskSchedulerGcmNetworkManagerTest {
@Test
@Feature("BackgroundTaskScheduler")
public void testScheduleNoGooglePlayServices() {
- Shadows.shadowOf(GoogleApiAvailability.getInstance())
- .setIsGooglePlayServicesAvailable(ConnectionResult.SERVICE_MISSING);
+ ShadowChromiumPlayServicesAvailability.setIsGooglePlayServicesAvailable(false);
TaskInfo.TimingInfo timingInfo =
TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TIME_24_H_TO_MS).build();
@@ -332,8 +327,7 @@ public class BackgroundTaskSchedulerGcmNetworkManagerTest {
@Feature("BackgroundTaskScheduler")
public void testCancelNoGooglePlayServices() {
// This simulates situation where Google Play Services is uninstalled.
- Shadows.shadowOf(GoogleApiAvailability.getInstance())
- .setIsGooglePlayServicesAvailable(ConnectionResult.SERVICE_MISSING);
+ ShadowChromiumPlayServicesAvailability.setIsGooglePlayServicesAvailable(false);
TaskInfo.TimingInfo timingInfo =
TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TIME_24_H_TO_MS).build();
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerImplTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerImplTest.java
index e0e19b33517..c29abef0187 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerImplTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerImplTest.java
@@ -15,8 +15,6 @@ import static org.mockito.Mockito.verify;
import android.os.Build;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.gcm.GcmNetworkManager;
import org.junit.Before;
@@ -27,8 +25,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.gms.Shadows;
-import org.robolectric.shadows.gms.common.ShadowGoogleApiAvailability;
import org.robolectric.util.ReflectionHelpers;
import org.chromium.base.ContextUtils;
@@ -37,13 +33,14 @@ import org.chromium.base.test.util.Feature;
import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;
+import org.chromium.gms.shadows.ShadowChromiumPlayServicesAvailability;
import java.util.concurrent.TimeUnit;
/** Unit tests for {@link BackgroundTaskScheduler}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE,
- shadows = {ShadowGcmNetworkManager.class, ShadowGoogleApiAvailability.class})
+ shadows = {ShadowGcmNetworkManager.class, ShadowChromiumPlayServicesAvailability.class})
public class BackgroundTaskSchedulerImplTest {
@Mock
private BackgroundTaskSchedulerDelegate mDelegate;
@@ -66,8 +63,7 @@ public class BackgroundTaskSchedulerImplTest {
TestBackgroundTask.reset();
// Initialize Google Play Services and GCM Network Manager for upgrade testing.
- Shadows.shadowOf(GoogleApiAvailability.getInstance())
- .setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
+ ShadowChromiumPlayServicesAvailability.setIsGooglePlayServicesAvailable(true);
mGcmNetworkManager = (ShadowGcmNetworkManager) Shadow.extract(
GcmNetworkManager.getInstance(ContextUtils.getApplicationContext()));
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
index ee6938a6be0..206f31bb696 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
@@ -8,10 +8,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import android.content.SharedPreferences;
import android.os.Build;
@@ -19,9 +15,6 @@ import android.os.Build;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@@ -42,9 +35,6 @@ import java.util.concurrent.TimeUnit;
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BackgroundTaskSchedulerPrefsTest {
- @Spy
- private BackgroundTaskSchedulerUma mUmaSpy;
-
private TaskInfo mTask1;
private TaskInfo mTask2;
@@ -57,10 +47,6 @@ public class BackgroundTaskSchedulerPrefsTest {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- BackgroundTaskSchedulerUma.setInstanceForTesting(mUmaSpy);
- doNothing().when(mUmaSpy).assertNativeIsLoaded();
-
TaskInfo.TimingInfo timingInfo1 =
TaskInfo.OneOffInfo.create().setWindowEndTimeMs(TimeUnit.DAYS.toMillis(1)).build();
mTask1 = TaskInfo.createTask(TaskIds.TEST, timingInfo1).build();
@@ -213,13 +199,6 @@ public class BackgroundTaskSchedulerPrefsTest {
editor.apply();
BackgroundTaskSchedulerPrefs.migrateStoredTasksToProto();
- verify(mUmaSpy, times(1))
- .cacheEvent(eq("Android.BackgroundTaskScheduler.MigrationToProto"),
- ArgumentMatchers.eq(BackgroundTaskSchedulerUma.BACKGROUND_TASK_TEST));
- verify(mUmaSpy, times(1))
- .cacheEvent(eq("Android.BackgroundTaskScheduler.MigrationToProto"),
- ArgumentMatchers.eq(
- BackgroundTaskSchedulerUma.BACKGROUND_TASK_OFFLINE_PAGES));
Set<Integer> taskIds = BackgroundTaskSchedulerPrefs.getScheduledTaskIds();
assertTrue(taskIds.contains(mTask1.getTaskId()));
@@ -230,12 +209,5 @@ public class BackgroundTaskSchedulerPrefsTest {
.getClass());
BackgroundTaskSchedulerPrefs.migrateStoredTasksToProto();
- verify(mUmaSpy, times(1))
- .cacheEvent(eq("Android.BackgroundTaskScheduler.MigrationToProto"),
- ArgumentMatchers.eq(BackgroundTaskSchedulerUma.BACKGROUND_TASK_TEST));
- verify(mUmaSpy, times(1))
- .cacheEvent(eq("Android.BackgroundTaskScheduler.MigrationToProto"),
- ArgumentMatchers.eq(
- BackgroundTaskSchedulerUma.BACKGROUND_TASK_OFFLINE_PAGES));
}
}
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
index cefc5d21a80..20d04de27c2 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
@@ -308,16 +308,6 @@ public class BackgroundTaskSchedulerUmaTest {
@Test
@Feature({"BackgroundTaskScheduler"})
- public void testReportMigrationToProto() {
- doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt());
- BackgroundTaskSchedulerUma.getInstance().reportMigrationToProto(TaskIds.TEST);
- verify(mUmaSpy, times(1))
- .cacheEvent(eq("Android.BackgroundTaskScheduler.MigrationToProto"),
- ArgumentMatchers.eq(BackgroundTaskSchedulerUma.BACKGROUND_TASK_TEST));
- }
-
- @Test
- @Feature({"BackgroundTaskScheduler"})
public void testReportTaskStartedNativeFullBrowser() {
doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt());
mExternalUma.reportTaskStartedNative(TaskIds.DOWNLOAD_SERVICE_JOB_ID, false);
diff --git a/chromium/components/blocked_content/android/popup_blocked_infobar_delegate.cc b/chromium/components/blocked_content/android/popup_blocked_infobar_delegate.cc
index 0e4d3818aef..af96a82fbbc 100644
--- a/chromium/components/blocked_content/android/popup_blocked_infobar_delegate.cc
+++ b/chromium/components/blocked_content/android/popup_blocked_infobar_delegate.cc
@@ -78,7 +78,7 @@ PopupBlockedInfoBarDelegate::PopupBlockedInfoBarDelegate(
on_accept_callback_(std::move(on_accept_callback)) {
content_settings::SettingInfo setting_info;
std::unique_ptr<base::Value> setting = map->GetWebsiteSetting(
- url, url, ContentSettingsType::POPUPS, std::string(), &setting_info);
+ url, url, ContentSettingsType::POPUPS, &setting_info);
can_show_popups_ =
setting_info.source != content_settings::SETTING_SOURCE_POLICY;
}
diff --git a/chromium/components/blocked_content/android/popup_blocked_infobar_delegate_unittest.cc b/chromium/components/blocked_content/android/popup_blocked_infobar_delegate_unittest.cc
index 419ca8dfe49..387e6775f52 100644
--- a/chromium/components/blocked_content/android/popup_blocked_infobar_delegate_unittest.cc
+++ b/chromium/components/blocked_content/android/popup_blocked_infobar_delegate_unittest.cc
@@ -5,7 +5,7 @@
#include "components/blocked_content/android/popup_blocked_infobar_delegate.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "components/blocked_content/popup_blocker_tab_helper.h"
#include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
@@ -126,8 +126,7 @@ TEST_F(PopupBlockedInfoBarDelegateTest, ShowsBlockedPopups) {
EXPECT_TRUE(result.did_navigate);
EXPECT_TRUE(on_accept_called);
EXPECT_EQ(settings_map()->GetContentSetting(GURL(kPageUrl), GURL(kPageUrl),
- ContentSettingsType::POPUPS,
- std::string()),
+ ContentSettingsType::POPUPS),
CONTENT_SETTING_ALLOW);
}
diff --git a/chromium/components/blocked_content/popup_blocker.cc b/chromium/components/blocked_content/popup_blocker.cc
index 44cc72e2625..8f8438ccd4b 100644
--- a/chromium/components/blocked_content/popup_blocker.cc
+++ b/chromium/components/blocked_content/popup_blocker.cc
@@ -44,8 +44,7 @@ PopupBlockType ShouldBlockPopup(content::WebContents* web_contents,
opener_url ? *opener_url : web_contents->GetLastCommittedURL();
ContentSetting cs;
if (url.is_valid()) {
- cs = settings_map->GetContentSetting(url, url, ContentSettingsType::POPUPS,
- std::string());
+ cs = settings_map->GetContentSetting(url, url, ContentSettingsType::POPUPS);
} else {
cs = settings_map->GetDefaultContentSetting(ContentSettingsType::POPUPS,
nullptr);
diff --git a/chromium/components/blocked_content/popup_blocker_tab_helper_unittest.cc b/chromium/components/blocked_content/popup_blocker_tab_helper_unittest.cc
index 8fbd32d4130..ccd2cd557f5 100644
--- a/chromium/components/blocked_content/popup_blocker_tab_helper_unittest.cc
+++ b/chromium/components/blocked_content/popup_blocker_tab_helper_unittest.cc
@@ -4,6 +4,7 @@
#include "components/blocked_content/popup_blocker_tab_helper.h"
+#include "base/scoped_observation.h"
#include "base/test/scoped_feature_list.h"
#include "components/blocked_content/popup_navigation_delegate.h"
#include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
@@ -30,7 +31,7 @@ constexpr char kUrl2[] = "http://example2.test";
class BlockedUrlListObserver : public UrlListManager::Observer {
public:
explicit BlockedUrlListObserver(PopupBlockerTabHelper* helper) {
- observer_.Add(helper->manager());
+ observation_.Observe(helper->manager());
}
// UrlListManager::Observer:
void BlockedUrlAdded(int32_t id, const GURL& url) override {
@@ -41,7 +42,8 @@ class BlockedUrlListObserver : public UrlListManager::Observer {
private:
std::map<int32_t, GURL> blocked_urls_;
- ScopedObserver<UrlListManager, UrlListManager::Observer> observer_{this};
+ base::ScopedObservation<UrlListManager, UrlListManager::Observer>
+ observation_{this};
};
} // namespace
diff --git a/chromium/components/blocked_content/popup_opener_tab_helper.cc b/chromium/components/blocked_content/popup_opener_tab_helper.cc
index 77a7d075087..69e264d9fb0 100644
--- a/chromium/components/blocked_content/popup_opener_tab_helper.cc
+++ b/chromium/components/blocked_content/popup_opener_tab_helper.cc
@@ -114,9 +114,9 @@ void PopupOpenerTabHelper::MaybeLogPagePopupContentSettings() {
// Do not record duplicate Popup.Page events for popups opened in succession
// from the same opener.
if (source_id != last_opener_source_id_) {
- bool user_allows_popups = settings_map_->GetContentSetting(
- url, url, ContentSettingsType::POPUPS,
- std::string()) == CONTENT_SETTING_ALLOW;
+ bool user_allows_popups =
+ settings_map_->GetContentSetting(
+ url, url, ContentSettingsType::POPUPS) == CONTENT_SETTING_ALLOW;
ukm::builders::Popup_Page(source_id)
.SetAllowed(user_allows_popups)
.Record(ukm::UkmRecorder::Get());
diff --git a/chromium/components/blocked_content/popup_tracker.cc b/chromium/components/blocked_content/popup_tracker.cc
index 22cf6b9cb44..f949085b524 100644
--- a/chromium/components/blocked_content/popup_tracker.cc
+++ b/chromium/components/blocked_content/popup_tracker.cc
@@ -47,7 +47,6 @@ PopupTracker::PopupTracker(content::WebContents* contents,
content::WebContents* opener,
WindowOpenDisposition disposition)
: content::WebContentsObserver(contents),
- scoped_observer_(this),
visibility_tracker_(
base::DefaultTickClock::GetInstance(),
contents->GetVisibility() != content::Visibility::HIDDEN),
@@ -56,11 +55,11 @@ PopupTracker::PopupTracker(content::WebContents* contents,
if (auto* popup_opener = PopupOpenerTabHelper::FromWebContents(opener))
popup_opener->OnOpenedPopup(this);
- auto* observer_manager =
+ auto* observation_manager =
subresource_filter::SubresourceFilterObserverManager::FromWebContents(
contents);
- if (observer_manager) {
- scoped_observer_.Add(observer_manager);
+ if (observation_manager) {
+ scoped_observation_.Observe(observation_manager);
}
}
@@ -102,6 +101,7 @@ void PopupTracker::WebContentsDestroyed() {
num_activation_events_, kMaxSubcatagoryInteractions))
.SetNumGestureScrollBeginInteractions(CappedUserInteractions(
num_gesture_scroll_begin_events_, kMaxSubcatagoryInteractions))
+ .SetRedirectCount(num_redirects_)
.Record(ukm::UkmRecorder::Get());
}
}
@@ -113,6 +113,13 @@ void PopupTracker::DidFinishNavigation(
return;
}
+ if (navigation_handle->IsInMainFrame() && !first_navigation_committed_) {
+ first_navigation_committed_ = true;
+ // The last page in the redirect chain is the current page, the number of
+ // redirects is one less than the size of the chain.
+ num_redirects_ = navigation_handle->GetRedirectChain().size() - 1;
+ }
+
if (!first_load_visible_time_start_) {
first_load_visible_time_start_ =
visibility_tracker_.GetForegroundDuration();
@@ -165,7 +172,7 @@ void PopupTracker::OnSafeBrowsingChecksComplete(
}
void PopupTracker::OnSubresourceFilterGoingAway() {
- scoped_observer_.RemoveAll();
+ scoped_observation_.RemoveObservation();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(PopupTracker)
diff --git a/chromium/components/blocked_content/popup_tracker.h b/chromium/components/blocked_content/popup_tracker.h
index 29483926eb6..2321b3baa9f 100644
--- a/chromium/components/blocked_content/popup_tracker.h
+++ b/chromium/components/blocked_content/popup_tracker.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
@@ -68,9 +68,9 @@ class PopupTracker : public content::WebContentsObserver,
CheckResult& result) override;
void OnSubresourceFilterGoingAway() override;
- ScopedObserver<subresource_filter::SubresourceFilterObserverManager,
- subresource_filter::SubresourceFilterObserver>
- scoped_observer_;
+ base::ScopedObservation<subresource_filter::SubresourceFilterObserverManager,
+ subresource_filter::SubresourceFilterObserver>
+ scoped_observation_{this};
// Will be unset until the first navigation commits. Will be set to the total
// time the contents was visible at commit time.
@@ -88,6 +88,10 @@ class PopupTracker : public content::WebContentsObserver,
int num_activation_events_ = 0;
int num_gesture_scroll_begin_events_ = 0;
+ // Number of redirects taken by the pop-up during navigation.
+ int num_redirects_ = 0;
+ bool first_navigation_committed_ = false;
+
// The id of the web contents that created the popup at the time of creation.
// SourceIds are permanent so it's okay to use at any point so long as it's
// not invalid.
diff --git a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
index 792295121cf..3f77fa8b8c4 100644
--- a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
+++ b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
@@ -97,10 +97,9 @@ SafeBrowsingTriggeredPopupBlocker::SafeBrowsingTriggeredPopupBlocker(
content::WebContents* web_contents,
subresource_filter::SubresourceFilterObserverManager* observer_manager)
: content::WebContentsObserver(web_contents),
- scoped_observer_(this),
current_page_data_(std::make_unique<PageData>()) {
DCHECK(observer_manager);
- scoped_observer_.Add(observer_manager);
+ scoped_observation_.Observe(observer_manager);
}
void SafeBrowsingTriggeredPopupBlocker::DidFinishNavigation(
@@ -173,7 +172,7 @@ void SafeBrowsingTriggeredPopupBlocker::OnSafeBrowsingChecksComplete(
}
void SafeBrowsingTriggeredPopupBlocker::OnSubresourceFilterGoingAway() {
- scoped_observer_.RemoveAll();
+ scoped_observation_.RemoveObservation();
}
bool SafeBrowsingTriggeredPopupBlocker::IsEnabled(
diff --git a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.h b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.h
index 4daa6c70756..7a7bdb0f5bd 100644
--- a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.h
+++ b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.h
@@ -10,7 +10,7 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/safe_browsing/core/db/util.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
@@ -126,9 +126,9 @@ class SafeBrowsingTriggeredPopupBlocker
DISALLOW_COPY_AND_ASSIGN(PageData);
};
- ScopedObserver<subresource_filter::SubresourceFilterObserverManager,
- subresource_filter::SubresourceFilterObserver>
- scoped_observer_;
+ base::ScopedObservation<subresource_filter::SubresourceFilterObserverManager,
+ subresource_filter::SubresourceFilterObserver>
+ scoped_observation_{this};
// Whether the next main frame navigation that commits should trigger the
// stronger popup blocker in enforce or warn mode.
diff --git a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
index 1bc377df237..d17c0b30c7e 100644
--- a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
+++ b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -71,6 +71,7 @@ class SafeBrowsingTriggeredPopupBlockerTest
GetSafeBrowsingDatabaseManager() override {
return nullptr;
}
+ void OnReloadRequested() override {}
// content::RenderViewHostTestHarness:
void SetUp() override {
@@ -453,57 +454,4 @@ TEST_F(SafeBrowsingTriggeredPopupBlockerTest,
EXPECT_FALSE(popup_blocker()->ShouldApplyAbusivePopupBlocker());
}
-TEST_F(SafeBrowsingTriggeredPopupBlockerTest, EnforcementRedirectPosition) {
- // Turn on the feature to perform safebrowsing on redirects.
- base::test::ScopedFeatureList scoped_feature_list;
-
- const GURL enforce_url("https://enforce.test/");
- const GURL warn_url("https://warn.test/");
- MarkUrlAsAbusiveEnforce(enforce_url);
- MarkUrlAsAbusiveWarning(warn_url);
-
- using subresource_filter::RedirectPosition;
- struct {
- std::vector<const char*> urls;
- base::Optional<RedirectPosition> last_enforcement_position;
- } kTestCases[] = {
- {{"https://normal.test/"}, base::nullopt},
- {{"https://enforce.test/"}, RedirectPosition::kOnly},
- {{"https://warn.test/"}, base::nullopt},
-
- {{"https://normal.test/", "https://warn.test/"}, base::nullopt},
- {{"https://normal.test/", "https://normal.test/",
- "https://enforce.test/"},
- RedirectPosition::kLast},
-
- {{"https://enforce.test", "https://normal.test/", "https://warn.test/"},
- RedirectPosition::kFirst},
- {{"https://warn.test/", "https://normal.test/"}, base::nullopt},
-
- {{"https://normal.test/", "https://enforce.test/",
- "https://normal.test/"},
- RedirectPosition::kMiddle},
- };
-
- for (const auto& test_case : kTestCases) {
- base::HistogramTester histograms;
- const GURL& first_url = GURL(test_case.urls.front());
- auto navigation_simulator =
- content::NavigationSimulator::CreateRendererInitiated(first_url,
- main_rfh());
- for (size_t i = 1; i < test_case.urls.size(); ++i) {
- navigation_simulator->Redirect(GURL(test_case.urls[i]));
- }
- navigation_simulator->Commit();
-
- histograms.ExpectTotalCount(
- "SubresourceFilter.PageLoad.Activation.RedirectPosition2.Enforcement",
- test_case.last_enforcement_position.has_value() ? 1 : 0);
- if (test_case.last_enforcement_position.has_value()) {
- histograms.ExpectUniqueSample(
- "SubresourceFilter.PageLoad.Activation.RedirectPosition2.Enforcement",
- static_cast<int>(test_case.last_enforcement_position.value()), 1);
- }
- }
-}
} // namespace blocked_content
diff --git a/chromium/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc b/chromium/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
index b2e1624ba50..6b8dca077bc 100644
--- a/chromium/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
+++ b/chromium/components/blocklist/opt_out_blocklist/opt_out_blocklist_unittest.cc
@@ -13,7 +13,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
diff --git a/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc b/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
index f13d2014a9e..55d9a192fbd 100644
--- a/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
+++ b/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
@@ -9,7 +9,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/location.h"
diff --git a/chromium/components/bookmarks/browser/BUILD.gn b/chromium/components/bookmarks/browser/BUILD.gn
index 4613f48fb9b..9d1193a645f 100644
--- a/chromium/components/bookmarks/browser/BUILD.gn
+++ b/chromium/components/bookmarks/browser/BUILD.gn
@@ -5,13 +5,6 @@
import("//build/config/ui.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("browser") {
friend = [ "//components/bookmarks/test" ]
@@ -48,7 +41,6 @@ static_library("browser") {
"bookmark_model.cc",
"bookmark_node.cc",
"bookmark_node_data.cc",
- "bookmark_node_data_ios.cc",
"bookmark_storage.cc",
"bookmark_utils.cc",
"model_loader.cc",
@@ -102,6 +94,10 @@ static_library("browser") {
"Foundation.framework",
]
}
+
+ if (is_ios) {
+ sources += [ "bookmark_node_data_ios.cc" ]
+ }
}
static_library("test_support") {
@@ -133,10 +129,10 @@ source_set("unit_tests") {
sources = [
"bookmark_codec_unittest.cc",
"bookmark_expanded_state_tracker_unittest.cc",
- "bookmark_index_unittest.cc",
"bookmark_model_unittest.cc",
"bookmark_storage_unittest.cc",
"bookmark_utils_unittest.cc",
+ "titled_url_index_unittest.cc",
"titled_url_match_unittest.cc",
]
diff --git a/chromium/components/bookmarks/browser/bookmark_index_unittest.cc b/chromium/components/bookmarks/browser/bookmark_index_unittest.cc
deleted file mode 100644
index 90173ff149d..00000000000
--- a/chromium/components/bookmarks/browser/bookmark_index_unittest.cc
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright 2014 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 <stddef.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/bookmarks/browser/titled_url_match.h"
-#include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/bookmarks/test/test_bookmark_client.h"
-#include "components/query_parser/query_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ASCIIToUTF16;
-using base::UTF8ToUTF16;
-
-namespace bookmarks {
-namespace {
-
-const char kAboutBlankURL[] = "about:blank";
-
-class BookmarkClientMock : public TestBookmarkClient {
- public:
- explicit BookmarkClientMock(const std::map<GURL, int>& typed_count_map)
- : typed_count_map_(typed_count_map) {}
-
- bool SupportsTypedCountForUrls() override { return true; }
-
- void GetTypedCountForUrls(UrlTypedCountMap* url_typed_count_map) override {
- for (auto& url_typed_count_pair : *url_typed_count_map) {
- const GURL* url = url_typed_count_pair.first;
- if (!url)
- continue;
-
- auto found = typed_count_map_.find(*url);
- if (found == typed_count_map_.end())
- continue;
-
- url_typed_count_pair.second = found->second;
- }
- }
-
- private:
- const std::map<GURL, int> typed_count_map_;
-
- DISALLOW_COPY_AND_ASSIGN(BookmarkClientMock);
-};
-
-class BookmarkIndexTest : public testing::Test {
- public:
- BookmarkIndexTest() : model_(TestBookmarkClient::CreateModel()) {}
-
- typedef std::pair<std::string, std::string> TitleAndURL;
-
- void AddBookmarks(const char** titles, const char** urls, size_t count) {
- // The pair is (title, url).
- std::vector<TitleAndURL> bookmarks;
- for (size_t i = 0; i < count; ++i) {
- TitleAndURL bookmark(titles[i], urls[i]);
- bookmarks.push_back(bookmark);
- }
- AddBookmarks(bookmarks);
- }
-
- void AddBookmarks(const std::vector<TitleAndURL>& bookmarks) {
- for (size_t i = 0; i < bookmarks.size(); ++i) {
- model_->AddURL(model_->other_node(), i, ASCIIToUTF16(bookmarks[i].first),
- GURL(bookmarks[i].second));
- }
- }
-
- void ExpectMatches(const std::string& query,
- const char** expected_titles,
- size_t expected_count) {
- std::vector<std::string> title_vector;
- for (size_t i = 0; i < expected_count; ++i)
- title_vector.push_back(expected_titles[i]);
- ExpectMatches(query, query_parser::MatchingAlgorithm::DEFAULT,
- title_vector);
- }
-
- void ExpectMatches(const std::string& query,
- query_parser::MatchingAlgorithm matching_algorithm,
- const std::vector<std::string>& expected_titles) {
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(ASCIIToUTF16(query), 1000, matching_algorithm,
- &matches);
- ASSERT_EQ(expected_titles.size(), matches.size());
- for (size_t i = 0; i < expected_titles.size(); ++i) {
- bool found = false;
- for (size_t j = 0; j < matches.size(); ++j) {
- const base::string16& title = matches[j].node->GetTitledUrlNodeTitle();
- if (ASCIIToUTF16(expected_titles[i]) == title) {
- matches.erase(matches.begin() + j);
- found = true;
- break;
- }
- }
- ASSERT_TRUE(found);
- }
- }
-
- void ExtractMatchPositions(const std::string& string,
- TitledUrlMatch::MatchPositions* matches) {
- for (const base::StringPiece& match :
- base::SplitStringPiece(string, ":",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
- std::vector<base::StringPiece> chunks = base::SplitStringPiece(
- match, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- ASSERT_EQ(2U, chunks.size());
- matches->push_back(TitledUrlMatch::MatchPosition());
- int chunks0, chunks1;
- EXPECT_TRUE(base::StringToInt(chunks[0], &chunks0));
- EXPECT_TRUE(base::StringToInt(chunks[1], &chunks1));
- matches->back().first = chunks0;
- matches->back().second = chunks1;
- }
- }
-
- void ExpectMatchPositions(
- const TitledUrlMatch::MatchPositions& actual_positions,
- const TitledUrlMatch::MatchPositions& expected_positions) {
- ASSERT_EQ(expected_positions.size(), actual_positions.size());
- for (size_t i = 0; i < expected_positions.size(); ++i) {
- EXPECT_EQ(expected_positions[i].first, actual_positions[i].first);
- EXPECT_EQ(expected_positions[i].second, actual_positions[i].second);
- }
- }
-
- protected:
- std::unique_ptr<BookmarkModel> model_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BookmarkIndexTest);
-};
-
-// Various permutations with differing input, queries and output that exercises
-// all query paths.
-TEST_F(BookmarkIndexTest, GetBookmarksMatching) {
- struct TestData {
- const std::string titles;
- const std::string query;
- const std::string expected;
- } data[] = {
- // Trivial test case of only one term, exact match.
- { "a;b", "A", "a" },
-
- // Two terms, exact matches.
- { "a b;b", "a b", "a b" },
-
- // Prefix match, one term.
- { "abcd;abc;b", "abc", "abcd;abc" },
-
- // Prefix match, multiple terms.
- { "abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
-
- // Exact and prefix match.
- { "ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef"},
-
- // Exact and prefix match.
- { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
- "ab cde ghi",
- "ab cdef ghij"},
-
- // Title with term multiple times.
- { "ab ab", "ab", "ab ab"},
-
- // Make sure quotes don't do a prefix match.
- { "think", "\"thi\"", ""},
-
- // Prefix matches against multiple candidates.
- { "abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
-
- // Multiple prefix matches (with a lot of redundancy) against multiple
- // candidates.
- { "abc1 abc2 abc3 abc4 def1 def2 def3 def4",
- "abc def abc def abc def abc def abc def",
- "abc1 abc2 abc3 abc4 def1 def2 def3 def4"},
-
- // Prefix match on the first term.
- { "abc", "a", "" },
-
- // Prefix match on subsequent terms.
- { "abc def", "abc d", "" },
- };
- for (size_t i = 0; i < base::size(data); ++i) {
- std::vector<TitleAndURL> bookmarks;
- for (const std::string& title : base::SplitString(
- data[i].titles, ";",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
- TitleAndURL bookmark(title, kAboutBlankURL);
- bookmarks.push_back(bookmark);
- }
- AddBookmarks(bookmarks);
-
- std::vector<std::string> expected;
- if (!data[i].expected.empty()) {
- expected = base::SplitString(data[i].expected, ";",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- }
-
- ExpectMatches(data[i].query, query_parser::MatchingAlgorithm::DEFAULT,
- expected);
-
- model_ = TestBookmarkClient::CreateModel();
- }
-}
-
-TEST_F(BookmarkIndexTest, GetBookmarksMatchingAlwaysPrefixSearch) {
- struct TestData {
- const std::string titles;
- const std::string query;
- const std::string expected;
- } data[] = {
- // Trivial test case of only one term, exact match.
- { "z;y", "Z", "z" },
-
- // Prefix match, one term.
- { "abcd;abc;b", "abc", "abcd;abc" },
-
- // Prefix match, multiple terms.
- { "abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg" },
-
- // Exact and prefix match.
- { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
- "ab cde ghi",
- "ab cdef ghij" },
-
- // Title with term multiple times.
- { "ab ab", "ab", "ab ab" },
-
- // Make sure quotes don't do a prefix match.
- { "think", "\"thi\"", "" },
-
- // Prefix matches against multiple candidates.
- { "abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4" },
-
- // Prefix match on the first term.
- { "abc", "a", "abc" },
-
- // Prefix match on subsequent terms.
- { "abc def", "abc d", "abc def" },
-
- // Exact and prefix match.
- { "ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef;abcd cdefg" },
- };
- for (size_t i = 0; i < base::size(data); ++i) {
- std::vector<TitleAndURL> bookmarks;
- for (const std::string& title : base::SplitString(
- data[i].titles, ";",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
- TitleAndURL bookmark(title, kAboutBlankURL);
- bookmarks.push_back(bookmark);
- }
- AddBookmarks(bookmarks);
-
- std::vector<std::string> expected;
- if (!data[i].expected.empty()) {
- expected = base::SplitString(data[i].expected, ";",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- }
-
- ExpectMatches(data[i].query,
- query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH,
- expected);
-
- model_ = TestBookmarkClient::CreateModel();
- }
-}
-
-// Analogous to GetBookmarksMatching, this test tests various permutations
-// of title, URL, and input to see if the title/URL matches the input as
-// expected.
-TEST_F(BookmarkIndexTest, GetBookmarksMatchingWithURLs) {
- struct TestData {
- const std::string query;
- const std::string title;
- const std::string url;
- const bool should_be_retrieved;
- } data[] = {
- // Test single-word inputs. Include both exact matches and prefix matches.
- { "foo", "Foo", "http://www.bar.com/", true },
- { "foo", "Foodie", "http://www.bar.com/", true },
- { "foo", "Bar", "http://www.foo.com/", true },
- { "foo", "Bar", "http://www.foodie.com/", true },
- { "foo", "Foo", "http://www.foo.com/", true },
- { "foo", "Bar", "http://www.bar.com/", false },
- { "foo", "Bar", "http://www.bar.com/blah/foo/blah-again/ ", true },
- { "foo", "Bar", "http://www.bar.com/blah/foodie/blah-again/ ", true },
- { "foo", "Bar", "http://www.bar.com/blah-foo/blah-again/ ", true },
- { "foo", "Bar", "http://www.bar.com/blah-foodie/blah-again/ ", true },
- { "foo", "Bar", "http://www.bar.com/blahafoo/blah-again/ ", false },
-
- // Test multi-word inputs.
- { "foo bar", "Foo Bar", "http://baz.com/", true },
- { "foo bar", "Foodie Bar", "http://baz.com/", true },
- { "bar foo", "Foo Bar", "http://baz.com/", true },
- { "bar foo", "Foodie Barly", "http://baz.com/", true },
- { "foo bar", "Foo Baz", "http://baz.com/", false },
- { "foo bar", "Foo Baz", "http://bar.com/", true },
- { "foo bar", "Foo Baz", "http://barly.com/", true },
- { "foo bar", "Foodie Baz", "http://barly.com/", true },
- { "bar foo", "Foo Baz", "http://bar.com/", true },
- { "bar foo", "Foo Baz", "http://barly.com/", true },
- { "foo bar", "Baz Bar", "http://blah.com/foo", true },
- { "foo bar", "Baz Barly", "http://blah.com/foodie", true },
- { "foo bar", "Baz Bur", "http://blah.com/foo/bar", true },
- { "foo bar", "Baz Bur", "http://blah.com/food/barly", true },
- { "foo bar", "Baz Bur", "http://bar.com/blah/foo", true },
- { "foo bar", "Baz Bur", "http://barly.com/blah/food", true },
- { "foo bar", "Baz Bur", "http://bar.com/blah/flub", false },
- { "foo bar", "Baz Bur", "http://foo.com/blah/flub", false }
- };
-
- for (size_t i = 0; i < base::size(data); ++i) {
- model_ = TestBookmarkClient::CreateModel();
- std::vector<TitleAndURL> bookmarks;
- bookmarks.push_back(TitleAndURL(data[i].title, data[i].url));
- AddBookmarks(bookmarks);
-
- std::vector<std::string> expected;
- if (data[i].should_be_retrieved)
- expected.push_back(data[i].title);
-
- ExpectMatches(data[i].query, query_parser::MatchingAlgorithm::DEFAULT,
- expected);
- }
-}
-
-TEST_F(BookmarkIndexTest, Normalization) {
- struct TestData {
- const char* const title;
- const char* const query;
- } data[] = {
- { "fooa\xcc\x88-test", "foo\xc3\xa4-test" },
- { "fooa\xcc\x88-test", "fooa\xcc\x88-test" },
- { "fooa\xcc\x88-test", "foo\xc3\xa4" },
- { "fooa\xcc\x88-test", "fooa\xcc\x88" },
- { "fooa\xcc\x88-test", "foo" },
- { "foo\xc3\xa4-test", "foo\xc3\xa4-test" },
- { "foo\xc3\xa4-test", "fooa\xcc\x88-test" },
- { "foo\xc3\xa4-test", "foo\xc3\xa4" },
- { "foo\xc3\xa4-test", "fooa\xcc\x88" },
- { "foo\xc3\xa4-test", "foo" },
- { "foo", "foo" }
- };
-
- GURL url(kAboutBlankURL);
- for (size_t i = 0; i < base::size(data); ++i) {
- model_->AddURL(model_->other_node(), 0, UTF8ToUTF16(data[i].title), url);
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(UTF8ToUTF16(data[i].query), 10, &matches);
- EXPECT_EQ(1u, matches.size());
- model_ = TestBookmarkClient::CreateModel();
- }
-}
-
-// Makes sure match positions are updated appropriately for title matches.
-TEST_F(BookmarkIndexTest, MatchPositionsTitles) {
- struct TestData {
- const std::string title;
- const std::string query;
- const std::string expected_title_match_positions;
- } data[] = {
- // Trivial test case of only one term, exact match.
- { "a", "A", "0,1" },
- { "foo bar", "bar", "4,7" },
- { "fooey bark", "bar foo", "0,3:6,9" },
- // Non-trivial tests.
- { "foobar foo", "foobar foo", "0,6:7,10" },
- { "foobar foo", "foo foobar", "0,6:7,10" },
- { "foobar foobar", "foobar foo", "0,6:7,13" },
- { "foobar foobar", "foo foobar", "0,6:7,13" },
- };
- for (size_t i = 0; i < base::size(data); ++i) {
- std::vector<TitleAndURL> bookmarks;
- TitleAndURL bookmark(data[i].title, kAboutBlankURL);
- bookmarks.push_back(bookmark);
- AddBookmarks(bookmarks);
-
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(ASCIIToUTF16(data[i].query), 1000, &matches);
- ASSERT_EQ(1U, matches.size());
-
- TitledUrlMatch::MatchPositions expected_title_matches;
- ExtractMatchPositions(data[i].expected_title_match_positions,
- &expected_title_matches);
- ExpectMatchPositions(matches[0].title_match_positions,
- expected_title_matches);
-
- model_ = TestBookmarkClient::CreateModel();
- }
-}
-
-// Makes sure match positions are updated appropriately for URL matches.
-TEST_F(BookmarkIndexTest, MatchPositionsURLs) {
- // The encoded stuff between /wiki/ and the # is 第二次世界大戦
- const std::string ja_wiki_url = "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4"
- "%BA%8C%E6%AC%A1%E4%B8%96%E7%95%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7"
- ".E3.83.AB.E3.82.B5.E3.82.A4.E3.83.A6.E4.BD.93.E5.88.B6";
- struct TestData {
- const std::string query;
- const std::string url;
- const std::string expected_url_match_positions;
- } data[] = {
- { "foo", "http://www.foo.com/", "11,14" },
- { "foo", "http://www.foodie.com/", "11,14" },
- { "foo", "http://www.foofoo.com/", "11,14" },
- { "www", "http://www.foo.com/", "7,10" },
- { "foo", "http://www.foodie.com/blah/foo/fi", "11,14:27,30" },
- { "foo", "http://www.blah.com/blah/foo/fi", "25,28" },
- { "foo www", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
- { "www foo", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30" },
- { "www bla", "http://www.foodie.com/blah/foo/fi", "7,10:22,25" },
- { "http", "http://www.foo.com/", "0,4" },
- { "http www", "http://www.foo.com/", "0,4:7,10" },
- { "http foo", "http://www.foo.com/", "0,4:11,14" },
- { "http foo", "http://www.bar.com/baz/foodie/hi", "0,4:23,26" },
- { "第二次", ja_wiki_url, "29,56" },
- { "ja 第二次", ja_wiki_url, "7,9:29,56" },
- { "第二次 E3.8", ja_wiki_url, "29,56:94,98:103,107:"
- "112,116:121,125:"
- "130,134:139,143" }
- };
-
- for (size_t i = 0; i < base::size(data); ++i) {
- model_ = TestBookmarkClient::CreateModel();
- std::vector<TitleAndURL> bookmarks;
- TitleAndURL bookmark("123456", data[i].url);
- bookmarks.push_back(bookmark);
- AddBookmarks(bookmarks);
-
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(UTF8ToUTF16(data[i].query), 1000, &matches);
- ASSERT_EQ(1U, matches.size()) << data[i].url << data[i].query;
-
- TitledUrlMatch::MatchPositions expected_url_matches;
- ExtractMatchPositions(data[i].expected_url_match_positions,
- &expected_url_matches);
- ExpectMatchPositions(matches[0].url_match_positions, expected_url_matches);
- }
-}
-
-// Makes sure index is updated when a node is removed.
-TEST_F(BookmarkIndexTest, Remove) {
- const char* titles[] = { "a", "b" };
- const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
- AddBookmarks(titles, urls, base::size(titles));
-
- // Remove the node and make sure we don't get back any results.
- model_->Remove(model_->other_node()->children().front().get());
- ExpectMatches("A", nullptr, 0U);
-}
-
-// Makes sure index is updated when a node's title is changed.
-TEST_F(BookmarkIndexTest, ChangeTitle) {
- const char* titles[] = { "a", "b" };
- const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
- AddBookmarks(titles, urls, base::size(titles));
-
- // Remove the node and make sure we don't get back any results.
- const char* expected[] = { "blah" };
- model_->SetTitle(model_->other_node()->children().front().get(),
- ASCIIToUTF16("blah"));
- ExpectMatches("BlAh", expected, base::size(expected));
-}
-
-// Makes sure index is updated when a node's URL is changed.
-TEST_F(BookmarkIndexTest, ChangeURL) {
- const char* titles[] = { "a", "b" };
- const char* urls[] = {"http://fizz",
- "http://fuzz"};
- AddBookmarks(titles, urls, base::size(titles));
-
- const char* expected[] = { "a" };
- model_->SetURL(model_->other_node()->children().front().get(),
- GURL("http://blah"));
- ExpectMatches("blah", expected, base::size(expected));
-}
-
-// Makes sure no more than max queries is returned.
-TEST_F(BookmarkIndexTest, HonorMax) {
- const char* titles[] = { "abcd", "abcde" };
- const char* urls[] = {kAboutBlankURL, kAboutBlankURL};
- AddBookmarks(titles, urls, base::size(titles));
-
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(ASCIIToUTF16("ABc"), 1, &matches);
- EXPECT_EQ(1U, matches.size());
-}
-
-// Makes sure if the lower case string of a bookmark title is more characters
-// than the upper case string no match positions are returned.
-TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
- const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0,
- base::WideToUTF16(L"\u0130 i"),
- GURL("http://www.google.com"));
-
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(ASCIIToUTF16("i"), 100, &matches);
- ASSERT_EQ(1U, matches.size());
- EXPECT_EQ(n1, matches[0].node);
- EXPECT_TRUE(matches[0].title_match_positions.empty());
-}
-
-TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
- struct TestData {
- const GURL url;
- const char* title;
- const int typed_count;
- } data[] = {
- { GURL("http://www.google.com/"), "Google", 100 },
- { GURL("http://maps.google.com/"), "Google Maps", 40 },
- { GURL("http://docs.google.com/"), "Google Docs", 50 },
- { GURL("http://reader.google.com/"), "Google Reader", 80 },
- };
-
- std::map<GURL, int> typed_count_map;
- for (size_t i = 0; i < base::size(data); ++i)
- typed_count_map.insert(std::make_pair(data[i].url, data[i].typed_count));
-
- std::unique_ptr<BookmarkModel> model =
- TestBookmarkClient::CreateModelWithClient(
- std::make_unique<BookmarkClientMock>(typed_count_map));
-
- for (size_t i = 0; i < base::size(data); ++i)
- // Populate the bookmark index.
- model->AddURL(
- model->other_node(), i, UTF8ToUTF16(data[i].title), data[i].url);
-
- // Populate match nodes.
- std::vector<TitledUrlMatch> matches;
- model->GetBookmarksMatching(ASCIIToUTF16("google"), 4, &matches);
-
- // The resulting order should be:
- // 1. Google (google.com) 100
- // 2. Google Reader (google.com/reader) 80
- // 3. Google Docs (docs.google.com) 50
- // 4. Google Maps (maps.google.com) 40
- ASSERT_EQ(4U, matches.size());
- EXPECT_EQ(data[0].url, matches[0].node->GetTitledUrlNodeUrl());
- EXPECT_EQ(data[3].url, matches[1].node->GetTitledUrlNodeUrl());
- EXPECT_EQ(data[2].url, matches[2].node->GetTitledUrlNodeUrl());
- EXPECT_EQ(data[1].url, matches[3].node->GetTitledUrlNodeUrl());
-
- matches.clear();
- // Select top two matches.
- model->GetBookmarksMatching(ASCIIToUTF16("google"), 2, &matches);
-
- ASSERT_EQ(2U, matches.size());
- EXPECT_EQ(data[0].url, matches[0].node->GetTitledUrlNodeUrl());
- EXPECT_EQ(data[3].url, matches[1].node->GetTitledUrlNodeUrl());
-}
-
-} // namespace
-} // namespace bookmarks
diff --git a/chromium/components/bookmarks/browser/bookmark_model.cc b/chromium/components/bookmarks/browser/bookmark_model.cc
index fffeb6341a2..9fc8906b5e9 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/guid.h"
#include "base/i18n/string_compare.h"
@@ -110,18 +110,6 @@ class EmptyUndoDelegate : public BookmarkUndoDelegate {
DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
};
-#if DCHECK_IS_ON()
-void AddGuidsToIndexRecursive(const BookmarkNode* node,
- std::set<std::string>* guid_index) {
- bool success = guid_index->insert(node->guid()).second;
- DCHECK(success);
-
- // Recurse through children.
- for (size_t i = node->children().size(); i > 0; --i)
- AddGuidsToIndexRecursive(node->children()[i - 1].get(), guid_index);
-}
-#endif // DCHECK_IS_ON()
-
} // namespace
// BookmarkModel --------------------------------------------------------------
@@ -730,26 +718,18 @@ void BookmarkModel::ResetDateFolderModified(const BookmarkNode* node) {
SetDateFolderModified(node, Time());
}
-void BookmarkModel::GetBookmarksMatching(const base::string16& text,
- size_t max_count,
- std::vector<TitledUrlMatch>* matches) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- GetBookmarksMatching(text, max_count,
- query_parser::MatchingAlgorithm::DEFAULT, matches);
-}
-
-void BookmarkModel::GetBookmarksMatching(
- const base::string16& text,
+std::vector<TitledUrlMatch> BookmarkModel::GetBookmarksMatching(
+ const base::string16& query,
size_t max_count,
query_parser::MatchingAlgorithm matching_algorithm,
- std::vector<TitledUrlMatch>* matches) {
+ bool match_ancestor_titles) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!loaded_)
- return;
+ return {};
- titled_url_index_->GetResultsMatching(text, max_count, matching_algorithm,
- matches);
+ return titled_url_index_->GetResultsMatching(
+ query, max_count, matching_algorithm, match_ancestor_titles);
}
void BookmarkModel::ClearStore() {
@@ -767,16 +747,16 @@ void BookmarkModel::RestoreRemovedNode(const BookmarkNode* parent,
// We might be restoring a folder node that have already contained a set of
// child nodes. We need to notify all of them.
- NotifyNodeAddedForAllDescendents(node_ptr);
+ NotifyNodeAddedForAllDescendants(node_ptr);
}
-void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
+void BookmarkModel::NotifyNodeAddedForAllDescendants(const BookmarkNode* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (size_t i = 0; i < node->children().size(); ++i) {
for (BookmarkModelObserver& observer : observers_)
observer.BookmarkNodeAdded(this, node, i);
- NotifyNodeAddedForAllDescendents(node->children()[i].get());
+ NotifyNodeAddedForAllDescendants(node->children()[i].get());
}
}
@@ -788,12 +768,6 @@ void BookmarkModel::RemoveNodeFromIndexRecursive(BookmarkNode* node) {
if (node->is_url())
titled_url_index_->Remove(node);
- // Note that |guid_index_| is used for DCHECK-enabled builds only.
-#if DCHECK_IS_ON()
- DCHECK(guid_index_.erase(node->guid()))
- << "Bookmark GUID missing in index: " << node->guid();
-#endif // DCHECK_IS_ON()
-
CancelPendingFaviconLoadRequests(node);
// Recurse through children.
@@ -827,10 +801,6 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
other_node_ = details->other_folder_node();
mobile_node_ = details->mobile_folder_node();
-#if DCHECK_IS_ON()
- AddGuidsToIndexRecursive(root_, &guid_index_);
-#endif // DCHECK_IS_ON()
-
titled_url_index_->SetNodeSorter(
std::make_unique<TypedCountSorter>(client_.get()));
// Sorting the permanent nodes has to happen on the main thread, so we do it
@@ -871,19 +841,15 @@ BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
return node_ptr;
}
-void BookmarkModel::AddNodeToIndexRecursive(BookmarkNode* node) {
+void BookmarkModel::AddNodeToIndexRecursive(const BookmarkNode* node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // TODO(crbug.com/1143246): add a DCHECK to validate that all nodes have
+ // unique GUID when it is guaranteed.
+
if (node->is_url())
titled_url_index_->Add(node);
- // The node's GUID must be unique. Note that |guid_index_| is used for
- // DCHECK-enabled builds only.
-#if DCHECK_IS_ON()
- DCHECK(guid_index_.insert(node->guid()).second)
- << "Duplicate bookmark GUID: " << node->guid();
-#endif // DCHECK_IS_ON()
-
for (const auto& child : node->children())
AddNodeToIndexRecursive(child.get());
}
diff --git a/chromium/components/bookmarks/browser/bookmark_model.h b/chromium/components/bookmarks/browser/bookmark_model.h
index 544b0630d29..317ef338f58 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.h
+++ b/chromium/components/bookmarks/browser/bookmark_model.h
@@ -244,18 +244,15 @@ class BookmarkModel : public BookmarkUndoProvider,
// combobox of most recently modified folders.
void ResetDateFolderModified(const BookmarkNode* node);
- // Returns up to |max_count| of bookmarks containing each term from |text|
- // in either the title or the URL. It uses default matching algorithm.
- void GetBookmarksMatching(const base::string16& text,
- size_t max_count,
- std::vector<TitledUrlMatch>* matches);
-
- // Returns up to |max_count| of bookmarks containing each term from |text|
- // in either the title or the URL.
- void GetBookmarksMatching(const base::string16& text,
- size_t max_count,
- query_parser::MatchingAlgorithm matching_algorithm,
- std::vector<TitledUrlMatch>* matches);
+ // Returns up to |max_count| bookmarks containing each term from |query| in
+ // either the title, URL, or, if |match_ancestor_titles| is true, the titles
+ // of ancestors. |matching_algorithm| determines the algorithm used by
+ // QueryParser internally to parse |query|.
+ std::vector<TitledUrlMatch> GetBookmarksMatching(
+ const base::string16& query,
+ size_t max_count,
+ query_parser::MatchingAlgorithm matching_algorithm,
+ bool match_ancestor_titles = false);
// Sets the store to NULL, making it so the BookmarkModel does not persist
// any changes to disk. This is only useful during testing to speed up
@@ -319,8 +316,8 @@ class BookmarkModel : public BookmarkUndoProvider,
size_t index,
std::unique_ptr<BookmarkNode> node) override;
- // Notifies the observers for adding every descedent of |node|.
- void NotifyNodeAddedForAllDescendents(const BookmarkNode* node);
+ // Notifies the observers for adding every descendant of |node|.
+ void NotifyNodeAddedForAllDescendants(const BookmarkNode* node);
// Removes the node from internal maps and recurses through all children. If
// the node is a url, its url is added to removed_urls.
@@ -337,8 +334,8 @@ class BookmarkModel : public BookmarkUndoProvider,
size_t index,
std::unique_ptr<BookmarkNode> node);
- // Adds |node| to |index_| and recursisvely invokes this for all children.
- void AddNodeToIndexRecursive(BookmarkNode* node);
+ // Adds |node| to |index_| and recursively invokes this for all children.
+ void AddNodeToIndexRecursive(const BookmarkNode* node);
// Returns true if the parent and index are valid.
bool IsValidIndex(const BookmarkNode* parent, size_t index, bool allow_end);
@@ -407,11 +404,6 @@ class BookmarkModel : public BookmarkUndoProvider,
std::unique_ptr<TitledUrlIndex> titled_url_index_;
-#if DCHECK_IS_ON()
- // GUID index used to verify uniqueness in DCHECK-enabled builds.
- std::set<std::string> guid_index_;
-#endif // DCHECK_IS_ON()
-
// Owned by |model_loader_|.
// WARNING: in some tests this does *not* refer to
// |ModelLoader::history_bookmark_model_|. This is because some tests
diff --git a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
index 64737900275..d0dfa866de7 100644
--- a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -744,16 +744,27 @@ TEST_F(BookmarkModelTest, RemoveAllUserBookmarks) {
TEST_F(BookmarkModelTest, SetTitle) {
const BookmarkNode* root = model_->bookmark_bar_node();
base::string16 title(ASCIIToUTF16("foo"));
- const GURL url("http://foo.com");
+ const GURL url("http://url.com");
const BookmarkNode* node = model_->AddURL(root, 0, title, url);
ClearCounts();
- title = ASCIIToUTF16("foo2");
+ title = ASCIIToUTF16("goo");
model_->SetTitle(node, title);
AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0);
observer_details_.ExpectEquals(node, nullptr, size_t{-1}, size_t{-1});
EXPECT_EQ(title, node->GetTitle());
+
+ // Should update the index.
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT);
+ EXPECT_TRUE(matches.empty());
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("goo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT);
+ ASSERT_EQ(1u, matches.size());
+ EXPECT_EQ(url, matches[0].node->GetTitledUrlNodeUrl());
}
TEST_F(BookmarkModelTest, SetTitleWithWhitespace) {
@@ -770,6 +781,39 @@ TEST_F(BookmarkModelTest, SetTitleWithWhitespace) {
}
}
+TEST_F(BookmarkModelTest, SetFolderTitle) {
+ const BookmarkNode* root = model_->bookmark_bar_node();
+ const BookmarkNode* folder =
+ model_->AddFolder(root, 0, ASCIIToUTF16("folder"));
+ const base::string16 title(ASCIIToUTF16("foo"));
+ const GURL url("http://foo.com");
+ const BookmarkNode* node = model_->AddURL(folder, 0, title, url);
+ ClearCounts();
+
+ model_->SetTitle(folder, base::UTF8ToUTF16("golder"));
+
+ // Should not change the hierarchy.
+ EXPECT_EQ(root->children().size(), 1u);
+ EXPECT_EQ(root->children().front().get(), folder);
+ EXPECT_EQ(folder->children().size(), 1u);
+ EXPECT_EQ(folder->children().front().get(), node);
+ EXPECT_EQ(node->parent(), folder);
+
+ // Should update the index.
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_TRUE(matches.empty());
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("golder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ ASSERT_EQ(matches.size(), 1u);
+ EXPECT_EQ(matches[0].node, node);
+ EXPECT_EQ(matches[0].node->GetTitledUrlNodeUrl(), url);
+}
+
TEST_F(BookmarkModelTest, SetURL) {
const BookmarkNode* root = model_->bookmark_bar_node();
const base::string16 title(ASCIIToUTF16("foo"));
@@ -805,7 +849,8 @@ TEST_F(BookmarkModelTest, Move) {
const base::string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
const BookmarkNode* node = model_->AddURL(root, 0, title, url);
- const BookmarkNode* folder1 = model_->AddFolder(root, 0, ASCIIToUTF16("foo"));
+ const BookmarkNode* folder1 =
+ model_->AddFolder(root, 0, ASCIIToUTF16("folder"));
ClearCounts();
model_->Move(node, folder1, 0);
@@ -818,6 +863,12 @@ TEST_F(BookmarkModelTest, Move) {
EXPECT_EQ(1u, folder1->children().size());
EXPECT_EQ(node, folder1->children().front().get());
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+
// And remove the folder.
ClearCounts();
model_->Remove(root->children().front().get());
@@ -825,6 +876,11 @@ TEST_F(BookmarkModelTest, Move) {
observer_details_.ExpectEquals(root, nullptr, 0, size_t{-1});
EXPECT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == nullptr);
EXPECT_EQ(0u, root->children().size());
+
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT);
+ EXPECT_TRUE(matches.empty());
}
TEST_F(BookmarkModelTest, NonMovingMoveCall) {
@@ -843,6 +899,111 @@ TEST_F(BookmarkModelTest, NonMovingMoveCall) {
EXPECT_EQ(old_date, root->date_folder_modified());
}
+TEST_F(BookmarkModelTest, MoveURLFromFolder) {
+ const BookmarkNode* root = model_->bookmark_bar_node();
+ const BookmarkNode* folder1 =
+ model_->AddFolder(root, 0, ASCIIToUTF16("folder"));
+ const BookmarkNode* folder2 =
+ model_->AddFolder(root, 0, ASCIIToUTF16("golder"));
+ const base::string16 title(ASCIIToUTF16("foo"));
+ const GURL url("http://foo.com");
+ const BookmarkNode* node = model_->AddURL(folder1, 0, title, url);
+ ClearCounts();
+
+ model_->Move(node, folder2, 0);
+
+ // Should update the hierarchy.
+ AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0);
+ observer_details_.ExpectEquals(folder1, folder2, 0, 0);
+ EXPECT_EQ(root->children().size(), 2u);
+ EXPECT_EQ(folder1->children().size(), 0u);
+ EXPECT_EQ(folder2->children().size(), 1u);
+ EXPECT_EQ(folder2->children().front().get(), node);
+
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_TRUE(matches.empty());
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("golder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+ matches.clear();
+
+ // Move back.
+ ClearCounts();
+ model_->Move(node, folder1, 0);
+
+ // Should update the hierarchy.
+ AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0);
+ observer_details_.ExpectEquals(folder2, folder1, 0, 0);
+ EXPECT_EQ(root->children().size(), 2u);
+ EXPECT_EQ(folder1->children().size(), 1u);
+ EXPECT_EQ(folder2->children().size(), 0u);
+ EXPECT_EQ(folder1->children().front().get(), node);
+
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+ matches.clear();
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("golder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_TRUE(matches.empty());
+}
+
+TEST_F(BookmarkModelTest, MoveFolder) {
+ const BookmarkNode* root = model_->bookmark_bar_node();
+ const BookmarkNode* folder1 =
+ model_->AddFolder(root, 0, ASCIIToUTF16("folder"));
+ const BookmarkNode* folder2 =
+ model_->AddFolder(root, 1, ASCIIToUTF16("golder"));
+ const BookmarkNode* folder3 =
+ model_->AddFolder(folder1, 0, ASCIIToUTF16("holder"));
+ const base::string16 title(ASCIIToUTF16("foo"));
+ const GURL url("http://foo.com");
+ const BookmarkNode* node = model_->AddURL(folder3, 0, title, url);
+ ClearCounts();
+
+ model_->Move(folder3, folder2, 0);
+
+ // Should update the hierarchy.
+ AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0);
+ observer_details_.ExpectEquals(folder1, folder2, 0, 0);
+ EXPECT_EQ(root->children().size(), 2u);
+ EXPECT_EQ(root->children()[0].get(), folder1);
+ EXPECT_EQ(root->children()[1].get(), folder2);
+ EXPECT_EQ(folder1->children().size(), 0u);
+ EXPECT_EQ(folder2->children().size(), 1u);
+ EXPECT_EQ(folder2->children()[0].get(), folder3);
+ EXPECT_EQ(folder3->children().size(), 1u);
+ EXPECT_EQ(folder3->children()[0].get(), node);
+
+ // Should update the index.
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_TRUE(matches.empty());
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("golder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+ matches.clear();
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("holder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+ matches.clear();
+}
+
TEST_F(BookmarkModelTest, Copy) {
const BookmarkNode* root = model_->bookmark_bar_node();
static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h ");
@@ -1228,11 +1389,127 @@ TEST_F(BookmarkModelTest, RenamedFolderNodeExcludedFromIndex) {
model_->SetTitle(folder, ASCIIToUTF16("MyBookmarks"));
// There should be no matching bookmarks.
- std::vector<TitledUrlMatch> matches;
- model_->GetBookmarksMatching(ASCIIToUTF16("MyB"), /*max_count = */ 1,
- query_parser::MatchingAlgorithm::DEFAULT,
- &matches);
+ std::vector<TitledUrlMatch> matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("MyB"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT);
+ EXPECT_TRUE(matches.empty());
+}
+
+TEST_F(BookmarkModelTest, GetBookmarksMatching) {
+ const BookmarkNode* root = model_->bookmark_bar_node();
+ const BookmarkNode* folder =
+ model_->AddFolder(root, 0, ASCIIToUTF16("folder"));
+ const base::string16 title(ASCIIToUTF16("foo"));
+ const GURL url("http://foo.com");
+ const BookmarkNode* node = model_->AddURL(folder, 0, title, url);
+
+ // Should not match paths by default.
+ auto matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT);
EXPECT_TRUE(matches.empty());
+
+ // Should not match incorrect paths.
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("golder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_TRUE(matches.empty());
+
+ // Should match correct paths.
+ matches =
+ model_->GetBookmarksMatching(ASCIIToUTF16("folder foo"), /*max_count=*/1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ /*match_ancestor_titles= */ true);
+ EXPECT_EQ(matches[0].node, node);
+}
+
+// Verifies that TitledUrlIndex is updated when a bookmark is removed.
+TEST_F(BookmarkModelTest, TitledUrlIndexUpdatedOnRemove) {
+ const base::string16 title = base::ASCIIToUTF16("Title");
+ const GURL url("http://google.com");
+ const BookmarkNode* root = model_->bookmark_bar_node();
+
+ model_->AddURL(root, 0, title, url);
+ ASSERT_EQ(1U, model_
+ ->GetBookmarksMatching(
+ title, 1, query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+
+ // Remove the node and make sure we don't get back any results.
+ model_->Remove(root->children().front().get());
+ EXPECT_EQ(0U, model_
+ ->GetBookmarksMatching(
+ title, 1, query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+}
+
+// Verifies that TitledUrlIndex is updated when a bookmark's title changes.
+TEST_F(BookmarkModelTest, TitledUrlIndexUpdatedOnChangeTitle) {
+ const base::string16 initial_title = base::ASCIIToUTF16("Initial");
+ const base::string16 new_title = base::ASCIIToUTF16("New");
+ const GURL url("http://google.com");
+ const BookmarkNode* root = model_->bookmark_bar_node();
+
+ model_->AddURL(root, 0, initial_title, url);
+ ASSERT_EQ(1U,
+ model_
+ ->GetBookmarksMatching(initial_title, 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+ ASSERT_EQ(0U, model_
+ ->GetBookmarksMatching(
+ new_title, 1, query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+
+ // Change the title.
+ model_->SetTitle(root->children().front().get(), new_title);
+
+ // Verify that we only get results for the new title.
+ EXPECT_EQ(0U,
+ model_
+ ->GetBookmarksMatching(initial_title, 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+ EXPECT_EQ(1U, model_
+ ->GetBookmarksMatching(
+ new_title, 1, query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+}
+
+// Verifies that TitledUrlIndex is updated when a bookmark's URL changes.
+TEST_F(BookmarkModelTest, TitledUrlIndexUpdatedOnChangeURL) {
+ const base::string16 title = base::ASCIIToUTF16("Title");
+ const GURL initial_url("http://initial");
+ const GURL new_url("http://new");
+ const BookmarkNode* root = model_->bookmark_bar_node();
+
+ model_->AddURL(root, 0, title, initial_url);
+ ASSERT_EQ(1U,
+ model_
+ ->GetBookmarksMatching(base::ASCIIToUTF16("initial"), 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+ ASSERT_EQ(0U,
+ model_
+ ->GetBookmarksMatching(base::ASCIIToUTF16("new"), 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+
+ // Change the URL.
+ model_->SetURL(root->children().front().get(), new_url);
+
+ // Verify that we only get results for the new URL.
+ EXPECT_EQ(0U,
+ model_
+ ->GetBookmarksMatching(base::ASCIIToUTF16("initial"), 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
+ EXPECT_EQ(1U,
+ model_
+ ->GetBookmarksMatching(base::ASCIIToUTF16("new"), 1,
+ query_parser::MatchingAlgorithm::DEFAULT)
+ .size());
}
// Verifies the TitledUrlIndex is probably loaded.
@@ -1260,10 +1537,8 @@ TEST(BookmarkModelLoadTest, TitledUrlIndexPopulatedOnLoad) {
model->Load(nullptr, tmp_dir.GetPath());
test::WaitForBookmarkModelToLoad(model.get());
- std::vector<TitledUrlMatch> matches;
- model->GetBookmarksMatching(base::ASCIIToUTF16("user"), 1,
- query_parser::MatchingAlgorithm::DEFAULT,
- &matches);
+ std::vector<TitledUrlMatch> matches = model->GetBookmarksMatching(
+ base::ASCIIToUTF16("user"), 1, query_parser::MatchingAlgorithm::DEFAULT);
ASSERT_EQ(1u, matches.size());
EXPECT_EQ(node_url, matches[0].node->GetTitledUrlNodeUrl());
}
diff --git a/chromium/components/bookmarks/browser/bookmark_node.cc b/chromium/components/bookmarks/browser/bookmark_node.cc
index 38c9e2319d5..35720494efe 100644
--- a/chromium/components/bookmarks/browser/bookmark_node.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node.cc
@@ -9,6 +9,7 @@
#include "base/guid.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/strings/grit/components_strings.h"
@@ -118,6 +119,14 @@ const GURL& BookmarkNode::GetTitledUrlNodeUrl() const {
return url_;
}
+std::vector<base::StringPiece16> BookmarkNode::GetTitledUrlNodeAncestorTitles()
+ const {
+ std::vector<base::StringPiece16> paths;
+ for (const BookmarkNode* n = this; n->parent(); n = n->parent())
+ paths.push_back(n->parent()->GetTitle());
+ return paths;
+}
+
BookmarkNode::BookmarkNode(int64_t id,
const std::string& guid,
const GURL& url,
diff --git a/chromium/components/bookmarks/browser/bookmark_node.h b/chromium/components/bookmarks/browser/bookmark_node.h
index cae4e89fdb3..9ef6df24fb5 100644
--- a/chromium/components/bookmarks/browser/bookmark_node.h
+++ b/chromium/components/bookmarks/browser/bookmark_node.h
@@ -12,6 +12,7 @@
#include <string>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/bookmarks/browser/titled_url_node.h"
@@ -127,6 +128,8 @@ class BookmarkNode : public ui::TreeNode<BookmarkNode>, public TitledUrlNode {
// TitledUrlNode interface methods.
const base::string16& GetTitledUrlNodeTitle() const override;
const GURL& GetTitledUrlNodeUrl() const override;
+ std::vector<base::StringPiece16> GetTitledUrlNodeAncestorTitles()
+ const override;
// TODO(sky): Consider adding last visit time here, it'll greatly simplify
// HistoryContentsProvider.
@@ -199,7 +202,7 @@ class BookmarkNode : public ui::TreeNode<BookmarkNode>, public TitledUrlNode {
// If not base::CancelableTaskTracker::kBadTaskId, it indicates
// we're loading the
- // favicon and the task is tracked by CancelabelTaskTracker.
+ // favicon and the task is tracked by CancelableTaskTracker.
base::CancelableTaskTracker::TaskId favicon_load_task_id_ =
base::CancelableTaskTracker::kBadTaskId;
diff --git a/chromium/components/bookmarks/browser/bookmark_node_data.cc b/chromium/components/bookmarks/browser/bookmark_node_data.cc
index b54c35d0c5f..612478bff64 100644
--- a/chromium/components/bookmarks/browser/bookmark_node_data.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node_data.cc
@@ -138,9 +138,11 @@ BookmarkNodeData::~BookmarkNodeData() {
#if !defined(OS_APPLE)
// static
bool BookmarkNodeData::ClipboardContainsBookmarks() {
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
ui::ClipboardFormatType::GetType(kClipboardFormatString),
- ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr);
+ ui::ClipboardBuffer::kCopyPaste, &data_dst);
}
#endif
diff --git a/chromium/components/bookmarks/browser/bookmark_utils.cc b/chromium/components/bookmarks/browser/bookmark_utils.cc
index c9fa2abc493..deda4927e68 100644
--- a/chromium/components/bookmarks/browser/bookmark_utils.cc
+++ b/chromium/components/bookmarks/browser/bookmark_utils.cc
@@ -31,6 +31,7 @@
#include "components/query_parser/query_parser.h"
#include "components/url_formatter/url_formatter.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/models/tree_node_iterator.h"
#include "url/gurl.h"
@@ -142,11 +143,13 @@ std::string TruncateUrl(const std::string& url) {
// Returns the URL from the clipboard. If there is no URL an empty URL is
// returned.
-GURL GetUrlFromClipboard() {
+GURL GetUrlFromClipboard(bool notify_if_restricted) {
base::string16 url_text;
#if !defined(OS_IOS)
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, notify_if_restricted);
ui::Clipboard::GetForCurrentThread()->ReadText(
- ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr, &url_text);
+ ui::ClipboardBuffer::kCopyPaste, &data_dst, &url_text);
#endif
return GURL(url_text);
}
@@ -290,7 +293,7 @@ void PasteFromClipboard(BookmarkModel* model,
BookmarkNodeData bookmark_data;
if (!bookmark_data.ReadFromClipboard(ui::ClipboardBuffer::kCopyPaste)) {
- GURL url = GetUrlFromClipboard();
+ GURL url = GetUrlFromClipboard(/*notify_if_restricted=*/true);
if (!url.is_valid())
return;
BookmarkNode node(/*id=*/0, base::GenerateGUID(), url);
@@ -315,7 +318,7 @@ bool CanPasteFromClipboard(BookmarkModel* model, const BookmarkNode* node) {
if (!node || !model->client()->CanBeEditedByUser(node))
return false;
return (BookmarkNodeData::ClipboardContainsBookmarks() ||
- GetUrlFromClipboard().is_valid());
+ GetUrlFromClipboard(/*notify_if_restricted=*/false).is_valid());
}
std::vector<const BookmarkNode*> GetMostRecentlyModifiedUserFolders(
diff --git a/chromium/components/bookmarks/browser/model_loader.cc b/chromium/components/bookmarks/browser/model_loader.cc
index 28d04dcb55c..3335915a0c2 100644
--- a/chromium/components/bookmarks/browser/model_loader.cc
+++ b/chromium/components/bookmarks/browser/model_loader.cc
@@ -5,7 +5,6 @@
#include "components/bookmarks/browser/model_loader.h"
#include "base/bind.h"
-#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
@@ -23,11 +22,6 @@ namespace bookmarks {
namespace {
-// TODO(mastiz): Remove this kill switch asap since the UMA metrics entail
-// negligible risks for stability or performance overhead.
-const base::Feature kEmitExperimentalBookmarkLoadUma{
- "EmitExperimentalBookmarkLoadUma", base::FEATURE_ENABLED_BY_DEFAULT};
-
// Adds node to the model's index, recursing through all children as well.
void AddBookmarksToIndex(BookmarkLoadDetails* details, BookmarkNode* node) {
if (node->is_url()) {
@@ -39,46 +33,9 @@ void AddBookmarksToIndex(BookmarkLoadDetails* details, BookmarkNode* node) {
}
}
-// Helper function to recursively traverse the bookmark tree and count the
-// number of bookmarks (excluding folders) per URL (more precisely, per URL
-// hash).
-void PopulateNumNodesPerUrlHash(
- const BookmarkNode* node,
- std::unordered_map<size_t, int>* num_nodes_per_url_hash) {
- DCHECK(num_nodes_per_url_hash);
- DCHECK(node);
-
- if (!node->is_folder())
- (*num_nodes_per_url_hash)[std::hash<std::string>()(node->url().spec())]++;
-
- for (const auto& child : node->children())
- PopulateNumNodesPerUrlHash(child.get(), num_nodes_per_url_hash);
-}
-
-// Computes the number of bookmarks (excluding folders) with a URL that is used
-// by at least one other bookmark.
-int GetNumDuplicateUrls(const BookmarkNode* root) {
- DCHECK(root);
-
- // The key is hash of the URL, instead of the full URL, to keep memory usage
- // low. The value indicates the node count.
- std::unordered_map<size_t, int> num_nodes_per_url_hash;
- PopulateNumNodesPerUrlHash(root, &num_nodes_per_url_hash);
-
- int num_duplicate_urls = 0;
- for (const auto& url_hash_and_count : num_nodes_per_url_hash) {
- if (url_hash_and_count.second > 1)
- num_duplicate_urls += url_hash_and_count.second;
- }
- return num_duplicate_urls;
-}
-
// Loads the bookmarks. This is intended to be called on the background thread.
-// Updates state in |details| based on the load. |emit_experimental_uma|
-// determines whether a few newly introduced and experimental UMA metrics should
-// be logged.
+// Updates state in |details| based on the load.
void LoadBookmarks(const base::FilePath& path,
- bool emit_experimental_uma,
BookmarkLoadDetails* details) {
bool load_index = false;
bool bookmark_file_exists = base::PathExists(path);
@@ -96,7 +53,6 @@ void LoadBookmarks(const base::FilePath& path,
int64_t max_node_id = 0;
std::string sync_metadata_str;
BookmarkCodec codec;
- base::TimeTicks start_time = base::TimeTicks::Now();
codec.Decode(*root, details->bb_node(), details->other_folder_node(),
details->mobile_folder_node(), &max_node_id,
&sync_metadata_str);
@@ -107,8 +63,6 @@ void LoadBookmarks(const base::FilePath& path,
details->set_ids_reassigned(codec.ids_reassigned());
details->set_guids_reassigned(codec.guids_reassigned());
details->set_model_meta_info_map(codec.model_meta_info_map());
- base::UmaHistogramTimes("Bookmarks.DecodeTime",
- base::TimeTicks::Now() - start_time);
load_index = true;
}
@@ -120,30 +74,57 @@ void LoadBookmarks(const base::FilePath& path,
// Load any extra root nodes now, after the IDs have been potentially
// reassigned.
if (load_index) {
- base::TimeTicks start_time = base::TimeTicks::Now();
AddBookmarksToIndex(details, details->root_node());
- base::UmaHistogramTimes("Bookmarks.CreateBookmarkIndexTime",
- base::TimeTicks::Now() - start_time);
}
details->CreateUrlIndex();
+ UrlIndex::Stats stats = details->url_index()->ComputeStats();
+
+ DCHECK_LE(stats.duplicate_url_bookmark_count, stats.total_url_bookmark_count);
+ DCHECK_LE(stats.duplicate_url_and_title_bookmark_count,
+ stats.duplicate_url_bookmark_count);
+ DCHECK_LE(stats.duplicate_url_and_title_and_parent_bookmark_count,
+ stats.duplicate_url_and_title_bookmark_count);
+
base::UmaHistogramCounts100000(
"Bookmarks.Count.OnProfileLoad",
- base::saturated_cast<int>(details->url_index()->UrlCount()));
+ base::saturated_cast<int>(stats.total_url_bookmark_count));
- if (emit_experimental_uma && details->root_node()) {
- base::TimeTicks start_time = base::TimeTicks::Now();
+ if (stats.duplicate_url_bookmark_count != 0) {
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.DuplicateUrl2",
+ base::saturated_cast<int>(stats.duplicate_url_bookmark_count));
+ }
- int num_duplicate_urls = GetNumDuplicateUrls(details->root_node());
- if (num_duplicate_urls > 0) {
- base::UmaHistogramCounts10000(
- "Bookmarks.Count.OnProfileLoad.DuplicateUrl", num_duplicate_urls);
- }
+ if (stats.duplicate_url_and_title_bookmark_count != 0) {
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.DuplicateUrlAndTitle",
+ base::saturated_cast<int>(
+ stats.duplicate_url_and_title_bookmark_count));
+ }
- base::UmaHistogramTimes("Bookmarks.DuplicateAndEmptyTitleDetectionTime",
- base::TimeTicks::Now() - start_time);
+ if (stats.duplicate_url_and_title_and_parent_bookmark_count != 0) {
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.DuplicateUrlAndTitleAndParent",
+ base::saturated_cast<int>(
+ stats.duplicate_url_and_title_and_parent_bookmark_count));
}
+
+ // Log derived metrics for convenience.
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.UniqueUrl",
+ base::saturated_cast<int>(stats.total_url_bookmark_count -
+ stats.duplicate_url_bookmark_count));
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.UniqueUrlAndTitle",
+ base::saturated_cast<int>(stats.total_url_bookmark_count -
+ stats.duplicate_url_and_title_bookmark_count));
+ base::UmaHistogramCounts100000(
+ "Bookmarks.Count.OnProfileLoad.UniqueUrlAndTitleAndParent",
+ base::saturated_cast<int>(
+ stats.total_url_bookmark_count -
+ stats.duplicate_url_and_title_and_parent_bookmark_count));
}
} // namespace
@@ -161,16 +142,10 @@ scoped_refptr<ModelLoader> ModelLoader::Create(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
- // We plumb the value for kEmitExperimentalBookmarkLoadUma as retrieved on
- // the UI thread to avoid issues with TSAN bots (in case there are tests that
- // override feature toggles -not necessarily this one- while bookmark loading
- // is ongoing, which is problematic due to how feature overriding for tests is
- // implemented).
model_loader->backend_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
&ModelLoader::DoLoadOnBackgroundThread, model_loader, profile_path,
- base::FeatureList::IsEnabled(kEmitExperimentalBookmarkLoadUma),
std::move(details)),
std::move(callback));
return model_loader;
@@ -188,9 +163,8 @@ ModelLoader::~ModelLoader() = default;
std::unique_ptr<BookmarkLoadDetails> ModelLoader::DoLoadOnBackgroundThread(
const base::FilePath& profile_path,
- bool emit_experimental_uma,
std::unique_ptr<BookmarkLoadDetails> details) {
- LoadBookmarks(profile_path, emit_experimental_uma, details.get());
+ LoadBookmarks(profile_path, details.get());
history_bookmark_model_ = details->url_index();
loaded_signal_.Signal();
return details;
diff --git a/chromium/components/bookmarks/browser/model_loader.h b/chromium/components/bookmarks/browser/model_loader.h
index 1c176fec9bb..ff3c3c43c7d 100644
--- a/chromium/components/bookmarks/browser/model_loader.h
+++ b/chromium/components/bookmarks/browser/model_loader.h
@@ -55,7 +55,6 @@ class ModelLoader : public base::RefCountedThreadSafe<ModelLoader> {
// Performs the load on a background thread.
std::unique_ptr<BookmarkLoadDetails> DoLoadOnBackgroundThread(
const base::FilePath& profile_path,
- bool emit_experimental_uma,
std::unique_ptr<BookmarkLoadDetails> details);
scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
diff --git a/chromium/components/bookmarks/browser/titled_url_index.cc b/chromium/components/bookmarks/browser/titled_url_index.cc
index dfe1181a268..61ffea3dad7 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.cc
+++ b/chromium/components/bookmarks/browser/titled_url_index.cc
@@ -60,44 +60,33 @@ void TitledUrlIndex::SetNodeSorter(
}
void TitledUrlIndex::Add(const TitledUrlNode* node) {
- std::vector<base::string16> terms =
- ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()));
- for (size_t i = 0; i < terms.size(); ++i)
- RegisterNode(terms[i], node);
- terms = ExtractQueryWords(
- CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), nullptr));
- for (size_t i = 0; i < terms.size(); ++i)
- RegisterNode(terms[i], node);
+ for (const base::string16& term : ExtractIndexTerms(node))
+ RegisterNode(term, node);
}
void TitledUrlIndex::Remove(const TitledUrlNode* node) {
- std::vector<base::string16> terms =
- ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()));
- for (size_t i = 0; i < terms.size(); ++i)
- UnregisterNode(terms[i], node);
- terms = ExtractQueryWords(
- CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), nullptr));
- for (size_t i = 0; i < terms.size(); ++i)
- UnregisterNode(terms[i], node);
+ for (const base::string16& term : ExtractIndexTerms(node))
+ UnregisterNode(term, node);
}
-void TitledUrlIndex::GetResultsMatching(
+std::vector<TitledUrlMatch> TitledUrlIndex::GetResultsMatching(
const base::string16& input_query,
size_t max_count,
query_parser::MatchingAlgorithm matching_algorithm,
- std::vector<TitledUrlMatch>* results) {
+ bool match_ancestor_titles) {
const base::string16 query = Normalize(input_query);
std::vector<base::string16> terms = ExtractQueryWords(query);
- if (terms.empty())
- return;
- TitledUrlNodeSet matches;
- for (size_t i = 0; i < terms.size(); ++i) {
- if (!GetResultsMatchingTerm(terms[i], i == 0, matching_algorithm,
- &matches)) {
- return;
- }
- }
+ // When |match_ancestor_titles| is true, |matches| shouldn't exclude nodes
+ // that don't match every query term, as the query terms may match in the
+ // ancestors. |MatchTitledUrlNodeWithQuery()| below will filter out nodes that
+ // neither match nor ancestor-match every query term.
+ TitledUrlNodeSet matches =
+ match_ancestor_titles
+ ? RetrieveNodesMatchingAnyTerms(terms, matching_algorithm)
+ : RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+ if (matches.empty())
+ return {};
TitledUrlNodes sorted_nodes;
SortMatches(matches, &sorted_nodes);
@@ -114,14 +103,19 @@ void TitledUrlIndex::GetResultsMatching(
// that calculates result relevance in HistoryContentsProvider::ConvertResults
// will run backwards to assure higher relevance will be attributed to the
// best matches.
+ std::vector<TitledUrlMatch> results;
for (TitledUrlNodes::const_iterator i = sorted_nodes.begin();
- i != sorted_nodes.end() && results->size() < max_count;
- ++i)
- AddMatchToResults(*i, &parser, query_nodes, results);
+ i != sorted_nodes.end() && results.size() < max_count; ++i) {
+ base::Optional<TitledUrlMatch> match = MatchTitledUrlNodeWithQuery(
+ *i, &parser, query_nodes, match_ancestor_titles);
+ if (match)
+ results.push_back(match.value());
+ }
+ return results;
}
void TitledUrlIndex::SortMatches(const TitledUrlNodeSet& matches,
- TitledUrlNodes* sorted_nodes) const {
+ TitledUrlNodes* sorted_nodes) const {
if (sorter_) {
sorter_->SortMatches(matches, sorted_nodes);
} else {
@@ -129,20 +123,20 @@ void TitledUrlIndex::SortMatches(const TitledUrlNodeSet& matches,
}
}
-void TitledUrlIndex::AddMatchToResults(
+base::Optional<TitledUrlMatch> TitledUrlIndex::MatchTitledUrlNodeWithQuery(
const TitledUrlNode* node,
query_parser::QueryParser* parser,
const query_parser::QueryNodeVector& query_nodes,
- std::vector<TitledUrlMatch>* results) {
+ bool match_ancestor_titles) {
if (!node) {
- return;
+ return base::nullopt;
}
// Check that the result matches the query. The previous search
// was a simple per-word search, while the more complex matching
// of QueryParser may filter it out. For example, the query
// ["thi"] will match the title [Thinking], but since
// ["thi"] is quoted we don't want to do a prefix match.
- query_parser::QueryWordVector title_words, url_words;
+ query_parser::QueryWordVector title_words, url_words, ancestor_words;
const base::string16 lower_title =
base::i18n::ToLower(Normalize(node->GetTitledUrlNodeTitle()));
parser->ExtractQueryWords(lower_title, &title_words);
@@ -150,16 +144,30 @@ void TitledUrlIndex::AddMatchToResults(
parser->ExtractQueryWords(
CleanUpUrlForMatching(node->GetTitledUrlNodeUrl(), &adjustments),
&url_words);
+ if (match_ancestor_titles) {
+ for (auto ancestor : node->GetTitledUrlNodeAncestorTitles()) {
+ parser->ExtractQueryWords(
+ base::i18n::ToLower(Normalize(base::string16(ancestor))),
+ &ancestor_words);
+ }
+ }
+
query_parser::Snippet::MatchPositions title_matches, url_matches;
+ bool query_has_ancestor_matches = false;
for (const auto& node : query_nodes) {
const bool has_title_matches =
node->HasMatchIn(title_words, &title_matches);
const bool has_url_matches = node->HasMatchIn(url_words, &url_matches);
- if (!has_title_matches && !has_url_matches)
- return;
+ const bool has_ancestor_matches =
+ match_ancestor_titles && node->HasMatchIn(ancestor_words);
+ query_has_ancestor_matches =
+ query_has_ancestor_matches || has_ancestor_matches;
+ if (!has_title_matches && !has_url_matches && !has_ancestor_matches)
+ return base::nullopt;
query_parser::QueryParser::SortAndCoalesceMatchPositions(&title_matches);
query_parser::QueryParser::SortAndCoalesceMatchPositions(&url_matches);
}
+
TitledUrlMatch match;
if (lower_title.length() == node->GetTitledUrlNodeTitle().length()) {
// Only use title matches if the lowercase string is the same length
@@ -176,53 +184,75 @@ void TitledUrlIndex::AddMatchToResults(
url_matches =
TitledUrlMatch::ReplaceOffsetsInMatchPositions(url_matches, offsets);
match.url_match_positions.swap(url_matches);
+ match.has_ancestor_match = query_has_ancestor_matches;
match.node = node;
- results->push_back(match);
+ return match;
}
-bool TitledUrlIndex::GetResultsMatchingTerm(
+TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAllTerms(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const {
+ if (terms.empty())
+ return {};
+
+ TitledUrlNodeSet matches =
+ RetrieveNodesMatchingTerm(terms[0], matching_algorithm);
+ for (size_t i = 1; i < terms.size() && !matches.empty(); ++i) {
+ TitledUrlNodeSet term_matches =
+ RetrieveNodesMatchingTerm(terms[i], matching_algorithm);
+ // Compute intersection between the two sets.
+ base::EraseIf(matches, base::IsNotIn<TitledUrlNodeSet>(term_matches));
+ }
+
+ return matches;
+}
+
+TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAnyTerms(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const {
+ if (terms.empty())
+ return {};
+
+ TitledUrlNodes matches =
+ RetrieveNodesMatchingTerm(terms[0], matching_algorithm);
+ for (size_t i = 1; i < terms.size(); ++i) {
+ TitledUrlNodes term_matches =
+ RetrieveNodesMatchingTerm(terms[i], matching_algorithm);
+ std::copy(term_matches.begin(), term_matches.end(),
+ std::back_inserter(matches));
+ }
+
+ return TitledUrlNodeSet(matches);
+}
+
+TitledUrlIndex::TitledUrlNodes TitledUrlIndex::RetrieveNodesMatchingTerm(
const base::string16& term,
- bool first_term,
- query_parser::MatchingAlgorithm matching_algorithm,
- TitledUrlNodeSet* matches) {
+ query_parser::MatchingAlgorithm matching_algorithm) const {
Index::const_iterator i = index_.lower_bound(term);
if (i == index_.end())
- return false;
+ return {};
if (!query_parser::QueryParser::IsWordLongEnoughForPrefixSearch(
term, matching_algorithm)) {
// Term is too short for prefix match, compare using exact match.
if (i->first != term)
- return false; // No title/URL pairs with this term.
+ return {}; // No title/URL pairs with this term.
+ return TitledUrlNodes(i->second.begin(), i->second.end());
+ }
- if (first_term) {
- (*matches) = i->second;
- return true;
- }
- base::EraseIf(*matches, base::IsNotIn<TitledUrlNodeSet>(i->second));
- } else {
- // Loop through index adding all entries that start with term to
- // |prefix_matches|.
- TitledUrlNodeSet tmp_prefix_matches;
- // If this is the first term, then store the result directly in |matches|
- // to avoid calling stl intersection (which requires a copy).
- TitledUrlNodeSet* prefix_matches =
- first_term ? matches : &tmp_prefix_matches;
- while (i != index_.end() &&
- i->first.size() >= term.size() &&
- term.compare(0, term.size(), i->first, 0, term.size()) == 0) {
- for (auto n = i->second.begin(); n != i->second.end(); ++n) {
- prefix_matches->insert(prefix_matches->end(), *n);
- }
- ++i;
- }
- if (!first_term) {
- base::EraseIf(*matches, base::IsNotIn<TitledUrlNodeSet>(*prefix_matches));
- }
+ // Loop through index adding all entries that start with term to
+ // |prefix_matches|.
+ TitledUrlNodes prefix_matches;
+ while (i != index_.end() && i->first.size() >= term.size() &&
+ term.compare(0, term.size(), i->first, 0, term.size()) == 0) {
+ prefix_matches.insert(prefix_matches.end(), i->second.begin(),
+ i->second.end());
+ ++i;
}
- return !matches->empty();
+ return prefix_matches;
}
+// static
std::vector<base::string16> TitledUrlIndex::ExtractQueryWords(
const base::string16& query) {
std::vector<base::string16> terms;
@@ -235,6 +265,24 @@ std::vector<base::string16> TitledUrlIndex::ExtractQueryWords(
return terms;
}
+// static
+std::vector<base::string16> TitledUrlIndex::ExtractIndexTerms(
+ const TitledUrlNode* node) {
+ std::vector<base::string16> terms;
+
+ for (const base::string16& term :
+ ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()))) {
+ terms.push_back(term);
+ }
+
+ for (const base::string16& term : ExtractQueryWords(CleanUpUrlForMatching(
+ node->GetTitledUrlNodeUrl(), /*adjustments=*/nullptr))) {
+ terms.push_back(term);
+ }
+
+ return terms;
+}
+
void TitledUrlIndex::RegisterNode(const base::string16& term,
const TitledUrlNode* node) {
index_[term].insert(node);
diff --git a/chromium/components/bookmarks/browser/titled_url_index.h b/chromium/components/bookmarks/browser/titled_url_index.h
index 37602fb4909..406dd55f8cb 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.h
+++ b/chromium/components/bookmarks/browser/titled_url_index.h
@@ -13,6 +13,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "components/bookmarks/browser/titled_url_node_sorter.h"
#include "components/query_parser/query_parser.h"
@@ -30,6 +31,8 @@ struct TitledUrlMatch;
// TitledUrlNodes that contain that string in their title or URL.
class TitledUrlIndex {
public:
+ using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
+
// Constructs a TitledUrlIndex. |sorter| is used to construct a sorted list
// of matches when matches are returned from the index. If null, matches are
// returned unsorted.
@@ -46,15 +49,31 @@ class TitledUrlIndex {
void Remove(const TitledUrlNode* node);
// Returns up to |max_count| of matches containing each term from the text
- // |query| in either the title or the URL.
- void GetResultsMatching(const base::string16& query,
- size_t max_count,
- query_parser::MatchingAlgorithm matching_algorithm,
- std::vector<TitledUrlMatch>* results);
+ // |query| in either the title, URL, or, if |match_ancestor_titles| is true,
+ // the titles of ancestor nodes. |matching_algorithm| determines the algorithm
+ // used by QueryParser internally to parse |query|.
+ std::vector<TitledUrlMatch> GetResultsMatching(
+ const base::string16& query,
+ size_t max_count,
+ query_parser::MatchingAlgorithm matching_algorithm,
+ bool match_ancestor_titles);
+
+ // For testing only.
+ TitledUrlNodeSet RetrieveNodesMatchingAllTermsForTesting(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const {
+ return RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+ }
+
+ // For testing only.
+ TitledUrlNodeSet RetrieveNodesMatchingAnyTermsForTesting(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const {
+ return RetrieveNodesMatchingAnyTerms(terms, matching_algorithm);
+ }
private:
using TitledUrlNodes = std::vector<const TitledUrlNode*>;
- using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
using Index = std::map<base::string16, TitledUrlNodeSet>;
// Constructs |sorted_nodes| by copying the matches in |matches| and sorting
@@ -62,23 +81,36 @@ class TitledUrlIndex {
void SortMatches(const TitledUrlNodeSet& matches,
TitledUrlNodes* sorted_nodes) const;
- // Add |node| to |results| if the node matches the query.
- void AddMatchToResults(const TitledUrlNode* node,
- query_parser::QueryParser* parser,
- const query_parser::QueryNodeVector& query_nodes,
- std::vector<TitledUrlMatch>* results);
-
- // Populates |matches| for the specified term. If |first_term| is true, this
- // is the first term in the query. Returns true if there is at least one node
- // matching the term.
- bool GetResultsMatchingTerm(
+ // Finds |query_nodes| matches in |node| and returns a TitledUrlMatch
+ // containing |node| and the matches.
+ base::Optional<TitledUrlMatch> MatchTitledUrlNodeWithQuery(
+ const TitledUrlNode* node,
+ query_parser::QueryParser* parser,
+ const query_parser::QueryNodeVector& query_nodes,
+ bool match_ancestor_titles);
+
+ // Return matches for the specified |terms|. This is an intersection of each
+ // term's matches.
+ TitledUrlNodeSet RetrieveNodesMatchingAllTerms(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const;
+
+ TitledUrlNodeSet RetrieveNodesMatchingAnyTerms(
+ const std::vector<base::string16>& terms,
+ query_parser::MatchingAlgorithm matching_algorithm) const;
+
+ // Return matches for the specified |term|. May return duplicates.
+ TitledUrlNodes RetrieveNodesMatchingTerm(
const base::string16& term,
- bool first_term,
- query_parser::MatchingAlgorithm matching_algorithm,
- TitledUrlNodeSet* matches);
+ query_parser::MatchingAlgorithm matching_algorithm) const;
// Returns the set of query words from |query|.
- std::vector<base::string16> ExtractQueryWords(const base::string16& query);
+ static std::vector<base::string16> ExtractQueryWords(
+ const base::string16& query);
+
+ // Return the index terms for |node|.
+ static std::vector<base::string16> ExtractIndexTerms(
+ const TitledUrlNode* node);
// Adds |node| to |index_|.
void RegisterNode(const base::string16& term, const TitledUrlNode* node);
diff --git a/chromium/components/bookmarks/browser/titled_url_index_unittest.cc b/chromium/components/bookmarks/browser/titled_url_index_unittest.cc
new file mode 100644
index 00000000000..cd12e71f7f3
--- /dev/null
+++ b/chromium/components/bookmarks/browser/titled_url_index_unittest.cc
@@ -0,0 +1,675 @@
+// Copyright 2014 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/bookmarks/browser/titled_url_index.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/titled_url_match.h"
+#include "components/bookmarks/browser/titled_url_node.h"
+#include "components/bookmarks/browser/typed_count_sorter.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/query_parser/query_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::UTF8ToUTF16;
+
+namespace bookmarks {
+namespace {
+
+// Used for sorting in combination with TypedCountSorter.
+class BookmarkClientMock : public TestBookmarkClient {
+ public:
+ explicit BookmarkClientMock(const std::map<GURL, int>& typed_count_map)
+ : typed_count_map_(typed_count_map) {}
+
+ bool SupportsTypedCountForUrls() override { return true; }
+
+ void GetTypedCountForUrls(UrlTypedCountMap* url_typed_count_map) override {
+ for (auto& url_typed_count_pair : *url_typed_count_map) {
+ const GURL* url = url_typed_count_pair.first;
+ if (!url)
+ continue;
+
+ auto found = typed_count_map_.find(*url);
+ if (found == typed_count_map_.end())
+ continue;
+
+ url_typed_count_pair.second = found->second;
+ }
+ }
+
+ private:
+ const std::map<GURL, int> typed_count_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkClientMock);
+};
+
+// Minimal implementation of TitledUrlNode.
+class TestTitledUrlNode : public TitledUrlNode {
+ public:
+ TestTitledUrlNode(const base::string16& title,
+ const GURL& url,
+ const base::string16& ancestor_title)
+ : title_(title), url_(url), ancestor_title_(ancestor_title) {}
+
+ ~TestTitledUrlNode() override = default;
+
+ const base::string16& GetTitledUrlNodeTitle() const override {
+ return title_;
+ }
+
+ const GURL& GetTitledUrlNodeUrl() const override { return url_; }
+
+ std::vector<base::StringPiece16> GetTitledUrlNodeAncestorTitles()
+ const override {
+ return {ancestor_title_};
+ }
+
+ private:
+ base::string16 title_;
+ GURL url_;
+ base::string16 ancestor_title_;
+};
+
+class TitledUrlIndexTest : public testing::Test {
+ public:
+ const GURL kAboutBlankURL = GURL("about:blank");
+
+ TitledUrlIndexTest() { ResetNodes(); }
+
+ ~TitledUrlIndexTest() override = default;
+
+ void ResetNodes() {
+ index_ = std::make_unique<TitledUrlIndex>();
+ owned_nodes_.clear();
+ }
+
+ TitledUrlNode* AddNode(const std::string& title,
+ const GURL& url,
+ const std::string& ancestor_title = "") {
+ return AddNode(UTF8ToUTF16(title), url, UTF8ToUTF16(ancestor_title));
+ }
+
+ TitledUrlNode* AddNode(
+ const base::string16& title,
+ const GURL& url,
+ const base::string16& ancestor_title = base::string16()) {
+ owned_nodes_.push_back(
+ std::make_unique<TestTitledUrlNode>(title, url, ancestor_title));
+ index_->Add(owned_nodes_.back().get());
+ return owned_nodes_.back().get();
+ }
+
+ void AddNodes(const char** titles, const char** urls, size_t count) {
+ for (size_t i = 0; i < count; ++i)
+ AddNode(titles[i], GURL(urls[i]));
+ }
+
+ std::vector<TitledUrlMatch> GetResultsMatching(
+ const std::string& query,
+ size_t max_count,
+ bool match_ancestor_titles = false) {
+ return index_->GetResultsMatching(UTF8ToUTF16(query), max_count,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ match_ancestor_titles);
+ }
+
+ void ExpectMatches(const std::string& query,
+ const char** expected_titles,
+ size_t expected_count) {
+ std::vector<std::string> title_vector;
+ for (size_t i = 0; i < expected_count; ++i)
+ title_vector.push_back(expected_titles[i]);
+ ExpectMatches(query, query_parser::MatchingAlgorithm::DEFAULT,
+ title_vector);
+ }
+
+ void ExpectMatches(const std::string& query,
+ query_parser::MatchingAlgorithm matching_algorithm,
+ const std::vector<std::string>& expected_titles) {
+ std::vector<TitledUrlMatch> matches = index_->GetResultsMatching(
+ UTF8ToUTF16(query), 1000, matching_algorithm, false);
+ ASSERT_EQ(expected_titles.size(), matches.size());
+ for (const std::string& expected_title : expected_titles) {
+ bool found = false;
+ for (size_t j = 0; j < matches.size(); ++j) {
+ const base::string16& title = matches[j].node->GetTitledUrlNodeTitle();
+ if (UTF8ToUTF16(expected_title) == title) {
+ matches.erase(matches.begin() + j);
+ found = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(found);
+ }
+ }
+
+ void ExtractMatchPositions(const std::string& string,
+ TitledUrlMatch::MatchPositions* matches) {
+ for (const base::StringPiece& match : base::SplitStringPiece(
+ string, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ std::vector<base::StringPiece> chunks = base::SplitStringPiece(
+ match, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(2U, chunks.size());
+ matches->push_back(TitledUrlMatch::MatchPosition());
+ int chunks0, chunks1;
+ EXPECT_TRUE(base::StringToInt(chunks[0], &chunks0));
+ EXPECT_TRUE(base::StringToInt(chunks[1], &chunks1));
+ matches->back().first = chunks0;
+ matches->back().second = chunks1;
+ }
+ }
+
+ void ExpectMatchPositions(
+ const TitledUrlMatch::MatchPositions& actual_positions,
+ const TitledUrlMatch::MatchPositions& expected_positions) {
+ ASSERT_EQ(expected_positions.size(), actual_positions.size());
+ for (size_t i = 0; i < expected_positions.size(); ++i) {
+ EXPECT_EQ(expected_positions[i].first, actual_positions[i].first);
+ EXPECT_EQ(expected_positions[i].second, actual_positions[i].second);
+ }
+ }
+
+ TitledUrlIndex* index() { return index_.get(); }
+
+ private:
+ std::vector<std::unique_ptr<TestTitledUrlNode>> owned_nodes_;
+ std::unique_ptr<TitledUrlIndex> index_;
+};
+
+// Various permutations with differing input, queries and output that exercises
+// all query paths.
+TEST_F(TitledUrlIndexTest, GetResultsMatching) {
+ struct TestData {
+ const std::string titles;
+ const std::string query;
+ const std::string expected;
+ } data[] = {
+ // Trivial test case of only one term, exact match.
+ {"a;b", "A", "a"},
+
+ // Two terms, exact matches.
+ {"a b;b", "a b", "a b"},
+
+ // Prefix match, one term.
+ {"abcd;abc;b", "abc", "abcd;abc"},
+
+ // Prefix match, multiple terms.
+ {"abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
+
+ // Exact and prefix match.
+ {"ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef"},
+
+ // Exact and prefix match.
+ {"ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab", "ab cde ghi",
+ "ab cdef ghij"},
+
+ // Title with term multiple times.
+ {"ab ab", "ab", "ab ab"},
+
+ // Make sure quotes don't do a prefix match.
+ {"think", "\"thi\"", ""},
+
+ // Prefix matches against multiple candidates.
+ {"abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
+
+ // Multiple prefix matches (with a lot of redundancy) against multiple
+ // candidates.
+ {"abc1 abc2 abc3 abc4 def1 def2 def3 def4",
+ "abc def abc def abc def abc def abc def",
+ "abc1 abc2 abc3 abc4 def1 def2 def3 def4"},
+
+ // Prefix match on the first term.
+ {"abc", "a", ""},
+
+ // Prefix match on subsequent terms.
+ {"abc def", "abc d", ""},
+ };
+ for (const TestData& test_data : data) {
+ ResetNodes();
+
+ for (const std::string& title :
+ base::SplitString(test_data.titles, ";", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ AddNode(title, kAboutBlankURL);
+ }
+
+ std::vector<std::string> expected;
+ if (!test_data.expected.empty()) {
+ expected = base::SplitString(test_data.expected, ";",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ }
+
+ ExpectMatches(test_data.query, query_parser::MatchingAlgorithm::DEFAULT,
+ expected);
+ }
+}
+
+TEST_F(TitledUrlIndexTest, GetResultsMatchingAlwaysPrefixSearch) {
+ struct TestData {
+ const std::string titles;
+ const std::string query;
+ const std::string expected;
+ } data[] = {
+ // Trivial test case of only one term, exact match.
+ {"z;y", "Z", "z"},
+
+ // Prefix match, one term.
+ {"abcd;abc;b", "abc", "abcd;abc"},
+
+ // Prefix match, multiple terms.
+ {"abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
+
+ // Exact and prefix match.
+ {"ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab", "ab cde ghi",
+ "ab cdef ghij"},
+
+ // Title with term multiple times.
+ {"ab ab", "ab", "ab ab"},
+
+ // Make sure quotes don't do a prefix match.
+ {"think", "\"thi\"", ""},
+
+ // Prefix matches against multiple candidates.
+ {"abc1 abc2 abc3 abc4", "abc", "abc1 abc2 abc3 abc4"},
+
+ // Prefix match on the first term.
+ {"abc", "a", "abc"},
+
+ // Prefix match on subsequent terms.
+ {"abc def", "abc d", "abc def"},
+
+ // Exact and prefix match.
+ {"ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef;abcd cdefg"},
+ };
+ for (const TestData& test_data : data) {
+ ResetNodes();
+
+ for (const std::string& title :
+ base::SplitString(test_data.titles, ";", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ AddNode(title, kAboutBlankURL);
+ }
+
+ std::vector<std::string> expected;
+ if (!test_data.expected.empty()) {
+ expected = base::SplitString(test_data.expected, ";",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ }
+
+ ExpectMatches(test_data.query,
+ query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH,
+ expected);
+ }
+}
+
+// Analogous to GetResultsMatching, this test tests various permutations
+// of title, URL, and input to see if the title/URL matches the input as
+// expected.
+TEST_F(TitledUrlIndexTest, GetResultsMatchingWithURLs) {
+ struct TestData {
+ const std::string query;
+ const std::string title;
+ const std::string url;
+ const bool should_be_retrieved;
+ } data[] = {
+ // Test single-word inputs. Include both exact matches and prefix
+ // matches.
+ {"foo", "Foo", "http://www.bar.com/", true},
+ {"foo", "Foodie", "http://www.bar.com/", true},
+ {"foo", "Bar", "http://www.foo.com/", true},
+ {"foo", "Bar", "http://www.foodie.com/", true},
+ {"foo", "Foo", "http://www.foo.com/", true},
+ {"foo", "Bar", "http://www.bar.com/", false},
+ {"foo", "Bar", "http://www.bar.com/blah/foo/blah-again/ ", true},
+ {"foo", "Bar", "http://www.bar.com/blah/foodie/blah-again/ ", true},
+ {"foo", "Bar", "http://www.bar.com/blah-foo/blah-again/ ", true},
+ {"foo", "Bar", "http://www.bar.com/blah-foodie/blah-again/ ", true},
+ {"foo", "Bar", "http://www.bar.com/blahafoo/blah-again/ ", false},
+
+ // Test multi-word inputs.
+ {"foo bar", "Foo Bar", "http://baz.com/", true},
+ {"foo bar", "Foodie Bar", "http://baz.com/", true},
+ {"bar foo", "Foo Bar", "http://baz.com/", true},
+ {"bar foo", "Foodie Barly", "http://baz.com/", true},
+ {"foo bar", "Foo Baz", "http://baz.com/", false},
+ {"foo bar", "Foo Baz", "http://bar.com/", true},
+ {"foo bar", "Foo Baz", "http://barly.com/", true},
+ {"foo bar", "Foodie Baz", "http://barly.com/", true},
+ {"bar foo", "Foo Baz", "http://bar.com/", true},
+ {"bar foo", "Foo Baz", "http://barly.com/", true},
+ {"foo bar", "Baz Bar", "http://blah.com/foo", true},
+ {"foo bar", "Baz Barly", "http://blah.com/foodie", true},
+ {"foo bar", "Baz Bur", "http://blah.com/foo/bar", true},
+ {"foo bar", "Baz Bur", "http://blah.com/food/barly", true},
+ {"foo bar", "Baz Bur", "http://bar.com/blah/foo", true},
+ {"foo bar", "Baz Bur", "http://barly.com/blah/food", true},
+ {"foo bar", "Baz Bur", "http://bar.com/blah/flub", false},
+ {"foo bar", "Baz Bur", "http://foo.com/blah/flub", false}};
+
+ for (const TestData& test_data : data) {
+ ResetNodes();
+ AddNode(test_data.title, GURL(test_data.url));
+
+ std::vector<std::string> expected;
+ if (test_data.should_be_retrieved)
+ expected.push_back(test_data.title);
+
+ ExpectMatches(test_data.query, query_parser::MatchingAlgorithm::DEFAULT,
+ expected);
+ }
+}
+
+TEST_F(TitledUrlIndexTest, Normalization) {
+ struct TestData {
+ const char* const title;
+ const char* const query;
+ } data[] = {{"fooa\xcc\x88-test", "foo\xc3\xa4-test"},
+ {"fooa\xcc\x88-test", "fooa\xcc\x88-test"},
+ {"fooa\xcc\x88-test", "foo\xc3\xa4"},
+ {"fooa\xcc\x88-test", "fooa\xcc\x88"},
+ {"fooa\xcc\x88-test", "foo"},
+ {"foo\xc3\xa4-test", "foo\xc3\xa4-test"},
+ {"foo\xc3\xa4-test", "fooa\xcc\x88-test"},
+ {"foo\xc3\xa4-test", "foo\xc3\xa4"},
+ {"foo\xc3\xa4-test", "fooa\xcc\x88"},
+ {"foo\xc3\xa4-test", "foo"},
+ {"foo", "foo"}};
+
+ for (const TestData& test_data : data) {
+ ResetNodes();
+ AddNode(test_data.title, kAboutBlankURL);
+
+ std::vector<TitledUrlMatch> matches =
+ GetResultsMatching(test_data.query, 10);
+ EXPECT_EQ(1u, matches.size());
+ }
+}
+
+// Makes sure match positions are updated appropriately for title matches.
+TEST_F(TitledUrlIndexTest, MatchPositionsTitles) {
+ struct TestData {
+ const std::string title;
+ const std::string query;
+ const std::string expected_title_match_positions;
+ } data[] = {
+ // Trivial test case of only one term, exact match.
+ {"a", "A", "0,1"},
+ {"foo bar", "bar", "4,7"},
+ {"fooey bark", "bar foo", "0,3:6,9"},
+ // Non-trivial tests.
+ {"foobar foo", "foobar foo", "0,6:7,10"},
+ {"foobar foo", "foo foobar", "0,6:7,10"},
+ {"foobar foobar", "foobar foo", "0,6:7,13"},
+ {"foobar foobar", "foo foobar", "0,6:7,13"},
+ };
+ for (const TestData& test_data : data) {
+ ResetNodes();
+ AddNode(test_data.title, kAboutBlankURL);
+
+ std::vector<TitledUrlMatch> matches =
+ GetResultsMatching(test_data.query, 1000);
+ ASSERT_EQ(1U, matches.size());
+
+ TitledUrlMatch::MatchPositions expected_title_matches;
+ ExtractMatchPositions(test_data.expected_title_match_positions,
+ &expected_title_matches);
+ ExpectMatchPositions(matches[0].title_match_positions,
+ expected_title_matches);
+ }
+}
+
+// Makes sure match positions are updated appropriately for URL matches.
+TEST_F(TitledUrlIndexTest, MatchPositionsURLs) {
+ // The encoded stuff between /wiki/ and the # is 第二次世界大戦
+ const std::string ja_wiki_url =
+ "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4"
+ "%BA%8C%E6%AC%A1%E4%B8%96%E7%95%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7"
+ ".E3.83.AB.E3.82.B5.E3.82.A4.E3.83.A6.E4.BD.93.E5.88.B6";
+ struct TestData {
+ const std::string query;
+ const std::string url;
+ const std::string expected_url_match_positions;
+ } data[] = {
+ {"foo", "http://www.foo.com/", "11,14"},
+ {"foo", "http://www.foodie.com/", "11,14"},
+ {"foo", "http://www.foofoo.com/", "11,14"},
+ {"www", "http://www.foo.com/", "7,10"},
+ {"foo", "http://www.foodie.com/blah/foo/fi", "11,14:27,30"},
+ {"foo", "http://www.blah.com/blah/foo/fi", "25,28"},
+ {"foo www", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30"},
+ {"www foo", "http://www.foodie.com/blah/foo/fi", "7,10:11,14:27,30"},
+ {"www bla", "http://www.foodie.com/blah/foo/fi", "7,10:22,25"},
+ {"http", "http://www.foo.com/", "0,4"},
+ {"http www", "http://www.foo.com/", "0,4:7,10"},
+ {"http foo", "http://www.foo.com/", "0,4:11,14"},
+ {"http foo", "http://www.bar.com/baz/foodie/hi", "0,4:23,26"},
+ {"第二次", ja_wiki_url, "29,56"},
+ {"ja 第二次", ja_wiki_url, "7,9:29,56"},
+ {"第二次 E3.8", ja_wiki_url,
+ "29,56:94,98:103,107:"
+ "112,116:121,125:"
+ "130,134:139,143"}};
+
+ for (const TestData& test_data : data) {
+ ResetNodes();
+ AddNode("123456", GURL(test_data.url));
+
+ std::vector<TitledUrlMatch> matches =
+ GetResultsMatching(test_data.query, 1000);
+ ASSERT_EQ(1U, matches.size()) << test_data.url << test_data.query;
+
+ TitledUrlMatch::MatchPositions expected_url_matches;
+ ExtractMatchPositions(test_data.expected_url_match_positions,
+ &expected_url_matches);
+ ExpectMatchPositions(matches[0].url_match_positions, expected_url_matches);
+ }
+}
+
+// Makes sure index is updated when a node is removed.
+TEST_F(TitledUrlIndexTest, Remove) {
+ TitledUrlNode* n1 = AddNode("foo", GURL("http://foo"));
+ TitledUrlNode* n2 = AddNode("bar", GURL("http://bar"));
+ TitledUrlNode* n3 = AddNode("bar", GURL("http://bar/baz"));
+
+ ASSERT_EQ(1U, GetResultsMatching("foo", 10).size());
+ ASSERT_EQ(2U, GetResultsMatching("bar", 10).size());
+
+ index()->Remove(n3);
+ EXPECT_EQ(1U, GetResultsMatching("bar", 10).size());
+ EXPECT_EQ(1U, GetResultsMatching("foo", 10).size());
+
+ index()->Remove(n1);
+ EXPECT_EQ(1U, GetResultsMatching("bar", 10).size());
+ EXPECT_EQ(0U, GetResultsMatching("foo", 10).size());
+
+ index()->Remove(n2);
+ EXPECT_EQ(0U, GetResultsMatching("bar", 10).size());
+}
+
+// Makes sure no more than max queries is returned.
+TEST_F(TitledUrlIndexTest, HonorMax) {
+ AddNode("abcd", kAboutBlankURL);
+ AddNode("abcde", kAboutBlankURL);
+
+ EXPECT_EQ(1U, GetResultsMatching("ABc", 1).size());
+}
+
+// Makes sure if the lower case string of a bookmark title is more characters
+// than the upper case string no match positions are returned.
+TEST_F(TitledUrlIndexTest, EmptyMatchOnMultiwideLowercaseString) {
+ TitledUrlNode* n1 =
+ AddNode(base::WideToUTF16(L"\u0130 i"), GURL("http://www.google.com"));
+
+ std::vector<TitledUrlMatch> matches = GetResultsMatching("i", 100);
+ ASSERT_EQ(1U, matches.size());
+ EXPECT_EQ(n1, matches[0].node);
+ EXPECT_TRUE(matches[0].title_match_positions.empty());
+}
+
+TEST_F(TitledUrlIndexTest, GetResultsSortedByTypedCount) {
+ struct TestData {
+ const GURL url;
+ const char* title;
+ const int typed_count;
+ } data[] = {
+ {GURL("http://www.google.com/"), "Google", 100},
+ {GURL("http://maps.google.com/"), "Google Maps", 40},
+ {GURL("http://docs.google.com/"), "Google Docs", 50},
+ {GURL("http://reader.google.com/"), "Google Reader", 80},
+ };
+
+ std::map<GURL, int> typed_count_map;
+ for (const TestData& test_data : data)
+ typed_count_map.insert(
+ std::make_pair(test_data.url, test_data.typed_count));
+
+ BookmarkClientMock bookmark_client(typed_count_map);
+ index()->SetNodeSorter(std::make_unique<TypedCountSorter>(&bookmark_client));
+
+ for (const TestData& test_data : data)
+ AddNode(test_data.title, GURL(test_data.url));
+
+ // Populate match nodes.
+ std::vector<TitledUrlMatch> matches = GetResultsMatching("google", 4);
+
+ // The resulting order should be:
+ // 1. Google (google.com) 100
+ // 2. Google Reader (google.com/reader) 80
+ // 3. Google Docs (docs.google.com) 50
+ // 4. Google Maps (maps.google.com) 40
+ ASSERT_EQ(4U, matches.size());
+ EXPECT_EQ(data[0].url, matches[0].node->GetTitledUrlNodeUrl());
+ EXPECT_EQ(data[3].url, matches[1].node->GetTitledUrlNodeUrl());
+ EXPECT_EQ(data[2].url, matches[2].node->GetTitledUrlNodeUrl());
+ EXPECT_EQ(data[1].url, matches[3].node->GetTitledUrlNodeUrl());
+
+ // Select top two matches.
+ matches = GetResultsMatching("google", 2);
+
+ ASSERT_EQ(2U, matches.size());
+ EXPECT_EQ(data[0].url, matches[0].node->GetTitledUrlNodeUrl());
+ EXPECT_EQ(data[3].url, matches[1].node->GetTitledUrlNodeUrl());
+}
+
+TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAllTerms) {
+ TitledUrlNode* node =
+ AddNode("termA termB otherTerm xyz ab", GURL("http://foo.com"));
+
+ struct TestData {
+ const std::string query;
+ const bool should_be_retrieved;
+ } data[] = {// Should return matches if all input terms match, even if not all
+ // node terms match.
+ {"term other", true},
+ // Should not match midword.
+ {"term ther", false},
+ // Short input terms should only return exact matches.
+ {"xy", false},
+ {"ab", true}};
+
+ for (const TestData& test_data : data) {
+ SCOPED_TRACE("Query: " + test_data.query);
+ std::vector<base::string16> terms = base::SplitString(
+ base::UTF8ToUTF16(test_data.query), base::UTF8ToUTF16(" "),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ auto matches = index()->RetrieveNodesMatchingAllTermsForTesting(
+ terms, query_parser::MatchingAlgorithm::DEFAULT);
+ if (test_data.should_be_retrieved) {
+ EXPECT_EQ(matches.size(), 1u);
+ EXPECT_TRUE(matches.contains(node));
+ } else
+ EXPECT_TRUE(matches.empty());
+ };
+}
+
+TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms) {
+ TitledUrlNode* node =
+ AddNode("termA termB otherTerm xyz ab", GURL("http://foo.com"));
+
+ struct TestData {
+ const std::string query;
+ const bool should_be_retrieved;
+ } data[] = {// Should return matches if any input terms match, even if not all
+ // node terms match.
+ {"term not", true},
+ // Should not return duplicate matches.
+ {"term termA termB", true},
+ // Should not early exit when there are no intermediate matches.
+ {"not term", true},
+ // Should not match midword.
+ {"ther", false},
+ // Short input terms should only return exact matches.
+ {"xy", false},
+ {"ab", true}};
+
+ for (const TestData& test_data : data) {
+ SCOPED_TRACE("Query: " + test_data.query);
+ std::vector<base::string16> terms = base::SplitString(
+ base::UTF8ToUTF16(test_data.query), base::UTF8ToUTF16(" "),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ auto matches = index()->RetrieveNodesMatchingAnyTermsForTesting(
+ terms, query_parser::MatchingAlgorithm::DEFAULT);
+ if (test_data.should_be_retrieved) {
+ EXPECT_EQ(matches.size(), 1u);
+ EXPECT_TRUE(matches.contains(node));
+ } else
+ EXPECT_TRUE(matches.empty());
+ };
+}
+
+TEST_F(TitledUrlIndexTest, GetResultsMatchingAncestors) {
+ TitledUrlNode* node = AddNode("leaf pare", GURL("http://foo.com"), "parent");
+
+ struct TestData {
+ const std::string query;
+ const bool match_ancestor_titles;
+ const bool should_be_retrieved;
+ const bool should_have_ancestor_match;
+ } data[] = {
+ // Should exclude matches with ancestor matches when
+ // |match_ancestor_titles| is false.
+ {"leaf parent", false, false, false},
+ // Should allow ancestor matches when |match_ancestor_titles| is true.
+ {"leaf parent", true, true, true},
+ // Should not early exit when there are no accumulated
+ // non-ancestor matches.
+ {"parent leaf", true, true, true},
+ // Should still require at least 1 non-ancestor match when
+ // |match_ancestor_titles| is true.
+ {"parent", true, false, false},
+ // Should set |has_ancestor_match| to true even if a term matched
+ // both an ancestor and title/URL.
+ {"pare", true, true, true},
+ // Short inputs should only match exact title or ancestor terms.
+ {"pa", true, false, false},
+ // Should not return matches if a term matches neither the title
+ // nor ancestor.
+ {"term not parent", true, false, false}};
+
+ for (const TestData& test_data : data) {
+ SCOPED_TRACE("Query: " + test_data.query);
+ auto matches = GetResultsMatching(test_data.query, 10,
+ test_data.match_ancestor_titles);
+ if (test_data.should_be_retrieved) {
+ EXPECT_EQ(matches.size(), 1u);
+ EXPECT_EQ(matches[0].node, node);
+ EXPECT_EQ(matches[0].has_ancestor_match,
+ test_data.should_have_ancestor_match);
+ } else
+ EXPECT_TRUE(matches.empty());
+ };
+}
+
+} // namespace
+} // namespace bookmarks
diff --git a/chromium/components/bookmarks/browser/titled_url_match.h b/chromium/components/bookmarks/browser/titled_url_match.h
index 767a1907d06..a700977dd42 100644
--- a/chromium/components/bookmarks/browser/titled_url_match.h
+++ b/chromium/components/bookmarks/browser/titled_url_match.h
@@ -44,6 +44,9 @@ struct TitledUrlMatch {
// Location of the matching words in the URL of the node.
MatchPositions url_match_positions;
+
+ // Whether there was at least 1 match in the titles of ancestors of the node.
+ bool has_ancestor_match;
};
} // namespace bookmarks
diff --git a/chromium/components/bookmarks/browser/titled_url_node.h b/chromium/components/bookmarks/browser/titled_url_node.h
index bbd6759b770..b43235b0b0b 100644
--- a/chromium/components/bookmarks/browser/titled_url_node.h
+++ b/chromium/components/bookmarks/browser/titled_url_node.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_BOOKMARKS_BROWSER_TITLED_URL_NODE_H_
#define COMPONENTS_BOOKMARKS_BROWSER_TITLED_URL_NODE_H_
+#include "base/containers/span.h"
+#include "base/strings/string_piece.h"
#include "url/gurl.h"
namespace bookmarks {
@@ -20,6 +22,11 @@ class TitledUrlNode {
// Returns the URL for the node.
virtual const GURL& GetTitledUrlNodeUrl() const = 0;
+ // Returns the titles of this node's ancestors ordered from child to parent.
+ // If |include_self| is true, will include its own title as well.
+ virtual std::vector<base::StringPiece16> GetTitledUrlNodeAncestorTitles()
+ const = 0;
+
protected:
virtual ~TitledUrlNode() {}
};
diff --git a/chromium/components/bookmarks/browser/url_index.cc b/chromium/components/bookmarks/browser/url_index.cc
index c0082db614d..7f9e1c6be39 100644
--- a/chromium/components/bookmarks/browser/url_index.cc
+++ b/chromium/components/bookmarks/browser/url_index.cc
@@ -4,12 +4,68 @@
#include "components/bookmarks/browser/url_index.h"
+#include <iterator>
+
#include "base/containers/adapters.h"
#include "base/guid.h"
#include "components/bookmarks/browser/url_and_title.h"
namespace bookmarks {
+namespace {
+
+// Computes and aggregates into |*stats| metrics corresponding to a particular
+// group of bookmarks with the same URL, listed in |*bookmarks_with_same_url|.
+// The caller is responsible to guarantee that these provided bookmarks all
+// share the same URL. Upon completion of this function, the state of
+// |*bookmarks_with_same_url| is unspecified, because the implementation is free
+// to modify its state desirable to avoid additional memory allocations on the
+// calling site.
+void AddStatsForBookmarksWithSameUrl(
+ std::vector<const BookmarkNode*>* bookmarks_with_same_url,
+ UrlIndex::Stats* stats) {
+ if (bookmarks_with_same_url->size() <= 1)
+ return;
+
+ stats->duplicate_url_bookmark_count += bookmarks_with_same_url->size() - 1;
+
+ // Sort only if there are 3 or more bookmarks. With exactly two (which is
+ // believed to be a common case) the precise ordering is irrelevant for the
+ // logic that follows.
+ if (bookmarks_with_same_url->size() > 2) {
+ std::sort(bookmarks_with_same_url->begin(), bookmarks_with_same_url->end(),
+ [](const BookmarkNode* a, const BookmarkNode* b) {
+ DCHECK_EQ(a->url(), b->url());
+ if (a->GetTitle() != b->GetTitle())
+ return a->GetTitle() < b->GetTitle();
+ return a->parent() < b->parent();
+ });
+ }
+
+ size_t duplicate_title_count = 0;
+ size_t duplicate_title_and_parent_count = 0;
+
+ auto prev_i = bookmarks_with_same_url->begin();
+ for (auto i = std::next(prev_i); i != bookmarks_with_same_url->end();
+ ++i, ++prev_i) {
+ DCHECK_EQ((*prev_i)->url(), (*i)->url());
+ if ((*prev_i)->GetTitle() == (*i)->GetTitle()) {
+ ++duplicate_title_count;
+ if ((*prev_i)->parent() == (*i)->parent())
+ ++duplicate_title_and_parent_count;
+ }
+ }
+
+ DCHECK_LT(duplicate_title_count, bookmarks_with_same_url->size());
+ DCHECK_LE(duplicate_title_and_parent_count, duplicate_title_count);
+
+ stats->duplicate_url_and_title_bookmark_count += duplicate_title_count;
+ stats->duplicate_url_and_title_and_parent_bookmark_count +=
+ duplicate_title_and_parent_count;
+}
+
+} // namespace
+
UrlIndex::UrlIndex(std::unique_ptr<BookmarkNode> root)
: root_(std::move(root)) {
base::AutoLock url_lock(url_lock_);
@@ -70,9 +126,28 @@ bool UrlIndex::HasBookmarks() const {
return !nodes_ordered_by_url_set_.empty();
}
-size_t UrlIndex::UrlCount() const {
+UrlIndex::Stats UrlIndex::ComputeStats() const {
base::AutoLock url_lock(url_lock_);
- return nodes_ordered_by_url_set_.size();
+ UrlIndex::Stats stats;
+ stats.total_url_bookmark_count = nodes_ordered_by_url_set_.size();
+
+ if (stats.total_url_bookmark_count <= 1)
+ return stats;
+
+ std::vector<const BookmarkNode*> bookmarks_with_same_url;
+ auto prev_i = nodes_ordered_by_url_set_.begin();
+ for (auto i = std::next(prev_i); i != nodes_ordered_by_url_set_.end();
+ ++i, ++prev_i) {
+ if ((*prev_i)->url() != (*i)->url()) {
+ AddStatsForBookmarksWithSameUrl(&bookmarks_with_same_url, &stats);
+ bookmarks_with_same_url.clear();
+ }
+
+ bookmarks_with_same_url.push_back(*i);
+ }
+
+ AddStatsForBookmarksWithSameUrl(&bookmarks_with_same_url, &stats);
+ return stats;
}
bool UrlIndex::IsBookmarked(const GURL& url) {
diff --git a/chromium/components/bookmarks/browser/url_index.h b/chromium/components/bookmarks/browser/url_index.h
index 9e7f026889c..8036ebb9584 100644
--- a/chromium/components/bookmarks/browser/url_index.h
+++ b/chromium/components/bookmarks/browser/url_index.h
@@ -65,8 +65,24 @@ class UrlIndex : public HistoryBookmarkModel {
// Returns true if there is at least one bookmark.
bool HasBookmarks() const;
- // Returns the number of URL bookmarks stored.
- size_t UrlCount() const;
+ // Returns some stats about number of URL bookmarks stored, for UMA purposes.
+ struct Stats {
+ // Number of bookmark in the index excluding folders.
+ size_t total_url_bookmark_count = 0;
+ // Number of bookmarks (excluding folders) with a URL that is used by at
+ // least one other bookmark, excluding one bookmark per unique URL (i.e. all
+ // except one are considered duplicates).
+ size_t duplicate_url_bookmark_count = 0;
+ // Number of bookmarks (excluding folders) with the pair <URL, title> that
+ // is used by at least one other bookmark, excluding one bookmark per unique
+ // URL (i.e. all except one are considered duplicates).
+ size_t duplicate_url_and_title_bookmark_count = 0;
+ // Number of bookmarks (excluding folders) with the triple <URL, title,
+ // parent> that is used by at least one other bookmark, excluding one
+ // bookmark per unique URL (i.e. all except one are considered duplicates).
+ size_t duplicate_url_and_title_and_parent_bookmark_count = 0;
+ };
+ Stats ComputeStats() const;
// HistoryBookmarkModel:
bool IsBookmarked(const GURL& url) override;
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
index fd2e0550931..cb3e748ffc9 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
@@ -8,8 +8,8 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/components/browser_sync/BUILD.gn b/chromium/components/browser_sync/BUILD.gn
index b13d47c2a48..8fac7d4d32a 100644
--- a/chromium/components/browser_sync/BUILD.gn
+++ b/chromium/components/browser_sync/BUILD.gn
@@ -6,7 +6,8 @@ import("//build/config/features.gni")
static_library("browser_sync") {
sources = [
- "browser_sync_client.cc",
+ "active_devices_provider_impl.cc",
+ "active_devices_provider_impl.h",
"browser_sync_client.h",
"browser_sync_switches.cc",
"browser_sync_switches.h",
@@ -29,6 +30,7 @@ static_library("browser_sync") {
"//components/send_tab_to_self",
"//components/sync/invalidations",
"//components/sync_bookmarks",
+ "//components/sync_preferences",
"//components/sync_sessions",
"//components/sync_user_events",
"//components/version_info",
@@ -43,11 +45,10 @@ static_library("browser_sync") {
source_set("unit_tests") {
testonly = true
- sources = []
+ sources = [ "active_devices_provider_impl_unittest.cc" ]
deps = [
":browser_sync",
- ":test_support",
"//base",
"//base/test:test_support",
"//components/autofill/core/browser:test_support",
@@ -61,10 +62,7 @@ source_set("unit_tests") {
"//components/sync:test_support",
"//components/sync_bookmarks",
"//components/sync_device_info",
- "//components/sync_preferences",
- "//components/sync_preferences:test_support",
- "//components/sync_sessions",
- "//components/sync_sessions:test_support",
+ "//components/sync_device_info:test_support",
"//components/version_info",
"//components/version_info:generate_version_info",
"//components/webdata/common",
@@ -73,24 +71,3 @@ source_set("unit_tests") {
"//testing/gtest",
]
}
-
-static_library("test_support") {
- testonly = true
- sources = [
- "test_http_bridge_factory.cc",
- "test_http_bridge_factory.h",
- ]
-
- deps = [
- ":browser_sync",
- "//base",
- "//base/test:test_support",
- "//components/bookmarks/browser",
- "//components/history/core/browser",
- "//components/sync",
- "//components/sync:test_support",
- "//components/sync_preferences:test_support",
- "//components/sync_sessions:test_support",
- "//services/network:test_support",
- ]
-}
diff --git a/chromium/components/browser_sync/active_devices_provider_impl.cc b/chromium/components/browser_sync/active_devices_provider_impl.cc
new file mode 100644
index 00000000000..ec07f794f1f
--- /dev/null
+++ b/chromium/components/browser_sync/active_devices_provider_impl.cc
@@ -0,0 +1,80 @@
+// Copyright 2020 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 <utility>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "components/browser_sync/active_devices_provider_impl.h"
+
+namespace browser_sync {
+
+// Enables filtering out inactive devices which haven't sent DeviceInfo update
+// recently (depending on the device's pulse_interval and an additional margin).
+const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
+ "SyncFilterOutInactiveDevicesForSingleClient",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// An additional threshold to consider devices as active. It extends device's
+// pulse interval to mitigate possible latency after DeviceInfo commit.
+const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
+ &kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
+ base::TimeDelta::FromMinutes(30)};
+
+ActiveDevicesProviderImpl::ActiveDevicesProviderImpl(
+ syncer::DeviceInfoTracker* device_info_tracker,
+ base::Clock* clock)
+ : device_info_tracker_(device_info_tracker), clock_(clock) {
+ DCHECK(device_info_tracker_);
+ device_info_tracker_->AddObserver(this);
+}
+
+ActiveDevicesProviderImpl::~ActiveDevicesProviderImpl() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(callback_.is_null());
+ device_info_tracker_->RemoveObserver(this);
+}
+
+size_t ActiveDevicesProviderImpl::CountActiveDevicesIfAvailable() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
+ device_info_tracker_->GetAllDeviceInfo();
+ if (!base::FeatureList::IsEnabled(
+ kSyncFilterOutInactiveDevicesForSingleClient)) {
+ return all_devices.size();
+ }
+
+ size_t active_devices = 0;
+ for (const auto& device : all_devices) {
+ const base::Time expected_expiration_time =
+ device->last_updated_timestamp() + device->pulse_interval() +
+ kSyncActiveDeviceMargin.Get();
+ // If the device's expiration time hasn't been reached, then it is
+ // considered active device.
+ if (expected_expiration_time > clock_->Now()) {
+ active_devices++;
+ }
+ }
+ return active_devices;
+}
+
+void ActiveDevicesProviderImpl::SetActiveDevicesChangedCallback(
+ ActiveDevicesChangedCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // The |callback_| must not be replaced with another non-null |callback|.
+ DCHECK(callback_.is_null() || callback.is_null());
+ callback_ = std::move(callback);
+}
+
+void ActiveDevicesProviderImpl::OnDeviceInfoChange() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (callback_) {
+ callback_.Run();
+ }
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/active_devices_provider_impl.h b/chromium/components/browser_sync/active_devices_provider_impl.h
new file mode 100644
index 00000000000..d0bbed0f989
--- /dev/null
+++ b/chromium/components/browser_sync/active_devices_provider_impl.h
@@ -0,0 +1,45 @@
+// Copyright 2020 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_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
+#define COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
+
+#include "base/sequence_checker.h"
+#include "base/time/default_clock.h"
+#include "components/sync/driver/active_devices_provider.h"
+#include "components/sync_device_info/device_info_tracker.h"
+
+namespace browser_sync {
+
+class ActiveDevicesProviderImpl : public syncer::ActiveDevicesProvider,
+ public syncer::DeviceInfoTracker::Observer {
+ public:
+ ActiveDevicesProviderImpl(syncer::DeviceInfoTracker* device_info_tracker,
+ base::Clock* clock);
+ ActiveDevicesProviderImpl(const ActiveDevicesProviderImpl&) = delete;
+ ActiveDevicesProviderImpl& operator=(const ActiveDevicesProviderImpl&) =
+ delete;
+
+ ~ActiveDevicesProviderImpl() override;
+
+ // syncer::ActiveDevicesProvider implementation.
+ size_t CountActiveDevicesIfAvailable() override;
+
+ void SetActiveDevicesChangedCallback(
+ ActiveDevicesChangedCallback callback) override;
+
+ // syncer::DeviceInfoTracker::Observer implementation.
+ void OnDeviceInfoChange() override;
+
+ private:
+ syncer::DeviceInfoTracker* const device_info_tracker_;
+ const base::Clock* const clock_;
+ ActiveDevicesChangedCallback callback_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_ACTIVE_DEVICES_PROVIDER_IMPL_H_
diff --git a/chromium/components/browser_sync/active_devices_provider_impl_unittest.cc b/chromium/components/browser_sync/active_devices_provider_impl_unittest.cc
new file mode 100644
index 00000000000..f9dbaa1ef8a
--- /dev/null
+++ b/chromium/components/browser_sync/active_devices_provider_impl_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 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/browser_sync/active_devices_provider_impl.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/guid.h"
+#include "base/test/mock_callback.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/sync_device_info/device_info_util.h"
+#include "components/sync_device_info/fake_device_info_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::DeviceInfo;
+using syncer::FakeDeviceInfoTracker;
+
+namespace browser_sync {
+namespace {
+
+constexpr int kPulseIntervalMinutes = 60;
+
+std::unique_ptr<DeviceInfo> CreateFakeDeviceInfo(
+ const std::string& name,
+ base::Time last_updated_timestamp) {
+ return std::make_unique<syncer::DeviceInfo>(
+ base::GenerateGUID(), name, "chrome_version", "user_agent",
+ sync_pb::SyncEnums::TYPE_UNSET, "device_id", "manufacturer_name",
+ "model_name", last_updated_timestamp,
+ base::TimeDelta::FromMinutes(kPulseIntervalMinutes),
+ /*send_tab_to_self_receiving_enabled=*/false,
+ /*sharing_info=*/base::nullopt,
+ /*fcm_registration_token=*/std::string(),
+ /*interested_data_types=*/syncer::ModelTypeSet());
+}
+
+class ActiveDevicesProviderImplTest : public testing::Test {
+ public:
+ ActiveDevicesProviderImplTest()
+ : active_devices_provider_(&fake_device_info_tracker_, &clock_) {}
+
+ ~ActiveDevicesProviderImplTest() override = default;
+
+ void AddDevice(const std::string& name, base::Time last_updated_timestamp) {
+ device_list_.push_back(CreateFakeDeviceInfo(name, last_updated_timestamp));
+ fake_device_info_tracker_.Add(device_list_.back().get());
+ }
+
+ protected:
+ std::vector<std::unique_ptr<DeviceInfo>> device_list_;
+ FakeDeviceInfoTracker fake_device_info_tracker_;
+ base::SimpleTestClock clock_;
+ ActiveDevicesProviderImpl active_devices_provider_;
+};
+
+TEST_F(ActiveDevicesProviderImplTest, ShouldFilterInactiveDevices) {
+ AddDevice("device_recent", clock_.Now() - base::TimeDelta::FromMinutes(1));
+
+ // Should be considered as active device due to margin even though the device
+ // is outside the pulse interval.
+ AddDevice(
+ "device_pulse_interval",
+ clock_.Now() - base::TimeDelta::FromMinutes(kPulseIntervalMinutes + 1));
+
+ // Very old device.
+ AddDevice("device_inactive", clock_.Now() - base::TimeDelta::FromDays(100));
+
+ EXPECT_EQ(2u, active_devices_provider_.CountActiveDevicesIfAvailable());
+}
+
+TEST_F(ActiveDevicesProviderImplTest, ShouldReturnZeroDevices) {
+ EXPECT_EQ(0u, active_devices_provider_.CountActiveDevicesIfAvailable());
+}
+
+TEST_F(ActiveDevicesProviderImplTest, ShouldInvokeCallback) {
+ base::MockCallback<
+ syncer::ActiveDevicesProvider::ActiveDevicesChangedCallback>
+ callback;
+ active_devices_provider_.SetActiveDevicesChangedCallback(callback.Get());
+ EXPECT_CALL(callback, Run());
+ active_devices_provider_.OnDeviceInfoChange();
+ active_devices_provider_.SetActiveDevicesChangedCallback(
+ base::RepeatingClosure());
+}
+
+} // namespace
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser_sync_client.cc b/chromium/components/browser_sync/browser_sync_client.cc
deleted file mode 100644
index 9c285221c32..00000000000
--- a/chromium/components/browser_sync/browser_sync_client.cc
+++ /dev/null
@@ -1,19 +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 "components/browser_sync/browser_sync_client.h"
-
-#include "components/sync/model/model_type_store_service.h"
-
-namespace browser_sync {
-
-BrowserSyncClient::BrowserSyncClient() = default;
-
-BrowserSyncClient::~BrowserSyncClient() = default;
-
-base::FilePath BrowserSyncClient::GetSyncDataPath() {
- return GetModelTypeStoreService()->GetSyncDataPath();
-}
-
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser_sync_client.h b/chromium/components/browser_sync/browser_sync_client.h
index 9e2829a4340..54ae5e4c362 100644
--- a/chromium/components/browser_sync/browser_sync_client.h
+++ b/chromium/components/browser_sync/browser_sync_client.h
@@ -30,6 +30,10 @@ namespace send_tab_to_self {
class SendTabToSelfSyncService;
} // namespace send_tab_to_self
+namespace sync_preferences {
+class PrefServiceSyncable;
+} // namespace sync_preferences
+
namespace sync_sessions {
class SessionSyncService;
} // namespace sync_sessions
@@ -47,10 +51,9 @@ namespace browser_sync {
// to handle these scenarios gracefully.
class BrowserSyncClient : public syncer::SyncClient {
public:
- BrowserSyncClient();
- ~BrowserSyncClient() override;
+ BrowserSyncClient() = default;
+ ~BrowserSyncClient() override = default;
- base::FilePath GetSyncDataPath() final;
virtual syncer::ModelTypeStoreService* GetModelTypeStoreService() = 0;
// Returns a weak pointer to the ModelTypeControllerDelegate specified by
@@ -63,6 +66,7 @@ class BrowserSyncClient : public syncer::SyncClient {
virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0;
virtual favicon::FaviconService* GetFaviconService() = 0;
virtual history::HistoryService* GetHistoryService() = 0;
+ virtual sync_preferences::PrefServiceSyncable* GetPrefServiceSyncable() = 0;
virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0;
virtual send_tab_to_self::SendTabToSelfSyncService*
GetSendTabToSelfSyncService() = 0;
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
index 9c1ceb1772c..78bc0d6d0f8 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -9,6 +9,8 @@
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h"
#include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
@@ -18,6 +20,7 @@
#include "components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge.h"
#include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/browser_sync/active_devices_provider_impl.h"
#include "components/browser_sync/browser_sync_client.h"
#include "components/history/core/browser/sync/history_delete_directives_model_type_controller.h"
#include "components/history/core/browser/sync/typed_url_model_type_controller.h"
@@ -25,8 +28,10 @@
#include "components/password_manager/core/browser/sync/password_model_type_controller.h"
#include "components/prefs/pref_service.h"
#include "components/reading_list/features/reading_list_switches.h"
+#include "components/send_tab_to_self/features.h"
#include "components/send_tab_to_self/send_tab_to_self_model_type_controller.h"
#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
+#include "components/sync/base/legacy_directory_deletion.h"
#include "components/sync/base/report_unrecoverable_error.h"
#include "components/sync/base/sync_base_switches.h"
#include "components/sync/driver/data_type_manager_impl.h"
@@ -41,6 +46,7 @@
#include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
#include "components/sync_bookmarks/bookmark_sync_service.h"
#include "components/sync_device_info/device_info_sync_service.h"
+#include "components/sync_preferences/pref_service_syncable.h"
#include "components/sync_sessions/proxy_tabs_data_type_controller.h"
#include "components/sync_sessions/session_model_type_controller.h"
#include "components/sync_sessions/session_sync_service.h"
@@ -104,6 +110,14 @@ AutofillWalletOfferDelegateFromDataService(
->GetControllerDelegate();
}
+// Helper function that deals will null (e.g. tests, iOS webview).
+base::WeakPtr<syncer::SyncableService> SyncableServiceForPrefs(
+ sync_preferences::PrefServiceSyncable* prefs_service,
+ syncer::ModelType type) {
+ return prefs_service ? prefs_service->GetSyncableService(type)->AsWeakPtr()
+ : nullptr;
+}
+
} // namespace
ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
@@ -126,6 +140,10 @@ ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
history_disabled_pref_(history_disabled_pref),
ui_thread_(ui_thread),
db_thread_(db_thread),
+ engines_and_directory_deletion_thread_(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
web_data_service_on_disk_(web_data_service_on_disk),
web_data_service_in_memory_(web_data_service_in_memory),
profile_password_store_(profile_password_store),
@@ -228,14 +246,17 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
// Bookmark sync is enabled by default. Register unless explicitly
// disabled.
if (!disabled_types.Has(syncer::BOOKMARKS)) {
+ favicon::FaviconService* favicon_service =
+ sync_client_->GetFaviconService();
+ // Services can be null in tests.
+ if (bookmark_sync_service_ && favicon_service) {
controllers.push_back(std::make_unique<ModelTypeController>(
syncer::BOOKMARKS,
- std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
- ui_thread_,
- base::BindRepeating(&sync_bookmarks::BookmarkSyncService::
- GetBookmarkSyncControllerDelegate,
- base::Unretained(bookmark_sync_service_),
- sync_client_->GetFaviconService()))));
+ std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
+ bookmark_sync_service_
+ ->GetBookmarkSyncControllerDelegate(favicon_service)
+ .get())));
+ }
}
// These features are enabled only if history is not disabled.
@@ -254,9 +275,10 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
// Delete directive sync is enabled by default.
if (!disabled_types.Has(syncer::HISTORY_DELETE_DIRECTIVES)) {
controllers.push_back(
- std::make_unique<HistoryDeleteDirectivesModelTypeController>(
+ std::make_unique<history::HistoryDeleteDirectivesModelTypeController>(
dump_stack, sync_service,
- sync_client_->GetModelTypeStoreService(), sync_client_));
+ sync_client_->GetModelTypeStoreService(),
+ sync_client_->GetHistoryService()));
}
// Session sync is enabled by default. This is disabled if history is
@@ -301,7 +323,8 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
std::make_unique<SyncableServiceBasedModelTypeController>(
syncer::PREFERENCES,
sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
- sync_client_->GetSyncableServiceForType(syncer::PREFERENCES),
+ SyncableServiceForPrefs(sync_client_->GetPrefServiceSyncable(),
+ syncer::PREFERENCES),
dump_stack));
}
@@ -310,8 +333,8 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
std::make_unique<SyncableServiceBasedModelTypeController>(
syncer::PRIORITY_PREFERENCES,
sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
- sync_client_->GetSyncableServiceForType(
- syncer::PRIORITY_PREFERENCES),
+ SyncableServiceForPrefs(sync_client_->GetPrefServiceSyncable(),
+ syncer::PRIORITY_PREFERENCES),
dump_stack));
}
@@ -341,13 +364,22 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
}
if (!disabled_types.Has(syncer::SEND_TAB_TO_SELF)) {
+ syncer::ModelTypeControllerDelegate* delegate =
+ sync_client_->GetSendTabToSelfSyncService()
+ ->GetControllerDelegate()
+ .get();
controllers.push_back(
std::make_unique<send_tab_to_self::SendTabToSelfModelTypeController>(
sync_service,
+ /*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
- sync_client_->GetSendTabToSelfSyncService()
- ->GetControllerDelegate()
- .get())));
+ delegate),
+ /*delegate_for_transport_mode=*/
+ base::FeatureList::IsEnabled(
+ send_tab_to_self::kSendTabToSelfWhenSignedIn)
+ ? std::make_unique<
+ syncer::ForwardingModelTypeControllerDelegate>(delegate)
+ : nullptr));
}
if (!disabled_types.Has(syncer::USER_CONSENTS)) {
@@ -386,8 +418,21 @@ ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
syncer::SyncInvalidationsService* sync_invalidation_service,
const base::WeakPtr<syncer::SyncPrefs>& sync_prefs) {
return std::make_unique<syncer::SyncEngineImpl>(
- name, invalidator, sync_invalidation_service, sync_prefs,
- sync_client_->GetModelTypeStoreService()->GetSyncDataPath());
+ name, invalidator, sync_invalidation_service,
+ std::make_unique<browser_sync::ActiveDevicesProviderImpl>(
+ sync_client_->GetDeviceInfoSyncService()->GetDeviceInfoTracker(),
+ base::DefaultClock::GetInstance()),
+ sync_prefs, sync_client_->GetModelTypeStoreService()->GetSyncDataPath(),
+ engines_and_directory_deletion_thread_);
+}
+
+void ProfileSyncComponentsFactoryImpl::
+ DeleteLegacyDirectoryFilesAndNigoriStorage() {
+ engines_and_directory_deletion_thread_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &syncer::DeleteLegacyDirectoryFilesAndNigoriStorage,
+ sync_client_->GetModelTypeStoreService()->GetSyncDataPath()));
}
std::unique_ptr<syncer::ModelTypeControllerDelegate>
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.h b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
index 01909fd054e..da0a32a1cce 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
@@ -83,6 +83,7 @@ class ProfileSyncComponentsFactoryImpl
invalidation::InvalidationService* invalidator,
syncer::SyncInvalidationsService* sync_invalidation_service,
const base::WeakPtr<syncer::SyncPrefs>& sync_prefs) override;
+ void DeleteLegacyDirectoryFilesAndNigoriStorage() override;
private:
// Factory function for ModelTypeController instances for models living on
@@ -120,6 +121,8 @@ class ProfileSyncComponentsFactoryImpl
const char* history_disabled_pref_;
const scoped_refptr<base::SequencedTaskRunner> ui_thread_;
const scoped_refptr<base::SequencedTaskRunner> db_thread_;
+ const scoped_refptr<base::SequencedTaskRunner>
+ engines_and_directory_deletion_thread_;
const scoped_refptr<autofill::AutofillWebDataService>
web_data_service_on_disk_;
const scoped_refptr<autofill::AutofillWebDataService>
diff --git a/chromium/components/browser_sync/test_http_bridge_factory.cc b/chromium/components/browser_sync/test_http_bridge_factory.cc
deleted file mode 100644
index 9a50a077efa..00000000000
--- a/chromium/components/browser_sync/test_http_bridge_factory.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 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/browser_sync/test_http_bridge_factory.h"
-
-namespace browser_sync {
-
-bool TestHttpBridge::MakeSynchronousPost(int* net_error_code,
- int* http_status_code) {
- return false;
-}
-
-int TestHttpBridge::GetResponseContentLength() const {
- return 0;
-}
-
-const char* TestHttpBridge::GetResponseContent() const {
- return nullptr;
-}
-
-const std::string TestHttpBridge::GetResponseHeaderValue(
- const std::string&) const {
- return std::string();
-}
-
-void TestHttpBridge::Abort() {}
-
-TestHttpBridgeFactory::TestHttpBridgeFactory() {}
-
-TestHttpBridgeFactory::~TestHttpBridgeFactory() {}
-
-syncer::HttpPostProviderInterface* TestHttpBridgeFactory::Create() {
- return new TestHttpBridge();
-}
-
-void TestHttpBridgeFactory::Destroy(syncer::HttpPostProviderInterface* http) {
- delete static_cast<TestHttpBridge*>(http);
-}
-
-} // namespace browser_sync
diff --git a/chromium/components/browser_sync/test_http_bridge_factory.h b/chromium/components/browser_sync/test_http_bridge_factory.h
deleted file mode 100644
index c1d0fccf5f3..00000000000
--- a/chromium/components/browser_sync/test_http_bridge_factory.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2012 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_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
-#define COMPONENTS_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "components/sync/engine/net/http_post_provider_factory.h"
-#include "components/sync/engine/net/http_post_provider_interface.h"
-
-namespace browser_sync {
-
-class TestHttpBridge : public syncer::HttpPostProviderInterface {
- public:
- // Begin syncer::HttpPostProviderInterface implementation:
- void SetExtraRequestHeaders(const char* headers) override {}
-
- void SetURL(const char* url, int port) override {}
-
- void SetPostPayload(const char* content_type,
- int content_length,
- const char* content) override {}
-
- bool MakeSynchronousPost(int* net_error_code, int* http_status_code) override;
-
- int GetResponseContentLength() const override;
-
- const char* GetResponseContent() const override;
-
- const std::string GetResponseHeaderValue(const std::string&) const override;
-
- void Abort() override;
- // End syncer::HttpPostProviderInterface implementation.
-};
-
-class TestHttpBridgeFactory : public syncer::HttpPostProviderFactory {
- public:
- TestHttpBridgeFactory();
- ~TestHttpBridgeFactory() override;
-
- // syncer::HttpPostProviderFactory:
- syncer::HttpPostProviderInterface* Create() override;
- void Destroy(syncer::HttpPostProviderInterface* http) override;
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_BROWSER_SYNC_TEST_HTTP_BRIDGE_FACTORY_H_
diff --git a/chromium/components/browser_ui/DIR_METADATA b/chromium/components/browser_ui/DIR_METADATA
new file mode 100644
index 00000000000..496d4121fe9
--- /dev/null
+++ b/chromium/components/browser_ui/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+ component: "UI>Browser>Mobile"
+}
+
+team_email: "clank-app-team@google.com"
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/OWNERS b/chromium/components/browser_ui/OWNERS
index 836f24840e5..e4f82087e3e 100644
--- a/chromium/components/browser_ui/OWNERS
+++ b/chromium/components/browser_ui/OWNERS
@@ -1,6 +1,2 @@
tedchoc@chromium.org
twellington@chromium.org
-
-# COMPONENT: UI>Browser>Mobile
-# TEAM: chrome-android-app@chromium.org
-# OS: Android
diff --git a/chromium/components/browser_ui/android/bottomsheet/DIR_METADATA b/chromium/components/browser_ui/android/bottomsheet/DIR_METADATA
new file mode 100644
index 00000000000..1a4392135e6
--- /dev/null
+++ b/chromium/components/browser_ui/android/bottomsheet/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+ component: "UI>Browser>Mobile>NavPanel"
+}
+
+team_email: "clank-app-team@google.com"
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/android/bottomsheet/OWNERS b/chromium/components/browser_ui/android/bottomsheet/OWNERS
index 64e73506e7b..d99c825000f 100644
--- a/chromium/components/browser_ui/android/bottomsheet/OWNERS
+++ b/chromium/components/browser_ui/android/bottomsheet/OWNERS
@@ -1,7 +1,3 @@
mdjones@chromium.org
twellington@chromium.org
-# COMPONENT: UI>Browser>Mobile>NavPanel
-# TEAM: chrome-android-app@chromium.org
-# OS: Android
-
diff --git a/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java b/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
index d9d25e382ef..335fec6bb43 100644
--- a/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
+++ b/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
@@ -180,6 +180,12 @@ class BottomSheet extends FrameLayout
*/
private int mScrollableHeight;
+ /**
+ * The instance passed to the current content that is allowed to
+ * change the sheet offset.
+ */
+ private Callback<Integer> mOffsetController;
+
@Override
public boolean shouldGestureMoveSheet(MotionEvent initialEvent, MotionEvent currentEvent) {
// If the sheet is scrolling off-screen or in the process of hiding, gestures should not
@@ -530,6 +536,10 @@ class BottomSheet extends FrameLayout
if (mSheetContent != null) {
mSheetContent.setContentSizeListener(null);
mSheetContent.getContentView().removeOnLayoutChangeListener(this);
+ if (mOffsetController != null) {
+ mSheetContent.setOffsetController(null);
+ mOffsetController = null;
+ }
}
if (content != null && getParent() == null) {
@@ -671,8 +681,21 @@ class BottomSheet extends FrameLayout
/**
* Sets the sheet's offset relative to the bottom of the screen.
* @param offset The offset that the sheet should be.
+ * @param reason The reason for the sheet offset to change to report to listeners.
*/
void setSheetOffsetFromBottom(float offset, @StateChangeReason int reason) {
+ setSheetOffsetFromBottom(offset, reason, /* reportOpenClosed= */ true);
+ }
+
+ /**
+ * Sets the sheet's offset relative to the bottom of the screen.
+ * @param offset The offset that the sheet should be.
+ * @param reason The reason for the sheet offset to change to report to listeners.
+ * @param reportOpenClosed {@code true} to allow reporting the sheet opened or closed as a
+ * result of this change. {@code reason} is never used when this is {@code false}.
+ */
+ void setSheetOffsetFromBottom(
+ float offset, @StateChangeReason int reason, boolean reportOpenClosed) {
mCurrentOffsetPx = offset;
// The browser controls offset is added here so that the sheet's toolbar behaves like the
@@ -683,28 +706,32 @@ class BottomSheet extends FrameLayout
setTranslationY(translationY);
- // Do open/close computation based on the minimum allowed state by the sheet's content.
- // Note that when transitioning from hidden to peek, even dismissable sheets may want
- // to have a peek state.
- @SheetState
- int minSwipableState = getMinSwipableSheetState();
- if (isPeekStateEnabled() && (!isSheetOpen() || mTargetState == SheetState.PEEK)) {
- minSwipableState = SheetState.PEEK;
- }
+ if (reportOpenClosed) {
+ // Do open/close computation based on the minimum allowed state by the sheet's content.
+ // Note that when transitioning from hidden to peek, even dismissable sheets may want
+ // to have a peek state.
+ @SheetState
+ int minSwipableState = getMinSwipableSheetState();
+ if (isPeekStateEnabled() && (!isSheetOpen() || mTargetState == SheetState.PEEK)) {
+ minSwipableState = SheetState.PEEK;
+ }
- float minScrollableHeight = getSheetHeightForState(minSwipableState);
- boolean isAtMinHeight = MathUtils.areFloatsEqual(getCurrentOffsetPx(), minScrollableHeight);
- boolean heightLessThanPeek = getCurrentOffsetPx() < minScrollableHeight;
- // Trigger the onSheetClosed event when the sheet is moving toward the hidden state if peek
- // is disabled. This should be fine since touch is disabled when the sheet's target is
- // hidden.
- boolean triggerCloseWithHidden = !isPeekStateEnabled() && mTargetState == SheetState.HIDDEN;
-
- if (isSheetOpen() && (heightLessThanPeek || isAtMinHeight || triggerCloseWithHidden)) {
- onSheetClosed(reason);
- } else if (!isSheetOpen() && mTargetState != SheetState.HIDDEN
- && getCurrentOffsetPx() > minScrollableHeight) {
- onSheetOpened(reason);
+ float minScrollableHeight = getSheetHeightForState(minSwipableState);
+ boolean isAtMinHeight =
+ MathUtils.areFloatsEqual(getCurrentOffsetPx(), minScrollableHeight);
+ boolean heightLessThanPeek = getCurrentOffsetPx() < minScrollableHeight;
+ // Trigger the onSheetClosed event when the sheet is moving toward the hidden state if
+ // peek is disabled. This should be fine since touch is disabled when the sheet's target
+ // is hidden.
+ boolean triggerCloseWithHidden =
+ !isPeekStateEnabled() && mTargetState == SheetState.HIDDEN;
+
+ if (isSheetOpen() && (heightLessThanPeek || isAtMinHeight || triggerCloseWithHidden)) {
+ onSheetClosed(reason);
+ } else if (!isSheetOpen() && mTargetState != SheetState.HIDDEN
+ && getCurrentOffsetPx() > minScrollableHeight) {
+ onSheetOpened(reason);
+ }
}
sendOffsetChangeEvents();
@@ -1232,18 +1259,34 @@ class BottomSheet extends FrameLayout
protected void onSheetContentChanged(@Nullable final BottomSheetContent content) {
mSheetContent = content;
- if (isFullHeightWrapContent()) {
- // Listen for layout/size changes.
- if (!content.setContentSizeListener(this::onContentSizeChanged)) {
- content.getContentView().addOnLayoutChangeListener(this);
- }
+ if (content != null) {
+ if (isFullHeightWrapContent()) {
+ // Listen for layout/size changes.
+ if (!content.setContentSizeListener(this::onContentSizeChanged)) {
+ content.getContentView().addOnLayoutChangeListener(this);
+ }
+
+ invalidateContentDesiredHeight();
+ ensureContentIsWrapped(/* animate= */ true);
- invalidateContentDesiredHeight();
- ensureContentIsWrapped(/* animate= */ true);
+ // HALF state is forbidden when wrapping the content.
+ if (mCurrentState == SheetState.HALF) {
+ setSheetState(SheetState.FULL, /* animate= */ true);
+ }
+ }
+ if (content.contentControlsOffset()) {
+ mOffsetController = new Callback<Integer>() {
+ @Override
+ public void onResult(Integer offsetPx) {
+ if (this != mOffsetController) return;
- // HALF state is forbidden when wrapping the content.
- if (mCurrentState == SheetState.HALF) {
- setSheetState(SheetState.FULL, /* animate= */ true);
+ cancelAnimation();
+ setSheetOffsetFromBottom(
+ MathUtils.clamp(offsetPx, 0, (int) getMaxOffsetPx()),
+ StateChangeReason.NONE, /* reportOpenClosed=*/false);
+ }
+ };
+ content.setOffsetController(mOffsetController);
}
}
@@ -1271,6 +1314,12 @@ class BottomSheet extends FrameLayout
*/
private void onContentSizeChanged(int width, int height, int oldWidth, int oldHeight) {
boolean heightChanged = mContentDesiredHeight != height;
+ boolean widthChanged = mContentWidth != width;
+
+ // onContentSizeChanged() is sometimes called when there's no size change, because of
+ // animations running in the content. Ignore these calls.
+ if (!heightChanged && !widthChanged) return;
+
mContentDesiredHeight = height;
if (heightChanged && mCurrentState == SheetState.SCROLLING) {
diff --git a/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java b/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
index 68685b6da41..2ed9edbda1b 100644
--- a/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
+++ b/chromium/components/browser_ui/android/bottomsheet/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
@@ -515,4 +515,9 @@ class BottomSheetControllerImpl implements ManagedBottomSheetController {
private boolean canBottomSheetSwitchContent() {
return !mBottomSheet.isSheetOpen();
}
+
+ @VisibleForTesting
+ boolean hasSuppressionTokensForTesting() {
+ return mSuppressionTokens.hasTokens();
+ }
}
diff --git a/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java b/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
index 554352dd25f..9b0c55e7043 100644
--- a/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
+++ b/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
@@ -9,6 +9,8 @@ import android.view.View;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
+import org.chromium.base.Callback;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -205,4 +207,23 @@ public interface BottomSheetContent {
* typically the name of your feature followed by 'closed'.
*/
int getSheetClosedAccessibilityStringId();
+
+ /**
+ * Return {@code true} if the content expects {@link #setOffsetController} to be called.
+ *
+ * This is an experimental feature. Use it at your own risks. TODO(b/177037825): Remove or
+ * cleanup.
+ */
+ default boolean contentControlsOffset() {
+ return false;
+ }
+
+ /**
+ * Set or reset the set offset callback.
+ *
+ * The active content can use this callback to move the sheet to the given offset.
+ *
+ * Only called if {@link #contentControlsOffset} returns {@code true}.
+ */
+ default void setOffsetController(@Nullable Callback<Integer> setOffset) {}
}
diff --git a/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java b/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
index d24e41afe7b..6e0266482ff 100644
--- a/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
+++ b/chromium/components/browser_ui/android/bottomsheet/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
@@ -50,7 +50,8 @@ public interface BottomSheetController {
@IntDef({StateChangeReason.NONE, StateChangeReason.SWIPE, StateChangeReason.BACK_PRESS,
StateChangeReason.TAP_SCRIM, StateChangeReason.NAVIGATION,
StateChangeReason.COMPOSITED_UI, StateChangeReason.VR, StateChangeReason.PROMOTE_TAB,
- StateChangeReason.OMNIBOX_FOCUS, StateChangeReason.MAX_VALUE})
+ StateChangeReason.OMNIBOX_FOCUS, StateChangeReason.INTERACTION_COMPLETE,
+ StateChangeReason.MAX_VALUE})
@Retention(RetentionPolicy.SOURCE)
@interface StateChangeReason {
int NONE = 0;
@@ -62,7 +63,10 @@ public interface BottomSheetController {
int VR = 6;
int PROMOTE_TAB = 7;
int OMNIBOX_FOCUS = 8;
- int MAX_VALUE = OMNIBOX_FOCUS;
+ int INTERACTION_COMPLETE = 9;
+
+ // STOP: Updates here require an update in enums.xml.
+ int MAX_VALUE = INTERACTION_COMPLETE;
}
/**
diff --git a/chromium/components/browser_ui/client_certificate/DIR_METADATA b/chromium/components/browser_ui/client_certificate/DIR_METADATA
new file mode 100644
index 00000000000..7e674fb1ad6
--- /dev/null
+++ b/chromium/components/browser_ui/client_certificate/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Internals>Network>Auth"
+}
diff --git a/chromium/components/browser_ui/client_certificate/OWNERS b/chromium/components/browser_ui/client_certificate/OWNERS
index bd8c1538b60..d6f39100104 100644
--- a/chromium/components/browser_ui/client_certificate/OWNERS
+++ b/chromium/components/browser_ui/client_certificate/OWNERS
@@ -3,5 +3,3 @@ dmcardle@chromium.org
# Secondary:
file://chrome/android/OWNERS
-
-# COMPONENT: Internals>Network>Auth
diff --git a/chromium/components/browser_ui/contacts_picker/android/DIR_METADATA b/chromium/components/browser_ui/contacts_picker/android/DIR_METADATA
new file mode 100644
index 00000000000..a11189669d4
--- /dev/null
+++ b/chromium/components/browser_ui/contacts_picker/android/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>Contacts"
+}
+
+team_email: "fugu-dev@chromium.org"
diff --git a/chromium/components/browser_ui/contacts_picker/android/OWNERS b/chromium/components/browser_ui/contacts_picker/android/OWNERS
index 662f3e7591d..517774d1ac4 100644
--- a/chromium/components/browser_ui/contacts_picker/android/OWNERS
+++ b/chromium/components/browser_ui/contacts_picker/android/OWNERS
@@ -1,6 +1,3 @@
finnur@chromium.org
peter@chromium.org
rayankans@chromium.org
-
-# COMPONENT: Blink>Contacts
-# TEAM: fugu-dev@chromium.org
diff --git a/chromium/components/browser_ui/display_cutout/DIR_METADATA b/chromium/components/browser_ui/display_cutout/DIR_METADATA
new file mode 100644
index 00000000000..53108245d32
--- /dev/null
+++ b/chromium/components/browser_ui/display_cutout/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "Blink>Layout"
+}
diff --git a/chromium/components/browser_ui/display_cutout/OWNERS b/chromium/components/browser_ui/display_cutout/OWNERS
index a421a715a74..70313512d0c 100644
--- a/chromium/components/browser_ui/display_cutout/OWNERS
+++ b/chromium/components/browser_ui/display_cutout/OWNERS
@@ -1,4 +1,2 @@
beccahughes@chromium.org
mlamouri@chromium.org
-
-# COMPONENT: Blink>Layout
diff --git a/chromium/components/browser_ui/media/DIR_METADATA b/chromium/components/browser_ui/media/DIR_METADATA
new file mode 100644
index 00000000000..87867de4c4a
--- /dev/null
+++ b/chromium/components/browser_ui/media/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Internals>Media>UI"
+}
+
+team_email: "media-dev@chromium.org"
diff --git a/chromium/components/browser_ui/media/OWNERS b/chromium/components/browser_ui/media/OWNERS
index 28f64e589e9..2d282460822 100644
--- a/chromium/components/browser_ui/media/OWNERS
+++ b/chromium/components/browser_ui/media/OWNERS
@@ -1,4 +1 @@
mlamouri@chromium.org
-
-# TEAM: media-dev@chromium.org
-# COMPONENT: Internals>Media>UI
diff --git a/chromium/components/browser_ui/media/android/BUILD.gn b/chromium/components/browser_ui/media/android/BUILD.gn
index 9e400046e5a..f7fb6220a25 100644
--- a/chromium/components/browser_ui/media/android/BUILD.gn
+++ b/chromium/components/browser_ui/media/android/BUILD.gn
@@ -22,6 +22,8 @@ android_library("java") {
":java_resources",
"//base:base_java",
"//components/browser_ui/notifications/android:java",
+ "//components/embedder_support/android:browser_context_java",
+ "//components/favicon/android:java",
"//components/url_formatter/android:url_formatter_java",
"//content/public/android:content_java",
"//services/media_session/public/cpp/android:media_session_java",
diff --git a/chromium/components/browser_ui/media/android/DEPS b/chromium/components/browser_ui/media/android/DEPS
index 652050725b0..b2861ef6d1a 100644
--- a/chromium/components/browser_ui/media/android/DEPS
+++ b/chromium/components/browser_ui/media/android/DEPS
@@ -1,4 +1,6 @@
include_rules = [
+ "+components/embedder_support/android",
+ "+components/favicon/android",
"+components/url_formatter/android",
"+content/public/android",
"+services/media_session/public/cpp/android",
diff --git a/chromium/components/browser_ui/notifications/android/DIR_METADATA b/chromium/components/browser_ui/notifications/android/DIR_METADATA
new file mode 100644
index 00000000000..55fac6aa24e
--- /dev/null
+++ b/chromium/components/browser_ui/notifications/android/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+ component: "UI>Notifications"
+}
+
+team_email: "chrome-notifications@google.com"
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/notifications/android/OWNERS b/chromium/components/browser_ui/notifications/android/OWNERS
index 2f0eb9c2ba8..62782dbc223 100644
--- a/chromium/components/browser_ui/notifications/android/OWNERS
+++ b/chromium/components/browser_ui/notifications/android/OWNERS
@@ -5,7 +5,3 @@ xingliu@chromium.org
# Common notification owners
file://chrome/browser/notifications/OWNERS
-
-# COMPONENT: UI>Notifications
-# TEAM: chrome-notifications@google.com
-# OS: Android \ No newline at end of file
diff --git a/chromium/components/browser_ui/photo_picker/android/DIR_METADATA b/chromium/components/browser_ui/photo_picker/android/DIR_METADATA
new file mode 100644
index 00000000000..32b2e155189
--- /dev/null
+++ b/chromium/components/browser_ui/photo_picker/android/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "UI>Browser>MediaPicker"
+}
+
+team_email: "fugu-dev@chromium.org"
diff --git a/chromium/components/browser_ui/photo_picker/android/OWNERS b/chromium/components/browser_ui/photo_picker/android/OWNERS
index 9a657226333..3a06654b44b 100644
--- a/chromium/components/browser_ui/photo_picker/android/OWNERS
+++ b/chromium/components/browser_ui/photo_picker/android/OWNERS
@@ -1,5 +1,2 @@
finnur@chromium.org
peter@chromium.org
-
-# COMPONENT: UI>Browser>MediaPicker
-# TEAM: fugu-dev@chromium.org
diff --git a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreference.java b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreference.java
index 52e32b90d96..bd42081e9b9 100644
--- a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreference.java
+++ b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreference.java
@@ -11,6 +11,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -40,6 +41,9 @@ public class ChromeImageViewPreference extends Preference {
// The image resource ID to use for the ImageView widget source.
@DrawableRes
private int mImageRes;
+ // The color resource ID for tinting of ImageView widget.
+ @ColorRes
+ private int mColorRes;
// The string resource ID to use for the ImageView widget content description.
@StringRes
private int mContentDescriptionRes;
@@ -61,6 +65,7 @@ public class ChromeImageViewPreference extends Preference {
setWidgetLayoutResource(R.layout.preference_chrome_image_view);
setSingleLineTitle(false);
+ setImageColor(R.color.default_icon_color);
}
/**
@@ -79,8 +84,7 @@ public class ChromeImageViewPreference extends Preference {
View view = holder.itemView;
if (mImageRes != 0) {
- Drawable buttonImg = SettingsUtils.getTintedIcon(getContext(), mImageRes);
-
+ Drawable buttonImg = SettingsUtils.getTintedIcon(getContext(), mImageRes, mColorRes);
button.setImageDrawable(buttonImg);
button.setBackgroundColor(Color.TRANSPARENT);
button.setVisibility(View.VISIBLE);
@@ -114,6 +118,14 @@ public class ChromeImageViewPreference extends Preference {
}
/**
+ * Sets the Color resource ID which will be used to set the color of the image.
+ * @param colorRes
+ */
+ public void setImageColor(@ColorRes int colorRes) {
+ mColorRes = colorRes;
+ }
+
+ /**
* Enables/Disables the ImageView, allowing for clicks to pass through (when disabled).
*/
public void setImageViewEnabled(boolean enabled) {
diff --git a/chromium/components/browser_ui/share/DIR_METADATA b/chromium/components/browser_ui/share/DIR_METADATA
new file mode 100644
index 00000000000..3e064095c61
--- /dev/null
+++ b/chromium/components/browser_ui/share/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "UI>Browser>Sharing"
+}
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/share/OWNERS b/chromium/components/browser_ui/share/OWNERS
index 4484c9bff6e..81db91097c3 100644
--- a/chromium/components/browser_ui/share/OWNERS
+++ b/chromium/components/browser_ui/share/OWNERS
@@ -1,6 +1,3 @@
dtrainor@chromium.org
file://components/send_tab_to_self/OWNERS
-
-# COMPONENT: UI>Browser>Sharing
-# OS: Android
diff --git a/chromium/components/browser_ui/site_settings/DIR_METADATA b/chromium/components/browser_ui/site_settings/DIR_METADATA
new file mode 100644
index 00000000000..4752c1209ca
--- /dev/null
+++ b/chromium/components/browser_ui/site_settings/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+ component: "UI>Browser>Mobile>Settings"
+}
diff --git a/chromium/components/browser_ui/site_settings/OWNERS b/chromium/components/browser_ui/site_settings/OWNERS
index 51a2813fe32..164ccd91523 100644
--- a/chromium/components/browser_ui/site_settings/OWNERS
+++ b/chromium/components/browser_ui/site_settings/OWNERS
@@ -2,5 +2,3 @@ finnur@chromium.org
hkamila@chromium.org
andypaicu@chromium.org
dullweber@chromium.org
-
-# COMPONENT: UI>Browser>Mobile>Settings
diff --git a/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc b/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
index a933d1159f3..aea039ec673 100644
--- a/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
+++ b/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
@@ -13,7 +13,7 @@
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
@@ -126,6 +126,7 @@ ScopedJavaLocalRef<jstring> ConvertOriginToJavaString(
typedef void (*InfoListInsertionFunction)(
JNIEnv*,
+ JniIntWrapper,
const base::android::JavaRef<jobject>&,
const base::android::JavaRef<jstring>&,
const base::android::JavaRef<jstring>&,
@@ -142,11 +143,9 @@ void GetOrigins(JNIEnv* env,
ContentSettingsForOneType all_settings;
ContentSettingsForOneType embargo_settings;
- content_settings_map->GetSettingsForOneType(content_type, std::string(),
- &all_settings);
+ content_settings_map->GetSettingsForOneType(content_type, &all_settings);
content_settings_map->GetSettingsForOneType(
- ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, std::string(),
- &embargo_settings);
+ ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, &embargo_settings);
ContentSetting default_content_setting =
content_settings_map->GetDefaultContentSetting(content_type, nullptr);
@@ -170,7 +169,8 @@ void GetOrigins(JNIEnv* env,
jembedder = ConvertUTF8ToJavaString(env, embedder);
seen_origins.push_back(origin);
- insertionFunc(env, list, ConvertOriginToJavaString(env, origin), jembedder,
+ insertionFunc(env, static_cast<int>(content_type), list,
+ ConvertOriginToJavaString(env, origin), jembedder,
/*is_embargoed=*/false);
}
@@ -192,8 +192,9 @@ void GetOrigins(JNIEnv* env,
if (auto_blocker->GetEmbargoResult(GURL(origin), content_type)
.content_setting == CONTENT_SETTING_BLOCK) {
seen_origins.push_back(origin);
- insertionFunc(env, list, ConvertOriginToJavaString(env, origin),
- jembedder, /*is_embargoed=*/true);
+ insertionFunc(env, static_cast<int>(content_type), list,
+ ConvertOriginToJavaString(env, origin), jembedder,
+ /*is_embargoed=*/true);
}
}
}
@@ -250,7 +251,7 @@ void SetSettingForOrigin(JNIEnv* env,
permissions::PermissionSourceUI::SITE_SETTINGS);
GetHostContentSettingsMap(browser_context)
->SetContentSettingDefaultScope(origin_url, embedder_url, content_type,
- std::string(), setting);
+ setting);
content_settings::LogWebSiteSettingsPermissionChange(content_type, setting);
}
@@ -319,175 +320,6 @@ bool IsContentSettingUserModifiable(
} // anonymous namespace
-static void JNI_WebsitePreferenceBridge_GetClipboardOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(
- env, jbrowser_context_handle, ContentSettingsType::CLIPBOARD_READ_WRITE,
- &Java_WebsitePreferenceBridge_insertClipboardInfoIntoList, list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetClipboardSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::CLIPBOARD_READ_WRITE, origin,
- origin);
-}
-
-static void JNI_WebsitePreferenceBridge_SetClipboardSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::CLIPBOARD_READ_WRITE, origin, origin,
- static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetGeolocationOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list,
- jboolean managedOnly) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::GEOLOCATION,
- &Java_WebsitePreferenceBridge_insertGeolocationInfoIntoList, list,
- managedOnly);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetGeolocationSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::GEOLOCATION, origin,
- embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetGeolocationSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::GEOLOCATION, origin, embedder,
- static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetIdleDetectionOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::IDLE_DETECTION,
- &Java_WebsitePreferenceBridge_insertIdleDetectionInfoIntoList,
- list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetIdleDetectionSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::IDLE_DETECTION, origin,
- embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetIdleDetectionSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::IDLE_DETECTION, origin, embedder,
- static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetMidiOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::MIDI_SYSEX,
- &Java_WebsitePreferenceBridge_insertMidiInfoIntoList, list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetMidiSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MIDI_SYSEX, origin, embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetMidiSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MIDI_SYSEX, origin, embedder,
- static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetProtectedMediaIdentifierOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(
- env, jbrowser_context_handle,
- ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
- &Java_WebsitePreferenceBridge_insertProtectedMediaIdentifierInfoIntoList,
- list, false);
-}
-
-static jint
-JNI_WebsitePreferenceBridge_GetProtectedMediaIdentifierSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
- origin, embedder);
-}
-
-static void
-JNI_WebsitePreferenceBridge_SetProtectedMediaIdentifierSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, origin,
- embedder, static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetNotificationOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::NOTIFICATIONS,
- &Java_WebsitePreferenceBridge_insertNotificationIntoList, list,
- false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetNotificationSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::NOTIFICATIONS, origin,
- origin);
-}
-
static jboolean JNI_WebsitePreferenceBridge_IsNotificationEmbargoedForOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
@@ -505,7 +337,7 @@ static jboolean JNI_WebsitePreferenceBridge_IsNotificationEmbargoedForOrigin(
permissions::PermissionStatusSource::MULTIPLE_DISMISSALS);
}
-static void JNI_WebsitePreferenceBridge_SetNotificationSettingForOrigin(
+static void SetNotificationSettingForOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
const JavaParamRef<jstring>& origin,
@@ -541,8 +373,7 @@ static void JNI_WebsitePreferenceBridge_SetNotificationSettingForOrigin(
GetHostContentSettingsMap(browser_context)
->SetContentSettingDefaultScope(
- url, GURL(), ContentSettingsType::NOTIFICATIONS,
- content_settings::ResourceIdentifier(), setting);
+ url, GURL(), ContentSettingsType::NOTIFICATIONS, setting);
content_settings::LogWebSiteSettingsPermissionChange(
ContentSettingsType::NOTIFICATIONS, setting);
}
@@ -568,67 +399,52 @@ static void JNI_WebsitePreferenceBridge_ReportNotificationRevokedForOrigin(
unwrap(jbrowser_context_handle));
}
-static void JNI_WebsitePreferenceBridge_GetCameraOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list,
- jboolean managedOnly) {
- GetOrigins(env, jbrowser_context_handle,
- ContentSettingsType::MEDIASTREAM_CAMERA,
- &Java_WebsitePreferenceBridge_insertCameraInfoIntoList, list,
- managedOnly);
-}
-
-static void JNI_WebsitePreferenceBridge_GetMicrophoneOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list,
- jboolean managedOnly) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::MEDIASTREAM_MIC,
- &Java_WebsitePreferenceBridge_insertMicrophoneInfoIntoList, list,
- managedOnly);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetMicrophoneSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MEDIASTREAM_MIC, origin,
- embedder);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetCameraSettingForOrigin(
+static jint JNI_WebsitePreferenceBridge_GetSettingForOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
+ jint content_settings_type,
const JavaParamRef<jstring>& origin,
const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MEDIASTREAM_CAMERA, origin,
+ ContentSettingsType type =
+ static_cast<ContentSettingsType>(content_settings_type);
+ return GetSettingForOrigin(env, jbrowser_context_handle, type, origin,
embedder);
}
-static void JNI_WebsitePreferenceBridge_SetMicrophoneSettingForOrigin(
+static void JNI_WebsitePreferenceBridge_SetSettingForOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
+ jint content_settings_type,
const JavaParamRef<jstring>& origin,
+ const JavaParamRef<jstring>& embedder,
jint value) {
- // Here 'nullptr' indicates that microphone uses wildcard for embedder.
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MEDIASTREAM_MIC, origin, nullptr,
- static_cast<ContentSetting>(value));
+ ContentSettingsType type =
+ static_cast<ContentSettingsType>(content_settings_type);
+
+ switch (type) {
+ case ContentSettingsType::NOTIFICATIONS:
+ return SetNotificationSettingForOrigin(env, jbrowser_context_handle,
+ origin, value);
+ case ContentSettingsType::MEDIASTREAM_MIC:
+ case ContentSettingsType::MEDIASTREAM_CAMERA:
+ return SetSettingForOrigin(env, jbrowser_context_handle, type, origin,
+ nullptr, static_cast<ContentSetting>(value));
+ default:
+ SetSettingForOrigin(env, jbrowser_context_handle, type, origin, embedder,
+ static_cast<ContentSetting>(value));
+ }
}
-static void JNI_WebsitePreferenceBridge_SetCameraSettingForOrigin(
+static void JNI_WebsitePreferenceBridge_GetOriginsForPermission(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- jint value) {
- // Here 'nullptr' indicates that camera uses wildcard for embedder.
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::MEDIASTREAM_CAMERA, origin, nullptr,
- static_cast<ContentSetting>(value));
+ jint content_settings_type,
+ const JavaParamRef<jobject>& list,
+ jboolean managedOnly) {
+ GetOrigins(env, jbrowser_context_handle,
+ static_cast<ContentSettingsType>(content_settings_type),
+ &Java_WebsitePreferenceBridge_insertPermissionInfoIntoList, list,
+ managedOnly);
}
static jboolean JNI_WebsitePreferenceBridge_IsContentSettingsPatternValid(
@@ -887,7 +703,7 @@ static void JNI_WebsitePreferenceBridge_ClearBannerData(
GetHostContentSettingsMap(jbrowser_context_handle)
->SetWebsiteSettingDefaultScope(
GURL(ConvertJavaStringToUTF8(env, jorigin)), GURL(),
- ContentSettingsType::APP_BANNER, std::string(), nullptr);
+ ContentSettingsType::APP_BANNER, nullptr);
}
static void JNI_WebsitePreferenceBridge_ClearMediaLicenses(
@@ -923,118 +739,8 @@ static jboolean JNI_WebsitePreferenceBridge_GetAdBlockingActivated(
unwrap(jbrowser_context_handle), url);
}
-static void JNI_WebsitePreferenceBridge_GetArOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::AR,
- &Java_WebsitePreferenceBridge_insertArInfoIntoList, list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetArSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::AR, origin, embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetArSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle, ContentSettingsType::AR,
- origin, embedder, static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetNfcOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::NFC,
- &Java_WebsitePreferenceBridge_insertNfcInfoIntoList, list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetNfcSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::NFC, origin, embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetNfcSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle, ContentSettingsType::NFC,
- origin, embedder, static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetSensorsOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::SENSORS,
- &Java_WebsitePreferenceBridge_insertSensorsInfoIntoList, list,
- false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetSensorsSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::SENSORS, origin, embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetSensorsSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::SENSORS, origin, embedder,
- static_cast<ContentSetting>(value));
-}
-
-static void JNI_WebsitePreferenceBridge_GetVrOrigins(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jobject>& list) {
- GetOrigins(env, jbrowser_context_handle, ContentSettingsType::VR,
- &Java_WebsitePreferenceBridge_insertVrInfoIntoList, list, false);
-}
-
-static jint JNI_WebsitePreferenceBridge_GetVrSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder) {
- return GetSettingForOrigin(env, jbrowser_context_handle,
- ContentSettingsType::VR, origin, embedder);
-}
-
-static void JNI_WebsitePreferenceBridge_SetVrSettingForOrigin(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- const JavaParamRef<jstring>& origin,
- const JavaParamRef<jstring>& embedder,
- jint value) {
- SetSettingForOrigin(env, jbrowser_context_handle, ContentSettingsType::VR,
- origin, embedder, static_cast<ContentSetting>(value));
-}
-
-// On Android O+ notification channels are not stored in the Chrome profile and
-// so are persisted across tests. This function resets them.
+// On Android O+ notification channels are not stored in the Chrome profile
+// and so are persisted across tests. This function resets them.
static void JNI_WebsitePreferenceBridge_ResetNotificationsSettingsForTest(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle) {
@@ -1142,7 +848,7 @@ static void JNI_WebsitePreferenceBridge_SetContentSettingForPattern(
? ContentSettingsPattern::Wildcard()
: ContentSettingsPattern::FromString(secondary_pattern_string),
static_cast<ContentSettingsType>(content_settings_type),
- std::string(), static_cast<ContentSetting>(setting));
+ static_cast<ContentSetting>(setting));
}
static void JNI_WebsitePreferenceBridge_GetContentSettingsExceptions(
@@ -1153,8 +859,7 @@ static void JNI_WebsitePreferenceBridge_GetContentSettingsExceptions(
ContentSettingsForOneType entries;
GetHostContentSettingsMap(jbrowser_context_handle)
->GetSettingsForOneType(
- static_cast<ContentSettingsType>(content_settings_type), "",
- &entries);
+ static_cast<ContentSettingsType>(content_settings_type), &entries);
for (size_t i = 0; i < entries.size(); ++i) {
Java_WebsitePreferenceBridge_addContentSettingExceptionToList(
env, list, content_settings_type,
@@ -1213,4 +918,3 @@ static jboolean JNI_WebsitePreferenceBridge_GetLocationAllowedByPolicy(
->GetDefaultContentSetting(ContentSettingsType::GEOLOCATION,
nullptr) == CONTENT_SETTING_ALLOW;
}
-
diff --git a/chromium/components/browser_ui/sms/android/BUILD.gn b/chromium/components/browser_ui/sms/android/BUILD.gn
index edb5d070cd1..a4acd7fde03 100644
--- a/chromium/components/browser_ui/sms/android/BUILD.gn
+++ b/chromium/components/browser_ui/sms/android/BUILD.gn
@@ -27,15 +27,15 @@ source_set("android") {
generate_jni("jni_headers") {
sources = [
- "java/src/org/chromium/components/browser_ui/sms/SmsReceiverInfoBar.java",
+ "java/src/org/chromium/components/browser_ui/sms/WebOTPServiceInfoBar.java",
]
}
android_library("java") {
resources_package = "org.chromium.components.browser_ui.sms"
sources = [
- "java/src/org/chromium/components/browser_ui/sms/SmsReceiverInfoBar.java",
- "java/src/org/chromium/components/browser_ui/sms/SmsReceiverUma.java",
+ "java/src/org/chromium/components/browser_ui/sms/WebOTPServiceInfoBar.java",
+ "java/src/org/chromium/components/browser_ui/sms/WebOTPServiceUma.java",
]
deps = [
diff --git a/chromium/components/browser_ui/sms/android/DIR_METADATA b/chromium/components/browser_ui/sms/android/DIR_METADATA
new file mode 100644
index 00000000000..9ade438fe6b
--- /dev/null
+++ b/chromium/components/browser_ui/sms/android/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>SMS"
+}
+
+team_email: "fugu-dev@chromium.org"
diff --git a/chromium/components/browser_ui/sms/android/OWNERS b/chromium/components/browser_ui/sms/android/OWNERS
index 39f063f46bf..ad9d6f7da28 100644
--- a/chromium/components/browser_ui/sms/android/OWNERS
+++ b/chromium/components/browser_ui/sms/android/OWNERS
@@ -1,4 +1 @@
file://content/browser/sms/OWNERS
-
-# COMPONENT: Blink>SMS
-# TEAM: fugu-dev@chromium.org
diff --git a/chromium/components/browser_ui/sms/android/README.md b/chromium/components/browser_ui/sms/android/README.md
index 1d78b97b0fc..72c950998cc 100644
--- a/chromium/components/browser_ui/sms/android/README.md
+++ b/chromium/components/browser_ui/sms/android/README.md
@@ -1,3 +1,3 @@
-# SMS Receiver API
+# WebOTP Service API
-This directory contains the android specific implementation of the SMS Receiver API user interface. For more details, refer to [this README file](https://cs.chromium.org/chromium/src/content/browser/sms/README.md).
+This directory contains the android specific implementation of the WebOTP Service API user interface. For more details, refer to [this README file](https://cs.chromium.org/chromium/src/content/browser/sms/README.md).
diff --git a/chromium/components/browser_ui/sms/android/sms_infobar.cc b/chromium/components/browser_ui/sms/android/sms_infobar.cc
index baa9ef9bf0f..8c9b6f46b0b 100644
--- a/chromium/components/browser_ui/sms/android/sms_infobar.cc
+++ b/chromium/components/browser_ui/sms/android/sms_infobar.cc
@@ -5,7 +5,7 @@
#include "components/browser_ui/sms/android/sms_infobar.h"
#include "base/android/jni_string.h"
-#include "components/browser_ui/sms/android/jni_headers/SmsReceiverInfoBar_jni.h"
+#include "components/browser_ui/sms/android/jni_headers/WebOTPServiceInfoBar_jni.h"
#include "components/browser_ui/sms/android/sms_infobar_delegate.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
@@ -52,8 +52,8 @@ ScopedJavaLocalRef<jobject> SmsInfoBar::CreateRenderInfoBar(JNIEnv* env) {
base::android::ScopedJavaLocalRef<jobject> window_android =
web_contents_->GetNativeView()->GetWindowAndroid()->GetJavaObject();
- return Java_SmsReceiverInfoBar_create(env, window_android, GetJavaIconId(),
- title, message, button);
+ return Java_WebOTPServiceInfoBar_create(env, window_android, GetJavaIconId(),
+ title, message, button);
}
} // namespace sms
diff --git a/chromium/components/browser_ui/sms/android/sms_infobar_delegate.cc b/chromium/components/browser_ui/sms/android/sms_infobar_delegate.cc
index d023211a271..59f1bd317d7 100644
--- a/chromium/components/browser_ui/sms/android/sms_infobar_delegate.cc
+++ b/chromium/components/browser_ui/sms/android/sms_infobar_delegate.cc
@@ -31,7 +31,7 @@ SmsInfoBarDelegate::~SmsInfoBarDelegate() = default;
infobars::InfoBarDelegate::InfoBarIdentifier SmsInfoBarDelegate::GetIdentifier()
const {
- return SMS_RECEIVER_INFOBAR_DELEGATE;
+ return WEBOTP_SERVICE_INFOBAR_DELEGATE;
}
int SmsInfoBarDelegate::GetIconId() const {
diff --git a/chromium/components/browser_ui/strings/android/BUILD.gn b/chromium/components/browser_ui/strings/android/BUILD.gn
index f7aca7a2d9d..d99f4d812f9 100644
--- a/chromium/components/browser_ui/strings/android/BUILD.gn
+++ b/chromium/components/browser_ui/strings/android/BUILD.gn
@@ -2,8 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
java_strings_grd("browser_ui_strings_grd") {
grd_file = "browser_ui_strings.grd"
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings.grd b/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
index 6ece679f9f7..5dfa59297ce 100644
--- a/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -553,10 +553,19 @@
<message name="IDS_PAGE_INFO_DSE_PERMISSION_BLOCKED" desc="The label used in the Page Info dialog to describe a blocked location permission for the current search engine. Eg: Location - Blocked for current search engine">
Blocked for current search engine
</message>
+ <message name="IDS_PAGE_INFO_URL_EXPANDED" desc="Accessibility announcement when the URL in PageInfo switches from truncated to full display">
+ URL expanded
+ </message>
+ <message name="IDS_PAGE_INFO_URL_TRUNCATED" desc="Accessibility announcement when the URL in PageInfo switches from full to truncated display">
+ URL truncated
+ </message>
<message name="IDS_COOKIES_TITLE" desc="Title for the Cookies settings screen [CHAR-LIMIT=32]">
Cookies
</message>
+ <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO" desc="Content description for the page icon that gives more site information when clicked. The icon can be a magnifier for search result pages, or other icons representing the page state.">
+ Site information
+ </message>
<!-- Media Capture and Streams -->
<message name="IDS_MEDIA_CAPTURE_NOTIFICATION_APP_NAME_SEPARATOR" desc="A separator between the app name and notification message.">
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO.png.sha1
new file mode 100644
index 00000000000..93240a6cc64
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO.png.sha1
@@ -0,0 +1 @@
+1e849f3b9392284f45e1b9aaf06c0c834089bb26 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_EXPANDED.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_EXPANDED.png.sha1
new file mode 100644
index 00000000000..49c03ca1a25
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_EXPANDED.png.sha1
@@ -0,0 +1 @@
+fd3446cd27d633040a452543788f61e8fac2d2a5 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_TRUNCATED.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_TRUNCATED.png.sha1
new file mode 100644
index 00000000000..49c03ca1a25
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_URL_TRUNCATED.png.sha1
@@ -0,0 +1 @@
+fd3446cd27d633040a452543788f61e8fac2d2a5 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings.grdp b/chromium/components/browser_ui/strings/android/site_settings.grdp
index 421dd7e9269..a48547185be 100644
--- a/chromium/components/browser_ui/strings/android/site_settings.grdp
+++ b/chromium/components/browser_ui/strings/android/site_settings.grdp
@@ -31,7 +31,7 @@
Clipboard
</message>
<message name="IDS_WEBSITE_SETTINGS_IDLE_DETECTION" desc="Title of the permission to detect user activity [CHAR-LIMIT=32]">
- User presence
+ Your presence
</message>
<message name="IDS_JAVASCRIPT_PERMISSION_TITLE" desc="Title of the permission to run javascript [CHAR-LIMIT=32]">
JavaScript
@@ -143,15 +143,21 @@
<message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOW" desc="Summary text explaining that Chrome will allow a website to access some permission, e.g. JavaScript: allow.">
Allow
</message>
- <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOW_DSE" desc="Summary text explaining that Chrome will allow the default search engine to access the user's location, both when performed from the address bar and from search result pages. e.g. Location access: Allow for current search engine">
+ <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOW_DSE" desc="Summary text explaining that Chrome will allow the default search engine to access this permission, both when performed from the address bar and from search result pages. e.g. Location access: Allow for current search engine">
Allow for current search engine
</message>
+ <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOWED_DSE" desc="Status message explaining that the default search engine is allowed to access this permission. Displayed in Site Settings page. e.g. Location: Allowed for current search engine">
+ Allowed for current search engine
+ </message>
<message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCK" desc="Summary text explaining that Chrome will block a website from accessing some permission, e.g. JavaScript: block.">
Block
</message>
- <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCK_DSE" desc="Summary text explaining that Chrome will block the default search engine from accessing the user's location, both when performed from the address bar and from search result pages. e.g. Location access: Block for current search engine">
+ <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCK_DSE" desc="Summary text explaining that Chrome will block the default search engine from accessing this permission, both when performed from the address bar and from search result pages. e.g. Location access: Block for current search engine">
Block for current search engine
</message>
+ <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCKED_DSE" desc="Status message explaining that the default search engine is blocked from accessing this permission. Displayed in Site Settings page. e.g. Location: Blocked for current search engine">
+ Blocked for current search engine
+ </message>
<message name="IDS_WEBSITE_SETTINGS_THIRD_PARTY_COOKIES_EXCEPTION_LABEL" desc="The label for site exceptions that affect third party cookies.">
Including third-party cookies on this site
</message>
@@ -289,9 +295,6 @@
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_CAMERA_ASK" desc="Summary text explaining that sites need to ask for permission before accessing the camera and that it is the recommended setting.">
Ask first before allowing sites to use your camera (recommended)
</message>
- <message name="IDS_CAMERA_PERMISSION_TITLE" desc="Title text to be shown when the user has allowed/denied video access for the website [CHAR-LIMIT=32]">
- Access your camera
- </message>
<message name="IDS_ANDROID_CAMERA_PERMISSION_OFF" desc="The message to show when the camera permission needs to be turned on not just in Chrome, but also in Android settings.">
To let <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph> access your camera, also turn on camera in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
</message>
@@ -345,9 +348,6 @@
</message>
<!-- Idle Detection -->
- <message name="IDS_IDLE_DETECTION_PERMISSION_TITLE" desc="Title for the permission of detecting user activity [CHAR-LIMIT=32]">
- User presence
- </message>
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_IDLE_DETECTION_ASK" desc="The description for the option to allow sites to ask for permission to access your activity state">
Ask when a site wants to know when you're present
</message>
@@ -369,9 +369,6 @@
<!-- Location -->
- <message name="IDS_GEOLOCATION_PERMISSION_TITLE" desc="Title for the permission of accessing the current location of a device [CHAR-LIMIT=32]">
- Location access
- </message>
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_LOCATION_ASK" desc="Summary text explaining that sites need to ask for permission before knowing location and that it is the recommended setting.">
Ask before allowing sites to know your location (recommended)
</message>
@@ -390,9 +387,6 @@
<!-- Microphone -->
- <message name="IDS_MIC_PERMISSION_TITLE" desc="Title text to be shown when the user has allowed/denied voice access for the website [CHAR-LIMIT=32]">
- Access your microphone
- </message>
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_MIC_ASK" desc="Summary text explaining that sites need to ask for permission before accessing the microphone and that it is the recommended setting.">
Ask first before allowing sites to use your microphone (recommended)
</message>
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_IDLE_DETECTION_PERMISSION_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_IDLE_DETECTION_PERMISSION_TITLE.png.sha1
deleted file mode 100644
index 746e21b3c1f..00000000000
--- a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_IDLE_DETECTION_PERMISSION_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-aa934c40c670cc5d531976c1277427e6f8faaa07 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_IDLE_DETECTION.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_IDLE_DETECTION.png.sha1
index 92e2cd78141..ac2d3373cdb 100644
--- a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_IDLE_DETECTION.png.sha1
+++ b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_IDLE_DETECTION.png.sha1
@@ -1 +1 @@
-185d0c9b1c1233660cd632ef919e025b7639ad3e \ No newline at end of file
+0d1f293561f2b3e78e639a2f3afd848347d1d82f \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOWED_DSE.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOWED_DSE.png.sha1
new file mode 100644
index 00000000000..5eb648a6489
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOWED_DSE.png.sha1
@@ -0,0 +1 @@
+12f7eaa36d9565ab6bc48cca5b2c99b27ecaf679 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCKED_DSE.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCKED_DSE.png.sha1
new file mode 100644
index 00000000000..5eb648a6489
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_BLOCKED_DSE.png.sha1
@@ -0,0 +1 @@
+12f7eaa36d9565ab6bc48cca5b2c99b27ecaf679 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
index db665575e0f..0a37314357c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Werf <ph name="SITE_NAME" /> bygevoeg</translation>
<translation id="1383876407941801731">Soek</translation>
<translation id="1384959399684842514">Aflaai is onderbreek</translation>
+<translation id="1415402041810619267">URL is afgekap</translation>
<translation id="1431402976894535801">Keer dat werwe weet wanneer jy teenwoordig is</translation>
<translation id="1446450296470737166">Laat vol MIDI-toestelbeheer toe</translation>
<translation id="1509960214886564027">Kenmerke op baie werwe kan breek</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Toegang tot jou kamera</translation>
<translation id="1660204651932907780">Laat werwe toe om klank te speel (aanbeveel)</translation>
<translation id="1677097821151855053">Webkoekies en ander werfdata word gebruik om jou te onthou, byvoorbeeld om jou aan te meld of om advertensies te personaliseer. Sien <ph name="BEGIN_LINK" />Instellings<ph name="END_LINK" /> om webkoekies vir alle werwe te bestuur.</translation>
<translation id="1688867105868176567">Vee werfdata uit?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Werf-URL</translation>
<translation id="2025115093177348061">Aangevulde realiteit</translation>
<translation id="2030769033451695672">Tik om na <ph name="URL_OF_THE_CURRENT_TAB" /> terug te keer</translation>
+<translation id="2054665754582400095">Jou teenwoordigheid</translation>
<translation id="2079545284768500474">Ontdoen</translation>
<translation id="2091887806945687916">Klank</translation>
<translation id="2107397443965016585">Vra voordat jy werwe toelaat om beskermde inhoud te speel (aanbeveel)</translation>
<translation id="2146738493024040262">Maak kitsprogram oop</translation>
<translation id="2148716181193084225">Vandag</translation>
<translation id="2182457891543959921">Vra voordat werwe toegelaat word om 'n 3D-kaart van jou omgewing te skep of kameraposisie na te spoor (aanbeveel)</translation>
-<translation id="2187243482123994665">Gebruikerteenwoordigheid</translation>
<translation id="2212565012507486665">Laat webkoekies toe</translation>
<translation id="2228071138934252756">Om <ph name="APP_NAME" /> toegang tot jou kamera te gee, moet jy kamera ook in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" /> aanskakel.</translation>
<translation id="2241634353105152135">Net een keer</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}}</translation>
<translation id="2434158240863470628">Aflaai is voltooi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Liggingtoegang</translation>
<translation id="2482878487686419369">Kennisgewings</translation>
<translation id="2490684707762498678">Bestuur deur <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hulp en terugvoer</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofoon</translation>
<translation id="3277252321222022663">Laat werwe toegang tot sensors toe (aanbeveel)</translation>
<translation id="3295602654194328831">Versteek inligting</translation>
+<translation id="3328801116991980348">Werfinligting</translation>
<translation id="3333961966071413176">Alle kontakte</translation>
<translation id="3386292677130313581">Vra voordat werwe toegelaat word om jou ligging te ken (aanbeveel)</translation>
<translation id="3538390592868664640">Verhoed werwe om 'n 3D-kaart van jou omgewing te skep of kameraposisie na te spoor</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Laat werwe toe om beskermde inhoud te speel</translation>
<translation id="4468959413250150279">Demp klank vir 'n spesifieke werf.</translation>
<translation id="4479647676395637221">Vra eers voordat werwe toegelaat word om jou kamera te gebruik (aanbeveel)</translation>
+<translation id="4505788138578415521">URL is uitgevou</translation>
<translation id="4534723447064627427">Om <ph name="APP_NAME" /> toegang tot jou mikrofoon te gee, moet jy mikrofoon ook in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" /> aanskakel.</translation>
<translation id="4570913071927164677">Besonderhede</translation>
<translation id="4645575059429386691">Deur jou ouer bestuur</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Skakel toestemmings vir <ph name="APP_NAME" /> in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" /> aan.</translation>
-<translation id="945632385593298557">Toegang tot jou mikrofoon</translation>
<translation id="965817943346481315">Blokkeer as werf indringerige of misleidende advertensies wys (aanbeveel)</translation>
<translation id="967624055006145463">Data geberg</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
index 1417967feae..1d5e9659b17 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ጣቢያ ተክáˆáˆ</translation>
<translation id="1383876407941801731">áለጋ </translation>
<translation id="1384959399684842514">የሚወርደዠላáታ ቆሟáˆ</translation>
+<translation id="1415402041810619267">ዩአርኤሠእንዲያጥር ተደርጓáˆ</translation>
<translation id="1431402976894535801">ጣቢያዎችን እርስዎ የሚገኙ በሚሆኑበት ጊዜ እንዳያá‹á‰ á‹«áŒá‹·á‰¸á‹</translation>
<translation id="1446450296470737166">ሙሉ የMIDI መሣሪያዎች መቆጣጠርን ያስችላáˆ</translation>
<translation id="1509960214886564027">በበርካታ ጣቢያዎች ላይ ያሉ ባሕሪያት ሊሰበሩ ይችላሉ</translation>
<translation id="1620510694547887537">ካሜራ</translation>
-<translation id="1647391597548383849">ካሜራዎን ይድረሱ</translation>
<translation id="1660204651932907780">ጣቢያዎች ድáˆáŒ½áŠ• እንዲያጫá‹á‰± áቀድ (የሚመከር)</translation>
<translation id="1677097821151855053">ኩኪዎች እና ሌላ የጣቢያ á‹áˆ‚ብ እርስዎን ለማስታወስ ያገለáŒáˆ‹áˆ‰á£ ለáˆáˆ³áˆŒ እርስዎን ለማስገባት ወይሠማስታወቂያዎችን áŒáˆ‹á‹Š ለማድረáŒá¢ ለáˆáˆ‰áˆ ጣቢያዎች ኩኪዎችን ለማቀናበርᣠ<ph name="BEGIN_LINK" />ቅንብሮችን<ph name="END_LINK" /> ይመáˆáŠ¨á‰±á¢</translation>
<translation id="1688867105868176567">የጣቢያ á‹áˆ‚ብ ይጸዳ?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">የጣቢያ ዩአርኤáˆ</translation>
<translation id="2025115093177348061">የላቀ እá‹áŠá‰³</translation>
<translation id="2030769033451695672">ወደ <ph name="URL_OF_THE_CURRENT_TAB" /> ለመመለስ መታ ያድርጉ</translation>
+<translation id="2054665754582400095">የእርስዎ መገኘት</translation>
<translation id="2079545284768500474">ቀáˆá‰¥áˆµ</translation>
<translation id="2091887806945687916">ድáˆá…</translation>
<translation id="2107397443965016585">ጣቢያዎች የተጠበቀ ይዘትን እንዲያጫá‹á‰± ከመáቀድዎ በáŠá‰µ ይጠይበ(የሚመከር)</translation>
<translation id="2146738493024040262">ቅጽበታዊ መተáŒá‰ áˆªá‹«áŠ• ክáˆá‰µ</translation>
<translation id="2148716181193084225">ዛሬ</translation>
<translation id="2182457891543959921">ጣቢያዎች የዙሪያዎ የ3ሠካርታ እንዲáˆáŒ¥áˆ© ወይሠየካሜራ ቦታን እንዲከታተሠከመáቀድ በáŠá‰µ ጠይቅ (የሚመከር)</translation>
-<translation id="2187243482123994665">የተጠቃሚ ተገáŠáŠá‰µ</translation>
<translation id="2212565012507486665">ኩኪዎችን áቀድ</translation>
<translation id="2228071138934252756">የእርስዎን ካሜራ <ph name="APP_NAME" /> እንዲደርስበት ለማድረáŒá£ በ <ph name="BEGIN_LINK" />Android ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ካሜራን በተጨማሪ ያብሩá¢</translation>
<translation id="2241634353105152135">አንድ ጊዜ ብቻ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> ሜባ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" />ᣠእና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}one{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}other{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}}</translation>
<translation id="2434158240863470628">ማá‹áˆ¨á‹µ ተጠናቅቋሠ<ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">የአካባቢ መዳረሻ</translation>
<translation id="2482878487686419369">ማስታወቂያዎች</translation>
<translation id="2490684707762498678">በ<ph name="APP_NAME" /> የሚተዳደር áŠá‹</translation>
<translation id="2498359688066513246">እገዛ እና áŒá‰¥áˆ¨áˆ˜áˆáˆµ</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ማይክሮáŽáŠ•</translation>
<translation id="3277252321222022663">ጣቢያዎች ዳሳሾችን እንዲደርሱ á‹­áቀዱላቸዠ(የሚመከር)</translation>
<translation id="3295602654194328831">መረጃ ደብቅ</translation>
+<translation id="3328801116991980348">የጣቢያ መረጃ</translation>
<translation id="3333961966071413176">áˆáˆ‰áˆ እá‹á‰‚ያዎች</translation>
<translation id="3386292677130313581">ጣቢያዎች አካባቢዎን እንዲያá‹á‰ ከመáቀድዎ በáŠá‰µ ይጠይቅ (የሚመከር)</translation>
<translation id="3538390592868664640">ጣቢያዎች የዙሪያዎ የ3ሠካርታ እንዳይáˆáŒ¥áˆ© ወይሠየካሜራ ቦታን እንዳይከታተሉ á‹«áŒá‹·á‰¸á‹</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ጣቢያዎች የተጠበቀ ይዘትን እንዲያጫá‹á‰µ á‹­áቀዱ</translation>
<translation id="4468959413250150279">በአንድ የተወሰአጣቢያ ላይ ድáˆáŒ¸-ከሠአድርáŒá¢</translation>
<translation id="4479647676395637221">ጣቢያዎች ካሜራዎን እንዲጠቀሙ ከመáቀድዎ በáŠá‰µ ይጠይቅ (የሚመከር)</translation>
+<translation id="4505788138578415521">ዩአርኤሠተዘርáŒá‰·áˆ</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> የእርስዎን ማይክራáŽáŠ• እንዲደርስ ለማድረáŒá£ በ <ph name="BEGIN_LINK" />Android ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ማይክራáŽáŠ•áŠ• በተጨማሪ ያብሩá¢</translation>
<translation id="4570913071927164677">á‹áˆ­á‹áˆ®á‰½</translation>
<translation id="4645575059429386691">በእርስዎ ወላጅ የሚቀናበር</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ብሉቱá‹</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" />ᣠእና <ph name="NUM_MORE" /> ተጨማሪ}one{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" />ᣠእና <ph name="NUM_MORE" /> ተጨማሪ}other{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" />ᣠእና <ph name="NUM_MORE" /> ተጨማሪ}}</translation>
<translation id="913657688200966289">ለ <ph name="APP_NAME" /> በ <ph name="BEGIN_LINK" />Android ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ áˆá‰ƒá‹¶á‰½áŠ• ያብሩá¢</translation>
-<translation id="945632385593298557">የእርስዎን ማይክሮáŽáŠ• ይድረሱ</translation>
<translation id="965817943346481315">ጣቢያዠረባሽ ወይሠአሳሳች ማስታወቂያዎችን የሚያሳይ ከሆአማገድ (የሚመከር)</translation>
<translation id="967624055006145463">የተከማቸ á‹áˆ‚ብ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
index 2608122981a..a296da73b09 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">تمت إضاÙØ© الموقع <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">البحث</translation>
<translation id="1384959399684842514">تم إيقا٠التنزيل مؤقتًا</translation>
+<translation id="1415402041810619267">â€ØªÙ… اقتطاع عنوان URL</translation>
<translation id="1431402976894535801">منع المواقع الإلكترونية من معرÙØ© متى تستخدم الجهاز</translation>
<translation id="1446450296470737166">â€Ø§Ù„سماح بالتحكم الكامل لأجهزة MIDI</translation>
<translation id="1509960214886564027">قد تتوق٠الميزات عن العمل ÙÙŠ العديد من المواقع الإلكترونية.</translation>
<translation id="1620510694547887537">الكاميرا</translation>
-<translation id="1647391597548383849">الدخول إلى الكاميرا</translation>
<translation id="1660204651932907780">السماح للمواقع الإلكترونية بتشغيل الصوت (موصى به)</translation>
<translation id="1677097821151855053">يتم استخدام ملÙات تعري٠الارتباط وبيانات المواقع الإلكترونية الأخرى لتذكّÙرك بهد٠تسجيل دخولك أو تقديم إعلانات مخصّصة لك مثلاً. لإدارة ملÙات تعري٠الارتباط لجميع المواقع الإلكترونية، يمكنك الاطّلاع على <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">هل تريد محو بيانات الموقع الإلكتروني؟</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">â€Ø¹Ù†ÙˆØ§Ù† URL للموقع</translation>
<translation id="2025115093177348061">الواقع المعزّز</translation>
<translation id="2030769033451695672">ÙŠÙرجى النقر للرجوع إلى <ph name="URL_OF_THE_CURRENT_TAB" />.</translation>
+<translation id="2054665754582400095">متى تستخدم جهازك</translation>
<translation id="2079545284768500474">تراجع</translation>
<translation id="2091887806945687916">الصوت</translation>
<translation id="2107397443965016585">السؤال أولاً قبل السماح للمواقع الإلكترونية بتشغيل المحتوى المَحمي (موصى به)</translation>
<translation id="2146738493024040262">Ùتح تطبيق Ùوري</translation>
<translation id="2148716181193084225">اليوم</translation>
<translation id="2182457891543959921">طلب الإذن قبل السماح لموقع إلكتروني بإنشاء خريطة ثلاثية الأبعاد للبيئة المحيطة بك أو تتبّÙع موضع الكاميرا (مقترَح)</translation>
-<translation id="2187243482123994665">استخدام الجهاز</translation>
<translation id="2212565012507486665">السماح بملÙات تعري٠الارتباط</translation>
<translation id="2228071138934252756">â€Ù„لسماح لتطبيق <ph name="APP_NAME" /> بالوصول إلى الكاميرا، ÙŠÙرجى أيضًا تÙعيل الكاميرا ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">مرة واحدة Ùقط</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> ميغابايت</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذن واحد (<ph name="NUM_MORE" />) آخر.}zero{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}two{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذنَين (<ph name="NUM_MORE" />) آخرَين.}few{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> أذونات أخرى.}many{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذنًا آخر.}other{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}}</translation>
<translation id="2434158240863470628">اكتمل التنزيل <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">تحديد الموقع الجغراÙÙŠ</translation>
<translation id="2482878487686419369">الإشعارات</translation>
<translation id="2490684707762498678">تتم إدارتها من خلال <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">المساعدة والتعليقات</translation>
@@ -75,7 +74,7 @@
<translation id="2874939134665556319">المقطع الصوتي السابق</translation>
<translation id="2903493209154104877">العناوين</translation>
<translation id="2910701580606108292">السؤال قبل السماح للمواقع الإلكترونية بتشغيل المحتوى المحمي</translation>
-<translation id="2913331724188855103">السماح للمواقع الإلكترونية بحÙظ بيانات ملÙات تعري٠الارتباط وقراءتها (موصى به)</translation>
+<translation id="2913331724188855103">ألسماح للمواقع الإلكترونية بحÙظ بيانات ملÙات تعري٠الارتباط وقراءتها (ÙŠÙنصح به)</translation>
<translation id="2968755619301702150">عارض الشهادات</translation>
<translation id="300526633675317032">سيؤدي هذا إلى محو مساحة التخزين البالغة <ph name="SIZE_IN_KB" /> بأكملها من مساحة تخزين المواقع الإلكترونية.</translation>
<translation id="3008272652534848354">إعادة ضبط الأذونات</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">الميكروÙون</translation>
<translation id="3277252321222022663">يمكنك السماح للمواقع بالوصول إلى أجهزة الاستشعار (Ù…Ùقترَح).</translation>
<translation id="3295602654194328831">إخÙاء المعلومات</translation>
+<translation id="3328801116991980348">معلومات الموقع الإلكتروني</translation>
<translation id="3333961966071413176">جميع جهات الاتصال</translation>
<translation id="3386292677130313581">السؤال قبل السماح للمواقع الإلكترونية بمعرÙØ© الموقع الجغراÙÙŠ (موصى به)</translation>
<translation id="3538390592868664640">منع المواقع الإلكترونية من إنشاء خريطة ثلاثية الأبعاد للبيئة المحيطة بك أو تتبّÙع موضع الكاميرا</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">السماح للمواقع الإلكترونية بتشغيل المحتوى المَحمي</translation>
<translation id="4468959413250150279">كتم صوت موقع إلكتروني معين.</translation>
<translation id="4479647676395637221">السؤال أولاً قبل السماح للمواقع الإلكترونية باستخدام الكاميرا (موصى به)</translation>
+<translation id="4505788138578415521">â€ØªÙ… توسيع عنوان URL.</translation>
<translation id="4534723447064627427">â€Ù„لسماح لتطبيق <ph name="APP_NAME" /> بالوصول إلى الميكروÙون، ÙŠÙرجى أيضًا تÙعيل الميكروÙون ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">التÙاصيل</translation>
<translation id="4645575059429386691">يديره والداك</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">بلوتوث</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذن واحد (<ph name="NUM_MORE" />) آخر}zero{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر}two{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذنان (<ph name="NUM_MORE" />) آخران}few{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> أذونات أخرى}many{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذنًا آخر}other{<ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر}}</translation>
<translation id="913657688200966289">â€ÙعّÙÙ„ الأذونات لتطبيق <ph name="APP_NAME" /> ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">الدخول إلى الميكروÙون</translation>
<translation id="965817943346481315">الحظر ÙÙŠ حال كان الموقع الإلكتروني يعرض إعلانات مضلّÙلة أو غير مرغوب Ùيها (Ù…Ùستحسَن)</translation>
<translation id="967624055006145463">البيانات المÙخزَّنة</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
index 312c9f58d6e..d9407bbfb4f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">ছাইট <ph name="SITE_NAME" /> যোগ কৰা হ’ল</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ডাইনল’ড পজ কৰা হৈছে</translation>
+<translation id="1415402041810619267">URL চà§à¦Ÿà¦¿ কৰা হ’ল</translation>
<translation id="1431402976894535801">ছাইটসমূহে আপà§à¦¨à¦¿ সকà§à§°à¦¿à§Ÿ হৈ থকা বà§à¦²à¦¿ জনাটো অৱৰোধ কৰক</translation>
<translation id="1446450296470737166">MIDI ডিভাইচৰ সমà§à¦ªà§‚রà§à¦£ নিয়নà§à¦¤à§à§°à¦£à§° অনà§à¦®à¦¤à¦¿ দিয়া</translation>
<translation id="1509960214886564027">বহà§à¦¤à§‹ ছাইটৰ সà§à¦¬à¦¿à¦§à¦¾à¦¸à¦®à§‚হ বà§à¦¯à¦¾à¦¹à¦¤ হ’ব পাৰে</translation>
<translation id="1620510694547887537">কেমেৰা</translation>
-<translation id="1647391597548383849">আপোনাৰ কেমেৰাৰ à¦à¦•à§à¦¸à§‡à¦›</translation>
<translation id="1660204651932907780">ছাইটবোৰক ধà§à¦¬à¦¨à¦¿ পà§à¦²à§‡â€™ কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা)</translation>
<translation id="1677097821151855053">কà§à¦•à¦¿à¦¸à¦®à§‚হ আৰৠছাইটৰ অনà§à¦¯ ডেটা আপোনাক মনত ৰাখিবলৈ বà§à¦¯à§±à¦¹à¦¾à§° কৰা হয়, উদাহৰণসà§à¦¬à§°à§‚পে, আপোনাক ছাইন ইন কৰাবলৈ অথবা বিজà§à¦žà¦¾à¦ªà¦¨à¦¸à¦®à§‚হ বà§à¦¯à¦•à§à¦¤à¦¿à¦—তকৰণ কৰিবলৈ। সকলো ছাইটৰ বাবে কà§à¦•à¦¿à¦¸à¦®à§‚হ পৰিচালনা কৰিবলৈ <ph name="BEGIN_LINK" />ছেটিংসমূহ<ph name="END_LINK" /> চাওক।</translation>
<translation id="1688867105868176567">ছাইটৰ ডেটা মচিবনে?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ছাইট URL</translation>
<translation id="2025115093177348061">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" />লৈ উভতি যাবলৈ টিপক</translation>
+<translation id="2054665754582400095">আপোনাৰ উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2079545284768500474">আনডৠকৰক</translation>
<translation id="2091887806945687916">শবà§à¦¦</translation>
<translation id="2107397443965016585">ছাইটসমূহক সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡â€™ কৰাৰ অনà§à¦®à¦¤à¦¿ দিয়াৰ আগতে সোধক (আমি চà§à¦ªà¦¾à§°à¦¿à¦› কৰোà¦)</translation>
<translation id="2146738493024040262">Instant à¦à¦ªà§â€Œ খোলক</translation>
<translation id="2148716181193084225">আজি</translation>
<translation id="2182457891543959921">ছাইটসমূহক আপোনাৰ চৌপাশৰ à¦à¦–ন 3D মেপ সৃষà§à¦Ÿà¦¿ কৰিবলৈ অথবা কেমেৰাৰ সà§à¦¥à¦¾à¦¨ টà§à§°à§‡à¦• কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়াৰ পূরà§à¦¬à§‡ সোধক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
-<translation id="2187243482123994665">বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° সকà§à§°à¦¿à§Ÿà¦¤à¦¾</translation>
<translation id="2212565012507486665">কà§à¦•à¦¿à¦¸à¦®à§‚হক অনà§à¦®à¦¤à¦¿ দিয়ক</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />ক আপোনাৰ কেমেৰা à¦à¦•à§à¦¸à§‡à¦› কৰিবলৈ দিবলৈ <ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />তো কেমেৰা অন কৰক।</translation>
<translation id="2241634353105152135">মাতà§à§° à¦à¦¬à¦¾à§°</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¦à¦®. বি.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}}</translation>
<translation id="2434158240863470628">ডাউনল’ড সমà§à¦ªà§‚রà§à¦£ হৈছে <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">অৱসà§à¦¥à¦¾à¦¨à§° à¦à¦•à§à¦¸à§‡à¦›</translation>
<translation id="2482878487686419369">জাননী</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" />ঠপৰিচালনা কৰে</translation>
<translation id="2498359688066513246">সহায় আৰৠমতামত</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">মাইকà§à§°â€™à¦«â€™à¦¨</translation>
<translation id="3277252321222022663">ছেনà§à¦¸à§°à¦¸à¦®à§‚হলৈ à¦à¦•à§à¦¸à§‡à¦› পাবলৈ ছাইটসমূহক অনà§à¦®à¦¤à¦¿ দিয়ক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা)</translation>
<translation id="3295602654194328831">তথà§à¦¯ লà§à¦•à§à§±à¦¾à¦“ক</translation>
+<translation id="3328801116991980348">ছাইটৰ তথà§à¦¯</translation>
<translation id="3333961966071413176">সকলো সমà§à¦ªà§°à§à¦•</translation>
<translation id="3386292677130313581">ছাইটসমূহে আপোনাৰ অৱসà§à¦¥à¦¾à¦¨ জনাৰ অনà§à¦®à¦¤à¦¿ দিয়াৰ পূৰà§à¦¬à§‡ সোধক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
<translation id="3538390592868664640">ছাইটসমূহক আপোনাৰ চৌপাশৰ à¦à¦–ন 3D মেপ সৃষà§à¦Ÿà¦¿ কৰাৰ পৰা অথবা কেমেৰাৰ সà§à¦¥à¦¾à¦¨ টà§à§°à§‡à¦• কৰাৰ পৰা অৱৰোধ কৰক</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ছাইটসমূহক সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡' কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক</translation>
<translation id="4468959413250150279">নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ ছাইটৰ বাবে ধà§à¦¬à¦¨à¦¿ মিউট কৰক।</translation>
<translation id="4479647676395637221">আপোনাৰ কেমেৰা ছাইটসমূহক বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ দিয়াৰ পূরà§à¦¬à§‡ অনà§à¦®à¦¤à¦¿ ল'বলৈ দিয়ক(চà§à¦ªà¦¾à§°à¦¿à¦› কৰা)</translation>
+<translation id="4505788138578415521">URL বিসà§à¦¤à¦¾à§° কৰা হৈছে</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" />ক আপোনাৰ মাইকà§à§°â€™à¦«â€™à¦¨ à¦à¦•à§à¦¸à§‡à¦› কৰিবলৈ দিবলৈ <ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />তো মাইকà§à§°â€™à¦«â€™à¦¨ অন কৰক।</translation>
<translation id="4570913071927164677">সবিশেষ</translation>
<translation id="4645575059429386691">আপোনাৰ অভিভাৱকৰ দà§à¦¬à¦¾à§°à¦¾ পৰিচালিত</translation>
@@ -302,7 +303,6 @@
<translation id="9074739597929991885">বà§à¦²à§à¦Ÿà§à¦¥</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টা}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টা}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টা}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />ত <ph name="APP_NAME" />ৰ বাবে অনà§à¦®à¦¤à¦¿à¦¸à¦®à§‚হ অন কৰক।</translation>
-<translation id="945632385593298557">আপোনাৰ মাইকà§à§°'ফ'ন à¦à¦•à§à¦¸à§‡à¦› কৰক</translation>
<translation id="965817943346481315">কোনো ছাইটে অননà§à¦®à§‹à¦¦à¦¿à¦¤ বা বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à§±à¦¾à¦²à§‡ সেয়া অৱৰোধ কৰক ( চà§à¦ªà¦¾à§°à¦¿à¦› কৰা)</translation>
<translation id="967624055006145463">ডেটা সঞà§à¦šà§Ÿ কৰা হ’ল</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
index 98f264edb99..7be52da6681 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> saytı əlavə edildi</translation>
<translation id="1383876407941801731">Axtar</translation>
<translation id="1384959399684842514">EndirmÉ™ durduruldu</translation>
+<translation id="1415402041810619267">URL tam deyil</translation>
<translation id="1431402976894535801">Saytların nə zaman evdə olduğunuzu bilməsini bloklayın</translation>
<translation id="1446450296470737166">MIDI cihazlar üzərində tam nəzarətə icazə verin</translation>
<translation id="1509960214886564027">Bir çox saytdakı xüsusiyyətlər işləməyə bilər</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kameranıza daxil olun</translation>
<translation id="1660204651932907780">Saytlara səs oxutmaq icazəsi verin (məsləhətli)</translation>
<translation id="1677097821151855053">Kukilər və digər sayt datası sizin yadda saxlamaq üçün istifadə edilir, məsələn, daxil olmanıza və ya reklamları fərdiləşdirməyə imkan yaradır. Bütün saytlar üçün kukiləri idarə etmək üçün <ph name="BEGIN_LINK" />Ayarlara<ph name="END_LINK" /> baxın.</translation>
<translation id="1688867105868176567">Sayt datası təmizlənsin?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Sayt URL-i</translation>
<translation id="2025115093177348061">Artırılmış reallıq</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> bölməsinə qayıtmaq üçün toxunun</translation>
+<translation id="2054665754582400095">Mövcudluğunuz</translation>
<translation id="2079545284768500474">Geri qaytarın</translation>
<translation id="2091887806945687916">Səs</translation>
<translation id="2107397443965016585">Saytlar qorunan kontenti oxutmazdan əvvəl icazə tələb edilsin (tövsiyyə edilir)</translation>
<translation id="2146738493024040262">Ani tətbiqi açın</translation>
<translation id="2148716181193084225">Bu gün</translation>
<translation id="2182457891543959921">Saytların ətrafınızdakı sahələrin 3D xəritəsini yaratmasına və ya kamera mövqeyini izləməsinə icazə verməzdən əvvəl icazə tələb edin (tövsiyə edilir)</translation>
-<translation id="2187243482123994665">İstifadəçinin evdə olması</translation>
<translation id="2212565012507486665">Kukilərə icazə verin</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> tətbiqinə kameranıza giriş icazəsi vermək üçün <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> kameranı da aktiv edin.</translation>
<translation id="2241634353105152135">Sadəcə bir dəfə</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}}</translation>
<translation id="2434158240863470628">Endirmə tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Məkan girişi</translation>
<translation id="2482878487686419369">Bildirişlər</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> tərəfindən idarə edilir</translation>
<translation id="2498359688066513246">Yardım və geri əlaqə</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Saytların sensorlara daxil olmasına icazə verin (tövsiyə edilir)</translation>
<translation id="3295602654194328831">Məlumatı gizlədin</translation>
+<translation id="3328801116991980348">Sayt haqqında</translation>
<translation id="3333961966071413176">Bütün kontaktar</translation>
<translation id="3386292677130313581">Saytlara məkanınızı bilmək icazəsi verməmişdən əvvəl soruşun (tövsiyə olunur)</translation>
<translation id="3538390592868664640">Saytların ətrafınızdakı sahələrin 3D xəritəsini yaratmasına və ya kamera mövqeyini izləməsinə qarşı blok qoyun</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Saytlara qorunan kontenti oxutmaÄŸa icazÉ™ verin</translation>
<translation id="4468959413250150279">Xüsusi saytı səsiz rejimə keçirin.</translation>
<translation id="4479647676395637221">Saytlara kameranızı istifadə etmək icazəsi verməmişdən əvvəl soruşun (tövsiyə olunur)</translation>
+<translation id="4505788138578415521">URL genişləndirilib</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> tətbiqinə mikrofonunuza giriş icazəsi vermək üçün <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> mikrofonu da aktiv edin.</translation>
<translation id="4570913071927164677">Ætraflı</translation>
<translation id="4645575059429386691">Valideyniniz tərəfindən idarə olunur</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> vÉ™ daha <ph name="NUM_MORE" /> icazÉ™}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> vÉ™ daha <ph name="NUM_MORE" /> icazÉ™}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" /> üçün icazələri <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> aktiv edin.</translation>
-<translation id="945632385593298557">Mikrofonunuza giriÅŸ</translation>
<translation id="965817943346481315">Sayt inadçı və ya aldadıcı reklamlar göstərirsə, blok edin (tövsiyə olunur)</translation>
<translation id="967624055006145463">Yadda saxlanmış data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
index b146187424a..013a8a65e48 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> дададзены</translation>
<translation id="1383876407941801731">Пошук</translation>
<translation id="1384959399684842514">Спампоўка прыпынена</translation>
+<translation id="1415402041810619267">URL-Ð°Ð´Ñ€Ð°Ñ Ð°Ð±Ñ€Ñзаны</translation>
<translation id="1431402976894535801">Забараніць перадаваць Ñайтам звеÑткі аб вашай прыÑутнаÑці</translation>
<translation id="1446450296470737166">Дазв. поўны кантроль MIDI-прылад</translation>
<translation id="1509960214886564027">Функцыі на многіх Ñайтах могуць пераÑтаць працаваць</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ДоÑтуп да камеры</translation>
<translation id="1660204651932907780">Дазволіць Ñайтам прайграваць гук (Ñ€Ñкамендуецца)</translation>
<translation id="1677097821151855053">Файлы cookie Ñ– Ñ–Ð½ÑˆÑ‹Ñ Ð´Ð°Ð½Ñ‹Ñ Ñайта выкарыÑтоўваюцца, каб запомніць Ð²Ð°Ñ (напрыклад, калі вы ўваходзіце ва ўліковы запіÑ) або Ð´Ð»Ñ Ð¿ÐµÑ€Ñаналізацыі змеÑціва. Каб кіраваць файламі cookie Ð´Ð»Ñ ÑžÑÑ–Ñ… Ñайтаў, перайдзіце Ñž <ph name="BEGIN_LINK" />Ðалады<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Выдаліць Ð´Ð°Ð½Ñ‹Ñ Ñайта?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL-Ð°Ð´Ñ€Ð°Ñ Ñайта</translation>
<translation id="2025115093177348061">Ð”Ð°Ð¿Ð¾ÑžÐ½ÐµÐ½Ð°Ñ Ñ€ÑальнаÑць</translation>
<translation id="2030769033451695672">ÐаціÑніце, каб вÑрнуцца на ўкладку <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Ваша прыÑутнаÑць</translation>
<translation id="2079545284768500474">Ðдрабіць</translation>
<translation id="2091887806945687916">Гук</translation>
<translation id="2107397443965016585">Пытаць, перш чым дазволіць прайграванне абароненага змеÑціва на Ñайтах (Ñ€Ñкамендуецца)</translation>
<translation id="2146738493024040262">Ðдкрыць імгненную праграму</translation>
<translation id="2148716181193084225">СённÑ</translation>
<translation id="2182457891543959921">Пытацца, перш чым дазволіць Ñайтам Ñтвараць 3D-карту вашага аÑÑÑ€Ð¾Ð´Ð´Ð·Ñ Ñ– адÑочваць Ñтановішча камеры (Ñ€Ñкамендуецца)</translation>
-<translation id="2187243482123994665">ПрыÑутнаÑць карыÑтальніка</translation>
<translation id="2212565012507486665">Дазволіць файлы cookie</translation>
<translation id="2228071138934252756">Каб праграма "<ph name="APP_NAME" />" атрымала доÑтуп да камеры, уключыце камеру такÑама Ñž <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Толькі адзін раз</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}one{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}few{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}many{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}other{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Спампоўванне завершана <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ДоÑтуп да даных геалакацыі</translation>
<translation id="2482878487686419369">ÐпавÑшчÑнні</translation>
<translation id="2490684707762498678">Пад кіраваннем праграмы "<ph name="APP_NAME" />"</translation>
<translation id="2498359688066513246">Даведка і водгукі</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Мікрафон</translation>
<translation id="3277252321222022663">Дазволіць Ñайтам доÑтуп да датчыкаў (Ñ€Ñкамендуецца)</translation>
<translation id="3295602654194328831">Схаваць інфармацыю</translation>
+<translation id="3328801116991980348">ЗвеÑткі пра Ñайт</translation>
<translation id="3333961966071413176">УÑе кантакты</translation>
<translation id="3386292677130313581">Пытацца, перш чым дазволіць Ñайтам атрымліваць інфармацыю пра ваша меÑцазнаходжанне (Ñ€Ñкамендуецца)</translation>
<translation id="3538390592868664640">Забараніць Ñайтам Ñтвараць 3D-карту вашага аÑÑÑ€Ð¾Ð´Ð´Ð·Ñ Ñ– адÑочваць Ñтановішча камеры</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Дазволіць Ñайтам прайграваць абароненае змеÑціва</translation>
<translation id="4468959413250150279">Выключыць гук на канкрÑтным Ñайце.</translation>
<translation id="4479647676395637221">Пытацца, перш чым дазволіць Ñайтам выкарыÑтоўваць камеру (Ñ€Ñкамендуецца)</translation>
+<translation id="4505788138578415521">URL-Ð°Ð´Ñ€Ð°Ñ Ñ€Ð°Ð·Ð³Ð¾Ñ€Ð½ÑƒÑ‚Ñ‹</translation>
<translation id="4534723447064627427">Каб даць праграме "<ph name="APP_NAME" />" доÑтуп да мікрафона, уключыце апошні Ñž <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">ПадрабÑÐ·Ð½Ñ‹Ñ Ð·Ð²ÐµÑткі</translation>
<translation id="4645575059429386691">Пад кіраваннем вашых бацькоў</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Уключыце Ð´Ð»Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹ "<ph name="APP_NAME" />" дазволы Ñž <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ДоÑтуп да мікрафона</translation>
<translation id="965817943346481315">Блакіраваць, калі Ñайт паказвае назойлівую Ñ€Ñкламу або Ñ€Ñкламу, ÑÐºÐ°Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ñ†ÑŒ у зман (Ñ€Ñкамендуецца)</translation>
<translation id="967624055006145463">Ð—Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð´Ð°Ð½Ñ‹Ñ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
index b35d3aa730f..9af19ef212b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Сайтът <ph name="SITE_NAME" /> е добавен</translation>
<translation id="1383876407941801731">ТърÑене</translation>
<translation id="1384959399684842514">ИзтеглÑнето е на пауза</translation>
+<translation id="1415402041810619267">URL адреÑÑŠÑ‚ е Ñъкратен</translation>
<translation id="1431402976894535801">Блокиране на Ñайтовете, така че да не знаÑÑ‚ дали приÑÑŠÑтвате</translation>
<translation id="1446450296470737166">Разр. на Ð¿ÑŠÐ»Ð½Ð¸Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð» над MIDI</translation>
<translation id="1509960214886564027">Функциите в много Ñайтове може да не работÑÑ‚ правилно</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ДоÑтъп до камерата</translation>
<translation id="1660204651932907780">Разрешаване на Ñайтовете да възпроизвеждат звук (препоръчително)</translation>
<translation id="1677097821151855053">„БиÑквитките“ и другите данни за Ñайтове Ñе използват Ñ Ñ†ÐµÐ» да бъдете запомнени, като например за влизане в профила ви или за перÑонализиране на реклами. За да управлÑвате „биÑквитките“ за вÑички Ñайтове, вижте <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Да Ñе изчиÑÑ‚ÑÑ‚ ли данните за Ñайта?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL Ð°Ð´Ñ€ÐµÑ Ð½Ð° Ñайт</translation>
<translation id="2025115093177348061">Обогатена реалноÑÑ‚</translation>
<translation id="2030769033451695672">ДокоÑнете, за да Ñе върнете към <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">ПриÑÑŠÑтвието ви</translation>
<translation id="2079545284768500474">ОтмÑна</translation>
<translation id="2091887806945687916">Звук</translation>
<translation id="2107397443965016585">Запитване преди разрешаване на Ñайтовете да възпроизвеждат защитено Ñъдържание (препоръчително)</translation>
<translation id="2146738493024040262">ОтварÑне на мигновеното приложение</translation>
<translation id="2148716181193084225">ДнеÑ</translation>
<translation id="2182457891543959921">Извеждане на запитване, преди да Ñе разреши на Ñайтовете да Ñъздават триизмерна карта на заобикалÑщата ви Ñреда или да ÑледÑÑ‚ позициÑта на камерата (препоръчително)</translation>
-<translation id="2187243482123994665">ПриÑÑŠÑтвие на потребителÑ</translation>
<translation id="2212565012507486665">Разрешаване на „биÑквитките“</translation>
<translation id="2228071138934252756">За да разрешите на <ph name="APP_NAME" /> да оÑъщеÑтвÑва доÑтъп до камерата ви, Ñ‚Ñ Ñ‚Ñ€Ñбва да бъде включена и от <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само веднъж</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{ДоÑтъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}other{ДоÑтъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}}</translation>
<translation id="2434158240863470628">ИзтеглÑнето завърши <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ДоÑтъп до меÑтоположението</translation>
<translation id="2482878487686419369">ИзвеÑтиÑ</translation>
<translation id="2490684707762498678">УправлÑват Ñе от <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Помощ и отзиви</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Разрешаване на доÑтъпа на Ñайтовете до Ñензорите (препоръчително)</translation>
<translation id="3295602654194328831">Скриване на информациÑта</translation>
+<translation id="3328801116991980348">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ñайта</translation>
<translation id="3333961966071413176">Ð’Ñички контакти</translation>
<translation id="3386292677130313581">Извеждане на запитване, преди на Ñайтовете да Ñе разреши доÑтъп до меÑтоположението ви (препоръчително)</translation>
<translation id="3538390592868664640">Блокиране на Ñайтовете, така че да не могат да Ñъздават триизмерна карта на заобикалÑщата ви Ñреда или да ÑледÑÑ‚ позициÑта на камерата</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Разрешаване на Ñайтовете да възпроизвеждат защитено Ñъдържание</translation>
<translation id="4468959413250150279">Спиране на звука за конкретен Ñайт.</translation>
<translation id="4479647676395637221">Извеждане на запитване, преди да Ñе разреши на Ñайтовете да използват камерата (препоръчително)</translation>
+<translation id="4505788138578415521">URL адреÑÑŠÑ‚ е разгънат</translation>
<translation id="4534723447064627427">За да разрешите на <ph name="APP_NAME" /> да оÑъщеÑтвÑва доÑтъп до микрофона ви, той Ñ‚Ñ€Ñбва да бъде включен и от <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">ПодробноÑти</translation>
<translation id="4645575059429386691">УправлÑва Ñе от ваш родител</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Включете разрешениÑта за <ph name="APP_NAME" /> от <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ДоÑтъп до микрофона</translation>
<translation id="965817943346481315">Блокиране, ако на Ñайта Ñе показват натрапчиви или подвеждащи реклами (препоръчително)</translation>
<translation id="967624055006145463">Съхранени данни</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
index ad267a01e15..e4fec20da96 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> সাইট যোগ করা হয়েছে</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ডাউনলোড পজ করা আছে</translation>
+<translation id="1415402041810619267">ইউআরà¦à¦² ছোট করা হয়েছে</translation>
<translation id="1431402976894535801">আপনি কখন ডিভাইস বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন তা জানাতে না চাইলে সাইটগà§à¦²à¦¿ বà§à¦²à¦• করে দিন</translation>
<translation id="1446450296470737166">MIDI ডিভাইসগà§à¦²à¦¿à¦° পূরà§à¦£ নিয়নà§à¦¤à§à¦°à¦£à§‡à¦° অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="1509960214886564027">à¦à¦•à¦¾à¦§à¦¿à¦• সাইটের ফিচারগà§à¦²à¦¿ কাজ নাও করতে পারে</translation>
<translation id="1620510694547887537">কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾</translation>
-<translation id="1647391597548383849">আপনার কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করà§à¦¨</translation>
<translation id="1660204651932907780">সাউনà§à¦¡à¦Ÿà¦¿ পà§à¦²à§‡ করার জনà§à¦¯ সাইটটিতে অনà§à¦®à¦¤à¦¿ দিন (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="1677097821151855053">কà§à¦•à¦¿ à¦à¦¬à¦‚ অনà§à¦¯à¦¨à§à¦¯ সাইটের ডেটা আপনার অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° তথà§à¦¯ মনে রাখে, যেমন আপনাকে সাইন-ইন করানোর সময় অথবা আপনার পছনà§à¦¦à¦®à¦¤à§‹ বিজà§à¦žà¦¾à¦ªà¦¨ দেখানোর সময়। সব সাইটের জনà§à¦¯ কà§à¦•à¦¿ মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে, <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> দেখà§à¦¨à¥¤</translation>
<translation id="1688867105868176567">সাইট ডেটা খালি করতে চান?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">সাইট URL</translation>
<translation id="2025115093177348061">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" />-ঠফিরে যেতে টà§à¦¯à¦¾à¦ª করà§à¦¨</translation>
+<translation id="2054665754582400095">আপনার উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2079545284768500474">আগের অবসà§à¦¥à¦¾à§Ÿ ফিরà§à¦¨</translation>
<translation id="2091887806945687916">আওয়াজ</translation>
<translation id="2107397443965016585">সাইটকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ চালানোর অনà§à¦®à¦¤à¦¿ দেওয়ার আগে জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨ (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="2146738493024040262">ইনসà§à¦Ÿà§à¦¯à¦¾à¦¨à§à¦Ÿ অà§à¦¯à¦¾à¦ª খà§à¦²à§à¦¨</translation>
<translation id="2148716181193084225">আজ</translation>
<translation id="2182457891543959921">আপনার আশেপাশের à¦à¦²à¦¾à¦•à¦¾à¦° à¦à¦•à¦Ÿà¦¿ 3D মà§à¦¯à¦¾à¦ª তৈরি করতে বা কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾à¦° অবসà§à¦¥à¦¾à¦¨ টà§à¦°à§à¦¯à¦¾à¦• করতে কোনও সাইট অনà§à¦®à§‹à¦¦à¦¨ দেওয়ার আগে, à¦à¦•à¦¬à¦¾à¦° জিজà§à¦žà¦¾à¦¸à¦¾ করে নিন (সাজেসà§à¦Ÿ করা হয়েছে)</translation>
-<translation id="2187243482123994665">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2212565012507486665">কà§à¦•à¦¿à¦—à§à¦²à¦¿à¦•à§‡ অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="2228071138934252756">তাছাড়া, যাতে <ph name="APP_NAME" /> আপনার কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে পারে, তার জনà§à¦¯ <ph name="BEGIN_LINK" />Android সেটিংসে<ph name="END_LINK" /> গিয়েও কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ চালৠকরে দিন।</translation>
<translation id="2241634353105152135">শà§à¦§à§à¦®à¦¾à¦¤à§à¦° à¦à¦•à¦¬à¦¾à¦°</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¦à¦®à¦¬à¦¿</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}}</translation>
<translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> ডাউনলোড সমà§à¦ªà§‚রà§à¦£ হয়েছে</translation>
-<translation id="2440823041667407902">লোকেশন অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸</translation>
<translation id="2482878487686419369">বিজà§à¦žà¦ªà§à¦¤à¦¿à¦—à§à¦²à¦¿</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> মà§à¦¯à¦¾à¦¨à§‡à¦œ করে</translation>
<translation id="2498359688066513246">সহায়তা ও পà§à¦°à¦¤à¦¿à¦¬à¦¾à¦°à§à¦¤à¦¾</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">মাইকà§à¦°à§‹à¦«à§‹à¦¨</translation>
<translation id="3277252321222022663">সাইটকে সেনà§à¦¸à¦° অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার অনà§à¦®à¦¤à¦¿ দিন (সাজেসà§à¦Ÿ করা হয়)</translation>
<translation id="3295602654194328831">তথà§à¦¯ লà§à¦•à¦¾à¦¨</translation>
+<translation id="3328801116991980348">সাইট তথà§à¦¯</translation>
<translation id="3333961966071413176">সব পরিচিতি</translation>
<translation id="3386292677130313581">সাইটগà§à¦²à¦¿à¦•à§‡ আপনার লোকেশন জানতে দিতে মঞà§à¦œà§à¦°à¦¿ দেওয়ার আগে জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨ (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="3538390592868664640">আপনার আশেপাশের à¦à¦²à¦¾à¦•à¦¾à¦° à¦à¦•à¦Ÿà¦¿ 3D মà§à¦¯à¦¾à¦ª তৈরি করা বা কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾à¦° অবসà§à¦¥à¦¾à¦¨ টà§à¦°à§à¦¯à¦¾à¦• করার কাজে নিযà§à¦•à§à¦¤ সাইটগà§à¦²à¦¿à¦•à§‡ বà§à¦²à¦• করে দিন</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">সাইটকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ চালানোর জনà§à¦¯ অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="4468959413250150279">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ কোনও সাইটের জনà§à¦¯ সাউনà§à¦¡ মিউট করà§à¦¨à¥¤</translation>
<translation id="4479647676395637221">সাইটগà§à¦²à¦¿à¦•à§‡ আপনার কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে দিতে মঞà§à¦œà§à¦°à¦¿ দেওয়ার আগে পà§à¦°à¦¥à¦®à§‡ জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨ (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
+<translation id="4505788138578415521">ইউআরà¦à¦² বড় করা হয়েছে</translation>
<translation id="4534723447064627427">তাছাড়া, যাতে <ph name="APP_NAME" /> আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে পারে, তার জনà§à¦¯ <ph name="BEGIN_LINK" />Android সেটিংসে<ph name="END_LINK" /> গিয়েও মাইকà§à¦°à§‹à¦«à§‹à¦¨ চালৠকরে দিন।</translation>
<translation id="4570913071927164677">বিবরণ</translation>
<translation id="4645575059429386691">আপনার পিতামাতার দà§à¦¬à¦¾à¦°à¦¾ পরিচালিত</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">বà§à¦²à§à¦Ÿà§à¦¥</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android সেটিংসে<ph name="END_LINK" /> <ph name="APP_NAME" />-à¦à¦° জনà§à¦¯ অনà§à¦®à¦¤à¦¿à¦—à§à¦²à¦¿ চালৠকরà§à¦¨à¥¤</translation>
-<translation id="945632385593298557">আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করà§à¦¨</translation>
<translation id="965817943346481315">সাইটে থাকা বà§à¦¯à¦¾à¦˜à¦¾à¦¤ সৃষà§à¦Ÿà¦¿à¦•à¦¾à¦°à§€ বা বিভà§à¦°à¦¾à¦¨à§à¦¤à¦¿à¦•à¦° বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• করà§à¦¨ (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="967624055006145463">ডেটা সà§à¦Ÿà§‹à¦° করা হয়েছে</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
index 0378cb3487a..a637000f664 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Web lokacija <ph name="SITE_NAME" /> je dodana</translation>
<translation id="1383876407941801731">Traži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1415402041810619267">URL je odsjeÄen</translation>
<translation id="1431402976894535801">Blokirajte web lokacijama informacije o prisutnosti</translation>
<translation id="1446450296470737166">Puna kontrola MIDI uređaja</translation>
<translation id="1509960214886564027">Moguće je da će funkcije na mnogim web lokacijama prestati s radom</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Pristup vašoj kameri</translation>
<translation id="1660204651932907780">Dozvolite web lokacijama da reproduciraju zvuk (preporuÄeno)</translation>
<translation id="1677097821151855053">KolaÄići i drugi podaci web lokacije se koriste da vas web lokacija zapamti, naprimjer radi vaÅ¡e prijave ili personaliziranja oglasa. Da upravljate kolaÄićima za sve web lokacije, pogledajte <ph name="BEGIN_LINK" />Postavke<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Obrisati podatke web lokacije?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL web lokacije</translation>
<translation id="2025115093177348061">Proširena realnost</translation>
<translation id="2030769033451695672">Dodirnite da se vratite na <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Vaša prisutnost</translation>
<translation id="2079545284768500474">Vrati</translation>
<translation id="2091887806945687916">Zvuk</translation>
<translation id="2107397443965016585">Web lokacije moraju tražiti dozvolu za reprodukciju zaÅ¡tićenog sadržaja (preporuÄeno)</translation>
<translation id="2146738493024040262">Otvori instant aplikaciju</translation>
<translation id="2148716181193084225">Danas</translation>
<translation id="2182457891543959921">Web lokacije moraju tražiti odobrenje za kreiranje 3D mape okruženja i praćenje položaja kamere (preporuÄeno)</translation>
-<translation id="2187243482123994665">Prisutnost korisnika</translation>
<translation id="2212565012507486665">Dozvoli kolaÄiće</translation>
<translation id="2228071138934252756">Da omogućite aplikaciji <ph name="APP_NAME" /> pristup kameri, takoÄ‘er ukljuÄite kameru u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo ovaj put</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Pristup lokaciji</translation>
<translation id="2482878487686419369">Obavještenja</translation>
<translation id="2490684707762498678">Upravlja aplikacija <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Pomoć i povr. inf.</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Dozvolite web lokacijama pristup senzorima (preporuÄeno)</translation>
<translation id="3295602654194328831">Sakrij informacije</translation>
+<translation id="3328801116991980348">Informacije o web lokaciji</translation>
<translation id="3333961966071413176">Svi kontakti</translation>
<translation id="3386292677130313581">Web lokacije moraju tražiti dozvolu za pristup lokaciji (preporuÄeno)</translation>
<translation id="3538390592868664640">Web lokacijama je blokirano kreiranje 3D mape vašeg okruženja ili praćenje položaja kamere</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Dozvoljava web lokacijama da reproduciraju zaštićen sadržaj</translation>
<translation id="4468959413250150279">IskljuÄen zvuk za odreÄ‘enu web lokaciju.</translation>
<translation id="4479647676395637221">Web-lokacije moraju tražiti dopuÅ¡tenje za pristup kameri (preporuÄeno)</translation>
+<translation id="4505788138578415521">URL je proširen</translation>
<translation id="4534723447064627427">Da aplikaciji <ph name="APP_NAME" /> dozvolite pristup mikrofonu, takoÄ‘er ukljuÄite mikrofon u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalji</translation>
<translation id="4645575059429386691">Upravlja roditelj</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">UkljuÄite odobrenja za aplikaciju <ph name="APP_NAME" /> u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Pristup mikrofonu</translation>
<translation id="965817943346481315">Blokirajte ako web lokacija prikazuje nametljive ili obmanjujuće oglase (preporuÄeno)</translation>
<translation id="967624055006145463">Pohranjeni podaci</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
index 7409c2ba53b..7c90deb14c2 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">El lloc <ph name="SITE_NAME" /> s'ha afegit</translation>
<translation id="1383876407941801731">Cerca</translation>
<translation id="1384959399684842514">La baixada s'ha posat en pausa</translation>
+<translation id="1415402041810619267">L'URL s'ha truncat</translation>
<translation id="1431402976894535801">Bloqueja els llocs web perquè no sàpiguen quan estàs present</translation>
<translation id="1446450296470737166">Permet control total disp. MIDI</translation>
<translation id="1509960214886564027">Pot ser que les funcions de molts llocs web no funcionin</translation>
<translation id="1620510694547887537">Càmera</translation>
-<translation id="1647391597548383849">Accés a la càmera</translation>
<translation id="1660204651932907780">Permet que els llocs web reprodueixin so (opció recomanada)</translation>
<translation id="1677097821151855053">Les galetes i altres dades dels llocs web s'utilitzen per recordar-te amb finalitats com ara iniciar la teva sessió o personalitzar anuncis. Per gestionar les galetes de tots els llocs web, consulta <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vols esborrar les dades del lloc web?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL del lloc web</translation>
<translation id="2025115093177348061">Realitat augmentada</translation>
<translation id="2030769033451695672">Toca per tornar a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">La teva presència</translation>
<translation id="2079545284768500474">Desfés</translation>
<translation id="2091887806945687916">So</translation>
<translation id="2107397443965016585">Pregunta abans de permetre que els llocs web reprodueixin contingut protegit (opció recomanada)</translation>
<translation id="2146738493024040262">Obre l'aplicació instantània</translation>
<translation id="2148716181193084225">Avui</translation>
<translation id="2182457891543959921">Pregunta abans de permetre que els llocs web creïn un mapa en 3D del teu entorn o facin un seguiment de la posició de la càmera (opció recomanada)</translation>
-<translation id="2187243482123994665">Presència de l'usuari</translation>
<translation id="2212565012507486665">Permet les galetes</translation>
<translation id="2228071138934252756">Perquè <ph name="APP_NAME" /> pugui accedir a la càmera, també has d'activar-la a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Només una vegada</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}other{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}}</translation>
<translation id="2434158240863470628">S'ha completat la baixada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Accés a la ubicació</translation>
<translation id="2482878487686419369">Notificacions</translation>
<translation id="2490684707762498678">Gestionades per <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ajuda i suggeriments </translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Micròfon</translation>
<translation id="3277252321222022663">Permet que els llocs web accedeixin als sensors (opció recomanada)</translation>
<translation id="3295602654194328831">Amaga la informació</translation>
+<translation id="3328801116991980348">Informació del lloc web</translation>
<translation id="3333961966071413176">Tots els contactes</translation>
<translation id="3386292677130313581">Pregunta abans de permetre que els llocs web sàpiguen la teva ubicació (opció recomanada)</translation>
<translation id="3538390592868664640">Impedeix que els llocs web creïn un mapa en 3D del teu entorn o que facin un seguiment de la posició de la càmera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Permet que els llocs web reprodueixin contingut protegit</translation>
<translation id="4468959413250150279">Silencia el so d'un lloc web concret.</translation>
<translation id="4479647676395637221">Pregunta abans de permetre que els llocs web utilitzin la càmera (opció recomanada)</translation>
+<translation id="4505788138578415521">L'URL s'ha ampliat</translation>
<translation id="4534723447064627427">Perquè <ph name="APP_NAME" /> pugui accedir al micròfon, també has d'activar-lo a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalls</translation>
<translation id="4645575059429386691">Gestionat pels pares</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}}</translation>
<translation id="913657688200966289">Activa els permisos per a <ph name="APP_NAME" /> a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Accés al micròfon</translation>
<translation id="965817943346481315">Bloqueja els anuncis si el lloc web mostra publicitat intrusiva o enganyosa (opció recomanada)</translation>
<translation id="967624055006145463">Dades emmagatzemades</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
index 2ffff836e26..206eebcac85 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Byl přidán web <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Vyhledávání</translation>
<translation id="1384959399684842514">Stahování pozastaveno</translation>
+<translation id="1415402041810619267">Zkrácená adresa URL</translation>
<translation id="1431402976894535801">Nedovolit webům zjistit, kdy jste aktivní</translation>
<translation id="1446450296470737166">Povolit úplné ovládání zařízení MIDI</translation>
<translation id="1509960214886564027">Mnoho webů může přestat fungovat</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Přístup k fotoaparátu</translation>
<translation id="1660204651932907780">Povolit webům pÅ™ehrávat zvuky (doporuÄeno)</translation>
<translation id="1677097821151855053">Soubory cookie a další data webů slouží k tomu, aby si vás web zapamatoval, například pro úÄely pÅ™ihlášení nebo personalizace reklam. Chcete-li spravovat cookies pro vÅ¡echny weby, pÅ™ejdÄ›te do <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vymazat data webu?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Adresa URL webu</translation>
<translation id="2025115093177348061">Rozšířená realita</translation>
<translation id="2030769033451695672">Klepnutím se vrátíte na web <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Vaše přítomnost</translation>
<translation id="2079545284768500474">Vrátit zpět</translation>
<translation id="2091887806945687916">Zvuk</translation>
<translation id="2107397443965016585">PÅ™ed povolením spuÅ¡tÄ›ní chránÄ›ného obsahu na webu se zeptat (doporuÄeno)</translation>
<translation id="2146738493024040262">Otevřít okamžitou aplikaci</translation>
<translation id="2148716181193084225">Dnes</translation>
<translation id="2182457891543959921">PÅ™edtím, než webům bude povoleno vytvoÅ™it 3D mapu vaÅ¡eho okolí nebo sledovat polohu kamery, se zeptat (doporuÄeno)</translation>
-<translation id="2187243482123994665">Aktivita uživatele</translation>
<translation id="2212565012507486665">Povolit cookies</translation>
<translation id="2228071138934252756">Pokud aplikaci <ph name="APP_NAME" /> chcete umožnit přístup k fotoaparátu, zapněte fotoaparát také v <ph name="BEGIN_LINK" />Nastavení Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Pouze jednou</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}few{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}many{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}other{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}}</translation>
<translation id="2434158240863470628">Stažení bylo dokonÄeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Přístup k poloze</translation>
<translation id="2482878487686419369">Oznámení</translation>
<translation id="2490684707762498678">Spravováno aplikací <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Nápověda a zpětná vazba</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Povolit webům přístup k senzorům (doporuÄeno)</translation>
<translation id="3295602654194328831">Skrýt informace</translation>
+<translation id="3328801116991980348">Informace o stránkách</translation>
<translation id="3333961966071413176">VÅ¡echny kontakty</translation>
<translation id="3386292677130313581">Pokud web bude chtít znát vaÅ¡i polohu, zobrazit dotaz (doporuÄeno)</translation>
<translation id="3538390592868664640">Bránit webům ve vytváření 3D mapy okolí a ve sledování polohy kamery</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Povolit webům přehrávat chráněný obsah</translation>
<translation id="4468959413250150279">Vypne zvuk na konkrétním webu.</translation>
<translation id="4479647676395637221">Pokud web bude chtít použít vaÅ¡i kameru, zobrazit dotaz (doporuÄeno)</translation>
+<translation id="4505788138578415521">Rozbalená adresa URL</translation>
<translation id="4534723447064627427">Pokud aplikaci <ph name="APP_NAME" /> chcete umožnit přístup k mikrofonu, zapněte mikrofon také v <ph name="BEGIN_LINK" />Nastavení Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Podrobnosti</translation>
<translation id="4645575059429386691">Spravováno vaším rodiÄem</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}}</translation>
<translation id="913657688200966289">Zapněte v <ph name="BEGIN_LINK" />Nastavení Android<ph name="END_LINK" /> oprávnění pro aplikaci <ph name="APP_NAME" />.</translation>
-<translation id="945632385593298557">Přístup k mikrofonu</translation>
<translation id="965817943346481315">Blokovat, pokud web zobrazuje ruÅ¡ivé nebo zavádÄ›jící reklamy (doporuÄeno)</translation>
<translation id="967624055006145463">Uložená data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
index 4d4c9c02f64..5301a070a1d 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Websitet <ph name="SITE_NAME" /> blev tilføjet</translation>
<translation id="1383876407941801731">Søg</translation>
<translation id="1384959399684842514">Download er sat på pause</translation>
+<translation id="1415402041810619267">Webadressen er forkortet</translation>
<translation id="1431402976894535801">Bloker websites fra at vide, hvornår du er til stede</translation>
<translation id="1446450296470737166">Tillad fuld kontrol over MIDI-enheder</translation>
<translation id="1509960214886564027">Funktioner på mange websites virker muligvis ikke</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Adgang til dit kamera</translation>
<translation id="1660204651932907780">Tillad, at websites afspiller lyd (anbefales)</translation>
<translation id="1677097821151855053">Cookies og andre websitedata bruges til at huske dig, f.eks. for at logge dig ind eller give dig personligt tilpassede annoncer. GÃ¥ til <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" /> for at administrere cookies for alle websites.</translation>
<translation id="1688867105868176567">Ville du rydde websitets data?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Webadresse</translation>
<translation id="2025115093177348061">Augmented reality</translation>
<translation id="2030769033451695672">Tryk for at vende tilbage til <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Din tilstedeværelse</translation>
<translation id="2079545284768500474">Fortryd</translation>
<translation id="2091887806945687916">Lyd</translation>
<translation id="2107397443965016585">Spørg, før websites får tilladelse til at afspille beskyttet indhold (anbefales)</translation>
<translation id="2146738493024040262">Ã…bn instant-app</translation>
<translation id="2148716181193084225">I dag</translation>
<translation id="2182457891543959921">Spørg, inden websites kan oprette et 3D-kort over dine omgivelser eller registrere kamerapositionen (anbefales)</translation>
-<translation id="2187243482123994665">Brugertilstedeværelse</translation>
<translation id="2212565012507486665">Tillad cookies</translation>
<translation id="2228071138934252756">Aktivér også dit kamera i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" /> for at give <ph name="APP_NAME" /> adgang til kameraet.</translation>
<translation id="2241634353105152135">Kun én gang</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}}</translation>
<translation id="2434158240863470628">Downloaden er fuldført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Placeringsadgang</translation>
<translation id="2482878487686419369">Notifikationer</translation>
<translation id="2490684707762498678">Administreret af <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hjælp og feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Tillad, at websites kan få adgang til sensorer (anbefales)</translation>
<translation id="3295602654194328831">Skjul oplysninger</translation>
+<translation id="3328801116991980348">Webstedoplysninger</translation>
<translation id="3333961966071413176">Alle kontakter</translation>
<translation id="3386292677130313581">Spørg, om websites må få adgang til din placering (anbefales)</translation>
<translation id="3538390592868664640">Bloker oprettelsen af 3D-kort over dine omgivelser eller registrering af kamerapositionen for websites</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Tillad, at websites afspiller beskyttet indhold</translation>
<translation id="4468959413250150279">Slå lyden fra for et bestemt website.</translation>
<translation id="4479647676395637221">Spørg, før websites bruger dit kamera (anbefales)</translation>
+<translation id="4505788138578415521">Webadressen er udvidet</translation>
<translation id="4534723447064627427">Aktivér også din mikrofon i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" /> for at give <ph name="APP_NAME" /> adgang til mikrofonen.</translation>
<translation id="4570913071927164677">Info</translation>
<translation id="4645575059429386691">Administreret af en af dine forældre</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere}}</translation>
<translation id="913657688200966289">Aktivér tilladelser for <ph name="APP_NAME" /> i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Adgang til din mikrofon</translation>
<translation id="965817943346481315">Bloker, hvis websitet viser påtrængende eller vildledende annoncer (anbefales)</translation>
<translation id="967624055006145463">Lagrede data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
index 9cb42fb102f..94cc948cae0 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Website "<ph name="SITE_NAME" />" hinzugefügt</translation>
<translation id="1383876407941801731">Durchsuchen</translation>
<translation id="1384959399684842514">Download angehalten</translation>
+<translation id="1415402041810619267">URL abgeschnitten</translation>
<translation id="1431402976894535801">Websites daran hindern, Informationen zu meiner Anwesenheit abzurufen</translation>
<translation id="1446450296470737166">Volle Kontr. über MIDI-Ger. erl.</translation>
<translation id="1509960214886564027">Funktionen auf vielen Websites funktionieren möglicherweise nicht mehr</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kamerazugriff</translation>
<translation id="1660204651932907780">Wiedergabe von Ton auf Websites zulassen (empfohlen)</translation>
<translation id="1677097821151855053">Durch Cookies und andere Websitedaten erinnert sich die Website an Sie, z. B. bei der Anmeldung oder für personalisierte Werbung. Sie können Cookies für alle Websites <ph name="BEGIN_LINK" />in den Einstellungen verwalten<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Websitedaten löschen?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Website-URL</translation>
<translation id="2025115093177348061">Augmented Reality</translation>
<translation id="2030769033451695672">Tippen, um zu <ph name="URL_OF_THE_CURRENT_TAB" /> zurückzukehren</translation>
+<translation id="2054665754582400095">Ihre Anwesenheit</translation>
<translation id="2079545284768500474">Rückgängig machen</translation>
<translation id="2091887806945687916">Ton</translation>
<translation id="2107397443965016585">Fragen, bevor Websites erlaubt wird, geschützten Inhalt wiederzugeben (empfohlen)</translation>
<translation id="2146738493024040262">Instant-App öffnen</translation>
<translation id="2148716181193084225">Heute</translation>
<translation id="2182457891543959921">Nachfragen, bevor Websites erlaubt wird, eine 3D-Karte meiner Umgebung zu erstellen oder die Kameraposition zu verfolgen (empfohlen)</translation>
-<translation id="2187243482123994665">Anwesenheit des Nutzers</translation>
<translation id="2212565012507486665">Cookies zulassen</translation>
<translation id="2228071138934252756">Um <ph name="APP_NAME" /> Zugriff auf Ihre Kamera zu gewähren, muss die Kameraberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
<translation id="2241634353105152135">Nur einmal</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}}</translation>
<translation id="2434158240863470628">Download abgeschlossen <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Standortzugriff</translation>
<translation id="2482878487686419369">Benachrichtigungen</translation>
<translation id="2490684707762498678">Ãœber <ph name="APP_NAME" /> verwaltet</translation>
<translation id="2498359688066513246">Hilfe &amp; Feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Websites den Zugriff auf Sensoren erlauben (empfohlen)</translation>
<translation id="3295602654194328831">Informationen ausblenden</translation>
+<translation id="3328801116991980348">Websiteinformationen</translation>
<translation id="3333961966071413176">Alle Kontakte</translation>
<translation id="3386292677130313581">Nachfragen, bevor Websites mein Standort angezeigt wird (empfohlen)</translation>
<translation id="3538390592868664640">Websites daran hindern, eine 3D-Karte meiner Umgebung zu erstellen oder die Kameraposition zu verfolgen</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Websites erlauben, geschützte Inhalte wiederzugeben</translation>
<translation id="4468959413250150279">Eine bestimmte Website stummschalten.</translation>
<translation id="4479647676395637221">Nachfragen, bevor Websites Zugriff auf meine Kamera erhalten (empfohlen)</translation>
+<translation id="4505788138578415521">URL maximiert</translation>
<translation id="4534723447064627427">Um <ph name="APP_NAME" /> Zugriff auf Ihr Mikrofon zu gewähren, muss die Mikrofonberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
<translation id="4570913071927164677">Details</translation>
<translation id="4645575059429386691">Von deinen Eltern verwaltet</translation>
@@ -147,7 +148,7 @@
<translation id="5317780077021120954">Speichern</translation>
<translation id="5335288049665977812">Ausführung von JavaScript durch Websites zulassen (empfohlen)</translation>
<translation id="534295439873310000">NFC-Geräte</translation>
-<translation id="5354152178998424783">Dadurch werden <ph name="DATASIZE" /> von Websites gespeicherte Daten und Cookies gelöscht.</translation>
+<translation id="5354152178998424783">Dadurch werden <ph name="DATASIZE" /> an von Websites gespeicherten Daten und Cookies gelöscht.</translation>
<translation id="5384883051496921101">Diese Website ist im Begriff, Informationen mit einer App außerhalb des Inkognitomodus zu teilen.</translation>
<translation id="5391532827096253100">Die Verbindung zu dieser Website ist nicht sicher. Websiteinformationen</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 weitere)}other{(+ # weitere)}}</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere}}</translation>
<translation id="913657688200966289">Die Berechtigungen für <ph name="APP_NAME" /> können in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
-<translation id="945632385593298557">Mikrofonzugriff</translation>
<translation id="965817943346481315">Blockieren, wenn Website aufdringliche oder irreführende Werbung anzeigt (empfohlen)</translation>
<translation id="967624055006145463">Gespeicherte Daten</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
index 2d853d5276e..ce8c50163d7 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">ΠÏοστέθηκε ο ιστότοπος <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Αναζήτηση</translation>
<translation id="1384959399684842514">Η λήψη διακόπηκε Ï€ÏοσωÏινά.</translation>
+<translation id="1415402041810619267">ΠεÏικομμένο URL</translation>
<translation id="1431402976894535801">Îα μην επιτÏέπεται σε ιστοτόπους να γνωÏίζουν πότε είστε ενεÏγοί.</translation>
<translation id="1446450296470737166">Îα επιτÏέπεται πλήÏης έλεγχος σε MIDI</translation>
<translation id="1509960214886564027">ΜποÏεί να παÏουσιαστοÏν Ï€Ïοβλήματα στις λειτουÏγίες πολλών ιστοτόπων.</translation>
<translation id="1620510694547887537">ΚάμεÏα</translation>
-<translation id="1647391597548383849">ΠÏόσβαση στην κάμεÏα</translation>
<translation id="1660204651932907780">Îα επιτÏέπεται στους ιστοτόπους να αναπαÏάγουν ήχο (συνιστάται)</translation>
<translation id="1677097821151855053">Τα cookie και άλλα δεδομένα ιστοτόπου χÏησιμοποιοÏνται για την απομνημόνευσή σας, όπως, για παÏάδειγμα, για σας συνδέουν ή να εξατομικεÏουν τις διαφημίσεις σας. Για να διαχειÏιστείτε τα cookie για όλους τους ιστοτόπους, ανατÏέξτε στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Îα διαγÏαφοÏν τα δεδομένα ιστοτόπου;</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL ιστότοπου</translation>
<translation id="2025115093177348061">Επαυξημένη Ï€Ïαγματικότητα</translation>
<translation id="2030769033451695672">Πατήστε για επιστÏοφή σε <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Η παÏουσία σας</translation>
<translation id="2079545284768500474">ΑναίÏεση</translation>
<translation id="2091887806945687916">Ήχος</translation>
<translation id="2107397443965016585">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί στους ιστοτόπους η αναπαÏαγωγή Ï€Ïοστατευόμενου πεÏιεχομένου (συνιστάται)</translation>
<translation id="2146738493024040262">Άνοιγμα Instant ΕφαÏμογής</translation>
<translation id="2148716181193084225">ΣήμεÏα</translation>
<translation id="2182457891543959921">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί σε ιστοτόπους η δημιουÏγία Ï„Ïισδιάστατου χάÏτη του πεÏιβάλλοντα χώÏου σας και η παÏακολοÏθηση της θέσης της κάμεÏας (συνιστάται)</translation>
-<translation id="2187243482123994665">ΠαÏουσία χÏήστη</translation>
<translation id="2212565012507486665">Αποδοχή cookie</translation>
<translation id="2228071138934252756">Για να επιτÏέψετε στην εφαÏμογή <ph name="APP_NAME" /> να αποκτήσει Ï€Ïόσβαση στην κάμεÏά σας, ενεÏγοποιήστε επίσης την κάμεÏα στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Μόνο μία φοÏά</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτÏάπηκαν.}other{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτÏάπηκαν.}}</translation>
<translation id="2434158240863470628">Η λήψη ολοκληÏώθηκε <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ΠÏόσβαση τοποθεσίας</translation>
<translation id="2482878487686419369">Ειδοποιήσεις</translation>
<translation id="2490684707762498678">ΔιαχειÏιζόμενες από την εφαÏμογή <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Βοήθεια και σχόλια</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ΜικÏόφωνο</translation>
<translation id="3277252321222022663">Îα επιτÏέπεται στους ιστοτόπους η Ï€Ïόσβαση στους αισθητήÏες (συνιστάται)</translation>
<translation id="3295602654194328831">ΑπόκÏυψη πληÏοφοÏιών</translation>
+<translation id="3328801116991980348">ΠληÏοφοÏίες ιστοτόπου</translation>
<translation id="3333961966071413176">Όλες οι επαφές</translation>
<translation id="3386292677130313581">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί η κοινοποίηση της τοποθεσίας σας σε ιστότοπους (συνιστάται)</translation>
<translation id="3538390592868664640">Αποκλείστε ιστοτόπους από τη δημιουÏγία ενός Ï„Ïισδιάστατου χάÏτη του πεÏιβάλλοντα χώÏου σας ή την παÏακολοÏθηση της θέσης της κάμεÏας.</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Îα επιτÏέπεται στους ιστοτόπους η αναπαÏαγωγή Ï€Ïοστατευμένου πεÏιεχομένου</translation>
<translation id="4468959413250150279">Σίγαση ήχου για συγκεκÏιμένο ιστότοπο.</translation>
<translation id="4479647676395637221">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί στους ιστότοπους να χÏησιμοποιοÏν την κάμεÏά σας (συνιστάται)</translation>
+<translation id="4505788138578415521">Το URL επεκτάθηκε</translation>
<translation id="4534723447064627427">Για να επιτÏέψετε στην εφαÏμογή <ph name="APP_NAME" /> να αποκτήσει Ï€Ïόσβαση στο μικÏόφωνό σας, ενεÏγοποιήστε επίσης το μικÏόφωνο στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">ΛεπτομέÏειες</translation>
<translation id="4645575059429386691">ΔιαχειÏίζεται από τους γονείς σου</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη}}</translation>
<translation id="913657688200966289">ΕνεÏγοποιήστε τις άδειες για την εφαÏμογή <ph name="APP_NAME" /> στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ΠÏόσβαση στο μικÏόφωνό σας</translation>
<translation id="965817943346481315">Αποκλεισμός εάν ο ιστότοπος εμφανίζει παÏεμβατικές ή παÏαπλανητικές διαφημίσεις (συνιστάται)</translation>
<translation id="967624055006145463">Αποθηκευμένα δεδομένα</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
index 2a7d90e998e..ec715bba4e7 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> added</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">Download paused</translation>
+<translation id="1415402041810619267">URL truncated</translation>
<translation id="1431402976894535801">Block sites from knowing when you're present</translation>
<translation id="1446450296470737166">Allow full control of MIDI devices</translation>
<translation id="1509960214886564027">Features on many sites may break</translation>
<translation id="1620510694547887537">Camera</translation>
-<translation id="1647391597548383849">Access your camera</translation>
<translation id="1660204651932907780">Allow sites to play sound (recommended)</translation>
<translation id="1677097821151855053">Cookies and other site data are used to remember you, for example, to sign you in or to personalise ads. To manage cookies for all sites, see <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Clear site data?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Site URL</translation>
<translation id="2025115093177348061">Augmented reality</translation>
<translation id="2030769033451695672">Tap to return to <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Your presence</translation>
<translation id="2079545284768500474">Undo</translation>
<translation id="2091887806945687916">Sound</translation>
<translation id="2107397443965016585">Ask before allowing sites to play protected content (recommended)</translation>
<translation id="2146738493024040262">Open Instant App</translation>
<translation id="2148716181193084225">Today</translation>
<translation id="2182457891543959921">Ask before allowing sites to create a 3D map of your surroundings or track camera position (recommended)</translation>
-<translation id="2187243482123994665">User presence</translation>
<translation id="2212565012507486665">Allow cookies</translation>
<translation id="2228071138934252756">To let <ph name="APP_NAME" /> access your camera, also turn on camera in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Just once</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}}</translation>
<translation id="2434158240863470628">Download complete <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Location access</translation>
<translation id="2482878487686419369">Notifications</translation>
<translation id="2490684707762498678">Managed by <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Help &amp; feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microphone</translation>
<translation id="3277252321222022663">Allow sites to access sensors (recommended)</translation>
<translation id="3295602654194328831">Hide info</translation>
+<translation id="3328801116991980348">Site information</translation>
<translation id="3333961966071413176">All contacts</translation>
<translation id="3386292677130313581">Ask before allowing sites to know your location (recommended)</translation>
<translation id="3538390592868664640">Block sites from creating a 3D map of your surroundings or tracking camera position</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Allow sites to play protected content</translation>
<translation id="4468959413250150279">Mute sound for a specific site.</translation>
<translation id="4479647676395637221">Ask first before allowing sites to use your camera (recommended)</translation>
+<translation id="4505788138578415521">URL expanded</translation>
<translation id="4534723447064627427">To let <ph name="APP_NAME" /> access your microphone, also turn on microphone in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Details</translation>
<translation id="4645575059429386691">Managed by your parent</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}}</translation>
<translation id="913657688200966289">Turn on permissions for <ph name="APP_NAME" /> in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Access your microphone</translation>
<translation id="965817943346481315">Block if site shows intrusive or misleading ads (recommended)</translation>
<translation id="967624055006145463">Data stored</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
index 69dd6c4d609..53fcd63d122 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Se agregó el sitio <ph name="SITE_NAME" />.</translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Descarga detenida</translation>
+<translation id="1415402041810619267">URL acortada</translation>
<translation id="1431402976894535801">No permitir que los sitios sepan cuando estás presente</translation>
<translation id="1446450296470737166">Control de dispositivos MIDI</translation>
<translation id="1509960214886564027">Es posible que las características de muchos sitios no funcionen de forma correcta</translation>
<translation id="1620510694547887537">Cámara</translation>
-<translation id="1647391597548383849">Acceso a la cámara</translation>
<translation id="1660204651932907780">Permitir que los sitios reproduzcan sonido (recomendado)</translation>
<translation id="1677097821151855053">Se utilizan cookies y otros datos del sitio para recordarte. De esta manera, podrás acceder a tu cuenta y ver anuncios personalizados, entre otras cosas. Para administrar las cookies de todos los sitios, visita la <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">¿Quieres borrar los datos del sitio?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL del sitio</translation>
<translation id="2025115093177348061">Realidad aumentada</translation>
<translation id="2030769033451695672">Presiona para volver a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Tu presencia</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="2091887806945687916">Sonido</translation>
<translation id="2107397443965016585">Preguntar antes de permitir que los sitios reproduzcan contenido protegido (recomendado)</translation>
<translation id="2146738493024040262">Abrir app instantánea</translation>
<translation id="2148716181193084225">Hoy</translation>
<translation id="2182457891543959921">Preguntar antes de permitir que los sitios creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara (recomendado)</translation>
-<translation id="2187243482123994665">Presencia del usuario</translation>
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para permitir que <ph name="APP_NAME" /> acceda a tu cámara, actívala también en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo esta vez</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}other{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}}</translation>
<translation id="2434158240863470628">Se completó la descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Acceso a la ubicación</translation>
<translation id="2482878487686419369">Notificaciones</translation>
<translation id="2490684707762498678">Administradas por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ayuda y comentarios</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Micrófono</translation>
<translation id="3277252321222022663">Permitir que los sitios accedan a los sensores (recomendado)</translation>
<translation id="3295602654194328831">Ocultar información</translation>
+<translation id="3328801116991980348">Información del sitio</translation>
<translation id="3333961966071413176">Todos los contactos</translation>
<translation id="3386292677130313581">Preguntar antes de permitir que los sitios conozcan tu ubicación (recomendado)</translation>
<translation id="3538390592868664640">No permitir que los sitios creen un mapa 3D de tu entorno ni hagan un seguimiento de la posición de la cámara</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Permitir que los sitios reproduzcan contenido protegido</translation>
<translation id="4468959413250150279">Silenciar un sitio específico.</translation>
<translation id="4479647676395637221">Preguntar primero antes de permitir que los sitios usen tu cámara (recomendado)</translation>
+<translation id="4505788138578415521">URL expandida</translation>
<translation id="4534723447064627427">Para permitir que <ph name="APP_NAME" /> acceda a tu micrófono, actívalo también en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalles</translation>
<translation id="4645575059429386691">Administrado por tus padres</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}}</translation>
<translation id="913657688200966289">Activa los permisos para <ph name="APP_NAME" /> en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Acceso al micrófono</translation>
<translation id="965817943346481315">Bloquear si el sitio muestra anuncios intrusivos o engañosos (opción recomendada)</translation>
<translation id="967624055006145463">Datos almacenados</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
index b2f2e0a2f44..f0146077aa8 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
@@ -2,12 +2,12 @@
<!DOCTYPE translationbundle>
<translationbundle lang="es">
<translation id="1006017844123154345">Abrir versión online</translation>
-<translation id="1044891598689252897">Los sitios web funcionarán con normalidad</translation>
-<translation id="1124090076051167250">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies almacenados por sitios web o aplicaciones en tu pantalla de inicio.</translation>
+<translation id="1044891598689252897">Los sitios funcionarán con normalidad</translation>
+<translation id="1124090076051167250">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies almacenados por sitios o aplicaciones en tu pantalla de inicio.</translation>
<translation id="1124772482545689468">Usuario</translation>
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Quitar</translation>
-<translation id="1195941046451948919">¿Seguro que quieres restablecer todos los permisos de este sitio web?</translation>
+<translation id="1195941046451948919">¿Seguro que quieres restablecer todos los permisos para este sitio web?</translation>
<translation id="1201402288615127009">Siguiente</translation>
<translation id="1242008676835033345">Insertada en <ph name="WEBSITE_URL" /></translation>
<translation id="1272079795634619415">Interrumpir</translation>
@@ -17,35 +17,35 @@
<translation id="1369915414381695676">Se ha añadido el sitio <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Descarga en pausa</translation>
-<translation id="1431402976894535801">Impedir que los sitios web sepan cuándo estás presente</translation>
+<translation id="1415402041810619267">URL truncada</translation>
+<translation id="1431402976894535801">No permitir que los sitios sepan cuándo estás presente</translation>
<translation id="1446450296470737166">Control total dispositivos MIDI</translation>
-<translation id="1509960214886564027">Es posible que las funciones de muchos sitios web no funcionen correctamente.</translation>
+<translation id="1509960214886564027">Es posible que las funciones de muchos sitios no funcionen correctamente.</translation>
<translation id="1620510694547887537">Cámara</translation>
-<translation id="1647391597548383849">Acceder a la cámara</translation>
-<translation id="1660204651932907780">Permitir que los sitios web reproduzcan sonidos (recomendado)</translation>
-<translation id="1677097821151855053">Las cookies y otros datos de los sitios web se usan para recordarte. Así, podrás iniciar sesión o ver anuncios personalizados, entre otras cosas. Para gestionar las cookies de todos los sitios web, ve a <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
-<translation id="1688867105868176567">¿Quieres borrar los datos del sitio web?</translation>
-<translation id="169515064810179024">No permitir que los sitios web accedan a los sensores de movimiento</translation>
+<translation id="1660204651932907780">Permitir que los sitios reproduzcan sonidos (recomendado)</translation>
+<translation id="1677097821151855053">Las cookies y otros datos de los sitios se usan para recordarte. Así, podrás iniciar sesión o ver anuncios personalizados, entre otras cosas. Para gestionar las cookies de todos los sitios, ve a <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
+<translation id="1688867105868176567">¿Borrar datos del sitio web?</translation>
+<translation id="169515064810179024">No permitir que los sitios accedan a los sensores de movimiento</translation>
<translation id="1717218214683051432">Sensores de movimiento</translation>
-<translation id="1743802530341753419">Preguntar antes de permitir que los sitios web se conecten a un dispositivo (recomendado)</translation>
+<translation id="1743802530341753419">Preguntar antes de permitir que los sitios se conecten a un dispositivo (recomendado)</translation>
<translation id="1779089405699405702">Decodificador de imágenes</translation>
<translation id="1818308510395330587">Para que <ph name="APP_NAME" /> pueda usar la realidad aumentada, activa la cámara también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
-<translation id="1887786770086287077">El acceso a la ubicación está desactivado en este dispositivo. Actívalo en los <ph name="BEGIN_LINK" />Ajustes de Android<ph name="END_LINK" />.</translation>
+<translation id="1887786770086287077">El acceso a la ubicación está desactivado en este dispositivo. Actívalo en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="1919345977826869612">Anuncios</translation>
<translation id="1919950603503897840">Seleccionar contactos</translation>
<translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/<ph name="FILE_SIZE_WITH_UNITS" /></translation>
-<translation id="1984937141057606926">Permitidas (excepto cookies de terceros)</translation>
+<translation id="1984937141057606926">Permitido (excepto cookies de terceros)</translation>
<translation id="1989112275319619282">Examinar</translation>
<translation id="1994173015038366702">URL del sitio</translation>
<translation id="2025115093177348061">Realidad aumentada</translation>
<translation id="2030769033451695672">Toca para volver a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Tu presencia</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="2091887806945687916">Sonido</translation>
-<translation id="2107397443965016585">Preguntar antes de permitir que los sitios web reproduzcan contenido protegido (recomendado)</translation>
+<translation id="2107397443965016585">Preguntar antes de permitir que los sitios reproduzcan contenido protegido (recomendado)</translation>
<translation id="2146738493024040262">Abrir aplicación instantánea</translation>
<translation id="2148716181193084225">Hoy</translation>
-<translation id="2182457891543959921">Preguntar antes de permitir que los sitios web creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara (recomendado)</translation>
-<translation id="2187243482123994665">Presencia del usuario</translation>
+<translation id="2182457891543959921">Preguntar antes de permitir que los sitios creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara (recomendado)</translation>
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para que <ph name="APP_NAME" /> pueda acceder a tu cámara, activa la cámara también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo una vez</translation>
@@ -55,26 +55,25 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}}</translation>
<translation id="2434158240863470628">Descarga finalizada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Acceso a la ubicación</translation>
<translation id="2482878487686419369">Notificaciones</translation>
<translation id="2490684707762498678">Gestionadas por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ayuda y comentarios</translation>
<translation id="2501278716633472235">Volver</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 cookie bloqueada}other{# cookies bloqueadas}}</translation>
-<translation id="2570922361219980984">El acceso a la ubicación también está desactivado en este dispositivo. Actívalo en los <ph name="BEGIN_LINK" />Ajustes de Android<ph name="END_LINK" />.</translation>
+<translation id="2570922361219980984">El acceso a la ubicación también está desactivado en este dispositivo. Actívalo en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="257931822824936280">Ampliado (hacer clic para contraer)</translation>
<translation id="2586657967955657006">Portapapeles</translation>
-<translation id="2621115761605608342">Habilita JavaScript en un sitio web específico.</translation>
+<translation id="2621115761605608342">Habilita JavaScript en un sitio específico.</translation>
<translation id="2653659639078652383">Enviar</translation>
<translation id="2677748264148917807">Salir</translation>
<translation id="2687403674020088961">Bloquear todas las cookies (no recomendado)</translation>
<translation id="2704606927547763573">Copiado</translation>
<translation id="2717722538473713889">Direcciones de correo electrónico</translation>
-<translation id="2822354292072154809">¿Seguro que quieres restablecer todos los permisos de los sitios web de <ph name="CHOSEN_OBJECT_NAME" />?</translation>
+<translation id="2822354292072154809">¿Seguro que quieres restablecer todos los permisos de los sitios de <ph name="CHOSEN_OBJECT_NAME" />?</translation>
<translation id="2870560284913253234">Sitio</translation>
<translation id="2874939134665556319">Pista anterior</translation>
<translation id="2903493209154104877">Direcciones</translation>
-<translation id="2910701580606108292">Preguntar antes de permitir que los sitios web reproduzcan contenido protegido</translation>
+<translation id="2910701580606108292">Preguntar antes de permitir que los sitios reproduzcan contenido protegido</translation>
<translation id="2913331724188855103">Permitir que los sitios guarden y lean datos de cookies (recomendado)</translation>
<translation id="2968755619301702150">Visor de certificados</translation>
<translation id="300526633675317032">Se borrarán los <ph name="SIZE_IN_KB" /> de almacenamiento del sitio web.</translation>
@@ -82,34 +81,35 @@
<translation id="301521992641321250">Bloqueado automáticamente</translation>
<translation id="3114012059975132928">Reproductor de vídeo</translation>
<translation id="3115898365077584848">Mostrar información</translation>
-<translation id="3123473560110926937">Bloqueados en algunos sitios web</translation>
+<translation id="3123473560110926937">Bloqueados en algunos sitios</translation>
<translation id="3165371858310906303">Preguntar cuando un sitio web quiera saber si estás presente</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de datos almacenados</translation>
<translation id="321187648315454507">Para que <ph name="APP_NAME" /> pueda enviarte notificaciones, actívalas también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micrófono</translation>
-<translation id="3277252321222022663">Permitir que los sitios web accedan a los sensores (recomendado)</translation>
+<translation id="3277252321222022663">Permitir que los sitios accedan a los sensores (recomendado)</translation>
<translation id="3295602654194328831">Ocultar información</translation>
+<translation id="3328801116991980348">Información del sitio</translation>
<translation id="3333961966071413176">Todos los contactos</translation>
-<translation id="3386292677130313581">Preguntar antes de permitir que los sitios web detecten tu ubicación (recomendado)</translation>
-<translation id="3538390592868664640">Impide que los sitios web creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara</translation>
+<translation id="3386292677130313581">Preguntar antes de permitir que los sitios detecten tu ubicación (recomendado)</translation>
+<translation id="3538390592868664640">No permitir que los sitios creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara</translation>
<translation id="3586500876634962664">Uso de cámara y micrófono</translation>
<translation id="3587482841069643663">Todo</translation>
<translation id="358794129225322306">Permitir que un sitio web descargue varios archivos automáticamente.</translation>
<translation id="3594780231884063836">Silenciar vídeo</translation>
-<translation id="3596414637720633074">Bloquear cookies de terceros en el modo de incógnito</translation>
-<translation id="3600792891314830896">Silenciar los sitios web que reproducen sonidos</translation>
+<translation id="3596414637720633074">Bloquear cookies de terceros en incógnito</translation>
+<translation id="3600792891314830896">Silenciar los sitios que reproducen sonidos</translation>
<translation id="3744111561329211289">Sincronización en segundo plano</translation>
<translation id="3763247130972274048">Toca dos veces a la derecha o a la izquierda del vídeo para saltar 10 s</translation>
<translation id="381841723434055211">Números de teléfono</translation>
<translation id="385051799172605136">Volver</translation>
<translation id="3859306556332390985">Buscar hacia delante</translation>
-<translation id="3955193568934677022">Permitir que los sitios web reproduzcan contenido protegido (recomendado)</translation>
+<translation id="3955193568934677022">Permitir que los sitios reproduzcan contenido protegido (recomendado)</translation>
<translation id="3987993985790029246">Copiar enlace</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Título</translation>
-<translation id="4008040567710660924">Permitir cookies en un sitio web específico.</translation>
+<translation id="4008040567710660924">Permitir cookies en un sitio específico.</translation>
<translation id="4046123991198612571">Pista siguiente</translation>
-<translation id="4165986682804962316">Configuración de sitios web</translation>
+<translation id="4165986682804962316">Configuración de sitios</translation>
<translation id="4200726100658658164">Abrir Ajustes de ubicación</translation>
<translation id="4226663524361240545">Es posible que las notificaciones hagan que el dispositivo vibre</translation>
<translation id="4259722352634471385">Se ha bloqueado la navegación: <ph name="URL" /></translation>
@@ -119,9 +119,10 @@
<translation id="4336434711095810371">Borrar todos los datos</translation>
<translation id="4433925000917964731">Página básica ofrecida por Google</translation>
<translation id="4434045419905280838">Ventanas emergentes y redirecciones</translation>
-<translation id="445467742685312942">Permitir que los sitios web reproduzcan contenido protegido</translation>
-<translation id="4468959413250150279">Silencia el sonido de un sitio web específico.</translation>
-<translation id="4479647676395637221">Preguntar antes de permitir que los sitios web utilicen la cámara (recomendado)</translation>
+<translation id="445467742685312942">Permitir que los sitios reproduzcan contenido protegido</translation>
+<translation id="4468959413250150279">Silencia el sonido de un sitio específico.</translation>
+<translation id="4479647676395637221">Preguntar antes de permitir que los sitios utilicen la cámara (recomendado)</translation>
+<translation id="4505788138578415521">URL ampliada</translation>
<translation id="4534723447064627427">Para que <ph name="APP_NAME" /> pueda acceder al micrófono, actívalo también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalles</translation>
<translation id="4645575059429386691">Administrado por uno de tus padres</translation>
@@ -129,13 +130,13 @@
<translation id="4708011789095599544">¿Seguro que quieres borrar las cookies y otros datos de este sitio web?</translation>
<translation id="4751476147751820511">Sensores de luz o movimiento</translation>
<translation id="4883854917563148705">No se pueden restablecer los ajustes gestionados</translation>
-<translation id="4887024562049524730">Preguntar antes de permitir que los sitios web usen tu dispositivo y tus datos de realidad virtual (recomendado)</translation>
+<translation id="4887024562049524730">Preguntar antes de permitir que los sitios usen tu dispositivo y tus datos de realidad virtual (recomendado)</translation>
<translation id="4962975101802056554">Revocar todos los permisos de este dispositivo</translation>
<translation id="497421865427891073">Avanzar</translation>
<translation id="4994033804516042629">No se han encontrado contactos</translation>
<translation id="4996978546172906250">Compartir a través de</translation>
<translation id="5039804452771397117">Permitir</translation>
-<translation id="5048398596102334565">Permitir que los sitios web accedan a los sensores de movimiento (recomendado)</translation>
+<translation id="5048398596102334565">Permitir que los sitios accedan a los sensores de movimiento (recomendado)</translation>
<translation id="5063480226653192405">Uso</translation>
<translation id="5100237604440890931">Contraído (hacer clic para ampliar)</translation>
<translation id="5123685120097942451">Pestaña de incógnito</translation>
@@ -145,26 +146,26 @@
<translation id="5301954838959518834">Entendido</translation>
<translation id="5313967007315987356">Añadir sitio</translation>
<translation id="5317780077021120954">Guardar</translation>
-<translation id="5335288049665977812">Permitir que los sitios web utilicen JavaScript (recomendado)</translation>
+<translation id="5335288049665977812">Permitir que los sitios utilicen JavaScript (recomendado)</translation>
<translation id="534295439873310000">Dispositivos NFC</translation>
-<translation id="5354152178998424783">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies almacenados por sitios web.</translation>
+<translation id="5354152178998424783">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies almacenados por sitios.</translation>
<translation id="5384883051496921101">Este sitio web va a compartir información con una aplicación con la que no se utilizará el modo de incógnito.</translation>
<translation id="5391532827096253100">Tu conexión a este sitio web no es segura. Información del sitio web</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(y 1 más)}other{(y # más)}}</translation>
<translation id="5403592356182871684">Nombres</translation>
<translation id="5489227211564503167">Tiempo transcurrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
-<translation id="5494752089476963479">Bloquea anuncios invasivos o engañosos en los sitios web que los muestran</translation>
+<translation id="5494752089476963479">Bloquea anuncios invasivos o engañosos en los sitios que los muestran</translation>
<translation id="5502860503640766021"><ph name="PERMISSION_1" /> permitido; <ph name="PERMISSION_2" /> bloqueado</translation>
-<translation id="5505264765875738116">Los sitios web no pueden preguntarte si quieres que te envíen notificaciones</translation>
+<translation id="5505264765875738116">Los sitios no pueden preguntarte si quieres que te envíen notificaciones</translation>
<translation id="5516455585884385570">Abrir ajustes de notificaciones</translation>
-<translation id="5527111080432883924">Preguntar antes de permitir que los sitios web lean texto e imágenes del portapapeles (recomendado)</translation>
+<translation id="5527111080432883924">Preguntar antes de permitir que los sitios lean texto e imágenes del portapapeles (recomendado)</translation>
<translation id="5556459405103347317">Volver a cargar</translation>
<translation id="5596627076506792578">Más opciones</translation>
<translation id="5649053991847567735">Descargas automáticas</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5689516760719285838">Ubicación</translation>
<translation id="5690795753582697420">La cámara está desactivada en los ajustes de Android</translation>
-<translation id="5710871682236653961">Pregunta antes de permitir que los sitios web envíen y reciban información cuando toques dispositivos NFC (recomendado)</translation>
+<translation id="5710871682236653961">Preguntar antes de permitir que los sitios envíen y reciban información cuando toques dispositivos NFC (recomendado)</translation>
<translation id="5719847187258001597">Esta acción borrará todos los datos y cookies almacenados por <ph name="ORIGIN" /> y su aplicación en tu pantalla de inicio.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> bloqueado</translation>
<translation id="5804241973901381774">Permisos</translation>
@@ -180,28 +181,28 @@
<translation id="6064125863973209585">Descargas completadas</translation>
<translation id="6165508094623778733">Más información</translation>
<translation id="6177111841848151710">Bloqueado en el motor de búsqueda actual</translation>
-<translation id="6181444274883918285">Añadir excepción de sitio web</translation>
+<translation id="6181444274883918285">Añadir excepción de sitio</translation>
<translation id="6192792657125177640">Excepciones</translation>
<translation id="6196640612572343990">Bloquear cookies de terceros</translation>
<translation id="6206551242102657620">La conexión es segura. Información del sitio web</translation>
<translation id="6216432067784365534">Opciones de <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="6262279340360821358"><ph name="PERMISSION_1" /> y <ph name="PERMISSION_2" /> bloqueados</translation>
-<translation id="6270391203985052864">Los sitios web pueden preguntarte si quieres que te envíen notificaciones</translation>
+<translation id="6270391203985052864">Los sitios pueden preguntarte si quieres que te envíen notificaciones</translation>
<translation id="6295158916970320988">Todos los sitios</translation>
<translation id="6320088164292336938">Vibrar</translation>
<translation id="6388207532828177975">Borrar y restablecer</translation>
<translation id="6398765197997659313">Salir del modo de pantalla completa</translation>
<translation id="6423924377271166037">Borrar cookies</translation>
-<translation id="6439114592976064011">Impedir que los sitios web usen tu dispositivo y tus datos de realidad virtual</translation>
+<translation id="6439114592976064011">No permitir que los sitios usen tu dispositivo y tus datos de realidad virtual</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6527303717912515753">Compartir</translation>
<translation id="6545864417968258051">Búsqueda de dispositivos Bluetooth</translation>
<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más bloqueados}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más bloqueados}}</translation>
-<translation id="6561560012278703671">Usa un tipo de aviso más discreto (bloquea las notificaciones emergentes para evitar interrupciones)</translation>
+<translation id="6561560012278703671">Usar avisos discretos (bloquea las notificaciones emergentes para evitar interrupciones)</translation>
<translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
<translation id="6612358246767739896">Contenido protegido</translation>
<translation id="662080504995468778">Seguir aquí</translation>
-<translation id="6643016212128521049">Eliminar</translation>
+<translation id="6643016212128521049">Borrar</translation>
<translation id="6689172468748959065">Fotos de perfil</translation>
<translation id="6697925417670533197">Descargas activas</translation>
<translation id="6746124502594467657">Bajar</translation>
@@ -210,18 +211,18 @@
<translation id="6818926723028410516">Seleccionar elementos</translation>
<translation id="6864395892908308021">Este dispositivo no puede leer NFC</translation>
<translation id="6910211073230771657">Eliminado</translation>
-<translation id="6912998170423641340">Evitar que los sitios web lean texto e imágenes del portapapeles</translation>
+<translation id="6912998170423641340">Evitar que los sitios lean texto e imágenes del portapapeles</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6963642900430330478">Esta página es peligrosa. Información del sitio web</translation>
<translation id="6965382102122355670">Aceptar</translation>
-<translation id="6992289844737586249">Preguntar antes de permitir que los sitios web utilicen el micrófono (recomendado)</translation>
+<translation id="6992289844737586249">Preguntar antes de permitir que los sitios utilicen el micrófono (recomendado)</translation>
<translation id="7000754031042624318">Desactivado en los ajustes de Android</translation>
<translation id="7016516562562142042">Permitido en el motor de búsqueda actual</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 seleccionada}other{# seleccionadas}}</translation>
<translation id="7087918508125750058">Elementos seleccionados: <ph name="ITEM_COUNT" />. Hay opciones disponibles en la parte superior de la pantalla</translation>
<translation id="7128222689758636196">Permitir para el motor de búsqueda actual</translation>
-<translation id="7141896414559753902">Impedir que los sitios web muestren ventanas emergentes y redirecciones (recomendado)</translation>
+<translation id="7141896414559753902">Impide que los sitios muestren ventanas emergentes y redirecciones (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
<translation id="723171743924126238">Seleccionar imágenes</translation>
<translation id="7243308994586599757">Opciones disponibles cerca de la parte inferior de la pantalla</translation>
@@ -233,8 +234,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un sitio web está usando tu micrófono</translation>
<translation id="7561196759112975576">Siempre</translation>
-<translation id="7572498721684305250">No permite que los sitios web envíen y reciban información cuando toques dispositivos NFC</translation>
-<translation id="757524316907819857">Impedir que los sitios web reproduzcan contenido protegido</translation>
+<translation id="7572498721684305250">No permitir que los sitios envíen y reciban información cuando toques dispositivos NFC</translation>
+<translation id="757524316907819857">No permitir que los sitios reproduzcan contenido protegido</translation>
<translation id="7589445247086920869">Bloquear para el motor de búsqueda actual</translation>
<translation id="7649070708921625228">Ayuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
@@ -243,21 +244,21 @@
<translation id="780301667611848630">No, gracias</translation>
<translation id="7804248752222191302">Un sitio web está usando tu cámara</translation>
<translation id="7817023149356982970">Se cerrará tu sesión en este sitio web.</translation>
-<translation id="7828557259026017104">Las cookies son archivos que crean los sitios web que visitas. Estos las usan para recordar tus preferencias. Las cookies de terceros las crean otros sitios web. Parte del contenido que ves en la página web que visitas, como anuncios o imágenes, pertenece a esos otros sitios web.</translation>
+<translation id="7828557259026017104">Las cookies son archivos que crean los sitios web que visitas. Los sitios las usan para recordar tus preferencias. Las cookies de terceros las crean otros sitios. Parte del contenido que ves en el sitio que visitas, como anuncios o imágenes, pertenece a esos otros sitios web.</translation>
<translation id="7835852323729233924">Reproduciendo contenido multimedia</translation>
<translation id="783819812427904514">Dejar de silenciar vídeo</translation>
<translation id="7846076177841592234">Cancelar selección</translation>
-<translation id="7846621471902887024">Se cerrarán tus sesiones en todos los sitios web.</translation>
-<translation id="7882806643839505685">Permite que se reproduzcan sonidos en un sitio web específico.</translation>
+<translation id="7846621471902887024">Se cerrarán tus sesiones en todos los sitios.</translation>
+<translation id="7882806643839505685">Permite que se reproduzcan sonidos en un sitio específico.</translation>
<translation id="7986741934819883144">Selecciona un contacto</translation>
-<translation id="7993619969781047893">Es posible que las funciones de algunos sitios web no funcionen correctamente</translation>
-<translation id="7999064672810608036">¿Seguro que quieres borrar todos los datos locales, incluidas las cookies, y restablecer todos los permisos de este sitio web?</translation>
+<translation id="7993619969781047893">Es posible que las funciones de algunos sitios no funcionen correctamente</translation>
+<translation id="7999064672810608036">¿Seguro que quieres borrar todos los datos locales, incluidas las cookies, y restablecer todos los permisos para este sitio web?</translation>
<translation id="8007176423574883786">Desactivada para este dispositivo</translation>
<translation id="802154636333426148">No se ha podido descargar el archivo</translation>
<translation id="8067883171444229417">Reproducir vídeo</translation>
<translation id="8068648041423924542">No se puede seleccionar el certificado.</translation>
<translation id="8087000398470557479">Este contenido procede de <ph name="DOMAIN_NAME" />, publicado por Google.</translation>
-<translation id="8116925261070264013">Silenciados</translation>
+<translation id="8116925261070264013">Silenciado</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8197286292360124385"><ph name="PERMISSION_1" /> permitido</translation>
<translation id="8200772114523450471">Reanudar</translation>
@@ -266,8 +267,8 @@
<translation id="8261506727792406068">Eliminar</translation>
<translation id="8300705686683892304">Administrados por una aplicación</translation>
<translation id="8324158725704657629">No volver a preguntar</translation>
-<translation id="8372893542064058268">Permite la sincronización en segundo plano de un sitio web específico.</translation>
-<translation id="8376384591331888629">Incluir cookies de terceros en este sitio web</translation>
+<translation id="8372893542064058268">Permite la sincronización en segundo plano de un sitio específico.</translation>
+<translation id="8376384591331888629">Incluir cookies de terceros en este sitio</translation>
<translation id="83792324527827022">Un sitio web está usando tu cámara y tu micrófono</translation>
<translation id="8380167699614421159">El sitio web muestra anuncios invasivos o engañosos</translation>
<translation id="8394832520002899662">Toca para volver al sitio web</translation>
@@ -277,7 +278,7 @@
<translation id="8447861592752582886">Revocar permiso de dispositivo</translation>
<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie en uso}other{# cookies en uso}}</translation>
<translation id="8463851957836045671">El sitio web es rápido</translation>
-<translation id="851751545965956758">No permitir que los sitios web se conecten a dispositivos</translation>
+<translation id="851751545965956758">No permitir que los sitios se conecten a dispositivos</translation>
<translation id="8525306231823319788">Pantalla completa</translation>
<translation id="857943718398505171">Permitido (recomendado)</translation>
<translation id="8609465669617005112">Subir</translation>
@@ -289,21 +290,20 @@
<translation id="8730621377337864115">Listo</translation>
<translation id="8737217482364735741">Esta acción borrará todos los datos y cookies guardados por <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Selecciona una imagen</translation>
-<translation id="8801436777607969138">Bloquear JavaScript en un sitio web específico.</translation>
-<translation id="8816026460808729765">No permite que los sitios web accedan a los sensores</translation>
+<translation id="8801436777607969138">Bloquea JavaScript en un sitio específico.</translation>
+<translation id="8816026460808729765">No permitir que los sitios accedan a los sensores</translation>
<translation id="8847988622838149491">USB</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">La tecnología NFC está desactivada en este dispositivo. Actívala en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="8929372349074745002">Este sitio web se abre y responde con rapidez en la mayoría de los casos</translation>
-<translation id="8941729603749328384">www.ejemplo.com</translation>
+<translation id="8941729603749328384">www.example.com</translation>
<translation id="894871326938397531">¿Salir del modo de incógnito?</translation>
-<translation id="8958424370300090006">Bloquear las cookies de un sitio web específico.</translation>
+<translation id="8958424370300090006">Bloquear las cookies de un sitio específico.</translation>
<translation id="8959122750345127698">No se puede realizar la navegación: <ph name="URL" /></translation>
<translation id="9019902583201351841">Administrado por tus padres</translation>
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}}</translation>
<translation id="913657688200966289">Activa los permisos para <ph name="APP_NAME" /> en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Acceder al micrófono</translation>
<translation id="965817943346481315">Bloquear si el sitio web muestra anuncios invasivos o engañosos (recomendado)</translation>
<translation id="967624055006145463">Datos almacenados</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
index 809969954a0..bdd0a7e07e6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> on lisatud</translation>
<translation id="1383876407941801731">Otsi</translation>
<translation id="1384959399684842514">Allalaadimine peatatud</translation>
+<translation id="1415402041810619267">Lühendatud URL</translation>
<translation id="1431402976894535801">Keela saitidel selle tuvastamine, millal saiti aktiivselt kasutan</translation>
<translation id="1446450296470737166">MIDI-seadm. täieliku juht. lub.</translation>
<translation id="1509960214886564027">Paljude saitide funktsioonid ei pruugi töötada</translation>
<translation id="1620510694547887537">Kaamera</translation>
-<translation id="1647391597548383849">Juurdepääs kaamerale</translation>
<translation id="1660204651932907780">Saitidel lubatakse esitada heli (soovitatav)</translation>
<translation id="1677097821151855053">Küpsisefaile ja muid saidi andmeid kasutatakse teie meeldejätmiseks, näiteks selleks, et teid sisse logida või reklaame isikupärastada. Kõigi saitide küpsisefailide haldamiseks vaadake jaotist <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Kas soovite saidi andmed kustutada?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Saidi URL</translation>
<translation id="2025115093177348061">Liitreaalsus</translation>
<translation id="2030769033451695672">Puudutage vahelehele <ph name="URL_OF_THE_CURRENT_TAB" /> naasmiseks</translation>
+<translation id="2054665754582400095">Teie kohalolek</translation>
<translation id="2079545284768500474">Võta tagasi</translation>
<translation id="2091887806945687916">Heli</translation>
<translation id="2107397443965016585">Küsi enne saidile kaitstud sisu esitamiseks loa andmist (soovitatav)</translation>
<translation id="2146738493024040262">Ava installimata avatav rakendus</translation>
<translation id="2148716181193084225">Täna</translation>
<translation id="2182457891543959921">Küsi enne saitidele loa andmist mind ümbritsevast 3D-kaardi loomiseks või kaamera asendi jälgimiseks (soovitatav)</translation>
-<translation id="2187243482123994665">Kasutaja kohalolek</translation>
<translation id="2212565012507486665">Luba küpsisefailid</translation>
<translation id="2228071138934252756">Selleks et anda rakendusele <ph name="APP_NAME" /> juurdepääs teie kaamerale, lülitage kaamera sisse ka <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Ainult ühe korra</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}}</translation>
<translation id="2434158240863470628">Allalaadimine jõudis lõpule: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Juurdepääs asukohale</translation>
<translation id="2482878487686419369">Märguanded</translation>
<translation id="2490684707762498678">Haldab <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Abi ja tagasiside</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Luba saitide jaoks juurdepääs anduritele (soovitatav)</translation>
<translation id="3295602654194328831">Peida teave</translation>
+<translation id="3328801116991980348">Saiditeave</translation>
<translation id="3333961966071413176">Kõik kontaktid</translation>
<translation id="3386292677130313581">Küsi enne saitidele minu asukoha avaldamist (soovitatav)</translation>
<translation id="3538390592868664640">Saitide jaoks blokeeritakse teid ümbritsevast 3D-kaardi loomine või kaamera asendi jälgimine</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Saitidel on lubatud esitada kaitstud sisu</translation>
<translation id="4468959413250150279">Konkreetse saidi heli vaigistamine.</translation>
<translation id="4479647676395637221">Küsi enne saitidele minu kaamera kasutamiseks juurdepääsu lubamist (soovitatav)</translation>
+<translation id="4505788138578415521">Laiendatud URL</translation>
<translation id="4534723447064627427">Selleks et anda rakendusele <ph name="APP_NAME" /> juurdepääs teie mikrofonile, lülitage mikrofon sisse ka <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Ãœksikasjad</translation>
<translation id="4645575059429386691">Vanema hallatud</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Lülitage <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" /> sisse load rakendusele <ph name="APP_NAME" />.</translation>
-<translation id="945632385593298557">Juurdepääs mikrofonile</translation>
<translation id="965817943346481315">Blokeeri, kui sait kuvab sekkuvaid või eksitavaid reklaame (soovitatav)</translation>
<translation id="967624055006145463">Salvestatud andmete maht</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
index b8828f749ca..5bd80c33cd5 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> webgunea gehitu da</translation>
<translation id="1383876407941801731">Bilaketa</translation>
<translation id="1384959399684842514">Pausatu da deskarga</translation>
+<translation id="1415402041810619267">URLa moztuta dago</translation>
<translation id="1431402976894535801">Ez utzi webguneei presente noiz zauden jakiten</translation>
<translation id="1446450296470737166">Onartu MIDI gailuen kontrol osoa</translation>
<translation id="1509960214886564027">Baliteke webgune askotako eginbideek ez funtzionatzea</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Atzitu kamera</translation>
<translation id="1660204651932907780">Baimendu webguneei soinua erreproduzitzea (gomendatua)</translation>
<translation id="1677097821151855053">Cookieak eta webguneko beste datu batzuk zu gogoratzeko erabiltzen dira; adibidez, saioa hasteko edo iragarkiak pertsonalizatzeko. Webgune guztietako cookieak kudeatzeko, ikusi <ph name="BEGIN_LINK" />Ezarpenak<ph name="END_LINK" /> atala.</translation>
<translation id="1688867105868176567">Webguneko datuak garbitu nahi dituzu?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Webgunearen URLa</translation>
<translation id="2025115093177348061">Errealitate areagotua</translation>
<translation id="2030769033451695672">Sakatu hau <ph name="URL_OF_THE_CURRENT_TAB" /> webgunera itzultzeko</translation>
+<translation id="2054665754582400095">Zure presentzia</translation>
<translation id="2079545284768500474">Desegin</translation>
<translation id="2091887806945687916">Soinua</translation>
<translation id="2107397443965016585">Webguneei eduki babestua erreproduzitzeko baimena eman aurretik, eskatu onespena (gomendatua)</translation>
<translation id="2146738493024040262">Ireki zuzeneko aplikazioa</translation>
<translation id="2148716181193084225">Gaur</translation>
<translation id="2182457891543959921">Eskatu zure baimena webguneei inguruaren 3D-ko mapa bat sortu edo kameraren posizioaren jarraipena egiteko baimena eman aurretik (gomendatua)</translation>
-<translation id="2187243482123994665">Erabiltzailearen presentzia</translation>
<translation id="2212565012507486665">Onartu cookieak</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> aplikazioari kamera atzitzeko baimena emateko, kamera atzitzeko baimena aktibatu behar duzu <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Behin soilik</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}other{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Deskargatu da <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Kokapenerako sarbidea</translation>
<translation id="2482878487686419369">Jakinarazpenak</translation>
<translation id="2490684707762498678">Kudeatzailea: <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Laguntza eta iritziak</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofonoa</translation>
<translation id="3277252321222022663">Eman sentsoreak atzitzeko baimena webguneei (gomendatua)</translation>
<translation id="3295602654194328831">Ezkutatu informazioa</translation>
+<translation id="3328801116991980348">Webgunearen informazioa</translation>
<translation id="3333961966071413176">Kontaktu guztiak</translation>
<translation id="3386292677130313581">Webguneei zure kokapena erakusteko baimena eman aurretik, eskatu onespena (gomendatua)</translation>
<translation id="3538390592868664640">Ez utzi inongo webguneri inguruaren 3D-ko mapa bat sortzen edo kameraren posizioaren jarraipena egiten</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Baimendu webguneei eduki babestua erreproduzitzea</translation>
<translation id="4468959413250150279">Desaktibatu webgune jakin baten audioa.</translation>
<translation id="4479647676395637221">Webguneei kamera erabiltzeko baimena eman aurretik, eskatu onespena (gomendatua)</translation>
+<translation id="4505788138578415521">URLa zabalduta dago</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> aplikazioari mikrofonoa atzitzeko baimena emateko, mikrofonoa atzitzeko baimena aktibatu behar duzu <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Xehetasunak</translation>
<translation id="4645575059429386691">Gurasoek kudeatuta</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth-a</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Aktibatu <ph name="APP_NAME" /> aplikaziorako baimenak <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Atzitu mikrofonoa</translation>
<translation id="965817943346481315">Webguneak iragarki oztopatzaileak erakusten baditu, blokea itzazu (gomendatua)</translation>
<translation id="967624055006145463">Gordetako datuak</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
index 3c93e842161..a4f01b9a491 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">سایت <ph name="SITE_NAME" /> اضاÙÙ‡ شد</translation>
<translation id="1383876407941801731">جستجو</translation>
<translation id="1384959399684842514">بارگیری موقتاً متوق٠شد</translation>
+<translation id="1415402041810619267">نشانی وب کوتاه‌شده</translation>
<translation id="1431402976894535801">مسدود کردن سایت‌ها برای اطلاع از وضعیت حضور شما</translation>
<translation id="1446450296470737166">â€Ø§Ø¬Ø§Ø²Ù‡ کنترل کامل دستگاه‌های MIDI</translation>
<translation id="1509960214886564027">ویژگی‌های بسیاری از سایت‌ها ممکن است درست کار نکنند</translation>
<translation id="1620510694547887537">دوربین</translation>
-<translation id="1647391597548383849">دسترسی به دوربین</translation>
<translation id="1660204651932907780">به سایت‌ها اجازه داده شود صدا پخش کنند (توصیه می‌شود)</translation>
<translation id="1677097821151855053">از کوکی‌ها Ùˆ دیگر داده‌های سایت برای به‌خاطر سپردن شما استÙاده می‌شود؛ برای مثال ورود به سیستم یا نمایش آگهی‌های شخصی‌شده. برای مدیریت کردن کوکی‌ها برای همه سایت‌ها، به <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" /> بروید.</translation>
<translation id="1688867105868176567">داده‌های سایت پاک شود؟</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">نشانی وب سایت</translation>
<translation id="2025115093177348061">واقعیت اÙزوده</translation>
<translation id="2030769033451695672">برای برگشتن به <ph name="URL_OF_THE_CURRENT_TAB" /> ضربه بزنید</translation>
+<translation id="2054665754582400095">حضور شما</translation>
<translation id="2079545284768500474">لغو</translation>
<translation id="2091887806945687916">صدا</translation>
<translation id="2107397443965016585">قبل از اجازه به سایت‌ها برای پخش محتوای محاÙظت‌شده سؤال شود (توصیه می‌شود)</translation>
<translation id="2146738493024040262">برنامه Ùوری را باز کنید</translation>
<translation id="2148716181193084225">امروز</translation>
<translation id="2182457891543959921">قبل از اینکه به سایت‌ها اجازه داده شود نقشه سه‌بعدی از محیط ایجاد کنند یا موقعیت دوربین را ردیابی کنند سؤال شود (توصیه می‌شود)</translation>
-<translation id="2187243482123994665">حضور کاربر</translation>
<translation id="2212565012507486665">مجاز کردن کوکی ها</translation>
<translation id="2228071138934252756">â€Ø¨Ø±Ø§ÛŒ اینکه به <ph name="APP_NAME" /> اجازه دهید به دوربین دسترسی پیدا کند، دوربین را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> نیز روشن کنید.</translation>
<translation id="2241634353105152135">Ùقط یک بار</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> مگابایت</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}one{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}}</translation>
<translation id="2434158240863470628">بارگیری کامل شد <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">دسترسی به موقعیت مکانی</translation>
<translation id="2482878487686419369">اعلان‌ها</translation>
<translation id="2490684707762498678">تحت مدیریت <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">راهنمایی و بازخورد</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">میکروÙÙ†</translation>
<translation id="3277252321222022663">مجاز بودن دسترسی سایت‌ها به حسگرها (توصیه می‌شود)</translation>
<translation id="3295602654194328831">پنهان کردن اطلاعات</translation>
+<translation id="3328801116991980348">اطلاعات سایت</translation>
<translation id="3333961966071413176">همه مخاطبین</translation>
<translation id="3386292677130313581">قبل از اجازه به سایت‌ها برای اطلاع از مکانتان، ابتدا سؤال شود (توصیه می‌شود)</translation>
<translation id="3538390592868664640">قابلیت سایت‌ها برای ایجاد نقشه سه‌بعدی از محیط یا ردیابی موقعیت دوربین مسدود می‌شود</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">به سایت‌ها اجازه داده شود محتوای محاÙظت‌شده پخش کنند</translation>
<translation id="4468959413250150279">سایتی خاص بی‌صدا شود.</translation>
<translation id="4479647676395637221">قبل از اجازه به سایت‌ها برای استÙاده از دوربین، ابتدا سؤال شود (توصیه می‌شود)</translation>
+<translation id="4505788138578415521">نشانی وب گسترده شد</translation>
<translation id="4534723447064627427">â€Ø¨Ø±Ø§ÛŒ اینکه به <ph name="APP_NAME" /> اجازه دهید به میکروÙون دسترسی پیدا کند، میکروÙون را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> نیز روشن کنید.</translation>
<translation id="4570913071927164677">جزئیات</translation>
<translation id="4645575059429386691">مدیریت شده توسط والدین شما</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">بلوتوث</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر}one{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر}}</translation>
<translation id="913657688200966289">â€Ø§Ø¬Ø§Ø²Ù‡â€ŒÙ‡Ø§ÛŒ <ph name="APP_NAME" /> را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> روشن کنید.</translation>
-<translation id="945632385593298557">دسترسی به میکروÙÙ†</translation>
<translation id="965817943346481315">اگر سایتْ آگهی‌های مزاحم یا گمراه‌کننده نشان می‌دهد مسدود شود (توصیه می‌شود)</translation>
<translation id="967624055006145463">داده ذخیره شد</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
index 75492a12f77..54abfae4f3e 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Sivusto <ph name="SITE_NAME" /> lisättiin.</translation>
<translation id="1383876407941801731">Haku</translation>
<translation id="1384959399684842514">Lataus keskeytettiin.</translation>
+<translation id="1415402041810619267">URL näkyy lyhennettynä</translation>
<translation id="1431402976894535801">Estä sivustoja tietämästä, kun olet paikalla</translation>
<translation id="1446450296470737166">Salli MIDI-laitteiden täysi käyttöoik.</translation>
<translation id="1509960214886564027">Useiden sivustojen ominaisuudet saattavat lakata toimimasta</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kameran käyttöoikeus</translation>
<translation id="1660204651932907780">Salli sivustojen toistaa ääniä (suositus)</translation>
<translation id="1677097821151855053">Evästeillä ja muulla sivustodatalla tunnistetaan sinut, jotta voit esimerkiksi kirjautua sisään tai nähdä personoituja mainoksia. Jos haluat ylläpitää kaikkien sivustojen evästeitä, siirry <ph name="BEGIN_LINK" />Asetuksiin<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Tyhjennetäänkö sivustotiedot?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Sivuston URL-osoite</translation>
<translation id="2025115093177348061">Lisätty todellisuus</translation>
<translation id="2030769033451695672">Napauta, niin palaat tänne: <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Paikallaolosi</translation>
<translation id="2079545284768500474">Kumoa</translation>
<translation id="2091887806945687916">Ääni</translation>
<translation id="2107397443965016585">Kysy, saavatko sivustot toistaa suojattua sisältöä (suositus)</translation>
<translation id="2146738493024040262">Avaa Instant-sovellus</translation>
<translation id="2148716181193084225">Tänään</translation>
<translation id="2182457891543959921">Kysy, saavatko sivustot luoda 3D-kartan ympäristöstäsi tai seurata kameran asentoa (suositus)</translation>
-<translation id="2187243482123994665">Käyttäjän paikallaolo</translation>
<translation id="2212565012507486665">Salli evästeet</translation>
<translation id="2228071138934252756">Laita kamera päälle myös <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />, jotta <ph name="APP_NAME" /> saa pääsyn kameraasi.</translation>
<translation id="2241634353105152135">Vain kerran</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mt</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}}</translation>
<translation id="2434158240863470628">Lataus valmis <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Sijaintitietojen käyttöoikeus</translation>
<translation id="2482878487686419369">Ilmoitukset</translation>
<translation id="2490684707762498678">Ylläpitäjä: <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ohjeet ja palaute</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofoni</translation>
<translation id="3277252321222022663">Anna sivustojen käyttää tunnistimia (suositus)</translation>
<translation id="3295602654194328831">Piilota tiedot</translation>
+<translation id="3328801116991980348">Tietoja sivustosta</translation>
<translation id="3333961966071413176">Kaikki yhteystiedot</translation>
<translation id="3386292677130313581">Pyydä lupaa, kun sivustot yrittävät käyttää sijaintiasi (suositus).</translation>
<translation id="3538390592868664640">Estä sivustoja luomasta 3D-karttaa ympäristöstäsi tai seuraamasta kameran asentoa</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Salli sivustojen toistaa suojattua sisältöä</translation>
<translation id="4468959413250150279">Mykistä tietyn sivuston äänet.</translation>
<translation id="4479647676395637221">Pyydä lupaa, kun sivustot yrittävät käyttää kameraasi (suositus).</translation>
+<translation id="4505788138578415521">URL näkyy laajennettuna</translation>
<translation id="4534723447064627427">Laita mikrofoni päälle myös <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />, jotta <ph name="APP_NAME" /> saa pääsyn mikrofoniisi.</translation>
<translation id="4570913071927164677">Tiedot</translation>
<translation id="4645575059429386691">Vanhempasi hallinnoima</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta}}</translation>
<translation id="913657688200966289">Laita luvat (<ph name="APP_NAME" />) päälle <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Mikrofonin käyttöoikeus</translation>
<translation id="965817943346481315">Estä, jos sivusto näyttää häiritseviä tai harhaanjohtavia mainoksia (suositus)</translation>
<translation id="967624055006145463">Tallennettu data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
index 1d3ba72aa11..02aab3c5aee 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Nadagdag na ang site ng <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Hanapin</translation>
<translation id="1384959399684842514">Na-pause ang pag-download</translation>
+<translation id="1415402041810619267">Naputol ang URL</translation>
<translation id="1431402976894535801">I-block ang mga site na malaman kapag aktibo ka</translation>
<translation id="1446450296470737166">Payagan ganap na kontrol sa MIDI device</translation>
<translation id="1509960214886564027">Posibleng masira ang mga feature sa maraming site</translation>
<translation id="1620510694547887537">Camera</translation>
-<translation id="1647391597548383849">I-access ang iyong camera</translation>
<translation id="1660204651932907780">Payagan ang mga site na mag-play ng tunog (inirerekomenda)</translation>
<translation id="1677097821151855053">Ginagamit ang cookies at iba pang data ng site para tandaan ka, halimbawa para i-sign in ka o i-personalize ang mga ad. Para mapamahalaan ang cookies para sa lahat ng site, tingnan ang <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">I-clear ang data ng site?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL ng site</translation>
<translation id="2025115093177348061">Augmented reality</translation>
<translation id="2030769033451695672">Mag-tap para bumalik sa <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Ang iyong presensya</translation>
<translation id="2079545284768500474">I-undo</translation>
<translation id="2091887806945687916">Tunog</translation>
<translation id="2107397443965016585">Magtanong bago pahintulutan ang mga site na mag-play ng pinoprotektahang content (inirerekomenda)</translation>
<translation id="2146738493024040262">Buksan ang Instant App</translation>
<translation id="2148716181193084225">Ngayon</translation>
<translation id="2182457891543959921">Magtanong bago payagan ang mga site na gumawa ng 3D na mapa ng iyong kapaligiran o subaybayan ang posisyon ng camera (inirerekomenda)</translation>
-<translation id="2187243482123994665">Pagiging aktibo ng user</translation>
<translation id="2212565012507486665">Payagan ang cookies</translation>
<translation id="2228071138934252756">Para payagan ang <ph name="APP_NAME" /> na i-access ang iyong camera, i-on din ang camera sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Isang beses lang</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}one{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}other{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}}</translation>
<translation id="2434158240863470628">Tapos nang mag-download <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Access sa lokasyon</translation>
<translation id="2482878487686419369">Mga Abiso</translation>
<translation id="2490684707762498678">Pinapamahalaan ng <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Tulong at feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikropono</translation>
<translation id="3277252321222022663">Payagan ang mga site na i-access ang mga sensor (inirerekomenda)</translation>
<translation id="3295602654194328831">Itago ang Impormasyon</translation>
+<translation id="3328801116991980348">Impormasyon ng site</translation>
<translation id="3333961966071413176">Lahat ng contact</translation>
<translation id="3386292677130313581">Magtanong bago payagan ang mga site na malaman ang iyong lokasyon (inirerekomenda)</translation>
<translation id="3538390592868664640">I-block ang mga site sa paggawa ng 3D na mapa ng iyong kapaligiran o pagsubaybay sa posisyon ng camera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Pahintulutan ang mga site na mag-play ng pinoprotektahang content</translation>
<translation id="4468959413250150279">I-mute ang tunog para sa isang partikular na site.</translation>
<translation id="4479647676395637221">Magtanong muna bago payagan ang mga site na gamitin ang iyong camera (inirerekomenda)</translation>
+<translation id="4505788138578415521">Na-expand ang URL</translation>
<translation id="4534723447064627427">Para payagan ang <ph name="APP_NAME" /> na i-access ang iyong mikropono, i-on din ang mikropono sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Mga Detalye</translation>
<translation id="4645575059429386691">Pinamamahalaan ng iyong magulang</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}}</translation>
<translation id="913657688200966289">I-on ang mga pahintulot para sa <ph name="APP_NAME" /> sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">I-access ang iyong mikropono</translation>
<translation id="965817943346481315">I-block kung nagpapakita ang site ng mga nakakasagabal o nakakapanlinlang na ad (inirerekomenda)</translation>
<translation id="967624055006145463">Naka-store na data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
index 5388376d8a9..83876c14597 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
@@ -17,13 +17,13 @@
<translation id="1369915414381695676">Le site <ph name="SITE_NAME" /> a été ajouté</translation>
<translation id="1383876407941801731">Rechercher</translation>
<translation id="1384959399684842514">Téléchargement interrompu</translation>
+<translation id="1415402041810619267">URL tronquée</translation>
<translation id="1431402976894535801">Empêcher les sites de savoir lorsque vous êtes présent</translation>
<translation id="1446450296470737166">Autoriser le contrôle des appareils MIDI</translation>
<translation id="1509960214886564027">Des fonctionnalités sur de nombreux sites risquent de ne pas fonctionner</translation>
<translation id="1620510694547887537">Caméra</translation>
-<translation id="1647391597548383849">Accès à votre caméra</translation>
<translation id="1660204651932907780">Autoriser les sites à faire jouer du son (recommandé)</translation>
-<translation id="1677097821151855053">Les témoins et d'autres données de sites sont utilisés pour se souvenir de vous. Par exemple : pour vous connecter à votre compte ou pour personnaliser les annonces. Pour gérer les témoins pour tous les sites, reportez-vous au menu <ph name="BEGIN_LINK" />Paramètres<ph name="END_LINK" />.</translation>
+<translation id="1677097821151855053">Les témoins et les autres données de sites sont utilisés pour se souvenir de vous. Par exemple : pour vous connecter à votre compte ou pour personnaliser les annonces. Pour gérer les témoins pour tous les sites, reportez-vous au menu <ph name="BEGIN_LINK" />Paramètres<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Effacer les données du site?</translation>
<translation id="169515064810179024">Empêcher les sites d'accéder aux capteurs de mouvement</translation>
<translation id="1717218214683051432">Capteurs de mouvements</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL du site</translation>
<translation id="2025115093177348061">Réalité augmentée</translation>
<translation id="2030769033451695672">Touchez pour revenir à <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Votre présence</translation>
<translation id="2079545284768500474">Annuler</translation>
<translation id="2091887806945687916">Son</translation>
<translation id="2107397443965016585">Demander avant d'autoriser les sites à lire du contenu protégé (recommandé)</translation>
<translation id="2146738493024040262">Ouvrir l'application instantanée</translation>
<translation id="2148716181193084225">Aujourd'hui</translation>
<translation id="2182457891543959921">Demander avant d'autoriser les sites à créer une carte 3D de votre environnement ou à faire le suivi de la position de l'appareil photo (recommandé)</translation>
-<translation id="2187243482123994665">Présence de l'utilisateur</translation>
<translation id="2212565012507486665">Autoriser les témoins</translation>
<translation id="2228071138934252756">Pour autoriser <ph name="APP_NAME" /> à accéder à votre appareil photo, activez aussi celui-ci dans les <ph name="BEGIN_LINK" />paramètres d'Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Une fois</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mo</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}one{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}other{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autres accordées}}</translation>
<translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Accès à la position</translation>
<translation id="2482878487686419369">Notifications</translation>
<translation id="2490684707762498678">Les notifications sont gérées par <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Aide et commentaires</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microphone</translation>
<translation id="3277252321222022663">Autoriser les sites à accéder aux capteurs (recommandé)</translation>
<translation id="3295602654194328831">Masquer les renseignements</translation>
+<translation id="3328801116991980348">Information sur le site</translation>
<translation id="3333961966071413176">Tous les contacts</translation>
<translation id="3386292677130313581">Demander avant d'autoriser des sites à connaître votre emplacement (recommandé)</translation>
<translation id="3538390592868664640">Empêcher les sites de créer une carte 3D de votre environnement et de faire le suivi de la position de l'appareil photo</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Autoriser les sites à lire du contenu protégé</translation>
<translation id="4468959413250150279">Désactivez le son sur un site précis.</translation>
<translation id="4479647676395637221">Demander avant d'autoriser des sites à utiliser votre caméra (recommandé)</translation>
+<translation id="4505788138578415521">URL développée</translation>
<translation id="4534723447064627427">Pour autoriser <ph name="APP_NAME" /> à accéder à votre microphone, vous devez aussi activer le microphone dans les <ph name="BEGIN_LINK" />paramètres d'Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Détails</translation>
<translation id="4645575059429386691">Géré par l’un de tes parents</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autres}}</translation>
<translation id="913657688200966289">Vous pouvez activer les autorisations pour <ph name="APP_NAME" /> dans les <ph name="BEGIN_LINK" />paramètres d'Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Accès à votre microphone</translation>
<translation id="965817943346481315">Bloquer si le site diffuse des annonces intrusives ou trompeuses (recommandé)</translation>
<translation id="967624055006145463">Données stockées</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
index bb486a0c2c7..0f85a3f0eed 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
@@ -17,15 +17,15 @@
<translation id="1369915414381695676">Site "<ph name="SITE_NAME" />" ajouté</translation>
<translation id="1383876407941801731">Rechercher</translation>
<translation id="1384959399684842514">Téléchargement suspendu</translation>
+<translation id="1415402041810619267">URL tronquée</translation>
<translation id="1431402976894535801">Empêcher les sites de savoir quand vous êtes là</translation>
<translation id="1446450296470737166">Autoriser le contrôle complet des appareils MIDI</translation>
<translation id="1509960214886564027">Des fonctionnalités sur de nombreux sites risquent de ne pas fonctionner</translation>
<translation id="1620510694547887537">Caméra</translation>
-<translation id="1647391597548383849">Accéder à votre caméra</translation>
<translation id="1660204651932907780">Autoriser le son des sites (recommandé)</translation>
<translation id="1677097821151855053">Les cookies et autres données de site servent à se souvenir de vous (par exemple, pour que vous puissiez vous connecter plus facilement ou pour personnaliser les annonces). Pour gérer les cookies de l'ensemble des sites, accédez aux <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
-<translation id="1688867105868176567">Effacer les données du site ?</translation>
-<translation id="169515064810179024">Empêcher les sites d'accéder aux capteurs de mouvement</translation>
+<translation id="1688867105868176567">Effacer les données de site ?</translation>
+<translation id="169515064810179024">Empêcher les sites d'accéder à vos capteurs de mouvement</translation>
<translation id="1717218214683051432">Capteurs de mouvement</translation>
<translation id="1743802530341753419">Demander avant d'autoriser les sites à se connecter à un appareil (recommandé)</translation>
<translation id="1779089405699405702">Décodage d'images</translation>
@@ -39,15 +39,15 @@
<translation id="1994173015038366702">URL du site</translation>
<translation id="2025115093177348061">Réalité augmentée</translation>
<translation id="2030769033451695672">Appuyez pour revenir à l'adresse <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Votre présence</translation>
<translation id="2079545284768500474">Annuler</translation>
<translation id="2091887806945687916">Son</translation>
<translation id="2107397443965016585">Demander avant d'autoriser les sites à lire les contenus protégés (recommandé)</translation>
<translation id="2146738493024040262">Ouvrir l'appli instantanée</translation>
<translation id="2148716181193084225">Aujourd'hui</translation>
-<translation id="2182457891543959921">Vous demander votre avis avant d'autoriser les sites à créer un plan 3D de votre environnement ou à suivre la position de la caméra (recommandé)</translation>
-<translation id="2187243482123994665">Présence de l'utilisateur</translation>
+<translation id="2182457891543959921">Demander avant d'autoriser les sites à créer un plan 3D de votre environnement ou à suivre la position de la caméra (recommandé)</translation>
<translation id="2212565012507486665">Autoriser les cookies</translation>
-<translation id="2228071138934252756">Pour autoriser <ph name="APP_NAME" /> à accéder à votre appareil photo, activez également celui-ci dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
+<translation id="2228071138934252756">Pour autoriser <ph name="APP_NAME" /> à accéder à votre caméra, activez-la également dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Une seule fois</translation>
<translation id="2289270750774289114">Me demander lorsqu'un site souhaite accéder aux appareils Bluetooth se trouvant à proximité (recommandé)</translation>
<translation id="2315043854645842844">La sélection de certificat côté client n'est pas compatible avec le système d'exploitation.</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mo</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
<translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Accès à la position</translation>
<translation id="2482878487686419369">Notifications</translation>
<translation id="2490684707762498678">Géré par <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Aide et commentaires</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Micro</translation>
<translation id="3277252321222022663">Autoriser les sites à accéder à vos capteurs (recommandé)</translation>
<translation id="3295602654194328831">Masquer les informations</translation>
+<translation id="3328801116991980348">Informations sur le site</translation>
<translation id="3333961966071413176">Tous les contacts</translation>
<translation id="3386292677130313581">Demander avant d'autoriser des sites à accéder à ma position (recommandé)</translation>
<translation id="3538390592868664640">Empêcher les sites de créer un plan 3D de votre environnement ou de suivre la position de la caméra</translation>
@@ -120,8 +120,9 @@
<translation id="4433925000917964731">Page simplifiée fournie par Google</translation>
<translation id="4434045419905280838">Pop-up et redirections</translation>
<translation id="445467742685312942">Autoriser les sites à lire les contenus protégés</translation>
-<translation id="4468959413250150279">Coupe le son d'un site spécifique.</translation>
+<translation id="4468959413250150279">Coupez le son d'un site spécifique.</translation>
<translation id="4479647676395637221">Demander avant d'autoriser des sites à utiliser ma caméra (recommandé)</translation>
+<translation id="4505788138578415521">URL étendue</translation>
<translation id="4534723447064627427">Pour autoriser <ph name="APP_NAME" /> à accéder au micro, activez également celui-ci dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Détails</translation>
<translation id="4645575059429386691">Géré par ton papa/ta maman</translation>
@@ -129,7 +130,7 @@
<translation id="4708011789095599544">Voulez-vous vraiment supprimer les cookies et autres données de ce site Web ?</translation>
<translation id="4751476147751820511">Capteurs de mouvement ou de lumière</translation>
<translation id="4883854917563148705">Impossible de réinitialiser les paramètres gérés</translation>
-<translation id="4887024562049524730">Vous demander votre avis avant d'autoriser les sites à utiliser vos données et votre appareil de réalité virtuelle (recommandé)</translation>
+<translation id="4887024562049524730">Demander avant d'autoriser les sites à utiliser vos données et votre appareil de réalité virtuelle (recommandé)</translation>
<translation id="4962975101802056554">Révoquer toutes les autorisations de l'appareil</translation>
<translation id="497421865427891073">Avancer</translation>
<translation id="4994033804516042629">Aucun contact trouvé</translation>
@@ -197,7 +198,7 @@
<translation id="6527303717912515753">Partager</translation>
<translation id="6545864417968258051">Recherche Bluetooth</translation>
<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{Autorisations refusées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
-<translation id="6561560012278703671">Activer l'affichage discret (permet d'empêcher les invites liées aux notifications de vous interrompre)</translation>
+<translation id="6561560012278703671">Activer l'affichage discret (empêche les notifications de vous interrompre)</translation>
<translation id="6608650720463149374"><ph name="GIGABYTES" /> Go</translation>
<translation id="6612358246767739896">Contenu protégé</translation>
<translation id="662080504995468778">Rester</translation>
@@ -221,7 +222,7 @@
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 élément sélectionné}one{# élément sélectionné}other{# éléments sélectionnés}}</translation>
<translation id="7087918508125750058">Nombre d'éléments sélectionnés : <ph name="ITEM_COUNT" />. Options disponibles dans la partie supérieure de l'écran</translation>
<translation id="7128222689758636196">Autoriser pour le moteur de recherche actuel</translation>
-<translation id="7141896414559753902">Bloquer l'affichage de fenêtres pop-up et de redirections par les sites (recommandé)</translation>
+<translation id="7141896414559753902">Bloquer l'affichage de fenêtres pop-up et les redirections par les sites (recommandé)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> Ko</translation>
<translation id="723171743924126238">Sélectionner des images</translation>
<translation id="7243308994586599757">Options disponibles au bas de l'écran</translation>
@@ -266,7 +267,7 @@
<translation id="8261506727792406068">Supprimer</translation>
<translation id="8300705686683892304">Gérés par l'application</translation>
<translation id="8324158725704657629">Ne plus me demander</translation>
-<translation id="8372893542064058268">Autorise la synchronisation en arrière-plan pour un site spécifique.</translation>
+<translation id="8372893542064058268">Autorisez la synchronisation en arrière-plan pour un site spécifique.</translation>
<translation id="8376384591331888629">Inclure les cookies tiers de ce site</translation>
<translation id="83792324527827022">Un site utilise votre appareil photo et votre micro</translation>
<translation id="8380167699614421159">Ce site affiche des annonces intrusives ou trompeuses</translation>
@@ -289,7 +290,7 @@
<translation id="8730621377337864115">OK</translation>
<translation id="8737217482364735741">L'ensemble des données et des cookies stockés par <ph name="ORIGIN" /> seront effacés.</translation>
<translation id="8751914237388039244">Sélectionner une image</translation>
-<translation id="8801436777607969138">Bloquer JavaScript sur un site spécifique.</translation>
+<translation id="8801436777607969138">Bloquez JavaScript sur un site spécifique.</translation>
<translation id="8816026460808729765">Bloque l'accès aux capteurs pour certains sites</translation>
<translation id="8847988622838149491">USB</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
<translation id="913657688200966289">Activez les autorisations pour <ph name="APP_NAME" /> dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Accéder à votre micro</translation>
<translation id="965817943346481315">Bloquer si le site affiche des annonces intrusives ou trompeuses (recommandé)</translation>
<translation id="967624055006145463">Données stockées</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
index 40a9152f883..3852a930056 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Engadiuse o sitio <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Pausouse a descarga</translation>
+<translation id="1415402041810619267">URL truncado</translation>
<translation id="1431402976894535801">Impedir que os sitios saiban cando estás activo</translation>
<translation id="1446450296470737166">Permitir control disposit. MIDI</translation>
<translation id="1509960214886564027">As funcións de moitos sitios poden deixar de funcionar</translation>
<translation id="1620510694547887537">Cámara</translation>
-<translation id="1647391597548383849">Acceso á túa cámara</translation>
<translation id="1660204651932907780">Permite que os sitios reproduzan son (recomendado)</translation>
<translation id="1677097821151855053">As cookies e outros datos do sitio utilízanse para lembrarte (por exemplo, á hora de iniciar de sesión ou de personalizar anuncios). Se queres xestionar as cookies para todos os sitios, vai a <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Queres borrar os datos do sitio?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL do sitio</translation>
<translation id="2025115093177348061">Realidade aumentada</translation>
<translation id="2030769033451695672">Toca para volver a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">A túa presenza</translation>
<translation id="2079545284768500474">Desfacer</translation>
<translation id="2091887806945687916">Son</translation>
<translation id="2107397443965016585">Preguntar antes de permitir que os sitios reproduzan contido protexido (recomendado)</translation>
<translation id="2146738493024040262">Abrir aplicacións instantáneas</translation>
<translation id="2148716181193084225">Hoxe</translation>
<translation id="2182457891543959921">Preguntar antes de permitir que os sitios creen un mapa 3D do que te rodea e fagan un seguimento da posición da cámara (recomendado)</translation>
-<translation id="2187243482123994665">Estado de actividade do usuario</translation>
<translation id="2212565012507486665">Permitir uso de cookies</translation>
<translation id="2228071138934252756">Para permitir que <ph name="APP_NAME" /> acceda á cámara, actívaa tamén en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Só unha vez</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}}</translation>
<translation id="2434158240863470628">Completouse a descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Acceso á localización</translation>
<translation id="2482878487686419369">Notificacións</translation>
<translation id="2490684707762498678">Xestionadas por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Axuda e comentarios</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Micrófono</translation>
<translation id="3277252321222022663">Permitir que os sitios accedan aos sensores (recomendado)</translation>
<translation id="3295602654194328831">Ocultar información</translation>
+<translation id="3328801116991980348">Información do sitio</translation>
<translation id="3333961966071413176">Todos os contactos</translation>
<translation id="3386292677130313581">Pregunta antes de permitir que os sitios coñezan a túa localización (recomendado)</translation>
<translation id="3538390592868664640">Impide que os sitios creen un mapa 3D do que te rodea e fagan un seguimento da posición da cámara</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Permitir que os sitios reproduzan contido protexido</translation>
<translation id="4468959413250150279">Silencia o son dun sitio específico.</translation>
<translation id="4479647676395637221">Pregunta antes de permitir que os sitios utilicen a túa cámara (recomendado)</translation>
+<translation id="4505788138578415521">URL despregado</translation>
<translation id="4534723447064627427">Para permitir que <ph name="APP_NAME" /> acceda ao micrófono, actívao tamén en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalles</translation>
<translation id="4645575059429386691">Xestionado por teus pais</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis}}</translation>
<translation id="913657688200966289">Activa os permisos para <ph name="APP_NAME" /> en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Acceso ao teu micrófono</translation>
<translation id="965817943346481315">Bloquear se o sitio mostra anuncios enganosos ou intrusivos (recomendado)</translation>
<translation id="967624055006145463">Datos almacenados</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
index 7c93e05c8d6..52526ccbe24 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">સાઈટ <ph name="SITE_NAME" /> ઉમેરવામાં આવી</translation>
<translation id="1383876407941801731">શોધો</translation>
<translation id="1384959399684842514">ડાઉનલોડ થોભાવà«àª¯à«àª‚</translation>
+<translation id="1415402041810619267">URL ટૂંકી કરી છે</translation>
<translation id="1431402976894535801">તમે કà«àª¯àª¾àª°à«‡ હાજર છો તે જાણવાથી સાઇટને બà«àª²à«‰àª• કરો</translation>
<translation id="1446450296470737166">MIDI ઉપકરણોના પૂરà«àª£ નિયંતà«àª°àª£àª¨à«€ મંજૂરી આપો</translation>
<translation id="1509960214886564027">ઘણી સાઇટ પરની સà«àªµàª¿àª§àª¾àª“ને કદાચ બંધ કરવામાં આવી શકે</translation>
<translation id="1620510694547887537">કૅમેરો</translation>
-<translation id="1647391597548383849">તમારા કૅમેરાની àªàª•à«àª¸à«‡àª¸</translation>
<translation id="1660204651932907780">સાઇટને અવાજ ચલાવવાની મંજૂરી આપો (સà«àªàª¾àªµ આપેલ)</translation>
<translation id="1677097821151855053">કà«àª•à«€ અને અનà«àª¯ સાઇટ ડેટાનો ઉપયોગ તમને યાદ રાખવા માટે કરવામાં આવે છે, ઉદાહરણ તરીકે, તમને સાઇન ઇન કરવા માટે અથવા જાહેરાતો મનગમતી બનાવવા માટે. બધી સાઇટ માટે કà«àª•à«€ મેનેજ કરવા, <ph name="BEGIN_LINK" />સેટિંગ<ph name="END_LINK" /> જà«àª“.</translation>
<translation id="1688867105868176567">સાઇટનો ડેટા સાફ કરી�</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">સાઈટ URL</translation>
<translation id="2025115093177348061">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> પર પરત ફરવા માટે, ટૅપ કરો</translation>
+<translation id="2054665754582400095">તમારી હાજરી</translation>
<translation id="2079545284768500474">છેલà«àª²à«‹ ફેરફાર રદ કરો</translation>
<translation id="2091887806945687916">ધà«àªµàª¨àª¿</translation>
<translation id="2107397443965016585">સાઇટને સંરકà«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવાની મંજૂરી આપતા પહેલાંં પૂછો (સà«àªàª¾àªµ આપેલ)</translation>
<translation id="2146738493024040262">àªàªŸàªªàªŸ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ખોલો</translation>
<translation id="2148716181193084225">આજે</translation>
<translation id="2182457891543959921">કોઈ સાઇટને તમારી આજà«àª¬àª¾àªœà«àª¨à«‹ 3D નકશો બનાવતા અથવા કૅમેરાની સà«àª¥àª¿àª¤àª¿àª¨à«‡ ટà«àª°à«…ક કરવાની મંજૂરી આપતા પહેલાં પૂછો (સà«àªàª¾àªµ આપીઠછીàª)</translation>
-<translation id="2187243482123994665">વપરાશકરà«àª¤àª¾àª¨à«€ હાજરી</translation>
<translation id="2212565012507486665">કà«àª•à«€àª¨à«‡ મંજૂરી આપો</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> તમારો કૅમેરા àªàª•à«àª¸à«‡àª¸ કરી શકે તે માટે <ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં પણ કૅમેરા ચાલૠકરો.</translation>
<translation id="2241634353105152135">માતà«àª° àªàª• વખત</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}}</translation>
<translation id="2434158240863470628">ડાઉનલોડ પૂરà«àª£ <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">સà«àª¥àª¾àª¨ àªàª•à«àª¸à«‡àª¸</translation>
<translation id="2482878487686419369">નોટિફિકેશનો</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> દà«àªµàª¾àª°àª¾ મેનેજ થયેલ</translation>
<translation id="2498359688066513246">સહાય અને પà«àª°àª¤àª¿àª¸àª¾àª¦</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">માઇકà«àª°à«‹àª«à«‹àª¨</translation>
<translation id="3277252321222022663">સાઇટને સેનà«àª¸àª°àª¨àª¾ àªàª•à«àª¸à«‡àª¸àª¨à«€ મંજૂરી આપો (સà«àªàª¾àªµ આપેલ)</translation>
<translation id="3295602654194328831">માહિતી છà«àªªàª¾àªµà«‹</translation>
+<translation id="3328801116991980348">સાઇટ માહિતી</translation>
<translation id="3333961966071413176">બધા સંપરà«àª•à«‹</translation>
<translation id="3386292677130313581">સાઇટà«àª¸àª¨à«‡ તમારા સà«àª¥àª¾àª¨àª¨à«‡ જાણવાની મંજૂરી આપતાં પહેલાં પૂછો (ભલામણ કરેલ)</translation>
<translation id="3538390592868664640">કોઈ સાઇટને તમારી આજà«àª¬àª¾àªœà«àª¨à«‹ 3D નકશો બનાવવા અથવા કૅમેરાની સà«àª¥àª¿àª¤àª¿àª¨à«‡ ટà«àª°à«…ક કરી શકવા માટે બà«àª²à«‰àª• કરો</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">સાઇટને સંરકà«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવાની મંજૂરી આપો</translation>
<translation id="4468959413250150279">કોઈ àªàª• ચોકà«àª•àª¸ સાઇટ માટે અવાજ બંધ કરો.</translation>
<translation id="4479647676395637221">સાઇટà«àª¸àª¨à«‡ તમારા કૅમેરાના ઉપયોગની મંજૂરી આપતાં પહેલાં પૂછો (ભલામણ કરેલ)</translation>
+<translation id="4505788138578415521">URL મોટી કરી છે</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> તમારà«àª‚ માઇકà«àª°à«‹àª«à«‹àª¨ àªàª•à«àª¸à«‡àª¸ કરી શકે તે માટે <ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં પણ માઇકà«àª°à«‹àª«à«‹àª¨ ચાલૠકરો.</translation>
<translation id="4570913071927164677">વિગતો</translation>
<translation id="4645575059429386691">તમારા માતાપિતા દà«àªµàª¾àª°àª¾ મેનેજ થયેલ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">બà«àª²à«‚ટૂથ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં <ph name="APP_NAME" /> માટે પરવાનગીઓ ચાલૠકરો.</translation>
-<translation id="945632385593298557">તમારા માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«€ àªàª•à«àª¸à«‡àª¸</translation>
<translation id="965817943346481315">જો સાઇટ ઘૃણાસà«àªªàª¦ અથવા ભà«àª°àª¾àª®àª• જાહેરાતો બતાવતી હોય, તો બà«àª²à«‰àª• કરો (ભલામણ કરેલ)</translation>
<translation id="967624055006145463">સà«àªŸà«‹àª° કરેલ ડેટા</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
index 6f48188ef2e..2508414279d 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> साइट जोड़ी गई</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">डाउनलोड रोका गया</translation>
+<translation id="1415402041810619267">यूआरà¤à¤² छोटा हो गया</translation>
<translation id="1431402976894535801">जब कोई साइट यह जानना चाहे कि आप डिवाइस का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कब करते हैं, तो उसे बà¥à¤²à¥‰à¤• करें</translation>
<translation id="1446450296470737166">MIDI डिवाइस के पूरे नियंतà¥à¤°à¤£ की अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="1509960214886564027">शायद कई साइटों पर सà¥à¤µà¤¿à¤§à¤¾à¤à¤‚ ठीक से काम न करें</translation>
<translation id="1620510694547887537">कैमरा</translation>
-<translation id="1647391597548383849">अपना कैमरा à¤à¤•à¥à¤¸à¥‡à¤¸ करें</translation>
<translation id="1660204651932907780">साइटों को आवाज़ चलाने दें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="1677097821151855053">कà¥à¤•à¥€ और अनà¥à¤¯ साइट डेटा का इसà¥à¤¤à¥‡à¤®à¤¾à¤² आपकी जानकारी को याद रखने के लिठकिया जाता है, जैसे कि आपको साइन इन करने देना या आपकी पसंद को धà¥à¤¯à¤¾à¤¨ में रखकर विजà¥à¤žà¤¾à¤ªà¤¨ दिखाना. सभी साइटों से जà¥à¤¡à¤¼à¥€ कà¥à¤•à¥€ पà¥à¤°à¤¬à¤‚धित करने के लिà¤, <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> देखें.</translation>
<translation id="1688867105868176567">'साइट डेटा' हटाà¤à¤‚?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">साइट URL</translation>
<translation id="2025115093177348061">ऑगमेंटेड रिà¤à¤²à¤¿à¤Ÿà¥€ (à¤à¤†à¤°)</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> पर वापस जाने के लिठटैप करें</translation>
+<translation id="2054665754582400095">आपकी मौजूदगी</translation>
<translation id="2079545284768500474">पहले जैसा करें</translation>
<translation id="2091887806945687916">आवाज़</translation>
<translation id="2107397443965016585">साइटों को सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाने देने से पहले पूछें (à¤à¤¸à¤¾ करने का सà¥à¤à¤¾à¤µ दिया जाता है)</translation>
<translation id="2146738493024040262">इंसà¥à¤Ÿà¥ˆà¤‚ट à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ खोलें</translation>
<translation id="2148716181193084225">आज</translation>
<translation id="2182457891543959921">किसी साइट को आपके आस-पास की जगह का 3D मैप बनाने या कैमरे की सà¥à¤¥à¤¿à¤¤à¤¿ टà¥à¤°à¥ˆà¤• करने की अनà¥à¤®à¤¤à¤¿ देने से पहले पूछें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
-<translation id="2187243482123994665">उपयोगकरà¥à¤¤à¤¾ की मौजूदगी</translation>
<translation id="2212565012507486665">कà¥à¤•à¥€ की अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> को कैमरे का à¤à¤•à¥à¤¸à¥‡à¤¸ देने के लिà¤, <ph name="BEGIN_LINK" />Android की सेटिंग<ph name="END_LINK" /> में जाकर भी कैमरा चालू करें.</translation>
<translation id="2241634353105152135">बस à¤à¤• बार</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¤à¤®à¤¬à¥€</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾ को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾ को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾à¤“ं को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}}</translation>
<translation id="2434158240863470628">डाउनलोड हो गया <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">जगह की जानकारी का à¤à¤•à¥â€à¤¸à¥‡à¤¸ दें</translation>
<translation id="2482878487686419369">सूचनाà¤à¤‚</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> पà¥à¤°à¤¬à¤‚धित करता है</translation>
<translation id="2498359688066513246">सहायता और फ़ीडबैक</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटों को सेंसर à¤à¤•à¥à¤¸à¥‡à¤¸ करने दें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="3295602654194328831">जानकारी छिपाà¤à¤‚</translation>
+<translation id="3328801116991980348">साइट जानकारी</translation>
<translation id="3333961966071413176">सभी संपरà¥à¤•</translation>
<translation id="3386292677130313581">साइटों को अपनी जगह की जानकारी देने से पहले अनà¥à¤®à¤¤à¤¿ लेना ज़रूरी बनाà¤à¤‚ (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="3538390592868664640">साइटों को अपने आस-पास की जगह का 3D मैप बनाने या कैमरे की सà¥à¤¥à¤¿à¤¤à¤¿ टà¥à¤°à¥ˆà¤• करने से रोकें</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">साइटों को सभी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाने दें</translation>
<translation id="4468959413250150279">किसी खास साइट के लिठआवाज़ बंद करें.</translation>
<translation id="4479647676395637221">साइटों को अपने कैमरे का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने देने से पहले अनà¥à¤®à¤¤à¤¿ लेना ज़रूरी बनाà¤à¤‚ (सà¥à¤à¤¾à¤¯à¤¾ गया )</translation>
+<translation id="4505788138578415521">यूआरà¤à¤² बड़ा हो गया</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> को माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ का à¤à¤•à¥à¤¸à¥‡à¤¸ देने के लिà¤, <ph name="BEGIN_LINK" />Android की सेटिंग<ph name="END_LINK" /> में जाकर भी माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ चालू करें.</translation>
<translation id="4570913071927164677">विवरण</translation>
<translation id="4645575059429386691">आपके अभिभावक दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¬à¤‚धित</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">बà¥à¤²à¥‚टूथ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾à¤à¤‚}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android की सेटिंग<ph name="END_LINK" /> में जाकर, <ph name="APP_NAME" /> के लिठअनà¥à¤®à¤¤à¤¿à¤¯à¤¾à¤‚ चालू करें.</translation>
-<translation id="945632385593298557">अपना माइकà¥à¤°à¥‹à¥žà¥‹à¤¨ à¤à¤•à¥à¤¸à¥‡à¤¸ करें</translation>
<translation id="965817943346481315">अगर साइट तंग करने वाले या गà¥à¤®à¤°à¤¾à¤¹ करने वाले विजà¥à¤žà¤¾à¤ªà¤¨ दिखाई देते हैं, तो उनà¥à¤¹à¥‡à¤‚ बà¥à¤²à¥‰à¤• करें (सà¥à¤à¤¾à¤µ)</translation>
<translation id="967624055006145463">डेटा संगà¥à¤°à¤¹à¤¿à¤¤ किया गया</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
index e56808269b4..41d35e52399 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Dodana je web-lokacija <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Traži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1415402041810619267">URL je skraćen</translation>
<translation id="1431402976894535801">Onemogućivanje web-lokacijama da znaju kad ste prisutni</translation>
<translation id="1446450296470737166">Omogući potpuni nadzor za MIDI</translation>
<translation id="1509960214886564027">ZnaÄajke na mnogim web-lokacijama mogu prestati funkcionirati</translation>
<translation id="1620510694547887537">Fotoaparat</translation>
-<translation id="1647391597548383849">Pristup fotoaparatu</translation>
<translation id="1660204651932907780">Web-lokacije mogu reproducirati zvuk (preporuÄeno)</translation>
<translation id="1677097821151855053">KolaÄići i drugi podaci web-lokacije koriste se kako bi vas web-lokacija zapamtila, na primjer kako bi vas prijavila na raÄun ili vam prilagodila oglase. Da biste upravljali kolaÄićima za sve web-lokacije, idite na <ph name="BEGIN_LINK" />Postavke<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Želite li izbrisati podatke web-lokacije?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL web-lokacije</translation>
<translation id="2025115093177348061">Proširena stvarnost</translation>
<translation id="2030769033451695672">Dodirnite da biste se vratili na <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Vaša prisutnost</translation>
<translation id="2079545284768500474">Poništi</translation>
<translation id="2091887806945687916">Zvuk</translation>
<translation id="2107397443965016585">Web-lokacije moraju tražiti dopuÅ¡tenje za reprodukciju zaÅ¡tićenog sadržaja (preporuÄeno)</translation>
<translation id="2146738493024040262">Otvori instant aplikaciju</translation>
<translation id="2148716181193084225">Danas</translation>
<translation id="2182457891543959921">Prikaži upit prije omogućivanja web-lokacijama da izraÄ‘uju 3D kartu vaÅ¡eg okruženja i prate položaj kamere (preporuÄeno)</translation>
-<translation id="2187243482123994665">Korisnikova prisutnost</translation>
<translation id="2212565012507486665">Dopusti kolaÄiće</translation>
<translation id="2228071138934252756">Da bi aplikacija <ph name="APP_NAME" /> mogla pristupiti vaÅ¡oj kameri, ukljuÄite kameru i u <ph name="BEGIN_LINK" />Androidovim postavkama<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo jednom</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je dovršeno: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Pristup lokaciji</translation>
<translation id="2482878487686419369">Obavijesti</translation>
<translation id="2490684707762498678">Upravlja: <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Pomoć i povratne informacije</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">DopuÅ¡tanje pristupa senzorima za web-lokacije (preporuÄeno)</translation>
<translation id="3295602654194328831">Sakrij informacije</translation>
+<translation id="3328801116991980348">Informacije o web-lokaciji</translation>
<translation id="3333961966071413176">Svi kontakti</translation>
<translation id="3386292677130313581">Web-lokacije moraju tražiti dopuÅ¡tenje za pristup lokaciji (preporuÄeno)</translation>
<translation id="3538390592868664640">Blokirajte web-lokacije da izrađuju 3D kartu vašeg okruženja ili prate položaj kamere</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Web-lokacijama je dopuštena reprodukcija zaštićenog sadržaja</translation>
<translation id="4468959413250150279">IskljuÄivanje zvuka za odreÄ‘enu web-lokaciju.</translation>
<translation id="4479647676395637221">Web-lokacije moraju tražiti dopuÅ¡tenje za pristup kameri (preporuÄeno)</translation>
+<translation id="4505788138578415521">URL je proširen</translation>
<translation id="4534723447064627427">Da bi aplikacija <ph name="APP_NAME" /> mogla pristupiti vaÅ¡em mikrofonu, ukljuÄite mikrofon i u <ph name="BEGIN_LINK" />Androidovim postavkama<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Pojedinosti</translation>
<translation id="4645575059429386691">Upravlja tvoj roditelj</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">UkljuÄite dopuÅ¡tenja za aplikaciju <ph name="APP_NAME" /> u <ph name="BEGIN_LINK" />Androidovim postavkama<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Pristup mikrofonu</translation>
<translation id="965817943346481315">Blokiraj ako web-lokacija prikazuje ometajuće ili obmanjujuće oglase (preporuÄeno)</translation>
<translation id="967624055006145463">Pohranjeni podaci</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
index a08ed712084..535f6554a00 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">A(z) <ph name="SITE_NAME" /> webhely hozzáadva</translation>
<translation id="1383876407941801731">Keresés</translation>
<translation id="1384959399684842514">A letöltés szünetel</translation>
+<translation id="1415402041810619267">URL csonkolva</translation>
<translation id="1431402976894535801">A webhelyek nem kaphatnak információt arról, hogy Ön mikor van jelen</translation>
<translation id="1446450296470737166">MIDI-eszközök teljes vezérlése</translation>
<translation id="1509960214886564027">Számos webhelyen nem működnek a funkciók</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Hozzáférés a fényképezőgéphez</translation>
<translation id="1660204651932907780">A webhelyek lejátszhatnak hangokat (ajánlott)</translation>
<translation id="1677097821151855053">A cookie-k és az egyéb webhelyadatok arra szolgálnak, hogy a webhelyek emlékezzenek Önre, és így például bejelentkeztetik, vagy személyre szabják a hirdetéseket. A <ph name="BEGIN_LINK" />Beállításokban<ph name="END_LINK" /> kezelheti a webhelyek cookie-jait.</translation>
<translation id="1688867105868176567">Törli a webhelyadatokat?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Webhely URL-je</translation>
<translation id="2025115093177348061">Kiterjesztett valóság</translation>
<translation id="2030769033451695672">Koppintson, hogy visszatérjen ide: <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Felhasználói jelenlét</translation>
<translation id="2079545284768500474">Visszavonás</translation>
<translation id="2091887806945687916">Hang</translation>
<translation id="2107397443965016585">Kérdezzen rá, mielőtt engedélyezné a webhelyek számára védett tartalmak lejátszását (ajánlott)</translation>
<translation id="2146738493024040262">Azonnali alkalmazás megnyitása</translation>
<translation id="2148716181193084225">Ma</translation>
<translation id="2182457891543959921">Kérdezzen rá, mielőtt engedélyezi a webhelyek számára 3D-s térkép létrehozását az Ön környezetéről, valamint a kamera pozíciójának követését (ajánlott)</translation>
-<translation id="2187243482123994665">Felhasználói jelenlét</translation>
<translation id="2212565012507486665">Cookie-k engedélyezése</translation>
<translation id="2228071138934252756">Ahhoz, hogy a(z) <ph name="APP_NAME" /> hozzáférhessen a kamerához, a kamerát az <ph name="BEGIN_LINK" />Android-beállítások<ph name="END_LINK" /> között is be kell kapcsolni.</translation>
<translation id="2241634353105152135">Csak egyszer</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}}</translation>
<translation id="2434158240863470628">Letöltés befejezve <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Helyhozzáférés</translation>
<translation id="2482878487686419369">Értesítések</translation>
<translation id="2490684707762498678">Kezelő: <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Súgó és visszajelzés</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Az érzékelőkhöz való hozzáférés engedélyezése a webhelyek számára (ajánlott)</translation>
<translation id="3295602654194328831">Információk elrejtése…</translation>
+<translation id="3328801116991980348">Webhelyadatok</translation>
<translation id="3333961966071413176">Összes névjegy</translation>
<translation id="3386292677130313581">Kérdezzen rá, mielőtt engedélyezné a webhelyek számára a tartózkodási helyhez való hozzáférést (ajánlott)</translation>
<translation id="3538390592868664640">Az Ön környezetéről készített 3D-s térkép létrehozásának, valamint a kamerapozíció követésének letiltása a webhelyek számára</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Védett tartalmak lejátszásának engedélyezése a webhelyek számára</translation>
<translation id="4468959413250150279">Egy adott webhely hangjának némítása.</translation>
<translation id="4479647676395637221">Kérdezzen rá, mielőtt engedélyezné a webhelyek számára a kamera használatát (ajánlott)</translation>
+<translation id="4505788138578415521">URL kibontva</translation>
<translation id="4534723447064627427">Ahhoz, hogy a(z) <ph name="APP_NAME" /> hozzáférhessen a mikrofonhoz, a mikrofont az <ph name="BEGIN_LINK" />Android-beállítások<ph name="END_LINK" /> között is be kell kapcsolni.</translation>
<translation id="4570913071927164677">Részletek</translation>
<translation id="4645575059429386691">A szülő kezeli</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">A(z) <ph name="APP_NAME" /> alkalmazásra vonatkozó engedélyeket az <ph name="BEGIN_LINK" />Android-beállítások<ph name="END_LINK" /> között lehet aktiválni.</translation>
-<translation id="945632385593298557">Hozzáférés a mikrofonhoz</translation>
<translation id="965817943346481315">Letiltás, ha a webhely tolakodó vagy félrevezető hirdetéseket jelenít meg (ajánlott)</translation>
<translation id="967624055006145463">Tárolt adatok</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
index 651d0b337a6..3d63c3b59f7 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¾Õ¥Õ¬ Õ§</translation>
<translation id="1383876407941801731">ÕˆÖ€Õ¸Õ¶Õ¸Ö‚Õ´</translation>
<translation id="1384959399684842514">Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¨ Õ¤Õ¡Õ¤Õ¡Ö€Õ¥ÖÕ¾Õ¥Õ¬ Õ§</translation>
+<translation id="1415402041810619267">URL-Õ¨ Õ¯Ö€Õ³Õ¡Õ¿Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="1431402976894535801">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ±Õ¥Ö€ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ¡Õ½Õ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ«Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="1446450296470737166">ÕÖ€Õ¡Õ´Õ¡Õ¤Ö€Õ¥Õ¬ Õ¡Õ´Õ¢Õ¸Õ²Õ»Õ¡Õ¯Õ¡Õ¶ Õ°Õ½Õ¯Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ MIDI Õ½Õ¡Ö€Ö„Õ¥Ö€Õ« Õ¶Õ¯Õ¡Õ¿Õ´Õ¡Õ´Õ¢</translation>
<translation id="1509960214886564027">Õ‡Õ¡Õ¿ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´ Õ£Õ¸Ö€Õ®Õ¡Õ¼Õ¸Ö‚ÕµÕ©Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¹Õ¡Õ·Õ­Õ¡Õ¿Õ¥Õ¬Ö‰</translation>
<translation id="1620510694547887537">ÕÕ¥Õ½Õ¡Õ­ÖÕ«Õ¯</translation>
-<translation id="1647391597548383849">ÕÕ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´</translation>
<translation id="1660204651932907780">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¿Õ¡Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ Õ±Õ¡ÕµÕ¶ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="1677097821151855053">Õ”Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¯Õ¡ÕµÖ„Õ« Õ¡ÕµÕ¬ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Ö‚Õ´ Õ¥Õ¶ Õ±Õ¥Õ¦ Õ°Õ«Õ·Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰ Ô´Õ¡ Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ«, Ö…Ö€Õ«Õ¶Õ¡Õ¯, Õ¤Õ¸Ö‚Ö„ Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Õ°Õ¡Õ·Õ«Õ¾ Õ´Õ¿Õ¶Õ¥Õ¬ Õ¯Õ¡Õ´ Õ±Õ¥Õ¦ Õ¡Õ¶Õ°Õ¡Õ¿Õ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¾Õ¡Õ® Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ«Ö‰ Ô²Õ¸Õ¬Õ¸Ö€ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ <ph name="BEGIN_LINK" />Õ”Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€<ph name="END_LINK" /> Õ¢Õ¡ÕªÕ¶Õ¸Ö‚Õ´Ö‰</translation>
<translation id="1688867105868176567">Õ‹Õ¶Õ»Õ¥ÕžÕ¬ Õ¯Õ¡ÕµÖ„Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Ô¿Õ¡ÕµÖ„Õ« URL</translation>
<translation id="2025115093177348061">Ô¼Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="2030769033451695672">Õ€ÕºÕ¥Ö„Õ <ph name="URL_OF_THE_CURRENT_TAB" /> Õ¾Õ¥Ö€Õ¡Õ¤Õ¡Õ¼Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
+<translation id="2054665754582400095">ÕÕ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ±Õ¥Ö€ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="2079545284768500474">Õ€Õ¥Õ¿Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="2091887806945687916">ÕÕ¡ÕµÕ¶</translation>
<translation id="2107397443965016585">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="2146738493024040262">Ô²Õ¡ÖÕ¥Õ¬ Õ¡Õ¯Õ¶Õ©Õ¡Ö€Õ©Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="2148716181193084225">Ô±ÕµÕ½Ö…Ö€</translation>
<translation id="2182457891543959921">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ­Õ¶Õ¤Ö€Õ¥Õ¬Õ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ·Ö€Õ»Õ¡Õ¯Õ¡ÕµÖ„Õ« Õ¥Õ¼Õ¡Õ¹Õ¡Öƒ Ö„Õ¡Ö€Õ¿Õ¥Õ¦Õ¶ Õ¸Ö‚ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬Õ¸Ö‚ Õ±Õ¥Ö€ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Õ¤Õ«Ö€Ö„Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
-<translation id="2187243482123994665">Õ•Õ£Õ¿Õ¡Õ¿Õ«Ö€Õ¸Õ» Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="2212565012507486665">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨</translation>
<translation id="2228071138934252756">ÕˆÖ€ÕºÕ¥Õ½Õ¦Õ« Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Õ¼Õ¶Õ¡ <ph name="APP_NAME" />-Õ«Õ¶, Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ¶ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="2241634353105152135">Õ„Õ«Õ¡ÕµÕ¶ Õ¡ÕµÕ½ Õ¡Õ¶Õ£Õ¡Õ´</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Õ„Ô²</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}one{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}other{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}}</translation>
<translation id="2434158240863470628">Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶ Õ¡Õ¾Õ¡Ö€Õ¿Õ¾Õ¡Õ® Õ§Õ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Ô»Õ´ Õ¿Õ¥Õ²Õ¡Õ¯Õ¡ÕµÕ¸Ö‚Õ´Õ¨</translation>
<translation id="2482878487686419369">Ô¾Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
<translation id="2490684707762498678">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Ö‚Õ´ Õ§ <ph name="APP_NAME" /> Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
<translation id="2498359688066513246">Õ•Õ£Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Ö‡ Õ°Õ¥Õ¿Õ¡Õ¤Õ¡Ö€Õ± Õ¯Õ¡Õº</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Ô½Õ¸Õ½Õ¡ÖƒÕ¸Õ²</translation>
<translation id="3277252321222022663">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¿Õ¡Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="3295602654194328831">Ô¹Õ¡Ö„ÖÕ¶Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
+<translation id="3328801116991980348">ÕÕ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€ Õ¯Õ¡ÕµÖ„Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="3333961966071413176">Ô²Õ¸Õ¬Õ¸Ö€ Õ¯Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3386292677130313581">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="3538390592868664640">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬ Õ·Ö€Õ»Õ¡Õ¯Õ¡ÕµÖ„Õ« Õ¥Õ¼Õ¡Õ¹Õ¡Öƒ Ö„Õ¡Ö€Õ¿Õ¥Õ¦Õ¨ Ö‡ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Õ¤Õ«Ö€Ö„Õ¨</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="4468959413250150279">Ô±Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ Õ±Õ¡ÕµÕ¶Õ¨ Õ¡Õ¼Õ¡Õ¶Õ±Õ«Õ¶ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="4479647676395637221">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="4505788138578415521">URL-Õ¨ Õ®Õ¡Õ¾Õ¡Õ¬Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="4534723447064627427">ÕˆÖ€ÕºÕ¥Õ½Õ¦Õ« Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Õ¼Õ¶Õ¡ <ph name="APP_NAME" />-Õ«Õ¶, Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ¶ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="4570913071927164677">Õ„Õ¡Õ¶Ö€Õ¡Õ´Õ¡Õ½Õ¶Õ¥Ö€</translation>
<translation id="4645575059429386691">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ®Õ¶Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}one{«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}other{«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» ու ևս <ph name="NUM_MORE" /> թույլտվություն}}</translation>
<translation id="913657688200966289">Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ <ph name="APP_NAME" />-Õ« Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
-<translation id="945632385593298557">Ô½Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´</translation>
<translation id="965817943346481315">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬, Õ¥Õ©Õ¥ Õ¯Õ¡ÕµÖ„Õ¨ Õ°Õ¸Õ£Õ¶Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ Õ§ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="967624055006145463">ÕŠÕ¡Õ°Õ¾Õ¡Õ® Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
index 239a138dc93..59645365194 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Situs <ph name="SITE_NAME" /> ditambahkan</translation>
<translation id="1383876407941801731">Telusuri</translation>
<translation id="1384959399684842514">Download dijeda</translation>
+<translation id="1415402041810619267">URL dipotong</translation>
<translation id="1431402976894535801">Blokir situs agar tidak mengetahui status kehadiran Anda</translation>
<translation id="1446450296470737166">Izinkan kontrol penuh perangkat MIDI</translation>
<translation id="1509960214886564027">Fitur di banyak situs mungkin error</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Mengakses kamera Anda</translation>
<translation id="1660204651932907780">Mengizinkan situs memutar suara (direkomendasikan)</translation>
<translation id="1677097821151855053">Cookie dan data situs lainnya digunakan untuk mengingat Anda, misalnya untuk login atau personalisasi iklan. Untuk mengelola cookie semua situs, lihat <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Hapus data situs?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL situs</translation>
<translation id="2025115093177348061">Augmented reality</translation>
<translation id="2030769033451695672">Ketuk untuk kembali ke <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Kehadiran Anda</translation>
<translation id="2079545284768500474">Urungkan</translation>
<translation id="2091887806945687916">Suara</translation>
<translation id="2107397443965016585">Tanyakan sebelum mengizinkan situs memutar konten yang dilindungi (direkomendasikan)</translation>
<translation id="2146738493024040262">Buka Aplikasi Instan</translation>
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2182457891543959921">Tanyakan sebelum mengizinkan situs membuat peta 3D untuk area di sekeliling Anda atau melacak posisi kamera (direkomendasikan)</translation>
-<translation id="2187243482123994665">Kehadiran pengguna</translation>
<translation id="2212565012507486665">Izinkan cookie</translation>
<translation id="2228071138934252756">Untuk mengizinkan <ph name="APP_NAME" /> mengakses kamera Anda, aktifkan juga kamera di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Sekali ini saja</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}}</translation>
<translation id="2434158240863470628">Download selesai <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Akses lokasi</translation>
<translation id="2482878487686419369">Notifikasi</translation>
<translation id="2490684707762498678">Dikelola oleh <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Bantuan &amp; masukan</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Mengizinkan situs untuk mengakses sensor (disarankan)</translation>
<translation id="3295602654194328831">Sembunyikan Info</translation>
+<translation id="3328801116991980348">Informasi situs</translation>
<translation id="3333961966071413176">Semua kontak</translation>
<translation id="3386292677130313581">Minta izin sebelum memungkinkan situs mengetahui lokasi Anda (disarankan)</translation>
<translation id="3538390592868664640">Blokir situs agar tidak membuat peta 3D untuk area di sekeliling Anda atau melacak posisi kamera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Izinkan situs memutar konten yang dilindungi</translation>
<translation id="4468959413250150279">Mematikan suara untuk situs tertentu.</translation>
<translation id="4479647676395637221">Minta izin terlebih dahulu sebelum memungkinkan situs menggunakan kamera Anda (disarankan)</translation>
+<translation id="4505788138578415521">URL ditampilkan penuh</translation>
<translation id="4534723447064627427">Untuk mengizinkan <ph name="APP_NAME" /> mengakses mikrofon, aktifkan juga mikrofon di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detail</translation>
<translation id="4645575059429386691">Dikelola oleh orang tua Anda</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya}}</translation>
<translation id="913657688200966289">Aktifkan izin untuk <ph name="APP_NAME" /> di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Akses mikrofon Anda</translation>
<translation id="965817943346481315">Blokir jika situs menampilkan iklan yang mengganggu atau menyesatkan (direkomendasikan)</translation>
<translation id="967624055006145463">Data disimpan</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
index f597aa071d3..442d6285552 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Vefsvæðinu <ph name="SITE_NAME" /> bætt við</translation>
<translation id="1383876407941801731">Leita</translation>
<translation id="1384959399684842514">Gert var hlé á niðurhali</translation>
+<translation id="1415402041810619267">Stytt vefslóð</translation>
<translation id="1431402976894535801">Lokar fyrir það að vefsvæði viti hvenær þú ert á staðnum</translation>
<translation id="1446450296470737166">Leyfa ótakmarkaða stjórn á MIDI-tækjum</translation>
<translation id="1509960214886564027">Eiginleikar gætu bilað á mörgum vefsvæðum</translation>
<translation id="1620510694547887537">Myndavél</translation>
-<translation id="1647391597548383849">Aðgangur að myndavélinni</translation>
<translation id="1660204651932907780">Leyfa vefsvæðum að spila hljóð (mælt með)</translation>
<translation id="1677097821151855053">Fótspor og önnur gögn af síðunni eru notuð til að muna eftir þér, t.d. til að skrá þig inn eða sérsníða auglýsingar. Upplýsingar um stjórnun fótspora fyrir öll vefsvæði eru í <ph name="BEGIN_LINK" />Stillingar<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Viltu hreinsa vefsvæðagögn?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Slóð vefsvæðis</translation>
<translation id="2025115093177348061">Aukinn veruleiki</translation>
<translation id="2030769033451695672">Ãttu til að fara aftur á <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Viðvera þín</translation>
<translation id="2079545284768500474">Afturkalla</translation>
<translation id="2091887806945687916">Hljóð</translation>
<translation id="2107397443965016585">Spyrja áður en vefsvæði fá leyfi til að spila varið efni (ráðlagt)</translation>
<translation id="2146738493024040262">Opna skyndiforrit</translation>
<translation id="2148716181193084225">Ã dag</translation>
<translation id="2182457891543959921">Spyrja áður en vefsvæðum er leyft að búa til þrívíddarkort af umhverfinu eða rekja staðsetningu myndavélarinnar (ráðlagt)</translation>
-<translation id="2187243482123994665">Viðvera notanda</translation>
<translation id="2212565012507486665">Leyfa fótspor</translation>
<translation id="2228071138934252756">Til að veita <ph name="APP_NAME" /> aðgang að myndavélinni þarftu einnig að kveikja á henni í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bara einu sinni</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}one{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}other{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}}</translation>
<translation id="2434158240863470628">Niðurhali lokið <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Aðgangur að staðsetningu</translation>
<translation id="2482878487686419369">Tilkynningar</translation>
<translation id="2490684707762498678">Stýrt af <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hjálp og ábendingar</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Hljóðnemi</translation>
<translation id="3277252321222022663">Leyfa vefsvæðum að fá aðgang að skynjurum (ráðlagt)</translation>
<translation id="3295602654194328831">Fela upplýsingar</translation>
+<translation id="3328801116991980348">Upplýsingar um vefsvæði</translation>
<translation id="3333961966071413176">Allir tengiliðir</translation>
<translation id="3386292677130313581">Spyrja áður en vefsvæðum er veitt heimild til að sjá staðsetningu þína (ráðlagt)</translation>
<translation id="3538390592868664640">Komdu í veg fyrir að vefsvæði búi til þrívíddarkort af umhverfinu eða reki staðsetningu myndavélarinnar</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Leyfa vefsvæðum að spila varið efni</translation>
<translation id="4468959413250150279">Slökkva á hljóði á tilteknu vefsvæði.</translation>
<translation id="4479647676395637221">Spyrja áður en vefsvæðum er veitt heimild til að nota myndavélina þína (ráðlagt)</translation>
+<translation id="4505788138578415521">Öll vefslóðin</translation>
<translation id="4534723447064627427">Til að veita <ph name="APP_NAME" /> aðgang að hljóðnemanum þarftu einnig að kveikja á honum í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Nánar</translation>
<translation id="4645575059429386691">Stjórnað af foreldri þínu</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót}one{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót}other{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót}}</translation>
<translation id="913657688200966289">Kveiktu á heimildum fyrir <ph name="APP_NAME" /> í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Aðgangur að hljóðnemanum</translation>
<translation id="965817943346481315">Loka fyrir ef vefsvæði sýnir ágengar eða villandi auglýsingar (ráðlagt)</translation>
<translation id="967624055006145463">Vistuð gögn</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
index fe3fac01fc1..ef848bc83e3 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Sito <ph name="SITE_NAME" /> aggiunto</translation>
<translation id="1383876407941801731">Cerca</translation>
<translation id="1384959399684842514">Download sospeso</translation>
+<translation id="1415402041810619267">URL troncato</translation>
<translation id="1431402976894535801">Impedisci ai siti di sapere quando sei presente</translation>
<translation id="1446450296470737166">Controllo completo dispos. MIDI</translation>
<translation id="1509960214886564027">Le funzionalità su molti siti potrebbero non essere disponibili</translation>
-<translation id="1620510694547887537">Videocamera</translation>
-<translation id="1647391597548383849">Accesso alla fotocamera</translation>
+<translation id="1620510694547887537">Fotocamera</translation>
<translation id="1660204651932907780">Consenti ai siti di riprodurre l'audio (opzione consigliata)</translation>
<translation id="1677097821151855053">I cookie e altri dati dei siti vengono utilizzati per ricordare attività e informazioni dell'utente, ad esempio per l'esecuzione dell'accesso o per personalizzare gli annunci. Per gestire i cookie per tutti i siti, consulta le <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Cancellare i dati del sito?</translation>
@@ -29,8 +29,8 @@
<translation id="1717218214683051432">Sensori di movimento</translation>
<translation id="1743802530341753419">Chiedi prima di consentire ai siti di connettersi a un dispositivo (opzione consigliata)</translation>
<translation id="1779089405699405702">Decoder di immagini</translation>
-<translation id="1818308510395330587">Per consentire all'app <ph name="APP_NAME" /> di utilizzare l'AR, attiva la fotocamera anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
-<translation id="1887786770086287077">L'accesso alla posizione è disattivato per questo dispositivo. Attivalo nelle <ph name="BEGIN_LINK" /> Impostazioni Android <ph name="END_LINK" />.</translation>
+<translation id="1818308510395330587">Per consentire all'app <ph name="APP_NAME" /> di utilizzare la realtà aumentata, attiva la fotocamera anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
+<translation id="1887786770086287077">L'accesso alla posizione è disattivato per questo dispositivo. Attivalo nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="1919345977826869612">Annunci</translation>
<translation id="1919950603503897840">Seleziona contatti</translation>
<translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> di <ph name="FILE_SIZE_WITH_UNITS" /></translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL sito</translation>
<translation id="2025115093177348061">Realtà aumentata</translation>
<translation id="2030769033451695672">Tocca per tornare a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">La tua presenza</translation>
<translation id="2079545284768500474">Annulla</translation>
<translation id="2091887806945687916">Audio</translation>
<translation id="2107397443965016585">Chiedi prima di consentire ai siti di riprodurre contenuti protetti (opzione consigliata)</translation>
<translation id="2146738493024040262">Apri l'app istantanea</translation>
<translation id="2148716181193084225">Oggi</translation>
<translation id="2182457891543959921">Chiedi conferma prima di consentire ai siti di creare una mappa 3D dell'ambiente circostante o di monitorare la posizione della fotocamera (opzione consigliata)</translation>
-<translation id="2187243482123994665">Presenza dell'utente</translation>
<translation id="2212565012507486665">Consenti cookie</translation>
<translation id="2228071138934252756">Per consentire all'app <ph name="APP_NAME" /> di accedere alla fotocamera, attiva la fotocamera anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo una volta</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Download completato: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Accesso alla posizione</translation>
<translation id="2482878487686419369">Notifiche</translation>
<translation id="2490684707762498678">Gestite da <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Guida e feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microfono</translation>
<translation id="3277252321222022663">Consenti ai siti di accedere ai sensori (opzione consigliata)</translation>
<translation id="3295602654194328831">Nascondi informazioni</translation>
+<translation id="3328801116991980348">Informazioni sito</translation>
<translation id="3333961966071413176">Tutti i contatti</translation>
<translation id="3386292677130313581">Chiedi conferma prima di consentire ai siti di conoscere la tua posizione (opzione consigliata)</translation>
<translation id="3538390592868664640">Impedisci ai siti di creare una mappa 3D dell'ambiente circostante o di monitorare la posizione della fotocamera</translation>
@@ -113,7 +113,7 @@
<translation id="4200726100658658164">Apri Impostazioni di geolocalizzazione</translation>
<translation id="4226663524361240545">Le notifiche possono far vibrare il dispositivo</translation>
<translation id="4259722352634471385">Navigazione bloccata: <ph name="URL" /></translation>
-<translation id="4278390842282768270">Consentito</translation>
+<translation id="4278390842282768270">Consenti</translation>
<translation id="429312253194641664">Un sito sta riproducendo contenuti multimediali</translation>
<translation id="42981349822642051">Espandi</translation>
<translation id="4336434711095810371">Cancella tutti i dati</translation>
@@ -121,7 +121,8 @@
<translation id="4434045419905280838">Popup e reindirizzamenti</translation>
<translation id="445467742685312942">Consenti ai siti di riprodurre contenuti protetti</translation>
<translation id="4468959413250150279">Disattiva l'audio per un sito specifico.</translation>
-<translation id="4479647676395637221">Chiedi conferma prima di consentire ai siti di utilizzare la videocamera (opzione consigliata)</translation>
+<translation id="4479647676395637221">Chiedi conferma prima di consentire ai siti di utilizzare la fotocamera (opzione consigliata)</translation>
+<translation id="4505788138578415521">URL espanso</translation>
<translation id="4534723447064627427">Per consentire all'app <ph name="APP_NAME" /> di accedere al tuo microfono, devi attivare il microfono anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Dettagli</translation>
<translation id="4645575059429386691">Gestito da un genitore</translation>
@@ -129,7 +130,7 @@
<translation id="4708011789095599544">Vuoi cancellare i cookie e altri dati del sito per questo sito web?</translation>
<translation id="4751476147751820511">Sensori di movimento o della luce</translation>
<translation id="4883854917563148705">Le impostazioni gestite non possono essere reimpostate</translation>
-<translation id="4887024562049524730">Chiedi conferma prima di consentire ai siti di usare i dati e dispositivi per realtà virtuale (opzione consigliata)</translation>
+<translation id="4887024562049524730">Chiedi conferma prima di consentire ai siti di usare i dati e i dispositivi della realtà virtuale (opzione consigliata)</translation>
<translation id="4962975101802056554">Revoca tutte le autorizzazioni per il dispositivo</translation>
<translation id="497421865427891073">Avanti</translation>
<translation id="4994033804516042629">Nessun contatto trovato</translation>
@@ -161,14 +162,14 @@
<translation id="5556459405103347317">Ricarica</translation>
<translation id="5596627076506792578">Altre opzioni</translation>
<translation id="5649053991847567735">Download automatici</translation>
-<translation id="5677928146339483299">Bloccato</translation>
+<translation id="5677928146339483299">Blocca</translation>
<translation id="5689516760719285838">Posizione</translation>
<translation id="5690795753582697420">La fotocamera è disattivata nelle impostazioni di Android</translation>
<translation id="5710871682236653961">Chiedi prima di consentire ai siti di inviare e ricevere informazioni quando tocchi i dispositivi NFC (opzione consigliata)</translation>
<translation id="5719847187258001597">Verranno cancellati tutti i dati e i cookie memorizzati dal sito <ph name="ORIGIN" /> o dalla relativa app nella schermata Home.</translation>
<translation id="5771720122942595109">Autorizzazione <ph name="PERMISSION_1" /> bloccata</translation>
<translation id="5804241973901381774">Autorizzazioni</translation>
-<translation id="5860033963881614850">OFF</translation>
+<translation id="5860033963881614850">Off</translation>
<translation id="5876056640971328065">Metti in pausa il video</translation>
<translation id="5916664084637901428">On</translation>
<translation id="5922853908706496913">Condivisione dello schermo</translation>
@@ -192,7 +193,7 @@
<translation id="6388207532828177975">Cancella e reimposta</translation>
<translation id="6398765197997659313">Esci da schermo intero</translation>
<translation id="6423924377271166037">Cancella cookie</translation>
-<translation id="6439114592976064011">Impedisci ai siti di usare i dati e dispositivi per realtà virtuale</translation>
+<translation id="6439114592976064011">Impedisci ai siti di usare i dati e dispositivi della realtà virtuale</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6527303717912515753">Condividi</translation>
<translation id="6545864417968258051">Scansione Bluetooth</translation>
@@ -206,7 +207,7 @@
<translation id="6697925417670533197">Download attivi</translation>
<translation id="6746124502594467657">Sposta giù</translation>
<translation id="6766622839693428701">Fai scorrere verso il basso per chiudere.</translation>
-<translation id="6790428901817661496">Play</translation>
+<translation id="6790428901817661496">Riproduci</translation>
<translation id="6818926723028410516">Seleziona elementi</translation>
<translation id="6864395892908308021">Questo dispositivo non può leggere la tecnologia NFC</translation>
<translation id="6910211073230771657">Eliminato</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Attiva le autorizzazioni per l'app <ph name="APP_NAME" /> nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Accesso al microfono</translation>
<translation id="965817943346481315">Blocca se il sito mostra annunci invasivi o fuorvianti (consigliato)</translation>
<translation id="967624055006145463">Dati memorizzati</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
index eec93e01ff8..6f56b320d90 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">×”×תר <ph name="SITE_NAME" /> נוסף</translation>
<translation id="1383876407941801731">חיפוש</translation>
<translation id="1384959399684842514">ההורדה הושהתה</translation>
+<translation id="1415402041810619267">â€×›×ª×•×‘ת ×”-URL קוצרה</translation>
<translation id="1431402976894535801">××ª×¨×™× ×œ× ×™×•×›×œ×• לדעת על זמני הנוכחות שלך</translation>
<translation id="1446450296470737166">â€×”תרת שליטה מל××” על מכשירי MIDI</translation>
<translation id="1509960214886564027">ייתכן שהתכונות של חלק גדול מה××ª×¨×™× ×œ× ×™×¤×¢×œ×• כר×וי</translation>
<translation id="1620510694547887537">מצלמה</translation>
-<translation id="1647391597548383849">גישה ×ל המצלמה שלך</translation>
<translation id="1660204651932907780">מתן הרש××” ל××ª×¨×™× ×œ×”×©×ž×™×¢ ×¦×œ×™×œ×™× (מומלץ)</translation>
<translation id="1677097821151855053">â€×§×•×‘צי cookie ×•× ×ª×•× ×™× ××—×¨×™× ×ž××ª×¨×™× ×ž×©×ž×©×™× ×›×“×™ לזכור ×ת ×”×¤×¨×˜×™× ×©×œ×š, למשל כדי להכניס ×ותך לחשבון ×ו להציג מודעות בהת×מה ×ישית. ×פשר לנהל ×ת קובצי ×”-cookie מכל ×”××ª×¨×™× ×“×¨×š ×”<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">למחוק ×ת נתוני ×”×תר?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">כתובת ×תר</translation>
<translation id="2025115093177348061">מצי×ות רבודה</translation>
<translation id="2030769033451695672">כדי לחזור ×ל <ph name="URL_OF_THE_CURRENT_TAB" />, יש להקיש ×›×ן</translation>
+<translation id="2054665754582400095">הנוכחות שלך ×ונליין</translation>
<translation id="2079545284768500474">ביטול הפעולה</translation>
<translation id="2091887806945687916">צליל</translation>
<translation id="2107397443965016585">יש לבקש ממני ×ישור לפני מתן הרש××” ל××ª×¨×™× ×œ×”×¦×™×’ תוכן מוגן (מומלץ)</translation>
<translation id="2146738493024040262">פתיחת ×פליקציה ×œ×œ× ×”×ª×§× ×”</translation>
<translation id="2148716181193084225">היו×</translation>
<translation id="2182457891543959921">תוצג ש×לה לפני מתן הרש××” ל××ª×¨×™× ×œ×™×¦×•×¨ מפה בתלת ממד של הסביבה שלך ×ו לעקוב ×חר ×ž×™×§×•× ×”×ž×¦×œ×ž×” (מומלץ)</translation>
-<translation id="2187243482123994665">נוכחות משתמש</translation>
<translation id="2212565012507486665">â€×ישור קובצי cookie</translation>
<translation id="2228071138934252756">â€×›×“×™ ל×פשר ל-<ph name="APP_NAME" /> לגשת ×ל המצלמה, צריך להפעיל ×ותה ×’× ×‘<ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">×¤×¢× ×חת בלבד</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד ×חת (<ph name="NUM_MORE" />)}two{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}many{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}other{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">ההורדה הושלמה <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">גישה למיקו×</translation>
<translation id="2482878487686419369">התר×ות</translation>
<translation id="2490684707762498678">מנוהלות על-ידי <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">עזרה ומשוב</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">מיקרופון</translation>
<translation id="3277252321222022663">התרת גישה של ××ª×¨×™× ×ל ×”×—×™×™×©× ×™× (מומלץ)</translation>
<translation id="3295602654194328831">הסתרת פרטי×</translation>
+<translation id="3328801116991980348">פרטי ×תר</translation>
<translation id="3333961966071413176">כל ×נשי הקשר</translation>
<translation id="3386292677130313581">יש לש×ול לפני שמ××¤×©×¨×™× ×œ××ª×¨×™× ×œ×“×¢×ª מה ×”×ž×™×§×•× ×©×œ×š (מומלץ)</translation>
<translation id="3538390592868664640">חסימה של יצירת מפה בתלת ממד של הסביבה שלך ×ו של מעקב ×חר ×ž×™×§×•× ×”×ž×¦×œ×ž×” על ידי ×תרי×.</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">מתן הרש××” ל××ª×¨×™× ×œ×”×¦×™×’ תוכן מוגן</translation>
<translation id="4468959413250150279">השתקת ×¦×œ×™×œ×™× ×‘×תר ספציפי.</translation>
<translation id="4479647676395637221">יש לש×ול לפני שמ××¤×©×¨×™× ×œ××ª×¨×™× ×œ×”×©×ª×ž×© במצלמה שלך (מומלץ)</translation>
+<translation id="4505788138578415521">â€×›×ª×•×‘ת ×”-URL הורחבה</translation>
<translation id="4534723447064627427">â€×›×“×™ ל×פשר ל-<ph name="APP_NAME" /> לגשת ×ל המיקרופון, צריך להפעיל ×ת המיקרופון ×’× ×‘<ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">פרטי×</translation>
<translation id="4645575059429386691">מנוהל על-ידי ההורה שלך</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד הרש××” ×חת (<ph name="NUM_MORE" />)}two{<ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}many{<ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">â€×™×© להעניק הרש×ות עבור <ph name="APP_NAME" /> ב<ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">גישה למיקרופון שלך</translation>
<translation id="965817943346481315">חסימה ×× ×‘×תר מוצגות מודעות מפריעות ×ו מטעות (מומלץ)</translation>
<translation id="967624055006145463">נפח הנתוני×</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
index 7dfc53bd558..0f0e47fb7c8 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">サイト <ph name="SITE_NAME" /> を追加ã—ã¾ã—ãŸ</translation>
<translation id="1383876407941801731">検索</translation>
<translation id="1384959399684842514">ダウンロードを一時åœæ­¢ã—ã¾ã—ãŸ</translation>
+<translation id="1415402041810619267">URL ã®çŸ­ç¸®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™</translation>
<translation id="1431402976894535801">サイトã«ã‚ˆã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態ã®æ¤œå‡ºã‚’ブロックã™ã‚‹</translation>
<translation id="1446450296470737166">MIDI機器ã®ãƒ•ãƒ«ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’許å¯</translation>
<translation id="1509960214886564027">多ãサイトã§æ©Ÿèƒ½ã‚’使用ã§ããªããªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™</translation>
<translation id="1620510694547887537">カメラ</translation>
-<translation id="1647391597548383849">カメラã¸ã®ã‚¢ã‚¯ã‚»ã‚¹</translation>
<translation id="1660204651932907780">音声ã®å†ç”Ÿã‚’サイトã«è¨±å¯ã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="1677097821151855053">Cookie ã¨ä»–ã®ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿ã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ã‚„広告ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚ºãªã©ã§ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’特定ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã™ã¹ã¦ã®ã‚µã‚¤ãƒˆã® Cookie を管ç†ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />ã‚’ã”覧ãã ã•ã„。</translation>
<translation id="1688867105868176567">サイトデータを削除ã—ã¾ã™ã‹ï¼Ÿ</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">サイト㮠URL</translation>
<translation id="2025115093177348061">æ‹¡å¼µç¾å®Ÿï¼ˆAR)</translation>
<translation id="2030769033451695672">タップã—㦠<ph name="URL_OF_THE_CURRENT_TAB" /> ã«æˆ»ã‚‹</translation>
+<translation id="2054665754582400095">ユーザーã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態</translation>
<translation id="2079545284768500474">å…ƒã«æˆ»ã™</translation>
<translation id="2091887806945687916">音声</translation>
<translation id="2107397443965016585">ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’サイトã«è¨±å¯ã™ã‚‹å‰ã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="2146738493024040262">プレビュー アプリを開ã</translation>
<translation id="2148716181193084225">今日</translation>
<translation id="2182457891543959921">サイトã«å‘¨å›²ã® 3D マップã®ä½œæˆã¾ãŸã¯ã‚«ãƒ¡ãƒ©ä½ç½®ã®è¿½è·¡ã‚’許å¯ã™ã‚‹å‰ã«ç¢ºèªã—ã¾ã™ï¼ˆæŽ¨å¥¨ï¼‰</translation>
-<translation id="2187243482123994665">ユーザーã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態</translation>
<translation id="2212565012507486665">Cookie を許å¯</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ã«ã‚«ãƒ¡ãƒ©ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />ã§ã‚‚カメラをオンã«ã—ã¦ãã ã•ã„。</translation>
<translation id="2241634353105152135">一回é™ã‚Š</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã™}other{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã™}}</translation>
<translation id="2434158240863470628">ダウンロードãŒå®Œäº†ã—ã¾ã—ãŸ<ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ä½ç½®æƒ…å ±ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ã§ç®¡ç†</translation>
<translation id="2498359688066513246">ヘルプã¨ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">マイク</translation>
<translation id="3277252321222022663">サイトã«ã‚ˆã‚‹ã‚»ãƒ³ã‚µãƒ¼ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="3295602654194328831">情報を表示ã—ãªã„</translation>
+<translation id="3328801116991980348">サイト情報</translation>
<translation id="3333961966071413176">ã™ã¹ã¦ã®é€£çµ¡å…ˆ</translation>
<translation id="3386292677130313581">サイトã«ç¾åœ¨åœ°ã®èªè­˜ã‚’許å¯ã™ã‚‹å‰ã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="3538390592868664640">サイトã«ã‚ˆã‚‹å‘¨å›²ã® 3D マップã®ä½œæˆã¾ãŸã¯ã‚«ãƒ¡ãƒ©ä½ç½®ã®è¿½è·¡ã‚’ブロックã—ã¾ã™</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’サイトã«è¨±å¯ã™ã‚‹</translation>
<translation id="4468959413250150279">特定ã®ã‚µã‚¤ãƒˆã®éŸ³å£°ã‚’ミュートã—ã¾ã™ã€‚</translation>
<translation id="4479647676395637221">サイトã«ã‚«ãƒ¡ãƒ©ã®ä½¿ç”¨ã‚’許å¯ã™ã‚‹å‰ã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
+<translation id="4505788138578415521">URL ã®ãƒ•ãƒ«ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ã«ãƒžã‚¤ã‚¯ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />ã§ã‚‚マイクをオンã«ã—ã¦ãã ã•ã„。</translation>
<translation id="4570913071927164677">詳細</translation>
<translation id="4645575059429386691">ä¿è­·è€…ã«ã‚ˆã‚Šç®¡ç†ã•ã‚Œã¦ã„ã¾ã™</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™}other{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />㧠<ph name="APP_NAME" /> ã®æ¨©é™ã‚’有効ã«ã—ã¦ãã ã•ã„。</translation>
-<translation id="945632385593298557">マイクã¸ã®ã‚¢ã‚¯ã‚»ã‚¹</translation>
<translation id="965817943346481315">ç…©ã‚ã—ã„広告や誤解を招ã広告ãŒè¡¨ç¤ºã•ã‚Œã‚‹ã‚µã‚¤ãƒˆã®å ´åˆã«ãƒ–ロック(推奨)</translation>
<translation id="967624055006145463">ä¿å­˜ãƒ‡ãƒ¼ã‚¿</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
index 73cae3b7293..51d77ad61a9 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">სáƒáƒ˜áƒ¢áƒ˜: <ph name="SITE_NAME" /> დáƒáƒ›áƒáƒ¢áƒ”ბულიáƒ</translation>
<translation id="1383876407941801731">ძიებáƒ</translation>
<translation id="1384959399684842514">ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრდáƒáƒžáƒáƒ£áƒ–ებულიáƒ</translation>
+<translation id="1415402041810619267">URL შემáƒáƒ™áƒšáƒ”ბულიáƒ</translation>
<translation id="1431402976894535801">სáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი დáƒáƒ¡áƒ¬áƒ áƒ”ბის შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
<translation id="1446450296470737166">MIDI მáƒáƒ¬áƒ§. სრული კáƒáƒœáƒ¢. დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="1509960214886564027">მრáƒáƒ•áƒáƒšáƒ˜ სáƒáƒ˜áƒ¢áƒ˜áƒ¡ ფუნქციებმრშეიძლებრáƒáƒ áƒáƒ¡áƒáƒ—áƒáƒœáƒáƒ“áƒáƒ“ იმუშáƒáƒáƒ¡</translation>
<translation id="1620510694547887537">კáƒáƒ›áƒ”რáƒ</translation>
-<translation id="1647391597548383849">თქვენს კáƒáƒ›áƒ”რáƒáƒ–ე წვდáƒáƒ›áƒ</translation>
<translation id="1660204651932907780">სáƒáƒ˜áƒ¢áƒ”ბისთვის ხმის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბრ(რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="1677097821151855053">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის სხვრმáƒáƒœáƒáƒªáƒ”მები გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნებრთქვენ დáƒáƒ¡áƒáƒ›áƒáƒ®áƒ¡áƒáƒ•áƒ áƒ”ბლáƒáƒ“, რáƒáƒ›, მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, შეიყვáƒáƒœáƒáƒ— სისტემáƒáƒ¨áƒ˜ áƒáƒœ რეკლáƒáƒ›áƒ მáƒáƒ’áƒáƒ áƒ’áƒáƒ—. ყველრსáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ გáƒáƒ“áƒáƒ“ით <ph name="BEGIN_LINK" />პáƒáƒ áƒáƒ›áƒ”ტრებზე<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">გსურთ სáƒáƒ˜áƒ¢áƒ˜áƒ¡ მáƒáƒœáƒáƒªáƒ”მების გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”ბáƒ?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">სáƒáƒ˜áƒ¢áƒ˜áƒ¡ URL</translation>
<translation id="2025115093177348061">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘áƒ</translation>
<translation id="2030769033451695672">შეეხეთ <ph name="URL_OF_THE_CURRENT_TAB" />-ზე დáƒáƒ¡áƒáƒ‘რუნებლáƒáƒ“</translation>
+<translation id="2054665754582400095">თქვენი დáƒáƒ¡áƒ¬áƒ áƒ”ბáƒ</translation>
<translation id="2079545284768500474">მáƒáƒ¥áƒ›áƒ”დების გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
<translation id="2091887806945687916">ხმáƒ</translation>
<translation id="2107397443965016585">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="2146738493024040262">მყისიერი áƒáƒžáƒ˜áƒ¡ გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="2148716181193084225">დღეს</translation>
<translation id="2182457891543959921">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი გáƒáƒ áƒ”მáƒáƒ¡ 3-გáƒáƒœáƒ–áƒáƒ›áƒ˜áƒšáƒ”ბიáƒáƒœáƒ˜ რუკის შექმნის áƒáƒœ კáƒáƒ›áƒ”რის პáƒáƒ–იციისთვის თვáƒáƒšáƒ˜áƒ¡ მიდევნების დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
-<translation id="2187243482123994665">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის დáƒáƒ¡áƒ¬áƒ áƒ”ბáƒ</translation>
<translation id="2212565012507486665">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />-მრკáƒáƒ›áƒ”რით რáƒáƒ› ისáƒáƒ áƒ’ებლáƒáƒ¡, გáƒáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”თ კáƒáƒ›áƒ”რáƒáƒ–ე წვდáƒáƒ›áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒª <ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">მხáƒáƒšáƒáƒ“ ერთხელ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> მბáƒáƒ˜áƒ¢áƒ˜</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვრდáƒáƒ¨áƒ•áƒ”ბულიáƒ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვრდáƒáƒ¨áƒ•áƒ”ბულიáƒ}}</translation>
<translation id="2434158240863470628">ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრდáƒáƒ¡áƒ áƒ£áƒšáƒ“áƒ: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">მდებáƒáƒ áƒ”áƒáƒ‘áƒáƒ–ე წვდáƒáƒ›áƒ</translation>
<translation id="2482878487686419369">შეტყáƒáƒ‘ინებები</translation>
<translation id="2490684707762498678">მáƒáƒ áƒ—áƒáƒ•áƒ¡ <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">დáƒáƒ®áƒ›áƒáƒ áƒ”ბრდრუკუკáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">მიკრáƒáƒ¤áƒáƒœáƒ˜</translation>
<translation id="3277252321222022663">სáƒáƒ˜áƒ¢áƒ”ბისთვის სენსáƒáƒ áƒ”ბზე წვდáƒáƒ›áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბრ(რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="3295602654194328831">ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ›áƒáƒšáƒ•áƒ</translation>
+<translation id="3328801116991980348">სáƒáƒ˜áƒ¢áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="3333961966071413176">ყველრკáƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ˜</translation>
<translation id="3386292677130313581">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი მდებáƒáƒ áƒ”áƒáƒ‘ის დáƒáƒ“გენის დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="3538390592868664640">სáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი გáƒáƒ áƒ”მáƒáƒ¡ 3-გáƒáƒœáƒ–áƒáƒ›áƒ˜áƒšáƒ”ბიáƒáƒœáƒ˜ რუკის შექმნის áƒáƒœ კáƒáƒ›áƒ”რის პáƒáƒ–იციისთვის თვáƒáƒšáƒ˜áƒ¡ მიდევნების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">სáƒáƒ˜áƒ¢áƒ”ბისთვის დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="4468959413250150279">ხმის დáƒáƒ“უმებრკáƒáƒœáƒ™áƒ áƒ”ტული სáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის.</translation>
<translation id="4479647676395637221">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი კáƒáƒ›áƒ”რის გáƒáƒ›áƒáƒ§áƒ”ნების დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
+<translation id="4505788138578415521">URL გáƒáƒ¨áƒšáƒ˜áƒšáƒ˜áƒ</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" />-მრმიკრáƒáƒ¤áƒáƒœáƒ˜áƒ— რáƒáƒ› ისáƒáƒ áƒ’ებლáƒáƒ¡, გáƒáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”თ მიკრáƒáƒ¤áƒáƒœáƒ–ე წვდáƒáƒ›áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒª <ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">დეტáƒáƒšáƒ”ბი</translation>
<translation id="4645575059429386691">იმáƒáƒ áƒ—ებრთქვენი მშáƒáƒ‘ლის მიერ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვáƒ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვáƒ}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" />-ისთვის ნებáƒáƒ áƒ—ვების გáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”ბრ<ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებში<ph name="END_LINK" /> შეგიძლიáƒáƒ—.</translation>
-<translation id="945632385593298557">თქვენი მიკრáƒáƒ¤áƒáƒœáƒ˜ ხელმისáƒáƒ¬áƒ•áƒ“áƒáƒ›áƒ˜áƒ</translation>
<translation id="965817943346481315">დáƒáƒ‘ლáƒáƒ™áƒ•áƒ, თუ სáƒáƒ˜áƒ¢áƒ˜ áƒáƒ©áƒ•áƒ”ნებს მáƒáƒ›áƒáƒ‘ეზრებელ áƒáƒœ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœ რეკლáƒáƒ›áƒáƒ¡ (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="967624055006145463">შენáƒáƒ®áƒ£áƒšáƒ˜ მáƒáƒœáƒáƒªáƒ”მები</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
index 9938c74e331..f8c9cf1964b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Ñайты қоÑылды</translation>
<translation id="1383876407941801731">Іздеу</translation>
<translation id="1384959399684842514">Жүктеу кідіртілді</translation>
+<translation id="1415402041810619267">URL қыÑқартылды</translation>
<translation id="1431402976894535801">Сайттардың Ñіздің бар болу уақытыңызды анықтауын бөгейді.</translation>
<translation id="1446450296470737166">MIDI толық бақылауға Ñ€Ò±Ò›Ñат беру</translation>
<translation id="1509960214886564027">Көптеген Ñайттағы функциÑлар Ð´Ò±Ñ€Ñ‹Ñ Ð¶Ò±Ð¼Ñ‹Ñ Ñ–Ñтемеуі мүмкін.</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">Камераңызға кіру</translation>
<translation id="1660204651932907780">Сайттарда дыбыÑÑ‚Ñ‹Ò£ шығуына Ñ€Ò±Ò›Ñат ету (Ò±Ñынылады)</translation>
<translation id="1677097821151855053">Cookie файлдары мен Ñайттың баÑқа деректері Ñізді еÑте Ñақтап қалу (мыÑалы, еÑептік жазбаңызға кіру процеÑін жеңілдету немеÑе жарнамаларды Ñізге бейімдеу) үшін қолданылады. Барлық Ñайт үшін cookie файлдарын баÑқару үшін <ph name="BEGIN_LINK" />Параметрлер<ph name="END_LINK" /> бөлімін қараңыз.</translation>
<translation id="1688867105868176567">Сайт деректері өшірілÑін бе?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL Ñайты</translation>
<translation id="2025115093177348061">Толықтырылған шындық</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> қойындыÑына оралу үшін түртіңіз.</translation>
+<translation id="2054665754582400095">Бар болу деректері</translation>
<translation id="2079545284768500474">Қайтару</translation>
<translation id="2091887806945687916">ДыбыÑ</translation>
<translation id="2107397443965016585">Қорғалған мазмұнды ойнатуға Ñ€Ò±Ò›Ñат Ñұрау (Ò±Ñынылады)</translation>
<translation id="2146738493024040262">Instant App ашу</translation>
<translation id="2148716181193084225">Бүгін</translation>
<translation id="2182457891543959921">Cайттарға айналаңыздың 3D картаÑын жаÑауға немеÑе камераңыздың орнын бақылауға Ñ€Ò±Ò›Ñат беру алдында Ñізден Ñұраy (Ò±Ñынылады)</translation>
-<translation id="2187243482123994665">Пайдаланушының бар-жоғы</translation>
<translation id="2212565012507486665">Cookie файлдарына Ñ€Ò±Ò›Ñат беру</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> браузері камераны пайдалануы үшін, <ph name="BEGIN_LINK" />Android параметрлерінде<ph name="END_LINK" /> оны да қоÑыңыз.</translation>
<translation id="2241634353105152135">Бір-ақ рет</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға Ñ€Ò±Ò›Ñат етілген.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға Ñ€Ò±Ò›Ñат етілген.}}</translation>
<translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> жүктеп алынды</translation>
-<translation id="2440823041667407902">ОрналаÑқан жерін көру</translation>
<translation id="2482878487686419369">Хабарландырулар</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> баÑқарады</translation>
<translation id="2498359688066513246">Ðнықтама және пікір</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайттардың датчиктерді пайдалануына Ñ€Ò±Ò›Ñат ету (Ò±Ñынылады)</translation>
<translation id="3295602654194328831">Ðқпаратты жаÑыру</translation>
+<translation id="3328801116991980348">Сайт ақпараты</translation>
<translation id="3333961966071413176">Барлық контакт</translation>
<translation id="3386292677130313581">Сайттар орналаÑқан орныңызды анықтау үшін Ñ€Ò±Ò›Ñат Ñұрайды (Ò±Ñынылады)</translation>
<translation id="3538390592868664640">Сайттарға айналаңыздың 3D картаÑын жаÑауға немеÑе камера орнын бақылауға тыйым Ñалу</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Сайттарға қорғалған мазмұнды ойнатуға Ñ€Ò±Ò›Ñат беру</translation>
<translation id="4468959413250150279">Белгілі бір Ñайтта дыбыÑÑ‚Ñ‹ өшіру.</translation>
<translation id="4479647676395637221">Сайттар камераңызды пайдалану үшін Ñ€Ò±Ò›Ñат Ñұрайды (Ò±Ñынылады)</translation>
+<translation id="4505788138578415521">URL жайылды</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> браузері микрофонды пайдалануы үшін, <ph name="BEGIN_LINK" />Android параметрлерінде<ph name="END_LINK" /> оны да қоÑыңыз.</translation>
<translation id="4570913071927164677">Мәліметтер</translation>
<translation id="4645575059429386691">Ðта-ана баÑқарады</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" /> браузері үшін Ñ€Ò±Ò›Ñаттарды <ph name="BEGIN_LINK" />Android параметрлерінде<ph name="END_LINK" /> қоÑыңыз.</translation>
-<translation id="945632385593298557">Микрофонды пайдалану мүмкіндігі</translation>
<translation id="965817943346481315">Сайт мазалайтын немеÑе жалған ақпаратты жарнамалар көрÑеткен жағдайда бөгеу (Ò±Ñынылады)</translation>
<translation id="967624055006145463">Сақталған деректер</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
index dd4c7ab3411..587f15e6f33 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">áž‚áŸáž áž‘ំពáŸážš <ph name="SITE_NAME" /> ážáŸ’រូវបានបន្ážáŸ‚ម</translation>
<translation id="1383876407941801731">ស្វែងរក</translation>
<translation id="1384959399684842514">បានផ្អាកការទាញយក</translation>
+<translation id="1415402041810619267">បានបង្រួម URL</translation>
<translation id="1431402976894535801">ទប់ស្កាážáŸ‹áž‚áŸáž áž‘ំពáŸážšâ€‹áž˜áž·áž“ឱ្យដឹងអំពីពáŸáž›ážœáŸáž›áž¶â€‹ážŠáŸ‚លអ្នក​មានវážáŸ’ážáž˜áž¶áž“</translation>
<translation id="1446450296470737166">អនុញ្ញាážáž²áŸ’យមានការគ្រប់គ្រងពáŸáž‰áž›áŸáž‰áž›áž¾áž§áž”ករណ០MIDI</translation>
<translation id="1509960214886564027">មុážáž„ារ​នៅលើ​គáŸáž áž‘ំពáŸážšâ€‹áž‡áž¶áž…្រើន​អាចដំណើរការមិន​ážáŸ’រឹមážáŸ’រូវ</translation>
<translation id="1620510694547887537">កាមáŸážšáŸ‰áž¶</translation>
-<translation id="1647391597548383849">ចូលប្រើកាមáŸážšáŸ‰áž¶ážšáž”ស់អ្នក</translation>
<translation id="1660204651932907780">អនុញ្ញាážáž±áŸ’យទំពáŸážšáž…ាក់សំឡáŸáž„ (បានណែនាំ)</translation>
<translation id="1677097821151855053">ážáž¼áž‚ី និងទិន្ននáŸáž™áž‚áŸáž áž‘ំពáŸážšáž•áŸ’សáŸáž„ទៀážážáŸ’រូវបានប្រើ ដើម្បីចងចាំអ្នក ឧទាហរណ០ដើម្បីនាំអ្នកចូលគណនី ឬដើម្បីកំណážáŸ‹â€‹áž€áž¶ážšáž•áŸ’សាយ​ពាណិជ្ជកម្ម​ឱ្យ​ស្របនឹងអ្នក។ ដើម្បីគ្រប់គ្រងážáž¼áž‚ីសម្រាប់គáŸáž áž‘ំពáŸážšáž‘ាំងអស់ សូមមើល<ph name="BEGIN_LINK" />ការកំណážáŸ‹<ph name="END_LINK" />។</translation>
<translation id="1688867105868176567">សម្អាážáž‘ិន្ននáŸáž™áž‚áŸáž áž‘ំពáŸážš?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL áž‚áŸáž áž‘ំពáŸážš</translation>
<translation id="2025115093177348061">AR</translation>
<translation id="2030769033451695672">ចុចដើម្បីážáŸ’រឡប់ទៅ <ph name="URL_OF_THE_CURRENT_TAB" /> វិញ</translation>
+<translation id="2054665754582400095">​វážáŸ’ážáž˜áž¶áž“របស់អ្នក</translation>
<translation id="2079545284768500474">ážáŸ’រឡប់វិញ</translation>
<translation id="2091887806945687916">សំឡáŸáž„</translation>
<translation id="2107397443965016585">សួរ​មុនពáŸáž›â€‹áž¢áž“ុញ្ញážáž±áŸ’យគáŸáž áž‘ំពáŸážšâ€‹áž…ាក់ážáŸ’លឹមសារ​ដែលមាន​ការការពារ (បានណែនាំ)</translation>
<translation id="2146738493024040262">បើកកម្មវិធីប្រើភ្លាមៗ</translation>
<translation id="2148716181193084225">ážáŸ’ងៃនáŸáŸ‡</translation>
<translation id="2182457891543959921">សួរ​មុនពáŸáž›â€‹áž¢áž“ុញ្ញាážáž±áŸ’យ​គáŸáž áž‘ំពáŸážšáž”ង្កើážáž•áŸ‚នទី 3D នៃមជ្ឈដ្ឋានជុំវិញរបស់អ្នក ឬážáž¶áž˜ážŠáž¶áž“ទីážáž¶áŸ†áž„កាមáŸážšáŸ‰áž¶ (បានណែនាំ)</translation>
-<translation id="2187243482123994665">ážœážáŸ’ážáž˜áž¶áž“របស់​អ្នកប្រើប្រាស់</translation>
<translation id="2212565012507486665">អនុញ្ញាážâ€‹ážáž¼áž‚ី</translation>
<translation id="2228071138934252756">ដើម្បីអនុញ្ញាážáž±áŸ’áž™ <ph name="APP_NAME" /> ចូលប្រើកាមáŸážšáŸ‰áž¶â€‹ážšáž”ស់អ្នក អ្នកកáŸážáŸ’រូវបើក​កាមáŸážšáŸ‰áž¶â€‹áž“ៅក្នុង​<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" /> ផងដែរ។</translation>
<translation id="2241634353105152135">ម្ážáž„ប៉ុណ្ណោះ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{បានអនុញ្ញាហ<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}other{បានអនុញ្ញាហ<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}}</translation>
<translation id="2434158240863470628">ការទាញយក​បានបញ្ចប់ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ទីážáž¶áŸ†áž„ការចូលប្រើ</translation>
<translation id="2482878487686419369">ការជូនដំណឹង</translation>
<translation id="2490684707762498678">ស្ážáž·ážáž€áŸ’រោម​ការគ្រប់គ្រង​របស់ <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">ជំនួយ &amp; មážáž·</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ម៉ៃក្រូហ្វូន</translation>
<translation id="3277252321222022663">អនុញ្ញាážâ€‹áž±áŸ’យ​គáŸáž áž‘ំពáŸážšâ€‹áž…ូលប្រើ​ឧបករណáŸâ€‹áž…ាប់សញ្ញា (បាន​ណែនាំ)</translation>
<translation id="3295602654194328831">លាក់ពáŸážáŸŒáž˜áž¶áž“</translation>
+<translation id="3328801116991980348">áž–áŸážáŸŒáž˜áž¶áž“áž‚áŸáž áž‘ំពáŸážš</translation>
<translation id="3333961966071413176">ទំនាក់​ទំនង​ទាំងអស់</translation>
<translation id="3386292677130313581">សួរមុនពáŸáž›áž¢áž“ុញ្ញាážáž²áŸ’យគáŸáž áž‘ំពáŸážšážŸáŸ’គាល់ទីážáž¶áŸ†áž„របស់អ្នក (បានណែនាំ)</translation>
<translation id="3538390592868664640">ទប់ស្កាážáŸ‹áž‚áŸáž áž‘ំពáŸážšáž˜áž·áž“ឱ្យបង្កើážáž•áŸ‚នទី 3D នៃមជ្ឈដ្ឋានជុំវិញរបស់អ្នក ឬážáž¶áž˜ážŠáž¶áž“ទីážáž¶áŸ†áž„កាមáŸážšáŸ‰áž¶</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">អនុញ្ញាážáž±áŸ’យ​គáŸáž áž‘ំពáŸážšâ€‹áž…ាក់ážáŸ’លឹមសារដែលមាន​ការការពារ</translation>
<translation id="4468959413250150279">បិទសំឡáŸáž„សម្រាប់ទំពáŸážšáž‡áž¶áž€áŸ‹áž›áž¶áž€áŸ‹áŸ”</translation>
<translation id="4479647676395637221">សួរជាមុនសិន មុនពáŸáž›áž¢áž“ុញ្ញាážáž²áŸ’យគáŸáž áž‘ំពáŸážšáž”្រើកាមáŸážšáŸ‰áž¶ážšáž”ស់អ្នក (បានណែនាំ)</translation>
+<translation id="4505788138578415521">បានពង្រីក URL</translation>
<translation id="4534723447064627427">ដើម្បីអនុញ្ញាážáž±áŸ’áž™ <ph name="APP_NAME" /> ចូលប្រើមីក្រូហ្វូន​របស់អ្នក អ្នកកáŸážáŸ’រូវបើក​មីក្រូហ្វូន​នៅក្នុង​<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" /> ផងដែរ។</translation>
<translation id="4570913071927164677">áž–áŸážáŸŒáž˜áž¶áž“​លម្អិáž</translation>
<translation id="4645575059429386691">គ្រប់គ្រងដោយឪពុកម្ážáž¶áž™ážšáž”ស់អ្នក</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ប៊្លូធូស</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}}</translation>
<translation id="913657688200966289">បើក​ការអនុញ្ញាážâ€‹ážŸáž˜áŸ’រាប់ <ph name="APP_NAME" /> នៅក្នុង​<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" />។</translation>
-<translation id="945632385593298557">ចូលប្រើម៉ៃក្រូហ្វូនរបស់អ្នក</translation>
<translation id="965817943346481315">ទប់ស្កាážáŸ‹ ​ប្រសិនបើ​គáŸáž áž‘ំពáŸážšáž”ង្ហាញ​ការផ្សាយពាណិជ្ជកម្ម​ដែលនាំឱ្យយល់ច្រឡំ ឬរំážáž¶áž“ (បានណែនាំ)</translation>
<translation id="967624055006145463">​ទិន្ននáŸáž™ážŠáŸ‚ល​បាន​រក្សា​ទុក</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
index ce82f96219a..d9b0bf6cae8 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ಸೈಟೠಸೇರಿಸಲಾಗಿದೆ</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ಡೌನà³â€Œà²²à³‹à²¡à³ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ</translation>
+<translation id="1415402041810619267">URL ಕಿರಿದà³à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="1431402976894535801">ಸೈಟà³â€Œà²—ಳೠನಿಮà³à²® ಉಪಸà³à²¥à²¿à²¤à²¿à²¯ ಕà³à²°à²¿à²¤à³ ತಿಳಿದà³à²•à³Šà²³à³à²³à²¦à²‚ತೆ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="1446450296470737166">MIDI ಸಾಧನಗಳ ಪೂರà³à²£ ನಿಯಂತà³à²°à²£ ಅನà³à²®à²¤à²¿à²¸à²¿</translation>
<translation id="1509960214886564027">ಹಲವೠಸೈಟà³â€Œà²—ಳಲà³à²²à²¿à²¨ ಫೀಚರà³â€Œà²—ಳೠಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ನಿಲà³à²²à²¿à²¸à²¬à²¹à³à²¦à³</translation>
<translation id="1620510694547887537">ಕà³à²¯à²¾à²®à²°à²¾</translation>
-<translation id="1647391597548383849">ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಪà³à²°à²µà³†à³•à²¶à²¿à²¸à²¿</translation>
<translation id="1660204651932907780">ಧà³à²µà²¨à²¿à²¯à²¨à³à²¨à³ ಪà³à²²à³‡ ಮಾಡಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à²¿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="1677097821151855053">ಕà³à²•à³€à²—ಳೠಮತà³à²¤à³ ಇತರ ಸೈಟೠಡೇಟಾವನà³à²¨à³ ಬಳಸಿಕೊಂಡೠನಿಮà³à²®à²¨à³à²¨à³ ನೆನಪಿಟà³à²Ÿà³à²•à³Šà²³à³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†, ಉದಾಹರಣೆಗೆ ನಿಮà³à²®à²¨à³à²¨à³ ಸೈನೠಇನೠಮಾಡಲೠಅಥವಾ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ವೈಯಕà³à²¤à³€à²•à²°à²¿à²¸à²²à³ ಬಳಸಲಾಗà³à²¤à³à²¤à²¦à³†. ಈ ಎಲà³à²²à²¾ ಸೈಟà³â€Œà²—ಳಿಗಾಗಿ ಕà³à²•à²¿à²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³, <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³<ph name="END_LINK" /> ನೋಡಿ.</translation>
<translation id="1688867105868176567">ಸೈಟೠಡೇಟಾವನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಬೇಕೇ?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ಸೈಟೠURL</translation>
<translation id="2025115093177348061">ಆಗà³â€Œà²®à³†à²‚ಟೆಡೠರಿಯಾಲಿಟಿ</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> ಗೆ ಮರಳಲೠಟà³à²¯à²¾à²ªà³ ಮಾಡಿ</translation>
+<translation id="2054665754582400095">ನಿಮà³à²® ಉಪಸà³à²¥à²¿à²¤à²¿</translation>
<translation id="2079545284768500474">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="2091887806945687916">ಶಬà³à²§</translation>
<translation id="2107397443965016585">ಸಂರಕà³à²·à²¿à²¤ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³‡ ಮಾಡಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="2146738493024040262">ತತà³â€Œà²•à³à²·à²£à²¦ ಅಪà³à²²à²¿à²•à³†à³•à²¶à²¨à³ ತೆರೆಯಿರಿ</translation>
<translation id="2148716181193084225">ಇಂದà³</translation>
<translation id="2182457891543959921">ನಿಮà³à²® ಸà³à²¤à³à²¤à²®à³à²¤à³à²¤à²²à²¿à²¨ 3D ನಕà³à²·à³†à²—ಳನà³à²¨à³ ರಚಿಸಲೠಅಥವಾ ಕà³à²¯à²¾à²®à²°à²¾ ಸà³à²¥à²¿à²¤à²¿à²¯à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡಲೠಸೈಟà³â€Œà²—ೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿರà³à²µà³à²¦à³)</translation>
-<translation id="2187243482123994665">ಬಳಕೆದಾರರ ಉಪಸà³à²¥à²¿à²¤à²¿</translation>
<translation id="2212565012507486665">ಕà³à²•à³€à²—ಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²¿</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µà³à²¦à²•à³à²•à³† ಅನà³à²®à²¤à²¿à²¸à²²à³, <ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಸಹ ಆನೠಮಾಡಬೇಕಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2241634353105152135">ಕೇವಲ ಒಂದೠಬಾರಿ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}}</translation>
<translation id="2434158240863470628">ಡೌನà³â€Œà²²à³‹à²¡à³â€Œâ€Œ ಪೂರà³à²£à²—ೊಂಡಿದೆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ಸà³à²¥à²³ ಪà³à²°à²µà³‡à²¶</translation>
<translation id="2482878487686419369">ಸೂಚನೆಗಳà³</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ಆà³à²¯à²ªà³ ನಿರà³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="2498359688066513246">ಸಹಾಯ ಮತà³à²¤à³ ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ಮೈಕà³à²°à³‹à²«à³‹à²¨à³</translation>
<translation id="3277252321222022663">ಸೆನà³à²¸à²°à³â€Œà²—ಳನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿ ನೀಡಿ (ಶಿಫಾರಸೠಮಾಡಿರà³à²µà³à²¦à³)</translation>
<translation id="3295602654194328831">ಮಾಹಿತಿಯನà³à²¨à³ ಮರೆಮಾಡಿ</translation>
+<translation id="3328801116991980348">ಸೈಟೠಮಾಹಿತಿ</translation>
<translation id="3333961966071413176">ಎಲà³à²²à²¾ ಸಂಪರà³à²•à²—ಳà³</translation>
<translation id="3386292677130313581">ನಿಮà³à²® ಸà³à²¥à²³à²µà²¨à³à²¨à³ ತಿಳಿಯಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="3538390592868664640">ನಿಮà³à²® ಸà³à²¤à³à²¤à²®à³à²¤à³à²¤à²²à²¿à²¨ 3D ನಕà³à²·à³†à²—ಳನà³à²¨à³ ರಚಿಸà³à²µà³à²¦à²°à²¿à²‚ದ ಅಥವಾ ಕà³à²¯à²¾à²®à²°à²¾ ಸà³à²¥à²¿à²¤à²¿à²¯à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡà³à²µà³à²¦à²°à²¿à²‚ದ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ಸಂರಕà³à²·à²¿à²¤ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³‡ ಮಾಡಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿ ನೀಡಿ</translation>
<translation id="4468959413250150279">ನಿರà³à²¦à²¿à²·à³à²Ÿ ಸೈಟà³â€Œà²¨ ಧà³à²µà²¨à²¿à²¯à²¨à³à²¨à³ ಮà³à²¯à³‚ಟೠಮಾಡಿ</translation>
<translation id="4479647676395637221">ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾ ಬಳಸಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
+<translation id="4505788138578415521">URL ಅನà³à²¨à³ ವಿಸà³à²¤à²°à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ನಿಮà³à²® ಮೈಕà³à²°à³‹à²«à³‹à²¨à³â€Œà²—ೆ ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µà³à²¦à²•à³à²•à³† ಅನà³à²®à²¤à²¿à²¸à²²à³, <ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ಮೈಕà³à²°à³‹à²«à³‹à²¨à³ ಅನà³à²¨à³ ಸಹ ಆನೠಮಾಡಬೇಕಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="4570913071927164677">ವಿವರಗಳà³</translation>
<translation id="4645575059429386691">ನಿಮà³à²® ಪೋಷಕರೠನಿರà³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¿à²¦à³à²¦à²¾à²°à³†</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ಬà³à²²à³‚ಟೂತà³â€Œ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> <ph name="APP_NAME" /> ಗಾಗಿ ಅನà³à²®à²¤à²¿à²—ಳನà³à²¨à³ ಆನೠಮಾಡಿ.</translation>
-<translation id="945632385593298557">ನಿಮà³à²® ಮೈಕà³à²°à³†à³‚ೕಫೋನೠಪà³à²°à²µà³†à³•à²¶à²¿à²¸à²¿</translation>
<translation id="965817943346481315">ಅತಿಕà³à²°à²®à²£à²•à²¾à²°à²¿à²¯à²¾à²—ಿರà³à²µ ಅಥವಾ ತಪà³à²ªà³à²¦à²¾à²°à²¿à²—ೆಳೆಯà³à²µ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ಸೈಟೠತೋರಿಸಿದರೆ ಅದನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="967624055006145463">ಸಂಗà³à²°à²¹à²£à³† ಮಾಡಿರà³à²µ ಡೇಟಾ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
index eb5e2b556d0..b98f3302283 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> 사ì´íŠ¸ 추가ë¨</translation>
<translation id="1383876407941801731">검색</translation>
<translation id="1384959399684842514">다운로드 ì¼ì‹œì¤‘지ë¨</translation>
+<translation id="1415402041810619267">URL 잘림</translation>
<translation id="1431402976894535801">사ì´íŠ¸ì—ì„œ ì‚¬ìš©ìž ì ‘ì† ìƒíƒœë¥¼ ì•Œ 수 ì—†ë„ë¡ ì°¨ë‹¨</translation>
<translation id="1446450296470737166">MIDI ê¸°ê¸°ì˜ ì „ì²´ 제어 허용</translation>
<translation id="1509960214886564027">ë‹¤ìˆ˜ì˜ ì‚¬ì´íŠ¸ì—ì„œ ê¸°ëŠ¥ì´ ìž‘ë™í•˜ì§€ ì•Šì„ ìˆ˜ 있ìŒ</translation>
<translation id="1620510694547887537">ì¹´ë©”ë¼</translation>
-<translation id="1647391597548383849">ì¹´ë©”ë¼ì— 액세스</translation>
<translation id="1660204651932907780">사ì´íŠ¸ì—ì„œ 소리를 재ìƒí•˜ë„ë¡ í—ˆìš©(권장)</translation>
<translation id="1677097821151855053">예를 들어 로그ì¸í•˜ê±°ë‚˜ 광고를 맞춤설정하기 위해 정보를 저장하는 ë° ì¿ í‚¤ì™€ 기타 사ì´íŠ¸ ë°ì´í„°ê°€ 사용ë©ë‹ˆë‹¤. 모든 사ì´íŠ¸ì˜ 쿠키를 관리하려면 <ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì„ ì°¸ì¡°í•˜ì„¸ìš”.</translation>
<translation id="1688867105868176567">사ì´íŠ¸ ë°ì´í„°ë¥¼ 삭제하시겠습니까?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">사ì´íŠ¸ URL</translation>
<translation id="2025115093177348061">ì¦ê°• 현실</translation>
<translation id="2030769033451695672">탭하여 <ph name="URL_OF_THE_CURRENT_TAB" />(으)ë¡œ ëŒì•„가기</translation>
+<translation id="2054665754582400095">활ë™</translation>
<translation id="2079545284768500474">실행취소</translation>
<translation id="2091887806945687916">소리</translation>
<translation id="2107397443965016585">사ì´íŠ¸ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ë„ë¡ í—ˆìš©í•˜ê¸° ì „ì— í™•ì¸(권장)</translation>
<translation id="2146738493024040262">ì¸ìŠ¤í„´íŠ¸ 앱 열기</translation>
<translation id="2148716181193084225">오늘</translation>
<translation id="2182457891543959921">사ì´íŠ¸ì—ì„œ 주변 í™˜ê²½ì˜ 3D 지ë„를 ìƒì„±í•˜ê±°ë‚˜ ì¹´ë©”ë¼ ìœ„ì¹˜ë¥¼ 추ì í•˜ë„ë¡ í—ˆìš©í•˜ê¸° ì „ì— í™•ì¸(권장)</translation>
-<translation id="2187243482123994665">ì‚¬ìš©ìž ì ‘ì† ìƒíƒœ</translation>
<translation id="2212565012507486665">쿠키 허용</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />ì—ì„œ ì¹´ë©”ë¼ì— 액세스하ë„ë¡ í—ˆìš©í•˜ë ¤ë©´ <ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œë„ ì¹´ë©”ë¼ë¥¼ 사용 설정하세요.</translation>
<translation id="2241634353105152135">한 번만</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" />MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />ê°œ 허용ë¨}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />ê°œ 허용ë¨}}</translation>
<translation id="2434158240863470628">다운로드 완료: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">위치 액세스</translation>
<translation id="2482878487686419369">알림</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" />ì—ì„œ 관리함</translation>
<translation id="2498359688066513246">ê³ ê°ì„¼í„°</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">마ì´í¬</translation>
<translation id="3277252321222022663">사ì´íŠ¸ì˜ 센서 액세스 허용(권장)</translation>
<translation id="3295602654194328831">정보 숨기기</translation>
+<translation id="3328801116991980348">사ì´íŠ¸ ì •ë³´</translation>
<translation id="3333961966071413176">모든 ì—°ë½ì²˜</translation>
<translation id="3386292677130313581">사ì´íŠ¸ì—ì„œ ë‚´ 위치를 파악하ë„ë¡ í—ˆìš©í•˜ê¸° ì „ì— í™•ì¸(권장)</translation>
<translation id="3538390592868664640">사ì´íŠ¸ì—ì„œ 주변 í™˜ê²½ì˜ 3D 지ë„를 ìƒì„±í•˜ê±°ë‚˜ ì¹´ë©”ë¼ ìœ„ì¹˜ë¥¼ 추ì í•˜ì§€ 못하ë„ë¡ ì°¨ë‹¨</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">사ì´íŠ¸ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ë„ë¡ í—ˆìš©</translation>
<translation id="4468959413250150279">특정 사ì´íŠ¸ë¥¼ ìŒì†Œê±°í•©ë‹ˆë‹¤.</translation>
<translation id="4479647676395637221">사ì´íŠ¸ì—ì„œ ì¹´ë©”ë¼ë¥¼ 사용하ë„ë¡ í—ˆìš©í•˜ê¸° ì „ì— í™•ì¸(권장)</translation>
+<translation id="4505788138578415521">URL 펼ì³ì§</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" />ì—ì„œ 마ì´í¬ì— 액세스하ë„ë¡ í—ˆìš©í•˜ë ¤ë©´ <ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œë„ ë§ˆì´í¬ë¥¼ 사용 설정하세요.</translation>
<translation id="4570913071927164677">세부정보</translation>
<translation id="4645575059429386691">ë¶€ëª¨ë‹˜ì´ ê´€ë¦¬í•©ë‹ˆë‹¤.</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">블루투스</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />개}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />개}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œ <ph name="APP_NAME" /> 관련 ê¶Œí•œì„ í—ˆìš©í•˜ì„¸ìš”.</translation>
-<translation id="945632385593298557">마ì´í¬ì— 액세스</translation>
<translation id="965817943346481315">사ì´íŠ¸ì—ì„œ ë°©í•´ê°€ ë˜ê±°ë‚˜ 사용ìžë¥¼ 현혹하는 광고를 표시하는 경우 ê´‘ê³  차단(권장)</translation>
<translation id="967624055006145463">ì €ìž¥ëœ ë°ì´í„°</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
index 95657dcb8b6..ea94e621352 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Ñайты кошулду</translation>
<translation id="1383876407941801731">Издөө</translation>
<translation id="1384959399684842514">Жүктөп алуу тындырылды</translation>
+<translation id="1415402041810619267">URL кеÑилди</translation>
<translation id="1431402976894535801">Сайттарга кирип турганыңызды алар билбеÑин</translation>
<translation id="1446450296470737166">MIDI түзмктрд толук көзмлд уркÑÑ‚</translation>
<translation id="1509960214886564027">ФункциÑлар көпчүлүк Ñайттарда туура иштебеши мүмкүн.</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">Камераңызга мүмкүнчүлүк алуу</translation>
<translation id="1660204651932907780">Сайттарга үн чыгарууга урукÑат берилÑин (Ñунушталат)</translation>
<translation id="1677097821151855053">Cookie файлдары жана башка маалымат Ñизди ÑÑтеп калып, аккаунтка кирүү же жарнамаларды жекелештирүү ж.б. үчүн колдонулат. Бардык Ñайттардын cookie файлдарын башкаруу үчүн <ph name="BEGIN_LINK" />Жөндөөлөргө<ph name="END_LINK" /> өтүңүз.</translation>
<translation id="1688867105868176567">Сайттын дайындары тазаланÑынбы?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Сайт URL'и</translation>
<translation id="2025115093177348061">Кошумчаланган чындык</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> кайтуу үчүн таптап коюңуз</translation>
+<translation id="2054665754582400095">Сайтта же Ñайтта ÑмеÑтигиңиз</translation>
<translation id="2079545284768500474">Кайтаруу</translation>
<translation id="2091887806945687916">Үн</translation>
<translation id="2107397443965016585">Сайттар корголгон мазмунду ойнотуудан мурда урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="2146738493024040262">Ыкчам ачылуучу колдонмону ачуу</translation>
<translation id="2148716181193084225">Бүгүн</translation>
<translation id="2182457891543959921">Сайттар айланаңыздын 3D картаÑын түзгөнү же камераңыздын абалын көргөнү жатканда урукÑат ÑуралÑын (Ñунушталат)</translation>
-<translation id="2187243482123994665">Колдонуучунун Ñайтта же Ñайтта ÑмеÑтиги</translation>
<translation id="2212565012507486665">Cookies файлдарына урукÑат берүү</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> колдонмоÑуна камерага кирүүгө урукÑат берүү үчүн, <ph name="BEGIN_LINK" />Android Жөндөөлөрүнөн<ph name="END_LINK" /> камераны күйгүзүңүз.</translation>
<translation id="2241634353105152135">Бир гана жлу</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Мб</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн урукÑат берилди}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн урукÑат берилди}}</translation>
<translation id="2434158240863470628">Жүктөлүп алынды: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Жайгашкн жерд көрп туруу</translation>
<translation id="2482878487686419369">Билдирмелер</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> тарабынан башкарылат</translation>
<translation id="2498359688066513246">Жардам/пикир билдирүү</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайттарга ÑенÑорлорду колдонууга урукÑат берүү (Ñунушталат)</translation>
<translation id="3295602654194328831">Маалыматты жашыруу</translation>
+<translation id="3328801116991980348">Сайт жөнүндө маалымат</translation>
<translation id="3333961966071413176">Бардык байланыштар</translation>
<translation id="3386292677130313581">Сайттарга жайгашкан жериңиз тууралуу маалымат берүүдөн мурун урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="3538390592868664640">Сайттарга айланаңыздын 3D картаÑын түзүүгө же камераңыздын абалына көз Ñалууга бөгөт коюуңуз</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Сайттарга корголгон мазмунду ойнотууга урукÑат берүү</translation>
<translation id="4468959413250150279">Белгилүү бир Ñайттын үнүн өчүрүү.</translation>
<translation id="4479647676395637221">Сайттар камераңызды колдоноордон мурун урукÑат ÑуралÑын (Ñунушталат)</translation>
+<translation id="4505788138578415521">URL жайылып көрÑөтүлдү</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> колдонмоÑуна микрофонго кирүүгө урукÑат берүү үчүн, <ph name="BEGIN_LINK" />Android Жөндөөлөрүнөн<ph name="END_LINK" /> микрофонду күйгүзүңүз.</translation>
<translation id="4570913071927164677">Чоо-жайы</translation>
<translation id="4645575059429386691">Ðта-Ñнеңиз башкарат</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" /> колдонмоÑу үчүн урукÑаттарды <ph name="BEGIN_LINK" />Android Жөндөөлөрүнөн<ph name="END_LINK" /> күйгүзүңүз.</translation>
-<translation id="945632385593298557">Микрофонуңузга мүмкүнчүлүк алуу</translation>
<translation id="965817943346481315">Эгер Ñайт тажатма же адаштыруучу жарнамаларды көрÑөтүп баштаÑа, бөгөттөлÑүн (Ñунушталат)</translation>
<translation id="967624055006145463">Сакталган дайындар</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
index 22addec2067..54b9b00727c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">ເພີ່ມ <ph name="SITE_NAME" /> ເວັບ​ໄຊ​ທ໌​à»àº¥à»‰àº§</translation>
<translation id="1383876407941801731">ຊອàºàº«àº²</translation>
<translation id="1384959399684842514">ຢຸດàºàº²àº™àº”າວໂຫລດໄວ້ຊົ່ວຄາວà»àº¥à»‰àº§</translation>
+<translation id="1415402041810619267">ຕັດ URL ໃຫ້ສັ້ນລົງà»àº¥à»‰àº§</translation>
<translation id="1431402976894535801">ບລັອàºàºšà»à»ˆà»ƒàº«à»‰à»€àº§àº±àºšà»„ຊຮູ້ເມື່ອທ່ານມີàºàº²àº™à»€àº„ື່ອນໄຫວນຳໃຊ້</translation>
<translation id="1446450296470737166">ອະ​ນຸ​àºàº²àº”​àºàº²àº™â€‹àº„ວບ​ຄຸມ​ອຸ​ປະ​àºàº­àº™ MIDI ເຕັມ</translation>
<translation id="1509960214886564027">ຄຸນສົມບັດໃນຫຼາàºà»†à»€àº§àº±àºšà»„ຊອາດຈະໃຊ້ບà»à»ˆà»„ດ້</translation>
<translation id="1620510694547887537">àºà»‰àº­àº‡â€‹àº–່າàºâ€‹àº®àº¹àºš</translation>
-<translation id="1647391597548383849">ເຂົ້າ​ຫາ​àºà»‰àº­àº‡â€‹àº–່າàºâ€‹àº®àº¹àºšâ€‹àº‚ອງ​ທ່ານ</translation>
<translation id="1660204651932907780">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຫຼິ້ນສຽງ (à»àº™àº°àº™àº³)</translation>
<translation id="1677097821151855053">ຄຸàºàºàºµà»‰ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™à»€àº§àº±àºšà»„ຊອື່ນໆຖືàºà»ƒàºŠà»‰à»€àºžàº·à»ˆàº­àºˆàº·à»ˆàº—່ານ, ຕົວຢ່າງ: ນຳທ່ານເຂົ້າສູ່ລະບົບ ຫຼື ເພື່ອປັບà»àº•à»ˆàº‡à»‚ຄສະນາເປັນà»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§. ເພື່ອຈັດàºàº²àº™àº„ຸàºàºàºµà»‰àºªàº³àº¥àº±àºšà»€àº§àº±àºšà»„ຊທັງà»àº»àº”, àºàº°àº¥àº¸àº™àº²à»€àºšàº´à»ˆàº‡ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">ລຶບລ້າງຂà»à»‰àº¡àº¹àº™à»€àº§àº±àºšà»„ຊບà»?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL ​ເວັບ​ໄຊທ໌</translation>
<translation id="2025115093177348061">ອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ</translation>
<translation id="2030769033451695672">à»àº•àº°à»€àºžàº·à»ˆàº­àºàº±àºšàº„ືນຫາ <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">àºàº²àº™àº™àº³à»ƒàºŠà»‰àº‚ອງທ່ານ</translation>
<translation id="2079545284768500474">ບà»à»ˆà»€àº®àº±àº”</translation>
<translation id="2091887806945687916">ສຽງ</translation>
<translation id="2107397443965016585">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຫຼິ້ນເນື້ອຫາທີ່ມີàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡ (à»àº™àº°àº™àº³)</translation>
<translation id="2146738493024040262">ເປີດà»àº­àº±àºšàºžà»‰àº­àº¡à»ƒàºŠà»‰</translation>
<translation id="2148716181193084225">ມື້​ນີ້</translation>
<translation id="2182457891543959921">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊສ້າງà»àºœàº™àº—ີ່ 3 ມິຕິຂອງສິ່ງທີ່ຢູ່ອ້ອມຂ້າງຕົວທ່ານ ຫຼື ຕາມຕຳà»à»œà»ˆàº‡àºà»‰àº­àº‡ (à»àº™àº°àº™àº³)</translation>
-<translation id="2187243482123994665">àºàº²àº™à»€àº„ື່ອນໄຫວນຳໃຊ້ຂອງຜູ້ໃຊ້</translation>
<translation id="2212565012507486665">ອະນຸàºàº²àº”ຄຸàºàºàºµà»‰</translation>
<translation id="2228071138934252756">ເພື່ອອະນຸàºàº²àº”ໃຫ້ <ph name="APP_NAME" /> ເຂົ້າເຖິງàºà»‰àº­àº‡àº–່າàºàº®àº¹àºšàº‚ອງທ່ານ, àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”àºà»‰àº­àº‡àº–່າàºàº®àº¹àºšà»ƒàº™ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" /> ນຳ.</translation>
<translation id="2241634353105152135">ຄັ້ງ​ດຽວ​ເທົ່າ​ນັ້ນ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{ອະນຸàºàº²àº” <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™à»àº¥à»‰àº§}other{ອະນຸàºàº²àº” <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™à»àº¥à»‰àº§}}</translation>
<translation id="2434158240863470628">àºàº²àº™àº”າວໂຫຼດສຳເລັດà»àº¥à»‰àº§ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">àºàº²àº™â€‹à»€àº‚ົ້າ​ເຖິງ​ຂà»à»‰àº¡àº¹àº™â€‹àºªàº°àº–ານທີ່</translation>
<translation id="2482878487686419369">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™</translation>
<translation id="2490684707762498678">ຈັດàºàº²àº™à»‚ດຠ<ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">ຊ່ວàºà»€àº«àº¼àº·àº­ ​à»àº¥àº° ຄà»àº²â€‹àº„ິດ​ເຫັນຕິ​ຊົມ</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ໄມໂຄຣໂຟນ</translation>
<translation id="3277252321222022663">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊເຂົ້າເຖິງເຊັນເຊີ (à»àº™àº°àº™àº³)</translation>
<translation id="3295602654194328831">ເຊື່ອງຂà»à»‰àº¡àº¹àº™</translation>
+<translation id="3328801116991980348">ຂà»à»‰â€‹àº¡àº¹àº™â€‹à»€àº§àº±àºšâ€‹à»„ຊທ໌</translation>
<translation id="3333961966071413176">ລາàºàºŠàº·à»ˆàºœàº¹à»‰àº•àº´àº”ຕà»à»ˆàº—ັງà»àº»àº”</translation>
<translation id="3386292677130313581">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຮູ້ສະຖານທີ່ຂອງທ່ານ (à»àº™àº°àº™àº³)</translation>
<translation id="3538390592868664640">ບລັອàºà»€àº§àº±àºšà»„ຊບà»à»ˆà»ƒàº«à»‰àºªà»‰àº²àº‡à»àºœàº™àº—ີ່ 3 ມິຕິຂອງສິ່ງທີ່ຢູ່ອ້ອມຂ້າງຕົວທ່ານ ຫຼື ຕິດຕາມຕຳà»à»œà»ˆàº‡àºà»‰àº­àº‡</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຫຼິ້ນເນື້ອຫາທີ່ໄດ້ຮັບàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡</translation>
<translation id="4468959413250150279">ປິດສຽງສຳລັບເວັບໄຊສະເພາະໃດໜຶ່ງ.</translation>
<translation id="4479647676395637221">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊໃຊ້àºà»‰àº­àº‡àº–່າàºàº®àº¹àºšàº‚ອງທ່ານ (à»àº™àº°àº™àº³)</translation>
+<translation id="4505788138578415521">ຂະຫàºàº²àº URL à»àº¥à»‰àº§</translation>
<translation id="4534723447064627427">ເພື່ອອະນຸàºàº²àº”ໃຫ້ <ph name="APP_NAME" /> ເຂົ້າເຖິງໄມໂຄຣໂຟນ, àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”ໄມໂຄຣໂຟນໃນ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" /> ນຳ.</translation>
<translation id="4570913071927164677">ລາàºàº¥àº°àº­àº½àº”</translation>
<translation id="4645575059429386691">ຈັດ​àºàº²àº™â€‹à»‚ດàºâ€‹àºœàº¹à»‰â€‹àº›àº»àºâ€‹àº„ອງ​ຂອງ​ທ່ານ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™}}</translation>
<translation id="913657688200966289">ເປີດàºàº²àº™àº­àº°àº™àº¸àºàº²àº”ສຳລັບ <ph name="APP_NAME" /> ໃນ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ເຂົ້າ​ຫາ​ໄມ​ໂຄ​ຣ​ໂຟນ​ຂອງ​ທ່ານ</translation>
<translation id="965817943346481315">ບລັອàºàº–້າເວັບໄຊສະà»àº”ງໂຄສະນາທີ່ລົບàºàº§àº™ ຫຼື ຫຼອàºàº¥àº§àº‡ (à»àº™àº°àº™àº³)</translation>
<translation id="967624055006145463">ເàºàº±àºšàº‚à»à»‰àº¡àº¹àº™à»„ວ້à»àº¥à»‰àº§</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
index c3802c33a7c..8c1a84f4534 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">PridÄ—ta svetainÄ— <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Ieškoti</translation>
<translation id="1384959399684842514">Atsisiuntimas pristabdytas</translation>
+<translation id="1415402041810619267">URL sutrumpintas</translation>
<translation id="1431402976894535801">Neleisti svetainėms žinoti, kada esate</translation>
<translation id="1446450296470737166">Leisti visiškai valdyti MIDI įr.</translation>
<translation id="1509960214886564027">Funkcijos gali neveikti daugybėje svetainių.</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Prieiga prie fotoaparato</translation>
<translation id="1660204651932907780">Leisti svetainÄ—ms leisti garsÄ… (rekomenduojama)</translation>
<translation id="1677097821151855053">Slapukai ir kiti svetainės duomenys naudojami siekiant jus prisiminti, pvz., prisijungiant ar suasmeninant skelbimus. Norėdami tvarkyti visų svetainių slapukus, žr. skiltį <ph name="BEGIN_LINK" />„Nustatymai“<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">IÅ¡valyti svetainÄ—s duomenis?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">SvetainÄ—s URL</translation>
<translation id="2025115093177348061">IÅ¡plÄ—stoji realybÄ—</translation>
<translation id="2030769033451695672">Palieskite, kad grįžtumėte į <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Jūsų veiklos duomenys</translation>
<translation id="2079545284768500474">Anuliuoti</translation>
<translation id="2091887806945687916">Garsas</translation>
<translation id="2107397443965016585">Paklausti prieš leidžiant svetainėms leisti saugomą turinį (rekomenduojama)</translation>
<translation id="2146738493024040262">Atidaryti akimirksniu įkeliamą programėlę</translation>
<translation id="2148716181193084225">Å iandien</translation>
<translation id="2182457891543959921">Klausti, ar svetainėms leidžiama kurti jūsų aplinkos 3D žemėlapį ir stebėti kameros padėtį (rekomenduojama)</translation>
-<translation id="2187243482123994665">Naudotojo buvimas</translation>
<translation id="2212565012507486665">Leisti slapukus</translation>
<translation id="2228071138934252756">Norėdami leisti „<ph name="APP_NAME" />“ pasiekti jūsų kamerą, taip pat įjunkite ją <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tik vienÄ… kartÄ…</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}one{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}few{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}many{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}other{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Atsisiųsta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Prieiga prie vietovÄ—s</translation>
<translation id="2482878487686419369">Pranešimai</translation>
<translation id="2490684707762498678">Tvarko „<ph name="APP_NAME" />“</translation>
<translation id="2498359688066513246">Pagalba ir atsiliepimai</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofonas</translation>
<translation id="3277252321222022663">Leidžiama svetainėms pasiekti jutiklius (rekomenduojama)</translation>
<translation id="3295602654194328831">SlÄ—pti informacijÄ…</translation>
+<translation id="3328801116991980348">SvetainÄ—s informacija</translation>
<translation id="3333961966071413176">Visi kontaktai</translation>
<translation id="3386292677130313581">Klausti prieš leidžiant svetainėms žinoti vietą (rekomenduojama)</translation>
<translation id="3538390592868664640">Blokuoti, kad svetainės nekurtų jūsų aplinkos 3D žemėlapio ir nestebėtų kameros padėties</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Leisti svetainėms leisti saugomą turinį</translation>
<translation id="4468959413250150279">KonkreÄios svetainÄ—s garso iÅ¡jungimas.</translation>
<translation id="4479647676395637221">Pirmiausia klausti prieš leidžiant svetainėms naudoti kamerą (rekomenduojama)</translation>
+<translation id="4505788138578415521">URL išskleistas</translation>
<translation id="4534723447064627427">Norėdami leisti „<ph name="APP_NAME" />“ pasiekti jūsų mikrofoną, taip pat įjunkite jį <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">IÅ¡sami informacija</translation>
<translation id="4645575059429386691">Tvarko vienas iš jūsų tėvų</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Įjunkite „<ph name="APP_NAME" />“ leidimus <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Prieiga prie mikrofono</translation>
<translation id="965817943346481315">Blokuoti, jei svetainÄ—je rodomi nepageidaujami arba klaidinantys skelbimai (rekomenduojama)</translation>
<translation id="967624055006145463">Saugomi duomenys</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
index 6ba23f54ad4..d8787cf74d6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Tika pievienota vietne <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Meklēt</translation>
<translation id="1384959399684842514">LejupielÄde pÄrtraukta</translation>
+<translation id="1415402041810619267">URL ir saÄ«sinÄts</translation>
<translation id="1431402976894535801">NerÄdÄ«t vietnÄ“m informÄciju par jÅ«su aktivitÄti</translation>
<translation id="1446450296470737166">PilnÄ«ga MIDI ierÄ«Äu pÄrvaldÄ«ba</translation>
<translation id="1509960214886564027">DaudzÄs vietnÄ“s funkcijas var nedarboties</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Piekļuve kamerai</translation>
<translation id="1660204651932907780">Atļaut vietnēm atskaņot skaņu (ieteicams)</translation>
<translation id="1677097821151855053">SÄ«kfaili un citi vietnes dati tiek izmantoti, lai saglabÄtu jÅ«su datus un tos izmantotu, piemÄ“ram, kad pierakstÄties, vai reklÄmu personalizÄ“Å¡anai. Lai pÄrvaldÄ«tu visu vietņu sÄ«kfailus, pÄrejiet uz sadaļu <ph name="BEGIN_LINK" />IestatÄ«jumi<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vai notīrīt vietnes datus?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Vietnes URL</translation>
<translation id="2025115093177348061">PapildinÄtÄ realitÄte</translation>
<translation id="2030769033451695672">Pieskarieties, lai atgrieztos cilnē <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">JÅ«su klÄtbÅ«tne</translation>
<translation id="2079545284768500474">Atsaukt</translation>
<translation id="2091887806945687916">SignÄls</translation>
<translation id="2107397443965016585">VaicÄt, pirms atļaut vietnÄ“m atskaņot aizsargÄtu saturu (ieteicams)</translation>
<translation id="2146738493024040262">Atvērt tūlītējo lietotni</translation>
<translation id="2148716181193084225">Å odien</translation>
<translation id="2182457891543959921">VaicÄt, pirms ļaut vietnÄ“m izveidot jÅ«su apkÄrtnes 3D karti vai izsekot kameras pozÄ«ciju (ieteicams)</translation>
-<translation id="2187243482123994665">LietotÄja aktivitÄte</translation>
<translation id="2212565012507486665">Atļaut sīkfailus</translation>
<translation id="2228071138934252756">Lai atļautu lietotnei <ph name="APP_NAME" /> piekļūt jūsu kamerai, ieslēdziet kameru arī <ph name="BEGIN_LINK" />Android iestatījumos<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tikai vienreiz</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}zero{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}one{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}other{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">LejupielÄde pabeigta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Piekļuve atraÅ¡anÄs vietai</translation>
<translation id="2482878487686419369">Paziņojumi</translation>
<translation id="2490684707762498678">PÄrvalda <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Palīdzība un atsauksmes</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofons</translation>
<translation id="3277252321222022663">Atļaut vietnēm piekļūt sensoriem (ieteicams)</translation>
<translation id="3295602654194328831">SlÄ“pt informÄciju</translation>
+<translation id="3328801116991980348">Vietnes informÄcija</translation>
<translation id="3333961966071413176">Visas kontaktpersonas</translation>
<translation id="3386292677130313581">JautÄt, pirms atļaut vietnÄ“m uzzinÄt jÅ«su atraÅ¡anÄs vietu (ieteicams)</translation>
<translation id="3538390592868664640">Neļaut vietnÄ“m izveidot jÅ«su apkÄrtnes 3D karti vai izsekot kameras pozÄ«ciju</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Ä»aut vietnÄ“m atskaņot aizsargÄtu saturu</translation>
<translation id="4468959413250150279">Izslēgt skaņu noteiktai vietnei</translation>
<translation id="4479647676395637221">JautÄt, pirms atļaut vietnÄ“m izmantot jÅ«su kameru (ieteicams)</translation>
+<translation id="4505788138578415521">URL ir izvērsts</translation>
<translation id="4534723447064627427">Lai atļautu lietotnei <ph name="APP_NAME" /> piekļūt jūsu mikrofonam, ieslēdziet mikrofonu arī <ph name="BEGIN_LINK" />Android iestatījumos<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">DetalizÄ“ta informÄcija</translation>
<translation id="4645575059429386691">PÄrvalda viens no jÅ«su vecÄkiem</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}zero{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android iestatījumos<ph name="END_LINK" /> ieslēdziet atļaujas lietotnei <ph name="APP_NAME" />.</translation>
-<translation id="945632385593298557">Piekļuve mikrofonam</translation>
<translation id="965817943346481315">BloÄ·Ä“t, ja vietnÄ“ tiek rÄdÄ«tas traucÄ“joÅ¡as vai maldinoÅ¡as reklÄmas (ieteicams)</translation>
<translation id="967624055006145463">Dati saglabÄti</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
index 3a42b9de094..4e1f0272c87 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Локацијата <ph name="SITE_NAME" /> е додадена</translation>
<translation id="1383876407941801731">Барај</translation>
<translation id="1384959399684842514">Преземањето е паузирано</translation>
+<translation id="1415402041810619267">URL-адреÑата е Ñкратена</translation>
<translation id="1431402976894535801">Ðе дозволувај Ñајтовите да знаат дали Ñум приÑутен</translation>
<translation id="1446450296470737166">Дозволи контрола над MIDI-уреди</translation>
<translation id="1509960214886564027">Функциите на многу Ñајтови може да не функционираат</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ПриÑтапи до камерата</translation>
<translation id="1660204651932907780">Дозволи Ñајтовите да пуштаат звук (Ñе препорачува)</translation>
<translation id="1677097821151855053">Колачињата и другите Ñајтови Ñе кориÑтат за да ве запомнат, на пр., за најавување или за перÑонализирање реклами. За да управувате Ñо колачињата за Ñите Ñајтови, погледнете ги <ph name="BEGIN_LINK" />ПоÑтавките<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Дали да Ñе иÑчиÑтат Ñите податоци?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL на локацијата</translation>
<translation id="2025115093177348061">Проширена реалноÑÑ‚</translation>
<translation id="2030769033451695672">Допрете за да Ñе вратите на <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Вашето приÑуÑтво</translation>
<translation id="2079545284768500474">Врати</translation>
<translation id="2091887806945687916">Звук</translation>
<translation id="2107397443965016585">Прашај пред да дозволиш Ñајтовите да пуштаат заштитени Ñодржини (Ñе препорачува)</translation>
<translation id="2146738493024040262">Отвори ја инÑтант апликацијата</translation>
<translation id="2148716181193084225">ДенеÑ</translation>
<translation id="2182457891543959921">Прашувај пред да им дозволиш на Ñајтовите да Ñоздадат 3D-карта на опкружувањето или да ја Ñледат позицијата на камерата (препорачано)</translation>
-<translation id="2187243482123994665">ПриÑуÑтво на кориÑник</translation>
<translation id="2212565012507486665">Дозволи колачиња</translation>
<translation id="2228071138934252756">За да овозможите <ph name="APP_NAME" /> да приÑтапува до вашата камера, вклучете ја дозволата за камерата и во <ph name="BEGIN_LINK" />ПоÑтавки за Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само еднаш</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}}</translation>
<translation id="2434158240863470628">Преземањето е завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ПриÑтап до локација</translation>
<translation id="2482878487686419369">ИзвеÑтувања</translation>
<translation id="2490684707762498678">Управувани од <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Помош и повратни информации</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Дозволете Ñајтовите да приÑтапуваат до Ñензорите (препорачано)</translation>
<translation id="3295602654194328831">Сокриј ги информациите</translation>
+<translation id="3328801116991980348">Информации за веб-локација</translation>
<translation id="3333961966071413176">Сите контакти</translation>
<translation id="3386292677130313581">Прашај пред да дозволиш Ñајтовите да ја дознаат локацијата (Ñе препорачува)</translation>
<translation id="3538390592868664640">Ðе дозволувај им на Ñајтовите да Ñоздаваат 3D-карта на опкружувањето или да ја Ñледат позицијата на камерата</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Дозволи Ñајтовите да пуштаат заштитени Ñодржини</translation>
<translation id="4468959413250150279">ИÑклучете го звукот за одреден Ñајт.</translation>
<translation id="4479647676395637221">Прво прашај пред да дозволиш Ñајтовите да ја кориÑтат камерата (Ñе препорачува)</translation>
+<translation id="4505788138578415521">URL-адреÑата е проширена</translation>
<translation id="4534723447064627427">За да овозможите <ph name="APP_NAME" /> да приÑтапува до вашиот микрофон, вклучете ја дозволата за микрофонот и во <ph name="BEGIN_LINK" />ПоÑтавки за Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Детали</translation>
<translation id="4645575059429386691">Управувано од вашиот родител</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> друго}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> друго}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> други}}</translation>
<translation id="913657688200966289">Вклучете ги дозволите за <ph name="APP_NAME" /> во <ph name="BEGIN_LINK" />ПоÑтавки за Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ПриÑтапи до микрофонот</translation>
<translation id="965817943346481315">Блокирај ако Ñајтот прикажува нападни или лажни реклами (препорачано)</translation>
<translation id="967624055006145463">Складирани податоци</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
index 63f7a0f0e7f..4122387cd58 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> à´Žà´¨àµà´¨ സൈറàµà´±àµ ചേർതàµà´¤àµ‚</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ഡൗൺലോഡൠതാൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ നിർതàµà´¤à´¿</translation>
+<translation id="1415402041810619267">URL à´šàµà´°àµà´•àµà´•à´¿</translation>
<translation id="1431402976894535801">നിങàµà´™à´³àµà´Ÿàµ† സാനàµà´¨à´¿à´§àµà´¯à´‚ അറിയàµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
<translation id="1446450296470737166">MIDI ഉപകരണങàµà´™à´³àµà´Ÿàµ† പൂർണàµà´£ നിയനàµà´¤àµà´°à´£à´‚ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="1509960214886564027">നിരവധി സൈറàµà´±àµà´•à´³à´¿à´²àµ† ഫീചàµà´šà´±àµà´•àµ¾à´•àµà´•àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´‚ നടതàµà´¤à´¾à´¨à´¾à´¯àµ‡à´•àµà´•à´¿à´²àµà´²</translation>
<translation id="1620510694547887537">à´•àµà´¯à´¾à´®à´±</translation>
-<translation id="1647391597548383849">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯àµà´•</translation>
<translation id="1660204651932907780">ശബàµâ€Œà´¦à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ)</translation>
<translation id="1677097821151855053">നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ ഓർകàµà´•à´¾àµ» à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ മറàµà´±àµ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚ ഉപയോഗിചàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, ഉദാഹരണതàµà´¤à´¿à´¨àµ നിങàµà´™à´³àµ† സൈൻ ഇൻ ചെയàµà´¯à´¿à´•àµà´•à´¾àµ» à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ പരസàµà´¯à´™àµà´™àµ¾ à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´•àµà´•à´¾àµ». à´Žà´²àµà´²à´¾ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµà´®àµà´³àµà´³ à´•àµà´•àµà´•à´¿à´•àµ¾ മാനേജൠചെയàµà´¯à´¾àµ», <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´°à´£à´‚<ph name="END_LINK" /> കാണàµà´•.</translation>
<translation id="1688867105868176567">സൈറàµà´±àµ ഡാറàµà´± മായàµâ€Œà´•àµà´•à´£àµ‹?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">സൈറàµà´±àµ URL</translation>
<translation id="2025115093177348061">à´…à´¨àµà´¬à´¨àµà´§à´¯à´¾à´¥à´¾àµ¼à´¤àµà´¥àµà´¯à´‚</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ മടങàµà´™à´¾àµ» ടാപàµà´ªàµ ചെയàµà´¯àµà´•</translation>
+<translation id="2054665754582400095">നിങàµà´™à´³àµà´Ÿàµ† സാനàµà´¨à´¿à´§àµà´¯à´‚</translation>
<translation id="2079545284768500474">പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="2091887806945687916">ശബàµâ€Œà´¦à´‚</translation>
<translation id="2107397443965016585">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶à´šàµ†à´¯àµâ€Œà´¤à´¤àµ)</translation>
<translation id="2146738493024040262">ഇൻസàµà´±àµà´±à´¨àµâ€à´±àµ ആപàµà´ªàµ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="2148716181193084225">ഇനàµà´¨àµ</translation>
<translation id="2182457891543959921">നിങàµà´™à´³àµà´Ÿàµ† à´šàµà´±àµà´±àµà´ªà´¾à´Ÿàµà´•à´³àµà´Ÿàµ† 3D മാപàµà´ªàµ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ‹ à´•àµà´¯à´¾à´®à´±à´¯àµà´Ÿàµ† à´¸àµà´¥à´¾à´¨à´‚ à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ‹ സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ)</translation>
-<translation id="2187243482123994665">ഉപയോകàµà´¤àµƒ സാനàµà´¨à´¿à´§àµà´¯à´‚</translation>
<translation id="2212565012507486665">à´•àµà´•àµà´•à´¿à´•àµ¾ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ആപàµà´ªà´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, <ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµà´‚<ph name="END_LINK" /> à´•àµà´¯à´¾à´®à´± ഓണാകàµà´•àµà´•.</translation>
<translation id="2241634353105152135">à´’à´°à´¿à´•àµà´•àµ½ മാതàµà´°à´‚</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚ à´…à´¨àµà´µà´¦à´¿à´šàµà´šàµ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚ à´…à´¨àµà´µà´¦à´¿à´šàµà´šàµ}}</translation>
<translation id="2434158240863470628">ഡൗൺലോഡൠപൂർതàµà´¤à´¿à´¯à´¾à´¯à´¿ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ലൊകàµà´•àµ‡à´·àµ» ആകàµâ€Œà´¸à´¸àµ</translation>
<translation id="2482878487686419369">അറിയിപàµà´ªàµà´•àµ¾</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ആണൠമാനേജൠചെയàµà´¯àµà´¨àµà´¨à´¤àµ</translation>
<translation id="2498359688066513246">സഹായവàµà´‚ ഫീഡàµà´¬à´¾à´•àµà´•àµà´‚</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">മൈകàµà´°àµ‹à´«àµ‹àµº</translation>
<translation id="3277252321222022663">സെൻസറàµà´•àµ¾ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ)</translation>
<translation id="3295602654194328831">വിവരങàµà´™àµ¾ മറയàµâ€Œà´•àµà´•àµà´•</translation>
+<translation id="3328801116991980348">സൈറàµà´±àµ വിവരങàµà´™à´³àµâ€</translation>
<translation id="3333961966071413176">à´Žà´²àµà´²à´¾ കോൺടാകàµà´±àµà´±àµà´•à´³àµà´‚</translation>
<translation id="3386292677130313581">നിങàµà´™à´³àµà´Ÿàµ† ലൊകàµà´•àµ‡à´·àµ» അറിയാൻ സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶à´šàµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ)</translation>
<translation id="3538390592868664640">നിങàµà´™à´³àµà´Ÿàµ† à´šàµà´±àµà´±àµà´ªà´¾à´Ÿàµà´•à´³àµà´Ÿàµ† 3D മാപàµà´ªàµ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ‹ à´•àµà´¯à´¾à´®à´±à´¯àµà´Ÿàµ† à´¸àµà´¥à´¾à´¨à´‚ à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ‹ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="4468959413250150279">ഒരൠപàµà´°à´¤àµà´¯àµ‡à´• സൈറàµà´±à´¿à´¨à´¾à´¯à´¿ ശബàµâ€Œà´¦à´‚ à´®àµà´¯àµ‚à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´•.</translation>
<translation id="4479647676395637221">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ഉപയോഗികàµà´•à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ആദàµà´¯à´‚ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶à´šàµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ)</translation>
+<translation id="4505788138578415521">URL വികസിപàµà´ªà´¿à´šàµà´šàµ</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ആപàµà´ªà´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, <ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµà´‚<ph name="END_LINK" /> മൈകàµà´°àµ‹à´«àµ‹àµº ഓണാകàµà´•àµà´•.</translation>
<translation id="4570913071927164677">വിശദാംശങàµà´™àµ¾</translation>
<translation id="4645575059429386691">നിങàµà´™à´³àµà´Ÿàµ† à´°à´•àµà´·à´¿à´¤à´¾à´µàµ നിയനàµà´¤àµà´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> <ph name="APP_NAME" /> ആപàµà´ªà´¿à´¨à´¾à´¯à´¿ à´…à´¨àµà´®à´¤à´¿à´•àµ¾ ഓണാകàµà´•àµà´•.</translation>
-<translation id="945632385593298557">നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯àµà´•</translation>
<translation id="965817943346481315">സൈറàµà´±àµ, അനാവശàµà´¯à´®àµ‹ തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ‹ ആയ പരസàµà´¯à´™àµà´™à´³àµâ€ കാണികàµà´•àµà´¨àµà´¨àµà´£àµà´Ÿàµ†à´™àµà´•à´¿à´²àµâ€ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´• (à´¶àµà´ªà´¾à´°àµâ€à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ)</translation>
<translation id="967624055006145463">ഡാറàµà´± സംഭരിചàµà´šàµ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
index 4ec21881215..f28476314ac 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> нÑмÑÑн</translation>
<translation id="1383876407941801731">Хайлт</translation>
<translation id="1384959399684842514">Таталтыг түр зогÑооÑон</translation>
+<translation id="1415402041810619267">URL-г танаÑан</translation>
<translation id="1431402976894535801">Сайтуудыг таныг байгаа үед мÑдÑхийг нь блоклоно</translation>
<translation id="1446450296470737166">MIDI төхөөрөмжийг бүрÑн Ñ…Ñнахыг зөвшөөрөх</translation>
<translation id="1509960214886564027">Олон Ñайтын онцлогууд ажиллахгүй байж болзошгүй</translation>
<translation id="1620510694547887537">Камер</translation>
-<translation id="1647391597548383849">Камерт хандах</translation>
<translation id="1660204651932907780">Сайтуудад дуу тоглуулахыг зөвшөөрөх (Ñанал болгоÑон)</translation>
<translation id="1677097821151855053">Күүки болон Ñайтын буÑад өгөгдлийг таныг нÑвтрүүлÑÑ… ÑÑвÑл зарыг хувийн болгох зÑргÑÑÑ€ таныг Ñанахад ашигладаг. Бүх Ñайтын күүкийг удирдахын тулд <ph name="BEGIN_LINK" />Тохиргоог<ph name="END_LINK" /> харна уу.</translation>
<translation id="1688867105868176567">Сайтын өгөгдлийг уÑтгах уу?</translation>
@@ -39,23 +39,22 @@
<translation id="1994173015038366702">Сайтын URL</translation>
<translation id="2025115093177348061">ӨргөтгөÑөн бодит орчин</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> руу буцах бол товшино уу</translation>
+<translation id="2054665754582400095">Таны байгаа ÑÑÑÑ…</translation>
<translation id="2079545284768500474">Буцаах</translation>
<translation id="2091887806945687916">Дуу</translation>
<translation id="2107397443965016585">Сайтад хамгаалагдÑан контент тоглуулахыг Ð·Ó©Ð²ÑˆÓ©Ó©Ñ€Ó©Ñ…Ó©Ó©Ñ Ó©Ð¼Ð½Ó© аÑуух (Ñанал болгоÑон)</translation>
<translation id="2146738493024040262">Шуурхай апп-г нÑÑÑ…</translation>
<translation id="2148716181193084225">Өнөөдөр</translation>
<translation id="2182457891543959921">Сайтуудад таны ÑргÑн тойрны 3D газрын зургийг Ò¯Ò¯ÑгÑÑ… ÑÑвÑл камерын хөдөлгөөнийг Ñ…Ñнахыг зөвшөөрөхийн өмнө аÑуух (Ñанал болгоÑон)</translation>
-<translation id="2187243482123994665">Ð¥ÑÑ€ÑглÑгч байгаа ÑÑÑÑ…</translation>
<translation id="2212565012507486665">Күүкиг зөвшөөрөх</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />-д камертаа хандахыг зөвшөөрөхийн тулд камерыг мөн <ph name="BEGIN_LINK" />Ðндройдын тохиргоо<ph name="END_LINK" />-нд аÑаана уу.</translation>
<translation id="2241634353105152135">Ганц удаа</translation>
<translation id="2289270750774289114">Сайт ойролцоох Bluetooth төхөөрөмжийг илрүүлÑÑ… Ñ…Ò¯ÑÑлтÑй үед аÑуух (Ñанал болгоÑон)</translation>
<translation id="2315043854645842844">ҮйлчлүүлÑгч талын Ñертификатын Ñонголтыг үйлдлийн ÑиÑтемÑÑÑ Ð´ÑмжÑÑгүй.</translation>
<translation id="2359808026110333948">Цааш</translation>
-<translation id="2402980924095424747"><ph name="MEGABYTES" /> мегабайт</translation>
+<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г зөвшөөрÑөн}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г зөвшөөрÑөн}}</translation>
<translation id="2434158240863470628">Татаж дууÑÑан <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Байршилд нÑвтрÑÑ…</translation>
<translation id="2482878487686419369">ÐœÑдÑгдÑл</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" />-Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð´Ð°Ð³</translation>
<translation id="2498359688066513246">ТуÑламж болон Ñанал Ñ…Ò¯ÑÑлт</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайтуудад мÑдрÑгчид хандахыг зөвшөөрөх (Ñанал болгоÑон)</translation>
<translation id="3295602654194328831">ÐœÑдÑÑллийг нуух</translation>
+<translation id="3328801116991980348">Сайтын мÑдÑÑлÑл</translation>
<translation id="3333961966071413176">Бүх харилцагч</translation>
<translation id="3386292677130313581">Сайтууд байршил мÑдÑÑ… зөвшөөрөл авах (Ñанал болгоÑон)</translation>
<translation id="3538390592868664640">Сайтуудад таны ÑргÑн тойрны 3D газрын зургийг Ò¯Ò¯ÑгÑÑ… ÑÑвÑл камерын хөдөлгөөнийг Ñ…Ñнахыг хориглох</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Сайтуудад хамгаалагдÑан контент тоглуулахыг зөвшөөрөх</translation>
<translation id="4468959413250150279">Тодорхой Ñайтын дууг хаана уу.</translation>
<translation id="4479647676395637221">Сайтууд камер ашиглах зөвшөөрөл авах (Ñанал болгоÑон)</translation>
+<translation id="4505788138578415521">URL-г өргөтгөÑөн</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" />-д таны микрофонд хандахыг зөвшөөрөхийн тулд микрофоныг мөн <ph name="BEGIN_LINK" />Ðндройдын тохиргоо<ph name="END_LINK" />-нд аÑаана уу.</translation>
<translation id="4570913071927164677">ДÑлгÑÑ€Ñнгүй</translation>
<translation id="4645575059429386691">ЭцÑг, ÑÑ… нь хариуцаж байна</translation>
@@ -138,7 +139,7 @@
<translation id="5048398596102334565">Сайтад хөдөлгөөн мÑдрÑгчид хандахыг зөвшөөрөх (Ñанал болгоÑон)</translation>
<translation id="5063480226653192405">Ðшиглалт</translation>
<translation id="5100237604440890931">ЗадарÑан, Ñнд дарж өргөтгөнө Ò¯Ò¯.</translation>
-<translation id="5123685120097942451">Ðууцлалтай чихтÑй хуудаÑ</translation>
+<translation id="5123685120097942451">Ðууцлалтай таб</translation>
<translation id="5197729504361054390">Таны Ñонгох харилцагчдыг <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-тай хуваалцана.</translation>
<translation id="528192093759286357">БүтÑн дÑлгÑцийн Ð³Ð¾Ñ€Ð¸Ð¼Ð¾Ð¾Ñ Ð³Ð°Ñ€Ð°Ñ…Ñ‹Ð½ тулд дÑÑÑ€ÑÑÑ Ð·Ó©Ó©Ð³Ó©Ó©Ð´, буцах товчлуурыг дарна уу.</translation>
<translation id="5300589172476337783">Харуулах</translation>
@@ -198,7 +199,7 @@
<translation id="6545864417968258051">Bluetooth Ñкан хийх</translation>
<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г блоклоÑон}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г блоклоÑон}}</translation>
<translation id="6561560012278703671">Илүү чимÑÑгүй меÑÑежийг ашиглах (мÑдÑгдлийн Ñануулгад танд Ñаад болохыг хориглодог)</translation>
-<translation id="6608650720463149374"><ph name="GIGABYTES" /> гигабайт</translation>
+<translation id="6608650720463149374"><ph name="GIGABYTES" /> ГБ</translation>
<translation id="6612358246767739896">ХамгаалагдÑан агуулга</translation>
<translation id="662080504995468778">ҮлдÑÑ…</translation>
<translation id="6643016212128521049">ЦÑвÑрлÑÑ…</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" />-н зөвшөөрлийг <ph name="BEGIN_LINK" />Ðндройдын тохиргоо<ph name="END_LINK" />-нд аÑаана уу.</translation>
-<translation id="945632385593298557">Микрофонд хандах</translation>
<translation id="965817943346481315">Сайт төвөгтÑй ÑÑвÑл хуурамч зар харуулÑан тохиолдолд блоклох (Ñанал болгоÑон)</translation>
<translation id="967624055006145463">ХадгалÑан өгөгдөл</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
index a71a1afa8eb..1490c9b5fae 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> साइट जोडली</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">डाउनलोडला विराम दिला</translation>
+<translation id="1415402041810619267">URL कापली गेली</translation>
<translation id="1431402976894535801">तà¥à¤®à¥à¤¹à¥€ डिवà¥à¤¹à¤¾à¤‡à¤¸ वापरत आहात हे साइटना कळू न देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤¯à¤¾ बà¥à¤²à¥‰à¤• करा</translation>
<translation id="1446450296470737166">MIDI डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤šà¥à¤¯à¤¾ पूरà¥à¤£ नियंतà¥à¤°à¤£à¤¾à¤¸ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾</translation>
<translation id="1509960214886564027">अनेक साइटवरील वैशिषà¥à¤Ÿà¥à¤¯à¤¾à¤‚मधà¥à¤¯à¥‡ खंड पडू शकतो</translation>
<translation id="1620510694547887537">कॅमेरा</translation>
-<translation id="1647391597548383849">तà¥à¤®à¤šà¤¾ कॅमेरा ॲकà¥à¤¸à¥‡à¤¸ करा</translation>
<translation id="1660204651932907780">साइटना धà¥à¤µà¤¨à¥€ पà¥à¤²à¥‡ करणà¥à¤¯à¤¾à¤šà¥€ परवानगी दà¥à¤¯à¤¾ (शिफारस केलेले)</translation>
<translation id="1677097821151855053">कà¥à¤•à¥€ आणि इतर साइट डेटा तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ लकà¥à¤·à¤¾à¤¤ ठेवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरला जातो, उदाहरणारà¥à¤¥, तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ साइन इन करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ किंवा जाहिराती परà¥à¤¸à¤¨à¤²à¤¾à¤‡à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€. सरà¥à¤µ साइटसाठी कà¥à¤•à¥€ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤•à¤°à¤¿à¤¤à¤¾ <ph name="BEGIN_LINK" />सेटिंगà¥à¤œ<ph name="END_LINK" /> पहा.</translation>
<translation id="1688867105868176567">साइट डेटा साफ करायचा?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">साइट URL</translation>
<translation id="2025115093177348061">ऑगमेंटेड रीअâ€à¥…लिटी</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> वर परत जाणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅप करा</translation>
+<translation id="2054665754582400095">तà¥à¤®à¤šà¥€ उपसà¥à¤¥à¤¿à¤¤à¥€</translation>
<translation id="2079545284768500474">पहिलà¥à¤¯à¤¾à¤¸à¤¾à¤°à¤–े करा</translation>
<translation id="2091887806945687916">धà¥à¤µà¤¨à¥€</translation>
<translation id="2107397443965016585">साइटना संरकà¥à¤·à¤¿à¤¤ आशय पà¥à¤²à¥‡ करू देणà¥à¤¯à¤¾à¤†à¤§à¥€ विचारा (शिफारस केली जाते)</translation>
<translation id="2146738493024040262">à¤à¤Ÿà¤ªà¤Ÿ ॲपà¥à¤¸ उघडा</translation>
<translation id="2148716181193084225">आज</translation>
<translation id="2182457891543959921">साइटना तà¥à¤®à¤šà¥à¤¯à¤¾ आसपासचà¥à¤¯à¤¾ परिसराचा 3D नकाशा तयार करू किंवा कॅमेरà¥â€à¤¯à¤¾à¤šà¥‡ सà¥à¤¥à¤¾à¤¨ टà¥à¤°à¥…क करू देणà¥à¤¯à¤¾à¤†à¤§à¥€ विचारा (शिफारस केलेले)</translation>
-<translation id="2187243482123994665">वापरकरà¥à¤¤à¥à¤¯à¤¾à¤šà¥€ ॲकà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€</translation>
<translation id="2212565012507486665">कà¥à¤•à¥€à¤‚ना अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ला तà¥à¤®à¤šà¤¾ कॅमेरा ॲकà¥à¤¸à¥‡à¤¸ करू देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, <ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡à¤¦à¥‡à¤–ील कॅमेरा सà¥à¤°à¥‚ करा.</translation>
<translation id="2241634353105152135">फकà¥à¤¤ à¤à¤•à¤¦à¤¾à¤š</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ला अनà¥à¤®à¤¤à¥€ दिली}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ना अनà¥à¤®à¤¤à¥€ दिली}}</translation>
<translation id="2434158240863470628">डाउनलोड पूरà¥à¤£ à¤à¤¾à¤²à¥‡ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">सà¥à¤¥à¤¾à¤¨ ॲकà¥à¤¸à¥‡à¤¸</translation>
<translation id="2482878487686419369">सूचना</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> दà¥à¤µà¤¾à¤°à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले आहे</translation>
<translation id="2498359688066513246">मदत आणि अभिपà¥à¤°à¤¾à¤¯</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">मायकà¥à¤°à¥‹à¤«à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटना सेनà¥à¤¸à¤° ॲकà¥à¤¸à¥‡à¤¸ करणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾ (शिफारस केलेले)</translation>
<translation id="3295602654194328831">माहिती लपवा</translation>
+<translation id="3328801116991980348">साइट माहिती</translation>
<translation id="3333961966071413176">सरà¥à¤µ संपरà¥à¤•</translation>
<translation id="3386292677130313581">साइटना तà¥à¤®à¤šà¥‡ सà¥à¤¥à¤¾à¤¨ जाणून घेणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ विचारा (शिफारस केलेले)</translation>
<translation id="3538390592868664640">तà¥à¤®à¤šà¥à¤¯à¤¾ आसपासचà¥à¤¯à¤¾ परिसराचा 3D नकाशा तयार करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न किंवा कॅमेरà¥â€à¤¯à¤¾à¤šà¥‡ सà¥à¤¥à¤¾à¤¨ टà¥à¤°à¥…क करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न साइट बà¥à¤²à¥‰à¤• करा</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">साइटना संरकà¥à¤·à¤¿à¤¤Â à¤†à¤¶à¤¯Â à¤ªà¥à¤²à¥‡Â à¤•à¤°à¥‚ दà¥à¤¯à¤¾</translation>
<translation id="4468959413250150279">विशिषà¥à¤Ÿ साइटसाठी धà¥à¤µà¤¨à¥€ मà¥à¤¯à¥‚ट करा.</translation>
<translation id="4479647676395637221">साइटना तà¥à¤®à¤šà¤¾ कॅमेरा वापरणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ पà¥à¤°à¤¥à¤® विचारा (शिफारस केलेले)</translation>
+<translation id="4505788138578415521">URL चा विसà¥à¤¤à¤¾à¤° केला गेला</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ला तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ ॲकà¥à¤¸à¥‡à¤¸ करू देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, <ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡à¤¦à¥‡à¤–ील मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ सà¥à¤°à¥‚ करा.</translation>
<translation id="4570913071927164677">तपशील</translation>
<translation id="4645575059429386691">आपलà¥à¤¯à¤¾ पालकांदà¥à¤µà¤¾à¤°à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¤ आले</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">बà¥à¤²à¥‚टूथ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥â€à¤¯à¥‡ <ph name="APP_NAME" /> साठी परवानगà¥à¤¯à¤¾ सà¥à¤°à¥‚ करा.</translation>
-<translation id="945632385593298557">तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ ॲकà¥à¤¸à¥‡à¤¸ करा</translation>
<translation id="965817943346481315">साइट अनाहूत किंवा दिशाभूल करणाऱà¥à¤¯à¤¾ जाहिराती दाखवत असलà¥à¤¯à¤¾à¤¸ बà¥à¤²à¥‰à¤• करा (शिफारस केलेले)</translation>
<translation id="967624055006145463">डेटा सà¥à¤Ÿà¥‹à¤…र केला</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
index a5d965b4500..4ea5e1aa5ce 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Tapak <ph name="SITE_NAME" /> telah ditambahkan</translation>
<translation id="1383876407941801731">Carian</translation>
<translation id="1384959399684842514">Muat turun dijeda</translation>
+<translation id="1415402041810619267">URL terpangkas</translation>
<translation id="1431402976894535801">Sekat tapak daripada mengetahui waktu anda ada</translation>
<translation id="1446450296470737166">Benarkan kawalan penuh peranti MIDI</translation>
<translation id="1509960214886564027">Ciri pada banyak tapak mungkin rosak</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Akses kamera anda</translation>
<translation id="1660204651932907780">Benarkan tapak untuk memainkan bunyi (disyorkan)</translation>
<translation id="1677097821151855053">Kuki dan data tapak lain digunakan untuk mengingat anda, misalnya untuk log anda masuk atau memperibadikan iklan. Untuk mengurus kuki bagi semua tapak, lihat <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Kosongkan data tapak?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL tapak</translation>
<translation id="2025115093177348061">Realiti tambahan</translation>
<translation id="2030769033451695672">Ketik untuk kembali kepada <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Kehadiran anda</translation>
<translation id="2079545284768500474">Buat asal</translation>
<translation id="2091887806945687916">Bunyi</translation>
<translation id="2107397443965016585">Tanya sebelum membenarkan tapak memainkan kandungan yang dilindungi (disyorkan)</translation>
<translation id="2146738493024040262">Buka Apl Segera</translation>
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2182457891543959921">Tanya sebelum membenarkan tapak membuat peta 3D bagi persekitaran anda atau menjejaki kedudukan kamera (disyorkan)</translation>
-<translation id="2187243482123994665">Kehadiran pengguna</translation>
<translation id="2212565012507486665">Benarkan kuki</translation>
<translation id="2228071138934252756">Untuk membolehkan <ph name="APP_NAME" /> mengakses kamera anda, hidupkan juga kamera dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Hanya sekali</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}}</translation>
<translation id="2434158240863470628">Muat turun selesai: <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Akses lokasi</translation>
<translation id="2482878487686419369">Pemberitahuan</translation>
<translation id="2490684707762498678">Diurus oleh <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Bantuan &amp; maklum balas</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Benarkan tapak mengakses penderia (disyorkan)</translation>
<translation id="3295602654194328831">Sembunyikan Maklumat</translation>
+<translation id="3328801116991980348">Maklumat tapak</translation>
<translation id="3333961966071413176">Semua kenalan</translation>
<translation id="3386292677130313581">Tanya sebelum membenarkan tapak mengetahui lokasi anda (disyorkan)</translation>
<translation id="3538390592868664640">Sekat tapak daripada membuat peta 3D bagi persekitaran anda atau menjejaki kedudukan kamera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Benarkan tapak memainkan kandungan yang dilindungi</translation>
<translation id="4468959413250150279">Redam bunyi untuk tapak tertentu.</translation>
<translation id="4479647676395637221">Tanya dahulu sebelum membenarkan tapak menggunakan kamera anda (disyorkan)</translation>
+<translation id="4505788138578415521">URL dikembangkan</translation>
<translation id="4534723447064627427">Untuk membolehkan <ph name="APP_NAME" /> mengakses mikrofon anda, hidupkan juga mikrofon dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Butiran</translation>
<translation id="4645575059429386691">Diurus oleh ibu bapa anda</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi}}</translation>
<translation id="913657688200966289">Hidupkan kebenaran untuk <ph name="APP_NAME" /> dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Akses mikrofon anda</translation>
<translation id="965817943346481315">Sekat jika tapak menyiarkan iklan yang mengganggu atau mengelirukan (disyorkan)</translation>
<translation id="967624055006145463">Data disimpan</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
index 7b08d23f522..263f1e7188c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">ဆိုက် <ph name="SITE_NAME" /> အား ထည့်á€á€²á€·á</translation>
<translation id="1383876407941801731">ရှာဖွေမှု</translation>
<translation id="1384959399684842514">ဒေါင်းလုဒ်လုပ်မှု ဆိုင်းငံ့ထားသည်</translation>
+<translation id="1415402041810619267">URL ကို ဖြá€á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
<translation id="1431402976894535801">သင်ရှိနေသည်ကို á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€žá€­á€á€¼á€„်းအား ပိá€á€ºá€‘ားရန်</translation>
<translation id="1446450296470737166">MIDI ကိရိယာများအား အပြည့်အဠထိန်းá€á€»á€¯á€•á€ºá€á€½á€„့် ပြုရန်</translation>
<translation id="1509960214886564027">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€á€±á€¬á€ºá€™á€»á€¬á€¸á€™á€»á€¬á€¸á€›á€¾á€­ á€á€”်ဆောင်မှုများ ရပ်သွားနိုင်သည်</translation>
<translation id="1620510694547887537">ကင်မရာ</translation>
-<translation id="1647391597548383849">သင့်ကင်မရာကို á€á€„်ကြည့်မည်</translation>
<translation id="1660204651932907780">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ အသံဖွင့်á€á€½á€„့်ပြုရန် (အကြံပြုထားသည်)</translation>
<translation id="1677097821151855053">သင့်ကို မှá€á€ºá€‘ားရန်အá€á€½á€€á€º ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€”ှင့် အá€á€¼á€¬á€¸ á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ အသုံးပြုပြီး ဥပမာ - သင့်ကို အကောင့်á€á€„်ပေးရန် သို့မဟုá€á€º စိá€á€ºá€€á€¼á€­á€¯á€€á€ºá€•á€¼á€„်ထားသော ကြော်ငြာများပြရန်ዠá€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸á€¡á€á€½á€€á€º ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ စီမံရန် <ph name="BEGIN_LINK" />ဆက်á€á€„်များ<ph name="END_LINK" /> ကို ကြည့်ပါá‹</translation>
<translation id="1688867105868176567">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ ရှင်းလင်းလိုပါသလားá‹</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ဆိုက် URL</translation>
<translation id="2025115093177348061">လွန်ကဲပကá€á€­á€¡á€žá€½á€„်</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> သို့ပြန်သွားရန် á€á€­á€¯á€·á€•á€«</translation>
+<translation id="2054665754582400095">သင်ရှိနေမှု</translation>
<translation id="2079545284768500474">á€á€…်ဆင့်နောက်ပြန်ရန်</translation>
<translation id="2091887806945687916">အသံ</translation>
<translation id="2107397443965016585">ကာကွယ်ထားသော အကြောင်းအရာကို ဖွင့်ရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်မပြုမီ á€á€½á€„့်á€á€±á€¬á€„်းပါ (အကြံပြုထားသည်)</translation>
<translation id="2146738493024040262">á€á€»á€€á€ºá€á€¼á€„်းသုံးအက်ပ်ကို ဖွင့်ရန်</translation>
<translation id="2148716181193084225">ယနေ့</translation>
<translation id="2182457891543959921">သင့်ပá€á€ºá€á€”်းကျင်á 3D မြေပုံဆွဲá€á€¼á€„်း သို့မဟုá€á€º ကင်မရာအနေအထား á€á€¼á€±á€›á€¬á€á€¶á€á€¼á€„်းá€á€­á€¯á€·á€¡á€á€½á€€á€º á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်မပြုမီ မေးမြန်းရန် (အကြံပြုထားသည်)</translation>
-<translation id="2187243482123994665">အသုံးပြုသူ ရှိနေမှု</translation>
<translation id="2212565012507486665">ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸ á€á€½á€„့်ပြုရန်</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> က သင့်ကင်မရာကို သုံးနိုင်ရန် <ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„်လည်း ကင်မရာကို ဖွင့်ပါá‹</translation>
<translation id="2241634353105152135">á€á€…်ကြိမ်သာ</translation>
@@ -55,14 +55,13 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> မီဂါဘိုက်</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯ á€á€½á€„့်ပြုထားသည်}other{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯ á€á€½á€„့်ပြုထားသည်}}</translation>
<translation id="2434158240863470628">ဒေါင်းလုဒ်လုပ်ပြီးပါပြီ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">á€á€Šá€ºá€”ေရာ ရယူသုံးမှု</translation>
<translation id="2482878487686419369">အကြောင်းကြားစာ</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> က စီမံá€á€”့်á€á€½á€²á€‘ားပါသည်</translation>
<translation id="2498359688066513246">အကူအညီ &amp; အကြံပြုá€á€»á€€á€º</translation>
<translation id="2501278716633472235">နောက်သို့ ပြန်ရန်</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{ကွá€á€ºá€€á€®á€¸ á á€á€¯ ကို ပိá€á€ºá€‘ားသည်}other{ကွá€á€ºá€€á€®á€¸ # á€á€¯ ကို ပိá€á€ºá€‘ားသည်}}</translation>
<translation id="2570922361219980984">ဤစက်ပစ္စည်းအá€á€½á€€á€ºá€œá€Šá€ºá€¸ á€á€Šá€ºá€”ေရာ အသုံးပြုá€á€½á€„့်ကို ပိá€á€ºá€‘ားသည်ዠ<ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„် áŽá€„်းကို ဖွင့်ပါá‹</translation>
-<translation id="257931822824936280">á€á€»á€²á€·á€‘ားá - á€á€±á€«á€€á€ºá€žá€­á€™á€ºá€¸á€›á€”် ကလစ်နှိပ်ပါ</translation>
+<translation id="257931822824936280">á€á€»á€²á€·á€‘ားá - á€á€±á€«á€€á€ºá€žá€­á€™á€ºá€¸á€›á€”် နှိပ်ပါ</translation>
<translation id="2586657967955657006">ကလစ်ဘုá€á€º</translation>
<translation id="2621115761605608342">á€á€­á€€á€»á€žá€Šá€·á€ºá€†á€­á€¯á€€á€ºá€¡á€á€½á€€á€º JavaScript ကိုá€á€½á€„့်ပြုပါá‹</translation>
<translation id="2653659639078652383">ပေးပို့ရန်</translation>
@@ -71,7 +70,7 @@
<translation id="2704606927547763573">ကူးယူပြီးပါပြီ</translation>
<translation id="2717722538473713889">အီးမေးလ်လိပ်စာများ</translation>
<translation id="2822354292072154809"><ph name="CHOSEN_OBJECT_NAME" /> အá€á€½á€€á€º á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€½á€„့်ပြုá€á€»á€€á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸á€€á€­á€¯ ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€œá€­á€¯á€žá€Šá€ºá€™á€¾á€¬ သေá€á€»á€¬á€žá€œá€¬á€¸á‹</translation>
-<translation id="2870560284913253234">ဆိုဒ်</translation>
+<translation id="2870560284913253234">ဆိုက်</translation>
<translation id="2874939134665556319">ယá€á€„်á€á€…်ပုဒ်</translation>
<translation id="2903493209154104877">လိပ်စာများ</translation>
<translation id="2910701580606108292">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ ကာကွယ်ထားသည့် အကြောင်းအရာများကို ပြသá€á€½á€„့် မပြုမီ ဦးစွာ မေးပါ</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">မိုက်á€á€›á€­á€¯á€–ုန်း</translation>
<translation id="3277252321222022663">အာရုံá€á€¶á€…နစ်များ အသုံးပြုရန် ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်ပြုသည် (အကြံပြုထားသည်)</translation>
<translation id="3295602654194328831">အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ဖျောက်ထားရန်</translation>
+<translation id="3328801116991980348">ဆိုက် အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="3333961966071413176">အဆက်အသွယ်အားလုံး</translation>
<translation id="3386292677130313581">သင့်á€á€Šá€ºá€”ေရာကို ဆိုက်များအား အသိမပေးမီ မေးပါ (အကြံပြုထားသည်)</translation>
<translation id="3538390592868664640">သင့်ပá€á€ºá€á€”်းကျင်á 3D မြေပုံဆွဲá€á€¼á€„်း သို့မဟုá€á€º ကင်မရာအနေအထား á€á€¼á€±á€›á€¬á€á€¶á€á€¼á€„်းá€á€­á€¯á€· မပြုလုပ်ရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€‘ားသည်</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ကာကွယ်ထားသော အကြောင်းအရာများ ဖွင့်ရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ï¿½ á€á€½á€„့်ပြုသည်</translation>
<translation id="4468959413250150279">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€…်á€á€¯á€¡á€á€½á€€á€º အသံá€á€­á€á€ºá€‘ားသည်á‹</translation>
<translation id="4479647676395637221">သင့်ကမရာကို ဆိုက်များအား အသုံးပြုá€á€½á€„့်မပေးမီ ဦးစွာမေးမြန်းပါ (အကြံပြုထားသည်)</translation>
+<translation id="4505788138578415521">URL ကို á€á€»á€²á€·á€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> က သင့်မိုက်á€á€›á€­á€¯á€–ုန်းကို သုံးနိုင်ရန် <ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„်လည်း မိုက်á€á€›á€­á€¯á€–ုန်း ဖွင့်ပါá‹</translation>
<translation id="4570913071927164677">အသေးစိá€á€º</translation>
<translation id="4645575059429386691">သင့်မိဘမှ စီမံသည်</translation>
@@ -137,7 +138,7 @@
<translation id="5039804452771397117">á€á€½á€„့်ပြုရန်</translation>
<translation id="5048398596102334565">အာရုံá€á€¶á€…နစ်များ အသုံးပြုရန် ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်ပြုသည် (အကြံပြုထားသည်)</translation>
<translation id="5063480226653192405">အသုံးပြုပုံ</translation>
-<translation id="5100237604440890931">á€á€»á€¯á€¶á€·á€‘ားá - á€á€»á€²á€·á€›á€”် ကလစ်နှိပ်ပါá‹</translation>
+<translation id="5100237604440890931">á€á€»á€¯á€¶á€·á€‘ားá - á€á€»á€²á€·á€›á€”် နှိပ်ပါá‹</translation>
<translation id="5123685120097942451">ရုပ်ဖျက်á€á€˜á€º</translation>
<translation id="5197729504361054390">သင်ရွေးá€á€»á€šá€ºá€žá€±á€¬ အဆက်အသွယ်များကို <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> နှင့် မျှá€á€±á€•á€«á€™á€Šá€ºá‹</translation>
<translation id="528192093759286357">မျက်နှာပြင်အပြည့်ဖွင့်á€á€¼á€„်းမှ ထွက်ရန် ထိပ်ဆုံးမှဆွဲá€á€»á€€á€¬ နောက်ဆုá€á€ºá€›á€”်á€á€œá€¯á€á€ºá€€á€­á€¯ နှိပ်ပါá‹</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ဘလူးá€á€¯á€žá€º</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯}other{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„် <ph name="APP_NAME" /> အá€á€½á€€á€º á€á€½á€„့်ပြုá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ဖွင့်ပါá‹</translation>
-<translation id="945632385593298557">သင့်မိုက်အား အသုံးပြုမည်</translation>
<translation id="965817943346481315">စိá€á€ºá€¡á€”ှောင့်အယှက်ဖြစ်စေသော (သို့) အထင်အမြင်မှားစေသော ကြော်ငြာများ ပြလျှင် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€€á€­á€¯ ပိá€á€ºá€žá€Šá€º (အကြံပြုထားသည်)</translation>
<translation id="967624055006145463">သိမ်းဆည်းထားသည့် ဒေá€á€¬</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
index 992cb1a299d..b3a996e8878 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">साइट <ph name="SITE_NAME" /> थपियो</translation>
<translation id="1383876407941801731">खोजà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1384959399684842514">डाउनलोड रोकिà¤à¤•à¥‹ छ</translation>
+<translation id="1415402041810619267">URL छोटो बनाइयो</translation>
<translation id="1431402976894535801">साइटहरूलाई तपाईं कहिले यनà¥à¤¤à¥à¤° पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› भनà¥à¤¨à¥‡ कà¥à¤°à¤¾ थाहा पाउन नदिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1446450296470737166">MIDI यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚को पूरà¥à¤£ नियनà¥à¤¤à¥à¤°à¤£à¤²à¤¾à¤ˆ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1509960214886564027">कयौठसाइटका सà¥à¤µà¤¿à¤§à¤¾à¤¹à¤°à¥‚ले काम नगरà¥à¤¨ सकà¥à¤›à¤¨à¥</translation>
<translation id="1620510694547887537">कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾</translation>
-<translation id="1647391597548383849">आफà¥à¤¨à¥‹ कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पहà¥à¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1660204651932907780">साइटहरूलाई आवाज पà¥à¤²à¥‡ गरà¥à¤¨ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="1677097821151855053">कà¥à¤•à¥€ र साइटका अनà¥à¤¯ डेटा तपाईंको जानकारी याद राखà¥à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरिनà¥à¤›à¤¨à¥à¥¤ जसà¥à¤¤à¥ˆ, कà¥à¤•à¥€ र साइटका अनà¥à¤¯ डेटा तपाईंलाई साइन इन गराउन वा तपाईंको चाखअनà¥à¤¸à¤¾à¤°à¤•à¤¾ विजà¥à¤žà¤¾à¤ªà¤¨ देखाउन पà¥à¤°à¤¯à¥‹à¤— गरिनà¥à¤›à¤¨à¥à¥¤ सबै साइटका कà¥à¤•à¥€à¤¹à¤°à¥‚ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ <ph name="BEGIN_LINK" />सेटिङ<ph name="END_LINK" />मा जानà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="1688867105868176567">साइटको डेटा खाली गरà¥à¤¨à¥‡ हो?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">साइट URL</translation>
<translation id="2025115093177348061">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटी</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> मा फरà¥à¤•à¤¨ टà¥à¤¯à¤¾à¤ª गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2054665754582400095">तपाईंको उपसà¥à¤¥à¤¿à¤¤à¤¿</translation>
<translation id="2079545284768500474">अनà¥à¤¡à¥‚ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2091887806945687916">आवाज</translation>
<translation id="2107397443965016585">साइटहरूलाई संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤…घि सोधà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="2146738493024040262">तातà¥à¤•à¤¾à¤²à¤¿à¤• à¤à¤ª खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2148716181193084225">आज</translation>
<translation id="2182457891543959921">साइटहरूलाई आफू वरपरको ठाउà¤à¤•à¥‹ 3D नकà¥à¤¸à¤¾ बनाउन वा कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾à¤•à¥‹ अवसà¥à¤¥à¤¾ पतà¥à¤¤à¤¾ लगाउन दिनà¥à¤…घि मलाई सोधियोसॠ(सिफारिस गरिà¤à¤•à¥‹)</translation>
-<translation id="2187243482123994665">पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾à¤•à¥‹ उपसà¥à¤¥à¤¿à¤¤à¤¿</translation>
<translation id="2212565012507486665">कà¥à¤•à¥€à¤¹à¤°à¥‚लाई अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> लाई आफà¥à¤¨à¥‹ कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ दिन <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पनि अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="2241634353105152135">à¤à¤•à¤ªà¤Ÿà¤• मातà¥à¤°</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¤à¤®.बि.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सà¥à¤µà¤¿à¤§à¤¾à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ अनà¥à¤®à¤¤à¤¿ दिइà¤à¤•à¥‹ छ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सà¥à¤µà¤¿à¤§à¤¾à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ अनà¥à¤®à¤¤à¤¿ दिइà¤à¤•à¥‹ छ}}</translation>
<translation id="2434158240863470628">डाउनलोड समà¥à¤ªà¤¨à¥à¤¨ भयो <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">सà¥à¤¥à¤¾à¤¨ पहà¥à¤à¤š</translation>
<translation id="2482878487686419369">सूचनाहरू</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ले वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरेको</translation>
<translation id="2498359688066513246">मदà¥à¤¦à¤¤ र पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">माइकà¥à¤°à¥‹à¤«à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटहरूलाई सेनà¥à¤¸à¤°à¤¹à¤°à¥‚माथि पहà¥à¤à¤š राखà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="3295602654194328831">जानकारी लà¥à¤•à¤¾à¤‰à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3328801116991980348">साइट जानकारी</translation>
<translation id="3333961966071413176">सबै समà¥à¤ªà¤°à¥à¤•à¤¹à¤°à¥‚</translation>
<translation id="3386292677130313581">साइटहरूलाई तपाईà¤à¤•à¥‹ सà¥à¤¥à¤¾à¤¨ थाहा पाउने अनà¥à¤®à¤¤à¤¿ दिनॠभनà¥à¤¦à¤¾ पहिले तपाईà¤à¤²à¤¾à¤ˆ सोधà¥à¤¨à¥‡ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="3538390592868664640">साइटहरूलाई आफू वरपरको ठाउà¤à¤•à¥‹ 3D नकà¥à¤¸à¤¾ बनाउन वा कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾à¤•à¥‹ अवसà¥à¤¥à¤¾ पतà¥à¤¤à¤¾ लगाउन नदिनà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">साइटहरूलाई संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4468959413250150279">निशà¥à¤šà¤¿à¤¤ साइटको धà¥à¤µà¤¨à¤¿ मà¥à¤¯à¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="4479647676395637221">साइटहरूलाई तपाईà¤à¤•à¥‹ कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤­à¤¨à¥à¤¦à¤¾ पहिले तपाईà¤à¤²à¤¾à¤ˆ सोधà¥à¤¨à¥‡ (सिफारिस गरिà¤à¤•à¥‹)</translation>
+<translation id="4505788138578415521">URL विसà¥à¤¤à¥ƒà¤¤ गरियो</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> लाई आफà¥à¤¨à¥‹ माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ दिन <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पनि अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="4570913071927164677">विवरणहरू</translation>
<translation id="4645575059429386691">तपाईà¤à¤•à¥‹ अविभावक दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¬à¤¨à¥à¤§ गरिà¤à¤•à¥‹</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">बà¥à¤²à¥à¤Ÿà¥à¤¥</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई <ph name="APP_NAME" /> लाई अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
-<translation id="945632385593298557">आफà¥à¤¨à¥‹ माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पहà¥à¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="965817943346481315">साइटले हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¤¾à¤°à¥€ वा भà¥à¤°à¤¾à¤®à¤• विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ देखाà¤à¤®à¤¾ तà¥à¤¯à¤¸à¤²à¤¾à¤ˆ रोक लगाउनà¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="967624055006145463">डेटा भणà¥à¤¡à¤¾à¤°à¤£ गरियो</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
index be5009a2d2f..26a1b0e4124 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> toegevoegd</translation>
<translation id="1383876407941801731">Zoeken</translation>
<translation id="1384959399684842514">Download onderbroken</translation>
+<translation id="1415402041810619267">URL afgekapt</translation>
<translation id="1431402976894535801">Voorkomen dat sites weten wanneer je aanwezig bent</translation>
<translation id="1446450296470737166">Volledig beheer van MIDI-apparaten toestaan</translation>
<translation id="1509960214886564027">Functies op veel sites werken mogelijk niet meer</translation>
<translation id="1620510694547887537">Camera</translation>
-<translation id="1647391597548383849">Toegang tot camera</translation>
<translation id="1660204651932907780">Toestaan dat sites geluid afspelen (aanbevolen)</translation>
<translation id="1677097821151855053">Cookies en andere sitegegevens worden gebruikt om je te onthouden, bijvoorbeeld voor inloggen of gepersonaliseerde advertenties. Ga naar <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" /> om de cookies voor alle sites te beheren.</translation>
<translation id="1688867105868176567">Sitegegevens wissen?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Site-URL</translation>
<translation id="2025115093177348061">Augmented reality</translation>
<translation id="2030769033451695672">Tik om terug te gaan naar <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Je aanwezigheid</translation>
<translation id="2079545284768500474">Ongedaan maken</translation>
<translation id="2091887806945687916">Geluid</translation>
<translation id="2107397443965016585">Vragen voordat sites beschermde content mogen afspelen (aanbevolen)</translation>
<translation id="2146738493024040262">Instant-app openen</translation>
<translation id="2148716181193084225">Vandaag</translation>
<translation id="2182457891543959921">Vragen voordat sites een 3D-kaart van je omgeving mogen maken of de camerapositie mogen volgen (aanbevolen)</translation>
-<translation id="2187243482123994665">Aanwezigheid van gebruiker</translation>
<translation id="2212565012507486665">Cookies toestaan</translation>
<translation id="2228071138934252756">Als je <ph name="APP_NAME" /> toegang wilt geven tot je camera, moet je de camera ook inschakelen via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Slechts één keer</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}}</translation>
<translation id="2434158240863470628">Download voltooid <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Locatietoegang</translation>
<translation id="2482878487686419369">Meldingen</translation>
<translation id="2490684707762498678">Beheerd door <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hulp en feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microfoon</translation>
<translation id="3277252321222022663">Sites toegang geven tot sensoren (aanbevolen)</translation>
<translation id="3295602654194328831">Informatie verbergen</translation>
+<translation id="3328801116991980348">Site-informatie</translation>
<translation id="3333961966071413176">Alle contacten</translation>
<translation id="3386292677130313581">Vragen of je sites toegang wilt verlenen tot je locatie (aanbevolen)</translation>
<translation id="3538390592868664640">Voorkomen dat sites een 3D-kaart van je omgeving maken of de camerapositie volgen</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Sites toestaan om beschermde content af te spelen</translation>
<translation id="4468959413250150279">Geluid dempen voor een specifieke site.</translation>
<translation id="4479647676395637221">Eerst vragen voordat sites je camera mogen gebruiken (aanbevolen)</translation>
+<translation id="4505788138578415521">URL uitgevouwen</translation>
<translation id="4534723447064627427">Als je <ph name="APP_NAME" /> toegang wilt geven tot je microfoon, moet je de microfoon ook inschakelen via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Details</translation>
<translation id="4645575059429386691">Beheerd door je ouder</translation>
@@ -182,7 +183,7 @@
<translation id="6177111841848151710">Geblokkeerd voor de huidige zoekmachine</translation>
<translation id="6181444274883918285">Site-uitzondering toevoegen</translation>
<translation id="6192792657125177640">Uitzonderingen</translation>
-<translation id="6196640612572343990">Indirecte cookies blokkeren</translation>
+<translation id="6196640612572343990">Cookies van derden blokkeren</translation>
<translation id="6206551242102657620">De verbinding is beveiligd. Site-informatie</translation>
<translation id="6216432067784365534">Opties voor <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="6262279340360821358"><ph name="PERMISSION_1" /> en <ph name="PERMISSION_2" /> geblokkeerd</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Schakel rechten in voor <ph name="APP_NAME" /> via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Toegang tot je microfoon</translation>
<translation id="965817943346481315">Blokkeren als site opdringerige of misleidende advertenties weergeeft (aanbevolen)</translation>
<translation id="967624055006145463">Opgeslagen gegevens</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
index 73a9ae2e34c..75e5c9b5e5b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Nettstedet <ph name="SITE_NAME" /> er lagt til</translation>
<translation id="1383876407941801731">Søk</translation>
<translation id="1384959399684842514">Nedlastingen er satt på pause</translation>
+<translation id="1415402041810619267">Nettadressen er avkortet</translation>
<translation id="1431402976894535801">Blokkér nettsteder fra å vite når du er til stede</translation>
<translation id="1446450296470737166">Full kontroll over MIDI-enheter</translation>
<translation id="1509960214886564027">Det kan hende at funksjoner på mange nettsteder slutter å fungere</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Tilgang til kameraet ditt</translation>
<translation id="1660204651932907780">Tillat nettsteder å spille av lyd (anbefales)</translation>
<translation id="1677097821151855053">Informasjonskapsler og andre nettstedsdata brukes til å huske deg, for eksempel for å logge deg på eller for å vise deg personlig tilpassede annonser. For å administrere informasjonskapsler for alle nettsteder, se <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vil du fjerne nettstedsdata?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Nettadressen til nettstedet</translation>
<translation id="2025115093177348061">Utvidet virkelighet</translation>
<translation id="2030769033451695672">Trykk for å gå tilbake til <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Tilstedeværelsen din</translation>
<translation id="2079545284768500474">Angre</translation>
<translation id="2091887806945687916">Lyd</translation>
<translation id="2107397443965016585">Spør før nettsteder får tillatelse til å spille beskyttet innhold (anbefalt)</translation>
<translation id="2146738493024040262">Ã…pne instant-appen</translation>
<translation id="2148716181193084225">I dag</translation>
<translation id="2182457891543959921">Spør før nettsteder får lage 3D-kart av omgivelsene dine eller spore kameraposisjonen (anbefales)</translation>
-<translation id="2187243482123994665">Brukertilstedeværelse</translation>
<translation id="2212565012507486665">Tillat informasjonskapsler</translation>
<translation id="2228071138934252756">For å gi <ph name="APP_NAME" /> tilgang til kameraet må du også slå på kameraet i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bare én gang</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}}</translation>
<translation id="2434158240863470628">Nedlasting fullført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Posisjonstilgang</translation>
<translation id="2482878487686419369">Varsler</translation>
<translation id="2490684707762498678">Administreres av <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hjelp og tilbakemelding</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Gi nettsteder tilgang til sensorer (anbefalt)</translation>
<translation id="3295602654194328831">Skjul informasjonen</translation>
+<translation id="3328801116991980348">Informasjon om nettstedet</translation>
<translation id="3333961966071413176">Alle kontakter</translation>
<translation id="3386292677130313581">Spør før nettsteder får vite posisjonen min (anbefales)</translation>
<translation id="3538390592868664640">Blokkér nettsteder fra å lage 3D-kart av omgivelsene dine eller spore kameraposisjonen</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Tillat at nettsteder kan spille beskyttet innhold</translation>
<translation id="4468959413250150279">Kutt lyden for et bestemt nettsted.</translation>
<translation id="4479647676395637221">Spør før nettsteder får bruke kameraet (anbefales)</translation>
+<translation id="4505788138578415521">Nettadressen er utvidet</translation>
<translation id="4534723447064627427">For å gi <ph name="APP_NAME" /> tilgang til mikrofonen må du også slå på mikrofonen i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detaljer</translation>
<translation id="4645575059429386691">Administreres av foreldrene dine</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til}}</translation>
<translation id="913657688200966289">Slå på tillatelser for <ph name="APP_NAME" /> i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Tilgang til mikrofonen din</translation>
<translation id="965817943346481315">Blokkér hvis nettstedet viser forstyrrende eller villedende annonser (anbefalt)</translation>
<translation id="967624055006145463">Lagrede data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
index cb46e9f39d9..486f39f878c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
@@ -6,7 +6,7 @@
<translation id="1124090076051167250">ଆପଣଙà­à¬• ମୂଳ ସà­à¬•à­à¬°à¬¿à¬¨à¬°à­‡ ସାଇଟୠକିମà­à¬¬à¬¾ ଆପଗà­à¬¡à¬¼à¬¿à¬• ଦà­à­±à¬¾à¬°à¬¾ ଷà­à¬Ÿà­‹à¬°à­ କରାଯାଇଥିବା <ph name="DATASIZE" /> ଡାଟା à¬à¬¬à¬‚ କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ à¬à¬¹à¬¾ ଖାଲି କରିଦେବ।</translation>
<translation id="1124772482545689468">ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾</translation>
<translation id="1178581264944972037">ବିରତି</translation>
-<translation id="1181037720776840403">ଅପସାରଣ</translation>
+<translation id="1181037720776840403">କାଢ଼ି ଦିଅନà­à¬¤à­</translation>
<translation id="1195941046451948919">à¬à¬¹à¬¿ ୱେବସାଇଟୠପାଇଠଆପଣ ସମସà­à¬¤ ଅନà­à¬®à¬¤à¬¿ ରିସେଟୠକରିବାକୠଚାହà­à¬à¬¥à¬¿à¬¬à¬¾ ନିଶà­à¬šà¬¿à¬¤ କି?</translation>
<translation id="1201402288615127009">ପରବରà­à¬¤à­à¬¤à­€</translation>
<translation id="1242008676835033345"><ph name="WEBSITE_URL" />ରେ à¬à¬®à­à¬¬à­‡à¬¡à­ କରାଯାଇଛି</translation>
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ସାଇଟୠଯୋଗ କରାଗଲା</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ଡାଉନà­â€Œà¬²à­‹à¬¡à­ ବିରତ ହୋଇଛି</translation>
+<translation id="1415402041810619267">URLକୠଛୋଟ କରାଯାଇଛି</translation>
<translation id="1431402976894535801">ଆପଣ କେତେବେଳେ ସକà­à¬°à¬¿à­Ÿ ହେବେ ତାହା ଜାଣିବାରୠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
<translation id="1446450296470737166">MIDI ଡିଭାଇସà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬° ପୂରà­à¬£à­à¬£ ନିୟନà­à¬¤à­à¬°à¬£à¬° ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="1509960214886564027">କିଛି ସାଇଟରେ ଫିଚରଗà­à¬¡à¬¼à¬¿à¬• ଠିକୠଭାବେ କାମ କରିନପାରେ</translation>
<translation id="1620510694547887537">କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾</translation>
-<translation id="1647391597548383849">ଆପଣଙà­à¬•à¬° କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ଆକà­à¬¸à­‡à¬¸à­â€Œ କରନà­à¬¤à­</translation>
<translation id="1660204651932907780">ସାଉଣà­à¬¡ ଚାଲୠକରିବାକୠସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­ କରାଯାଇଛି)</translation>
<translation id="1677097821151855053">ଆପଣଙà­à¬•à­ ସାଇନୠଇନୠକରିବା କିମà­à¬¬à¬¾ ବିଜà­à¬žà¬¾à¬ªà¬¨à¬—à­à­œà¬¿à¬•à­ ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତକୃତ କରିବା ପରି, ଆପଣଙà­à¬• ସୂଚନା ମନେରଖିବା ପାଇଠକà­à¬•à­€ à¬à¬¬à¬‚ ଅନà­à­Ÿ ସାଇଟୠଡାଟା ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇଥାà¬à¥¤ ସମସà­à¬¤ ସାଇଟୠପାଇଠକà­à¬•à­€à¬—à­à­œà¬¿à¬• ପରିଚାଳନା କରିବାକà­, <ph name="BEGIN_LINK" />ସେଟିଂସà­<ph name="END_LINK" /> ଦେଖନà­à¬¤à­à¥¤</translation>
<translation id="1688867105868176567">ସାଇଟà­â€ ଡାଟା ଖାଲି କରିବେ?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ସାଇଟୠURL</translation>
<translation id="2025115093177348061">ଅଗମେଣà­à¬Ÿà­‡à¬¡à­ ରିଆଲିଟୀ</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" />କୠଫେରିବା ପାଇଠଟାପୠକରନà­à¬¤à­</translation>
+<translation id="2054665754582400095">ଆପଣଙà­à¬• ଉପସà­à¬¥à¬¿à¬¤à¬¿</translation>
<translation id="2079545284768500474">ପୂରà­à¬¬à¬¬à¬¤à­</translation>
<translation id="2091887806945687916">ଧà­à­±à¬¨à¬¿</translation>
<translation id="2107397443965016585">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­à¬•à­(ସà­à¬ªà¬¾à¬°à¬¿à¬¸à­ କରାଯାଇଥିବା) ଚଲାଇବା ପାଇଠସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­, ପଚାରନà­à¬¤à­</translation>
<translation id="2146738493024040262">ଇନà­â€Œà¬·à­à¬Ÿà¬¾à¬£à­à¬Ÿ ଆପୠଖୋଲନà­à¬¤à­</translation>
<translation id="2148716181193084225">ଆଜି</translation>
<translation id="2182457891543959921">ଆପଣଙà­à¬• ପରିପାରà­à¬¶à­à­±à¬° à¬à¬• 3D ମà­à­Ÿà¬¾à¬ªà­ ତିଆରି କରିବା à¬à¬¬à¬‚ କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ସà­à¬¥à¬¿à¬¤à¬¿ ଟà­à¬°à¬¾à¬•à­ କରିବାକୠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
-<translation id="2187243482123994665">ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾à¬™à­à¬• ସକà­à¬°à¬¿à­Ÿà¬¤à¬¾</translation>
<translation id="2212565012507486665">କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />କୠଆପଣଙà­à¬• କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ଆକà­à¬¸à­‡à¬¸à­ ଦେବା ପାଇà¬, <ph name="BEGIN_LINK" />Android ସେଟିଂସ<ph name="END_LINK" />ରେ କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ମଧà­à­Ÿ ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
<translation id="2241634353105152135">ଥରେ ମାତà­à¬°</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, à¬à¬¬à¬‚ ଅଧିକ <ph name="NUM_MORE" />ଟିକୠଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, à¬à¬¬à¬‚ ଅଧିକ <ph name="NUM_MORE" />ଟିକୠଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି}}</translation>
<translation id="2434158240863470628">ଡାଉନà­â€Œà¬²à­‹à¬¡à­ ଶେଷ ହେଲା <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ଲୋକେସନୠଆକà­à¬¸à­‡à¬¸à­</translation>
<translation id="2482878487686419369">ବିଜà­à¬žà¬ªà­à¬¤à¬¿</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ଦà­à­±à¬¾à¬°à¬¾ ପରିଚାଳିତ</translation>
<translation id="2498359688066513246">ସାହାଯà­à­Ÿ ଓ ମତାମତ</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­</translation>
<translation id="3277252321222022663">ସେନà­à¬¸à¬°à­ ଆକà­à¬¸à­‡à¬¸à­ କରିବାକୠସାଇଟà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
<translation id="3295602654194328831">ସୂଚନା ଲà­à¬šà¬¾à¬¨à­à¬¤à­</translation>
+<translation id="3328801116991980348">ସାଇଟà­â€Œ ସୂଚନା</translation>
<translation id="3333961966071413176">ସମସà­à¬¤ ଯୋଗାଯୋଗଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="3386292677130313581">ସାଇଟà­â€à¬—à­à­œà¬¿à¬• ଆପଣଙà­à¬•à¬° ଲୋକେସନà­â€Œ ଜାଣିବା ପୂରà­à¬¬à¬°à­ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­â€Œ କରାଯାଇଛି)</translation>
<translation id="3538390592868664640">ଆପଣଙà­à¬• ପରିପାରà­à¬¶à­à­±à¬° à¬à¬• 3D ମà­à­Ÿà¬¾à¬ªà­ ତିଆରି କରିବା à¬à¬¬à¬‚ କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ସà­à¬¥à¬¿à¬¤à¬¿ ଟà­à¬°à¬¾à¬•à­ କରିବାକୠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ସାଇଟà­â€à¬—à­à­œà¬¿à¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­ ଚଳାଇବାକୠଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="4468959413250150279">ଗୋଟିଠନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ସାଇଟୠପାଇଠସାଉଣà­à¬¡à¬•à­ ମà­à­Ÿà­à¬Ÿà­ କରନà­à¬¤à­à¥¤</translation>
<translation id="4479647676395637221">ଆପଣଙà­à¬•à¬° କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­, ପà­à¬°à¬¥à¬®à­‡ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
+<translation id="4505788138578415521">URLକୠବିସà­à¬¤à¬¾à¬° କରାଯାଇଛି</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" />କୠଆପଣଙà­à¬• ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ଆକà­à¬¸à­‡à¬¸à­ ଦେବା ପାଇà¬, <ph name="BEGIN_LINK" />Android ସେଟିଂସ<ph name="END_LINK" />ରେ ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ମଧà­à­Ÿ ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
<translation id="4570913071927164677">ବିବରଣୀ</translation>
<translation id="4645575059429386691">ଆପଣଙà­à¬•à¬° ଅଭିବାବକଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ପରିଚାଳିତ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ବà­à¬²à­à¬Ÿà­à¬¥à­</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ଓ ଅଧିକ <ph name="NUM_MORE" />ଟି}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ଓ ଅଧିକ <ph name="NUM_MORE" />ଟି}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ସେଟିଂସ<ph name="END_LINK" />ରେ <ph name="APP_NAME" /> ପାଇଠଅନà­à¬®à¬¤à¬¿ ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
-<translation id="945632385593298557">ଆପଣଙà­à¬•à¬° ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ଆକà­à¬¸à­‡à¬¸à­ କରନà­à¬¤à­</translation>
<translation id="965817943346481315">ଯଦି ସାଇଟୠଅନଧିକାର ପà­à¬°à¬¬à­‡à¬¶ କରିଥିବା କିମà­à¬¬à¬¾ ବିଭà­à¬°à¬¾à¬¨à­à¬¤à¬¿à¬•à¬° ବିଜà­à¬žà¬¾à¬ªà¬¨ ଦେଖାଉଛି, ତେବେ ବà­à¬²à¬•à­ କରନà­à¬¤à­(ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­ କରାଯାଇଛି)</translation>
<translation id="967624055006145463">ଡାଟା ଷà­à¬Ÿà­‹à¬°à­ କରାଯାଇଛି</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
index a8b18029485..cb465657ca4 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">ਸਾਈਟ <ph name="SITE_NAME" /> ਜੋੜੀ ਗਈ</translation>
<translation id="1383876407941801731">ਖੋਜੋ</translation>
<translation id="1384959399684842514">ਡਾਊਨਲੋਡ ਰੋਕਿਆ ਗਿਆ</translation>
+<translation id="1415402041810619267">URL ਛੋਟਾ ਕੀਤਾ ਗਿਆ</translation>
<translation id="1431402976894535801">ਸਾਈਟਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©€ ਮੌਜੂਦਗੀ ਬਾਰੇ ਜਾਣਨ ਤੋਂ ਰੋਕਣ ਲਈ ਬਲਾਕ ਕਰੋ</translation>
<translation id="1446450296470737166">MIDI ਡਿਵਾਈਸਾਂ ਦੇ ਪੂਰੇ ਨਿਯੰਤਰਣ ਦੀ ਆਗਿਆ ਦਿਓ</translation>
<translation id="1509960214886564027">ਸ਼ਾਇਦ ਕਈ ਸਾਈਟਾਂ 'ਤੇ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਠੀਕ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਨਾ ਕਰਨ</translation>
<translation id="1620510694547887537">ਕੈਮਰਾ</translation>
-<translation id="1647391597548383849">ਆਪਣੇ ਕੈਮਰੇ ਤੱਕ ਪਹà©à©°à¨šà©‹</translation>
<translation id="1660204651932907780">ਸਾਈਟਾਂ ਨੂੰ ਧà©à¨¨à©€ ਵਜਾਉਣ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="1677097821151855053">ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਹੋਰ ਸਾਈਟ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਯਾਦ ਰੱਖਣ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਉਦਾਹਰਨ ਦੇ ਤੌਰ 'ਤੇ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਜਾਂ ਵਿਗਿਆਪਨਾਂ ਨੂੰ ਵਿਅਕਤੀਗਤ ਬਣਾਉਣ ਲਈ। ਸਾਰੀਆਂ ਸਾਈਟਾਂ ਲਈ ਕà©à¨•à©€à©› ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ, <ph name="BEGIN_LINK" />ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਦੇਖੋ।</translation>
<translation id="1688867105868176567">ਕੀ ਸਾਈਟ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ ਹੈ?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ਸਾਈਟ URL</translation>
<translation id="2025115093177348061">ਆਗਮੈਂਟਿਡ ਰਿà¨à¨²à¨¿à¨Ÿà©€</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> 'ਤੇ ਵਾਪਸ ਜਾਣ ਲਈ ਟੈਪ ਕਰੋ</translation>
+<translation id="2054665754582400095">ਤà©à¨¹à¨¾à¨¡à©€ ਮੌਜੂਦਗੀ</translation>
<translation id="2079545284768500474">ਅਣਕੀਤਾ ਕਰੋ</translation>
<translation id="2091887806945687916">ਧà©à¨¨à©€</translation>
<translation id="2107397443965016585">ਸਾਈਟਾਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੀ ਸਮੱਗਰੀ ਚਲਾਉਣ ਦੇਣ ਤੋਂ ਪਹਿਲਾਂ ਪà©à©±à¨›à©‹ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="2146738493024040262">ਤਤਕਾਲ à¨à¨ª ਖੋਲà©à¨¹à©‹</translation>
<translation id="2148716181193084225">ਅੱਜ</translation>
<translation id="2182457891543959921">ਸਾਈਟਾਂ ਵੱਲੋਂ ਤà©à¨¹à¨¾à¨¡à©‡ ਆਲੇ-ਦà©à¨†à¨²à©‡ ਦਾ 3D ਨਕਸ਼ਾ ਬਣਾਉਣ ਜਾਂ ਕੈਮਰਾ ਸਥਿਤੀ ਨੂੰ ਟਰੈਕ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ ਤੋਂ ਪਹਿਲਾਂ ਪà©à©±à¨›à©‹ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
-<translation id="2187243482123994665">ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ</translation>
<translation id="2212565012507486665">ਕà©à¨•à©€à©› ਨੂੰ ਆਗਿਆ ਦਿਓ</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ਨੂੰ ਆਪਣੇ ਕੈਮਰੇ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦੇਣ ਲਈ, <ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਕੈਮਰਾ ਵੀ ਚਾਲੂ ਕਰੋ।</translation>
<translation id="2241634353105152135">ਸਿਰਫ ਇੱਕ ਵਾਰ</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}}</translation>
<translation id="2434158240863470628">ਡਾਊਨਲੋਡ ਮà©à¨•à©°à¨®à¨² ਹੋਇਆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪਹà©à©°à¨š</translation>
<translation id="2482878487686419369">ਸੂਚਨਾਵਾਂ</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ਵੱਲੋਂ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕੀਤਾ ਜਾਂਦਾ ਹੈ</translation>
<translation id="2498359688066513246">ਮਦਦ ਅਤੇ ਪà©à¨°à¨¤à©€à¨•à¨°à¨®</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨</translation>
<translation id="3277252321222022663">ਸਾਈਟਾਂ ਨੂੰ ਸੈਂਸਰਾਂ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="3295602654194328831">ਜਾਣਕਾਰੀ ਲà©à¨•à¨¾à¨“</translation>
+<translation id="3328801116991980348">ਸਾਈਟ ਜਾਣਕਾਰੀ</translation>
<translation id="3333961966071413176">ਸਭ ਸੰਪਰਕ</translation>
<translation id="3386292677130313581">ਸਾਈਟਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à¨¾ ਟਿਕਾਣਾ ਜਾਣਨ ਤੋਂ ਪਹਿਲਾਂ ਤà©à¨¹à¨¾à¨¡à©€ ਇਜਾਜ਼ਤ ਲੈਣ ਨੂੰ ਜ਼ਰੂਰੀ ਬਣਾਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="3538390592868664640">ਸਾਈਟਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©‡ ਆਲੇ-ਦà©à¨†à¨²à©‡ ਦਾ 3D ਨਕਸ਼ਾ ਬਣਾਉਣ ਜਾਂ ਕੈਮਰਾ ਸਥਿਤੀ ਨੂੰ ਟਰੈਕ ਕਰਨ ਤੋਂ ਬਲਾਕ ਕਰੋ</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">ਸਾਈਟਾਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੀ ਸਮੱਗਰੀ ਚਲਾਉਣ ਦਿਓ</translation>
<translation id="4468959413250150279">ਕਿਸੇ ਖਾਸ ਸਾਈਟ ਦੀ ਧà©à¨¨à©€ ਨੂੰ ਮਿਊਟ ਕਰੋ।</translation>
<translation id="4479647676395637221">ਸਾਈਟਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕੈਮਰੇ ਦੀ ਵਰਤੋਂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਤà©à¨¹à¨¾à¨¡à©€ ਇਜਾਜ਼ਤ ਲੈਣ ਨੂੰ ਜ਼ਰੂਰੀ ਬਣਾਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
+<translation id="4505788138578415521">URL ਦਾ ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ਨੂੰ ਆਪਣੇ ਮਾਈਕà©à¨°à©‹à¨«à¨¼à©‹à¨¨ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦੇਣ ਲਈ, <ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਮਾਈਕà©à¨°à©‹à¨«à¨¼à©‹à¨¨ ਵੀ ਚਾਲੂ ਕਰੋ।</translation>
<translation id="4570913071927164677">ਵੇਰਵੇ</translation>
<translation id="4645575059429386691">ਤà©à¨¹à¨¾à¨¡à©‡ ਮਾਤਾ ਜਾਂ ਪਿਤਾ ਵੱਲੋਂ ਵਿਵਸਥਿਤ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">ਬਲੂਟà©à©±à¨¥</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ <ph name="APP_NAME" /> ਲਈ ਇਜਾਜ਼ਤਾਂ ਚਾਲੂ ਕਰੋ।</translation>
-<translation id="945632385593298557">ਆਪਣੇ ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨ ਤੱਕ ਪਹà©à©°à¨šà©‹</translation>
<translation id="965817943346481315">ਜੇਕਰ ਸਾਈਟ ਦਖਲਅੰਦਾਜ਼ੀ ਅਤੇ ਗà©à¨®à¨°à¨¾à¨¹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀ ਹੈ, ਤਾਂ ਇਸਨੂੰ ਬਲਾਕ ਕਰੋ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="967624055006145463">ਸਟੋਰ ਕੀਤਾ ਡਾਟਾ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
index 366f7397ced..9e87c529a09 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Strona <ph name="SITE_NAME" /> została dodana</translation>
<translation id="1383876407941801731">Szukaj</translation>
<translation id="1384959399684842514">Pobieranie wstrzymane</translation>
+<translation id="1415402041810619267">URL obcięty</translation>
<translation id="1431402976894535801">Nie pozwalaj stronom sprawdzać, czy aktualnie używasz urządzenia</translation>
<translation id="1446450296470737166">Pełne sterowanie urządzeniami MIDI</translation>
<translation id="1509960214886564027">Funkcje wielu stron mogą nie działać prawidłowo</translation>
-<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Dostęp do kamery</translation>
+<translation id="1620510694547887537">Aparat</translation>
<translation id="1660204651932907780">Zezwalaj na odtwarzanie dźwięku na stronach internetowych (zalecane)</translation>
<translation id="1677097821151855053">Plików cookie i innych danych stron używamy, żeby Cię zapamiętać, na przykład w celu logowania czy personalizowania reklam. Plikami cookie wszystkich stron możesz zarządzać w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Wyczyścić dane witryn?</translation>
@@ -29,7 +29,7 @@
<translation id="1717218214683051432">Czujniki ruchu</translation>
<translation id="1743802530341753419">Pytaj, zanim zezwolisz stronom na połączenie z urządzeniem (zalecane)</translation>
<translation id="1779089405699405702">Dekoder obrazów</translation>
-<translation id="1818308510395330587">Aby w aplikacji <ph name="APP_NAME" /> można było korzystać z AR, włącz też aparat w <ph name="BEGIN_LINK" />ustawieniach Androida<ph name="END_LINK" />.</translation>
+<translation id="1818308510395330587">Aby w aplikacji <ph name="APP_NAME" /> można było korzystać z rzeczywistości rozszerzonej, włącz też aparat w <ph name="BEGIN_LINK" />ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="1887786770086287077">Dostęp do lokalizacji jest wyłączony na tym urządzeniu. Włącz go w <ph name="BEGIN_LINK" />Ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="1919345977826869612">Reklamy</translation>
<translation id="1919950603503897840">Wybierz kontakty</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL strony</translation>
<translation id="2025115093177348061">Rzeczywistość rozszerzona</translation>
<translation id="2030769033451695672">Kliknij, by wrócić na <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Twoja obecność</translation>
<translation id="2079545284768500474">Cofnij</translation>
<translation id="2091887806945687916">Dźwięk</translation>
<translation id="2107397443965016585">Pytaj, zanim pozwolisz stronom na odtwarzanie treści chronionej (zalecane)</translation>
<translation id="2146738493024040262">Otwórz aplikację błyskawiczną</translation>
<translation id="2148716181193084225">Dzisiaj</translation>
<translation id="2182457891543959921">Pytaj, zanim zezwolisz stronom na tworzenie mapy 3D Twojego otoczenia lub śledzenie pozycji kamery (zalecane)</translation>
-<translation id="2187243482123994665">Obecność użytkownika</translation>
<translation id="2212565012507486665">Zezwalaj na pliki cookie</translation>
<translation id="2228071138934252756">Aby zezwolić aplikacji <ph name="APP_NAME" /> na dostęp do aparatu, musisz go też włączyć w <ph name="BEGIN_LINK" />Ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tylko raz</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}few{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}many{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}other{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Ukończono pobieranie <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Dostęp do lokalizacji</translation>
<translation id="2482878487686419369">Powiadomienia</translation>
<translation id="2490684707762498678">ZarzÄ…dzane przez <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Pomoc i opinie</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Zezwalaj stronom na dostęp do czujników (zalecane)</translation>
<translation id="3295602654194328831">Ukryj informacje</translation>
+<translation id="3328801116991980348">Informacje o witrynie</translation>
<translation id="3333961966071413176">Wszystkie kontakty</translation>
<translation id="3386292677130313581">Pytaj, zanim udostępnisz stronom swoją lokalizację (zalecane)</translation>
<translation id="3538390592868664640">Nie zezwalaj stronom na tworzenie mapy 3D Twojego otoczenia ani na śledzenie pozycji kamery</translation>
@@ -103,7 +103,7 @@
<translation id="381841723434055211">Numery telefonów</translation>
<translation id="385051799172605136">Wstecz</translation>
<translation id="3859306556332390985">Przewiń do przodu</translation>
-<translation id="3955193568934677022">Zezwalaj witrynom na odtwarzanie treści chronionej (zalecane)</translation>
+<translation id="3955193568934677022">Zezwalaj stronom na odtwarzanie treści chronionej (zalecane)</translation>
<translation id="3987993985790029246">Kopiuj link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Tytuł</translation>
@@ -121,7 +121,8 @@
<translation id="4434045419905280838">Pop-upy i przekierowania</translation>
<translation id="445467742685312942">Zezwalaj stronom na odtwarzanie treści chronionych</translation>
<translation id="4468959413250150279">Wycisz dźwięk na konkretnej stronie.</translation>
-<translation id="4479647676395637221">Pytaj, zanim zezwolisz stronom na korzystanie z kamery (zalecane)</translation>
+<translation id="4479647676395637221">Pytaj, zanim zezwolisz stronom na korzystanie z aparatu (zalecane)</translation>
+<translation id="4505788138578415521">URL pokazany w całości</translation>
<translation id="4534723447064627427">Aby zezwolić aplikacji <ph name="APP_NAME" /> na dostęp do mikrofonu, musisz go też włączyć w <ph name="BEGIN_LINK" />ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Szczegóły</translation>
<translation id="4645575059429386691">ZarzÄ…dzany przez Twojego rodzica</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Przyznaj aplikacji <ph name="APP_NAME" /> uprawnienia w <ph name="BEGIN_LINK" />ustawieniach Androida<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Dostęp do mikrofonu</translation>
<translation id="965817943346481315">Zablokuj, jeśli na stronie wyświetlają się uciążliwe lub wprowadzające w błąd reklamy (zalecane)</translation>
<translation id="967624055006145463">Zapisane dane</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
index 4d09cf7ffa8..563c68d718a 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="pt-BR">
<translation id="1006017844123154345">Abrir on-line</translation>
<translation id="1044891598689252897">Os sites funcionarão normalmente</translation>
-<translation id="1124090076051167250">Isso limpará <ph name="DATASIZE" /> de dados e cookies armazenados por sites ou apps na sua tela inicial.</translation>
+<translation id="1124090076051167250">Essa ação apagará <ph name="DATASIZE" /> de dados e cookies armazenados por sites ou apps na sua tela inicial.</translation>
<translation id="1124772482545689468">Usuário</translation>
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Remover</translation>
@@ -17,20 +17,20 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> adicionado</translation>
<translation id="1383876407941801731">Pesquisar</translation>
<translation id="1384959399684842514">Download pausado</translation>
+<translation id="1415402041810619267">URL truncado</translation>
<translation id="1431402976894535801">Impedir que sites saibam quando você está interagindo</translation>
<translation id="1446450296470737166">Permitir controle total de dispositivos MIDI</translation>
<translation id="1509960214886564027">Os recursos de muitos sites podem apresentar falhas</translation>
<translation id="1620510694547887537">Câmera</translation>
-<translation id="1647391597548383849">Acessar sua câmera</translation>
<translation id="1660204651932907780">Permitir o áudio dos sites (recomendado)</translation>
<translation id="1677097821151855053">Os cookies e outros dados do site são usados para lembrar de você, por exemplo, para conectar sua conta ou personalizar anúncios. Para gerenciar os cookies de todos os sites, acesse <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Limpar dados do site?</translation>
<translation id="169515064810179024">Impedir que sites acessem os sensores de movimento</translation>
<translation id="1717218214683051432">Sensores de movimento</translation>
-<translation id="1743802530341753419">Perguntar antes de permitir a conexão de sites a um dispositivo (recomendado)</translation>
+<translation id="1743802530341753419">Perguntar antes de permitir que sites se conectem ao dispositivo (recomendado)</translation>
<translation id="1779089405699405702">Decodificador de imagem</translation>
<translation id="1818308510395330587">Para permitir que o app <ph name="APP_NAME" /> use RA, também é necessário ativar a câmera nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
-<translation id="1887786770086287077">O acesso ao local está desativado para este dispositivo. Ative-o nas <ph name="BEGIN_LINK" />Configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="1887786770086287077">O acesso ao local está desativado neste dispositivo. Ative nas <ph name="BEGIN_LINK" />Configurações do Android<ph name="END_LINK" />.</translation>
<translation id="1919345977826869612">Anúncios</translation>
<translation id="1919950603503897840">Selecionar contatos</translation>
<translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / <ph name="FILE_SIZE_WITH_UNITS" /></translation>
@@ -39,15 +39,15 @@
<translation id="1994173015038366702">URL do site</translation>
<translation id="2025115093177348061">Realidade aumentada</translation>
<translation id="2030769033451695672">Toque para voltar para <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Sua presença</translation>
<translation id="2079545284768500474">Desfazer</translation>
<translation id="2091887806945687916">Som</translation>
-<translation id="2107397443965016585">Perguntar antes de permitir que sites reproduzam conteúdo protegido (recomendado)</translation>
+<translation id="2107397443965016585">Perguntar antes de permitir que sites mostrem conteúdo protegido (recomendado)</translation>
<translation id="2146738493024040262">Abrir Instant App</translation>
<translation id="2148716181193084225">Hoje</translation>
-<translation id="2182457891543959921">Perguntar antes de permitir que sites criem um mapa 3D dos seus arredores ou acompanhem a posição da câmera (recomendado)</translation>
-<translation id="2187243482123994665">Presença do usuário</translation>
+<translation id="2182457891543959921">Perguntar antes de permitir que sites criem um mapa 3D do ambiente a sua volta ou acompanhem a posição da câmera (recomendado)</translation>
<translation id="2212565012507486665">Permitir cookies</translation>
-<translation id="2228071138934252756">Para permitir que o app <ph name="APP_NAME" /> acesse sua câmera, também é necessário ativá-la nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="2228071138934252756">Para permitir que o app <ph name="APP_NAME" /> acesse sua câmera, ative-a também nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Apenas uma vez</translation>
<translation id="2289270750774289114">Perguntar quando um site quer descobrir dispositivos Bluetooth nas proximidades (recomendado)</translation>
<translation id="2315043854645842844">A seleção de certificado do cliente não é compatível com o sistema operacional.</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}one{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}other{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Download concluído <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Acesso ao local</translation>
<translation id="2482878487686419369">Notificações</translation>
<translation id="2490684707762498678">Gerenciadas por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ajuda e feedback</translation>
@@ -74,24 +73,25 @@
<translation id="2870560284913253234">Site</translation>
<translation id="2874939134665556319">Faixa anterior</translation>
<translation id="2903493209154104877">Endereços</translation>
-<translation id="2910701580606108292">Perguntar antes de permitir que sites reproduzam conteúdo protegido</translation>
+<translation id="2910701580606108292">Perguntar antes de permitir que sites mostrem conteúdo protegido</translation>
<translation id="2913331724188855103">Permitir que os sites salvem e leiam os dados de arquivos "cookies" - que armazenam temporariamente o que você visitou na rede. (Recomendado)</translation>
<translation id="2968755619301702150">Leitor de certificados</translation>
-<translation id="300526633675317032">Essa ação limpará tudo, <ph name="SIZE_IN_KB" /> de dados de armazenamento de sites.</translation>
+<translation id="300526633675317032">Essa ação apagará tudo, <ph name="SIZE_IN_KB" /> de dados de armazenamento de sites.</translation>
<translation id="3008272652534848354">Redefinir permissões</translation>
<translation id="301521992641321250">Bloqueada automaticamente</translation>
<translation id="3114012059975132928">Player de vídeo</translation>
<translation id="3115898365077584848">Mostrar informações</translation>
<translation id="3123473560110926937">Bloqueados em alguns sites</translation>
-<translation id="3165371858310906303">Perguntar quando um site quiser saber seu estado de atividade</translation>
+<translation id="3165371858310906303">Perguntar sempre que um site quiser saber quando você está interagindo</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de dados armazenados</translation>
<translation id="321187648315454507">Para permitir que o app <ph name="APP_NAME" /> envie notificações, também é necessário ativá-las nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfone</translation>
<translation id="3277252321222022663">Permitir que sites acessem os sensores (recomendado)</translation>
<translation id="3295602654194328831">Ocultar informações</translation>
+<translation id="3328801116991980348">Informações do site</translation>
<translation id="3333961966071413176">Todos os contatos</translation>
<translation id="3386292677130313581">Perguntar antes de permitir que sites saibam seu local (recomendado)</translation>
-<translation id="3538390592868664640">Impedir sites de criar um mapa 3D dos seus arredores ou acompanhar a posição da câmera</translation>
+<translation id="3538390592868664640">Impedir sites de criar um mapa 3D do ambiente a sua volta ou acompanhar a posição da câmera</translation>
<translation id="3586500876634962664">Uso de câmera e microfone</translation>
<translation id="3587482841069643663">Tudo</translation>
<translation id="358794129225322306">Permite que um site faça o download de vários arquivos automaticamente.</translation>
@@ -103,11 +103,11 @@
<translation id="381841723434055211">Números de telefone</translation>
<translation id="385051799172605136">Voltar</translation>
<translation id="3859306556332390985">Avançar</translation>
-<translation id="3955193568934677022">Permitir que os sites reproduzam conteúdo protegido (recomendado)</translation>
+<translation id="3955193568934677022">Permitir que os sites mostrem conteúdo protegido (recomendado)</translation>
<translation id="3987993985790029246">Copiar link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Título</translation>
-<translation id="4008040567710660924">Permita cookies para um site específico.</translation>
+<translation id="4008040567710660924">Permita cookies de um site específico.</translation>
<translation id="4046123991198612571">Próxima faixa</translation>
<translation id="4165986682804962316">Configurações do site</translation>
<translation id="4200726100658658164">Abrir as configurações de localização</translation>
@@ -119,10 +119,11 @@
<translation id="4336434711095810371">Limpar todos os dados</translation>
<translation id="4433925000917964731">Página Lite exibida pelo Google</translation>
<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
-<translation id="445467742685312942">Permitir que sites reproduzam conteúdo protegido</translation>
-<translation id="4468959413250150279">Desative o som de um site específico.</translation>
+<translation id="445467742685312942">Permitir que sites mostrem conteúdo protegido</translation>
+<translation id="4468959413250150279">Desativar o som de um site específico.</translation>
<translation id="4479647676395637221">Perguntar antes de permitir que sites usem sua câmera (recomendado)</translation>
-<translation id="4534723447064627427">Para permitir que o app <ph name="APP_NAME" /> acesse seu microfone, também é necessário ativá-lo nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="4505788138578415521">URL expandido</translation>
+<translation id="4534723447064627427">Para permitir que o app <ph name="APP_NAME" /> acesse seu microfone, também é preciso ativá-lo nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalhes</translation>
<translation id="4645575059429386691">Gerenciado pelos seus pais</translation>
<translation id="4670064810192446073">Realidade virtual</translation>
@@ -147,7 +148,7 @@
<translation id="5317780077021120954">Salvar</translation>
<translation id="5335288049665977812">Permitir que sites executem o JavaScript (recomendado)</translation>
<translation id="534295439873310000">Dispositivos NFC</translation>
-<translation id="5354152178998424783">Essa ação limpará <ph name="DATASIZE" /> de dados e cookies armazenados por sites.</translation>
+<translation id="5354152178998424783">Essa ação apagará <ph name="DATASIZE" /> de dados e cookies armazenados por sites.</translation>
<translation id="5384883051496921101">Este site está prestes a compartilhar informações com um app fora do modo de navegação anônima.</translation>
<translation id="5391532827096253100">Sua conexão com este site não é segura. Informações do site</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(mais 1)}one{(mais #)}other{(mais #)}}</translation>
@@ -165,7 +166,7 @@
<translation id="5689516760719285838">Local</translation>
<translation id="5690795753582697420">A câmera está desativada nas configurações do Android</translation>
<translation id="5710871682236653961">Perguntar antes de permitir que sites enviem e recebam informações quando você tocar em dispositivos NFC (recomendado)</translation>
-<translation id="5719847187258001597">Isso limpará todos os dados e cookies armazenados por <ph name="ORIGIN" /> ou pelo app dele na sua tela inicial.</translation>
+<translation id="5719847187258001597">Essa ação apagará todos os dados e cookies armazenados por <ph name="ORIGIN" /> ou pelo app dele na sua tela inicial.</translation>
<translation id="5771720122942595109">Bloqueada: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Permissões</translation>
<translation id="5860033963881614850">Desativado</translation>
@@ -221,7 +222,7 @@
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selecionado}one{# selecionado}other{# selecionados}}</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> itens selecionados. Opções disponíveis perto da parte superior da tela</translation>
<translation id="7128222689758636196">Permitir o mecanismo de pesquisa atual</translation>
-<translation id="7141896414559753902">Impedir que sites exibam pop-ups e façam redirecionamentos (recomendado)</translation>
+<translation id="7141896414559753902">Impedir pop-ups e redirecionamento dos sites (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
<translation id="723171743924126238">Selecionar imagens</translation>
<translation id="7243308994586599757">Opções disponíveis perto da parte inferior da tela</translation>
@@ -234,7 +235,7 @@
<translation id="7554752735887601236">Um site está usando seu microfone</translation>
<translation id="7561196759112975576">Sempre</translation>
<translation id="7572498721684305250">Impedir que sites enviem e recebam informações quando você tocar em dispositivos NFC</translation>
-<translation id="757524316907819857">Impedir que sites reproduzam conteúdos protegidos</translation>
+<translation id="757524316907819857">Impedir que sites mostrem conteúdo protegido</translation>
<translation id="7589445247086920869">Bloquear o mecanismo de pesquisa atual</translation>
<translation id="7649070708921625228">Ajuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
@@ -243,7 +244,7 @@
<translation id="780301667611848630">Não</translation>
<translation id="7804248752222191302">Um site está usando sua câmera</translation>
<translation id="7817023149356982970">Sua conta será desconectada desse site.</translation>
-<translation id="7828557259026017104">Os cookies são arquivos criados pelos sites que você visita, usados por esses sites para lembrar suas preferências. Os cookies de terceiros são criados por outros sites que possuem uma parte do conteúdo, como anúncios ou imagens, que você vê na página da Web acessada.</translation>
+<translation id="7828557259026017104">Os cookies são arquivos criados pelos sites que você visita, usados para lembrar suas preferências. Os cookies de terceiros são criados por outros sites que possuem uma parte do conteúdo da página acessada, como imagens ou anúncios.</translation>
<translation id="7835852323729233924">Tocando mídia</translation>
<translation id="783819812427904514">Ativar som do vídeo</translation>
<translation id="7846076177841592234">Cancelar seleção</translation>
@@ -266,18 +267,18 @@
<translation id="8261506727792406068">Excluir</translation>
<translation id="8300705686683892304">Gerenciados por app</translation>
<translation id="8324158725704657629">Não perguntar novamente</translation>
-<translation id="8372893542064058268">Permite a sincronização em segundo plano para um site específico.</translation>
-<translation id="8376384591331888629">Incluindo os cookies de terceiros desse site</translation>
+<translation id="8372893542064058268">Permitir a sincronização em segundo plano para um site específico.</translation>
+<translation id="8376384591331888629">Incluir também os cookies de terceiros desse site</translation>
<translation id="83792324527827022">Um site está usando sua câmera e seu microfone</translation>
<translation id="8380167699614421159">Neste site, há exibição de anúncios invasivos ou enganosos</translation>
<translation id="8394832520002899662">Toque para voltar ao site</translation>
<translation id="8425213833346101688">Alterar</translation>
<translation id="8441146129660941386">Retroceder</translation>
-<translation id="8444433999583714703">Para permitir que o app <ph name="APP_NAME" /> acesse sua localização, também é necessário ativá-la nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="8444433999583714703">Para permitir que o app <ph name="APP_NAME" /> acesse seu local, ative-o também nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="8447861592752582886">Revogar permissão do dispositivo</translation>
<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie em uso}one{# cookie em uso}other{# cookies em uso}}</translation>
<translation id="8463851957836045671">O site é rápido</translation>
-<translation id="851751545965956758">Impedir a conexão de sites a dispositivos</translation>
+<translation id="851751545965956758">Impedir que sites se conectem a dispositivos</translation>
<translation id="8525306231823319788">Tela cheia</translation>
<translation id="857943718398505171">Permitido (recomendado)</translation>
<translation id="8609465669617005112">Mover para cima</translation>
@@ -287,7 +288,7 @@
<translation id="8719283222052720129">Ative a permissão para o app <ph name="APP_NAME" /> nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
<translation id="8730621377337864115">Concluído</translation>
-<translation id="8737217482364735741">Isso limpará todos os dados e cookies armazenados por <ph name="ORIGIN" />.</translation>
+<translation id="8737217482364735741">Essa ação apagará todos os dados e cookies armazenados por <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Selecione uma imagem</translation>
<translation id="8801436777607969138">Bloquear JavaScript para um site específico.</translation>
<translation id="8816026460808729765">Impedir que sites acessem os sensores</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Ative as permissões para o app <ph name="APP_NAME" /> nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Acessar seu microfone</translation>
<translation id="965817943346481315">Bloquear se o site mostrar anúncios invasivos ou enganosos (recomendado)</translation>
<translation id="967624055006145463">Dados armazenados</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
index 230e45be5cc..f6a64f3d730 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> adicionado</translation>
<translation id="1383876407941801731">Pesquisar</translation>
<translation id="1384959399684842514">Transferência interrompida</translation>
+<translation id="1415402041810619267">URL truncado</translation>
<translation id="1431402976894535801">Impedir que os sites saibam quando está presente</translation>
<translation id="1446450296470737166">Perm. controlo total dispo. MIDI</translation>
<translation id="1509960214886564027">As funcionalidades em muitos sites podem falhar.</translation>
<translation id="1620510694547887537">Câmara</translation>
-<translation id="1647391597548383849">Aceder à câmara</translation>
<translation id="1660204651932907780">Permitir que os sites reproduzam som (recomendado)</translation>
<translation id="1677097821151855053">Os cookies e outros dados de sites são utilizados para memorizar o utilizador, por exemplo, para iniciar a sua sessão ou para personalizar anúncios. Para gerir cookies de todos os sites, veja <ph name="BEGIN_LINK" />Definições <ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Pretende limpar os dados do site?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL do site</translation>
<translation id="2025115093177348061">Realidade aumentada</translation>
<translation id="2030769033451695672">Toque para voltar a <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">A sua presença</translation>
<translation id="2079545284768500474">Anular</translation>
<translation id="2091887806945687916">Som</translation>
<translation id="2107397443965016585">Perguntar antes de permitir que os sites reproduzam conteúdos protegidos (recomendado)</translation>
<translation id="2146738493024040262">Abrir app instantânea</translation>
<translation id="2148716181193084225">Hoje</translation>
<translation id="2182457891543959921">Perguntar antes de permitir que os sites criem um mapa 3D do ambiente à sua volta ou monitorizem a posição da câmara (recomendado)</translation>
-<translation id="2187243482123994665">Presença do utilizador</translation>
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para permitir que a app <ph name="APP_NAME" /> aceda à câmara, ative também a câmara nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Apenas uma vez</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}}</translation>
<translation id="2434158240863470628">Transferência concluída: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Acesso à localização</translation>
<translation id="2482878487686419369">Notificações</translation>
<translation id="2490684707762498678">Gerido por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ajuda e comentários</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microfone</translation>
<translation id="3277252321222022663">Permitir que os sites acedam aos sensores (recomendado)</translation>
<translation id="3295602654194328831">Ocultar informações</translation>
+<translation id="3328801116991980348">Informações do site</translation>
<translation id="3333961966071413176">Todos os contactos</translation>
<translation id="3386292677130313581">Perguntar antes de permitir que os sites conheçam a sua localização (recomendado)</translation>
<translation id="3538390592868664640">Impeça que os sites criem um mapa 3D do ambiente à sua volta ou monitorizem a posição da câmara</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Permitir que os sites reproduzam conteúdos protegidos</translation>
<translation id="4468959413250150279">Desative o som de um site específico.</translation>
<translation id="4479647676395637221">Perguntar antes de permitir que os sites utilizem a câmara (recomendado)</translation>
+<translation id="4505788138578415521">URL expandido</translation>
<translation id="4534723447064627427">Para permitir que a app <ph name="APP_NAME" /> aceda ao microfone, ative também o microfone nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalhes</translation>
<translation id="4645575059429386691">Gerido pelos teus pais</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}}</translation>
<translation id="913657688200966289">Ative as autorizações para a app <ph name="APP_NAME" /> nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Aceder ao microfone</translation>
<translation id="965817943346481315">Bloquear se o site apresentar anúncios intrusivos ou enganadores (recomendado)</translation>
<translation id="967624055006145463">Dados armazenados</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
index f771fb28cd9..269535af782 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Site-ul <ph name="SITE_NAME" /> a fost adăugat</translation>
<translation id="1383876407941801731">Caută</translation>
<translation id="1384959399684842514">Descărcare întreruptă</translation>
+<translation id="1415402041810619267">Adresă URL trunchiată</translation>
<translation id="1431402976894535801">Împiedică site-urile să-ți detecteze prezența</translation>
<translation id="1446450296470737166">Control complet dispozitive MIDI</translation>
<translation id="1509960214886564027">Este posibil ca funcțiile de pe mai multe site-uri să fie întrerupte</translation>
<translation id="1620510694547887537">Cameră</translation>
-<translation id="1647391597548383849">Accesează camera foto</translation>
<translation id="1660204651932907780">Permite site-urilor să redea sunet (recomandat)</translation>
<translation id="1677097821151855053">Cookie-urile și alte date ale site-urilor sunt folosite pentru a te reține, de exemplu, pentru a te conecta sau pentru a personaliza anunțuri. Pentru a gestiona cookie-urile pentru toate site-urile, consultă <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Ștergi datele site-ului?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Adresa URL a site-ului</translation>
<translation id="2025115093177348061">Realitate augmentată</translation>
<translation id="2030769033451695672">Atinge pentru a reveni la <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Prezența ta</translation>
<translation id="2079545284768500474">Anulează</translation>
<translation id="2091887806945687916">Sunet</translation>
<translation id="2107397443965016585">Întreabă înainte de a permite site-urilor să redea conținut protejat (recomandat)</translation>
<translation id="2146738493024040262">Deschide aplicația instantanee</translation>
<translation id="2148716181193084225">Astăzi</translation>
<translation id="2182457891543959921">Întreabă înainte de a permite site-urilor să creeze o hartă 3D a lucrurilor din jur sau să urmărească poziția camerei video (recomandat)</translation>
-<translation id="2187243482123994665">Prezența utilizatorului</translation>
<translation id="2212565012507486665">Permite cookie-urile</translation>
<translation id="2228071138934252756">Pentru a permite aplicației <ph name="APP_NAME" /> să acceseze camera, activează camera și în <ph name="BEGIN_LINK" />Setările Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Numai o singură dată</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}}</translation>
<translation id="2434158240863470628">Descărcare finalizată <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Accesul la locație</translation>
<translation id="2482878487686419369">Notificări</translation>
<translation id="2490684707762498678">Gestionate de <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ajutor și feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Microfon</translation>
<translation id="3277252321222022663">Permite accesul site-urilor la senzori (recomandat)</translation>
<translation id="3295602654194328831">Ascunde informațiile</translation>
+<translation id="3328801116991980348">Informații despre site</translation>
<translation id="3333961966071413176">Toată agenda</translation>
<translation id="3386292677130313581">Întreabă înainte de a permite site-urilor să afle locația (recomandat)</translation>
<translation id="3538390592868664640">Împiedică site-urile să creeze o hartă 3D a lucrurilor din jur sau să urmărească poziția camerei video</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Permite site-urilor să redea conținut protejat</translation>
<translation id="4468959413250150279">Dezactivează sunetul pentru un anumit site.</translation>
<translation id="4479647676395637221">Întreabă înainte de a permite site-urilor să folosească camera foto (recomandat)</translation>
+<translation id="4505788138578415521">Adresă URL extinsă</translation>
<translation id="4534723447064627427">Pentru a permite aplicației <ph name="APP_NAME" /> să acceseze microfonul, activează microfonul și în <ph name="BEGIN_LINK" />Setările Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalii</translation>
<translation id="4645575059429386691">Gestionat de părintele tău</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Activează permisiunile pentru <ph name="APP_NAME" /> din <ph name="BEGIN_LINK" />Setări Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Accesează microfonul</translation>
<translation id="965817943346481315">Blochează dacă site-ul afișează anunțuri deranjante sau înșelătoare (recomandat)</translation>
<translation id="967624055006145463">Date stocate</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
index 34490c6474f..c4719b10e44 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Добавлен Ñайт <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">ПоиÑк</translation>
<translation id="1384959399684842514">Скачивание приоÑтановлено.</translation>
+<translation id="1415402041810619267">URL укорочен</translation>
<translation id="1431402976894535801">Блокировать передачу на Ñайты информации о вашем приÑутÑтвии</translation>
<translation id="1446450296470737166">Полный доÑтуп к управлению MIDI-уÑтройÑтвами</translation>
<translation id="1509960214886564027">Многие функции на Ñайтах могут работать некорректно</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ДоÑтуп к камере</translation>
<translation id="1660204651932907780">Разрешить Ñайтам воÑпроизводить звуки (рекомендуетÑÑ)</translation>
<translation id="1677097821151855053">Файлы cookie и другие данные Ñайтов иÑпользуютÑÑ Ñ‡Ñ‚Ð¾Ð±Ñ‹ хранить информацию о ваÑ, в том чиÑле Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð° в ÑиÑтему и перÑонализации рекламы. УправлÑÑ‚ÑŒ файлами cookie можно в <ph name="BEGIN_LINK" />разделе наÑтроек<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Удалить данные Ñайта?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">ÐÐ´Ñ€ÐµÑ Ñайта</translation>
<translation id="2025115093177348061">Ð”Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð½Ð°Ñ Ñ€ÐµÐ°Ð»ÑŒÐ½Ð¾ÑÑ‚ÑŒ</translation>
<translation id="2030769033451695672">Ðажмите, чтобы вернутьÑÑ Ð½Ð° Ñтраницу <ph name="URL_OF_THE_CURRENT_TAB" />.</translation>
+<translation id="2054665754582400095">Ваше приÑутÑтвие</translation>
<translation id="2079545284768500474">Отмена</translation>
<translation id="2091887806945687916">Звук</translation>
<translation id="2107397443965016585">Запрашивать разрешение на воÑпроизведение защищенного контента (рекомендуетÑÑ)</translation>
<translation id="2146738493024040262">Открыть приложение Ñ Ð¼Ð³Ð½Ð¾Ð²ÐµÐ½Ð½Ñ‹Ð¼ запуÑком</translation>
<translation id="2148716181193084225">СегоднÑ</translation>
<translation id="2182457891543959921">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на Ñоздание 3D-карты меÑта, в котором вы находитеÑÑŒ, и отÑлеживание Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ (рекомендуетÑÑ)</translation>
-<translation id="2187243482123994665">ПриÑутÑтвие пользователÑ</translation>
<translation id="2212565012507486665">Разрешить файлы cookie</translation>
<translation id="2228071138934252756">Чтобы у Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ "<ph name="APP_NAME" />" был доÑтуп к камере, включите ее в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Однократно</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}one{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}few{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}many{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}other{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Скачивание завершено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Данные о меÑтоположении</translation>
<translation id="2482878487686419369">УведомлениÑ</translation>
<translation id="2490684707762498678">Под управлением Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ "<ph name="APP_NAME" />"</translation>
<translation id="2498359688066513246">Справка/отзыв</translation>
@@ -64,7 +63,7 @@
<translation id="2570922361219980984">Определение меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¾ и Ð´Ð»Ñ Ñамого уÑтройÑтва. Включите Ñту функцию в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
<translation id="257931822824936280">Развернуто. Ðажмите, чтобы Ñвернуть.</translation>
<translation id="2586657967955657006">Буфер обмена</translation>
-<translation id="2621115761605608342">Разрешить JavaScript Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайта.</translation>
+<translation id="2621115761605608342">Разрешить JavaScript Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайта</translation>
<translation id="2653659639078652383">Отправить</translation>
<translation id="2677748264148917807">Закрыть</translation>
<translation id="2687403674020088961">Заблокировать вÑе файлы cookie (не рекомендуетÑÑ)</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">ПредоÑтавить Ñайтам доÑтуп к датчикам (рекомендуетÑÑ)</translation>
<translation id="3295602654194328831">Скрыть информацию</translation>
+<translation id="3328801116991980348">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñайте</translation>
<translation id="3333961966071413176">Ð’Ñе контакты</translation>
<translation id="3386292677130313581">Запрашивать разрешение на доÑтуп к данным о меÑтоположении (рекомендуетÑÑ)</translation>
<translation id="3538390592868664640">Запретить Ñайтам Ñоздавать 3D-карту меÑта, в котором вы находитеÑÑŒ, и отÑлеживать положение камеры</translation>
@@ -107,7 +107,7 @@
<translation id="3987993985790029246">Копировать ÑÑылку</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> из ?</translation>
<translation id="4002066346123236978">Ðазвание</translation>
-<translation id="4008040567710660924">Разрешить определенному Ñайту ÑохранÑÑ‚ÑŒ файлы cookie.</translation>
+<translation id="4008040567710660924">Разрешить определенному Ñайту ÑохранÑÑ‚ÑŒ файлы cookie</translation>
<translation id="4046123991198612571">Следующий трек</translation>
<translation id="4165986682804962316">ÐаÑтройки Ñайтов</translation>
<translation id="4200726100658658164">Открыть наÑтройки геолокации</translation>
@@ -120,8 +120,9 @@
<translation id="4433925000917964731">Lite-верÑÐ¸Ñ Ñтраницы получена Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Google</translation>
<translation id="4434045419905280838">Ð’Ñплывающие окна и переадреÑациÑ</translation>
<translation id="445467742685312942">Разрешить Ñайтам воÑпроизводить защищенный контент</translation>
-<translation id="4468959413250150279">Отключить звуки на определенном Ñайте.</translation>
+<translation id="4468959413250150279">Отключить звуки на определенном Ñайте</translation>
<translation id="4479647676395637221">Запрашивать разрешение на доÑтуп к камере (рекомендуетÑÑ)</translation>
+<translation id="4505788138578415521">URL развернут</translation>
<translation id="4534723447064627427">Чтобы у Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ "<ph name="APP_NAME" />" был доÑтуп к микрофону, предоÑтавьте разрешение в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Подробнее…</translation>
<translation id="4645575059429386691">УправлÑетÑÑ Ð²Ð°ÑˆÐ¸Ð¼Ð¸ родителÑми</translation>
@@ -146,7 +147,7 @@
<translation id="5313967007315987356">Добавить Ñайт</translation>
<translation id="5317780077021120954">Сохранить</translation>
<translation id="5335288049665977812">Разрешить Ñайтам иÑпользовать JavaScript (рекомендуетÑÑ)</translation>
-<translation id="534295439873310000">УÑтройÑтва Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸ÐµÐ¹ NFC</translation>
+<translation id="534295439873310000">УÑтройÑтва Ñ NFC</translation>
<translation id="5354152178998424783">Будут удалены данные и файлы cookie (вÑего <ph name="DATASIZE" />), Ñохраненные Ñайтами.</translation>
<translation id="5384883051496921101">Этот Ñайт передает информацию Ñтороннему приложению, пока вы в режиме инкогнито.</translation>
<translation id="5391532827096253100">Подключение к Ñайту не защищено. Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñайте</translation>
@@ -164,7 +165,7 @@
<translation id="5677928146339483299">Заблокировано</translation>
<translation id="5689516760719285838">Геоданные</translation>
<translation id="5690795753582697420">Камера выключена в наÑтройках Android.</translation>
-<translation id="5710871682236653961">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на обмен информацией через NFC (рекомендуетÑÑ).</translation>
+<translation id="5710871682236653961">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на обмен информацией через NFC (рекомендуетÑÑ)</translation>
<translation id="5719847187258001597">Будут удалены вÑе данные и файлы cookie, которые Ñохранены Ñайтом <ph name="ORIGIN" /> или его приложением, добавленным на главный Ñкран.</translation>
<translation id="5771720122942595109">Заблокировано: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">РазрешениÑ</translation>
@@ -228,7 +229,7 @@
<translation id="7250468141469952378">Выбрано: <ph name="ITEM_COUNT" /></translation>
<translation id="7260727271532453612">Разрешено: <ph name="PERMISSION_1" /> и <ph name="PERMISSION_2" /></translation>
<translation id="7302486331832100261">Обычно вы блокируете уведомлениÑ. Чтобы разрешить их показ, нажмите "Подробнее".</translation>
-<translation id="7423098979219808738">Ð’Ñегда Ñпрашивать</translation>
+<translation id="7423098979219808738">Сначала Ñпрашивать</translation>
<translation id="7423538860840206698">ДоÑтуп к данным в буфере обмена заблокирован</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт иÑпользует ваш микрофон</translation>
@@ -248,7 +249,7 @@
<translation id="783819812427904514">Включить звук Ð´Ð»Ñ Ð²Ð¸Ð´ÐµÐ¾</translation>
<translation id="7846076177841592234">Отменить выбор</translation>
<translation id="7846621471902887024">Ð’Ñ‹ выйдете из аккаунта на вÑех Ñайтах.</translation>
-<translation id="7882806643839505685">Включить звуки на определенном Ñайте.</translation>
+<translation id="7882806643839505685">Включить звуки на определенном Ñайте</translation>
<translation id="7986741934819883144">Выберите контакт</translation>
<translation id="7993619969781047893">Ðекоторые функции на Ñайтах могут работать некорректно</translation>
<translation id="7999064672810608036">Ð’Ñ‹ уверены, что хотите удалить вÑе данные Ñтого веб-Ñайта, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ñ„Ð°Ð¹Ð»Ñ‹ cookie, и ÑброÑить заданные разрешениÑ?</translation>
@@ -266,7 +267,7 @@
<translation id="8261506727792406068">Удалить</translation>
<translation id="8300705686683892304">Под управлением приложениÑ</translation>
<translation id="8324158725704657629">Больше не Ñпрашивать</translation>
-<translation id="8372893542064058268">Разрешить фоновую Ñинхронизацию Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайта.</translation>
+<translation id="8372893542064058268">Разрешить фоновую Ñинхронизацию Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайта</translation>
<translation id="8376384591331888629">Ð’ том чиÑле Ñторонние файлы cookie на Ñайте</translation>
<translation id="83792324527827022">Сайт иÑпользует вашу камеру и микрофон</translation>
<translation id="8380167699614421159">Этот Ñайт показывает навÑзчивую или вводÑщую в заблуждение рекламу</translation>
@@ -289,7 +290,7 @@
<translation id="8730621377337864115">Готово</translation>
<translation id="8737217482364735741">Будут удалены вÑе данные и файлы cookie, которые Ñохранены Ñайтом <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Выберите фото</translation>
-<translation id="8801436777607969138">Блокировать код JavaScript на определенном Ñайте.</translation>
+<translation id="8801436777607969138">Блокировать код JavaScript на определенном Ñайте</translation>
<translation id="8816026460808729765">Закрыть Ñайтам доÑтуп к датчикам</translation>
<translation id="8847988622838149491">USB</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">ПредоÑтавьте приложению "<ph name="APP_NAME" />" Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð² <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ДоÑтуп к микрофону</translation>
<translation id="965817943346481315">Блокировать, еÑли Ñайт показывает навÑзчивую или вводÑщую в заблуждение рекламу (рекомендуетÑÑ)</translation>
-<translation id="967624055006145463">Объем занÑтой памÑти</translation>
+<translation id="967624055006145463">Объем памÑти</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
index a1af7a468cd..d6258a539db 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">අඩවි <ph name="SITE_NAME" /> එක් කරන ලදී</translation>
<translation id="1383876407941801731">සොයන්න</translation>
<translation id="1384959399684842514">බà·à¶œà·à¶±à·“ම විරà·à¶¸à¶ºà·’</translation>
+<translation id="1415402041810619267">URL කපන ලදි</translation>
<translation id="1431402976894535801">ඔබ සිටින විට දà·à¶± ගà·à¶±à·“මෙන් අඩවි අවහිර කරන්න</translation>
<translation id="1446450296470737166">MIDI උපà·à¶‚ගවල සම්පූර්ණ පà·à¶½à¶±à¶ºà¶§ ඉඩ දෙන්න</translation>
<translation id="1509960214886564027">බොහ෠වෙබ් අඩවි මත විà·à·šà·‚à·à¶‚ග කà·à¶©à·“ ගිය à·„à·à¶š</translation>
<translation id="1620510694547887537">කà·à¶¸à¶»à·à·€</translation>
-<translation id="1647391597548383849">ඔබේ කà·à¶¸à¶»à·à·€ වෙත ප්â€à¶»à·€à·šà· වන්න</translation>
<translation id="1660204651932907780">අඩවිවලට à·à¶¶à·Šà¶¯à¶º à·€à·à¶¯à¶±à¶º කිරීමට ඉඩ දෙන්න (නිර්දේà·à·’තයි)</translation>
<translation id="1677097821151855053">ඔබව මතක තබ෠ගà·à¶±à·“මට කුකි සහ වෙනත් අඩවි දත්ත භà·à·€à·’ත කරයි, උදà·à·„රණයක් ලෙස ඔබව පිරීමට හ෠වෙළඳ දà·à¶±à·Šà·€à·“ම් පුද්ගලිකකරණය කිරීමට. සියලුම වෙබ් අඩවි සඳහ෠කුකී කළමනà·à¶šà¶»à¶«à¶º කිරීමට, <ph name="BEGIN_LINK" />à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> බලන්න.</translation>
<translation id="1688867105868176567">අඩවි දත්ත හිස් කරන්නද?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">අඩවි URL</translation>
<translation id="2025115093177348061">ආවර්ධිත යථà·à¶»à·Šà¶®à¶º</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> වෙත ආපසු යà·à¶¸à¶§ තට්ටු කරන්න</translation>
+<translation id="2054665754582400095">ඔබගේ සිටීම</translation>
<translation id="2079545284768500474">පසුගමනය</translation>
<translation id="2091887806945687916">හඬ</translation>
<translation id="2107397443965016585">වෙබ් අඩවිවලට ආරක්â€à·‚ිත අන්තර්ගත ධà·à·€à¶± කිරීමට ඉඩ දීමට පෙර විමසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="2146738493024040262">ක්ෂණික යෙදුම විවෘත කරන්න</translation>
<translation id="2148716181193084225">අද</translation>
<translation id="2182457891543959921">වෙබ් අඩවිවලට ඔබේ වටපිටà·à·€à·š ත්â€à¶»à·’මà·à¶± සිතියමක් සෑදීමට හ෠කà·à¶¸à¶»à· ස්ථà·à¶±à¶º හඹ෠යෑමට ඉඩ දීමට පෙර අසන්න (නිර්දේà·à·’තයි)</translation>
-<translation id="2187243482123994665">පරිà·à·“ලකයà·à¶œà·š සිටීම</translation>
<translation id="2212565012507486665">කුකීවලට ඉඩ දෙන්න</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> හට ඔබේ කà·à¶¸à¶»à·à·€à¶§ ප්â€à¶»à·€à·šà· වීමට ඉඩ දීමට, <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළද කà·à¶¸à¶»à·à·€ ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න.</translation>
<translation id="2241634353105152135">හුදෙක් එක් වරක්</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}}</translation>
<translation id="2434158240863470628">බà·à¶œà·à¶±à·“ම සම්පූර්ණයි <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ස්ථà·à¶±à¶º ප්â€à¶»à·€à·šà·à¶º</translation>
<translation id="2482878487686419369">දà·à¶±à·”ම්දීම්</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> විසින් කළමන෠කෙරේ</translation>
<translation id="2498359688066513246">උදවු සහ ප්â€à¶»à¶­à·’පà·à·‚ණය</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">මයික්â€à¶»à·†à·à¶±à¶º:</translation>
<translation id="3277252321222022663">වෙබ් අඩවිවලට සංවේදක වෙත ප්â€à¶»à·€à·šà· වීමට ඉඩ දෙන්න (නිර්දේà·à·’තයි)</translation>
<translation id="3295602654194328831">තතු සඟවන්න</translation>
+<translation id="3328801116991980348">අඩවි තොරතුරු</translation>
<translation id="3333961966071413176">සියලු සම්බන්ධතà·</translation>
<translation id="3386292677130313581">අඩවි වලට ඔබගේ ස්ථà·à¶±à¶º දà·à¶± ගà·à¶±à·“මට ඉඩ දීමට පෙර විමසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="3538390592868664640">වෙබ් අඩවිය ඔබේ වටපිටà·à·€à·š ත්â€à¶»à·’මà·à¶± සිතියමක් සෑදීමෙන් හ෠කà·à¶¸à¶»à· ස්ථà·à¶±à¶º හඹ෠යෑමෙන් අවහිර කරන්න</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">මෙම වෙබ් අඩවියට ආරක්â€à·‚ිත අන්තර්ගතය ධà·à·€à¶± කිරීමට ඉඩ දෙන්න.</translation>
<translation id="4468959413250150279">නිà·à·Šà¶ à·’ත අඩවියක් සඳහ෠à·à¶¶à·Šà¶¯à¶º නිහඬ කරන්න.</translation>
<translation id="4479647676395637221">අඩවි වලට ඔබගේ කà·à¶¸à¶»à·à·€ භà·à·€à·’ත෠කිරීමට ඉඩ දීමට පෙර පළමුව විමසන්න (නිර්දේà·à·’තයි)</translation>
+<translation id="4505788138578415521">URL දිග හරින ලදි</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> හට ඔබේ මයික්â€à¶»à·†à·à¶±à¶ºà¶§ ප්â€à¶»à·€à·šà· වීමට ඉඩ දීමට, <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළ මයික්â€à¶»à·†à·à¶±à¶ºà¶¯ ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න.</translation>
<translation id="4570913071927164677">විස්තර</translation>
<translation id="4645575059429386691">ඔබේ දෙමව්පියන් පà·à¶½à¶±à¶º කරයි</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තවත් <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තවත් <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තවත් <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" /> සඳහ෠අවසර <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළ ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න.</translation>
-<translation id="945632385593298557">ඔබේ මයික්â€à¶»à·†à·à¶±à¶º වෙත ප්â€à¶»à·€à·šà· වන්න</translation>
<translation id="965817943346481315">වෙබ් අඩවිය ආක්â€à¶»à¶¸à¶«à·à·“ලී හ෠නොමඟ යවන දà·à¶±à·Šà·€à·“ම් පෙන්වන්නේ නම් අවහිර කරන්න (නිර්දේà·à·’තයි)</translation>
<translation id="967624055006145463">දත්ත ගබඩ෠කර ඇත</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
index 2c4750d7736..781243f4dc8 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
@@ -17,15 +17,15 @@
<translation id="1369915414381695676">Boli pridané stránky <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Vyhľadávanie</translation>
<translation id="1384959399684842514">Sťahovanie bolo pozastavené</translation>
-<translation id="1431402976894535801">NeumožniÅ¥ webom zistiÅ¥, Äi ste prítomný/-á</translation>
+<translation id="1415402041810619267">Skrátená webová adresa</translation>
+<translation id="1431402976894535801">Brániť webom overovať si vašu prítomnosť</translation>
<translation id="1446450296470737166">Povoliť úplné ovlád. zar. MIDI</translation>
<translation id="1509960214886564027">Funkcie na mnohých weboch môžu zlyhávať</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Prístup ku kamere</translation>
<translation id="1660204651932907780">PovoliÅ¥ webom prehrávaÅ¥ zvuk (odporúÄané)</translation>
<translation id="1677097821151855053">Stránky si vás pomocou súborov cookie a Äalších údajov webov zapamätajú, napríklad vás pomocou nich prihlásia alebo prispôsobia reklamy. Ak chcete spravovaÅ¥ súbory cookie pre vÅ¡etky weby, prejdite do <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vymazať dáta webu?</translation>
-<translation id="169515064810179024">Blokovať webom prístup k senzorom pohybu</translation>
+<translation id="169515064810179024">Brániť webom v prístupe k senzorom pohybu</translation>
<translation id="1717218214683051432">Senzory pohybu</translation>
<translation id="1743802530341753419">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu pripojiÅ¥ sa k zariadeniu (odporúÄané)</translation>
<translation id="1779089405699405702">Dekodér obrázkov</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Webová adresa</translation>
<translation id="2025115093177348061">Rozšírená realita</translation>
<translation id="2030769033451695672">Klepnutím sa vrátite na kartu <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Vaša prítomnosť</translation>
<translation id="2079545284768500474">Späť</translation>
<translation id="2091887806945687916">Zvuk</translation>
<translation id="2107397443965016585">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu prehrávaÅ¥ chránený obsah (odporúÄané)</translation>
<translation id="2146738493024040262">Otvoriť okamžitú aplikáciu</translation>
<translation id="2148716181193084225">Dnes</translation>
-<translation id="2182457891543959921">OpýtaÅ¥ sa, Äi chcete povoliÅ¥ webom vytvoriÅ¥ 3D mapu vášho okolia alebo sledovaÅ¥ umiestnenie kamier (odporúÄané)</translation>
-<translation id="2187243482123994665">Prítomnosť používateľa</translation>
+<translation id="2182457891543959921">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu vytváraÅ¥ priestorovú mapu okolia alebo sledovaÅ¥ pozíciu kamery (odporúÄané)</translation>
<translation id="2212565012507486665">Povoliť súbory cookie</translation>
<translation id="2228071138934252756">Ak chcete povoliť aplikácii <ph name="APP_NAME" /> používať váš fotoaparát, zapnite ho aj v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Iba raz</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie}few{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> Äalších}}</translation>
<translation id="2434158240863470628">SÅ¥ahovanie bolo dokonÄené <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Prístup k polohe</translation>
<translation id="2482878487686419369">Upozornenia</translation>
<translation id="2490684707762498678">Spravuje <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Pomocník a spätná väzba</translation>
@@ -64,7 +63,7 @@
<translation id="2570922361219980984">Prístup k polohe je vypnutý aj v tomto zariadení. Zapnite ho v <ph name="BEGIN_LINK" />Nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="257931822824936280">Rozbalená (zbalíte ju kliknutím)</translation>
<translation id="2586657967955657006">Schránka</translation>
-<translation id="2621115761605608342">Povoliť JavaScript pre konkrétny web.</translation>
+<translation id="2621115761605608342">Povoliť JavaScript na konkrétnom webe.</translation>
<translation id="2653659639078652383">Odoslať</translation>
<translation id="2677748264148917807">Odísť</translation>
<translation id="2687403674020088961">BlokovaÅ¥ vÅ¡etky súbory cookie (neodporúÄa sa)</translation>
@@ -89,14 +88,15 @@
<translation id="3227137524299004712">Mikrofón</translation>
<translation id="3277252321222022663">PovoliÅ¥ webom prístup k senzorom (odporúÄané)</translation>
<translation id="3295602654194328831">Skryť informácie</translation>
+<translation id="3328801116991980348">Informácie o stránkach</translation>
<translation id="3333961966071413176">VÅ¡etky kontakty</translation>
<translation id="3386292677130313581">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu zisÅ¥ovaÅ¥ vaÅ¡u polohu (odporúÄané)</translation>
-<translation id="3538390592868664640">Zabráňte webom vytváraÅ¥ 3D mapu vášho okolia Äi sledovaÅ¥ umiestnenie kamier</translation>
+<translation id="3538390592868664640">Brániť webom vytvárať priestorovú mapu okolia a sledovať pozíciu kamery</translation>
<translation id="3586500876634962664">Používanie kamery a mikrofónu</translation>
<translation id="3587482841069643663">VÅ¡etko</translation>
<translation id="358794129225322306">Povoľuje webu automaticky sÅ¥ahovaÅ¥ viacero súborov súÄasne.</translation>
<translation id="3594780231884063836">Vypnúť zvuk videa</translation>
-<translation id="3596414637720633074">Blokovať súbory cookie tretích strán v anonymnom režime</translation>
+<translation id="3596414637720633074">Blokovať súbory cookie tretích strán v režime inkognito</translation>
<translation id="3600792891314830896">Stlmiť weby, ktoré prehrávajú zvuk</translation>
<translation id="3744111561329211289">Synchronizácia na pozadí</translation>
<translation id="3763247130972274048">Dvojitým klepnutím doľava alebo doprava preskoÄíte vo videu o 10 s</translation>
@@ -107,7 +107,7 @@
<translation id="3987993985790029246">Kopírovať odkaz</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Názov</translation>
-<translation id="4008040567710660924">Povolenie súborov cookie konkrétneho webu</translation>
+<translation id="4008040567710660924">Povoliť súbory cookie na konkrétnom webe.</translation>
<translation id="4046123991198612571">Ďalšia skladba</translation>
<translation id="4165986682804962316">Nastavenia webu</translation>
<translation id="4200726100658658164">Otvoriť nastavenia polohy</translation>
@@ -116,12 +116,13 @@
<translation id="4278390842282768270">Povolené</translation>
<translation id="429312253194641664">Web prehráva médiá</translation>
<translation id="42981349822642051">Rozbaliť</translation>
-<translation id="4336434711095810371">Vymazať všetky údaje</translation>
+<translation id="4336434711095810371">Vymazať všetky dáta</translation>
<translation id="4433925000917964731">Zjednodušenú verziu stránky poskytol Google</translation>
<translation id="4434045419905280838">Vyskakovacie okná a presmerovania</translation>
<translation id="445467742685312942">Povoliť webom prehrávať chránený obsah</translation>
-<translation id="4468959413250150279">Vypnite zvuk konkrétneho webu.</translation>
-<translation id="4479647676395637221">OpýtaÅ¥ sa pred povolením webu používaÅ¥ vaÅ¡u kameru (odporúÄané)</translation>
+<translation id="4468959413250150279">Vypnúť zvuk na konkrétnom webe.</translation>
+<translation id="4479647676395637221">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu používaÅ¥ kameru (odporúÄané)</translation>
+<translation id="4505788138578415521">Webová adresa bola rozbalená</translation>
<translation id="4534723447064627427">Ak chcete povoliť aplikácii <ph name="APP_NAME" /> používať mikrofón, zapnite ho aj v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Podrobnosti</translation>
<translation id="4645575059429386691">Spravované vaším rodiÄom</translation>
@@ -129,7 +130,7 @@
<translation id="4708011789095599544">Naozaj chcete vymazaÅ¥ súbory cookie a ÄalÅ¡ie údaje tohto webu?</translation>
<translation id="4751476147751820511">Senzory pohybu alebo svetla</translation>
<translation id="4883854917563148705">Spravované nastavenia sa nedajú resetovať</translation>
-<translation id="4887024562049524730">OpýtaÅ¥ sa, Äi chcete povoliÅ¥ webom používaÅ¥ vaÅ¡e zariadenie a údaje virtuálnej reality (odporúÄané)</translation>
+<translation id="4887024562049524730">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu používaÅ¥ zariadenie a dáta pre virtuálnu realitu (odporúÄané)</translation>
<translation id="4962975101802056554">Odvolať všetky povolenia pre zariadenie</translation>
<translation id="497421865427891073">ÄŽalej</translation>
<translation id="4994033804516042629">Nenašli sa žiadne kontakty</translation>
@@ -153,18 +154,18 @@
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ÄalÅ¡ie)}few{(+ # ÄalÅ¡ie)}many{(+ # more)}other{(+ # Äalších)}}</translation>
<translation id="5403592356182871684">Názvy</translation>
<translation id="5489227211564503167">Uplynutý Äas: <ph name="ELAPSED_TIME" /> z <ph name="TOTAL_TIME" />.</translation>
-<translation id="5494752089476963479">Blokovať reklamy webov, ktoré zobrazujú obťažujúce alebo zavádzajúce reklamy</translation>
+<translation id="5494752089476963479">Blokovať reklamy na weboch, ktoré zobrazujú obťažujúce alebo zavádzajúce reklamy</translation>
<translation id="5502860503640766021">Povolené: <ph name="PERMISSION_1" />, blokované: <ph name="PERMISSION_2" /></translation>
<translation id="5505264765875738116">Weby nemôžu žiadať o odosielanie upozornení</translation>
<translation id="5516455585884385570">Otvoriť nastavenia upozornení</translation>
-<translation id="5527111080432883924">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu ÄítaÅ¥ text a obrázky v schránke (odporúÄané)</translation>
+<translation id="5527111080432883924">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu prístup k textom a obrázkom v schránke (odporúÄané)</translation>
<translation id="5556459405103347317">Znova naÄítaÅ¥</translation>
<translation id="5596627076506792578">Ďalšie možnosti</translation>
<translation id="5649053991847567735">Automatické sťahovanie</translation>
<translation id="5677928146339483299">Blokované</translation>
<translation id="5689516760719285838">Poloha</translation>
<translation id="5690795753582697420">Fotoaparát je vypnutý v nastaveniach Androidu</translation>
-<translation id="5710871682236653961">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webom odosielaÅ¥ a prijímaÅ¥ informácie, keÄ priložíte zariadenia NFC (odporúÄané)</translation>
+<translation id="5710871682236653961">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu posielaÅ¥ a prijímaÅ¥ informácie cez NFC (odporúÄané)</translation>
<translation id="5719847187258001597">Týmto vymažete všetky dáta a súbory cookie uložené webom <ph name="ORIGIN" /> alebo jeho aplikáciou na ploche.</translation>
<translation id="5771720122942595109">Blokované: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Povolenia</translation>
@@ -187,12 +188,12 @@
<translation id="6216432067784365534"><ph name="NAME_OF_LIST_ITEM" /> – možnosti</translation>
<translation id="6262279340360821358">Blokované: <ph name="PERMISSION_1" /> a <ph name="PERMISSION_2" /></translation>
<translation id="6270391203985052864">Weby môžu žiadať o odosielanie upozornení</translation>
-<translation id="6295158916970320988">Všetky stránky</translation>
+<translation id="6295158916970320988">VÅ¡etky weby</translation>
<translation id="6320088164292336938">Vibrovanie</translation>
<translation id="6388207532828177975">Vymazať a resetovať</translation>
<translation id="6398765197997659313">UkonÄiÅ¥ zobrazenie na celú obrazovku</translation>
<translation id="6423924377271166037">Vymazať súbory cookie</translation>
-<translation id="6439114592976064011">Blokovať weby, aby nemohli používať vaše zariadenie a údaje virtuálnej reality</translation>
+<translation id="6439114592976064011">Brániť webom používať zariadenie a dáta pre virtuálnu realitu</translation>
<translation id="6447842834002726250">Súbory cookie</translation>
<translation id="6527303717912515753">Zdieľať</translation>
<translation id="6545864417968258051">Vyhľadávanie zariadení Bluetooth</translation>
@@ -210,18 +211,18 @@
<translation id="6818926723028410516">Vyberte položky</translation>
<translation id="6864395892908308021">Toto zariadenie nedokáže ÄítaÅ¥ NFC</translation>
<translation id="6910211073230771657">Odstránené</translation>
-<translation id="6912998170423641340">ZakázaÅ¥ webom ÄítaÅ¥ text a obrázky v schránke</translation>
+<translation id="6912998170423641340">Brániť webom v prístupe k textom a obrázkom v schránke</translation>
<translation id="6945221475159498467">Vybrať</translation>
<translation id="6963642900430330478">Táto stránka je nebezpeÄná. Informácie o webe</translation>
<translation id="6965382102122355670">OK</translation>
-<translation id="6992289844737586249">OpýtaÅ¥ sa pred povolením webu používaÅ¥ váš mikrofón (odporúÄané)</translation>
+<translation id="6992289844737586249">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu používaÅ¥ mikrofón (odporúÄané)</translation>
<translation id="7000754031042624318">Vypnuté v nastaveniach Androidu</translation>
<translation id="7016516562562142042">Povolené v aktuálnom vyhľadávaÄi</translation>
<translation id="7053983685419859001">Blokovať</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 vybratá položka}few{# vybraté položky}many{Niekoľko (#) vybratých položiek}other{# vybratých položiek}}</translation>
<translation id="7087918508125750058">Vybrané: <ph name="ITEM_COUNT" />. Možnosti sú k dispozícii v hornej Äasti obrazovky.</translation>
<translation id="7128222689758636196">PovoliÅ¥ pre aktuálny vyhľadávaÄ</translation>
-<translation id="7141896414559753902">ZakázaÅ¥ webom otváraÅ¥ vyskakovacie okná a používaÅ¥ presmerovania (odporúÄané)</translation>
+<translation id="7141896414559753902">BrániÅ¥ webom otváraÅ¥ vyskakovacie okná a používaÅ¥ presmerovania (odporúÄané)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
<translation id="723171743924126238">Výber obrázkov</translation>
<translation id="7243308994586599757">Možnosti sú k dispozícii v dolnej Äasti obrazovky</translation>
@@ -233,8 +234,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Váš mikrofón používa nejaký web</translation>
<translation id="7561196759112975576">Vždy</translation>
-<translation id="7572498721684305250">BlokovaÅ¥ odosielanie a prijímanie informácií webmi, keÄ priložíte zariadenia NFC</translation>
-<translation id="757524316907819857">Zakázať webom prehrávať chránený obsah</translation>
+<translation id="7572498721684305250">BrániÅ¥ webom posielaÅ¥ a prijímaÅ¥ údaje, keÄ sa dotknete zariadenia NFC</translation>
+<translation id="757524316907819857">Brániť webom prehrávať chránený obsah</translation>
<translation id="7589445247086920869">BlokovaÅ¥ pre aktuálny vyhľadávaÄ</translation>
<translation id="7649070708921625228">Pomocník</translation>
<translation id="7658239707568436148">Zrušiť</translation>
@@ -243,12 +244,12 @@
<translation id="780301667611848630">Nie, Äakujem</translation>
<translation id="7804248752222191302">Váš fotoaparát používa nejaký web</translation>
<translation id="7817023149356982970">Systém vás z tohto webu odhlási.</translation>
-<translation id="7828557259026017104">Súbory cookie sú vytvárané webmi, ktoré navÅ¡tívite. Pamätajú si pomocou nich vaÅ¡e predvoľby. Súbory cookie tretích strán sú vytvárané Äalšími webmi. Tieto weby sú vlastníkmi prvkov obsahu, ktorý sa zobrazuje na navÅ¡tívenej webovej stránke (napríklad reklamy alebo obrázky).</translation>
+<translation id="7828557259026017104">Súbory cookie vytvárajú weby, ktoré navÅ¡tevujete. Weby si pomocou nich pamätajú vaÅ¡e nastavenia. Súbory cookie tretích strán vytvárajú iné weby, ktorým patrí urÄitý obsah na navÅ¡tívenej webovej stránke, napríklad reklamy Äi obrázky.</translation>
<translation id="7835852323729233924">Prehrávanie médií</translation>
<translation id="783819812427904514">Zapnúť zvuk videa</translation>
<translation id="7846076177841592234">Zrušiť výber</translation>
<translation id="7846621471902887024">Systém vás odhlási zo všetkých webov.</translation>
-<translation id="7882806643839505685">Povoliť zvuk pre konkrétny web.</translation>
+<translation id="7882806643839505685">Povoliť zvuk na konkrétnom webe.</translation>
<translation id="7986741934819883144">Výber kontaktu</translation>
<translation id="7993619969781047893">Funkcie na niektorých weboch môžu zlyhávať</translation>
<translation id="7999064672810608036">Naozaj chcete vymazať všetky miestne dáta tohto webu, vrátane súborov cookie, a resetovať všetky jeho povolenia?</translation>
@@ -257,7 +258,7 @@
<translation id="8067883171444229417">Prehrať video</translation>
<translation id="8068648041423924542">Nedá sa vybrať certifikát</translation>
<translation id="8087000398470557479">Tento obsah pochádza z domény <ph name="DOMAIN_NAME" /> a bol doruÄený Googlom.</translation>
-<translation id="8116925261070264013">Zvuk bol vypnutý</translation>
+<translation id="8116925261070264013">Vypnuté</translation>
<translation id="8131740175452115882">Potvrdiť</translation>
<translation id="8197286292360124385">Povolené: <ph name="PERMISSION_1" /></translation>
<translation id="8200772114523450471">PokraÄovaÅ¥</translation>
@@ -266,8 +267,8 @@
<translation id="8261506727792406068">Odstrániť</translation>
<translation id="8300705686683892304">Spravované aplikáciou</translation>
<translation id="8324158725704657629">Nabudúce sa nepýtať</translation>
-<translation id="8372893542064058268">Povolenie synchronizácie na pozadí na konkrétnom webe.</translation>
-<translation id="8376384591331888629">Vrátane súborov cookie tretej strany na tomto webe</translation>
+<translation id="8372893542064058268">Povoliť synchronizáciu na pozadí na konkrétnom webe.</translation>
+<translation id="8376384591331888629">Vrátane súborov cookie tretích strán na tomto webe</translation>
<translation id="83792324527827022">Váš fotoaparát a mikrofón používa nejaký web</translation>
<translation id="8380167699614421159">Tento web zobrazuje obťažujúce alebo zavádzajúce reklamy</translation>
<translation id="8394832520002899662">Klepnutím sa vrátite na web</translation>
@@ -277,33 +278,32 @@
<translation id="8447861592752582886">Odvolať povolenie pre zariadenie</translation>
<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{Používa sa 1 súbor cookie}few{Používajú sa # súbory cookie}many{# cookies in use}other{Používa sa # súborov cookie}}</translation>
<translation id="8463851957836045671">Web je rýchly</translation>
-<translation id="851751545965956758">Zakázať webom pripájať sa k zariadeniam</translation>
+<translation id="851751545965956758">Brániť webom pripájať sa k zariadeniam</translation>
<translation id="8525306231823319788">Celá obrazovka</translation>
<translation id="857943718398505171">Povolené (odporúÄané)</translation>
<translation id="8609465669617005112">Presunúť nahor</translation>
<translation id="8676374126336081632">Vymazať vstup</translation>
<translation id="868929229000858085">Prehľadať kontakty</translation>
-<translation id="8702612070107455751">Budú vymazané všetky offline údaje.</translation>
+<translation id="8702612070107455751">Všetky offline dáta budú vymazané.</translation>
<translation id="8719283222052720129">Zapnite v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" /> povolenie pre aplikáciu <ph name="APP_NAME" />.</translation>
<translation id="8725066075913043281">Skúsiť znova</translation>
<translation id="8730621377337864115">Hotovo</translation>
-<translation id="8737217482364735741">Týmto vymažete všetky dáta a súbory cookie uložené zdrojom <ph name="ORIGIN" />.</translation>
+<translation id="8737217482364735741">Týmto vymažete všetky dáta a súbory cookie uložené webom <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Vyberte obrázok</translation>
-<translation id="8801436777607969138">Zablokujte JavaScript pre konkrétny web.</translation>
-<translation id="8816026460808729765">Zablokovať webom prístup k senzorom</translation>
+<translation id="8801436777607969138">Blokovať JavaScript na konkrétnom webe.</translation>
+<translation id="8816026460808729765">Brániť webom v prístupe k senzorom</translation>
<translation id="8847988622838149491">USB</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Technológia NFC je v tomto zariadení vypnutá. Zapnite ju v <ph name="BEGIN_LINK" />Nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="8929372349074745002">Tento web sa väÄÅ¡ine ľudí otvára rýchlo, aj tak reaguje</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="894871326938397531">UkonÄiÅ¥ režim inkognito?</translation>
-<translation id="8958424370300090006">Blokovanie súborov cookie konkrétneho webu</translation>
+<translation id="8958424370300090006">Blokovať súbory cookie na konkrétnom webe.</translation>
<translation id="8959122750345127698">Navigácia je nedostupná: <ph name="URL" /></translation>
<translation id="9019902583201351841">Spravované vaÅ¡imi rodiÄmi</translation>
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie povolenie}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie povolenia}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> Äalších povolení}}</translation>
<translation id="913657688200966289">Zapnite v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" /> povolenia pre aplikáciu <ph name="APP_NAME" />.</translation>
-<translation id="945632385593298557">Prístup k mikrofónu</translation>
<translation id="965817943346481315">BlokovaÅ¥, ak web zobrazuje obÅ¥ažujúce alebo zavádzajúce reklamy (odporúÄané)</translation>
<translation id="967624055006145463">Uložené dáta</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
index 2917ba90642..d0f5dd8889e 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Spletno mesto <ph name="SITE_NAME" /> je bilo dodano</translation>
<translation id="1383876407941801731">IÅ¡Äi</translation>
<translation id="1384959399684842514">Prenos je zaustavljen</translation>
+<translation id="1415402041810619267">URL je skrajšan</translation>
<translation id="1431402976894535801">PrepreÄevanje, da bi spletna mesta vedela, da ste prisotni</translation>
<translation id="1446450296470737166">Dovolitev popolnega nadzora nad napravami MIDI</translation>
<translation id="1509960214886564027">Funkcije na Å¡tevilnih spletnih mestih morda ne bodo delovale</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Dostop do fotoaparata</translation>
<translation id="1660204651932907780">Dovoli spletnim mestom predvajanje zvoka (priporoÄljivo)</translation>
<translation id="1677097821151855053">Piškotke in druge podatke spletnega mesta uporabljamo, da si zapomnimo vaše podatke, na primer za prijavo ali osebno prilagajanje oglasov. Če želite upravljati piškotke za vsa spletna mesta, si oglejte <ph name="BEGIN_LINK" />Nastavitve<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Ali želite izbrisati podatke spletnega mesta?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL spletnega mesta</translation>
<translation id="2025115093177348061">RazÅ¡irjena resniÄnost</translation>
<translation id="2030769033451695672">Dotaknite se, Äe se želite vrniti na <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Vaša prisotnost</translation>
<translation id="2079545284768500474">Razveljavi</translation>
<translation id="2091887806945687916">Zvok</translation>
<translation id="2107397443965016585">Prikaži poziv, preden se spletnim mestom dovoli predvajanje zaÅ¡Äitene vsebine (priporoÄeno)</translation>
<translation id="2146738493024040262">Odpri nenamestljivo aplikacijo</translation>
<translation id="2148716181193084225">Danes</translation>
<translation id="2182457891543959921">VpraÅ¡aj, preden se spletnim mestom dovoli ustvarjanje 3D-zemljevida vaÅ¡e okolice ali spremljanje položaja kamere (priporoÄljivo)</translation>
-<translation id="2187243482123994665">Prisotnost uporabnika</translation>
<translation id="2212565012507486665">Dovoli piškotke</translation>
<translation id="2228071138934252756">ÄŒe želite aplikaciji <ph name="APP_NAME" /> omogoÄiti dostop do fotoaparata, fotoaparat vklopite tudi v <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo enkrat</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}one{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}two{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}few{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}other{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Prenos je konÄan <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Dostop do lokacije</translation>
<translation id="2482878487686419369">Obvestila</translation>
<translation id="2490684707762498678">Upravlja aplikacija <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">PomoÄ in povratne inform.</translation>
@@ -75,7 +74,7 @@
<translation id="2874939134665556319">Prejšnja skladba</translation>
<translation id="2903493209154104877">Naslovi</translation>
<translation id="2910701580606108292">Prikaži poziv, preden se spletnim mestom dovoli predvajanje zaÅ¡Äitene vsebine</translation>
-<translation id="2913331724188855103">Dovoli spletnim mestom shranjevanje in branje podatkov piÅ¡kotkov (priporoÄljivo)</translation>
+<translation id="2913331724188855103">Spletnim mestom dovoli shranjevanje in branje podatkov piÅ¡kotkov (priporoÄljivo)</translation>
<translation id="2968755619301702150">Pregledovalnik potrdil</translation>
<translation id="300526633675317032">S tem bo izbrisanih vseh <ph name="SIZE_IN_KB" /> shranjenih podatkov spletnega mesta.</translation>
<translation id="3008272652534848354">Ponastavi dovoljenja</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Spletnim mestom dovoli dostop do tipal (priporoÄeno)</translation>
<translation id="3295602654194328831">Skrij informacije</translation>
+<translation id="3328801116991980348">Podatki o mestu</translation>
<translation id="3333961966071413176">Vsi stiki</translation>
<translation id="3386292677130313581">Prikaži poziv, preden se spletnim mestom razkrije vaÅ¡a lokacija (priporoÄeno)</translation>
<translation id="3538390592868664640">PrepreÄevanje, da bi spletna mesta ustvarila 3D-zemljevid vaÅ¡e okolice ali spremljala položaj kamere</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Spletnim mestom dovoli predvajanje zaÅ¡Äitene vsebine</translation>
<translation id="4468959413250150279">Izklop zvoka za doloÄeno spletno mesto.</translation>
<translation id="4479647676395637221">Prikaži poziv, preden se spletnim mestom dovoli uporaba kamere (priporoÄeno)</translation>
+<translation id="4505788138578415521">URL je razširjen</translation>
<translation id="4534723447064627427">ÄŒe želite aplikaciji <ph name="APP_NAME" /> omogoÄiti dostop do mikrofona, mikrofon vklopite tudi v <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Podrobnosti</translation>
<translation id="4645575059429386691">Upravlja starš</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}two{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">V <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" /> vklopite dovoljenja za aplikacijo <ph name="APP_NAME" />.</translation>
-<translation id="945632385593298557">Dostop do mikrofona</translation>
<translation id="965817943346481315">Blokiraj, Äe spletno mesto prikazuje vsiljive ali zavajajoÄe oglase (priporoÄljivo)</translation>
<translation id="967624055006145463">Shranjeni podatki</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
index 2927d2fffcc..bd675c90570 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
@@ -8,7 +8,7 @@
<translation id="1178581264944972037">Pauzë</translation>
<translation id="1181037720776840403">Hiq</translation>
<translation id="1195941046451948919">E konfirmon që dëshiron t'i rivendosësh të gjitha lejet për këtë faqe interneti?</translation>
-<translation id="1201402288615127009">Tjetra</translation>
+<translation id="1201402288615127009">Para</translation>
<translation id="1242008676835033345">Integruar në <ph name="WEBSITE_URL" /></translation>
<translation id="1272079795634619415">Ndalo</translation>
<translation id="1289742167380433257">Për të ruajtur të dhënat, imazhet e kësaj faqeje janë optimizuar nga Google.</translation>
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Sajti <ph name="SITE_NAME" /> u shtua</translation>
<translation id="1383876407941801731">Kërko</translation>
<translation id="1384959399684842514">Shkarkimi u ndërpre</translation>
+<translation id="1415402041810619267">URL e prerë</translation>
<translation id="1431402976894535801">Blloko sajtet që të mos dinë kur je i pranishëm</translation>
<translation id="1446450296470737166">Lejo kontrollin e plotë të pajisjeve MIDI</translation>
<translation id="1509960214886564027">Veçoritë në shumë sajte mund të ndalojnë së funksionuari</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Qasu te kamera</translation>
<translation id="1660204651932907780">Lejo që sajtet të luajnë tinguj (rekomandohet)</translation>
<translation id="1677097821151855053">Kukit dhe të dhënat e tjera të sajtit përdoren për të të kujtuar ty, për shembull për të të identifikuar ose për të personalizuar reklamat. Për të menaxhuar kukit për të gjitha sajtet, shiko <ph name="BEGIN_LINK" />Cilësimet<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Të spastrohen të dhënat e sajtit?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL-ja e sajtit</translation>
<translation id="2025115093177348061">Realiteti i zgjeruar</translation>
<translation id="2030769033451695672">Trokit për t'u kthyer te <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Prania jote</translation>
<translation id="2079545284768500474">Zhbëj</translation>
<translation id="2091887806945687916">Tingulli</translation>
<translation id="2107397443965016585">Pyet përpara se sajtet të lejohen të luajnë përmbajtje të mbrojtura (rekomandohet)</translation>
<translation id="2146738493024040262">Hap aplikacionin e çastit</translation>
<translation id="2148716181193084225">Sot</translation>
<translation id="2182457891543959921">Pyet përpara se të lejosh krijimin nga sajtet të një harte 3D të ambientit tënd rrethues ose gjurmimin prej tyre të pozicionit të kamerës (rekomandohet)</translation>
-<translation id="2187243482123994665">Prania e përdoruesit</translation>
<translation id="2212565012507486665">Lejo kukit</translation>
<translation id="2228071138934252756">Për të lejuar që <ph name="APP_NAME" /> të ketë qasje te kamera jote, aktivizo gjithashtu kamerën në <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Vetëm një herë</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> tjetër e lejuar}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> të tjera të lejuara}}</translation>
<translation id="2434158240863470628">Shkarkimi përfundoi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Qasja e vendndodhjes</translation>
<translation id="2482878487686419369">Njoftimet</translation>
<translation id="2490684707762498678">Menaxhuar nga <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ndihmë dhe komente</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofoni</translation>
<translation id="3277252321222022663">Lejoju faqeve të të hapin sensorët (rekomandohet)</translation>
<translation id="3295602654194328831">Fshih informacionin</translation>
+<translation id="3328801116991980348">Informacionet rreth sajtit</translation>
<translation id="3333961966071413176">Të gjitha kontaktet</translation>
<translation id="3386292677130313581">Pyet përpara se sajtet të lejohen të dinë vendndodhjen tënde (rekomandohet)</translation>
<translation id="3538390592868664640">Blloko krijimin nga sajtet të një harte 3D të ambientit tënd rrethues ose gjurmimin prej tyre të pozicionit të kamerës</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Lejo sajtet të luajnë përmbajtje të mbrojtura</translation>
<translation id="4468959413250150279">Hiq zërin për një sajt specifik.</translation>
<translation id="4479647676395637221">Pyet përpara se të lejohen sajtet të përdorin kamerën (rekomandohet)</translation>
+<translation id="4505788138578415521">URL e zgjeruar</translation>
<translation id="4534723447064627427">Për të lejuar që <ph name="APP_NAME" /> të ketë qasje te mikrofoni yt, aktivizo gjithashtu mikrofonin në <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detajet</translation>
<translation id="4645575059429386691">Menaxhohet nga prindi yt</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth-i</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> tjetër}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> të tjera}}</translation>
<translation id="913657688200966289">Aktivizo lejet për <ph name="APP_NAME" /> në <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Qasu te mikrofoni</translation>
<translation id="965817943346481315">Blloko nëse sajti shfaq reklama ndërhyrëse ose mashtruese (rekomandohet)</translation>
<translation id="967624055006145463">Të dhënat e ruajtura</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
index b1d6d5c0171..030cb3b2aab 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Sajt <ph name="SITE_NAME" /> je dodat</translation>
<translation id="1383876407941801731">Pretraži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1415402041810619267">URL je skracÌen</translation>
<translation id="1431402976894535801">Ne dozvolite sajtovima da znaju kada ste prisutni</translation>
<translation id="1446450296470737166">Puna kontrola nad MIDI uređajima</translation>
<translation id="1509960214886564027">Funkcije na mnogim sajtovima mogu da prestanu sa radom</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Pristup kameri</translation>
<translation id="1660204651932907780">Dozvoli sajtovima da puÅ¡taju zvuk (preporuÄeno)</translation>
<translation id="1677097821151855053">KolaÄicÌi i drugi podaci o sajtovima se koriste da biste bili zapamcÌeni, na primer, radi prijavljivanja ili personalizovanja oglasa. Da biste upravljali kolaÄicÌima za sve sajtove, pogledajte <ph name="BEGIN_LINK" />PodeÅ¡avanja<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Želite li da obrišete podatke sajta?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL sajta</translation>
<translation id="2025115093177348061">Proširena realnost</translation>
<translation id="2030769033451695672">Dodirnite da biste se vratili na <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Prisustvo</translation>
<translation id="2079545284768500474">Opozovi</translation>
<translation id="2091887806945687916">Zvuk</translation>
<translation id="2107397443965016585">Upit se prikazuje pre nego Å¡to dozvolite sajtovima da puÅ¡taju zaÅ¡ticÌeni sadržaj (preporuÄeno)</translation>
<translation id="2146738493024040262">Otvori instant aplikaciju</translation>
<translation id="2148716181193084225">Danas</translation>
<translation id="2182457891543959921">Pre nego Å¡to dozvolite sajtovima da prave 3D mapu okruženja ili prate položaj kamere prikazuje se upit (preporuÄeno)</translation>
-<translation id="2187243482123994665">Prisustvo korisnika</translation>
<translation id="2212565012507486665">Dozvoli kolaÄicÌe</translation>
<translation id="2228071138934252756">Da biste dozvolili da <ph name="APP_NAME" /> pristupa kameri, ukljuÄite kameru i u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo jednom</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Pristup lokaciji</translation>
<translation id="2482878487686419369">Obaveštenja</translation>
<translation id="2490684707762498678">Upravlja <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">PomocÌ i povratne informacije</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Dozvoli sajtovima da pristupaju senzorima (preporuÄeno)</translation>
<translation id="3295602654194328831">Sakrij informacije</translation>
+<translation id="3328801116991980348">Informacije o sajtu</translation>
<translation id="3333961966071413176">Svi kontakti</translation>
<translation id="3386292677130313581">Pitaj pre nego Å¡to dozvoliÅ¡ sajtovima da znaju lokaciju (preporuÄeno)</translation>
<translation id="3538390592868664640">SpreÄite sajtove da prave 3D mapu okruženja ili da prate položaj kamere</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Dozvolite sajtovima da puÅ¡taju zaÅ¡ticÌeni sadržaj</translation>
<translation id="4468959413250150279">IskljuÄi zvuk za odreÄ‘eni sajt</translation>
<translation id="4479647676395637221">Pitaj pre nego Å¡to dozvoliÅ¡ sajtovima da koriste kameru (preporuÄeno)</translation>
+<translation id="4505788138578415521">URL je proširen</translation>
<translation id="4534723447064627427">Da biste dozvolili da <ph name="APP_NAME" /> pristupa mikrofonu, ukljuÄite mikrofon i u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Detalji</translation>
<translation id="4645575059429386691">Ovim upravlja tvoj roditelj</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">UkljuÄite dozvole za aplikaciju <ph name="APP_NAME" /> u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Pristup mikrofonu</translation>
<translation id="965817943346481315">Blokiraj ako sajt prikazuje oglase koji ometaju aktivnosti ili obmanjujucÌe oglase (preporuÄeno)</translation>
<translation id="967624055006145463">SaÄuvani podaci</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
index 305e5c1d16e..f9076cc0415 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Сајт <ph name="SITE_NAME" /> је додат</translation>
<translation id="1383876407941801731">Претражи</translation>
<translation id="1384959399684842514">Преузимање је паузирано</translation>
+<translation id="1415402041810619267">URL је Ñкраћен</translation>
<translation id="1431402976894535801">Ðе дозволите Ñајтовима да знају када Ñте приÑутни</translation>
<translation id="1446450296470737166">Пуна контрола над MIDI уређајима</translation>
<translation id="1509960214886564027">Функције на многим Ñајтовима могу да преÑтану Ñа радом</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ПриÑтуп камери</translation>
<translation id="1660204651932907780">Дозволи Ñајтовима да пуштају звук (препоручено)</translation>
<translation id="1677097821151855053">Колачићи и други подаци о Ñајтовима Ñе кориÑте да биÑте били запамћени, на пример, ради пријављивања или перÑонализовања оглаÑа. Да биÑте управљали колачићима за Ñве Ñајтове, погледајте <ph name="BEGIN_LINK" />Подешавања<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Желите ли да обришете податке Ñајта?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL Ñајта</translation>
<translation id="2025115093177348061">Проширена реалноÑÑ‚</translation>
<translation id="2030769033451695672">Додирните да биÑте Ñе вратили на <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">ПриÑуÑтво</translation>
<translation id="2079545284768500474">Опозови</translation>
<translation id="2091887806945687916">Звук</translation>
<translation id="2107397443965016585">Упит Ñе приказује пре него што дозволите Ñајтовима да пуштају заштићени Ñадржај (препоручено)</translation>
<translation id="2146738493024040262">Отвори инÑтант апликацију</translation>
<translation id="2148716181193084225">ДанаÑ</translation>
<translation id="2182457891543959921">Пре него што дозволите Ñајтовима да праве 3D мапу окружења или прате положај камере приказује Ñе упит (препоручено)</translation>
-<translation id="2187243482123994665">ПриÑуÑтво кориÑника</translation>
<translation id="2212565012507486665">Дозволи колачиће</translation>
<translation id="2228071138934252756">Да биÑте дозволили да <ph name="APP_NAME" /> приÑтупа камери, укључите камеру и у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само једном</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}one{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}few{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}other{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Преузимање је завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ПриÑтуп локацији</translation>
<translation id="2482878487686419369">Обавештења</translation>
<translation id="2490684707762498678">Управља <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Помоћ и повратне информације</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Дозволи Ñајтовима да приÑтупају Ñензорима (препоручено)</translation>
<translation id="3295602654194328831">Сакриј информације</translation>
+<translation id="3328801116991980348">Информације о Ñајту</translation>
<translation id="3333961966071413176">Сви контакти</translation>
<translation id="3386292677130313581">Питај пре него што дозволиш Ñајтовима да знају локацију (препоручено)</translation>
<translation id="3538390592868664640">Спречите Ñајтове да праве 3D мапу окружења или да прате положај камере</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Дозволите Ñајтовима да пуштају заштићени Ñадржај</translation>
<translation id="4468959413250150279">ИÑкључи звук за одређени Ñајт</translation>
<translation id="4479647676395637221">Питај пре него што дозволиш Ñајтовима да кориÑте камеру (препоручено)</translation>
+<translation id="4505788138578415521">URL је проширен</translation>
<translation id="4534723447064627427">Да биÑте дозволили да <ph name="APP_NAME" /> приÑтупа микрофону, укључите микрофон и у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Детаљи</translation>
<translation id="4645575059429386691">Овим управља твој родитељ</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Укључите дозволе за апликацију <ph name="APP_NAME" /> у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ПриÑтуп микрофону</translation>
<translation id="965817943346481315">Блокирај ако Ñајт приказује оглаÑе који ометају активноÑти или обмањујуће оглаÑе (препоручено)</translation>
<translation id="967624055006145463">Сачувани подаци</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
index 6b9d6ede26d..d03975949c6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Webbplatsen <ph name="SITE_NAME" /> har lagts till</translation>
<translation id="1383876407941801731">Sök</translation>
<translation id="1384959399684842514">Nedladdningen har pausats</translation>
+<translation id="1415402041810619267">Webbadressen har trunkerats</translation>
<translation id="1431402976894535801">Blockera webbplatser från att registrera om du är närvarande</translation>
<translation id="1446450296470737166">Tillåt fullst. kontroll av MIDI</translation>
<translation id="1509960214886564027">Funktioner kan sluta att fungera på många webbplatser</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Tillgång till din kamera</translation>
<translation id="1660204651932907780">Tillåt att ljud spelas upp på webbplatser (rekommenderas)</translation>
<translation id="1677097821151855053">Cookies och annan webbplatsdata används för att komma ihåg dig, till exempel vid inloggning och annonsanpassning. Du kan hantera cookies för alla webbplatser i <ph name="BEGIN_LINK" />inställningarna<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Vill du ta bort webbplatsdata?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Webbadress</translation>
<translation id="2025115093177348061">Förstärkt verklighet</translation>
<translation id="2030769033451695672">Återgå till <ph name="URL_OF_THE_CURRENT_TAB" /> genom att trycka här</translation>
+<translation id="2054665754582400095">Din närvaro</translation>
<translation id="2079545284768500474">Ã…ngra</translation>
<translation id="2091887806945687916">Ljud</translation>
<translation id="2107397443965016585">Fråga innan webbplatser tillåts att spela upp skyddat innehåll (rekommenderas)</translation>
<translation id="2146738493024040262">Öppna snabbappen</translation>
<translation id="2148716181193084225">Idag</translation>
<translation id="2182457891543959921">Fråga innan webbplatser tillåts att skapa en 3D-karta över dina omgivningar eller registrera kamerans position (rekommenderas)</translation>
-<translation id="2187243482123994665">Användarens närvaro</translation>
<translation id="2212565012507486665">Tillåt cookies</translation>
<translation id="2228071138934252756">Om du vill ge <ph name="APP_NAME" /> åtkomst till kameran måste du även aktivera kameran i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bara en gång</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}}</translation>
<translation id="2434158240863470628">Nedladdningen är klar<ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Platsåtkomst</translation>
<translation id="2482878487686419369">Aviseringar</translation>
<translation id="2490684707762498678">Hanteras av <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Hjälp och feedback</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Tillåt att webbplatser får åtkomst till enhetens sensorer (rekommenderas)</translation>
<translation id="3295602654194328831">Dölj info</translation>
+<translation id="3328801116991980348">Platsinformation</translation>
<translation id="3333961966071413176">Alla kontakter</translation>
<translation id="3386292677130313581">Fråga innan webbplatser tillåts att veta var du befinner dig (rekommenderas)</translation>
<translation id="3538390592868664640">Blockera webbplatser från att skapa en 3D-karta över dina omgivningar eller registrera kamerans position</translation>
@@ -98,7 +98,7 @@
<translation id="3594780231884063836">Stäng av ljudet för videon</translation>
<translation id="3596414637720633074">Blockera cookies från tredje part med inkognitoläget</translation>
<translation id="3600792891314830896">Stäng av ljudet på webbplatser</translation>
-<translation id="3744111561329211289">Synkronisera i bakgrunden</translation>
+<translation id="3744111561329211289">Synkronisering i bakgrunden</translation>
<translation id="3763247130972274048">Hoppa över 10 s genom att trycka två gånger till vänster/höger på videon</translation>
<translation id="381841723434055211">Telefonnummer</translation>
<translation id="385051799172605136">Föregående</translation>
@@ -109,7 +109,7 @@
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Tillåt cookies för en enskild webbplats.</translation>
<translation id="4046123991198612571">Nästa spår</translation>
-<translation id="4165986682804962316">Platsinställningar</translation>
+<translation id="4165986682804962316">Webbplatsinställningar</translation>
<translation id="4200726100658658164">Öppna platsinställningarna</translation>
<translation id="4226663524361240545">Aviseringar kan göra att enheten vibrerar</translation>
<translation id="4259722352634471385">Webbadressen har blockerats: <ph name="URL" /></translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Tillåt att webbplatser spelar upp skyddat innehåll</translation>
<translation id="4468959413250150279">Stäng av ljudet för en webbplats.</translation>
<translation id="4479647676395637221">Fråga innan webbplatser tillåts att använda kameran (rekommenderas)</translation>
+<translation id="4505788138578415521">Webbadressen har utökats</translation>
<translation id="4534723447064627427">Om du vill ge <ph name="APP_NAME" /> åtkomst till mikrofonen måste du även aktivera mikrofonen i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Information</translation>
<translation id="4645575059429386691">Hanteras av din förälder</translation>
@@ -161,7 +162,7 @@
<translation id="5556459405103347317">Hämta igen</translation>
<translation id="5596627076506792578">Fler alternativ</translation>
<translation id="5649053991847567735">Automatiska nedladdningar</translation>
-<translation id="5677928146339483299">Blockerade</translation>
+<translation id="5677928146339483299">Blockerat</translation>
<translation id="5689516760719285838">Plats</translation>
<translation id="5690795753582697420">Kameran har inaktiverats i inställningarna för Android</translation>
<translation id="5710871682236653961">Fråga innan webbplatser tillåts att skicka och ta emot uppgifter när du snuddar vid NFC-enheter (rekommenderas)</translation>
@@ -267,7 +268,7 @@
<translation id="8300705686683892304">Hanteras av app</translation>
<translation id="8324158725704657629">Fråga inte igen</translation>
<translation id="8372893542064058268">Tillåt bakgrundssynkronisering för en specifik webbplats.</translation>
-<translation id="8376384591331888629">Inklusive cookies från tredje part på den här webbplatsen</translation>
+<translation id="8376384591331888629">Inkludera cookies från tredje part på den här webbplatsen</translation>
<translation id="83792324527827022">En webbplats använder kameran och mikrofonen</translation>
<translation id="8380167699614421159">Påträngande eller vilseledande annonser visas på den här webbplatsen</translation>
<translation id="8394832520002899662">Återgå till webbplatsen genom att trycka här</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till}}</translation>
<translation id="913657688200966289">Aktivera behörigheter för <ph name="APP_NAME" /> i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Tillgång till din mikrofon</translation>
<translation id="965817943346481315">Blockera om påträngande eller vilseledande annonser visas på webbplatsen (rekommenderas)</translation>
<translation id="967624055006145463">Sparad data</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
index 277c21cd849..af945163ad1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Tovuti <ph name="SITE_NAME" /> imeongezwa</translation>
<translation id="1383876407941801731">Tafuta</translation>
<translation id="1384959399684842514">Upakuaji umesitishwa</translation>
+<translation id="1415402041810619267">URL imepunguzwa</translation>
<translation id="1431402976894535801">Zuia tovuti zisijue wakati unapatikana</translation>
<translation id="1446450296470737166">Ruhusu udhibiti kamili wa vifaa vya MIDI</translation>
<translation id="1509960214886564027">Huenda vipengele kwenye tovuti nyingi vikakosa kufanya kazi</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kufikia kamera yako</translation>
<translation id="1660204651932907780">Ruhusu tovuti kucheza sauti (inapendekezwa)</translation>
<translation id="1677097821151855053">Vidakuzi na data nyingine ya tovuti hutumika kukukumbuka, kwa mfano kukuingiza katika akaunti au kuweka mapendeleo kwenye matangazo. Ili udhibiti vidakuzi vya tovuti zote, angalia <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Ungependa kufuta data ya tovuti?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL ya Tovuti</translation>
<translation id="2025115093177348061">Uhalisia ulioboreshwa</translation>
<translation id="2030769033451695672">Gusa ili urudi kwenye <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Maelezo ya wakati upo mtandaoni</translation>
<translation id="2079545284768500474">Tendua</translation>
<translation id="2091887806945687916">Sauti</translation>
<translation id="2107397443965016585">Iulize kabla ya kuruhusu tovuti kucheza maudhui yanayolindwa (inapendekezwa)</translation>
<translation id="2146738493024040262">Fungua Programu Inayofunguka Papo Hapo</translation>
<translation id="2148716181193084225">Leo</translation>
<translation id="2182457891543959921">Uliza kabla ya kuruhusu tovuti zibuni ramani ya 3D ya mazingira yako au kufuatilia mkao wa kamera (inapendekezwa)</translation>
-<translation id="2187243482123994665">Upatikanaji wa mtumiaji</translation>
<translation id="2212565012507486665">Ruhusu vidakuzi</translation>
<translation id="2228071138934252756">Ili uruhusu <ph name="APP_NAME" /> ifikie kamera yako, washa pia kamera katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Mara moja tu</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747">MB <ph name="MEGABYTES" /></translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}other{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Upakuaji umekamilika <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Ufikiaji wa eneo</translation>
<translation id="2482878487686419369">Arifa</translation>
<translation id="2490684707762498678">Inasimamiwa na <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Usaidizi na maoni</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Maikrofoni</translation>
<translation id="3277252321222022663">Ruhusu tovuti zifikie vitambuzi (inapendekezwa)</translation>
<translation id="3295602654194328831">Ficha Maelezo</translation>
+<translation id="3328801116991980348">Maelezo ya tovuti</translation>
<translation id="3333961966071413176">Anwani zote</translation>
<translation id="3386292677130313581">Uliza kabla ya kuruhusu tovuti zijue mahali ulipo (inapendekezwa)</translation>
<translation id="3538390592868664640">Zuia tovuti zisibuni ramani ya 3D ya mazingira yako wala kufuatilia mkao wa kamera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Ruhusu tovuti icheze maudhui yanayolindwa</translation>
<translation id="4468959413250150279">Zima sauti katika tovuti mahususi.</translation>
<translation id="4479647676395637221">Uliza kwanza kabla ya kuruhusu tovuti zitumie kamera yako (inapendekezwa)</translation>
+<translation id="4505788138578415521">URL imepanuliwa</translation>
<translation id="4534723447064627427">Ili uruhusu <ph name="APP_NAME" /> ifikie maikrofoni yako, washa pia maikrofoni katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Maelezo</translation>
<translation id="4645575059429386691">Inadhibitiwa na wazazi wako</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Washa ruhusa za <ph name="APP_NAME" /> katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Kufikia maikrofoni yako</translation>
<translation id="965817943346481315">Zuia ikiwa tovuti inaonyesha matangazo yanayopotosha au yanayokatiza huduma (inapendekezwa)</translation>
<translation id="967624055006145463">Data iliyohifadhiwa</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
index 15d6b2eca42..21e35eb84a2 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> தளம௠சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">பதிவிறகà¯à®•à®®à¯ இடைநிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="1415402041810619267">URL தà¯à®£à¯à®Ÿà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="1431402976894535801">நான௠செயலில௠இரà¯à®•à¯à®•à¯à®®à¯ நேரதà¯à®¤à¯ˆà®¤à¯ தளஙà¯à®•à®³à¯ அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®µà®¤à¯ˆà®¤à¯ தடà¯</translation>
<translation id="1446450296470737166">MIDI சாதனஙà¯à®•à®³à¯à®•à¯à®•à¯ à®®à¯à®´à¯à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆ அனà¯à®®à®¤à®¿</translation>
<translation id="1509960214886564027">பெரà¯à®®à¯à®ªà®¾à®²à®¾à®© தளஙà¯à®•à®³à®¿à®²à¯à®³à¯à®³ à®…à®®à¯à®šà®™à¯à®•à®³à¯ செயலà¯à®ªà®Ÿà®¾à®®à®²à¯ போககà¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="1620510694547887537">கேமரா</translation>
-<translation id="1647391597548383849">உஙà¯à®•à®³à¯ கேமராவை அணà¯à®•à®²à®¾à®®à¯</translation>
<translation id="1660204651932907780">ஒலியை இயகà¯à®•, தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯)</translation>
<translation id="1677097821151855053">கà¯à®•à¯à®•à¯€à®•à®³à¯à®®à¯ பிற தளதà¯à®¤à®¿à®©à¯ தரவà¯à®®à¯ உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆ நினைவில௠வைதà¯à®¤à¯à®•à¯à®•à¯Šà®³à¯à®³à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®©. உதாரணமாக, உஙà¯à®•à®³à¯ˆ உளà¯à®¨à¯à®´à¯ˆà®¯à®šà¯ செயà¯à®µà®¤à¯, விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®ªà¯ பிரதà¯à®¤à®¿à®¯à¯‡à®•à®®à®¾à®•à¯à®•à¯à®µà®¤à¯. அனைதà¯à®¤à¯à®¤à¯ தளஙà¯à®•à®³à¯à®•à¯à®•à®¾à®© கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®¯à¯à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•, <ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à¯ˆà®ªà¯<ph name="END_LINK" /> பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="1688867105868176567">தளத௠தரவை அழிகà¯à®•à®µà®¾?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">தள URL</translation>
<translation id="2025115093177348061">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" />கà¯à®•à¯à®šà¯ செலà¯à®², தடà¯à®Ÿà®µà¯à®®à¯</translation>
+<translation id="2054665754582400095">எனத௠செயலà¯à®ªà®¾à®Ÿà¯</translation>
<translation id="2079545284768500474">செயலà¯à®¤à®µà®¿à®°à¯</translation>
<translation id="2091887806945687916">ஒலி</translation>
<translation id="2107397443965016585">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ இயகà¯à®•à¯à®µà®¤à®±à¯à®•à¯à®¤à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ à®®à¯à®©à¯à®ªà¯ அனà¯à®®à®¤à®¿ கோரà¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯)</translation>
<translation id="2146738493024040262">இனà¯à®¸à¯à®Ÿà®£à¯à®Ÿà¯ ஆபà¯à®¸à¯ˆà®¤à¯ திற</translation>
<translation id="2148716181193084225">இனà¯à®±à¯</translation>
<translation id="2182457891543959921">உஙà¯à®•à®³à¯ˆà®šà¯ சà¯à®±à¯à®±à®¿à®¯à¯à®³à¯à®³ இடஙà¯à®•à®³à®¿à®©à¯ 3D மேபà¯à®ªà¯ˆ உரà¯à®µà®¾à®•à¯à®•à®µà¯‹ கேமரா நிலையை டிராக௠செயà¯à®¯à®µà¯‹ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ à®®à¯à®©à¯à®ªà®¾à®• அனà¯à®®à®¤à®¿ கேடà¯à®•à¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
-<translation id="2187243482123994665">பயனர௠செயலà¯à®¨à®¿à®²à¯ˆ</translation>
<translation id="2212565012507486665">கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ அனà¯à®®à®¤à®¿</translation>
<translation id="2228071138934252756">உஙà¯à®•à®³à¯ கேமராவை அணà¯à®• <ph name="APP_NAME" /> ஆபà¯à®¸à¯ˆ அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ <ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯à®®à¯<ph name="END_LINK" /> கேமராவிறà¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="2241634353105152135">à®’à®°à¯à®®à¯à®±à¯ˆ மடà¯à®Ÿà¯à®®à¯‡</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> மெ.பை.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©}}</translation>
<translation id="2434158240863470628">பதிவிறகà¯à®•à®®à¯ à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯ <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">இரà¯à®ªà¯à®ªà®¿à®Ÿ அணà¯à®•à®²à¯</translation>
<translation id="2482878487686419369">அறிவிபà¯à®ªà¯à®•à®³à¯</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> நிரà¯à®µà®•à®¿à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="2498359688066513246">உதவி &amp; கரà¯à®¤à¯à®¤à¯</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">மைகà¯à®°à¯‡à®¾à®ƒà®ªà¯‡à®¾à®©à¯</translation>
<translation id="3277252321222022663">தளஙà¯à®•à®³à¯ செனà¯à®šà®¾à®°à¯à®•à®³à¯ˆ அணà¯à®• அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="3295602654194328831">தகவலை மறை</translation>
+<translation id="3328801116991980348">தளம௠கà¯à®±à®¿à®¤à¯à®¤ தகவலà¯</translation>
<translation id="3333961966071413176">எலà¯à®²à®¾à®¤à¯ தொடரà¯à®ªà¯à®•à®³à¯à®®à¯</translation>
<translation id="3386292677130313581">எனத௠இரà¯à®ªà¯à®ªà®¿à®Ÿà®¤à¯à®¤à¯ˆ அறிய தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ à®®à¯à®©à¯ கேள௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="3538390592868664640">தளஙà¯à®•à®³à¯, எனà¯à®©à¯ˆà®šà¯ சà¯à®±à¯à®±à®¿à®¯à¯à®³à¯à®³ இடஙà¯à®•à®³à®¿à®©à¯ 3D மேபà¯à®ªà¯ˆ உரà¯à®µà®¾à®•à¯à®•à¯à®µà®¤à¯ˆà®¯à¯à®®à¯ கேமரா நிலையை டிராக௠செயà¯à®µà®¤à¯ˆà®¯à¯à®®à¯ தடà¯</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ இயகà¯à®•à¯à®µà®¤à®±à¯à®•à¯à®¤à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯</translation>
<translation id="4468959413250150279">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தளதà¯à®¤à®¿à®±à¯à®•à¯ ஒலியடகà¯à®•à¯</translation>
<translation id="4479647676395637221">எனத௠கேமராவைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¤à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ à®®à¯à®©à¯ கேள௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
+<translation id="4505788138578415521">URL விரிவாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> ஆபà¯à®¸à¯ உஙà¯à®•à®³à¯ மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆ அணà¯à®• அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ <ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯à®®à¯<ph name="END_LINK" /> மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯à®•à¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="4570913071927164677">விவரஙà¯à®•à®³à¯</translation>
<translation id="4645575059429386691">உஙà¯à®•à®³à¯ பெறà¯à®±à¯‹à®°à®¾à®²à¯ நிரà¯à®µà®•à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">பà¯à®³à¯‚டூதà¯</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ <ph name="END_LINK" /> <ph name="APP_NAME" /> ஆபà¯à®¸à¯à®•à¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®•à®³à¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
-<translation id="945632385593298557">உஙà¯à®•à®³à¯ மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆ அணà¯à®•à®²à®¾à®®à¯</translation>
<translation id="965817943346481315">கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ அலà¯à®²à®¤à¯ தவறாக வழிநடதà¯à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆ தளம௠காணà¯à®ªà®¿à®¤à¯à®¤à®¾à®²à¯, அதைத௠தட௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯)</translation>
<translation id="967624055006145463">சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ தரவினà¯à®ªà®Ÿà®¿</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
index 2dbe49606e2..f2483a6fc0c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> సైటౠజోడించబడింది</translation>
<translation id="1383876407941801731">సెరà±à°šà±</translation>
<translation id="1384959399684842514">డౌనà±â€Œà°²à±‹à°¡à± పాజౠచేయబడింది</translation>
+<translation id="1415402041810619267">URL à°•à±à°¦à°¿à°‚చబడింది</translation>
<translation id="1431402976894535801">మీ ఉనికిని తెలà±à°¸à±à°•à±‹à°¨à°¿à°µà±à°µà°•à±à°‚à°¡à°¾ సైటà±â€Œà°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి</translation>
<translation id="1446450296470737166">MIDI పరికరాల పూరà±à°¤à°¿ నియం. à°…à°¨à±à°®.</translation>
<translation id="1509960214886564027">చాలా సైటà±â€Œà°²à°²à±‹à°¨à°¿ ఫీచరà±â€Œà°²à± పని చేయకà±à°‚డాపోవచà±à°šà±</translation>
<translation id="1620510694547887537">కెమెరా</translation>
-<translation id="1647391597548383849">మీ కెమెరా యాకà±à°¸à±†à°¸à± à°…à°¨à±à°®à°¤à°¿</translation>
<translation id="1660204651932907780">à°§à±à°µà°¨à°¿à°¨à°¿ à°ªà±à°²à±‡ చేయగలిగేలా సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="1677097821151855053">మిమà±à°®à°²à±à°¨à°¿ à°—à±à°°à±à°¤à±à°‚à°šà±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ à°•à±à°•à±à°•à±€à°²à±, ఇతర సైటౠడేటా ఉపయోగించబడతాయి, ఉదాహరణకౠమిమలà±à°¨à°¿ సైనౠఇనౠచేయడం కోసం లేదా యాడà±â€Œà°²à°¨à± à°µà±à°¯à°•à±à°¤à°¿à°—తీకరించడం కోసం. à°…à°¨à±à°¨à°¿ సైటà±â€Œà°²à°•à± à°•à±à°•à±à°•à±€à°²à°¨à± మేనేజౠచేయడానికి, <ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />నౠచూడండి.</translation>
<translation id="1688867105868176567">సైటౠడేటాని à°•à±à°²à°¿à°¯à°°à± చేయాలా?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">సైటౠURL</translation>
<translation id="2025115093177348061">à°…à°—à±â€Œà°®à±†à°‚టెడౠరియాలిటీ</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" />కౠతిరిగి వెళà±à°²à°¡à°¾à°¨à°¿à°•à°¿ à°Ÿà±à°¯à°¾à°ªà± చేయండి</translation>
+<translation id="2054665754582400095">మీ ఉనికి</translation>
<translation id="2079545284768500474">à°šà°°à±à°¯ à°°à°¦à±à°¦à±</translation>
<translation id="2091887806945687916">à°§à±à°µà°¨à°¿</translation>
<translation id="2107397443965016585">సైటà±â€Œà°²à± à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయడానికి à°®à±à°‚దౠఅనà±à°®à°¤à°¿ కోసం à°…à°¡à±à°—à±à°¤à°¾à°¯à°¿ (సిఫారà±à°¸à± చేయడమైనది)</translation>
<translation id="2146738493024040262">తకà±à°·à°£ యాపà±â€Œà°¨à± తెరà±à°µà±</translation>
<translation id="2148716181193084225">à°ˆ రోజà±</translation>
<translation id="2182457891543959921">మీ పరిసరాల 3D à°®à±à°¯à°¾à°ªà±â€Œà°¨à± రూపొందించడానికి లేదా కెమెరా పొజిషనà±â€Œà°¨à± à°Ÿà±à°°à°¾à°•à± చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚చే à°®à±à°‚దౠఅడగాలి (సిఫారà±à°¸à± చేయడమైనది)</translation>
-<translation id="2187243482123994665">యూజరౠఉనికి</translation>
<translation id="2212565012507486665">à°•à±à°•à±à°•à±€à°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà±</translation>
<translation id="2228071138934252756">మీ కెమెరానౠయాకà±à°¸à±†à°¸à± చేయడానికి <ph name="APP_NAME" />ని à°…à°¨à±à°®à°¤à°¿à°‚చడానికి, <ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో కూడా కెమెరానౠఆనౠచేయండి.</translation>
<translation id="2241634353105152135">ఒకసారి మాతà±à°°à°®à±‡</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> à°…à°¨à±à°®à°¤à°¿à°‚చబడà±à°¡à°¾à°¯à°¿}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> à°…à°¨à±à°®à°¤à°¿à°‚చబడà±à°¡à°¾à°¯à°¿}}</translation>
<translation id="2434158240863470628">డౌనà±â€Œà°²à±‹à°¡à± పూరà±à°¤à°¯à°¿à°‚ది <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">à°¸à±à°¥à°¾à°¨ యాకà±à°¸à±†à°¸à±</translation>
<translation id="2482878487686419369">నోటిఫికేషనà±â€Œà°²à±</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> à°¦à±à°µà°¾à°°à°¾ నిరà±à°µà°¹à°¿à°‚చబడà±à°¤à±à°¨à±à°¨à°¾à°¯à°¿</translation>
<translation id="2498359688066513246">సహాయం &amp; à°…à°­à°¿à°ªà±à°°à°¾à°¯à°‚</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">మైకà±à°°à±‹à°«à±‹à°¨à±</translation>
<translation id="3277252321222022663">సెనà±à°¸à°¾à°°à±â€Œà°²à°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేసà±à°¤à±à°¨à±à°¨à°¾à°®à±)</translation>
<translation id="3295602654194328831">సమాచారానà±à°¨à°¿ దాచà±</translation>
+<translation id="3328801116991980348">సైటౠసమాచారం</translation>
<translation id="3333961966071413176">మొతà±à°¤à°‚ పరిచయాలà±</translation>
<translation id="3386292677130313581">మీ à°¸à±à°¥à°¾à°¨à°¾à°¨à±à°¨à°¿ సైటà±â€Œà°²à± తెలà±à°¸à±à°•à±à°¨à±‡à°²à°¾ వాటిని à°…à°¨à±à°®à°¤à°¿à°‚చే à°®à±à°‚à°¦à±, మిమà±à°®à°²à±à°¨à°¿ à°…à°¡à±à°—à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="3538390592868664640">మీ పరిసరాల 3D à°®à±à°¯à°¾à°ªà±â€Œà°¨à± సృషà±à°Ÿà°¿à°‚à°šà°•à±à°‚à°¡à°¾ లేదా కెమెరా పొజిషనà±â€Œà°¨à± à°Ÿà±à°°à°¾à°•à± చేయకà±à°‚à°¡à°¾ సైటà±â€Œà°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది</translation>
<translation id="4468959413250150279">నిరà±à°¦à°¿à°·à±à°Ÿ సైటౠకోసం à°§à±à°µà°¨à°¿à°¨à°¿ à°®à±à°¯à±‚టౠచేయండి.</translation>
<translation id="4479647676395637221">మీ కెమెరానౠà°à°µà±ˆà°¨à°¾ సైటà±â€Œà°²à± ఉపయోగించగలిగేలా వాటిని à°…à°¨à±à°®à°¤à°¿à°‚చే à°®à±à°‚à°¦à±, మిమà±à°®à°²à±à°¨à°¿ à°…à°¡à±à°—à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
+<translation id="4505788138578415521">URL విసà±à°¤à°°à°¿à°‚చబడింది</translation>
<translation id="4534723447064627427">మీ మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి <ph name="APP_NAME" />ని à°…à°¨à±à°®à°¤à°¿à°‚చేందà±à°•à±, <ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో కూడా మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఆనౠచేయండి.</translation>
<translation id="4570913071927164677">వివరాలà±</translation>
<translation id="4645575059429386691">మీ తలà±à°²à°¿/తండà±à°°à°¿ à°¦à±à°µà°¾à°°à°¾ నిరà±à°µà°¹à°¿à°‚చబడà±à°¤à±‹à°‚ది</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">à°¬à±à°²à±‚టూతà±</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో <ph name="APP_NAME" /> కోసం à°…à°¨à±à°®à°¤à±à°²à°¨à± ఆనౠచేయండి.</translation>
-<translation id="945632385593298557">మీ మైకà±à°°à±‹à°«à±‹à°¨à± యాకà±à°¸à±†à°¸à± à°…à°¨à±à°®à°¤à°¿</translation>
<translation id="965817943346481315">సైటౠఅనà±à°šà°¿à°¤à°®à±ˆà°¨ లేదా తపà±à°ªà±à°¦à°¾à°°à°¿ పటà±à°Ÿà°¿à°‚చే à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± చూపించినపà±à°ªà±à°¡à± à°¬à±à°²à°¾à°•à± చేయి (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="967624055006145463">నిలà±à°µ చేయబడిన డేటా</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
index 095736bf285..018317a2e77 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">เพิ่มเว็บไซต์ <ph name="SITE_NAME" /> à¹à¸¥à¹‰à¸§</translation>
<translation id="1383876407941801731">ค้นหา</translation>
<translation id="1384959399684842514">หยุดดาวน์โหลดไว้ชั่วคราว</translation>
+<translation id="1415402041810619267">ตัด URL ให้สั้นลงà¹à¸¥à¹‰à¸§</translation>
<translation id="1431402976894535801">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้ทราบว่าคุณใช้งานอยู่</translation>
<translation id="1446450296470737166">ควบคุมอุปà¸à¸£à¸“์ MIDI ได้สมบูรณ์</translation>
<translation id="1509960214886564027">ฟีเจอร์ในหลายเว็บไซต์อาจใช้งานไม่ได้</translation>
<translation id="1620510694547887537">à¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูป</translation>
-<translation id="1647391597548383849">เข้าถึงà¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูป</translation>
<translation id="1660204651932907780">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เล่นเสียง (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="1677097821151855053">คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลอื่นๆ ของเว็บไซต์ใช้ในà¸à¸²à¸£à¸ˆà¸”จำคุณ เช่น เพื่อลงชื่อเข้าใช้ให้คุณหรือปรับโฆษณาตามโปรไฟล์ของคุณ ดู<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" />เพื่อจัดà¸à¸²à¸£à¸„ุà¸à¸à¸µà¹‰à¸ªà¸³à¸«à¸£à¸±à¸šà¸—ุà¸à¹€à¸§à¹‡à¸šà¹„ซต์</translation>
<translation id="1688867105868176567">ล้างข้อมูลเว็บไซต์ไหม</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL ของเว็บไซต์</translation>
<translation id="2025115093177348061">Augmented Reality</translation>
<translation id="2030769033451695672">à¹à¸•à¸°à¹€à¸žà¸·à¹ˆà¸­à¸à¸¥à¸±à¸šà¹„ปที่ <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™</translation>
<translation id="2079545284768500474">เลิà¸à¸—ำ</translation>
<translation id="2091887806945687916">เสียง</translation>
<translation id="2107397443965016585">ถามà¸à¹ˆà¸­à¸™à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="2146738493024040262">เปิด Instant App</translation>
<translation id="2148716181193084225">วันนี้</translation>
<translation id="2182457891543959921">ถามà¸à¹ˆà¸­à¸™à¸—ี่จะอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์สร้างà¹à¸œà¸™à¸—ี่ 3 มิติของสิ่งที่อยู่รอบตัวคุณหรือติดตามตำà¹à¸«à¸™à¹ˆà¸‡à¸‚องà¸à¸¥à¹‰à¸­à¸‡ (à¹à¸™à¸°à¸™à¸³)</translation>
-<translation id="2187243482123994665">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸­à¸¢à¸¹à¹ˆà¸‚องผู้ใช้</translation>
<translation id="2212565012507486665">อนุà¸à¸²à¸•à¸„ุà¸à¸à¸µà¹‰</translation>
<translation id="2228071138934252756">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="APP_NAME" /> เข้าถึงà¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูป ให้เปิดใช้à¸à¸¥à¹‰à¸­à¸‡à¹ƒà¸™<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /> ด้วย</translation>
<translation id="2241634353105152135">เพียงครั้งเดียว</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}other{อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}}</translation>
<translation id="2434158240863470628">ดาวน์โหลดเสร็จสมบูรณ์ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">à¸à¸²à¸£à¹€à¸‚้าถึงตำà¹à¸«à¸™à¹ˆà¸‡</translation>
<translation id="2482878487686419369">à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™</translation>
<translation id="2490684707762498678">จัดà¸à¸²à¸£à¹‚ดย <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">ความช่วยเหลือà¹à¸¥à¸°à¸„วามคิดเห็น</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">ไมโครโฟน</translation>
<translation id="3277252321222022663">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เข้าถึงเซ็นเซอร์ (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="3295602654194328831">ซ่อนข้อมูล</translation>
+<translation id="3328801116991980348">ข้อมูลไซต์</translation>
<translation id="3333961966071413176">รายชื่อติดต่อทั้งหมด</translation>
<translation id="3386292677130313581">ถามà¸à¹ˆà¸­à¸™à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์ทราบตำà¹à¸«à¸™à¹ˆà¸‡à¸‚องคุณ (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="3538390592868664640">บล็อà¸à¹„ม่ให้เว็บไซต์สร้างà¹à¸œà¸™à¸—ี่ 3 มิติของสิ่งที่อยู่รอบตัวคุณหรือติดตามตำà¹à¸«à¸™à¹ˆà¸‡à¸‚องà¸à¸¥à¹‰à¸­à¸‡</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง</translation>
<translation id="4468959413250150279">ปิดเสียงไซต์ที่ต้องà¸à¸²à¸£</translation>
<translation id="4479647676395637221">ถามà¸à¹ˆà¸­à¸™ à¸à¹ˆà¸­à¸™à¸—ี่จะอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์ใช้à¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูปของคุณ (à¹à¸™à¸°à¸™à¸³)</translation>
+<translation id="4505788138578415521">ขยาย URL à¹à¸¥à¹‰à¸§</translation>
<translation id="4534723447064627427">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="APP_NAME" /> เข้าถึงไมโครโฟน ให้เปิดใช้ไมโครโฟนใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /> ด้วย</translation>
<translation id="4570913071927164677">รายละเอียด</translation>
<translation id="4645575059429386691">มีà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¹‚ดยผู้ปà¸à¸„รอง</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">บลูทูธ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}other{<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}}</translation>
<translation id="913657688200966289">เปิดà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸ªà¸´à¸—ธิ์สำหรับ <ph name="APP_NAME" /> ใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /></translation>
-<translation id="945632385593298557">เข้าถึงไมโครโฟน</translation>
<translation id="965817943346481315">บล็อà¸à¸«à¸²à¸à¹€à¸§à¹‡à¸šà¹„ซต์à¹à¸ªà¸”งโฆษณาที่à¹à¸—รà¸à¸«à¸£à¸·à¸­à¸—ำให้เข้าใจผิด (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="967624055006145463">ข้อมูลที่จัดเà¸à¹‡à¸š</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
index 40c87067a11..cc488fd4a78 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> sitesi eklendi</translation>
<translation id="1383876407941801731">Ara</translation>
<translation id="1384959399684842514">İndirme işlemi duraklatıldı</translation>
-<translation id="1431402976894535801">Etkin olduÄŸunuzda sitelerin bilmesini engelleyin</translation>
+<translation id="1415402041810619267">URL kısaltıldı</translation>
+<translation id="1431402976894535801">Sitelerin etkin olduğumu öğrenmesini engelle</translation>
<translation id="1446450296470737166">MIDI cihazlarının tam denetimine izin verme</translation>
-<translation id="1509960214886564027">Birçok sitedeki özellikler bozulabilir</translation>
+<translation id="1509960214886564027">Birçok sitedeki özellikler çalışmayabilir</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kameranıza erişim</translation>
<translation id="1660204651932907780">Sitelerin ses çalmasına izin ver (önerilir)</translation>
<translation id="1677097821151855053">Çerezler ve diğer site verileri sizi hatırlamamız için kullanılır, örneğin oturumunuzu açmak veya reklamları kişiselleştirmek için. Çerezlerin tüm siteler için nasıl yönetileceğini <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" /> bölümünden öğrenebilirsiniz.</translation>
<translation id="1688867105868176567">Site verileri temizlensin mi?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Site URL'si</translation>
<translation id="2025115093177348061">Artırılmış gerçeklik</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> sekmesine dönmek için dokunun</translation>
+<translation id="2054665754582400095">Bir yerde olduÄŸunuza dair bilgi</translation>
<translation id="2079545284768500474">Geri al</translation>
<translation id="2091887806945687916">Ses</translation>
<translation id="2107397443965016585">Sitelerin korumalı içeriği oynatmasına izin vermeden önce sor (önerilir)</translation>
<translation id="2146738493024040262">Hazır Uygulamayı aç</translation>
<translation id="2148716181193084225">Bugün</translation>
<translation id="2182457891543959921">Sitelerin çevremin 3D haritasını oluşturmasına veya kamera konumunu takip etmesine izin vermeden önce sor (önerilir)</translation>
-<translation id="2187243482123994665">Kullanıcı etkinliği</translation>
<translation id="2212565012507486665">Çerezlere izin ver</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> uygulamasının kameranıza erişebilmesi için <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda da kamerayı açın.</translation>
<translation id="2241634353105152135">Sadece bir defa</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}}</translation>
<translation id="2434158240863470628">İndirme işlemi tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Konum eriÅŸimi</translation>
<translation id="2482878487686419369">Bildirimler</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> tarafından yönetiliyor</translation>
<translation id="2498359688066513246">Yardım ve geri bildirim</translation>
@@ -83,12 +82,13 @@
<translation id="3114012059975132928">Video oynatıcı</translation>
<translation id="3115898365077584848">Bilgileri Göster</translation>
<translation id="3123473560110926937">Bazı sitelerde engellendi</translation>
-<translation id="3165371858310906303">Bir site, etkin olduÄŸumu bilmek istediÄŸinde sor</translation>
+<translation id="3165371858310906303">Bir site, etkin olduğumu öğrenmek istediğinde sor</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> depolanmış veri</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> uygulamasının size bildirim gönderebilmesi için <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda da bildirimleri açın.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Sitelerin sensörlere erişmesine izin ver (önerilen)</translation>
<translation id="3295602654194328831">Bilgileri Gizle</translation>
+<translation id="3328801116991980348">Site bilgileri</translation>
<translation id="3333961966071413176">Tüm kişiler</translation>
<translation id="3386292677130313581">Sitelerin, konumunuzu öğrenmesine izin verilmeden önce size sorulsun (önerilir)</translation>
<translation id="3538390592868664640">Sitelerin çevremin 3D haritasını oluşturmasını veya kamera konumunu takip etmesini engelle</translation>
@@ -113,7 +113,7 @@
<translation id="4200726100658658164">Konum Ayarlarını açın</translation>
<translation id="4226663524361240545">Bildirimler cihazı titretebilir</translation>
<translation id="4259722352634471385">Gezinme engellendi: <ph name="URL" /></translation>
-<translation id="4278390842282768270">Ä°zin verilen</translation>
+<translation id="4278390842282768270">Ä°zin veriliyor</translation>
<translation id="429312253194641664">Bir site medya oynatıyor</translation>
<translation id="42981349822642051">GeniÅŸlet</translation>
<translation id="4336434711095810371">Tüm verileri temizle</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Sitelerin korumalı içeriği oynatmasına izin ver</translation>
<translation id="4468959413250150279">Belirli bir site için sesi kapatın.</translation>
<translation id="4479647676395637221">Sitelerin, kameranızı kullanmasına izin verilmeden önce size sorulsun (önerilir)</translation>
+<translation id="4505788138578415521">URL geniÅŸletildi</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> uygulamasının mikrofonunuza erişebilmesi için <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda da mikrofonu açın.</translation>
<translation id="4570913071927164677">Ayrıntılar</translation>
<translation id="4645575059429386691">Ebeveyniniz tarafından yönetiliyor</translation>
@@ -161,7 +162,7 @@
<translation id="5556459405103347317">Yeniden Yükle</translation>
<translation id="5596627076506792578">Diğer seçenekler</translation>
<translation id="5649053991847567735">Otomatik indirmeler</translation>
-<translation id="5677928146339483299">Engellendi</translation>
+<translation id="5677928146339483299">Engelleniyor</translation>
<translation id="5689516760719285838">Konum</translation>
<translation id="5690795753582697420">Kamera, Android ayarlarında kapatıldı</translation>
<translation id="5710871682236653961">NFC cihazlarına dokunduğunuzda sitelerin bilgi göndermesine ve almasına izin verilmeden önce size sorulur (önerilen)</translation>
@@ -186,18 +187,18 @@
<translation id="6206551242102657620">Bağlantı güvenli. Site bilgileri</translation>
<translation id="6216432067784365534"><ph name="NAME_OF_LIST_ITEM" /> Seçenekleri</translation>
<translation id="6262279340360821358"><ph name="PERMISSION_1" /> ve <ph name="PERMISSION_2" /> engellendi</translation>
-<translation id="6270391203985052864">Siteler bildirim göndermek isteyebilir</translation>
+<translation id="6270391203985052864">Siteler bildirim gönderme izni isteyebilir</translation>
<translation id="6295158916970320988">Tüm siteler</translation>
<translation id="6320088164292336938">TitreÅŸim</translation>
<translation id="6388207532828177975">Temizle ve sıfırla</translation>
<translation id="6398765197997659313">Tam ekrandan çık</translation>
<translation id="6423924377271166037">Çerezleri sil</translation>
-<translation id="6439114592976064011">Sitelerin sanal gerçeklik cihazınızı ve verilerinizi kullanması engellenir</translation>
+<translation id="6439114592976064011">Sitelerin sanal gerçeklik cihazımı ve verilerimi kullanmasını engelle</translation>
<translation id="6447842834002726250">Çerezler</translation>
<translation id="6527303717912515753">PaylaÅŸ</translation>
<translation id="6545864417968258051">Bluetooth taraması</translation>
<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> izin daha engellendi}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> izin daha engellendi}}</translation>
-<translation id="6561560012278703671">Bilgiyi daha az rahatsız edici bir şekilde alın (bildirim istemlerinin sizi rahatsız etmesini engelleyin)</translation>
+<translation id="6561560012278703671">İletişim daha sessiz kurulsun (bildirim istemlerinin sizi rahatsız etmesini engeller)</translation>
<translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
<translation id="6612358246767739896">Korunan içerik</translation>
<translation id="662080504995468778">Kal</translation>
@@ -210,7 +211,7 @@
<translation id="6818926723028410516">Öğe seçin</translation>
<translation id="6864395892908308021">Bu cihaz NFC'yi okuyamıyor</translation>
<translation id="6910211073230771657">Silindi</translation>
-<translation id="6912998170423641340">Sitelerin panodaki metni ve resimleri okumasını engelleyin</translation>
+<translation id="6912998170423641340">Sitelerin panodaki metni ve resimleri okumasını engelle</translation>
<translation id="6945221475159498467">Seç</translation>
<translation id="6963642900430330478">Bu sayfa tehlikeli. Site bilgileri</translation>
<translation id="6965382102122355670">Tamam</translation>
@@ -233,7 +234,7 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Bir site mikrofonunuzu kullanıyor</translation>
<translation id="7561196759112975576">Her zaman</translation>
-<translation id="7572498721684305250">NFC cihazlarına dokunduğunuzda sitelerin bilgi göndermesi ve alması engellenir</translation>
+<translation id="7572498721684305250">NFC cihazlarına dokunduğunuzda sitelerin bilgi göndermesini ve almasını engelle</translation>
<translation id="757524316907819857">Sitelerin korumalı içeriği oynatmasını engellenir</translation>
<translation id="7589445247086920869">Geçerli arama motorunu engelle</translation>
<translation id="7649070708921625228">Yardım</translation>
@@ -250,7 +251,7 @@
<translation id="7846621471902887024">Tüm sitelerdeki oturumunuz kapatılacak.</translation>
<translation id="7882806643839505685">Belirli bir site için sese izin verin.</translation>
<translation id="7986741934819883144">Kişi seçin</translation>
-<translation id="7993619969781047893">Bazı sitelerdeki özellikler bozulabilir</translation>
+<translation id="7993619969781047893">Bazı sitelerdeki özellikler çalışmayabilir</translation>
<translation id="7999064672810608036">Bu web sitesine ilişkin çerezler dahil tüm yerel verileri temizlemek ve bu sitenin tüm izinlerini sıfırlamak istediğinizden emin misiniz?</translation>
<translation id="8007176423574883786">Bu cihaz için kapatıldı</translation>
<translation id="802154636333426148">Ä°ndirilemedi</translation>
@@ -283,7 +284,7 @@
<translation id="8609465669617005112">Yukarı taşı</translation>
<translation id="8676374126336081632">GiriÅŸi temizle</translation>
<translation id="868929229000858085">Kişilerinizde arama yapın</translation>
-<translation id="8702612070107455751">Tüm çevrimdışı veriler temizlenecektir.</translation>
+<translation id="8702612070107455751">Tüm çevrimdışı veriler temizlenecek.</translation>
<translation id="8719283222052720129"><ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'ında <ph name="APP_NAME" /> için izni açın.</translation>
<translation id="8725066075913043281">Yeniden dene</translation>
<translation id="8730621377337864115">Bitti</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tane daha}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tane daha}}</translation>
<translation id="913657688200966289"><ph name="APP_NAME" /> için izinleri açmak üzere <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda izinleri açın.</translation>
-<translation id="945632385593298557">Mikrofonunuza eriÅŸim</translation>
-<translation id="965817943346481315">Site, araya giren veya yanıltıcı reklamlar gösteriyorsa engelle (önerilen)</translation>
+<translation id="965817943346481315">Araya giren veya yanıltıcı reklamlar gösteren sitelerde reklamları engelle (önerilir)</translation>
<translation id="967624055006145463">Depolanan veriler</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
index 1bd4e9cf021..7f4f734b209 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> додано</translation>
<translation id="1383876407941801731">Пошук</translation>
<translation id="1384959399684842514">Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð·ÑƒÐ¿Ð¸Ð½ÐµÐ½Ð¾</translation>
+<translation id="1415402041810619267">URL-адреÑу Ñкорочено</translation>
<translation id="1431402976894535801">Блокувати Ñайтам інформацію про те, чи ви приÑутні</translation>
<translation id="1446450296470737166">Повний контроль приÑтроїв MIDI</translation>
<translation id="1509960214886564027">Функції на багатьох Ñайтах можуть не працювати</translation>
<translation id="1620510694547887537">Камера</translation>
-<translation id="1647391597548383849">ДоÑтуп до камери</translation>
<translation id="1660204651932907780">Дозволити Ñайтам відтворювати звук (рекомендуєтьÑÑ)</translation>
<translation id="1677097821151855053">Файли cookie та інші дані із Ñайтів викориÑтовуютьÑÑ, щоб запам'Ñтати ваші дані, наприклад, щоб входити у ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð°Ð±Ð¾ перÑоналізувати рекламу. Щоб керувати файлами cookie Ð´Ð»Ñ Ð²ÑÑ–Ñ… Ñайтів, переглÑньте <ph name="BEGIN_LINK" />ÐалаштуваннÑ<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">ОчиÑтити дані Ñайту?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL-адреÑа Ñайту</translation>
<translation id="2025115093177348061">Доповнена реальніÑÑ‚ÑŒ</translation>
<translation id="2030769033451695672">ÐатиÑніть, щоб повернутиÑÑ Ð½Ð° Ñторінку <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Дані про те, чи ви приÑутні</translation>
<translation id="2079545284768500474">Відмінити</translation>
<translation id="2091887806945687916">Сигнал</translation>
<translation id="2107397443965016585">Запитувати, перш ніж дозволÑти Ñайтам відтворювати захищений вміÑÑ‚ (рекомендовано)</translation>
<translation id="2146738493024040262">Відкрити додаток із миттєвим запуÑком</translation>
<translation id="2148716181193084225">Сьогодні</translation>
<translation id="2182457891543959921">Запитувати, перш ніж дозволÑти Ñайтам Ñтворювати 3D-карту вашого Ð¾Ñ‚Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ відÑтежувати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸ (рекомендовано)</translation>
-<translation id="2187243482123994665">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ приÑутніÑÑ‚ÑŒ</translation>
<translation id="2212565012507486665">Дозволити файли cookie</translation>
<translation id="2228071138934252756">Щоб надати додатку <ph name="APP_NAME" /> доÑтуп до камери, також увімкніть Ñ—Ñ— в <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Лише цього разу</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}one{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}few{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}many{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}other{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Завантажено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ДоÑтуп до геоданих</translation>
<translation id="2482878487686419369">СповіщеннÑ</translation>
<translation id="2490684707762498678">ÐдмініÑтратор Ñімейної групи: <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Довідка й відгуки</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Мікрофон</translation>
<translation id="3277252321222022663">Ðадати Ñайтам доÑтуп до датчиків (рекомендовано)</translation>
<translation id="3295602654194328831">Сховати інформацію</translation>
+<translation id="3328801116991980348">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñайт</translation>
<translation id="3333961966071413176">УÑÑ– контакти</translation>
<translation id="3386292677130313581">Запитувати, перш ніж дозволити Ñайтам визначати ваше міÑÑ†ÐµÐ·Ð½Ð°Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ (рекомендуєтьÑÑ)</translation>
<translation id="3538390592868664640">Заборонити Ñайтам Ñтворювати 3D-карту вашого Ð¾Ñ‚Ð¾Ñ‡ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ відÑтежувати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Дозволити Ñайтам відтворювати захищений вміÑÑ‚</translation>
<translation id="4468959413250150279">Вимкнути звук Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ð³Ð¾ Ñайту.</translation>
<translation id="4479647676395637221">Запитувати, перш ніж дозволити Ñайтам викориÑтовувати камеру (рекомендуєтьÑÑ)</translation>
+<translation id="4505788138578415521">URL-адреÑу розгорнуто</translation>
<translation id="4534723447064627427">Щоб надати додатку <ph name="APP_NAME" /> доÑтуп до мікрофона, також увімкніть його в <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Деталі</translation>
<translation id="4645575059429386691">КеруєтьÑÑ Ð¾Ð´Ð½Ð¸Ð¼ із батьків</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{"<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}one{"<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}few{"<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}many{"<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}other{"<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Увімкніть дозволи Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ° <ph name="APP_NAME" /> у <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">ДоÑтуп до мікрофона</translation>
<translation id="965817943346481315">Блокувати, Ñкщо Ñайт показує нав’Ñзливі чи оманливі Ð¾Ð³Ð¾Ð»Ð¾ÑˆÐµÐ½Ð½Ñ (рекомендовано)</translation>
<translation id="967624055006145463">Збережені дані</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
index 468ec9e4cca..fb0066e87b5 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">سائٹ <ph name="SITE_NAME" /> شامل کی گئی</translation>
<translation id="1383876407941801731">تلاش کریں</translation>
<translation id="1384959399684842514">ڈاؤن لوڈ موقو٠Ûوگیا</translation>
+<translation id="1415402041810619267">â€URL Ú©Ùˆ چھوٹا کیا گیا</translation>
<translation id="1431402976894535801">سائٹس کو اپنی موجودگی کے بارے میں جاننے سے مسدود کریں</translation>
<translation id="1446450296470737166">â€MIDI آلات Ú©Û’ مکمل کنٹرول Ú©ÛŒ اجازت دیں</translation>
<translation id="1509960214886564027">بÛت سی سائٹس پر خصوصیات میں خلل ÛÙˆ سکتا ÛÛ’</translation>
<translation id="1620510694547887537">کیمرا</translation>
-<translation id="1647391597548383849">اپنے کیمرے تک رسائی حاصل کریں</translation>
<translation id="1660204651932907780">سائٹس Ú©Ùˆ آواز چلانے Ú©ÛŒ اجازت دیں (تجویز کردÛ)</translation>
<translation id="1677097821151855053">کوکیز اور سائٹ کا دیگر ڈیٹا آپ Ú©Ùˆ یاد رکھنے Ú©Û’ لئے استعمال Ûوتا ÛÛ’ØŒ مثال Ú©Û’ طور پر آپ Ú©Ùˆ سائن ان کرنے یا اشتÛارات Ú©Ùˆ ذاتی نوعیت کا بنانے Ú©Û’ لیے۔ سبھی سائٹس Ú©ÛŒ خاطر کوکیز کا نظم کرنے Ú©Û’ لیے، <ph name="BEGIN_LINK" />ترتیبات<ph name="END_LINK" /> دیکھیں۔</translation>
<translation id="1688867105868176567">سائٹ کا ڈیٹا صا٠کریں؟</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">â€Ø³Ø§Ø¦Ù¹ کا URL</translation>
<translation id="2025115093177348061">اÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> پر واپس جانے کے لیے تھپتھپائیں</translation>
+<translation id="2054665754582400095">آپ کی موجودگی</translation>
<translation id="2079545284768500474">کالعدم کریں</translation>
<translation id="2091887806945687916">آواز</translation>
<translation id="2107397443965016585">سائٹس Ú©Ùˆ محÙوظ مواد چلانے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
<translation id="2146738493024040262">Ùوری ایپ کھولیں</translation>
<translation id="2148716181193084225">آج</translation>
<translation id="2182457891543959921">â€Ø³Ø§Ø¦Ù¹Ø³ Ú©Ùˆ اپنے اطرا٠کا 3D Ù†Ù‚Ø´Û ØªØ®Ù„ÛŒÙ‚ یا کیمرے Ú©ÛŒ پوزیشن ٹریک کرنے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
-<translation id="2187243482123994665">صار٠کی موجودگی</translation>
<translation id="2212565012507486665">کوکیز کی اجازت دیں</translation>
<translation id="2228071138934252756">â€<ph name="APP_NAME" /> Ú©Ùˆ اپنے کیمرے تک رسائی دینے Ú©Û’ لیے، <ph name="BEGIN_LINK" />Android Ú©ÛŒ ترتیبات<ph name="END_LINK" /> میں بھی کیمرا آن کریں۔</translation>
<translation id="2241634353105152135">بس ایک بار</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747">‎<ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}}</translation>
<translation id="2434158240863470628">ڈاؤن لوڈ مکمل ÛÙˆ گیا <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">مقام تک رسائی</translation>
<translation id="2482878487686419369">اطلاعات</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> کے زیر انتظام</translation>
<translation id="2498359688066513246">مدد اور تاثرات</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">مائیکروÙون</translation>
<translation id="3277252321222022663">سائٹس Ú©Ùˆ سینسرز تک رسائی حاصل کرنے Ú©ÛŒ اجازت دیں (تجویز کردÛ)</translation>
<translation id="3295602654194328831">معلومات چھپائیں</translation>
+<translation id="3328801116991980348">سائٹ کی معلومات</translation>
<translation id="3333961966071413176">تمام رابطے</translation>
<translation id="3386292677130313581">سائٹس Ú©Ùˆ آپ کا مقام جاننے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
<translation id="3538390592868664640">â€Ø³Ø§Ø¦Ù¹Ø³ Ú©Ùˆ اپنے اطرا٠کا 3D Ù†Ù‚Ø´Û ØªØ®Ù„ÛŒÙ‚ یا کیمرے Ú©ÛŒ پوزیشن ٹریک کرنے سے مسدود کریں</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">سائٹس Ú©Ùˆ محÙوظ مواد چلانے Ú©ÛŒ اجازت دیں</translation>
<translation id="4468959413250150279">کسی مخصوص سائٹ کیلئے آواز بند کریں۔</translation>
<translation id="4479647676395637221">سائٹس Ú©Ùˆ آپ کا کیمرا استعمال کرنے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
+<translation id="4505788138578415521">â€URL Ú©Ùˆ پھیلا دیا گیا</translation>
<translation id="4534723447064627427">â€<ph name="APP_NAME" /> Ú©Ùˆ اپنے مائیکروÙون تک رسائی دینے Ú©Û’ لیے، <ph name="BEGIN_LINK" />Android Ú©ÛŒ ترتیبات<ph name="END_LINK" /> میں بھی مائیکروÙون آن کریں۔</translation>
<translation id="4570913071927164677">تÙاصیل</translation>
<translation id="4645575059429386691">آپ کے والدین کے زیر انتظام</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">بلوٹوتھ</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید}}</translation>
<translation id="913657688200966289">â€<ph name="BEGIN_LINK" />Android ترتیبات<ph name="END_LINK" /> میں <ph name="APP_NAME" /> Ú©Û’ لیے اجازتیں آن کریں۔</translation>
-<translation id="945632385593298557">اپنے مائیکروÙون تک رسائی حاصل کریں</translation>
<translation id="965817943346481315">اگر سائٹ دخل انداز یا Ú¯Ù…Ø±Ø§Û Ú©Ù† اشتÛارات دکھاتی ÛÛ’ تو مسدود کریں (تجویز کردÛ)</translation>
<translation id="967624055006145463">اسٹور Ú©Ø±Ø¯Û ÚˆÛŒÙ¹Ø§</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
index 3fd8704ff50..66aa6ffc94b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> sayti qo‘shildi</translation>
<translation id="1383876407941801731">Qidiruv</translation>
<translation id="1384959399684842514">Yuklab olish pauza qilindi.</translation>
+<translation id="1415402041810619267">URL manzil qisqartirildi</translation>
<translation id="1431402976894535801">Faolligingizni saytlar bilishini taqiqlash</translation>
<translation id="1446450296470737166">MIDI qurilmalarini boshqarishga to‘liq ruxsat berish</translation>
<translation id="1509960214886564027">Aksariyat saytlardagi funksiyalar ishalamay qolishi mumkin</translation>
<translation id="1620510694547887537">Kamera</translation>
-<translation id="1647391597548383849">Kameraga ruxsat</translation>
<translation id="1660204651932907780">Saytlarga ovoz ijro etish uchun ruxsat berish (tavsiya etiladi)</translation>
<translation id="1677097821151855053">Saytga kirish uchun yoki reklamani moslashtirish uchun ishlatiladigan cookie fayllari va boshqa sayt maʼlumotlari. Barcha saytlar uchun cookie fayllarni boshqarish uchun <ph name="BEGIN_LINK" />Cookie sozlamalari<ph name="END_LINK" /> sahifasini oching.</translation>
<translation id="1688867105868176567">Sayt ma’lumotlari tozalansinmi?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">Sayt URL manzili</translation>
<translation id="2025115093177348061">Boyitilgan reallik</translation>
<translation id="2030769033451695672"><ph name="URL_OF_THE_CURRENT_TAB" /> sahifasiga qaytish uchun bosing</translation>
+<translation id="2054665754582400095">Faolligingiz</translation>
<translation id="2079545284768500474">Bekor qilish</translation>
<translation id="2091887806945687916">Tovush</translation>
<translation id="2107397443965016585">Himoyalangan kontentni ijro etishdan avval ruxsat soʻralsin (tavsiya etiladi)</translation>
<translation id="2146738493024040262">Darhol ishga tushadigan ilovada ochish</translation>
<translation id="2148716181193084225">Bugun</translation>
<translation id="2182457891543959921">Saytlar atrofingiz 3D xaritasini yaratish yoki kamera holatini kuzatish oldin ruxsat olsin (tavsiya etiladi)</translation>
-<translation id="2187243482123994665">Foydalanuvchining faolligi</translation>
<translation id="2212565012507486665">Cookie fayllariga ruxsat berish</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> kameradan foydalanishiga ruxsat berish uchun <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali kamerani yoqing.</translation>
<translation id="2241634353105152135">Bir marta</translation>
@@ -55,10 +55,9 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}other{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}}</translation>
<translation id="2434158240863470628">Yuklab olindi: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Joylashuv ma’lumotidan foyd-sh</translation>
<translation id="2482878487686419369">Bildirishnomalar</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> tomonidan boshqariladi</translation>
-<translation id="2498359688066513246">Yordam va fikr-mulohaza</translation>
+<translation id="2498359688066513246">Yordam/fikr-mulohaza</translation>
<translation id="2501278716633472235">Ortga qaytish</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 ta cookie fayl bloklandi}other{# ta cookie fayl bloklandi}}</translation>
<translation id="2570922361219980984">Bu qurilmada joylashuv xizmati yoqilmagan, uni <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali yoqing.</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Saytlarga sensorlardan foydalanish uchun ruxsat berish (tavsiya etiladi)</translation>
<translation id="3295602654194328831">Ma’lumotlarni yashirish</translation>
+<translation id="3328801116991980348">Sayt haqida ma’lumot</translation>
<translation id="3333961966071413176">Barcha kontaktlar</translation>
<translation id="3386292677130313581">Joylashuv ma’lumotini ko‘rishiga ruxsat so‘ralsin (tavsiya etiladi)</translation>
<translation id="3538390592868664640">Saytlarni atrofingizning 3D xaritasini yaratish yoki kamera joylashuvini aniqlashdan bloklash</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Saytlarga himoyalangan kontentni ijro qilish uchun ruxsat berish</translation>
<translation id="4468959413250150279">Muayyan saytdagi ovozni o‘chirish.</translation>
<translation id="4479647676395637221">Kameradan foydalanishga ruxsat so‘ralsin (tavsiya etiladi)</translation>
+<translation id="4505788138578415521">URL manzil yoyildi</translation>
<translation id="4534723447064627427"><ph name="APP_NAME" /> mikrofondan foydalanishiga ruxsat berish uchun <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali mikrofonni yoqing.</translation>
<translation id="4570913071927164677">Tafsilotlar</translation>
<translation id="4645575059429386691">Ota-onangiz tomonidan boshqariladi</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}}</translation>
<translation id="913657688200966289"><ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali <ph name="APP_NAME" /> uchun ruxsatnomalarni yoqing.</translation>
-<translation id="945632385593298557">Mikrofonga ruxsat</translation>
<translation id="965817943346481315">Saytlarda chiquvchi yoqimsiz yoki befoyda reklamalar bloklansin (tavsiya etiladi)</translation>
<translation id="967624055006145463">Ishlatilgan joy</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
index b8074c017a6..9a533695768 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Äã thêm trang web <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Tìm kiếm</translation>
<translation id="1384959399684842514">Äã tạm dừng quá trình tải xuống</translation>
+<translation id="1415402041810619267">URL đã được cắt bớt</translation>
<translation id="1431402976894535801">Không cho các trang web biết trạng thái hoạt động của bạn</translation>
<translation id="1446450296470737166">Cho pheÌp kiểm soaÌt hoaÌ€n toaÌ€n thiêÌt biÌ£ MIDI</translation>
<translation id="1509960214886564027">Các tính năng trên nhiá»u trang web có thể hoạt Ä‘á»™ng không đúng cách</translation>
<translation id="1620510694547887537">Máy ảnh</translation>
-<translation id="1647391597548383849">Truy cập máy ảnh của bạn</translation>
<translation id="1660204651932907780">Cho phép các trang web phát âm thanh (được đỠxuất)</translation>
<translation id="1677097821151855053">Cookie và dữ liệu trang web khác được dùng để ghi nhá»› bạn, chẳng hạn nhÆ° giúp bạn đăng nhập hoặc cá nhân hóa quảng cáo. Äể quản lý cookie cho tất cả trang web, hãy xem phần <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Xóa dữ liệu trang web?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">URL trang web</translation>
<translation id="2025115093177348061">Thá»±c tế tăng cÆ°á»ng</translation>
<translation id="2030769033451695672">Nhấn để quay lại <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Sự hiện diện của bạn</translation>
<translation id="2079545284768500474">Hoàn tác</translation>
<translation id="2091887806945687916">Âm thanh</translation>
<translation id="2107397443965016585">Há»i trÆ°á»›c khi cho phép trang web phát ná»™i dung được bảo vệ (khuyên dùng)</translation>
<translation id="2146738493024040262">Mở ứng dụng tức thì</translation>
<translation id="2148716181193084225">Hôm nay</translation>
<translation id="2182457891543959921">Há»i trÆ°á»›c khi cho phép các trang web tạo bản đồ 3D vá» các khu vá»±c xung quanh bạn hoặc theo dõi thông tin vị trí của máy ảnh (khuyên dùng)</translation>
-<translation id="2187243482123994665">Hoạt Ä‘á»™ng của ngÆ°á»i dùng</translation>
<translation id="2212565012507486665">Cho phép cookie</translation>
<translation id="2228071138934252756">Äể cho phép <ph name="APP_NAME" /> truy cập vào máy ảnh của bạn, hãy bật cả máy ảnh trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Chỉ một lần</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Äã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}other{Äã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}}</translation>
<translation id="2434158240863470628">Quá trình tải xuống hoàn tất <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Quyá»n truy cập thông tin vị trí</translation>
<translation id="2482878487686419369">Thông báo</translation>
<translation id="2490684707762498678">Do <ph name="APP_NAME" /> quản lý</translation>
<translation id="2498359688066513246">Trợ giúp và phản hồi</translation>
@@ -75,7 +74,7 @@
<translation id="2874939134665556319">Bản nhạc trước</translation>
<translation id="2903493209154104877">Äịa chỉ</translation>
<translation id="2910701580606108292">Há»i trÆ°á»›c khi cho phép trang web phát ná»™i dung được bảo vệ</translation>
-<translation id="2913331724188855103">Cho phép trang web lÆ°u và Ä‘á»c dữ liệu cookie (được Ä‘á» xuất)</translation>
+<translation id="2913331724188855103">Cho phép các trang web lÆ°u và Ä‘á»c dữ liệu cookie (nên chá»n)</translation>
<translation id="2968755619301702150">Trình xem chứng chỉ</translation>
<translation id="300526633675317032">Thao tác này sẽ xóa tất cả <ph name="SIZE_IN_KB" /> bộ nhớ trang web.</translation>
<translation id="3008272652534848354">Äặt lại quyá»n</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Micrô</translation>
<translation id="3277252321222022663">Cho phép các trang web sử dụng cảm biến của thiết bị (nên dùng)</translation>
<translation id="3295602654194328831">Ẩn thông tin</translation>
+<translation id="3328801116991980348">Thông tin vỠtrang web</translation>
<translation id="3333961966071413176">Tất cả ngÆ°á»i liên hệ</translation>
<translation id="3386292677130313581">Há»i trÆ°á»›c khi cho phép các trang web biết vị trí của bạn (được Ä‘á» xuất)</translation>
<translation id="3538390592868664640">Chặn không cho trang web tạo bản đồ 3D vỠcác khu vực xung quanh bạn hoặc theo dõi thông tin vị trí của máy ảnh</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Cho phép trang web phát nội dung được bảo vệ</translation>
<translation id="4468959413250150279">Tắt âm thanh trên một trang web cụ thể.</translation>
<translation id="4479647676395637221">Há»i trÆ°á»›c trÆ°á»›c khi cho phép các trang web sá»­ dụng máy ảnh của bạn (được Ä‘á» xuất)</translation>
+<translation id="4505788138578415521">URL đã được mở rộng</translation>
<translation id="4534723447064627427">Äể cho phép <ph name="APP_NAME" /> truy cập vào micrô của bạn, hãy bật cả micrô trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Chi tiết</translation>
<translation id="4645575059429386691">Do cha mẹ của bạn quản lý</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}}</translation>
<translation id="913657688200966289">Bật quyá»n cho <ph name="APP_NAME" /> trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Truy cập micrô của bạn</translation>
<translation id="965817943346481315">Chặn nếu trang web hiển thị quảng cáo xâm nhập hoặc quảng cáo gây hiểu nhầm (khuyên dùng)</translation>
<translation id="967624055006145463">Dữ liệu đã lưu trữ</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
index 0fbb6cb8afc..3f2c5fb8561 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
@@ -17,17 +17,17 @@
<translation id="1369915414381695676">网站 <ph name="SITE_NAME" /> 已添加</translation>
<translation id="1383876407941801731">æœç´¢</translation>
<translation id="1384959399684842514">已暂åœä¸‹è½½</translation>
+<translation id="1415402041810619267">网å€è¢«æˆªæ–­äº†</translation>
<translation id="1431402976894535801">ç¦æ­¢ç½‘站了解您何时处于活跃状æ€</translation>
<translation id="1446450296470737166">å…许全é¢æŽ§åˆ¶ MIDI 设备</translation>
<translation id="1509960214886564027">很多网站上的功能å¯èƒ½ä¼šæ— æ³•æ­£å¸¸è¿ä½œ</translation>
<translation id="1620510694547887537">æ‘„åƒå¤´</translation>
-<translation id="1647391597548383849">使用您的摄åƒå¤´</translation>
<translation id="1660204651932907780">å…许网站播放声音(推è)</translation>
<translation id="1677097821151855053">系统会使用 Cookie 和其他网站数æ®æ¥è®°ä½æ‚¨ï¼Œä»¥ä¾¿å®žçŽ°æŸäº›åŠŸèƒ½æˆ–目的(例如帮您登录或å‘您展示个性化广告)。如需管ç†æ‰€æœ‰ç½‘站的 Cookie,请å‚阅<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />。</translation>
<translation id="1688867105868176567">è¦æ¸…除网站数æ®å—?</translation>
-<translation id="169515064810179024">ç¦æ­¢ç½‘站使用动æ€ä¼ æ„Ÿå™¨</translation>
-<translation id="1717218214683051432">动æ€ä¼ æ„Ÿå™¨</translation>
-<translation id="1743802530341753419">网站需先询问并得到许å¯æ‰èƒ½è¿žæŽ¥è®¾å¤‡ï¼ˆæŽ¨è)</translation>
+<translation id="169515064810179024">ç¦æ­¢ç½‘站使用移动传感器</translation>
+<translation id="1717218214683051432">移动传感器</translation>
+<translation id="1743802530341753419">需先询问,得到许å¯åŽæ‰å…许网站连接设备(推è)</translation>
<translation id="1779089405699405702">图片解ç å™¨</translation>
<translation id="1818308510395330587">è‹¥è¦å…许 <ph name="APP_NAME" /> 使用 AR 功能,您还需在 <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯æ‘„åƒå¤´ã€‚</translation>
<translation id="1887786770086287077">此设备的ä½ç½®ä¿¡æ¯ä½¿ç”¨æƒå·²å…³é—­ï¼›è‹¥æƒ³å¼€å¯è¿™é¡¹æƒé™ï¼Œè¯·è½¬åˆ° <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />。</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">网站网å€</translation>
<translation id="2025115093177348061">增强现实</translation>
<translation id="2030769033451695672">点按å³å¯è¿”回到 <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">您的状æ€</translation>
<translation id="2079545284768500474">撤消</translation>
<translation id="2091887806945687916">声音</translation>
-<translation id="2107397443965016585">网站需先询问并得到许å¯æ‰èƒ½æ’­æ”¾å—ä¿æŠ¤å†…容 (推è)</translation>
+<translation id="2107397443965016585">需先询问,得到许å¯åŽæ‰å…许网站播放å—ä¿æŠ¤çš„内容 (推è)</translation>
<translation id="2146738493024040262">打开å…安装应用</translation>
<translation id="2148716181193084225">今天</translation>
-<translation id="2182457891543959921">在å…许网站为您的周边环境创建 3D 地图或跟踪摄åƒå¤´ä½ç½®ä¹‹å‰è¯¢é—®æ‚¨ï¼ˆæŽ¨è)</translation>
-<translation id="2187243482123994665">用户活跃状æ€</translation>
+<translation id="2182457891543959921">需先询问,得到许å¯åŽæ‰å…许网站为您的周边环境创建 3D 地图或跟踪摄åƒå¤´ä½ç½®ï¼ˆæŽ¨è)</translation>
<translation id="2212565012507486665">å…许使用 Cookie</translation>
<translation id="2228071138934252756">è‹¥è¦å…许 <ph name="APP_NAME" /> 使用您的摄åƒå¤´ï¼Œæ‚¨è¿˜éœ€åœ¨ <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯æ‘„åƒå¤´ã€‚</translation>
<translation id="2241634353105152135">仅一次</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{已授予“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}other{已授予“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}}</translation>
<translation id="2434158240863470628">ä¸‹è½½å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ä½ç½®ä¿¡æ¯ä½¿ç”¨æƒ</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2490684707762498678">ç”± <ph name="APP_NAME" /> 管ç†</translation>
<translation id="2498359688066513246">帮助和å馈</translation>
@@ -74,7 +73,7 @@
<translation id="2870560284913253234">网站</translation>
<translation id="2874939134665556319">上一首</translation>
<translation id="2903493209154104877">地å€</translation>
-<translation id="2910701580606108292">网站需先询问并得到许å¯æ‰èƒ½æ’­æ”¾å—ä¿æŠ¤å†…容</translation>
+<translation id="2910701580606108292">需先询问,得到许å¯åŽæ‰å…许网站播放å—ä¿æŠ¤çš„内容</translation>
<translation id="2913331724188855103">å…许网站ä¿å­˜å’Œè¯»å– Cookie æ•°æ®ï¼ˆæŽ¨è)</translation>
<translation id="2968755619301702150">è¯ä¹¦æŸ¥çœ‹å™¨</translation>
<translation id="300526633675317032">è¿™ä¼šæ¸…é™¤å…¨éƒ¨çš„ç½‘ç«™å­˜å‚¨æ•°æ® (<ph name="SIZE_IN_KB" />)。</translation>
@@ -89,8 +88,9 @@
<translation id="3227137524299004712">麦克风</translation>
<translation id="3277252321222022663">å…许网站使用传感器(推è)</translation>
<translation id="3295602654194328831">éšè—ä¿¡æ¯</translation>
+<translation id="3328801116991980348">网站信æ¯</translation>
<translation id="3333961966071413176">所有è”系人</translation>
-<translation id="3386292677130313581">网站需è¦å…ˆè¯¢é—®å¹¶å¾—到您的许å¯æ‰èƒ½èŽ·å–您的ä½ç½®ä¿¡æ¯ï¼ˆæŽ¨è)</translation>
+<translation id="3386292677130313581">需先询问,得到许å¯åŽæ‰å…许网站获å–您的ä½ç½®ä¿¡æ¯ï¼ˆæŽ¨è)</translation>
<translation id="3538390592868664640">ç¦æ­¢ç½‘站为您的周边环境创建 3D 地图或跟踪摄åƒå¤´ä½ç½®</translation>
<translation id="3586500876634962664">正在使用摄åƒå¤´å’Œéº¦å…‹é£Ž</translation>
<translation id="3587482841069643663">全部</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">å…许网站播放å—ä¿æŠ¤å†…容。</translation>
<translation id="4468959413250150279">å°†æŸä¸ªç‰¹å®šç½‘ç«™é™éŸ³ã€‚</translation>
<translation id="4479647676395637221">在å…许网站使用您的摄åƒå¤´å‰å…ˆè¯¢é—®ï¼ˆæŽ¨è)</translation>
+<translation id="4505788138578415521">网å€å·²å±•å¼€</translation>
<translation id="4534723447064627427">è‹¥è¦å…许 <ph name="APP_NAME" /> 使用您的麦克风,您还需在 <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯éº¦å…‹é£Žã€‚</translation>
<translation id="4570913071927164677">详情</translation>
<translation id="4645575059429386691">由您父æ¯ç®¡ç†</translation>
@@ -129,14 +130,14 @@
<translation id="4708011789095599544">确定è¦æ¸…除此网站的 Cookie 和其他网站数æ®å—?</translation>
<translation id="4751476147751820511">动æ€ä¼ æ„Ÿå™¨æˆ–光传感器</translation>
<translation id="4883854917563148705">无法é‡ç½®æ‰˜ç®¡è®¾ç½®</translation>
-<translation id="4887024562049524730">网站需在使用您的虚拟实境设备和数æ®ä¹‹å‰èŽ·å¾—您的许å¯ï¼ˆæŽ¨è)</translation>
+<translation id="4887024562049524730">需先询问,得到许å¯åŽæ‰å…许网站使用您的虚拟实境设备和数æ®ï¼ˆæŽ¨è)</translation>
<translation id="4962975101802056554">撤消设备的所有æƒé™</translation>
<translation id="497421865427891073">å‰è¿›</translation>
<translation id="4994033804516042629">找ä¸åˆ°ä»»ä½•è”系人</translation>
<translation id="4996978546172906250">分享方å¼</translation>
<translation id="5039804452771397117">å…许</translation>
-<translation id="5048398596102334565">å…许网站使用动æ€ä¼ æ„Ÿå™¨ï¼ˆæŽ¨è)</translation>
-<translation id="5063480226653192405">使用情况</translation>
+<translation id="5048398596102334565">å…许网站使用移动传感器(推è)</translation>
+<translation id="5063480226653192405">空间å ç”¨é‡</translation>
<translation id="5100237604440890931">已收起 - 点击此处å³å¯å±•å¼€ã€‚</translation>
<translation id="5123685120097942451">æ— ç—•å¼æ ‡ç­¾é¡µ</translation>
<translation id="5197729504361054390">系统会将您所选è”系人的详细信æ¯åˆ†äº«ç»™ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />。</translation>
@@ -157,14 +158,14 @@
<translation id="5502860503640766021">已授予“<ph name="PERMISSION_1" />â€æƒé™ï¼Œå·²ç¦ç”¨â€œ<ph name="PERMISSION_2" />â€æƒé™</translation>
<translation id="5505264765875738116">网站无法询问能å¦å‘您å‘é€é€šçŸ¥</translation>
<translation id="5516455585884385570">打开通知设置</translation>
-<translation id="5527111080432883924">网站需先询问并得到许å¯æ‰èƒ½è¯»å–剪贴æ¿ä¸­çš„文字和图片(推è)</translation>
+<translation id="5527111080432883924">需先询问,得到许å¯åŽæ‰å…许网站读å–剪贴æ¿ä¸­çš„文字和图片(推è)</translation>
<translation id="5556459405103347317">é‡æ–°åŠ è½½</translation>
<translation id="5596627076506792578">更多选项</translation>
<translation id="5649053991847567735">自动下载项</translation>
<translation id="5677928146339483299">å·²ç¦æ­¢</translation>
<translation id="5689516760719285838">ä½ç½®ä¿¡æ¯</translation>
<translation id="5690795753582697420">已在 Android 设置中关闭摄åƒå¤´</translation>
-<translation id="5710871682236653961">(推è)网站需先询问并获得您的许å¯ï¼Œæ‰èƒ½åœ¨æ‚¨è§¦ç¢° NFC 设备时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯</translation>
+<translation id="5710871682236653961">需先询问,得到许å¯åŽæ‰å…许网站在您触碰 NFC 设备时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯ï¼ˆæŽ¨è)</translation>
<translation id="5719847187258001597">æ­¤æ“作会清除 <ph name="ORIGIN" /> 或其在主å±å¹•ä¸­å®‰è£…的应用所存储的全部数æ®å’Œ Cookie。</translation>
<translation id="5771720122942595109">å·²ç¦ç”¨â€œ<ph name="PERMISSION_1" />â€æƒé™</translation>
<translation id="5804241973901381774">æƒé™</translation>
@@ -197,7 +198,7 @@
<translation id="6527303717912515753">分享</translation>
<translation id="6545864417968258051">è“牙扫æ</translation>
<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{å·²ç¦ç”¨â€œ<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}other{å·²ç¦ç”¨â€œ<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}}</translation>
-<translation id="6561560012278703671">改用é™æ€æŒ‡ç¤ºæ–¹å¼ï¼ˆç¦æ­¢ç½‘ç«™å‘é€é€šçŸ¥ï¼Œä»¥å…干扰)</translation>
+<translation id="6561560012278703671">改用干扰性更低的æ示方å¼ï¼ˆç¦æ­¢ç½‘ç«™å‘é€é€šçŸ¥ï¼Œä»¥å…干扰)</translation>
<translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
<translation id="6612358246767739896">å—ä¿æŠ¤çš„内容</translation>
<translation id="662080504995468778">留下</translation>
@@ -234,7 +235,7 @@
<translation id="7554752735887601236">有一个网站正在使用您的麦克风</translation>
<translation id="7561196759112975576">永远</translation>
<translation id="7572498721684305250">ç¦æ­¢ç½‘站在您触碰 NFC 设备时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯</translation>
-<translation id="757524316907819857">ç¦æ­¢ç½‘站播放å—ä¿æŠ¤å†…容</translation>
+<translation id="757524316907819857">ç¦æ­¢ç½‘站播放å—ä¿æŠ¤çš„内容</translation>
<translation id="7589445247086920869">ä¸å…许当å‰æœç´¢å¼•æ“Žä½¿ç”¨</translation>
<translation id="7649070708921625228">帮助</translation>
<translation id="7658239707568436148">å–消</translation>
@@ -257,7 +258,7 @@
<translation id="8067883171444229417">播放视频</translation>
<translation id="8068648041423924542">无法选择è¯ä¹¦ã€‚</translation>
<translation id="8087000398470557479">此内容æ¥è‡ª <ph name="DOMAIN_NAME" />(由 Google æ供)。</translation>
-<translation id="8116925261070264013">å·²é™éŸ³çš„网站</translation>
+<translation id="8116925261070264013">å·²é™éŸ³</translation>
<translation id="8131740175452115882">确认</translation>
<translation id="8197286292360124385">已授予“<ph name="PERMISSION_1" />â€æƒé™</translation>
<translation id="8200772114523450471">继续</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">è“牙</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}other{“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}}</translation>
<translation id="913657688200966289">在 <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中为 <ph name="APP_NAME" /> å¼€å¯è¿™äº›æƒé™ã€‚</translation>
-<translation id="945632385593298557">使用您的麦克风</translation>
<translation id="965817943346481315">å±è”½ä¼šå±•ç¤ºä¾µæ‰°æ€§æˆ–误导性广告的网站(推è)</translation>
<translation id="967624055006145463">已存储的数æ®</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
index 38b737e1400..1459dd2f7a3 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">已新增網站 <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">æœå°‹</translation>
<translation id="1384959399684842514">已暫åœä¸‹è¼‰</translation>
+<translation id="1415402041810619267">縮短咗網å€</translation>
<translation id="1431402976894535801">ç¦æ­¢ç¶²ç«™çŸ¥é“您何時使用è£ç½®</translation>
<translation id="1446450296470737166">å…許全權控制 MIDI è£ç½®ã€‚</translation>
<translation id="1509960214886564027">很多網站的功能å¯èƒ½æœƒç„¡æ³•æ­£å¸¸é‹ä½œ</translation>
<translation id="1620510694547887537">相機</translation>
-<translation id="1647391597548383849">å­˜å–您的相機</translation>
<translation id="1660204651932907780">å…許網站播放音效 (建議)</translation>
<translation id="1677097821151855053">系統會使用 Cookie 和其他網站資料記ä½æ‚¨çš„身分,例如登入帳戶或個人化廣告。如è¦ç®¡ç†æ‰€æœ‰ç¶²ç«™çš„ Cookie,請åƒé–±ã€Œ<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />ã€ã€‚</translation>
<translation id="1688867105868176567">è¦æ¸…除網站資料嗎?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">網站網å€</translation>
<translation id="2025115093177348061">擴張實境</translation>
<translation id="2030769033451695672">輕按å³å¯è¿”回 <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">您的狀態</translation>
<translation id="2079545284768500474">復原</translation>
<translation id="2091887806945687916">音效</translation>
<translation id="2107397443965016585">網站播放å—ä¿è­·å…§å®¹å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
<translation id="2146738493024040262">é–‹å•Ÿå…安è£æ‡‰ç”¨ç¨‹å¼</translation>
<translation id="2148716181193084225">今天</translation>
<translation id="2182457891543959921">在å…許網站建立您身處環境的 3D 地圖或追蹤æ”錄機ä½ç½®å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
-<translation id="2187243482123994665">使用者狀態</translation>
<translation id="2212565012507486665">å…許 Cookie</translation>
<translation id="2228071138934252756">如è¦è®“ <ph name="APP_NAME" /> å­˜å–您的相機,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟相機。</translation>
<translation id="2241634353105152135">åªæœ‰é€™ä¸€æ¬¡</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="2434158240863470628">ä¸‹è¼‰å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ä½ç½®è³‡æ–™å­˜å–權</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2490684707762498678">ç”± <ph name="APP_NAME" /> 管ç†</translation>
<translation id="2498359688066513246">說明和æ„見å映</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">麥克風</translation>
<translation id="3277252321222022663">å…許網站存å–感應器 (建議)</translation>
<translation id="3295602654194328831">éš±è—資料</translation>
+<translation id="3328801116991980348">網站資料</translation>
<translation id="3333961966071413176">所有è¯çµ¡äºº</translation>
<translation id="3386292677130313581">å…許網站存å–您的ä½ç½®å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
<translation id="3538390592868664640">ç¦æ­¢ç¶²ç«™å»ºç«‹æ‚¨èº«è™•ç’°å¢ƒçš„ 3D 地圖或追蹤æ”錄機ä½ç½®</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">å…許網站播放å—ä¿è­·çš„內容</translation>
<translation id="4468959413250150279">將特定網站設為éœéŸ³ã€‚</translation>
<translation id="4479647676395637221">å…許網站使用相機å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
+<translation id="4505788138578415521">展開咗網å€</translation>
<translation id="4534723447064627427">如è¦è®“ <ph name="APP_NAME" /> å­˜å–您的麥克風,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟麥克風。</translation>
<translation id="4570913071927164677">詳細資料</translation>
<translation id="4645575059429386691">由您的家長管ç†</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">è—牙</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="913657688200966289">請在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中為 <ph name="APP_NAME" /> 啟用這些權é™ã€‚</translation>
-<translation id="945632385593298557">å­˜å–您的麥克風</translation>
<translation id="965817943346481315">å°éŽ–顯示滋擾性或誤導廣告網站上的廣告 (建議)</translation>
<translation id="967624055006145463">已儲存的資料</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
index 22e4a8d32f5..59cf4757693 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">已新增 <ph name="SITE_NAME" /> 網站</translation>
<translation id="1383876407941801731">æœå°‹</translation>
<translation id="1384959399684842514">已暫åœä¸‹è¼‰</translation>
+<translation id="1415402041810619267">已截斷網å€</translation>
<translation id="1431402976894535801">ç¦æ­¢ç¶²ç«™å–得你的使用狀態</translation>
<translation id="1446450296470737166">å…許完整控制 MIDI è£ç½®</translation>
<translation id="1509960214886564027">許多網站的功能å¯èƒ½ç„¡æ³•æ­£å¸¸é‹ä½œ</translation>
<translation id="1620510694547887537">æ”影機</translation>
-<translation id="1647391597548383849">å­˜å–您的æ”影機</translation>
<translation id="1660204651932907780">å…許網站播放音訊 (建議)</translation>
<translation id="1677097821151855053">系統會使用 Cookie 和其他網站資料來記ä½ä½ ï¼Œä»¥ä¾¿å°‡ä½ ç™»å…¥å¸³æˆ¶æˆ–是æ供個人化廣告等æœå‹™ã€‚如è¦ç®¡ç†æ‰€æœ‰ç¶²ç«™çš„ Cookie,請查看<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />。</translation>
<translation id="1688867105868176567">è¦æ¸…除網站資料嗎?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">網站網å€</translation>
<translation id="2025115093177348061">擴增實境</translation>
<translation id="2030769033451695672">輕觸å³å¯è¿”回 <ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">你的使用狀態</translation>
<translation id="2079545284768500474">復原</translation>
<translation id="2091887806945687916">音訊</translation>
<translation id="2107397443965016585">å…許網站播放å—ä¿è­·çš„內容å‰ï¼Œå¿…須先詢å•ä½  (建議)</translation>
<translation id="2146738493024040262">é–‹å•Ÿå…安è£æ‡‰ç”¨ç¨‹å¼</translation>
<translation id="2148716181193084225">今天</translation>
<translation id="2182457891543959921">網站必須先詢å•ä½ ï¼Œæ‰èƒ½æ ¹æ“šä½ çš„周é­ç’°å¢ƒå»ºç«‹ 3D 地圖或追蹤æ”影機ä½ç½® (建議)</translation>
-<translation id="2187243482123994665">使用者狀態</translation>
<translation id="2212565012507486665">å…許 Cookie</translation>
<translation id="2228071138934252756">如è¦å…許 <ph name="APP_NAME" /> å­˜å–è£ç½®çš„相機,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟相機。</translation>
<translation id="2241634353105152135">åªæœ‰é€™ä¸€æ¬¡</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="2434158240863470628">ä¸‹è¼‰å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">ä½ç½®è³‡è¨Šå­˜å–權</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2490684707762498678">ç”± <ph name="APP_NAME" /> 管ç†</translation>
<translation id="2498359688066513246">說明與æ„見回饋</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">麥克風</translation>
<translation id="3277252321222022663">å…許網站存å–感應器 (建議)</translation>
<translation id="3295602654194328831">éš±è—資訊</translation>
+<translation id="3328801116991980348">網站資訊</translation>
<translation id="3333961966071413176">所有è¯çµ¡äºº</translation>
<translation id="3386292677130313581">å…許網站存å–ä½ çš„ä½ç½®è³‡è¨Šå‰ï¼Œå¿…須先詢å•ä½  (建議)</translation>
<translation id="3538390592868664640">ç¦æ­¢ç¶²ç«™æ ¹æ“šä½ çš„周é­ç’°å¢ƒå»ºç«‹ 3D 地圖或追蹤æ”影機ä½ç½®</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">å…許網站播放å—ä¿è­·çš„內容</translation>
<translation id="4468959413250150279">將特定網站設為éœéŸ³ã€‚</translation>
<translation id="4479647676395637221">å…許網站使用你的æ”影機å‰ï¼Œå¿…須先詢å•ä½  (建議)</translation>
+<translation id="4505788138578415521">已展開網å€</translation>
<translation id="4534723447064627427">如è¦å…許 <ph name="APP_NAME" /> å­˜å–è£ç½®çš„麥克風,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟麥克風。</translation>
<translation id="4570913071927164677">詳細資料</translation>
<translation id="4645575059429386691">你的家長已åœç”¨é€™é …功能</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">è—牙</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="913657688200966289">請在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中啟用「<ph name="APP_NAME" />ã€çš„權é™ã€‚</translation>
-<translation id="945632385593298557">å­˜å–您的麥克風</translation>
<translation id="965817943346481315">å°éŽ–干擾性或誤導性的網站廣告 (建議)</translation>
<translation id="967624055006145463">已儲存的資料</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
index 0eaebdec960..c127c0b5800 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
@@ -17,11 +17,11 @@
<translation id="1369915414381695676">Isayithi le-<ph name="SITE_NAME" /> lingeziwe</translation>
<translation id="1383876407941801731">Sesha</translation>
<translation id="1384959399684842514">Ukulayisha kumiswe isikhashana</translation>
+<translation id="1415402041810619267">I-URL inciphisiwe</translation>
<translation id="1431402976894535801">Vimbela amasayithi ukuthi azi lapho ukhona</translation>
<translation id="1446450296470737166">Vumela ulawulo olugcwele lwamadivayisi we-MIDI</translation>
<translation id="1509960214886564027">Izici ezikumasayithi amaningi zingase zinqamuke</translation>
<translation id="1620510694547887537">Ikhamela</translation>
-<translation id="1647391597548383849">Finyelela kukhamela yakho</translation>
<translation id="1660204651932907780">Vumela amasayithi ukuthi adlale umsindo (kunconyiwe)</translation>
<translation id="1677097821151855053">Amakhukhi nenye idatha yesayithi kusetshenziselwa ukukukhumbula, ngokwesibonelo ukungenisa ngemvume noma ukwenza izikhangiso zibe ngezakho. Ukuze uphathe amakhukhi awo wonke amasayithi, bona okuthi<ph name="BEGIN_LINK" />Amasethingi<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Sula idatha yesayithi?</translation>
@@ -39,13 +39,13 @@
<translation id="1994173015038366702">I-URL yesayithi</translation>
<translation id="2025115093177348061">I-Augmented Reality</translation>
<translation id="2030769033451695672">Thepha ukubuyela ku-<ph name="URL_OF_THE_CURRENT_TAB" /></translation>
+<translation id="2054665754582400095">Ubukhona bakho</translation>
<translation id="2079545284768500474">Hlehlisa</translation>
<translation id="2091887806945687916">Umsindo</translation>
<translation id="2107397443965016585">Buza ngaphambi kokuvumela amasayithi ukudlala okuqukethwe okuvikelwe (kunconyiwe)</translation>
<translation id="2146738493024040262">Vula i-app elisheshayo</translation>
<translation id="2148716181193084225">Namhlanje</translation>
<translation id="2182457891543959921">Buza ngaphambi kokuvumela amasayithi ukudala imephu ye-3D yendawo ekuzungezile noma ukulandelela indawo yekhamera (kuyanconywa)</translation>
-<translation id="2187243482123994665">Ukuba khona komsebenzisi</translation>
<translation id="2212565012507486665">Vumela amakhukhi</translation>
<translation id="2228071138934252756">Ukuze uvumele i-<ph name="APP_NAME" /> ifinyelele ikhamera yakho, vula nekhamera <ph name="BEGIN_LINK" />Kumasethingi e-Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Kanye nje</translation>
@@ -55,7 +55,6 @@
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}one{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}other{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}}</translation>
<translation id="2434158240863470628">Ukulanda kuqedile <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2440823041667407902">Ukufinyelela kundawo</translation>
<translation id="2482878487686419369">Izaziso</translation>
<translation id="2490684707762498678">Ilawulwa ngu-<ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Usizo nempendulo</translation>
@@ -89,6 +88,7 @@
<translation id="3227137524299004712">Imakrofoni</translation>
<translation id="3277252321222022663">Vumela amasayithi ukuthi afinyelele kuzinzwa (kunconyiwe)</translation>
<translation id="3295602654194328831">Fihla ulwazi</translation>
+<translation id="3328801116991980348">Ulwazi lwesayithi</translation>
<translation id="3333961966071413176">Bonke oxhumana nabo</translation>
<translation id="3386292677130313581">Buza ngaphambi kokuvumela amasayithi ukuthi azi indawo yakho (kunconyiwe)</translation>
<translation id="3538390592868664640">Vimbela amasayithi ekudaleni imephu ye-3D yendawo ekuzungezile noma ukulandelela indawo yekhamera</translation>
@@ -122,6 +122,7 @@
<translation id="445467742685312942">Vumela amasayithi ukudlala okuqukethwe okuvikelekile</translation>
<translation id="4468959413250150279">Thulisa umsindo kusayithi elithile.</translation>
<translation id="4479647676395637221">Buza kuqala ngaphambi kokuvumela amasayithi ukuthi asebenzise ikhamera yakho (kunconyiwe)</translation>
+<translation id="4505788138578415521">I-URL inwetshiwe</translation>
<translation id="4534723447064627427">Ukuze uvumele i-<ph name="APP_NAME" /> ifinyelele imakrofoni yakho, vula nemakrofoni <ph name="BEGIN_LINK" />Kumasethingi e-Android<ph name="END_LINK" />.</translation>
<translation id="4570913071927164677">Imininingwane</translation>
<translation id="4645575059429386691">Kuphethwe umzali wakho</translation>
@@ -303,7 +304,6 @@
<translation id="9074739597929991885">I-Bluetooth</translation>
<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nokungu-<ph name="NUM_MORE" /> ngaphezulu}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nokungu-<ph name="NUM_MORE" /> ngaphezulu}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nokungu-<ph name="NUM_MORE" /> ngaphezulu}}</translation>
<translation id="913657688200966289">Vula izimvume ze-<ph name="APP_NAME" /> <ph name="BEGIN_LINK" />Kumasethingi e-Android<ph name="END_LINK" />.</translation>
-<translation id="945632385593298557">Finyelela imakrofoni yakho</translation>
<translation id="965817943346481315">Vimba uma isayithi libonisa izikhangiso ezingathandeki noma ezidukisayo (kunconyiwe)</translation>
<translation id="967624055006145463">Idatha ilondoloziwe</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/browser_ui/styles/android/BUILD.gn b/chromium/components/browser_ui/styles/android/BUILD.gn
index 10fbbe29592..efd2a790fa1 100644
--- a/chromium/components/browser_ui/styles/android/BUILD.gn
+++ b/chromium/components/browser_ui/styles/android/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/android/rules.gni")
+import("//device/vr/buildflags/buildflags.gni")
android_library("java") {
sources =
@@ -27,6 +28,7 @@ android_resources("java_resources") {
"java/res/color/default_icon_color_tint_list.xml",
"java/res/drawable-hdpi/btn_star_filled.png",
"java/res/drawable-hdpi/ic_delete_white_24dp.png",
+ "java/res/drawable-hdpi/ic_edit_24dp.png",
"java/res/drawable-hdpi/ic_folder_blue_24dp.png",
"java/res/drawable-hdpi/ic_logo_googleg_24dp.png",
"java/res/drawable-hdpi/ic_pause_white_24dp.png",
@@ -43,6 +45,7 @@ android_resources("java_resources") {
"java/res/drawable-hdpi/top_round.9.png",
"java/res/drawable-mdpi/btn_star_filled.png",
"java/res/drawable-mdpi/ic_delete_white_24dp.png",
+ "java/res/drawable-mdpi/ic_edit_24dp.png",
"java/res/drawable-mdpi/ic_folder_blue_24dp.png",
"java/res/drawable-mdpi/ic_logo_googleg_24dp.png",
"java/res/drawable-mdpi/ic_pause_white_24dp.png",
@@ -64,6 +67,7 @@ android_resources("java_resources") {
"java/res/drawable-night-xxxhdpi/top_round.9.png",
"java/res/drawable-xhdpi/btn_star_filled.png",
"java/res/drawable-xhdpi/ic_delete_white_24dp.png",
+ "java/res/drawable-xhdpi/ic_edit_24dp.png",
"java/res/drawable-xhdpi/ic_folder_blue_24dp.png",
"java/res/drawable-xhdpi/ic_logo_googleg_24dp.png",
"java/res/drawable-xhdpi/ic_pause_white_24dp.png",
@@ -80,6 +84,7 @@ android_resources("java_resources") {
"java/res/drawable-xhdpi/top_round.9.png",
"java/res/drawable-xxhdpi/btn_star_filled.png",
"java/res/drawable-xxhdpi/ic_delete_white_24dp.png",
+ "java/res/drawable-xxhdpi/ic_edit_24dp.png",
"java/res/drawable-xxhdpi/ic_folder_blue_24dp.png",
"java/res/drawable-xxhdpi/ic_logo_googleg_24dp.png",
"java/res/drawable-xxhdpi/ic_pause_white_24dp.png",
@@ -96,6 +101,7 @@ android_resources("java_resources") {
"java/res/drawable-xxhdpi/top_round.9.png",
"java/res/drawable-xxxhdpi/btn_star_filled.png",
"java/res/drawable-xxxhdpi/ic_delete_white_24dp.png",
+ "java/res/drawable-xxxhdpi/ic_edit_24dp.png",
"java/res/drawable-xxxhdpi/ic_folder_blue_24dp.png",
"java/res/drawable-xxxhdpi/ic_logo_googleg_24dp.png",
"java/res/drawable-xxxhdpi/ic_pause_white_24dp.png",
@@ -121,12 +127,13 @@ android_resources("java_resources") {
"java/res/drawable/ic_info_outline_grey_16dp.xml",
"java/res/drawable/ic_info_outline_grey_24dp.xml",
"java/res/drawable/ic_offline_pin_24dp_on_light_bg.xml",
+ "java/res/drawable/ic_permission_location_filled.xml",
+ "java/res/drawable/ic_permission_location_outline.xml",
"java/res/drawable/ic_security_grey.xml",
"java/res/drawable/ic_update_grey.xml",
"java/res/drawable/ic_vpn_key_grey.xml",
"java/res/drawable/ic_warning_red_16dp.xml",
"java/res/drawable/ic_warning_red_24dp.xml",
- "java/res/drawable/permission_location.xml",
"java/res/drawable/smartphone_black_24dp.xml",
"java/res/values-night/colors.xml",
"java/res/values-night/values.xml",
@@ -138,5 +145,9 @@ android_resources("java_resources") {
"java/res/values/values.xml",
]
+ if (enable_arcore) {
+ sources += [ "java/res-arcore/drawable/ic_ar_core_install.xml" ]
+ }
+
deps = [ "//ui/android:ui_java_resources" ]
}
diff --git a/chromium/components/browser_ui/webshare/DIR_METADATA b/chromium/components/browser_ui/webshare/DIR_METADATA
new file mode 100644
index 00000000000..8875242bb0f
--- /dev/null
+++ b/chromium/components/browser_ui/webshare/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+ component: "Blink>WebShare"
+}
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/webshare/OWNERS b/chromium/components/browser_ui/webshare/OWNERS
index c880f89d823..86d73a29e82 100644
--- a/chromium/components/browser_ui/webshare/OWNERS
+++ b/chromium/components/browser_ui/webshare/OWNERS
@@ -1,5 +1,2 @@
ericwilligers@chromium.org
raymes@chromium.org
-
-# COMPONENT: Blink>WebShare
-# OS: Android
diff --git a/chromium/components/browser_ui/widget/android/BUILD.gn b/chromium/components/browser_ui/widget/android/BUILD.gn
index 94360600d58..df652e94776 100644
--- a/chromium/components/browser_ui/widget/android/BUILD.gn
+++ b/chromium/components/browser_ui/widget/android/BUILD.gn
@@ -40,6 +40,10 @@ android_library("java") {
"java/src/org/chromium/components/browser_ui/widget/animation/CancelAwareAnimatorListener.java",
"java/src/org/chromium/components/browser_ui/widget/animation/FocusAnimator.java",
"java/src/org/chromium/components/browser_ui/widget/animation/Interpolators.java",
+ "java/src/org/chromium/components/browser_ui/widget/async_image/AsyncImageView.java",
+ "java/src/org/chromium/components/browser_ui/widget/async_image/AutoAnimatorDrawable.java",
+ "java/src/org/chromium/components/browser_ui/widget/async_image/ForegroundDrawableCompat.java",
+ "java/src/org/chromium/components/browser_ui/widget/async_image/ForegroundRoundedCornerImageView.java",
"java/src/org/chromium/components/browser_ui/widget/displaystyle/DisplayStyleObserver.java",
"java/src/org/chromium/components/browser_ui/widget/displaystyle/DisplayStyleObserverAdapter.java",
"java/src/org/chromium/components/browser_ui/widget/displaystyle/HorizontalDisplayStyle.java",
@@ -48,6 +52,7 @@ android_library("java") {
"java/src/org/chromium/components/browser_ui/widget/displaystyle/ViewResizer.java",
"java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableListAdapter.java",
"java/src/org/chromium/components/browser_ui/widget/dragreorder/DragStateDelegate.java",
+ "java/src/org/chromium/components/browser_ui/widget/gesture/SwipeGestureListener.java",
"java/src/org/chromium/components/browser_ui/widget/highlight/PulseDrawable.java",
"java/src/org/chromium/components/browser_ui/widget/highlight/PulseInterpolator.java",
"java/src/org/chromium/components/browser_ui/widget/highlight/ViewHighlighter.java",
@@ -158,6 +163,8 @@ android_resources("java_resources") {
"java/res/drawable-xxxhdpi/ic_check_googblue_24dp.png",
"java/res/drawable-xxxhdpi/ic_more_vert_24dp_on_dark_bg.png",
"java/res/drawable-xxxhdpi/ic_more_vert_24dp_on_light_bg.png",
+ "java/res/drawable/async_image_view_unavailable.xml",
+ "java/res/drawable/async_image_view_waiting.xml",
"java/res/drawable/hairline_border_card_background.xml",
"java/res/drawable/hairline_border_card_dark_transparent_bg.xml",
"java/res/drawable/ic_check_googblue_24dp_animated.xml",
@@ -263,6 +270,7 @@ android_library("javatests") {
"//third_party/android_support_test_runner:runner_java",
"//third_party/hamcrest:hamcrest_java",
"//third_party/junit",
+ "//third_party/mockito:mockito_java",
"//ui/android:ui_java",
"//ui/android:ui_java_test_support",
]
@@ -302,6 +310,7 @@ java_library("junit") {
"java/src/org/chromium/components/browser_ui/widget/CompositeTouchDelegateUnitTest.java",
"java/src/org/chromium/components/browser_ui/widget/InsetObserverViewTest.java",
"java/src/org/chromium/components/browser_ui/widget/LoadingViewTest.java",
+ "java/src/org/chromium/components/browser_ui/widget/gesture/SwipeGestureListenerTest.java",
"java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectionDelegateTest.java",
]
deps = [
diff --git a/chromium/components/browser_ui/widget/android/DIR_METADATA b/chromium/components/browser_ui/widget/android/DIR_METADATA
new file mode 100644
index 00000000000..496d4121fe9
--- /dev/null
+++ b/chromium/components/browser_ui/widget/android/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+ component: "UI>Browser>Mobile"
+}
+
+team_email: "clank-app-team@google.com"
+
+os: ANDROID
diff --git a/chromium/components/browser_ui/widget/android/OWNERS b/chromium/components/browser_ui/widget/android/OWNERS
index db5a8099e0b..96a00dbf29d 100644
--- a/chromium/components/browser_ui/widget/android/OWNERS
+++ b/chromium/components/browser_ui/widget/android/OWNERS
@@ -1,7 +1,3 @@
twellington@chromium.org
file://chrome/android/OWNERS
-
-# COMPONENT: UI>Browser>Mobile
-# TEAM: chrome-android-app@chromium.org
-# OS: Android
diff --git a/chromium/components/browsing_data/content/BUILD.gn b/chromium/components/browsing_data/content/BUILD.gn
index 0426a9bccff..2d0ff22eea9 100644
--- a/chromium/components/browsing_data/content/BUILD.gn
+++ b/chromium/components/browsing_data/content/BUILD.gn
@@ -39,8 +39,8 @@ static_library("content") {
"//components/browsing_data/core",
"//components/content_settings/core/browser",
"//components/content_settings/core/common",
+ "//components/no_state_prefetch/browser",
"//components/prefs",
- "//components/prerender/browser",
"//components/site_isolation",
"//content/public/browser",
"//net",
diff --git a/chromium/components/browsing_data/content/DEPS b/chromium/components/browsing_data/content/DEPS
index 1697dc36311..fd71be87f4a 100644
--- a/chromium/components/browsing_data/content/DEPS
+++ b/chromium/components/browsing_data/content/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+components/content_settings/core/browser",
"+components/content_settings/core/common",
"+components/prefs",
- "+components/prerender/browser",
+ "+components/no_state_prefetch/browser",
"+components/services/storage/public",
"+components/site_isolation",
"+content/public/browser",
diff --git a/chromium/components/browsing_data/content/appcache_helper.cc b/chromium/components/browsing_data/content/appcache_helper.cc
index 9fe79afdfd8..8a67983660c 100644
--- a/chromium/components/browsing_data/content/appcache_helper.cc
+++ b/chromium/components/browsing_data/content/appcache_helper.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/time/time.h"
#include "components/browsing_data/content/browsing_data_helper.h"
diff --git a/chromium/components/browsing_data/content/appcache_helper_unittest.cc b/chromium/components/browsing_data/content/appcache_helper_unittest.cc
index 32e5d6d09fe..93ddeeb3bb9 100644
--- a/chromium/components/browsing_data/content/appcache_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/appcache_helper_unittest.cc
@@ -7,11 +7,11 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "build/build_config.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/storage_usage_info.h"
diff --git a/chromium/components/browsing_data/content/browsing_data_helper.cc b/chromium/components/browsing_data/content/browsing_data_helper.cc
index c4b165c6ab4..5005e7b9951 100644
--- a/chromium/components/browsing_data/content/browsing_data_helper.cc
+++ b/chromium/components/browsing_data/content/browsing_data_helper.cc
@@ -12,8 +12,8 @@
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
#include "components/prefs/pref_service.h"
-#include "components/prerender/browser/prerender_manager.h"
#include "components/site_isolation/pref_names.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/browsing_data_remover.h"
diff --git a/chromium/components/browsing_data/content/cache_storage_helper_browsertest.cc b/chromium/components/browsing_data/content/cache_storage_helper_browsertest.cc
index 2225923d89b..c652c275120 100644
--- a/chromium/components/browsing_data/content/cache_storage_helper_browsertest.cc
+++ b/chromium/components/browsing_data/content/cache_storage_helper_browsertest.cc
@@ -5,7 +5,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/browsing_data/content/cookie_helper.cc b/chromium/components/browsing_data/content/cookie_helper.cc
index f74483b2a51..595b4c4e45e 100644
--- a/chromium/components/browsing_data/content/cookie_helper.cc
+++ b/chromium/components/browsing_data/content/cookie_helper.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/no_destructor.h"
diff --git a/chromium/components/browsing_data/content/cookie_helper_unittest.cc b/chromium/components/browsing_data/content/cookie_helper_unittest.cc
index ebd5e6f100e..bf083ffbfd0 100644
--- a/chromium/components/browsing_data/content/cookie_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/cookie_helper_unittest.cc
@@ -5,10 +5,10 @@
#include "components/browsing_data/content/cookie_helper.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/time/time.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/storage_partition.h"
diff --git a/chromium/components/browsing_data/content/database_helper_browsertest.cc b/chromium/components/browsing_data/content/database_helper_browsertest.cc
index bba977e53ec..cd78168c9f5 100644
--- a/chromium/components/browsing_data/content/database_helper_browsertest.cc
+++ b/chromium/components/browsing_data/content/database_helper_browsertest.cc
@@ -5,11 +5,11 @@
#include <stdint.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/browsing_data/content/browsing_data_helper_browsertest.h"
#include "components/browsing_data/content/database_helper.h"
#include "content/public/browser/browser_context.h"
diff --git a/chromium/components/browsing_data/content/file_system_helper_unittest.cc b/chromium/components/browsing_data/content/file_system_helper_unittest.cc
index 7ce274b4ea4..be0e6871535 100644
--- a/chromium/components/browsing_data/content/file_system_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/file_system_helper_unittest.cc
@@ -10,7 +10,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
diff --git a/chromium/components/browsing_data/content/indexed_db_helper_browsertest.cc b/chromium/components/browsing_data/content/indexed_db_helper_browsertest.cc
index 72f4e2b288b..cbe8e244ae2 100644
--- a/chromium/components/browsing_data/content/indexed_db_helper_browsertest.cc
+++ b/chromium/components/browsing_data/content/indexed_db_helper_browsertest.cc
@@ -5,7 +5,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/browsing_data/content/indexed_db_helper_unittest.cc b/chromium/components/browsing_data/content/indexed_db_helper_unittest.cc
index af458981884..d15f69e93fb 100644
--- a/chromium/components/browsing_data/content/indexed_db_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/indexed_db_helper_unittest.cc
@@ -6,7 +6,7 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
diff --git a/chromium/components/browsing_data/content/local_storage_helper_browsertest.cc b/chromium/components/browsing_data/content/local_storage_helper_browsertest.cc
index 039776fe0ea..a11d8eca665 100644
--- a/chromium/components/browsing_data/content/local_storage_helper_browsertest.cc
+++ b/chromium/components/browsing_data/content/local_storage_helper_browsertest.cc
@@ -9,8 +9,8 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
diff --git a/chromium/components/browsing_data/content/local_storage_helper_unittest.cc b/chromium/components/browsing_data/content/local_storage_helper_unittest.cc
index 29c86136b57..0f14d98ccd9 100644
--- a/chromium/components/browsing_data/content/local_storage_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/local_storage_helper_unittest.cc
@@ -4,7 +4,7 @@
#include "components/browsing_data/content/local_storage_helper.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/browsing_data/content/mock_cookie_helper.cc b/chromium/components/browsing_data/content/mock_cookie_helper.cc
index 69c06953c16..af48d9d8c97 100644
--- a/chromium/components/browsing_data/content/mock_cookie_helper.cc
+++ b/chromium/components/browsing_data/content/mock_cookie_helper.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/time/time.h"
diff --git a/chromium/components/browsing_data/content/service_worker_helper.cc b/chromium/components/browsing_data/content/service_worker_helper.cc
index 34ba37c3fdf..c417fe69d20 100644
--- a/chromium/components/browsing_data/content/service_worker_helper.cc
+++ b/chromium/components/browsing_data/content/service_worker_helper.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "components/browsing_data/content/browsing_data_helper.h"
#include "content/public/browser/browser_task_traits.h"
diff --git a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
index e217276791d..f3a012f2929 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
+++ b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -7,7 +7,7 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc b/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
index 52bf76828c8..5b3e7b76900 100644
--- a/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/browsing_data/core/counters/passwords_counter.cc b/chromium/components/browsing_data/core/counters/passwords_counter.cc
index f8b47a33c30..d6b6ba4e3de 100644
--- a/chromium/components/browsing_data/core/counters/passwords_counter.cc
+++ b/chromium/components/browsing_data/core/counters/passwords_counter.cc
@@ -47,7 +47,8 @@ class PasswordStoreFetcher : public password_manager::PasswordStoreConsumer,
base::OnceClosure fetch_complete);
void OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+ std::vector<std::unique_ptr<password_manager::PasswordForm>> results)
+ override;
// Called when the contents of the password store change. Triggers new
// counting.
@@ -102,20 +103,20 @@ void PasswordStoreFetcher::Fetch(base::Time start,
}
void PasswordStoreFetcher::OnGetPasswordStoreResults(
- std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+ std::vector<std::unique_ptr<password_manager::PasswordForm>> results) {
domain_examples_.clear();
results.erase(
std::remove_if(
results.begin(), results.end(),
- [this](const std::unique_ptr<autofill::PasswordForm>& form) {
+ [this](const std::unique_ptr<password_manager::PasswordForm>& form) {
return (form->date_created < start_ || form->date_created >= end_);
}),
results.end());
num_passwords_ = results.size();
std::sort(results.begin(), results.end(),
- [](const std::unique_ptr<autofill::PasswordForm>& a,
- const std::unique_ptr<autofill::PasswordForm>& b) {
+ [](const std::unique_ptr<password_manager::PasswordForm>& a,
+ const std::unique_ptr<password_manager::PasswordForm>& b) {
return a->times_used > b->times_used;
});
diff --git a/chromium/components/browsing_data/core/features.cc b/chromium/components/browsing_data/core/features.cc
index e57c1192202..cc0cf04ce3d 100644
--- a/chromium/components/browsing_data/core/features.cc
+++ b/chromium/components/browsing_data/core/features.cc
@@ -10,5 +10,7 @@ namespace features {
const base::Feature kEnableRemovingAllThirdPartyCookies{
"EnableRemovingAllThirdPartyCookies", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kEnableBrowsingDataLifetimeManager{
+ "BrowsingDataLifetimeManager", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/features.h b/chromium/components/browsing_data/core/features.h
index 6543d4081ab..62779a1be00 100644
--- a/chromium/components/browsing_data/core/features.h
+++ b/chromium/components/browsing_data/core/features.h
@@ -13,6 +13,10 @@ namespace features {
// Enable removal of all third-party cookies and site data.
extern const base::Feature kEnableRemovingAllThirdPartyCookies;
+// Enable BrowsingDataLifetimeManager that periodically delete browsing data as
+// defined by the BrowsingDataLifetime policy.
+extern const base::Feature kEnableBrowsingDataLifetimeManager;
+
} // namespace features
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/history_notice_utils_unittest.cc b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
index 165cf2605e1..7d8d1ce83fe 100644
--- a/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
+++ b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
@@ -8,7 +8,7 @@
#include "base/callback.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/history/core/test/fake_web_history_service.h"
#include "components/sync/base/model_type.h"
diff --git a/chromium/components/browsing_data/core/pref_names.cc b/chromium/components/browsing_data/core/pref_names.cc
index adf13db4410..2c999c9a49e 100644
--- a/chromium/components/browsing_data/core/pref_names.cc
+++ b/chromium/components/browsing_data/core/pref_names.cc
@@ -4,12 +4,16 @@
#include "components/browsing_data/core/pref_names.h"
+#include "base/values.h"
#include "components/pref_registry/pref_registry_syncable.h"
namespace browsing_data {
namespace prefs {
+// JSON config to periodically delete some user browsing data.
+const char kBrowsingDataLifetime[] = "browsing_data_lifetime";
+
// Clear browsing data deletion time period.
const char kDeleteTimePeriod[] = "browser.clear_data.time_period";
const char kDeleteTimePeriodBasic[] = "browser.clear_data.time_period_basic";
@@ -38,6 +42,8 @@ const char kPreferencesMigratedToBasic[] =
"browser.clear_data.preferences_migrated_to_basic";
void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterListPref(kBrowsingDataLifetime,
+ base::Value(base::Value::Type::LIST));
registry->RegisterIntegerPref(
kDeleteTimePeriod, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
diff --git a/chromium/components/browsing_data/core/pref_names.h b/chromium/components/browsing_data/core/pref_names.h
index 401d1cf67ad..4124e1301c5 100644
--- a/chromium/components/browsing_data/core/pref_names.h
+++ b/chromium/components/browsing_data/core/pref_names.h
@@ -13,6 +13,8 @@ namespace browsing_data {
namespace prefs {
+extern const char kBrowsingDataLifetime[];
+
extern const char kDeleteTimePeriod[];
extern const char kDeleteTimePeriodBasic[];
diff --git a/chromium/components/captive_portal/content/captive_portal_service.cc b/chromium/components/captive_portal/content/captive_portal_service.cc
index 1acd9d8debd..ca9fa3390a1 100644
--- a/chromium/components/captive_portal/content/captive_portal_service.cc
+++ b/chromium/components/captive_portal/content/captive_portal_service.cc
@@ -5,7 +5,7 @@
#include "components/captive_portal/content/captive_portal_service.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
diff --git a/chromium/components/captive_portal/content/captive_portal_tab_helper_unittest.cc b/chromium/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
index 4bca09a2010..75670ee8cf1 100644
--- a/chromium/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
+++ b/chromium/components/captive_portal/content/captive_portal_tab_helper_unittest.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "components/captive_portal/content/captive_portal_service.h"
#include "components/captive_portal/content/captive_portal_tab_reloader.h"
diff --git a/chromium/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc b/chromium/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
index 563e89be17f..f52c4f11c07 100644
--- a/chromium/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
+++ b/chromium/components/captive_portal/content/captive_portal_tab_reloader_unittest.cc
@@ -4,8 +4,8 @@
#include "components/captive_portal/content/captive_portal_tab_reloader.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "components/captive_portal/content/captive_portal_service.h"
diff --git a/chromium/components/cast/BUILD.gn b/chromium/components/cast/BUILD.gn
index 66f8d31e981..90a45408064 100644
--- a/chromium/components/cast/BUILD.gn
+++ b/chromium/components/cast/BUILD.gn
@@ -5,3 +5,8 @@
source_set("export") {
sources = [ "cast_component_export.h" ]
}
+
+source_set("unit_tests") {
+ testonly = true
+ deps = [ "//components/cast/message_port:message_port_unittest" ]
+}
diff --git a/chromium/components/cast/api_bindings/BUILD.gn b/chromium/components/cast/api_bindings/BUILD.gn
index 5e2647e55e5..242673e371d 100644
--- a/chromium/components/cast/api_bindings/BUILD.gn
+++ b/chromium/components/cast/api_bindings/BUILD.gn
@@ -15,8 +15,7 @@ source_set("manager") {
deps = [
"//base",
"//components/cast:export",
- "//third_party/blink/public/common",
]
defines = [ "CAST_COMPONENT_IMPLEMENTATION" ]
- public_deps = [ "//mojo/public/cpp/bindings" ]
+ public_deps = [ "//components/cast/message_port" ]
}
diff --git a/chromium/components/cast/api_bindings/DEPS b/chromium/components/cast/api_bindings/DEPS
index e07691e1175..e69de29bb2d 100644
--- a/chromium/components/cast/api_bindings/DEPS
+++ b/chromium/components/cast/api_bindings/DEPS
@@ -1,3 +0,0 @@
-include_rules = [
- "+third_party/blink/public/common/messaging",
-]
diff --git a/chromium/components/cast/api_bindings/manager.cc b/chromium/components/cast/api_bindings/manager.cc
index 29e1c255d9e..f945167e713 100644
--- a/chromium/components/cast/api_bindings/manager.cc
+++ b/chromium/components/cast/api_bindings/manager.cc
@@ -27,9 +27,10 @@ void Manager::UnregisterPortHandler(base::StringPiece port_name) {
DCHECK_EQ(deleted, 1u);
}
-bool Manager::OnPortConnected(base::StringPiece port_name,
- blink::WebMessagePort port) {
- if (!port.IsValid())
+bool Manager::OnPortConnected(
+ base::StringPiece port_name,
+ std::unique_ptr<cast_api_bindings::MessagePort> port) {
+ if (!port)
return false;
auto handler = port_handlers_.find(port_name);
diff --git a/chromium/components/cast/api_bindings/manager.h b/chromium/components/cast/api_bindings/manager.h
index d0da0a64716..9f833af9477 100644
--- a/chromium/components/cast/api_bindings/manager.h
+++ b/chromium/components/cast/api_bindings/manager.h
@@ -12,7 +12,7 @@
#include "base/containers/flat_map.h"
#include "base/strings/string_piece.h"
#include "components/cast/cast_component_export.h"
-#include "third_party/blink/public/common/messaging/web_message_port.h"
+#include "components/cast/message_port/message_port.h"
namespace cast_api_bindings {
@@ -20,8 +20,8 @@ namespace cast_api_bindings {
// and to register handlers for communication with the content.
class CAST_COMPONENT_EXPORT Manager {
public:
- using MessagePortConnectedHandler =
- base::RepeatingCallback<void(blink::WebMessagePort)>;
+ using MessagePortConnectedHandler = base::RepeatingCallback<void(
+ std::unique_ptr<cast_api_bindings::MessagePort>)>;
Manager();
virtual ~Manager();
@@ -48,7 +48,8 @@ class CAST_COMPONENT_EXPORT Manager {
// connection to |port_name|.
// Returns |false| if the port was invalid or not registered in advance, at
// which point the matchmaking port should be dropped.
- bool OnPortConnected(base::StringPiece port_name, blink::WebMessagePort port);
+ bool OnPortConnected(base::StringPiece port_name,
+ std::unique_ptr<cast_api_bindings::MessagePort> port);
private:
base::flat_map<std::string, MessagePortConnectedHandler> port_handlers_;
diff --git a/chromium/components/cast/api_bindings/scoped_api_binding.cc b/chromium/components/cast/api_bindings/scoped_api_binding.cc
index 60adf505f2c..30843b3af92 100644
--- a/chromium/components/cast/api_bindings/scoped_api_binding.cc
+++ b/chromium/components/cast/api_bindings/scoped_api_binding.cc
@@ -6,8 +6,8 @@
#include <string>
+#include "base/bind.h"
#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
#include "components/cast/api_bindings/manager.h"
namespace cast_api_bindings {
@@ -41,9 +41,10 @@ ScopedApiBinding::~ScopedApiBinding() {
}
}
-void ScopedApiBinding::OnPortConnected(blink::WebMessagePort port) {
+void ScopedApiBinding::OnPortConnected(
+ std::unique_ptr<cast_api_bindings::MessagePort> port) {
message_port_ = std::move(port);
- message_port_.SetReceiver(this, base::SequencedTaskRunnerHandle::Get());
+ message_port_->SetReceiver(this);
delegate_->OnConnected();
}
@@ -51,28 +52,23 @@ bool ScopedApiBinding::SendMessage(base::StringPiece data_utf8) {
DCHECK(delegate_);
DVLOG(1) << "SendMessage: message=" << data_utf8;
- if (!message_port_.IsValid()) {
+ if (!message_port_->CanPostMessage()) {
LOG(WARNING)
<< "Attempted to write to unconnected MessagePort, dropping message.";
return false;
}
- if (!message_port_.PostMessage(
- blink::WebMessagePort::Message(base::UTF8ToUTF16(data_utf8)))) {
+ if (!message_port_->PostMessage(data_utf8.as_string())) {
return false;
}
return true;
}
-bool ScopedApiBinding::OnMessage(blink::WebMessagePort::Message message) {
- std::string message_utf8;
- if (!base::UTF16ToUTF8(message.data.data(), message.data.size(),
- &message_utf8)) {
- return false;
- }
-
- return delegate_->OnMessage(message_utf8);
+bool ScopedApiBinding::OnMessage(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) {
+ return delegate_->OnMessage(message);
}
void ScopedApiBinding::OnPipeError() {
diff --git a/chromium/components/cast/api_bindings/scoped_api_binding.h b/chromium/components/cast/api_bindings/scoped_api_binding.h
index 68d3f8360e4..bb5f3cdbb75 100644
--- a/chromium/components/cast/api_bindings/scoped_api_binding.h
+++ b/chromium/components/cast/api_bindings/scoped_api_binding.h
@@ -12,7 +12,7 @@
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "components/cast/cast_component_export.h"
-#include "third_party/blink/public/common/messaging/web_message_port.h"
+#include "components/cast/message_port/message_port.h"
namespace cast_api_bindings {
@@ -22,7 +22,7 @@ class Manager;
// communication channels, as well as unregistration on object teardown, using
// RAII semantics.
class CAST_COMPONENT_EXPORT ScopedApiBinding
- : public blink::WebMessagePort::MessageReceiver {
+ : public cast_api_bindings::MessagePort::Receiver {
public:
// Methods for handling message I/O with bindings scripts.
class Delegate {
@@ -71,10 +71,12 @@ class CAST_COMPONENT_EXPORT ScopedApiBinding
private:
// Called when a port is received from the page.
- void OnPortConnected(blink::WebMessagePort port);
+ void OnPortConnected(std::unique_ptr<cast_api_bindings::MessagePort> port);
- // blink::WebMessagePort::MessageReceiver implementation:
- bool OnMessage(blink::WebMessagePort::Message message) final;
+ // cast_api_bindings::MessagePort::Receiver implementation:
+ bool OnMessage(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) final;
void OnPipeError() final;
Manager* const bindings_manager_;
@@ -82,7 +84,7 @@ class CAST_COMPONENT_EXPORT ScopedApiBinding
const std::string js_bindings_id_;
// The MessagePort used to receive messages from the receiver JS.
- blink::WebMessagePort message_port_;
+ std::unique_ptr<cast_api_bindings::MessagePort> message_port_;
};
} // namespace cast_api_bindings
diff --git a/chromium/components/cast/message_port/BUILD.gn b/chromium/components/cast/message_port/BUILD.gn
new file mode 100644
index 00000000000..a2c15794272
--- /dev/null
+++ b/chromium/components/cast/message_port/BUILD.gn
@@ -0,0 +1,83 @@
+# Copyright 2020 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("//build/config/features.gni")
+import("//testing/test.gni")
+
+source_set("message_port") {
+ if (is_fuchsia) {
+ public_deps = [ ":message_port_fuchsia" ]
+ } else {
+ public_deps = [ ":message_port_cast" ]
+ }
+}
+
+source_set("public") {
+ sources = [
+ "message_port.cc",
+ "message_port.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/cast:export",
+ ]
+
+ defines = [ "CAST_COMPONENT_IMPLEMENTATION" ]
+
+ visibility = [ ":*" ]
+}
+
+if (is_fuchsia) {
+ source_set("message_port_fuchsia") {
+ public = [ "message_port_fuchsia.h" ]
+
+ sources = [ "message_port_fuchsia.cc" ]
+
+ public_deps = [
+ ":public",
+ "//fuchsia:cast_fidl",
+ "//fuchsia/base",
+ ]
+
+ deps = [ "//base" ]
+ }
+}
+
+source_set("message_port_cast") {
+ public = [ "message_port_cast.h" ]
+
+ sources = [ "message_port_cast.cc" ]
+
+ public_deps = [ ":public" ]
+
+ deps = [
+ ":public",
+ "//base",
+ "//third_party/blink/public/common",
+ ]
+}
+
+source_set("message_port_unittest") {
+ testonly = true
+ sources = [ "message_port_unittest.cc" ]
+ deps = [
+ ":message_port",
+ ":test_message_port_receiver",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+}
+
+source_set("test_message_port_receiver") {
+ testonly = true
+ sources = [
+ "test_message_port_receiver.cc",
+ "test_message_port_receiver.h",
+ ]
+ deps = [
+ ":public",
+ "//base",
+ ]
+}
diff --git a/chromium/components/cast/message_port/DEPS b/chromium/components/cast/message_port/DEPS
new file mode 100644
index 00000000000..b6e90a64b95
--- /dev/null
+++ b/chromium/components/cast/message_port/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+fuchsia",
+ "+third_party/blink/public/common/messaging",
+]
diff --git a/chromium/components/cast/message_port/message_port.cc b/chromium/components/cast/message_port/message_port.cc
new file mode 100644
index 00000000000..f5451bf759e
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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/cast/message_port/message_port.h"
+
+namespace cast_api_bindings {
+
+MessagePort::Receiver::~Receiver() = default;
+MessagePort::~MessagePort() = default;
+
+} // namespace cast_api_bindings \ No newline at end of file
diff --git a/chromium/components/cast/message_port/message_port.h b/chromium/components/cast/message_port/message_port.h
new file mode 100644
index 00000000000..ef5b924641c
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port.h
@@ -0,0 +1,64 @@
+// Copyright 2020 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_CAST_MESSAGE_PORT_MESSAGE_PORT_H_
+#define COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "components/cast/cast_component_export.h"
+
+namespace cast_api_bindings {
+
+// HTML5 MessagePort abstraction; allows usage of the platform MessagePort type
+// without exposing details of the message format, paired port creation, or
+// transfer of ports.
+class CAST_COMPONENT_EXPORT MessagePort {
+ public:
+ // Implemented by receivers of messages from the MessagePort class.
+ class Receiver {
+ public:
+ virtual ~Receiver();
+
+ // Receives a |message| and ownership of |ports|.
+ virtual bool OnMessage(base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) = 0;
+
+ // Receives an error.
+ virtual void OnPipeError() = 0;
+ };
+
+ virtual ~MessagePort();
+
+ // Creates a pair of message ports. Clients must respect |client| and
+ // |server| semantics because they matter for some implementations.
+ static void CreatePair(std::unique_ptr<MessagePort>* client,
+ std::unique_ptr<MessagePort>* server);
+
+ // Sends a |message| from the port.
+ virtual bool PostMessage(base::StringPiece message) = 0;
+
+ // Sends a |message| from the port along with transferable |ports|.
+ virtual bool PostMessageWithTransferables(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) = 0;
+
+ // Sets the |receiver| for messages arriving to this port. May only be set
+ // once.
+ virtual void SetReceiver(
+ cast_api_bindings::MessagePort::Receiver* receiver) = 0;
+
+ // Closes the underlying port.
+ virtual void Close() = 0;
+
+ // Whether a message can be posted; may be used to check the state of the port
+ // without posting a message.
+ virtual bool CanPostMessage() const = 0;
+};
+
+} // namespace cast_api_bindings
+
+#endif // COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_H_
diff --git a/chromium/components/cast/message_port/message_port_cast.cc b/chromium/components/cast/message_port/message_port_cast.cc
new file mode 100644
index 00000000000..231f8cede7e
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port_cast.cc
@@ -0,0 +1,102 @@
+// Copyright 2020 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/cast/message_port/message_port_cast.h"
+
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+
+namespace cast_api_bindings {
+
+// static
+void MessagePort::CreatePair(std::unique_ptr<MessagePort>* client,
+ std::unique_ptr<MessagePort>* server) {
+ auto pair_raw = blink::WebMessagePort::CreatePair();
+ *client = MessagePortCast::Create(std::move(pair_raw.first));
+ *server = MessagePortCast::Create(std::move(pair_raw.second));
+}
+
+// static
+std::unique_ptr<MessagePort> MessagePortCast::Create(
+ blink::WebMessagePort&& port) {
+ return std::make_unique<MessagePortCast>(std::move(port));
+}
+
+// static
+MessagePortCast* MessagePortCast::FromMessagePort(MessagePort* port) {
+ DCHECK(port);
+ // This is safe because there is one MessagePort implementation per platform
+ // and this is called internally to the implementation.
+ return static_cast<MessagePortCast*>(port);
+}
+
+bool MessagePortCast::OnMessage(blink::WebMessagePort::Message message) {
+ DCHECK(receiver_);
+ std::string message_str;
+ if (!base::UTF16ToUTF8(message.data.data(), message.data.size(),
+ &message_str)) {
+ return false;
+ }
+
+ std::vector<std::unique_ptr<MessagePort>> transferables;
+ for (blink::WebMessagePort& port : message.ports) {
+ transferables.push_back(Create(std::move(port)));
+ }
+
+ return receiver_->OnMessage(message_str, std::move(transferables));
+}
+
+MessagePortCast::MessagePortCast(blink::WebMessagePort&& port)
+ : receiver_(nullptr), port_(std::move(port)) {}
+
+MessagePortCast::~MessagePortCast() {}
+
+void MessagePortCast::OnPipeError() {
+ DCHECK(receiver_);
+ receiver_->OnPipeError();
+}
+
+blink::WebMessagePort MessagePortCast::TakePort() {
+ return std::move(port_);
+}
+
+bool MessagePortCast::PostMessage(base::StringPiece message) {
+ return PostMessageWithTransferables(message, {});
+}
+
+bool MessagePortCast::PostMessageWithTransferables(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) {
+ DCHECK(port_.IsValid());
+ std::vector<blink::WebMessagePort> transferables;
+
+ for (auto& port : ports) {
+ MessagePortCast* port_cast = FromMessagePort(port.get());
+ transferables.push_back(port_cast->TakePort());
+ }
+
+ blink::WebMessagePort::Message msg = blink::WebMessagePort::Message(
+ base::UTF8ToUTF16(message), std::move(transferables));
+ return port_.PostMessage(std::move(msg));
+}
+
+void MessagePortCast::SetReceiver(
+ cast_api_bindings::MessagePort::Receiver* receiver) {
+ DCHECK(receiver);
+ DCHECK(!receiver_);
+ receiver_ = receiver;
+ port_.SetReceiver(this, base::SequencedTaskRunnerHandle::Get());
+}
+
+void MessagePortCast::Close() {
+ return port_.Close();
+}
+
+bool MessagePortCast::CanPostMessage() const {
+ return port_.CanPostMessage();
+}
+
+} // namespace cast_api_bindings
diff --git a/chromium/components/cast/message_port/message_port_cast.h b/chromium/components/cast/message_port/message_port_cast.h
new file mode 100644
index 00000000000..202bc174666
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port_cast.h
@@ -0,0 +1,52 @@
+// Copyright 2020 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_CAST_MESSAGE_PORT_MESSAGE_PORT_CAST_H_
+#define COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_CAST_H_
+
+#include "components/cast/message_port/message_port.h"
+#include "third_party/blink/public/common/messaging/web_message_port.h"
+
+namespace cast_api_bindings {
+
+// Abstraction of HTML MessagePortCast away from blink::WebMessagePort
+// Represents one end of a message channel.
+class MessagePortCast : public cast_api_bindings::MessagePort,
+ public blink::WebMessagePort::MessageReceiver {
+ public:
+ explicit MessagePortCast(blink::WebMessagePort&& port);
+ ~MessagePortCast() override;
+
+ MessagePortCast(const MessagePortCast&) = delete;
+ MessagePortCast& operator=(const MessagePortCast&) = delete;
+
+ static std::unique_ptr<MessagePort> Create(blink::WebMessagePort&& port);
+
+ // Gets the implementation of |port| for callers who know its platform type.
+ static MessagePortCast* FromMessagePort(MessagePort* port);
+
+ // Retrieves the platform-specific port and invalidates this object.
+ blink::WebMessagePort TakePort();
+
+ private:
+ // cast_api_bindings::MessagePort implementation
+ bool PostMessage(base::StringPiece message) final;
+ bool PostMessageWithTransferables(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) final;
+ void SetReceiver(cast_api_bindings::MessagePort::Receiver* receiver) final;
+ void Close() final;
+ bool CanPostMessage() const final;
+
+ // blink::WebMessagePort::MessageReceiver implementation
+ bool OnMessage(blink::WebMessagePort::Message message) final;
+ void OnPipeError() final;
+
+ cast_api_bindings::MessagePort::Receiver* receiver_;
+ blink::WebMessagePort port_;
+};
+
+} // namespace cast_api_bindings
+
+#endif // COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_CAST_H_
diff --git a/chromium/components/cast/message_port/message_port_fuchsia.cc b/chromium/components/cast/message_port/message_port_fuchsia.cc
new file mode 100644
index 00000000000..61a7589ad21
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port_fuchsia.cc
@@ -0,0 +1,344 @@
+// Copyright 2020 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/cast/message_port/message_port_fuchsia.h"
+
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/notreached.h"
+#include "fuchsia/base/mem_buffer_util.h"
+#include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
+
+namespace cast_api_bindings {
+namespace {
+
+// A MessagePortFuchsia instantiated with an
+// InterfaceHandle<fuchsia::web::MessagePort>. Acts as a client of a
+// MessagePortFuchsiaServer.
+class MessagePortFuchsiaClient : public MessagePortFuchsia {
+ public:
+ explicit MessagePortFuchsiaClient(
+ fidl::InterfaceHandle<::fuchsia::web::MessagePort> port)
+ : MessagePortFuchsia(PortType::HANDLE), port_(port.Bind()) {}
+
+ ~MessagePortFuchsiaClient() override {}
+
+ // MessagePortFuchsia implementation.
+ fidl::InterfaceHandle<::fuchsia::web::MessagePort> TakeClientHandle() final {
+ DCHECK(!receiver_);
+ DCHECK(port_.is_bound());
+ return port_.Unbind();
+ }
+
+ fidl::InterfaceRequest<::fuchsia::web::MessagePort> TakeServiceRequest()
+ final {
+ NOTREACHED();
+ return {};
+ }
+
+ // MessagePort implementation.
+ void SetReceiver(cast_api_bindings::MessagePort::Receiver* receiver) final {
+ DCHECK(receiver);
+ DCHECK(!receiver_);
+ receiver_ = receiver;
+ port_.set_error_handler(
+ [this](zx_status_t status) { MessagePortFuchsia::OnZxError(status); });
+ ReadNextMessage();
+ }
+
+ void Close() final {
+ if (port_.is_bound()) {
+ port_.Unbind();
+ }
+ }
+
+ bool CanPostMessage() const final { return port_.is_bound(); }
+
+ private:
+ void OnDeliverMessageToFidlComplete(
+ fuchsia::web::MessagePort_PostMessage_Result result) {
+ if (result.is_err()) {
+ LOG(ERROR) << "PostMessage failed, reason: "
+ << static_cast<int32_t>(result.err());
+ ReportPipeError();
+ }
+
+ message_queue_.pop_front();
+ DeliverMessageToFidl();
+ }
+
+ void DeliverMessageToFidl() final {
+ if (message_queue_.empty()) {
+ return;
+ }
+
+ port_->PostMessage(
+ std::move(message_queue_.front()),
+ fit::bind_member(
+ this, &MessagePortFuchsiaClient::OnDeliverMessageToFidlComplete));
+ }
+
+ // Helpers for reading and writing messages on the |port_|
+ void OnMessageReady(fuchsia::web::WebMessage message) {
+ auto status = ReceiveMessageFromFidl(std::move(message));
+ if (status) {
+ LOG(WARNING) << "Received bad message, error: "
+ << static_cast<int32_t>(*status);
+ ReportPipeError();
+ return;
+ }
+
+ ReadNextMessage();
+ }
+
+ void ReadNextMessage() {
+ DCHECK(receiver_);
+ DCHECK(port_);
+
+ port_->ReceiveMessage(
+ fit::bind_member(this, &MessagePortFuchsiaClient::OnMessageReady));
+ }
+
+ fuchsia::web::MessagePortPtr port_;
+};
+
+// A MessagePortFuchsia instantiated with an
+// InterfaceRequest<fuchsia::web::MessagePort>. Acts as the server for a
+// MessagePortFuchsiaClient.
+class MessagePortFuchsiaServer : public MessagePortFuchsia,
+ public fuchsia::web::MessagePort {
+ public:
+ explicit MessagePortFuchsiaServer(
+ fidl::InterfaceRequest<::fuchsia::web::MessagePort> port)
+ : MessagePortFuchsia(PortType::REQUEST), binding_(this) {
+ binding_.Bind(std::move(port));
+ }
+
+ ~MessagePortFuchsiaServer() override {}
+
+ // MessagePortFuchsia implementation.
+ fidl::InterfaceHandle<::fuchsia::web::MessagePort> TakeClientHandle() final {
+ NOTREACHED();
+ return {};
+ }
+
+ fidl::InterfaceRequest<::fuchsia::web::MessagePort> TakeServiceRequest()
+ final {
+ return binding_.Unbind();
+ }
+
+ // MessagePort implementation.
+ void SetReceiver(cast_api_bindings::MessagePort::Receiver* receiver) final {
+ DCHECK(receiver);
+ DCHECK(!receiver_);
+ receiver_ = receiver;
+ binding_.set_error_handler(
+ [this](zx_status_t status) { MessagePortFuchsia::OnZxError(status); });
+ }
+
+ void Close() final {
+ if (binding_.is_bound()) {
+ binding_.Unbind();
+ }
+ }
+
+ bool CanPostMessage() const final { return binding_.is_bound(); }
+
+ private:
+ void DeliverMessageToFidl() final {
+ // Do nothing if the client hasn't requested a read, or if there's nothing
+ // to read.
+ if (!pending_receive_message_callback_)
+ return;
+
+ if (message_queue_.empty())
+ return;
+
+ pending_receive_message_callback_(std::move(message_queue_.front()));
+ pending_receive_message_callback_ = {};
+ message_queue_.pop_front();
+ }
+
+ // Avoid hiding warning by other PostMessage
+ using MessagePortFuchsia::PostMessage;
+
+ // fuchsia::web::MessagePort implementation.
+ void PostMessage(fuchsia::web::WebMessage message,
+ PostMessageCallback callback) final {
+ auto status = ReceiveMessageFromFidl(std::move(message));
+ if (status) {
+ LOG(WARNING) << "Received bad message, error: "
+ << static_cast<int32_t>(*status);
+ ReportPipeError();
+ return;
+ }
+
+ fuchsia::web::MessagePort_PostMessage_Result result;
+ result.set_response(fuchsia::web::MessagePort_PostMessage_Response());
+ callback(std::move(result));
+ }
+
+ void ReceiveMessage(ReceiveMessageCallback callback) final {
+ if (pending_receive_message_callback_) {
+ LOG(WARNING)
+ << "ReceiveMessage called multiple times without acknowledgement.";
+ ReportPipeError();
+ return;
+ }
+
+ pending_receive_message_callback_ = std::move(callback);
+ DeliverMessageToFidl();
+ }
+
+ fidl::Binding<fuchsia::web::MessagePort> binding_;
+ ReceiveMessageCallback pending_receive_message_callback_;
+};
+} // namespace
+
+// static
+void MessagePort::CreatePair(std::unique_ptr<MessagePort>* client,
+ std::unique_ptr<MessagePort>* server) {
+ fidl::InterfaceHandle<fuchsia::web::MessagePort> port0;
+ fidl::InterfaceRequest<fuchsia::web::MessagePort> port1 = port0.NewRequest();
+ *client = MessagePortFuchsia::Create(std::move(port0));
+ *server = MessagePortFuchsia::Create(std::move(port1));
+}
+
+// static
+std::unique_ptr<MessagePort> MessagePortFuchsia::Create(
+ fidl::InterfaceHandle<::fuchsia::web::MessagePort> handle) {
+ return std::make_unique<MessagePortFuchsiaClient>(std::move(handle));
+}
+
+// static
+std::unique_ptr<MessagePort> MessagePortFuchsia::Create(
+ fidl::InterfaceRequest<::fuchsia::web::MessagePort> request) {
+ return std::make_unique<MessagePortFuchsiaServer>(std::move(request));
+}
+
+MessagePortFuchsia* MessagePortFuchsia::FromMessagePort(MessagePort* port) {
+ DCHECK(port);
+ // This is safe because there is one MessagePort implementation per platform
+ // and this is called internally to the implementation.
+ return static_cast<MessagePortFuchsia*>(port);
+}
+
+// static
+fuchsia::web::WebMessage MessagePortFuchsia::CreateWebMessage(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) {
+ fuchsia::web::WebMessage message_fidl;
+ message_fidl.set_data(cr_fuchsia::MemBufferFromString(message.as_string(),
+ message.as_string()));
+ if (!ports.empty()) {
+ PortType expected_port_type = FromMessagePort(ports[0].get())->port_type_;
+ std::vector<fuchsia::web::IncomingTransferable> incoming_transferables;
+ std::vector<fuchsia::web::OutgoingTransferable> receiver_transferables;
+ for (auto& port : ports) {
+ MessagePortFuchsia* port_fuchsia = FromMessagePort(port.get());
+ PortType port_type = port_fuchsia->port_type_;
+
+ DCHECK_EQ(expected_port_type, port_type)
+ << "Only one implementation of MessagePortFuchsia can be transmitted "
+ "in the same message.";
+ if (expected_port_type != port_type) {
+ continue;
+ }
+
+ switch (port_type) {
+ case PortType::HANDLE: {
+ fuchsia::web::IncomingTransferable in;
+ in.set_message_port(
+ reinterpret_cast<MessagePortFuchsiaClient*>(port_fuchsia)
+ ->TakeClientHandle());
+ incoming_transferables.emplace_back(std::move(in));
+ break;
+ }
+ case PortType::REQUEST: {
+ fuchsia::web::OutgoingTransferable out;
+ out.set_message_port(
+ reinterpret_cast<MessagePortFuchsiaServer*>(port_fuchsia)
+ ->TakeServiceRequest());
+ receiver_transferables.emplace_back(std::move(out));
+ break;
+ }
+ }
+ }
+
+ message_fidl.set_incoming_transfer(std::move(incoming_transferables));
+ message_fidl.set_outgoing_transfer(std::move(receiver_transferables));
+ }
+
+ return message_fidl;
+}
+
+MessagePortFuchsia::MessagePortFuchsia(PortType port_type)
+ : receiver_(nullptr), port_type_(port_type) {}
+MessagePortFuchsia::~MessagePortFuchsia() = default;
+
+base::Optional<fuchsia::web::FrameError>
+MessagePortFuchsia::ReceiveMessageFromFidl(fuchsia::web::WebMessage message) {
+ DCHECK(receiver_);
+ if (!message.has_data()) {
+ return fuchsia::web::FrameError::NO_DATA_IN_MESSAGE;
+ }
+
+ std::string data;
+ if (!cr_fuchsia::StringFromMemBuffer(message.data(), &data)) {
+ return fuchsia::web::FrameError::BUFFER_NOT_UTF8;
+ }
+
+ std::vector<std::unique_ptr<MessagePort>> ports;
+ if (message.has_incoming_transfer()) {
+ for (fuchsia::web::IncomingTransferable& transferable :
+ *message.mutable_incoming_transfer()) {
+ ports.emplace_back(Create(std::move(transferable.message_port())));
+ }
+ }
+
+ if (message.mutable_outgoing_transfer()) {
+ for (fuchsia::web::OutgoingTransferable& transferable :
+ *message.mutable_outgoing_transfer()) {
+ ports.emplace_back(Create(std::move(transferable.message_port())));
+ }
+ }
+
+ if (!receiver_->OnMessage(std::move(data), std::move(ports))) {
+ return fuchsia::web::FrameError::INTERNAL_ERROR;
+ }
+
+ return base::nullopt;
+}
+
+void MessagePortFuchsia::OnZxError(zx_status_t status) {
+ ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED && status != ZX_ERR_CANCELED,
+ status)
+ << " MessagePort disconnected.";
+ ReportPipeError();
+}
+
+void MessagePortFuchsia::ReportPipeError() {
+ DCHECK(receiver_);
+ receiver_->OnPipeError();
+}
+
+// cast_api_bindings::MessagePortFuchsia implementation
+bool MessagePortFuchsia::PostMessage(base::StringPiece message) {
+ return PostMessageWithTransferables(message, {});
+}
+
+bool MessagePortFuchsia::PostMessageWithTransferables(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) {
+ DCHECK(receiver_);
+ message_queue_.emplace_back(CreateWebMessage(message, std::move(ports)));
+
+ // Start draining the queue if it was empty beforehand.
+ if (message_queue_.size() == 1u) {
+ DeliverMessageToFidl();
+ }
+
+ return true;
+}
+
+} // namespace cast_api_bindings
diff --git a/chromium/components/cast/message_port/message_port_fuchsia.h b/chromium/components/cast/message_port/message_port_fuchsia.h
new file mode 100644
index 00000000000..f1b2a5e3e0a
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port_fuchsia.h
@@ -0,0 +1,87 @@
+// Copyright 2020 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_CAST_MESSAGE_PORT_MESSAGE_PORT_FUCHSIA_H_
+#define COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_FUCHSIA_H_
+
+#include <fuchsia/web/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+#include <lib/fidl/cpp/interface_handle.h>
+#include <lib/fidl/cpp/interface_request.h>
+
+#include "base/containers/circular_deque.h"
+#include "components/cast/message_port/message_port.h"
+#include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
+
+namespace cast_api_bindings {
+
+// Implements the MessagePort abstraction for the FIDL interface
+// fuchsia::web::WebMessagePort.
+class MessagePortFuchsia : public cast_api_bindings::MessagePort {
+ public:
+ ~MessagePortFuchsia() override;
+
+ MessagePortFuchsia(const MessagePortFuchsia&) = delete;
+ MessagePortFuchsia& operator=(const MessagePortFuchsia&) = delete;
+
+ static std::unique_ptr<MessagePort> Create(
+ fidl::InterfaceHandle<::fuchsia::web::MessagePort> port);
+ static std::unique_ptr<MessagePort> Create(
+ fidl::InterfaceRequest<::fuchsia::web::MessagePort> port);
+
+ // Gets the implementation of |port| for callers who know its platform type.
+ static MessagePortFuchsia* FromMessagePort(MessagePort* port);
+
+ // Returns the platform-specific port resources and invalidates this object.
+ // The caller is responsible for choosing the take method which is appropriate
+ // to the underlying FIDL resource. Attempting to take the wrong resource will
+ // produce a DCHECK failure.
+ virtual fidl::InterfaceHandle<::fuchsia::web::MessagePort>
+ TakeClientHandle() = 0;
+ virtual fidl::InterfaceRequest<::fuchsia::web::MessagePort>
+ TakeServiceRequest() = 0;
+
+ protected:
+ // Represents whether a MessagePortFuchsia was created from an InterfaceHandle
+ // (PortType::HANDLE) or InterfaceRequest (PortType::REQUEST)
+ enum class PortType {
+ HANDLE = 1,
+ REQUEST = 2,
+ };
+
+ explicit MessagePortFuchsia(PortType port_type);
+
+ // Creates a fuchsia::web::WebMessage containing |message| and transferring
+ // |ports|
+ static fuchsia::web::WebMessage CreateWebMessage(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports);
+
+ // Delivers a message to FIDL from |message_queue_|.
+ virtual void DeliverMessageToFidl() = 0;
+
+ // Receives a |message| from FIDL into |message_queue_|. Returns a value if
+ // an error occurred.
+ base::Optional<fuchsia::web::FrameError> ReceiveMessageFromFidl(
+ fuchsia::web::WebMessage message);
+
+ void OnZxError(zx_status_t status);
+ void ReportPipeError();
+
+ // cast_api_bindings::MessagePort implementation
+ bool PostMessage(base::StringPiece message) final;
+ bool PostMessageWithTransferables(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) final;
+
+ cast_api_bindings::MessagePort::Receiver* receiver_;
+ base::circular_deque<fuchsia::web::WebMessage> message_queue_;
+
+ private:
+ const PortType port_type_;
+};
+
+} // namespace cast_api_bindings
+
+#endif // COMPONENTS_CAST_MESSAGE_PORT_MESSAGE_PORT_FUCHSIA_H_
diff --git a/chromium/components/cast/message_port/message_port_unittest.cc b/chromium/components/cast/message_port/message_port_unittest.cc
new file mode 100644
index 00000000000..0e0f9c722d9
--- /dev/null
+++ b/chromium/components/cast/message_port/message_port_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2020 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/cast/message_port/message_port.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "components/cast/message_port/test_message_port_receiver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_FUCHSIA)
+#include "components/cast/message_port/message_port_fuchsia.h"
+#include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
+#else
+#include "components/cast/message_port/message_port_cast.h" // nogncheck
+#include "third_party/blink/public/common/messaging/web_message_port.h" // nogncheck
+#endif // defined(OS_FUCHSIA)
+
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+namespace cast_api_bindings {
+
+class MessagePortTest : public ::testing::Test {
+ public:
+ MessagePortTest()
+ : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {
+ MessagePort::CreatePair(&client_, &server_);
+ }
+
+ ~MessagePortTest() override = default;
+
+ void SetDefaultReceivers() {
+ client_->SetReceiver(&client_receiver_);
+ server_->SetReceiver(&server_receiver_);
+ }
+
+ // Posts multiple |messages| from |sender| to |receiver| and validates their
+ // arrival order
+ void PostMessages(const std::vector<std::string>& messages,
+ MessagePort* sender,
+ TestMessagePortReceiver* receiver) {
+ for (const auto& message : messages) {
+ sender->PostMessage(message);
+ }
+
+ EXPECT_TRUE(receiver->RunUntilMessageCountEqual(messages.size()));
+ for (size_t i = 0; i < messages.size(); i++) {
+ EXPECT_EQ(receiver->buffer()[i].first, messages[i]);
+ }
+ }
+
+ // Posts a |port| from |sender| to |receiver| and validates its arrival.
+ // Returns the transferred |port|.
+ std::unique_ptr<MessagePort> PostMessageWithTransferables(
+ std::unique_ptr<MessagePort> port,
+ MessagePort* sender,
+ TestMessagePortReceiver* receiver) {
+ std::vector<std::unique_ptr<MessagePort>> ports;
+ ports.emplace_back(std::move(port));
+ sender->PostMessageWithTransferables("", std::move(ports));
+ EXPECT_TRUE(receiver->RunUntilMessageCountEqual(1));
+ EXPECT_EQ(receiver->buffer()[0].second.size(), (size_t)1);
+ return std::move(receiver->buffer()[0].second[0]);
+ }
+
+ void TestPostMessage() {
+ SetDefaultReceivers();
+ PostMessages({"from client"}, client_.get(), &server_receiver_);
+ PostMessages({"from server"}, server_.get(), &client_receiver_);
+ }
+
+ protected:
+ std::unique_ptr<MessagePort> client_;
+ std::unique_ptr<MessagePort> server_;
+ TestMessagePortReceiver client_receiver_;
+ TestMessagePortReceiver server_receiver_;
+
+ private:
+ const base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(MessagePortTest, Close) {
+ SetDefaultReceivers();
+ ASSERT_TRUE(client_->CanPostMessage());
+ ASSERT_TRUE(server_->CanPostMessage());
+
+ server_->Close();
+ client_receiver_.RunUntilDisconnected();
+ ASSERT_FALSE(client_->CanPostMessage());
+ ASSERT_FALSE(server_->CanPostMessage());
+}
+
+TEST_F(MessagePortTest, OnError) {
+ server_receiver_.SetOnMessageResult(false);
+ SetDefaultReceivers();
+ client_->PostMessage("");
+
+#if defined(OS_FUCHSIA)
+ // blink::WebMessagePort reports failure when PostMessage returns false, but
+ // fuchsia::web::MessagePort will not report the error until the port closes
+ server_receiver_.RunUntilMessageCountEqual(1);
+ server_.reset();
+#endif
+
+ client_receiver_.RunUntilDisconnected();
+}
+
+TEST_F(MessagePortTest, PostMessage) {
+ TestPostMessage();
+}
+
+TEST_F(MessagePortTest, PostMessageMultiple) {
+ SetDefaultReceivers();
+ PostMessages({"c1", "c2", "c3"}, client_.get(), &server_receiver_);
+ PostMessages({"s1", "s2", "s3"}, server_.get(), &client_receiver_);
+}
+
+TEST_F(MessagePortTest, PostMessageWithTransferables) {
+ std::unique_ptr<MessagePort> port0;
+ std::unique_ptr<MessagePort> port1;
+ TestMessagePortReceiver port0_receiver;
+ TestMessagePortReceiver port1_receiver;
+ MessagePort::CreatePair(&port0, &port1);
+
+ // If the ports are represented by multiple types as in the case of
+ // MessagePortFuchsia, make sure both are transferrable
+ SetDefaultReceivers();
+ port0 = PostMessageWithTransferables(std::move(port0), client_.get(),
+ &server_receiver_);
+ port1 = PostMessageWithTransferables(std::move(port1), server_.get(),
+ &client_receiver_);
+
+ // Make sure the ports are still usable
+ port0->SetReceiver(&port0_receiver);
+ port1->SetReceiver(&port1_receiver);
+ PostMessages({"from port0"}, port0.get(), &port1_receiver);
+ PostMessages({"from port1"}, port1.get(), &port0_receiver);
+}
+
+TEST_F(MessagePortTest, WrapPlatformPort) {
+ // Initialize ports from the platform type instead of agnostic CreatePair
+#if defined(OS_FUCHSIA)
+ fidl::InterfaceHandle<fuchsia::web::MessagePort> port0;
+ fidl::InterfaceRequest<fuchsia::web::MessagePort> port1 = port0.NewRequest();
+ client_ = MessagePortFuchsia::Create(std::move(port0));
+ server_ = MessagePortFuchsia::Create(std::move(port1));
+#else
+ auto pair = blink::WebMessagePort::CreatePair();
+ client_ = MessagePortCast::Create(std::move(pair.first));
+ server_ = MessagePortCast::Create(std::move(pair.second));
+#endif // defined(OS_FUCHSIA)
+
+ TestPostMessage();
+}
+
+TEST_F(MessagePortTest, UnwrapPlatformPortCast) {
+ // Test unwrapping via TakePort (rewrapped for test methods)
+#if defined(OS_FUCHSIA)
+ client_ = MessagePortFuchsia::Create(
+ MessagePortFuchsia::FromMessagePort(client_.get())->TakeClientHandle());
+ server_ = MessagePortFuchsia::Create(
+ MessagePortFuchsia::FromMessagePort(server_.get())->TakeServiceRequest());
+#else
+ client_ = MessagePortCast::Create(
+ MessagePortCast::FromMessagePort(client_.get())->TakePort());
+ server_ = MessagePortCast::Create(
+ MessagePortCast::FromMessagePort(server_.get())->TakePort());
+#endif // defined(OS_FUCHSIA)
+
+ TestPostMessage();
+}
+
+} // namespace cast_api_bindings
diff --git a/chromium/components/cast/message_port/test_message_port_receiver.cc b/chromium/components/cast/message_port/test_message_port_receiver.cc
new file mode 100644
index 00000000000..6dcacfd0075
--- /dev/null
+++ b/chromium/components/cast/message_port/test_message_port_receiver.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 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/cast/message_port/test_message_port_receiver.h"
+
+#include "base/run_loop.h"
+
+namespace cast_api_bindings {
+
+TestMessagePortReceiver::TestMessagePortReceiver() = default;
+
+TestMessagePortReceiver::~TestMessagePortReceiver() = default;
+
+void TestMessagePortReceiver::SetOnMessageResult(bool result) {
+ on_message_result_ = result;
+}
+
+bool TestMessagePortReceiver::RunUntilMessageCountEqual(size_t message_count) {
+ base::RunLoop run_loop;
+ on_receive_satisfied_ = run_loop.QuitClosure();
+ message_count_target_ = message_count;
+ run_loop.Run();
+ return message_count_target_ == message_count;
+}
+
+void TestMessagePortReceiver::RunUntilDisconnected() {
+ base::RunLoop run_loop;
+ on_disconnect_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+bool TestMessagePortReceiver::OnMessage(
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) {
+ buffer_.push_back(std::make_pair(message.as_string(), std::move(ports)));
+ if (message_count_target_ == buffer_.size()) {
+ DCHECK(on_receive_satisfied_);
+ std::move(on_receive_satisfied_).Run();
+ }
+ return on_message_result_;
+}
+
+void TestMessagePortReceiver::OnPipeError() {
+ if (on_disconnect_)
+ std::move(on_disconnect_).Run();
+}
+
+} // namespace cast_api_bindings
diff --git a/chromium/components/cast/message_port/test_message_port_receiver.h b/chromium/components/cast/message_port/test_message_port_receiver.h
new file mode 100644
index 00000000000..d674d6f6a81
--- /dev/null
+++ b/chromium/components/cast/message_port/test_message_port_receiver.h
@@ -0,0 +1,57 @@
+// Copyright 2020 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_CAST_MESSAGE_PORT_TEST_MESSAGE_PORT_RECEIVER_H_
+#define COMPONENTS_CAST_MESSAGE_PORT_TEST_MESSAGE_PORT_RECEIVER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/strings/string_piece.h"
+#include "components/cast/message_port/message_port.h"
+
+namespace cast_api_bindings {
+
+class TestMessagePortReceiver
+ : public cast_api_bindings::MessagePort::Receiver {
+ public:
+ TestMessagePortReceiver();
+ ~TestMessagePortReceiver() override;
+
+ TestMessagePortReceiver(const TestMessagePortReceiver&) = delete;
+ TestMessagePortReceiver& operator=(const TestMessagePortReceiver&) = delete;
+
+ // Spins a RunLoop until |buffer_| has |message_count| messages.
+ bool RunUntilMessageCountEqual(size_t message_count);
+
+ // Spins a RunLoop until the associated MessagePort is disconnected.
+ void RunUntilDisconnected();
+
+ // Sets the return value of OnMessage
+ void SetOnMessageResult(bool result);
+
+ std::vector<
+ std::pair<std::string, std::vector<std::unique_ptr<MessagePort>>>>&
+ buffer() {
+ return buffer_;
+ }
+
+ private:
+ // MessagePort::Receiver implementation.
+ bool OnMessage(base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) final;
+ void OnPipeError() final;
+
+ std::vector<std::pair<std::string, std::vector<std::unique_ptr<MessagePort>>>>
+ buffer_;
+ size_t message_count_target_ = 0;
+ base::OnceClosure on_receive_satisfied_;
+ base::OnceClosure on_disconnect_;
+ bool on_message_result_ = true;
+};
+
+} // namespace cast_api_bindings
+
+#endif // COMPONENTS_CAST_MESSAGE_PORT_TEST_MESSAGE_PORT_RECEIVER_H_
diff --git a/chromium/components/cast/named_message_port_connector/BUILD.gn b/chromium/components/cast/named_message_port_connector/BUILD.gn
index 6db6a65bf73..be5d969af7c 100644
--- a/chromium/components/cast/named_message_port_connector/BUILD.gn
+++ b/chromium/components/cast/named_message_port_connector/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni")
source_set("named_message_port_connector") {
@@ -13,16 +14,15 @@ source_set("named_message_port_connector") {
deps = [
"//base",
"//components/cast:export",
+ "//components/cast/message_port",
]
- public_deps = [
- ":resources",
- "//third_party/blink/public/common",
- ]
+ public_deps = [ ":resources" ]
}
grit("resources") {
source = "named_message_port_connector_resources.grd"
+ deps = [ ":js_type_check" ]
outputs = [
"grit/named_message_port_connector_resources.h",
"named_message_port_connector_resources.pak",
@@ -31,3 +31,9 @@ grit("resources") {
# Allow GRIT to assign IDs using its default set of base IDs.
resource_ids = ""
}
+
+js_binary("js_type_check") {
+ sources = [ "named_message_port_connector.js" ]
+ checks_only = true
+ closure_flags = strict_error_checking_closure_args
+}
diff --git a/chromium/components/cast/named_message_port_connector/named_message_port_connector.cc b/chromium/components/cast/named_message_port_connector/named_message_port_connector.cc
index 3f5c312f839..d989023564d 100644
--- a/chromium/components/cast/named_message_port_connector/named_message_port_connector.cc
+++ b/chromium/components/cast/named_message_port_connector/named_message_port_connector.cc
@@ -25,35 +25,32 @@ void NamedMessagePortConnector::RegisterPortHandler(
// Receives the MessagePort and forwards ports to their corresponding binding
// handlers.
bool NamedMessagePortConnector::OnMessage(
- blink::WebMessagePort::Message message) {
- if (message.ports.size() != 1) {
+ base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) {
+ if (ports.size() != 1) {
DLOG(FATAL) << "Only one control port should be provided";
return false;
}
// Read the port ID.
- base::string16 data_utf16 = std::move(message.data);
- std::string binding_id;
- if (!base::UTF16ToUTF8(data_utf16.data(), data_utf16.size(), &binding_id))
+ if (message.empty()) {
+ DLOG(FATAL) << "No port ID was specified.";
return false;
+ }
- return handler_.Run(binding_id, std::move(message.ports[0]));
+ return handler_.Run(message, std::move(ports[0]));
}
-blink::WebMessagePort::Message NamedMessagePortConnector::GetConnectMessage() {
- constexpr char kControlPortConnectMessage[] = "cast.master.connect";
-
- // Pass the control message port into the page as an HTML5 MessageChannel
- // message.
- auto port_pair = blink::WebMessagePort::CreatePair();
+void NamedMessagePortConnector::OnPipeError() {}
- control_port_ = std::move(port_pair.first);
- control_port_.SetReceiver(this, base::ThreadTaskRunnerHandle::Get());
-
- blink::WebMessagePort::Message connect_message;
- connect_message.data = base::UTF8ToUTF16(kControlPortConnectMessage);
- connect_message.ports.push_back(std::move(port_pair.second));
- return connect_message;
+void NamedMessagePortConnector::GetConnectMessage(
+ std::string* message,
+ std::unique_ptr<MessagePort>* port) {
+ constexpr char kControlPortConnectMessage[] = "cast.master.connect";
+ std::unique_ptr<MessagePort> control_port_for_web_engine;
+ MessagePort::CreatePair(&control_port_, port);
+ *message = kControlPortConnectMessage;
+ control_port_->SetReceiver(this);
}
} // namespace cast_api_bindings
diff --git a/chromium/components/cast/named_message_port_connector/named_message_port_connector.h b/chromium/components/cast/named_message_port_connector/named_message_port_connector.h
index 6ebe36e8e1c..93ce32b7a96 100644
--- a/chromium/components/cast/named_message_port_connector/named_message_port_connector.h
+++ b/chromium/components/cast/named_message_port_connector/named_message_port_connector.h
@@ -7,7 +7,7 @@
#include "base/callback.h"
#include "base/strings/string_piece.h"
-#include "third_party/blink/public/common/messaging/web_message_port.h"
+#include "components/cast/message_port/message_port.h"
namespace cast_api_bindings {
@@ -16,15 +16,13 @@ namespace cast_api_bindings {
// Platform specific details, such as how the script resources are injected, and
// how the connection message is posted to the page, are delegated to the
// caller.
-// TODO(crbug.com/1126571): Migrate off Blink::WebMessagePort to a
-// platform-agnostic MessagePort abstraction.
-class NamedMessagePortConnector
- : public blink::WebMessagePort::MessageReceiver {
+class NamedMessagePortConnector : public MessagePort::Receiver {
public:
// Signature of callback to be invoked when a port is connected.
// The callback should return true if the connection request was valid.
using PortConnectedCallback =
- base::RepeatingCallback<bool(base::StringPiece, blink::WebMessagePort)>;
+ base::RepeatingCallback<bool(base::StringPiece,
+ std::unique_ptr<MessagePort>)>;
NamedMessagePortConnector();
~NamedMessagePortConnector() override;
@@ -36,17 +34,20 @@ class NamedMessagePortConnector
// Sets the callback which will be invoked when a port is connected.
void RegisterPortHandler(PortConnectedCallback handler);
- // Returns a connection message which should be posted to the page on
- // every navigation.
- // Calling this method will drop any preexisting connections made to the page.
- blink::WebMessagePort::Message GetConnectMessage();
+ // Returns a data payload and MessagePort which, when posted into a web
+ // content main frame, will establish a connection between |this| and the
+ // NamedMessagePortConnector JavaScript module.
+ void GetConnectMessage(std::string* message,
+ std::unique_ptr<MessagePort>* port);
private:
- // blink::WebMessagePort::MessageReceiver implementation:
- bool OnMessage(blink::WebMessagePort::Message message) override;
+ // MessagePort::Receiver implementation.
+ bool OnMessage(base::StringPiece message,
+ std::vector<std::unique_ptr<MessagePort>> ports) final;
+ void OnPipeError() final;
PortConnectedCallback handler_;
- blink::WebMessagePort control_port_;
+ std::unique_ptr<MessagePort> control_port_;
};
} // namespace cast_api_bindings
diff --git a/chromium/components/cast/named_message_port_connector/named_message_port_connector.js b/chromium/components/cast/named_message_port_connector/named_message_port_connector.js
index 6ce9a3ec75c..53913adc42d 100644
--- a/chromium/components/cast/named_message_port_connector/named_message_port_connector.js
+++ b/chromium/components/cast/named_message_port_connector/named_message_port_connector.js
@@ -4,34 +4,48 @@
'use strict';
-if (!cast) {
+if (!window['cast']) {
+ /**
+ * @const
+ */
// eslint-disable-next-line no-var
var cast = new Object;
}
-if (!cast.__platform__) {
- cast.__platform__ = new Object;
+if (!cast['__platform__']) {
+ /**
+ * @const
+ */
+ cast.__platform__ = {};
}
// Creates named HTML5 MessagePorts that are connected to native code.
cast.__platform__.PortConnector = new class {
constructor() {
+ /** @private {MessagePort} */
this.controlPort_ = null;
// A map of ports waiting to be published to the controlPort_, keyed by
// string IDs.
+ /** @private {Object<string, MessagePort>} */
this.pendingPorts_ = {};
+ /** @private */
this.listener = this.onMessageEvent.bind(this);
+
window.addEventListener(
'message', this.listener,
true // Let the listener handle events before they hit the DOM tree.
);
}
- // Returns a MessagePort whose channel will be passed to the native code.
- // The channel can be used immediately after construction. Outgoing messages
- // will be automatically buffered until the connection is established.
+ /**
+ * Returns a MessagePort whose channel will be passed to the native code.
+ * The channel can be used immediately after construction. Outgoing messages
+ * will be automatically buffered until the connection is established.
+ * @param {string} id The ID of the port being registered.
+ * @return {MessagePort}
+ */
bind(id) {
const channel = new MessageChannel();
if (this.controlPort_) {
@@ -43,33 +57,43 @@ cast.__platform__.PortConnector = new class {
return channel.port1;
}
+ /**
+ * Sends a MessagePort to the remote NamedMessagePortConnector.
+ * @param {string} portId The name of the port to send over the control port.
+ * @param {MessagePort} port The port being sent.
+ */
sendPort(portId, port) {
this.controlPort_.postMessage(portId, [port]);
}
- // Receives a control port from native code.
- onMessageEvent(e) {
+ /**
+ * Handles frame message events to receive a connection "control port" from
+ * native code.
+ * @param {Event} messageEvent
+ */
+ onMessageEvent(messageEvent) {
// Only process window.onmessage events which are intended for this class.
- if (e.data != 'cast.master.connect') {
+ if (messageEvent.data != 'cast.master.connect') {
return;
}
- if (e.ports.length != 1) {
+ if (messageEvent.ports.length != 1) {
console.error(
- 'Expected only one MessagePort, got ' + e.ports.length + ' instead.');
- for (const i in e.ports) {
- e.ports[i].close();
+ 'Expected only one MessagePort, got ' + messageEvent.ports.length +
+ ' instead.');
+ for (const port of messageEvent.ports) {
+ port.close();
}
return;
}
- this.controlPort_ = e.ports[0];
+ this.controlPort_ = messageEvent.ports[0];
for (const portId in this.pendingPorts_) {
this.sendPort(portId, this.pendingPorts_[portId]);
}
this.pendingPorts_ = null;
- e.stopPropagation();
+ messageEvent.stopPropagation();
// No need to receive more onmessage events.
window.removeEventListener('message', this.listener);
diff --git a/chromium/components/cast_certificate/BUILD.gn b/chromium/components/cast_certificate/BUILD.gn
index 6332342efb5..2e67a689662 100644
--- a/chromium/components/cast_certificate/BUILD.gn
+++ b/chromium/components/cast_certificate/BUILD.gn
@@ -2,6 +2,29 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+declare_args() {
+ # Allow use of custom Cast root certificate for authentication.
+ cast_allow_developer_certificate = false
+}
+
+config("certificate_config") {
+ defines = []
+ if (cast_allow_developer_certificate) {
+ defines += [ "CAST_ALLOW_DEVELOPER_CERTIFICATE" ]
+ }
+}
+
+source_set("cast_certificate_reader") {
+ sources = [
+ "cast_cert_reader.cc",
+ "cast_cert_reader.h",
+ ]
+ deps = [
+ "//base",
+ "//net",
+ ]
+}
+
static_library("cast_certificate") {
sources = [
"cast_cert_validator.cc",
@@ -11,21 +34,34 @@ static_library("cast_certificate") {
"cast_root_ca_cert_der-inc.h",
"eureka_root_ca_der-inc.h",
]
+ configs += [ ":certificate_config" ]
deps = [
"//base",
"//net",
"//third_party/openscreen/src/cast/common/certificate/proto:certificate_proto",
+
+ # Although we won't use the reader unless cast_allow_developer_certificate
+ # is enabled, the buildfiles generation step requires the inclusion
+ # anyway since it doesn't check preprocesser macros.
+ ":cast_certificate_reader",
]
+ if (cast_allow_developer_certificate) {
+ sources += [
+ "switches.cc",
+ "switches.h",
+ ]
+ }
}
static_library("test_support") {
testonly = true
sources = [
- "cast_cert_validator_test_helpers.cc",
- "cast_cert_validator_test_helpers.h",
+ "cast_cert_test_helpers.cc",
+ "cast_cert_test_helpers.h",
]
deps = [
":cast_certificate",
+ ":cast_certificate_reader",
"//base",
"//net",
"//testing/gtest",
@@ -41,8 +77,10 @@ source_set("unit_tests") {
]
deps = [
":cast_certificate",
+ ":cast_certificate_reader",
":test_support",
"//base",
+ "//base/test:test_support",
"//net",
"//testing/gtest",
"//third_party/openscreen/src/cast/common/certificate/proto:certificate_unittest_proto",
diff --git a/chromium/components/cast_certificate/DEPS b/chromium/components/cast_certificate/DEPS
index cdbad50b255..fb9b28a5d80 100644
--- a/chromium/components/cast_certificate/DEPS
+++ b/chromium/components/cast_certificate/DEPS
@@ -2,4 +2,4 @@ include_rules = [
"+crypto",
"+net",
"+third_party/openscreen/src/cast/common/certificate/proto",
-]
+] \ No newline at end of file
diff --git a/chromium/components/cast_certificate/cast_cert_reader.cc b/chromium/components/cast_certificate/cast_cert_reader.cc
new file mode 100644
index 00000000000..3f3186f4c4d
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_cert_reader.cc
@@ -0,0 +1,55 @@
+// Copyright 2020 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/cast_certificate/cast_cert_reader.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "net/cert/internal/common_cert_errors.h"
+#include "net/cert/pem.h"
+#include "net/cert/x509_util.h"
+
+namespace cast_certificate {
+
+bool PopulateStoreWithCertsFromPath(net::TrustStoreInMemory* store,
+ const base::FilePath& path) {
+ const std::vector<std::string> trusted_roots =
+ ReadCertificateChainFromFile(path);
+
+ for (const auto& trusted_root : trusted_roots) {
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert(net::ParsedCertificate::Create(
+ net::x509_util::CreateCryptoBuffer(trusted_root), {}, &errors));
+
+ if (errors.ContainsAnyErrorWithSeverity(
+ net::CertError::Severity::SEVERITY_HIGH)) {
+ LOG(ERROR) << "Failed to load cert due to following error(s): "
+ << errors.ToDebugString();
+ return false;
+ }
+ store->AddTrustAnchorWithConstraints(cert);
+ }
+ return true;
+}
+
+std::vector<std::string> ReadCertificateChainFromFile(
+ const base::FilePath& path) {
+ std::string file_data;
+ if (!base::ReadFileToString(path, &file_data)) {
+ LOG(ERROR) << "Failed to read certificate chain from file: " << path;
+ return {};
+ }
+
+ std::vector<std::string> pem_headers;
+ pem_headers.push_back("CERTIFICATE");
+
+ std::vector<std::string> certs;
+ net::PEMTokenizer pem_tokenizer(file_data, pem_headers);
+ while (pem_tokenizer.GetNext())
+ certs.push_back(pem_tokenizer.data());
+
+ return certs;
+}
+
+} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_cert_reader.h b/chromium/components/cast_certificate/cast_cert_reader.h
new file mode 100644
index 00000000000..bb84520cd4e
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_cert_reader.h
@@ -0,0 +1,28 @@
+// Copyright 2020 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_CAST_CERTIFICATE_CAST_CERT_READER_H_
+#define COMPONENTS_CAST_CERTIFICATE_CAST_CERT_READER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+
+namespace cast_certificate {
+
+// Creates a trust store using the test roots encoded in the PEM file at |path|.
+bool PopulateStoreWithCertsFromPath(net::TrustStoreInMemory* store,
+ const base::FilePath& path);
+
+// Reads a PEM file located at |path|, containing certificates to a vector of
+// their DER data.
+std::vector<std::string> ReadCertificateChainFromFile(
+ const base::FilePath& path);
+
+} // namespace cast_certificate
+
+#endif // COMPONENTS_CAST_CERTIFICATE_CAST_CERT_READER_H_
diff --git a/chromium/components/cast_certificate/cast_cert_test_helpers.cc b/chromium/components/cast_certificate/cast_cert_test_helpers.cc
new file mode 100644
index 00000000000..89440ad2512
--- /dev/null
+++ b/chromium/components/cast_certificate/cast_cert_test_helpers.cc
@@ -0,0 +1,89 @@
+// Copyright 2020 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/cast_certificate/cast_cert_test_helpers.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/pem.h"
+#include "net/cert/x509_util.h"
+
+namespace cast_certificate {
+namespace testing {
+
+namespace {
+
+// Test cast certificate directory, relative to source root.
+constexpr base::FilePath::CharType kCastCertsRelativePath[] =
+ FILE_PATH_LITERAL("components/test/data/cast_certificate");
+
+} // namespace
+
+base::FilePath GetCastTestCertsDirectory() {
+ base::FilePath src_root;
+ {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+ }
+
+ return src_root.Append(kCastCertsRelativePath);
+}
+
+base::FilePath GetCastTestCertsCertsDirectory() {
+ return GetCastTestCertsDirectory().AppendASCII("certificates");
+}
+
+SignatureTestData ReadSignatureTestData(const base::StringPiece& file_name) {
+ SignatureTestData result;
+
+ std::string file_data;
+ base::ReadFileToString(GetCastTestCertsDirectory().AppendASCII(file_name),
+ &file_data);
+ CHECK(!file_data.empty());
+
+ std::vector<std::string> pem_headers;
+ pem_headers.push_back("MESSAGE");
+ pem_headers.push_back("SIGNATURE SHA1");
+ pem_headers.push_back("SIGNATURE SHA256");
+
+ net::PEMTokenizer pem_tokenizer(file_data, pem_headers);
+ while (pem_tokenizer.GetNext()) {
+ const std::string& type = pem_tokenizer.block_type();
+ const std::string& value = pem_tokenizer.data();
+
+ if (type == "MESSAGE") {
+ result.message = value;
+ } else if (type == "SIGNATURE SHA1") {
+ result.signature_sha1 = value;
+ } else if (type == "SIGNATURE SHA256") {
+ result.signature_sha256 = value;
+ }
+ }
+
+ CHECK(!result.message.empty());
+ CHECK(!result.signature_sha1.empty());
+ CHECK(!result.signature_sha256.empty());
+
+ return result;
+}
+
+base::Time ConvertUnixTimestampSeconds(uint64_t time) {
+ return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(time);
+}
+
+std::unique_ptr<net::TrustStoreInMemory> LoadTestCert(
+ const base::StringPiece& cert_file_name) {
+ auto store = std::make_unique<net::TrustStoreInMemory>();
+ CHECK(PopulateStoreWithCertsFromPath(
+ store.get(),
+ testing::GetCastTestCertsCertsDirectory().AppendASCII(cert_file_name)));
+ CHECK(store);
+ return store;
+}
+} // namespace testing
+} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h b/chromium/components/cast_certificate/cast_cert_test_helpers.h
index abd0751b54d..06b51f553a3 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.h
+++ b/chromium/components/cast_certificate/cast_cert_test_helpers.h
@@ -1,30 +1,27 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2020 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_CAST_CERTIFICATE_CAST_CERT_VALIDATOR_TEST_HELPERS_H_
-#define COMPONENTS_CAST_CERTIFICATE_CAST_CERT_VALIDATOR_TEST_HELPERS_H_
+#ifndef COMPONENTS_CAST_CERTIFICATE_CAST_CERT_TEST_HELPERS_H_
+#define COMPONENTS_CAST_CERTIFICATE_CAST_CERT_TEST_HELPERS_H_
#include <memory>
#include <string>
#include <vector>
+#include "base/files/file_path.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "net/cert/internal/trust_store_in_memory.h"
-namespace net {
-class TrustStoreInMemory;
-}
-
namespace cast_certificate {
-
namespace testing {
-// Reads a PEM file containing certificates to a vector of their DER data.
-// |file_name| should be relative to //components/test/data/cast_certificate
-std::vector<std::string> ReadCertificateChainFromFile(
- const base::StringPiece& file_name);
+// Returns components/test/data/cast_certificates
+base::FilePath GetCastTestCertsDirectory();
+
+// Returns components/test/data/cast_certificates/certificates
+base::FilePath GetCastTestCertsCertsDirectory();
// Helper structure that describes a message and its various signatures.
struct SignatureTestData {
@@ -42,19 +39,15 @@ struct SignatureTestData {
// |file_name| should be relative to //components/test/data/cast_certificate
SignatureTestData ReadSignatureTestData(const base::StringPiece& file_name);
-// Reads a file from the test data directory
-// (//src/components/test/data/cast_certificate)
-std::string ReadTestFileToString(const base::StringPiece& file_name);
-
-// Creates a trust store using the test roots encoded in the PEM file at |path|.
-std::unique_ptr<net::TrustStoreInMemory> CreateTrustStoreFromFile(
- const std::string& path);
-
// Converts uint64_t unix timestamp in seconds to base::Time.
base::Time ConvertUnixTimestampSeconds(uint64_t time);
-} // namespace testing
+// Helper method that loads a certificate from the test certificates folder and
+// places it in an heap allocated trust store.
+std::unique_ptr<net::TrustStoreInMemory> LoadTestCert(
+ const base::StringPiece& cert_file_name);
+} // namespace testing
} // namespace cast_certificate
-#endif // COMPONENTS_CAST_CERTIFICATE_CAST_CERT_VALIDATOR_TEST_HELPERS_H_
+#endif // COMPONENTS_CAST_CERTIFICATE_CAST_CERT_TEST_HELPERS_H_
diff --git a/chromium/components/cast_certificate/cast_cert_validator.cc b/chromium/components/cast_certificate/cast_cert_validator.cc
index 6cf222ade50..85babbf5a90 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator.cc
@@ -11,8 +11,12 @@
#include <memory>
#include <utility>
-#include "base/memory/singleton.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/stl_util.h"
+#include "base/synchronization/lock.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "components/cast_certificate/cast_crl.h"
#include "net/cert/internal/cert_issuer_source_static.h"
#include "net/cert/internal/certificate_policies.h"
@@ -26,10 +30,18 @@
#include "net/cert/internal/simple_path_builder_delegate.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "net/cert/internal/verify_signed_data.h"
+#include "net/cert/pem.h"
#include "net/cert/x509_util.h"
#include "net/der/encode_values.h"
#include "net/der/input.h"
+// Used specifically when CAST_ALLOW_DEVELOPER_CERTIFICATE is true:
+#include "base/command_line.h"
+#include "base/memory/weak_ptr.h"
+#include "base/path_service.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "components/cast_certificate/switches.h"
+
namespace cast_certificate {
namespace {
@@ -51,22 +63,57 @@ namespace {
#include "components/cast_certificate/cast_root_ca_cert_der-inc.h"
#include "components/cast_certificate/eureka_root_ca_der-inc.h"
-// Singleton for the Cast trust store.
class CastTrustStore {
public:
- static CastTrustStore* GetInstance() {
- return base::Singleton<CastTrustStore,
- base::LeakySingletonTraits<CastTrustStore>>::get();
+ using AccessCallback = base::OnceCallback<void(net::TrustStore*)>;
+ static void AccessInstance(AccessCallback callback) {
+ CastTrustStore* instance = GetInstance();
+ const base::AutoLock guard(instance->lock_);
+ std::move(callback).Run(&instance->store_);
}
- static net::TrustStore& Get() { return GetInstance()->store_; }
-
private:
- friend struct base::DefaultSingletonTraits<CastTrustStore>;
+ friend class base::NoDestructor<CastTrustStore>;
+
+ static CastTrustStore* GetInstance() {
+ static base::NoDestructor<CastTrustStore> instance;
+ return instance.get();
+ }
CastTrustStore() {
AddAnchor(kCastRootCaDer);
AddAnchor(kEurekaRootCaDer);
+
+ // Adding developer certificates must be done off of the IO thread due
+ // to blocking file access.
+#if defined(CAST_ALLOW_DEVELOPER_CERTIFICATE)
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::MayBlock()},
+ // NOTE: the singleton instance is never destroyed, so we can use
+ // Unretained here instead of a weak pointer.
+ base::BindOnce(&CastTrustStore::AddDeveloperCertificates,
+ base::Unretained(this)));
+ }
+
+ // Check for custom root developer certificate and create a trust store
+ // from it if present and enabled.
+ void AddDeveloperCertificates() {
+ base::AutoLock guard(lock_);
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ std::string cert_path = command_line->GetSwitchValueASCII(
+ switches::kCastDeveloperCertificatePath);
+ if (!cert_path.empty()) {
+ base::FilePath path;
+ base::PathService::Get(base::DIR_CURRENT, &path);
+ path = path.Append(cert_path);
+ VLOG(1) << "Using cast developer certificate path=" << cert_path
+ << ", processed as: " << path;
+ if (!PopulateStoreWithCertsFromPath(&store_, path)) {
+ LOG(WARNING) << "No developer certs added to store, only official"
+ "Google root CA certificates will work.";
+ }
+ }
+#endif
}
// Adds a trust anchor given a DER-encoded certificate from static
@@ -79,10 +126,12 @@ class CastTrustStore {
&errors);
CHECK(cert) << errors.ToDebugString();
// Enforce pathlen constraints and policies defined on the root certificate.
+ base::AutoLock guard(lock_);
store_.AddTrustAnchorWithConstraints(std::move(cert));
}
- net::TrustStoreInMemory store_;
+ base::Lock lock_;
+ net::TrustStoreInMemory store_ GUARDED_BY(lock_);
DISALLOW_COPY_AND_ASSIGN(CastTrustStore);
};
@@ -258,8 +307,17 @@ CastCertError VerifyDeviceCert(
CastDeviceCertPolicy* policy,
const CastCRL* crl,
CRLPolicy crl_policy) {
- return VerifyDeviceCertUsingCustomTrustStore(
- certs, time, context, policy, crl, crl_policy, &CastTrustStore::Get());
+ CastCertError verification_result;
+ CastTrustStore::AccessInstance(base::BindOnce(
+ [](const std::vector<std::string>& certs, const base::Time& time,
+ std::unique_ptr<CertVerificationContext>* context,
+ CastDeviceCertPolicy* policy, const CastCRL* crl, CRLPolicy crl_policy,
+ CastCertError* result, net::TrustStore* store) {
+ *result = VerifyDeviceCertUsingCustomTrustStore(
+ certs, time, context, policy, crl, crl_policy, store);
+ },
+ certs, time, context, policy, crl, crl_policy, &verification_result));
+ return verification_result;
}
CastCertError VerifyDeviceCertUsingCustomTrustStore(
diff --git a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
deleted file mode 100644
index 961a037db79..00000000000
--- a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
-
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "net/cert/internal/cert_errors.h"
-#include "net/cert/pem.h"
-#include "net/cert/x509_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cast_certificate {
-
-namespace testing {
-
-std::string ReadTestFileToString(const base::StringPiece& file_name) {
- base::FilePath filepath;
- base::PathService::Get(base::DIR_SOURCE_ROOT, &filepath);
- filepath = filepath.Append(FILE_PATH_LITERAL("components"));
- filepath = filepath.Append(FILE_PATH_LITERAL("test"));
- filepath = filepath.Append(FILE_PATH_LITERAL("data"));
- filepath = filepath.Append(FILE_PATH_LITERAL("cast_certificate"));
- filepath = filepath.AppendASCII(file_name);
-
- // Read the full contents of the file.
- std::string file_data;
- if (!base::ReadFileToString(filepath, &file_data)) {
- ADD_FAILURE() << "Couldn't read file: " << filepath.value();
- return std::string();
- }
-
- return file_data;
-}
-
-std::vector<std::string> ReadCertificateChainFromFile(
- const base::StringPiece& file_name) {
- std::string file_data = ReadTestFileToString(file_name);
-
- std::vector<std::string> pem_headers;
- pem_headers.push_back("CERTIFICATE");
-
- std::vector<std::string> certs;
- net::PEMTokenizer pem_tokenizer(file_data, pem_headers);
- while (pem_tokenizer.GetNext())
- certs.push_back(pem_tokenizer.data());
-
- EXPECT_FALSE(certs.empty());
- return certs;
-}
-
-SignatureTestData ReadSignatureTestData(const base::StringPiece& file_name) {
- SignatureTestData result;
-
- std::string file_data = ReadTestFileToString(file_name);
- EXPECT_FALSE(file_data.empty());
-
- std::vector<std::string> pem_headers;
- pem_headers.push_back("MESSAGE");
- pem_headers.push_back("SIGNATURE SHA1");
- pem_headers.push_back("SIGNATURE SHA256");
-
- net::PEMTokenizer pem_tokenizer(file_data, pem_headers);
- while (pem_tokenizer.GetNext()) {
- const std::string& type = pem_tokenizer.block_type();
- const std::string& value = pem_tokenizer.data();
-
- if (type == "MESSAGE") {
- result.message = value;
- } else if (type == "SIGNATURE SHA1") {
- result.signature_sha1 = value;
- } else if (type == "SIGNATURE SHA256") {
- result.signature_sha256 = value;
- }
- }
-
- EXPECT_FALSE(result.message.empty());
- EXPECT_FALSE(result.signature_sha1.empty());
- EXPECT_FALSE(result.signature_sha256.empty());
-
- return result;
-}
-
-std::unique_ptr<net::TrustStoreInMemory> CreateTrustStoreFromFile(
- const std::string& path) {
- std::unique_ptr<net::TrustStoreInMemory> trust_store(
- new net::TrustStoreInMemory());
- const auto trusted_test_roots =
- cast_certificate::testing::ReadCertificateChainFromFile(path);
- for (const auto& trusted_root : trusted_test_roots) {
- net::CertErrors errors;
- scoped_refptr<net::ParsedCertificate> cert(net::ParsedCertificate::Create(
- net::x509_util::CreateCryptoBuffer(trusted_root), {}, &errors));
- EXPECT_TRUE(cert) << errors.ToDebugString();
- trust_store->AddTrustAnchorWithConstraints(cert);
- }
- return trust_store;
-}
-
-base::Time ConvertUnixTimestampSeconds(uint64_t time) {
- return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(time);
-}
-
-} // namespace testing
-
-} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
index 53dfd0ad791..3b8da502a17 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator_unittest.cc
@@ -4,7 +4,9 @@
#include "components/cast_certificate/cast_cert_validator.h"
-#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
+#include "base/test/task_environment.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "components/cast_certificate/cast_cert_test_helpers.h"
#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/signature_algorithm.h"
@@ -61,8 +63,9 @@ void RunTest(CastCertError expected_result,
const base::Time& time,
TrustStoreDependency trust_store_dependency,
const std::string& optional_signed_data_file_name) {
- auto certs =
- cast_certificate::testing::ReadCertificateChainFromFile(certs_file_name);
+ base::test::TaskEnvironment te;
+ auto certs = ReadCertificateChainFromFile(
+ testing::GetCastTestCertsCertsDirectory().AppendASCII(certs_file_name));
std::unique_ptr<net::TrustStoreInMemory> trust_store;
@@ -188,8 +191,8 @@ base::Time MarchFirst2037() {
// Eureka Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
RunTest(CastCertError::OK, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
- "certificates/chromecast_gen1.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ "chromecast_gen1.pem", AprilFirst2016(), TRUST_STORE_BUILTIN,
+ "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -201,8 +204,8 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1) {
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
RunTest(CastCertError::OK, "2ZZBG9 FA8FCA3EF91A", CastDeviceCertPolicy::NONE,
- "certificates/chromecast_gen1_reissue.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
+ "chromecast_gen1_reissue.pem", AprilFirst2016(), TRUST_STORE_BUILTIN,
+ "signeddata/2ZZBG9_FA8FCA3EF91A.pem");
}
// Tests verifying a valid certificate chain of length 2:
@@ -214,8 +217,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen1Reissue) {
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
RunTest(CastCertError::OK, "3ZZAK6 FA8FCA3F0D35", CastDeviceCertPolicy::NONE,
- "certificates/chromecast_gen2.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "");
+ "chromecast_gen2.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 3:
@@ -228,7 +230,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2) {
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Fugu) {
RunTest(CastCertError::OK, "-6394818897508095075", CastDeviceCertPolicy::NONE,
- "certificates/fugu.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+ "fugu.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying an invalid certificate chain of length 1:
@@ -241,8 +243,8 @@ TEST(VerifyCastDeviceCertTest, Fugu) {
// This is invalid because it does not chain to a trust anchor.
TEST(VerifyCastDeviceCertTest, Unchained) {
RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "",
- CastDeviceCertPolicy::NONE, "certificates/unchained.pem",
- AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+ CastDeviceCertPolicy::NONE, "unchained.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying one of the self-signed trust anchors (chain of length 1):
@@ -257,8 +259,7 @@ TEST(VerifyCastDeviceCertTest, Unchained) {
// certificate*.
TEST(VerifyCastDeviceCertTest, CastRootCa) {
RunTest(CastCertError::ERR_CERTS_RESTRICTIONS, "", CastDeviceCertPolicy::NONE,
- "certificates/cast_root_ca.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "");
+ "cast_root_ca.pem", AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2:
@@ -273,7 +274,7 @@ TEST(VerifyCastDeviceCertTest, CastRootCa) {
// devices.
TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
RunTest(CastCertError::OK, "4ZZDZJ FA8FCA7EFE3C",
- CastDeviceCertPolicy::AUDIO_ONLY, "certificates/chromecast_audio.pem",
+ CastDeviceCertPolicy::AUDIO_ONLY, "chromecast_audio.pem",
AprilFirst2016(), TRUST_STORE_BUILTIN, "");
}
@@ -290,7 +291,7 @@ TEST(VerifyCastDeviceCertTest, ChromecastAudio) {
// devices.
TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
RunTest(CastCertError::OK, "MediaTek Audio Dev Test",
- CastDeviceCertPolicy::AUDIO_ONLY, "certificates/mtk_audio_dev.pem",
+ CastDeviceCertPolicy::AUDIO_ONLY, "mtk_audio_dev.pem",
JanuaryFirst2015(), TRUST_STORE_BUILTIN, "");
}
@@ -303,14 +304,14 @@ TEST(VerifyCastDeviceCertTest, MtkAudioDev) {
// Cast Root CA (built-in trust store)
TEST(VerifyCastDeviceCertTest, Vizio) {
RunTest(CastCertError::OK, "9V0000VB FA8FCA784D01",
- CastDeviceCertPolicy::NONE, "certificates/vizio.pem",
- AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+ CastDeviceCertPolicy::NONE, "vizio.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2 using expired
// time points.
TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
- const char* kCertsFile = "certificates/chromecast_gen2.pem";
+ const char* kCertsFile = "chromecast_gen2.pem";
// Control test - certificate should be valid at some time otherwise
// this test is pointless.
@@ -339,9 +340,9 @@ TEST(VerifyCastDeviceCertTest, ChromecastGen2InvalidTime) {
// devices.
TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
RunTest(CastCertError::OK, "Audio Reference Dev Test",
- CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/audio_ref_dev_test_chain_3.pem", AprilFirst2016(),
- TRUST_STORE_BUILTIN, "signeddata/AudioReferenceDevTest.pem");
+ CastDeviceCertPolicy::AUDIO_ONLY, "audio_ref_dev_test_chain_3.pem",
+ AprilFirst2016(), TRUST_STORE_BUILTIN,
+ "signeddata/AudioReferenceDevTest.pem");
}
// Tests verifying a valid certificate chain of length 3. Note that the first
@@ -361,8 +362,8 @@ TEST(VerifyCastDeviceCertTest, AudioRefDevTestChain3) {
TEST(VerifyCastDeviceCertTest, IntermediateSerialNumberTooLong) {
RunTest(CastCertError::OK, "8C579B806FFC8A9DFFFF F8:8F:CA:6B:E6:DA",
CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/intermediate_serialnumber_toolong.pem",
- AprilFirst2016(), TRUST_STORE_BUILTIN, "");
+ "intermediate_serialnumber_toolong.pem", AprilFirst2016(),
+ TRUST_STORE_BUILTIN, "");
}
// Tests verifying a valid certificate chain of length 2 when the trust anchor
@@ -378,8 +379,7 @@ TEST(VerifyCastDeviceCertTest, ExpiredTrustAnchor) {
// The root certificate is only valid in 2015, so validating with a time in
// 2016 means it is expired.
RunTest(CastCertError::OK, "CastDevice", CastDeviceCertPolicy::NONE,
- "certificates/expired_root.pem", AprilFirst2016(),
- TRUST_STORE_FROM_TEST_FILE, "");
+ "expired_root.pem", AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
// Tests verifying a certificate chain where the root certificate has a pathlen
@@ -399,15 +399,14 @@ TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
// First do a control test -- when anchor constraints are NOT enforced this
// chain should validate just fine.
RunTest(CastCertError::OK, "Target", CastDeviceCertPolicy::NONE,
- "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
+ "violates_root_pathlen_constraint.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE_UNCONSTRAINED, "");
// Now do the real test and verify validation fails when using a TrustAncho
// with pathlen constraint.
RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "Target",
- CastDeviceCertPolicy::NONE,
- "certificates/violates_root_pathlen_constraint.pem", AprilFirst2016(),
- TRUST_STORE_FROM_TEST_FILE, "");
+ CastDeviceCertPolicy::NONE, "violates_root_pathlen_constraint.pem",
+ AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
// Tests verifying a certificate chain with the policies:
@@ -417,8 +416,8 @@ TEST(VerifyCastDeviceCertTest, ViolatesPathlenTrustAnchorConstraint) {
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAnypolicy) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_anypolicy_leaf_anypolicy.pem",
- AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
+ "policies_ica_anypolicy_leaf_anypolicy.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// Test verifying a certificate chain with the policies:
@@ -428,8 +427,8 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAnypolicy) {
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAudioonly) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_anypolicy_leaf_audioonly.pem",
- AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
+ "policies_ica_anypolicy_leaf_audioonly.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// Test verifying a certificate chain with the policies:
@@ -439,7 +438,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafAudioonly) {
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafFoo) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_anypolicy_leaf_foo.pem", AprilFirst2016(),
+ "policies_ica_anypolicy_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -450,7 +449,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafFoo) {
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafNone) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_anypolicy_leaf_none.pem", AprilFirst2016(),
+ "policies_ica_anypolicy_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -461,8 +460,8 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAnypolicyLeafNone) {
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAnypolicy) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_audioonly_leaf_anypolicy.pem",
- AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
+ "policies_ica_audioonly_leaf_anypolicy.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// Test verifying a certificate chain with the policies:
@@ -472,8 +471,8 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAnypolicy) {
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAudioonly) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_audioonly_leaf_audioonly.pem",
- AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
+ "policies_ica_audioonly_leaf_audioonly.pem", AprilFirst2016(),
+ TRUST_STORE_FROM_TEST_FILE, "");
}
// Test verifying a certificate chain with the policies:
@@ -483,7 +482,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafAudioonly) {
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafFoo) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_audioonly_leaf_foo.pem", AprilFirst2016(),
+ "policies_ica_audioonly_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -494,7 +493,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafFoo) {
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafNone) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_audioonly_leaf_none.pem", AprilFirst2016(),
+ "policies_ica_audioonly_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -505,7 +504,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaAudioonlyLeafNone) {
// Leaf: policies={anyPolicy}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAnypolicy) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_none_leaf_anypolicy.pem", AprilFirst2016(),
+ "policies_ica_none_leaf_anypolicy.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -516,7 +515,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAnypolicy) {
// Leaf: policies={audioOnly}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAudioonly) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::AUDIO_ONLY,
- "certificates/policies_ica_none_leaf_audioonly.pem", AprilFirst2016(),
+ "policies_ica_none_leaf_audioonly.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -527,7 +526,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafAudioonly) {
// Leaf: policies={foo}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafFoo) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_none_leaf_foo.pem", AprilFirst2016(),
+ "policies_ica_none_leaf_foo.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -538,7 +537,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafFoo) {
// Leaf: policies={}
TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafNone) {
RunTest(CastCertError::OK, "Leaf", CastDeviceCertPolicy::NONE,
- "certificates/policies_ica_none_leaf_none.pem", AprilFirst2016(),
+ "policies_ica_none_leaf_none.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -547,7 +546,7 @@ TEST(VerifyCastDeviceCertTest, PoliciesIcaNoneLeafNone) {
// too weak.
TEST(VerifyCastDeviceCertTest, DeviceCertHas1024BitRsaKey) {
RunTest(CastCertError::ERR_CERTS_VERIFY_GENERIC, "RSA 1024 Device Cert",
- CastDeviceCertPolicy::NONE, "certificates/rsa1024_device_cert.pem",
+ CastDeviceCertPolicy::NONE, "rsa1024_device_cert.pem",
AprilFirst2016(), TRUST_STORE_FROM_TEST_FILE, "");
}
@@ -556,7 +555,7 @@ TEST(VerifyCastDeviceCertTest, DeviceCertHas1024BitRsaKey) {
// for it.
TEST(VerifyCastDeviceCertTest, DeviceCertHas2048BitRsaKey) {
RunTest(CastCertError::OK, "RSA 2048 Device Cert", CastDeviceCertPolicy::NONE,
- "certificates/rsa2048_device_cert.pem", AprilFirst2016(),
+ "rsa2048_device_cert.pem", AprilFirst2016(),
TRUST_STORE_FROM_TEST_FILE,
"signeddata/rsa2048_device_cert_data.pem");
}
diff --git a/chromium/components/cast_certificate/cast_crl_unittest.cc b/chromium/components/cast_certificate/cast_crl_unittest.cc
index f4837d3580f..e6a39eeb489 100644
--- a/chromium/components/cast_certificate/cast_crl_unittest.cc
+++ b/chromium/components/cast_certificate/cast_crl_unittest.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "components/cast_certificate/cast_crl.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/time/time.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "components/cast_certificate/cast_cert_test_helpers.h"
#include "components/cast_certificate/cast_cert_validator.h"
-#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -95,17 +97,14 @@ bool TestVerifyRevocation(CastCertError expected_result,
// Runs a single test case.
bool RunTest(const DeviceCertTest& test_case) {
- std::unique_ptr<net::TrustStoreInMemory> crl_trust_store;
- std::unique_ptr<net::TrustStoreInMemory> cast_trust_store;
- if (test_case.use_test_trust_anchors()) {
- crl_trust_store = testing::CreateTrustStoreFromFile(
- "certificates/cast_crl_test_root_ca.pem");
- cast_trust_store =
- testing::CreateTrustStoreFromFile("certificates/cast_test_root_ca.pem");
-
- EXPECT_TRUE(crl_trust_store.get());
- EXPECT_TRUE(cast_trust_store.get());
- }
+ std::unique_ptr<net::TrustStoreInMemory> cast_trust_store =
+ test_case.use_test_trust_anchors()
+ ? cast_certificate::testing::LoadTestCert("cast_test_root_ca.pem")
+ : nullptr;
+ std::unique_ptr<net::TrustStoreInMemory> crl_trust_store =
+ test_case.use_test_trust_anchors()
+ ? cast_certificate::testing::LoadTestCert("cast_crl_test_root_ca.pem")
+ : nullptr;
std::vector<std::string> certificate_chain;
for (auto const& cert : test_case.der_cert_path()) {
@@ -175,8 +174,11 @@ bool RunTest(const DeviceCertTest& test_case) {
// To see the description of the test, execute the test.
// These tests are generated by a test generator in google3.
void RunTestSuite(const std::string& test_suite_file_name) {
- std::string testsuite_raw =
- cast_certificate::testing::ReadTestFileToString(test_suite_file_name);
+ std::string testsuite_raw;
+ base::ReadFileToString(
+ testing::GetCastTestCertsDirectory().AppendASCII(test_suite_file_name),
+ &testsuite_raw);
+
DeviceCertTestSuite test_suite;
EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
uint16_t success = 0;
diff --git a/chromium/components/cast_certificate/switches.cc b/chromium/components/cast_certificate/switches.cc
new file mode 100644
index 00000000000..b7b3282cb2f
--- /dev/null
+++ b/chromium/components/cast_certificate/switches.cc
@@ -0,0 +1,16 @@
+// Copyright 2020 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/cast_certificate/switches.h"
+
+namespace cast_certificate {
+namespace switches {
+
+// When enabled by build flags, passing this argument allows the Cast
+// authentication utils to use a custom root developer certificate in the trust
+// store instead of the root Google-signed cert.
+const char kCastDeveloperCertificatePath[] = "cast-developer-certificate-path";
+
+} // namespace switches
+} // namespace cast_certificate
diff --git a/chromium/components/cast_certificate/switches.h b/chromium/components/cast_certificate/switches.h
new file mode 100644
index 00000000000..433dbf2c805
--- /dev/null
+++ b/chromium/components/cast_certificate/switches.h
@@ -0,0 +1,16 @@
+// Copyright 2020 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_CAST_CERTIFICATE_SWITCHES_H_
+#define COMPONENTS_CAST_CERTIFICATE_SWITCHES_H_
+
+namespace cast_certificate {
+namespace switches {
+
+extern const char kCastDeveloperCertificatePath[];
+
+} // namespace switches
+} // namespace cast_certificate
+
+#endif // COMPONENTS_CAST_CERTIFICATE_SWITCHES_H_
diff --git a/chromium/components/cast_channel/BUILD.gn b/chromium/components/cast_channel/BUILD.gn
index 3ebd4e398db..d14aadd85c3 100644
--- a/chromium/components/cast_channel/BUILD.gn
+++ b/chromium/components/cast_channel/BUILD.gn
@@ -43,7 +43,6 @@ static_library("cast_channel") {
"//components/prefs",
"//components/version_info",
"//content/public/browser",
- "//content/public/common",
"//crypto",
"//net",
"//third_party/openscreen/src/cast/common/channel/proto:channel_proto",
@@ -91,6 +90,7 @@ source_set("unit_tests") {
":test_support",
"//base/test:test_support",
"//components/cast_certificate",
+ "//components/cast_certificate:cast_certificate_reader",
"//components/cast_certificate:test_support",
"//components/prefs",
"//components/prefs:test_support",
@@ -144,6 +144,7 @@ fuzzer_test("cast_auth_util_fuzzer") {
":cast_channel",
":cast_channel_fuzzer_inputs",
"//components/cast_certificate",
+ "//components/cast_certificate:cast_certificate_reader",
"//components/cast_certificate:test_support",
"//net:test_support",
"//net/data/ssl/certificates:generate_fuzzer_cert_includes",
diff --git a/chromium/components/cast_channel/cast_auth_util_fuzzer.cc b/chromium/components/cast_channel/cast_auth_util_fuzzer.cc
index 979f7188aa4..d04e9cf799b 100644
--- a/chromium/components/cast_channel/cast_auth_util_fuzzer.cc
+++ b/chromium/components/cast_channel/cast_auth_util_fuzzer.cc
@@ -10,7 +10,8 @@
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/time/time_override.h"
-#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "components/cast_certificate/cast_cert_test_helpers.h"
#include "components/cast_channel/cast_auth_util.h"
#include "components/cast_channel/fuzz_proto/fuzzer_inputs.pb.h"
#include "net/cert/x509_certificate.h"
@@ -30,8 +31,9 @@ const char kCertData[] = {
base::NoDestructor<std::vector<std::string>> certs;
static bool InitializeOnce() {
- *certs = cast_certificate::testing::ReadCertificateChainFromFile(
- "certificates/chromecast_gen1.pem");
+ *certs = cast_certificate::ReadCertificateChainFromFile(
+ cast_certificate::testing::GetCastTestCertsCertsDirectory().AppendASCII(
+ "chromecast_gen1.pem"));
DCHECK(certs->size() >= 1);
return true;
}
diff --git a/chromium/components/cast_channel/cast_auth_util_unittest.cc b/chromium/components/cast_channel/cast_auth_util_unittest.cc
index 674b3f13874..178c289fa55 100644
--- a/chromium/components/cast_channel/cast_auth_util_unittest.cc
+++ b/chromium/components/cast_channel/cast_auth_util_unittest.cc
@@ -6,12 +6,14 @@
#include <string>
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
+#include "components/cast_certificate/cast_cert_reader.h"
+#include "components/cast_certificate/cast_cert_test_helpers.h"
#include "components/cast_certificate/cast_cert_validator.h"
-#include "components/cast_certificate/cast_cert_validator_test_helpers.h"
#include "components/cast_certificate/cast_crl.h"
#include "net/cert/internal/trust_store_in_memory.h"
#include "net/cert/x509_certificate.h"
@@ -36,8 +38,9 @@ class CastAuthUtilTest : public testing::Test {
static AuthResponse CreateAuthResponse(
std::string* signed_data,
cast::channel::HashAlgorithm digest_algorithm) {
- auto chain = cast_certificate::testing::ReadCertificateChainFromFile(
- "certificates/chromecast_gen1.pem");
+ auto chain = cast_certificate::ReadCertificateChainFromFile(
+ cast_certificate::testing::GetCastTestCertsCertsDirectory().AppendASCII(
+ "chromecast_gen1.pem"));
CHECK(!chain.empty());
auto signature_data = cast_certificate::testing::ReadSignatureTestData(
@@ -186,8 +189,9 @@ TEST_F(CastAuthUtilTest, VerifySenderNonceMissing) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
- auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
- "certificates/test_tls_cert.pem");
+ auto tls_cert_der = cast_certificate::ReadCertificateChainFromFile(
+ cast_certificate::testing::GetCastTestCertsCertsDirectory().AppendASCII(
+ "test_tls_cert.pem"));
scoped_refptr<net::X509Certificate> tls_cert =
net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
@@ -199,8 +203,9 @@ TEST_F(CastAuthUtilTest, VerifyTLSCertificateSuccess) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
- auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
- "certificates/test_tls_cert.pem");
+ auto tls_cert_der = cast_certificate::ReadCertificateChainFromFile(
+ cast_certificate::testing::GetCastTestCertsCertsDirectory().AppendASCII(
+ "test_tls_cert.pem"));
scoped_refptr<net::X509Certificate> tls_cert =
net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
@@ -215,8 +220,9 @@ TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooEarly) {
}
TEST_F(CastAuthUtilTest, VerifyTLSCertificateTooLate) {
- auto tls_cert_der = cast_certificate::testing::ReadCertificateChainFromFile(
- "certificates/test_tls_cert.pem");
+ auto tls_cert_der = cast_certificate::ReadCertificateChainFromFile(
+ cast_certificate::testing::GetCastTestCertsCertsDirectory().AppendASCII(
+ "test_tls_cert.pem"));
scoped_refptr<net::X509Certificate> tls_cert =
net::X509Certificate::CreateFromBytes(tls_cert_der[0].data(),
@@ -271,17 +277,14 @@ AuthResult TestVerifyRevocation(
// Runs a single test case.
bool RunTest(const cast::certificate::DeviceCertTest& test_case) {
- std::unique_ptr<net::TrustStore> crl_trust_store;
- std::unique_ptr<net::TrustStore> cast_trust_store;
- if (test_case.use_test_trust_anchors()) {
- crl_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
- "certificates/cast_crl_test_root_ca.pem");
- cast_trust_store = cast_certificate::testing::CreateTrustStoreFromFile(
- "certificates/cast_test_root_ca.pem");
-
- EXPECT_TRUE(crl_trust_store.get());
- EXPECT_TRUE(cast_trust_store.get());
- }
+ std::unique_ptr<net::TrustStoreInMemory> cast_trust_store =
+ test_case.use_test_trust_anchors()
+ ? cast_certificate::testing::LoadTestCert("cast_test_root_ca.pem")
+ : nullptr;
+ std::unique_ptr<net::TrustStoreInMemory> crl_trust_store =
+ test_case.use_test_trust_anchors()
+ ? cast_certificate::testing::LoadTestCert("cast_crl_test_root_ca.pem")
+ : nullptr;
std::vector<std::string> certificate_chain;
for (auto const& cert : test_case.der_cert_path()) {
@@ -345,8 +348,12 @@ bool RunTest(const cast::certificate::DeviceCertTest& test_case) {
// To see the description of the test, execute the test.
// These tests are generated by a test generator in google3.
void RunTestSuite(const std::string& test_suite_file_name) {
- std::string testsuite_raw =
- cast_certificate::testing::ReadTestFileToString(test_suite_file_name);
+ std::string testsuite_raw;
+ base::ReadFileToString(
+ cast_certificate::testing::GetCastTestCertsDirectory().AppendASCII(
+ test_suite_file_name),
+ &testsuite_raw);
+
cast::certificate::DeviceCertTestSuite test_suite;
EXPECT_TRUE(test_suite.ParseFromString(testsuite_raw));
uint16_t success = 0;
diff --git a/chromium/components/cast_channel/cast_message_handler.cc b/chromium/components/cast_channel/cast_message_handler.cc
index 47b46533f95..b342d18911b 100644
--- a/chromium/components/cast_channel/cast_message_handler.cc
+++ b/chromium/components/cast_channel/cast_message_handler.cc
@@ -479,7 +479,7 @@ void CastMessageHandler::OnMessageSent(int result) {
DVLOG_IF(2, result < 0) << "SendMessage failed with code: " << result;
}
-CastMessageHandler::PendingRequests::PendingRequests() {}
+CastMessageHandler::PendingRequests::PendingRequests() = default;
CastMessageHandler::PendingRequests::~PendingRequests() {
for (auto& request : pending_app_availability_requests_) {
std::move(request->callback)
@@ -523,8 +523,12 @@ bool CastMessageHandler::PendingRequests::AddAppAvailabilityRequest(
bool CastMessageHandler::PendingRequests::AddLaunchRequest(
std::unique_ptr<LaunchSessionRequest> request,
base::TimeDelta timeout) {
- if (pending_launch_session_request_)
+ if (pending_launch_session_request_) {
+ std::move(request->callback)
+ .Run(cast_channel::GetLaunchSessionResponseError(
+ "There already exists a launch request for the channel"));
return false;
+ }
int request_id = request->request_id;
request->timeout_timer.Start(
@@ -538,8 +542,10 @@ bool CastMessageHandler::PendingRequests::AddLaunchRequest(
bool CastMessageHandler::PendingRequests::AddStopRequest(
std::unique_ptr<StopSessionRequest> request) {
- if (pending_stop_session_request_)
+ if (pending_stop_session_request_) {
+ std::move(request->callback).Run(cast_channel::Result::kFailed);
return false;
+ }
int request_id = request->request_id;
request->timeout_timer.Start(
diff --git a/chromium/components/cast_channel/cast_message_handler_unittest.cc b/chromium/components/cast_channel/cast_message_handler_unittest.cc
index d52598789cb..ef7aa00cc1a 100644
--- a/chromium/components/cast_channel/cast_message_handler_unittest.cc
+++ b/chromium/components/cast_channel/cast_message_handler_unittest.cc
@@ -3,11 +3,13 @@
// found in the LICENSE file.
#include "components/cast_channel/cast_message_handler.h"
+#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
@@ -39,8 +41,9 @@ constexpr char kAppId2[] = "85CDB22F";
constexpr char kTestUserAgentString[] =
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/66.0.3331.0 Safari/537.36";
-constexpr char kSourceId[] = "sourceId";
-constexpr char kDestinationId[] = "destinationId";
+constexpr char kSessionId[] = "theSessionId";
+constexpr char kSourceId[] = "theSourceId";
+constexpr char kDestinationId[] = "theDestinationId";
constexpr char kAppParams[] = R"(
{
"requiredFeatures" : ["STREAM_TRANSFER"],
@@ -105,7 +108,7 @@ class CastMessageHandlerTest : public testing::Test {
.WillByDefault(testing::Return(&cast_socket_));
}
- ~CastMessageHandlerTest() override {}
+ ~CastMessageHandlerTest() override = default;
void OnMessage(const CastMessage& message) {
handler_.OnMessage(cast_socket_, message);
@@ -159,9 +162,9 @@ class CastMessageHandlerTest : public testing::Test {
handler_.SendSetVolumeRequest(
channel_id_,
ParseJson(R"({"sessionId": "theSessionId", "type": "SET_VOLUME"})"),
- "theSourceId", set_volume_callback_.Get());
+ kSourceId, set_volume_callback_.Get());
}
- handler_.StopSession(channel_id_, "theSessionId", "theSourceId",
+ handler_.StopSession(channel_id_, kSessionId, kSourceId,
stop_session_callback_.Get());
}
@@ -186,6 +189,36 @@ class CastMessageHandlerTest : public testing::Test {
EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
}
+ void HandlePendingLaunchSessionRequest(int request_id) {
+ handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
+ "theNamespace",
+ ParseJsonLikeDataDecoder(R"(
+ {
+ "requestId": )" + base::NumberToString(request_id) + R"(,
+ "type": "RECEIVER_STATUS",
+ "status": {"foo": "bar"},
+ })"));
+ }
+
+ void HandlePendingGeneralRequest(int request_id) {
+ handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
+ "theNamespace",
+ ParseJsonLikeDataDecoder(R"(
+ {
+ "requestId": )" + base::NumberToString(request_id) + R"(
+ })"));
+ }
+
+ void HandleAppAvailabilityRequest(int request_id) {
+ handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
+ "theNamespace",
+ ParseJsonLikeDataDecoder(R"(
+ {
+ "requestId": )" + base::NumberToString(request_id) + R"(,
+ "availability": {")" + kAppId1 + R"(": "APP_AVAILABLE"},
+ })"));
+ }
+
protected:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<base::RunLoop> run_loop_;
@@ -477,7 +510,7 @@ TEST_F(CastMessageHandlerTest, SendMediaRequest) {
"type": "PLAY",
})";
auto expected = CreateMediaRequest(ParseJson(expected_body), 1,
- "theSourceId", "theDestinationId");
+ "theSourceId", kDestinationId);
EXPECT_EQ(expected.namespace_(), message.namespace_());
EXPECT_EQ(expected.source_id(), message.source_id());
EXPECT_EQ(expected.destination_id(), message.destination_id());
@@ -493,7 +526,7 @@ TEST_F(CastMessageHandlerTest, SendMediaRequest) {
"type": "PLAY",
})";
base::Optional<int> request_id = handler_.SendMediaRequest(
- channel_id_, ParseJson(message_str), "theSourceId", "theDestinationId");
+ channel_id_, ParseJson(message_str), "theSourceId", kDestinationId);
EXPECT_EQ(1, request_id);
}
@@ -579,6 +612,7 @@ TEST_F(CastMessageHandlerTest, PendingRequestsDestructor) {
}
TEST_F(CastMessageHandlerTest, HandlePendingRequest) {
+ int next_request_id = 1;
CreatePendingRequests();
// Set up expanctions for pending request callbacks.
@@ -594,43 +628,18 @@ TEST_F(CastMessageHandlerTest, HandlePendingRequest) {
EXPECT_CALL(set_volume_callback_, Run(Result::kOk)).Times(2);
EXPECT_CALL(stop_session_callback_, Run(Result::kOk));
- // Handle pending launch session request.
- handler_.HandleCastInternalMessage(channel_id_, "theSourceId",
- "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(R"(
- {
- "requestId": 1,
- "type": "RECEIVER_STATUS",
- "status": {"foo": "bar"},
- })"));
-
+ HandlePendingLaunchSessionRequest(next_request_id++);
// Handle both pending get app availability requests.
- handler_.HandleCastInternalMessage(
- channel_id_, "theSourceId", "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(base::StringPrintf(R"(
- {
- "requestId": 2,
- "availability": {"%s": "APP_AVAILABLE"},
- })",
- kAppId1)));
-
+ HandleAppAvailabilityRequest(next_request_id++);
// Handle pending set volume request (1 of 2).
- handler_.HandleCastInternalMessage(
- channel_id_, "theSourceId", "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(R"({"requestId": 3})"));
-
+ HandlePendingGeneralRequest(next_request_id++);
// Skip request_id == 4, since it was used by the second get app availability
// request.
-
+ next_request_id++;
// Handle pending set volume request (2 of 2).
- handler_.HandleCastInternalMessage(
- channel_id_, "theSourceId", "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(R"({"requestId": 5})"));
-
+ HandlePendingGeneralRequest(next_request_id++);
// Handle pending stop session request.
- handler_.HandleCastInternalMessage(
- channel_id_, "theSourceId", "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(R"({"requestId": 6})"));
+ HandlePendingGeneralRequest(next_request_id++);
}
// Check that set volume requests time out correctly.
@@ -648,4 +657,53 @@ TEST_F(CastMessageHandlerTest, SetVolumeTimedOut) {
task_environment_.FastForwardBy(kRequestTimeout);
}
+TEST_F(CastMessageHandlerTest, SendMultipleLaunchRequests) {
+ int next_request_id = 1;
+ base::MockCallback<LaunchSessionCallback> expect_success_callback;
+ base::MockCallback<LaunchSessionCallback> expect_failure_callback;
+
+ EXPECT_CALL(expect_success_callback, Run(_))
+ .WillOnce(WithArg<0>([](LaunchSessionResponse response) {
+ EXPECT_EQ(LaunchSessionResponse::Result::kOk, response.result);
+ }));
+ EXPECT_CALL(expect_failure_callback, Run(_))
+ .WillOnce(WithArg<0>([](LaunchSessionResponse response) {
+ EXPECT_EQ(LaunchSessionResponse::Result::kError, response.result);
+ }));
+ EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+ handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
+ /* appParams */ base::nullopt,
+ expect_success_callback.Get());
+ // When there already is a launch request queued, we expect subsequent
+ // requests to fail.
+ handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
+ /* appParams */ base::nullopt,
+ expect_failure_callback.Get());
+ // This resolves the first launch request.
+ HandlePendingLaunchSessionRequest(next_request_id++);
+}
+
+TEST_F(CastMessageHandlerTest, SendMultipleStopRequests) {
+ int next_request_id = 1;
+ base::MockCallback<ResultCallback> expect_success_callback;
+ base::MockCallback<ResultCallback> expect_failure_callback;
+
+ EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
+ handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
+ /* appParams */ base::nullopt,
+ launch_session_callback_.Get());
+ HandlePendingLaunchSessionRequest(next_request_id++);
+
+ EXPECT_CALL(expect_success_callback, Run(Result::kOk));
+ EXPECT_CALL(expect_failure_callback, Run(Result::kFailed));
+ handler_.StopSession(channel_id_, kSessionId, kSourceId,
+ expect_success_callback.Get());
+ // When there already is a stop request queued, we expect subsequent requests
+ // to fail.
+ handler_.StopSession(channel_id_, kSessionId, kSourceId,
+ expect_failure_callback.Get());
+ // This resolves the first stop request.
+ HandlePendingGeneralRequest(next_request_id++);
+}
+
} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_socket.cc b/chromium/components/cast_channel/cast_socket.cc
index 9ca58414254..c0d4b1cadeb 100644
--- a/chromium/components/cast_channel/cast_socket.cc
+++ b/chromium/components/cast_channel/cast_socket.cc
@@ -300,7 +300,7 @@ void CastSocketImpl::OnConnectTimeout() {
void CastSocketImpl::ResetConnectLoopCallback() {
DCHECK(connect_loop_callback_.IsCancelled());
connect_loop_callback_.Reset(
- base::Bind(&CastSocketImpl::DoConnectLoop, base::Unretained(this)));
+ base::BindOnce(&CastSocketImpl::DoConnectLoop, base::Unretained(this)));
}
void CastSocketImpl::PostTaskToStartConnectLoop(int result) {
diff --git a/chromium/components/cast_channel/cast_socket.h b/chromium/components/cast_channel/cast_socket.h
index de772d230ae..ad420f942f9 100644
--- a/chromium/components/cast_channel/cast_socket.h
+++ b/chromium/components/cast_channel/cast_socket.h
@@ -406,7 +406,7 @@ class CastSocketImpl : public CastSocket {
// The callback signature is based on net::CompletionCallback, which passes
// operation result codes as byte counts in the success case, or as
// net::Error enum values for error cases.
- base::CancelableCallback<void(int)> connect_loop_callback_;
+ base::CancelableOnceCallback<void(int)> connect_loop_callback_;
// Cast message formatting and parsing layer.
std::unique_ptr<CastTransport> transport_;
diff --git a/chromium/components/cast_channel/cast_socket_unittest.cc b/chromium/components/cast_channel/cast_socket_unittest.cc
index 934039e5ad6..e5d814c325f 100644
--- a/chromium/components/cast_channel/cast_socket_unittest.cc
+++ b/chromium/components/cast_channel/cast_socket_unittest.cc
@@ -21,7 +21,7 @@
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/timer/mock_timer.h"
#include "build/build_config.h"
@@ -534,11 +534,12 @@ class SslCastSocketTest : public CastSocketTestBase {
std::unique_ptr<crypto::RSAPrivateKey> ReadTestKeyFromPEM(
const base::StringPiece& name) {
base::FilePath key_path = GetTestCertsDirectory().AppendASCII(name);
- std::vector<std::string> headers({"PRIVATE KEY"});
std::string pem_data;
if (!base::ReadFileToString(key_path, &pem_data)) {
return nullptr;
}
+
+ const std::vector<std::string> headers({"PRIVATE KEY"});
net::PEMTokenizer pem_tokenizer(pem_data, headers);
if (!pem_tokenizer.GetNext()) {
return nullptr;
diff --git a/chromium/components/cdm/common/BUILD.gn b/chromium/components/cdm/common/BUILD.gn
index 6164caaff18..abc9865ca91 100644
--- a/chromium/components/cdm/common/BUILD.gn
+++ b/chromium/components/cdm/common/BUILD.gn
@@ -2,22 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("common") {
sources = [
"cdm_message_generator.cc",
"cdm_message_generator.h",
- "cdm_messages_android.h",
- "widevine_drm_delegate_android.cc",
- "widevine_drm_delegate_android.h",
]
+ if (is_android) {
+ sources += [
+ "cdm_messages_android.h",
+ "widevine_drm_delegate_android.cc",
+ "widevine_drm_delegate_android.h",
+ ]
+ }
+
deps = [
"//base",
"//content/public/common",
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
index d072578c1fd..03b849d8ed5 100644
--- a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
@@ -16,7 +16,6 @@
#include "crypto/rsa_private_key.h"
#include "crypto/sha2.h"
#include "net/cert/ct_policy_status.h"
-#include "net/cert/ct_verify_result.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "net/log/net_log_with_source.h"
diff --git a/chromium/components/chrome_cleaner/public/constants/constants.cc b/chromium/components/chrome_cleaner/public/constants/constants.cc
index 345d481c051..34fb9a688da 100644
--- a/chromium/components/chrome_cleaner/public/constants/constants.cc
+++ b/chromium/components/chrome_cleaner/public/constants/constants.cc
@@ -21,6 +21,7 @@ const char kExecutionModeSwitch[] = "execution-mode";
const char kExtendedSafeBrowsingEnabledSwitch[] =
"extended-safebrowsing-enabled";
const char kRegistrySuffixSwitch[] = "registry-suffix";
+const char kResetShortcutsSwitch[] = "reset-shortcuts";
const char kSessionIdSwitch[] = "session-id";
const char kSRTPromptFieldTrialGroupNameSwitch[] = "srt-field-trial-group-name";
const char kUmaUserSwitch[] = "uma-user";
diff --git a/chromium/components/chrome_cleaner/public/constants/constants.h b/chromium/components/chrome_cleaner/public/constants/constants.h
index 1a1d84da675..6186297749c 100644
--- a/chromium/components/chrome_cleaner/public/constants/constants.h
+++ b/chromium/components/chrome_cleaner/public/constants/constants.h
@@ -61,6 +61,9 @@ extern const char kExtendedSafeBrowsingEnabledSwitch[];
// Specifies the suffix to the registry path where metrics data will be saved.
extern const char kRegistrySuffixSwitch[];
+// Indicates that resetting shortcuts is enabled.
+extern const char kResetShortcutsSwitch[];
+
// Identifier used to group all reports generated during the same run of the
// software reporter (which may include multiple invocations of the reporter
/// binary, each generating a report). An ASCII, base-64 encoded random string.
diff --git a/chromium/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/chromium/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
index 5a8a0901b20..3a52635f67c 100644
--- a/chromium/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
+++ b/chromium/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -673,7 +673,8 @@ void JpegClient::StartEncodeDmaBuf(int32_t bitstream_buffer_id) {
libyuv::I420ToNV12(src, width, src + width * height, width / 2,
src + width * height * 5 / 4, width / 2, plane_buf[0],
- width, plane_buf[1], width, width, height);
+ input_buffer->stride(0), plane_buf[1],
+ input_buffer->stride(1), width, height);
auto input_frame = GetVideoFrameFromGpuMemoryBuffer(
input_buffer.get(), test_image->visible_size, media::PIXEL_FORMAT_NV12);
diff --git a/chromium/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc b/chromium/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc
index 9896a2c8112..4fcd7976db4 100644
--- a/chromium/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc
+++ b/chromium/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/ptr_util.h"
@@ -127,9 +127,9 @@ void MojoJpegEncodeAcceleratorService::EncodeWithFD(
uint32_t output_buffer_size,
EncodeWithFDCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- base::PlatformFile input_fd;
- base::PlatformFile exif_fd;
- base::PlatformFile output_fd;
+ base::ScopedPlatformFile input_fd;
+ base::ScopedPlatformFile exif_fd;
+ base::ScopedPlatformFile output_fd;
MojoResult result;
if (coded_size_width <= 0 || coded_size_height <= 0) {
@@ -166,13 +166,13 @@ void MojoJpegEncodeAcceleratorService::EncodeWithFD(
base::UnsafeSharedMemoryRegion input_region =
base::UnsafeSharedMemoryRegion::Deserialize(
base::subtle::PlatformSharedMemoryRegion::Take(
- base::ScopedFD(input_fd),
+ std::move(input_fd),
base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
input_buffer_size, base::UnguessableToken::Create()));
base::subtle::PlatformSharedMemoryRegion output_shm_region =
base::subtle::PlatformSharedMemoryRegion::Take(
- base::ScopedFD(output_fd),
+ std::move(output_fd),
base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
output_buffer_size, base::UnguessableToken::Create());
@@ -182,8 +182,7 @@ void MojoJpegEncodeAcceleratorService::EncodeWithFD(
if (exif_buffer_size > 0) {
base::subtle::PlatformSharedMemoryRegion exif_shm_region =
base::subtle::PlatformSharedMemoryRegion::Take(
- base::subtle::ScopedFDPair(base::ScopedFD(exif_fd),
- base::ScopedFD()),
+ base::subtle::ScopedFDPair(std::move(exif_fd), base::ScopedFD()),
base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
exif_buffer_size, base::UnguessableToken::Create());
exif_buffer = std::make_unique<media::BitstreamBuffer>(
@@ -261,7 +260,7 @@ void MojoJpegEncodeAcceleratorService::EncodeWithDmaBuf(
return;
}
- base::PlatformFile exif_fd;
+ base::ScopedPlatformFile exif_fd;
auto result = mojo::UnwrapPlatformFile(std::move(exif_handle), &exif_fd);
if (result != MOJO_RESULT_OK) {
std::move(callback).Run(
@@ -289,8 +288,7 @@ void MojoJpegEncodeAcceleratorService::EncodeWithDmaBuf(
// the encode task process from both Chrome OS and Chrome side.
base::subtle::PlatformSharedMemoryRegion exif_shm_region =
base::subtle::PlatformSharedMemoryRegion::Take(
- base::subtle::ScopedFDPair(base::ScopedFD(exif_fd),
- base::ScopedFD()),
+ base::subtle::ScopedFDPair(std::move(exif_fd), base::ScopedFD()),
base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
exif_buffer_size, base::UnguessableToken::Create());
exif_buffer = std::make_unique<media::BitstreamBuffer>(
diff --git a/chromium/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc b/chromium/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
index 12b93b0398d..9366ab00155 100644
--- a/chromium/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
+++ b/chromium/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/platform_file.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
diff --git a/chromium/components/client_hints/browser/client_hints.cc b/chromium/components/client_hints/browser/client_hints.cc
index b3766ce192f..93c9c2c0aba 100644
--- a/chromium/components/client_hints/browser/client_hints.cc
+++ b/chromium/components/client_hints/browser/client_hints.cc
@@ -49,14 +49,14 @@ void ClientHints::GetAllowedClientHintsFromSource(
blink::WebEnabledClientHints* client_hints) {
ContentSettingsForOneType client_hints_rules;
settings_map_->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
- std::string(), &client_hints_rules);
+ &client_hints_rules);
client_hints::GetAllowedClientHintsFromSource(url, client_hints_rules,
client_hints);
}
bool ClientHints::IsJavaScriptAllowed(const GURL& url) {
- return settings_map_->GetContentSetting(
- url, url, ContentSettingsType::JAVASCRIPT, std::string()) !=
+ return settings_map_->GetContentSetting(url, url,
+ ContentSettingsType::JAVASCRIPT) !=
CONTENT_SETTING_BLOCK;
}
@@ -110,9 +110,8 @@ void ClientHints::PersistClientHints(
if (expiration_duration <= base::TimeDelta::FromSeconds(0))
return;
- std::unique_ptr<base::ListValue> expiration_times_list =
- std::make_unique<base::ListValue>();
- expiration_times_list->Reserve(client_hints.size());
+ base::Value::ListStorage expiration_times_list;
+ expiration_times_list.reserve(client_hints.size());
// Use wall clock since the expiration time would be persisted across embedder
// restarts.
@@ -120,17 +119,17 @@ void ClientHints::PersistClientHints(
(base::Time::Now() + expiration_duration).ToDoubleT();
for (const auto& entry : client_hints)
- expiration_times_list->AppendInteger(static_cast<int>(entry));
+ expiration_times_list.push_back(base::Value(static_cast<int>(entry)));
auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
- expiration_times_dictionary->SetList("client_hints",
- std::move(expiration_times_list));
- expiration_times_dictionary->SetDouble("expiration_time", expiration_time);
+ expiration_times_dictionary->SetKey(
+ "client_hints", base::Value(std::move(expiration_times_list)));
+ expiration_times_dictionary->SetDoubleKey("expiration_time", expiration_time);
// TODO(tbansal): crbug.com/735518. Disable updates to client hints settings
// when cookies are disabled for |primary_origin|.
settings_map_->SetWebsiteSettingDefaultScope(
- primary_url, GURL(), ContentSettingsType::CLIENT_HINTS, std::string(),
+ primary_url, GURL(), ContentSettingsType::CLIENT_HINTS,
std::move(expiration_times_dictionary),
{base::Time(), content_settings::SessionModel::UserSession});
diff --git a/chromium/components/cloud_devices/common/cloud_devices_urls.cc b/chromium/components/cloud_devices/common/cloud_devices_urls.cc
index 06cff707585..1409d6fc2b8 100644
--- a/chromium/components/cloud_devices/common/cloud_devices_urls.cc
+++ b/chromium/components/cloud_devices/common/cloud_devices_urls.cc
@@ -16,19 +16,6 @@ namespace cloud_devices {
const char kCloudPrintAuthScope[] =
"https://www.googleapis.com/auth/cloudprint";
-const char kCloudPrintDeprecationHelpURL[] =
-#if defined(OS_CHROMEOS)
- "https://support.google.com/chromebook/?p=cloudprint";
-#else
- "https://support.google.com/chrome/?p=cloudprint";
-#endif
-
-const char kCloudPrintLearnMoreURL[] =
- "https://www.google.com/support/cloudprint";
-
-const char kCloudPrintTestPageURL[] =
- "http://www.google.com/landing/cloudprint/enable.html?print=true";
-
namespace {
// Url must not be matched by "urls" section of
diff --git a/chromium/components/cloud_devices/common/cloud_devices_urls.h b/chromium/components/cloud_devices/common/cloud_devices_urls.h
index d1818fe5c73..5e1351d3f7e 100644
--- a/chromium/components/cloud_devices/common/cloud_devices_urls.h
+++ b/chromium/components/cloud_devices/common/cloud_devices_urls.h
@@ -12,9 +12,6 @@
namespace cloud_devices {
extern const char kCloudPrintAuthScope[];
-extern const char kCloudPrintDeprecationHelpURL[];
-extern const char kCloudPrintLearnMoreURL[];
-extern const char kCloudPrintTestPageURL[];
GURL GetCloudPrintURL();
GURL GetCloudPrintRelativeURL(const std::string& relative_path);
diff --git a/chromium/components/component_updater/component_installer_unittest.cc b/chromium/components/component_updater/component_installer_unittest.cc
index 7a5bef71d28..2dce9fcaadb 100644
--- a/chromium/components/component_updater/component_installer_unittest.cc
+++ b/chromium/components/component_updater/component_installer_unittest.cc
@@ -9,8 +9,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
diff --git a/chromium/components/component_updater/component_updater_service.cc b/chromium/components/component_updater/component_updater_service.cc
index 1577064bd9c..49ce676e11a 100644
--- a/chromium/components/component_updater/component_updater_service.cc
+++ b/chromium/components/component_updater/component_updater_service.cc
@@ -11,8 +11,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
diff --git a/chromium/components/component_updater/component_updater_service.h b/chromium/components/component_updater/component_updater_service.h
index f926034a2c8..5a5f0d32ea4 100644
--- a/chromium/components/component_updater/component_updater_service.h
+++ b/chromium/components/component_updater/component_updater_service.h
@@ -26,8 +26,8 @@ namespace policy {
class ComponentUpdaterPolicyTest;
}
-namespace settings {
-class AccessibilityMainHandler;
+namespace speech {
+class SODAInstallerImpl;
}
namespace update_client {
@@ -147,7 +147,7 @@ class ComponentUpdateService {
virtual bool GetComponentDetails(const std::string& id,
CrxUpdateItem* item) const = 0;
- friend class settings::AccessibilityMainHandler;
+ friend class speech::SODAInstallerImpl;
friend class ::ComponentsHandler;
FRIEND_TEST_ALL_PREFIXES(ComponentInstallerTest, RegisterComponent);
};
diff --git a/chromium/components/component_updater/component_updater_service_unittest.cc b/chromium/components/component_updater/component_updater_service_unittest.cc
index 183d36f96d7..96c39616bd1 100644
--- a/chromium/components/component_updater/component_updater_service_unittest.cc
+++ b/chromium/components/component_updater/component_updater_service_unittest.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
diff --git a/chromium/components/component_updater/installer_policies/BUILD.gn b/chromium/components/component_updater/installer_policies/BUILD.gn
index 5adc74018ef..1e0d8eab7a2 100644
--- a/chromium/components/component_updater/installer_policies/BUILD.gn
+++ b/chromium/components/component_updater/installer_policies/BUILD.gn
@@ -6,6 +6,8 @@ static_library("installer_policies") {
sources = [
"on_device_head_suggest_component_installer.cc",
"on_device_head_suggest_component_installer.h",
+ "safety_tips_component_installer.cc",
+ "safety_tips_component_installer.h",
]
deps = [
@@ -13,5 +15,7 @@ static_library("installer_policies") {
"//components/component_updater",
"//components/omnibox/browser",
"//components/omnibox/common",
+ "//components/reputation/core",
+ "//components/reputation/core:proto",
]
}
diff --git a/chromium/components/component_updater/installer_policies/DEPS b/chromium/components/component_updater/installer_policies/DEPS
index 473dc87ce99..188a1ba29ab 100644
--- a/chromium/components/component_updater/installer_policies/DEPS
+++ b/chromium/components/component_updater/installer_policies/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/omnibox/browser",
"+components/omnibox/common",
+ "+components/reputation/core",
]
diff --git a/chromium/components/component_updater/installer_policies/safety_tips_component_installer.cc b/chromium/components/component_updater/installer_policies/safety_tips_component_installer.cc
new file mode 100644
index 00000000000..ea7d62e4efb
--- /dev/null
+++ b/chromium/components/component_updater/installer_policies/safety_tips_component_installer.cc
@@ -0,0 +1,147 @@
+// 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 "components/component_updater/installer_policies/safety_tips_component_installer.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "components/reputation/core/safety_tips.pb.h"
+#include "components/reputation/core/safety_tips_config.h"
+
+using component_updater::ComponentUpdateService;
+
+namespace {
+
+const base::FilePath::CharType kSafetyTipsConfigBinaryPbFileName[] =
+ FILE_PATH_LITERAL("safety_tips.pb");
+
+// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
+// The extension id is: jflookgnkcckhobaglndicnbbgbonegd
+const uint8_t kSafetyTipsPublicKeySHA256[32] = {
+ 0x95, 0xbe, 0xea, 0x6d, 0xa2, 0x2a, 0x7e, 0x10, 0x6b, 0xd3, 0x82,
+ 0xd1, 0x16, 0x1e, 0xd4, 0x63, 0x21, 0xfe, 0x79, 0x5d, 0x02, 0x30,
+ 0xc2, 0xcf, 0x4a, 0x9c, 0x8a, 0x39, 0xcc, 0x4a, 0x00, 0xce};
+
+std::unique_ptr<reputation::SafetyTipsConfig> LoadSafetyTipsProtoFromDisk(
+ const base::FilePath& pb_path) {
+ std::string binary_pb;
+ if (!base::ReadFileToString(pb_path, &binary_pb)) {
+ // The file won't exist on new installations, so this is not always an
+ // error.
+ DVLOG(1) << "Failed reading from " << pb_path.value();
+ return nullptr;
+ }
+ auto proto = std::make_unique<reputation::SafetyTipsConfig>();
+ if (!proto->ParseFromString(binary_pb)) {
+ DVLOG(1) << "Failed parsing proto " << pb_path.value();
+ return nullptr;
+ }
+ return proto;
+}
+
+} // namespace
+
+namespace component_updater {
+
+SafetyTipsComponentInstallerPolicy::SafetyTipsComponentInstallerPolicy() =
+ default;
+
+SafetyTipsComponentInstallerPolicy::~SafetyTipsComponentInstallerPolicy() =
+ default;
+
+bool SafetyTipsComponentInstallerPolicy::
+ SupportsGroupPolicyEnabledComponentUpdates() const {
+ return false;
+}
+
+bool SafetyTipsComponentInstallerPolicy::RequiresNetworkEncryption() const {
+ return false;
+}
+
+update_client::CrxInstaller::Result
+SafetyTipsComponentInstallerPolicy::OnCustomInstall(
+ const base::DictionaryValue& /* manifest */,
+ const base::FilePath& /* install_dir */) {
+ return update_client::CrxInstaller::Result(0); // Nothing custom here.
+}
+
+void SafetyTipsComponentInstallerPolicy::OnCustomUninstall() {}
+
+base::FilePath SafetyTipsComponentInstallerPolicy::GetInstalledPath(
+ const base::FilePath& base) {
+ return base.Append(kSafetyTipsConfigBinaryPbFileName);
+}
+
+void SafetyTipsComponentInstallerPolicy::ComponentReady(
+ const base::Version& version,
+ const base::FilePath& install_dir,
+ std::unique_ptr<base::DictionaryValue> /* manifest */) {
+ DVLOG(1) << "Component ready, version " << version.GetString() << " in "
+ << install_dir.value();
+
+ const base::FilePath pb_path = GetInstalledPath(install_dir);
+ if (pb_path.empty())
+ return;
+
+ // The default proto will always be a placeholder since the updated versions
+ // are not checked in to the repo. Simply load whatever the component updater
+ // gave us without checking the default proto from the resource bundle.
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&LoadSafetyTipsProtoFromDisk, pb_path),
+ base::BindOnce(&reputation::SetSafetyTipsRemoteConfigProto));
+}
+
+// Called during startup and installation before ComponentReady().
+bool SafetyTipsComponentInstallerPolicy::VerifyInstallation(
+ const base::DictionaryValue& /* manifest */,
+ const base::FilePath& install_dir) const {
+ // No need to actually validate the proto here, since we'll do the checking
+ // in PopulateFromDynamicUpdate().
+ return base::PathExists(GetInstalledPath(install_dir));
+}
+
+base::FilePath SafetyTipsComponentInstallerPolicy::GetRelativeInstallDir()
+ const {
+ return base::FilePath(FILE_PATH_LITERAL("SafetyTips"));
+}
+
+void SafetyTipsComponentInstallerPolicy::GetHash(
+ std::vector<uint8_t>* hash) const {
+ hash->assign(
+ kSafetyTipsPublicKeySHA256,
+ kSafetyTipsPublicKeySHA256 + base::size(kSafetyTipsPublicKeySHA256));
+}
+
+std::string SafetyTipsComponentInstallerPolicy::GetName() const {
+ return "Safety Tips";
+}
+
+update_client::InstallerAttributes
+SafetyTipsComponentInstallerPolicy::GetInstallerAttributes() const {
+ return update_client::InstallerAttributes();
+}
+
+std::vector<std::string> SafetyTipsComponentInstallerPolicy::GetMimeTypes()
+ const {
+ return std::vector<std::string>();
+}
+
+void RegisterSafetyTipsComponent(ComponentUpdateService* cus) {
+ DVLOG(1) << "Registering Safety Tips component.";
+
+ auto installer = base::MakeRefCounted<ComponentInstaller>(
+ std::make_unique<SafetyTipsComponentInstallerPolicy>());
+ installer->Register(cus, base::OnceClosure());
+}
+
+} // namespace component_updater
diff --git a/chromium/components/component_updater/installer_policies/safety_tips_component_installer.h b/chromium/components/component_updater/installer_policies/safety_tips_component_installer.h
new file mode 100644
index 00000000000..c1b6bdea743
--- /dev/null
+++ b/chromium/components/component_updater/installer_policies/safety_tips_component_installer.h
@@ -0,0 +1,54 @@
+// 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 COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_SAFETY_TIPS_COMPONENT_INSTALLER_H_
+#define COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_SAFETY_TIPS_COMPONENT_INSTALLER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/component_updater/component_installer.h"
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace component_updater {
+
+class SafetyTipsComponentInstallerPolicy : public ComponentInstallerPolicy {
+ public:
+ SafetyTipsComponentInstallerPolicy();
+ ~SafetyTipsComponentInstallerPolicy() override;
+
+ private:
+ // ComponentInstallerPolicy methods:
+ bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+ bool RequiresNetworkEncryption() const override;
+ update_client::CrxInstaller::Result OnCustomInstall(
+ const base::DictionaryValue& manifest,
+ const base::FilePath& install_dir) override;
+ void OnCustomUninstall() override;
+ bool VerifyInstallation(const base::DictionaryValue& manifest,
+ const base::FilePath& install_dir) const override;
+ void ComponentReady(const base::Version& version,
+ const base::FilePath& install_dir,
+ std::unique_ptr<base::DictionaryValue> manifest) override;
+ base::FilePath GetRelativeInstallDir() const override;
+ void GetHash(std::vector<uint8_t>* hash) const override;
+ std::string GetName() const override;
+ update_client::InstallerAttributes GetInstallerAttributes() const override;
+ std::vector<std::string> GetMimeTypes() const override;
+
+ static base::FilePath GetInstalledPath(const base::FilePath& base);
+
+ DISALLOW_COPY_AND_ASSIGN(SafetyTipsComponentInstallerPolicy);
+};
+
+void RegisterSafetyTipsComponent(ComponentUpdateService* cus);
+
+} // namespace component_updater
+
+#endif // COMPONENTS_COMPONENT_UPDATER_INSTALLER_POLICIES_SAFETY_TIPS_COMPONENT_INSTALLER_H_
diff --git a/chromium/components/component_updater/timer.cc b/chromium/components/component_updater/timer.cc
index 92b129e722b..eccfcfb0cbe 100644
--- a/chromium/components/component_updater/timer.cc
+++ b/chromium/components/component_updater/timer.cc
@@ -18,7 +18,7 @@ Timer::~Timer() {
void Timer::Start(base::TimeDelta initial_delay,
base::TimeDelta delay,
- const base::Closure& user_task) {
+ const base::RepeatingClosure& user_task) {
DCHECK(thread_checker_.CalledOnValidThread());
delay_ = delay;
diff --git a/chromium/components/component_updater/timer.h b/chromium/components/component_updater/timer.h
index 12c6c5107cc..8d9a600901b 100644
--- a/chromium/components/component_updater/timer.h
+++ b/chromium/components/component_updater/timer.h
@@ -20,7 +20,7 @@ class Timer {
void Start(base::TimeDelta initial_delay,
base::TimeDelta delay,
- const base::Closure& user_task);
+ const base::RepeatingClosure& user_task);
void Stop();
@@ -32,7 +32,7 @@ class Timer {
base::OneShotTimer timer_;
base::TimeDelta delay_;
- base::Closure user_task_;
+ base::RepeatingClosure user_task_;
DISALLOW_COPY_AND_ASSIGN(Timer);
};
diff --git a/chromium/components/component_updater/timer_update_scheduler.cc b/chromium/components/component_updater/timer_update_scheduler.cc
index 9035af21113..7e576d5d3b6 100644
--- a/chromium/components/component_updater/timer_update_scheduler.cc
+++ b/chromium/components/component_updater/timer_update_scheduler.cc
@@ -4,7 +4,7 @@
#include "components/component_updater/timer_update_scheduler.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
namespace component_updater {
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index a29aa340053..5bd448ca54a 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -314,6 +314,7 @@
<part file="send_tab_to_self_strings.grdp" />
<part file="sms_strings.grdp" />
<part file="ssl_errors_strings.grdp" />
+ <part file="subresource_filter_strings.grdp" />
<part file="sync_ui_strings.grdp" />
<part file="translate_strings.grdp" />
<part file="tab_groups_strings.grdp" />
@@ -329,6 +330,9 @@
<if expr="is_ios">
<part file="management_ios_strings.grdp" />
</if>
+ <if expr="enable_vr">
+ <part file="webxr_strings.grdp" />
+ </if>
<!-- Generic terms -->
<message name="IDS_CANCEL" desc="Used for Cancel on buttons">
@@ -349,6 +353,9 @@
<message name="IDS_OK" desc="Used for OK on buttons">
OK
</message>
+ <message name="IDS_RELOAD" desc="Used for Reload on buttons">
+ Reload
+ </message>
<message name="IDS_ADD" desc="Used for Add on buttons">
Add
</message>
@@ -361,6 +368,12 @@
<message name="IDS_MENU" desc="The accessible name for the Menu. This is used as the aria-roledescription for context menus.">
Menu
</message>
+ <message name="IDS_INSTALL" desc="Text to be displayed when an action will trigger an installation (of a component, app from the Play Store, etc.).">
+ Install
+ </message>
+ <message name="IDS_UPDATE" desc="Text to be displayed when an action will trigger an update of an existing item (e.g. a component, app from the Play Store, etc.).">
+ Update
+ </message>
<if expr="is_android">
<message name="IDS_SHOW_CONTENT" desc="Generic label to show content for a feature. [CHAR-LIMIT=20]" formatter_data="android_java">
Show
diff --git a/chromium/components/components_strings_grd/IDS_INSTALL.png.sha1 b/chromium/components/components_strings_grd/IDS_INSTALL.png.sha1
new file mode 100644
index 00000000000..1caf8a15ff2
--- /dev/null
+++ b/chromium/components/components_strings_grd/IDS_INSTALL.png.sha1
@@ -0,0 +1 @@
+0c5ff3801cdd9746c79d06f5e5e275e50da2d1d1 \ No newline at end of file
diff --git a/chromium/components/components_strings_grd/IDS_UPDATE.png.sha1 b/chromium/components/components_strings_grd/IDS_UPDATE.png.sha1
new file mode 100644
index 00000000000..f86b51f5dd0
--- /dev/null
+++ b/chromium/components/components_strings_grd/IDS_UPDATE.png.sha1
@@ -0,0 +1 @@
+42a5bb8f363828fa231b343659f2483f80dd8e07 \ No newline at end of file
diff --git a/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc b/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
index bdd22e3e5c9..566b920a518 100644
--- a/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
+++ b/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
@@ -14,7 +14,7 @@
#include "base/time/default_clock.h"
#include "components/consent_auditor/pref_names.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/sync/model/fake_model_type_controller_delegate.h"
+#include "components/sync/test/model/fake_model_type_controller_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
using ArcPlayTermsOfServiceConsent =
diff --git a/chromium/components/consent_auditor/consent_sync_bridge_impl.cc b/chromium/components/consent_auditor/consent_sync_bridge_impl.cc
index cd9c224d66f..67652540d66 100644
--- a/chromium/components/consent_auditor/consent_sync_bridge_impl.cc
+++ b/chromium/components/consent_auditor/consent_sync_bridge_impl.cc
@@ -10,7 +10,7 @@
#include "base/big_endian.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/stl_util.h"
diff --git a/chromium/components/consent_auditor/consent_sync_bridge_impl_unittest.cc b/chromium/components/consent_auditor/consent_sync_bridge_impl_unittest.cc
index 89695be9a3c..2aaa7d39580 100644
--- a/chromium/components/consent_auditor/consent_sync_bridge_impl_unittest.cc
+++ b/chromium/components/consent_auditor/consent_sync_bridge_impl_unittest.cc
@@ -9,13 +9,13 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "components/sync/model/data_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/content_capture/android/BUILD.gn b/chromium/components/content_capture/android/BUILD.gn
index 0b607fda74f..e49f619dfb0 100644
--- a/chromium/components/content_capture/android/BUILD.gn
+++ b/chromium/components/content_capture/android/BUILD.gn
@@ -41,6 +41,8 @@ android_library("java") {
"java/src/org/chromium/components/content_capture/ExperimentContentCaptureConsumer.java",
"java/src/org/chromium/components/content_capture/FrameSession.java",
"java/src/org/chromium/components/content_capture/NotificationTask.java",
+ "java/src/org/chromium/components/content_capture/PlatformAPIWrapper.java",
+ "java/src/org/chromium/components/content_capture/PlatformAPIWrapperImpl.java",
"java/src/org/chromium/components/content_capture/PlatformSession.java",
"java/src/org/chromium/components/content_capture/ProcessContentCaptureDataTask.java",
"java/src/org/chromium/components/content_capture/SessionRemovedTask.java",
diff --git a/chromium/components/content_capture/android/junit/BUILD.gn b/chromium/components/content_capture/android/junit/BUILD.gn
new file mode 100644
index 00000000000..4ce417846ee
--- /dev/null
+++ b/chromium/components/content_capture/android/junit/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2020 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("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+java_library("components_content_capture_junit_tests") {
+ # Platform checks are broken for Robolectric. See https://crbug.com/1071638.
+ bypass_platform_checks = true
+ testonly = true
+ sources = [
+ "src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java",
+ ]
+ deps = [
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//base:base_junit_test_support",
+ "//components/content_capture/android:java",
+ "//content/public/android:content_java",
+ "//third_party/android_deps:robolectric_all_java",
+ "//third_party/junit",
+ "//third_party/mockito:mockito_java",
+ ]
+}
diff --git a/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java b/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java
new file mode 100644
index 00000000000..4f68b468689
--- /dev/null
+++ b/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformAPIWrapperTest.java
@@ -0,0 +1,569 @@
+// Copyright 2020 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.components.content_capture;
+
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Rect;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureSession;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The unit tests for PlatformAPIWrapper, NotificationTask and its subclasses. It runs the
+ * ContentCapturedTask, ContentUpdateTask, ContentRemovedTask and SessionRemovedTask, then
+ * verifies if the PlatformAPIWrapper get the expected parameters.
+ *
+ * This test also verifies that the covered code path won't call ContentCaptureSession API
+ * directly, and verified that all tasks catch the PlatformAPIException correctly.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class PlatformAPIWrapperTest {
+ /**
+ * This class implements the methods we care, mockito will mock other method
+ * for us. By declaring the method be final, it won't be mocked by mockito.
+ */
+ private abstract static class ViewStructureTestHelper extends ViewStructure {
+ private CharSequence mText;
+ private Rect mDimens;
+ @Override
+ public final void setText(CharSequence text) {
+ mText = text;
+ }
+
+ @Override
+ public final CharSequence getText() {
+ return mText;
+ }
+
+ @Override
+ public final void setDimens(
+ int left, int top, int scrollX, int scrollY, int width, int height) {
+ mDimens = new Rect(left, top, left + width, top + height);
+ }
+
+ public final Rect getDimens() {
+ return mDimens;
+ }
+ }
+
+ /**
+ * This class records the invoked method and the passing parameter in sequence for
+ * verification later.
+ */
+ private static class PlatformAPIWrapperTestHelper extends PlatformAPIWrapper {
+ // The Id of API call.
+ public static final int CREATE_CONTENT_CAPTURE_SESSION = 1;
+ public static final int NEW_AUTOFILL_ID = 2;
+ public static final int NEW_VIRTUAL_VIEW_STRUCTURE = 3;
+ public static final int NOTIFY_VIEW_APPEARED = 4;
+ public static final int NOTIFY_VIEW_DISAPPEARED = 5;
+ public static final int NOTIFY_VIEWS_DISAPPEARED = 6;
+ public static final int NOTIFY_VIEW_TEXT_CHANGED = 7;
+ public static final int DESTROY_CONTENT_CAPTURE_SESSION = 8;
+
+ // The array for objects returned by the mocked APIs
+ public final ArrayList<ContentCaptureSession> mCreatedContentCaptureSessions =
+ new ArrayList<ContentCaptureSession>();
+ public final ArrayList<AutofillId> mCreatedAutofilIds = new ArrayList<AutofillId>();
+ public final ArrayList<ViewStructureTestHelper> mCreatedViewStructures =
+ new ArrayList<ViewStructureTestHelper>();
+ public final ArrayList<AutofillId> mCreatedViewStructuresAutofilIds =
+ new ArrayList<AutofillId>();
+
+ // Array to record the API calls in sequence.
+ private volatile ArrayList<Integer> mCallbacks = new ArrayList<Integer>();
+
+ // Mock a ContentCaptureSession which will throw a exception if all its public
+ // method is called because this test use the mocked PlatformAPIWrapper, the methods
+ // of ContentCaptureSession will never be called.
+ private ContentCaptureSession createMockedContentCaptureSession() {
+ ContentCaptureSession mockedContentCaptureSession =
+ Mockito.mock(ContentCaptureSession.class);
+ // Prevent the below methods being called from the class other than PlatformAPIWrapper.
+ final String errorMsg = "Shall be called from PlatformAPIWrapper.";
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .createContentCaptureSession(ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .newAutofillId(ArgumentMatchers.any(), ArgumentMatchers.anyLong());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .destroy();
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .getContentCaptureContext();
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .getContentCaptureSessionId();
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .newViewStructure(ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .newVirtualViewStructure(ArgumentMatchers.any(), ArgumentMatchers.anyLong());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .notifyViewAppeared(ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .notifyViewDisappeared(ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .notifyViewTextChanged(ArgumentMatchers.any(), ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .notifyViewsDisappeared(ArgumentMatchers.any(), ArgumentMatchers.any());
+ doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ .when(mockedContentCaptureSession)
+ .setContentCaptureContext(ArgumentMatchers.any());
+ // TODO(crbug.com/1145784): Enable below once mockito support them.
+ // doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ // .when(mockedContentCaptureSession)
+ // .notifySessionPaused();
+ // doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ // .when(mockedContentCaptureSession)
+ // .notifySessionResumed();
+ // doThrow(new RuntimeException("Shall be called from PlatformAPIWrapper."))
+ // .when(mockedContentCaptureSession)
+ // .notifyViewInsetsChanged(ArgumentMatchers.any());
+ return mockedContentCaptureSession;
+ }
+
+ @Override
+ public ContentCaptureSession createContentCaptureSession(
+ ContentCaptureSession parent, String url) {
+ mCallbacks.add(CREATE_CONTENT_CAPTURE_SESSION);
+ ContentCaptureSession mockedContentCaptureSession = createMockedContentCaptureSession();
+ mCreatedContentCaptureSessions.add(mockedContentCaptureSession);
+ return mockedContentCaptureSession;
+ }
+
+ @Override
+ public void destroyContentCaptureSession(ContentCaptureSession session) {
+ mCallbacks.add(DESTROY_CONTENT_CAPTURE_SESSION);
+ }
+ @Override
+ public AutofillId newAutofillId(
+ ContentCaptureSession parent, AutofillId rootAutofillId, long id) {
+ mCallbacks.add(NEW_AUTOFILL_ID);
+ AutofillId mockedAutofillId = Mockito.mock(AutofillId.class);
+ mCreatedAutofilIds.add(mockedAutofillId);
+ return mockedAutofillId;
+ }
+
+ @Override
+ public ViewStructure newVirtualViewStructure(
+ ContentCaptureSession parent, AutofillId parentAutofillId, long id) {
+ mCallbacks.add(NEW_VIRTUAL_VIEW_STRUCTURE);
+ ViewStructureTestHelper mockedViewStructure =
+ Mockito.mock(ViewStructureTestHelper.class);
+ AutofillId mockedAutofilId = Mockito.mock(AutofillId.class);
+ mCreatedViewStructuresAutofilIds.add(mockedAutofilId);
+ when(mockedViewStructure.getAutofillId()).thenReturn(mockedAutofilId);
+ mCreatedViewStructures.add(mockedViewStructure);
+ return mockedViewStructure;
+ }
+
+ @Override
+ public void notifyViewAppeared(ContentCaptureSession session, ViewStructure viewStructure) {
+ mCallbacks.add(NOTIFY_VIEW_APPEARED);
+ }
+
+ @Override
+ public void notifyViewDisappeared(ContentCaptureSession parent, AutofillId autofillId) {
+ mCallbacks.add(NOTIFY_VIEW_DISAPPEARED);
+ }
+
+ @Override
+ public void notifyViewsDisappeared(
+ ContentCaptureSession session, AutofillId autofillId, long[] ids) {
+ mCallbacks.add(NOTIFY_VIEWS_DISAPPEARED);
+ }
+
+ @Override
+ public void notifyViewTextChanged(
+ ContentCaptureSession session, AutofillId autofillId, String newContent) {
+ mCallbacks.add(NOTIFY_VIEW_TEXT_CHANGED);
+ }
+
+ public void reset() {
+ mCallbacks.clear();
+ }
+
+ public int[] getCallbacks() {
+ int[] result = new int[mCallbacks.size()];
+ int index = 0;
+ for (Integer c : mCallbacks) {
+ result[index++] = c;
+ }
+ return result;
+ }
+ }
+
+ private static final String MAIN_URL = "http://main.domain.com";
+ private static final long MAIN_ID = 4;
+ private static final Rect MAIN_FRAME_RECT = new Rect(0, 0, 200, 200);
+ private static final String CHILD_URL = "http://test.domain.com";
+ private static final long CHILD_FRAME_ID = 1;
+ private static final Rect CHILD_FRAME_RECT = new Rect(0, 0, 100, 100);
+ private static final long CHILD1_ID = 2;
+ private static final String CHILD1_TEXT = "Hello";
+ private static final Rect CHILD1_RECT = new Rect(10, 10, 20, 20);
+ private static final long CHILD2_ID = 3;
+ private static final String CHILD2_TEXT = "World";
+ private static final Rect CHILD2_RECT = new Rect(20, 20, 20, 20);
+ private static final String CHILD2_NEW_TEXT = " world!";
+ private static final long[] REMOVED_IDS = {CHILD1_ID, CHILD2_ID};
+
+ private ContentCaptureSession mMockedRootContentCaptureSession;
+ private AutofillId mMockedRootAutofillId;
+ private PlatformSession mRootPlatformSession;
+ private PlatformAPIWrapperTestHelper mPlatformAPIWrapperTestHelper;
+ private PlatformAPIWrapperTestHelper mPlatformAPIWrapperTestHelperSpy;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mMockedRootContentCaptureSession = Mockito.mock(ContentCaptureSession.class);
+ mMockedRootAutofillId = Mockito.mock(AutofillId.class);
+ mRootPlatformSession =
+ new PlatformSession(mMockedRootContentCaptureSession, mMockedRootAutofillId);
+ mPlatformAPIWrapperTestHelper = new PlatformAPIWrapperTestHelper();
+ mPlatformAPIWrapperTestHelperSpy = spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mPlatformAPIWrapperTestHelperSpy);
+ }
+
+ private static void verifyCallbacks(int[] expectedCallbacks, int[] results) {
+ Assert.assertArrayEquals("Expect: " + Arrays.toString(expectedCallbacks)
+ + " Result: " + Arrays.toString(results),
+ expectedCallbacks, results);
+ }
+
+ private static int[] toIntArray(int... callbacks) {
+ return callbacks;
+ }
+
+ private void runTaskAndVerifyCallback(NotificationTask task, int[] expectedCallbacks)
+ throws Exception {
+ mPlatformAPIWrapperTestHelper.reset();
+ task.doInBackground();
+ verifyCallbacks(expectedCallbacks, mPlatformAPIWrapperTestHelper.getCallbacks());
+ }
+
+ private void runTaskAndVerifyCallbackWithException(
+ NotificationTask task, int[] expectedCallbacks) throws Exception {
+ runTaskAndVerifyCallback(task, expectedCallbacks);
+ Assert.assertTrue(task.hasPlatformExceptionForTesting());
+ }
+
+ private void verifyVirtualViewStructure(String expectedText, Rect expectedRect, int index) {
+ Assert.assertEquals("Index:" + index, expectedText,
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(index).getText());
+ Assert.assertEquals("Index:" + index, expectedRect,
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(index).getDimens());
+ }
+
+ private FrameSession createFrameSession() {
+ FrameSession frameSession = new FrameSession(1);
+ frameSession.add(ContentCaptureData.createContentCaptureData(null, MAIN_ID, MAIN_URL,
+ MAIN_FRAME_RECT.left, MAIN_FRAME_RECT.top, MAIN_FRAME_RECT.width(),
+ MAIN_FRAME_RECT.height()));
+ return frameSession;
+ }
+
+ private FrameSession createFrameSessionForRemoveTask() {
+ FrameSession frameSessionForRemoveTask = createFrameSession();
+ frameSessionForRemoveTask.add(0,
+ ContentCaptureData.createContentCaptureData(null, CHILD_FRAME_ID, CHILD_URL,
+ CHILD_FRAME_RECT.left, CHILD_FRAME_RECT.top, CHILD_FRAME_RECT.width(),
+ CHILD_FRAME_RECT.height()));
+ return frameSessionForRemoveTask;
+ }
+
+ // The below createFooTask() create the tasks for tests.
+ private ContentCapturedTask createContentCapturedTask() {
+ FrameSession frameSession = createFrameSession();
+ ContentCaptureData data = ContentCaptureData.createContentCaptureData(null, CHILD_FRAME_ID,
+ CHILD_URL, CHILD_FRAME_RECT.left, CHILD_FRAME_RECT.top, CHILD_FRAME_RECT.width(),
+ CHILD_FRAME_RECT.height());
+ ContentCaptureData.createContentCaptureData(data, CHILD1_ID, CHILD1_TEXT, CHILD1_RECT.left,
+ CHILD1_RECT.top, CHILD1_RECT.width(), CHILD1_RECT.height());
+ ContentCaptureData.createContentCaptureData(data, CHILD2_ID, CHILD2_TEXT, CHILD2_RECT.left,
+ CHILD2_RECT.top, CHILD2_RECT.width(), CHILD2_RECT.height());
+ return new ContentCapturedTask(frameSession, data, mRootPlatformSession);
+ }
+
+ private ContentUpdateTask createChild2ContentUpdateTask() {
+ // Modifies child2
+ ContentCaptureData changeTextData = ContentCaptureData.createContentCaptureData(null,
+ CHILD_FRAME_ID, CHILD_URL, CHILD_FRAME_RECT.left, CHILD_FRAME_RECT.top,
+ CHILD_FRAME_RECT.width(), CHILD_FRAME_RECT.height());
+ ContentCaptureData.createContentCaptureData(changeTextData, CHILD2_ID, CHILD2_NEW_TEXT,
+ CHILD2_RECT.left, CHILD2_RECT.top, CHILD2_RECT.width(), CHILD2_RECT.height());
+ return new ContentUpdateTask(createFrameSession(), changeTextData, mRootPlatformSession);
+ }
+
+ private ContentRemovedTask createRemoveChildrenTask() {
+ // Removes the child1 and child2
+ return new ContentRemovedTask(
+ createFrameSessionForRemoveTask(), REMOVED_IDS, mRootPlatformSession);
+ }
+
+ private SessionRemovedTask createSessionRemovedTask() {
+ return new SessionRemovedTask(createFrameSessionForRemoveTask(), mRootPlatformSession);
+ }
+
+ private void runContentCapturedTask() throws Exception {
+ runTaskAndVerifyCallback(createContentCapturedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION,
+ PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID,
+ PlatformAPIWrapperTestHelper.NEW_VIRTUAL_VIEW_STRUCTURE,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_APPEARED,
+ PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION,
+ PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID,
+ PlatformAPIWrapperTestHelper.NEW_VIRTUAL_VIEW_STRUCTURE,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_APPEARED,
+ PlatformAPIWrapperTestHelper.NEW_VIRTUAL_VIEW_STRUCTURE,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_APPEARED,
+ PlatformAPIWrapperTestHelper.NEW_VIRTUAL_VIEW_STRUCTURE,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_APPEARED));
+ }
+
+ private NullPointerException createMainContentCaptureSessionException() {
+ NullPointerException e = new NullPointerException() {
+ @Override
+ public StackTraceElement[] getStackTrace() {
+ StackTraceElement[] stack = new StackTraceElement[super.getStackTrace().length + 1];
+ int index = 0;
+ for (StackTraceElement s : super.getStackTrace()) {
+ stack[index++] = s;
+ }
+ stack[index] = new StackTraceElement(
+ "android.view.contentcapture.MainContentCaptureSession", "sendEvent",
+ "MainContentCaptureSession.java", 349);
+ return stack;
+ }
+ };
+ return e;
+ }
+ @Test
+ public void testTypicalLifecycle() throws Throwable {
+ runContentCapturedTask();
+ // Verifies main frame.
+ InOrder inOrder = Mockito.inOrder(mPlatformAPIWrapperTestHelperSpy);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .createContentCaptureSession(mMockedRootContentCaptureSession, MAIN_URL);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newAutofillId(mMockedRootContentCaptureSession, mMockedRootAutofillId, MAIN_ID);
+
+ // Verifies the ViewStructure for the main frame.
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newVirtualViewStructure(
+ mMockedRootContentCaptureSession, mMockedRootAutofillId, MAIN_ID);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewAppeared(mMockedRootContentCaptureSession,
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(0));
+ verifyVirtualViewStructure(MAIN_URL, MAIN_FRAME_RECT, 0);
+
+ // Verifies the child frame.
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .createContentCaptureSession(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(0),
+ CHILD_URL);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newAutofillId(mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(0),
+ mMockedRootAutofillId, CHILD_FRAME_ID);
+
+ // Verifies the ViewStructure for the child frame.
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newVirtualViewStructure(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(0),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructuresAutofilIds.get(0),
+ CHILD_FRAME_ID);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewAppeared(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(0),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(1));
+ verifyVirtualViewStructure(null, CHILD_FRAME_RECT, 1);
+
+ // Verifies child1
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newVirtualViewStructure(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructuresAutofilIds.get(1),
+ CHILD1_ID);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewAppeared(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(2));
+ verifyVirtualViewStructure(CHILD1_TEXT, CHILD1_RECT, 2);
+
+ // Verifies child2
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .newVirtualViewStructure(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructuresAutofilIds.get(1),
+ CHILD2_ID);
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewAppeared(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mPlatformAPIWrapperTestHelper.mCreatedViewStructures.get(3));
+ verifyVirtualViewStructure(CHILD2_TEXT, CHILD2_RECT, 3);
+
+ // Modifies child2
+ runTaskAndVerifyCallback(createChild2ContentUpdateTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_TEXT_CHANGED));
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewTextChanged(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mPlatformAPIWrapperTestHelper.mCreatedAutofilIds.get(2), CHILD2_NEW_TEXT);
+
+ // Removes the child1 and child2
+ runTaskAndVerifyCallback(createRemoveChildrenTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.NOTIFY_VIEWS_DISAPPEARED));
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .notifyViewsDisappeared(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1),
+ mMockedRootAutofillId, REMOVED_IDS);
+
+ // Remove the child frame
+ runTaskAndVerifyCallback(createSessionRemovedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.DESTROY_CONTENT_CAPTURE_SESSION,
+ PlatformAPIWrapperTestHelper.NOTIFY_VIEW_DISAPPEARED));
+ inOrder.verify(mPlatformAPIWrapperTestHelperSpy)
+ .destroyContentCaptureSession(
+ mPlatformAPIWrapperTestHelper.mCreatedContentCaptureSessions.get(1));
+ }
+
+ // The below testFooException() tests mock the specific method to throw exception, then verify
+ // if it is caught by NotificationTask.
+ @Test
+ public void testCreateContentCaptureSessionException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .createContentCaptureSession(ArgumentMatchers.any(), ArgumentMatchers.any());
+ runTaskAndVerifyCallbackWithException(createContentCapturedTask(), toIntArray());
+ }
+
+ @Test
+ public void testNewAutofillIdException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .newAutofillId(
+ ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.anyLong());
+ runTaskAndVerifyCallbackWithException(createContentCapturedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION));
+ }
+
+ @Test
+ public void testNewVirtualViewStructureException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .newVirtualViewStructure(
+ ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.anyLong());
+ runTaskAndVerifyCallbackWithException(createContentCapturedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION,
+ PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID));
+ }
+
+ @Test
+ public void testNotifyViewAppearException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .notifyViewAppeared(ArgumentMatchers.any(), ArgumentMatchers.any());
+ runTaskAndVerifyCallbackWithException(createContentCapturedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.CREATE_CONTENT_CAPTURE_SESSION,
+ PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID,
+ PlatformAPIWrapperTestHelper.NEW_VIRTUAL_VIEW_STRUCTURE));
+ }
+
+ @Test
+ public void testNotifyViewTextChangedException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .notifyViewTextChanged(
+ ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
+ runContentCapturedTask();
+ // Modifies child2
+ runTaskAndVerifyCallbackWithException(createChild2ContentUpdateTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.NEW_AUTOFILL_ID));
+ }
+
+ @Test
+ public void testNotifyViewsDisappearedException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .notifyViewsDisappeared(
+ ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any());
+ runContentCapturedTask();
+ // Modifies child2
+ runTaskAndVerifyCallbackWithException(createRemoveChildrenTask(), toIntArray());
+ }
+
+ @Test
+ public void testDestroyContentCaptureSessionException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .destroyContentCaptureSession(ArgumentMatchers.any());
+ runContentCapturedTask();
+ // Modifies child2
+ runTaskAndVerifyCallbackWithException(createSessionRemovedTask(), toIntArray());
+ }
+
+ @Test
+ public void testNotifyViewDisappearedException() throws Throwable {
+ PlatformAPIWrapperTestHelper mockedApiWrapperTestHelper =
+ Mockito.spy(mPlatformAPIWrapperTestHelper);
+ PlatformAPIWrapper.setPlatformAPIWrapperImplForTesting(mockedApiWrapperTestHelper);
+ doThrow(createMainContentCaptureSessionException())
+ .when(mockedApiWrapperTestHelper)
+ .notifyViewDisappeared(ArgumentMatchers.any(), ArgumentMatchers.any());
+ runContentCapturedTask();
+ // Modifies child2
+ runTaskAndVerifyCallbackWithException(createSessionRemovedTask(),
+ toIntArray(PlatformAPIWrapperTestHelper.DESTROY_CONTENT_CAPTURE_SESSION));
+ }
+}
diff --git a/chromium/components/content_capture/common/content_capture_features.cc b/chromium/components/content_capture/common/content_capture_features.cc
index 3258e664620..58832c32788 100644
--- a/chromium/components/content_capture/common/content_capture_features.cc
+++ b/chromium/components/content_capture/common/content_capture_features.cc
@@ -16,7 +16,7 @@ const base::Feature kContentCapture{"ContentCapture",
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kContentCaptureTriggeringForExperiment{
- "ContentCaptureTriggeringForExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ContentCaptureTriggeringForExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
#else
const base::Feature kContentCapture{"ContentCapture",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/content_settings/android/cookie_controls_bridge.cc b/chromium/components/content_settings/android/cookie_controls_bridge.cc
index de8f12f299b..ce68a33812c 100644
--- a/chromium/components/content_settings/android/cookie_controls_bridge.cc
+++ b/chromium/components/content_settings/android/cookie_controls_bridge.cc
@@ -33,7 +33,7 @@ CookieControlsBridge::CookieControlsBridge(
permissions_client->GetCookieSettings(web_contents->GetBrowserContext()),
original_context ? permissions_client->GetCookieSettings(original_context)
: nullptr);
- observer_.Add(controller_.get());
+ observation_.Observe(controller_.get());
controller_->Update(web_contents);
}
diff --git a/chromium/components/content_settings/android/cookie_controls_bridge.h b/chromium/components/content_settings/android/cookie_controls_bridge.h
index a96e41847c7..67fee8c97e1 100644
--- a/chromium/components/content_settings/android/cookie_controls_bridge.h
+++ b/chromium/components/content_settings/android/cookie_controls_bridge.h
@@ -7,6 +7,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/optional.h"
+#include "base/scoped_observation.h"
#include "components/content_settings/browser/ui/cookie_controls_controller.h"
#include "components/content_settings/browser/ui/cookie_controls_view.h"
#include "components/content_settings/core/common/cookie_controls_status.h"
@@ -51,7 +52,8 @@ class CookieControlsBridge : public CookieControlsView {
base::Optional<int> blocked_cookies_;
base::Optional<int> allowed_cookies_;
std::unique_ptr<CookieControlsController> controller_;
- ScopedObserver<CookieControlsController, CookieControlsView> observer_{this};
+ base::ScopedObservation<CookieControlsController, CookieControlsView>
+ observation_{this};
DISALLOW_COPY_AND_ASSIGN(CookieControlsBridge);
};
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings.cc b/chromium/components/content_settings/browser/page_specific_content_settings.cc
index 4570fb4ce1f..5bf15c19254 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings.cc
+++ b/chromium/components/content_settings/browser/page_specific_content_settings.cc
@@ -213,18 +213,6 @@ void PageSpecificContentSettings::WebContentsHandler::OnServiceWorkerAccessed(
tscs->OnServiceWorkerAccessed(scope, allowed);
}
-void PageSpecificContentSettings::WebContentsHandler::
- RenderFrameForInterstitialPageCreated(
- content::RenderFrameHost* render_frame_host) {
- // We want to tell the renderer-side code to ignore content settings for this
- // page.
- mojo::AssociatedRemote<content_settings::mojom::ContentSettingsAgent>
- content_settings_agent;
- render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
- &content_settings_agent);
- content_settings_agent->SetAsInterstitial();
-}
-
void PageSpecificContentSettings::WebContentsHandler::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
if (!WillNavigationCreateNewPageSpecificContentSettingsOnCommit(
@@ -347,7 +335,7 @@ PageSpecificContentSettings::PageSpecificContentSettings(
delegate_->GetIsDeletionDisabledCallback()),
load_plugins_link_enabled_(true),
microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED) {
- observer_.Add(map_);
+ observation_.Observe(map_);
}
PageSpecificContentSettings::~PageSpecificContentSettings() = default;
@@ -825,10 +813,9 @@ void PageSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
void PageSpecificContentSettings::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
const ContentSettingsDetails details(primary_pattern, secondary_pattern,
- content_type, resource_identifier);
+ content_type);
if (!details.update_all() &&
// The visible URL is the URL in the URL field of a tab.
// Currently this should be matched by the |primary_pattern|.
@@ -841,8 +828,8 @@ void PageSpecificContentSettings::OnContentSettingChanged(
case ContentSettingsType::MEDIASTREAM_MIC:
case ContentSettingsType::MEDIASTREAM_CAMERA: {
const GURL media_origin = media_stream_access_origin();
- ContentSetting setting = map_->GetContentSetting(
- media_origin, media_origin, content_type, std::string());
+ ContentSetting setting =
+ map_->GetContentSetting(media_origin, media_origin, content_type);
if (content_type == ContentSettingsType::MEDIASTREAM_MIC &&
setting == CONTENT_SETTING_ALLOW) {
@@ -859,8 +846,8 @@ void PageSpecificContentSettings::OnContentSettingChanged(
break;
}
case ContentSettingsType::GEOLOCATION: {
- ContentSetting geolocation_setting = map_->GetContentSetting(
- visible_url_, visible_url_, content_type, std::string());
+ ContentSetting geolocation_setting =
+ map_->GetContentSetting(visible_url_, visible_url_, content_type);
if (geolocation_setting == CONTENT_SETTING_ALLOW)
geolocation_was_just_granted_on_site_level_ = true;
FALLTHROUGH;
@@ -877,8 +864,8 @@ void PageSpecificContentSettings::OnContentSettingChanged(
case ContentSettingsType::SOUND:
case ContentSettingsType::CLIPBOARD_READ_WRITE:
case ContentSettingsType::SENSORS: {
- ContentSetting setting = map_->GetContentSetting(
- visible_url_, visible_url_, content_type, std::string());
+ ContentSetting setting =
+ map_->GetContentSetting(visible_url_, visible_url_, content_type);
// If an indicator is shown and the content settings has changed, swap the
// indicator for the one with the opposite meaning (allowed <=> blocked).
if (setting == CONTENT_SETTING_BLOCK && status.allowed) {
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings.h b/chromium/components/content_settings/browser/page_specific_content_settings.h
index fc08ba6bbf1..7378a2f5fa5 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings.h
+++ b/chromium/components/content_settings/browser/page_specific_content_settings.h
@@ -16,7 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "components/browsing_data/content/cookie_helper.h"
#include "components/browsing_data/content/local_shared_objects_container.h"
@@ -453,8 +453,6 @@ class PageSpecificContentSettings
content::RenderFrameHost* rfh);
// content::WebContentsObserver overrides.
- void RenderFrameForInterstitialPageCreated(
- content::RenderFrameHost* render_frame_host) override;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void ReadyToCommitNavigation(
@@ -509,8 +507,7 @@ class PageSpecificContentSettings
// content_settings::Observer implementation.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
// Clears settings changed by the user via PageInfo since the last navigation.
void ClearContentSettingsChangedViaPageInfo();
@@ -563,8 +560,8 @@ class PageSpecificContentSettings
bool geolocation_was_just_granted_on_site_level_ = false;
// Observer to watch for content settings changed.
- ScopedObserver<HostContentSettingsMap, content_settings::Observer> observer_{
- this};
+ base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+ observation_{this};
// Stores content settings changed by the user via page info since the last
// navigation. Used to determine whether to display the settings in page info.
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc b/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
index 8892acafd0a..2973993821e 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
+++ b/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
@@ -423,7 +423,7 @@ TEST_F(PageSpecificContentSettingsTest,
map->SetWebsiteSettingCustomScope(
pattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::CLIPBOARD_READ_WRITE, std::string(),
+ ContentSettingsType::CLIPBOARD_READ_WRITE,
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
// Now the indicator is set to allowed.
@@ -435,7 +435,7 @@ TEST_F(PageSpecificContentSettingsTest,
// Simulate the user modifying the setting back to blocked.
map->SetWebsiteSettingCustomScope(
pattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::CLIPBOARD_READ_WRITE, std::string(),
+ ContentSettingsType::CLIPBOARD_READ_WRITE,
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
// Now the indicator is set to allowed.
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
index d0f3a2ed11e..79482df5f33 100644
--- a/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
@@ -33,7 +33,7 @@ CookieControlsController::CookieControlsController(
scoped_refptr<CookieSettings> original_cookie_settings)
: cookie_settings_(cookie_settings),
original_cookie_settings_(original_cookie_settings) {
- cookie_observer_.Add(cookie_settings_.get());
+ cookie_observation_.Observe(cookie_settings_.get());
}
CookieControlsController::~CookieControlsController() = default;
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_controller.h b/chromium/components/content_settings/browser/ui/cookie_controls_controller.h
index d9f21eefcbf..d38b8b3dc65 100644
--- a/chromium/components/content_settings/browser/ui/cookie_controls_controller.h
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_controller.h
@@ -7,6 +7,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
+#include "base/scoped_observation.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/cookie_controls_enforcement.h"
@@ -94,9 +95,9 @@ class CookieControlsController : content_settings::CookieSettings::Observer {
// This may be null.
scoped_refptr<content_settings::CookieSettings> original_cookie_settings_;
- ScopedObserver<content_settings::CookieSettings,
- content_settings::CookieSettings::Observer>
- cookie_observer_{this};
+ base::ScopedObservation<content_settings::CookieSettings,
+ content_settings::CookieSettings::Observer>
+ cookie_observation_{this};
bool should_reload_ = false;
diff --git a/chromium/components/content_settings/common/content_settings_agent.mojom b/chromium/components/content_settings/common/content_settings_agent.mojom
index 939120ec05a..0fb4272aa09 100644
--- a/chromium/components/content_settings/common/content_settings_agent.mojom
+++ b/chromium/components/content_settings/common/content_settings_agent.mojom
@@ -10,9 +10,6 @@ interface ContentSettingsAgent {
// main frame, it will also reload the frame afterwards.
SetAllowRunningInsecureContent();
- // Sent to inform the renderer that it is displaying interstitial page.
- SetAsInterstitial();
-
// Sent to inform the renderer automatic upgrades for mixed content are
// disabled.
SetDisabledMixedContentUpgrades();
diff --git a/chromium/components/content_settings/core/browser/BUILD.gn b/chromium/components/content_settings/core/browser/BUILD.gn
index 5ce9ad00c2c..2ce3bb2ed29 100644
--- a/chromium/components/content_settings/core/browser/BUILD.gn
+++ b/chromium/components/content_settings/core/browser/BUILD.gn
@@ -7,7 +7,6 @@ import("//ppapi/buildflags/buildflags.gni")
static_library("browser") {
sources = [
- "content_settings_constraints.h",
"content_settings_default_provider.cc",
"content_settings_default_provider.h",
"content_settings_details.cc",
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
index 687b4c8fd40..6e67b3720ea 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -40,6 +40,10 @@ const char kObsoleteFullscreenDefaultPref[] =
#if !defined(OS_ANDROID)
const char kObsoleteMouseLockDefaultPref[] =
"profile.default_content_setting_values.mouselock";
+const char kObsoletePluginsDefaultPref[] =
+ "profile.default_content_setting_values.plugins";
+const char kObsoletePluginsDataDefaultPref[] =
+ "profile.default_content_setting_values.flash_data";
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
@@ -124,6 +128,7 @@ void DefaultProvider::RegisterProfilePrefs(
registry->RegisterIntegerPref(
kObsoleteMouseLockDefaultPref, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterIntegerPref(kObsoletePluginsDataDefaultPref, 0);
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
@@ -136,9 +141,9 @@ void DefaultProvider::RegisterProfilePrefs(
#endif // !defined(OS_ANDROID)
}
-DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
+DefaultProvider::DefaultProvider(PrefService* prefs, bool off_the_record)
: prefs_(prefs),
- is_incognito_(incognito),
+ is_off_the_record_(off_the_record),
updating_preferences_(false) {
DCHECK(prefs_);
@@ -161,10 +166,6 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
IntToContentSetting(prefs_->GetInteger(
GetPrefName(ContentSettingsType::IMAGES))),
CONTENT_SETTING_NUM_SETTINGS);
- UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultPluginsSetting",
- IntToContentSetting(prefs_->GetInteger(
- GetPrefName(ContentSettingsType::PLUGINS))),
- CONTENT_SETTING_NUM_SETTINGS);
#endif
#if !defined(OS_IOS)
@@ -235,7 +236,6 @@ bool DefaultProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& in_value,
const ContentSettingConstraints& constraints) {
DCHECK(CalledOnValidThread());
@@ -253,7 +253,7 @@ bool DefaultProvider::SetWebsiteSetting(
// The default settings may not be directly modified for OTR sessions.
// Instead, they are synced to the main profile's setting.
- if (is_incognito_)
+ if (is_off_the_record_)
return true;
{
@@ -269,26 +269,20 @@ bool DefaultProvider::SetWebsiteSetting(
WriteToPref(content_type, value.get());
}
- NotifyObservers(ContentSettingsPattern(),
- ContentSettingsPattern(),
- content_type,
- ResourceIdentifier());
+ NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
+ content_type);
return true;
}
std::unique_ptr<RuleIterator> DefaultProvider::GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
- bool incognito) const {
- // The default provider never has incognito-specific settings.
- if (incognito)
+ bool off_the_record) const {
+ // The default provider never has off-the-record-specific settings.
+ if (off_the_record)
return nullptr;
base::AutoLock lock(lock_);
- if (!resource_identifier.empty())
- return nullptr;
-
auto it = default_settings_.find(content_type);
if (it == default_settings_.end()) {
NOTREACHED();
@@ -387,10 +381,8 @@ void DefaultProvider::OnPreferenceChanged(const std::string& name) {
}
}
- NotifyObservers(ContentSettingsPattern(),
- ContentSettingsPattern(),
- content_type,
- ResourceIdentifier());
+ NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
+ content_type);
}
std::unique_ptr<base::Value> DefaultProvider::ReadFromPref(
@@ -400,7 +392,7 @@ std::unique_ptr<base::Value> DefaultProvider::ReadFromPref(
}
void DefaultProvider::DiscardOrMigrateObsoletePreferences() {
- if (is_incognito_)
+ if (is_off_the_record_)
return;
// These prefs were never stored on iOS/Android so they don't need to be
// deleted.
@@ -408,14 +400,8 @@ void DefaultProvider::DiscardOrMigrateObsoletePreferences() {
prefs_->ClearPref(kObsoleteFullscreenDefaultPref);
#if !defined(OS_ANDROID)
prefs_->ClearPref(kObsoleteMouseLockDefaultPref);
-
- // ALLOW-by-default is an obsolete pref value for plugins (Flash). Erase that
- // pref and fall back to the default behavior - but preserve other values.
- const std::string& plugins_pref = GetPrefName(ContentSettingsType::PLUGINS);
- if (IntToContentSetting(prefs_->GetInteger(plugins_pref)) ==
- ContentSetting::CONTENT_SETTING_ALLOW) {
- prefs_->ClearPref(plugins_pref);
- }
+ prefs_->ClearPref(kObsoletePluginsDefaultPref);
+ prefs_->ClearPref(kObsoletePluginsDataDefaultPref);
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.h b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
index 79688ba940f..c27323c6db4 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
@@ -30,21 +30,18 @@ class DefaultProvider : public ObservableProvider {
public:
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
- DefaultProvider(PrefService* prefs,
- bool incognito);
+ DefaultProvider(PrefService* prefs, bool off_the_record);
~DefaultProvider() override;
// ProviderInterface implementations.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
- bool incognito) const override;
+ bool off_the_record) const override;
bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraint = {}) override;
@@ -82,8 +79,8 @@ class DefaultProvider : public ObservableProvider {
PrefService* prefs_;
- // Whether this settings map is for an Incognito session.
- const bool is_incognito_;
+ // Whether this settings map is for an off-the-record session.
+ const bool is_off_the_record_;
// Used around accesses to the |default_settings_| object to guarantee
// thread safety.
diff --git a/chromium/components/content_settings/core/browser/content_settings_details.cc b/chromium/components/content_settings/core/browser/content_settings_details.cc
index f5a16246493..46291691585 100644
--- a/chromium/components/content_settings/core/browser/content_settings_details.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_details.cc
@@ -7,10 +7,7 @@
ContentSettingsDetails::ContentSettingsDetails(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType type,
- const std::string& resource_identifier)
+ ContentSettingsType type)
: primary_pattern_(primary_pattern),
secondary_pattern_(secondary_pattern),
- type_(type),
- resource_identifier_(resource_identifier) {
-}
+ type_(type) {}
diff --git a/chromium/components/content_settings/core/browser/content_settings_details.h b/chromium/components/content_settings/core/browser/content_settings_details.h
index 915c81f244f..fd36c0a7248 100644
--- a/chromium/components/content_settings/core/browser/content_settings_details.h
+++ b/chromium/components/content_settings/core/browser/content_settings_details.h
@@ -22,8 +22,7 @@ class ContentSettingsDetails {
// Update the setting that matches this pattern/content type/resource.
ContentSettingsDetails(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType type,
- const std::string& resource_identifier);
+ ContentSettingsType type);
// The item pattern whose settings have changed.
const ContentSettingsPattern& primary_pattern() const {
@@ -44,11 +43,6 @@ class ContentSettingsDetails {
// The type of the pattern whose settings have changed.
ContentSettingsType type() const { return type_; }
- // The resource identifier for the settings type that has changed.
- const std::string& resource_identifier() const {
- return resource_identifier_;
- }
-
// True if all types should be updated. If update_all() is false, this will
// be false as well (although the reverse does not hold true).
bool update_all_types() const {
@@ -59,7 +53,6 @@ class ContentSettingsDetails {
ContentSettingsPattern primary_pattern_;
ContentSettingsPattern secondary_pattern_;
ContentSettingsType type_;
- std::string resource_identifier_;
DISALLOW_COPY_AND_ASSIGN(ContentSettingsDetails);
};
diff --git a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.cc b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.cc
index c3a346e83e3..c4d3f65a62c 100644
--- a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.cc
@@ -40,17 +40,14 @@ EphemeralProvider::~EphemeralProvider() {}
std::unique_ptr<RuleIterator> EphemeralProvider::GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const {
- return content_settings_rules_.GetRuleIterator(content_type,
- resource_identifier, nullptr);
+ return content_settings_rules_.GetRuleIterator(content_type, nullptr);
}
bool EphemeralProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& in_value,
const ContentSettingConstraints& /*constraint*/) {
DCHECK(CalledOnValidThread());
@@ -64,28 +61,24 @@ bool EphemeralProvider::SetWebsiteSetting(
// specific sites/origins defined by the |primary_pattern| and the
// |secondary_pattern|. Default settings are handled by the DefaultProvider.
if (primary_pattern == ContentSettingsPattern::Wildcard() &&
- secondary_pattern == ContentSettingsPattern::Wildcard() &&
- resource_identifier.empty()) {
+ secondary_pattern == ContentSettingsPattern::Wildcard()) {
return false;
}
std::unique_ptr<base::Value> value(std::move(in_value));
if (value) {
content_settings_rules_.SetValue(
- primary_pattern, secondary_pattern, content_type, resource_identifier,
+ primary_pattern, secondary_pattern, content_type,
store_last_modified_ ? clock_->Now() : base::Time(), std::move(*value),
{});
- NotifyObservers(primary_pattern, secondary_pattern, content_type,
- resource_identifier);
+ NotifyObservers(primary_pattern, secondary_pattern, content_type);
} else {
// If the value exists, delete it.
if (content_settings_rules_.GetLastModified(
- primary_pattern, secondary_pattern, content_type,
- resource_identifier) != base::Time()) {
+ primary_pattern, secondary_pattern, content_type) != base::Time()) {
content_settings_rules_.DeleteValue(primary_pattern, secondary_pattern,
- content_type, resource_identifier);
- NotifyObservers(primary_pattern, secondary_pattern, content_type,
- resource_identifier);
+ content_type);
+ NotifyObservers(primary_pattern, secondary_pattern, content_type);
}
}
return true;
@@ -94,34 +87,25 @@ bool EphemeralProvider::SetWebsiteSetting(
base::Time EphemeralProvider::GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) {
+ ContentSettingsType content_type) {
DCHECK(CalledOnValidThread());
return content_settings_rules_.GetLastModified(
- primary_pattern, secondary_pattern, content_type, resource_identifier);
+ primary_pattern, secondary_pattern, content_type);
}
void EphemeralProvider::ClearAllContentSettingsRules(
ContentSettingsType content_type) {
DCHECK(CalledOnValidThread());
- // Get all resource identifiers for this |content_type|.
- std::set<ResourceIdentifier> resource_identifiers;
- for (OriginIdentifierValueMap::EntryMap::const_iterator entry =
- content_settings_rules_.begin();
- entry != content_settings_rules_.end(); entry++) {
- if (entry->first.content_type == content_type)
- resource_identifiers.insert(entry->first.resource_identifier);
- }
+ if (content_settings_rules_.find(content_type) ==
+ content_settings_rules_.end())
+ return;
- for (const ResourceIdentifier& resource_identifier : resource_identifiers)
- content_settings_rules_.DeleteValues(content_type, resource_identifier);
+ content_settings_rules_.DeleteValues(content_type);
- if (!resource_identifiers.empty()) {
- NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
- content_type, ResourceIdentifier());
- }
+ NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
+ content_type);
}
void EphemeralProvider::ShutdownOnUIThread() {
diff --git a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.h b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.h
index 8f7fd6bc96e..703b253b6a6 100644
--- a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider.h
@@ -26,13 +26,11 @@ class EphemeralProvider : public UserModifiableProvider {
// UserModifiableProvider implementations.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const override;
bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraints = {}) override;
void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
@@ -40,8 +38,7 @@ class EphemeralProvider : public UserModifiableProvider {
base::Time GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) override;
+ ContentSettingsType content_type) override;
void SetClockForTesting(base::Clock* clock) override;
void SetSupportedTypesForTesting(
diff --git a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider_unittest.cc
index 75093088760..ec82970f4be 100644
--- a/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_ephemeral_provider_unittest.cc
@@ -52,11 +52,11 @@ TEST_F(ContentSettingsEphemeralProviderTest, EphemeralTypeStorageAndRetrieval) {
ContentSettingsPattern::FromString("https://example.com");
EXPECT_TRUE(provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW)));
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_NE(nullptr, rule_iterator);
EXPECT_TRUE(rule_iterator->HasNext());
content_settings::Rule rule = rule_iterator->Next();
@@ -64,11 +64,10 @@ TEST_F(ContentSettingsEphemeralProviderTest, EphemeralTypeStorageAndRetrieval) {
// Overwrite previous value.
EXPECT_TRUE(provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)));
- rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ rule_iterator = provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_NE(nullptr, rule_iterator);
EXPECT_TRUE(rule_iterator->HasNext());
rule = rule_iterator->Next();
@@ -81,11 +80,10 @@ TEST_F(ContentSettingsEphemeralProviderTest, PersistentTypeRejection) {
ContentSettingsPattern::FromString("https://example.com");
std::unique_ptr<base::Value> value(new base::Value(false));
- EXPECT_FALSE(provider()->SetWebsiteSetting(site_pattern, site_pattern,
- persistent_type(), std::string(),
- std::move(value)));
+ EXPECT_FALSE(provider()->SetWebsiteSetting(
+ site_pattern, site_pattern, persistent_type(), std::move(value)));
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(persistent_type(), std::string(), false);
+ provider()->GetRuleIterator(persistent_type(), false);
EXPECT_EQ(nullptr, rule_iterator);
}
@@ -100,10 +98,10 @@ TEST_F(ContentSettingsEphemeralProviderTest, LastModifiedTime) {
base::Time t1 = test_clock.Now();
provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
base::Time last_modified = provider()->GetWebsiteSettingLastModified(
- site_pattern, site_pattern, ephemeral_type(0), std::string());
+ site_pattern, site_pattern, ephemeral_type(0));
EXPECT_EQ(t1, last_modified);
}
@@ -115,14 +113,14 @@ TEST_F(ContentSettingsEphemeralProviderTest, ClearAll) {
ContentSettingsPattern::FromString("https://example2.com");
provider()->SetWebsiteSetting(
- site_pattern1, site_pattern1, ephemeral_type(0), std::string(),
+ site_pattern1, site_pattern1, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
provider()->SetWebsiteSetting(
- site_pattern2, site_pattern2, ephemeral_type(0), std::string(),
+ site_pattern2, site_pattern2, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
provider()->ClearAllContentSettingsRules(ephemeral_type(0));
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_EQ(nullptr, rule_iterator);
}
@@ -132,14 +130,14 @@ TEST_F(ContentSettingsEphemeralProviderTest, SelectiveClear) {
ContentSettingsPattern::FromString("https://example.com");
provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(1), std::string(),
+ site_pattern, site_pattern, ephemeral_type(1),
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
provider()->ClearAllContentSettingsRules(ephemeral_type(0));
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(1), std::string(), false);
+ provider()->GetRuleIterator(ephemeral_type(1), false);
EXPECT_NE(nullptr, rule_iterator);
}
@@ -149,11 +147,11 @@ TEST_F(ContentSettingsEphemeralProviderTest, StorageIsEphemeral) {
ContentSettingsPattern::FromString("https://example.com");
provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
Reset();
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_EQ(nullptr, rule_iterator);
}
@@ -163,16 +161,15 @@ TEST_F(ContentSettingsEphemeralProviderTest, DeleteValueByPassingNull) {
ContentSettingsPattern::FromString("https://example.com");
provider()->SetWebsiteSetting(
- site_pattern, site_pattern, ephemeral_type(0), std::string(),
+ site_pattern, site_pattern, ephemeral_type(0),
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
std::unique_ptr<RuleIterator> rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_NE(nullptr, rule_iterator);
provider()->SetWebsiteSetting(site_pattern, site_pattern, ephemeral_type(0),
- std::string(), nullptr);
- rule_iterator =
- provider()->GetRuleIterator(ephemeral_type(0), std::string(), false);
+ nullptr);
+ rule_iterator = provider()->GetRuleIterator(ephemeral_type(0), false);
EXPECT_EQ(nullptr, rule_iterator);
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_global_value_map.cc b/chromium/components/content_settings/core/browser/content_settings_global_value_map.cc
index 57ae5598d93..b2cd549dee5 100644
--- a/chromium/components/content_settings/core/browser/content_settings_global_value_map.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_global_value_map.cc
@@ -43,11 +43,7 @@ GlobalValueMap::GlobalValueMap() {}
GlobalValueMap::~GlobalValueMap() {}
std::unique_ptr<RuleIterator> GlobalValueMap::GetRuleIterator(
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const {
- if (!resource_identifier.empty())
- return nullptr;
-
+ ContentSettingsType content_type) const {
auto it = settings_.find(content_type);
if (it == settings_.end())
return nullptr;
diff --git a/chromium/components/content_settings/core/browser/content_settings_global_value_map.h b/chromium/components/content_settings/core/browser/content_settings_global_value_map.h
index 99407a1ab08..816e0e5dba6 100644
--- a/chromium/components/content_settings/core/browser/content_settings_global_value_map.h
+++ b/chromium/components/content_settings/core/browser/content_settings_global_value_map.h
@@ -26,8 +26,7 @@ class GlobalValueMap {
// Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const;
+ ContentSettingsType content_type) const;
void SetContentSetting(ContentSettingsType content_type,
ContentSetting setting);
ContentSetting GetContentSetting(ContentSettingsType content_type) const;
diff --git a/chromium/components/content_settings/core/browser/content_settings_info.cc b/chromium/components/content_settings/core/browser/content_settings_info.cc
index b70e9dc0438..b2c86ec43f3 100644
--- a/chromium/components/content_settings/core/browser/content_settings_info.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_info.cc
@@ -12,13 +12,13 @@ namespace content_settings {
ContentSettingsInfo::ContentSettingsInfo(
const WebsiteSettingsInfo* website_settings_info,
- const std::vector<std::string>& whitelisted_schemes,
+ const std::vector<std::string>& allowlisted_schemes,
const std::set<ContentSetting>& valid_settings,
IncognitoBehavior incognito_behavior,
StorageBehavior storage_behavior,
OriginRestriction origin_restriction)
: website_settings_info_(website_settings_info),
- whitelisted_schemes_(whitelisted_schemes),
+ allowlisted_schemes_(allowlisted_schemes),
valid_settings_(valid_settings),
incognito_behavior_(incognito_behavior),
storage_behavior_(storage_behavior),
diff --git a/chromium/components/content_settings/core/browser/content_settings_info.h b/chromium/components/content_settings/core/browser/content_settings_info.h
index 834913d7ecc..3d479113a2b 100644
--- a/chromium/components/content_settings/core/browser/content_settings_info.h
+++ b/chromium/components/content_settings/core/browser/content_settings_info.h
@@ -50,7 +50,7 @@ class ContentSettingsInfo {
// This object does not take ownership of |website_settings_info|.
ContentSettingsInfo(const WebsiteSettingsInfo* website_settings_info,
- const std::vector<std::string>& whitelisted_schemes,
+ const std::vector<std::string>& allowlisted_schemes,
const std::set<ContentSetting>& valid_settings,
IncognitoBehavior incognito_behavior,
StorageBehavior storage_behavior,
@@ -60,8 +60,8 @@ class ContentSettingsInfo {
const WebsiteSettingsInfo* website_settings_info() const {
return website_settings_info_;
}
- const std::vector<std::string>& whitelisted_schemes() const {
- return whitelisted_schemes_;
+ const std::vector<std::string>& allowlisted_schemes() const {
+ return allowlisted_schemes_;
}
// Gets the original default setting for a particular content type.
@@ -76,7 +76,7 @@ class ContentSettingsInfo {
private:
const WebsiteSettingsInfo* website_settings_info_;
- const std::vector<std::string> whitelisted_schemes_;
+ const std::vector<std::string> allowlisted_schemes_;
const std::set<ContentSetting> valid_settings_;
const IncognitoBehavior incognito_behavior_;
const StorageBehavior storage_behavior_;
diff --git a/chromium/components/content_settings/core/browser/content_settings_observable_provider.cc b/chromium/components/content_settings/core/browser/content_settings_observable_provider.cc
index b4a36212653..d8b1dd61ff6 100644
--- a/chromium/components/content_settings/core/browser/content_settings_observable_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_observable_provider.cc
@@ -27,11 +27,10 @@ void ObservableProvider::RemoveObserver(Observer* observer) {
void ObservableProvider::NotifyObservers(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
for (Observer& observer : observer_list_) {
observer.OnContentSettingChanged(primary_pattern, secondary_pattern,
- content_type, resource_identifier);
+ content_type);
}
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_observable_provider.h b/chromium/components/content_settings/core/browser/content_settings_observable_provider.h
index 7fcdab72195..29c44138993 100644
--- a/chromium/components/content_settings/core/browser/content_settings_observable_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_observable_provider.h
@@ -26,8 +26,7 @@ class ObservableProvider : public ProviderInterface {
protected:
void NotifyObservers(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier);
+ ContentSettingsType content_type);
void RemoveAllObservers();
bool CalledOnValidThread();
diff --git a/chromium/components/content_settings/core/browser/content_settings_observer.h b/chromium/components/content_settings/core/browser/content_settings_observer.h
index db53e74272e..569c3b3fe09 100644
--- a/chromium/components/content_settings/core/browser/content_settings_observer.h
+++ b/chromium/components/content_settings/core/browser/content_settings_observer.h
@@ -17,8 +17,7 @@ class Observer {
virtual void OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) = 0;
+ ContentSettingsType content_type) = 0;
protected:
virtual ~Observer() {}
diff --git a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
index 59279a36509..a7d40da7b7d 100644
--- a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
@@ -55,19 +55,6 @@ class RuleIteratorImpl : public RuleIterator {
} // namespace
-OriginIdentifierValueMap::EntryMapKey::EntryMapKey(
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier)
- : content_type(content_type),
- resource_identifier(resource_identifier) {
-}
-
-bool OriginIdentifierValueMap::EntryMapKey::operator<(
- const OriginIdentifierValueMap::EntryMapKey& other) const {
- return std::tie(content_type, resource_identifier) <
- std::tie(other.content_type, other.resource_identifier);
-}
-
OriginIdentifierValueMap::PatternPair::PatternPair(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern)
@@ -90,17 +77,15 @@ OriginIdentifierValueMap::ValueEntry::~ValueEntry() {}
std::unique_ptr<RuleIterator> OriginIdentifierValueMap::GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
base::Lock* lock) const {
- EntryMapKey key(content_type, resource_identifier);
- // We access |entries_| here, so we need to lock |lock_| first. The lock must
- // be passed to the |RuleIteratorImpl| in a locked state, so that nobody can
- // access |entries_| after |find()| but before the |RuleIteratorImpl| is
+ // We access |entries_| here, so we need to lock |auto_lock| first. The lock
+ // must be passed to the |RuleIteratorImpl| in a locked state, so that nobody
+ // can access |entries_| after |find()| but before the |RuleIteratorImpl| is
// created.
std::unique_ptr<base::AutoLock> auto_lock;
if (lock)
- auto_lock.reset(new base::AutoLock(*lock));
- auto it = entries_.find(key);
+ auto_lock = std::make_unique<base::AutoLock>(*lock);
+ auto it = entries_.find(content_type);
if (it == entries_.end())
return nullptr;
return std::unique_ptr<RuleIterator>(new RuleIteratorImpl(
@@ -121,10 +106,8 @@ OriginIdentifierValueMap::~OriginIdentifierValueMap() {}
const base::Value* OriginIdentifierValueMap::GetValue(
const GURL& primary_url,
const GURL& secondary_url,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const {
- EntryMapKey key(content_type, resource_identifier);
- auto it = entries_.find(key);
+ ContentSettingsType content_type) const {
+ auto it = entries_.find(content_type);
if (it == entries_.end())
return nullptr;
@@ -143,14 +126,12 @@ const base::Value* OriginIdentifierValueMap::GetValue(
base::Time OriginIdentifierValueMap::GetLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const {
+ ContentSettingsType content_type) const {
DCHECK(primary_pattern.IsValid());
DCHECK(secondary_pattern.IsValid());
- EntryMapKey key(content_type, resource_identifier);
PatternPair patterns(primary_pattern, secondary_pattern);
- auto it = entries_.find(key);
+ auto it = entries_.find(content_type);
if (it == entries_.end())
return base::Time();
auto r = it->second.find(patterns);
@@ -163,7 +144,6 @@ void OriginIdentifierValueMap::SetValue(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
base::Time last_modified,
base::Value value,
const ContentSettingConstraints& constraints) {
@@ -172,9 +152,8 @@ void OriginIdentifierValueMap::SetValue(
// TODO(raymes): Remove this after we track down the cause of
// crbug.com/531548.
CHECK_NE(ContentSettingsType::DEFAULT, content_type);
- EntryMapKey key(content_type, resource_identifier);
PatternPair patterns(primary_pattern, secondary_pattern);
- ValueEntry* entry = &entries_[key][patterns];
+ ValueEntry* entry = &entries_[content_type][patterns];
entry->value = std::move(value);
entry->last_modified = last_modified;
entry->expiration = constraints.expiration;
@@ -182,13 +161,11 @@ void OriginIdentifierValueMap::SetValue(
}
void OriginIdentifierValueMap::DeleteValue(
- const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) {
- EntryMapKey key(content_type, resource_identifier);
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
PatternPair patterns(primary_pattern, secondary_pattern);
- auto it = entries_.find(key);
+ auto it = entries_.find(content_type);
if (it == entries_.end())
return;
it->second.erase(patterns);
@@ -196,11 +173,8 @@ void OriginIdentifierValueMap::DeleteValue(
entries_.erase(it);
}
-void OriginIdentifierValueMap::DeleteValues(
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) {
- EntryMapKey key(content_type, resource_identifier);
- entries_.erase(key);
+void OriginIdentifierValueMap::DeleteValues(ContentSettingsType content_type) {
+ entries_.erase(content_type);
}
void OriginIdentifierValueMap::clear() {
diff --git a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
index d502d2e8be3..515f849db57 100644
--- a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
+++ b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.h
@@ -13,8 +13,8 @@
#include "base/macros.h"
#include "base/time/time.h"
-#include "components/content_settings/core/browser/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
class GURL;
@@ -29,14 +29,6 @@ class RuleIterator;
class OriginIdentifierValueMap {
public:
- struct EntryMapKey {
- ContentSettingsType content_type;
- ResourceIdentifier resource_identifier;
- EntryMapKey(ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier);
- bool operator<(const OriginIdentifierValueMap::EntryMapKey& other) const;
- };
-
struct PatternPair {
ContentSettingsPattern primary_pattern;
ContentSettingsPattern secondary_pattern;
@@ -55,7 +47,7 @@ class OriginIdentifierValueMap {
};
typedef std::map<PatternPair, ValueEntry> Rules;
- typedef std::map<EntryMapKey, Rules> EntryMap;
+ typedef std::map<ContentSettingsType, Rules> EntryMap;
EntryMap::iterator begin() {
return entries_.begin();
@@ -73,6 +65,10 @@ class OriginIdentifierValueMap {
return entries_.end();
}
+ EntryMap::iterator find(ContentSettingsType content_type) {
+ return entries_.find(content_type);
+ }
+
bool empty() const {
return size() == 0u;
}
@@ -87,53 +83,42 @@ class OriginIdentifierValueMap {
// Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
base::Lock* lock) const;
OriginIdentifierValueMap();
~OriginIdentifierValueMap();
// Returns a weak pointer to the value for the given |primary_pattern|,
- // |secondary_pattern|, |content_type|, |resource_identifier| tuple. If
+ // |secondary_pattern|, |content_type| tuple. If
// no value is stored for the passed parameter |NULL| is returned.
- const base::Value* GetValue(
- const GURL& primary_url,
- const GURL& secondary_url,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const;
+ const base::Value* GetValue(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type) const;
- base::Time GetLastModified(
- const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) const;
+ base::Time GetLastModified(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) const;
// Sets the |value| for the given |primary_pattern|, |secondary_pattern|,
- // |content_type|, |resource_identifier| tuple. The caller can also store a
+ // |content_type| tuple. The caller can also store a
// |last_modified| date for each value. The |constraints| will be used to
// constrain the setting to a valid time-range and lifetime model if
// specified.
void SetValue(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
base::Time last_modified,
base::Value value,
const ContentSettingConstraints& constraints);
// Deletes the map entry for the given |primary_pattern|,
- // |secondary_pattern|, |content_type|, |resource_identifier| tuple.
- void DeleteValue(
- const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier);
+ // |secondary_pattern|, |content_type| tuple.
+ void DeleteValue(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type);
- // Deletes all map entries for the given |content_type| and
- // |resource_identifier|.
- void DeleteValues(
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier);
+ // Deletes all map entries for the given |content_type|.
+ void DeleteValues(ContentSettingsType content_type);
// Clears all map entries.
void clear();
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
index 14d7f21e3f8..6b210067aed 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -61,12 +61,6 @@ const PrefsForManagedContentSettingsMapEntry
ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW},
{prefs::kManagedNotificationsBlockedForUrls,
ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_BLOCK},
- {prefs::kManagedPluginsAllowedForUrls, ContentSettingsType::PLUGINS,
- CONTENT_SETTING_ALLOW,
- content_settings::WildcardsInPrimaryPattern::NOT_ALLOWED},
- {prefs::kManagedPluginsBlockedForUrls, ContentSettingsType::PLUGINS,
- CONTENT_SETTING_BLOCK,
- content_settings::WildcardsInPrimaryPattern::NOT_ALLOWED},
{prefs::kManagedPopupsAllowedForUrls, ContentSettingsType::POPUPS,
CONTENT_SETTING_ALLOW},
{prefs::kManagedPopupsBlockedForUrls, ContentSettingsType::POPUPS,
@@ -147,7 +141,6 @@ const PolicyProvider::PrefsForManagedDefaultMapEntry
prefs::kManagedDefaultInsecureContentSetting},
{ContentSettingsType::NOTIFICATIONS,
prefs::kManagedDefaultNotificationsSetting},
- {ContentSettingsType::PLUGINS, prefs::kManagedDefaultPluginsSetting},
{ContentSettingsType::POPUPS, prefs::kManagedDefaultPopupsSetting},
{ContentSettingsType::BLUETOOTH_GUARD,
prefs::kManagedDefaultWebBluetoothGuardSetting},
@@ -181,8 +174,6 @@ void PolicyProvider::RegisterProfilePrefs(
registry->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls);
registry->RegisterListPref(prefs::kManagedNotificationsAllowedForUrls);
registry->RegisterListPref(prefs::kManagedNotificationsBlockedForUrls);
- registry->RegisterListPref(prefs::kManagedPluginsAllowedForUrls);
- registry->RegisterListPref(prefs::kManagedPluginsBlockedForUrls);
registry->RegisterListPref(prefs::kManagedPopupsAllowedForUrls);
registry->RegisterListPref(prefs::kManagedPopupsBlockedForUrls);
registry->RegisterListPref(prefs::kManagedWebUsbAllowDevicesForUrls);
@@ -219,8 +210,6 @@ void PolicyProvider::RegisterProfilePrefs(
CONTENT_SETTING_DEFAULT);
registry->RegisterIntegerPref(prefs::kManagedDefaultMediaStreamSetting,
CONTENT_SETTING_DEFAULT);
- registry->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting,
- CONTENT_SETTING_DEFAULT);
registry->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting,
CONTENT_SETTING_DEFAULT);
registry->RegisterIntegerPref(prefs::kManagedDefaultWebBluetoothGuardSetting,
@@ -269,8 +258,6 @@ PolicyProvider::PolicyProvider(PrefService* prefs) : prefs_(prefs) {
prefs::kManagedNotificationsAllowedForUrls, callback);
pref_change_registrar_.Add(
prefs::kManagedNotificationsBlockedForUrls, callback);
- pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, callback);
- pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, callback);
pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, callback);
pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, callback);
pref_change_registrar_.Add(prefs::kManagedWebUsbAskForUrls, callback);
@@ -310,7 +297,6 @@ PolicyProvider::PolicyProvider(PrefService* prefs) : prefs_(prefs) {
prefs::kManagedDefaultNotificationsSetting, callback);
pref_change_registrar_.Add(
prefs::kManagedDefaultMediaStreamSetting, callback);
- pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, callback);
pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, callback);
pref_change_registrar_.Add(prefs::kManagedDefaultWebBluetoothGuardSetting,
callback);
@@ -335,14 +321,12 @@ PolicyProvider::~PolicyProvider() {
std::unique_ptr<RuleIterator> PolicyProvider::GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const {
- return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_);
+ return value_map_.GetRuleIterator(content_type, &lock_);
}
std::unique_ptr<RuleIterator> PolicyProvider::GetDiscardedRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const {
auto it = discarded_rules_value_map_.find(content_type);
if (it == discarded_rules_value_map_.end()) {
@@ -425,8 +409,7 @@ void PolicyProvider::GetContentSettingsFromPreferences(
// Don't set a timestamp for policy settings.
value_map->SetValue(
- pattern_pair.first, secondary_pattern, content_type,
- ResourceIdentifier(), base::Time(),
+ pattern_pair.first, secondary_pattern, content_type, base::Time(),
base::Value(kPrefsForManagedContentSettingsMap[i].setting), {});
}
}
@@ -519,7 +502,7 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
value_map->SetValue(pattern, ContentSettingsPattern::Wildcard(),
ContentSettingsType::AUTO_SELECT_CERTIFICATE,
- std::string(), base::Time(), setting.Clone(), {});
+ base::Time(), setting.Clone(), {});
}
}
@@ -547,22 +530,15 @@ void PolicyProvider::UpdateManagedDefaultSetting(
prefs_->IsManagedPreference(entry.pref_name));
base::AutoLock auto_lock(lock_);
int setting = prefs_->GetInteger(entry.pref_name);
- // TODO(wfh): Remove once HDB is enabled by default.
- if (entry.pref_name == prefs::kManagedDefaultPluginsSetting) {
- static constexpr base::Feature kIgnoreDefaultPluginsSetting = {
- "IgnoreDefaultPluginsSetting", base::FEATURE_DISABLED_BY_DEFAULT};
- if (base::FeatureList::IsEnabled(kIgnoreDefaultPluginsSetting))
- setting = CONTENT_SETTING_DEFAULT;
- }
if (setting == CONTENT_SETTING_DEFAULT) {
value_map_.DeleteValue(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
- entry.content_type, std::string());
+ entry.content_type);
} else if (info->IsSettingValid(IntToContentSetting(setting))) {
// Don't set a timestamp for policy settings.
value_map_.SetValue(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(), entry.content_type,
- std::string(), base::Time(), base::Value(setting), {});
+ base::Time(), base::Value(setting), {});
}
}
@@ -581,7 +557,6 @@ bool PolicyProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraints) {
return false;
@@ -624,8 +599,6 @@ void PolicyProvider::OnPreferenceChanged(const std::string& name) {
name == prefs::kManagedJavaScriptBlockedForUrls ||
name == prefs::kManagedNotificationsAllowedForUrls ||
name == prefs::kManagedNotificationsBlockedForUrls ||
- name == prefs::kManagedPluginsAllowedForUrls ||
- name == prefs::kManagedPluginsBlockedForUrls ||
name == prefs::kManagedPopupsAllowedForUrls ||
name == prefs::kManagedPopupsBlockedForUrls ||
name == prefs::kManagedWebUsbAskForUrls ||
@@ -641,7 +614,7 @@ void PolicyProvider::OnPreferenceChanged(const std::string& name) {
}
NotifyObservers(ContentSettingsPattern(), ContentSettingsPattern(),
- ContentSettingsType::DEFAULT, std::string());
+ ContentSettingsType::DEFAULT);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.h b/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
index f92702ba187..52a7f3392e5 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
@@ -33,19 +33,16 @@ class PolicyProvider : public ObservableProvider {
// ProviderInterface implementations.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const override;
std::unique_ptr<RuleIterator> GetDiscardedRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const override;
bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraint = {}) override;
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.cc b/chromium/components/content_settings/core/browser/content_settings_pref.cc
index cd57f1a2a0b..dcfb882f82c 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.cc
@@ -34,15 +34,6 @@ const char kExpirationPath[] = "expiration";
const char kSessionModelPath[] = "model";
const char kSettingPath[] = "setting";
const char kLastModifiedPath[] = "last_modified";
-const char kPerResourceIdentifierPrefName[] = "per_resource";
-
-// If the given content type supports resource identifiers in user preferences,
-// returns true and sets |pref_key| to the key in the content settings
-// dictionary under which per-resource content settings are stored.
-// Otherwise, returns false.
-bool SupportsResourceIdentifiers(ContentSettingsType content_type) {
- return content_type == ContentSettingsType::PLUGINS;
-}
bool IsValueAllowedForType(const base::Value* value, ContentSettingsType type) {
const content_settings::ContentSettingsInfo* info =
@@ -140,8 +131,7 @@ ContentSettingsPref::ContentSettingsPref(
off_the_record_(off_the_record),
restore_session_(restore_session),
updating_preferences_(false),
- notify_callback_(notify_callback),
- allow_resource_identifiers_(false) {
+ notify_callback_(notify_callback) {
DCHECK(prefs_);
ReadContentSettingsFromPref();
@@ -154,23 +144,15 @@ ContentSettingsPref::ContentSettingsPref(
ContentSettingsPref::~ContentSettingsPref() {}
std::unique_ptr<RuleIterator> ContentSettingsPref::GetRuleIterator(
- const ResourceIdentifier& resource_identifier,
bool off_the_record) const {
- // Resource Identifiers have been supported by the API but never used by any
- // users of the API.
- // TODO(crbug.com/754178): remove |resource_identifier| from the API.
- DCHECK(resource_identifier.empty() || allow_resource_identifiers_);
-
if (off_the_record)
- return off_the_record_value_map_.GetRuleIterator(
- content_type_, resource_identifier, &lock_);
- return value_map_.GetRuleIterator(content_type_, resource_identifier, &lock_);
+ return off_the_record_value_map_.GetRuleIterator(content_type_, &lock_);
+ return value_map_.GetRuleIterator(content_type_, &lock_);
}
bool ContentSettingsPref::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier,
base::Time modified_time,
std::unique_ptr<base::Value>&& in_value,
const ContentSettingConstraints& constraints) {
@@ -178,13 +160,7 @@ bool ContentSettingsPref::SetWebsiteSetting(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(prefs_);
DCHECK(primary_pattern != ContentSettingsPattern::Wildcard() ||
- secondary_pattern != ContentSettingsPattern::Wildcard() ||
- (!resource_identifier.empty() && allow_resource_identifiers_));
-
- // Resource Identifiers have been supported by the API but never used by any
- // users of the API.
- // TODO(crbug.com/754178): remove |resource_identifier| from the API.
- DCHECK(resource_identifier.empty() || allow_resource_identifiers_);
+ secondary_pattern != ContentSettingsPattern::Wildcard());
// At this point take the ownership of the |in_value|.
std::unique_ptr<base::Value> value(std::move(in_value));
@@ -198,35 +174,32 @@ bool ContentSettingsPref::SetWebsiteSetting(
base::AutoLock auto_lock(lock_);
if (value) {
map_to_modify->SetValue(primary_pattern, secondary_pattern, content_type_,
- resource_identifier, modified_time,
- value->Clone(), constraints);
+ modified_time, value->Clone(), constraints);
} else {
map_to_modify->DeleteValue(primary_pattern, secondary_pattern,
- content_type_, resource_identifier);
+ content_type_);
}
}
// Update the content settings preference.
if (!off_the_record_) {
- UpdatePref(primary_pattern, secondary_pattern, resource_identifier,
- modified_time, value.get(), constraints);
+ UpdatePref(primary_pattern, secondary_pattern, modified_time, value.get(),
+ constraints);
}
- notify_callback_.Run(primary_pattern, secondary_pattern, content_type_,
- resource_identifier);
+ notify_callback_.Run(primary_pattern, secondary_pattern, content_type_);
return true;
}
base::Time ContentSettingsPref::GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier) {
+ const ContentSettingsPattern& secondary_pattern) {
OriginIdentifierValueMap* map_to_modify = &off_the_record_value_map_;
if (!off_the_record_)
map_to_modify = &value_map_;
base::Time last_modified = map_to_modify->GetLastModified(
- primary_pattern, secondary_pattern, content_type_, resource_identifier);
+ primary_pattern, secondary_pattern, content_type_);
return last_modified;
}
@@ -258,7 +231,7 @@ void ContentSettingsPref::ClearAllContentSettingsRules() {
}
notify_callback_.Run(ContentSettingsPattern(), ContentSettingsPattern(),
- content_type_, ResourceIdentifier());
+ content_type_);
}
size_t ContentSettingsPref::GetNumExceptions() {
@@ -347,29 +320,6 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
continue;
}
- if (SupportsResourceIdentifiers(content_type_)) {
- const base::DictionaryValue* resource_dictionary = nullptr;
- if (settings_dictionary->GetDictionary(kPerResourceIdentifierPrefName,
- &resource_dictionary)) {
- base::Time last_modified = GetTimeStamp(settings_dictionary);
- for (base::DictionaryValue::Iterator j(*resource_dictionary);
- !j.IsAtEnd(); j.Advance()) {
- const std::string& resource_identifier(j.key());
- int setting = CONTENT_SETTING_DEFAULT;
- bool is_integer = j.value().GetAsInteger(&setting);
- DCHECK(is_integer);
- DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
- std::unique_ptr<base::Value> setting_ptr(new base::Value(setting));
- DCHECK(IsValueAllowedForType(setting_ptr.get(), content_type_));
- // Per resource settings store a single timestamps for all resources.
- value_map_.SetValue(pattern_pair.first, pattern_pair.second,
- content_type_, resource_identifier, last_modified,
- setting_ptr->Clone(),
- {expiration, session_model});
- }
- }
- }
-
const base::Value* value = nullptr;
settings_dictionary->GetWithoutPathExpansion(kSettingPath, &value);
if (value) {
@@ -377,7 +327,7 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
DCHECK(IsValueAllowedForType(value, content_type_));
value_map_.SetValue(std::move(pattern_pair.first),
std::move(pattern_pair.second), content_type_,
- ResourceIdentifier(), last_modified, value->Clone(),
+ last_modified, value->Clone(),
{expiration, session_model});
}
}
@@ -418,13 +368,12 @@ void ContentSettingsPref::OnPrefChanged() {
ReadContentSettingsFromPref();
notify_callback_.Run(ContentSettingsPattern(), ContentSettingsPattern(),
- content_type_, ResourceIdentifier());
+ content_type_);
}
void ContentSettingsPref::UpdatePref(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier,
const base::Time last_modified,
const base::Value* value,
const ContentSettingConstraints& constraints) {
@@ -452,78 +401,32 @@ void ContentSettingsPref::UpdatePref(
}
if (settings_dictionary) {
- if (SupportsResourceIdentifiers(content_type_) &&
- !resource_identifier.empty()) {
- std::unique_ptr<prefs::DictionaryValueUpdate> resource_dictionary;
- found = settings_dictionary->GetDictionary(
- kPerResourceIdentifierPrefName, &resource_dictionary);
- if (!found) {
- if (value == nullptr)
- return; // Nothing to remove. Exit early.
- resource_dictionary =
- settings_dictionary->SetDictionaryWithoutPathExpansion(
- kPerResourceIdentifierPrefName,
- std::make_unique<base::DictionaryValue>());
- }
- // Update resource dictionary.
- if (value == nullptr) {
- resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
- nullptr);
- if (resource_dictionary->empty()) {
- settings_dictionary->RemoveWithoutPathExpansion(
- kPerResourceIdentifierPrefName, nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kLastModifiedPath,
- nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kExpirationPath,
- nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kSessionModelPath,
- nullptr);
- }
- } else {
- resource_dictionary->SetWithoutPathExpansion(resource_identifier,
- value->CreateDeepCopy());
- // Update timestamp for whole resource dictionary.
- settings_dictionary->SetKey(
- kLastModifiedPath,
- base::Value(base::NumberToString(
- last_modified.ToDeltaSinceWindowsEpoch().InMicroseconds())));
- settings_dictionary->SetKey(
- kExpirationPath,
- base::Value(base::NumberToString(
- constraints.expiration.ToDeltaSinceWindowsEpoch()
- .InMicroseconds())));
- settings_dictionary->SetKey(
- kSessionModelPath,
- base::Value(static_cast<int>(constraints.session_model)));
- }
+ // Update settings dictionary.
+ if (value == nullptr) {
+ settings_dictionary->RemoveWithoutPathExpansion(kSettingPath, nullptr);
+ settings_dictionary->RemoveWithoutPathExpansion(kLastModifiedPath,
+ nullptr);
+ settings_dictionary->RemoveWithoutPathExpansion(kExpirationPath,
+ nullptr);
+ settings_dictionary->RemoveWithoutPathExpansion(kSessionModelPath,
+ nullptr);
} else {
- // Update settings dictionary.
- if (value == nullptr) {
- settings_dictionary->RemoveWithoutPathExpansion(kSettingPath,
- nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kLastModifiedPath,
- nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kExpirationPath,
- nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kSessionModelPath,
- nullptr);
- } else {
- settings_dictionary->SetWithoutPathExpansion(kSettingPath,
- value->CreateDeepCopy());
- settings_dictionary->SetKey(
- kLastModifiedPath,
- base::Value(base::NumberToString(
- last_modified.ToDeltaSinceWindowsEpoch().InMicroseconds())));
- settings_dictionary->SetKey(
- kExpirationPath,
- base::Value(base::NumberToString(
- constraints.expiration.ToDeltaSinceWindowsEpoch()
- .InMicroseconds())));
- settings_dictionary->SetKey(
- kSessionModelPath,
- base::Value(static_cast<int>(constraints.session_model)));
- }
+ settings_dictionary->SetWithoutPathExpansion(kSettingPath,
+ value->CreateDeepCopy());
+ settings_dictionary->SetKey(
+ kLastModifiedPath,
+ base::Value(base::NumberToString(
+ last_modified.ToDeltaSinceWindowsEpoch().InMicroseconds())));
+ settings_dictionary->SetKey(
+ kExpirationPath,
+ base::Value(base::NumberToString(
+ constraints.expiration.ToDeltaSinceWindowsEpoch()
+ .InMicroseconds())));
+ settings_dictionary->SetKey(
+ kSessionModelPath,
+ base::Value(static_cast<int>(constraints.session_model)));
}
+
// Remove the settings dictionary if it is empty.
if (settings_dictionary->empty()) {
pattern_pairs_settings->RemoveWithoutPathExpansion(pattern_str,
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.h b/chromium/components/content_settings/core/browser/content_settings_pref.h
index 90d776a8528..60e8c5e1640 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.h
@@ -32,8 +32,7 @@ class ContentSettingsPref {
public:
typedef base::RepeatingCallback<void(const ContentSettingsPattern&,
const ContentSettingsPattern&,
- ContentSettingsType,
- const std::string&)>
+ ContentSettingsType)>
NotifyObserversCallback;
ContentSettingsPref(ContentSettingsType content_type,
@@ -47,12 +46,10 @@ class ContentSettingsPref {
// Returns nullptr to indicate the RuleIterator is empty.
std::unique_ptr<RuleIterator> GetRuleIterator(
- const ResourceIdentifier& resource_identifier,
bool off_the_record) const;
bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier,
base::Time modified_time,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraints);
@@ -60,8 +57,7 @@ class ContentSettingsPref {
// Returns the |last_modified| date of a setting.
base::Time GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier);
+ const ContentSettingsPattern& secondary_pattern);
void ClearPref();
@@ -71,12 +67,6 @@ class ContentSettingsPref {
// Tries to lock |lock_|. If successful, returns true and releases the lock.
bool TryLockForTesting() const;
- void set_allow_resource_identifiers_for_testing() {
- allow_resource_identifiers_ = true;
- }
- void reset_allow_resource_identifiers_for_testing() {
- allow_resource_identifiers_ = false;
- }
private:
// Reads all content settings exceptions from the preference and loads them
@@ -92,7 +82,6 @@ class ContentSettingsPref {
// preference changes.
void UpdatePref(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- const ResourceIdentifier& resource_identifier,
const base::Time last_modified,
const base::Value* value,
const ContentSettingConstraints& constraints);
@@ -133,10 +122,6 @@ class ContentSettingsPref {
base::ThreadChecker thread_checker_;
- // Used for setting preferences with resource identifiers to simmulate legacy
- // prefs that did have resource identifiers set.
- bool allow_resource_identifiers_;
-
DISALLOW_COPY_AND_ASSIGN(ContentSettingsPref);
};
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
index 6d2a5c0f23e..9ffac847adc 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -26,6 +26,7 @@
#include "components/content_settings/core/browser/website_settings_registry.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry.h"
@@ -48,6 +49,10 @@ const char kObsoleteFullscreenExceptionsPref[] =
#if !defined(OS_ANDROID)
const char kObsoleteMouseLockExceptionsPref[] =
"profile.content_settings.exceptions.mouselock";
+const char kObsoletePluginsExceptionsPref[] =
+ "profile.content_settings.exceptions.plugins";
+const char kObsoletePluginsDataExceptionsPref[] =
+ "profile.content_settings.exceptions.flash_data";
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
@@ -93,6 +98,7 @@ void PrefProvider::RegisterProfilePrefs(
registry->RegisterDictionaryPref(
kObsoleteMouseLockExceptionsPref,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterDictionaryPref(kObsoletePluginsDataExceptionsPref);
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
@@ -144,13 +150,6 @@ PrefProvider::PrefProvider(PrefService* prefs,
info->pref_name(), off_the_record_, restore_session,
base::BindRepeating(&PrefProvider::Notify,
base::Unretained(this)))));
- } else if (info->type() == ContentSettingsType::PLUGINS) {
- // TODO(https://crbug.com/850062): Remove after M71, two milestones after
- // migration of the Flash permissions to ephemeral provider.
- flash_content_settings_pref_ = std::make_unique<ContentSettingsPref>(
- info->type(), prefs_, &pref_change_registrar_, info->pref_name(),
- off_the_record_, restore_session,
- base::BindRepeating(&PrefProvider::Notify, base::Unretained(this)));
}
}
@@ -173,20 +172,17 @@ PrefProvider::~PrefProvider() {
std::unique_ptr<RuleIterator> PrefProvider::GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool off_the_record) const {
if (!supports_type(content_type))
return nullptr;
- return GetPref(content_type)
- ->GetRuleIterator(resource_identifier, off_the_record);
+ return GetPref(content_type)->GetRuleIterator(off_the_record);
}
bool PrefProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& in_value,
const ContentSettingConstraints& constraints) {
DCHECK(CalledOnValidThread());
@@ -201,25 +197,30 @@ bool PrefProvider::SetWebsiteSetting(
// sites/origins defined by the |primary_pattern| and the |secondary_pattern|.
// Default settings are handled by the |DefaultProvider|.
if (primary_pattern == ContentSettingsPattern::Wildcard() &&
- secondary_pattern == ContentSettingsPattern::Wildcard() &&
- resource_identifier.empty()) {
+ secondary_pattern == ContentSettingsPattern::Wildcard()) {
return false;
}
base::Time modified_time =
store_last_modified_ ? clock_->Now() : base::Time();
+ // If SessionModel is OneTime, we know for sure that a one time permission
+ // has been set by the One Time Provider, therefore we reset a potentially
+ // existing Allow Always setting.
+ if (constraints.session_model == SessionModel::OneTime) {
+ DCHECK_EQ(content_type, ContentSettingsType::GEOLOCATION);
+ in_value = nullptr;
+ }
+
return GetPref(content_type)
- ->SetWebsiteSetting(primary_pattern, secondary_pattern,
- resource_identifier, modified_time,
+ ->SetWebsiteSetting(primary_pattern, secondary_pattern, modified_time,
std::move(in_value), constraints);
}
base::Time PrefProvider::GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) {
+ ContentSettingsType content_type) {
DCHECK(CalledOnValidThread());
DCHECK(prefs_);
@@ -227,8 +228,7 @@ base::Time PrefProvider::GetWebsiteSettingLastModified(
return base::Time();
return GetPref(content_type)
- ->GetWebsiteSettingLastModified(primary_pattern, secondary_pattern,
- resource_identifier);
+ ->GetWebsiteSettingLastModified(primary_pattern, secondary_pattern);
}
void PrefProvider::ClearAllContentSettingsRules(
@@ -239,14 +239,6 @@ void PrefProvider::ClearAllContentSettingsRules(
if (supports_type(content_type))
GetPref(content_type)->ClearAllContentSettingsRules();
- // TODO(https://crbug.com/850062): Remove after M71, two milestones after
- // migration of the Flash permissions to ephemeral provider.
- // |flash_content_settings_pref_| is not null only if Flash permissions are
- // ephemeral and handled in EphemeralProvider.
- if (content_type == ContentSettingsType::PLUGINS &&
- flash_content_settings_pref_) {
- flash_content_settings_pref_->ClearAllContentSettingsRules();
- }
}
void PrefProvider::ShutdownOnUIThread() {
@@ -271,15 +263,10 @@ ContentSettingsPref* PrefProvider::GetPref(ContentSettingsType type) const {
return it->second.get();
}
-void PrefProvider::Notify(
- const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
- NotifyObservers(primary_pattern,
- secondary_pattern,
- content_type,
- resource_identifier);
+void PrefProvider::Notify(const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ ContentSettingsType content_type) {
+ NotifyObservers(primary_pattern, secondary_pattern, content_type);
}
void PrefProvider::DiscardOrMigrateObsoletePreferences() {
@@ -294,6 +281,8 @@ void PrefProvider::DiscardOrMigrateObsoletePreferences() {
prefs_->ClearPref(kObsoleteFullscreenExceptionsPref);
#if !defined(OS_ANDROID)
prefs_->ClearPref(kObsoleteMouseLockExceptionsPref);
+ prefs_->ClearPref(kObsoletePluginsExceptionsPref);
+ prefs_->ClearPref(kObsoletePluginsDataExceptionsPref);
#endif // !defined(OS_ANDROID)
#endif // !defined(OS_IOS)
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
index 4a9ce3a8eb9..7c16ebc5e33 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -45,12 +45,10 @@ class PrefProvider : public UserModifiableProvider {
// UserModifiableProvider implementations.
std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool off_the_record) const override;
bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraints) override;
void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
@@ -58,8 +56,7 @@ class PrefProvider : public UserModifiableProvider {
base::Time GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) override;
+ ContentSettingsType content_type) override;
void SetClockForTesting(base::Clock* clock) override;
void ClearPrefs();
@@ -71,8 +68,7 @@ class PrefProvider : public UserModifiableProvider {
void Notify(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier);
+ ContentSettingsType content_type);
// Clean up the obsolete preferences from the user's profile.
void DiscardOrMigrateObsoletePreferences();
@@ -95,10 +91,6 @@ class PrefProvider : public UserModifiableProvider {
std::map<ContentSettingsType, std::unique_ptr<ContentSettingsPref>>
content_settings_prefs_;
- // TODO(https://crbug.com/850062): Remove after M71, two milestones after
- // migration of the Flash permissions to ephemeral provider.
- std::unique_ptr<ContentSettingsPref> flash_content_settings_pref_;
-
base::ThreadChecker thread_checker_;
base::Clock* clock_;
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
index 150bfe0958f..1ebaa09ee63 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gtest_util.h"
@@ -43,49 +43,6 @@ constexpr char kLastModifiedKey[] = "last_modified";
constexpr char kSettingKey[] = "setting";
constexpr char kTagKey[] = "tag";
-#if BUILDFLAG(ENABLE_PLUGINS)
-constexpr char kPluginsContentSettingPrefName[] = "content_settings.plugins";
-constexpr char kPerResourceTag[] = "per_resource";
-
-// Tests that a particular pref has the expected values with and without a
-// resource id
-void LegacyPersistedPluginTests(
- ContentSettingsPref* content_settings_pref,
- const std::string& pattern,
- const GURL& host,
- const std::string& resource,
- ContentSetting no_resource_id_perf_expected_value,
- ContentSetting with_resource_id_perf_expected_value) {
- auto pattern_pair = ParsePatternString(pattern);
- // Retrieving the pref without a resource id for pattern works and
- // its value is the expected one.
- EXPECT_EQ(no_resource_id_perf_expected_value,
- content_settings::ValueToContentSetting(
- content_settings::TestUtils::GetContentSettingValueAndPatterns(
- content_settings_pref->GetRuleIterator("", false).get(),
- host, GURL(), &(pattern_pair.first), &(pattern_pair.second))
- .get()));
-
- // Retrieving the pref with a resource id will throw.
- EXPECT_DCHECK_DEATH(
- content_settings_pref->GetRuleIterator(resource, false)->HasNext());
-
- // Allow resource ids for testing in order to test that the perf was correctly
- // loaded from the json. This basically verifies that we did build a correct
- // json and it was parsed and loaded without any issues.
- content_settings_pref->set_allow_resource_identifiers_for_testing();
- EXPECT_EQ(
- with_resource_id_perf_expected_value,
- content_settings::ValueToContentSetting(
- content_settings::TestUtils::GetContentSettingValueAndPatterns(
- content_settings_pref->GetRuleIterator(resource, false).get(),
- host, GURL(), &(pattern_pair.first), &(pattern_pair.second))
- .get()));
- content_settings_pref->reset_allow_resource_identifiers_for_testing();
-}
-
-#endif // BUILDFLAG(ENABLE_PLUGINS)
-
// Creates a JSON dictionary representing a dummy content setting exception
// value in preferences. The setting will be marked with the |tag| like so:
//
@@ -179,8 +136,8 @@ TEST(ContentSettingsPref, CanonicalizationWhileReadingFromPrefs) {
// and setting.
std::vector<CanonicalPatternToTag> patterns_to_tags_in_memory;
- auto rule_iterator = content_settings_pref.GetRuleIterator(
- std::string() /* resource_identifier */, false /* is_incognito */);
+ auto rule_iterator =
+ content_settings_pref.GetRuleIterator(false /* is_incognito */);
while (rule_iterator->HasNext()) {
auto rule = rule_iterator->Next();
patterns_to_tags_in_memory.emplace_back(
@@ -206,82 +163,6 @@ TEST(ContentSettingsPref, CanonicalizationWhileReadingFromPrefs) {
testing::UnorderedElementsAreArray(kExpectedPatternsToTags));
}
-#if BUILDFLAG(ENABLE_PLUGINS)
-// Test that a legagcy persisted plugin setting does not cause errors and has
-// a sane behaviour.
-TEST(ContentSettingsPref, LegacyPersistedPluginSetting) {
- const GURL kHost1("http://example.com/");
- const GURL kHost2("http://other-example.com/");
- constexpr char kPattern1[] = "http://example.com,*";
- constexpr char kPattern2[] = "http://other-example.com,*";
- constexpr char kResource[] = "someplugin";
-
- TestingPrefServiceSimple prefs;
- prefs.registry()->RegisterDictionaryPref(kPluginsContentSettingPrefName);
-
- // Build a json simulating some pre-existing plugin settings situation where
- // a mix of per_resource and regular settings are present:
- // "content_settings.plugins": {
- // kPattern1: {
- // "setting": 1, <-- CONTENT_SETTING_ALLOW
- // "per_resource": {
- // "someplugin": 2 <-- CONTENT_SETTING_BLOCK
- // }
- // }
- // kPattern2: {
- // "per_resource": {
- // "someplugin": 1 <-- CONTENT_SETTING_ALLOW
- // }
- // }
- // }
-
- auto original_pref_value = std::make_unique<base::DictionaryValue>();
-
- base::Value per_resource_value1(base::Value::Type::DICTIONARY);
- per_resource_value1.SetKey(kResource, base::Value(CONTENT_SETTING_BLOCK));
-
- base::Value pref_value1(base::Value::Type::DICTIONARY);
- pref_value1.SetKey(kLastModifiedKey, base::Value("13189876543210000"));
- pref_value1.SetKey(kSettingKey, base::Value(CONTENT_SETTING_ALLOW));
- pref_value1.SetKey(kPerResourceTag, std::move(per_resource_value1));
-
- original_pref_value->SetKey(kPattern1, std::move(pref_value1));
-
- base::Value per_resource_value2(base::Value::Type::DICTIONARY);
- per_resource_value2.SetKey(kResource, base::Value(CONTENT_SETTING_ALLOW));
-
- base::Value pref_value2(base::Value::Type::DICTIONARY);
- pref_value2.SetKey(kLastModifiedKey, base::Value("13189876543210000"));
- pref_value2.SetKey(kPerResourceTag, std::move(per_resource_value2));
-
- original_pref_value->SetKey(kPattern2, std::move(pref_value2));
-
- prefs.SetUserPref(kPluginsContentSettingPrefName,
- std::move(original_pref_value));
-
- PrefChangeRegistrar registrar;
- registrar.Init(&prefs);
- ContentSettingsPref content_settings_pref(
- ContentSettingsType::PLUGINS, &prefs, &registrar,
- kPluginsContentSettingPrefName, false, false, base::DoNothing());
-
- // For kPattern1 retrieving the setting without a resource id returns the
- // CONTENT_SETTING_ALLOW value and retrieving it with the resource id (after
- // allowing resource ids for testing) returns CONTENT_SETTING_BLOCK.
- LegacyPersistedPluginTests(&content_settings_pref, kPattern1, kHost1,
- kResource, CONTENT_SETTING_ALLOW,
- CONTENT_SETTING_BLOCK);
-
- // For kPattern2 retrieving the setting without a resource id returns the
- // CONTENT_SETTING_DEFAULT value since it was not set in the first place and
- // retrieving it with the resource id (after allowing resource ids for
- // testing) returns CONTENT_SETTING_ALLOW.
- LegacyPersistedPluginTests(&content_settings_pref, kPattern2, kHost2,
- kResource, CONTENT_SETTING_DEFAULT,
- CONTENT_SETTING_ALLOW);
-}
-#endif // BUILDFLAG(ENABLE_PLUGINS)
-
// If we are reading from prefs and we have any persistend settings that have
// expired we should remove these to prevent unbounded growth and bloat.
TEST(ContentSettingsPref, ExpirationWhileReadingFromPrefs) {
@@ -321,8 +202,8 @@ TEST(ContentSettingsPref, ExpirationWhileReadingFromPrefs) {
// Verify that the |value_map| contains the expected content setting patterns
// and setting.
std::vector<CanonicalPatternToTag> patterns_to_tags_in_memory;
- auto rule_iterator = content_settings_pref.GetRuleIterator(
- std::string() /* resource_identifier */, false /* is_incognito */);
+ auto rule_iterator =
+ content_settings_pref.GetRuleIterator(false /* is_incognito */);
while (rule_iterator->HasNext()) {
auto rule = rule_iterator->Next();
patterns_to_tags_in_memory.emplace_back(
@@ -382,8 +263,7 @@ TEST(ContentSettingsPref, LegacyLastModifiedLoad) {
base::Time retrieved_last_modified =
content_settings_pref.GetWebsiteSettingLastModified(
ContentSettingsPattern::FromString("http://example.com"),
- ContentSettingsPattern::Wildcard(),
- /*resource_identifier=*/std::string());
+ ContentSettingsPattern::Wildcard());
EXPECT_EQ(last_modified, retrieved_last_modified);
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider.cc b/chromium/components/content_settings/core/browser/content_settings_provider.cc
index f46f9682a4e..cbc351b2d7c 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_provider.cc
@@ -7,7 +7,6 @@
namespace content_settings {
std::unique_ptr<RuleIterator> ProviderInterface::GetDiscardedRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const {
return std::make_unique<EmptyRuleIterator>();
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider.h b/chromium/components/content_settings/core/browser/content_settings_provider.h
index b23e3c7bf80..7dfbaeff2ff 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_provider.h
@@ -11,9 +11,9 @@
#include <string>
#include "base/values.h"
-#include "components/content_settings/core/browser/content_settings_constraints.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
class ContentSettingsPattern;
@@ -35,7 +35,6 @@ class ProviderInterface {
// Returns nullptr to indicate the RuleIterator is empty.
virtual std::unique_ptr<RuleIterator> GetRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const = 0;
// Returns a |RuleIterator| over the discarded content setting rules stored
@@ -45,7 +44,6 @@ class ProviderInterface {
// mode.
virtual std::unique_ptr<RuleIterator> GetDiscardedRuleIterator(
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
bool incognito) const;
// Asks the provider to set the website setting for a particular
@@ -60,7 +58,6 @@ class ProviderInterface {
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
std::unique_ptr<base::Value>&& value,
const ContentSettingConstraints& constraints) = 0;
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
index c3b4d94fc7c..8a682fb7baa 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
@@ -19,67 +19,57 @@ TEST(ContentSettingsProviderTest, Mock) {
MockProvider mock_provider(false);
mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::PLUGINS, "java_plugin",
+ pattern, pattern, ContentSettingsType::NOTIFICATIONS,
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::PLUGINS,
- "java_plugin", false));
+ EXPECT_EQ(
+ CONTENT_SETTING_BLOCK,
+ TestUtils::GetContentSetting(&mock_provider, url, url,
+ ContentSettingsType::NOTIFICATIONS, false));
std::unique_ptr<base::Value> value_ptr(TestUtils::GetContentSettingValue(
- &mock_provider, url, url, ContentSettingsType::PLUGINS, "java_plugin",
- false));
+ &mock_provider, url, url, ContentSettingsType::NOTIFICATIONS, false));
int int_value = -1;
value_ptr->GetAsInteger(&int_value);
EXPECT_EQ(CONTENT_SETTING_BLOCK, IntToContentSetting(int_value));
- EXPECT_EQ(CONTENT_SETTING_DEFAULT,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::PLUGINS,
- "flash_plugin", false));
+ EXPECT_EQ(
+ CONTENT_SETTING_DEFAULT,
+ TestUtils::GetContentSetting(&mock_provider, url, url,
+ ContentSettingsType::GEOLOCATION, false));
EXPECT_EQ(nullptr, TestUtils::GetContentSettingValue(
- &mock_provider, url, url, ContentSettingsType::PLUGINS,
- "flash_plugin", false));
- EXPECT_EQ(CONTENT_SETTING_DEFAULT,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::GEOLOCATION,
- std::string(), false));
- EXPECT_EQ(nullptr,
- TestUtils::GetContentSettingValue(&mock_provider, url, url,
- ContentSettingsType::GEOLOCATION,
- std::string(), false));
+ &mock_provider, url, url,
+ ContentSettingsType::GEOLOCATION, false));
bool owned = mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::PLUGINS, "java_plugin",
+ pattern, pattern, ContentSettingsType::NOTIFICATIONS,
std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
EXPECT_TRUE(owned);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::PLUGINS,
- "java_plugin", false));
+ EXPECT_EQ(
+ CONTENT_SETTING_ALLOW,
+ TestUtils::GetContentSetting(&mock_provider, url, url,
+ ContentSettingsType::NOTIFICATIONS, false));
mock_provider.set_read_only(true);
std::unique_ptr<base::Value> value(new base::Value(CONTENT_SETTING_BLOCK));
- owned = mock_provider.SetWebsiteSetting(pattern, pattern,
- ContentSettingsType::PLUGINS,
- "java_plugin", std::move(value));
+ owned = mock_provider.SetWebsiteSetting(
+ pattern, pattern, ContentSettingsType::NOTIFICATIONS, std::move(value));
EXPECT_FALSE(owned);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::PLUGINS,
- "java_plugin", false));
+ EXPECT_EQ(
+ CONTENT_SETTING_ALLOW,
+ TestUtils::GetContentSetting(&mock_provider, url, url,
+ ContentSettingsType::NOTIFICATIONS, false));
EXPECT_TRUE(mock_provider.read_only());
mock_provider.set_read_only(false);
owned = mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::PLUGINS, "java_plugin",
+ pattern, pattern, ContentSettingsType::NOTIFICATIONS,
std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
EXPECT_TRUE(owned);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- TestUtils::GetContentSetting(&mock_provider, url, url,
- ContentSettingsType::PLUGINS,
- "java_plugin", false));
+ EXPECT_EQ(
+ CONTENT_SETTING_BLOCK,
+ TestUtils::GetContentSetting(&mock_provider, url, url,
+ ContentSettingsType::NOTIFICATIONS, false));
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry.cc b/chromium/components/content_settings/core/browser/content_settings_registry.cc
index 24fdb2c10f9..c4c777cd8d4 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.cc
@@ -30,22 +30,22 @@ base::LazyInstance<ContentSettingsRegistry>::DestructorAtExit
// TODO(raymes): These overloaded functions make the registration code clearer.
// When initializer lists are available they won't be needed. The initializer
// list can be implicitly or explicitly converted to a std::vector.
-std::vector<std::string> WhitelistedSchemes() {
+std::vector<std::string> AllowlistedSchemes() {
return std::vector<std::string>();
}
-std::vector<std::string> WhitelistedSchemes(const char* scheme1) {
+std::vector<std::string> AllowlistedSchemes(const char* scheme1) {
const char* schemes[] = {scheme1};
return std::vector<std::string>(schemes, schemes + base::size(schemes));
}
-std::vector<std::string> WhitelistedSchemes(const char* scheme1,
+std::vector<std::string> AllowlistedSchemes(const char* scheme1,
const char* scheme2) {
const char* schemes[] = {scheme1, scheme2};
return std::vector<std::string>(schemes, schemes + base::size(schemes));
}
-std::vector<std::string> WhitelistedSchemes(const char* scheme1,
+std::vector<std::string> AllowlistedSchemes(const char* scheme1,
const char* scheme2,
const char* scheme3) {
const char* schemes[] = {scheme1, scheme2, scheme3};
@@ -142,7 +142,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::COOKIES, "cookies", CONTENT_SETTING_ALLOW,
WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_SESSION_ONLY),
WebsiteSettingsInfo::COOKIES_SCOPE,
@@ -153,7 +153,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::IMAGES, "images", CONTENT_SETTING_ALLOW,
WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
@@ -164,7 +164,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::JAVASCRIPT, "javascript", CONTENT_SETTING_ALLOW,
WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
@@ -176,7 +176,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::PLUGINS, "plugins", CONTENT_SETTING_BLOCK,
WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK,
CONTENT_SETTING_DETECT_IMPORTANT_CONTENT),
@@ -188,7 +188,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::POPUPS, "popups", CONTENT_SETTING_BLOCK,
WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
@@ -198,7 +198,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
Register(ContentSettingsType::GEOLOCATION, "geolocation", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -210,7 +210,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::NOTIFICATIONS, "notifications",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -224,7 +224,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::MEDIASTREAM_MIC, "media-stream-mic",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -236,7 +236,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::MEDIASTREAM_CAMERA, "media-stream-camera",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -248,7 +248,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::PPAPI_BROKER, "ppapi-broker",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
@@ -259,7 +259,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::AUTOMATIC_DOWNLOADS, "automatic-downloads",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
kExtensionScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
@@ -274,7 +274,7 @@ void ContentSettingsRegistry::Init() {
// out the kPermissionDelegation feature. We may want to make it syncable
// again sometime in the future. See https://crbug.com/879954 for details.
Register(ContentSettingsType::MIDI_SYSEX, "midi-sysex", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -288,7 +288,7 @@ void ContentSettingsRegistry::Init() {
GetInitialDefaultContentSettingForProtectedMediaIdentifier();
Register(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
"protected-media-identifier", protected_media_identifier_setting,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -302,7 +302,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::DURABLE_STORAGE, "durable-storage",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -314,7 +314,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::BACKGROUND_SYNC, "background-sync",
CONTENT_SETTING_ALLOW, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -324,7 +324,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::AUTOPLAY, "autoplay", CONTENT_SETTING_ALLOW,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -334,7 +334,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
Register(ContentSettingsType::SOUND, "sound", CONTENT_SETTING_ALLOW,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -345,7 +345,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::ADS, "subresource-filter",
CONTENT_SETTING_BLOCK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -360,7 +360,7 @@ void ContentSettingsRegistry::Init() {
: CONTENT_SETTING_ALLOW;
Register(ContentSettingsType::LEGACY_COOKIE_ACCESS, "legacy-cookie-access",
legacy_cookie_access_initial_default,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
@@ -374,7 +374,7 @@ void ContentSettingsRegistry::Init() {
// content setting.
Register(ContentSettingsType::PROTOCOL_HANDLERS, "protocol-handler",
CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(), ValidSettings(),
+ AllowlistedSchemes(), ValidSettings(),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE,
@@ -383,7 +383,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::MIXEDSCRIPT, "mixed-script",
CONTENT_SETTING_BLOCK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
@@ -393,7 +393,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::BLUETOOTH_GUARD, "bluetooth-guard",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -404,7 +404,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::ACCESSIBILITY_EVENTS, "accessibility-events",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -418,7 +418,7 @@ void ContentSettingsRegistry::Init() {
// DeviceOrientationEvents and DeviceMotionEvents are only fired in secure
// contexts.
Register(ContentSettingsType::SENSORS, "sensors", CONTENT_SETTING_ALLOW,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -429,7 +429,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::CLIPBOARD_READ_WRITE, "clipboard",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme),
+ AllowlistedSchemes(kChromeUIScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -441,7 +441,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::PAYMENT_HANDLER, "payment-handler",
CONTENT_SETTING_ALLOW, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -451,7 +451,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::USB_GUARD, "usb-guard", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -462,7 +462,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::SERIAL_GUARD, "serial-guard",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
@@ -472,7 +472,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::PERIODIC_BACKGROUND_SYNC,
"periodic-background-sync", CONTENT_SETTING_ALLOW,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -483,7 +483,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::BLUETOOTH_SCANNING, "bluetooth-scanning",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::DESKTOP |
@@ -493,7 +493,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::HID_GUARD, "hid-guard", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
WebsiteSettingsRegistry::DESKTOP,
@@ -503,7 +503,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::FILE_SYSTEM_WRITE_GUARD,
"file-system-write-guard", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -514,7 +514,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::FILE_SYSTEM_READ_GUARD,
"file-system-read-guard", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -524,7 +524,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::NFC, "nfc", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -535,7 +535,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::VR, "vr", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -546,7 +546,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
Register(ContentSettingsType::AR, "ar", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -558,7 +558,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::STORAGE_ACCESS, "storage-access",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK, CONTENT_SETTING_SESSION_ONLY),
WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
@@ -569,7 +569,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::CAMERA_PAN_TILT_ZOOM, "camera-pan-tilt-zoom",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
+ AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -581,7 +581,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::WINDOW_PLACEMENT, "window-placement",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::SYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -593,7 +593,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::INSECURE_PRIVATE_NETWORK,
"insecure-private-network", CONTENT_SETTING_BLOCK,
- WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
@@ -602,7 +602,7 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
Register(ContentSettingsType::FONT_ACCESS, "font-access", CONTENT_SETTING_ASK,
- WebsiteSettingsInfo::SYNCABLE, WhitelistedSchemes(),
+ WebsiteSettingsInfo::SYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -613,7 +613,7 @@ void ContentSettingsRegistry::Init() {
Register(ContentSettingsType::IDLE_DETECTION, "idle-detection",
CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
- WhitelistedSchemes(),
+ AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -628,7 +628,7 @@ void ContentSettingsRegistry::Register(
const std::string& name,
ContentSetting initial_default_value,
WebsiteSettingsInfo::SyncStatus sync_status,
- const std::vector<std::string>& whitelisted_schemes,
+ const std::vector<std::string>& allowlisted_schemes,
const std::set<ContentSetting>& valid_settings,
WebsiteSettingsInfo::ScopingType scoping_type,
Platforms platforms,
@@ -653,7 +653,7 @@ void ContentSettingsRegistry::Register(
DCHECK(!base::Contains(content_settings_info_, type));
content_settings_info_[type] = std::make_unique<ContentSettingsInfo>(
- website_settings_info, whitelisted_schemes, valid_settings,
+ website_settings_info, allowlisted_schemes, valid_settings,
incognito_behavior, storage_behavior, origin_restriction);
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry.h b/chromium/components/content_settings/core/browser/content_settings_registry.h
index 20c43a7ee29..16ac97e8c7d 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.h
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.h
@@ -62,7 +62,7 @@ class ContentSettingsRegistry {
const std::string& name,
ContentSetting initial_default_value,
WebsiteSettingsInfo::SyncStatus sync_status,
- const std::vector<std::string>& whitelisted_schemes,
+ const std::vector<std::string>& allowlisted_schemes,
const std::set<ContentSetting>& valid_settings,
WebsiteSettingsInfo::ScopingType scoping_type,
Platforms platforms,
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
index a6679731773..85ae1572ad8 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
@@ -68,7 +68,7 @@ TEST_F(ContentSettingsRegistryTest, Properties) {
registry()->Get(ContentSettingsType::COOKIES);
ASSERT_TRUE(info);
- EXPECT_THAT(info->whitelisted_schemes(), ElementsAre("chrome", "devtools"));
+ EXPECT_THAT(info->allowlisted_schemes(), ElementsAre("chrome", "devtools"));
// Check the other properties are populated correctly.
EXPECT_TRUE(info->IsSettingValid(CONTENT_SETTING_SESSION_ONLY));
diff --git a/chromium/components/content_settings/core/browser/content_settings_rule.h b/chromium/components/content_settings/core/browser/content_settings_rule.h
index c58fe6c8d58..c338abe8e04 100644
--- a/chromium/components/content_settings/core/browser/content_settings_rule.h
+++ b/chromium/components/content_settings/core/browser/content_settings_rule.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
-#include "components/content_settings/core/browser/content_settings_constraints.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
namespace content_settings {
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils.cc b/chromium/components/content_settings/core/browser/content_settings_utils.cc
index a7a88cf7c45..b462833a618 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.cc
@@ -120,10 +120,10 @@ PatternPair ParsePatternString(const std::string& pattern_str) {
void GetRendererContentSettingRules(const HostContentSettingsMap* map,
RendererContentSettingRules* rules) {
#if !defined(OS_ANDROID)
- map->GetSettingsForOneType(ContentSettingsType::IMAGES, ResourceIdentifier(),
+ map->GetSettingsForOneType(ContentSettingsType::IMAGES,
&(rules->image_rules));
map->GetSettingsForOneType(ContentSettingsType::MIXEDSCRIPT,
- ResourceIdentifier(),
+
&(rules->mixed_content_rules));
#else
// Android doesn't use image content settings, so ALLOW rule is added for
@@ -142,8 +142,8 @@ void GetRendererContentSettingRules(const HostContentSettingsMap* map,
std::string(), map->IsOffTheRecord()));
#endif
map->GetSettingsForOneType(ContentSettingsType::JAVASCRIPT,
- ResourceIdentifier(), &(rules->script_rules));
- map->GetSettingsForOneType(ContentSettingsType::POPUPS, ResourceIdentifier(),
+ &(rules->script_rules));
+ map->GetSettingsForOneType(ContentSettingsType::POPUPS,
&(rules->popup_redirect_rules));
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils.h b/chromium/components/content_settings/core/browser/content_settings_utils.h
index bae842be456..a192b29a702 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.h
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.h
@@ -9,8 +9,8 @@
#include <utility>
#include "base/compiler_specific.h"
-#include "components/content_settings/core/browser/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
diff --git a/chromium/components/content_settings/core/browser/cookie_settings.cc b/chromium/components/content_settings/core/browser/cookie_settings.cc
index 59fc798b497..eb17bb1058a 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings.cc
@@ -37,7 +37,7 @@ CookieSettings::CookieSettings(
is_incognito_(is_incognito),
extension_scheme_(extension_scheme),
block_third_party_cookies_(false) {
- content_settings_observer_.Add(host_content_settings_map_.get());
+ content_settings_observation_.Observe(host_content_settings_map_.get());
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(
prefs::kCookieControlsMode,
@@ -55,7 +55,7 @@ ContentSetting CookieSettings::GetDefaultCookieSetting(
void CookieSettings::GetCookieSettings(
ContentSettingsForOneType* settings) const {
host_content_settings_map_->GetSettingsForOneType(
- ContentSettingsType::COOKIES, std::string(), settings);
+ ContentSettingsType::COOKIES, settings);
}
void CookieSettings::RegisterProfilePrefs(
@@ -76,8 +76,7 @@ void CookieSettings::SetCookieSetting(const GURL& primary_url,
ContentSetting setting) {
DCHECK(IsValidSetting(setting));
host_content_settings_map_->SetContentSettingDefaultScope(
- primary_url, GURL(), ContentSettingsType::COOKIES, std::string(),
- setting);
+ primary_url, GURL(), ContentSettingsType::COOKIES, setting);
}
void CookieSettings::ResetCookieSetting(const GURL& primary_url) {
@@ -102,14 +101,14 @@ void CookieSettings::SetThirdPartyCookieSetting(const GURL& first_party_url,
host_content_settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromURLNoWildcard(first_party_url),
- ContentSettingsType::COOKIES, std::string(), setting);
+ ContentSettingsType::COOKIES, setting);
}
void CookieSettings::ResetThirdPartyCookieSetting(const GURL& first_party_url) {
host_content_settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromURLNoWildcard(first_party_url),
- ContentSettingsType::COOKIES, std::string(), CONTENT_SETTING_DEFAULT);
+ ContentSettingsType::COOKIES, CONTENT_SETTING_DEFAULT);
}
bool CookieSettings::IsStorageDurable(const GURL& origin) const {
@@ -117,8 +116,7 @@ bool CookieSettings::IsStorageDurable(const GURL& origin) const {
// https://crbug.com/539538
ContentSetting setting = host_content_settings_map_->GetContentSetting(
origin /*primary*/, origin /*secondary*/,
- ContentSettingsType::DURABLE_STORAGE,
- std::string() /*resource_identifier*/);
+ ContentSettingsType::DURABLE_STORAGE);
return setting == CONTENT_SETTING_ALLOW;
}
@@ -133,8 +131,7 @@ void CookieSettings::GetSettingForLegacyCookieAccess(
cookie_domain, false /* secure scheme */);
*setting = host_content_settings_map_->GetContentSetting(
- cookie_domain_url, GURL(), ContentSettingsType::LEGACY_COOKIE_ACCESS,
- std::string() /* resource_identifier */);
+ cookie_domain_url, GURL(), ContentSettingsType::LEGACY_COOKIE_ACCESS);
}
bool CookieSettings::ShouldIgnoreSameSiteRestrictions(
@@ -184,8 +181,7 @@ void CookieSettings::GetCookieSettingInternal(
SettingInfo info;
std::unique_ptr<base::Value> value =
host_content_settings_map_->GetWebsiteSetting(
- url, first_party_url, ContentSettingsType::COOKIES, std::string(),
- &info);
+ url, first_party_url, ContentSettingsType::COOKIES, &info);
if (source)
*source = info.source;
@@ -216,8 +212,7 @@ void CookieSettings::GetCookieSettingInternal(
if (block &&
base::FeatureList::IsEnabled(blink::features::kStorageAccessAPI)) {
ContentSetting setting = host_content_settings_map_->GetContentSetting(
- url, first_party_url, ContentSettingsType::STORAGE_ACCESS,
- std::string());
+ url, first_party_url, ContentSettingsType::STORAGE_ACCESS);
if (setting == CONTENT_SETTING_ALLOW) {
block = false;
@@ -262,8 +257,7 @@ bool CookieSettings::ShouldBlockThirdPartyCookiesInternal() {
void CookieSettings::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
if (content_type == ContentSettingsType::COOKIES) {
for (auto& observer : observers_)
observer.OnCookieSettingChanged();
diff --git a/chromium/components/content_settings/core/browser/cookie_settings.h b/chromium/components/content_settings/core/browser/cookie_settings.h
index 3e558089797..71c14e2de43 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings.h
+++ b/chromium/components/content_settings/core/browser/cookie_settings.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
@@ -165,8 +165,7 @@ class CookieSettings : public CookieSettingsBase,
// content_settings::Observer:
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
void OnCookiePreferencesChanged();
@@ -177,8 +176,8 @@ class CookieSettings : public CookieSettingsBase,
base::ThreadChecker thread_checker_;
base::ObserverList<Observer> observers_;
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
- ScopedObserver<HostContentSettingsMap, content_settings::Observer>
- content_settings_observer_{this};
+ base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+ content_settings_observation_{this};
PrefChangeRegistrar pref_change_registrar_;
const bool is_incognito_;
const char* extension_scheme_; // Weak.
diff --git a/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc b/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
index c01d5ec9e03..b7abb30c69b 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
@@ -6,7 +6,7 @@
#include <cstddef>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
@@ -45,7 +45,7 @@ class CookieSettingsObserver : public CookieSettings::Observer {
public:
explicit CookieSettingsObserver(CookieSettings* settings)
: settings_(settings) {
- scoped_observer_.Add(settings);
+ scoped_observation_.Observe(settings);
}
void OnThirdPartyCookieBlockingChanged(
@@ -60,8 +60,8 @@ class CookieSettingsObserver : public CookieSettings::Observer {
private:
CookieSettings* settings_;
bool last_value_ = false;
- ScopedObserver<CookieSettings, CookieSettings::Observer> scoped_observer_{
- this};
+ base::ScopedObservation<CookieSettings, CookieSettings::Observer>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(CookieSettingsObserver);
};
@@ -149,7 +149,7 @@ class CookieSettingsTest : public testing::Test {
base::test::ScopedFeatureList feature_list_;
};
-TEST_F(CookieSettingsTest, TestWhitelistedScheme) {
+TEST_F(CookieSettingsTest, TestAllowlistedScheme) {
cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
EXPECT_FALSE(cookie_settings_->IsCookieAccessAllowed(kHttpSite, kChromeURL));
EXPECT_TRUE(cookie_settings_->IsCookieAccessAllowed(kHttpsSite, kChromeURL));
@@ -399,7 +399,7 @@ TEST_F(CookieSettingsTest, CookiesThirdPartyBlockedAllSitesAllowed) {
// match all HTTPS sites.
settings_map_->SetContentSettingCustomScope(
kAllHttpsSitesPattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::COOKIES, std::string(), CONTENT_SETTING_ALLOW);
+ ContentSettingsType::COOKIES, CONTENT_SETTING_ALLOW);
cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY);
// |kAllowedSite| should be allowed.
@@ -480,8 +480,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingDisabledSAA) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
ContentSetting setting;
cookie_settings_->GetCookieSetting(url, top_level_url, nullptr, &setting);
@@ -503,8 +502,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingDefaultSAA) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
ContentSetting setting;
cookie_settings_->GetCookieSetting(url, top_level_url, nullptr, &setting);
@@ -535,8 +533,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingEnabledSAA) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
// When requesting our setting for the url/top-level combination our
// grant is for access should be allowed. For any other domain pairs access
@@ -579,8 +576,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingSAAResourceWildcards) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
ContentSetting setting;
cookie_settings_->GetCookieSetting(url, top_level_url, nullptr, &setting);
@@ -606,8 +602,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingSAATopLevelWildcards) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
ContentSetting setting;
cookie_settings_->GetCookieSetting(url, top_level_url, nullptr, &setting);
@@ -632,8 +627,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingSAARespectsSettings) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW);
ContentSetting setting;
cookie_settings_->GetCookieSetting(url, top_level_url, nullptr, &setting);
@@ -654,7 +648,7 @@ TEST_F(CookieSettingsTest, GetCookieSettingSAAExpiredGrant) {
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(url),
ContentSettingsPattern::FromURLNoWildcard(top_level_url),
- ContentSettingsType::STORAGE_ACCESS, std::string(), CONTENT_SETTING_ALLOW,
+ ContentSettingsType::STORAGE_ACCESS, CONTENT_SETTING_ALLOW,
{content_settings::GetConstraintExpiration(
base::TimeDelta::FromSeconds(100)),
SessionModel::UserSession});
@@ -795,8 +789,7 @@ TEST_F(CookieSettingsTest,
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromString(kDomain),
ContentSettingsPattern::Wildcard(),
- ContentSettingsType::LEGACY_COOKIE_ACCESS, std::string(),
- CONTENT_SETTING_BLOCK);
+ ContentSettingsType::LEGACY_COOKIE_ACCESS, CONTENT_SETTING_BLOCK);
const struct {
net::CookieAccessSemantics status;
std::string cookie_domain;
@@ -826,8 +819,7 @@ TEST_F(CookieSettingsTest,
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromString(kDomainWildcardPattern),
ContentSettingsPattern::Wildcard(),
- ContentSettingsType::LEGACY_COOKIE_ACCESS, std::string(),
- CONTENT_SETTING_BLOCK);
+ ContentSettingsType::LEGACY_COOKIE_ACCESS, CONTENT_SETTING_BLOCK);
const struct {
net::CookieAccessSemantics status;
std::string cookie_domain;
@@ -868,8 +860,7 @@ TEST_F(SameSiteByDefaultCookieSettingsTest,
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromString(kDomain),
ContentSettingsPattern::Wildcard(),
- ContentSettingsType::LEGACY_COOKIE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::LEGACY_COOKIE_ACCESS, CONTENT_SETTING_ALLOW);
const struct {
net::CookieAccessSemantics status;
std::string cookie_domain;
@@ -898,8 +889,7 @@ TEST_F(SameSiteByDefaultCookieSettingsTest,
settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::FromString(kDomainWildcardPattern),
ContentSettingsPattern::Wildcard(),
- ContentSettingsType::LEGACY_COOKIE_ACCESS, std::string(),
- CONTENT_SETTING_ALLOW);
+ ContentSettingsType::LEGACY_COOKIE_ACCESS, CONTENT_SETTING_ALLOW);
const struct {
net::CookieAccessSemantics status;
std::string cookie_domain;
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.cc b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
index 7e72290b40f..25a386bb037 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
@@ -71,9 +71,10 @@ constexpr ProviderNamesSourceMapEntry kProviderNamesSourceMap[] = {
{"supervised_user", content_settings::SETTING_SOURCE_SUPERVISED},
{"extension", content_settings::SETTING_SOURCE_EXTENSION},
{"installed_webapp_provider",
- content_settings::SETTING_SOURCE_INSTALLED_WEBAPP},
+ content_settings::SETTING_SOURCE_INSTALLED_WEBAPP},
{"notification_android", content_settings::SETTING_SOURCE_USER},
{"ephemeral", content_settings::SETTING_SOURCE_USER},
+ {"one_time", content_settings::SETTING_SOURCE_USER},
{"preference", content_settings::SETTING_SOURCE_USER},
{"default", content_settings::SETTING_SOURCE_USER},
{"tests", content_settings::SETTING_SOURCE_USER},
@@ -101,13 +102,7 @@ static_assert(FirstUserModifiableProviderIsHighestPrecedence(),
"kFirstUserModifiableProvider is not the highest precedence user "
"modifiable provider.");
-// Returns true if the |content_type| supports a resource identifier.
-// Resource identifiers are supported (but not required) for plugins.
-bool SupportsResourceIdentifier(ContentSettingsType content_type) {
- return content_type == ContentSettingsType::PLUGINS;
-}
-
-bool SchemeCanBeWhitelisted(const std::string& scheme) {
+bool SchemeCanBeAllowlisted(const std::string& scheme) {
return scheme == content_settings::kChromeDevToolsScheme ||
scheme == content_settings::kExtensionScheme ||
scheme == content_settings::kChromeUIScheme;
@@ -282,7 +277,6 @@ HostContentSettingsMap::HostContentSettingsMap(
default_provider->AddObserver(this);
content_settings_providers_[DEFAULT_PROVIDER] = std::move(default_provider);
- InitializePluginsDataSettings();
MigrateSettingsPrecedingPermissionDelegationActivation();
RecordExceptionMetrics();
}
@@ -321,14 +315,14 @@ void HostContentSettingsMap::RegisterProvider(
#endif
OnContentSettingChanged(ContentSettingsPattern(), ContentSettingsPattern(),
- ContentSettingsType::DEFAULT, std::string());
+ ContentSettingsType::DEFAULT);
}
ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
ContentSettingsType content_type,
content_settings::ProviderInterface* provider) const {
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
- provider->GetRuleIterator(content_type, std::string(), false));
+ provider->GetRuleIterator(content_type, false));
if (rule_iterator) {
ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
@@ -386,35 +380,30 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
ContentSetting HostContentSettingsMap::GetContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const {
+ ContentSettingsType content_type) const {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- std::unique_ptr<base::Value> value = GetWebsiteSetting(
- primary_url, secondary_url, content_type, resource_identifier, nullptr);
+ std::unique_ptr<base::Value> value =
+ GetWebsiteSetting(primary_url, secondary_url, content_type, nullptr);
return content_settings::ValueToContentSetting(value.get());
}
ContentSetting HostContentSettingsMap::GetUserModifiableContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const {
+ ContentSettingsType content_type) const {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- std::unique_ptr<base::Value> value = GetWebsiteSettingInternal(
- primary_url, secondary_url, content_type, resource_identifier,
- kFirstUserModifiableProvider, nullptr);
+ std::unique_ptr<base::Value> value =
+ GetWebsiteSettingInternal(primary_url, secondary_url, content_type,
+ kFirstUserModifiableProvider, nullptr);
return content_settings::ValueToContentSetting(value.get());
}
void HostContentSettingsMap::GetSettingsForOneType(
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings,
base::Optional<content_settings::SessionModel> session_model) const {
- DCHECK(SupportsResourceIdentifier(content_type) ||
- resource_identifier.empty());
DCHECK(settings);
UsedContentSettingsProviders();
@@ -424,28 +413,23 @@ void HostContentSettingsMap::GetSettingsForOneType(
// normal rules.
if (is_off_the_record_) {
AddSettingsForOneType(provider_pair.second.get(), provider_pair.first,
- content_type, resource_identifier, settings, true,
- session_model);
+ content_type, settings, true, session_model);
}
AddSettingsForOneType(provider_pair.second.get(), provider_pair.first,
- content_type, resource_identifier, settings, false,
- session_model);
+ content_type, settings, false, session_model);
}
}
void HostContentSettingsMap::GetDiscardedSettingsForOneType(
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings) const {
- DCHECK(SupportsResourceIdentifier(content_type) ||
- resource_identifier.empty());
DCHECK(settings);
UsedContentSettingsProviders();
for (const auto& provider_pair : content_settings_providers_) {
std::unique_ptr<content_settings::RuleIterator> discarded_rule_iterator(
- provider_pair.second->GetDiscardedRuleIterator(
- content_type, resource_identifier, is_off_the_record_));
+ provider_pair.second->GetDiscardedRuleIterator(content_type,
+ is_off_the_record_));
while (discarded_rule_iterator->HasNext()) {
content_settings::Rule discarded_rule = discarded_rule_iterator->Next();
settings->emplace_back(
@@ -470,14 +454,13 @@ void HostContentSettingsMap::SetDefaultContentSetting(
}
SetWebsiteSettingCustomScope(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(), content_type,
- std::string(), std::move(value));
+ std::move(value));
}
void HostContentSettingsMap::SetWebsiteSettingDefaultScope(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
std::unique_ptr<base::Value> value,
const content_settings::ContentSettingConstraints& constraints) {
content_settings::PatternPair patterns = GetPatternsForContentSettingsType(
@@ -488,29 +471,25 @@ void HostContentSettingsMap::SetWebsiteSettingDefaultScope(
return;
SetWebsiteSettingCustomScope(primary_pattern, secondary_pattern, content_type,
- resource_identifier, std::move(value),
- constraints);
+ std::move(value), constraints);
}
void HostContentSettingsMap::SetWebsiteSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const std::string& resource_identifier,
std::unique_ptr<base::Value> value,
const content_settings::ContentSettingConstraints& constraints) {
DCHECK(IsSecondaryPatternAllowed(primary_pattern, secondary_pattern,
content_type, value.get()));
- DCHECK(SupportsResourceIdentifier(content_type) ||
- resource_identifier.empty());
// TODO(crbug.com/731126): Verify that assumptions for notification content
// settings are met.
UsedContentSettingsProviders();
for (const auto& provider_pair : content_settings_providers_) {
if (provider_pair.second->SetWebsiteSetting(
- primary_pattern, secondary_pattern, content_type,
- resource_identifier, std::move(value), constraints)) {
+ primary_pattern, secondary_pattern, content_type, std::move(value),
+ constraints)) {
// If successful then ownership is passed to the provider.
return;
}
@@ -541,15 +520,16 @@ void HostContentSettingsMap::SetNarrowestContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType type,
- ContentSetting setting) {
+ ContentSetting setting,
+ const content_settings::ContentSettingConstraints& constraints) {
content_settings::PatternPair patterns =
GetNarrowestPatterns(primary_url, secondary_url, type);
if (!patterns.first.IsValid() || !patterns.second.IsValid())
return;
- SetContentSettingCustomScope(patterns.first, patterns.second, type,
- std::string(), setting);
+ SetContentSettingCustomScope(patterns.first, patterns.second, type, setting,
+ constraints);
}
content_settings::PatternPair HostContentSettingsMap::GetNarrowestPatterns (
@@ -564,7 +544,7 @@ content_settings::PatternPair HostContentSettingsMap::GetNarrowestPatterns (
// of creating a new rule that would be hidden behind the existing rule.
content_settings::SettingInfo info;
std::unique_ptr<base::Value> v = GetWebsiteSettingInternal(
- primary_url, secondary_url, type, std::string(), kFirstProvider, &info);
+ primary_url, secondary_url, type, kFirstProvider, &info);
if (info.source != content_settings::SETTING_SOURCE_USER) {
// Return an invalid pattern if the current setting is not a user setting
// and thus can't be changed.
@@ -594,27 +574,11 @@ void HostContentSettingsMap::SetContentSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSetting setting,
const content_settings::ContentSettingConstraints& constraints) {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- // Record stats on Flash permission grants with ephemeral storage.
- if (content_type == ContentSettingsType::PLUGINS &&
- setting == CONTENT_SETTING_ALLOW) {
- GURL url(primary_pattern.ToString());
- ContentSettingsPattern temp_patterns[2];
- std::unique_ptr<base::Value> value(GetContentSettingValueAndPatterns(
- content_settings_providers_[PREF_PROVIDER].get(), url, url,
- ContentSettingsType::PLUGINS_DATA, resource_identifier,
- is_off_the_record_, temp_patterns, temp_patterns + 1));
-
- UMA_HISTOGRAM_ENUMERATION(
- "ContentSettings.EphemeralFlashPermission",
- value ? FlashPermissions::kRepeated : FlashPermissions::kFirstTime);
- }
-
std::unique_ptr<base::Value> value;
// A value of CONTENT_SETTING_DEFAULT implies deleting the content setting.
if (setting != CONTENT_SETTING_DEFAULT) {
@@ -624,15 +588,13 @@ void HostContentSettingsMap::SetContentSettingCustomScope(
value.reset(new base::Value(setting));
}
SetWebsiteSettingCustomScope(primary_pattern, secondary_pattern, content_type,
- resource_identifier, std::move(value),
- constraints);
+ std::move(value), constraints);
}
void HostContentSettingsMap::SetContentSettingDefaultScope(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSetting setting,
const content_settings::ContentSettingConstraints& constraints) {
content_settings::PatternPair patterns = GetPatternsForContentSettingsType(
@@ -644,7 +606,7 @@ void HostContentSettingsMap::SetContentSettingDefaultScope(
return;
SetContentSettingCustomScope(primary_pattern, secondary_pattern, content_type,
- resource_identifier, setting, constraints);
+ setting, constraints);
}
base::WeakPtr<HostContentSettingsMap> HostContentSettingsMap::GetWeakPtr() {
@@ -665,7 +627,7 @@ void HostContentSettingsMap::RecordExceptionMetrics() {
const std::string type_name = info->name();
ContentSettingsForOneType settings;
- GetSettingsForOneType(content_type, std::string(), &settings);
+ GetSettingsForOneType(content_type, &settings);
size_t num_exceptions = 0;
size_t num_third_party_cookie_allow_exceptions = 0;
base::flat_map<ContentSetting, size_t> num_exceptions_with_setting;
@@ -771,7 +733,7 @@ base::Time HostContentSettingsMap::GetSettingLastModifiedDate(
base::Time most_recent_time;
for (auto* provider : user_modifiable_providers_) {
base::Time time = provider->GetWebsiteSettingLastModified(
- primary_pattern, secondary_pattern, content_type, std::string());
+ primary_pattern, secondary_pattern, content_type);
most_recent_time = std::max(time, most_recent_time);
}
return most_recent_time;
@@ -789,20 +751,19 @@ void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
}
UsedContentSettingsProviders();
ContentSettingsForOneType settings;
- GetSettingsForOneType(content_type, std::string(), &settings);
+ GetSettingsForOneType(content_type, &settings);
for (const ContentSettingPatternSource& setting : settings) {
if (pattern_predicate.is_null() ||
pattern_predicate.Run(setting.primary_pattern,
setting.secondary_pattern)) {
for (auto* provider : user_modifiable_providers_) {
base::Time last_modified = provider->GetWebsiteSettingLastModified(
- setting.primary_pattern, setting.secondary_pattern, content_type,
- std::string());
+ setting.primary_pattern, setting.secondary_pattern, content_type);
if (last_modified >= begin_time &&
(last_modified < end_time || end_time.is_null())) {
provider->SetWebsiteSetting(setting.primary_pattern,
setting.secondary_pattern, content_type,
- std::string(), nullptr, {});
+ nullptr, {});
}
}
}
@@ -812,11 +773,10 @@ void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
void HostContentSettingsMap::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
for (content_settings::Observer& observer : observers_) {
observer.OnContentSettingChanged(primary_pattern, secondary_pattern,
- content_type, resource_identifier);
+ content_type);
}
}
@@ -837,12 +797,11 @@ void HostContentSettingsMap::AddSettingsForOneType(
const content_settings::ProviderInterface* provider,
ProviderType provider_type,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings,
bool incognito,
base::Optional<content_settings::SessionModel> session_model) const {
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
- provider->GetRuleIterator(content_type, resource_identifier, incognito));
+ provider->GetRuleIterator(content_type, incognito));
if (!rule_iterator)
return;
@@ -890,12 +849,9 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
content_settings::SettingInfo* info) const {
- DCHECK(SupportsResourceIdentifier(content_type) ||
- resource_identifier.empty());
- // Check if the requested setting is whitelisted.
+ // Check if the requested setting is allowlisted.
// TODO(raymes): Move this into GetContentSetting. This has nothing to do with
// website settings
const content_settings::ContentSettingsInfo* content_settings_info =
@@ -903,8 +859,8 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
content_type);
if (content_settings_info) {
for (const std::string& scheme :
- content_settings_info->whitelisted_schemes()) {
- DCHECK(SchemeCanBeWhitelisted(scheme));
+ content_settings_info->allowlisted_schemes()) {
+ DCHECK(SchemeCanBeAllowlisted(scheme));
if (primary_url.SchemeIs(scheme)) {
if (info) {
@@ -919,7 +875,7 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
}
return GetWebsiteSettingInternal(primary_url, secondary_url, content_type,
- resource_identifier, kFirstProvider, info);
+ kFirstProvider, info);
}
// static
@@ -950,15 +906,16 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ProviderType first_provider_to_search,
content_settings::SettingInfo* info) const {
UsedContentSettingsProviders();
ContentSettingsPattern* primary_pattern = nullptr;
ContentSettingsPattern* secondary_pattern = nullptr;
+ content_settings::SessionModel* session_model = nullptr;
if (info) {
primary_pattern = &info->primary_pattern;
secondary_pattern = &info->secondary_pattern;
+ session_model = &info->session_model;
}
// The list of |content_settings_providers_| is ordered according to their
@@ -967,8 +924,7 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
for (; it != content_settings_providers_.end(); ++it) {
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
it->second.get(), primary_url, secondary_url, content_type,
- resource_identifier, is_off_the_record_, primary_pattern,
- secondary_pattern);
+ is_off_the_record_, primary_pattern, secondary_pattern, session_model);
if (value) {
if (info)
info->source = kProviderNamesSourceMap[it->first].provider_source;
@@ -991,30 +947,28 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
bool include_incognito,
ContentSettingsPattern* primary_pattern,
- ContentSettingsPattern* secondary_pattern) {
+ ContentSettingsPattern* secondary_pattern,
+ content_settings::SessionModel* session_model) {
if (include_incognito) {
// Check incognito-only specific settings. It's essential that the
// |RuleIterator| gets out of scope before we get a rule iterator for the
// normal mode.
std::unique_ptr<content_settings::RuleIterator> incognito_rule_iterator(
- provider->GetRuleIterator(content_type, resource_identifier,
- true /* incognito */));
+ provider->GetRuleIterator(content_type, true /* incognito */));
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
incognito_rule_iterator.get(), primary_url, secondary_url,
- primary_pattern, secondary_pattern);
+ primary_pattern, secondary_pattern, session_model);
if (value)
return value;
}
// No settings from the incognito; use the normal mode.
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
- provider->GetRuleIterator(content_type, resource_identifier,
- false /* incognito */));
+ provider->GetRuleIterator(content_type, false /* incognito */));
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
rule_iterator.get(), primary_url, secondary_url, primary_pattern,
- secondary_pattern);
+ secondary_pattern, session_model);
if (value && include_incognito)
value = ProcessIncognitoInheritanceBehavior(content_type, std::move(value));
return value;
@@ -1027,7 +981,8 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsPattern* primary_pattern,
- ContentSettingsPattern* secondary_pattern) {
+ ContentSettingsPattern* secondary_pattern,
+ content_settings::SessionModel* session_model) {
if (rule_iterator) {
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
@@ -1039,6 +994,8 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
*primary_pattern = rule.primary_pattern;
if (secondary_pattern)
*secondary_pattern = rule.secondary_pattern;
+ if (session_model)
+ *session_model = rule.session_model;
return rule.value.CreateDeepCopy();
}
}
@@ -1046,36 +1003,6 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
return std::unique_ptr<base::Value>();
}
-void HostContentSettingsMap::InitializePluginsDataSettings() {
- if (!content_settings::WebsiteSettingsRegistry::GetInstance()->Get(
- ContentSettingsType::PLUGINS_DATA)) {
- return;
- }
- ContentSettingsForOneType host_settings;
- GetSettingsForOneType(ContentSettingsType::PLUGINS_DATA, std::string(),
- &host_settings);
- if (host_settings.empty()) {
- GetSettingsForOneType(ContentSettingsType::PLUGINS, std::string(),
- &host_settings);
- for (ContentSettingPatternSource pattern : host_settings) {
- if (pattern.source != "preference")
- continue;
- const GURL primary(pattern.primary_pattern.ToString());
- if (!primary.is_valid())
- continue;
- DCHECK_EQ(ContentSettingsPattern::Relation::IDENTITY,
- ContentSettingsPattern::Wildcard().Compare(
- pattern.secondary_pattern));
- auto dict = std::make_unique<base::DictionaryValue>();
- constexpr char kFlagKey[] = "flashPreviouslyChanged";
- dict->SetKey(kFlagKey, base::Value(true));
- SetWebsiteSettingDefaultScope(primary, primary,
- ContentSettingsType::PLUGINS_DATA,
- std::string(), std::move(dict));
- }
- }
-}
-
void HostContentSettingsMap::
MigrateSettingsPrecedingPermissionDelegationActivation() {
content_settings::ContentSettingsRegistry* registry =
@@ -1088,7 +1015,7 @@ void HostContentSettingsMap::
ContentSettingsType type = info->website_settings_info()->type();
ContentSettingsForOneType host_settings;
- GetSettingsForOneType(type, std::string(), &host_settings);
+ GetSettingsForOneType(type, &host_settings);
for (ContentSettingPatternSource pattern : host_settings) {
if (pattern.source != "preference" ||
pattern.secondary_pattern == ContentSettingsPattern::Wildcard()) {
@@ -1104,7 +1031,7 @@ void HostContentSettingsMap::
pattern.secondary_pattern != pattern.primary_pattern) {
SetContentSettingCustomScope(pattern.primary_pattern,
pattern.secondary_pattern, type,
- std::string(), CONTENT_SETTING_DEFAULT);
+ CONTENT_SETTING_DEFAULT);
// Also clear the setting for the top level origin so that the user
// receives another prompt. This is necessary in case they have allowed
// the top level origin but blocked an embedded origin in which case
@@ -1112,19 +1039,19 @@ void HostContentSettingsMap::
// embedded origin.
SetContentSettingCustomScope(pattern.secondary_pattern,
pattern.secondary_pattern, type,
- std::string(), CONTENT_SETTING_DEFAULT);
+ CONTENT_SETTING_DEFAULT);
SetContentSettingCustomScope(pattern.secondary_pattern,
ContentSettingsPattern::Wildcard(), type,
- std::string(), CONTENT_SETTING_DEFAULT);
+ CONTENT_SETTING_DEFAULT);
} else if (pattern.primary_pattern.IsValid() &&
pattern.primary_pattern == pattern.secondary_pattern) {
// Migrate settings from (x,x) -> (x,*).
SetContentSettingCustomScope(pattern.primary_pattern,
pattern.secondary_pattern, type,
- std::string(), CONTENT_SETTING_DEFAULT);
- SetContentSettingCustomScope(
- pattern.primary_pattern, ContentSettingsPattern::Wildcard(), type,
- std::string(), pattern.GetContentSetting());
+ CONTENT_SETTING_DEFAULT);
+ SetContentSettingCustomScope(pattern.primary_pattern,
+ ContentSettingsPattern::Wildcard(), type,
+ pattern.GetContentSetting());
}
}
}
@@ -1145,4 +1072,4 @@ bool HostContentSettingsMap::IsSecondaryPatternAllowed(
->SupportsSecondaryPattern() ||
content_settings::ValueToContentSetting(value) ==
CONTENT_SETTING_DEFAULT;
-} \ No newline at end of file
+}
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.h b/chromium/components/content_settings/core/browser/host_content_settings_map.h
index 7628a6b4b14..ad703bf2242 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.h
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.h
@@ -19,11 +19,11 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
-#include "components/content_settings/core/browser/content_settings_constraints.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/browser/user_modifiable_provider.h"
#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/core/refcounted_keyed_service.h"
@@ -41,8 +41,8 @@ namespace content_settings {
class ObservableProvider;
class ProviderInterface;
class PrefProvider;
-class RuleIterator;
class TestUtils;
+class RuleIterator;
}
namespace user_prefs {
@@ -63,6 +63,7 @@ class HostContentSettingsMap : public content_settings::Observer,
INSTALLED_WEBAPP_PROVIDER,
NOTIFICATION_ANDROID_PROVIDER,
EPHEMERAL_PROVIDER,
+ ONE_TIME_GEOLOCATION_PROVIDER,
PREF_PROVIDER,
DEFAULT_PROVIDER,
@@ -107,32 +108,29 @@ class HostContentSettingsMap : public content_settings::Observer,
std::string* provider_id) const;
// Returns a single |ContentSetting| which applies to the given URLs. Note
- // that certain internal schemes are whitelisted. For |CONTENT_TYPE_COOKIES|,
+ // that certain internal schemes are allowlisted. For |CONTENT_TYPE_COOKIES|,
// |CookieSettings| should be used instead. For content types that can't be
// converted to a |ContentSetting|, |GetContentSettingValue| should be called.
// If there is no content setting, returns CONTENT_SETTING_DEFAULT.
//
// May be called on any thread.
- ContentSetting GetContentSetting(
- const GURL& primary_url,
- const GURL& secondary_url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const;
+ ContentSetting GetContentSetting(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type) const;
// This is the same as GetContentSetting() but ignores providers which are not
// user-controllable (e.g. policy and extensions).
ContentSetting GetUserModifiableContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const;
+ ContentSettingsType content_type) const;
// Returns a single content setting |Value| which applies to the given URLs.
// If |info| is not NULL, then the |source| field of |info| is set to the
// source of the returned |Value| (POLICY, EXTENSION, USER, ...) and the
// |primary_pattern| and the |secondary_pattern| fields of |info| are set to
// the patterns of the applying rule. Note that certain internal schemes are
- // whitelisted. For whitelisted schemes the |source| field of |info| is set
+ // allowlisted. For allowlisted schemes the |source| field of |info| is set
// the |SETTING_SOURCE_ALLOWLIST| and the |primary_pattern| and
// |secondary_pattern| are set to a wildcard pattern. If there is no content
// setting, NULL is returned and the |source| field of |info| is set to
@@ -143,7 +141,6 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
content_settings::SettingInfo* info) const;
// For a given content type, returns all patterns with a non-default setting,
@@ -157,7 +154,6 @@ class HostContentSettingsMap : public content_settings::Observer,
//
// This may be called on any thread.
void GetSettingsForOneType(ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings,
base::Optional<content_settings::SessionModel>
session_model = base::nullopt) const;
@@ -167,7 +163,6 @@ class HostContentSettingsMap : public content_settings::Observer,
// won't have any effect because they are deprecated.
void GetDiscardedSettingsForOneType(
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings) const;
// Sets the default setting for a particular content type. This method must
@@ -177,12 +172,12 @@ class HostContentSettingsMap : public content_settings::Observer,
void SetDefaultContentSetting(ContentSettingsType content_type,
ContentSetting setting);
- // Sets the content |setting| for the given patterns, |content_type| and
- // |resource_identifier| applying any provided |constraints|. Setting the
- // value to CONTENT_SETTING_DEFAULT causes the default setting for that type
- // to be used when loading pages matching this pattern. Unless adding a
- // custom-scoped setting, most developers will want to use
- // SetContentSettingDefaultScope() instead.
+ // Sets the content |setting| for the given patterns and|content_type|
+ // applying any provided |constraints|. Setting the value to
+ // CONTENT_SETTING_DEFAULT causes the default setting for that type to be used
+ // when loading pages matching this pattern. Unless adding a custom-scoped
+ // setting, most developers will want to use SetContentSettingDefaultScope()
+ // instead.
//
// NOTICE: This is just a convenience method for content types that use
// |CONTENT_SETTING| as their data type. For content types that use other
@@ -193,14 +188,13 @@ class HostContentSettingsMap : public content_settings::Observer,
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSetting setting,
const content_settings::ContentSettingConstraints& constraints = {});
// Sets the content |setting| for the default scope of the url that is
- // appropriate for the given |content_type| and |resource_identifier| applying
- // any provided |constraints|. Setting the value to CONTENT_SETTING_DEFAULT
- // causes the default setting for that type to be used.
+ // appropriate for the given |content_type| applying any provided
+ // |constraints|. Setting the value to CONTENT_SETTING_DEFAULT causes the
+ // default setting for that type to be used.
//
// NOTICE: This is just a convenience method for content types that use
// |CONTENT_SETTING| as their data type. For content types that use other
@@ -216,14 +210,12 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSetting setting,
const content_settings::ContentSettingConstraints& constraints = {});
// Sets the |value| for the default scope of the url that is appropriate for
- // the given |content_type| and |resource_identifier| applying any provided
- // |constraints|. Setting the value to null removes the default pattern pair
- // for this content type.
+ // the given |content_type| applying any provided |constraints|. Setting the
+ // value to null removes the default pattern pair for this content type.
//
// Internally this will call SetWebsiteSettingCustomScope() with the default
// scope patterns for the given |content_type|. Developers will generally want
@@ -233,20 +225,17 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& requesting_url,
const GURL& top_level_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
std::unique_ptr<base::Value> value,
const content_settings::ContentSettingConstraints& constraints = {});
// Sets a rule to apply the |value| for all sites matching |pattern|,
- // |content_type| and |resource_identifier| applying any provided
- // |constraints|. Setting the value to null removes the given pattern pair.
- // Unless adding a custom-scoped setting, most developers will want to use
- // SetWebsiteSettingDefaultScope() instead.
+ // |content_type| applying any provided |constraints|. Setting the value to
+ // null removes the given pattern pair. Unless adding a custom-scoped setting,
+ // most developers will want to use SetWebsiteSettingDefaultScope() instead.
void SetWebsiteSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- const std::string& resource_identifier,
std::unique_ptr<base::Value> value,
const content_settings::ContentSettingConstraints& constraints = {});
@@ -266,10 +255,12 @@ class HostContentSettingsMap : public content_settings::Observer,
// are scoped to origin scope. There is no scope more narrow than origin
// scope, so we can just blindly set the value of the origin scope when that
// happens.
- void SetNarrowestContentSetting(const GURL& primary_url,
- const GURL& secondary_url,
- ContentSettingsType type,
- ContentSetting setting);
+ void SetNarrowestContentSetting(
+ const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType type,
+ ContentSetting setting,
+ const content_settings::ContentSettingConstraints& constraints = {});
// Clears all host-specific settings for one content type.
//
@@ -306,8 +297,7 @@ class HostContentSettingsMap : public content_settings::Observer,
// content_settings::Observer implementation.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
// Returns the ProviderType associated with the given source string.
// TODO(estade): I regret adding this. At the moment there are no legitimate
@@ -369,16 +359,15 @@ class HostContentSettingsMap : public content_settings::Observer,
// Collect UMA data of exceptions.
void RecordExceptionMetrics();
- // Adds content settings for |content_type| and |resource_identifier|,
- // provided by |provider|, into |settings|. If |incognito| is true, adds only
- // the content settings which are applicable to the incognito mode and differ
- // from the normal mode. Otherwise, adds the content settings for the normal
- // mode (applying inheritance rules if |is_off_the_record_|).
+ // Adds content settings for |content_type| provided by |provider|, into
+ // |settings|. If |incognito| is true, adds only the content settings which
+ // are applicable to the incognito mode and differ from the normal mode.
+ // Otherwise, adds the content settings for the normal mode (applying
+ // inheritance rules if |is_off_the_record_|).
void AddSettingsForOneType(
const content_settings::ProviderInterface* provider,
ProviderType provider_type,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ContentSettingsForOneType* settings,
bool incognito,
base::Optional<content_settings::SessionModel> session_model) const;
@@ -395,7 +384,6 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
ProviderType first_provider_to_search,
content_settings::SettingInfo* info) const;
@@ -409,22 +397,18 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- const std::string& resource_identifier,
bool include_incognito,
ContentSettingsPattern* primary_pattern,
- ContentSettingsPattern* secondary_pattern);
+ ContentSettingsPattern* secondary_pattern,
+ content_settings::SessionModel* session_model);
static std::unique_ptr<base::Value> GetContentSettingValueAndPatterns(
content_settings::RuleIterator* rule_iterator,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsPattern* primary_pattern,
- ContentSettingsPattern* secondary_pattern);
-
- // Make sure existing non-default Flash settings set by the user are marked to
- // always show the Flash setting for this site in Page Info.
- // TODO(patricialor): Remove after m66 (migration code).
- void InitializePluginsDataSettings();
+ ContentSettingsPattern* secondary_pattern,
+ content_settings::SessionModel* session_model);
// Migrate requesting and top level origin content settings to remove all
// settings that have a top level pattern. If there is a pattern set for
diff --git a/chromium/components/content_settings/core/browser/private_network_settings.cc b/chromium/components/content_settings/core/browser/private_network_settings.cc
index 98bc34fea39..d29d6c42351 100644
--- a/chromium/components/content_settings/core/browser/private_network_settings.cc
+++ b/chromium/components/content_settings/core/browser/private_network_settings.cc
@@ -23,10 +23,8 @@ namespace content_settings {
bool ShouldAllowInsecurePrivateNetworkRequests(
const HostContentSettingsMap* map,
const GURL& url) {
- const std::string unused_resource_identifier;
const ContentSetting setting = map->GetContentSetting(
- url, url, ContentSettingsType::INSECURE_PRIVATE_NETWORK,
- unused_resource_identifier);
+ url, url, ContentSettingsType::INSECURE_PRIVATE_NETWORK);
switch (setting) {
case CONTENT_SETTING_ALLOW:
diff --git a/chromium/components/content_settings/core/browser/user_modifiable_provider.h b/chromium/components/content_settings/core/browser/user_modifiable_provider.h
index 06a94d175c0..38ff9c5f647 100644
--- a/chromium/components/content_settings/core/browser/user_modifiable_provider.h
+++ b/chromium/components/content_settings/core/browser/user_modifiable_provider.h
@@ -25,8 +25,7 @@ class UserModifiableProvider : public ObservableProvider {
virtual base::Time GetWebsiteSettingLastModified(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier) = 0;
+ ContentSettingsType content_type) = 0;
// Sets the providers internal clock for testing purposes.
virtual void SetClockForTesting(base::Clock* clock) = 0;
};
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry.cc b/chromium/components/content_settings/core/browser/website_settings_registry.cc
index b1f5e768cd0..e301d6f2f5a 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.cc
@@ -180,13 +180,6 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
- // To counteract the reduced usability of the Flash permission when it becomes
- // ephemeral, we sync the bit indicating that the Flash permission should be
- // displayed in the page info.
- Register(ContentSettingsType::PLUGINS_DATA, "flash-data", nullptr,
- WebsiteSettingsInfo::SYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
- WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
- DESKTOP, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
// Set to keep track of dismissals without user's interaction for intent
// picker UI.
Register(ContentSettingsType::INTENT_PICKER_DISPLAY,
@@ -226,6 +219,11 @@ void WebsiteSettingsRegistry::Init() {
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
+ Register(ContentSettingsType::FILE_SYSTEM_LAST_PICKED_DIRECTORY,
+ "file-system-last-picked-directory", nullptr,
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
+ WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/BUILD.gn b/chromium/components/content_settings/core/common/BUILD.gn
index 2caaf315bdb..84bf57a2f77 100644
--- a/chromium/components/content_settings/core/common/BUILD.gn
+++ b/chromium/components/content_settings/core/common/BUILD.gn
@@ -9,6 +9,7 @@ static_library("common") {
sources = [
"content_settings.cc",
"content_settings.h",
+ "content_settings_constraints.h",
"content_settings_param_traits.cc",
"content_settings_param_traits.h",
"content_settings_pattern.cc",
diff --git a/chromium/components/content_settings/core/common/content_settings.cc b/chromium/components/content_settings/core/common/content_settings.cc
index c6f6ff7ca37..4de6d5608a0 100644
--- a/chromium/components/content_settings/core/common/content_settings.cc
+++ b/chromium/components/content_settings/core/common/content_settings.cc
@@ -62,7 +62,6 @@ constexpr HistogramValue kHistogramValue[] = {
{ContentSettingsType::CLIENT_HINTS, 37},
{ContentSettingsType::SENSORS, 38},
{ContentSettingsType::ACCESSIBILITY_EVENTS, 39},
- {ContentSettingsType::PLUGINS_DATA, 42},
{ContentSettingsType::PAYMENT_HANDLER, 43},
{ContentSettingsType::USB_GUARD, 44},
{ContentSettingsType::BACKGROUND_FETCH, 45},
@@ -93,6 +92,7 @@ constexpr HistogramValue kHistogramValue[] = {
{ContentSettingsType::INSECURE_PRIVATE_NETWORK, 70},
{ContentSettingsType::FONT_ACCESS, 71},
{ContentSettingsType::PERMISSION_AUTOREVOCATION_DATA, 72},
+ {ContentSettingsType::FILE_SYSTEM_LAST_PICKED_DIRECTORY, 73},
};
} // namespace
diff --git a/chromium/components/content_settings/core/common/content_settings.h b/chromium/components/content_settings/core/common/content_settings.h
index 66254566b48..5d2109d96d9 100644
--- a/chromium/components/content_settings/core/common/content_settings.h
+++ b/chromium/components/content_settings/core/common/content_settings.h
@@ -12,6 +12,7 @@
#include "base/time/time.h"
#include "base/values.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
@@ -82,8 +83,6 @@ struct RendererContentSettingRules {
namespace content_settings {
-typedef std::string ResourceIdentifier;
-
// Enum containing the various source for content settings. Settings can be
// set by policy, extension, the user or by the custodian of a supervised user.
// Certain (internal) origins are allowlisted. For these origins the source is
@@ -105,6 +104,7 @@ struct SettingInfo {
SettingSource source;
ContentSettingsPattern primary_pattern;
ContentSettingsPattern secondary_pattern;
+ SessionModel session_model;
};
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_constraints.h b/chromium/components/content_settings/core/common/content_settings_constraints.h
index 6505ef573c2..a294f747289 100644
--- a/chromium/components/content_settings/core/browser/content_settings_constraints.h
+++ b/chromium/components/content_settings/core/common/content_settings_constraints.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 COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CONSTRAINTS_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CONSTRAINTS_H_
+#ifndef COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_CONTENT_SETTINGS_CONSTRAINTS_H_
+#define COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_CONTENT_SETTINGS_CONSTRAINTS_H_
#include "base/time/time.h"
@@ -16,10 +16,13 @@ namespace content_settings {
// if set.
// UserSession: Settings will persist no longer than the user session
// regardless of expiry date, if set.
+// OneTime: Settings will persist for the current "tab session", meaning
+// until the last tab from the origin is closed.
enum class SessionModel {
Durable = 0,
UserSession = 1,
- kMaxValue = UserSession,
+ OneTime = 2,
+ kMaxValue = OneTime,
};
// Constraints to be applied when setting a content setting.
@@ -34,4 +37,4 @@ struct ContentSettingConstraints {
} // namespace content_settings
-#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_CONTENT_SETTINGS_CONSTRAINTS_H_
+#endif // COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_CONTENT_SETTINGS_CONSTRAINTS_H_
diff --git a/chromium/components/content_settings/core/common/content_settings_types.h b/chromium/components/content_settings/core/common/content_settings_types.h
index 56da03dd7d8..27dbaba5b91 100644
--- a/chromium/components/content_settings/core/common/content_settings_types.h
+++ b/chromium/components/content_settings/core/common/content_settings_types.h
@@ -96,10 +96,6 @@ enum class ContentSettingsType : int32_t {
// technology.
ACCESSIBILITY_EVENTS,
- // Used to store whether the user has ever changed the Flash permission for
- // a site.
- PLUGINS_DATA,
-
// Used to store whether to allow a website to install a payment handler.
PAYMENT_HANDLER,
@@ -229,6 +225,10 @@ enum class ContentSettingsType : int32_t {
// types).
PERMISSION_AUTOREVOCATION_DATA,
+ // Stores per-origin state of the most recently selected directory for the use
+ // by the File System Access API.
+ FILE_SYSTEM_LAST_PICKED_DIRECTORY,
+
NUM_TYPES,
};
diff --git a/chromium/components/content_settings/core/common/features.cc b/chromium/components/content_settings/core/common/features.cc
index c8c4b529b50..19d9ab9d9dc 100644
--- a/chromium/components/content_settings/core/common/features.cc
+++ b/chromium/components/content_settings/core/common/features.cc
@@ -19,8 +19,4 @@ const base::Feature kDisallowWildcardsInPluginContentSettings{
"DisallowWildcardsInPluginContentSettings",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kDisallowExtensionsToSetPluginContentSettings{
- "DisallowExtensionsToSetPluginContentSettings",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/features.h b/chromium/components/content_settings/core/common/features.h
index d1777e92ab3..10ef3666680 100644
--- a/chromium/components/content_settings/core/common/features.h
+++ b/chromium/components/content_settings/core/common/features.h
@@ -24,11 +24,6 @@ extern const base::Feature kImprovedCookieControls;
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
extern const base::Feature kDisallowWildcardsInPluginContentSettings;
-// Feature to remove the chrome.contentSettings.plugins.set() API in extensions
-// for extensions.
-COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
-extern const base::Feature kDisallowExtensionsToSetPluginContentSettings;
-
} // namespace content_settings
#endif // COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_FEATURES_H_
diff --git a/chromium/components/content_settings/core/common/pref_names.cc b/chromium/components/content_settings/core/common/pref_names.cc
index 1567a52df8f..8b4ebc83909 100644
--- a/chromium/components/content_settings/core/common/pref_names.cc
+++ b/chromium/components/content_settings/core/common/pref_names.cc
@@ -37,8 +37,6 @@ const char kManagedDefaultNotificationsSetting[] =
"profile.managed_default_content_settings.notifications";
const char kManagedDefaultMediaStreamSetting[] =
"profile.managed_default_content_settings.media_stream";
-const char kManagedDefaultPluginsSetting[] =
- "profile.managed_default_content_settings.plugins";
const char kManagedDefaultPopupsSetting[] =
"profile.managed_default_content_settings.popups";
const char kManagedDefaultSensorsSetting[] =
@@ -84,10 +82,6 @@ const char kManagedNotificationsAllowedForUrls[] =
"profile.managed_notifications_allowed_for_urls";
const char kManagedNotificationsBlockedForUrls[] =
"profile.managed_notifications_blocked_for_urls";
-const char kManagedPluginsAllowedForUrls[] =
- "profile.managed_plugins_allowed_for_urls";
-const char kManagedPluginsBlockedForUrls[] =
- "profile.managed_plugins_blocked_for_urls";
const char kManagedPopupsAllowedForUrls[] =
"profile.managed_popups_allowed_for_urls";
const char kManagedPopupsBlockedForUrls[] =
@@ -117,11 +111,18 @@ const char kManagedSerialBlockedForUrls[] =
const char kManagedInsecurePrivateNetworkAllowedForUrls[] =
"profile.managed_insecure_private_network_allowed_for_urls";
-// Boolean indicating whether the quiet UX is enabled for notification
+// Boolean indicating whether the quiet UI is enabled for notification
// permission requests.
const char kEnableQuietNotificationPermissionUi[] =
"profile.content_settings.enable_quiet_permission_ui.notifications";
+// Enum indicating by which method the quiet UI has been enabled for
+// notification permission requests. This is stored as of M88 and will be
+// backfilled if the quiet UI is enabled but this preference has no value.
+const char kQuietNotificationPermissionUiEnablingMethod[] =
+ "profile.content_settings.enable_quiet_permission_ui_enabling_method."
+ "notifications";
+
#if defined(OS_ANDROID)
// Enable vibration for web notifications.
const char kNotificationsVibrateEnabled[] = "notifications.vibrate_enabled";
diff --git a/chromium/components/content_settings/core/common/pref_names.h b/chromium/components/content_settings/core/common/pref_names.h
index 68e1f959de1..23533df7666 100644
--- a/chromium/components/content_settings/core/common/pref_names.h
+++ b/chromium/components/content_settings/core/common/pref_names.h
@@ -23,7 +23,6 @@ extern const char kManagedDefaultCookiesSetting[];
extern const char kManagedDefaultImagesSetting[];
extern const char kManagedDefaultInsecureContentSetting[];
extern const char kManagedDefaultJavaScriptSetting[];
-extern const char kManagedDefaultPluginsSetting[];
extern const char kManagedDefaultPopupsSetting[];
extern const char kManagedDefaultGeolocationSetting[];
extern const char kManagedDefaultNotificationsSetting[];
@@ -46,8 +45,6 @@ extern const char kManagedInsecureContentAllowedForUrls[];
extern const char kManagedInsecureContentBlockedForUrls[];
extern const char kManagedJavaScriptAllowedForUrls[];
extern const char kManagedJavaScriptBlockedForUrls[];
-extern const char kManagedPluginsAllowedForUrls[];
-extern const char kManagedPluginsBlockedForUrls[];
extern const char kManagedPopupsAllowedForUrls[];
extern const char kManagedPopupsBlockedForUrls[];
extern const char kManagedNotificationsAllowedForUrls[];
@@ -68,6 +65,7 @@ extern const char kManagedSerialBlockedForUrls[];
extern const char kManagedInsecurePrivateNetworkAllowedForUrls[];
extern const char kEnableQuietNotificationPermissionUi[];
+extern const char kQuietNotificationPermissionUiEnablingMethod[];
#if defined(OS_ANDROID)
extern const char kNotificationsVibrateEnabled[];
diff --git a/chromium/components/content_settings/renderer/content_settings_agent_impl.cc b/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
index 20ae512af80..c932b27c6ab 100644
--- a/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
+++ b/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
@@ -76,7 +76,7 @@ bool IsFrameWithOpaqueOrigin(WebFrame* frame) {
ContentSettingsAgentImpl::Delegate::~Delegate() = default;
-bool ContentSettingsAgentImpl::Delegate::IsSchemeWhitelisted(
+bool ContentSettingsAgentImpl::Delegate::IsSchemeAllowlisted(
const std::string& scheme) {
return false;
}
@@ -100,20 +100,21 @@ void ContentSettingsAgentImpl::Delegate::PassiveInsecureContentFound(
ContentSettingsAgentImpl::ContentSettingsAgentImpl(
content::RenderFrame* render_frame,
- bool should_whitelist,
+ bool should_allowlist,
std::unique_ptr<Delegate> delegate)
: content::RenderFrameObserver(render_frame),
content::RenderFrameObserverTracker<ContentSettingsAgentImpl>(
render_frame),
- should_whitelist_(should_whitelist),
+ should_allowlist_(should_allowlist),
delegate_(std::move(delegate)) {
DCHECK(delegate_);
ClearBlockedContentSettings();
render_frame->GetWebFrame()->SetContentSettingsClient(this);
render_frame->GetAssociatedInterfaceRegistry()->AddInterface(
- base::Bind(&ContentSettingsAgentImpl::OnContentSettingsAgentRequest,
- base::Unretained(this)));
+ base::BindRepeating(
+ &ContentSettingsAgentImpl::OnContentSettingsAgentRequest,
+ base::Unretained(this)));
content::RenderFrame* main_frame =
render_frame->GetRenderView()->GetMainRenderFrame();
@@ -126,7 +127,6 @@ ContentSettingsAgentImpl::ContentSettingsAgentImpl(
ContentSettingsAgentImpl* parent =
ContentSettingsAgentImpl::Get(main_frame);
allow_running_insecure_content_ = parent->allow_running_insecure_content_;
- is_interstitial_page_ = parent->is_interstitial_page_;
}
}
@@ -240,10 +240,6 @@ void ContentSettingsAgentImpl::SetAllowRunningInsecureContent() {
frame->StartReload(blink::WebFrameLoadType::kReload);
}
-void ContentSettingsAgentImpl::SetAsInterstitial() {
- is_interstitial_page_ = true;
-}
-
void ContentSettingsAgentImpl::SetDisabledMixedContentUpgrades() {
mixed_content_autoupgrades_disabled_ = true;
}
@@ -334,10 +330,7 @@ bool ContentSettingsAgentImpl::AllowImage(bool enabled_per_settings,
const WebURL& image_url) {
bool allow = enabled_per_settings;
if (enabled_per_settings) {
- if (is_interstitial_page_)
- return true;
-
- if (IsWhitelistedForContentSettings())
+ if (IsAllowlistedForContentSettings())
return true;
if (content_setting_rules_) {
@@ -356,8 +349,6 @@ bool ContentSettingsAgentImpl::AllowScript(bool enabled_per_settings) {
return false;
if (IsScriptDisabledForPreview(render_frame()))
return false;
- if (is_interstitial_page_)
- return true;
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
const auto it = cached_script_permissions_.find(frame);
@@ -365,7 +356,7 @@ bool ContentSettingsAgentImpl::AllowScript(bool enabled_per_settings) {
return it->second;
// Evaluate the content setting rules before
- // IsWhitelistedForContentSettings(); if there is only the default rule
+ // IsAllowlistedForContentSettings(); if there is only the default rule
// allowing all scripts, it's quicker this way.
bool allow = true;
if (content_setting_rules_) {
@@ -374,7 +365,7 @@ bool ContentSettingsAgentImpl::AllowScript(bool enabled_per_settings) {
url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL());
allow = setting != CONTENT_SETTING_BLOCK;
}
- allow = allow || IsWhitelistedForContentSettings();
+ allow = allow || IsAllowlistedForContentSettings();
cached_script_permissions_[frame] = allow;
return allow;
@@ -387,8 +378,6 @@ bool ContentSettingsAgentImpl::AllowScriptFromSource(
return false;
if (IsScriptDisabledForPreview(render_frame()))
return false;
- if (is_interstitial_page_)
- return true;
bool allow = true;
if (content_setting_rules_) {
@@ -397,7 +386,7 @@ bool ContentSettingsAgentImpl::AllowScriptFromSource(
render_frame()->GetWebFrame(), script_url);
allow = setting != CONTENT_SETTING_BLOCK;
}
- return allow || IsWhitelistedForContentSettings();
+ return allow || IsAllowlistedForContentSettings();
}
bool ContentSettingsAgentImpl::AllowReadFromClipboard(bool default_value) {
@@ -471,11 +460,11 @@ void ContentSettingsAgentImpl::ClearBlockedContentSettings() {
cached_script_permissions_.clear();
}
-bool ContentSettingsAgentImpl::IsWhitelistedForContentSettings() const {
- if (should_whitelist_)
+bool ContentSettingsAgentImpl::IsAllowlistedForContentSettings() const {
+ if (should_allowlist_)
return true;
- // Whitelist ftp directory listings, as they require JavaScript to function
+ // Allowlist ftp directory listings, as they require JavaScript to function
// properly.
if (render_frame()->IsFTPDirectoryListing())
return true;
@@ -497,7 +486,7 @@ bool ContentSettingsAgentImpl::IsWhitelistedForContentSettings() const {
if (protocol == content::kChromeDevToolsScheme)
return true; // DevTools UI elements should still work.
- if (delegate_->IsSchemeWhitelisted(protocol.Utf8()))
+ if (delegate_->IsSchemeAllowlisted(protocol.Utf8()))
return true;
// If the scheme is file:, an empty file name indicates a directory listing,
diff --git a/chromium/components/content_settings/renderer/content_settings_agent_impl.h b/chromium/components/content_settings/renderer/content_settings_agent_impl.h
index 41dcaac2782..868b7e6d98e 100644
--- a/chromium/components/content_settings/renderer/content_settings_agent_impl.h
+++ b/chromium/components/content_settings/renderer/content_settings_agent_impl.h
@@ -47,8 +47,8 @@ class ContentSettingsAgentImpl
public:
virtual ~Delegate();
- // Return true if this scheme should be whitelisted for content settings.
- virtual bool IsSchemeWhitelisted(const std::string& scheme);
+ // Return true if this scheme should be allowlisted for content settings.
+ virtual bool IsSchemeAllowlisted(const std::string& scheme);
// Allows the delegate to override logic for various
// blink::WebContentSettingsClient methods. If an optional value is
@@ -59,10 +59,10 @@ class ContentSettingsAgentImpl
virtual void PassiveInsecureContentFound(const blink::WebURL& resource_url);
};
- // Set |should_whitelist| to true if |render_frame()| contains content that
- // should be whitelisted for content settings.
+ // Set |should_allowlist| to true if |render_frame()| contains content that
+ // should be allowlisted for content settings.
ContentSettingsAgentImpl(content::RenderFrame* render_frame,
- bool should_whitelist,
+ bool should_allowlist,
std::unique_ptr<Delegate> delegate);
~ContentSettingsAgentImpl() override;
@@ -122,7 +122,7 @@ class ContentSettingsAgentImpl
private:
FRIEND_TEST_ALL_PREFIXES(ContentSettingsAgentImplBrowserTest,
- WhitelistedSchemes);
+ AllowlistedSchemes);
FRIEND_TEST_ALL_PREFIXES(ContentSettingsAgentImplBrowserTest,
ContentSettingsInterstitialPages);
@@ -132,7 +132,6 @@ class ContentSettingsAgentImpl
// mojom::ContentSettingsAgent:
void SetAllowRunningInsecureContent() override;
- void SetAsInterstitial() override;
void SetDisabledMixedContentUpgrades() override;
void OnContentSettingsAgentRequest(
@@ -142,9 +141,9 @@ class ContentSettingsAgentImpl
void ClearBlockedContentSettings();
// Helpers.
- // True if |render_frame()| contains content that is white-listed for content
+ // True if |render_frame()| contains content that is allowlisted for content
// settings.
- bool IsWhitelistedForContentSettings() const;
+ bool IsAllowlistedForContentSettings() const;
// A getter for |content_settings_manager_| that ensures it is bound.
mojom::ContentSettingsManager& GetContentSettingsManager();
@@ -170,11 +169,10 @@ class ContentSettingsAgentImpl
// Caches the result of AllowScript.
base::flat_map<blink::WebFrame*, bool> cached_script_permissions_;
- bool is_interstitial_page_ = false;
bool mixed_content_autoupgrades_disabled_ = false;
- // If true, IsWhitelistedForContentSettings will always return true.
- const bool should_whitelist_;
+ // If true, IsAllowlistedForContentSettings will always return true.
+ const bool should_allowlist_;
std::unique_ptr<Delegate> delegate_;
diff --git a/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc b/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
index 217f968f314..9fa11e0fe01 100644
--- a/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
+++ b/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
@@ -5,7 +5,7 @@
#include <stddef.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/values.h"
@@ -27,7 +27,7 @@
namespace content_settings {
namespace {
-constexpr char kWhitelistScheme[] = "foo";
+constexpr char kAllowlistScheme[] = "foo";
constexpr char kEndUrl[] = ":something";
constexpr char kScriptHtml[] = R"HTML(
@@ -86,8 +86,8 @@ class MockContentSettingsManagerImpl : public mojom::ContentSettingsManager {
class MockContentSettingsAgentDelegate
: public ContentSettingsAgentImpl::Delegate {
public:
- bool IsSchemeWhitelisted(const std::string& scheme) override {
- return scheme == kWhitelistScheme;
+ bool IsSchemeAllowlisted(const std::string& scheme) override {
+ return scheme == kAllowlistScheme;
}
};
@@ -182,32 +182,32 @@ class ContentSettingsAgentImplBrowserTest : public content::RenderViewTest {
}
};
-TEST_F(ContentSettingsAgentImplBrowserTest, WhitelistedSchemes) {
+TEST_F(ContentSettingsAgentImplBrowserTest, AllowlistedSchemes) {
url::ScopedSchemeRegistryForTests scoped_registry;
- url::AddStandardScheme(kWhitelistScheme, url::SCHEME_WITH_HOST);
+ url::AddStandardScheme(kAllowlistScheme, url::SCHEME_WITH_HOST);
MockContentSettingsAgentImpl mock_agent(view_->GetMainRenderFrame());
GURL chrome_ui_url =
GURL(std::string(content::kChromeUIScheme).append(kEndUrl));
LoadHTMLWithUrlOverride("<html></html>", chrome_ui_url.spec().c_str());
- EXPECT_TRUE(mock_agent.IsWhitelistedForContentSettings());
+ EXPECT_TRUE(mock_agent.IsAllowlistedForContentSettings());
GURL chrome_dev_tools_url =
GURL(std::string(content::kChromeDevToolsScheme).append(kEndUrl));
LoadHTMLWithUrlOverride("<html></html>", chrome_dev_tools_url.spec().c_str());
- EXPECT_TRUE(mock_agent.IsWhitelistedForContentSettings());
+ EXPECT_TRUE(mock_agent.IsAllowlistedForContentSettings());
- GURL whitelist_url = GURL(std::string(kWhitelistScheme).append(kEndUrl));
- LoadHTMLWithUrlOverride("<html></html>", whitelist_url.spec().c_str());
- EXPECT_TRUE(mock_agent.IsWhitelistedForContentSettings());
+ GURL allowlist_url = GURL(std::string(kAllowlistScheme).append(kEndUrl));
+ LoadHTMLWithUrlOverride("<html></html>", allowlist_url.spec().c_str());
+ EXPECT_TRUE(mock_agent.IsAllowlistedForContentSettings());
LoadHTMLWithUrlOverride("<html></html>", "file:///dir/");
- EXPECT_TRUE(mock_agent.IsWhitelistedForContentSettings());
+ EXPECT_TRUE(mock_agent.IsAllowlistedForContentSettings());
LoadHTMLWithUrlOverride("<html></html>", "file:///dir/file");
- EXPECT_FALSE(mock_agent.IsWhitelistedForContentSettings());
+ EXPECT_FALSE(mock_agent.IsAllowlistedForContentSettings());
LoadHTMLWithUrlOverride("<html></html>", "http://server.com/path");
- EXPECT_FALSE(mock_agent.IsWhitelistedForContentSettings());
+ EXPECT_FALSE(mock_agent.IsAllowlistedForContentSettings());
}
TEST_F(ContentSettingsAgentImplBrowserTest, DidBlockContentType) {
@@ -304,7 +304,8 @@ TEST_F(ContentSettingsAgentImplBrowserTest, JSBlockSentAfterPageLoad) {
// has not yet been sent at the time when the navigation commits.
CommitTimeConditionChecker checker(
view_->GetMainRenderFrame(),
- base::Bind(HasSentOnContentBlocked, base::Unretained(&mock_agent)),
+ base::BindRepeating(HasSentOnContentBlocked,
+ base::Unretained(&mock_agent)),
false);
std::string url_str = "data:text/html;charset=utf-8,";
@@ -563,43 +564,6 @@ TEST_F(ContentSettingsAgentImplBrowserTest,
EXPECT_TRUE(agent->AllowScript(true));
}
-TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsInterstitialPages) {
- MockContentSettingsAgentImpl mock_agent(view_->GetMainRenderFrame());
- // Block scripts.
- RendererContentSettingRules content_setting_rules;
- ContentSettingsForOneType& script_setting_rules =
- content_setting_rules.script_rules;
- script_setting_rules.push_back(ContentSettingPatternSource(
- ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
- std::string(), false));
- // Block images.
- ContentSettingsForOneType& image_setting_rules =
- content_setting_rules.image_rules;
- image_setting_rules.push_back(ContentSettingPatternSource(
- ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
- std::string(), false));
-
- ContentSettingsAgentImpl* agent =
- ContentSettingsAgentImpl::Get(view_->GetMainRenderFrame());
- agent->SetContentSettingRules(&content_setting_rules);
- agent->SetAsInterstitial();
-
- // Load a page which contains a script.
- LoadHTML(kScriptHtml);
-
- // Verify that the script was allowed.
- EXPECT_EQ(0, mock_agent.on_content_blocked_count());
-
- // Verify that images are allowed.
- EXPECT_TRUE(agent->AllowImage(true, mock_agent.image_url()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, mock_agent.on_content_blocked_count());
-}
-
TEST_F(ContentSettingsAgentImplBrowserTest, MixedAutoupgradesDisabledByRules) {
MockContentSettingsAgentImpl mock_agent(view_->GetMainRenderFrame());
diff --git a/chromium/components/crash/content/browser/BUILD.gn b/chromium/components/crash/content/browser/BUILD.gn
index efc8041b413..7649900ccec 100644
--- a/chromium/components/crash/content/browser/BUILD.gn
+++ b/chromium/components/crash/content/browser/BUILD.gn
@@ -6,27 +6,11 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
# TODO(crbug.com/753619): Enable crash reporting on Fuchsia.
assert(!is_fuchsia)
source_set("browser") {
- sources = [
- "child_exit_observer_android.cc",
- "child_exit_observer_android.h",
- "child_process_crash_observer_android.cc",
- "child_process_crash_observer_android.h",
- "crash_memory_metrics_collector_android.cc",
- "crash_memory_metrics_collector_android.h",
- "crash_metrics_reporter_android.cc",
- "crash_metrics_reporter_android.h",
- ]
+ sources = []
deps = [
"//base",
@@ -36,8 +20,6 @@ source_set("browser") {
]
if (is_linux || is_chromeos || is_android) {
- set_sources_assignment_filter([])
-
# Want this file on both Linux and Android.
sources += [
"crash_handler_host_linux.cc",
@@ -49,10 +31,6 @@ source_set("browser") {
deps += [ "//third_party/crashpad/crashpad/client" ]
}
- if (!is_android) {
- deps += [ "//third_party/breakpad:client" ]
- }
-
# This is not in the GYP build but this target includes breakpad client
# headers, so add the dependency here.
if ((is_posix && !is_ios) || is_fuchsia) {
@@ -61,16 +39,31 @@ source_set("browser") {
}
if (is_android) {
+ sources += [
+ "child_exit_observer_android.cc",
+ "child_exit_observer_android.h",
+ "child_process_crash_observer_android.cc",
+ "child_process_crash_observer_android.h",
+ "crash_memory_metrics_collector_android.cc",
+ "crash_memory_metrics_collector_android.h",
+ "crash_metrics_reporter_android.cc",
+ "crash_metrics_reporter_android.h",
+ ]
deps += [
"//components/crash/android:jni_headers",
"//mojo/public/cpp/bindings",
]
+ } else {
+ deps += [ "//third_party/breakpad:client" ]
}
}
source_set("unit_tests") {
testonly = true
- sources = [ "crash_metrics_reporter_android_unittest.cc" ]
+ sources = []
+ if (is_android) {
+ sources += [ "crash_metrics_reporter_android_unittest.cc" ]
+ }
deps = [
":browser",
"//base/test:test_support",
diff --git a/chromium/components/crash/content/browser/child_exit_observer_android.cc b/chromium/components/crash/content/browser/child_exit_observer_android.cc
index 6b9a219c10d..6cd62b6edbc 100644
--- a/chromium/components/crash/content/browser/child_exit_observer_android.cc
+++ b/chromium/components/crash/content/browser/child_exit_observer_android.cc
@@ -81,7 +81,7 @@ ChildExitObserver::ChildExitObserver() {
content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::NotificationService::AllSources());
BrowserChildProcessObserver::Add(this);
- scoped_observer_.Add(crashpad::CrashHandlerHost::Get());
+ scoped_observation_.Observe(crashpad::CrashHandlerHost::Get());
}
ChildExitObserver::~ChildExitObserver() {
diff --git a/chromium/components/crash/content/browser/child_exit_observer_android.h b/chromium/components/crash/content/browser/child_exit_observer_android.h
index f70f5cf5ee5..3b17693d025 100644
--- a/chromium/components/crash/content/browser/child_exit_observer_android.h
+++ b/chromium/components/crash/content/browser/child_exit_observer_android.h
@@ -13,7 +13,7 @@
#include "base/android/child_process_binding_types.h"
#include "base/lazy_instance.h"
#include "base/process/process.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/synchronization/lock.h"
#include "components/crash/content/browser/crash_handler_host_linux.h"
#include "content/public/browser/browser_child_process_observer.h"
@@ -172,9 +172,9 @@ class ChildExitObserver : public content::BrowserChildProcessObserver,
base::Lock crash_signals_lock_;
std::map<base::ProcessId, int> child_pid_to_crash_signal_;
- ScopedObserver<crashpad::CrashHandlerHost,
- crashpad::CrashHandlerHost::Observer>
- scoped_observer_{this};
+ base::ScopedObservation<crashpad::CrashHandlerHost,
+ crashpad::CrashHandlerHost::Observer>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(ChildExitObserver);
};
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.cc b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
index 949a1d9cbeb..5297dd2997f 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
@@ -16,7 +16,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
diff --git a/chromium/components/crash/content/browser/error_reporting/BUILD.gn b/chromium/components/crash/content/browser/error_reporting/BUILD.gn
index 1f31c8caaba..c37d31917cd 100644
--- a/chromium/components/crash/content/browser/error_reporting/BUILD.gn
+++ b/chromium/components/crash/content/browser/error_reporting/BUILD.gn
@@ -2,30 +2,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Error reporting is not enabled on Fuchsia, so there is no consent checking
-# function. TODO(crbug.com/753619): Enable crash reporting on Fuchsia.
-assert(!is_fuchsia)
-
-# Javascript Error reporting is not currently used on iOS
-assert(!is_ios)
-
-static_library("error_reporting") {
+component("error_reporting") {
sources = [
"javascript_error_report.cc",
"javascript_error_report.h",
- "send_javascript_error_report.cc",
- "send_javascript_error_report.h",
+ "js_error_report_processor.cc",
+ "js_error_report_processor.h",
]
- deps = [
- "//base",
- "//components/crash/core/app",
- "//components/feedback",
- "//content/public/browser",
- "//net",
- "//services/network:network_service",
- "//services/network/public/cpp",
- ]
+ defines = [ "IS_JS_ERROR_REPORTING_IMPL" ]
+
+ deps = [ "//base" ]
}
source_set("mock_crash_endpoint") {
@@ -44,17 +31,3 @@ source_set("mock_crash_endpoint") {
"//url",
]
}
-
-source_set("unit_tests") {
- testonly = true
- sources = [ "send_javascript_error_report_unittest.cc" ]
- deps = [
- ":error_reporting",
- ":mock_crash_endpoint",
- "//base",
- "//components/crash/core/app",
- "//content/test:test_support",
- "//net:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/crash/content/browser/error_reporting/DEPS b/chromium/components/crash/content/browser/error_reporting/DEPS
index 3d71d06c717..8fa9d48d882 100644
--- a/chromium/components/crash/content/browser/error_reporting/DEPS
+++ b/chromium/components/crash/content/browser/error_reporting/DEPS
@@ -1,5 +1,3 @@
include_rules = [
- "+components/feedback",
"+net",
- "+services/network",
]
diff --git a/chromium/components/crash/content/browser/error_reporting/javascript_error_report.h b/chromium/components/crash/content/browser/error_reporting/javascript_error_report.h
index 49f1bed3279..83da8bcf379 100644
--- a/chromium/components/crash/content/browser/error_reporting/javascript_error_report.h
+++ b/chromium/components/crash/content/browser/error_reporting/javascript_error_report.h
@@ -7,12 +7,22 @@
#include <string>
+#include "base/component_export.h"
#include "base/optional.h"
+enum class WindowType {
+ // No browser found, thus no window exists.
+ kNoBrowser,
+ // Valid window types.
+ kRegularTabbed,
+ kWebApp,
+ kSystemWebApp,
+};
+
// A report about a JavaScript error that we might want to send back to Google
// so it can be fixed. Fill in the fields and then call
// SendJavaScriptErrorReport.
-struct JavaScriptErrorReport {
+struct COMPONENT_EXPORT(JS_ERROR_REPORTING) JavaScriptErrorReport {
JavaScriptErrorReport();
JavaScriptErrorReport(const JavaScriptErrorReport& rhs);
JavaScriptErrorReport(JavaScriptErrorReport&& rhs) noexcept;
@@ -44,6 +54,23 @@ struct JavaScriptErrorReport {
// String containing the stack trace for the error. Not sent if not present.
base::Optional<std::string> stack_trace;
+
+ // String containing the application locale. Not sent if not present.
+ base::Optional<std::string> app_locale;
+
+ // Uptime of the renderer process in milliseconds. 0 if the callee
+ // |web_contents| is null (shouldn't really happen as this is caled from a JS
+ // context) or the renderer process doesn't exist (possible due to termination
+ // / failure to start).
+ int renderer_process_uptime_ms = 0;
+
+ // The window type of the JS context that reported this error.
+ base::Optional<WindowType> window_type;
+
+ // If true (the default), send this report to the production server. If false,
+ // send to the staging server. This should be set to false for errors from
+ // tests and dev builds, and true for real (end-user) errors.
+ bool send_to_production_servers = true;
};
#endif // COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JAVASCRIPT_ERROR_REPORT_H_
diff --git a/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.cc b/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.cc
new file mode 100644
index 00000000000..087bd0bec0c
--- /dev/null
+++ b/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.cc
@@ -0,0 +1,29 @@
+// Copyright 2020 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/crash/content/browser/error_reporting/js_error_report_processor.h"
+
+#include "base/no_destructor.h"
+
+namespace {
+scoped_refptr<JsErrorReportProcessor>& GetPointer() {
+ static base::NoDestructor<scoped_refptr<JsErrorReportProcessor>>
+ default_processor;
+ return *default_processor;
+}
+} // namespace
+
+JsErrorReportProcessor::JsErrorReportProcessor() = default;
+JsErrorReportProcessor::~JsErrorReportProcessor() = default;
+
+// static
+scoped_refptr<JsErrorReportProcessor> JsErrorReportProcessor::Get() {
+ return GetPointer();
+}
+
+// static
+void JsErrorReportProcessor::SetDefault(
+ scoped_refptr<JsErrorReportProcessor> processor) {
+ GetPointer() = processor;
+}
diff --git a/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.h b/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.h
new file mode 100644
index 00000000000..924b0a6b3ac
--- /dev/null
+++ b/chromium/components/crash/content/browser/error_reporting/js_error_report_processor.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
+#define COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace content {
+class BrowserContext;
+}
+struct JavaScriptErrorReport;
+
+// Interface class that exposes the SendErrorReport function.
+// We use RefCountedThreadSafe instead of the more normal RefCounted or WeakPtrs
+// because multiple reports can be in-flight at the same time, each on a
+// different sequence, but still using the same JsErrorReportProcessor.
+class COMPONENT_EXPORT(JS_ERROR_REPORTING) JsErrorReportProcessor
+ : public base::RefCountedThreadSafe<JsErrorReportProcessor> {
+ public:
+ REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+ // Returns the current implementation of JsErrorReportProcessor. Callers
+ // should check for nullptr.
+ static scoped_refptr<JsErrorReportProcessor> Get();
+
+ // Sends a report of an error in JavaScript (such as an unhandled exception)
+ // to Google's error collection service. This should be called on the UI
+ // thread; it will return after the report sending is started.
+ // |completion_callback| is called when the report send completes or fails.
+ virtual void SendErrorReport(JavaScriptErrorReport error_report,
+ base::OnceClosure completion_callback,
+ content::BrowserContext* browser_context) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<JsErrorReportProcessor>;
+ JsErrorReportProcessor();
+ virtual ~JsErrorReportProcessor();
+
+ // Sets the JsErrorReportProcessor pointer than should be returned by Get().
+ static void SetDefault(scoped_refptr<JsErrorReportProcessor> processor);
+};
+
+#endif // COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_JS_ERROR_REPORT_PROCESSOR_H_
diff --git a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
index 2e8aae435aa..42f60414f51 100644
--- a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
+++ b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
@@ -7,7 +7,6 @@
#include "base/run_loop.h"
#include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h"
-#include "components/crash/content/browser/error_reporting/send_javascript_error_report.h"
#include "components/crash/core/app/crash_reporter_client.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
@@ -55,7 +54,6 @@ MockCrashEndpoint::MockCrashEndpoint(
&MockCrashEndpoint::HandleRequest, base::Unretained(this)));
EXPECT_TRUE(test_server->Start());
- SetCrashEndpointForTesting(test_server->GetURL(kTestCrashEndpoint).spec());
client_ = std::make_unique<Client>(this);
crash_reporter::SetCrashReporterClient(client_.get());
}
@@ -64,6 +62,10 @@ MockCrashEndpoint::~MockCrashEndpoint() {
crash_reporter::SetCrashReporterClient(nullptr);
}
+std::string MockCrashEndpoint::GetCrashEndpointURL() const {
+ return test_server_->GetURL(kTestCrashEndpoint).spec();
+}
+
MockCrashEndpoint::Report MockCrashEndpoint::WaitForReport() {
if (last_report_) {
return *last_report_;
@@ -82,6 +84,7 @@ MockCrashEndpoint::HandleRequest(const net::test_server::HttpRequest& request) {
return nullptr;
}
+ ++report_count_;
last_report_ = Report(absolute_url.query(), request.content);
auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
diff --git a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.h b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
index 53b11849151..e53732ec6f4 100644
--- a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
+++ b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
@@ -20,7 +20,7 @@ struct HttpRequest;
} // namespace test_server
} // namespace net
-// Installs a mock crash server endpoint into chrome.crashReportPrivate.
+// Installs a mock crash server endpoint.
class MockCrashEndpoint {
public:
struct Report {
@@ -40,10 +40,16 @@ class MockCrashEndpoint {
// Returns the last report received, if any.
const base::Optional<Report>& last_report() const { return last_report_; }
+ // Get the number of reports received since this object was created.
+ int report_count() const { return report_count_; }
+
// Configures whether the mock crash reporter client has user-consent for
// submitting crash reports.
void set_consented(bool consented) { consented_ = consented; }
+ // Returns the URL that tests should send crash reports to.
+ std::string GetCrashEndpointURL() const;
+
private:
class Client;
@@ -53,6 +59,7 @@ class MockCrashEndpoint {
net::test_server::EmbeddedTestServer* test_server_;
std::unique_ptr<Client> client_;
base::Optional<Report> last_report_;
+ int report_count_ = 0;
bool consented_ = true;
base::RepeatingClosure on_report_;
};
diff --git a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.cc b/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.cc
deleted file mode 100644
index 1ce1aebaf91..00000000000
--- a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.cc
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2020 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/crash/content/browser/error_reporting/send_javascript_error_report.h"
-
-#include <memory>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/no_destructor.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/system/sys_info.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "components/crash/content/browser/error_reporting/javascript_error_report.h"
-#include "components/crash/core/app/client_upload_info.h"
-#include "components/feedback/redaction_tool.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "net/base/escape.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-
-namespace {
-
-#if defined(GOOGLE_CHROME_BUILD)
-constexpr char kCrashEndpointUrl[] = "https://clients2.google.com/cr/report";
-#else
-constexpr char kCrashEndpointUrl[] = "";
-#endif
-
-std::string& GetCrashEndpoint() {
- static base::NoDestructor<std::string> crash_endpoint(kCrashEndpointUrl);
- return *crash_endpoint;
-}
-
-struct OsVersionOverride {
- OsVersionOverride(int32_t major_override,
- int32_t minor_override,
- int32_t bugfix_override)
- : major(major_override), minor(minor_override), bugfix(bugfix_override) {}
- int32_t major;
- int32_t minor;
- int32_t bugfix;
-};
-
-// If return value is set, use that as the major/minor/bugfix OS version
-// numbers. This is used as dependency injection during testing.
-base::Optional<OsVersionOverride>& GetOsVersionOverrides() {
- static base::NoDestructor<base::Optional<OsVersionOverride>> testing_override;
- return *testing_override;
-}
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-void OnRequestComplete(std::unique_ptr<network::SimpleURLLoader> url_loader,
- base::ScopedClosureRunner callback_runner,
- std::unique_ptr<std::string> response_body) {
- if (response_body) {
- // TODO(iby): Update the crash log (uploads.log)
- DVLOG(1) << "Uploaded crash report. ID: " << *response_body;
- } else {
- LOG(ERROR) << "Failed to upload crash report";
- }
- // callback_runner will implicitly run the callback when we reach this line.
-}
-
-// Sometimes, the stack trace will contain an error message as the first line,
-// which confuses the Crash server. This function deletes it if it is present.
-void RemoveErrorMessageFromStackTrace(const std::string& error_message,
- std::string& stack_trace) {
- // Keep the original stack trace if the error message is not present.
- const auto error_message_index = stack_trace.find(error_message);
- if (error_message_index == std::string::npos) {
- return;
- }
-
- // If the stack trace only contains one line, then delete the whole trace.
- const auto first_line_end_index = stack_trace.find('\n');
- if (first_line_end_index == std::string::npos) {
- stack_trace.clear();
- return;
- }
-
- // Otherwise, delete the first line.
- stack_trace = stack_trace.substr(first_line_end_index + 1);
-}
-
-std::string RedactErrorMessage(const std::string& message) {
- return feedback::RedactionTool(/*first_party_extension_ids=*/nullptr)
- .Redact(message);
-}
-
-// Returns the redacted, fixed-up error report if the user consented to have it
-// sent. Returns base::nullopt if the user did not consent or we otherwise
-// should not send the report. All the MayBlock work should be done in here.
-base::Optional<JavaScriptErrorReport> CheckConsentAndRedact(
- JavaScriptErrorReport error_report) {
- if (!crash_reporter::GetClientCollectStatsConsent()) {
- return base::nullopt;
- }
-
- // Remove error message from stack trace before redaction, since redaction
- // might change the error message enough that we don't find it.
- if (error_report.stack_trace) {
- RemoveErrorMessageFromStackTrace(error_report.message,
- *error_report.stack_trace);
- }
-
- error_report.message = RedactErrorMessage(error_report.message);
- // TODO(https://crbug.com/1121816): Also redact stack trace, but don't
- // completely remove the URL (only query & fragment).
- return error_report;
-}
-
-using ParameterMap = std::map<std::string, std::string>;
-
-std::string BuildPostRequestQueryString(const ParameterMap& params) {
- std::vector<std::string> query_parts;
- for (const auto& kv : params) {
- query_parts.push_back(base::StrCat(
- {kv.first, "=",
- net::EscapeQueryParamValue(kv.second, /*use_plus=*/false)}));
- }
- return base::JoinString(query_parts, "&");
-}
-
-struct PlatformInfo {
- std::string product_name;
- std::string version;
- std::string channel;
- std::string os_version;
-};
-
-PlatformInfo GetPlatformInfo() {
- PlatformInfo info;
-
- // TODO(https://crbug.com/1121816): Get correct product_name for non-POSIX
- // platforms.
-#if defined(OS_POSIX) && !defined(OS_APPLE)
- crash_reporter::GetClientProductNameAndVersion(&info.product_name,
- &info.version, &info.channel);
-#endif
- int32_t os_major_version = 0;
- int32_t os_minor_version = 0;
- int32_t os_bugfix_version = 0;
- const base::Optional<OsVersionOverride>& version_override =
- GetOsVersionOverrides();
- if (version_override) {
- os_major_version = version_override->major;
- os_minor_version = version_override->minor;
- os_bugfix_version = version_override->bugfix;
- } else {
- base::SysInfo::OperatingSystemVersionNumbers(
- &os_major_version, &os_minor_version, &os_bugfix_version);
- }
-
- info.os_version = base::StringPrintf("%d.%d.%d", os_major_version,
- os_minor_version, os_bugfix_version);
- return info;
-}
-
-void SendReport(const GURL& url,
- const std::string& body,
- base::ScopedClosureRunner callback_runner,
- network::SharedURLLoaderFactory* loader_factory) {
- auto resource_request = std::make_unique<network::ResourceRequest>();
- resource_request->method = "POST";
- resource_request->url = url;
-
- const auto traffic_annotation =
- net::DefineNetworkTrafficAnnotation("javascript_report_error", R"(
- semantics {
- sender: "JavaScript error reporter"
- description:
- "Chrome can send JavaScript errors that occur within built-in "
- "component extensions. If enabled, the error message, along "
- "with information about Chrome and the operating system, is sent to "
- "Google."
- trigger:
- "A JavaScript error occurs in a Chrome component extension (an "
- "extension bundled with the Chrome browser, not downloaded "
- "separately)."
- data:
- "The JavaScript error message, the version and channel of Chrome, "
- "the URL of the extension, the line and column number where the "
- "error occurred, and a stack trace of the error."
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: NO
- setting:
- "You can enable or disable this feature via 'Automatically send "
- "usage statistics and crash reports to Google' in Chromium's "
- "settings under Advanced, Privacy. (This is in System Settings on "
- "Chromebooks.) This feature is enabled by default."
- chrome_policy {
- MetricsReportingEnabled {
- policy_options {mode: MANDATORY}
- MetricsReportingEnabled: false
- }
- }
- })");
-
- DVLOG(1) << "Sending crash report: " << resource_request->url;
-
- auto url_loader = network::SimpleURLLoader::Create(
- std::move(resource_request), traffic_annotation);
-
- if (!body.empty()) {
- url_loader->AttachStringForUpload(body, "text/plain");
- }
-
- constexpr int kCrashEndpointResponseMaxSizeInBytes = 1024;
- network::SimpleURLLoader* loader = url_loader.get();
- loader->DownloadToString(
- loader_factory,
- base::BindOnce(&OnRequestComplete, std::move(url_loader),
- std::move(callback_runner)),
- kCrashEndpointResponseMaxSizeInBytes);
-}
-
-// Finishes sending process once the MayBlock processing is done. On UI thread.
-void OnConsentCheckCompleted(
- base::ScopedClosureRunner callback_runner,
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
- base::Optional<JavaScriptErrorReport> error_report) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!error_report) {
- // User didn't consent. This isn't an error so don't log an error.
- return;
- }
-
- std::string& crash_endpoint_string = GetCrashEndpoint();
- if (crash_endpoint_string.empty()) {
- LOG(WARNING) << "Not sending error reports to Google for browsers that are "
- "not Google Chrome";
- return;
- }
-
- // TODO(https://crbug.com/986166): Use crash_reporter for Chrome OS.
- const auto platform = GetPlatformInfo();
-
- const GURL source(error_report->url);
- const auto product = error_report->product.empty() ? platform.product_name
- : error_report->product;
- const auto version =
- error_report->version.empty() ? platform.version : error_report->version;
-
- ParameterMap params;
- params["prod"] = net::EscapeQueryParamValue(product, /*use_plus=*/false);
- params["ver"] = net::EscapeQueryParamValue(version, /*use_plus=*/false);
- params["type"] = "JavascriptError";
- params["error_message"] = error_report->message;
- params["browser"] = "Chrome";
- params["browser_version"] = platform.version;
- params["channel"] = platform.channel;
- // TODO(https://crbug.com/1121816): Handle non-ChromeOS platforms.
- params["os"] = "ChromeOS";
- params["os_version"] = platform.os_version;
- params["full_url"] = source.spec();
- params["url"] = source.path();
- params["src"] = source.spec();
- if (error_report->line_number)
- params["line"] = base::NumberToString(*error_report->line_number);
- if (error_report->column_number)
- params["column"] = base::NumberToString(*error_report->column_number);
-
- const GURL url(base::StrCat(
- {crash_endpoint_string, "?", BuildPostRequestQueryString(params)}));
- std::string body;
- if (error_report->stack_trace) {
- body = std::move(*error_report->stack_trace);
- }
-
- SendReport(url, body, std::move(callback_runner), loader_factory.get());
-}
-
-#endif // !defined(OS_WIN)
-
-} // namespace
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-void SendJavaScriptErrorReport(JavaScriptErrorReport error_report,
- base::OnceClosure completion_callback,
- content::BrowserContext* browser_context) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- base::ScopedClosureRunner callback_runner(std::move(completion_callback));
-
- // loader_factory must be created on UI thread. Get it now while we still
- // know the browser_context pointer is valid.
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
- content::BrowserContext::GetDefaultStoragePartition(browser_context)
- ->GetURLLoaderFactoryForBrowserProcess();
-
- // Consent check needs to be done on a blockable thread. We must return to
- // this thread (the UI thread) to use the loader_factory.
- base::ThreadPool::PostTaskAndReplyWithResult(
- FROM_HERE, {base::MayBlock()},
- base::BindOnce(&CheckConsentAndRedact, std::move(error_report)),
- base::BindOnce(&OnConsentCheckCompleted, std::move(callback_runner),
- std::move(loader_factory)));
-}
-
-#endif // !defined(OS_WIN)
-
-void SetCrashEndpointForTesting(const std::string& endpoint) {
- GetCrashEndpoint() = endpoint;
-}
-
-// The weird "{" comment is to get the
-// CheckNoProductionCodeUsingTestOnlyFunctions PRESUBMIT to be quiet.
-void SetOsVersionForTesting(int32_t os_major_version, // {
- int32_t os_minor_version,
- int32_t os_bugfix_version) {
- GetOsVersionOverrides().emplace(os_major_version, os_minor_version,
- os_bugfix_version);
-}
-
-void ClearOsVersionTestingOverride() {
- GetOsVersionOverrides().reset();
-}
diff --git a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.h b/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.h
deleted file mode 100644
index 70ab3b36fe5..00000000000
--- a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2020 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_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
-#define COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "build/build_config.h"
-
-namespace content {
-class BrowserContext;
-}
-struct JavaScriptErrorReport;
-
-// TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
-// thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-// Sends a report of an error in JavaScript (such as an unhandled exception) to
-// Google's error collection service. This should be called on the UI thread;
-// it will return after the report sending is started. |completion_callback| is
-// called when the report send completes or fails.
-void SendJavaScriptErrorReport(JavaScriptErrorReport error_report,
- base::OnceClosure completion_callback,
- content::BrowserContext* browser_context);
-
-#endif // !defined(OS_WIN)
-
-// Override the URL we send the crashes to.
-void SetCrashEndpointForTesting(const std::string& endpoint);
-
-// Override the OS Version.
-void SetOsVersionForTesting(int32_t os_major_version,
- int32_t os_minor_version,
- int32_t os_bugfix_version);
-// Go back to the default behavior of getting the OS version from the OS.
-void ClearOsVersionTestingOverride();
-
-#endif // COMPONENTS_CRASH_CONTENT_BROWSER_ERROR_REPORTING_SEND_JAVASCRIPT_ERROR_REPORT_H_
diff --git a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc b/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc
deleted file mode 100644
index 7e0417d837b..00000000000
--- a/chromium/components/crash/content/browser/error_reporting/send_javascript_error_report_unittest.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2020 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/crash/content/browser/error_reporting/send_javascript_error_report.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "build/build_config.h"
-#include "components/crash/content/browser/error_reporting/javascript_error_report.h"
-#include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
-#include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_browser_context.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// TODO(crbug.com/1129544) The SendJavaScriptErrorReport function is currently
-// disabled due to Windows DLL thunking issues. Fix & re-enable.
-#if !defined(OS_WIN)
-
-using ::testing::AllOf;
-using ::testing::HasSubstr;
-
-class SendJavaScriptErrorReportTest : public ::testing::Test {
- public:
- SendJavaScriptErrorReportTest()
- : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
- run_loop_quit_(run_loop_.QuitClosure()) {}
-
- void SetUp() override {
- test_server_ = std::make_unique<net::test_server::EmbeddedTestServer>();
- endpoint_ = std::make_unique<MockCrashEndpoint>(test_server_.get());
- SetOsVersionForTesting(7, 20, 1);
- }
-
- void TearDown() override { ClearOsVersionTestingOverride(); }
-
- void FinishCallback() {
- finish_callback_was_called_ = true;
- run_loop_quit_.Run();
- }
-
- protected:
- content::BrowserTaskEnvironment task_environment_;
- base::RunLoop run_loop_;
- base::RepeatingClosure run_loop_quit_;
- content::TestBrowserContext browser_context_;
- std::unique_ptr<net::test_server::EmbeddedTestServer> test_server_;
- std::unique_ptr<MockCrashEndpoint> endpoint_;
- bool finish_callback_was_called_ = false;
-};
-
-TEST_F(SendJavaScriptErrorReportTest, Basic) {
- JavaScriptErrorReport report;
- report.message = "Hello World";
- report.url = "https://www.chromium.org/Home";
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- const base::Optional<MockCrashEndpoint::Report>& actual_report =
- endpoint_->last_report();
- ASSERT_TRUE(actual_report);
- EXPECT_THAT(actual_report->query, HasSubstr("error_message=Hello%20World"));
- EXPECT_THAT(actual_report->query, HasSubstr("type=JavascriptError"));
- // TODO(iby) research why URL is repeated...
- EXPECT_THAT(actual_report->query,
- HasSubstr("src=https%3A%2F%2Fwww.chromium.org%2FHome"));
- EXPECT_THAT(actual_report->query,
- HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
- EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
- // This is from SetOsVersionForTesting(7, 20, 1) in SetUp().
- EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
- EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
- // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which
- // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816):
- // Get this info for non-POSIX platforms.
-#if defined(OS_POSIX) && !defined(OS_MAC)
- EXPECT_THAT(actual_report->query, HasSubstr("prod=Chrome_ChromeOS"));
- EXPECT_THAT(actual_report->query, HasSubstr("ver=1.2.3.4"));
- EXPECT_THAT(actual_report->query, HasSubstr("browser_version=1.2.3.4"));
- EXPECT_THAT(actual_report->query, HasSubstr("channel=Stable"));
-#endif
- EXPECT_EQ(actual_report->content, "");
-}
-
-TEST_F(SendJavaScriptErrorReportTest, AllFields) {
- JavaScriptErrorReport report;
- report.message = "Hello World";
- report.url = "https://www.chromium.org/Home";
- report.product = "Unit test";
- report.version = "6.2.3.4";
- report.line_number = 83;
- report.column_number = 14;
- report.stack_trace = "bad_func(1, 2)\nonclick()\n";
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- const base::Optional<MockCrashEndpoint::Report>& actual_report =
- endpoint_->last_report();
- ASSERT_TRUE(actual_report);
- EXPECT_THAT(actual_report->query, HasSubstr("error_message=Hello%20World"));
- EXPECT_THAT(actual_report->query, HasSubstr("type=JavascriptError"));
- // TODO(iby) research why URL is repeated...
- EXPECT_THAT(actual_report->query,
- HasSubstr("src=https%3A%2F%2Fwww.chromium.org%2FHome"));
- EXPECT_THAT(actual_report->query,
- HasSubstr("full_url=https%3A%2F%2Fwww.chromium.org%2FHome"));
- EXPECT_THAT(actual_report->query, HasSubstr("url=%2FHome"));
- // This is from SetOsVersionForTesting(7, 20, 1) in SetUp().
- EXPECT_THAT(actual_report->query, HasSubstr("os_version=7.20.1"));
- EXPECT_THAT(actual_report->query, HasSubstr("browser=Chrome"));
- // product is double-escaped. The first time, it transforms to Unit%20test,
- // then the % is turned into %25.
- EXPECT_THAT(actual_report->query, HasSubstr("prod=Unit%2520test"));
- EXPECT_THAT(actual_report->query, HasSubstr("ver=6.2.3.4"));
- EXPECT_THAT(actual_report->query, HasSubstr("line=83"));
- EXPECT_THAT(actual_report->query, HasSubstr("column=14"));
- // These are from MockCrashEndpoint::Client::GetProductNameAndVersion, which
- // is only defined for non-MAC POSIX systems. TODO(https://crbug.com/1121816):
- // Get this info for non-POSIX platforms.
-#if defined(OS_POSIX) && !defined(OS_MAC)
- EXPECT_THAT(actual_report->query, HasSubstr("browser_version=1.2.3.4"));
- EXPECT_THAT(actual_report->query, HasSubstr("channel=Stable"));
-#endif
- EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
-}
-
-TEST_F(SendJavaScriptErrorReportTest, NoConsent) {
- endpoint_->set_consented(false);
- JavaScriptErrorReport report;
- report.message = "Hello World";
- report.url = "https://www.chromium.org/Home";
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- EXPECT_FALSE(endpoint_->last_report());
-}
-
-TEST_F(SendJavaScriptErrorReportTest, StackTraceWithErrorMessage) {
- JavaScriptErrorReport report;
- report.message = "Hello World";
- report.url = "https://www.chromium.org/Home";
- report.stack_trace = "Hello World\nbad_func(1, 2)\nonclick()\n";
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- const base::Optional<MockCrashEndpoint::Report>& actual_report =
- endpoint_->last_report();
- ASSERT_TRUE(actual_report);
- EXPECT_THAT(actual_report->query, HasSubstr("error_message=Hello%20World"));
- EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
-}
-
-TEST_F(SendJavaScriptErrorReportTest, RedactMessage) {
- JavaScriptErrorReport report;
- report.message = "alpha@beta.org says hi to gamma@omega.co.uk";
- report.url = "https://www.chromium.org/Home";
- report.stack_trace =
- "alpha@beta.org says hi to gamma@omega.co.uk\n"
- "bad_func(1, 2)\nonclick()\n";
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- const base::Optional<MockCrashEndpoint::Report>& actual_report =
- endpoint_->last_report();
- ASSERT_TRUE(actual_report);
- // Escaped version of "<email: 1> says hi to <email: 2>"
- EXPECT_THAT(actual_report->query,
- HasSubstr("error_message=%3Cemail%3A%201%3E%20says%20hi%20to%20"
- "%3Cemail%3A%202%3E"));
- // Redacted messages still need to be removed from stack trace.
- EXPECT_EQ(actual_report->content, "bad_func(1, 2)\nonclick()\n");
-}
-
-TEST_F(SendJavaScriptErrorReportTest, NonGoogleChrome) {
- JavaScriptErrorReport report;
- report.message = "Hello World";
- report.url = "https://www.chromium.org/Home";
- // We use a blank URL in non-GOOGLE_CHROME_BUILDs to avoid uploading reports
- // from those browsers.
- SetCrashEndpointForTesting("");
-
- SendJavaScriptErrorReport(
- std::move(report),
- base::BindOnce(&SendJavaScriptErrorReportTest::FinishCallback,
- base::Unretained(this)),
- &browser_context_);
- run_loop_.Run();
- EXPECT_TRUE(finish_callback_was_called_);
-
- const base::Optional<MockCrashEndpoint::Report>& actual_report =
- endpoint_->last_report();
- EXPECT_FALSE(actual_report);
-}
-
-#endif // !defined(OS_WIN)
diff --git a/chromium/components/crash/core/app/BUILD.gn b/chromium/components/crash/core/app/BUILD.gn
index 93c330b4652..4eb4173c7ff 100644
--- a/chromium/components/crash/core/app/BUILD.gn
+++ b/chromium/components/crash/core/app/BUILD.gn
@@ -11,13 +11,6 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
source_set("lib") {
visibility = [
":*",
@@ -56,10 +49,6 @@ static_library("app") {
"crash_switches.cc",
"crash_switches.h",
"crashpad.h",
- "crashpad_android.cc",
- "crashpad_linux.cc",
- "crashpad_mac.mm",
- "crashpad_win.cc",
]
if (is_mac || is_win || is_android || is_linux || is_chromeos) {
@@ -71,6 +60,7 @@ static_library("app") {
"breakpad_linux.cc",
"breakpad_linux.h",
"breakpad_linux_impl.h",
+ "crashpad_linux.cc",
]
}
@@ -91,12 +81,14 @@ static_library("app") {
}
if (is_android) {
+ sources += [ "crashpad_android.cc" ]
deps += [
":crashpad_handler_main",
"//components/crash/android:jni_headers",
"//third_party/crashpad/crashpad/handler",
"//third_party/crashpad/crashpad/snapshot",
]
+ libs = [ "log" ]
}
if (is_android || is_linux || is_chromeos) {
@@ -113,6 +105,7 @@ static_library("app") {
if (is_win) {
sources += [
+ "crashpad_win.cc",
"dump_hung_process_with_ptype.cc",
"dump_hung_process_with_ptype.h",
"minidump_with_crashpad_info.cc",
@@ -128,16 +121,13 @@ static_library("app") {
}
if (is_mac) {
+ sources += [ "crashpad_mac.mm" ]
deps += [
"//third_party/crashpad/crashpad/minidump",
"//third_party/crashpad/crashpad/snapshot",
]
}
- if (is_android) {
- libs = [ "log" ]
- }
-
if (is_linux || is_chromeos) {
data_deps = [ "//third_party/crashpad/crashpad/handler:crashpad_handler" ]
}
@@ -284,11 +274,7 @@ source_set("test_support") {
source_set("unit_tests") {
testonly = true
- sources = [
- "fallback_crash_handler_launcher_win_unittest.cc",
- "fallback_crash_handler_win_unittest.cc",
- "fallback_crash_handling_win_unittest.cc",
- ]
+ sources = []
deps = [
":lib",
"//base",
@@ -298,6 +284,11 @@ source_set("unit_tests") {
]
if (is_win) {
+ sources += [
+ "fallback_crash_handler_launcher_win_unittest.cc",
+ "fallback_crash_handler_win_unittest.cc",
+ "fallback_crash_handling_win_unittest.cc",
+ ]
deps += [
":run_as_crashpad_handler",
"//third_party/breakpad:client",
diff --git a/chromium/components/crash/core/browser/resources/crashes.html b/chromium/components/crash/core/browser/resources/crashes.html
index e04058e786a..a304a004d36 100644
--- a/chromium/components/crash/core/browser/resources/crashes.html
+++ b/chromium/components/crash/core/browser/resources/crashes.html
@@ -18,6 +18,7 @@
<link rel="stylesheet" href="crashes.css">
<script src="chrome://resources/js/action_link.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="strings.js"></script>
<script src="crashes.js"></script>
diff --git a/chromium/components/crash/core/common/BUILD.gn b/chromium/components/crash/core/common/BUILD.gn
index 6dbaaea10eb..d2f6ef41a03 100644
--- a/chromium/components/crash/core/common/BUILD.gn
+++ b/chromium/components/crash/core/common/BUILD.gn
@@ -99,6 +99,7 @@ target(crash_key_target_type, "crash_key_lib") {
if (is_ios) {
sources += [ "crash_key_breakpad_ios.mm" ]
+ deps += [ "//components/previous_session_info" ]
configs += [ "//build/config/compiler:enable_arc" ]
} else {
diff --git a/chromium/components/crash/core/common/DEPS b/chromium/components/crash/core/common/DEPS
index 4d2222b3a0d..17468b60913 100644
--- a/chromium/components/crash/core/common/DEPS
+++ b/chromium/components/crash/core/common/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+components/gwp_asan/buildflags/buildflags.h",
"+components/gwp_asan/client/sampling_malloc_shims.h",
+ "+components/previous_session_info/previous_session_info.h",
"+third_party/breakpad/breakpad/src/client/ios/Breakpad.h",
"+third_party/breakpad/breakpad/src/client/ios/BreakpadController.h",
]
diff --git a/chromium/components/crash/core/common/crash_key_breakpad_ios.mm b/chromium/components/crash/core/common/crash_key_breakpad_ios.mm
index b4099df2e28..a93512f8da0 100644
--- a/chromium/components/crash/core/common/crash_key_breakpad_ios.mm
+++ b/chromium/components/crash/core/common/crash_key_breakpad_ios.mm
@@ -8,6 +8,7 @@
#include "base/strings/sys_string_conversions.h"
#include "components/crash/core/common/crash_key_base_support.h"
+#import "components/previous_session_info/previous_session_info.h"
#import "third_party/breakpad/breakpad/src/client/ios/Breakpad.h"
#import "third_party/breakpad/breakpad/src/client/ios/BreakpadController.h"
@@ -55,6 +56,9 @@ void CrashKeyStringImpl::Set(base::StringPiece value) {
WithBreakpadRefAsync(^(BreakpadRef ref) {
BreakpadAddUploadParameter(ref, key, value_ns);
});
+
+ [[PreviousSessionInfo sharedInstance] setReportParameterValue:value_ns
+ forKey:key];
}
void CrashKeyStringImpl::Clear() {
@@ -63,6 +67,7 @@ void CrashKeyStringImpl::Clear() {
WithBreakpadRefAsync(^(BreakpadRef ref) {
BreakpadRemoveUploadParameter(ref, key);
});
+ [[PreviousSessionInfo sharedInstance] removeReportParameterForKey:key];
}
bool CrashKeyStringImpl::is_set() const {
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index 94b56613408..b5462483305 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -67,6 +67,10 @@ java_cpp_enum("net_request_priority_java") {
sources = [ "//net/base/request_priority.h" ]
}
+java_cpp_enum("net_idempotency_java") {
+ sources = [ "//net/base/idempotency.h" ]
+}
+
java_cpp_enum("network_quality_observation_source_java") {
sources = [ "//net/nqe/network_quality_observation_source.h" ]
}
@@ -82,12 +86,10 @@ java_cpp_enum("http_cache_type_java") {
java_cpp_template("load_states_list") {
sources = [ "java/src/org/chromium/net/impl/LoadState.template" ]
inputs = [ "//net/base/load_states_list.h" ]
- package_path = "org/chromium/net/impl"
}
java_cpp_template("integrated_mode_state") {
sources = [ "java/src/org/chromium/net/impl/IntegratedModeState.template" ]
- package_path = "org/chromium/net/impl"
if (integrated_mode) {
defines = [ "INTEGRATED_MODE" ]
}
@@ -348,6 +350,7 @@ android_library("cronet_impl_fake_base_java") {
}
cronet_impl_native_java_srcjar_deps = [
+ ":net_idempotency_java",
":net_request_priority_java",
":network_quality_observation_source_java",
":url_request_error_java",
@@ -1017,6 +1020,7 @@ if (!is_component_build) {
# it depends on basically all source files.
enable_lint = true
lint_suppressions_file = "lint-suppressions.xml"
+ lint_baseline_file = "lint-baseline.xml"
# Still needs to support Jelly Bean. See crbug.com/922656.
lint_min_sdk_version = 16
@@ -1184,6 +1188,7 @@ if (!is_component_build) {
"//base/android/proguard/chromium_apk.flags",
"//testing/android/proguard_for_test.flags",
]
+ enable_proguard_checks = false
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 3ebce18da59..8ef138c00a5 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -10,7 +10,7 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/json/json_writer.h"
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index cb20b9d6f4c..162657f0e0d 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -15,7 +15,7 @@
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/scoped_feature_list.h"
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
index f2b11e75d85..2a13a6d7e41 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service_unittest.cc
@@ -12,7 +12,6 @@
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h"
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index e6427f5ffde..5e81210a181 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -560,7 +560,7 @@ DataReductionProxyTestContext::data_reduction_proxy_service() const {
TestDataReductionProxyService*
DataReductionProxyTestContext::test_data_reduction_proxy_service() const {
DCHECK(!(test_context_flags_ & USE_MOCK_SERVICE));
- return reinterpret_cast<TestDataReductionProxyService*>(
+ return static_cast<TestDataReductionProxyService*>(
data_reduction_proxy_service());
}
@@ -568,21 +568,21 @@ MockDataReductionProxyService*
DataReductionProxyTestContext::mock_data_reduction_proxy_service() const {
DCHECK(!(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION));
DCHECK(test_context_flags_ & USE_MOCK_SERVICE);
- return reinterpret_cast<MockDataReductionProxyService*>(
+ return static_cast<MockDataReductionProxyService*>(
data_reduction_proxy_service());
}
MockDataReductionProxyRequestOptions*
DataReductionProxyTestContext::mock_request_options() const {
DCHECK(test_context_flags_ & USE_MOCK_REQUEST_OPTIONS);
- return reinterpret_cast<MockDataReductionProxyRequestOptions*>(
+ return static_cast<MockDataReductionProxyRequestOptions*>(
data_reduction_proxy_service()->request_options());
}
TestDataReductionProxyConfigServiceClient*
DataReductionProxyTestContext::test_config_client() {
DCHECK(test_context_flags_ & USE_TEST_CONFIG_CLIENT);
- return reinterpret_cast<TestDataReductionProxyConfigServiceClient*>(
+ return static_cast<TestDataReductionProxyConfigServiceClient*>(
data_reduction_proxy_service()->config_client());
}
diff --git a/chromium/components/data_reduction_proxy/proto/BUILD.gn b/chromium/components/data_reduction_proxy/proto/BUILD.gn
index 6ed094b8d8d..7d97e46c5ec 100644
--- a/chromium/components/data_reduction_proxy/proto/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/proto/BUILD.gn
@@ -10,3 +10,7 @@ proto_library("data_reduction_proxy_proto") {
"data_store.proto",
]
}
+
+proto_library("subresource_redirect_proto") {
+ sources = [ "robots_rules.proto" ]
+}
diff --git a/chromium/components/data_reduction_proxy/proto/robots_rules.proto b/chromium/components/data_reduction_proxy/proto/robots_rules.proto
new file mode 100644
index 00000000000..72173ba6142
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/proto/robots_rules.proto
@@ -0,0 +1,26 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package subresource_redirect.proto;
+
+message RobotsRules {
+ // A single page-pattern rule, either allowed or disallowed.
+ message Rule {
+ oneof rule_field {
+ // The allowed path-patterns.
+ string allowed_pattern = 1;
+ // The disallowed path-patterns.
+ string disallowed_pattern = 2;
+ }
+ }
+
+ // Rules for image resources, ordered by length (longest first).
+ repeated Rule image_ordered_rules = 1;
+ // Rules for video resources, ordered by length (longest first).
+ repeated Rule video_ordered_rules = 2;
+} \ No newline at end of file
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.cc b/chromium/components/data_use_measurement/core/data_use_measurement.cc
index 51708b685e6..e27cf032983 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/stringprintf.h"
@@ -197,13 +198,17 @@ void DataUseMeasurement::MaybeRecordNetworkBytesOS(bool force_record_metrics) {
if (bytes > rx_bytes_os_) {
int64_t incremental_bytes = bytes - rx_bytes_os_;
// Do not record samples with value 0.
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS", incremental_bytes);
+ base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS",
+ incremental_bytes, 50, 10 * 1000 * 1000,
+ 50);
if (IsInForeground(app_state_)) {
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS.Foreground",
- incremental_bytes);
+ base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS.Foreground",
+ incremental_bytes, 50,
+ 10 * 1000 * 1000, 50);
} else {
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesReceived.OS.Background",
- incremental_bytes);
+ base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS.Background",
+ incremental_bytes, 50,
+ 10 * 1000 * 1000, 50);
}
}
}
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
index 5eb549068ca..e29bedb08ad 100644
--- a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
+++ b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
@@ -7,7 +7,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
diff --git a/chromium/components/dbus/menu/BUILD.gn b/chromium/components/dbus/menu/BUILD.gn
index 75dd0ebd379..8192b75892c 100644
--- a/chromium/components/dbus/menu/BUILD.gn
+++ b/chromium/components/dbus/menu/BUILD.gn
@@ -29,6 +29,9 @@ component("menu") {
"//ui/gfx/x",
]
}
+ if (use_ozone) {
+ deps += [ "//ui/ozone" ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/dbus/menu/DEPS b/chromium/components/dbus/menu/DEPS
index 9b41b13c813..1afde18ebad 100644
--- a/chromium/components/dbus/menu/DEPS
+++ b/chromium/components/dbus/menu/DEPS
@@ -4,4 +4,5 @@ include_rules = [
"+ui/events/keycodes",
"+ui/gfx/image",
"+ui/gfx/x",
+ "+ui/ozone/public",
]
diff --git a/chromium/components/dbus/menu/menu.cc b/chromium/components/dbus/menu/menu.cc
index 5b7d11ac49d..556670d6886 100644
--- a/chromium/components/dbus/menu/menu.cc
+++ b/chromium/components/dbus/menu/menu.cc
@@ -167,7 +167,7 @@ DbusMenu::DbusMenu(dbus::ExportedObject* exported_object,
properties_->RegisterInterface(kInterfaceDbusMenu);
auto set_property = [&](const std::string& property_name, auto&& value) {
properties_->SetProperty(kInterfaceDbusMenu, property_name,
- std::move(value), false);
+ std::forward<decltype(value)>(value), false);
};
set_property(kPropertyIconThemePath, DbusArray<DbusString>());
set_property(kPropertyMenuStatus, DbusString(kPropertyValueStatusNormal));
diff --git a/chromium/components/dbus/menu/menu_property_list.cc b/chromium/components/dbus/menu/menu_property_list.cc
index 94f9b3f6349..136ff5735ff 100644
--- a/chromium/components/dbus/menu/menu_property_list.cc
+++ b/chromium/components/dbus/menu/menu_property_list.cc
@@ -8,19 +8,64 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
#include "ui/base/models/image_model.h"
#include "ui/base/models/menu_model.h"
-#include "ui/events/keycodes/keysym_to_unicode.h"
#include "ui/gfx/image/image.h"
#if defined(USE_X11)
-#include "ui/base/ui_base_features.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h" // nogncheck
-#include "ui/gfx/x/x11.h" // nogncheck
+#include "ui/events/keycodes/keysym_to_unicode.h" // nogncheck
#endif
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h" // nogncheck
+#include "ui/ozone/public/ozone_platform.h" // nogncheck
+#include "ui/ozone/public/platform_menu_utils.h" // nogncheck
+#endif
+
+namespace {
+
+std::string ToDBusKeySym(ui::KeyboardCode code) {
+#if defined(USE_OZONE)
+ if (features::IsUsingOzonePlatform()) {
+ const auto* const platorm_menu_utils =
+ ui::OzonePlatform::GetInstance()->GetPlatformMenuUtils();
+ if (platorm_menu_utils)
+ return platorm_menu_utils->ToDBusKeySym(code);
+ return {};
+ }
+#endif
+#if defined(USE_X11)
+ return base::UTF16ToUTF8(
+ base::string16(1, ui::GetUnicodeCharacterFromXKeySym(
+ XKeysymForWindowsKeyCode(code, false))));
+#endif
+ return {};
+}
+
+std::vector<DbusString> GetDbusMenuShortcut(ui::Accelerator accelerator) {
+ auto dbus_key_sym = ToDBusKeySym(accelerator.key_code());
+ if (dbus_key_sym.empty())
+ return {};
+
+ std::vector<DbusString> parts;
+ if (accelerator.IsCtrlDown())
+ parts.emplace_back("Control");
+ if (accelerator.IsAltDown())
+ parts.emplace_back("Alt");
+ if (accelerator.IsShiftDown())
+ parts.emplace_back("Shift");
+ if (accelerator.IsCmdDown())
+ parts.emplace_back("Super");
+ parts.emplace_back(dbus_key_sym);
+ return parts;
+}
+
+} // namespace
+
MenuItemProperties ComputeMenuPropertiesForMenuItem(ui::MenuModel* menu,
int i) {
// Properties should only be set if they differ from the default values.
@@ -48,26 +93,11 @@ MenuItemProperties ComputeMenuPropertiesForMenuItem(ui::MenuModel* menu,
ui::Accelerator accelerator;
if (menu->GetAcceleratorAt(i, &accelerator)) {
- std::vector<DbusString> parts;
- if (accelerator.IsCtrlDown())
- parts.emplace_back("Control");
- if (accelerator.IsAltDown())
- parts.emplace_back("Alt");
- if (accelerator.IsShiftDown())
- parts.emplace_back("Shift");
- if (accelerator.IsCmdDown())
- parts.emplace_back("Super");
-#if defined(USE_X11)
- if (!features::IsUsingOzonePlatform()) {
- uint16_t keysym = ui::GetUnicodeCharacterFromXKeySym(
- XKeysymForWindowsKeyCode(accelerator.key_code(), false));
- parts.emplace_back(base::UTF16ToUTF8(base::string16(1, keysym)));
+ auto parts = GetDbusMenuShortcut(accelerator);
+ if (!parts.empty()) {
properties["shortcut"] = MakeDbusVariant(
MakeDbusArray(DbusArray<DbusString>(std::move(parts))));
}
-#else
- NOTIMPLEMENTED();
-#endif
}
switch (menu->GetTypeAt(i)) {
diff --git a/chromium/components/dbus/menu/menu_property_list_unittest.cc b/chromium/components/dbus/menu/menu_property_list_unittest.cc
index 06e24b83f5d..4de29197b67 100644
--- a/chromium/components/dbus/menu/menu_property_list_unittest.cc
+++ b/chromium/components/dbus/menu/menu_property_list_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/dbus/properties/types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/accelerator.h"
@@ -318,7 +319,7 @@ TEST(MenuPropertyListTest, ComputePropertiesIcon) {
EXPECT_EQ(menu->ComputeProperties(), props);
}
-#if defined(USE_X11)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
TEST(MenuPropertyListTest, ComputePropertiesAccelerator) {
if (features::IsUsingOzonePlatform())
return;
diff --git a/chromium/components/dbus/properties/dbus_properties.h b/chromium/components/dbus/properties/dbus_properties.h
index 0a12aef88e7..ac25d699ac5 100644
--- a/chromium/components/dbus/properties/dbus_properties.h
+++ b/chromium/components/dbus/properties/dbus_properties.h
@@ -36,7 +36,7 @@ class COMPONENT_EXPORT(DBUS) DbusProperties {
auto interface_it = properties_.find(interface);
DCHECK(interface_it != properties_.end());
auto property_it = interface_it->second.find(name);
- DbusVariant new_value = MakeDbusVariant(std::move(value));
+ DbusVariant new_value = MakeDbusVariant(std::forward<T>(value));
const bool send_signal =
emit_signal && (property_it == interface_it->second.end() ||
property_it->second != new_value);
diff --git a/chromium/components/dbus/properties/types.h b/chromium/components/dbus/properties/types.h
index 454f0ab5027..0ce364810eb 100644
--- a/chromium/components/dbus/properties/types.h
+++ b/chromium/components/dbus/properties/types.h
@@ -375,7 +375,7 @@ class COMPONENT_EXPORT(DBUS) DbusDictEntry
template <typename K, typename V>
auto MakeDbusDictEntry(K&& k, V&& v) {
- return DbusDictEntry<K, V>(std::move(k), std::move(v));
+ return DbusDictEntry<K, V>(std::forward<K>(k), std::forward<V>(v));
}
// A convenience class for DbusArray<DbusDictEntry<DbusString, DbusVariant>>,
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
index 528e02d11ec..ddf0f3ba616 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -190,11 +190,11 @@ ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager(
mojo::PendingRemote<mojom::DiscardableSharedMemoryManager> manager,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner)
- : heap_(std::make_unique<DiscardableSharedMemoryHeap>()),
- periodic_purge_task_runner_(std::move(periodic_purge_task_runner)),
- io_task_runner_(std::move(io_task_runner)),
- manager_mojo_(std::make_unique<
- mojo::Remote<mojom::DiscardableSharedMemoryManager>>()) {
+ : ClientDiscardableSharedMemoryManager(
+ std::move(io_task_runner),
+ std::move(periodic_purge_task_runner)) {
+ manager_mojo_ =
+ std::make_unique<mojo::Remote<mojom::DiscardableSharedMemoryManager>>();
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "ClientDiscardableSharedMemoryManager",
base::ThreadTaskRunnerHandle::Get());
@@ -206,7 +206,9 @@ ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager(
ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner)
- : heap_(std::make_unique<DiscardableSharedMemoryHeap>()),
+ : RefCountedDeleteOnSequence<ClientDiscardableSharedMemoryManager>(
+ base::ThreadTaskRunnerHandle::Get()),
+ heap_(std::make_unique<DiscardableSharedMemoryHeap>()),
periodic_purge_task_runner_(std::move(periodic_purge_task_runner)),
io_task_runner_(std::move(io_task_runner)) {}
@@ -314,6 +316,11 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
free_span->set_is_locked(true);
+ if (pages >= allocation_pages) {
+ UMA_HISTOGRAM_BOOLEAN("Memory.Discardable.LargeAllocationFromFreelist",
+ true);
+ }
+
// Memory usage is guaranteed to have changed after having removed
// at least one span from the free lists.
MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());
@@ -373,6 +380,11 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
heap_->MergeIntoFreeLists(std::move(leftover));
}
+ if (pages >= allocation_pages) {
+ UMA_HISTOGRAM_BOOLEAN("Memory.Discardable.LargeAllocationFromFreelist",
+ false);
+ }
+
MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());
auto discardable_memory =
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
index f949718011d..f0695afbbff 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
@@ -12,7 +12,7 @@
#include "base/feature_list.h"
#include "base/memory/discardable_memory_allocator.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -34,14 +34,15 @@ DISCARDABLE_MEMORY_EXPORT extern const base::Feature kSchedulePeriodicPurge;
// discardable memory segments through the browser process.
class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
: public base::DiscardableMemoryAllocator,
- public base::trace_event::MemoryDumpProvider {
+ public base::trace_event::MemoryDumpProvider,
+ public base::RefCountedDeleteOnSequence<
+ ClientDiscardableSharedMemoryManager> {
public:
ClientDiscardableSharedMemoryManager(
mojo::PendingRemote<mojom::DiscardableSharedMemoryManager> manager,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner =
nullptr);
- ~ClientDiscardableSharedMemoryManager() override;
// Overridden from base::DiscardableMemoryAllocator:
std::unique_ptr<base::DiscardableMemory> AllocateLockedDiscardableMemory(
@@ -96,6 +97,11 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
// These fields are only protected for testing, they would otherwise be
// private. Everything else should be either public or private.
protected:
+ friend class base::RefCountedDeleteOnSequence<
+ ClientDiscardableSharedMemoryManager>;
+ friend class base::DeleteHelper<ClientDiscardableSharedMemoryManager>;
+
+ ~ClientDiscardableSharedMemoryManager() override;
ClientDiscardableSharedMemoryManager(
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> periodic_purge_task_runner);
@@ -134,7 +140,9 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
bool is_locked() const EXCLUSIVE_LOCKS_REQUIRED(manager_->GetLock());
friend class ClientDiscardableSharedMemoryManager;
- ClientDiscardableSharedMemoryManager* const manager_;
+ // We need to ensure that |manager_| outlives |this|, to avoid a
+ // use-after-free.
+ scoped_refptr<ClientDiscardableSharedMemoryManager> const manager_;
std::unique_ptr<DiscardableSharedMemoryHeap::Span> span_;
// Set to an invalid base::TimeTicks when |this| is Lock()-ed, and to
// |TimeTicks::Now()| each time |this| is Unlock()-ed.
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
index 5dc8114df96..8b5e5baf7f2 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
@@ -48,8 +48,6 @@ class TestClientDiscardableSharedMemoryManager
base::MakeRefCounted<TestSingleThreadTaskRunner>(),
periodic_purge_task_runner) {}
- ~TestClientDiscardableSharedMemoryManager() override = default;
-
std::unique_ptr<base::DiscardableSharedMemory>
AllocateLockedDiscardableSharedMemory(size_t size, int32_t id) override {
auto shared_memory = std::make_unique<base::DiscardableSharedMemory>();
@@ -73,29 +71,23 @@ class TestClientDiscardableSharedMemoryManager
base::AutoLock lock(lock_);
return timer_ == nullptr;
}
-};
-class ClientDiscardableSharedMemoryManagerTest : public testing::Test {
- public:
- void SetUp() override {
- client_ =
- std::make_unique<TestClientDiscardableSharedMemoryManager>(nullptr);
- }
- std::unique_ptr<TestClientDiscardableSharedMemoryManager> client_;
- const size_t page_size_ = base::GetPageSize();
+ private:
+ ~TestClientDiscardableSharedMemoryManager() override = default;
};
-class ClientDiscardableSharedMemoryManagerPeriodicPurgingTest
- : public ClientDiscardableSharedMemoryManagerTest {
+class ClientDiscardableSharedMemoryManagerTest : public testing::Test {
public:
- ClientDiscardableSharedMemoryManagerPeriodicPurgingTest()
+ ClientDiscardableSharedMemoryManagerTest()
: task_env_(base::test::TaskEnvironment::MainThreadType::UI,
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
- client_ = std::make_unique<TestClientDiscardableSharedMemoryManager>(
+ client_ = base::MakeRefCounted<TestClientDiscardableSharedMemoryManager>(
task_env_.GetMainThreadTaskRunner());
}
base::test::TaskEnvironment task_env_;
+ scoped_refptr<TestClientDiscardableSharedMemoryManager> client_;
+ const size_t page_size_ = base::GetPageSize();
};
// This test allocates a single piece of memory, then verifies that calling
@@ -285,8 +277,7 @@ TEST_F(ClientDiscardableSharedMemoryManagerTest, ReleaseUnlocked) {
// This tests that memory is actually removed by the periodic purging. We mock a
// task runner for this test and fast forward to make sure that the memory is
// purged at the right time.
-TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
- ScheduledReleaseUnlocked) {
+TEST_F(ClientDiscardableSharedMemoryManagerTest, ScheduledReleaseUnlocked) {
base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
ASSERT_EQ(client_->GetBytesAllocated(), 0u);
@@ -309,7 +300,7 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
// Same as the above test, but tests that multiple pieces of memory will be
// handled properly.
-TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
+TEST_F(ClientDiscardableSharedMemoryManagerTest,
ScheduledReleaseUnlockedMultiple) {
base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
@@ -394,8 +385,7 @@ TEST_F(ClientDiscardableSharedMemoryManagerTest, LockingSuccessUma) {
// Test that a repeating timer for background purging is created when we
// allocate memory and discarded when we run out of allocated memory.
-TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
- SchedulingProactivePurging) {
+TEST_F(ClientDiscardableSharedMemoryManagerTest, SchedulingProactivePurging) {
base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
ASSERT_TRUE(client_->TimerIsNull());
@@ -427,7 +417,7 @@ TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
// This test is similar to the one above, but tests that creating and deleting
// the timer still works with multiple pieces of allocated memory.
-TEST_F(ClientDiscardableSharedMemoryManagerPeriodicPurgingTest,
+TEST_F(ClientDiscardableSharedMemoryManagerTest,
SchedulingProactivePurgingMultipleAllocations) {
base::test::ScopedFeatureList fl;
fl.InitAndEnableFeature(discardable_memory::kSchedulePeriodicPurge);
diff --git a/chromium/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc b/chromium/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
index 5d3a7843f5f..52cc3637b70 100644
--- a/chromium/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
+++ b/chromium/components/discardable_memory/common/discardable_shared_memory_heap_unittest.cc
@@ -9,7 +9,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/discardable_shared_memory.h"
#include "base/process/process_metrics.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
index d98bcb94aca..a3e4fa9ab38 100644
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "build/build_config.h"
diff --git a/chromium/components/dom_distiller/core/distiller_unittest.cc b/chromium/components/dom_distiller/core/distiller_unittest.cc
index f36336a952d..1aed94ad9e9 100644
--- a/chromium/components/dom_distiller/core/distiller_unittest.cc
+++ b/chromium/components/dom_distiller/core/distiller_unittest.cc
@@ -14,7 +14,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc b/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
index cb65c933ad5..e2be41c6c88 100644
--- a/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
+++ b/chromium/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
@@ -5,7 +5,7 @@
#include "components/dom_distiller/core/distiller_url_fetcher.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
diff --git a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
index 8c645002cff..b3380e95a04 100644
--- a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/id_map.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
diff --git a/chromium/components/domain_reliability/OWNERS b/chromium/components/domain_reliability/OWNERS
index 03bc329a96e..6016d30496f 100644
--- a/chromium/components/domain_reliability/OWNERS
+++ b/chromium/components/domain_reliability/OWNERS
@@ -1,7 +1,5 @@
file://net/OWNERS
file://net/network_error_logging/OWNERS
-per-file quic_error_mapping*=zhongyi@chromium.org
-
# COMPONENT: Internals>Network>ReportingAndNEL
# TEAM: net-dev@chromium.org
diff --git a/chromium/components/domain_reliability/context_manager.cc b/chromium/components/domain_reliability/context_manager.cc
index ef062424cda..4dd1b50c348 100644
--- a/chromium/components/domain_reliability/context_manager.cc
+++ b/chromium/components/domain_reliability/context_manager.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/domain_reliability/google_configs.h"
#include "net/base/url_util.h"
diff --git a/chromium/components/domain_reliability/monitor_unittest.cc b/chromium/components/domain_reliability/monitor_unittest.cc
index 628c4175305..8031bb46b86 100644
--- a/chromium/components/domain_reliability/monitor_unittest.cc
+++ b/chromium/components/domain_reliability/monitor_unittest.cc
@@ -13,7 +13,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/string_piece.h"
#include "base/test/task_environment.h"
#include "components/domain_reliability/baked_in_configs.h"
diff --git a/chromium/components/domain_reliability/quic_error_mapping.cc b/chromium/components/domain_reliability/quic_error_mapping.cc
index 7d104df5c1a..70aeff4bf41 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.cc
+++ b/chromium/components/domain_reliability/quic_error_mapping.cc
@@ -312,9 +312,44 @@ const struct QuicErrorMapping {
{quic::QUIC_TRANSPORT_INVALID_CLIENT_INDICATION,
"quic.transport.invalid.client.indication"},
- {quic::QUIC_QPACK_DECOMPRESSION_FAILED, "QUIC.QPACK.DECOMPRESSION.FAILED"},
- {quic::QUIC_QPACK_ENCODER_STREAM_ERROR, "QUIC.QPACK.ENCODER.STREAM.ERROR"},
- {quic::QUIC_QPACK_DECODER_STREAM_ERROR, "QUIC.QPACK.DECODER.STREAM.ERROR"},
+ {quic::QUIC_QPACK_DECOMPRESSION_FAILED, "quic.qpack.decompression.failed"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_ERROR, "quic.qpack.encoder.stream.error"},
+ {quic::QUIC_QPACK_DECODER_STREAM_ERROR, "quic.qpack.decoder.stream.error"},
+
+ {quic::QUIC_QPACK_ENCODER_STREAM_INTEGER_TOO_LARGE,
+ "quic.qpack.encoder.stream.integer.too.large"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_STRING_LITERAL_TOO_LONG,
+ "quic.qpack.encoder.stream.string.literal.too.long"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_HUFFMAN_ENCODING_ERROR,
+ "quic.qpack.encoder.stream.huffman.encoding.error"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_INVALID_STATIC_ENTRY,
+ "quic.qpack.encoder.stream.invalid.static.entry"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_STATIC,
+ "quic.qpack.encoder.stream.error.inserting.static"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_INSERTION_INVALID_RELATIVE_INDEX,
+ "quic.qpack.encoder.stream.insertion.invalid.relative.index"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_INSERTION_DYNAMIC_ENTRY_NOT_FOUND,
+ "quic.qpack.encoder.stream.insertion.dynamic.entry.not.found"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_DYNAMIC,
+ "quic.qpack.encoder.stream.error.inserting.dynamic"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_LITERAL,
+ "quic.qpack.encoder.stream.error.inserting.literal"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_DUPLICATE_INVALID_RELATIVE_INDEX,
+ "quic.qpack.encoder.stream.duplicate.invalid.relative.index"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_DUPLICATE_DYNAMIC_ENTRY_NOT_FOUND,
+ "quic.qpack.encoder.stream.duplicate.dynamic.entry.not.found"},
+ {quic::QUIC_QPACK_ENCODER_STREAM_SET_DYNAMIC_TABLE_CAPACITY,
+ "quic.qpack.encoder.stream.set.dynamic.table.capacity"},
+ {quic::QUIC_QPACK_DECODER_STREAM_INTEGER_TOO_LARGE,
+ "quic.qpack.decoder.stream.integer.too.large"},
+ {quic::QUIC_QPACK_DECODER_STREAM_INVALID_ZERO_INCREMENT,
+ "quic.qpack.decoder.stream.invalid.zero.increment"},
+ {quic::QUIC_QPACK_DECODER_STREAM_INCREMENT_OVERFLOW,
+ "quic.qpack.decoder.stream.increment.overflow"},
+ {quic::QUIC_QPACK_DECODER_STREAM_IMPOSSIBLE_INSERT_COUNT,
+ "quic.qpack.decoder.stream.impossible.insert.count"},
+ {quic::QUIC_QPACK_DECODER_STREAM_INCORRECT_ACKNOWLEDGEMENT,
+ "quic.qpack.decoder.stream.incorrect.acknowledgement"},
{quic::QUIC_STREAM_DATA_BEYOND_CLOSE_OFFSET,
"quic.stream.data.beyond.close.offset"},
@@ -384,6 +419,10 @@ const struct QuicErrorMapping {
{quic::QUIC_SILENT_IDLE_TIMEOUT, "quic.silent_idle_timeout"},
{quic::QUIC_HTTP_RECEIVE_SPDY_SETTING, "quic.http_receive_spdy_setting"},
{quic::QUIC_MISSING_WRITE_KEYS, "quic.missing_write_keys"},
+ {quic::QUIC_HTTP_RECEIVE_SPDY_FRAME, "quic.http_receive_spdy_frame"},
+
+ {quic::QUIC_KEY_UPDATE_ERROR, "quic.quic_key_update_error"},
+ {quic::QUIC_AEAD_LIMIT_REACHED, "quic.quic_aead_limit_reached"},
// QUIC_INVALID_APPLICATION_CLOSE_DATA was code 101. The code has been
// deprecated, but to keep the assert below happy, there needs to be
@@ -391,6 +430,7 @@ const struct QuicErrorMapping {
{static_cast<quic::QuicErrorCode>(101),
"quic.invalid.application_close_data"},
+ {quic::QUIC_MAX_AGE_TIMEOUT, "quic.quic_max_age_timeout"},
// No error. Used as bound while iterating.
{quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/chromium/components/download/content/DEPS b/chromium/components/download/content/DEPS
index aea8a9407dc..1970e140a85 100644
--- a/chromium/components/download/content/DEPS
+++ b/chromium/components/download/content/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/keyed_service",
"+components/leveldb_proto",
"+content/public/browser",
+ "+content/public/common",
"+content/public/test",
"+base",
"+net",
diff --git a/chromium/components/download/content/internal/BUILD.gn b/chromium/components/download/content/internal/BUILD.gn
index 341bb8e446b..00eda462d8a 100644
--- a/chromium/components/download/content/internal/BUILD.gn
+++ b/chromium/components/download/content/internal/BUILD.gn
@@ -13,6 +13,10 @@ source_set("internal") {
"download_driver_impl.h",
]
+ if (is_android) {
+ sources += [ "context_menu_download.cc" ]
+ }
+
public_deps = [
"//components/download/content/public",
"//components/download/internal/background_service:internal",
diff --git a/chromium/components/download/content/internal/context_menu_download.cc b/chromium/components/download/content/internal/context_menu_download.cc
new file mode 100644
index 00000000000..8540e33d8d2
--- /dev/null
+++ b/chromium/components/download/content/internal/context_menu_download.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 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/download/content/public/context_menu_download.h"
+
+#include "components/download/public/common/download_url_parameters.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_request_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/referrer.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace download {
+
+void CreateContextMenuDownload(content::WebContents* web_contents,
+ const content::ContextMenuParams& params,
+ const std::string& origin,
+ bool is_link) {
+ const GURL& url = is_link ? params.link_url : params.src_url;
+ const GURL& referring_url =
+ params.frame_url.is_empty() ? params.page_url : params.frame_url;
+ content::DownloadManager* dlm = content::BrowserContext::GetDownloadManager(
+ web_contents->GetBrowserContext());
+ std::unique_ptr<download::DownloadUrlParameters> dl_params(
+ content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
+ web_contents, url,
+ TRAFFIC_ANNOTATION_WITHOUT_PROTO("Download via context menu")));
+ content::Referrer referrer = content::Referrer::SanitizeForRequest(
+ url,
+ content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
+ dl_params->set_referrer(referrer.url);
+ dl_params->set_referrer_policy(
+ content::Referrer::ReferrerPolicyForUrlRequest(referrer.policy));
+
+ if (is_link)
+ dl_params->set_referrer_encoding(params.frame_charset);
+ if (!is_link)
+ dl_params->set_prefer_cache(true);
+ dl_params->set_prompt(false);
+ dl_params->set_request_origin(origin);
+ dl_params->set_suggested_name(params.suggested_filename);
+ dl_params->set_download_source(download::DownloadSource::CONTEXT_MENU);
+ dlm->DownloadUrl(std::move(dl_params));
+}
+
+} // namespace download
diff --git a/chromium/components/download/content/internal/download_driver_impl.cc b/chromium/components/download/content/internal/download_driver_impl.cc
index 1a95d5b6d53..eb5d6fc2d0f 100644
--- a/chromium/components/download/content/internal/download_driver_impl.cc
+++ b/chromium/components/download/content/internal/download_driver_impl.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
diff --git a/chromium/components/download/content/internal/download_driver_impl_unittest.cc b/chromium/components/download/content/internal/download_driver_impl_unittest.cc
index 61f933116ce..c32912245db 100644
--- a/chromium/components/download/content/internal/download_driver_impl_unittest.cc
+++ b/chromium/components/download/content/internal/download_driver_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <string>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/download/content/public/BUILD.gn b/chromium/components/download/content/public/BUILD.gn
index 21f231849df..5d4a1e327f7 100644
--- a/chromium/components/download/content/public/BUILD.gn
+++ b/chromium/components/download/content/public/BUILD.gn
@@ -15,6 +15,10 @@ source_set("public") {
"download_navigation_observer.h",
]
+ if (is_android) {
+ sources += [ "context_menu_download.h" ]
+ }
+
public_deps = [ "//base" ]
deps = [
diff --git a/chromium/components/download/content/public/context_menu_download.h b/chromium/components/download/content/public/context_menu_download.h
new file mode 100644
index 00000000000..366d2b2f5c7
--- /dev/null
+++ b/chromium/components/download/content/public/context_menu_download.h
@@ -0,0 +1,25 @@
+// Copyright 2020 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_DOWNLOAD_CONTENT_PUBLIC_CONTEXT_MENU_DOWNLOAD_H_
+#define COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_CONTEXT_MENU_DOWNLOAD_H_
+
+#include <string>
+
+namespace content {
+class WebContents;
+struct ContextMenuParams;
+} // namespace content
+
+namespace download {
+
+// Starts a download for the given ContextMenuParams.
+void CreateContextMenuDownload(content::WebContents* web_contents,
+ const content::ContextMenuParams& params,
+ const std::string& origin,
+ bool is_link);
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_CONTEXT_MENU_DOWNLOAD_H_
diff --git a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
index c8d65fcc709..4064c983072 100644
--- a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
+++ b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
@@ -8,7 +8,7 @@
#include "base/guid.h"
#include "base/message_loop/message_pump_type.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
#include "net/base/io_buffer.h"
diff --git a/chromium/components/download/internal/background_service/logger_impl.cc b/chromium/components/download/internal/background_service/logger_impl.cc
index 554ac37b560..6120d0e9eac 100644
--- a/chromium/components/download/internal/background_service/logger_impl.cc
+++ b/chromium/components/download/internal/background_service/logger_impl.cc
@@ -56,6 +56,8 @@ std::string ClientToString(DownloadClient client) {
return "MountainInternal";
case DownloadClient::PLUGIN_VM_IMAGE:
return "PluginVmImage";
+ case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
+ return "OptimizationGuidePredictionModels";
case DownloadClient::BOUNDARY: // Intentional fallthrough.
default:
NOTREACHED();
diff --git a/chromium/components/download/internal/background_service/proto/entry.proto b/chromium/components/download/internal/background_service/proto/entry.proto
index 081b68a9b23..f699afc3f04 100644
--- a/chromium/components/download/internal/background_service/proto/entry.proto
+++ b/chromium/components/download/internal/background_service/proto/entry.proto
@@ -23,7 +23,10 @@ enum DownloadClient {
DEBUGGING = 6;
MOUNTAIN_INTERNAL = 7;
PLUGIN_VM_IMAGE = 8;
- BOUNDARY = 9;
+ OPTIMIZATION_GUIDE_PREDICTION_MODELS = 9;
+
+ // New clients should be added above here.
+ BOUNDARY = 10;
}
// Stores the request params, internal state, metrics and metadata associated
diff --git a/chromium/components/download/internal/background_service/proto_conversions.cc b/chromium/components/download/internal/background_service/proto_conversions.cc
index 4970848cf42..560fd484d03 100644
--- a/chromium/components/download/internal/background_service/proto_conversions.cc
+++ b/chromium/components/download/internal/background_service/proto_conversions.cc
@@ -72,6 +72,8 @@ protodb::DownloadClient ProtoConversions::DownloadClientToProto(
return protodb::DownloadClient::MOUNTAIN_INTERNAL;
case DownloadClient::PLUGIN_VM_IMAGE:
return protodb::DownloadClient::PLUGIN_VM_IMAGE;
+ case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
+ return protodb::DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS;
case DownloadClient::BOUNDARY:
return protodb::DownloadClient::BOUNDARY;
}
@@ -101,6 +103,8 @@ DownloadClient ProtoConversions::DownloadClientFromProto(
return DownloadClient::MOUNTAIN_INTERNAL;
case protodb::DownloadClient::PLUGIN_VM_IMAGE:
return DownloadClient::PLUGIN_VM_IMAGE;
+ case protodb::DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
+ return DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS;
case protodb::DownloadClient::BOUNDARY:
return DownloadClient::BOUNDARY;
}
diff --git a/chromium/components/download/internal/background_service/stats.cc b/chromium/components/download/internal/background_service/stats.cc
index 1a98f954f23..e4444d9119a 100644
--- a/chromium/components/download/internal/background_service/stats.cc
+++ b/chromium/components/download/internal/background_service/stats.cc
@@ -96,6 +96,8 @@ std::string ClientToHistogramSuffix(DownloadClient client) {
return "MountainInternal";
case DownloadClient::PLUGIN_VM_IMAGE:
return "PluginVmImage";
+ case DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS:
+ return "OptimizationGuidePredictionModels";
case DownloadClient::BOUNDARY:
NOTREACHED();
break;
diff --git a/chromium/components/download/internal/common/BUILD.gn b/chromium/components/download/internal/common/BUILD.gn
index b2e26585bbe..37672de3548 100644
--- a/chromium/components/download/internal/common/BUILD.gn
+++ b/chromium/components/download/internal/common/BUILD.gn
@@ -9,13 +9,6 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
source_set("internal") {
visibility = [
":for_tests",
@@ -29,7 +22,6 @@ source_set("internal") {
sources = [
"all_download_event_notifier.cc",
"base_file.cc",
- "base_file_win.cc",
"download_create_info.cc",
"download_db_cache.cc",
"download_db_cache.h",
@@ -109,6 +101,10 @@ source_set("internal") {
deps += [ ":jni_headers" ]
}
+ if (is_win) {
+ sources += [ "base_file_win.cc" ]
+ }
+
if (is_posix || is_fuchsia) {
sources += [ "base_file_posix.cc" ]
}
@@ -156,7 +152,6 @@ source_set("unit_tests") {
sources = [
"all_download_event_notifier_unittest.cc",
"base_file_unittest.cc",
- "base_file_win_unittest.cc",
"download_db_cache_unittest.cc",
"download_file_unittest.cc",
"download_item_impl_unittest.cc",
@@ -168,6 +163,10 @@ source_set("unit_tests") {
"rate_estimator_unittest.cc",
]
+ if (is_win) {
+ sources += [ "base_file_win_unittest.cc" ]
+ }
+
deps = [
":for_tests",
"//base/test:test_support",
diff --git a/chromium/components/download/internal/common/all_download_event_notifier_unittest.cc b/chromium/components/download/internal/common/all_download_event_notifier_unittest.cc
index b84fe2ad3b8..e71591186f8 100644
--- a/chromium/components/download/internal/common/all_download_event_notifier_unittest.cc
+++ b/chromium/components/download/internal/common/all_download_event_notifier_unittest.cc
@@ -4,7 +4,7 @@
#include "components/download/public/common/all_download_event_notifier.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "components/download/public/common/mock_download_item.h"
#include "components/download/public/common/mock_simple_download_manager.h"
diff --git a/chromium/components/download/internal/common/download_item_impl_delegate.cc b/chromium/components/download/internal/common/download_item_impl_delegate.cc
index f31ba16df7e..0f5ca1f5834 100644
--- a/chromium/components/download/internal/common/download_item_impl_delegate.cc
+++ b/chromium/components/download/internal/common/download_item_impl_delegate.cc
@@ -4,7 +4,7 @@
#include "components/download/public/common/download_item_impl_delegate.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "build/build_config.h"
#include "components/download/public/common/auto_resumption_handler.h"
diff --git a/chromium/components/download/internal/common/download_item_impl_unittest.cc b/chromium/components/download/internal/common/download_item_impl_unittest.cc
index 39d60b83a6d..3f30ed1b4f5 100644
--- a/chromium/components/download/internal/common/download_item_impl_unittest.cc
+++ b/chromium/components/download/internal/common/download_item_impl_unittest.cc
@@ -13,8 +13,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/containers/circular_deque.h"
#include "base/containers/queue.h"
#include "base/files/file_util.h"
diff --git a/chromium/components/download/internal/common/download_job.cc b/chromium/components/download/internal/common/download_job.cc
index d27f2406816..852dbfe40c7 100644
--- a/chromium/components/download/internal/common/download_job.cc
+++ b/chromium/components/download/internal/common/download_job.cc
@@ -5,7 +5,7 @@
#include "components/download/public/common/download_job.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_task_runner.h"
diff --git a/chromium/components/download/internal/common/download_job_factory.cc b/chromium/components/download/internal/common/download_job_factory.cc
index 052f69f7769..f40905b7bb3 100644
--- a/chromium/components/download/internal/common/download_job_factory.cc
+++ b/chromium/components/download/internal/common/download_job_factory.cc
@@ -13,7 +13,6 @@
#include "components/download/internal/common/save_package_download_job.h"
#include "components/download/public/common/download_features.h"
#include "components/download/public/common/download_item.h"
-#include "components/download/public/common/download_stats.h"
#include "net/http/http_response_info.h"
namespace download {
@@ -92,47 +91,6 @@ bool IsParallelizableDownload(const DownloadCreateInfo& create_info,
has_content_length && satisfy_min_file_size &&
satisfy_connection_type && http_get_method &&
can_support_parallel_requests;
-
- if (!IsParallelDownloadEnabled())
- return is_parallelizable;
-
- RecordParallelDownloadCreationEvent(
- is_parallelizable
- ? ParallelDownloadCreationEvent::STARTED_PARALLEL_DOWNLOAD
- : ParallelDownloadCreationEvent::FELL_BACK_TO_NORMAL_DOWNLOAD);
- if (!has_strong_validator) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_STRONG_VALIDATORS);
- }
- if (!range_support_allowed) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_ACCEPT_RANGE_HEADER);
- if (create_info.accept_range == RangeRequestSupportType::kUnknown) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_UNKNOWN_RANGE_SUPPORT);
- }
- }
- if (!has_content_length) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_CONTENT_LENGTH_HEADER);
- }
- if (!satisfy_min_file_size) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_FILE_SIZE);
- }
- if (!satisfy_connection_type) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_CONNECTION_TYPE);
- }
- if (!http_get_method) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_HTTP_METHOD);
- }
- if (!can_support_parallel_requests) {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::
- FALLBACK_REASON_RESUMPTION_WITHOUT_SLICES);
- }
return is_parallelizable;
}
diff --git a/chromium/components/download/internal/common/download_stats.cc b/chromium/components/download/internal/common/download_stats.cc
index 338fc892817..3d9f4b61c5e 100644
--- a/chromium/components/download/internal/common/download_stats.cc
+++ b/chromium/components/download/internal/common/download_stats.cc
@@ -601,18 +601,6 @@ void RecordParallelDownloadRequestCount(int request_count) {
request_count, 1, 10, 11);
}
-void RecordParallelDownloadAddStreamSuccess(bool success,
- bool support_range_request) {
- if (support_range_request) {
- base::UmaHistogramBoolean("Download.ParallelDownloadAddStreamSuccess",
- success);
- } else {
- base::UmaHistogramBoolean(
- "Download.ParallelDownloadAddStreamSuccess.NoAcceptRangesHeader",
- success);
- }
-}
-
void RecordParallelRequestCreationFailure(DownloadInterruptReason reason) {
base::UmaHistogramSparse("Download.ParallelDownload.CreationFailureReason",
reason);
@@ -684,11 +672,6 @@ void RecordParallelizableDownloadAverageStats(
}
}
-void RecordParallelDownloadCreationEvent(ParallelDownloadCreationEvent event) {
- UMA_HISTOGRAM_ENUMERATION("Download.ParallelDownload.CreationEvent", event,
- ParallelDownloadCreationEvent::COUNT);
-}
-
void RecordSavePackageEvent(SavePackageEvent event) {
UMA_HISTOGRAM_ENUMERATION("Download.SavePackage", event,
SAVE_PACKAGE_LAST_ENTRY);
diff --git a/chromium/components/download/internal/common/download_utils.cc b/chromium/components/download/internal/common/download_utils.cc
index ecd6e62990d..f75993e5d01 100644
--- a/chromium/components/download/internal/common/download_utils.cc
+++ b/chromium/components/download/internal/common/download_utils.cc
@@ -273,7 +273,7 @@ std::unique_ptr<network::ResourceRequest> CreateResourceRequest(
// been visited before.
url::Origin origin = url::Origin::Create(params->url());
request->trusted_params->isolation_info = net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateTopFrame, origin, origin,
+ net::IsolationInfo::RequestType::kMainFrame, origin, origin,
net::SiteForCookies::FromOrigin(origin));
request->do_not_prompt_for_login = params->do_not_prompt_for_login();
diff --git a/chromium/components/download/internal/common/parallel_download_job.cc b/chromium/components/download/internal/common/parallel_download_job.cc
index c8355e740ee..c4c88473b28 100644
--- a/chromium/components/download/internal/common/parallel_download_job.cc
+++ b/chromium/components/download/internal/common/parallel_download_job.cc
@@ -34,7 +34,6 @@ ParallelDownloadJob::ParallelDownloadJob(
content_length_(create_info.total_bytes),
requests_sent_(false),
is_canceled_(false),
- range_support_(create_info.accept_range),
url_loader_factory_provider_(std::move(url_loader_factory_provider)),
wake_lock_provider_binder_(std::move(wake_lock_provider_binder)) {}
@@ -130,9 +129,6 @@ void ParallelDownloadJob::OnInputStreamReady(
bool success =
DownloadJob::AddInputStream(std::move(input_stream), worker->offset());
- RecordParallelDownloadAddStreamSuccess(
- success, range_support_ == RangeRequestSupportType::kSupport);
-
// Destroy the request if the sink is gone.
if (!success) {
VLOG(kDownloadJobVerboseLevel)
@@ -189,9 +185,6 @@ void ParallelDownloadJob::BuildParallelRequests() {
first_slice_offset,
content_length_ - first_slice_offset + initial_request_offset_,
GetParallelRequestCount(), GetMinSliceSize());
- } else {
- RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent::FALLBACK_REASON_REMAINING_TIME);
}
}
diff --git a/chromium/components/download/internal/common/parallel_download_job.h b/chromium/components/download/internal/common/parallel_download_job.h
index 88ec0138e12..d04359ce667 100644
--- a/chromium/components/download/internal/common/parallel_download_job.h
+++ b/chromium/components/download/internal/common/parallel_download_job.h
@@ -110,9 +110,6 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob
// If the download progress is canceled.
bool is_canceled_;
- // Whether the server accepts range requests.
- RangeRequestSupportType range_support_;
-
// URLLoaderFactoryProvider to retrieve the URLLoaderFactory and issue
// parallel requests.
URLLoaderFactoryProvider::URLLoaderFactoryProviderPtr
diff --git a/chromium/components/download/public/background_service/clients.h b/chromium/components/download/public/background_service/clients.h
index 57d574b8cfa..6f0575113ba 100644
--- a/chromium/components/download/public/background_service/clients.h
+++ b/chromium/components/download/public/background_service/clients.h
@@ -41,7 +41,10 @@ enum class DownloadClient {
PLUGIN_VM_IMAGE = 5,
- BOUNDARY = 6,
+ OPTIMIZATION_GUIDE_PREDICTION_MODELS = 6,
+
+ // New clients should be added above here.
+ BOUNDARY = 7,
};
using DownloadClientMap = std::map<DownloadClient, std::unique_ptr<Client>>;
diff --git a/chromium/components/download/public/common/download_stats.h b/chromium/components/download/public/common/download_stats.h
index 3c7f34ef01a..06dc85c7a35 100644
--- a/chromium/components/download/public/common/download_stats.h
+++ b/chromium/components/download/public/common/download_stats.h
@@ -173,51 +173,6 @@ enum InProgressDBCountTypes {
kMaxValue = kCacheMigrationFailedCount
};
-// When parallel download is enabled, the download may fall back to a normal
-// download for various reasons. This enum counts the number of parallel
-// download and fallbacks. Also records the reasons why the download falls back
-// to a normal download. The reasons are not mutually exclusive.
-// Used in histogram "Download.ParallelDownload.CreationEvent" and should be
-// treated as append-only.
-enum class ParallelDownloadCreationEvent {
- // The total number of downloads started as parallel download.
- STARTED_PARALLEL_DOWNLOAD = 0,
-
- // The total number of downloads fell back to normal download when parallel
- // download is enabled.
- FELL_BACK_TO_NORMAL_DOWNLOAD,
-
- // No ETag or Last-Modified response header.
- FALLBACK_REASON_STRONG_VALIDATORS,
-
- // No Accept-Range response header.
- FALLBACK_REASON_ACCEPT_RANGE_HEADER,
-
- // No Content-Length response header.
- FALLBACK_REASON_CONTENT_LENGTH_HEADER,
-
- // File size is not complied to finch configuration.
- FALLBACK_REASON_FILE_SIZE,
-
- // The HTTP connection type does not meet the requirement.
- FALLBACK_REASON_CONNECTION_TYPE,
-
- // The remaining time does not meet the requirement.
- FALLBACK_REASON_REMAINING_TIME,
-
- // The http method or url scheme does not meet the requirement.
- FALLBACK_REASON_HTTP_METHOD,
-
- // Range support is unknown from the response.
- FALLBACK_REASON_UNKNOWN_RANGE_SUPPORT,
-
- // Resumed download doesn't have any slices.
- FALLBACK_REASON_RESUMPTION_WITHOUT_SLICES,
-
- // Last entry of the enum.
- COUNT,
-};
-
// Events for user scheduled downloads. Used in histograms, don't reuse or
// remove items. Keep in sync with DownloadLaterEvent in enums.xml.
enum class DownloadLaterEvent {
@@ -305,13 +260,6 @@ COMPONENTS_DOWNLOAD_EXPORT void RecordParallelizableDownloadCount(
COMPONENTS_DOWNLOAD_EXPORT void RecordParallelDownloadRequestCount(
int request_count);
-// Records if each byte stream is successfully added to download sink.
-// |support_range_request| indicates whether the server strongly supports range
-// requests.
-COMPONENTS_DOWNLOAD_EXPORT void RecordParallelDownloadAddStreamSuccess(
- bool success,
- bool support_range_request);
-
// Records the bandwidth for parallelizable download and estimates the saved
// time at the file end. Does not count in any hash computation or file
// open/close time.
@@ -328,11 +276,6 @@ COMPONENTS_DOWNLOAD_EXPORT void RecordParallelizableDownloadAverageStats(
int64_t bytes_downloaded,
const base::TimeDelta& time_span);
-// Records the parallel download creation counts and the reasons why the
-// download falls back to non-parallel download.
-COMPONENTS_DOWNLOAD_EXPORT void RecordParallelDownloadCreationEvent(
- ParallelDownloadCreationEvent event);
-
// Record the result of a download file rename.
COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadFileRenameResultAfterRetry(
base::TimeDelta time_since_first_failure,
diff --git a/chromium/components/download/public/common/download_url_parameters.cc b/chromium/components/download/public/common/download_url_parameters.cc
index 5f879b8e450..0d898ac922c 100644
--- a/chromium/components/download/public/common/download_url_parameters.cc
+++ b/chromium/components/download/public/common/download_url_parameters.cc
@@ -9,12 +9,11 @@ namespace download {
DownloadUrlParameters::DownloadUrlParameters(
const GURL& url,
const net::NetworkTrafficAnnotationTag& traffic_annotation)
- : DownloadUrlParameters(url, -1, -1, -1, traffic_annotation) {}
+ : DownloadUrlParameters(url, -1, -1, traffic_annotation) {}
DownloadUrlParameters::DownloadUrlParameters(
const GURL& url,
int render_process_host_id,
- int render_view_host_routing_id,
int render_frame_host_routing_id,
const net::NetworkTrafficAnnotationTag& traffic_annotation)
: content_initiated_(false),
@@ -25,9 +24,7 @@ DownloadUrlParameters::DownloadUrlParameters(
referrer_policy_(
net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
render_process_host_id_(render_process_host_id),
- render_view_host_routing_id_(render_view_host_routing_id),
render_frame_host_routing_id_(render_frame_host_routing_id),
- frame_tree_node_id_(-1),
url_(url),
do_not_prompt_for_login_(false),
cross_origin_redirects_(network::mojom::RedirectMode::kFollow),
diff --git a/chromium/components/download/public/common/download_url_parameters.h b/chromium/components/download/public/common/download_url_parameters.h
index 569faaafe8e..b91ed408140 100644
--- a/chromium/components/download/public/common/download_url_parameters.h
+++ b/chromium/components/download/public/common/download_url_parameters.h
@@ -81,13 +81,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters {
const GURL& url,
const net::NetworkTrafficAnnotationTag& traffic_annotation);
- // The RenderView routing ID must correspond to the RenderView of the
- // RenderFrame, both of which share the same RenderProcess. This may be a
- // different RenderView than the WebContents' main RenderView.
DownloadUrlParameters(
const GURL& url,
int render_process_host_id,
- int render_view_host_routing_id,
int render_frame_host_routing_id,
const net::NetworkTrafficAnnotationTag& traffic_annotation);
@@ -276,16 +272,10 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters {
// These will be -1 if the request is not associated with a frame. See
// the constructors for more.
int render_process_host_id() const { return render_process_host_id_; }
- int render_view_host_routing_id() const {
- return render_view_host_routing_id_;
- }
int render_frame_host_routing_id() const {
return render_frame_host_routing_id_;
}
- void set_frame_tree_node_id(int id) { frame_tree_node_id_ = id; }
- int frame_tree_node_id() const { return frame_tree_node_id_; }
-
const RequestHeadersType& request_headers() const { return request_headers_; }
const base::FilePath& file_path() const { return save_info_.file_path; }
const base::string16& suggested_name() const {
@@ -338,9 +328,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadUrlParameters {
base::Optional<url::Origin> initiator_;
std::string referrer_encoding_;
int render_process_host_id_;
- int render_view_host_routing_id_;
int render_frame_host_routing_id_;
- int frame_tree_node_id_;
DownloadSaveInfo save_info_;
GURL url_;
bool do_not_prompt_for_login_;
diff --git a/chromium/components/embedder_support/android/BUILD.gn b/chromium/components/embedder_support/android/BUILD.gn
index cd05bf70be3..eae62fb717a 100644
--- a/chromium/components/embedder_support/android/BUILD.gn
+++ b/chromium/components/embedder_support/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
android_library("browser_context_java") {
sources = [ "java/src/org/chromium/components/embedder_support/browser_context/BrowserContextHandle.java" ]
@@ -47,8 +48,11 @@ android_library("util_java") {
deps = [
"//base:base_java",
"//base:jni_java",
+ "//components/url_formatter/android:url_formatter_java",
"//content/public/android:content_java",
+ "//net/android:net_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:androidx_core_core_java",
"//url:gurl_java",
]
}
@@ -57,6 +61,8 @@ static_library("util") {
sources = [
"util/android_stream_reader_url_loader.cc",
"util/android_stream_reader_url_loader.h",
+ "util/cdn_utils.cc",
+ "util/cdn_utils.h",
"util/input_stream.cc",
"util/input_stream.h",
"util/input_stream_reader.cc",
@@ -64,6 +70,8 @@ static_library("util") {
"util/response_delegate_impl.cc",
"util/response_delegate_impl.h",
"util/url_utilities.cc",
+ "util/user_agent_utils.cc",
+ "util/user_agent_utils.h",
"util/web_resource_response.cc",
"util/web_resource_response.h",
]
@@ -72,6 +80,8 @@ static_library("util") {
":util_jni_headers",
"//base",
"//components/google/core/common",
+ "//components/version_info",
+ "//content/public/browser",
"//mojo/public/cpp/bindings:bindings",
"//mojo/public/cpp/system:system",
"//net",
@@ -308,5 +318,6 @@ android_library("embedder_support_javatests") {
"//third_party/junit",
"//ui/android:ui_java",
"//ui/android:ui_java_test_support",
+ "//url:gurl_java",
]
}
diff --git a/chromium/components/embedder_support/android/DEPS b/chromium/components/embedder_support/android/DEPS
index b44cbc1173f..654e019fa5f 100644
--- a/chromium/components/embedder_support/android/DEPS
+++ b/chromium/components/embedder_support/android/DEPS
@@ -2,11 +2,12 @@ include_rules = [
"-content/public/android/java",
"+content/public/android/java/src/org/chromium/content_public",
"+content/public/test/android",
-
"+cc",
"+components/embedder_support/android/web_contents_delegate_jni_headers",
+ "+components/url_formatter/android/java",
"+content/public/browser",
"+content/public/common",
+ "+net/android/java/src/org/chromium/net",
"+ui/android",
"+ui/base",
"+ui/gfx"
diff --git a/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/util/UrlUtilitiesUnitTest.java b/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/util/UrlUtilitiesUnitTest.java
index 078fc2a3379..c0d9a7ebed5 100644
--- a/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/util/UrlUtilitiesUnitTest.java
+++ b/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/util/UrlUtilitiesUnitTest.java
@@ -14,6 +14,7 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
+import org.chromium.url.GURL;
/**
* Unit tests for {@link UrlUtilities}.
@@ -189,4 +190,34 @@ public class UrlUtilitiesUnitTest {
Assert.assertFalse(UrlUtilities.urlsFragmentsDiffer(url, url));
Assert.assertTrue(UrlUtilities.urlsFragmentsDiffer(url + "#fragment", url));
}
+
+ @Test
+ @SmallTest
+ public void testIsNtpUrlString() {
+ Assert.assertTrue(UrlUtilities.isNTPUrl("chrome-native://newtab"));
+ Assert.assertTrue(UrlUtilities.isNTPUrl("chrome://newtab"));
+ Assert.assertTrue(UrlUtilities.isNTPUrl("about:newtab"));
+
+ Assert.assertFalse(UrlUtilities.isNTPUrl("http://www.example.com"));
+ Assert.assertFalse(UrlUtilities.isNTPUrl("chrome://history"));
+ Assert.assertFalse(UrlUtilities.isNTPUrl("chrome-native://newtabz"));
+ Assert.assertFalse(UrlUtilities.isNTPUrl("newtab"));
+ Assert.assertFalse(UrlUtilities.isNTPUrl(""));
+ }
+
+ @Test
+ @SmallTest
+ public void testIsNtpUrlGurl() {
+ Assert.assertTrue(UrlUtilities.isNTPUrl(new GURL("chrome-native://newtab")));
+ Assert.assertTrue(UrlUtilities.isNTPUrl(new GURL("chrome://newtab")));
+
+ // TODO(crbug.com/1139437): Differs from UrlUtilities#isNTPUrl(String)
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("about:newtab")));
+
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("http://www.example.com")));
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("chrome://history")));
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("chrome-native://newtabz")));
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("newtab")));
+ Assert.assertFalse(UrlUtilities.isNTPUrl(new GURL("")));
+ }
}
diff --git a/chromium/components/embedder_support/android/metrics/BUILD.gn b/chromium/components/embedder_support/android/metrics/BUILD.gn
index 7a0e269c738..387ffd0de18 100644
--- a/chromium/components/embedder_support/android/metrics/BUILD.gn
+++ b/chromium/components/embedder_support/android/metrics/BUILD.gn
@@ -30,7 +30,6 @@ static_library("metrics") {
"//components/version_info/android:channel_getter",
"//content/public/browser",
"//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
- "//third_party/metrics_proto",
]
}
@@ -43,6 +42,8 @@ android_library("java") {
deps = [
"//base:base_java",
"//base:jni_java",
+ "//third_party/android_deps:protobuf_lite_runtime_java",
+ "//third_party/metrics_proto:metrics_proto_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc b/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
index 18dabdad7ae..a737dc5bcc4 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc
@@ -5,10 +5,8 @@
#include "components/embedder_support/android/metrics/android_metrics_log_uploader.h"
#include "base/android/jni_array.h"
-#include "base/check.h"
#include "components/embedder_support/android/metrics/jni/AndroidMetricsLogUploader_jni.h"
#include "components/metrics/log_decoder.h"
-#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaByteArray;
@@ -36,16 +34,6 @@ void AndroidMetricsLogUploader::UploadLog(
return;
}
- // Speculative CHECKs to see why WebView UMA (and probably other embedders of
- // this component) are missing system_profiles for a small fraction of
- // records. TODO(https://crbug.com/1081925): downgrade these to DCHECKs or
- // remove entirely when we figure out the issue.
- CHECK(!log_data.empty());
- metrics::ChromeUserMetricsExtension uma_log;
- bool can_parse = uma_log.ParseFromString(log_data);
- CHECK(can_parse);
- CHECK(uma_log.has_system_profile());
-
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> java_data = ToJavaByteArray(
env, reinterpret_cast<const uint8_t*>(log_data.data()), log_data.size());
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
index c4508daef9a..1b108cbe65d 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
@@ -141,6 +141,8 @@ bool IsSamplesCounterEnabled() {
base::kPersistentHistogramsFeature, "prev_run_metrics_count_only", false);
}
+// TODO(crbug.com/1152072): Unify this implementation with the one in
+// ChromeMetricsServiceClient.
std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider(
PrefService* pref_service,
bool metrics_reporting_enabled) {
@@ -185,11 +187,34 @@ std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider(
active_path,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN));
+ } else {
+ // When metrics reporting is not enabled, any existing files should be
+ // deleted in order to preserve user privacy.
+ base::ThreadPool::PostTask(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(base::GetDeletePathRecursivelyCallback(),
+ std::move(browser_metrics_upload_dir)));
}
return file_metrics_provider;
}
+base::OnceClosure CreateChainedClosure(base::OnceClosure cb1,
+ base::OnceClosure cb2) {
+ return base::BindOnce(
+ [](base::OnceClosure cb1, base::OnceClosure cb2) {
+ if (cb1) {
+ std::move(cb1).Run();
+ }
+ if (cb2) {
+ std::move(cb2).Run();
+ }
+ },
+ std::move(cb1), std::move(cb2));
+}
+
} // namespace
// Needs to be kept in sync with the writer in
@@ -223,9 +248,20 @@ void AndroidMetricsServiceClient::Initialize(PrefService* pref_service) {
base::BindRepeating(&LoadClientInfo));
init_finished_ = true;
+
+ // Create the MetricsService immediately so that other code can make use of
+ // it. Chrome always creates the MetricsService as well.
+ metrics_service_ = std::make_unique<MetricsService>(
+ metrics_state_manager_.get(), this, pref_service_);
+
+ // Registration of providers has to wait until consent is determined. To
+ // do otherwise means the providers would always be configured with reporting
+ // disabled (because when this is called in production consent hasn't been
+ // determined). If consent has not been determined, this does nothing.
MaybeStartMetrics();
}
+// TODO:(crbug.com/1148351) Make the initialization consistent with Chrome.
void AndroidMetricsServiceClient::MaybeStartMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Treat the debugging flag the same as user consent because the user set it,
@@ -234,14 +270,17 @@ void AndroidMetricsServiceClient::MaybeStartMetrics() {
bool user_consent_or_flag = user_consent_ || IsMetricsReportingForceEnabled();
if (IsConsentDetermined()) {
if (app_consent_ && user_consent_or_flag) {
- CreateMetricsService(metrics_state_manager_.get(), this, pref_service_);
+ did_start_metrics_ = true;
+ // Make GetSampleBucketValue() work properly.
+ metrics_state_manager_->ForceClientIdCreation();
+ is_client_id_forced_ = true;
+ RegisterMetricsProvidersAndInitState();
// Register for notifications so we can detect when the user or app are
// interacting with the embedder. We use these as signals to wake up the
// MetricsService.
RegisterForNotifications();
- metrics_state_manager_->ForceClientIdCreation();
OnMetricsStart();
- is_in_sample_ = IsInSample();
+
if (IsReportingEnabled()) {
// We assume the embedder has no shutdown sequence, so there's no need
// for a matching Stop() call.
@@ -256,12 +295,7 @@ void AndroidMetricsServiceClient::MaybeStartMetrics() {
}
}
-void AndroidMetricsServiceClient::CreateMetricsService(
- MetricsStateManager* state_manager,
- AndroidMetricsServiceClient* client,
- PrefService* prefs) {
- metrics_service_ =
- std::make_unique<MetricsService>(state_manager, client, prefs);
+void AndroidMetricsServiceClient::RegisterMetricsProvidersAndInitState() {
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::SubprocessMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
@@ -271,10 +305,8 @@ void AndroidMetricsServiceClient::CreateMetricsService(
std::make_unique<CPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<ScreenInfoMetricsProvider>());
- if (client->IsPersistentHistogramsEnabled()) {
- metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
- pref_service_, metrics_state_manager_->IsMetricsReportingEnabled()));
- }
+ metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
+ pref_service_, metrics_state_manager_->IsMetricsReportingEnabled()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<CallStackProfileMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
@@ -286,7 +318,7 @@ void AndroidMetricsServiceClient::CreateMetricsService(
std::make_unique<metrics::GPUMetricsProvider>());
RegisterAdditionalMetricsProviders(metrics_service_.get());
- // The file metrics provider makes IO.
+ // The file metrics provider performs IO.
base::ScopedAllowBlocking allow_io;
metrics_service_->InitializeMetricsRecordingState();
}
@@ -393,13 +425,17 @@ bool AndroidMetricsServiceClient::IsReportingEnabled() const {
if (!app_consent_)
return false;
return IsMetricsReportingForceEnabled() ||
- (EnabledStateProvider::IsReportingEnabled() && is_in_sample_);
+ (EnabledStateProvider::IsReportingEnabled() && IsInSample());
+}
+
+MetricsService* AndroidMetricsServiceClient::GetMetricsServiceIfStarted() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return did_start_metrics_ ? metrics_service_.get() : nullptr;
}
MetricsService* AndroidMetricsServiceClient::GetMetricsService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // This will be null if initialization hasn't finished, or if metrics
- // collection is disabled.
+ // This will be null if initialization hasn't finished.
return metrics_service_.get();
}
@@ -442,8 +478,11 @@ void AndroidMetricsServiceClient::CollectFinalMetricsForLog(
// Set up the callback task to call after we receive histograms from all
// child processes. |timeout| specifies how long to wait before absolutely
// calling us back on the task.
- content::FetchHistogramsAsynchronously(base::ThreadTaskRunnerHandle::Get(),
- std::move(done_callback), timeout);
+ content::FetchHistogramsAsynchronously(
+ base::ThreadTaskRunnerHandle::Get(),
+ CreateChainedClosure(std::move(done_callback),
+ on_final_metrics_collected_listener_),
+ timeout);
if (collect_final_metrics_for_log_closure_)
std::move(collect_final_metrics_for_log_closure_).Run();
@@ -519,11 +558,17 @@ void AndroidMetricsServiceClient::SetCollectFinalMetricsForLogClosureForTesting(
collect_final_metrics_for_log_closure_ = std::move(closure);
}
-int AndroidMetricsServiceClient::GetSampleBucketValue() {
+void AndroidMetricsServiceClient::SetOnFinalMetricsCollectedListenerForTesting(
+ base::RepeatingClosure listener) {
+ on_final_metrics_collected_listener_ = std::move(listener);
+}
+
+int AndroidMetricsServiceClient::GetSampleBucketValue() const {
+ DCHECK(is_client_id_forced_);
return UintToPerMille(base::PersistentHash(metrics_service_->GetClientId()));
}
-bool AndroidMetricsServiceClient::IsInSample() {
+bool AndroidMetricsServiceClient::IsInSample() const {
// Called in MaybeStartMetrics(), after |metrics_service_| is created.
// NOTE IsInSample and IsInPackageNameSample deliberately use the same hash to
// guarantee we never exceed 10% of total, opted-in clients for PackageNames.
@@ -550,10 +595,6 @@ bool AndroidMetricsServiceClient::IsInPackageNameSample() {
void AndroidMetricsServiceClient::RegisterAdditionalMetricsProviders(
MetricsService* service) {}
-bool AndroidMetricsServiceClient::IsPersistentHistogramsEnabled() {
- return false;
-}
-
std::string AndroidMetricsServiceClient::GetAppPackageName() {
if (IsInPackageNameSample() && CanRecordPackageNameForAppType())
return GetAppPackageNameInternal();
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
index d0edeeaea09..c4e2a8a6ebc 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
@@ -87,6 +87,9 @@ extern const char kCrashpadHistogramAllocatorName[];
// the client ID (generating a new ID if there was none). If this client is in
// the sample, it then calls MetricsService::Start(). If consent was not
// granted, MaybeStartMetrics() instead clears the client ID, if any.
+//
+// To match chrome on other platforms (including android), the MetricsService is
+// always created.
class AndroidMetricsServiceClient : public MetricsServiceClient,
public EnabledStateProvider,
public content::NotificationObserver {
@@ -125,6 +128,10 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
bool IsConsentGiven() const override;
bool IsReportingEnabled() const override;
+ // Returns the MetricService only if it has been started (which means consent
+ // was given).
+ MetricsService* GetMetricsServiceIfStarted();
+
// MetricsServiceClient
MetricsService* GetMetricsService() override;
ukm::UkmService* GetUkmService() override;
@@ -154,9 +161,14 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
- // Runs |closure| when CollectFinalMetricsForLog() is called.
+ // Runs |closure| when CollectFinalMetricsForLog() is called, when we begin
+ // collecting final metrics.
void SetCollectFinalMetricsForLogClosureForTesting(base::OnceClosure closure);
+ // Runs |listener| after all final metrics have been collected.
+ void SetOnFinalMetricsCollectedListenerForTesting(
+ base::RepeatingClosure listener);
+
metrics::MetricsStateManager* metrics_state_manager() const {
return metrics_state_manager_.get();
}
@@ -172,20 +184,20 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
// per mille value, so this integer must always be in the inclusive range [0,
// 1000]. A value of 0 will always be out-of-sample, and a value of 1000 is
// always in-sample.
- virtual int GetSampleRatePerMille() = 0;
+ virtual int GetSampleRatePerMille() const = 0;
// Returns a value in the inclusive range [0, 999], to be compared against a
// per mille sample rate. This value will be based on a persisted value, so it
// should be consistent across restarts. This value should also be mostly
// consistent across upgrades, to avoid significantly impacting IsInSample()
// and IsInPackageNameSample(). Virtual for testing.
- virtual int GetSampleBucketValue();
+ virtual int GetSampleBucketValue() const;
// Determines if the client is within the random sample of clients for which
// we log metrics. If this returns false, MetricsServiceClient should
// indicate reporting is disabled. Sampling is due to storage/bandwidth
// considerations.
- bool IsInSample();
+ bool IsInSample() const;
// Determines if the embedder app is the type of app for which we may log the
// package name. If this returns false, GetAppPackageName() must return empty
@@ -208,12 +220,6 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
// MetricsProviders. Does nothing by default.
virtual void RegisterAdditionalMetricsProviders(MetricsService* service);
- // Called by CreateMetricsService if metrics should be persisted. If the
- // client returns true then its
- // variations::PlatformFieldTrials::SetupFieldTrials needs to also call
- // InstantiatePersistentHistograms.
- virtual bool IsPersistentHistogramsEnabled();
-
// Returns the embedding application's package name (unconditionally). Virtual
// for testing.
virtual std::string GetAppPackageNameInternal();
@@ -234,9 +240,7 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
void MaybeStartMetrics();
void RegisterForNotifications();
- void CreateMetricsService(MetricsStateManager* state_manager,
- AndroidMetricsServiceClient* client,
- PrefService* prefs);
+ void RegisterMetricsProvidersAndInitState();
void CreateUkmService();
std::unique_ptr<MetricsStateManager> metrics_state_manager_;
@@ -248,14 +252,16 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
bool set_consent_finished_ = false;
bool user_consent_ = false;
bool app_consent_ = false;
- bool is_in_sample_ = false;
+ bool is_client_id_forced_ = false;
bool fast_startup_for_testing_ = false;
+ bool did_start_metrics_ = false;
// When non-zero, this overrides the default value in
// GetStandardUploadInterval().
base::TimeDelta overridden_upload_interval_;
base::OnceClosure collect_final_metrics_for_log_closure_;
+ base::RepeatingClosure on_final_metrics_collected_listener_;
// MetricsServiceClient may be created before the UI thread is promoted to
// BrowserThread::UI. Use |sequence_checker_| to enforce that the
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
index ac23eda0abe..40f1a819637 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
@@ -7,14 +7,19 @@
#include <memory>
#include "base/command_line.h"
+#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/test_simple_task_runner.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_switches.h"
+#include "components/metrics/persistent_histograms.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -75,9 +80,11 @@ class TestClient : public AndroidMetricsServiceClient {
void OnMetricsNotStarted() override {}
- int GetSampleBucketValue() override { return sample_bucket_value_; }
+ int GetSampleBucketValue() const override { return sample_bucket_value_; }
- int GetSampleRatePerMille() override { return sampled_in_rate_per_mille_; }
+ int GetSampleRatePerMille() const override {
+ return sampled_in_rate_per_mille_;
+ }
bool CanRecordPackageNameForAppType() override {
return record_package_name_for_app_type_;
@@ -127,6 +134,10 @@ class AndroidMetricsServiceClientTest : public testing::Test {
const int64_t test_begin_time_;
+ content::BrowserTaskEnvironment* task_environment() {
+ return &task_environment_;
+ }
+
protected:
~AndroidMetricsServiceClientTest() override = default;
@@ -366,4 +377,74 @@ TEST_F(AndroidMetricsServiceClientTest,
EXPECT_FALSE(client->IsRecordingActive());
}
+TEST_F(AndroidMetricsServiceClientTest,
+ TestBrowserMetricsDirClearedIfReportingDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ base::kPersistentHistogramsFeature, {{"storage", "MappedFile"}});
+
+ base::FilePath metrics_dir;
+ ASSERT_TRUE(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &metrics_dir));
+ InstantiatePersistentHistograms(metrics_dir);
+ base::FilePath upload_dir = metrics_dir.AppendASCII(kBrowserMetricsName);
+ ASSERT_TRUE(base::PathExists(upload_dir));
+
+ auto prefs = CreateTestPrefs();
+ auto client = std::make_unique<TestClient>();
+
+ // Setup the client isn't in sample.
+ client->SetHaveMetricsConsent(/* user_consent= */ true,
+ /* app_consent= */ true);
+ client->SetInSample(false);
+ client->Initialize(prefs.get());
+ task_environment()->RunUntilIdle();
+
+ EXPECT_FALSE(base::PathExists(upload_dir));
+}
+
+TEST_F(AndroidMetricsServiceClientTest,
+ TestBrowserMetricsDirExistsIfReportingEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ base::kPersistentHistogramsFeature, {{"storage", "MappedFile"}});
+
+ base::FilePath metrics_dir;
+ ASSERT_TRUE(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &metrics_dir));
+ InstantiatePersistentHistograms(metrics_dir);
+ base::FilePath upload_dir = metrics_dir.AppendASCII(kBrowserMetricsName);
+ ASSERT_TRUE(base::PathExists(upload_dir));
+
+ auto prefs = CreateTestPrefs();
+ auto client = std::make_unique<TestClient>();
+
+ // Setup the client is in sample.
+ client->SetHaveMetricsConsent(/* user_consent= */ true,
+ /* app_consent= */ true);
+ client->SetInSample(true);
+ client->Initialize(prefs.get());
+ task_environment()->RunUntilIdle();
+
+ EXPECT_TRUE(base::PathExists(upload_dir));
+}
+
+TEST_F(AndroidMetricsServiceClientTest,
+ MetricsServiceCreatedFromInitializeWithNoConsent) {
+ auto prefs = CreateTestPrefs();
+ auto client = std::make_unique<TestClient>();
+ client->Initialize(prefs.get());
+ EXPECT_FALSE(client->IsReportingEnabled());
+ EXPECT_TRUE(client->GetMetricsService());
+}
+
+TEST_F(AndroidMetricsServiceClientTest, GetMetricsServiceIfStarted) {
+ auto prefs = CreateTestPrefs();
+ auto client = std::make_unique<TestClient>();
+ client->SetInSample(true);
+ client->Initialize(prefs.get());
+ EXPECT_EQ(nullptr, client->GetMetricsServiceIfStarted());
+ client->SetHaveMetricsConsent(/* user_consent= */ true,
+ /* app_consent= */ true);
+ EXPECT_TRUE(client->GetMetricsServiceIfStarted());
+}
+
} // namespace metrics
diff --git a/chromium/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java b/chromium/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
index 58f9a2e573a..351c8be1259 100644
--- a/chromium/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
+++ b/chromium/components/embedder_support/android/metrics/java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java
@@ -4,9 +4,12 @@
package org.chromium.components.metrics;
+import com.google.protobuf.InvalidProtocolBufferException;
+
import org.chromium.base.Consumer;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.metrics.ChromeUserMetricsExtensionProtos.ChromeUserMetricsExtension;
/**
* Passes UMA logs from native to a java uploader.
@@ -26,9 +29,19 @@ public class AndroidMetricsLogUploader {
}
@CalledByNative
- public static void uploadLog(byte[] data) {
+ public static void uploadLog(byte[] data) throws InvalidProtocolBufferException {
final Consumer<byte[]> uploader = sUploader;
if (uploader != null) {
+ // Speculative validity checks to see why WebView UMA (and probably other embedders of
+ // this component) are missing system_profiles for a small fraction of records.
+ // TODO(https://crbug.com/1081925): remove entirely when we figure out the issue.
+ if (data.length == 0) {
+ throw new RuntimeException("UMA log is completely empty");
+ }
+ ChromeUserMetricsExtension log = ChromeUserMetricsExtension.parseFrom(data);
+ if (!log.hasSystemProfile()) {
+ throw new RuntimeException("UMA log is missing a system_profile");
+ }
uploader.accept(data);
}
}
diff --git a/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc b/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
index a923508fb6a..9db30073a4b 100644
--- a/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
+++ b/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
@@ -5,7 +5,7 @@
#include "components/embedder_support/android/metrics/memory_metrics_logger.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_functions.h"
diff --git a/chromium/components/embedder_support/android/util/DEPS b/chromium/components/embedder_support/android/util/DEPS
index 839bc00c37e..7b811833fec 100644
--- a/chromium/components/embedder_support/android/util/DEPS
+++ b/chromium/components/embedder_support/android/util/DEPS
@@ -1,9 +1,11 @@
include_rules = [
"+components/google/core/common",
+ "+components/version_info",
"+mojo/public/cpp/bindings",
"+mojo/public/cpp/system",
"+net",
"+services/network/public",
+ "+third_party/blink/public/common/user_agent",
"+third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h",
]
diff --git a/chromium/components/embedder_support/android/util/cdn_utils.cc b/chromium/components/embedder_support/android/util/cdn_utils.cc
new file mode 100644
index 00000000000..fe3e982651b
--- /dev/null
+++ b/chromium/components/embedder_support/android/util/cdn_utils.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 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/embedder_support/android/util/cdn_utils.h"
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/no_destructor.h"
+#include "content/public/browser/navigation_handle.h"
+#include "url/gurl.h"
+
+namespace embedder_support {
+
+namespace {
+
+constexpr char kDefaultTrustedCDNBaseURL[] = "https://cdn.ampproject.org";
+
+// Specifies a base URL for the trusted CDN for tests.
+const char kTrustedCDNBaseURLForTests[] = "trusted-cdn-base-url-for-tests";
+
+// Returns whether the given URL is hosted by a trusted CDN. This can be turned
+// off via a Feature, and the base URL to trust can be set via a command line
+// flag for testing.
+bool IsTrustedCDN(const GURL& url) {
+ if (!base::FeatureList::IsEnabled(kShowTrustedPublisherURL))
+ return false;
+
+ // Use a static local (without destructor) to construct the base URL only
+ // once. |trusted_cdn_base_url| is initialized with the result of an
+ // immediately evaluated lambda, which allows wrapping the code in a single
+ // expression.
+ static const base::NoDestructor<GURL> trusted_cdn_base_url([]() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(kTrustedCDNBaseURLForTests)) {
+ GURL base_url(
+ command_line->GetSwitchValueASCII(kTrustedCDNBaseURLForTests));
+ LOG_IF(WARNING, !base_url.is_valid()) << "Invalid trusted CDN base URL: "
+ << base_url.possibly_invalid_spec();
+ return base_url;
+ }
+
+ return GURL(kDefaultTrustedCDNBaseURL);
+ }());
+
+ // Allow any subdomain of the base URL.
+ return url.DomainIs(trusted_cdn_base_url->host_piece()) &&
+ (url.scheme_piece() == trusted_cdn_base_url->scheme_piece()) &&
+ (url.EffectiveIntPort() == trusted_cdn_base_url->EffectiveIntPort());
+}
+
+} // namespace
+
+const base::Feature kShowTrustedPublisherURL{"ShowTrustedPublisherURL",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+GURL GetPublisherURL(content::NavigationHandle* navigation_handle) {
+ if (!IsTrustedCDN(navigation_handle->GetURL()))
+ return GURL();
+
+ const net::HttpResponseHeaders* headers =
+ navigation_handle->GetResponseHeaders();
+ if (!headers) {
+ // TODO(https://crbug.com/829323): In some cases other than offline pages
+ // we don't have headers.
+ LOG(WARNING) << "No headers for navigation to "
+ << navigation_handle->GetURL();
+ return GURL();
+ }
+
+ std::string publisher_url;
+ if (!headers->GetNormalizedHeader("x-amp-cache", &publisher_url))
+ return GURL();
+
+ return GURL(publisher_url);
+}
+
+} // namespace embedder_support
diff --git a/chromium/components/embedder_support/android/util/cdn_utils.h b/chromium/components/embedder_support/android/util/cdn_utils.h
new file mode 100644
index 00000000000..d7eb332c130
--- /dev/null
+++ b/chromium/components/embedder_support/android/util/cdn_utils.h
@@ -0,0 +1,26 @@
+// Copyright 2020 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_EMBEDDER_SUPPORT_ANDROID_UTIL_CDN_UTILS_H_
+#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_CDN_UTILS_H_
+
+#include "base/feature_list.h"
+
+class GURL;
+
+namespace content {
+class NavigationHandle;
+}
+
+namespace embedder_support {
+
+extern const base::Feature kShowTrustedPublisherURL;
+
+// This should be called from content::WebContentsObserver::DidFinishNavigation
+// to get a publisher url for the committed navigation, else an empty GURL().
+GURL GetPublisherURL(content::NavigationHandle* navigation_handle);
+
+} // namespace embedder_support
+
+#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_CDN_UTILS_H_
diff --git a/chromium/components/embedder_support/android/util/user_agent_utils.cc b/chromium/components/embedder_support/android/util/user_agent_utils.cc
new file mode 100644
index 00000000000..1a15c692fd7
--- /dev/null
+++ b/chromium/components/embedder_support/android/util/user_agent_utils.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 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/embedder_support/android/util/user_agent_utils.h"
+
+#include "components/version_info/version_info.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/user_agent.h"
+#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
+
+namespace embedder_support {
+
+void SetDesktopUserAgentOverride(content::WebContents* web_contents,
+ const blink::UserAgentMetadata& metadata) {
+ const char kLinuxInfoStr[] = "X11; Linux x86_64";
+ std::string product = version_info::GetProductNameAndVersionForUserAgent();
+
+ blink::UserAgentOverride spoofed_ua;
+ spoofed_ua.ua_string_override =
+ content::BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
+ spoofed_ua.ua_metadata_override = metadata;
+ spoofed_ua.ua_metadata_override->platform = "Linux";
+ spoofed_ua.ua_metadata_override->platform_version =
+ std::string(); // match content::GetOSVersion(false) on Linux
+ spoofed_ua.ua_metadata_override->architecture = "x86";
+ spoofed_ua.ua_metadata_override->model = std::string();
+ spoofed_ua.ua_metadata_override->mobile = false;
+
+ web_contents->SetUserAgentOverride(spoofed_ua, false);
+}
+
+} // namespace embedder_support
diff --git a/chromium/components/embedder_support/android/util/user_agent_utils.h b/chromium/components/embedder_support/android/util/user_agent_utils.h
new file mode 100644
index 00000000000..f2e91448a22
--- /dev/null
+++ b/chromium/components/embedder_support/android/util/user_agent_utils.h
@@ -0,0 +1,23 @@
+// Copyright 2020 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_EMBEDDER_SUPPORT_ANDROID_UTIL_USER_AGENT_UTILS_H_
+#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_USER_AGENT_UTILS_H_
+
+namespace blink {
+struct UserAgentMetadata;
+}
+
+namespace content {
+class WebContents;
+}
+
+namespace embedder_support {
+
+void SetDesktopUserAgentOverride(content::WebContents* web_contents,
+ const blink::UserAgentMetadata& metadata);
+
+} // namespace embedder_support
+
+#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_UTIL_USER_AGENT_UTILS_H_
diff --git a/chromium/components/embedder_support/origin_trials/features.cc b/chromium/components/embedder_support/origin_trials/features.cc
index 4dba61a0203..c0bbf717ff4 100644
--- a/chromium/components/embedder_support/origin_trials/features.cc
+++ b/chromium/components/embedder_support/origin_trials/features.cc
@@ -17,4 +17,8 @@ const base::Feature kOriginTrialsSampleAPIThirdPartyAlternativeUsage{
"OriginTrialsSampleAPIThirdPartyAlternativeUsage",
base::FEATURE_ENABLED_BY_DEFAULT};
-} // namespace embedder_support \ No newline at end of file
+const base::Feature kConversionMeasurementAPIAlternativeUsage{
+ "ConversionMeasurementAPIAlternativeUsage",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace embedder_support
diff --git a/chromium/components/embedder_support/origin_trials/features.h b/chromium/components/embedder_support/origin_trials/features.h
index ff06364dd90..0674cab93ab 100644
--- a/chromium/components/embedder_support/origin_trials/features.h
+++ b/chromium/components/embedder_support/origin_trials/features.h
@@ -15,6 +15,11 @@ namespace embedder_support {
// origin trial third party tokens.
extern const base::Feature kOriginTrialsSampleAPIThirdPartyAlternativeUsage;
+// Field trial feature for controlling usage restriction of the
+// Conversion Measurement API's origin trial tokens. When disabled, the API
+// cannot be enabled by tokens using the user subset usage restriction.
+extern const base::Feature kConversionMeasurementAPIAlternativeUsage;
+
} // namespace embedder_support
-#endif // COMPONENTS_EMBEDDER_SUPPORT_ORIGIN_TRIALS_FEATURES_H_ \ No newline at end of file
+#endif // COMPONENTS_EMBEDDER_SUPPORT_ORIGIN_TRIALS_FEATURES_H_
diff --git a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc
index 9f0b6502101..2c8fea099c5 100644
--- a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc
+++ b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc
@@ -83,8 +83,8 @@ bool OriginTrialPolicyImpl::IsFeatureDisabledForUser(
const char* origin_trial_feature_name;
const base::Feature field_trial_feature;
} origin_trial_feature_to_field_trial_feature_map[] = {
- {"FrobulateThirdParty",
- kOriginTrialsSampleAPIThirdPartyAlternativeUsage}};
+ {"FrobulateThirdParty", kOriginTrialsSampleAPIThirdPartyAlternativeUsage},
+ {"ConversionMeasurement", kConversionMeasurementAPIAlternativeUsage}};
for (const auto& mapping : origin_trial_feature_to_field_trial_feature_map) {
if (feature == mapping.origin_trial_feature_name) {
return !base::FeatureList::IsEnabled(mapping.field_trial_feature);
diff --git a/chromium/components/enterprise/BUILD.gn b/chromium/components/enterprise/BUILD.gn
index 9f82abd5961..430910e412e 100644
--- a/chromium/components/enterprise/BUILD.gn
+++ b/chromium/components/enterprise/BUILD.gn
@@ -8,6 +8,8 @@ static_library("enterprise") {
"browser/controller/browser_dm_token_storage.h",
"browser/controller/chrome_browser_cloud_management_helper.cc",
"browser/controller/chrome_browser_cloud_management_helper.h",
+ "browser/enterprise_switches.cc",
+ "browser/enterprise_switches.h",
"browser/reporting/common_pref_names.cc",
"browser/reporting/common_pref_names.h",
]
@@ -34,6 +36,7 @@ static_library("enterprise") {
"browser/reporting/report_request_queue_generator.h",
"browser/reporting/report_scheduler.cc",
"browser/reporting/report_scheduler.h",
+ "browser/reporting/report_type.h",
"browser/reporting/report_uploader.cc",
"browser/reporting/report_uploader.h",
"browser/reporting/reporting_delegate_factory.h",
diff --git a/chromium/components/enterprise/browser/controller/browser_dm_token_storage.cc b/chromium/components/enterprise/browser/controller/browser_dm_token_storage.cc
index b2591fcf7af..4cfb0eec4d0 100644
--- a/chromium/components/enterprise/browser/controller/browser_dm_token_storage.cc
+++ b/chromium/components/enterprise/browser/controller/browser_dm_token_storage.cc
@@ -11,8 +11,8 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
diff --git a/chromium/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc b/chromium/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
index 6776706c1cf..ed5f4257027 100644
--- a/chromium/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
+++ b/chromium/components/enterprise/browser/controller/browser_dm_token_storage_unittest.cc
@@ -5,7 +5,7 @@
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
index 2a33b3f4e9a..fa2de73d043 100644
--- a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
+++ b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
@@ -17,6 +18,7 @@
#include "build/build_config.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "components/enterprise/browser/controller/chrome_browser_cloud_management_helper.h"
+#include "components/enterprise/browser/enterprise_switches.h"
#include "components/enterprise/browser/reporting/report_generator.h"
#include "components/enterprise/browser/reporting/report_scheduler.h"
#include "components/policy/core/browser/browser_policy_connector.h"
@@ -67,7 +69,12 @@ const base::FilePath::CharType
FILE_PATH_LITERAL("Policy");
bool ChromeBrowserCloudManagementController::IsEnabled() {
- return delegate_->IsEnabled();
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ return true;
+#else
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableChromeBrowserCloudManagement);
+#endif
}
ChromeBrowserCloudManagementController::ChromeBrowserCloudManagementController(
@@ -87,7 +94,7 @@ ChromeBrowserCloudManagementController::
std::unique_ptr<MachineLevelUserCloudPolicyManager>
ChromeBrowserCloudManagementController::CreatePolicyManager(
ConfigurationPolicyProvider* platform_provider) {
- if (!delegate_->IsEnabled())
+ if (!IsEnabled())
return nullptr;
std::string enrollment_token =
@@ -148,7 +155,7 @@ ChromeBrowserCloudManagementController::CreatePolicyManager(
void ChromeBrowserCloudManagementController::Init(
PrefService* local_state,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
- if (!delegate_->IsEnabled())
+ if (!IsEnabled())
return;
if (base::FeatureList::IsEnabled(
diff --git a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
index ed3bbab37e3..3ee45263a0b 100644
--- a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
+++ b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
@@ -70,14 +70,6 @@ class ChromeBrowserCloudManagementController
// Sets the platform-specific DM token storage delegate;
virtual void SetDMTokenStorageDelegate() = 0;
- // Platform-specific check whether Chrome browser cloud management is
- // enabled.
- // TODO(crbug.com/1111435): This needs to be an instance method because iOS
- // needs custom logic to determine whether CBCM is enabled. After it is
- // fully launched on iOS, however, this can be moved back to the base class
- // as a static method.
- virtual bool IsEnabled() = 0;
-
// Returns the platform-specific DIR_USER_DATA value to pass to the
// PathService.
virtual int GetUserDataDirKey() = 0;
diff --git a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
index c55e90dd61c..5d55db8cbd5 100644
--- a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
+++ b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
@@ -8,8 +8,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h"
diff --git a/chromium/components/enterprise/browser/enterprise_switches.cc b/chromium/components/enterprise/browser/enterprise_switches.cc
new file mode 100644
index 00000000000..17046caf744
--- /dev/null
+++ b/chromium/components/enterprise/browser/enterprise_switches.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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/enterprise/browser/enterprise_switches.h"
+
+#include "build/build_config.h"
+
+namespace switches {
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+// Enables the Chrome Browser Cloud Management integration on Chromium builds.
+// CBCM is always enabled in branded builds.
+const char kEnableChromeBrowserCloudManagement[] =
+ "enable-chrome-browser-cloud-management";
+#endif
+
+} // namespace switches
diff --git a/chromium/components/enterprise/browser/enterprise_switches.h b/chromium/components/enterprise/browser/enterprise_switches.h
new file mode 100644
index 00000000000..2a9b4342ac1
--- /dev/null
+++ b/chromium/components/enterprise/browser/enterprise_switches.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2020 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.
+
+// Defines the enterprise-related command-line switches used on several
+// platforms.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_ENTERPRISE_SWITCHES_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_ENTERPRISE_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace switches {
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+extern const char kEnableChromeBrowserCloudManagement[];
+#endif
+
+} // namespace switches
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_ENTERPRISE_SWITCHES_H_
diff --git a/chromium/components/enterprise/browser/reporting/browser_report_generator.cc b/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
index 8c9fbb730f4..e16dda63149 100644
--- a/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
@@ -23,10 +23,16 @@ BrowserReportGenerator::BrowserReportGenerator(
BrowserReportGenerator::~BrowserReportGenerator() = default;
-void BrowserReportGenerator::Generate(ReportCallback callback) {
+void BrowserReportGenerator::Generate(ReportType report_type,
+ ReportCallback callback) {
auto report = std::make_unique<em::BrowserReport>();
+ delegate_->GenerateProfileInfo(report_type, report.get());
+ if (report_type == ReportType::kExtensionRequest) {
+ report->set_executable_path(delegate_->GetExecutablePath());
+ std::move(callback).Run(std::move(report));
+ return;
+ }
GenerateBasicInfo(report.get());
- delegate_->GenerateProfileInfo(report.get());
// std::move is required here because the function completes the report
// asynchronously.
diff --git a/chromium/components/enterprise/browser/reporting/browser_report_generator.h b/chromium/components/enterprise/browser/reporting/browser_report_generator.h
index d166e64f331..6bff0cd33ef 100644
--- a/chromium/components/enterprise/browser/reporting/browser_report_generator.h
+++ b/chromium/components/enterprise/browser/reporting/browser_report_generator.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/callback.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/version_info/channel.h"
@@ -33,6 +34,7 @@ class BrowserReportGenerator {
virtual void GenerateBuildStateInfo(
enterprise_management::BrowserReport* report) = 0;
virtual void GenerateProfileInfo(
+ ReportType report_type,
enterprise_management::BrowserReport* report) = 0;
virtual void GeneratePluginsIfNeeded(
ReportCallback callback,
@@ -48,7 +50,7 @@ class BrowserReportGenerator {
// - browser_version, channel, executable_path
// - user profiles: id, name, is_full_report (always be false).
// - plugins: name, version, filename, description.
- void Generate(ReportCallback callback);
+ void Generate(ReportType report_type, ReportCallback callback);
private:
std::unique_ptr<Delegate> delegate_;
diff --git a/chromium/components/enterprise/browser/reporting/profile_report_generator.cc b/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
index 1c6e46eb406..ded36fe8506 100644
--- a/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
@@ -31,32 +31,44 @@ void ProfileReportGenerator::set_policies_enabled(bool enabled) {
std::unique_ptr<em::ChromeUserProfileInfo>
ProfileReportGenerator::MaybeGenerate(const base::FilePath& path,
- const std::string& name) {
+ const std::string& name,
+ ReportType report_type) {
if (!delegate_->Init(path)) {
return nullptr;
}
report_ = std::make_unique<em::ChromeUserProfileInfo>();
report_->set_id(path.AsUTF8Unsafe());
- report_->set_name(name);
- report_->set_is_full_report(true);
- delegate_->GetSigninUserInfo(report_.get());
- if (extensions_enabled_) {
- delegate_->GetExtensionInfo(report_.get());
- }
- delegate_->GetExtensionRequest(report_.get());
-
- if (policies_enabled_) {
- // TODO(crbug.com/983151): Upload policy error as their IDs.
- auto client = delegate_->MakePolicyConversionsClient();
- policies_ = policy::DictionaryPolicyConversions(std::move(client))
- .EnableConvertTypes(false)
- .EnablePrettyPrint(false)
- .ToValue();
- GetChromePolicyInfo();
- GetExtensionPolicyInfo();
- GetPolicyFetchTimestampInfo();
+ if (report_type == ReportType::kExtensionRequest) {
+ delegate_->GetExtensionRequest(report_.get());
+ report_->set_is_full_report(true);
+#if defined(OS_CHROMEOS)
+ // Extension request is aggregated at the user level on CrOS.
+ report_->set_name(name);
+ delegate_->GetSigninUserInfo(report_.get());
+#endif // defined(OS_CHROMEOS)
+ } else {
+ report_->set_name(name);
+ report_->set_is_full_report(true);
+
+ delegate_->GetSigninUserInfo(report_.get());
+ if (extensions_enabled_) {
+ delegate_->GetExtensionInfo(report_.get());
+ }
+ delegate_->GetExtensionRequest(report_.get());
+
+ if (policies_enabled_) {
+ // TODO(crbug.com/983151): Upload policy error as their IDs.
+ auto client = delegate_->MakePolicyConversionsClient();
+ policies_ = policy::DictionaryPolicyConversions(std::move(client))
+ .EnableConvertTypes(false)
+ .EnablePrettyPrint(false)
+ .ToValue();
+ GetChromePolicyInfo();
+ GetExtensionPolicyInfo();
+ GetPolicyFetchTimestampInfo();
+ }
}
return std::move(report_);
diff --git a/chromium/components/enterprise/browser/reporting/profile_report_generator.h b/chromium/components/enterprise/browser/reporting/profile_report_generator.h
index 63ce13d807b..a16a03c8a25 100644
--- a/chromium/components/enterprise/browser/reporting/profile_report_generator.h
+++ b/chromium/components/enterprise/browser/reporting/profile_report_generator.h
@@ -9,6 +9,8 @@
#include <string>
#include "base/values.h"
+#include "components/enterprise/browser/reporting/report_request_definition.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/core/browser/policy_conversions_client.h"
#include "components/policy/proto/device_management_backend.pb.h"
@@ -72,7 +74,8 @@ class ProfileReportGenerator {
// generated.
std::unique_ptr<enterprise_management::ChromeUserProfileInfo> MaybeGenerate(
const base::FilePath& path,
- const std::string& name);
+ const std::string& name,
+ ReportType report_type);
protected:
void GetChromePolicyInfo();
diff --git a/chromium/components/enterprise/browser/reporting/report_generator.cc b/chromium/components/enterprise/browser/reporting/report_generator.cc
index c17e29e9024..a881a051929 100644
--- a/chromium/components/enterprise/browser/reporting/report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/report_generator.cc
@@ -28,8 +28,9 @@ ReportGenerator::ReportGenerator(ReportingDelegateFactory* delegate_factory)
ReportGenerator::~ReportGenerator() = default;
-void ReportGenerator::Generate(bool with_profiles, ReportCallback callback) {
- CreateBasicRequest(std::make_unique<ReportRequest>(), with_profiles,
+void ReportGenerator::Generate(ReportType report_type,
+ ReportCallback callback) {
+ CreateBasicRequest(std::make_unique<ReportRequest>(), report_type,
std::move(callback));
}
@@ -39,22 +40,29 @@ void ReportGenerator::SetMaximumReportSizeForTesting(size_t size) {
void ReportGenerator::CreateBasicRequest(
std::unique_ptr<ReportRequest> basic_request,
- bool with_profiles,
+ ReportType report_type,
ReportCallback callback) {
+ if (report_type == kExtensionRequest) {
+ basic_request->add_partial_report_types(
+ em::PartialReportType::EXTENSION_REQUEST);
+ } else {
#if defined(OS_CHROMEOS)
- delegate_->SetAndroidAppInfos(basic_request.get());
+ delegate_->SetAndroidAppInfos(basic_request.get());
#else
- basic_request->set_computer_name(this->GetMachineName());
- basic_request->set_os_user_name(GetOSUserName());
- basic_request->set_serial_number(GetSerialNumber());
- basic_request->set_allocated_os_report(GetOSReport().release());
- basic_request->set_allocated_browser_device_identifier(
- policy::GetBrowserDeviceIdentifier().release());
+ basic_request->set_computer_name(this->GetMachineName());
+ basic_request->set_os_user_name(GetOSUserName());
+ basic_request->set_serial_number(GetSerialNumber());
+ basic_request->set_allocated_os_report(GetOSReport().release());
+ basic_request->set_allocated_browser_device_identifier(
+ policy::GetBrowserDeviceIdentifier().release());
#endif
+ }
- browser_report_generator_.Generate(base::BindOnce(
- &ReportGenerator::OnBrowserReportReady, weak_ptr_factory_.GetWeakPtr(),
- with_profiles, std::move(callback), std::move(basic_request)));
+ browser_report_generator_.Generate(
+ report_type,
+ base::BindOnce(&ReportGenerator::OnBrowserReportReady,
+ weak_ptr_factory_.GetWeakPtr(), report_type,
+ std::move(callback), std::move(basic_request)));
}
std::unique_ptr<em::OSReport> ReportGenerator::GetOSReport() {
@@ -83,16 +91,16 @@ std::string ReportGenerator::GetSerialNumber() {
}
void ReportGenerator::OnBrowserReportReady(
- bool with_profiles,
+ ReportType report_type,
ReportCallback callback,
std::unique_ptr<ReportRequest> basic_request,
std::unique_ptr<em::BrowserReport> browser_report) {
basic_request->set_allocated_browser_report(browser_report.release());
- if (with_profiles) {
+ if (report_type != kBrowserVersion) {
// Generate a queue of requests containing detailed profile information.
std::move(callback).Run(
- report_request_queue_generator_.Generate(*basic_request));
+ report_request_queue_generator_.Generate(report_type, *basic_request));
return;
}
diff --git a/chromium/components/enterprise/browser/reporting/report_generator.h b/chromium/components/enterprise/browser/reporting/report_generator.h
index 22bfd0c04a3..e9eb2f4e70b 100644
--- a/chromium/components/enterprise/browser/reporting/report_generator.h
+++ b/chromium/components/enterprise/browser/reporting/report_generator.h
@@ -15,6 +15,7 @@
#include "components/enterprise/browser/reporting/browser_report_generator.h"
#include "components/enterprise/browser/reporting/report_request_definition.h"
#include "components/enterprise/browser/reporting/report_request_queue_generator.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace enterprise_reporting {
@@ -44,17 +45,17 @@ class ReportGenerator {
virtual ~ReportGenerator();
// Asynchronously generates a queue of report requests, providing them to
- // |callback| when ready. If |with_profiles| is true, full details are
- // included for all loaded profiles; otherwise, only profile name and path
- // are included.
- virtual void Generate(bool with_profiles, ReportCallback callback);
+ // |callback| when ready. If |report_type| is kFull, all details are
+ // included for all loaded profiles. Otherwise, the report only contains
+ // information that are needed by that particular type.
+ virtual void Generate(ReportType report_type, ReportCallback callback);
void SetMaximumReportSizeForTesting(size_t size);
protected:
// Creates a basic request that will be used by all Profiles.
void CreateBasicRequest(std::unique_ptr<ReportRequest> basic_request,
- bool with_profiles,
+ ReportType report_type,
ReportCallback callback);
// Returns an OS report contains basic OS information includes OS name, OS
@@ -73,7 +74,7 @@ class ReportGenerator {
private:
void OnBrowserReportReady(
- bool with_profiles,
+ ReportType report_type,
ReportCallback callback,
std::unique_ptr<ReportRequest> basic_request,
std::unique_ptr<enterprise_management::BrowserReport> browser_report);
diff --git a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
index d3411e4cfb2..a719a505107 100644
--- a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
@@ -53,7 +53,8 @@ void ReportRequestQueueGenerator::SetMaximumReportSizeForTesting(
}
ReportRequestQueueGenerator::ReportRequests
-ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
+ReportRequestQueueGenerator::Generate(ReportType report_type,
+ const ReportRequest& basic_request) {
ReportRequests requests;
size_t basic_request_size = basic_request.ByteSizeLong();
base::UmaHistogramMemoryKB(kBasicRequestSizeMetricsName,
@@ -64,7 +65,8 @@ ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
int profile_infos_size =
basic_request.browser_report().chrome_user_profile_infos_size();
for (int index = 0; index < profile_infos_size; index++) {
- GenerateProfileReportWithIndex(basic_request, index, &requests);
+ GenerateProfileReportWithIndex(index, report_type, basic_request,
+ &requests);
}
base::UmaHistogramMemoryKB(kRequestSizeMetricsName,
@@ -77,8 +79,9 @@ ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
}
void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
- const ReportRequest& basic_request,
int profile_index,
+ ReportType report_type,
+ const ReportRequest& basic_request,
ReportRequests* requests) {
DCHECK_LT(profile_index,
basic_request.browser_report().chrome_user_profile_infos_size());
@@ -87,7 +90,8 @@ void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
auto basic_profile =
basic_request.browser_report().chrome_user_profile_infos(profile_index);
auto profile_report = profile_report_generator_.MaybeGenerate(
- base::FilePath::FromUTF8Unsafe(basic_profile.id()), basic_profile.name());
+ base::FilePath::FromUTF8Unsafe(basic_profile.id()), basic_profile.name(),
+ report_type);
// Return if Profile is not loaded and there is no full report.
if (!profile_report)
diff --git a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
index 20ad675d5d2..99e2f9c75de 100644
--- a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
+++ b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
@@ -13,6 +13,7 @@
#include "build/build_config.h"
#include "components/enterprise/browser/reporting/profile_report_generator.h"
#include "components/enterprise/browser/reporting/report_request_definition.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace enterprise_reporting {
@@ -44,13 +45,15 @@ class ReportRequestQueueGenerator {
// Generate a queue of requests including full profile info based on given
// basic request.
- ReportRequests Generate(const ReportRequest& basic_request);
+ ReportRequests Generate(ReportType report_type,
+ const ReportRequest& basic_request);
private:
// Generate request with full profile info at |profile_index| according to
// |basic_request|, then store it into |requests|.
- void GenerateProfileReportWithIndex(const ReportRequest& basic_request,
- int profile_index,
+ void GenerateProfileReportWithIndex(int profile_index,
+ ReportType report_type,
+ const ReportRequest& basic_request,
ReportRequests* requests);
private:
diff --git a/chromium/components/enterprise/browser/reporting/report_scheduler.cc b/chromium/components/enterprise/browser/reporting/report_scheduler.cc
index 1f3ecdb78ff..63dbdd98124 100644
--- a/chromium/components/enterprise/browser/reporting/report_scheduler.cc
+++ b/chromium/components/enterprise/browser/reporting/report_scheduler.cc
@@ -30,6 +30,30 @@ constexpr base::TimeDelta kDefaultUploadInterval =
base::TimeDelta::FromHours(24); // Default upload interval is 24 hours.
const int kMaximumRetry = 10; // Retry 10 times takes about 15 to 19 hours.
+bool IsBrowserVersionUploaded(ReportScheduler::ReportTrigger trigger) {
+ switch (trigger) {
+ case ReportScheduler::kTriggerTimer:
+ case ReportScheduler::kTriggerUpdate:
+ case ReportScheduler::kTriggerNewVersion:
+ return true;
+ case ReportScheduler::kTriggerNone:
+ case ReportScheduler::kTriggerExtensionRequest:
+ return false;
+ }
+}
+
+bool IsExtensionRequestUploaded(ReportScheduler::ReportTrigger trigger) {
+ switch (trigger) {
+ case ReportScheduler::kTriggerTimer:
+ case ReportScheduler::kTriggerExtensionRequest:
+ return true;
+ case ReportScheduler::kTriggerNone:
+ case ReportScheduler::kTriggerUpdate:
+ case ReportScheduler::kTriggerNewVersion:
+ return false;
+ }
+}
+
} // namespace
ReportScheduler::Delegate::Delegate() = default;
@@ -114,11 +138,13 @@ void ReportScheduler::OnReportEnabledPrefChanged() {
delegate_->StartWatchingUpdatesIfNeeded(last_upload_timestamp,
kDefaultUploadInterval);
+ delegate_->StartWatchingExtensionRequestIfNeeded();
}
void ReportScheduler::Stop() {
request_timer_.Stop();
delegate_->StopWatchingUpdates();
+ delegate_->StopWatchingExtensionRequest();
}
bool ReportScheduler::SetupBrowserPolicyClientRegistration() {
@@ -164,7 +190,7 @@ void ReportScheduler::GenerateAndUploadReport(ReportTrigger trigger) {
}
active_trigger_ = trigger;
- bool with_profiles = true;
+ ReportType report_type = kFull;
switch (trigger) {
case kTriggerNone:
NOTREACHED();
@@ -174,17 +200,21 @@ void ReportScheduler::GenerateAndUploadReport(ReportTrigger trigger) {
break;
case kTriggerUpdate:
VLOG(1) << "Generating basic enterprise report upon update.";
- with_profiles = false;
+ report_type = kBrowserVersion;
break;
case kTriggerNewVersion:
VLOG(1) << "Generating basic enterprise report upon new version.";
- with_profiles = false;
+ report_type = kBrowserVersion;
+ break;
+ case kTriggerExtensionRequest:
+ VLOG(1) << "Generating extension request partially report.";
+ report_type = kExtensionRequest;
break;
}
report_generator_->Generate(
- with_profiles, base::BindOnce(&ReportScheduler::OnReportGenerated,
- base::Unretained(this)));
+ report_type, base::BindOnce(&ReportScheduler::OnReportGenerated,
+ base::Unretained(this)));
}
void ReportScheduler::OnReportGenerated(
@@ -218,7 +248,11 @@ void ReportScheduler::OnReportUploaded(ReportUploader::ReportStatus status) {
// Schedule the next report for success. Reset uploader to reset failure
// count.
report_uploader_.reset();
- delegate_->SaveLastUploadVersion();
+ if (IsBrowserVersionUploaded(active_trigger_))
+ delegate_->OnBrowserVersionUploaded();
+
+ if (IsExtensionRequestUploaded(active_trigger_))
+ delegate_->OnExtensionRequestUploaded();
FALLTHROUGH;
case ReportUploader::kTransientError:
// Stop retrying and schedule the next report to avoid stale report.
@@ -231,6 +265,7 @@ void ReportScheduler::OnReportUploaded(ReportUploader::ReportStatus status) {
}
break;
case ReportUploader::kPersistentError:
+ Stop();
// No future upload until Chrome relaunch or pref change event.
break;
}
@@ -246,12 +281,21 @@ void ReportScheduler::RunPendingTriggers() {
// Timer-triggered reports are a superset of those triggered by an update or a
// new version, so favor them and consider that they serve all purposes.
- uint32_t pending_triggers = std::exchange(pending_triggers_, 0);
- ReportTrigger trigger = kTriggerTimer;
- if ((pending_triggers & kTriggerTimer) == 0) {
- trigger = (pending_triggers & kTriggerUpdate) != 0 ? kTriggerUpdate
- : kTriggerNewVersion;
+
+ ReportTrigger trigger;
+ if ((pending_triggers_ & kTriggerTimer) != 0) {
+ // Timer-triggered reports contain data of all other report types.
+ trigger = kTriggerTimer;
+ pending_triggers_ = 0;
+ } else if ((pending_triggers_ & kTriggerExtensionRequest) != 0) {
+ trigger = kTriggerExtensionRequest;
+ pending_triggers_ -= kTriggerExtensionRequest;
+ } else {
+ trigger = (pending_triggers_ & kTriggerUpdate) != 0 ? kTriggerUpdate
+ : kTriggerNewVersion;
+ pending_triggers_ = 0;
}
+
GenerateAndUploadReport(trigger);
}
@@ -264,7 +308,8 @@ void ReportScheduler::RecordUploadTrigger(ReportTrigger trigger) {
kTimer = 1,
kUpdate = 2,
kNewVersion = 3,
- kMaxValue = kNewVersion
+ kExtensionRequest = 4,
+ kMaxValue = kExtensionRequest
} sample = Sample::kNone;
switch (trigger) {
case kTriggerNone:
@@ -278,6 +323,9 @@ void ReportScheduler::RecordUploadTrigger(ReportTrigger trigger) {
case kTriggerNewVersion:
sample = Sample::kNewVersion;
break;
+ case kTriggerExtensionRequest:
+ sample = Sample::kExtensionRequest;
+ break;
}
base::UmaHistogramEnumeration("Enterprise.CloudReportingUploadTrigger",
sample);
diff --git a/chromium/components/enterprise/browser/reporting/report_scheduler.h b/chromium/components/enterprise/browser/reporting/report_scheduler.h
index 93ca3e26a11..5052f12ed1f 100644
--- a/chromium/components/enterprise/browser/reporting/report_scheduler.h
+++ b/chromium/components/enterprise/browser/reporting/report_scheduler.h
@@ -36,10 +36,11 @@ class ReportScheduler {
// The trigger leading to report generation. Values are bitmasks in the
// |pending_triggers_| bitfield.
enum ReportTrigger : uint32_t {
- kTriggerNone = 0, // No trigger.
- kTriggerTimer = 1U << 0, // The periodic timer expired.
- kTriggerUpdate = 1U << 1, // An update was detected.
- kTriggerNewVersion = 1U << 2, // A new version is running.
+ kTriggerNone = 0, // No trigger.
+ kTriggerTimer = 1U << 0, // The periodic timer expired.
+ kTriggerUpdate = 1U << 1, // An update was detected.
+ kTriggerNewVersion = 1U << 2, // A new version is running.
+ kTriggerExtensionRequest = 1U << 3, // Pending extension requests updated.
};
using ReportTriggerCallback = base::RepeatingCallback<void(ReportTrigger)>;
@@ -55,11 +56,18 @@ class ReportScheduler {
void SetReportTriggerCallback(ReportTriggerCallback callback);
virtual PrefService* GetLocalState() = 0;
+
+ // Browser version
virtual void StartWatchingUpdatesIfNeeded(
base::Time last_upload,
base::TimeDelta upload_interval) = 0;
virtual void StopWatchingUpdates() = 0;
- virtual void SaveLastUploadVersion() = 0;
+ virtual void OnBrowserVersionUploaded() = 0;
+
+ // Extension request
+ virtual void StartWatchingExtensionRequestIfNeeded() = 0;
+ virtual void StopWatchingExtensionRequest() = 0;
+ virtual void OnExtensionRequestUploaded() = 0;
protected:
ReportTriggerCallback trigger_report_callback_;
diff --git a/chromium/components/enterprise/browser/reporting/report_type.h b/chromium/components/enterprise/browser/reporting/report_type.h
new file mode 100644
index 00000000000..f244dc6c837
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/report_type.h
@@ -0,0 +1,18 @@
+// Copyright 2020 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_ENTERPRISE_BROWSER_REPORTING_REPORT_TYPE_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_TYPE_H_
+
+namespace enterprise_reporting {
+
+enum ReportType : uint32_t {
+ kFull = 0,
+ kBrowserVersion = 1u << 0,
+ kExtensionRequest = 2u << 1,
+};
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_TYPE_H_
diff --git a/chromium/components/enterprise/common/proto/connectors.proto b/chromium/components/enterprise/common/proto/connectors.proto
index fca4a51fdae..a49072adcce 100644
--- a/chromium/components/enterprise/common/proto/connectors.proto
+++ b/chromium/components/enterprise/common/proto/connectors.proto
@@ -102,6 +102,12 @@ message ContentAnalysisResponse {
optional string rule_id = 3;
}
repeated TriggeredRule triggered_rules = 3;
+
+ // TODO(crbug.com/1147036): Remove fields 4-6 once a definitive approach is
+ // agreed upon.
+ optional string malware_family = 4;
+ optional string malware_category = 5;
+ optional string evidence_locker_filepath = 6;
}
repeated Result results = 4;
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index 07ae22aae21..76eac75d891 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -43,6 +43,10 @@ namespace error_page {
namespace {
+// Hardcode these constants to avoid dependences on //chrome and //content.
+const char kChromeUIScheme[] = "chrome";
+const char kChromeUIDinoHost[] = "dino";
+
static const char kRedirectLoopLearnMoreUrl[] =
"https://support.google.com/chrome?p=rl_error";
@@ -906,6 +910,9 @@ LocalizedError::PageState LocalizedError::GetPageState(
webui::SetLoadTimeDataDefaults(locale, &result.strings);
+ bool show_game_instructions = failed_url.host() == kChromeUIDinoHost &&
+ failed_url.scheme() == kChromeUIScheme;
+
// Grab the strings and settings that depend on the error type. Init
// options with default values.
LocalizedErrorMap options = {
@@ -956,19 +963,14 @@ LocalizedError::PageState LocalizedError::GetPageState(
result.strings.SetString("iconClass", icon_class);
auto heading = std::make_unique<base::DictionaryValue>();
- heading->SetString("msg",
- l10n_util::GetStringUTF16(options.heading_resource_id));
+
+ int msg_id = show_game_instructions ? IDS_ERRORPAGES_GAME_INSTRUCTIONS
+ : options.heading_resource_id;
+ heading->SetString("msg", l10n_util::GetStringUTF16(msg_id));
heading->SetString("hostName", host_name);
result.strings.Set("heading", std::move(heading));
- auto summary = std::make_unique<base::DictionaryValue>();
-
- // Set summary message under the heading.
- summary->SetString(
- "msg", l10n_util::GetStringUTF16(options.summary_resource_id));
-
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
// Check if easter egg should be disabled.
if (command_line->HasSwitch(
error_page::switches::kDisableDinosaurEasterEgg)) {
@@ -978,6 +980,19 @@ LocalizedError::PageState LocalizedError::GetPageState(
l10n_util::GetStringUTF16(IDS_ERRORPAGE_FUN_DISABLED));
}
+ // Return early and don't add suggestions or other information when showing
+ // game instructions.
+ if (show_game_instructions) {
+ // When showing instructions, set an empty error to prevent a "NULL" string.
+ result.strings.SetString("errorCode", "");
+ return result;
+ }
+
+ auto summary = std::make_unique<base::DictionaryValue>();
+
+ // Set summary message under the heading.
+ summary->SetString("msg",
+ l10n_util::GetStringUTF16(options.summary_resource_id));
summary->SetString("failedUrl", failed_url_string);
summary->SetString("hostName", host_name);
diff --git a/chromium/components/error_page/content/browser/net_error_auto_reloader.cc b/chromium/components/error_page/content/browser/net_error_auto_reloader.cc
index 755549f9d0a..5c1372d27cb 100644
--- a/chromium/components/error_page/content/browser/net_error_auto_reloader.cc
+++ b/chromium/components/error_page/content/browser/net_error_auto_reloader.cc
@@ -51,7 +51,10 @@ bool ShouldAutoReload(content::NavigationHandle* handle) {
// TODO(crbug.com/1016164): Explore how to allow reloads for secure DNS
// network errors without interfering with the captive portal probe
// state.
- !handle->GetResolveErrorInfo().is_secure_network_error;
+ !handle->GetResolveErrorInfo().is_secure_network_error &&
+ // Don't auto reload if the error is caused by the server returning a
+ // non-2xx HTTP response code.
+ net_error != net::ERR_HTTP_RESPONSE_CODE_FAILURE;
}
base::TimeDelta GetNextReloadDelay(size_t reload_count) {
diff --git a/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc b/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
index ca3013ad546..91d2f26cceb 100644
--- a/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
+++ b/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/optional.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
diff --git a/chromium/components/error_page_strings.grdp b/chromium/components/error_page_strings.grdp
index 578e3601ba9..c91ff8c08a1 100644
--- a/chromium/components/error_page_strings.grdp
+++ b/chromium/components/error_page_strings.grdp
@@ -369,5 +369,15 @@
If spelling is correct, <ph name="BEGIN_LINK">&lt;a href="javascript:diagnoseErrors()" id="diagnose-link"&gt;</ph>try running Connectivity Diagnostics<ph name="END_LINK">&lt;/a&gt;</ph>.
</message>
</if>
+ <if expr="is_android or is_ios">
+ <message name="IDS_ERRORPAGES_GAME_INSTRUCTIONS" desc="Mobile: Instructions on how to start playing the offline game. 'dino' is an acceptable English nickname that refers to 'dinosaur'">
+ Tap the dino to play
+ </message>
+ </if>
+ <if expr="not is_android and not is_ios">
+ <message name="IDS_ERRORPAGES_GAME_INSTRUCTIONS" desc="Instructions on how to start playing the offline game.">
+ Press space to play
+ </message>
+ </if>
</grit-part>
diff --git a/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_GAME_INSTRUCTIONS.png.sha1 b/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_GAME_INSTRUCTIONS.png.sha1
new file mode 100644
index 00000000000..b996bc90e23
--- /dev/null
+++ b/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_GAME_INSTRUCTIONS.png.sha1
@@ -0,0 +1 @@
+2cdc160e31c0a323842c4996a1a4c5bef05b5678 \ No newline at end of file
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index b3e128ab786..ae38abce347 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -33,10 +33,7 @@ static_library("exo") {
"display.h",
"drag_drop_operation.cc",
"drag_drop_operation.h",
- "extended_drag_offer.cc",
- "extended_drag_offer.h",
- "extended_drag_source.cc",
- "extended_drag_source.h",
+ "file_helper.h",
"frame_sink_resource_manager.cc",
"frame_sink_resource_manager.h",
"input_trace.h",
@@ -90,6 +87,7 @@ static_library("exo") {
"//services/viz/privileged/mojom/compositing",
"//skia",
"//third_party/blink/public/common",
+ "//ui/accessibility:ax_base",
"//ui/aura",
"//ui/base/cursor",
"//ui/base/ime",
@@ -127,6 +125,10 @@ static_library("exo") {
"//ash/keyboard/ui",
"//ash/public/cpp",
"//chromeos/constants",
+ "//chromeos/crosapi/cpp",
+ "//chromeos/ui/base",
+ "//chromeos/ui/frame",
+ "//ui/base",
"//ui/events/ozone/layout",
]
sources += [
@@ -134,6 +136,10 @@ static_library("exo") {
"client_controlled_accelerators.h",
"client_controlled_shell_surface.cc",
"client_controlled_shell_surface.h",
+ "extended_drag_offer.cc",
+ "extended_drag_offer.h",
+ "extended_drag_source.cc",
+ "extended_drag_source.h",
"gamepad.cc",
"gamepad.h",
"gamepad_observer.h",
@@ -186,6 +192,8 @@ source_set("test_support") {
testonly = true
sources = [
+ "mock_vsync_timing_observer.cc",
+ "mock_vsync_timing_observer.h",
"test/exo_test_base_views.cc",
"test/exo_test_base_views.h",
"test/exo_test_suite_aura.cc",
@@ -217,12 +225,15 @@ source_set("test_support") {
sources += [
"test/exo_test_base.cc",
"test/exo_test_base.h",
+ "test/exo_test_file_helper.cc",
+ "test/exo_test_file_helper.h",
"test/exo_test_helper.cc",
"test/exo_test_helper.h",
]
deps += [
"//ash:test_support",
"//ash/public/cpp",
+ "//chromeos/ui/base",
]
}
}
@@ -274,6 +285,7 @@ source_set("unit_tests") {
"data_source_unittest.cc",
"display_unittest.cc",
"drag_drop_operation_unittest.cc",
+ "extended_drag_source_unittest.cc",
"gamepad_unittest.cc",
"gaming_seat_unittest.cc",
"input_method_surface_unittest.cc",
@@ -290,6 +302,7 @@ source_set("unit_tests") {
"toast_surface_unittest.cc",
"touch_unittest.cc",
"ui_lock_controller_unittest.cc",
+ "wm_helper_chromeos_unittest.cc",
"xdg_shell_surface_unittest.cc",
]
@@ -299,6 +312,8 @@ source_set("unit_tests") {
"//ash/keyboard/ui",
"//ash/public/cpp",
"//chromeos/constants",
+ "//chromeos/ui/base",
+ "//chromeos/ui/frame",
"//ui/base:test_support",
"//ui/base/cursor/mojom:cursor_type",
"//ui/base/dragdrop/mojom:mojom_shared",
diff --git a/chromium/components/exo/DEPS b/chromium/components/exo/DEPS
index 46520b6c925..c32564d668b 100644
--- a/chromium/components/exo/DEPS
+++ b/chromium/components/exo/DEPS
@@ -3,6 +3,9 @@ include_rules = [
"+cc",
"+chromeos/audio/chromeos_sounds.h",
"+chromeos/constants/chromeos_features.h",
+ "+chromeos/crosapi/cpp/crosapi_constants.h",
+ "+chromeos/ui/base",
+ "+chromeos/ui/frame",
"+components/viz/common",
"+components/viz/host",
"+device/gamepad",
@@ -12,6 +15,7 @@ include_rules = [
"+net/base",
"+services/data_decoder/public/cpp",
"+services/viz/privileged/mojom/compositing/vsync_parameter_observer.mojom.h",
+ "+skia/ext",
"+third_party/blink/public/common",
"+third_party/khronos",
"+third_party/skia",
diff --git a/chromium/components/exo/client_controlled_shell_surface.cc b/chromium/components/exo/client_controlled_shell_surface.cc
index 42fbcc39763..43b3813103e 100644
--- a/chromium/components/exo/client_controlled_shell_surface.cc
+++ b/chromium/components/exo/client_controlled_shell_surface.cc
@@ -11,15 +11,10 @@
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/frame/wide_frame_view.h"
#include "ash/public/cpp/ash_features.h"
-#include "ash/public/cpp/caption_buttons/caption_button_model.h"
-#include "ash/public/cpp/default_frame_header.h"
-#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
#include "ash/public/cpp/rounded_corner_decorator.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_backdrop.h"
-#include "ash/public/cpp/window_pin_type.h"
#include "ash/public/cpp/window_properties.h"
-#include "ash/public/cpp/window_state_type.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wm/client_controlled_state.h"
@@ -39,6 +34,13 @@
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
+#include "chromeos/ui/base/tablet_state.h"
+#include "chromeos/ui/base/window_pin_type.h"
+#include "chromeos/ui/base/window_properties.h"
+#include "chromeos/ui/base/window_state_type.h"
+#include "chromeos/ui/frame/caption_buttons/caption_button_model.h"
+#include "chromeos/ui/frame/default_frame_header.h"
+#include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
@@ -52,6 +54,7 @@
#include "ui/compositor/compositor_lock.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/display/tablet_state.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget.h"
@@ -62,6 +65,8 @@ namespace exo {
namespace {
+using ::chromeos::WindowStateType;
+
// Client controlled specific accelerators.
const struct {
ui::KeyboardCode keycode;
@@ -106,12 +111,12 @@ class ClientControlledStateDelegate
// Overridden from ash::ClientControlledState::Delegate:
void HandleWindowStateRequest(ash::WindowState* window_state,
- ash::WindowStateType next_state) override {
+ chromeos::WindowStateType next_state) override {
shell_surface_->OnWindowStateChangeEvent(window_state->GetStateType(),
next_state);
}
void HandleBoundsRequest(ash::WindowState* window_state,
- ash::WindowStateType requested_state,
+ chromeos::WindowStateType requested_state,
const gfx::Rect& bounds_in_display,
int64_t display_id) override {
shell_surface_->OnBoundsChangeEvent(
@@ -140,31 +145,31 @@ class ClientControlledWindowStateDelegate : public ash::WindowStateDelegate {
// Overridden from ash::WindowStateDelegate:
bool ToggleFullscreen(ash::WindowState* window_state) override {
- ash::WindowStateType next_state;
+ chromeos::WindowStateType next_state;
aura::Window* window = window_state->window();
switch (window_state->GetStateType()) {
- case ash::WindowStateType::kDefault:
- case ash::WindowStateType::kNormal:
+ case chromeos::WindowStateType::kDefault:
+ case chromeos::WindowStateType::kNormal:
window->SetProperty(aura::client::kPreFullscreenShowStateKey,
ui::SHOW_STATE_NORMAL);
- next_state = ash::WindowStateType::kFullscreen;
+ next_state = chromeos::WindowStateType::kFullscreen;
break;
- case ash::WindowStateType::kMaximized:
+ case chromeos::WindowStateType::kMaximized:
window->SetProperty(aura::client::kPreFullscreenShowStateKey,
ui::SHOW_STATE_MAXIMIZED);
- next_state = ash::WindowStateType::kFullscreen;
+ next_state = chromeos::WindowStateType::kFullscreen;
break;
- case ash::WindowStateType::kFullscreen:
+ case chromeos::WindowStateType::kFullscreen:
switch (window->GetProperty(aura::client::kPreFullscreenShowStateKey)) {
case ui::SHOW_STATE_DEFAULT:
case ui::SHOW_STATE_NORMAL:
- next_state = ash::WindowStateType::kNormal;
+ next_state = chromeos::WindowStateType::kNormal;
break;
case ui::SHOW_STATE_MAXIMIZED:
- next_state = ash::WindowStateType::kMaximized;
+ next_state = chromeos::WindowStateType::kMaximized;
break;
case ui::SHOW_STATE_MINIMIZED:
- next_state = ash::WindowStateType::kMinimized;
+ next_state = chromeos::WindowStateType::kMinimized;
break;
case ui::SHOW_STATE_FULLSCREEN:
case ui::SHOW_STATE_INACTIVE:
@@ -175,14 +180,14 @@ class ClientControlledWindowStateDelegate : public ash::WindowStateDelegate {
return false;
}
break;
- case ash::WindowStateType::kMinimized: {
+ case chromeos::WindowStateType::kMinimized: {
ui::WindowShowState pre_full_state =
window->GetProperty(aura::client::kPreMinimizedShowStateKey);
if (pre_full_state != ui::SHOW_STATE_FULLSCREEN) {
window->SetProperty(aura::client::kPreFullscreenShowStateKey,
pre_full_state);
}
- next_state = ash::WindowStateType::kFullscreen;
+ next_state = chromeos::WindowStateType::kFullscreen;
break;
}
default:
@@ -212,7 +217,7 @@ bool IsPinned(const ash::WindowState* window_state) {
return window_state->IsPinned() || window_state->IsTrustedPinned();
}
-class CaptionButtonModel : public ash::CaptionButtonModel {
+class CaptionButtonModel : public chromeos::CaptionButtonModel {
public:
CaptionButtonModel(uint32_t visible_button_mask, uint32_t enabled_button_mask)
: visible_button_mask_(visible_button_mask),
@@ -322,7 +327,7 @@ ClientControlledShellSurface::ClientControlledShellSurface(
int container,
bool default_scale_cancellation)
: ShellSurfaceBase(surface, gfx::Point(), true, can_minimize, container),
- current_pin_(ash::WindowPinType::kNone),
+ current_pin_(chromeos::WindowPinType::kNone),
use_default_scale_cancellation_(default_scale_cancellation) {}
ClientControlledShellSurface::~ClientControlledShellSurface() {
@@ -333,8 +338,8 @@ ClientControlledShellSurface::~ClientControlledShellSurface() {
if (client_controlled_state_)
client_controlled_state_->ResetDelegate();
wide_frame_.reset();
- if (current_pin_ != ash::WindowPinType::kNone)
- SetPinned(ash::WindowPinType::kNone);
+ if (current_pin_ != chromeos::WindowPinType::kNone)
+ SetPinned(chromeos::WindowPinType::kNone);
}
void ClientControlledShellSurface::SetBounds(int64_t display_id,
@@ -382,49 +387,49 @@ void ClientControlledShellSurface::SetBoundsSize(const gfx::Size& size) {
void ClientControlledShellSurface::SetMaximized() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetMaximized");
- pending_window_state_ = ash::WindowStateType::kMaximized;
+ pending_window_state_ = chromeos::WindowStateType::kMaximized;
}
void ClientControlledShellSurface::SetMinimized() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetMinimized");
- pending_window_state_ = ash::WindowStateType::kMinimized;
+ pending_window_state_ = chromeos::WindowStateType::kMinimized;
}
void ClientControlledShellSurface::SetRestored() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetRestored");
- pending_window_state_ = ash::WindowStateType::kNormal;
+ pending_window_state_ = chromeos::WindowStateType::kNormal;
}
void ClientControlledShellSurface::SetFullscreen(bool fullscreen) {
TRACE_EVENT1("exo", "ClientControlledShellSurface::SetFullscreen",
"fullscreen", fullscreen);
- pending_window_state_ = fullscreen ? ash::WindowStateType::kFullscreen
- : ash::WindowStateType::kNormal;
+ pending_window_state_ = fullscreen ? chromeos::WindowStateType::kFullscreen
+ : chromeos::WindowStateType::kNormal;
}
void ClientControlledShellSurface::SetSnappedToLeft() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetSnappedToLeft");
- pending_window_state_ = ash::WindowStateType::kLeftSnapped;
+ pending_window_state_ = chromeos::WindowStateType::kLeftSnapped;
}
void ClientControlledShellSurface::SetSnappedToRight() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetSnappedToRight");
- pending_window_state_ = ash::WindowStateType::kRightSnapped;
+ pending_window_state_ = chromeos::WindowStateType::kRightSnapped;
}
void ClientControlledShellSurface::SetPip() {
TRACE_EVENT0("exo", "ClientControlledShellSurface::SetPip");
- pending_window_state_ = ash::WindowStateType::kPip;
+ pending_window_state_ = chromeos::WindowStateType::kPip;
}
-void ClientControlledShellSurface::SetPinned(ash::WindowPinType type) {
+void ClientControlledShellSurface::SetPinned(chromeos::WindowPinType type) {
TRACE_EVENT1("exo", "ClientControlledShellSurface::SetPinned", "type",
static_cast<int>(type));
if (!widget_)
CreateShellSurfaceWidget(ui::SHOW_STATE_NORMAL);
- widget_->GetNativeWindow()->SetProperty(ash::kWindowPinTypeKey, type);
+ widget_->GetNativeWindow()->SetProperty(chromeos::kWindowPinTypeKey, type);
current_pin_ = type;
}
@@ -509,8 +514,8 @@ void ClientControlledShellSurface::SetResizeOutset(int outset) {
}
void ClientControlledShellSurface::OnWindowStateChangeEvent(
- ash::WindowStateType current_state,
- ash::WindowStateType next_state) {
+ chromeos::WindowStateType current_state,
+ chromeos::WindowStateType next_state) {
// Android already knows this state change. Don't send state change to Android
// that it is about to do anyway.
if (state_changed_callback_ && pending_window_state_ != next_state)
@@ -565,7 +570,7 @@ void ClientControlledShellSurface::UpdateAutoHideFrame() {
bool enabled = (frame_type_ == SurfaceFrameType::AUTOHIDE &&
(GetWindowState()->IsMaximizedOrFullscreenOrPinned() ||
GetWindowState()->IsSnapped()));
- ash::ImmersiveFullscreenController::EnableForWidget(widget_, enabled);
+ chromeos::ImmersiveFullscreenController::EnableForWidget(widget_, enabled);
}
}
@@ -588,8 +593,10 @@ void ClientControlledShellSurface::SetExtraTitle(
TRACE_EVENT1("exo", "ClientControlledShellSurface::SetExtraTitle",
"extra_title", base::UTF16ToUTF8(extra_title));
- if (!widget_)
+ if (!widget_) {
+ initial_extra_title_ = extra_title;
return;
+ }
GetFrameView()->GetHeaderView()->GetFrameHeader()->SetFrameTextOverride(
extra_title);
@@ -637,8 +644,8 @@ void ClientControlledShellSurface::DidReceiveCompositorFrameAck() {
}
void ClientControlledShellSurface::OnBoundsChangeEvent(
- ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ chromeos::WindowStateType current_state,
+ chromeos::WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& window_bounds,
int bounds_change) {
@@ -651,28 +658,17 @@ void ClientControlledShellSurface::OnBoundsChangeEvent(
// The bounds will be provided by client when unminimized.
if (geometry().IsEmpty() || window_bounds.IsEmpty() ||
(widget_->IsMinimized() &&
- requested_state == ash::WindowStateType::kMinimized) ||
+ requested_state == chromeos::WindowStateType::kMinimized) ||
!bounds_changed_callback_) {
return;
}
// Sends the client bounds, which matches the geometry
// when frame is enabled.
- ash::NonClientFrameViewAsh* frame_view = GetFrameView();
+ const gfx::Rect client_bounds = GetClientBoundsForWindowBoundsAndWindowState(
+ window_bounds, requested_state);
- // The client's geometry uses fullscreen in client controlled,
- // (but the surface is placed under the frame), so just use
- // the window bounds instead for maximixed state.
- // Snapped window states in tablet mode do not include the caption height.
- const bool becoming_snapped =
- requested_state == ash::WindowStateType::kLeftSnapped ||
- requested_state == ash::WindowStateType::kRightSnapped;
- const bool is_tablet_mode = WMHelper::GetInstance()->InTabletMode();
- gfx::Rect client_bounds =
- widget_->IsMaximized() || (becoming_snapped && is_tablet_mode)
- ? window_bounds
- : frame_view->GetClientBoundsForWindowBounds(window_bounds);
- gfx::Size current_size = frame_view->GetBoundsForClientView().size();
+ gfx::Size current_size = GetFrameView()->GetBoundsForClientView().size();
bool is_resize = client_bounds.size() != current_size &&
!widget_->IsMaximized() && !widget_->IsFullscreen();
@@ -748,8 +744,8 @@ void ClientControlledShellSurface::OnSetFrameColors(SkColor active_color,
ShellSurfaceBase::OnSetFrameColors(active_color, inactive_color);
if (wide_frame_) {
aura::Window* window = wide_frame_->GetWidget()->GetNativeWindow();
- window->SetProperty(ash::kFrameActiveColorKey, active_color);
- window->SetProperty(ash::kFrameInactiveColorKey, inactive_color);
+ window->SetProperty(chromeos::kFrameActiveColorKey, active_color);
+ window->SetProperty(chromeos::kFrameInactiveColorKey, inactive_color);
}
}
@@ -796,7 +792,7 @@ ClientControlledShellSurface::CreateNonClientFrameView(views::Widget* widget) {
auto frame_view =
CreateNonClientFrameViewInternal(widget, /*client_controlled=*/true);
immersive_fullscreen_controller_ =
- std::make_unique<ash::ImmersiveFullscreenController>();
+ std::make_unique<chromeos::ImmersiveFullscreenController>();
static_cast<ash::NonClientFrameViewAsh*>(frame_view.get())
->InitImmersiveFullscreenControllerForView(
immersive_fullscreen_controller_.get());
@@ -1043,6 +1039,8 @@ void ClientControlledShellSurface::InitializeWindowState(
UpdateFrameWidth();
if (initial_orientation_lock_ != ash::OrientationLockType::kAny)
SetOrientationLock(initial_orientation_lock_);
+ if (initial_extra_title_ != base::string16())
+ SetExtraTitle(initial_extra_title_);
// Register Client controlled accelerators.
views::FocusManager* focus_manager = widget_->GetFocusManager();
@@ -1095,7 +1093,8 @@ bool ClientControlledShellSurface::OnPreWidgetCommit() {
// explicit target display.
if (!pending_geometry_.IsEmpty())
origin_ = pending_geometry_.origin();
- CreateShellSurfaceWidget(ash::ToWindowShowState(pending_window_state_));
+ CreateShellSurfaceWidget(
+ chromeos::ToWindowShowState(pending_window_state_));
}
// Finish ignoring obsolete bounds update as the state changes caused by
@@ -1124,14 +1123,14 @@ bool ClientControlledShellSurface::OnPreWidgetCommit() {
auto animation_type = ash::ClientControlledState::kAnimationNone;
switch (pending_window_state_) {
- case ash::WindowStateType::kNormal:
+ case chromeos::WindowStateType::kNormal:
if (widget_->IsMaximized() || widget_->IsFullscreen()) {
animation_type = ash::ClientControlledState::kAnimationCrossFade;
}
break;
- case ash::WindowStateType::kMaximized:
- case ash::WindowStateType::kFullscreen:
+ case chromeos::WindowStateType::kMaximized:
+ case chromeos::WindowStateType::kFullscreen:
if (!window_state->IsPip())
animation_type = ash::ClientControlledState::kAnimationCrossFade;
break;
@@ -1140,7 +1139,7 @@ bool ClientControlledShellSurface::OnPreWidgetCommit() {
break;
}
- if (pending_window_state_ == ash::WindowStateType::kPip) {
+ if (pending_window_state_ == chromeos::WindowStateType::kPip) {
if (ash::features::IsPipRoundedCornersEnabled()) {
decorator_ = std::make_unique<ash::RoundedCornerDecorator>(
window_state->window(), host_window(), host_window()->layer(),
@@ -1255,7 +1254,7 @@ void ClientControlledShellSurface::UpdateFrame() {
if (!wide_frame_) {
update_frame = true;
wide_frame_ = std::make_unique<ash::WideFrameView>(widget_);
- ash::ImmersiveFullscreenController::EnableForWidget(widget_, false);
+ chromeos::ImmersiveFullscreenController::EnableForWidget(widget_, false);
wide_frame_->Init(immersive_fullscreen_controller_.get());
wide_frame_->header_view()->GetFrameHeader()->SetFrameTextOverride(
GetFrameView()
@@ -1269,12 +1268,12 @@ void ClientControlledShellSurface::UpdateFrame() {
UpdateCaptionButtonModel();
}
- DCHECK_EQ(ash::FrameHeader::Get(widget_),
+ DCHECK_EQ(chromeos::FrameHeader::Get(widget_),
wide_frame_->header_view()->GetFrameHeader());
} else {
if (wide_frame_) {
update_frame = true;
- ash::ImmersiveFullscreenController::EnableForWidget(widget_, false);
+ chromeos::ImmersiveFullscreenController::EnableForWidget(widget_, false);
wide_frame_.reset();
GetFrameView()->InitImmersiveFullscreenControllerForView(
immersive_fullscreen_controller_.get());
@@ -1283,7 +1282,7 @@ void ClientControlledShellSurface::UpdateFrame() {
UpdateCaptionButtonModel();
}
- DCHECK_EQ(ash::FrameHeader::Get(widget_),
+ DCHECK_EQ(chromeos::FrameHeader::Get(widget_),
GetFrameView()->GetHeaderView()->GetFrameHeader());
UpdateFrameWidth();
}
@@ -1405,6 +1404,39 @@ float ClientControlledShellSurface::GetClientToDpPendingScale() const {
return use_default_scale_cancellation_ ? 1.f : 1.f / pending_scale_;
}
+gfx::Rect
+ClientControlledShellSurface::GetClientBoundsForWindowBoundsAndWindowState(
+ const gfx::Rect& window_bounds,
+ chromeos::WindowStateType window_state) const {
+ // The client's geometry uses fullscreen in client controlled,
+ // (but the surface is placed under the frame), so just use
+ // the window bounds instead for maximixed state.
+ // Snapped window states in tablet mode do not include the caption height.
+ const bool is_snapped =
+ window_state == chromeos::WindowStateType::kLeftSnapped ||
+ window_state == chromeos::WindowStateType::kRightSnapped;
+ const bool is_maximized =
+ window_state == chromeos::WindowStateType::kMaximized;
+ const display::TabletState tablet_state =
+ chromeos::TabletState::Get()->state();
+ const bool is_tablet_mode = WMHelper::GetInstance()->InTabletMode();
+
+ if (is_maximized || (is_snapped && is_tablet_mode))
+ return window_bounds;
+
+ gfx::Rect client_bounds =
+ GetFrameView()->GetClientBoundsForWindowBounds(window_bounds);
+
+ if (is_snapped && tablet_state == display::TabletState::kExitingTabletMode) {
+ // Until the next commit, the frame view is in immersive mode, and the above
+ // GetClientBoundsForWindowBounds doesn't return bounds taking the caption
+ // height into account.
+ client_bounds.Inset(0, GetFrameView()->NonClientTopBorderPreferredHeight(),
+ 0, 0);
+ }
+ return client_bounds;
+}
+
// static
void ClientControlledShellSurface::
SetClientControlledStateDelegateFactoryForTest(
diff --git a/chromium/components/exo/client_controlled_shell_surface.h b/chromium/components/exo/client_controlled_shell_surface.h
index 008ba08d359..62f9c4afff1 100644
--- a/chromium/components/exo/client_controlled_shell_surface.h
+++ b/chromium/components/exo/client_controlled_shell_surface.h
@@ -19,7 +19,6 @@
namespace ash {
class NonClientFrameViewAsh;
-class ImmersiveFullscreenController;
class RoundedCornerDecorator;
class WideFrameView;
@@ -28,6 +27,10 @@ enum class WindowPinType;
}
} // namespace ash
+namespace chromeos {
+class ImmersiveFullscreenController;
+} // namespace chromeos
+
namespace exo {
class Surface;
class ClientControlledAcceleratorTarget;
@@ -91,8 +94,8 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
// Set the callback to run when the surface state changed.
using StateChangedCallback =
- base::RepeatingCallback<void(ash::WindowStateType old_state_type,
- ash::WindowStateType new_state_type)>;
+ base::RepeatingCallback<void(chromeos::WindowStateType old_state_type,
+ chromeos::WindowStateType new_state_type)>;
void set_state_changed_callback(
const StateChangedCallback& state_changed_callback) {
state_changed_callback_ = state_changed_callback;
@@ -100,8 +103,8 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
// Set the callback to run when the surface bounds changed.
using BoundsChangedCallback =
- base::RepeatingCallback<void(ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ base::RepeatingCallback<void(chromeos::WindowStateType current_state,
+ chromeos::WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool is_resize,
@@ -138,7 +141,7 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
// Pin/unpin the surface. Pinned surface cannot be switched to
// other windows unless its explicitly unpinned.
- void SetPinned(ash::WindowPinType type);
+ void SetPinned(chromeos::WindowPinType type);
// Sets the surface to be on top of all other windows.
void SetAlwaysOnTop(bool always_on_top);
@@ -172,16 +175,16 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
void ChangeZoomLevel(ZoomChange change);
// Sends the window state change event to client.
- void OnWindowStateChangeEvent(ash::WindowStateType old_state,
- ash::WindowStateType next_state);
+ void OnWindowStateChangeEvent(chromeos::WindowStateType old_state,
+ chromeos::WindowStateType next_state);
// Sends the window bounds change event to client. |display_id| specifies in
// which display the surface should live in. |drag_bounds_change| is
// a masked value of ash::WindowResizer::kBoundsChange_Xxx, and specifies
// how the bounds was changed. The bounds change event may also come from a
// snapped window state change |requested_state|.
- void OnBoundsChangeEvent(ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ void OnBoundsChangeEvent(chromeos::WindowStateType current_state,
+ chromeos::WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds,
int drag_bounds_change);
@@ -314,6 +317,10 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
void EnsurePendingScale();
float GetClientToDpPendingScale() const;
+ gfx::Rect GetClientBoundsForWindowBoundsAndWindowState(
+ const gfx::Rect& window_bounds,
+ chromeos::WindowStateType window_state) const;
+
GeometryChangedCallback geometry_changed_callback_;
int top_inset_height_ = 0;
@@ -340,17 +347,18 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
ash::ClientControlledState* client_controlled_state_ = nullptr;
- ash::WindowStateType pending_window_state_ = ash::WindowStateType::kNormal;
+ chromeos::WindowStateType pending_window_state_ =
+ chromeos::WindowStateType::kNormal;
bool pending_always_on_top_ = false;
SurfaceFrameType pending_frame_type_ = SurfaceFrameType::NONE;
- ash::WindowPinType current_pin_;
+ chromeos::WindowPinType current_pin_;
bool can_maximize_ = true;
- std::unique_ptr<ash::ImmersiveFullscreenController>
+ std::unique_ptr<chromeos::ImmersiveFullscreenController>
immersive_fullscreen_controller_;
std::unique_ptr<ash::WideFrameView> wide_frame_;
@@ -363,6 +371,8 @@ class ClientControlledShellSurface : public ShellSurfaceBase,
// widget is not created yet orientation lock is being set.
ash::OrientationLockType initial_orientation_lock_ =
ash::OrientationLockType::kAny;
+ // The extra title to be applied when widget is being created.
+ base::string16 initial_extra_title_ = base::string16();
bool preserve_widget_bounds_ = false;
diff --git a/chromium/components/exo/client_controlled_shell_surface_unittest.cc b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
index 79728d5ac9a..3794a5acb95 100644
--- a/chromium/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
@@ -8,11 +8,7 @@
#include "ash/frame/header_view.h"
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/frame/wide_frame_view.h"
-#include "ash/public/cpp/caption_buttons/caption_button_model.h"
-#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h"
#include "ash/public/cpp/test/shell_test_api.h"
-#include "ash/public/cpp/window_pin_type.h"
-#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/wm/drag_window_resizer.h"
@@ -33,6 +29,10 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "cc/paint/display_item_list.h"
+#include "chromeos/ui/base/window_pin_type.h"
+#include "chromeos/ui/base/window_properties.h"
+#include "chromeos/ui/frame/caption_buttons/caption_button_model.h"
+#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/pointer.h"
@@ -62,6 +62,8 @@
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_types.h"
+using chromeos::WindowStateType;
+
namespace exo {
namespace {
using ClientControlledShellSurfaceTest = test::ExoTestBase;
@@ -72,10 +74,10 @@ bool HasBackdrop() {
}
bool IsWidgetPinned(views::Widget* widget) {
- ash::WindowPinType type =
- widget->GetNativeWindow()->GetProperty(ash::kWindowPinTypeKey);
- return type == ash::WindowPinType::kPinned ||
- type == ash::WindowPinType::kTrustedPinned;
+ chromeos::WindowPinType type =
+ widget->GetNativeWindow()->GetProperty(chromeos::kWindowPinTypeKey);
+ return type == chromeos::WindowPinType::kPinned ||
+ type == chromeos::WindowPinType::kTrustedPinned;
}
int GetShadowElevation(aura::Window* window) {
@@ -121,16 +123,16 @@ TEST_F(ClientControlledShellSurfaceTest, SetPinned) {
auto shell_surface(
exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
- shell_surface->SetPinned(ash::WindowPinType::kTrustedPinned);
+ shell_surface->SetPinned(chromeos::WindowPinType::kTrustedPinned);
EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(ash::WindowPinType::kNone);
+ shell_surface->SetPinned(chromeos::WindowPinType::kNone);
EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(ash::WindowPinType::kPinned);
+ shell_surface->SetPinned(chromeos::WindowPinType::kPinned);
EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
- shell_surface->SetPinned(ash::WindowPinType::kNone);
+ shell_surface->SetPinned(chromeos::WindowPinType::kNone);
EXPECT_FALSE(IsWidgetPinned(shell_surface->GetWidget()));
}
@@ -1061,7 +1063,7 @@ TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) {
ash::WindowState* window_state1 = ash::WindowState::Get(window1);
ash::ClientControlledState* state1 = static_cast<ash::ClientControlledState*>(
ash::WindowState::TestApi::GetStateImpl(window_state1));
- EXPECT_EQ(window_state1->GetStateType(), ash::WindowStateType::kMaximized);
+ EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kMaximized);
// Snap window to left.
ash::SplitViewController* split_view_controller =
@@ -1071,7 +1073,7 @@ TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) {
window1->SetBounds(split_view_controller->GetSnappedWindowBoundsInScreen(
ash::SplitViewController::LEFT, window1));
state1->set_bounds_locally(false);
- EXPECT_EQ(window_state1->GetStateType(), ash::WindowStateType::kLeftSnapped);
+ EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
EXPECT_EQ(shell_surface1->GetWidget()->GetWindowBoundsInScreen(),
split_view_controller->GetSnappedWindowBoundsInScreen(
ash::SplitViewController::LEFT,
@@ -1085,7 +1087,7 @@ TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) {
window1->SetBounds(split_view_controller->GetSnappedWindowBoundsInScreen(
ash::SplitViewController::RIGHT, window1));
state1->set_bounds_locally(false);
- EXPECT_EQ(window_state1->GetStateType(), ash::WindowStateType::kRightSnapped);
+ EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kRightSnapped);
EXPECT_EQ(shell_surface1->GetWidget()->GetWindowBoundsInScreen(),
split_view_controller->GetSnappedWindowBoundsInScreen(
ash::SplitViewController::RIGHT,
@@ -1288,7 +1290,7 @@ TEST_F(ClientControlledShellSurfaceDragTest, DragWindowFromTopInTabletMode) {
shell->overview_controller()->EndOverview();
SendGestureEvents(window, gfx::Point(0, 210));
EXPECT_EQ(ash::WindowState::Get(window)->GetStateType(),
- ash::WindowStateType::kLeftSnapped);
+ WindowStateType::kLeftSnapped);
}
namespace {
@@ -1319,8 +1321,8 @@ class ClientControlledShellSurfaceDisplayTest : public test::ExoTestBase {
}
void OnBoundsChangeEvent(ClientControlledShellSurface* shell_surface,
- ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ WindowStateType current_state,
+ WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool is_resize,
@@ -1501,7 +1503,7 @@ TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) {
ash::NonClientFrameViewAsh* frame_view =
static_cast<ash::NonClientFrameViewAsh*>(
shell_surface->GetWidget()->non_client_view()->frame_view());
- ash::FrameCaptionButtonContainerView* container =
+ chromeos::FrameCaptionButtonContainerView* container =
static_cast<ash::HeaderView*>(frame_view->GetHeaderView())
->caption_button_container();
@@ -1509,7 +1511,7 @@ TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) {
for (auto visible : kAllButtons) {
uint32_t visible_buttons = 1 << visible;
shell_surface->SetFrameButtons(visible_buttons, 0);
- const ash::CaptionButtonModel* model = container->model();
+ const chromeos::CaptionButtonModel* model = container->model();
for (auto not_visible : kAllButtons) {
if (not_visible != visible)
EXPECT_FALSE(model->IsVisible(not_visible));
@@ -1522,7 +1524,7 @@ TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) {
for (auto enabled : kAllButtons) {
uint32_t enabled_buttons = 1 << enabled;
shell_surface->SetFrameButtons(kAllButtonMask, enabled_buttons);
- const ash::CaptionButtonModel* model = container->model();
+ const chromeos::CaptionButtonModel* model = container->model();
for (auto not_enabled : kAllButtons) {
if (not_enabled != enabled)
EXPECT_FALSE(model->IsEnabled(not_enabled));
@@ -1937,8 +1939,8 @@ TEST_F(ClientControlledShellSurfaceTest, AdjustBoundsLocally) {
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
gfx::Rect requested_bounds;
shell_surface->set_bounds_changed_callback(base::BindRepeating(
- [](gfx::Rect* dst, ash::WindowStateType current_state,
- ash::WindowStateType requested_state, int64_t display_id,
+ [](gfx::Rect* dst, WindowStateType current_state,
+ WindowStateType requested_state, int64_t display_id,
const gfx::Rect& bounds, bool is_resize,
int bounds_change) { *dst = bounds; },
base::Unretained(&requested_bounds)));
@@ -1979,7 +1981,7 @@ TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) {
ash::WMEvent event(ash::WM_EVENT_SNAP_LEFT);
window_state->OnWMEvent(&event);
- EXPECT_EQ(window_state->GetStateType(), ash::WindowStateType::kLeftSnapped);
+ EXPECT_EQ(window_state->GetStateType(), WindowStateType::kLeftSnapped);
ash::NonClientFrameViewAsh* frame_view =
static_cast<ash::NonClientFrameViewAsh*>(
@@ -2040,8 +2042,8 @@ TEST_F(ClientControlledShellSurfaceDisplayTest,
ash::WindowState::Get(shell_surface->GetWidget()->GetNativeWindow());
int64_t display_id = window_state->GetDisplay().id();
- shell_surface->OnBoundsChangeEvent(ash::WindowStateType::kNormal,
- ash::WindowStateType::kNormal, display_id,
+ shell_surface->OnBoundsChangeEvent(WindowStateType::kNormal,
+ WindowStateType::kNormal, display_id,
gfx::Rect(10, 10, 100, 100), 0);
ASSERT_EQ(1, bounds_change_count());
@@ -2051,14 +2053,14 @@ TEST_F(ClientControlledShellSurfaceDisplayTest,
surface->Commit();
EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
- shell_surface->OnBoundsChangeEvent(ash::WindowStateType::kMinimized,
- ash::WindowStateType::kMinimized,
- display_id, gfx::Rect(0, 0, 100, 100), 0);
+ shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
+ WindowStateType::kMinimized, display_id,
+ gfx::Rect(0, 0, 100, 100), 0);
ASSERT_EQ(1, bounds_change_count());
// Send bounds change when exiting minmized.
- shell_surface->OnBoundsChangeEvent(ash::WindowStateType::kMinimized,
- ash::WindowStateType::kNormal, display_id,
+ shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
+ WindowStateType::kNormal, display_id,
gfx::Rect(0, 0, 100, 100), 0);
ASSERT_EQ(2, bounds_change_count());
@@ -2068,9 +2070,9 @@ TEST_F(ClientControlledShellSurfaceDisplayTest,
shell_surface->GetWidget()->non_client_view()->frame_view());
surface->SetFrame(SurfaceFrameType::NORMAL);
surface->Commit();
- shell_surface->OnBoundsChangeEvent(ash::WindowStateType::kMinimized,
- ash::WindowStateType::kRightSnapped,
- display_id, gfx::Rect(0, 0, 100, 100), 0);
+ shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
+ WindowStateType::kRightSnapped, display_id,
+ gfx::Rect(0, 0, 100, 100), 0);
EXPECT_EQ(3, bounds_change_count());
EXPECT_EQ(
frame_view->GetClientBoundsForWindowBounds(gfx::Rect(0, 0, 100, 100)),
@@ -2079,9 +2081,9 @@ TEST_F(ClientControlledShellSurfaceDisplayTest,
// Snapped, in tablet mode.
EnableTabletMode(true);
- shell_surface->OnBoundsChangeEvent(ash::WindowStateType::kMinimized,
- ash::WindowStateType::kRightSnapped,
- display_id, gfx::Rect(0, 0, 100, 100), 0);
+ shell_surface->OnBoundsChangeEvent(WindowStateType::kMinimized,
+ WindowStateType::kRightSnapped, display_id,
+ gfx::Rect(0, 0, 100, 100), 0);
EXPECT_EQ(4, bounds_change_count());
EXPECT_EQ(gfx::Rect(0, 0, 100, 100), requested_bounds().back());
}
@@ -2253,7 +2255,7 @@ TEST_F(ClientControlledShellSurfaceTest, DoNotReplayWindowStateRequest) {
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
shell_surface->set_state_changed_callback(
- base::BindRepeating([](ash::WindowStateType, ash::WindowStateType) {
+ base::BindRepeating([](WindowStateType, WindowStateType) {
// This callback must not be called when a widget is created.
EXPECT_TRUE(false);
}));
@@ -2424,8 +2426,8 @@ class ClientControlledShellSurfaceScaleTest : public test::ExoTestBase {
}
void OnBoundsChangeEvent(ClientControlledShellSurface* shell_surface,
- ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ WindowStateType current_state,
+ WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool is_resize,
@@ -2611,4 +2613,72 @@ TEST_F(ClientControlledShellSurfaceScaleTest,
EXPECT_GE(bounds_change_count(), 1);
}
+TEST_F(ClientControlledShellSurfaceTest, SnappedClientBounds) {
+ UpdateDisplay("800x600");
+
+ gfx::Size buffer_size(256, 256);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+
+ std::unique_ptr<Surface> surface(new Surface);
+ auto shell_surface =
+ exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
+ // Clear insets so that it won't affects the bounds.
+ shell_surface->SetSystemUiVisibility(true);
+ int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+ ash::Shell::Get()->display_manager()->UpdateWorkAreaOfDisplay(
+ display_id, gfx::Insets(0, 0, 0, 0));
+
+ gfx::Rect requested_bounds;
+ shell_surface->set_bounds_changed_callback(base::BindRepeating(
+ [](gfx::Rect* dst, WindowStateType current_state,
+ WindowStateType requested_state, int64_t display_id,
+ const gfx::Rect& bounds, bool is_resize,
+ int bounds_change) { *dst = bounds; },
+ base::Unretained(&requested_bounds)));
+
+ surface->Attach(buffer.get());
+ surface->Commit();
+ views::Widget* widget = shell_surface->GetWidget();
+ aura::Window* window = widget->GetNativeWindow();
+
+ // Normal state -> Snap.
+ shell_surface->SetGeometry(gfx::Rect(50, 100, 200, 300));
+ surface->SetFrame(SurfaceFrameType::NORMAL);
+ surface->Commit();
+ EXPECT_EQ(gfx::Rect(50, 68, 200, 332), widget->GetWindowBoundsInScreen());
+
+ ash::WMEvent event(ash::WM_EVENT_SNAP_LEFT);
+ ash::WindowState::Get(window)->OnWMEvent(&event);
+ EXPECT_EQ(gfx::Rect(0, 32, 400, 568), requested_bounds);
+
+ // Maximized -> Snap.
+ shell_surface->SetMaximized();
+ shell_surface->SetGeometry(gfx::Rect(0, 0, 800, 568));
+ surface->Commit();
+ EXPECT_TRUE(widget->IsMaximized());
+
+ ash::WindowState::Get(window)->OnWMEvent(&event);
+ EXPECT_EQ(gfx::Rect(0, 32, 400, 568), requested_bounds);
+ shell_surface->SetSnappedToLeft();
+ shell_surface->SetGeometry(gfx::Rect(0, 0, 400, 568));
+ surface->Commit();
+
+ // Clamshell mode -> tablet mode. The bounds start from top-left corner.
+ EnableTabletMode(true);
+ EXPECT_EQ(gfx::Rect(0, 0, 396, 564), requested_bounds);
+ shell_surface->SetGeometry(gfx::Rect(0, 0, 396, 568));
+ surface->SetFrame(SurfaceFrameType::AUTOHIDE);
+ surface->Commit();
+
+ // Tablet mode -> clamshell mode. Top caption height should be reserved.
+ EnableTabletMode(false);
+ EXPECT_EQ(gfx::Rect(0, 32, 396, 568), requested_bounds);
+
+ // Clean up state.
+ shell_surface->SetSnappedToLeft();
+ surface->Commit();
+}
+
} // namespace exo
diff --git a/chromium/components/exo/data_device.cc b/chromium/components/exo/data_device.cc
index 62ed63f394b..1ac9530fc03 100644
--- a/chromium/components/exo/data_device.cc
+++ b/chromium/components/exo/data_device.cc
@@ -9,6 +9,7 @@
#include "components/exo/data_offer.h"
#include "components/exo/data_source.h"
#include "components/exo/seat.h"
+#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_monitor.h"
@@ -66,7 +67,7 @@ void DataDevice::StartDrag(DataSource* source,
Surface* origin,
Surface* icon,
ui::mojom::DragEventSource event_source) {
- seat_->StartDrag(source, origin, icon, event_source);
+ seat_->StartDrag(file_helper_, source, origin, icon, event_source);
}
void DataDevice::SetSelection(DataSource* source) {
@@ -91,9 +92,10 @@ void DataDevice::OnDragEntered(const ui::DropTargetEvent& event) {
dnd_actions.insert(DndAction::kAsk);
}
- data_offer_ = std::make_unique<ScopedDataOffer>(
- delegate_->OnDataOffer(DataOffer::DRAG_DROP), this);
- data_offer_->get()->SetDropData(file_helper_, event.data());
+ data_offer_ =
+ std::make_unique<ScopedDataOffer>(delegate_->OnDataOffer(), this);
+ data_offer_->get()->SetDropData(file_helper_, surface->window(),
+ event.data());
data_offer_->get()->SetSourceActions(dnd_actions);
data_offer_->get()->SetActions(base::flat_set<DndAction>(), DndAction::kAsk);
delegate_->OnEnter(surface, event.location_f(), *data_offer_->get());
@@ -201,7 +203,7 @@ Surface* DataDevice::GetEffectiveTargetForEvent(
}
void DataDevice::SetSelectionToCurrentClipboardData() {
- DataOffer* data_offer = delegate_->OnDataOffer(DataOffer::COPY_PASTE);
+ DataOffer* data_offer = delegate_->OnDataOffer();
data_offer->SetClipboardData(file_helper_,
*ui::Clipboard::GetForCurrentThread());
delegate_->OnSelection(*data_offer);
diff --git a/chromium/components/exo/data_device_delegate.h b/chromium/components/exo/data_device_delegate.h
index f6bb517c13e..6120ff1f783 100644
--- a/chromium/components/exo/data_device_delegate.h
+++ b/chromium/components/exo/data_device_delegate.h
@@ -34,7 +34,7 @@ class DataDeviceDelegate {
// Called when DataOffer object is delivered from a client. DataDeviceDelegate
// has responsibility to release the returned DataOffer object.
- virtual DataOffer* OnDataOffer(DataOffer::Purpose purpose) = 0;
+ virtual DataOffer* OnDataOffer() = 0;
// Called during a drag operation when pointer enters |surface|.
virtual void OnEnter(Surface* surface,
diff --git a/chromium/components/exo/data_device_unittest.cc b/chromium/components/exo/data_device_unittest.cc
index 189a6d9f6de..ce67ef6d271 100644
--- a/chromium/components/exo/data_device_unittest.cc
+++ b/chromium/components/exo/data_device_unittest.cc
@@ -18,6 +18,7 @@
#include "components/exo/seat.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h"
#include "ui/aura/client/focus_client.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
@@ -74,9 +75,9 @@ class TestDataDeviceDelegate : public DataDeviceDelegate {
void OnDataDeviceDestroying(DataDevice* data_device) override {
events_.push_back(DataEvent::kDestroy);
}
- DataOffer* OnDataOffer(DataOffer::Purpose purpose) override {
+ DataOffer* OnDataOffer() override {
events_.push_back(DataEvent::kOffer);
- data_offer_.reset(new DataOffer(new TestDataOfferDelegate, purpose));
+ data_offer_.reset(new DataOffer(new TestDataOfferDelegate));
return data_offer_.get();
}
void OnEnter(Surface* surface,
@@ -107,26 +108,6 @@ class TestDataDeviceDelegate : public DataDeviceDelegate {
DISALLOW_COPY_AND_ASSIGN(TestDataDeviceDelegate);
};
-class TestFileHelper : public FileHelper {
- public:
- TestFileHelper() = default;
-
- // Overridden from FileHelper:
- std::string GetMimeTypeForUriList() const override { return ""; }
- bool GetUrlFromPath(const std::string& app_id,
- const base::FilePath& path,
- GURL* out) override {
- return true;
- }
- bool HasUrlsInPickle(const base::Pickle& pickle) override { return false; }
- void GetUrlsFromPickle(const std::string& app_id,
- const base::Pickle& pickle,
- UrlsFromPickleCallback callback) override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestFileHelper);
-};
-
class TestSeat : public Seat {
public:
TestSeat() {}
diff --git a/chromium/components/exo/data_offer.cc b/chromium/components/exo/data_offer.cc
index a2fc40367d9..19a4e629c4b 100644
--- a/chromium/components/exo/data_offer.cc
+++ b/chromium/components/exo/data_offer.cc
@@ -13,6 +13,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/pickle.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
@@ -20,13 +21,14 @@
#include "components/exo/data_offer_delegate.h"
#include "components/exo/data_offer_observer.h"
#include "components/exo/file_helper.h"
+#include "net/base/filename_util.h"
#include "third_party/skia/include/core/SkEncodedImageFormat.h"
#include "third_party/skia/include/core/SkImageEncoder.h"
#include "third_party/skia/include/core/SkStream.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
-#include "ui/base/clipboard/clipboard_data_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "url/gurl.h"
@@ -39,33 +41,10 @@ constexpr char kTextHtmlMimeTypeUtf8[] = "text/html;charset=utf-8";
constexpr char kTextHtmlMimeTypeUtf16[] = "text/html;charset=utf-16";
constexpr char kTextRtfMimeType[] = "text/rtf";
constexpr char kImagePngMimeType[] = "image/png";
-constexpr char kUriListSeparator[] = "\r\n";
constexpr char kUTF8[] = "utf8";
constexpr char kUTF16[] = "utf16";
-class RefCountedString16 : public base::RefCountedMemory {
- public:
- static scoped_refptr<RefCountedString16> TakeString(
- base::string16&& to_destroy) {
- scoped_refptr<RefCountedString16> self(new RefCountedString16);
- to_destroy.swap(self->data_);
- return self;
- }
-
- // Overridden from base::RefCountedMemory:
- const unsigned char* front() const override {
- return reinterpret_cast<const unsigned char*>(data_.data());
- }
- size_t size() const override { return data_.size() * sizeof(base::char16); }
-
- protected:
- ~RefCountedString16() override {}
-
- private:
- base::string16 data_;
-};
-
void WriteFileDescriptorOnWorkerThread(
base::ScopedFD fd,
scoped_refptr<base::RefCountedMemory> memory) {
@@ -83,27 +62,6 @@ void WriteFileDescriptor(base::ScopedFD fd,
std::move(memory)));
}
-// Gets a comma-separated list of urls extracted from |data|->file.
-bool GetUrlListFromDataFile(FileHelper* file_helper,
- const ui::OSExchangeData& data,
- base::string16* url_list_string) {
- if (!data.HasFile())
- return false;
- std::vector<ui::FileInfo> files;
- if (data.GetFilenames(&files)) {
- for (const auto& info : files) {
- GURL url;
- // TODO(niwa): Need to fill the correct app_id.
- if (file_helper->GetUrlFromPath(/* app_id */ "", info.path, &url)) {
- if (!url_list_string->empty())
- *url_list_string += base::UTF8ToUTF16(kUriListSeparator);
- *url_list_string += base::UTF8ToUTF16(url.spec());
- }
- }
- }
- return !url_list_string->empty();
-}
-
ui::ClipboardFormatType GetClipboardFormatType() {
static const char kFormatString[] = "chromium/x-file-system-files";
static base::NoDestructor<ui::ClipboardFormatType> format_type(
@@ -121,57 +79,77 @@ scoped_refptr<base::RefCountedString> EncodeAsRefCountedString(
return base::RefCountedString::TakeString(&encoded_text);
}
-void ReadTextFromClipboard(const std::string& charset, base::ScopedFD fd) {
+DataOffer::AsyncSendDataCallback AsyncEncodeAsRefCountedString(
+ const base::string16& text,
+ const std::string& charset) {
+ return base::BindOnce(
+ [](const base::string16& text, const std::string& charset,
+ DataOffer::SendDataCallback callback) {
+ std::move(callback).Run(EncodeAsRefCountedString(text, charset));
+ },
+ text, charset);
+}
+
+void ReadTextFromClipboard(const std::string& charset,
+ DataOffer::SendDataCallback callback) {
base::string16 text;
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kGuestOs);
ui::Clipboard::GetForCurrentThread()->ReadText(
ui::ClipboardBuffer::kCopyPaste, &data_dst, &text);
- WriteFileDescriptor(std::move(fd), EncodeAsRefCountedString(text, charset));
+ std::move(callback).Run(EncodeAsRefCountedString(text, charset));
}
-void ReadHTMLFromClipboard(const std::string& charset, base::ScopedFD fd) {
+void ReadHTMLFromClipboard(const std::string& charset,
+ DataOffer::SendDataCallback callback) {
base::string16 text;
std::string url;
uint32_t start, end;
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kGuestOs);
ui::Clipboard::GetForCurrentThread()->ReadHTML(
ui::ClipboardBuffer::kCopyPaste, &data_dst, &text, &url, &start, &end);
- WriteFileDescriptor(std::move(fd), EncodeAsRefCountedString(text, charset));
+ std::move(callback).Run(EncodeAsRefCountedString(text, charset));
}
-void ReadRTFFromClipboard(base::ScopedFD fd) {
+void ReadRTFFromClipboard(DataOffer::SendDataCallback callback) {
std::string text;
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kGuestOs);
ui::Clipboard::GetForCurrentThread()->ReadRTF(ui::ClipboardBuffer::kCopyPaste,
&data_dst, &text);
- WriteFileDescriptor(std::move(fd), base::RefCountedString::TakeString(&text));
+ std::move(callback).Run(base::RefCountedString::TakeString(&text));
}
-void SendAsPNGOnWorkerThread(base::ScopedFD fd, const SkBitmap& sk_bitmap) {
+scoped_refptr<base::RefCountedMemory> EncodePNGOnWorkerThread(
+ const SkBitmap& sk_bitmap) {
SkDynamicMemoryWStream data_stream;
if (SkEncodeImage(&data_stream, sk_bitmap.pixmap(),
SkEncodedImageFormat::kPNG, 100)) {
std::vector<uint8_t> data(data_stream.bytesWritten());
data_stream.copyToAndReset(data.data());
- WriteFileDescriptorOnWorkerThread(std::move(fd),
- base::RefCountedBytes::TakeVector(&data));
+ return base::RefCountedBytes::TakeVector(&data);
} else {
LOG(ERROR) << "Couldn't encode image as PNG";
+ return nullptr;
}
}
-void OnReceivePNGFromClipboard(base::ScopedFD fd, const SkBitmap& sk_bitmap) {
- base::ThreadPool::PostTask(
+void OnReceivePNGFromClipboard(DataOffer::SendDataCallback callback,
+ const SkBitmap& sk_bitmap) {
+ base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
- base::BindOnce(&SendAsPNGOnWorkerThread, std::move(fd),
- std::move(sk_bitmap)));
+ base::BindOnce(&EncodePNGOnWorkerThread, std::move(sk_bitmap)),
+ base::BindOnce(
+ [](DataOffer::SendDataCallback callback,
+ scoped_refptr<base::RefCountedMemory> data) {
+ std::move(callback).Run(data);
+ },
+ std::move(callback)));
}
-void ReadPNGFromClipboard(base::ScopedFD fd) {
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+void ReadPNGFromClipboard(DataOffer::SendDataCallback callback) {
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kGuestOs);
ui::Clipboard::GetForCurrentThread()->ReadImage(
ui::ClipboardBuffer::kCopyPaste, &data_dst,
- base::BindOnce(&OnReceivePNGFromClipboard, std::move(fd)));
+ base::BindOnce(&OnReceivePNGFromClipboard, std::move(callback)));
}
} // namespace
@@ -186,11 +164,8 @@ ScopedDataOffer::~ScopedDataOffer() {
data_offer_->RemoveObserver(observer_);
}
-DataOffer::DataOffer(DataOfferDelegate* delegate, Purpose purpose)
- : delegate_(delegate),
- dnd_action_(DndAction::kNone),
- purpose_(purpose),
- finished_(false) {}
+DataOffer::DataOffer(DataOfferDelegate* delegate)
+ : delegate_(delegate), dnd_action_(DndAction::kNone), finished_(false) {}
DataOffer::~DataOffer() {
delegate_->OnDataOfferDestroying(this);
@@ -210,28 +185,31 @@ void DataOffer::RemoveObserver(DataOfferObserver* observer) {
void DataOffer::Accept(const std::string* mime_type) {}
void DataOffer::Receive(const std::string& mime_type, base::ScopedFD fd) {
- if (purpose_ == Purpose::COPY_PASTE) {
- const auto data_it = data_callbacks_.find(mime_type);
- if (data_it == data_callbacks_.end()) {
- DLOG(ERROR) << "Unexpected mime type is requested";
- return;
- }
- data_it->second.Run(std::move(fd));
- } else if (purpose_ == Purpose::DRAG_DROP) {
- const auto data_it = data_.find(mime_type);
- if (data_it == data_.end()) {
- DLOG(ERROR) << "Unexpected mime type is requested";
- return;
- }
- if (data_it->second) {
- WriteFileDescriptor(std::move(fd), data_it->second);
- } else {
- // Data bytes for this mime type are being processed currently.
- pending_receive_requests_.push_back(
- std::make_pair(mime_type, std::move(fd)));
- }
+ const auto callbacks_it = data_callbacks_.find(mime_type);
+ if (callbacks_it != data_callbacks_.end()) {
+ // Set cache with empty data to indicate in process.
+ DCHECK(data_cache_.count(mime_type) == 0);
+ data_cache_.emplace(mime_type, nullptr);
+ std::move(callbacks_it->second)
+ .Run(base::BindOnce(&DataOffer::OnDataReady,
+ weak_ptr_factory_.GetWeakPtr(), mime_type,
+ base::Passed(std::move(fd))));
+ data_callbacks_.erase(callbacks_it);
+ return;
+ }
+
+ const auto cache_it = data_cache_.find(mime_type);
+ if (cache_it == data_cache_.end()) {
+ DLOG(ERROR) << "Unexpected mime type is requested " << mime_type;
+ return;
+ }
+
+ if (cache_it->second) {
+ WriteFileDescriptor(std::move(fd), cache_it->second);
} else {
- NOTREACHED();
+ // Data bytes for this mime type are being processed currently.
+ pending_receive_requests_.push_back(
+ std::make_pair(mime_type, std::move(fd)));
}
}
@@ -252,29 +230,31 @@ void DataOffer::SetSourceActions(
}
void DataOffer::SetDropData(FileHelper* file_helper,
+ aura::Window* target,
const ui::OSExchangeData& data) {
- DCHECK_EQ(0u, data_.size());
-
- const std::string uri_list_mime_type = file_helper->GetMimeTypeForUriList();
- base::string16 url_list_string;
- if (GetUrlListFromDataFile(file_helper, data, &url_list_string)) {
- data_.emplace(uri_list_mime_type,
- RefCountedString16::TakeString(std::move(url_list_string)));
- delegate_->OnOffer(uri_list_mime_type);
- return;
+ DCHECK_EQ(0u, data_callbacks_.size());
+
+ const std::string uri_list_mime_type =
+ file_helper->GetMimeTypeForUriList(target);
+ if (data.HasFile()) {
+ std::vector<ui::FileInfo> files;
+ if (data.GetFilenames(&files)) {
+ data_callbacks_.emplace(uri_list_mime_type,
+ base::BindOnce(&FileHelper::SendFileInfo,
+ base::Unretained(file_helper),
+ target, std::move(files)));
+ delegate_->OnOffer(uri_list_mime_type);
+ return;
+ }
}
base::Pickle pickle;
if (data.GetPickledData(GetClipboardFormatType(), &pickle) &&
file_helper->HasUrlsInPickle(pickle)) {
- // Set nullptr as a temporary value for the mime type.
- // The value will be overriden in the callback below.
- data_.emplace(uri_list_mime_type, nullptr);
- // TODO(niwa): Need to fill the correct app_id.
- file_helper->GetUrlsFromPickle(
- /* app_id */ "", pickle,
- base::BindOnce(&DataOffer::OnPickledUrlsResolved,
- weak_ptr_factory_.GetWeakPtr(), uri_list_mime_type));
+ data_callbacks_.emplace(
+ uri_list_mime_type,
+ base::BindOnce(&FileHelper::SendPickle, base::Unretained(file_helper),
+ target, pickle));
delegate_->OnOffer(uri_list_mime_type);
return;
}
@@ -282,20 +262,20 @@ void DataOffer::SetDropData(FileHelper* file_helper,
base::string16 string_content;
if (data.HasString() && data.GetString(&string_content)) {
const std::string utf8_mime_type = std::string(ui::kMimeTypeTextUtf8);
- data_.emplace(utf8_mime_type,
- EncodeAsRefCountedString(string_content, kUTF8));
+ data_callbacks_.emplace(
+ utf8_mime_type, AsyncEncodeAsRefCountedString(string_content, kUTF8));
delegate_->OnOffer(utf8_mime_type);
const std::string utf16_mime_type = std::string(kTextMimeTypeUtf16);
- data_.emplace(utf16_mime_type,
- EncodeAsRefCountedString(string_content, kUTF16));
+ data_callbacks_.emplace(
+ utf16_mime_type, AsyncEncodeAsRefCountedString(string_content, kUTF16));
delegate_->OnOffer(utf16_mime_type);
const std::string text_plain_mime_type = std::string(ui::kMimeTypeText);
// The MIME type standard says that new text/ subtypes should default to a
// UTF-8 encoding, but that old ones, including text/plain, keep ASCII as
// the default. Nonetheless, we use UTF8 here because it is a superset of
// ASCII and the defacto standard text encoding.
- data_.emplace(text_plain_mime_type,
- EncodeAsRefCountedString(string_content, kUTF8));
+ data_callbacks_.emplace(text_plain_mime_type, AsyncEncodeAsRefCountedString(
+ string_content, kUTF8));
delegate_->OnOffer(text_plain_mime_type);
}
@@ -303,22 +283,22 @@ void DataOffer::SetDropData(FileHelper* file_helper,
GURL url_content;
if (data.HasHtml() && data.GetHtml(&html_content, &url_content)) {
const std::string utf8_html_mime_type = std::string(kTextHtmlMimeTypeUtf8);
- data_.emplace(utf8_html_mime_type,
- EncodeAsRefCountedString(html_content, kUTF8));
+ data_callbacks_.emplace(utf8_html_mime_type,
+ AsyncEncodeAsRefCountedString(html_content, kUTF8));
delegate_->OnOffer(utf8_html_mime_type);
const std::string utf16_html_mime_type =
std::string(kTextHtmlMimeTypeUtf16);
- data_.emplace(utf16_html_mime_type,
- EncodeAsRefCountedString(html_content, kUTF16));
+ data_callbacks_.emplace(utf16_html_mime_type, AsyncEncodeAsRefCountedString(
+ html_content, kUTF16));
delegate_->OnOffer(utf16_html_mime_type);
}
}
void DataOffer::SetClipboardData(FileHelper* file_helper,
const ui::Clipboard& data) {
- DCHECK_EQ(0u, data_.size());
- const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+ DCHECK_EQ(0u, data_callbacks_.size());
+ const ui::DataTransferEndpoint data_dst(ui::EndpointType::kGuestOs);
if (data.IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(),
ui::ClipboardBuffer::kCopyPaste, &data_dst)) {
auto utf8_callback =
@@ -331,57 +311,50 @@ void DataOffer::SetClipboardData(FileHelper* file_helper,
delegate_->OnOffer(std::string(kTextMimeTypeUtf16));
data_callbacks_.emplace(
std::string(kTextMimeTypeUtf16),
- base::BindRepeating(&ReadTextFromClipboard, std::string(kUTF16)));
+ base::BindOnce(&ReadTextFromClipboard, std::string(kUTF16)));
}
if (data.IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(),
ui::ClipboardBuffer::kCopyPaste, &data_dst)) {
delegate_->OnOffer(std::string(kTextHtmlMimeTypeUtf8));
data_callbacks_.emplace(
std::string(kTextHtmlMimeTypeUtf8),
- base::BindRepeating(&ReadHTMLFromClipboard, std::string(kUTF8)));
+ base::BindOnce(&ReadHTMLFromClipboard, std::string(kUTF8)));
delegate_->OnOffer(std::string(kTextHtmlMimeTypeUtf16));
data_callbacks_.emplace(
std::string(kTextHtmlMimeTypeUtf16),
- base::BindRepeating(&ReadHTMLFromClipboard, std::string(kUTF16)));
+ base::BindOnce(&ReadHTMLFromClipboard, std::string(kUTF16)));
}
if (data.IsFormatAvailable(ui::ClipboardFormatType::GetRtfType(),
ui::ClipboardBuffer::kCopyPaste, &data_dst)) {
delegate_->OnOffer(std::string(kTextRtfMimeType));
data_callbacks_.emplace(std::string(kTextRtfMimeType),
- base::BindRepeating(&ReadRTFFromClipboard));
+ base::BindOnce(&ReadRTFFromClipboard));
}
if (data.IsFormatAvailable(ui::ClipboardFormatType::GetBitmapType(),
ui::ClipboardBuffer::kCopyPaste, &data_dst)) {
delegate_->OnOffer(std::string(kImagePngMimeType));
data_callbacks_.emplace(std::string(kImagePngMimeType),
- base::BindRepeating(&ReadPNGFromClipboard));
+ base::BindOnce(&ReadPNGFromClipboard));
}
}
-void DataOffer::OnPickledUrlsResolved(const std::string& mime_type,
- const std::vector<GURL>& urls) {
- const auto data_it = data_.find(mime_type);
- DCHECK(data_it != data_.end());
- DCHECK(!data_it->second); // nullptr should be set as a temporary value.
- data_.erase(data_it);
-
- base::string16 url_list_string;
- for (const GURL& url : urls) {
- if (!url.is_valid())
- continue;
- if (!url_list_string.empty())
- url_list_string += base::UTF8ToUTF16(kUriListSeparator);
- url_list_string += base::UTF8ToUTF16(url.spec());
- }
- const auto ref_counted_memory =
- RefCountedString16::TakeString(std::move(url_list_string));
- data_.emplace(mime_type, ref_counted_memory);
+void DataOffer::OnDataReady(const std::string& mime_type,
+ base::ScopedFD fd,
+ scoped_refptr<base::RefCountedMemory> data) {
+ // Update cache from nullptr to data.
+ const auto cache_it = data_cache_.find(mime_type);
+ DCHECK(cache_it != data_cache_.end());
+ DCHECK(!cache_it->second);
+ data_cache_.erase(cache_it);
+ data_cache_.emplace(mime_type, data);
+
+ WriteFileDescriptor(std::move(fd), data);
// Process pending receive requests for this mime type, if there are any.
auto it = pending_receive_requests_.begin();
while (it != pending_receive_requests_.end()) {
if (it->first == mime_type) {
- WriteFileDescriptor(std::move(it->second), ref_counted_memory);
+ WriteFileDescriptor(std::move(it->second), data);
it = pending_receive_requests_.erase(it);
} else {
++it;
diff --git a/chromium/components/exo/data_offer.h b/chromium/components/exo/data_offer.h
index 3c540f35583..0725741f63f 100644
--- a/chromium/components/exo/data_offer.h
+++ b/chromium/components/exo/data_offer.h
@@ -18,7 +18,12 @@
#include "ui/base/class_property.h"
#include "url/gurl.h"
+namespace aura {
+class Window;
+}
+
namespace base {
+class Pickle;
class RefCountedMemory;
}
@@ -37,12 +42,11 @@ enum class DndAction;
// Object representing transferred data offered to a client.
class DataOffer final : public ui::PropertyHandler {
public:
- enum Purpose {
- COPY_PASTE,
- DRAG_DROP,
- };
+ using SendDataCallback =
+ base::OnceCallback<void(scoped_refptr<base::RefCountedMemory>)>;
+ using AsyncSendDataCallback = base::OnceCallback<void(SendDataCallback)>;
- DataOffer(DataOfferDelegate* delegate, Purpose purpose);
+ DataOffer(DataOfferDelegate* delegate);
~DataOffer() override;
void AddObserver(DataOfferObserver* observer);
@@ -66,12 +70,15 @@ class DataOffer final : public ui::PropertyHandler {
// Sets the dropped data from |data| to the DataOffer object. |file_helper|
// will be used to convert paths to handle mount points which is mounted in
- // the mount point namespace of clinet process.
- // While this function immediately calls DataOfferDelegate::OnOffer inside it
- // with found mime types, dropped data bytes may be populated asynchronously
- // after this function call.
- // (e.g. Asynchronous lookup is required for resolving file system urls.)
- void SetDropData(FileHelper* file_helper, const ui::OSExchangeData& data);
+ // the mount point namespace of clinet process. |target| is the drop target
+ // window and can be used to apply the target specitic logic to interpret the
+ // data. While this function immediately calls DataOfferDelegate::OnOffer
+ // inside it with found mime types, dropped data bytes may be populated
+ // asynchronously after this function call. (e.g. Asynchronous lookup is
+ // required for resolving file system urls.)
+ void SetDropData(FileHelper* file_helper,
+ aura::Window* target,
+ const ui::OSExchangeData& data);
// Sets the clipboard data from |data| to the DataOffer object.
void SetClipboardData(FileHelper* file_helper, const ui::Clipboard& data);
@@ -84,28 +91,35 @@ class DataOffer final : public ui::PropertyHandler {
bool finished() const { return finished_; }
private:
- void OnPickledUrlsResolved(const std::string& uri_list_mime_type,
+ void OnDataReady(const std::string& mime_type,
+ base::ScopedFD fd,
+ scoped_refptr<base::RefCountedMemory> data);
+ void GetUrlsFromPickle(FileHelper* file_helper,
+ aura::Window* target,
+ const base::Pickle& pickle,
+ SendDataCallback callback);
+ void OnPickledUrlsResolved(SendDataCallback callback,
const std::vector<GURL>& urls);
DataOfferDelegate* const delegate_;
- // Map between mime type and drop data bytes.
- // nullptr may be set as a temporary value until data bytes are populated.
- base::flat_map<std::string, scoped_refptr<base::RefCountedMemory>> data_;
- // Unprocessed receive requests (pairs of mime type and FD) that are waiting
- // for unpopulated (nullptr) data bytes in |data_| to be populated.
+ // Data for a given mime type may not ever be requested, or may be requested
+ // more than once. Using callbacks and a cache allows us to delay any
+ // expensive operations until they are required, and then ensure that they are
+ // performed at most once. When we offer data for a given mime type we will
+ // populate |data_callbacks_| with mime type and a callback which will produce
+ // the required data. On the first request to |Receive()| we remove and invoke
+ // the callback and set |data_cache_| with null data. When the callback
+ // completes we populate |data_cache_| with data and fulfill any
+ // |pending_receive_requests|.
+ base::flat_map<std::string, AsyncSendDataCallback> data_callbacks_;
+ base::flat_map<std::string, scoped_refptr<base::RefCountedMemory>>
+ data_cache_;
std::vector<std::pair<std::string, base::ScopedFD>> pending_receive_requests_;
- using SendDataCallback = base::RepeatingCallback<void(base::ScopedFD)>;
- // Map from mime type (or other offered data type) to a callback that sends
- // data for that type. Using callbacks allows us to delay making copies or
- // doing other expensive processing until actually necessary.
- base::flat_map<std::string, SendDataCallback> data_callbacks_;
-
base::flat_set<DndAction> source_actions_;
DndAction dnd_action_;
base::ObserverList<DataOfferObserver>::Unchecked observers_;
- Purpose purpose_;
bool finished_;
base::WeakPtrFactory<DataOffer> weak_ptr_factory_{this};
diff --git a/chromium/components/exo/data_offer_unittest.cc b/chromium/components/exo/data_offer_unittest.cc
index 162d36aa3f3..42ad85a0ec3 100644
--- a/chromium/components/exo/data_offer_unittest.cc
+++ b/chromium/components/exo/data_offer_unittest.cc
@@ -14,14 +14,20 @@
#include "base/containers/flat_set.h"
#include "base/files/file_util.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
+#include "cc/test/pixel_comparator.h"
+#include "cc/test/pixel_test_utils.h"
#include "components/exo/data_device.h"
#include "components/exo/data_offer_delegate.h"
#include "components/exo/file_helper.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/gfx/codec/png_codec.h"
#include "url/gurl.h"
namespace exo {
@@ -65,35 +71,6 @@ class TestDataOfferDelegate : public DataOfferDelegate {
DISALLOW_COPY_AND_ASSIGN(TestDataOfferDelegate);
};
-class TestFileHelper : public FileHelper {
- public:
- TestFileHelper() = default;
-
- // Overridden from FileHelper:
- std::string GetMimeTypeForUriList() const override { return "text/uri-list"; }
- bool GetUrlFromPath(const std::string& app_id,
- const base::FilePath& path,
- GURL* out) override {
- *out = GURL("file://" + path.AsUTF8Unsafe());
- return true;
- }
- bool HasUrlsInPickle(const base::Pickle& pickle) override { return true; }
- void GetUrlsFromPickle(const std::string& app_id,
- const base::Pickle& pickle,
- UrlsFromPickleCallback callback) override {
- callback_ = std::move(callback);
- }
-
- void RunUrlsCallback(std::vector<GURL> urls) {
- std::move(callback_).Run(urls);
- }
-
- private:
- UrlsFromPickleCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(TestFileHelper);
-};
-
bool ReadString(base::ScopedFD fd, std::string* out) {
std::array<char, 128> buffer;
char* it = buffer.begin();
@@ -133,14 +110,14 @@ TEST_F(DataOfferTest, SetTextDropData) {
data.SetString(base::string16(base::ASCIIToUTF16("Test data")));
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
EXPECT_EQ(0u, delegate.mime_types().size());
EXPECT_EQ(0u, delegate.source_actions().size());
EXPECT_EQ(DndAction::kNone, delegate.dnd_action());
TestFileHelper file_helper;
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
data_offer.SetSourceActions(source_actions);
data_offer.SetActions(base::flat_set<DndAction>(), DndAction::kMove);
@@ -163,14 +140,14 @@ TEST_F(DataOfferTest, SetHTMLDropData) {
data.SetHtml(base::UTF8ToUTF16(html_data), GURL());
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
EXPECT_EQ(0u, delegate.mime_types().size());
EXPECT_EQ(0u, delegate.source_actions().size());
EXPECT_EQ(DndAction::kNone, delegate.dnd_action());
TestFileHelper file_helper;
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
data_offer.SetSourceActions(source_actions);
data_offer.SetActions(base::flat_set<DndAction>(), DndAction::kMove);
@@ -197,12 +174,12 @@ TEST_F(DataOfferTest, SetHTMLDropData) {
TEST_F(DataOfferTest, SetFileDropData) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
data.SetFilename(base::FilePath("/test/downloads/file"));
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
EXPECT_EQ(1u, delegate.mime_types().size());
EXPECT_EQ(1u, delegate.mime_types().count("text/uri-list"));
@@ -210,7 +187,7 @@ TEST_F(DataOfferTest, SetFileDropData) {
TEST_F(DataOfferTest, SetPickleDropData) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
@@ -222,7 +199,7 @@ TEST_F(DataOfferTest, SetPickleDropData) {
pickle.WriteString("id"); // filesystem id
data.SetPickledData(
ui::ClipboardFormatType::GetType("chromium/x-file-system-files"), pickle);
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
EXPECT_EQ(1u, delegate.mime_types().size());
EXPECT_EQ(1u, delegate.mime_types().count("text/uri-list"));
@@ -230,12 +207,12 @@ TEST_F(DataOfferTest, SetPickleDropData) {
TEST_F(DataOfferTest, ReceiveString) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
data.SetString(base::ASCIIToUTF16("Test data"));
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
base::ScopedFD read_pipe;
base::ScopedFD write_pipe;
@@ -265,12 +242,12 @@ TEST_F(DataOfferTest, ReceiveString) {
TEST_F(DataOfferTest, ReceiveHTML) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
data.SetHtml(base::ASCIIToUTF16("Test HTML data"), GURL());
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
base::ScopedFD read_pipe_16;
base::ScopedFD write_pipe_16;
@@ -291,62 +268,26 @@ TEST_F(DataOfferTest, ReceiveHTML) {
TEST_F(DataOfferTest, ReceiveUriList) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
data.SetFilename(base::FilePath("/test/downloads/file"));
- data_offer.SetDropData(&file_helper, data);
-
- base::ScopedFD read_pipe;
- base::ScopedFD write_pipe;
- ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
-
- data_offer.Receive("text/uri-list", std::move(write_pipe));
- base::string16 result;
- ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
- EXPECT_EQ(base::ASCIIToUTF16("file:///test/downloads/file"), result);
-}
-
-TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveAfterUrlIsResolved) {
- TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
-
- TestFileHelper file_helper;
- ui::OSExchangeData data;
-
- base::Pickle pickle;
- pickle.WriteUInt32(1); // num files
- pickle.WriteString("filesystem:chrome-extension://path/to/file1");
- pickle.WriteInt64(1000); // file size
- pickle.WriteString("id"); // filesystem id
- data.SetPickledData(
- ui::ClipboardFormatType::GetType("chromium/x-file-system-files"), pickle);
- data_offer.SetDropData(&file_helper, data);
-
- // Run callback with a resolved URL.
- std::vector<GURL> urls;
- urls.push_back(
- GURL("content://org.chromium.arc.chromecontentprovider/path/to/file1"));
- file_helper.RunUrlsCallback(urls);
+ data_offer.SetDropData(&file_helper, nullptr, data);
base::ScopedFD read_pipe;
base::ScopedFD write_pipe;
ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
- // Receive is called after UrlsCallback runs.
data_offer.Receive("text/uri-list", std::move(write_pipe));
- base::string16 result;
- ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
- EXPECT_EQ(
- base::ASCIIToUTF16(
- "content://org.chromium.arc.chromecontentprovider/path/to/file1"),
- result);
+ std::string result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &result));
+ EXPECT_EQ("file:///test/downloads/file", result);
}
TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveBeforeUrlIsResolved) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
@@ -358,7 +299,7 @@ TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveBeforeUrlIsResolved) {
pickle.WriteString("id"); // filesystem id
data.SetPickledData(
ui::ClipboardFormatType::GetType("chromium/x-file-system-files"), pickle);
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
base::ScopedFD read_pipe1;
base::ScopedFD write_pipe1;
@@ -375,26 +316,22 @@ TEST_F(DataOfferTest, ReceiveUriListFromPickle_ReceiveBeforeUrlIsResolved) {
std::vector<GURL> urls;
urls.push_back(
GURL("content://org.chromium.arc.chromecontentprovider/path/to/file1"));
- file_helper.RunUrlsCallback(urls);
-
- base::string16 result1;
- ASSERT_TRUE(ReadString16(std::move(read_pipe1), &result1));
- EXPECT_EQ(
- base::ASCIIToUTF16(
- "content://org.chromium.arc.chromecontentprovider/path/to/file1"),
- result1);
- base::string16 result2;
- ASSERT_TRUE(ReadString16(std::move(read_pipe2), &result2));
- EXPECT_EQ(
- base::ASCIIToUTF16(
- "content://org.chromium.arc.chromecontentprovider/path/to/file1"),
- result2);
+ file_helper.RunSendPickleCallback(urls);
+
+ std::string result1;
+ ASSERT_TRUE(ReadString(std::move(read_pipe1), &result1));
+ EXPECT_EQ("content://org.chromium.arc.chromecontentprovider/path/to/file1",
+ result1);
+ std::string result2;
+ ASSERT_TRUE(ReadString(std::move(read_pipe2), &result2));
+ EXPECT_EQ("content://org.chromium.arc.chromecontentprovider/path/to/file1",
+ result2);
}
TEST_F(DataOfferTest,
ReceiveUriListFromPickle_ReceiveBeforeEmptyUrlIsReturned) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::DRAG_DROP);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
ui::OSExchangeData data;
@@ -406,7 +343,7 @@ TEST_F(DataOfferTest,
pickle.WriteString("id"); // filesystem id
data.SetPickledData(
ui::ClipboardFormatType::GetType("chromium/x-file-system-files"), pickle);
- data_offer.SetDropData(&file_helper, data);
+ data_offer.SetDropData(&file_helper, nullptr, data);
base::ScopedFD read_pipe;
base::ScopedFD write_pipe;
@@ -418,7 +355,7 @@ TEST_F(DataOfferTest,
// Run callback with an empty URL.
std::vector<GURL> urls;
urls.push_back(GURL(""));
- file_helper.RunUrlsCallback(urls);
+ file_helper.RunSendPickleCallback(urls);
base::string16 result;
ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
@@ -427,7 +364,7 @@ TEST_F(DataOfferTest,
TEST_F(DataOfferTest, SetClipboardDataPlainText) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::COPY_PASTE);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
{
@@ -444,13 +381,21 @@ TEST_F(DataOfferTest, SetClipboardDataPlainText) {
base::ScopedFD read_pipe;
base::ScopedFD write_pipe;
- ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ // Read as utf-8.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
std::string result;
ASSERT_TRUE(ReadString(std::move(read_pipe), &result));
EXPECT_EQ("Test data", result);
+ // Read a second time.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &result));
+ EXPECT_EQ("Test data", result);
+
+ // Read as utf-16.
ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
data_offer.Receive("text/plain;charset=utf-16", std::move(write_pipe));
base::string16 result16;
@@ -460,7 +405,7 @@ TEST_F(DataOfferTest, SetClipboardDataPlainText) {
TEST_F(DataOfferTest, SetClipboardDataHTML) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::COPY_PASTE);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
{
@@ -492,7 +437,7 @@ TEST_F(DataOfferTest, SetClipboardDataHTML) {
TEST_F(DataOfferTest, SetClipboardDataRTF) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::COPY_PASTE);
+ DataOffer data_offer(&delegate);
TestFileHelper file_helper;
{
@@ -515,9 +460,59 @@ TEST_F(DataOfferTest, SetClipboardDataRTF) {
EXPECT_EQ("Test data", result);
}
+TEST_F(DataOfferTest, SetClipboardDataImage) {
+ TestDataOfferDelegate delegate;
+ DataOffer data_offer(&delegate);
+
+ SkBitmap image;
+ image.allocN32Pixels(10, 10);
+ image.eraseColor(SK_ColorMAGENTA);
+
+ TestFileHelper file_helper;
+ {
+ ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste);
+ writer.WriteImage(image);
+ }
+ data_offer.SetClipboardData(&file_helper,
+ *ui::Clipboard::GetForCurrentThread());
+
+ EXPECT_EQ(1u, delegate.mime_types().size());
+ EXPECT_EQ(1u, delegate.mime_types().count("image/png"));
+
+ base::ScopedFD read_pipe;
+ base::ScopedFD write_pipe;
+ base::ScopedFD read_pipe2;
+ base::ScopedFD write_pipe2;
+ std::string result;
+
+ // Call Receive() twice in quick succession. Requires RunUntilIdle() since
+ // processing is done on worker thread.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ ASSERT_TRUE(base::CreatePipe(&read_pipe2, &write_pipe2));
+ data_offer.Receive("image/png", std::move(write_pipe));
+ data_offer.Receive("image/png", std::move(write_pipe2));
+ task_environment()->RunUntilIdle();
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &result));
+ SkBitmap decoded;
+ ASSERT_TRUE(gfx::PNGCodec::Decode(
+ reinterpret_cast<const unsigned char*>(result.data()), result.size(),
+ &decoded));
+ EXPECT_TRUE(cc::MatchesBitmap(
+ image, decoded, cc::ExactPixelComparator(/*discard_alpha=*/false)));
+ std::string good = result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe2), &result));
+ EXPECT_EQ(good, result);
+
+ // Receive() should now return immediately with result from cache.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("image/png", std::move(write_pipe));
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &result));
+ EXPECT_EQ(good, result);
+}
+
TEST_F(DataOfferTest, AcceptWithNull) {
TestDataOfferDelegate delegate;
- DataOffer data_offer(&delegate, DataOffer::Purpose::COPY_PASTE);
+ DataOffer data_offer(&delegate);
data_offer.Accept(nullptr);
}
diff --git a/chromium/components/exo/data_source.cc b/chromium/components/exo/data_source.cc
index e6120827312..458c4fbe462 100644
--- a/chromium/components/exo/data_source.cc
+++ b/chromium/components/exo/data_source.cc
@@ -7,7 +7,7 @@
#include <limits>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/i18n/character_encoding.h"
#include "base/i18n/icu_string_conversions.h"
@@ -31,6 +31,7 @@ namespace {
constexpr char kTextPlain[] = "text/plain";
constexpr char kTextRTF[] = "text/rtf";
constexpr char kTextHTML[] = "text/html";
+constexpr char kTextUriList[] = "text/uri-list";
constexpr char kUtfPrefix[] = "UTF";
constexpr char kEncoding16[] = "16";
@@ -240,8 +241,9 @@ void DataSource::GetDataForPreferredMimeTypes(
ReadDataCallback rtf_reader,
ReadTextDataCallback html_reader,
ReadDataCallback image_reader,
+ ReadDataCallback filenames_reader,
base::RepeatingClosure failure_callback) {
- std::string text_mime, rtf_mime, html_mime, image_mime;
+ std::string text_mime, rtf_mime, html_mime, image_mime, filenames_mime;
int text_rank = std::numeric_limits<int>::max();
int html_rank = std::numeric_limits<int>::max();
@@ -286,6 +288,11 @@ void DataSource::GetDataForPreferredMimeTypes(
image_mime = mime_type;
image_rank = new_rank;
}
+ } else if (net::MatchesMimeType(std::string(kTextUriList), mime_type)) {
+ if (filenames_reader.is_null())
+ continue;
+
+ filenames_mime = mime_type;
}
}
@@ -301,6 +308,7 @@ void DataSource::GetDataForPreferredMimeTypes(
std::move(html_reader)),
failure_callback);
ReadData(image_mime, std::move(image_reader), failure_callback);
+ ReadData(filenames_mime, std::move(filenames_reader), failure_callback);
}
void DataSource::OnTextRead(ReadTextDataCallback callback,
diff --git a/chromium/components/exo/data_source.h b/chromium/components/exo/data_source.h
index bc669cc86ec..e8631f1f627 100644
--- a/chromium/components/exo/data_source.h
+++ b/chromium/components/exo/data_source.h
@@ -60,8 +60,9 @@ class DataSource {
void DndFinished();
// Search the set of offered MIME types for the most preferred of each of the
- // following categories: text/plain*, text/rtf, text/html*, image/*. If any
- // usable MIME types in a given category are available, the corresponding
+ // following categories: text/plain*, text/rtf, text/html*, image/*,
+ // text/uri-list. If any usable MIME types in a given category are available,
+ // the corresponding
// |*_reader| input callback will be called with the best one and the
// corresponding data. For any category that has no available MIME types,
// |failure_callback| is run. |failure_callback| may therefore be run as many
@@ -74,6 +75,7 @@ class DataSource {
ReadDataCallback rtf_reader,
ReadTextDataCallback html_reader,
ReadDataCallback image_reader,
+ ReadDataCallback filenames_reader,
base::RepeatingClosure failure_callback);
void ReadDataForTesting(const std::string& mime_type,
diff --git a/chromium/components/exo/data_source_unittest.cc b/chromium/components/exo/data_source_unittest.cc
index 924f176e397..a16a59b2389 100644
--- a/chromium/components/exo/data_source_unittest.cc
+++ b/chromium/components/exo/data_source_unittest.cc
@@ -6,7 +6,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/test/task_environment.h"
#include "components/exo/data_source_delegate.h"
@@ -68,11 +68,12 @@ void IncrementCounter(base::RepeatingClosure counter) {
std::move(counter).Run();
}
-void CheckMimeTypesRecieved(DataSource* data_source,
+void CheckMimeTypesReceived(DataSource* data_source,
const std::string& text_mime,
const std::string& rtf_mime,
const std::string& html_mime,
- const std::string& image_mime) {
+ const std::string& image_mime,
+ const std::string& filenames_mime) {
base::RunLoop run_loop;
base::RepeatingClosure counter =
base::BarrierClosure(4, run_loop.QuitClosure());
@@ -81,6 +82,7 @@ void CheckMimeTypesRecieved(DataSource* data_source,
base::BindOnce(&CheckMimeType, rtf_mime, counter),
base::BindOnce(&CheckTextMimeType, html_mime, counter),
base::BindOnce(&CheckMimeType, image_mime, counter),
+ base::BindOnce(&CheckMimeType, filenames_mime, counter),
base::BindRepeating(&IncrementCounter, counter));
run_loop.Run();
}
@@ -170,11 +172,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeUTF16) {
data_source.Offer("text/html;charset=UTF-16");
data_source.Offer("text/html;charset=utf-8");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=utf-16",
"",
"text/html;charset=UTF-16",
+ "",
"");
}
@@ -186,11 +189,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeUTF16LE) {
data_source.Offer("text/html;charset=utf16le");
data_source.Offer("text/html;charset=utf-8");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=utf-16le",
"",
"text/html;charset=utf16le",
+ "",
"");
}
@@ -202,11 +206,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeUTF16BE) {
data_source.Offer("text/html;charset=UTF16be");
data_source.Offer("text/html;charset=utf-8");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=utf-16be",
"",
"text/html;charset=UTF16be",
+ "",
"");
}
@@ -218,11 +223,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeUTFToOther) {
data_source.Offer("text/html;charset=utf-8");
data_source.Offer("text/html;charset=iso-8859-1");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=utf-8",
"",
"text/html;charset=utf-8",
+ "",
"");
}
@@ -232,11 +238,12 @@ TEST_F(DataSourceTest, RecogniseUTF8Legaccy) {
data_source.Offer("UTF8_STRING");
data_source.Offer("text/plain;charset=iso-8859-1");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"UTF8_STRING",
"",
"",
+ "",
"");
}
@@ -248,11 +255,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeOtherToAscii) {
data_source.Offer("text/html;charset=iso-8859-1");
data_source.Offer("text/html;charset=ascii");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=iso-8859-1",
"",
"text/html;charset=iso-8859-1",
+ "",
"");
}
@@ -264,11 +272,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeOtherToUnspecified) {
data_source.Offer("text/html;charset=iso-8859-1");
data_source.Offer("text/html");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"text/plain;charset=iso-8859-1",
"",
"text/html;charset=iso-8859-1",
+ "",
"");
}
@@ -277,11 +286,12 @@ TEST_F(DataSourceTest, PreferredMimeTypeRTF) {
DataSource data_source(&delegate);
data_source.Offer("text/rtf");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"",
"text/rtf",
"",
+ "",
"");
}
@@ -291,12 +301,13 @@ TEST_F(DataSourceTest, PreferredMimeTypeBitmapToPNG) {
data_source.Offer("image/bmp");
data_source.Offer("image/png");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
&data_source,
"",
"",
"",
- "image/bmp");
+ "image/bmp",
+ "");
}
TEST_F(DataSourceTest, PreferredMimeTypePNGToJPEG) {
@@ -306,12 +317,27 @@ TEST_F(DataSourceTest, PreferredMimeTypePNGToJPEG) {
data_source.Offer("image/jpeg");
data_source.Offer("image/jpg");
- CheckMimeTypesRecieved(
+ CheckMimeTypesReceived(
+ &data_source,
+ "",
+ "",
+ "",
+ "image/png",
+ "");
+}
+
+TEST_F(DataSourceTest, PreferredMimeTypeTextUriList) {
+ TestDataSourceDelegate delegate;
+ DataSource data_source(&delegate);
+ data_source.Offer("text/uri-list");
+
+ CheckMimeTypesReceived(
&data_source,
"",
"",
"",
- "image/png");
+ "",
+ "text/uri-list");
}
} // namespace
diff --git a/chromium/components/exo/display_unittest.cc b/chromium/components/exo/display_unittest.cc
index b8fc458e4df..38b120dc9ab 100644
--- a/chromium/components/exo/display_unittest.cc
+++ b/chromium/components/exo/display_unittest.cc
@@ -4,8 +4,8 @@
#include "components/exo/display.h"
#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/cpp/window_pin_type.h"
#include "ash/wm/desks/desks_util.h"
+#include "chromeos/ui/base/window_pin_type.h"
#include "components/exo/buffer.h"
#include "components/exo/client_controlled_shell_surface.h"
#include "components/exo/data_device.h"
@@ -18,6 +18,7 @@
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/toast_surface_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -210,9 +211,7 @@ class TestDataDeviceDelegate : public DataDeviceDelegate {
public:
// Overriden from DataDeviceDelegate:
void OnDataDeviceDestroying(DataDevice* data_device) override {}
- DataOffer* OnDataOffer(DataOffer::Purpose purpose) override {
- return nullptr;
- }
+ DataOffer* OnDataOffer() override { return nullptr; }
void OnEnter(Surface* surface,
const gfx::PointF& location,
const DataOffer& data_offer) override {}
@@ -226,22 +225,6 @@ class TestDataDeviceDelegate : public DataDeviceDelegate {
}
};
-class TestFileHelper : public FileHelper {
- public:
- // Overriden from TestFileHelper:
- TestFileHelper() {}
- std::string GetMimeTypeForUriList() const override { return ""; }
- bool GetUrlFromPath(const std::string& app_id,
- const base::FilePath& path,
- GURL* out) override {
- return true;
- }
- bool HasUrlsInPickle(const base::Pickle& pickle) override { return false; }
- void GetUrlsFromPickle(const std::string& app_id,
- const base::Pickle& pickle,
- UrlsFromPickleCallback callback) override {}
-};
-
TEST_F(DisplayTest, CreateDataDevice) {
TestDataDeviceDelegate device_delegate;
Display display(nullptr, nullptr, nullptr,
@@ -268,7 +251,7 @@ TEST_F(DisplayTest, PinnedAlwaysOnTopWindow) {
// This should not crash
shell_surface->SetAlwaysOnTop(true);
- shell_surface->SetPinned(ash::WindowPinType::kPinned);
+ shell_surface->SetPinned(chromeos::WindowPinType::kPinned);
}
} // namespace
diff --git a/chromium/components/exo/drag_drop_operation.cc b/chromium/components/exo/drag_drop_operation.cc
index bd95b7dfad7..97d00801606 100644
--- a/chromium/components/exo/drag_drop_operation.cc
+++ b/chromium/components/exo/drag_drop_operation.cc
@@ -5,25 +5,33 @@
#include "components/exo/drag_drop_operation.h"
#include "base/barrier_closure.h"
+#include "base/check.h"
+#include "base/strings/string_split.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/exo/data_offer.h"
#include "components/exo/data_source.h"
+#include "components/exo/file_helper.h"
#include "components/exo/seat.h"
#include "components/exo/surface.h"
+#include "components/exo/surface_tree_host.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/file_info/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/transform_util.h"
+#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#include "ash/drag_drop/drag_drop_controller.h"
+#include "components/exo/extended_drag_source.h"
#endif // defined(OS_CHROMEOS)
namespace exo {
@@ -78,29 +86,86 @@ DndAction DragOperationToDndAction(int op) {
} // namespace
+// Internal representation of a drag icon surface. Used when a non-null surface
+// is passed in wl_data_device::start_drag requests.
+// TODO(crbug.com/1119385): Rework icon implementation to avoid frame copies.
+class DragDropOperation::IconSurface final : public SurfaceTreeHost,
+ public ScopedSurface {
+ public:
+ IconSurface(Surface* icon, DragDropOperation* operation)
+ : SurfaceTreeHost("ExoDragIcon"),
+ ScopedSurface(icon, operation),
+ operation_(operation) {
+ DCHECK(operation_);
+ DCHECK(!icon->HasSurfaceDelegate());
+
+ Surface* origin_surface = operation_->origin_->get();
+ origin_surface->window()->AddChild(host_window());
+ SetRootSurface(icon);
+ }
+
+ IconSurface(const IconSurface&) = delete;
+ IconSurface& operator=(const IconSurface&) = delete;
+ ~IconSurface() override = default;
+
+ private:
+ // SurfaceTreeHost:
+ void OnSurfaceCommit() override {
+ SurfaceTreeHost::OnSurfaceCommit();
+ RequestCaptureIcon();
+ }
+
+ void RequestCaptureIcon() {
+ SubmitCompositorFrame();
+
+ std::unique_ptr<viz::CopyOutputRequest> request =
+ std::make_unique<viz::CopyOutputRequest>(
+ viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
+ base::BindOnce(&IconSurface::OnCaptured,
+ weak_ptr_factory_.GetWeakPtr()));
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
+
+ host_window()->layer()->RequestCopyOfOutput(std::move(request));
+ }
+
+ void OnCaptured(std::unique_ptr<viz::CopyOutputResult> icon_result) {
+ // An empty response means the request was deleted before it was completed.
+ // If this happens, and no operation has yet finished, restart the capture.
+ if (icon_result->IsEmpty()) {
+ RequestCaptureIcon();
+ return;
+ }
+
+ operation_->OnDragIconCaptured(icon_result->AsSkBitmap());
+ }
+
+ DragDropOperation* const operation_;
+ base::WeakPtrFactory<IconSurface> weak_ptr_factory_{this};
+};
+
base::WeakPtr<DragDropOperation> DragDropOperation::Create(
+ FileHelper* file_helper,
DataSource* source,
Surface* origin,
Surface* icon,
const gfx::PointF& drag_start_point,
ui::mojom::DragEventSource event_source) {
- auto* dnd_op = new DragDropOperation(source, origin, icon, drag_start_point,
- event_source);
+ auto* dnd_op = new DragDropOperation(file_helper, source, origin, icon,
+ drag_start_point, event_source);
return dnd_op->weak_ptr_factory_.GetWeakPtr();
}
-DragDropOperation::DragDropOperation(DataSource* source,
+DragDropOperation::DragDropOperation(FileHelper* file_helper,
+ DataSource* source,
Surface* origin,
Surface* icon,
const gfx::PointF& drag_start_point,
ui::mojom::DragEventSource event_source)
- : SurfaceTreeHost("ExoDragDropOperation"),
- source_(std::make_unique<ScopedDataSource>(source, this)),
+ : source_(std::make_unique<ScopedDataSource>(source, this)),
origin_(std::make_unique<ScopedSurface>(origin, this)),
drag_start_point_(drag_start_point),
os_exchange_data_(std::make_unique<ui::OSExchangeData>()),
- event_source_(event_source),
- weak_ptr_factory_(this) {
+ event_source_(event_source) {
aura::Window* root_window = origin_->get()->window()->GetRootWindow();
DCHECK(root_window);
#if defined(OS_CHROMEOS)
@@ -116,8 +181,17 @@ DragDropOperation::DragDropOperation(DataSource* source,
drag_drop_controller_->AddObserver(this);
+#if defined(OS_CHROMEOS)
+ extended_drag_source_ = ExtendedDragSource::Get();
+ if (extended_drag_source_) {
+ drag_drop_controller_->set_toplevel_window_drag_delegate(
+ extended_drag_source_);
+ extended_drag_source_->AddObserver(this);
+ }
+#endif
+
if (icon)
- icon_ = std::make_unique<ScopedSurface>(icon, this);
+ icon_ = std::make_unique<IconSurface>(icon, this);
auto start_op_callback =
base::BindOnce(&DragDropOperation::ScheduleStartDragDropOperation,
@@ -134,12 +208,11 @@ DragDropOperation::DragDropOperation(DataSource* source,
DataSource::ReadDataCallback(),
base::BindOnce(&DragDropOperation::OnHTMLRead,
weak_ptr_factory_.GetWeakPtr()),
- DataSource::ReadDataCallback(), counter_);
-
- if (icon) {
- origin_->get()->window()->AddChild(host_window());
- SetRootSurface(icon);
- }
+ DataSource::ReadDataCallback(),
+ base::BindOnce(&DragDropOperation::OnFilenamesRead,
+ weak_ptr_factory_.GetWeakPtr(), file_helper,
+ origin->window()),
+ counter_);
}
DragDropOperation::~DragDropOperation() {
@@ -150,6 +223,11 @@ DragDropOperation::~DragDropOperation() {
if (drag_drop_controller_->IsDragDropInProgress() && started_by_this_object_)
drag_drop_controller_->DragCancel();
+
+#if defined(OS_CHROMEOS)
+ if (extended_drag_source_)
+ ResetExtendedDragSource();
+#endif
}
void DragDropOperation::AbortIfPending() {
@@ -176,48 +254,28 @@ void DragDropOperation::OnHTMLRead(const std::string& mime_type,
counter_.Run();
}
-void DragDropOperation::OnSurfaceCommit() {
- SurfaceTreeHost::OnSurfaceCommit();
-
- if (icon_)
- CaptureDragIcon();
-}
-
-void DragDropOperation::CaptureDragIcon() {
- SubmitCompositorFrame();
-
- std::unique_ptr<viz::CopyOutputRequest> request =
- std::make_unique<viz::CopyOutputRequest>(
- viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&DragDropOperation::OnDragIconCaptured,
- weak_ptr_factory_.GetWeakPtr()));
- request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
-
- host_window()->layer()->RequestCopyOfOutput(std::move(request));
+void DragDropOperation::OnFilenamesRead(FileHelper* file_helper,
+ aura::Window* source,
+ const std::string& mime_type,
+ const std::vector<uint8_t>& data) {
+ DCHECK(os_exchange_data_);
+ os_exchange_data_->SetFilenames(file_helper->GetFilenames(source, data));
+ mime_type_ = mime_type;
+ counter_.Run();
}
-void DragDropOperation::OnDragIconCaptured(
- std::unique_ptr<viz::CopyOutputResult> icon_result) {
- gfx::ImageSkia icon_skia;
-
- // An empty response means the request was deleted before it was completed. If
- // this happens, and no operation has yet finished, restart the capture.
- if (icon_result->IsEmpty()) {
- CaptureDragIcon();
- return;
- }
+void DragDropOperation::OnDragIconCaptured(const SkBitmap& icon_bitmap) {
+ DCHECK(icon_);
float scale_factor = origin_->get()->window()->layer()->device_scale_factor();
- icon_skia = gfx::ImageSkia(
- gfx::ImageSkiaRep(icon_result->AsSkBitmap(), scale_factor));
+ gfx::ImageSkia icon_skia(gfx::ImageSkiaRep(icon_bitmap, scale_factor));
+ gfx::Vector2d icon_offset = -icon_->get()->GetBufferOffset();
if (os_exchange_data_) {
- os_exchange_data_->provider().SetDragImage(
- icon_skia, -icon_->get()->GetBufferOffset());
+ os_exchange_data_->provider().SetDragImage(icon_skia, icon_offset);
} else {
#if defined(OS_CHROMEOS)
- drag_drop_controller_->SetDragImage(icon_skia,
- -icon_->get()->GetBufferOffset());
+ drag_drop_controller_->SetDragImage(icon_skia, icon_offset);
#endif
}
@@ -303,22 +361,29 @@ void DragDropOperation::OnDragActionsChanged(int actions) {
source_->get()->Action(dnd_action);
}
+
+void DragDropOperation::OnExtendedDragSourceDestroying(
+ ExtendedDragSource* source) {
+ ResetExtendedDragSource();
+}
+
+void DragDropOperation::ResetExtendedDragSource() {
+ DCHECK(extended_drag_source_);
+ extended_drag_source_->RemoveObserver(this);
+ drag_drop_controller_->set_toplevel_window_drag_delegate(nullptr);
+ extended_drag_source_ = nullptr;
+}
#endif
void DragDropOperation::OnSurfaceDestroying(Surface* surface) {
- if (surface == origin_->get() || surface == icon_->get()) {
- delete this;
- } else {
- NOTREACHED();
- }
+ DCHECK(surface == origin_->get() || (icon_ && surface == icon_->get()));
+ delete this;
}
void DragDropOperation::OnDataSourceDestroying(DataSource* source) {
- if (source == source_->get()) {
- source_.reset();
- delete this;
- } else {
- NOTREACHED();
- }
+ DCHECK_EQ(source, source_->get());
+ source_.reset();
+ delete this;
}
+
} // namespace exo
diff --git a/chromium/components/exo/drag_drop_operation.h b/chromium/components/exo/drag_drop_operation.h
index cf6da01fede..616b2a95804 100644
--- a/chromium/components/exo/drag_drop_operation.h
+++ b/chromium/components/exo/drag_drop_operation.h
@@ -5,16 +5,24 @@
#ifndef COMPONENTS_EXO_DRAG_DROP_OPERATION_H_
#define COMPONENTS_EXO_DRAG_DROP_OPERATION_H_
+#include <memory>
+#include <string>
+
#include "components/exo/data_device.h"
#include "components/exo/data_offer_observer.h"
#include "components/exo/data_source_observer.h"
#include "components/exo/surface_observer.h"
-#include "components/exo/surface_tree_host.h"
#include "components/exo/wm_helper.h"
#include "ui/aura/client/drag_drop_client_observer.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
#include "ui/gfx/geometry/point_f.h"
+#if defined(OS_CHROMEOS)
+#include "components/exo/extended_drag_source.h"
+#endif
+
+class SkBitmap;
+
namespace ash {
class DragDropController;
} // namespace ash
@@ -29,12 +37,11 @@ namespace ui {
class OSExchangeData;
}
-namespace viz {
-class CopyOutputResult;
-}
-
namespace exo {
+class FileHelper;
class ScopedDataSource;
+class Surface;
+class ScopedSurface;
// This class represents an ongoing drag-drop operation started by an exo
// client. It manages its own lifetime. It will delete itself when the drag
@@ -42,12 +49,15 @@ class ScopedDataSource;
// (e.g. the client deletes the data source used to start the drag operation),
// or if another drag operation races with this one to start and wins.
class DragDropOperation : public DataSourceObserver,
- public SurfaceTreeHost,
public SurfaceObserver,
+#if defined(OS_CHROMEOS)
+ public ExtendedDragSource::Observer,
+#endif
public aura::client::DragDropClientObserver {
public:
// Create an operation for a drag-drop originating from a wayland app.
static base::WeakPtr<DragDropOperation> Create(
+ FileHelper* file_helper,
DataSource* source,
Surface* origin,
Surface* icon,
@@ -60,9 +70,6 @@ class DragDropOperation : public DataSourceObserver,
// DataSourceObserver:
void OnDataSourceDestroying(DataSource* source) override;
- // SurfaceDelegate:
- void OnSurfaceCommit() override;
-
// SurfaceObserver:
void OnSurfaceDestroying(Surface* surface) override;
@@ -71,23 +78,32 @@ class DragDropOperation : public DataSourceObserver,
void OnDragEnded() override;
#if defined(OS_CHROMEOS)
void OnDragActionsChanged(int actions) override;
+
+ // ExtendedDragSource::Observer:
+ void OnExtendedDragSourceDestroying(ExtendedDragSource* source) override;
#endif
private:
+ class IconSurface;
+
// A private constructor and destructor are used to prevent anyone else from
// attempting to manage the lifetime of a DragDropOperation.
- DragDropOperation(DataSource* source,
+ DragDropOperation(FileHelper* file_helper,
+ DataSource* source,
Surface* origin,
Surface* icon,
const gfx::PointF& drag_start_point,
ui::mojom::DragEventSource event_source);
~DragDropOperation() override;
- void CaptureDragIcon();
- void OnDragIconCaptured(std::unique_ptr<viz::CopyOutputResult> icon_result);
+ void OnDragIconCaptured(const SkBitmap& icon_bitmap);
void OnTextRead(const std::string& mime_type, base::string16 data);
void OnHTMLRead(const std::string& mime_type, base::string16 data);
+ void OnFilenamesRead(FileHelper* file_helper,
+ aura::Window* source,
+ const std::string& mime_type,
+ const std::vector<uint8_t>& data);
void ScheduleStartDragDropOperation();
@@ -95,6 +111,10 @@ class DragDropOperation : public DataSourceObserver,
// directly. Use ScheduleStartDragDropOperation instead.
void StartDragDropOperation();
+#if defined(OS_CHROMEOS)
+ void ResetExtendedDragSource();
+#endif
+
std::unique_ptr<ScopedDataSource> source_;
std::unique_ptr<ScopedSurface> icon_;
std::unique_ptr<ScopedSurface> origin_;
@@ -122,7 +142,11 @@ class DragDropOperation : public DataSourceObserver,
ui::mojom::DragEventSource event_source_;
- base::WeakPtrFactory<DragDropOperation> weak_ptr_factory_;
+#if defined(OS_CHROMEOS)
+ ExtendedDragSource* extended_drag_source_;
+#endif
+
+ base::WeakPtrFactory<DragDropOperation> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DragDropOperation);
};
diff --git a/chromium/components/exo/drag_drop_operation_unittest.cc b/chromium/components/exo/drag_drop_operation_unittest.cc
index e0e30b8ad58..68db83e701c 100644
--- a/chromium/components/exo/drag_drop_operation_unittest.cc
+++ b/chromium/components/exo/drag_drop_operation_unittest.cc
@@ -13,8 +13,10 @@
#include "components/exo/buffer.h"
#include "components/exo/data_source.h"
#include "components/exo/data_source_delegate.h"
+#include "components/exo/file_helper.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/gfx/geometry/point_f.h"
@@ -90,6 +92,8 @@ class DragDropOperationTest : public test::ExoTestBase,
};
TEST_F(DragDropOperationTest, DeleteDuringDragging) {
+ TestFileHelper file_helper;
+
auto delegate = std::make_unique<TestDataSourceDelegate>();
auto data_source = std::make_unique<DataSource>(delegate.get());
data_source->Offer(kTextMimeType);
@@ -104,7 +108,7 @@ TEST_F(DragDropOperationTest, DeleteDuringDragging) {
icon_surface->Attach(buffer.get());
auto operation = DragDropOperation::Create(
- data_source.get(), origin_surface.get(), icon_surface.get(),
+ &file_helper, data_source.get(), origin_surface.get(), icon_surface.get(),
gfx::PointF(), ui::mojom::DragEventSource::kMouse);
icon_surface->Commit();
diff --git a/chromium/components/exo/extended_drag_source.cc b/chromium/components/exo/extended_drag_source.cc
index 5d07fe93584..69a50fb41b0 100644
--- a/chromium/components/exo/extended_drag_source.cc
+++ b/chromium/components/exo/extended_drag_source.cc
@@ -4,25 +4,116 @@
#include "components/exo/extended_drag_source.h"
+#include <memory>
+#include <string>
+
+#include "ash/shell.h"
+#include "ash/wm/toplevel_window_event_handler.h"
+#include "base/check.h"
#include "base/check_op.h"
#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/optional.h"
#include "components/exo/data_source.h"
-#include "components/exo/seat.h"
#include "components/exo/surface.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/base/hit_test.h"
+#include "ui/events/event.h"
+#include "ui/events/event_target.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d.h"
+#include "ui/wm/core/coordinate_conversion.h"
+#include "ui/wm/public/window_move_client.h"
namespace exo {
-ExtendedDragSource::ExtendedDragSource(DataSource* source,
- Seat* seat,
- Delegate* delegate)
- : delegate_(delegate), seat_(seat), source_(source) {
+// static
+ExtendedDragSource* ExtendedDragSource::instance_ = nullptr;
+
+// Internal representation of a toplevel window, backed by an Exo shell surface,
+// which is being dragged. It supports both already mapped/visible windows as
+// well as newly created ones (i.e: not added to a root window yet), in which
+// case OnDraggedWindowVisibilityChanging callback is called to notify when it
+// is about to get visible.
+class ExtendedDragSource::DraggedWindowHolder : public aura::WindowObserver {
+ public:
+ DraggedWindowHolder(Surface* surface,
+ const gfx::Vector2d& drag_offset,
+ ExtendedDragSource* source)
+ : surface_(surface), drag_offset_(drag_offset), source_(source) {
+ DCHECK(surface_);
+ DCHECK(surface_->window());
+ if (!FindToplevelWindow()) {
+ DVLOG(1) << "Dragged window not added to root window yet.";
+ surface_->window()->AddObserver(this);
+ }
+ }
+
+ DraggedWindowHolder(const DraggedWindowHolder&) = delete;
+ DraggedWindowHolder& operator=(const DraggedWindowHolder&) = delete;
+
+ ~DraggedWindowHolder() override {
+ if (toplevel_window_) {
+ toplevel_window_->RemoveObserver(this);
+ toplevel_window_ = nullptr;
+ } else {
+ surface_->window()->RemoveObserver(this);
+ }
+ }
+
+ aura::Window* toplevel_window() { return toplevel_window_; }
+ const gfx::Vector2d& offset() const { return drag_offset_; }
+
+ private:
+ // aura::WindowObserver:
+ void OnWindowAddedToRootWindow(aura::Window* window) override {
+ DCHECK_EQ(window, surface_->window());
+ FindToplevelWindow();
+ DCHECK(toplevel_window_);
+ surface_->window()->RemoveObserver(this);
+ }
+
+ void OnWindowVisibilityChanging(aura::Window* window, bool visible) override {
+ DCHECK(window);
+ if (window == toplevel_window_)
+ source_->OnDraggedWindowVisibilityChanging(visible);
+ }
+
+ bool FindToplevelWindow() {
+ if (!surface_->window()->GetRootWindow())
+ return false;
+
+ toplevel_window_ = surface_->window()->GetToplevelWindow();
+ toplevel_window_->AddObserver(this);
+ return true;
+ }
+
+ Surface* const surface_;
+ gfx::Vector2d drag_offset_;
+ ExtendedDragSource* const source_;
+ aura::Window* toplevel_window_ = nullptr;
+};
+
+// static
+ExtendedDragSource* ExtendedDragSource::Get() {
+ return instance_;
+}
+
+ExtendedDragSource::ExtendedDragSource(DataSource* source, Delegate* delegate)
+ : source_(source), delegate_(delegate) {
DCHECK(source_);
- DCHECK(seat_);
DCHECK(delegate_);
- DVLOG(1) << "ExtendedDragSource created. wl_source=" << source_;
source_->AddObserver(this);
+
+ DCHECK(!instance_);
+ instance_ = this;
}
ExtendedDragSource::~ExtendedDragSource() {
@@ -32,6 +123,9 @@ ExtendedDragSource::~ExtendedDragSource() {
if (source_)
source_->RemoveObserver(this);
+
+ DCHECK_EQ(instance_, this);
+ instance_ = nullptr;
}
void ExtendedDragSource::AddObserver(Observer* observer) {
@@ -50,16 +144,67 @@ void ExtendedDragSource::Drag(Surface* dragged_surface,
if (!source_)
return;
- if (dragged_surface == dragged_surface_ && drag_offset == drag_offset_)
+ if (!dragged_surface) {
+ DVLOG(1) << "Unsetting dragged surface.";
+ dragged_window_holder_.reset();
return;
+ }
- dragged_surface_ = dragged_surface;
- drag_offset_ = drag_offset;
- DVLOG(1) << "Dragged surface changed: surface=" << dragged_surface_
- << " offset=" << drag_offset_.ToString();
+ DVLOG(1) << "Dragged surface changed:"
+ << " surface=" << dragged_surface
+ << " offset=" << drag_offset.ToString();
- for (auto& observer : observers_)
- observer.OnDraggedSurfaceChanged(this);
+ // Ensure that the surface already has a "role" assigned.
+ DCHECK(dragged_surface->HasSurfaceDelegate());
+ dragged_window_holder_ =
+ std::make_unique<DraggedWindowHolder>(dragged_surface, drag_offset, this);
+
+ // Drag process will be started once OnDragStarted gets called.
+}
+
+bool ExtendedDragSource::IsActive() const {
+ return !!source_;
+}
+
+void ExtendedDragSource::OnToplevelWindowDragStarted(
+ const gfx::PointF& start_location,
+ ui::mojom::DragEventSource source) {
+ pointer_location_ = start_location;
+ drag_event_source_ = source;
+ MaybeLockCursor();
+
+ if (dragged_window_holder_ && dragged_window_holder_->toplevel_window())
+ StartDrag(dragged_window_holder_->toplevel_window(), start_location);
+}
+
+int ExtendedDragSource::OnToplevelWindowDragDropped() {
+ DVLOG(1) << "OnDragDropped()";
+ Cleanup();
+ return delegate_->ShouldAllowDropAnywhere() ? ui::DragDropTypes::DRAG_MOVE
+ : ui::DragDropTypes::DRAG_NONE;
+}
+
+void ExtendedDragSource::OnToplevelWindowDragCancelled() {
+ DVLOG(1) << "OnDragCancelled()";
+ // TODO(crbug.com/1099418): Handle cancellation/revert.
+ Cleanup();
+}
+
+void ExtendedDragSource::OnToplevelWindowDragEvent(ui::LocatedEvent* event) {
+ DCHECK(event);
+ pointer_location_ = event->root_location_f();
+
+ if (!dragged_window_holder_)
+ return;
+
+ auto* handler = ash::Shell::Get()->toplevel_window_event_handler();
+ if (event->IsMouseEvent()) {
+ handler->OnMouseEvent(event->AsMouseEvent());
+ return;
+ }
+
+ // TODO(crbug.com/1099418): Support touch move source.
+ NOTIMPLEMENTED() << "Non-mouse window dragging not supported yet.";
}
void ExtendedDragSource::OnDataSourceDestroying(DataSource* source) {
@@ -68,4 +213,93 @@ void ExtendedDragSource::OnDataSourceDestroying(DataSource* source) {
source_ = nullptr;
}
+void ExtendedDragSource::MaybeLockCursor() {
+ if (delegate_->ShouldLockCursor()) {
+ ash::Shell::Get()->cursor_manager()->LockCursor();
+ cursor_locked_ = true;
+ }
+}
+
+void ExtendedDragSource::UnlockCursor() {
+ if (cursor_locked_) {
+ ash::Shell::Get()->cursor_manager()->UnlockCursor();
+ cursor_locked_ = false;
+ }
+}
+
+void ExtendedDragSource::StartDrag(aura::Window* toplevel,
+ const gfx::PointF& pointer_location) {
+ // Ensure |toplevel| window does skip events while it's being dragged.
+ event_blocker_ =
+ std::make_unique<aura::ScopedWindowEventTargetingBlocker>(toplevel);
+
+ // Disable visibility change animations on the dragged window.
+ toplevel->SetProperty(aura::client::kAnimationsDisabledKey, true);
+
+ DVLOG(1) << "Starting drag. pointer_loc=" << pointer_location.ToString();
+ auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler();
+ auto move_source = drag_event_source_ == ui::mojom::DragEventSource::kTouch
+ ? ::wm::WINDOW_MOVE_SOURCE_TOUCH
+ : ::wm::WINDOW_MOVE_SOURCE_MOUSE;
+ toplevel_handler->AttemptToStartDrag(
+ toplevel, pointer_location, HTCAPTION, move_source,
+ ash::ToplevelWindowEventHandler::EndClosure(),
+ /*update_gesture_target=*/true, /*grab_capture=*/false);
+}
+
+void ExtendedDragSource::OnDraggedWindowVisibilityChanging(bool visible) {
+ DCHECK(dragged_window_holder_);
+ DVLOG(1) << "Dragged window visibility changed. visible=" << visible;
+
+ if (!visible) {
+ dragged_window_holder_.reset();
+ return;
+ }
+
+ aura::Window* toplevel = dragged_window_holder_->toplevel_window();
+ DCHECK(toplevel);
+
+ // The |toplevel| window for the dragged surface has just been created and
+ // it's about to be mapped. Calculate and set its position based on
+ // |drag_offset_| and |pointer_location_| before starting the actual drag.
+ auto screen_location = CalculateOrigin(toplevel);
+ toplevel->SetBounds({screen_location, toplevel->bounds().size()});
+
+ DVLOG(1) << "Dragged window mapped. toplevel=" << toplevel
+ << " origin=" << screen_location.ToString();
+
+ gfx::PointF pointer_location(screen_location +
+ dragged_window_holder_->offset());
+ StartDrag(toplevel, pointer_location);
+}
+
+gfx::Point ExtendedDragSource::CalculateOrigin(aura::Window* target) const {
+ DCHECK(dragged_window_holder_);
+ gfx::Point screen_location = gfx::ToRoundedPoint(pointer_location_);
+ wm::ConvertPointToScreen(target->GetRootWindow(), &screen_location);
+ return screen_location - dragged_window_holder_->offset();
+}
+
+void ExtendedDragSource::Cleanup() {
+ if (dragged_window_holder_ && dragged_window_holder_->toplevel_window()) {
+ dragged_window_holder_->toplevel_window()->ClearProperty(
+ aura::client::kAnimationsDisabledKey);
+ }
+ event_blocker_.reset();
+ dragged_window_holder_.reset();
+ UnlockCursor();
+}
+
+aura::Window* ExtendedDragSource::GetDraggedWindowForTesting() {
+ return dragged_window_holder_ ? dragged_window_holder_->toplevel_window()
+ : nullptr;
+}
+
+base::Optional<gfx::Vector2d> ExtendedDragSource::GetDragOffsetForTesting()
+ const {
+ return dragged_window_holder_
+ ? base::Optional<gfx::Vector2d>(dragged_window_holder_->offset())
+ : base::nullopt;
+}
+
} // namespace exo
diff --git a/chromium/components/exo/extended_drag_source.h b/chromium/components/exo/extended_drag_source.h
index 9886b83b45c..3aed93f9ee7 100644
--- a/chromium/components/exo/extended_drag_source.h
+++ b/chromium/components/exo/extended_drag_source.h
@@ -5,27 +5,45 @@
#ifndef COMPONENTS_EXO_EXTENDED_DRAG_SOURCE_H_
#define COMPONENTS_EXO_EXTENDED_DRAG_SOURCE_H_
+#include <memory>
#include <string>
+#include "ash/drag_drop/toplevel_window_drag_delegate.h"
+#include "ash/wm/toplevel_window_event_handler.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "components/exo/data_source_observer.h"
-#include "ui/gfx/geometry/vector2d.h"
+#include "ui/aura/scoped_window_event_targeting_blocker.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace aura {
+class Window;
+}
+
+namespace gfx {
+class Vector2d;
+}
+
+namespace ui {
+class LocatedEvent;
+}
namespace exo {
class DataSource;
-class Seat;
class Surface;
-class ExtendedDragSource : public DataSourceObserver {
+class ExtendedDragSource : public DataSourceObserver,
+ public ash::ToplevelWindowDragDelegate {
public:
class Delegate {
public:
virtual bool ShouldAllowDropAnywhere() const = 0;
virtual bool ShouldLockCursor() const = 0;
- virtual void OnSwallowed(std::string mime_type) = 0;
- virtual void OnUnswallowed(std::string mime_type,
+ virtual void OnSwallowed(const std::string& mime_type) = 0;
+ virtual void OnUnswallowed(const std::string& mime_type,
const gfx::Vector2d& offset) = 0;
virtual void OnDataSourceDestroying() = 0;
@@ -36,13 +54,14 @@ class ExtendedDragSource : public DataSourceObserver {
class Observer {
public:
virtual void OnExtendedDragSourceDestroying(ExtendedDragSource* source) = 0;
- virtual void OnDraggedSurfaceChanged(ExtendedDragSource* source) = 0;
protected:
virtual ~Observer() = default;
};
- ExtendedDragSource(DataSource* source, Seat* seat, Delegate* delegate);
+ static ExtendedDragSource* Get();
+
+ ExtendedDragSource(DataSource* source, Delegate* delegate);
ExtendedDragSource(const ExtendedDragSource&) = delete;
ExtendedDragSource& operator=(const ExtendedDragSource&) = delete;
~ExtendedDragSource() override;
@@ -50,28 +69,52 @@ class ExtendedDragSource : public DataSourceObserver {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- bool should_allow_drop_anywhere() const {
- return delegate_->ShouldAllowDropAnywhere();
- }
- bool should_lock_cursor() const { return delegate_->ShouldLockCursor(); }
+ void Drag(Surface* surface, const gfx::Vector2d& offset);
- const gfx::Vector2d& drag_offset() const { return drag_offset_; }
+ bool IsActive() const;
- void Drag(Surface* surface, const gfx::Vector2d& offset);
+ // ash::ToplevelWindowDragDelegate:
+ void OnToplevelWindowDragStarted(const gfx::PointF& start_location,
+ ui::mojom::DragEventSource source) override;
+ int OnToplevelWindowDragDropped() override;
+ void OnToplevelWindowDragCancelled() override;
+ void OnToplevelWindowDragEvent(ui::LocatedEvent* event) override;
- private:
// DataSourceObserver:
void OnDataSourceDestroying(DataSource* source) override;
+ aura::Window* GetDraggedWindowForTesting();
+ base::Optional<gfx::Vector2d> GetDragOffsetForTesting() const;
+
+ private:
+ class DraggedWindowHolder;
+
+ void MaybeLockCursor();
+ void UnlockCursor();
+ void StartDrag(aura::Window* toplevel,
+ const gfx::PointF& pointer_location_in_screen);
+ void OnDraggedWindowVisibilityChanging(bool visible);
+ gfx::Point CalculateOrigin(aura::Window* target) const;
+ void Cleanup();
+
+ static ExtendedDragSource* instance_;
+
+ DataSource* source_ = nullptr;
+
// Created and destroyed at wayland/zcr_extended_drag.cc and its lifetime is
// tied to the zcr_extended_drag_source_v1 object it's attached to.
Delegate* const delegate_;
- Seat* const seat_;
- DataSource* source_ = nullptr;
- Surface* dragged_surface_ = nullptr;
- gfx::Vector2d drag_offset_;
+ gfx::PointF pointer_location_;
+ ui::mojom::DragEventSource drag_event_source_;
+ bool cursor_locked_ = false;
+
+ std::unique_ptr<DraggedWindowHolder> dragged_window_holder_;
+ std::unique_ptr<aura::ScopedWindowEventTargetingBlocker> event_blocker_;
+
base::ObserverList<Observer>::Unchecked observers_;
+
+ base::WeakPtrFactory<ExtendedDragSource> weak_factory_{this};
};
} // namespace exo
diff --git a/chromium/components/exo/extended_drag_source_unittest.cc b/chromium/components/exo/extended_drag_source_unittest.cc
new file mode 100644
index 00000000000..a7d6b0041df
--- /dev/null
+++ b/chromium/components/exo/extended_drag_source_unittest.cc
@@ -0,0 +1,288 @@
+// Copyright 2020 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/exo/extended_drag_source.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/drag_drop/drag_drop_controller.h"
+#include "ash/drag_drop/toplevel_window_drag_delegate.h"
+#include "ash/shell.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/exo/buffer.h"
+#include "components/exo/data_source.h"
+#include "components/exo/data_source_delegate.h"
+#include "components/exo/seat.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+namespace exo {
+namespace {
+
+class TestDataSourceDelegate : public DataSourceDelegate {
+ public:
+ TestDataSourceDelegate() {}
+ TestDataSourceDelegate(const TestDataSourceDelegate&) = delete;
+ TestDataSourceDelegate& operator=(const TestDataSourceDelegate&) = delete;
+ ~TestDataSourceDelegate() override = default;
+
+ bool cancelled() const { return cancelled_; }
+
+ // Overridden from DataSourceDelegate:
+ void OnDataSourceDestroying(DataSource* device) override { delete this; }
+ void OnTarget(const base::Optional<std::string>& mime_type) override {}
+ void OnSend(const std::string& mime_type, base::ScopedFD fd) override {}
+ void OnCancelled() override { cancelled_ = true; }
+ void OnDndDropPerformed() override {}
+ void OnDndFinished() override { finished_ = true; }
+ void OnAction(DndAction dnd_action) override {}
+ bool CanAcceptDataEventsForSurface(Surface* surface) const override {
+ return true;
+ }
+
+ private:
+ bool cancelled_ = false;
+ bool finished_ = false;
+};
+
+class TestExtendedDragSourceDelegate : public ExtendedDragSource::Delegate {
+ public:
+ TestExtendedDragSourceDelegate(bool allow_drop_no_target, bool lock_cursor)
+ : allow_drap_no_target_(allow_drop_no_target),
+ lock_cursor_(lock_cursor) {}
+ TestExtendedDragSourceDelegate(const TestExtendedDragSourceDelegate&) =
+ delete;
+ TestExtendedDragSourceDelegate& operator=(
+ const TestExtendedDragSourceDelegate&) = delete;
+ ~TestExtendedDragSourceDelegate() override = default;
+
+ // ExtendedDragSource::Delegate:
+ bool ShouldAllowDropAnywhere() const override {
+ return allow_drap_no_target_;
+ }
+
+ bool ShouldLockCursor() const override { return lock_cursor_; }
+
+ void OnSwallowed(const std::string& mime_type) override {
+ ASSERT_FALSE(swallowed_);
+ swallowed_ = true;
+ }
+
+ void OnUnswallowed(const std::string& mime_type,
+ const gfx::Vector2d& offset) override {
+ ASSERT_TRUE(swallowed_);
+ swallowed_ = false;
+ }
+
+ void OnDataSourceDestroying() override { delete this; }
+
+ private:
+ const bool allow_drap_no_target_;
+ const bool lock_cursor_;
+
+ bool swallowed_ = true;
+};
+
+class ExtendedDragSourceTest : public test::ExoTestBase {
+ public:
+ ExtendedDragSourceTest() {}
+ ExtendedDragSourceTest(const ExtendedDragSourceTest&) = delete;
+ ExtendedDragSourceTest& operator=(const ExtendedDragSourceTest&) = delete;
+ ~ExtendedDragSourceTest() override = default;
+
+ void SetUp() override {
+ test::ExoTestBase::SetUp();
+ drag_drop_controller_ = static_cast<ash::DragDropController*>(
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()));
+ ASSERT_TRUE(drag_drop_controller_);
+ drag_drop_controller_->set_should_block_during_drag_drop(false);
+ drag_drop_controller_->set_enabled(true);
+
+ seat_ = std::make_unique<Seat>();
+ data_source_ = std::make_unique<DataSource>(new TestDataSourceDelegate);
+ extended_drag_source_ = std::make_unique<ExtendedDragSource>(
+ data_source_.get(), new TestExtendedDragSourceDelegate(
+ /*allow_drop_no_target=*/true,
+ /*lock_cursor=*/true));
+ }
+
+ void TearDown() override {
+ extended_drag_source_.reset();
+ data_source_.reset();
+ seat_.reset();
+ test::ExoTestBase::TearDown();
+ }
+
+ protected:
+ void StartExtendedDragSession(aura::Window* origin,
+ gfx::Point start_location,
+ int operation,
+ ui::mojom::DragEventSource source) {
+ auto data = std::make_unique<ui::OSExchangeData>();
+ data->SetString(base::UTF8ToUTF16("I am being dragged"));
+ drag_drop_controller_->set_toplevel_window_drag_delegate(
+ extended_drag_source_.get());
+ drag_drop_controller_->StartDragAndDrop(std::move(data),
+ origin->GetRootWindow(), origin,
+ start_location, operation, source);
+ }
+
+ std::unique_ptr<Buffer> CreateBuffer(gfx::Size size) {
+ return std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(size));
+ }
+
+ ash::DragDropController* drag_drop_controller_ = nullptr;
+ std::unique_ptr<Seat> seat_;
+ std::unique_ptr<DataSource> data_source_;
+ std::unique_ptr<ExtendedDragSource> extended_drag_source_;
+};
+
+} // namespace
+
+TEST_F(ExtendedDragSourceTest, DestroySource) {
+ Surface origin;
+ TestFileHelper file_helper;
+
+ // Give |origin| a root window and start DragDropOperation.
+ GetContext()->AddChild(origin.window());
+ seat_->StartDrag(&file_helper, data_source_.get(), &origin, /*icon=*/nullptr,
+ ui::mojom::DragEventSource::kMouse);
+
+ // Ensure that destroying the data source invalidates its extended_drag_source
+ // counterpart for the rest of its lifetime.
+ EXPECT_TRUE(seat_->get_drag_drop_operation_for_testing());
+ EXPECT_TRUE(extended_drag_source_->IsActive());
+ data_source_.reset();
+ EXPECT_FALSE(seat_->get_drag_drop_operation_for_testing());
+ EXPECT_FALSE(extended_drag_source_->IsActive());
+}
+
+TEST_F(ExtendedDragSourceTest, DragSurfaceAlreadyMapped) {
+ // Create and map a toplevel shell surface.
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ auto buffer = CreateBuffer({32, 32});
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ gfx::Point origin(0, 0);
+ shell_surface->GetWidget()->SetBounds(gfx::Rect(origin, buffer->GetSize()));
+ EXPECT_EQ(origin, surface->window()->GetBoundsInRootWindow().origin());
+
+ // Set it as the dragged surface when it's already mapped. This allows clients
+ // to set existing/visible windows as the dragged surface and possibly
+ // snapping it to another surface, which is required for Chrome's tab drag use
+ // case, for example.
+ aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+ extended_drag_source_->Drag(surface.get(), gfx::Vector2d());
+ EXPECT_EQ(window, extended_drag_source_->GetDraggedWindowForTesting());
+ EXPECT_TRUE(extended_drag_source_->GetDragOffsetForTesting().has_value());
+ EXPECT_EQ(gfx::Vector2d(0, 0),
+ *extended_drag_source_->GetDragOffsetForTesting());
+
+ // Start the DND + extended-drag session.
+ StartExtendedDragSession(window, gfx::Point(0, 0),
+ ui::DragDropTypes::DRAG_MOVE,
+ ui::mojom::DragEventSource::kMouse);
+
+ // Verify that dragging it by 190,190, with the current pointer location being
+ // 10,10 will set the dragged window bounds as expected.
+ ui::test::EventGenerator generator(GetContext(), gfx::Point(10, 10));
+ generator.DragMouseBy(190, 190);
+ EXPECT_EQ(gfx::Point(200, 200), window->GetBoundsInScreen().origin());
+}
+
+TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet) {
+ // Create and Map the drag origin surface
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ auto buffer = CreateBuffer({32, 32});
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ // Start the DND + extended-drag session.
+ StartExtendedDragSession(shell_surface->GetWidget()->GetNativeWindow(),
+ gfx::Point(0, 0), ui::DragDropTypes::DRAG_MOVE,
+ ui::mojom::DragEventSource::kMouse);
+
+ // Create a new surface to emulate a "detachment" process.
+ auto detached_surface = std::make_unique<Surface>();
+ auto detached_shell_surface =
+ std::make_unique<ShellSurface>(detached_surface.get());
+
+ // Set |surface| as the dragged surface while it's still unmapped/invisible.
+ // This can be used to implement tab detaching in Chrome's tab drag use case,
+ // for example. Extended drag source will monitor surface mapping and it's
+ // expected to position it correctly using the provided drag offset here
+ // relative to the current pointer location.
+ extended_drag_source_->Drag(detached_surface.get(), gfx::Vector2d(10, 10));
+ EXPECT_FALSE(extended_drag_source_->GetDraggedWindowForTesting());
+ EXPECT_TRUE(extended_drag_source_->GetDragOffsetForTesting().has_value());
+ EXPECT_EQ(gfx::Vector2d(10, 10),
+ *extended_drag_source_->GetDragOffsetForTesting());
+
+ // Map the |detached_surface|.
+ auto detached_buffer = CreateBuffer({50, 50});
+ detached_surface->Attach(detached_buffer.get());
+ detached_surface->Commit();
+
+ // Ensure the toplevel window for the dragged surface set above, is correctly
+ // detected, after it's mapped.
+ aura::Window* window = detached_shell_surface->GetWidget()->GetNativeWindow();
+ EXPECT_TRUE(extended_drag_source_->GetDraggedWindowForTesting());
+ EXPECT_EQ(window, extended_drag_source_->GetDraggedWindowForTesting());
+
+ // Verify that dragging it by 100,100, with drag offset 10,10 and current
+ // pointer location 50,50 will set the dragged window bounds as expected.
+ ui::test::EventGenerator generator(GetContext());
+ generator.set_current_screen_location(gfx::Point(100, 100));
+ generator.DragMouseBy(50, 50);
+ EXPECT_EQ(gfx::Point(140, 140), window->GetBoundsInScreen().origin());
+}
+
+TEST_F(ExtendedDragSourceTest, DestroyDraggedSurfaceWhileDragging) {
+ // Create and map a toplevel shell surface.
+ gfx::Size buffer_size(32, 32);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ gfx::Point origin(0, 0);
+ shell_surface->GetWidget()->SetBounds(gfx::Rect(origin, buffer_size));
+ EXPECT_EQ(origin, surface->window()->GetBoundsInRootWindow().origin());
+
+ // Start dragging |surface|'s window.
+ extended_drag_source_->Drag(surface.get(), gfx::Vector2d());
+ aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+ EXPECT_EQ(window, extended_drag_source_->GetDraggedWindowForTesting());
+
+ // Make sure extended drag source gracefully handles window destruction during
+ // while the drag session is still alive.
+ shell_surface.reset();
+ EXPECT_TRUE(surface->window()->GetBoundsInScreen().origin().IsOrigin());
+
+ ui::test::EventGenerator generator(GetContext());
+ generator.DragMouseBy(190, 190);
+ EXPECT_TRUE(surface->window()->GetBoundsInScreen().origin().IsOrigin());
+}
+
+} // namespace exo
diff --git a/chromium/components/exo/file_helper.h b/chromium/components/exo/file_helper.h
index 80c746badea..94a1964d936 100644
--- a/chromium/components/exo/file_helper.h
+++ b/chromium/components/exo/file_helper.h
@@ -6,46 +6,60 @@
#define COMPONENTS_EXO_FILE_HELPER_H_
#include <string>
+#include <vector>
-class GURL;
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
-namespace base {
-class FilePath;
+namespace aura {
+class Window;
}
+namespace base {
+class Pickle;
+class RefCountedMemory;
+} // namespace base
+
+namespace ui {
+struct FileInfo;
+} // namespace ui
+
namespace exo {
+// Handles file-related translations for wayland clipboard and drag-and-drop.
class FileHelper {
public:
virtual ~FileHelper() {}
- // Returns mime type which is used for list of Uris returned by this
- // FileHelper.
- virtual std::string GetMimeTypeForUriList() const = 0;
+ // Read filenames from |data| which was provided by source window |source|.
+ // Translates paths from source to host format.
+ virtual std::vector<ui::FileInfo> GetFilenames(
+ aura::Window* source,
+ const std::vector<uint8_t>& data) const = 0;
+
+ // Returns the mime type which is used by target window |target| for a list of
+ // file path URIs.
+ virtual std::string GetMimeTypeForUriList(aura::Window* target) const = 0;
- // Converts native file path to URL which can be used by application with
- // |app_id|. We don't expose enter file system to a container directly.
- // Instead we mount specific directory in the containers' namespace. Thus we
- // need to convert native path to file URL which points mount point in
- // containers. The conversion should be container specific, now we only have
- // ARC container though.
- virtual bool GetUrlFromPath(const std::string& app_id,
- const base::FilePath& path,
- GURL* out) = 0;
+ // Sends the given file list |files| to target window |target| window.
+ // Translates paths from host format to the target and performs any required
+ // file sharing for VMs.
+ using SendDataCallback =
+ base::OnceCallback<void(scoped_refptr<base::RefCountedMemory>)>;
+ virtual void SendFileInfo(aura::Window* target,
+ const std::vector<ui::FileInfo>& files,
+ SendDataCallback callback) const = 0;
// Takes in |pickle| constructed by the web contents view and returns true if
// it contains any valid filesystem URLs.
- virtual bool HasUrlsInPickle(const base::Pickle& pickle) = 0;
-
- using UrlsFromPickleCallback =
- base::OnceCallback<void(const std::vector<GURL>& urls)>;
+ virtual bool HasUrlsInPickle(const base::Pickle& pickle) const = 0;
- // Takes in |pickle| constructed by the web contents view, reads filesystem
- // URLs from it and converts the URLs to something that applications can
- // understand. e.g. content:// URI for Android apps.
- virtual void GetUrlsFromPickle(const std::string& app_id,
- const base::Pickle& pickle,
- UrlsFromPickleCallback callback) = 0;
+ // Takes in |pickle| constructed by the web contents view containing
+ // filesystem URLs. Provides translations for the specified target window
+ // |target| and performs any required file sharing for VMs..
+ virtual void SendPickle(aura::Window* target,
+ const base::Pickle& pickle,
+ SendDataCallback callback) = 0;
};
} // namespace exo
diff --git a/chromium/components/exo/keyboard.cc b/chromium/components/exo/keyboard.cc
index 24b7438d185..8e6830dd9b1 100644
--- a/chromium/components/exo/keyboard.cc
+++ b/chromium/components/exo/keyboard.cc
@@ -141,15 +141,21 @@ bool ProcessAcceleratorIfReserved(Surface* surface, ui::KeyEvent* event) {
return IsReservedAccelerator(event) && ProcessAccelerator(surface, event);
}
-// Returns true if surface belongs to an ARC application.
+// Returns true if the surface needs to support IME.
// TODO(yhanada, https://crbug.com/847500): Remove this when we find a way
-// to fix https://crbug.com/847500 without breaking ARC++ apps.
-bool IsArcSurface(Surface* surface) {
+// to fix https://crbug.com/847500 without breaking ARC apps/Lacros browser.
+bool IsImeSupportedSurface(Surface* surface) {
aura::Window* window = surface->window();
for (; window; window = window->parent()) {
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
- return true;
+ const auto app_type =
+ static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
+ switch (app_type) {
+ case ash::AppType::ARC_APP:
+ case ash::AppType::LACROS:
+ return true;
+ default:
+ // Do nothing.
+ break;
}
}
return false;
@@ -284,12 +290,18 @@ void Keyboard::OnKeyEvent(ui::KeyEvent* event) {
// Ensured by the observer registration order.
delegate_->OnKeyboardModifiers(seat_->xkb_tracker()->GetModifiers());
+ // Currently, physical keycode is tracked in Seat, assuming that the
+ // Keyboard::OnKeyEvent is called between Seat::WillProcessEvent and
+ // Seat::DidProcessEvent. However, if IME is enabled, it is no longer true,
+ // because IME work in async approach, and on its dispatching, call stack
+ // is split so actually Keyboard::OnKeyEvent is called after
+ // Seat::DidProcessEvent.
// TODO(yhanada): This is a quick fix for https://crbug.com/859071. Remove
- // ARC-specific code path once we can find a way to manage press/release
- // events pair for synthetic events.
+ // ARC-/Lacros-specific code path once we can find a way to manage
+ // press/release events pair for synthetic events.
ui::DomCode physical_code =
seat_->physical_code_for_currently_processing_event();
- if (physical_code == ui::DomCode::NONE && focus_belongs_to_arc_app_) {
+ if (physical_code == ui::DomCode::NONE && focused_on_ime_supported_surface_) {
// This key event is a synthetic event.
// Consider DomCode field of the event as a physical code
// for synthetic events when focus surface belongs to an ARC application.
@@ -426,7 +438,7 @@ void Keyboard::SetFocus(Surface* surface) {
delegate_->OnKeyboardEnter(surface, pressed_keys_);
focus_ = surface;
focus_->AddSurfaceObserver(this);
- focus_belongs_to_arc_app_ = IsArcSurface(surface);
+ focused_on_ime_supported_surface_ = IsImeSupportedSurface(surface);
}
}
diff --git a/chromium/components/exo/keyboard.h b/chromium/components/exo/keyboard.h
index 98bdf734548..8bde23a5fd8 100644
--- a/chromium/components/exo/keyboard.h
+++ b/chromium/components/exo/keyboard.h
@@ -130,7 +130,7 @@ class Keyboard : public ui::EventHandler,
// True when the ARC app window is focused.
// TODO(yhanada, https://crbug.com/847500): Remove this when we find a way to
// fix https://crbug.com/847500 without breaking ARC++ apps.
- bool focus_belongs_to_arc_app_ = false;
+ bool focused_on_ime_supported_surface_ = false;
base::ObserverList<KeyboardObserver>::Unchecked observer_list_;
diff --git a/chromium/components/exo/mock_vsync_timing_observer.cc b/chromium/components/exo/mock_vsync_timing_observer.cc
new file mode 100644
index 00000000000..b895019abbc
--- /dev/null
+++ b/chromium/components/exo/mock_vsync_timing_observer.cc
@@ -0,0 +1,13 @@
+// Copyright 2020 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/exo/mock_vsync_timing_observer.h"
+
+namespace exo {
+
+MockVSyncTimingObserver::MockVSyncTimingObserver() = default;
+
+MockVSyncTimingObserver::~MockVSyncTimingObserver() = default;
+
+} // namespace exo
diff --git a/chromium/components/exo/mock_vsync_timing_observer.h b/chromium/components/exo/mock_vsync_timing_observer.h
new file mode 100644
index 00000000000..1b9ca660872
--- /dev/null
+++ b/chromium/components/exo/mock_vsync_timing_observer.h
@@ -0,0 +1,26 @@
+// Copyright 2020 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_EXO_MOCK_VSYNC_TIMING_OBSERVER_H_
+#define COMPONENTS_EXO_MOCK_VSYNC_TIMING_OBSERVER_H_
+
+#include "components/exo/vsync_timing_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace exo {
+
+class MockVSyncTimingObserver : public VSyncTimingManager::Observer {
+ public:
+ MockVSyncTimingObserver();
+ ~MockVSyncTimingObserver() override;
+
+ MOCK_METHOD(void,
+ OnUpdateVSyncParameters,
+ (base::TimeTicks timebase, base::TimeDelta interval),
+ (override));
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_MOCK_VSYNC_TIMING_OBSERVER_H_
diff --git a/chromium/components/exo/notification_unittest.cc b/chromium/components/exo/notification_unittest.cc
index 8fdbaaf78f5..aaca5bf6aca 100644
--- a/chromium/components/exo/notification_unittest.cc
+++ b/chromium/components/exo/notification_unittest.cc
@@ -5,8 +5,8 @@
#include "components/exo/notification.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "ui/message_center/message_center.h"
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index aaeeef03f3b..1d88b9f4784 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -30,8 +30,9 @@
#include "ui/base/cursor/cursor_size.h"
#include "ui/base/cursor/cursor_util.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/layout.h"
+#include "ui/base/resource/scale_factor.h"
#include "ui/display/manager/display_manager.h"
-#include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
@@ -113,7 +114,6 @@ Pointer::Pointer(PointerDelegate* delegate, Seat* seat)
seat_(seat),
cursor_(ui::mojom::CursorType::kNull),
capture_scale_(GetCaptureDisplayInfo().device_scale_factor()),
- capture_ratio_(GetCaptureDisplayInfo().GetDensityRatio()),
cursor_capture_source_id_(base::UnguessableToken::Create()) {
WMHelper* helper = WMHelper::GetInstance();
helper->AddPreTargetHandler(this);
@@ -597,7 +597,6 @@ void Pointer::OnCursorDisplayChanged(const display::Display& display) {
UpdatePointerSurface(root_surface());
auto info = GetCaptureDisplayInfo();
capture_scale_ = info.device_scale_factor();
- capture_ratio_ = info.GetDensityRatio();
auto* cursor_client = WMHelper::GetInstance()->GetCursorClient();
// TODO(crbug.com/631103): CursorClient does not exist in mash yet.
@@ -746,14 +745,16 @@ void Pointer::UpdateCursor() {
if (cursor_ == ui::mojom::CursorType::kCustom) {
SkBitmap bitmap = cursor_bitmap_;
gfx::Point hotspot =
- gfx::ScaleToFlooredPoint(cursor_hotspot_, capture_ratio_);
+ gfx::ScaleToFlooredPoint(cursor_hotspot_, capture_scale_);
// TODO(oshima|weidongg): Add cutsom cursor API to handle size/display
// change without explicit management like this. https://crbug.com/721601.
- const display::Display& display = cursor_client->GetDisplay();
- float scale =
- helper->GetDisplayInfo(display.id()).GetDensityRatio() / capture_ratio_;
+ // Scaling bitmap to match the corresponding supported scale factor of ash.
+ const display::Display& display = cursor_client->GetDisplay();
+ float scale = ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(
+ display.device_scale_factor())) /
+ capture_scale_;
if (cursor_client->GetCursorSize() == ui::CursorSize::kLarge)
scale *= kLargeCursorScale;
@@ -766,8 +767,8 @@ void Pointer::UpdateCursor() {
// TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
// and use that here instead of the current bitmap API.
// https://crbug.com/686600
- platform_cursor =
- ui::CursorFactory::GetInstance()->CreateImageCursor(bitmap, hotspot);
+ platform_cursor = ui::CursorFactory::GetInstance()->CreateImageCursor(
+ cursor_.type(), bitmap, hotspot);
cursor_.SetPlatformCursor(platform_cursor);
cursor_.set_custom_bitmap(bitmap);
cursor_.set_custom_hotspot(hotspot);
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index 3211c400804..b1bcbd7f18b 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -211,10 +211,6 @@ class Pointer : public SurfaceTreeHost,
// Scale at which cursor snapshot is captured.
float capture_scale_;
- // Density ratio of the cursor snapshot. The bitmap is scaled on displays with
- // a different ratio.
- float capture_ratio_;
-
// Source used for cursor capture copy output requests.
const base::UnguessableToken cursor_capture_source_id_;
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index 30adb7c8643..da10ec00a21 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -23,6 +23,7 @@
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/service/surfaces/surface.h"
@@ -941,6 +942,7 @@ TEST_F(PointerTest, DragDropAbort) {
TestDataSourceDelegate data_source_delegate;
DataSource source(&data_source_delegate);
Surface origin, icon;
+ TestFileHelper file_helper;
// Make origin into a real window so the pointer can click it
ShellSurface shell_surface(&origin);
@@ -956,7 +958,8 @@ TEST_F(PointerTest, DragDropAbort) {
EXPECT_CALL(pointer_delegate, OnPointerEnter(&origin, gfx::PointF(), 0));
generator.MoveMouseTo(origin.window()->GetBoundsInScreen().origin());
- seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse);
+ seat.StartDrag(&file_helper, &source, &origin, &icon,
+ ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
EXPECT_CALL(pointer_delegate, OnPointerButton).Times(2);
diff --git a/chromium/components/exo/seat.cc b/chromium/components/exo/seat.cc
index 6b8c9db181f..2a0cd99fbf1 100644
--- a/chromium/components/exo/seat.cc
+++ b/chromium/components/exo/seat.cc
@@ -14,7 +14,7 @@
#include "base/auto_reset.h"
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
@@ -28,9 +28,9 @@
#include "components/exo/xkb_tracker.h"
#include "services/data_decoder/public/cpp/decode_image.h"
#include "ui/aura/client/focus_client.h"
-#include "ui/base/clipboard/clipboard_data_endpoint.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/events/event_utils.h"
#include "ui/events/platform/platform_event_source.h"
@@ -105,13 +105,14 @@ Surface* Seat::GetFocusedSurface() {
return GetEffectiveFocus(WMHelper::GetInstance()->GetFocusedWindow());
}
-void Seat::StartDrag(DataSource* source,
+void Seat::StartDrag(FileHelper* file_helper,
+ DataSource* source,
Surface* origin,
Surface* icon,
ui::mojom::DragEventSource event_source) {
// DragDropOperation manages its own lifetime.
drag_drop_operation_ = DragDropOperation::Create(
- source, origin, icon, last_pointer_location_, event_source);
+ file_helper, source, origin, icon, last_pointer_location_, event_source);
}
void Seat::SetLastPointerLocation(const gfx::PointF& last_pointer_location) {
@@ -151,6 +152,8 @@ void Seat::SetSelection(DataSource* source) {
data_read_callback),
base::BindOnce(&Seat::OnImageRead, weak_ptr_factory_.GetWeakPtr(), writer,
data_read_callback),
+ base::BindOnce(&Seat::OnFilenamesRead, weak_ptr_factory_.GetWeakPtr(),
+ writer, data_read_callback),
data_read_callback);
}
@@ -160,7 +163,7 @@ class Seat::RefCountedScopedClipboardWriter
public:
explicit RefCountedScopedClipboardWriter()
: ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste,
- std::make_unique<ui::ClipboardDataEndpoint>(
+ std::make_unique<ui::DataTransferEndpoint>(
ui::EndpointType::kGuestOs)) {}
private:
@@ -218,6 +221,14 @@ void Seat::OnImageDecoded(base::OnceClosure callback,
}
#endif // defined(OS_CHROMEOS)
+void Seat::OnFilenamesRead(
+ scoped_refptr<RefCountedScopedClipboardWriter> writer,
+ base::OnceClosure callback,
+ const std::string& mime_type,
+ const std::vector<uint8_t>& data) {
+ std::move(callback).Run();
+}
+
void Seat::OnAllReadsFinished(
scoped_refptr<RefCountedScopedClipboardWriter> writer) {
// We need to destroy the ScopedClipboardWriter in this call, before
diff --git a/chromium/components/exo/seat.h b/chromium/components/exo/seat.h
index 348f1f13c4f..ff6860a4b7c 100644
--- a/chromium/components/exo/seat.h
+++ b/chromium/components/exo/seat.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_EXO_SEAT_H_
#define COMPONENTS_EXO_SEAT_H_
+#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
@@ -30,14 +31,15 @@ class KeyEvent;
namespace exo {
class DragDropOperation;
+class FileHelper;
class ScopedDataSource;
class SeatObserver;
class Surface;
class XkbTracker;
// The maximum number of different data types that we will write to the
-// clipboard (plain text, RTF, HTML, image)
-constexpr int kMaxClipboardDataTypes = 4;
+// clipboard (plain text, RTF, HTML, image, text/uri-list)
+constexpr int kMaxClipboardDataTypes = 5;
// Seat object represent a group of input devices such as keyboard, pointer and
// touch devices and keeps track of input focus.
@@ -79,7 +81,8 @@ class Seat : public aura::client::FocusChangeObserver,
// Sets clipboard data from |source|.
void SetSelection(DataSource* source);
- void StartDrag(DataSource* source,
+ void StartDrag(FileHelper* file_helper,
+ DataSource* source,
Surface* origin,
Surface* icon,
ui::mojom::DragEventSource event_source);
@@ -151,6 +154,10 @@ class Seat : public aura::client::FocusChangeObserver,
scoped_refptr<RefCountedScopedClipboardWriter> writer,
const SkBitmap& bitmap);
#endif // defined(OS_CHROMEOS)
+ void OnFilenamesRead(scoped_refptr<RefCountedScopedClipboardWriter> writer,
+ base::OnceClosure callback,
+ const std::string& mime_type,
+ const std::vector<uint8_t>& data);
void OnAllReadsFinished(
scoped_refptr<RefCountedScopedClipboardWriter> writer);
diff --git a/chromium/components/exo/seat_unittest.cc b/chromium/components/exo/seat_unittest.cc
index bde042f13a3..d5a55ef3eba 100644
--- a/chromium/components/exo/seat_unittest.cc
+++ b/chromium/components/exo/seat_unittest.cc
@@ -13,6 +13,7 @@
#include "components/exo/seat_observer.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
@@ -488,11 +489,13 @@ TEST_F(SeatTest, DragDropAbort) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
Surface origin, icon;
+ TestFileHelper file_helper;
// Give origin a root window for DragDropOperation.
GetContext()->AddChild(origin.window());
- seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse);
+ seat.StartDrag(&file_helper, &source, &origin, &icon,
+ ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
seat.AbortPendingDragOperation();
EXPECT_FALSE(seat.get_drag_drop_operation_for_testing());
diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc
index 4ca1923ee4b..6d738ebc004 100644
--- a/chromium/components/exo/shell_surface.cc
+++ b/chromium/components/exo/shell_surface.cc
@@ -5,7 +5,6 @@
#include "components/exo/shell_surface.h"
#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/cpp/window_state_type.h"
#include "ash/scoped_animation_disabler.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
@@ -15,6 +14,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ui/base/window_state_type.h"
#include "components/exo/shell_surface_util.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
@@ -386,16 +386,17 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
////////////////////////////////////////////////////////////////////////////////
// ash::WindowStateObserver overrides:
-void ShellSurface::OnPreWindowStateTypeChange(ash::WindowState* window_state,
- ash::WindowStateType old_type) {
- ash::WindowStateType new_type = window_state->GetStateType();
- if (ash::IsMinimizedWindowStateType(old_type) ||
- ash::IsMinimizedWindowStateType(new_type)) {
+void ShellSurface::OnPreWindowStateTypeChange(
+ ash::WindowState* window_state,
+ chromeos::WindowStateType old_type) {
+ chromeos::WindowStateType new_type = window_state->GetStateType();
+ if (chromeos::IsMinimizedWindowStateType(old_type) ||
+ chromeos::IsMinimizedWindowStateType(new_type)) {
return;
}
- if (ash::IsMaximizedOrFullscreenOrPinnedWindowStateType(old_type) ||
- ash::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
+ if (chromeos::IsMaximizedOrFullscreenOrPinnedWindowStateType(old_type) ||
+ chromeos::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
if (!widget_)
return;
// When transitioning in/out of maximized or fullscreen mode, we need to
@@ -418,10 +419,11 @@ void ShellSurface::OnPreWindowStateTypeChange(ash::WindowState* window_state,
}
}
-void ShellSurface::OnPostWindowStateTypeChange(ash::WindowState* window_state,
- ash::WindowStateType old_type) {
- ash::WindowStateType new_type = window_state->GetStateType();
- if (ash::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
+void ShellSurface::OnPostWindowStateTypeChange(
+ ash::WindowState* window_state,
+ chromeos::WindowStateType old_type) {
+ chromeos::WindowStateType new_type = window_state->GetStateType();
+ if (chromeos::IsMaximizedOrFullscreenOrPinnedWindowStateType(new_type)) {
Configure();
}
@@ -499,32 +501,28 @@ bool ShellSurface::OnPreWidgetCommit() {
////////////////////////////////////////////////////////////////////////////////
// ShellSurface, private:
-void ShellSurface::SetParentWindow(aura::Window* parent) {
- if (parent_) {
- parent_->RemoveObserver(this);
+void ShellSurface::SetParentWindow(aura::Window* new_parent) {
+ if (parent()) {
+ parent()->RemoveObserver(this);
if (widget_) {
aura::Window* child_window = widget_->GetNativeWindow();
wm::TransientWindowManager::GetOrCreate(child_window)
->set_parent_controls_visibility(false);
- wm::RemoveTransientChild(parent_, child_window);
+ wm::RemoveTransientChild(parent(), child_window);
}
}
- parent_ = parent;
- if (parent_) {
- parent_->AddObserver(this);
+ SetParentInternal(new_parent);
+ if (parent()) {
+ parent()->AddObserver(this);
MaybeMakeTransient();
}
-
- // If |parent_| is set effects the ability to maximize the window.
- if (widget_)
- widget_->OnSizeConstraintsChanged();
}
void ShellSurface::MaybeMakeTransient() {
- if (!parent_ || !widget_)
+ if (!parent() || !widget_)
return;
aura::Window* child_window = widget_->GetNativeWindow();
- wm::AddTransientChild(parent_, child_window);
+ wm::AddTransientChild(parent(), child_window);
// In the case of activatable non-popups, we also want the parent to control
// the child's visibility.
if (!widget_->is_top_level() || !widget_->CanActivate())
@@ -557,9 +555,9 @@ void ShellSurface::Configure(bool ends_drag) {
GetClientViewBounds().size(), window_state->GetStateType(),
IsResizing(), widget_->IsActive(), origin_offset);
} else {
- serial =
- configure_callback_.Run(gfx::Size(), ash::WindowStateType::kNormal,
- false, false, origin_offset);
+ serial = configure_callback_.Run(gfx::Size(),
+ chromeos::WindowStateType::kNormal,
+ false, false, origin_offset);
}
}
diff --git a/chromium/components/exo/shell_surface.h b/chromium/components/exo/shell_surface.h
index c04db23326c..056114a1e36 100644
--- a/chromium/components/exo/shell_surface.h
+++ b/chromium/components/exo/shell_surface.h
@@ -43,7 +43,7 @@ class ShellSurface : public ShellSurfaceBase, public ash::WindowStateObserver {
// in steps of NxM pixels).
using ConfigureCallback =
base::RepeatingCallback<uint32_t(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset)>;
@@ -112,9 +112,9 @@ class ShellSurface : public ShellSurfaceBase, public ash::WindowStateObserver {
// Overridden from ash::WindowStateObserver:
void OnPreWindowStateTypeChange(ash::WindowState* window_state,
- ash::WindowStateType old_type) override;
+ chromeos::WindowStateType old_type) override;
void OnPostWindowStateTypeChange(ash::WindowState* window_state,
- ash::WindowStateType old_type) override;
+ chromeos::WindowStateType old_type) override;
// Overridden from wm::ActivationChangeObserver:
void OnWindowActivated(ActivationReason reason,
diff --git a/chromium/components/exo/shell_surface_base.cc b/chromium/components/exo/shell_surface_base.cc
index ecd10962f22..7c4b1a53805 100644
--- a/chromium/components/exo/shell_surface_base.cc
+++ b/chromium/components/exo/shell_surface_base.cc
@@ -9,9 +9,7 @@
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/cpp/window_pin_type.h"
#include "ash/public/cpp/window_properties.h"
-#include "ash/public/cpp/window_state_type.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/drag_window_resizer.h"
@@ -26,6 +24,10 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "cc/trees/layer_tree_frame_sink.h"
+#include "chromeos/crosapi/cpp/crosapi_constants.h"
+#include "chromeos/ui/base//window_properties.h"
+#include "chromeos/ui/base/window_pin_type.h"
+#include "chromeos/ui/base/window_state_type.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
@@ -66,6 +68,11 @@ void SetSkipImeProcessingToDescendentSurfaces(aura::Window* window) {
SetSkipImeProcessingToDescendentSurfaces(child);
}
+// Returns true, if the given ID represents Lacros.
+bool IsLacrosAppId(base::StringPiece app_id) {
+ return base::StartsWith(app_id, crosapi::kLacrosAppIdPrefix);
+}
+
// The accelerator keys used to close ShellSurfaces.
const struct {
ui::KeyboardCode keycode;
@@ -317,6 +324,9 @@ ShellSurfaceBase::ShellSurfaceBase(Surface* surface,
host_window()->Show();
set_owned_by_client();
+ SetCanMinimize(can_minimize_);
+ SetCanMaximize(ash::desks_util::IsDeskContainerId(container_));
+ SetCanResize(true);
SetShowTitle(false);
}
@@ -409,8 +419,11 @@ void ShellSurfaceBase::SetApplicationId(const char* application_id) {
else
application_id_.reset();
- if (widget_ && widget_->GetNativeWindow())
+ if (widget_ && widget_->GetNativeWindow()) {
SetShellApplicationId(widget_->GetNativeWindow(), application_id_);
+ if (application_id_.has_value() && IsLacrosAppId(*application_id_))
+ SetLacrosAppType(widget_->GetNativeWindow());
+ }
}
void ShellSurfaceBase::SetStartupId(const char* startup_id) {
@@ -474,8 +487,7 @@ void ShellSurfaceBase::SetActivatable(bool activatable) {
void ShellSurfaceBase::SetContainer(int container) {
TRACE_EVENT1("exo", "ShellSurfaceBase::SetContainer", "container", container);
-
- container_ = container;
+ SetContainerInternal(container);
}
void ShellSurfaceBase::SetMaximumSize(const gfx::Size& size) {
@@ -504,10 +516,12 @@ void ShellSurfaceBase::SetCanMinimize(bool can_minimize) {
can_minimize);
can_minimize_ = can_minimize;
+ WidgetDelegate::SetCanMinimize(!parent_ && can_minimize_);
}
void ShellSurfaceBase::DisableMovement() {
movement_disabled_ = true;
+ SetCanResize(false);
if (widget_)
widget_->set_movement_disabled(true);
@@ -619,9 +633,9 @@ void ShellSurfaceBase::OnSetFrameColors(SkColor active_color,
active_frame_color_ = SkColorSetA(active_color, SK_AlphaOPAQUE);
inactive_frame_color_ = SkColorSetA(inactive_color, SK_AlphaOPAQUE);
if (widget_) {
- widget_->GetNativeWindow()->SetProperty(ash::kFrameActiveColorKey,
+ widget_->GetNativeWindow()->SetProperty(chromeos::kFrameActiveColorKey,
active_frame_color_);
- widget_->GetNativeWindow()->SetProperty(ash::kFrameInactiveColorKey,
+ widget_->GetNativeWindow()->SetProperty(chromeos::kFrameInactiveColorKey,
inactive_frame_color_);
}
}
@@ -668,28 +682,6 @@ void ShellSurfaceBase::OnSurfaceDestroying(Surface* surface) {
////////////////////////////////////////////////////////////////////////////////
// views::WidgetDelegate overrides:
-bool ShellSurfaceBase::CanResize() const {
- if (movement_disabled_)
- return false;
- // The shell surface is resizable by default when min/max size is empty,
- // othersize it's resizable when min size != max size.
- return minimum_size_.IsEmpty() || minimum_size_ != maximum_size_;
-}
-
-bool ShellSurfaceBase::CanMaximize() const {
- // Shell surfaces in system modal container cannot be maximized.
- if (!ash::desks_util::IsDeskContainerId(container_))
- return false;
-
- // Non-transient shell surfaces can be maximized.
- return !parent_;
-}
-
-bool ShellSurfaceBase::CanMinimize() const {
- // Non-transient shell surfaces can be minimized.
- return !parent_ && can_minimize_;
-}
-
bool ShellSurfaceBase::OnCloseRequested(
views::Widget::ClosedReason close_reason) {
if (!pre_close_callback_.is_null())
@@ -825,12 +817,8 @@ void ShellSurfaceBase::GetAccessibleNodeData(ui::AXNodeData* node_data) {
// aura::WindowObserver overrides:
void ShellSurfaceBase::OnWindowDestroying(aura::Window* window) {
- if (window == parent_) {
- parent_ = nullptr;
- // |parent_| being set to null effects the ability to maximize the window.
- if (widget_)
- widget_->OnSizeConstraintsChanged();
- }
+ if (window == parent_)
+ SetParentInternal(nullptr);
window->RemoveObserver(this);
}
@@ -894,7 +882,7 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
// override redirect is used for menu, tooltips etc, which should be placed
// above normal windows, but below lock screen. Specify the container here
// to avoid using parent_ in params.parent.
- container_ = ash::kShellWindowId_ShelfBubbleContainer;
+ SetContainerInternal(ash::kShellWindowId_ShelfBubbleContainer);
// X11 override redirect should not be activatable.
activatable_ = false;
DisableMovement();
@@ -944,6 +932,8 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
aura::EventTargetingPolicy::kTargetAndDescendants);
InstallCustomWindowTargeter();
SetShellApplicationId(window, application_id_);
+ if (application_id_.has_value() && IsLacrosAppId(*application_id_))
+ SetLacrosAppType(window);
SetShellStartupId(window, startup_id_);
SetShellMainSurface(window, root_surface());
@@ -1095,7 +1085,7 @@ ShellSurfaceBase::CreateNonClientFrameViewInternal(views::Widget* widget,
bool client_controlled) {
aura::Window* window = widget_->GetNativeWindow();
// ShellSurfaces always use immersive mode.
- window->SetProperty(ash::kImmersiveIsActive, true);
+ window->SetProperty(chromeos::kImmersiveIsActive, true);
ash::WindowState* window_state = ash::WindowState::Get(window);
if (!frame_enabled() && !window_state->HasDelegate()) {
window_state->SetDelegate(std::make_unique<CustomWindowStateDelegate>());
@@ -1129,6 +1119,23 @@ void ShellSurfaceBase::OnPostWidgetCommit() {
shadow_bounds_changed_ = false;
}
+void ShellSurfaceBase::SetContainerInternal(int container) {
+ container_ = container;
+ WidgetDelegate::SetCanMaximize(
+ !parent_ && ash::desks_util::IsDeskContainerId(container_));
+ if (widget_)
+ widget_->OnSizeConstraintsChanged();
+}
+
+void ShellSurfaceBase::SetParentInternal(aura::Window* parent) {
+ parent_ = parent;
+ WidgetDelegate::SetCanMinimize(!parent_ && can_minimize_);
+ WidgetDelegate::SetCanMaximize(
+ !parent_ && ash::desks_util::IsDeskContainerId(container_));
+ if (widget_)
+ widget_->OnSizeConstraintsChanged();
+}
+
void ShellSurfaceBase::CommitWidget() {
// Apply new window geometry.
geometry_ = pending_geometry_;
@@ -1139,6 +1146,8 @@ void ShellSurfaceBase::CommitWidget() {
maximum_size_ != pending_maximum_size_;
minimum_size_ = pending_minimum_size_;
maximum_size_ = pending_maximum_size_;
+ SetCanResize(!movement_disabled_ &&
+ (minimum_size_.IsEmpty() || minimum_size_ != maximum_size_));
if (!widget_)
return;
diff --git a/chromium/components/exo/shell_surface_base.h b/chromium/components/exo/shell_surface_base.h
index b8f67fc307c..3ff7114cda9 100644
--- a/chromium/components/exo/shell_surface_base.h
+++ b/chromium/components/exo/shell_surface_base.h
@@ -156,9 +156,6 @@ class ShellSurfaceBase : public SurfaceTreeHost,
aura::Window* gained_capture) override;
// views::WidgetDelegate:
- bool CanResize() const override;
- bool CanMaximize() const override;
- bool CanMinimize() const override;
bool OnCloseRequested(views::Widget::ClosedReason close_reason) override;
void WindowClosing() override;
views::Widget* GetWidget() override;
@@ -242,6 +239,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
void StartCapture();
const gfx::Rect& geometry() const { return geometry_; }
+ aura::Window* parent() const { return parent_; }
// Install custom window targeter. Used to restore window targeter.
void InstallCustomWindowTargeter();
@@ -253,8 +251,10 @@ class ShellSurfaceBase : public SurfaceTreeHost,
virtual void OnPostWidgetCommit();
+ void SetParentInternal(aura::Window* window);
+ void SetContainerInternal(int container);
+
views::Widget* widget_ = nullptr;
- aura::Window* parent_ = nullptr;
bool movement_disabled_ = false;
gfx::Point origin_;
@@ -291,6 +291,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
void CommitWidget();
+ aura::Window* parent_ = nullptr;
bool activatable_ = true;
bool can_minimize_ = true;
bool has_frame_colors_ = false;
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index 84757943d99..48b97a79601 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -53,11 +53,11 @@ bool HasBackdrop() {
uint32_t ConfigureFullscreen(uint32_t serial,
const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset) {
- EXPECT_EQ(ash::WindowStateType::kFullscreen, state_type);
+ EXPECT_EQ(chromeos::WindowStateType::kFullscreen, state_type);
return serial;
}
@@ -644,11 +644,11 @@ TEST_F(ShellSurfaceTest, ForceClose) {
}
uint32_t Configure(gfx::Size* suggested_size,
- ash::WindowStateType* has_state_type,
+ chromeos::WindowStateType* has_state_type,
bool* is_resizing,
bool* is_active,
const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset) {
@@ -663,7 +663,7 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
// Must be before shell_surface so it outlives it, for shell_surface's
// destructor calls Configure() referencing these 4 variables.
gfx::Size suggested_size;
- ash::WindowStateType has_state_type = ash::WindowStateType::kNormal;
+ chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal;
bool is_resizing = false;
bool is_active = false;
@@ -692,7 +692,7 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
EXPECT_FALSE(shell_surface->GetWidget());
EXPECT_TRUE(suggested_size.IsEmpty());
- EXPECT_EQ(ash::WindowStateType::kNormal, has_state_type);
+ EXPECT_EQ(chromeos::WindowStateType::kNormal, has_state_type);
gfx::Size buffer_size(64, 64);
std::unique_ptr<Buffer> buffer(
@@ -704,7 +704,7 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
EXPECT_TRUE(shell_surface->GetWidget());
EXPECT_EQ(maximized_bounds.size(), suggested_size);
- EXPECT_EQ(ash::WindowStateType::kMaximized, has_state_type);
+ EXPECT_EQ(chromeos::WindowStateType::kMaximized, has_state_type);
shell_surface->Restore();
shell_surface->AcknowledgeConfigure(0);
// It should be restored to the original geometry size.
@@ -714,7 +714,7 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
shell_surface->AcknowledgeConfigure(0);
EXPECT_EQ(GetContext()->bounds().size().ToString(),
suggested_size.ToString());
- EXPECT_EQ(ash::WindowStateType::kFullscreen, has_state_type);
+ EXPECT_EQ(chromeos::WindowStateType::kFullscreen, has_state_type);
shell_surface->SetFullscreen(false);
shell_surface->AcknowledgeConfigure(0);
EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize());
diff --git a/chromium/components/exo/shell_surface_util.cc b/chromium/components/exo/shell_surface_util.cc
index c39d08f578a..bbe2341c6ac 100644
--- a/chromium/components/exo/shell_surface_util.cc
+++ b/chromium/components/exo/shell_surface_util.cc
@@ -23,7 +23,7 @@
#include "ui/wm/core/window_util.h"
#if defined(OS_CHROMEOS)
-#include "ash/public/cpp/window_properties.h"
+#include "chromeos/ui/base/window_properties.h"
#endif // defined(OS_CHROMEOS)
DEFINE_UI_CLASS_PROPERTY_TYPE(exo::Permission*)
@@ -97,6 +97,11 @@ void SetArcAppType(aura::Window* window) {
static_cast<int>(ash::AppType::ARC_APP));
}
+void SetLacrosAppType(aura::Window* window) {
+ window->SetProperty(aura::client::kAppType,
+ static_cast<int>(ash::AppType::LACROS));
+}
+
void SetShellStartupId(aura::Window* window,
const base::Optional<std::string>& id) {
TRACE_EVENT1("exo", "SetStartupId", "startup_id", id ? *id : "null");
@@ -113,11 +118,11 @@ const std::string* GetShellStartupId(aura::Window* window) {
void SetShellUseImmersiveForFullscreen(aura::Window* window, bool value) {
#if defined(OS_CHROMEOS)
- window->SetProperty(ash::kImmersiveImpliedByFullscreen, value);
+ window->SetProperty(chromeos::kImmersiveImpliedByFullscreen, value);
// Ensure the shelf is fully hidden in plain fullscreen, but shown
// (auto-hides based on mouse movement) when in immersive fullscreen.
- window->SetProperty(ash::kHideShelfWhenFullscreenKey, !value);
+ window->SetProperty(chromeos::kHideShelfWhenFullscreenKey, !value);
#endif // defined(OS_CHROMEOS)
}
@@ -141,6 +146,10 @@ const base::Optional<int32_t> GetShellClientAccessibilityId(
return id;
}
+bool IsShellMainSurfaceKey(const void* key) {
+ return kMainSurfaceKey == key;
+}
+
void SetShellMainSurface(aura::Window* window, Surface* surface) {
window->SetProperty(kMainSurfaceKey, surface);
}
diff --git a/chromium/components/exo/shell_surface_util.h b/chromium/components/exo/shell_surface_util.h
index 7a1592910c8..20e92676530 100644
--- a/chromium/components/exo/shell_surface_util.h
+++ b/chromium/components/exo/shell_surface_util.h
@@ -37,6 +37,9 @@ const std::string* GetShellApplicationId(const aura::Window* window);
// Sets ARC app type for the provided |window|.
void SetArcAppType(aura::Window* window);
+// Sets Lacros app type for the provided |window|.
+void SetLacrosAppType(aura::Window* window);
+
// Sets the startup ID for the window. The startup ID identifies the
// application using startup notification protocol.
void SetShellStartupId(aura::Window* window,
@@ -55,6 +58,9 @@ void SetShellClientAccessibilityId(aura::Window* window,
const base::Optional<int32_t> GetShellClientAccessibilityId(
aura::Window* window);
+// Returns true if the given key is the shell main surface key
+bool IsShellMainSurfaceKey(const void* key);
+
// Sets the main surface for the window.
void SetShellMainSurface(aura::Window* window, Surface* surface);
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index fb9675ed28a..7dd665cdcea 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "ash/public/cpp/shell_window_ids.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/containers/adapters.h"
#include "base/logging.h"
@@ -16,6 +15,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
+#include "build/build_config.h"
#include "components/exo/buffer.h"
#include "components/exo/frame_sink_resource_manager.h"
#include "components/exo/shell_surface_util.h"
@@ -228,7 +228,7 @@ int surface_id = 0;
} // namespace
-DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kClientSurfaceIdKey, 0)
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kClientSurfaceIdKey, nullptr)
ScopedSurface::ScopedSurface(Surface* surface, SurfaceObserver* observer)
: surface_(surface), observer_(observer) {
@@ -259,15 +259,20 @@ Surface::~Surface() {
// Call all frame callbacks with a null frame time to indicate that they
// have been cancelled.
- frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
- for (const auto& frame_callback : frame_callbacks_)
+ state_.frame_callbacks.splice(state_.frame_callbacks.end(),
+ cached_state_.frame_callbacks);
+ state_.frame_callbacks.splice(state_.frame_callbacks.end(),
+ pending_state_.frame_callbacks);
+ for (const auto& frame_callback : state_.frame_callbacks)
frame_callback.Run(base::TimeTicks());
// Call all presentation callbacks with a null presentation time to indicate
// that they have been cancelled.
- presentation_callbacks_.splice(presentation_callbacks_.end(),
- pending_presentation_callbacks_);
- for (const auto& presentation_callback : presentation_callbacks_)
+ state_.presentation_callbacks.splice(state_.presentation_callbacks.end(),
+ cached_state_.presentation_callbacks);
+ state_.presentation_callbacks.splice(state_.presentation_callbacks.end(),
+ pending_state_.presentation_callbacks);
+ for (const auto& presentation_callback : state_.presentation_callbacks)
presentation_callback.Run(gfx::PresentationFeedback());
WMHelper::GetInstance()->ResetDragDropDelegate(window_.get());
@@ -287,72 +292,73 @@ void Surface::Attach(Buffer* buffer, gfx::Vector2d offset) {
buffer ? buffer->gfx_buffer() : nullptr, "app_id",
GetApplicationId(window_.get()));
has_pending_contents_ = true;
- pending_buffer_.Reset(buffer ? buffer->AsWeakPtr() : base::WeakPtr<Buffer>());
- pending_state_.offset = offset;
+ pending_state_.buffer.Reset(buffer ? buffer->AsWeakPtr()
+ : base::WeakPtr<Buffer>());
+ pending_state_.basic_state.offset = offset;
}
gfx::Vector2d Surface::GetBufferOffset() {
- return state_.offset;
+ return state_.basic_state.offset;
}
bool Surface::HasPendingAttachedBuffer() const {
- return pending_buffer_.buffer() != nullptr;
+ return pending_state_.buffer.buffer() != nullptr;
}
void Surface::Damage(const gfx::Rect& damage) {
TRACE_EVENT1("exo", "Surface::Damage", "damage", damage.ToString());
- pending_damage_.Union(damage);
+ pending_state_.damage.Union(damage);
}
void Surface::RequestFrameCallback(const FrameCallback& callback) {
TRACE_EVENT0("exo", "Surface::RequestFrameCallback");
- pending_frame_callbacks_.push_back(callback);
+ pending_state_.frame_callbacks.push_back(callback);
}
void Surface::RequestPresentationCallback(
const PresentationCallback& callback) {
TRACE_EVENT0("exo", "Surface::RequestPresentationCallback");
- pending_presentation_callbacks_.push_back(callback);
+ pending_state_.presentation_callbacks.push_back(callback);
}
void Surface::SetOpaqueRegion(const cc::Region& region) {
TRACE_EVENT1("exo", "Surface::SetOpaqueRegion", "region", region.ToString());
- pending_state_.opaque_region = region;
+ pending_state_.basic_state.opaque_region = region;
}
void Surface::SetInputRegion(const cc::Region& region) {
TRACE_EVENT1("exo", "Surface::SetInputRegion", "region", region.ToString());
- pending_state_.input_region = region;
+ pending_state_.basic_state.input_region = region;
}
void Surface::ResetInputRegion() {
TRACE_EVENT0("exo", "Surface::ResetInputRegion");
- pending_state_.input_region = base::nullopt;
+ pending_state_.basic_state.input_region = base::nullopt;
}
void Surface::SetInputOutset(int outset) {
TRACE_EVENT1("exo", "Surface::SetInputOutset", "outset", outset);
- pending_state_.input_outset = outset;
+ pending_state_.basic_state.input_outset = outset;
}
void Surface::SetBufferScale(float scale) {
TRACE_EVENT1("exo", "Surface::SetBufferScale", "scale", scale);
- pending_state_.buffer_scale = scale;
+ pending_state_.basic_state.buffer_scale = scale;
}
void Surface::SetBufferTransform(Transform transform) {
TRACE_EVENT1("exo", "Surface::SetBufferTransform", "transform",
static_cast<int>(transform));
- pending_state_.buffer_transform = transform;
+ pending_state_.basic_state.buffer_transform = transform;
}
void Surface::AddSubSurface(Surface* sub_surface) {
@@ -480,33 +486,34 @@ void Surface::OnSubSurfaceCommit() {
void Surface::SetViewport(const gfx::Size& viewport) {
TRACE_EVENT1("exo", "Surface::SetViewport", "viewport", viewport.ToString());
- pending_state_.viewport = viewport;
+ pending_state_.basic_state.viewport = viewport;
}
void Surface::SetCrop(const gfx::RectF& crop) {
TRACE_EVENT1("exo", "Surface::SetCrop", "crop", crop.ToString());
- pending_state_.crop = crop;
+ pending_state_.basic_state.crop = crop;
}
void Surface::SetOnlyVisibleOnSecureOutput(bool only_visible_on_secure_output) {
TRACE_EVENT1("exo", "Surface::SetOnlyVisibleOnSecureOutput",
"only_visible_on_secure_output", only_visible_on_secure_output);
- pending_state_.only_visible_on_secure_output = only_visible_on_secure_output;
+ pending_state_.basic_state.only_visible_on_secure_output =
+ only_visible_on_secure_output;
}
void Surface::SetBlendMode(SkBlendMode blend_mode) {
TRACE_EVENT1("exo", "Surface::SetBlendMode", "blend_mode",
static_cast<int>(blend_mode));
- pending_state_.blend_mode = blend_mode;
+ pending_state_.basic_state.blend_mode = blend_mode;
}
void Surface::SetAlpha(float alpha) {
TRACE_EVENT1("exo", "Surface::SetAlpha", "alpha", alpha);
- pending_state_.alpha = alpha;
+ pending_state_.basic_state.alpha = alpha;
}
void Surface::SetFrame(SurfaceFrameType type) {
@@ -550,7 +557,7 @@ void Surface::SetColorSpace(gfx::ColorSpace color_space) {
TRACE_EVENT1("exo", "Surface::SetColorSpace", "color_space",
color_space.ToString());
- pending_state_.color_space = color_space;
+ pending_state_.basic_state.color_space = color_space;
}
void Surface::SetParent(Surface* parent, const gfx::Point& position) {
@@ -568,15 +575,17 @@ void Surface::RequestActivation() {
delegate_->OnActivationRequested();
}
-void Surface::SetClientSurfaceId(int32_t client_surface_id) {
- if (client_surface_id)
- window_->SetProperty(kClientSurfaceIdKey, client_surface_id);
+void Surface::SetClientSurfaceId(const char* client_surface_id) {
+ if (client_surface_id && strlen(client_surface_id) > 0)
+ window_->SetProperty(kClientSurfaceIdKey,
+ new std::string(client_surface_id));
else
window_->ClearProperty(kClientSurfaceIdKey);
}
-int32_t Surface::GetClientSurfaceId() const {
- return window_->GetProperty(kClientSurfaceIdKey);
+std::string Surface::GetClientSurfaceId() const {
+ std::string* value = window_->GetProperty(kClientSurfaceIdKey);
+ return value ? *value : std::string();
}
void Surface::SetEmbeddedSurfaceId(
@@ -590,25 +599,50 @@ void Surface::SetEmbeddedSurfaceSize(const gfx::Size& size) {
}
void Surface::SetAcquireFence(std::unique_ptr<gfx::GpuFence> gpu_fence) {
+#if defined(OS_POSIX)
TRACE_EVENT1("exo", "Surface::SetAcquireFence", "fence_fd",
gpu_fence ? gpu_fence->GetGpuFenceHandle().owned_fd.get() : -1);
+#endif // defined(OS_POSIX)
- pending_acquire_fence_ = std::move(gpu_fence);
+ pending_state_.acquire_fence = std::move(gpu_fence);
}
bool Surface::HasPendingAcquireFence() const {
- return !!pending_acquire_fence_;
+ return !!pending_state_.acquire_fence;
}
void Surface::Commit() {
TRACE_EVENT1("exo", "Surface::Commit", "buffer_id",
- pending_buffer_.buffer() ? pending_buffer_.buffer()->gfx_buffer()
- : nullptr);
+ pending_state_.buffer.buffer()
+ ? pending_state_.buffer.buffer()->gfx_buffer()
+ : nullptr);
for (auto& observer : observers_)
observer.OnCommit(this);
needs_commit_surface_ = true;
+
+ // Transfer pending state to cached state.
+ cached_state_.basic_state = pending_state_.basic_state;
+ pending_state_.basic_state.only_visible_on_secure_output = false;
+ has_cached_contents_ |= has_pending_contents_;
+ has_pending_contents_ = false;
+ cached_state_.buffer = std::move(pending_state_.buffer);
+ cached_state_.acquire_fence = std::move(pending_state_.acquire_fence);
+ cached_state_.frame_callbacks.splice(cached_state_.frame_callbacks.end(),
+ pending_state_.frame_callbacks);
+ cached_state_.damage.Union(pending_state_.damage);
+ pending_state_.damage.Clear();
+
+ // Existing presentation callbacks in the cached state when a new pending
+ // state is merged in should end up delivered as "discarded".
+ for (const auto& presentation_callback : cached_state_.presentation_callbacks)
+ presentation_callback.Run(gfx::PresentationFeedback());
+ cached_state_.presentation_callbacks.clear();
+ cached_state_.presentation_callbacks.splice(
+ cached_state_.presentation_callbacks.end(),
+ pending_state_.presentation_callbacks);
+
if (delegate_)
delegate_->OnSurfaceCommit();
else
@@ -634,45 +668,53 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
// https://crbug.com/779704
bool needs_full_damage =
sub_surfaces_changed_ ||
- pending_state_.opaque_region != state_.opaque_region ||
- pending_state_.buffer_scale != state_.buffer_scale ||
- pending_state_.buffer_transform != state_.buffer_transform ||
- pending_state_.viewport != state_.viewport ||
- pending_state_.crop != state_.crop ||
- pending_state_.only_visible_on_secure_output !=
- state_.only_visible_on_secure_output ||
- pending_state_.blend_mode != state_.blend_mode ||
- pending_state_.alpha != state_.alpha ||
- pending_state_.color_space != state_.color_space ||
- pending_state_.is_tracking_occlusion != state_.is_tracking_occlusion;
+ cached_state_.basic_state.opaque_region !=
+ state_.basic_state.opaque_region ||
+ cached_state_.basic_state.buffer_scale !=
+ state_.basic_state.buffer_scale ||
+ cached_state_.basic_state.buffer_transform !=
+ state_.basic_state.buffer_transform ||
+ cached_state_.basic_state.viewport != state_.basic_state.viewport ||
+ cached_state_.basic_state.crop != state_.basic_state.crop ||
+ cached_state_.basic_state.only_visible_on_secure_output !=
+ state_.basic_state.only_visible_on_secure_output ||
+ cached_state_.basic_state.blend_mode != state_.basic_state.blend_mode ||
+ cached_state_.basic_state.alpha != state_.basic_state.alpha ||
+ cached_state_.basic_state.color_space !=
+ state_.basic_state.color_space ||
+ cached_state_.basic_state.is_tracking_occlusion !=
+ state_.basic_state.is_tracking_occlusion;
bool needs_update_buffer_transform =
- pending_state_.buffer_scale != state_.buffer_scale ||
- pending_state_.buffer_transform != state_.buffer_transform;
+ cached_state_.basic_state.buffer_scale !=
+ state_.basic_state.buffer_scale ||
+ cached_state_.basic_state.buffer_transform !=
+ state_.basic_state.buffer_transform;
#if defined(OS_CHROMEOS)
bool needs_output_protection =
- pending_state_.only_visible_on_secure_output !=
- state_.only_visible_on_secure_output;
+ cached_state_.basic_state.only_visible_on_secure_output !=
+ state_.basic_state.only_visible_on_secure_output;
#endif // defined(OS_CHROMEOS)
- bool pending_invert_y = false;
+ bool cached_invert_y = false;
// If the current state is fully transparent, the last submitted frame will
// not include the TextureDrawQuad for the resource, so the resource might
// have been released and needs to be updated again.
- if (!state_.alpha && pending_state_.alpha)
+ if (!state_.basic_state.alpha && cached_state_.basic_state.alpha)
needs_update_resource_ = true;
- state_ = pending_state_;
- pending_state_.only_visible_on_secure_output = false;
+ state_.basic_state = cached_state_.basic_state;
+ cached_state_.basic_state.only_visible_on_secure_output = false;
window_->SetEventTargetingPolicy(
- (state_.input_region.has_value() && state_.input_region->IsEmpty())
+ (state_.basic_state.input_region.has_value() &&
+ state_.basic_state.input_region->IsEmpty())
? aura::EventTargetingPolicy::kDescendantsOnly
: aura::EventTargetingPolicy::kTargetAndDescendants);
- if (state_.is_tracking_occlusion) {
+ if (state_.basic_state.is_tracking_occlusion) {
// TODO(edcourtney): Currently, it doesn't seem to be possible to stop
// tracking the occlusion state once started, but it would be nice to stop
// if the tracked occlusion region becomes empty.
@@ -686,51 +728,56 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
std::make_unique<ash::OutputProtectionDelegate>(window_.get());
}
- uint32_t protection_mask = state_.only_visible_on_secure_output
- ? display::CONTENT_PROTECTION_METHOD_HDCP
- : display::CONTENT_PROTECTION_METHOD_NONE;
+ uint32_t protection_mask =
+ state_.basic_state.only_visible_on_secure_output
+ ? display::CONTENT_PROTECTION_METHOD_HDCP
+ : display::CONTENT_PROTECTION_METHOD_NONE;
output_protection_->SetProtection(protection_mask, base::DoNothing());
}
#endif // defined(OS_CHROMEOS)
// We update contents if Attach() has been called since last commit.
- if (has_pending_contents_) {
- has_pending_contents_ = false;
+ if (has_cached_contents_) {
+ has_cached_contents_ = false;
bool current_invert_y =
- current_buffer_.buffer() && current_buffer_.buffer()->y_invert();
- pending_invert_y =
- pending_buffer_.buffer() && pending_buffer_.buffer()->y_invert();
- if (current_invert_y != pending_invert_y)
+ state_.buffer.buffer() && state_.buffer.buffer()->y_invert();
+ cached_invert_y = cached_state_.buffer.buffer() &&
+ cached_state_.buffer.buffer()->y_invert();
+ if (current_invert_y != cached_invert_y)
needs_update_buffer_transform = true;
- current_buffer_ = std::move(pending_buffer_);
- acquire_fence_ = std::move(pending_acquire_fence_);
- if (state_.alpha)
+ state_.buffer = std::move(cached_state_.buffer);
+ state_.acquire_fence = std::move(cached_state_.acquire_fence);
+ if (state_.basic_state.alpha)
needs_update_resource_ = true;
}
// Either we didn't have a pending acquire fence, or we had one along with
- // a new buffer, and it was already moved to acquire_fence_. Note that
+ // a new buffer, and it was already moved to state_.acquire_fence. Note that
// it is a commit-time client error to commit a fence without a buffer.
- DCHECK(!pending_acquire_fence_);
+ DCHECK(!cached_state_.acquire_fence);
if (needs_update_buffer_transform)
- UpdateBufferTransform(pending_invert_y);
+ UpdateBufferTransform(cached_invert_y);
- // Move pending frame callbacks to the end of |frame_callbacks_|.
- frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
+ // Move pending frame callbacks to the end of |state_.frame_callbacks|.
+ state_.frame_callbacks.splice(state_.frame_callbacks.end(),
+ cached_state_.frame_callbacks);
// Move pending presentation callbacks to the end of
- // |presentation_callbacks_|.
- presentation_callbacks_.splice(presentation_callbacks_.end(),
- pending_presentation_callbacks_);
+ // |state_.presentation_callbacks|.
+ state_.presentation_callbacks.splice(state_.presentation_callbacks.end(),
+ cached_state_.presentation_callbacks);
UpdateContentSize();
// Synchronize window hierarchy. This will position and update the stacking
// order of all sub-surfaces after committing all pending state of
// sub-surface descendants.
+ // Changes to sub_surface stack is immediately applied to pending, which
+ // will be copied to active directly when parent surface is committed,
+ // skipping the cached state.
if (sub_surfaces_changed_) {
sub_surfaces_.clear();
aura::Window* stacking_target = nullptr;
@@ -753,24 +800,24 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
gfx::Rect output_rect(content_size_);
if (needs_full_damage) {
- damage_ = output_rect;
+ state_.damage = output_rect;
} else {
- // pending_damage_ is in Surface coordinates.
- damage_.Swap(&pending_damage_);
- damage_.Intersect(output_rect);
+ // cached_state_.damage is in Surface coordinates.
+ state_.damage.Swap(&cached_state_.damage);
+ state_.damage.Intersect(output_rect);
}
- pending_damage_.Clear();
+ cached_state_.damage.Clear();
}
surface_hierarchy_content_bounds_ = gfx::Rect(content_size_);
- if (state_.input_region) {
- hit_test_region_ = *state_.input_region;
+ if (state_.basic_state.input_region) {
+ hit_test_region_ = *state_.basic_state.input_region;
hit_test_region_.Intersect(surface_hierarchy_content_bounds_);
} else {
hit_test_region_ = surface_hierarchy_content_bounds_;
}
- int outset = state_.input_outset;
+ int outset = state_.basic_state.input_outset;
if (outset > 0) {
gfx::Rect input_rect = surface_hierarchy_content_bounds_;
input_rect.Inset(-outset, -outset);
@@ -793,10 +840,10 @@ void Surface::AppendSurfaceHierarchyCallbacks(
std::list<FrameCallback>* frame_callbacks,
std::list<PresentationCallback>* presentation_callbacks) {
// Move frame callbacks to the end of |frame_callbacks|.
- frame_callbacks->splice(frame_callbacks->end(), frame_callbacks_);
+ frame_callbacks->splice(frame_callbacks->end(), state_.frame_callbacks);
// Move presentation callbacks to the end of |presentation_callbacks|.
presentation_callbacks->splice(presentation_callbacks->end(),
- presentation_callbacks_);
+ state_.presentation_callbacks);
for (const auto& sub_surface_entry : base::Reversed(sub_surfaces_)) {
auto* sub_surface = sub_surface_entry.first;
@@ -895,16 +942,16 @@ void Surface::SurfaceHierarchyResourcesLost() {
bool Surface::FillsBoundsOpaquely() const {
return !current_resource_has_alpha_ ||
- state_.blend_mode == SkBlendMode::kSrc ||
- state_.opaque_region.Contains(gfx::Rect(content_size_));
+ state_.basic_state.blend_mode == SkBlendMode::kSrc ||
+ state_.basic_state.opaque_region.Contains(gfx::Rect(content_size_));
}
void Surface::SetOcclusionTracking(bool tracking) {
- pending_state_.is_tracking_occlusion = tracking;
+ pending_state_.basic_state.is_tracking_occlusion = tracking;
}
bool Surface::IsTrackingOcclusion() {
- return state_.is_tracking_occlusion;
+ return state_.basic_state.is_tracking_occlusion;
}
void Surface::SetSurfaceHierarchyContentBoundsForTest(
@@ -936,6 +983,10 @@ Surface::BufferAttachment::~BufferAttachment() {
buffer_->OnDetach();
}
+Surface::ExtendedState::ExtendedState() = default;
+
+Surface::ExtendedState::~ExtendedState() = default;
+
Surface::BufferAttachment& Surface::BufferAttachment::operator=(
BufferAttachment&& other) {
if (buffer_)
@@ -973,26 +1024,27 @@ void Surface::BufferAttachment::Reset(base::WeakPtr<Buffer> buffer) {
void Surface::UpdateResource(FrameSinkResourceManager* resource_manager) {
DCHECK(needs_update_resource_);
needs_update_resource_ = false;
- if (current_buffer_.buffer()) {
- if (current_buffer_.buffer()->ProduceTransferableResource(
- resource_manager, std::move(acquire_fence_),
- state_.only_visible_on_secure_output, &current_resource_)) {
+ if (state_.buffer.buffer()) {
+ if (state_.buffer.buffer()->ProduceTransferableResource(
+ resource_manager, std::move(state_.acquire_fence),
+ state_.basic_state.only_visible_on_secure_output,
+ &current_resource_)) {
current_resource_has_alpha_ =
- FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+ FormatHasAlpha(state_.buffer.buffer()->GetFormat());
// Planar buffers are sampled as RGB. Technically, the driver is supposed
// to preserve the colorspace, so we could still pass the primaries and
// transfer function. However, we don't actually pass the colorspace
// to the driver, and it's unclear what drivers would actually do if we
// did. So in effect, the colorspace is undefined.
if (NumberOfPlanesForLinearBufferFormat(
- current_buffer_.buffer()->GetFormat()) > 1) {
- current_resource_.color_space = state_.color_space;
+ state_.buffer.buffer()->GetFormat()) > 1) {
+ current_resource_.color_space = state_.basic_state.color_space;
}
} else {
current_resource_.id = 0;
// Use the buffer's size, so the AppendContentsToFrame() will append
// a SolidColorDrawQuad with the buffer's size.
- current_resource_.size = current_buffer_.size();
+ current_resource_.size = state_.buffer.size();
current_resource_has_alpha_ = false;
}
} else {
@@ -1004,7 +1056,7 @@ void Surface::UpdateResource(FrameSinkResourceManager* resource_manager) {
void Surface::UpdateBufferTransform(bool y_invert) {
SkMatrix buffer_matrix;
- switch (state_.buffer_transform) {
+ switch (state_.basic_state.buffer_transform) {
case Transform::NORMAL:
buffer_matrix.setIdentity();
break;
@@ -1020,9 +1072,9 @@ void Surface::UpdateBufferTransform(bool y_invert) {
}
if (y_invert)
buffer_matrix.preScale(1, -1, 0.5f, 0.5f);
- if (state_.buffer_scale != 0)
- buffer_matrix.postScale(1.0f / state_.buffer_scale,
- 1.0f / state_.buffer_scale);
+ if (state_.basic_state.buffer_scale != 0)
+ buffer_matrix.postScale(1.0f / state_.basic_state.buffer_scale,
+ 1.0f / state_.basic_state.buffer_scale);
buffer_transform_ = gfx::Transform(buffer_matrix);
}
@@ -1036,7 +1088,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
// Surface bounds are in DIPs, but |damage_rect| and |output_rect| are in
// pixels, so we need to scale by the |device_scale_factor|.
- gfx::Rect damage_rect = damage_.bounds();
+ gfx::Rect damage_rect = state_.damage.bounds();
if (!damage_rect.IsEmpty()) {
// Outset damage by 1 DIP to as damage is in surface coordinate space and
// client might not be aware of |device_scale_factor| and the
@@ -1057,7 +1109,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
render_pass->damage_rect.Union(gfx::ToEnclosedRect(scaled_damage));
}
}
- damage_.Clear();
+ state_.damage.Clear();
gfx::PointF scale(content_size_.width(), content_size_.height());
@@ -1069,19 +1121,19 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
quad_rect = gfx::Rect(embedded_surface_size_);
scale = gfx::PointF(1.0f, 1.0f);
- if (!state_.crop.IsEmpty()) {
+ if (!state_.basic_state.crop.IsEmpty()) {
// In order to crop an AxB rect to CxD we need to scale by A/C, B/D.
// We achieve clipping by scaling it up and then drawing only in the
// output rectangle.
- scale.Scale(content_size_.width() / state_.crop.width(),
- content_size_.height() / state_.crop.height());
+ scale.Scale(content_size_.width() / state_.basic_state.crop.width(),
+ content_size_.height() / state_.basic_state.crop.height());
- auto offset = state_.crop.origin().OffsetFromOrigin();
+ auto offset = state_.basic_state.crop.origin().OffsetFromOrigin();
translate =
gfx::Vector2dF(-offset.x() * scale.x(), -offset.y() * scale.y());
}
} else {
- scale.Scale(state_.buffer_scale);
+ scale.Scale(state_.basic_state.buffer_scale);
}
// Compute the total transformation from post-transform buffer coordinates to
@@ -1099,29 +1151,32 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
quad_to_target_transform.ConcatTransform(
gfx::Transform(viewport_to_target_matrix));
- bool are_contents_opaque = !current_resource_has_alpha_ ||
- state_.blend_mode == SkBlendMode::kSrc ||
- state_.opaque_region.Contains(output_rect);
+ bool are_contents_opaque =
+ !current_resource_has_alpha_ ||
+ state_.basic_state.blend_mode == SkBlendMode::kSrc ||
+ state_.basic_state.opaque_region.Contains(output_rect);
viz::SharedQuadState* quad_state =
render_pass->CreateAndAppendSharedQuadState();
- quad_state->SetAll(
- quad_to_target_transform, quad_rect /*quad_layer_rect=*/,
- quad_rect /*visible_quad_layer_rect=*/,
- gfx::RRectF() /*rounded_corner_bounds=*/, gfx::Rect() /*clip_rect=*/,
- false /*is_clipped=*/, are_contents_opaque, state_.alpha /*opacity=*/,
- SkBlendMode::kSrcOver /*blend_mode=*/, 0 /*sorting_context_id=*/);
+
+ quad_state->SetAll(quad_to_target_transform, quad_rect /*quad_layer_rect=*/,
+ quad_rect /*visible_quad_layer_rect=*/,
+ gfx::MaskFilterInfo() /*mask_filter_info=*/,
+ gfx::Rect() /*clip_rect=*/, false /*is_clipped=*/,
+ are_contents_opaque, state_.basic_state.alpha /*opacity=*/,
+ SkBlendMode::kSrcOver /*blend_mode=*/,
+ 0 /*sorting_context_id=*/);
quad_state->no_damage = damage_rect.IsEmpty();
if (current_resource_.id) {
gfx::RectF uv_crop(gfx::SizeF(1, 1));
- if (!state_.crop.IsEmpty()) {
+ if (!state_.basic_state.crop.IsEmpty()) {
// The crop rectangle is a post-transformation rectangle. To get the UV
// coordinates, we need to convert it to normalized buffer coordinates and
// pass them through the inverse of the buffer transformation.
- uv_crop = gfx::RectF(state_.crop);
- gfx::Size transformed_buffer_size(
- ToTransformedSize(current_resource_.size, state_.buffer_transform));
+ uv_crop = gfx::RectF(state_.basic_state.crop);
+ gfx::Size transformed_buffer_size(ToTransformedSize(
+ current_resource_.size, state_.basic_state.buffer_transform));
if (!transformed_buffer_size.IsEmpty())
uv_crop.Scale(1.f / transformed_buffer_size.width(),
1.f / transformed_buffer_size.height());
@@ -1147,7 +1202,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
}
if (latest_embedded_surface_id_.is_valid() &&
!embedded_surface_size_.IsEmpty()) {
- if (!state_.crop.IsEmpty()) {
+ if (!state_.basic_state.crop.IsEmpty()) {
quad_state->is_clipped = true;
quad_state->clip_rect = output_rect;
}
@@ -1162,7 +1217,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
// A resource was still produced for this so we still need to release it
// later.
frame->resource_list.push_back(current_resource_);
- } else if (state_.alpha) {
+ } else if (state_.basic_state.alpha) {
// Texture quad is only needed if buffer is not fully transparent.
viz::TextureDrawQuad* texture_quad =
render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
@@ -1173,7 +1228,7 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
/* premultiplied_alpha=*/true, uv_crop.origin(),
uv_crop.bottom_right(), background_color, vertex_opacity,
/* y_flipped=*/false, /* nearest_neighbor=*/false,
- state_.only_visible_on_secure_output,
+ state_.basic_state.only_visible_on_secure_output,
gfx::ProtectedVideoType::kClear);
if (current_resource_.is_overlay_candidate)
texture_quad->set_resource_size_in_pixels(current_resource_.size);
@@ -1189,20 +1244,21 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
void Surface::UpdateContentSize() {
gfx::Size content_size;
- if (!state_.viewport.IsEmpty()) {
- content_size = state_.viewport;
- } else if (!state_.crop.IsEmpty()) {
- DLOG_IF(WARNING,
- !base::IsValueInRangeForNumericType<int>(state_.crop.width()) ||
- !base::IsValueInRangeForNumericType<int>(state_.crop.height()))
- << "Crop rectangle size (" << state_.crop.size().ToString()
+ if (!state_.basic_state.viewport.IsEmpty()) {
+ content_size = state_.basic_state.viewport;
+ } else if (!state_.basic_state.crop.IsEmpty()) {
+ DLOG_IF(WARNING, !base::IsValueInRangeForNumericType<int>(
+ state_.basic_state.crop.width()) ||
+ !base::IsValueInRangeForNumericType<int>(
+ state_.basic_state.crop.height()))
+ << "Crop rectangle size (" << state_.basic_state.crop.size().ToString()
<< ") most be expressible using integers when viewport is not set";
- content_size = gfx::ToCeiledSize(state_.crop.size());
+ content_size = gfx::ToCeiledSize(state_.basic_state.crop.size());
} else {
- content_size = gfx::ToCeiledSize(
- gfx::ScaleSize(gfx::SizeF(ToTransformedSize(current_buffer_.size(),
- state_.buffer_transform)),
- 1.0f / state_.buffer_scale));
+ content_size = gfx::ToCeiledSize(gfx::ScaleSize(
+ gfx::SizeF(ToTransformedSize(state_.buffer.size(),
+ state_.basic_state.buffer_transform)),
+ 1.0f / state_.basic_state.buffer_scale));
}
// Enable/disable sub-surface based on if it has contents.
@@ -1221,7 +1277,7 @@ void Surface::UpdateContentSize() {
}
void Surface::OnWindowOcclusionChanged() {
- if (!state_.is_tracking_occlusion)
+ if (!state_.basic_state.is_tracking_occlusion)
return;
for (SurfaceObserver& observer : observers_)
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index a544f828bc2..21b36df8df0 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -59,7 +59,7 @@ class PropertyHelper;
enum class Transform { NORMAL, ROTATE_90, ROTATE_180, ROTATE_270 };
// A property key to store the surface Id set by the client.
-extern const ui::ClassProperty<int32_t>* const kClientSurfaceIdKey;
+extern const ui::ClassProperty<std::string*>* const kClientSurfaceIdKey;
// This class represents a rectangular area that is displayed on the screen.
// It has a location, size and pixel contents.
@@ -188,8 +188,8 @@ class Surface final : public ui::PropertyHandler {
void SetParent(Surface* parent, const gfx::Point& position);
// Request that surface should have a specific ID assigned by client.
- void SetClientSurfaceId(int32_t client_surface_id);
- int32_t GetClientSurfaceId() const;
+ void SetClientSurfaceId(const char* client_surface_id);
+ std::string GetClientSurfaceId() const;
// Enable embedding of an arbitrary viz surface in this exo surface.
// If the callback is valid, a SurfaceDrawQuad will be emitted targeting
@@ -287,7 +287,7 @@ class Surface final : public ui::PropertyHandler {
bool FillsBoundsOpaquely() const;
bool HasPendingDamageForTesting(const gfx::Rect& damage) const {
- return pending_damage_.Contains(damage);
+ return pending_state_.damage.Contains(damage);
}
// Set occlusion tracking region for surface.
@@ -346,6 +346,26 @@ class Surface final : public ui::PropertyHandler {
DISALLOW_COPY_AND_ASSIGN(BufferAttachment);
};
+ struct ExtendedState {
+ ExtendedState();
+ ~ExtendedState();
+
+ State basic_state;
+
+ // The buffer that will become the content of surface.
+ BufferAttachment buffer;
+ // The damage region to schedule paint for.
+ cc::Region damage;
+ // These lists contain the callbacks to notify the client when it is a good
+ // time to start producing a new frame.
+ std::list<FrameCallback> frame_callbacks;
+ // These lists contain the callbacks to notify the client when surface
+ // contents have been presented.
+ std::list<PresentationCallback> presentation_callbacks;
+ // The acquire gpu fence to associate with the surface buffer.
+ std::unique_ptr<gfx::GpuFence> acquire_fence;
+ };
+
friend class subtle::PropertyHelper;
// Updates current_resource_ with a new resource id corresponding to the
@@ -367,7 +387,7 @@ class Surface final : public ui::PropertyHandler {
void UpdateContentSize();
// This returns true when the surface has some contents assigned to it.
- bool has_contents() const { return !current_buffer_.size().IsEmpty(); }
+ bool has_contents() const { return !state_.buffer.size().IsEmpty(); }
// This window has the layer which contains the Surface contents.
std::unique_ptr<aura::Window> window_;
@@ -381,43 +401,19 @@ class Surface final : public ui::PropertyHandler {
// This is the bounds of the last committed surface hierarchy contents.
gfx::Rect surface_hierarchy_content_bounds_;
- // This is true when Attach() has been called and new contents should take
- // effect next time Commit() is called.
+ // This is true when Attach() has been called and new contents should be
+ // cached next time Commit() is called.
bool has_pending_contents_ = false;
+ // This is true when new contents are cached and should take effect next time
+ // synchronized CommitSurfaceHierarchy() is called.
+ bool has_cached_contents_ = false;
- // The buffer that will become the content of surface when Commit() is called.
- BufferAttachment pending_buffer_;
-
- // The damage region to schedule paint for when Commit() is called.
- cc::Region pending_damage_;
-
- // The damage region which will be used by
- // AppendSurfaceHierarchyContentsToFrame() to generate frame.
- cc::Region damage_;
-
- // These lists contains the callbacks to notify the client when it is a good
- // time to start producing a new frame. These callbacks move to
- // |frame_callbacks_| when Commit() is called. Later they are moved to
- // |active_frame_callbacks_| when the effect of the Commit() is scheduled to
- // be drawn. They fire at the first begin frame notification after this.
- std::list<FrameCallback> pending_frame_callbacks_;
- std::list<FrameCallback> frame_callbacks_;
-
- // These lists contains the callbacks to notify the client when surface
- // contents have been presented. These callbacks move to
- // |presentation_callbacks_| when Commit() is called. Later they are moved to
- // |swapping_presentation_callbacks_| when the effect of the Commit() is
- // scheduled to be drawn and then moved to |swapped_presentation_callbacks_|
- // after receiving VSync parameters update for the previous frame. They fire
- // at the next VSync parameters update after that.
- std::list<PresentationCallback> pending_presentation_callbacks_;
- std::list<PresentationCallback> presentation_callbacks_;
-
+ // This is the state that has yet to be cached.
+ ExtendedState pending_state_;
// This is the state that has yet to be committed.
- State pending_state_;
-
+ ExtendedState cached_state_;
// This is the state that has been committed.
- State state_;
+ ExtendedState state_;
// Cumulative input region of surface and its sub-surfaces.
cc::Region hit_test_region_;
@@ -430,21 +426,12 @@ class Surface final : public ui::PropertyHandler {
SubSurfaceEntryList pending_sub_surfaces_;
SubSurfaceEntryList sub_surfaces_;
- // The buffer that is currently set as content of surface.
- BufferAttachment current_buffer_;
-
// The last resource that was sent to a surface.
viz::TransferableResource current_resource_;
// Whether the last resource that was sent to a surface has an alpha channel.
bool current_resource_has_alpha_ = false;
- // The acquire gpu fence to associate with the surface buffer when Commit()
- // is called.
- std::unique_ptr<gfx::GpuFence> pending_acquire_fence_;
- // The acquire gpu fence that is currently associated with the surface buffer.
- std::unique_ptr<gfx::GpuFence> acquire_fence_;
-
// This is true if a call to Commit() as been made but
// CommitSurfaceHierarchy() has not yet been called.
bool needs_commit_surface_ = false;
@@ -488,7 +475,7 @@ class Surface final : public ui::PropertyHandler {
class ScopedSurface {
public:
ScopedSurface(Surface* surface, SurfaceObserver* observer);
- ~ScopedSurface();
+ virtual ~ScopedSurface();
Surface* get() { return surface_; }
private:
diff --git a/chromium/components/exo/surface_tree_host.cc b/chromium/components/exo/surface_tree_host.cc
index ceb5e06a305..d12527519ae 100644
--- a/chromium/components/exo/surface_tree_host.cc
+++ b/chromium/components/exo/surface_tree_host.cc
@@ -300,7 +300,7 @@ void SurfaceTreeHost::SubmitEmptyCompositorFrame() {
quad_state->SetAll(
gfx::Transform(), /*quad_layer_rect=*/quad_rect,
/*visible_quad_layer_rect=*/quad_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/gfx::Rect(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(), /*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false, /*are_contents_opaque=*/true, /*opacity=*/1.f,
/*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index 98b4d948b8c..3123575c339 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_unittest.cc
@@ -260,6 +260,128 @@ TEST_P(SurfaceTest, SubsurfaceDamageAggregation) {
}
}
+TEST_P(SurfaceTest, SubsurfaceDamageSynchronizedCommitBehavior) {
+ gfx::Size buffer_size(256, 512);
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ surface->Attach(buffer.get());
+ gfx::Size child_buffer_size(64, 128);
+ auto child_buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
+ auto child_surface = std::make_unique<Surface>();
+ auto sub_surface =
+ std::make_unique<SubSurface>(child_surface.get(), surface.get());
+ // Set commit behavior to synchronized.
+ sub_surface->SetCommitBehavior(true);
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Initial frame has full damage.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
+ gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
+ EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
+ }
+
+ const gfx::RectF subsurface_damage(32, 32, 16, 16);
+ const gfx::RectF subsurface_damage2(0, 0, 16, 16);
+ int margin = ceil(device_scale_factor());
+
+ child_surface->Damage(gfx::ToNearestRect(subsurface_damage));
+ EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
+ gfx::ToNearestRect(subsurface_damage)));
+ // Subsurface damage is cached.
+ child_surface->Commit();
+ EXPECT_FALSE(child_surface->HasPendingDamageForTesting(
+ gfx::ToNearestRect(subsurface_damage)));
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface damage should not be propagated at all.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
+ gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
+ EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
+ }
+
+ // Damage but do not commit.
+ child_surface->Damage(gfx::ToNearestRect(subsurface_damage2));
+ EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
+ gfx::ToNearestRect(subsurface_damage2)));
+ // Apply subsurface damage from cached state, not pending state.
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface damage in cached state should be propagated.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(
+ gfx::ScaleRect(subsurface_damage, device_scale_factor()));
+ EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
+ frame.render_pass_list.back()->damage_rect, margin));
+ }
+}
+
+TEST_P(SurfaceTest, SubsurfaceDamageDesynchronizedCommitBehavior) {
+ gfx::Size buffer_size(256, 512);
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ surface->Attach(buffer.get());
+ gfx::Size child_buffer_size(64, 128);
+ auto child_buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
+ auto child_surface = std::make_unique<Surface>();
+ auto sub_surface =
+ std::make_unique<SubSurface>(child_surface.get(), surface.get());
+ // Set commit behavior to desynchronized.
+ sub_surface->SetCommitBehavior(false);
+ child_surface->Attach(child_buffer.get());
+ child_surface->Commit();
+ surface->Commit();
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Initial frame has full damage.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(gfx::ScaleRect(
+ gfx::RectF(gfx::Rect(buffer_size)), device_scale_factor()));
+ EXPECT_EQ(scaled_damage, frame.render_pass_list.back()->damage_rect);
+ }
+
+ const gfx::RectF subsurface_damage(32, 32, 16, 16);
+ int margin = ceil(device_scale_factor());
+
+ child_surface->Damage(gfx::ToNearestRect(subsurface_damage));
+ EXPECT_TRUE(child_surface->HasPendingDamageForTesting(
+ gfx::ToNearestRect(subsurface_damage)));
+ // Subsurface damage is applied.
+ child_surface->Commit();
+ EXPECT_FALSE(child_surface->HasPendingDamageForTesting(
+ gfx::ToNearestRect(subsurface_damage)));
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Subsurface damage should be propagated.
+ const viz::CompositorFrame& frame =
+ GetFrameFromSurface(shell_surface.get());
+ const gfx::Rect scaled_damage = gfx::ToNearestRect(
+ gfx::ScaleRect(subsurface_damage, device_scale_factor()));
+ EXPECT_TRUE(scaled_damage.ApproximatelyEqual(
+ frame.render_pass_list.back()->damage_rect, margin));
+ }
+}
+
void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
*result = frame_time;
}
@@ -1109,9 +1231,9 @@ TEST_P(SurfaceTest, DestroyAttachedBuffer) {
TEST_P(SurfaceTest, SetClientSurfaceId) {
auto surface = std::make_unique<Surface>();
- constexpr int kTestId = 42;
+ const std::string kTestId = "42";
- surface->SetClientSurfaceId(kTestId);
+ surface->SetClientSurfaceId(kTestId.c_str());
EXPECT_EQ(kTestId, surface->GetClientSurfaceId());
}
diff --git a/chromium/components/exo/text_input.cc b/chromium/components/exo/text_input.cc
index 71fdd0cc09e..f2d53437339 100644
--- a/chromium/components/exo/text_input.cc
+++ b/chromium/components/exo/text_input.cc
@@ -7,13 +7,14 @@
#include <algorithm>
#include "ash/keyboard/ui/keyboard_ui_controller.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/strings/string_piece.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/utf_offset.h"
#include "ui/events/event.h"
namespace exo {
@@ -28,14 +29,6 @@ ui::InputMethod* GetInputMethod(aura::Window* window) {
} // namespace
-size_t OffsetFromUTF8Offset(const base::StringPiece& text, uint32_t offset) {
- return base::UTF8ToUTF16(text.substr(0, offset)).size();
-}
-
-size_t OffsetFromUTF16Offset(const base::StringPiece16& text, uint32_t offset) {
- return base::UTF16ToUTF8(text.substr(0, offset)).size();
-}
-
TextInput::TextInput(std::unique_ptr<Delegate> delegate)
: delegate_(std::move(delegate)) {}
@@ -132,6 +125,8 @@ uint32_t TextInput::ConfirmCompositionText(bool keep_selection) {
}
void TextInput::ClearCompositionText() {
+ if (composition_.text.empty())
+ return;
composition_ = ui::CompositionText();
delegate_->SetCompositionText(composition_);
}
@@ -220,18 +215,26 @@ bool TextInput::GetEditableSelectionRange(gfx::Range* range) const {
bool TextInput::SetEditableSelectionRange(const gfx::Range& range) {
if (surrounding_text_.size() < range.GetMax())
return false;
- delegate_->SetCursor(
- gfx::Range(OffsetFromUTF16Offset(surrounding_text_, range.start()),
- OffsetFromUTF16Offset(surrounding_text_, range.end())));
+ auto start = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, range.start());
+ if (!start)
+ return false;
+ auto end = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, range.end());
+ if (!end)
+ return false;
+ delegate_->SetCursor(gfx::Range(*start, *end));
return true;
}
bool TextInput::DeleteRange(const gfx::Range& range) {
if (surrounding_text_.size() < range.GetMax())
return false;
- delegate_->DeleteSurroundingText(
- gfx::Range(OffsetFromUTF16Offset(surrounding_text_, range.start()),
- OffsetFromUTF16Offset(surrounding_text_, range.end())));
+ auto start = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, range.start());
+ if (!start)
+ return false;
+ auto end = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, range.end());
+ if (!end)
+ return false;
+ delegate_->DeleteSurroundingText(gfx::Range(*start, *end));
return true;
}
@@ -292,13 +295,18 @@ bool TextInput::ChangeTextDirectionAndLayoutAlignment(
void TextInput::ExtendSelectionAndDelete(size_t before, size_t after) {
if (!cursor_pos_)
return;
- uint32_t start =
+ size_t utf16_start =
(cursor_pos_->GetMin() < before) ? 0 : (cursor_pos_->GetMin() - before);
- uint32_t end =
+ size_t utf16_end =
std::min(cursor_pos_->GetMax() + after, surrounding_text_.size());
- delegate_->DeleteSurroundingText(
- gfx::Range(OffsetFromUTF16Offset(surrounding_text_, start),
- OffsetFromUTF16Offset(surrounding_text_, end)));
+ auto start = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, utf16_start);
+ if (!start)
+ return;
+ auto end = ui::Utf8OffsetFromUtf16Offset(surrounding_text_, utf16_end);
+ if (!end)
+ return;
+
+ delegate_->DeleteSurroundingText(gfx::Range(*start, *end));
}
void TextInput::EnsureCaretNotInRect(const gfx::Rect& rect) {}
diff --git a/chromium/components/exo/text_input.h b/chromium/components/exo/text_input.h
index bf4664de087..ebe88ff10b6 100644
--- a/chromium/components/exo/text_input.h
+++ b/chromium/components/exo/text_input.h
@@ -8,7 +8,7 @@
#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "base/strings/string_piece.h"
+#include "base/strings/string16.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_flags.h"
#include "ui/base/ime/text_input_mode.h"
@@ -26,9 +26,6 @@ class KeyboardUIController;
namespace exo {
class Surface;
-size_t OffsetFromUTF8Offset(const base::StringPiece& text, uint32_t offset);
-size_t OffsetFromUTF16Offset(const base::StringPiece16& text, uint32_t offset);
-
// This class bridges the ChromeOS input method and a text-input context.
class TextInput : public ui::TextInputClient,
public ash::KeyboardControllerObserver {
diff --git a/chromium/components/exo/text_input_unittest.cc b/chromium/components/exo/text_input_unittest.cc
index 21573e10d3a..7fa5d7a28cb 100644
--- a/chromium/components/exo/text_input_unittest.cc
+++ b/chromium/components/exo/text_input_unittest.cc
@@ -246,6 +246,13 @@ TEST_F(TextInputTest, CompositionText) {
text_input()->ClearCompositionText();
}
+TEST_F(TextInputTest, CompositionTextEmpty) {
+ SetCompositionText("");
+
+ EXPECT_CALL(*delegate(), SetCompositionText(_)).Times(0);
+ text_input()->ClearCompositionText();
+}
+
TEST_F(TextInputTest, CommitCompositionText) {
SetCompositionText("composition");
diff --git a/chromium/components/exo/touch_unittest.cc b/chromium/components/exo/touch_unittest.cc
index 9c4c6b616a2..53d46983cbd 100644
--- a/chromium/components/exo/touch_unittest.cc
+++ b/chromium/components/exo/touch_unittest.cc
@@ -15,6 +15,7 @@
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_file_helper.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/exo/touch_delegate.h"
#include "components/exo/touch_stylus_delegate.h"
@@ -506,6 +507,7 @@ TEST_F(TouchTest, DragDropAbort) {
TestDataSourceDelegate data_source_delegate;
DataSource source(&data_source_delegate);
Surface origin, icon;
+ TestFileHelper file_helper;
// Make origin into a real window so the touch can click it
ShellSurface shell_surface(&origin);
@@ -520,7 +522,8 @@ TEST_F(TouchTest, DragDropAbort) {
EXPECT_CALL(touch_delegate, OnTouchFrame()).Times(2);
generator.MoveTouch(origin.window()->GetBoundsInScreen().origin());
- seat.StartDrag(&source, &origin, &icon, ui::mojom::DragEventSource::kMouse);
+ seat.StartDrag(&file_helper, &source, &origin, &icon,
+ ui::mojom::DragEventSource::kMouse);
EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
EXPECT_CALL(touch_delegate, OnTouchDown).Times(1);
diff --git a/chromium/components/exo/ui_lock_controller.cc b/chromium/components/exo/ui_lock_controller.cc
index ef4a1605a46..cb417e0b4e5 100644
--- a/chromium/components/exo/ui_lock_controller.cc
+++ b/chromium/components/exo/ui_lock_controller.cc
@@ -5,10 +5,10 @@
#include "components/exo/ui_lock_controller.h"
#include "ash/public/cpp/app_types.h"
-#include "ash/public/cpp/window_properties.h"
#include "ash/wm/window_state.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "chromeos/ui/base/window_properties.h"
#include "components/exo/seat.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
@@ -67,7 +67,7 @@ bool FocusedWindowIsNonImmersiveFullscreen(Seat* seat) {
return false;
aura::Window* window = widget->GetNativeWindow();
- if (!window || window->GetProperty(ash::kImmersiveImpliedByFullscreen))
+ if (!window || window->GetProperty(chromeos::kImmersiveImpliedByFullscreen))
return false;
// TODO(b/165865831): Add the Borealis AppType if/when we add one.
diff --git a/chromium/components/exo/vsync_timing_manager.cc b/chromium/components/exo/vsync_timing_manager.cc
index a8148d00862..e39b11473c3 100644
--- a/chromium/components/exo/vsync_timing_manager.cc
+++ b/chromium/components/exo/vsync_timing_manager.cc
@@ -6,11 +6,13 @@
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
namespace exo {
VSyncTimingManager::VSyncTimingManager(Delegate* delegate)
- : delegate_(delegate) {}
+ : last_interval_(viz::BeginFrameArgs::DefaultInterval()),
+ delegate_(delegate) {}
VSyncTimingManager::~VSyncTimingManager() = default;
@@ -36,8 +38,25 @@ void VSyncTimingManager::RemoveObserver(Observer* obs) {
void VSyncTimingManager::OnUpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) {
- for (auto* observer : observers_)
- observer->OnUpdateVSyncParameters(timebase, interval);
+ for (auto* observer : observers_) {
+ observer->OnUpdateVSyncParameters(timebase, throttled_interval_.is_zero()
+ ? interval
+ : throttled_interval_);
+ }
+ last_timebase_ = timebase;
+ last_interval_ = interval;
+}
+
+void VSyncTimingManager::OnThrottlingStarted(
+ const std::vector<aura::Window*>& windows,
+ uint8_t fps) {
+ throttled_interval_ = base::TimeDelta::FromSeconds(1) / fps;
+ OnUpdateVSyncParameters(last_timebase_, last_interval_);
+}
+
+void VSyncTimingManager::OnThrottlingEnded() {
+ throttled_interval_ = base::TimeDelta();
+ OnUpdateVSyncParameters(last_timebase_, last_interval_);
}
void VSyncTimingManager::InitializeConnection() {
diff --git a/chromium/components/exo/vsync_timing_manager.h b/chromium/components/exo/vsync_timing_manager.h
index 0dd73ca0f4e..841650f09ce 100644
--- a/chromium/components/exo/vsync_timing_manager.h
+++ b/chromium/components/exo/vsync_timing_manager.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "ash/frame_throttler/frame_throttling_observer.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@@ -18,7 +19,8 @@ namespace exo {
// Multiplexes vsync parameter updates from the display compositor to exo
// clients using the zcr_vsync_feedback_v1 protocol. Will maintain an IPC
// connection to the display compositor only when necessary.
-class VSyncTimingManager : public viz::mojom::VSyncParameterObserver {
+class VSyncTimingManager : public viz::mojom::VSyncParameterObserver,
+ public ash::FrameThrottlingObserver {
public:
// Will be notified about changes in vsync parameters.
class Observer {
@@ -44,15 +46,26 @@ class VSyncTimingManager : public viz::mojom::VSyncParameterObserver {
void AddObserver(Observer* obs);
void RemoveObserver(Observer* obs);
+ base::TimeDelta throttled_interval() const { return throttled_interval_; }
+
private:
// Overridden from viz::mojom::VSyncParameterObserver:
void OnUpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
+ // Overridden from ash::FrameThrottlingObserver
+ void OnThrottlingStarted(const std::vector<aura::Window*>& windows,
+ uint8_t fps) override;
+ void OnThrottlingEnded() override;
+
void InitializeConnection();
void MaybeInitializeConnection();
void OnConnectionError();
+ base::TimeDelta throttled_interval_;
+ base::TimeDelta last_interval_;
+ base::TimeTicks last_timebase_;
+
Delegate* const delegate_;
std::vector<Observer*> observers_;
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index cb9090555de..5b8d0d93a41 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/ozone.gni")
import("//build/config/ui.gni")
import("//gpu/vulkan/features.gni")
import("//testing/test.gni")
import("//ui/base/ui_features.gni")
-import("//ui/ozone/ozone.gni")
source_set("wayland") {
sources = [
@@ -49,8 +49,6 @@ source_set("wayland") {
"zaura_shell.h",
"zcr_alpha_compositing.cc",
"zcr_alpha_compositing.h",
- "zcr_extended_drag.cc",
- "zcr_extended_drag.h",
"zcr_secure_output.cc",
"zcr_secure_output.h",
"zcr_stylus.cc",
@@ -124,6 +122,7 @@ source_set("wayland") {
deps += [
"//ash",
"//ash/public/cpp",
+ "//chromeos/ui/base",
]
}
}
@@ -155,6 +154,8 @@ source_set("wayland") {
"zcr_color_space.h",
"zcr_cursor_shapes.cc",
"zcr_cursor_shapes.h",
+ "zcr_extended_drag.cc",
+ "zcr_extended_drag.h",
"zcr_gaming_input.cc",
"zcr_gaming_input.h",
"zcr_keyboard_configuration.cc",
@@ -469,6 +470,8 @@ test("wayland_client_perftests") {
"clients/test/run_all_client_perftests.cc",
"clients/test/wayland_client_test.cc",
"clients/test/wayland_client_test.h",
+ "clients/test/wayland_client_test_server.cc",
+ "clients/test/wayland_client_test_server.h",
]
deps = [
@@ -506,6 +509,43 @@ test("wayland_client_perftests") {
}
}
+test("wayland_client_compatibility_tests") {
+ testonly = true
+
+ sources = [
+ "clients/test/wayland_client_test.cc",
+ "clients/test/wayland_client_test.h",
+ "clients/test/wayland_client_test_server.cc",
+ "clients/test/wayland_client_test_server.h",
+ "compatibility_test/client_compatibility_test.cc",
+ "compatibility_test/client_compatibility_test.h",
+ "compatibility_test/client_compatibility_test_server.cc",
+ "compatibility_test/wayland_client_event_receiver_version_fixtures.h",
+ "compatibility_test/wayland_client_event_recorder.cc",
+ "compatibility_test/wayland_client_event_recorder.h",
+ "compatibility_test/wayland_client_registry.cc",
+ "compatibility_test/wayland_client_registry.h",
+ ]
+
+ deps = [
+ ":wayland",
+ ":wayland_client_test_helper",
+ "//base",
+ "//base/test:test_support",
+ "//components/exo/wayland/compatibility_test",
+ "//components/exo/wayland/compatibility_test:generated_client_helper_headers",
+ "//components/viz/test:test_support",
+ "//mojo/core/embedder:embedder",
+ "//ui/gl:test_support",
+ ]
+
+ if (is_chromeos) {
+ deps += [ "//ash:test_support" ]
+ }
+
+ data_deps = []
+}
+
if (ozone_platform_drm) {
executable("wayland_yuv_client") {
sources = [ "clients/yuv.cc" ]
diff --git a/chromium/components/exo/wayland/clients/client_base.cc b/chromium/components/exo/wayland/clients/client_base.cc
index cd9b1959fcb..ce06570eac9 100644
--- a/chromium/components/exo/wayland/clients/client_base.cc
+++ b/chromium/components/exo/wayland/clients/client_base.cc
@@ -32,6 +32,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/unguessable_token.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -884,10 +885,11 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
return nullptr;
}
+ SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
buffer->sk_surface = SkSurface::MakeRasterDirect(
SkImageInfo::Make(size.width(), size.height(), kColorType,
kOpaque_SkAlphaType),
- mapped_data, stride);
+ mapped_data, stride, &props);
DCHECK(buffer->sk_surface);
}
diff --git a/chromium/components/exo/wayland/compatibility_test/BUILD.gn b/chromium/components/exo/wayland/compatibility_test/BUILD.gn
new file mode 100644
index 00000000000..df9bef7c965
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/BUILD.gn
@@ -0,0 +1,103 @@
+# Copyright 2020 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(
+ "//components/exo/wayland/compatibility_test/wayland_protocol_codegen.gni")
+
+# This is the canonical list of all protocols which are potentially exposed by the server
+server_wayland_protocols = [
+ "//components/exo/wayland/protocol/aura-shell.xml",
+ "//third_party/wayland/src/protocol/wayland.xml",
+ "//third_party/wayland-protocols/src/stable/presentation-time/presentation-time.xml",
+ "//third_party/wayland-protocols/src/stable/viewporter/viewporter.xml",
+ "//third_party/wayland-protocols/src/stable/xdg-shell/xdg-shell.xml",
+ "//third_party/wayland-protocols/src/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/input-timestamps/input-timestamps-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/linux-explicit-synchronization/linux-explicit-synchronization-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/relative-pointer/relative-pointer-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/text-input/text-input-unstable-v1.xml",
+ "//third_party/wayland-protocols/src/unstable/xdg-shell/xdg-shell-unstable-v6.xml",
+ "//third_party/wayland-protocols/unstable/alpha-compositing/alpha-compositing-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/color-space/color-space-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/cursor-shapes/cursor-shapes-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/gaming-input/gaming-input-unstable-v2.xml",
+ "//third_party/wayland-protocols/unstable/keyboard/keyboard-configuration-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/keyboard/keyboard-extension-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/notification-shell/notification-shell-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/secure-output/secure-output-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/stylus/stylus-unstable-v2.xml",
+ "//third_party/wayland-protocols/unstable/stylus-tools/stylus-tools-unstable-v1.xml",
+ "//third_party/wayland-protocols/unstable/vsync-feedback/vsync-feedback-unstable-v1.xml",
+]
+
+wayland_protocol_codegen("generated_client_helper_headers") {
+ template = "//components/exo/wayland/compatibility_test/template_client_helpers.h.tmpl"
+ sources = server_wayland_protocols
+ output_pattern =
+ "$target_gen_dir/generated-{{source_name_part}}-client-helpers.h"
+}
+
+wayland_protocol_codegen("generated_client_helper_impl") {
+ template = "//components/exo/wayland/compatibility_test/template_client_helpers.cc.tmpl"
+ sources = server_wayland_protocols
+ output_pattern =
+ "$target_gen_dir/generated-{{source_name_part}}-client-helpers.cc"
+}
+
+wayland_protocol_codegen("generated_client_event_receiver_version_tests") {
+ testonly = true
+ reduce = true
+ template = "//components/exo/wayland/compatibility_test/template_client_event_receiver_version_tests.cc.tmpl"
+ sources = server_wayland_protocols
+ output_pattern =
+ "$target_gen_dir/all_generated_client_event_receiver_version_tests.cc"
+}
+
+source_set("compatibility_test") {
+ testonly = true
+
+ sources = get_target_outputs(":generated_client_helper_impl")
+ sources +=
+ get_target_outputs(":generated_client_event_receiver_version_tests")
+
+ deps = [
+ ":generated_client_event_receiver_version_tests",
+ ":generated_client_helper_headers",
+ ":generated_client_helper_impl",
+ ]
+
+ public_deps = [
+ "//components/exo/wayland/protocol:aura_shell_protocol",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/wayland:wayland_client",
+ "//third_party/wayland-protocols:alpha_compositing_protocol",
+ "//third_party/wayland-protocols:color_space_protocol",
+ "//third_party/wayland-protocols:cursor_shapes_protocol",
+ "//third_party/wayland-protocols:fullscreen_shell_protocol",
+ "//third_party/wayland-protocols:gaming_input_protocol",
+ "//third_party/wayland-protocols:input_timestamps_protocol",
+ "//third_party/wayland-protocols:keyboard_configuration_protocol",
+ "//third_party/wayland-protocols:keyboard_extension_protocol",
+ "//third_party/wayland-protocols:linux_dmabuf_protocol",
+ "//third_party/wayland-protocols:linux_explicit_synchronization_protocol",
+ "//third_party/wayland-protocols:notification_shell_protocol",
+ "//third_party/wayland-protocols:pointer_constraints_protocol",
+ "//third_party/wayland-protocols:pointer_gestures_protocol",
+ "//third_party/wayland-protocols:presentation_time_protocol",
+ "//third_party/wayland-protocols:relative_pointer_protocol",
+ "//third_party/wayland-protocols:remote_shell_protocol",
+ "//third_party/wayland-protocols:secure_output_protocol",
+ "//third_party/wayland-protocols:stylus_protocol",
+ "//third_party/wayland-protocols:stylus_tools_protocol",
+ "//third_party/wayland-protocols:text_input_protocol",
+ "//third_party/wayland-protocols:viewporter_protocol",
+ "//third_party/wayland-protocols:vsync_feedback_protocol",
+ "//third_party/wayland-protocols:xdg_shell_protocol",
+ ]
+}
diff --git a/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.cc b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.cc
new file mode 100644
index 00000000000..392104742c2
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.cc
@@ -0,0 +1,18 @@
+// Copyright 2020 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/exo/wayland/compatibility_test/client_compatibility_test.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+ClientCompatibilityTest::ClientCompatibilityTest() = default;
+ClientCompatibilityTest::~ClientCompatibilityTest() = default;
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo \ No newline at end of file
diff --git a/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.h b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.h
new file mode 100644
index 00000000000..37d067ea791
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test.h
@@ -0,0 +1,29 @@
+// Copyright 2020 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_EXO_WAYLAND_COMPATIBILITY_TEST_CLIENT_COMPATIBILITY_TEST_H_
+#define COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_CLIENT_COMPATIBILITY_TEST_H_
+
+#include "components/exo/wayland/clients/test/wayland_client_test.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+class ClientCompatibilityTest : public WaylandClientTest {
+ public:
+ ClientCompatibilityTest();
+ ~ClientCompatibilityTest() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClientCompatibilityTest);
+};
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_CLIENT_COMPATIBILITY_TEST_H_
diff --git a/chromium/components/exo/wayland/compatibility_test/client_compatibility_test_server.cc b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test_server.cc
new file mode 100644
index 00000000000..163b4cc7539
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/client_compatibility_test_server.cc
@@ -0,0 +1,44 @@
+// Copyright 2020 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 "base/bind.h"
+#include "components/exo/wayland/clients/test/wayland_client_test_server.h"
+#include "components/exo/wayland/compatibility_test/client_compatibility_test.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+namespace {
+
+class CompatibilityTestSuiteServer : public WaylandClientTestSuiteServer {
+ public:
+ using WaylandClientTestSuiteServer::WaylandClientTestSuiteServer;
+
+ void SetClientTestUIThreadTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
+ override {
+ ClientCompatibilityTest::SetUIThreadTaskRunner(
+ std::move(ui_thread_task_runner));
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CompatibilityTestSuiteServer);
+};
+
+std::unique_ptr<WaylandClientTestSuiteServer> MakeServer(int argc,
+ char** argv) {
+ return std::make_unique<CompatibilityTestSuiteServer>(argc, argv);
+}
+
+} // namespace
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+int main(int argc, char** argv) {
+ return exo::WaylandClientTestSuiteServer::TestMain(
+ argc, argv,
+ base::BindOnce(&exo::wayland::compatibility::test::MakeServer));
+}
diff --git a/chromium/components/exo/wayland/compatibility_test/template_client_event_receiver_version_tests.cc.tmpl b/chromium/components/exo/wayland/compatibility_test/template_client_event_receiver_version_tests.cc.tmpl
new file mode 100644
index 00000000000..2f1f95bed33
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/template_client_event_receiver_version_tests.cc.tmpl
@@ -0,0 +1,415 @@
+// Copyright 2020 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 <algorithm>
+#include <memory>
+#include <type_traits>
+
+#include "base/check.h"
+#include "base/logging.h"
+#include "components/exo/wayland/compatibility_test/client_compatibility_test.h"
+{% for protocol in protocols %}
+#include "components/exo/wayland/compatibility_test/generated-{{ protocol.filename }}-client-helpers.h"
+{% endfor %}
+#include "components/exo/wayland/compatibility_test/wayland_client_registry.h"
+#include "components/exo/wayland/compatibility_test/wayland_client_event_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+
+{#
+Figure out which Wayland interfaces need to be tested.
+
+We only need to test interfaces which have events with a "since" that is
+greater than the first possible version of the interface.
+#}
+{% set interfaces_to_test = [] %}
+{% for protocol in protocols %}
+ {% for interface in protocol.interfaces %}
+ {% set min_version = get_minimum_version_to_construct(interface) %}
+ {# if interface.events|selectattr("since")|max(attribute="since") > min_version #}
+ {% if interface.events|selectattr("since")|selectattr("since", ">", min_version)|list|length %}
+ {% set _ = interfaces_to_test.append(interface) %}
+ {% endif %}
+ {% endfor %}
+{% endfor %}
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+namespace {
+
+// Each of these generated fixture interfaces can be overriden by
+// non-generated code in wayland_client_event_receiver_version_fixtures.h
+
+{% for target_interface in interfaces_to_test %}
+ {% set steps = get_construction_steps(target_interface) %}
+
+class {{ target_interface.name | pascal }}EventTestBase : public ClientCompatibilityTest {
+ protected:
+ // Returns true if this test should be skipped. The base implementation
+ // checks that the server supports the required interface versions.
+ virtual bool ShouldSkip(uint32_t target_interface_version) const noexcept;
+ {% for step in steps %}
+ {% if step.ctor %}
+ {% if step.ctor.message.is_event %}
+ // Overriden by non-generated code to ensure the server sends the interface
+ // creation event.
+ virtual void NudgeServerFor{{ step.instance_name | pascal }}Creation() noexcept;
+ {% endif %}
+ // Factory function to set {{ step.instance_name }}
+ virtual std::unique_ptr<struct {{ step.interface.name }}> Make{{ step.instance_name | pascal }}() noexcept;
+ {% endif %}
+ {% endfor %}
+ // Overriden by non-generated code to ensure the server sends the required
+ // events.
+ virtual void NudgeServerForTestEvents() noexcept;
+
+ void ValidateEventsImpl(uint32_t target_interface_version) noexcept;
+ void ValidateEvents(uint32_t target_interface_version) noexcept;
+
+ // Interfaces and helpers needed for the test, in construction order.
+ std::unique_ptr<wl_display> display_;
+ std::unique_ptr<WaylandClientRegistry> registry_;
+ {% for step in steps %}
+ std::unique_ptr<struct {{ step.interface.name }}> {{ step.instance_name }};
+ {% endfor %}
+};
+
+{% endfor %}
+
+} // namespace
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+// This is intentionally included after all the fixture class definitions
+// above, so that the header file can provide overrides.
+#include "components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+namespace {
+
+{% for target_interface in interfaces_to_test %}
+ {% set steps = get_construction_steps(target_interface) %}
+ {% set base_fixture_name = target_interface.name | pascal + "EventTestBase" %}
+// Make sure this is defined even if not complete.
+struct {{ target_interface.name | pascal }}EventTest;
+
+// Use {{ target_interface.name | pascal }}EventTest if it is defined, otherwise
+// fall back to {{ target_interface.name | pascal }}EventTestBase.
+constexpr bool k{{ target_interface.name | pascal }}EventTestFixtureUsesOverride =
+ std::is_convertible<
+ {{ target_interface.name | pascal }}EventTest*,
+ {{ target_interface.name | pascal }}EventTestBase*
+ >::value;
+using {{ target_interface.name | pascal }}EventTestFixture =
+ std::conditional_t<
+ k{{ target_interface.name | pascal }}EventTestFixtureUsesOverride,
+ {{ target_interface.name | pascal }}EventTest,
+ {{ target_interface.name | pascal }}EventTestBase>;
+
+bool {{ base_fixture_name }}::ShouldSkip(uint32_t target_interface_version) const noexcept {
+ return false
+ {% for step in steps %}
+ {% if not step.ctor %}
+ {% if step.interface.protocol == target_interface.protocol %}
+ || !registry_->Has<struct {{step.interface.name}}>(
+ std::max(target_interface_version, {{ step.minimum_version }}u))
+ {% else %}
+ || !registry_->Has<struct {{step.interface.name}}>({{ step.minimum_version }}u)
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ ;
+}
+
+ {% for step in steps %}
+ {% if step.ctor %}
+ {% if step.ctor.message.is_event %}
+void {{ base_fixture_name }}::NudgeServerFor{{ step.instance_name | pascal }}Creation() noexcept {}
+
+ {% endif %}
+std::unique_ptr<struct {{ step.interface.name }}>
+{{ base_fixture_name }}::Make{{ step.instance_name | pascal }}() noexcept {
+ {% if not step.ctor.message.is_event %}
+ auto {{ step.instance_name }} = std::unique_ptr<struct {{ step.interface.name }}>(
+ {{ step.ctor.interface_step.interface.name }}_{{ step.ctor.message.name }}(
+ {{ step.ctor.interface_step.instance_name }}.get()
+ {% for arg in step.ctor.message.args %}
+ {% if arg.type == "new_id" %}
+ {% elif arg.type == "object" %}
+ , {{ step.ctor.object_args[loop.index0].instance_name }}.get()
+ {% elif arg.type == "fd" %}
+ , -1 /* generated default {{ arg.type }} value for {{ arg.name }} */
+ {% elif arg.type == "string" %}
+ , "" /* generated default {{ arg.type }} value for {{ arg.name }} */
+ {% elif arg.type == "array" %}
+ , nullptr_t /* generated default {{ arg.type }} value for {{ arg.name }} */
+ {% elif arg.type in ["int", "uint", "fixed"] %}
+ , 0 /* generated default {{ arg.type }} value for {{ arg.name }} */
+ {% else %}
+ , nullptr_t /* generated default {{ arg.type }} value for {{ arg.name }} */
+ {% endif %}
+ {% endfor %}
+ ));
+ {% else %}
+ std::unique_ptr<struct {{ step.interface.name }}> {{ step.instance_name }};
+
+ static {{ step.ctor.interface_step.interface.name }}_listener {{ step.ctor.interface_step.interface.name }}_listener = {
+ {% for event in step.ctor.interface_step.interface.events %}
+ /* {{ event.name }} */
+ [](void* user_data_, struct {{ step.ctor.interface_step.interface.name }}* interface_
+ {% for arg in event.args %}
+ {{ get_c_arg_for_client_event_arg(arg) }}
+ {% endfor %}
+ ) {
+ {% if event.name == step.ctor.message.name %}
+ if (user_data_) {
+ {% for arg in event.args %}
+ {% if arg.type == "ctor" and arg.interface == step.interface.name %}
+ auto* container = static_cast<std::unique_ptr<struct {{ step.interface.name }}>*>(context);
+ (*container) = {{ arg.name }};
+ {% endif %}
+ {% endfor %}
+ } else {
+ LOG(INFO) << "Received unexpected " << "{{ step.ctor.interface_step.interface.name }}::{{ event.name }}";
+ }
+ {% else %}
+ LOG(INFO) << "Received unexpected " << "{{ step.ctor.interface_step.interface.name }}::{{ event.name }}";
+ {% endif %}
+
+ {% for arg in event.args %}
+ {% if event.args.type == "fd" %}
+ base::ScopedFD unused_scoped_{{ arg.name }}(fd);
+ {% endif %}
+ {% endfor %}
+ },
+ {% endfor %}
+ };
+
+ {
+ int err = {{ step.ctor.interface_step.interface.name }}_add_listener(
+ {{ step.ctor.interface_step.instance_name }}.get(),
+ &{{ step.ctor.interface_step.interface.name }}_listener,
+ &{{ step.instance_name }});
+ if (err != 0) {
+ ADD_FAILURE() << "Failed to add listener!";
+ return {};
+ }
+ }
+
+ // Sync with the server to ensure it receives all requests
+ {
+ int err = wl_display_roundtrip(display_.get());
+ if (err < 0) {
+ ADD_FAILURE() << "Failed to roundtrip!";
+ return {};
+ }
+ }
+
+ NudgeServerFor{{ step.instance_name | pascal }}Creation();
+
+ // Sync with the server again to process all events
+ {
+ int err = wl_display_roundtrip(display_.get());
+ if (err < 0) {
+ ADD_FAILURE() << "Failed to roundtrip!";
+ return {};
+ }
+ }
+
+ // We want to keep the instance but want to ignore further events.
+ {{ step.ctor.interface_step.interface.name }}_set_user_data({{ step.ctor.interface_step.instance_name }}.get(), nullptr);
+
+ if (!{{ step.instance_name }}.get())
+ ADD_FAILURE()
+ << "Required event {{ step.ctor.interface_step.interface.name }}::{{ step.ctor.message.name }}\n"
+ << "not received! This is needed to construct a {{ step.interface.name }} instance.\n"
+ << "You may need to define "
+ << "{{ step.interface.name | pascal }}EventTest::NudgeServerFor{{ step.instance_name | pascal }}Creation()";
+
+ {% endif %}
+ return {{ step.instance_name }};
+}
+
+ {% endif %}
+ {% endfor %}
+
+void {{ base_fixture_name }}::NudgeServerForTestEvents() noexcept {}
+
+void {{ base_fixture_name }}::ValidateEventsImpl(uint32_t target_interface_version) noexcept {
+ display_ = std::unique_ptr<wl_display>(wl_display_connect(nullptr));
+ ASSERT_THAT(display_.get(), ::testing::IsTrue());
+
+ registry_ = std::make_unique<WaylandClientRegistry>(display_.get());
+ ASSERT_THAT(registry_.get(), ::testing::IsTrue());
+ ASSERT_THAT(wl_display_roundtrip(display_.get()), ::testing::Ge(0));
+
+ if (ShouldSkip(target_interface_version)) {
+ GTEST_SKIP();
+ return;
+ }
+
+ {% for step in steps %}
+ {% if step.ctor %}
+ {{ step.instance_name }} = Make{{ step.instance_name|pascal }}();
+ {% else %}
+ {% if step.interface.protocol == target_interface.protocol %}
+ {{ step.instance_name }} = registry_->Bind<struct {{step.interface.name}}>(
+ std::max(target_interface_version, {{ step.minimum_version }}u));
+ {% else %}
+ {{ step.instance_name }} = registry_->Bind<struct {{step.interface.name}}>(
+ {{ step.minimum_version }}u);
+ {% endif %}
+ {% endif %}
+ ASSERT_THAT({{ step.instance_name }}.get(), ::testing::IsTrue());
+ {% endfor %}
+
+ {% set min_version = get_minimum_version_to_construct(target_interface) %}
+// Min version: {{ min_version }}
+ {% for event in target_interface.events %}
+// event {{ event.name }} since {{ event.since }} {{ event.since and event.since > min_version }}
+ {% endfor %}
+
+ static {{ target_interface.name }}_listener {{ target_interface.name }}_listener = {
+ {% for event in target_interface.events %}
+ /* {{ event.name }} */
+ [](void* user_data_, struct {{ target_interface.name }}* interface_
+ {% for arg in event.args %}
+ {{ get_c_arg_for_client_event_arg(arg) }}
+ {% endfor %}
+ ) {
+ {% if event.since and event.since > min_version %}
+ auto* recorder = static_cast<EventRecorder*>(user_data_);
+ uint32_t version = {{ target_interface.name }}_get_version(interface_);
+ recorder->OnEvent(
+ "{{ target_interface.name }}::{{ event.name }}",
+ version);
+ {% endif %}
+
+ {% for arg in event.args %}
+ {% if event.args.type == "fd" %}
+ base::ScopedFD unused_scoped_{{ arg.name }}(fd);
+ {% endif %}
+ {% endfor %}
+ },
+ {% endfor %}
+ };
+
+ EventRecorder recorder;
+
+ {
+ int err = {{ target_interface.name }}_add_listener(
+ {{ steps[-1].instance_name }}.get(),
+ &{{ target_interface.name }}_listener,
+ &recorder);
+ ASSERT_THAT(err, ::testing::Eq(0)) << "Failed to add target listener!";
+ }
+
+ // Ensure the server side receives all the creation requests
+ ASSERT_THAT(wl_display_roundtrip(display_.get()), ::testing::Ge(0));
+
+ NudgeServerForTestEvents();
+
+ // Ensure the server side events are received and processed
+ ASSERT_THAT(wl_display_roundtrip(display_.get()), ::testing::Ge(0));
+
+ // These expectations are really what this test is checking.
+ {% for event in target_interface.events %}
+ {% if event.since and event.since > min_version %}
+ {
+ const char* event_name =
+ "{{ target_interface.name }}::{{ event.name }}";
+ constexpr uint32_t event_since_version =
+ {{ event.since or 1 }}u;
+ base::Optional<uint32_t> received_at_version =
+ recorder.MaybeGetReceivedAtVersion(event_name);
+
+ if (target_interface_version == event_since_version) {
+ EXPECT_THAT(received_at_version, ::testing::Not(::testing::Eq(base::nullopt)))
+ << "Failed to receive " << event_name << " at interface version "
+ << target_interface_version
+ << " as the event is defined as since version "
+ << event_since_version << ".\n"
+ << "\n"
+ << "You may need to override:\n"
+ << " {{ target_interface.name | pascal }}EventTest::NudgeServerForTestEvents()\n"
+ << "to ensure the event is sent by the server.";
+ }
+
+ if (target_interface_version >= event_since_version) {
+ ASSERT_THAT(received_at_version, ::testing::AnyOf(
+ ::testing::Eq(base::nullopt),
+ ::testing::Optional(::testing::Eq(target_interface_version))))
+ << "Unexpected version mismatch. Test expected to create a\n"
+ << " {{ target_interface.name }}"
+ << "at version "
+ << target_interface_version
+ << " but actually created the interface at version "
+ << received_at_version.value_or(0u)
+ << ".";
+ }
+
+ if (target_interface_version < event_since_version) {
+ EXPECT_THAT(received_at_version, ::testing::Eq(base::nullopt))
+ << "Unexpectedly received "
+ << event_name
+ << " at interface version "
+ << received_at_version.value_or(0u)
+ << ".\n"
+ << "The event is defined as since version "
+ << event_since_version
+ << " and can cause the client to\n"
+ << "abort or crash if sent to a client that uses an earlier version.";
+ }
+ }
+
+ {% endif %}
+ {% endfor %}
+}
+
+void {{ base_fixture_name }}::ValidateEvents(uint32_t target_interface_version) noexcept {
+ ValidateEventsImpl(target_interface_version);
+
+ if (HasFailure() && !k{{ target_interface.name | pascal }}EventTestFixtureUsesOverride) {
+ LOG(INFO)
+ << "\n"
+ << "Note:\n"
+ << " {{ target_interface.name | pascal }}EventTest\n"
+ << "can be defined to override the default generated code for this test.\n"
+ << "\n"
+ << "For example, to disable/skip this test, add this to\n"
+ << "components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h:\n"
+ << "\n"
+ << " struct {{ target_interface.name | pascal }}EventTest\n"
+ << " : public {{ target_interface.name | pascal }}EventTestBase {\n"
+ << " bool ShouldSkip(uint32_t) const noexcept override;\n"
+ << " };\n"
+ << " bool {{ target_interface.name | pascal }}EventTest::ShouldSkip(uint32_t) const noexcept {\n"
+ << " return true;\n"
+ << " }\n"
+ << "\n"
+ << "Otherwise see that header for more general notes.";
+ }
+}
+
+ {% for target_interface_version in get_versions_to_test_for_event_delivery(target_interface) %}
+TEST_F({{ target_interface.name | pascal }}EventTestFixture,
+ EventsForV{{ target_interface_version }}) {
+ ValidateEvents({{ target_interface_version }});
+}
+
+ {% endfor %}
+{% endfor %}
+} // namespace
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
diff --git a/chromium/components/exo/wayland/compatibility_test/template_client_helpers.cc.tmpl b/chromium/components/exo/wayland/compatibility_test/template_client_helpers.cc.tmpl
new file mode 100644
index 00000000000..89edfc97de8
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/template_client_helpers.cc.tmpl
@@ -0,0 +1,32 @@
+// Copyright 2020 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.
+
+{% if protocol.name == 'wayland' %}
+#include <wayland-client-core.h>
+{% endif %}
+#include "components/exo/wayland/compatibility_test/generated-{{ protocol.filename|kebab }}-client-helpers.h"
+
+
+namespace std {
+
+{% for interface in protocol.interfaces|sort(attribute="name") %}
+void default_delete<struct {{ interface.name }}>::operator()(struct {{ interface.name }}* instance) noexcept {
+ if (instance)
+ {% if interface.name == 'wl_display' %}
+ wl_display_disconnect(instance);
+ {% else %}
+ {{ interface.name }}_{{ get_destructor(interface).name or "destroy" }}(instance);
+ {% endif %}
+}
+
+{% endfor %}
+
+} // namespace std
+
+{% for interface in protocol.interfaces|sort(attribute="name") %}
+const wl_interface*
+ WaylandGlobalInterfaceDescriptor<struct {{ interface.name }}>::protocol_interface =
+ &{{ interface.name }}_interface;
+
+{% endfor %}
diff --git a/chromium/components/exo/wayland/compatibility_test/template_client_helpers.h.tmpl b/chromium/components/exo/wayland/compatibility_test/template_client_helpers.h.tmpl
new file mode 100644
index 00000000000..d3641c690a4
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/template_client_helpers.h.tmpl
@@ -0,0 +1,39 @@
+// Copyright 2020 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.
+
+{% set header_guard = "COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_" + protocol.name|upper + "_CLIENT_HELPERS_H_" %}
+#ifndef {{ header_guard }}
+#define {{ header_guard }}
+
+#include <memory>
+
+#include <{{ protocol.filename }}-client-protocol.h>
+
+namespace std {
+
+{% for interface in protocol.interfaces|sort(attribute="name") %}
+template <>
+struct default_delete<struct {{ interface.name }}> {
+ void operator()(struct {{ interface.name }}*) noexcept;
+};
+
+{% endfor %}
+
+} // namespace std
+
+template <typename T>
+struct WaylandGlobalInterfaceDescriptor;
+
+{% for interface in protocol.interfaces|sort(attribute="name") %}
+template <>
+struct WaylandGlobalInterfaceDescriptor<struct {{ interface.name }}> {
+ using CType = struct {{ interface.name }};
+ static const wl_interface* protocol_interface;
+ static constexpr const char* interface_name = "{{ interface.name }}";
+ static constexpr uint32_t protocol_version = {{ interface.version }};
+};
+
+{% endfor %}
+
+#endif /* {{ header_guard }} */
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h
new file mode 100644
index 00000000000..ec3577b300b
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_receiver_version_fixtures.h
@@ -0,0 +1,159 @@
+// Copyright 2020 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_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECEIVER_VERSION_FIXTURES_H_
+#define COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECEIVER_VERSION_FIXTURES_H_
+
+// ===========================================================================
+//
+// This file contains optional fixture overrides/customizations for each of
+// the generated fixtures. Each generated fixture has functions that can be
+// overridden for:
+//
+// 1) Determining if the test should be skipped. The generated code skips
+// tests for interface versions not supported by the server.
+//
+// 2) Creating target and dependent interfaces for each test. For some tests,
+// the generated default creation steps may work to get a valid target
+// interface.
+//
+// 3) "Nudge" functions called by the client test to help inject or otherwise
+// trigger event generation by the server. The server may otherwise not
+// send certain events without some other trigger, such as keys being
+// pressed to generate keyboard input events.
+//
+// Understanding what can and may need to be overridden means examining the
+// generated code in:
+//
+// out/$target/gen/components/exo/wayland/compatibility_test/
+// all_generated_client_event_receiver_version_tests.cc
+//
+// At present this file contains examples for only the first case. Getting more
+// tests to work (see TODO's below) will require the other two types of
+// overrides.
+// ===========================================================================
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+namespace {
+
+struct ZauraSurfaceEventTest : public ZauraSurfaceEventTestBase {
+ using Base = ZauraSurfaceEventTestBase;
+ bool ShouldSkip(uint32_t version) const noexcept override;
+};
+
+bool ZauraSurfaceEventTest::ShouldSkip(uint32_t version) const noexcept {
+ // TODO(b/157254342): Remove the skip for versions >= 8
+ if (version >= 8)
+ return true;
+ return Base::ShouldSkip(version);
+}
+
+struct WlDataOfferEventTest : public WlDataOfferEventTestBase {
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool WlDataOfferEventTest::ShouldSkip(uint32_t) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+}
+
+struct WlDataSourceEventTest : public WlDataSourceEventTestBase {
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool WlDataSourceEventTest::ShouldSkip(uint32_t) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+}
+
+struct WlPointerEventTest : public WlPointerEventTestBase {
+ using Base = WlPointerEventTestBase;
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool WlPointerEventTest::ShouldSkip(uint32_t version) const noexcept {
+ // TODO(b/157254342): Remove the skip for versions >= 5
+ if (version >= 5)
+ return true;
+ return Base::ShouldSkip(version);
+}
+
+struct WlTouchEventTest : public WlTouchEventTestBase {
+ using Base = WlTouchEventTestBase;
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool WlTouchEventTest::ShouldSkip(uint32_t version) const noexcept {
+ // TODO(b/157254342): Remove the skip for versions >= 6
+ if (version >= 6)
+ return true;
+ return Base::ShouldSkip(version);
+}
+
+struct XdgPopupEventTest : public XdgPopupEventTestBase {
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool XdgPopupEventTest::ShouldSkip(uint32_t) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+}
+
+struct ZcrGamepadV2EventTest : public ZcrGamepadV2EventTestBase {
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool ZcrGamepadV2EventTest::ShouldSkip(uint32_t) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+}
+
+struct ZcrKeyboardDeviceConfigurationV1EventTest
+ : public ZcrKeyboardDeviceConfigurationV1EventTestBase {
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool ZcrKeyboardDeviceConfigurationV1EventTest::ShouldSkip(
+ uint32_t) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+}
+
+struct ZcrRemoteShellV1EventTest : public ZcrRemoteShellV1EventTestBase {
+ using Base = ZcrRemoteShellV1EventTestBase;
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool ZcrRemoteShellV1EventTest::ShouldSkip(uint32_t version) const noexcept {
+ // Note: versions < 20 are NO LONGER supported by the server.
+ if (version < 20)
+ return true;
+ return Base::ShouldSkip(version);
+}
+
+struct ZcrRemoteSurfaceV1EventTest : public ZcrRemoteSurfaceV1EventTestBase {
+ using Base = ZcrRemoteSurfaceV1EventTestBase;
+ bool ShouldSkip(uint32_t) const noexcept override;
+};
+
+bool ZcrRemoteSurfaceV1EventTest::ShouldSkip(uint32_t version) const noexcept {
+ // TODO(b/157254342): Remove the skip for any version
+ return true;
+
+ // Note: versions < 20 are NO LONGER supported by the server.
+ // if (version < 20)
+ // return true;
+ // return Base::ShouldSkip(version);
+}
+
+} // namespace
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECEIVER_VERSION_FIXTURES_H_
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.cc b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.cc
new file mode 100644
index 00000000000..adca10683b8
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.cc
@@ -0,0 +1,18 @@
+// Copyright 2020 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/exo/wayland/compatibility_test/wayland_client_event_recorder.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+EventRecorder::EventRecorder() = default;
+EventRecorder::~EventRecorder() = default;
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.h b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.h
new file mode 100644
index 00000000000..5dc15c2c10e
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_client_event_recorder.h
@@ -0,0 +1,41 @@
+// Copyright 2020 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_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECORDER_H_
+#define COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECORDER_H_
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+#include "base/optional.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+struct EventRecorder {
+ EventRecorder();
+ ~EventRecorder();
+
+ void OnEvent(const char* event_name, uint32_t version) noexcept {
+ data.emplace(event_name, version);
+ }
+
+ base::Optional<uint32_t> MaybeGetReceivedAtVersion(
+ const char* event_name) const noexcept {
+ auto it = data.find(event_name);
+ return it != data.end() ? base::make_optional(it->second) : base::nullopt;
+ }
+
+ std::unordered_map<std::string, uint32_t> data;
+};
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_EVENT_RECORDER_H_
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.cc b/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.cc
new file mode 100644
index 00000000000..9434cb92c9d
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.cc
@@ -0,0 +1,85 @@
+// Copyright 2020 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 <wayland-client-core.h>
+#include <wayland-client-protocol.h>
+
+#include "base/check.h"
+#include "base/logging.h"
+#include "components/exo/wayland/compatibility_test/wayland_client_registry.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+WaylandClientRegistry::WaylandClientRegistry(wl_display* display)
+ : registry_(wl_display_get_registry(display)) {
+ static wl_registry_listener registry_listener = {
+ &WaylandClientRegistry::Add,
+ &WaylandClientRegistry::Remove,
+ };
+ int err = wl_registry_add_listener(registry_.get(), &registry_listener, this);
+ DCHECK(err == 0);
+}
+
+WaylandClientRegistry::~WaylandClientRegistry() = default;
+
+base::Optional<WaylandClientRegistry::Entry> WaylandClientRegistry::GetEntry(
+ const char* interface_name) const noexcept {
+ DCHECK(registry_);
+ if (!registry_)
+ return {};
+
+ const auto it = globals_.find(interface_name);
+ if (it == globals_.end())
+ return {};
+
+ return it->second;
+}
+
+bool WaylandClientRegistry::Has(const char* interface_name,
+ uint32_t client_version) const noexcept {
+ const auto entry = GetEntry(interface_name);
+ return entry ? entry->server_version >= client_version : false;
+}
+
+void* WaylandClientRegistry::Bind(const char* interface_name,
+ const struct wl_interface* protocol_interface,
+ uint32_t protocol_version,
+ uint32_t client_version) noexcept {
+ const auto entry = GetEntry(interface_name);
+
+ if (!entry || entry->server_version < client_version)
+ return nullptr;
+
+ // This code should be built from the same sources. While the newest
+ // versions of the protocol may not be used by the server, the server
+ // shouldn't be claiming support for an unexpected version.
+ DCHECK(entry->server_version <= protocol_version);
+
+ return wl_registry_bind(registry_.get(), entry->name, protocol_interface,
+ client_version);
+}
+
+void WaylandClientRegistry::Add(void* context,
+ wl_registry*,
+ uint32_t name,
+ const char* interface,
+ uint32_t version) {
+ WaylandClientRegistry* registry =
+ static_cast<WaylandClientRegistry*>(context);
+ registry->globals_.emplace(interface,
+ WaylandClientRegistry::Entry{name, version});
+}
+
+void WaylandClientRegistry::Remove(void*, wl_registry*, uint32_t name) {
+ LOG(ERROR) << "Unexpected global remove of id " << name;
+ DCHECK(false);
+}
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.h b/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.h
new file mode 100644
index 00000000000..bae0206a0ee
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_client_registry.h
@@ -0,0 +1,83 @@
+// Copyright 2020 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_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_REGISTRY_H_
+#define COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_REGISTRY_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include <wayland-client-core.h>
+#include <wayland-client-protocol.h>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/exo/wayland/compatibility_test/generated-wayland-client-helpers.h"
+
+namespace exo {
+namespace wayland {
+namespace compatibility {
+namespace test {
+
+class WaylandClientRegistry {
+ public:
+ explicit WaylandClientRegistry(wl_display* display);
+ ~WaylandClientRegistry();
+
+ WaylandClientRegistry(const WaylandClientRegistry&) = delete;
+ WaylandClientRegistry& operator=(const WaylandClientRegistry&) = delete;
+
+ template <typename T>
+ bool Has(uint32_t client_version) const noexcept;
+
+ template <typename T>
+ std::unique_ptr<T> Bind(uint32_t client_version) noexcept;
+
+ private:
+ static void Add(void*,
+ wl_registry*,
+ uint32_t name,
+ const char* interface,
+ uint32_t version) noexcept;
+ static void Remove(void*, wl_registry*, uint32_t name) noexcept;
+
+ struct Entry {
+ uint32_t name;
+ uint32_t server_version;
+ };
+
+ base::Optional<Entry> GetEntry(const char* interface_name) const noexcept;
+ bool Has(const char* interface_name, uint32_t client_version) const noexcept;
+ void* Bind(const char* interface_name,
+ const struct wl_interface* protocol_interface,
+ uint32_t protocol_version,
+ uint32_t client_version) noexcept;
+
+ std::unique_ptr<wl_registry> registry_;
+ std::unordered_map<std::string, Entry> globals_;
+};
+
+template <typename T>
+bool WaylandClientRegistry::Has(uint32_t client_version) const noexcept {
+ using Descriptor = WaylandGlobalInterfaceDescriptor<T>;
+ return Has(Descriptor::interface_name, client_version);
+}
+
+template <typename T>
+std::unique_ptr<T> WaylandClientRegistry::Bind(
+ uint32_t client_version) noexcept {
+ using Descriptor = WaylandGlobalInterfaceDescriptor<T>;
+ return std::unique_ptr<typename Descriptor::CType>(
+ static_cast<typename Descriptor::CType*>(
+ Bind(Descriptor::interface_name, Descriptor::protocol_interface,
+ Descriptor::protocol_version, client_version)));
+}
+
+} // namespace test
+} // namespace compatibility
+} // namespace wayland
+} // namespace exo
+
+#endif // COMPONENTS_EXO_WAYLAND_COMPATIBILITY_TEST_WAYLAND_CLIENT_REGISTRY_H_
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_c_arg_handling.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_c_arg_handling.py
new file mode 100644
index 00000000000..92c36e9dd7f
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_c_arg_handling.py
@@ -0,0 +1,85 @@
+# Copyright 2020 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 wayland_protocol_data_classes
+
+MessageArgType = wayland_protocol_data_classes.MessageArgType
+
+
+def get_c_argument_type(arg_type):
+ # type: (MessageArgType) -> str
+ """Maps a protocol argument type to a C type."""
+ # Note: This should match what the core scanner.c does
+ return {
+ MessageArgType.INT.value: 'int32_t',
+ MessageArgType.UINT.value: 'uint32_t',
+ MessageArgType.FIXED.value: 'wl_fixed_t',
+ MessageArgType.STRING.value: 'const char*',
+ MessageArgType.FD.value: 'int32_t',
+ MessageArgType.ARRAY.value: 'struct wl_array *',
+ MessageArgType.NEW_ID.value: 'uint32_t',
+ }[arg_type]
+
+
+def get_c_arg_for_server_request_arg(arg):
+ # type: (MessageArg) -> str:
+ """Maps a protocol argument to C argument(s) for server-side requests."""
+ # Note: This should match what the core scanner.c does
+ if arg.type == MessageArgType.NEW_ID.value and not arg.interface:
+ return (', const char *interface, uint32_t version, '
+ 'uint32_t %s' % arg.name)
+ elif arg.type == MessageArgType.NEW_ID.value:
+ return ', uint32_t %s' % arg.name
+ elif arg.type == MessageArgType.OBJECT.value:
+ return ', struct %s *%s' % (arg.interface, arg.name)
+ else:
+ return ', %s %s' % (get_c_argument_type(arg.type), arg.name)
+
+
+def get_c_arg_for_server_event_arg(arg):
+ # type: (MessageArg) -> str:
+ """Maps a protocol argument to C argument(s) for server-side events."""
+ # Note: This should match what the core scanner.c does
+ if arg.type == MessageArgType.NEW_ID.value:
+ return ', struct wl_resource* %s' % arg.name
+ else:
+ return ', %s %s' % (get_c_argument_type(arg.type), arg.name)
+
+
+def get_c_return_type_for_client_request(message):
+ # type: (Message) -> str:
+ """Determines the C return type for client-side requests."""
+ # Note: This should match what the core scanner.c does
+ for arg in message.args:
+ if arg.type == MessageArgType.NEW_ID.value:
+ if arg.interface is None:
+ return 'void *'
+ else:
+ return 'struct %s' % arg.interface
+ return 'void'
+
+
+def get_c_arg_for_client_request_arg(arg):
+ # type: (MessageArg) -> str:
+ """Maps a protocol argument to C argument(s) for client-side requeuests."""
+ # Note: This should match what the core scanner.c does
+ if arg.type == MessageArgType.NEW_ID.value and not arg.interface:
+ return ', const struct wl_interface *interface, uint32_t version'
+ elif arg.type == MessageArgType.NEW_ID.value:
+ return ''
+ else:
+ return ', %s %s' % (get_c_argument_type(arg.type), arg.name)
+
+
+def get_c_arg_for_client_event_arg(arg):
+ # type: (MessageArg) -> str:
+ """Maps a protocol argument to C argument(s) for client-side events."""
+ if arg.type == MessageArgType.OBJECT.value and arg.interface is None:
+ return ', void * %s' % arg.name
+ elif arg.type == MessageArgType.NEW_ID.value:
+ return ', struct %s *%s' % (arg.interface, arg.name)
+ elif arg.type == MessageArgType.OBJECT.value:
+ return ', struct %s *%s' % (arg.interface, arg.name)
+ else:
+ return ', %s %s' % (get_c_argument_type(arg.type), arg.name)
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.gni b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.gni
new file mode 100644
index 00000000000..d3fb213f84d
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.gni
@@ -0,0 +1,57 @@
+template("wayland_protocol_codegen") {
+ assert(defined(invoker.template),
+ "Need template for for wayland_protocol_codegen")
+ assert(defined(invoker.sources),
+ "Need sources for for wayland_protocol_codegen")
+ assert(defined(invoker.output_pattern),
+ "Need output_pattern for for wayland_protocol_codegen")
+
+ # If the invoker sets "reduce=true", we are generating a single output from
+ # all the source protocols.
+ if (defined(invoker.reduce) && invoker.reduce) {
+ action = "action"
+ } else {
+ action = "action_foreach"
+ }
+
+ target(action, target_name) {
+ forward_variables_from(invoker,
+ [
+ "data",
+ "data_deps",
+ "depfile",
+ "deps",
+ "metadata",
+ "pool",
+ "response_file_contents",
+ "sources",
+ "testonly",
+ ])
+
+ script = "//components/exo/wayland/compatibility_test/wayland_protocol_codegen.py"
+ inputs = [ invoker.template ]
+ outputs = [ invoker.output_pattern ]
+
+ if (host_os == "win") {
+ clang_format_path = "//buildtools/win/clang-format.exe"
+ } else if (host_os == "mac") {
+ clang_format_path = "//buildtools/mac/clang-format"
+ } else if (host_os == "linux") {
+ clang_format_path = "//buildtools/linux64/clang-format"
+ } else {
+ assert(false)
+ }
+
+ args = [
+ rebase_path("//third_party", root_build_dir),
+ rebase_path(clang_format_path, root_build_dir),
+ rebase_path(invoker.template, root_build_dir),
+ rebase_path(invoker.output_pattern, root_build_dir),
+ ]
+ if (defined(invoker.reduce) && invoker.reduce) {
+ args += rebase_path(sources, root_build_dir)
+ } else {
+ args += [ "{{source}}" ]
+ }
+ }
+}
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.py
new file mode 100644
index 00000000000..0b8215ccbef
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_codegen.py
@@ -0,0 +1,119 @@
+# Copyright 2020 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 argparse
+import os.path
+import subprocess
+import sys
+
+import wayland_protocol_c_arg_handling
+import wayland_protocol_construction
+import wayland_protocol_data_classes
+import wayland_protocol_externals
+import wayland_protocol_identifiers
+
+
+def expand_template(template, context):
+ # type: (str, Mapping[str, Any]) -> str
+ """Expands the template using context, and returns the result"""
+
+ # Loaded from third_party/jinja2 after a sys.path modification
+ import jinja2
+
+ env = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(os.path.dirname(template)),
+ keep_trailing_newline=True, # newline-terminate generated files
+ lstrip_blocks=True,
+ trim_blocks=True) # so don't need {%- -%} everywhere
+
+ # Additional global functions
+ env.globals['get_c_arg_for_server_request_arg'] = (
+ wayland_protocol_c_arg_handling.get_c_arg_for_server_request_arg)
+ env.globals['get_c_arg_for_server_event_arg'] = (
+ wayland_protocol_c_arg_handling.get_c_arg_for_server_event_arg)
+ env.globals['get_c_return_type_for_client_request'] = (
+ wayland_protocol_c_arg_handling.get_c_return_type_for_client_request)
+ env.globals['get_c_arg_for_client_request_arg'] = (
+ wayland_protocol_c_arg_handling.get_c_arg_for_client_request_arg)
+ env.globals['get_c_arg_for_client_event_arg'] = (
+ wayland_protocol_c_arg_handling.get_c_arg_for_client_event_arg)
+ env.globals['get_construction_steps'] = (
+ wayland_protocol_construction.get_construction_steps)
+ env.globals['get_destructor'] = (
+ wayland_protocol_construction.get_destructor)
+ env.globals['get_external_interfaces_for_protocol'] = (
+ wayland_protocol_externals.get_external_interfaces_for_protocol)
+ env.globals['get_minimum_version_to_construct'] = (
+ wayland_protocol_construction.get_minimum_version_to_construct)
+ env.globals['get_versions_to_test_for_event_delivery'] = (
+ wayland_protocol_construction.get_versions_to_test_for_event_delivery)
+ env.globals['is_global_interface'] = (
+ wayland_protocol_construction.is_global_interface)
+
+ # Additional filters for transforming text
+ env.filters['kebab'] = wayland_protocol_identifiers.kebab_case
+ env.filters['pascal'] = wayland_protocol_identifiers.pascal_case
+
+ return env.get_template(os.path.basename(template)).render(context)
+
+
+def clang_format_source_text(source_text, clang_format_path,
+ effective_filename):
+ # type: (str, str, str) -> str
+ """Runs clang-format on source_text and returns the result."""
+ # clang-format the output, for better readability and for
+ # -Wmisleading-indentation.
+ proc = subprocess.Popen(
+ [clang_format_path, '--assume-filename', effective_filename],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ stdout_output, stderr_output = proc.communicate(input=source_text)
+ retcode = proc.wait()
+ if retcode != 0:
+ raise CalledProcessError(retcode,
+ 'clang-format error: ' + stderr_output)
+ return stdout_output
+
+
+def write_if_changed(source_text, output):
+ # type: (str, str) -> None
+ """Writes source_text to output, but only if different."""
+ if os.path.exists(output):
+ with open(output, 'rt') as infile:
+ if infile.read() == source_text:
+ return
+
+ with open(output, 'wt') as outfile:
+ outfile.write(source_text)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('third_party_path')
+ parser.add_argument('clang_format_path')
+ parser.add_argument('template')
+ parser.add_argument('output')
+ parser.add_argument('protocols', nargs='+')
+ args = parser.parse_args()
+
+ # Allows us to import jinga2
+ sys.path.append(args.third_party_path)
+
+ protocols = wayland_protocol_data_classes.Protocols.parse_xml_files(
+ args.protocols)
+
+ if len(protocols.protocols) == 1:
+ expanded = expand_template(args.template,
+ {'protocol': protocols.protocols[0]})
+ else:
+ expanded = expand_template(args.template,
+ {'protocols': protocols.protocols})
+
+ formatted = clang_format_source_text(expanded, args.clang_format_path,
+ args.output)
+ write_if_changed(formatted, args.output)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_construction.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_construction.py
new file mode 100644
index 00000000000..1873890f3f3
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_construction.py
@@ -0,0 +1,252 @@
+# Copyright 2020 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 argparse
+import collections
+import functools
+import io
+import itertools
+import sys
+
+import wayland_protocol_data_classes
+import wayland_protocol_identifiers
+import wayland_protocol_utils
+
+RequestType = wayland_protocol_data_classes.RequestType
+
+
+@wayland_protocol_utils.memoize(cache={})
+def get_interface_for_name(protocols, target_interface_name):
+ # type: (Iterable[Protocol], str) -> Optional[Interface]
+ """Given a name string, gets the interface that has that name, or None."""
+ for protocol in protocols:
+ for interface in protocol.interfaces:
+ if interface.name == target_interface_name:
+ return interface
+ return None
+
+
+@wayland_protocol_utils.memoize(cache={})
+def get_constructor_for_interface(target_interface):
+ # type: (Interface) -> Optional[Message]
+ """Gets the message to use to construct the target interface, or None."""
+
+ # Note: We assume there is only one constructor for any interface, and
+ # return the first found, but there could be a protocol that defines
+ # more than one way.
+
+ for interface in target_interface.protocol.interfaces:
+ for request in interface.requests:
+ for arg in request.args:
+ if (arg.type == 'new_id'
+ and arg.interface == target_interface.name):
+ return request
+ for event in interface.events:
+ for arg in event.args:
+ if (arg.type == 'new_id'
+ and arg.interface == target_interface.name):
+ return event
+ return None
+
+
+class ConstructionStepCtor(object):
+ """Message and related data for a ConstructionStep"""
+ def __init__(self, interface_step, message, object_args):
+ # type: (ConstructionStep, Message,
+ # Tuple[Optional['ConstructionStep'], ...]) -> None
+
+ # The construction step for the interface needed for this step.
+ self.interface_step = interface_step
+
+ # The message on the interface used to perform the construction in this
+ # step. Note that while this is normally a client request, it can
+ # occasionally be a server event. One example of that is the
+ # wl_data_offer in the core Wayland protocol.
+ self.message = message
+
+ # For request constructors, gives the construction steps for any
+ # additional objects that are needed for constructing the target.
+ # There are entries only for the arguments that are objects. The rest
+ # are None. For event constructors this will always be empty.
+ self.object_args = object_args
+
+
+class ConstructionStep(object):
+ """Represents a step in the construction path of a target interface."""
+ def __init__(self, interface, instance_name, ctor, minimum_version):
+ # type: (Interface, str, Optional[ConstructionStepCtor], int) -> None
+
+ # Wayland interface constructed by this step
+ self.interface = interface
+
+ # A reasonable human-readable name that can be used to generate variable
+ # and function names for this step. The names will be unique within a
+ # single generated sequence of steps.
+ self.instance_name = instance_name
+
+ # The details of how to construct this interface, based on other
+ # construction steps. This will be None if the interface in this step
+ # is a Wayland global interface.
+ self.ctor = ctor
+
+ # Set to the minimum version needed for this interface.
+ self.minimum_version = minimum_version
+
+
+@wayland_protocol_utils.memoize(cache={})
+def get_construction_steps(target_interface):
+ # type: (Interface) -> Tuple[ConstructionStep, ...]
+ """Generates the ConstructionSteps to construct a target interface."""
+
+ # For brevity later, get the list of protocols as a local
+ protocols = target_interface.protocol.protocols.protocols
+
+ # Helper map for constructing human readable instance names
+ base_human_readable_name_map = (
+ wayland_protocol_identifiers.get_base_human_readable_name_map(
+ target_interface.protocol.protocols.protocols))
+
+ # Globals that will be needed (not ordered)
+ global_steps = {}
+
+ # Non-global instances that will be needed (ordered)
+ instance_steps = []
+
+ # To help ensure unique instance names
+ uniquifier = collections.Counter()
+
+ def unique_instance_name(prefix, name):
+ # type: (str, str) -> str
+
+ def dedupe_words(name):
+ # type: (str) -> str
+
+ # Otherwise a generated name might be "parent_surface_surface"
+ # for a wl_surface passed as a parent_surface argument.
+ words = name.split("_")
+ if len(words) == 1:
+ return name
+ words = [
+ w for i, w in enumerate(words[:-1]) if w not in words[i + 1]
+ ] + [words[-1]]
+ return "_".join(words)
+
+ name = prefix + base_human_readable_name_map.get(name, name)
+ name = dedupe_words(name)
+ suffix = str(uniquifier.get(name, ''))
+ uniquifier[name] += 1
+ return name + suffix + "_"
+
+ def recursive_construction_steps(current_target, prefix, minimum_version):
+ # type: (Interface, str, int) -> ConstructionStep
+
+ ctor_message = get_constructor_for_interface(current_target)
+ ctor = None
+
+ if ctor_message is not None:
+ # If we have a message, we have to use another interface to
+ # create the current target.
+ ctor_interface = recursive_construction_steps(
+ ctor_message.interface, prefix,
+ max(minimum_version,
+ ctor_message.since if ctor_message.since else 1))
+ ctor_object_args = []
+
+ if not ctor_message.is_event:
+ # We may also have to construct other interfaces as well to
+ # pass as object arguments. Those interfaces can be part of
+ # any protocol, though normally it is either in the same
+ # protocol or the core Wayland protocol.
+ for arg in ctor_message.args:
+ arg_step = None
+ if arg.type == 'object':
+ arg_interface = get_interface_for_name(
+ protocols, arg.interface)
+ arg_step = recursive_construction_steps(
+ arg_interface, '%s%s_' % (prefix, arg.name), 1)
+ ctor_object_args.append(arg_step)
+
+ ctor = ConstructionStepCtor(ctor_interface, ctor_message,
+ tuple(ctor_object_args))
+
+ # Construct the step
+ step = ConstructionStep(interface=current_target,
+ instance_name=unique_instance_name(
+ prefix if ctor is not None else '',
+ current_target.name),
+ ctor=ctor,
+ minimum_version=minimum_version)
+
+ if ctor is None:
+ # For a global, interface, we only make/get one instance
+ step = global_steps.setdefault(current_target.name, step)
+ else:
+ # Otherwise store each individual step
+ instance_steps.append(step)
+
+ return step
+
+ recursive_construction_steps(target_interface, '', 1)
+
+ return tuple([global_steps[name]
+ for name in sorted(global_steps)] + instance_steps)
+
+
+@wayland_protocol_utils.memoize(cache={})
+def get_destructor(interface):
+ # type: (Interface) -> Optional[Message]
+ """Gets the Message that acts as the interface destructor, if present."""
+ for message in interface.requests:
+ if message.request_type == RequestType.DESTRUCTOR.value:
+ return message
+ return None
+
+
+def get_minimum_version_to_construct(target):
+ # type: (Interface) -> int
+ """Gets the minimum version of the global needed to construct a target."""
+ def recursive_minimum(interface, minimum_version):
+ # type: (Interface, int) -> int
+
+ ctor_message = get_constructor_for_interface(interface)
+
+ # If there is no explicit constructor for this target, it must be a
+ # global
+ if not ctor_message:
+ # Return the global interface
+ return minimum_version
+
+ # If the constructor has a "since", it constrains the minimum version
+ if ctor_message.since:
+ minimum_version = max(minimum_version, ctor_message.since)
+
+ return recursive_minimum(ctor_message.interface, minimum_version)
+
+ # Until proven otherwise, assume the first version can create the target
+ return recursive_minimum(target, 1)
+
+
+def get_versions_to_test_for_event_delivery(interface):
+ # type: (Interface) -> Tuple[int, ...]
+ """Returns the list of versions around which the interface changes."""
+
+ # Get the minimum interface version
+ min_version = get_minimum_version_to_construct(interface)
+
+ # Include all versions where events are introduced
+ versions = set(event.since for event in interface.events
+ if event.since and event.since > min_version)
+ # Include all versions one less than where events are introduced
+ versions = versions.union(event.since - 1 for event in interface.events
+ if event.since and event.since - 1 > min_version)
+ # Include the minimum and maximum versions
+ versions = versions.union((min_version, interface.version))
+
+ return tuple(versions)
+
+
+def is_global_interface(interface):
+ # type: (Interface) -> bool
+ """Returns true if the interface is a global interface."""
+ return get_constructor_for_interface(interface) is None
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_data_classes.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_data_classes.py
new file mode 100644
index 00000000000..a00d97d152a
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_data_classes.py
@@ -0,0 +1,519 @@
+# Copyright 2020 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 os.path
+import xml.etree.ElementTree
+
+import wayland_protocol_utils
+
+EnumValue = wayland_protocol_utils.EnumValue
+
+
+class Description(object):
+ """Holds the data from a Wayland protocol <description> subtree."""
+ def __init__(self, summary, description):
+ # type: (str, str) -> None
+
+ # The value of the name summary of the <description>.
+ object.__setattr__(self, 'summary', summary)
+
+ # The text content of the <description>.
+ object.__setattr__(self, 'description', description)
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return 'Description(summary=%r, description=%r)' % (self.summary,
+ self.description)
+
+ def __hash__(self):
+ return hash((self.summary, self.description))
+
+ def __eq__(self, other):
+ return ((self.summary, self.description) == (other.summary,
+ other.description))
+
+ @staticmethod
+ def parse_xml(e):
+ # type: (Element) -> Optional[Description]
+
+ return Description(summary=e.get('summary'),
+ description=e.text.strip()
+ if e.text else '') if e is not None else None
+
+
+class MessageArgType(object):
+ """The valid types of an <arg>."""
+ INT = EnumValue('int')
+ UINT = EnumValue('uint')
+ FIXED = EnumValue('fixed')
+ STRING = EnumValue('string')
+ FD = EnumValue('fd') # File descriptor
+ ARRAY = EnumValue('array') # untyped Array
+ NEW_ID = EnumValue('new_id') # Special type for constructing
+ OBJECT = EnumValue('object') # An interface
+
+
+class MessageArg(object):
+ """Holds the data from a Wayland protocol <arg> subtree."""
+ def __init__(self, message, name, type, summary, interface, nullable, enum,
+ description):
+ # type: (Message, str, MessageArgType, Optional[str], Optional[str],
+ # Optional[bool], Optional[str], Optional[Description]) -> None
+
+ # The containing Message, for context.
+ object.__setattr__(self, 'message', message)
+
+ # The value of the name attribute of the <arg>.
+ object.__setattr__(self, 'name', name)
+
+ # The value of the type attribute of the <arg>.
+ object.__setattr__(self, 'type', type)
+
+ # The value of the optional summary attribute of the <arg>.
+ object.__setattr__(self, 'summary', summary)
+
+ # The value of the optional interface attribute of the <arg>.
+ object.__setattr__(self, 'interface', interface)
+
+ # The value of the optional nullable attribute of the <arg>.
+ object.__setattr__(self, 'nullable', nullable)
+
+ # The value of the optional enum attribute of the <arg>.
+ object.__setattr__(self, 'enum', enum)
+
+ # The optional <description> child element of the <arg>.
+ object.__setattr__(self, 'description', description)
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('MessageArg(name=%r, type=%r, summary=%r, interface=%r, '
+ 'nullable=%r, enum=%r, description=%r)' %
+ (self.name, self.type, self.summary, self.interface,
+ self.nullable, self.enum, self.description))
+
+ def __hash__(self):
+ return hash((self.name, self.type, self.summary, self.interface,
+ self.nullable, self.enum, self.description))
+
+ def __eq__(self, other):
+ return ((self.name, self.type, self.summary, self.interface,
+ self.nullable, self.enum,
+ self.description) == (other.name, other.type, other.summary,
+ other.interface, other.nullable,
+ other.enum, other.description))
+
+ @staticmethod
+ def parse_xml(message, e):
+ # type: (Message, Element) -> MessageArg
+ return MessageArg(message=message,
+ name=e.get('name'),
+ type=e.get('type'),
+ summary=e.get('summary'),
+ interface=e.get('interface'),
+ nullable=e.get('allow-null') == 'true'
+ if e.get('allow-null') else None,
+ enum=e.get('enum'),
+ description=Description.parse_xml(
+ e.find('description')))
+
+
+class RequestType(object):
+ """The valid types of a <request> message."""
+ DESTRUCTOR = EnumValue('destructor')
+
+
+class Message(object):
+ """Holds the data from a Wayland protocol <request> OR <event> subtree."""
+ def __init__(self, interface, is_event, name, request_type, since,
+ description):
+ # type: (Interface, bool, str, Optional[RequestType], Optional[int],
+ # Optional[Description]) -> None
+
+ # The containing Interface, for context.
+ object.__setattr__(self, 'interface', interface)
+
+ # If true, this message is an <event> in the containing interface.
+ # Otherwise it is a <request>.
+ object.__setattr__(self, 'is_event', is_event)
+
+ # The value of the name attribute of the <request> or <event>.
+ object.__setattr__(self, 'name', name)
+
+ # The value of the optional type attribute of the <request> Always empty
+ # for <events>.
+ object.__setattr__(self, 'request_type', request_type)
+
+ # The value of the optional since attribute of the <request> or <event>.
+ object.__setattr__(self, 'since', since)
+
+ # The optional <description> child element of the <request> or <event>.
+ object.__setattr__(self, 'description', description)
+
+ # The child <arg> elements of the <request> or <event>
+ # type: Tuple[MessageArg, ...]
+ object.__setattr__(self, 'args', ())
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('Message(is_event=%r, name=%r, request_type=%r, since=%r, '
+ 'description=%r, args=%r)' %
+ (self.is_event, self.name, self.request_type, self.since,
+ self.description, self.args))
+
+ def __hash__(self):
+ return hash((self.is_event, self.name, self.request_type, self.since,
+ self.description, self.args))
+
+ def __eq__(self, other):
+ return ((self.is_event, self.name, self.request_type, self.since,
+ self.description,
+ self.args) == (other.is_event, other.name, other.request_type,
+ other.since, other.description, other.args))
+
+ @staticmethod
+ def parse_xml(interface, is_event, e):
+ # type (Interface, bool, Element) -> Message
+
+ message = Message(
+ interface=interface,
+ is_event=is_event,
+ name=e.get('name'),
+ request_type=e.get('type'),
+ since=int(e.get('since')) if e.get('since') else None,
+ description=Description.parse_xml(e.find('description')))
+
+ # Note: This is needed to finish up since the instance is frozen.
+ object.__setattr__(
+ message, 'args',
+ tuple(MessageArg.parse_xml(message, c) for c in e.findall('arg')))
+
+ return message
+
+
+class EnumEntry(object):
+ """Holds the data from a Wayland protocol <entry> subtree."""
+ def __init__(self, enum, name, value, summary, since, description):
+ # type: (Enum, str, int, Optional[str], Optional[int],
+ # Optional[Description]) -> None
+
+ # The containing Enum, for context.
+ object.__setattr__(self, 'enum', enum)
+
+ # The value of the name attribute of the <entry>.
+ object.__setattr__(self, 'name', name)
+
+ # The value of the value attribute of the <entry>.
+ object.__setattr__(self, 'value', value)
+
+ # The value of the optional summary attribute of the <entry>.
+ object.__setattr__(self, 'summary', summary)
+
+ # The value of the optional since attribute of the <entry>.
+ object.__setattr__(self, 'since', since)
+
+ # The optional <description> child element of the <request> or <event>.
+ object.__setattr__(self, 'description', description)
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('EnumEntry(name=%r, value=%r, summary=%r, since=%r,'
+ 'description=%r)' % (self.name, self.value, self.summary,
+ self.since, self.description))
+
+ def __hash__(self):
+ return hash((self.name, self.value, self.summary, self.since,
+ self.description))
+
+ def __eq__(self, other):
+ return ((self.name, self.value, self.summary, self.since,
+ self.description) == (other.enum, other.name, other.value,
+ other.summary, other.since,
+ other.description))
+
+ @staticmethod
+ def parse_xml(enum, e):
+ # type: (Enum, Element) -> EnumEntry:
+
+ return EnumEntry(
+ enum=enum,
+ name=e.get('name'),
+ value=int(e.get('value'), 0),
+ summary=e.get('summary'),
+ since=int(e.get('since'), 0) if e.get('since') else None,
+ description=Description.parse_xml(e.find('description')))
+
+
+class Enum(object):
+ """Holds the data from a Wayland protocol <enum> subtree."""
+ def __init__(self, interface, name, since, bitfield, description):
+ # type: (Interface, str, Optional[int], Optional[bool],
+ # Optional[Description]) -> None
+
+ # The containing Interface, for context.
+ object.__setattr__(self, 'interface', interface)
+
+ # The value of the name attribute of the <enum>.
+ object.__setattr__(self, 'name', name)
+
+ # The value of the optional since attribute of the <enum>.
+ object.__setattr__(self, 'since', since)
+
+ # The value of the optional bitfield attribute of the <enum>.
+ object.__setattr__(self, 'bitfield', bitfield)
+
+ # The optional <description> child element of the <request> or <event>.
+ object.__setattr__(self, 'description', description)
+
+ # The child <entry> elements for the <enum>.
+ # type: Tuple[EnumEntry, ...]
+ object.__setattr__(self, 'entries', ())
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('EnumEntry(name=%r, since=%r, bitfield=%r, description=%r, '
+ 'entries=%r)' % (self.name, self.since, self.bitfield,
+ self.description, self.entries))
+
+ def __hash__(self):
+ return hash((self.name, self.since, self.bitfield, self.description,
+ self.entries))
+
+ def __eq__(self, other):
+ return ((self.name, self.since, self.bitfield, self.description,
+ self.entries) == (other.name, other.since, other.bitfield,
+ other.description, other.entries))
+
+ @staticmethod
+ def parse_xml(interface, e):
+ # type: (Interface, Element) -> Enum
+
+ enum = Enum(interface=interface,
+ name=e.get('name'),
+ since=int(e.get('since'), 0) if e.get('since') else None,
+ bitfield=e.get('bitfield') == 'true'
+ if e.get('bitfield') else None,
+ description=Description.parse_xml(e.find('description')))
+
+ # Note: This is needed to finish up since the instance is frozen.
+ object.__setattr__(
+ enum, 'entries',
+ tuple(EnumEntry.parse_xml(enum, c) for c in e.findall('entry')))
+
+ return enum
+
+
+class Interface(object):
+ """Holds the data from a Wayland protocol <interface> subtree."""
+ def __init__(self, protocol, name, version, description):
+ # type: (Protocol, str, int, Optional[Description]) -> None
+
+ # The containing Protocol, for context.
+ object.__setattr__(self, 'protocol', protocol)
+
+ # The value of the name attribute of the <interface>.
+ object.__setattr__(self, 'name', name)
+
+ # The value of the version attribute of the <interface>.
+ object.__setattr__(self, 'version', version)
+
+ # The optional <description> child element of the <interface>.
+ object.__setattr__(self, 'description', description)
+
+ # The child <request> elements for the <interface>.
+ # type: Tuple[Message, ...]
+ object.__setattr__(self, 'requests', ())
+
+ # The child <event> elements for the <interface>.
+ # type: Tuple[Message, ...]
+ object.__setattr__(self, 'events', ())
+
+ # The child <enum> elements for the <interface>.
+ # type: Tuple[Enum, ...]
+ object.__setattr__(self, 'enums', ())
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('Interface(name=%r, version=%r, description=%r, requests=%r, '
+ 'events=%r, enums=%r)' %
+ (self.name, self.version, self.description, self.requests,
+ self.events, self.enums))
+
+ def __hash__(self):
+ return hash((self.name, self.version, self.description, self.requests,
+ self.events, self.enums))
+
+ def __eq__(self, other):
+ return ((self.name, self.version, self.description, self.requests,
+ self.events,
+ self.enums) == (other.name, other.version, other.description,
+ other.requests, other.events.other, enums))
+
+ @staticmethod
+ def parse_xml(protocol, e):
+ # type: (Protocol, Element) -> Interface
+ interface = Interface(protocol=protocol,
+ name=e.get('name'),
+ version=int(e.get('version'), 0),
+ description=Description.parse_xml(
+ e.find('description')))
+
+ # Note: This is needed to finish up since the instance is frozen.
+ object.__setattr__(
+ interface, 'requests',
+ tuple(
+ Message.parse_xml(interface, False, c)
+ for c in e.findall('request')))
+ object.__setattr__(
+ interface, 'events',
+ tuple(
+ Message.parse_xml(interface, True, c)
+ for c in e.findall('event')))
+ object.__setattr__(
+ interface, 'enums',
+ tuple(Enum.parse_xml(interface, c) for c in e.findall('enum')))
+
+ return interface
+
+
+class Copyright(object):
+ """Holds the data from a Wayland protocol <copyright> subtree."""
+ def __init__(self, text):
+ # type: (str) -> None
+
+ # The text content of the <copyright>.
+ object.__setattr__(self, 'text', text)
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return 'Copyright(text=%r)' % (self.text, )
+
+ def __hash__(self):
+ return hash((self.text, ))
+
+ def __eq__(self, other):
+ return (self.text, ) == (other.text, )
+
+ @staticmethod
+ def parse_xml(e):
+ # type: (Element) -> Optional['Copyright']
+
+ return Copyright(text=e.text.strip()) if e is not None else None
+
+
+class Protocol(object):
+ """Holds the data from a Wayland protocol <protocol> subtree."""
+ def __init__(self, protocols, filename, name, copyright, description):
+ # type: (Protocols, str, str, Optional[Copyright],
+ # Optional[Description]) -> None
+
+ # The universe of known protocols this is part of.
+ object.__setattr__(self, 'protocols', protocols)
+
+ # The containing base filename (no path, no extension), for context.
+ object.__setattr__(self, 'filename', filename)
+
+ # The value of the name attribute of the <protocol>.
+ object.__setattr__(self, 'name', name)
+
+ # The optional <copyright> child element of the <protocol>.
+ object.__setattr__(self, 'copyright', copyright)
+
+ # The optional <description> child element of the <protocol>.
+ object.__setattr__(self, 'description', description)
+
+ # The child <interface> elements for the <protocol>.
+ # type: Tuple[Interface, ...]
+ object.__setattr__(self, 'interfaces', ())
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return ('Protocol(filename=%r, name=%r, copyright=%r, description=%r, '
+ 'interfaces=%r)' % (self.filename, self.name, self.copyright,
+ self.description, self.interfaces))
+
+ def __hash__(self):
+ return hash((self.filename, self.name, self.copyright,
+ self.description, self.interfaces))
+
+ def __eq__(self, other):
+ return ((self.filename, self.name, self.copyright, self.description,
+ self.interfaces) == (other.filename, other.name,
+ other.copyright, other.description,
+ other.interfaces))
+
+ @staticmethod
+ def parse_xml(protocols, filename, e):
+ # type: (Protocols, str, Element) -> Protocol
+
+ protocol = Protocol(protocols,
+ filename=filename,
+ name=e.get('name'),
+ copyright=Copyright.parse_xml(e.find('copyright')),
+ description=Description.parse_xml(
+ e.find('description')))
+
+ # Note: This is needed to finish up since the instance is frozen.
+ object.__setattr__(
+ protocol, 'interfaces',
+ tuple(
+ Interface.parse_xml(protocol, i)
+ for i in e.findall('interface')))
+
+ return protocol
+
+
+class Protocols(object):
+ """Holds the data from multiple Wayland protocol files."""
+ def __init__(self):
+ # type: () -> None
+
+ # The parsed protocol dataclasses
+ # type: Tuple[Protocol, ...]
+ object.__setattr__(self, 'protocols', ())
+
+ def __setattr__(self, name, value):
+ raise AttributeError('Frozen instance')
+
+ def __repr__(self):
+ return 'Protocols(protocols=%r)' % (self.protocols, )
+
+ def __hash__(self):
+ return hash((self.protocols, ))
+
+ def __eq__(self, other):
+ return ((self.protocols, ) == (other.protocols, ))
+
+ @staticmethod
+ def parse_xml_files(filenames):
+ # type: (Iterable[str]) -> Protocols
+
+ protocols = Protocols()
+
+ # Note: This is needed to finish up since the instance is frozen.
+ object.__setattr__(
+ protocols, 'protocols',
+ tuple(
+ Protocol.parse_xml(
+ protocols,
+ os.path.splitext(os.path.basename(filename))[0],
+ xml.etree.ElementTree.parse(filename).getroot())
+ for filename in filenames))
+
+ return protocols
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_externals.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_externals.py
new file mode 100644
index 00000000000..527172498de
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_externals.py
@@ -0,0 +1,25 @@
+# Copyright 2020 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 wayland_protocol_data_classes
+
+
+def get_external_interfaces_for_protocol(protocol):
+ # type: (Protocol) -> Tuple[str, ...]
+ """Gets the names of interfaces referenced but not defined by a protocol."""
+
+ # Get the set of interfaces defined by the protocol
+ defined_interfaces = set(i.name for i in protocol.interfaces)
+
+ # Get and store the set of interfaces that are external to the protocol
+ external_interface_names = set()
+ for i in protocol.interfaces:
+ external_interface_names.update(
+ a.interface for r in i.requests for a in r.args
+ if a.interface and a.interface not in defined_interfaces)
+ external_interface_names.update(
+ a.interface for e in i.events for a in e.args
+ if a.interface and a.interface not in defined_interfaces)
+
+ return tuple(external_interface_names)
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_identifiers.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_identifiers.py
new file mode 100644
index 00000000000..8e509de3091
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_identifiers.py
@@ -0,0 +1,109 @@
+# Copyright 2020 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 collections
+import functools
+import itertools
+import re
+
+import wayland_protocol_data_classes
+import wayland_protocol_utils
+
+
+def split_for_words(x):
+ # type: (str) -> Tuple[str, ...]
+ """Split underscore_seperated identifiers into a component words."""
+ return tuple(w.lower() for w in x.split('_'))
+
+
+def kebab_case(x):
+ # type: (str) -> str
+ """Convert the input identifier to kebab-case"""
+ return '-'.join(split_for_words(x))
+
+
+def pascal_case(x):
+ # type: (str) -> str
+ """Convert the input identifier to PascalCase"""
+ return ''.join(w.title() for w in split_for_words(x))
+
+
+@wayland_protocol_utils.memoize(cache={})
+def get_base_human_readable_name_map(protocols):
+ # type: (Iterable[Protocol]) -> Dict[str, str]
+ """Determines a mapping of each interface name to an identifier name."""
+
+ # Default to the full interface name as the identifier.
+ interface_identifiers = dict((interface.name, interface.name)
+ for protocol in protocols
+ for interface in protocol.interfaces)
+
+ # Reserve the full interface names as identifiers, so nothing is
+ # ever shortened to another interface name.
+ used = set(interface_identifiers.keys())
+
+ def set_identifier_name_for_protocol(names, interface):
+ # type: (Iterable[str], Interface) -> None
+ """Set the first unused name in |names| as the name for |interface|"""
+ for name in names:
+ if name not in used:
+ used.add(name)
+ interface_identifiers[interface.name] = name
+ return
+
+ def set_identifier_names_for_interface(interfaces):
+ # type: (Iterable[Interface]) -> None
+ """Try and set a shorter name for each interface"""
+ # For each interface in protocol, try and find a shorter name to use
+ # when representing instances of that interface.
+ for interface in interfaces:
+ name = interface.name
+ name_no_prefix = name.split('_', 1)[-1]
+ name_no_suffix = re.sub('_v\d+$', '', name)
+ name_no_prefix_or_suffix = re.sub(r'_v\d+$', '', name_no_prefix)
+
+ set_identifier_name_for_protocol(
+ [name_no_prefix_or_suffix, name_no_prefix, name_no_suffix],
+ interface)
+
+ def prioritize_interfaces(interfaces):
+ # type: (Iterable[Interface]) -> Tuple[Interface, ...]
+
+ DEFAULT_STABLE_PRIORITY = 100
+ DEFAULT_UNSTABLE_PRIORITY = 101
+ UNSTABLE_PREFIX = 'z'
+ prefix_priorities = dict(wl_=0,
+ wp_=1,
+ xdg_=2,
+ zwl_=10,
+ zwp_=11,
+ zxdg_=12,
+ aura_=200,
+ cr_=201,
+ zaura_=202,
+ zcr_=203)
+
+ interfaces_by_priority = collections.defaultdict(list)
+
+ for protocol in protocols:
+ for interface in protocol.interfaces:
+ name = interface.name
+ priority = DEFAULT_STABLE_PRIORITY if not name.startswith(
+ UNSTABLE_PREFIX) else DEFAULT_UNSTABLE_PRIORITY
+ for prefix, prefix_priority in prefix_priorities.items():
+ if name.startswith(prefix):
+ priority = prefix_priority
+ break
+ interfaces_by_priority[priority].append(interface)
+
+ return tuple(
+ itertools.chain(*tuple(interfaces_by_priority[p]
+ for p in sorted(interfaces_by_priority))))
+
+ set_identifier_names_for_interface(
+ prioritize_interfaces(
+ tuple(
+ itertools.chain(*tuple(protocol.interfaces
+ for protocol in protocols)))))
+ return interface_identifiers
diff --git a/chromium/components/exo/wayland/compatibility_test/wayland_protocol_utils.py b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_utils.py
new file mode 100644
index 00000000000..0e35efea81b
--- /dev/null
+++ b/chromium/components/exo/wayland/compatibility_test/wayland_protocol_utils.py
@@ -0,0 +1,30 @@
+# Copyright 2020 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 functools
+
+
+# Use functools.lru_cache in Python 3 and up.
+def memoize(cache):
+ """Minimal memoization decorator"""
+ def decorator(func):
+ def wrapper(*args):
+ try:
+ return cache[args]
+ except KeyError:
+ pass # Not found
+
+ result = func(*args)
+ cache[args] = result
+ return result
+
+ return functools.update_wrapper(wrapper, func)
+
+ return decorator
+
+
+class EnumValue(object):
+ """Minimal enum value wrapper to look like Python3's Enum class."""
+ def __init__(self, value):
+ self.value = value \ No newline at end of file
diff --git a/chromium/components/exo/wayland/protocol/aura-shell.xml b/chromium/components/exo/wayland/protocol/aura-shell.xml
index 0c587b67662..3aa169f4032 100644
--- a/chromium/components/exo/wayland/protocol/aura-shell.xml
+++ b/chromium/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="zaura_shell" version="10">
+ <interface name="zaura_shell" version="12">
<description summary="aura_shell">
The global interface exposing aura shell capabilities is used to
instantiate an interface extension for a wl_surface object.
@@ -66,9 +66,26 @@
<arg name="output" type="object" interface="wl_output"
summary="the output"/>
</request>
+
+ <!-- Version 11 additions -->
+
+ <enum name="layout_mode">
+ <description summary="the layout mode">
+ Specifies the server's window layout mode.
+ </description>
+ <entry name="windowed" value="1" summary="multiple windows"/>
+ <entry name="tablet" value="2" summary="restricted mode for tablet"/>
+ </enum>
+
+ <event name="layout_mode" since="11">
+ <description summary="sends the layout_mode">
+ Sends the layout_mode used by the server.
+ </description>
+ <arg name="layout_mode" type="uint" summary="layout_mode enum"/>
+ </event>
</interface>
- <interface name="zaura_surface" version="10">
+ <interface name="zaura_surface" version="12">
<description summary="aura shell interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to access aura shell specific functionality for surface.
@@ -134,6 +151,7 @@
<request name="set_client_surface_id" since="7">
<description summary="set the client surface ID of this surface">
+ Deprecated. Please use set_client_surface_str_id instead.
Set the identifier of the surface assigned by the client.
</description>
<arg name="client_surface_id" type="int" />
@@ -224,6 +242,16 @@
</description>
<arg name="mode" type="uint" enum="fullscreen_mode"/>
</request>
+
+ <!-- Version 12 additions -->
+
+ <request name="set_client_surface_str_id" since="12">
+ <description summary="set the client surface ID of this surface">
+ Set the identifier of the surface assigned by the client.
+ </description>
+ <arg name="client_surface_id" type="string" />
+ </request>
+
</interface>
<interface name="zaura_output" version="6">
diff --git a/chromium/components/exo/wayland/wl_data_device_manager.cc b/chromium/components/exo/wayland/wl_data_device_manager.cc
index a34b13c7673..eab743f5f0f 100644
--- a/chromium/components/exo/wayland/wl_data_device_manager.cc
+++ b/chromium/components/exo/wayland/wl_data_device_manager.cc
@@ -252,12 +252,12 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate {
return surface &&
wl_resource_get_client(GetSurfaceResource(surface)) == client_;
}
- DataOffer* OnDataOffer(DataOffer::Purpose purpose) override {
+ DataOffer* OnDataOffer() override {
wl_resource* data_offer_resource =
wl_resource_create(client_, &wl_data_offer_interface,
wl_resource_get_version(data_device_resource_), 0);
std::unique_ptr<DataOffer> data_offer = std::make_unique<DataOffer>(
- new WaylandDataOfferDelegate(data_offer_resource), purpose);
+ new WaylandDataOfferDelegate(data_offer_resource));
SetDataOfferResource(data_offer.get(), data_offer_resource);
SetImplementation(data_offer_resource, &data_offer_implementation,
std::move(data_offer));
@@ -306,21 +306,27 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate {
serial_tracker_->GetEventType(serial);
if (event_type == base::nullopt) {
LOG(ERROR) << "The serial passed to StartDrag does not exist.";
- source->Cancelled();
+ if (source) {
+ source->Cancelled();
+ }
return;
}
if (event_type == wayland::SerialTracker::EventType::POINTER_BUTTON_DOWN &&
serial_tracker_->GetPointerDownSerial() == serial) {
+ DCHECK(data_device);
data_device->StartDrag(source, origin, icon,
ui::mojom::DragEventSource::kMouse);
} else if (event_type == wayland::SerialTracker::EventType::TOUCH_DOWN &&
serial_tracker_->GetTouchDownSerial() == serial) {
+ DCHECK(data_device);
data_device->StartDrag(source, origin, icon,
ui::mojom::DragEventSource::kTouch);
} else {
LOG(ERROR) << "The serial passed to StartDrag does not match its "
"expected types.";
- source->Cancelled();
+ if (source) {
+ source->Cancelled();
+ }
}
}
@@ -331,9 +337,12 @@ class WaylandDataDeviceDelegate : public DataDeviceDelegate {
serial_tracker_->GetEventType(serial);
if (event_type == base::nullopt) {
LOG(ERROR) << "The serial passed to SetSelection does not exist.";
- source->Cancelled();
+ if (source) {
+ source->Cancelled();
+ }
return;
}
+ DCHECK(data_device);
data_device->SetSelection(source);
}
diff --git a/chromium/components/exo/wayland/wl_shell.cc b/chromium/components/exo/wayland/wl_shell.cc
index 2b4250a960b..167ddbd07b1 100644
--- a/chromium/components/exo/wayland/wl_shell.cc
+++ b/chromium/components/exo/wayland/wl_shell.cc
@@ -125,7 +125,7 @@ const struct wl_shell_surface_interface shell_surface_implementation = {
uint32_t HandleShellSurfaceConfigureCallback(
wl_resource* resource,
const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset) {
diff --git a/chromium/components/exo/wayland/xdg_shell.cc b/chromium/components/exo/wayland/xdg_shell.cc
index 6aa20573c6a..07abcf4926d 100644
--- a/chromium/components/exo/wayland/xdg_shell.cc
+++ b/chromium/components/exo/wayland/xdg_shell.cc
@@ -11,9 +11,9 @@
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
-#include "ash/public/cpp/window_state_type.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ui/base/window_state_type.h"
#include "components/exo/display.h"
#include "components/exo/wayland/serial_tracker.h"
#include "components/exo/wayland/server_util.h"
@@ -124,7 +124,7 @@ int XdgToplevelResizeComponent(uint32_t edges) {
using XdgSurfaceConfigureCallback =
base::RepeatingCallback<void(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated)>;
@@ -133,7 +133,7 @@ uint32_t HandleXdgSurfaceConfigureCallback(
SerialTracker* serial_tracker,
const XdgSurfaceConfigureCallback& callback,
const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset) {
@@ -301,14 +301,14 @@ class WaylandToplevel : public aura::WindowObserver {
}
void OnConfigure(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated) {
wl_array states;
wl_array_init(&states);
- if (state_type == ash::WindowStateType::kMaximized)
+ if (state_type == chromeos::WindowStateType::kMaximized)
AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED);
- if (state_type == ash::WindowStateType::kFullscreen)
+ if (state_type == chromeos::WindowStateType::kFullscreen)
AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN);
if (resizing)
AddState(&states, XDG_TOPLEVEL_STATE_RESIZING);
@@ -477,7 +477,7 @@ class WaylandPopup : aura::WindowObserver {
}
void OnConfigure(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated) {
// Nothing to do here as popups don't have additional configure state.
diff --git a/chromium/components/exo/wayland/zaura_shell.cc b/chromium/components/exo/wayland/zaura_shell.cc
index bff35010428..2a1a3697e20 100644
--- a/chromium/components/exo/wayland/zaura_shell.cc
+++ b/chromium/components/exo/wayland/zaura_shell.cc
@@ -16,6 +16,7 @@
#include "ash/public/cpp/window_properties.h"
#include "ash/wm/window_state.h"
+#include "base/strings/string_number_conversions.h"
#include "components/exo/wayland/server_util.h"
#include "components/exo/wayland/wayland_display_observer.h"
#include "components/exo/wayland/wl_output.h"
@@ -31,8 +32,10 @@
#include "ui/wm/public/activation_client.h"
#if defined(OS_CHROMEOS)
+#include "ash/public/cpp/tablet_mode_observer.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
+#include "components/exo/wm_helper_chromeos.h"
#endif // defined(OS_CHROMEOS)
namespace exo {
@@ -117,10 +120,13 @@ void aura_surface_set_application_id(wl_client* client,
GetUserDataAs<AuraSurface>(resource)->SetApplicationId(application_id);
}
-void aura_surface_set_client_surface_id(wl_client* client,
- wl_resource* resource,
- int client_surface_id) {
- GetUserDataAs<AuraSurface>(resource)->SetClientSurfaceId(client_surface_id);
+void aura_surface_set_client_surface_id_DEPRECATED(wl_client* client,
+ wl_resource* resource,
+ int client_surface_id) {
+ // DEPRECATED. Use aura_surface_set_client_surface_str_id
+ std::string client_surface_str_id = base::NumberToString(client_surface_id);
+ GetUserDataAs<AuraSurface>(resource)->SetClientSurfaceId(
+ client_surface_str_id.c_str());
}
void aura_surface_set_occlusion_tracking(wl_client* client,
@@ -147,18 +153,25 @@ void aura_surface_set_fullscreen_mode(wl_client* client,
GetUserDataAs<AuraSurface>(resource)->SetFullscreenMode(mode);
}
+void aura_surface_set_client_surface_str_id(wl_client* client,
+ wl_resource* resource,
+ const char* client_surface_id) {
+ GetUserDataAs<AuraSurface>(resource)->SetClientSurfaceId(client_surface_id);
+}
+
const struct zaura_surface_interface aura_surface_implementation = {
aura_surface_set_frame,
aura_surface_set_parent,
aura_surface_set_frame_colors,
aura_surface_set_startup_id,
aura_surface_set_application_id,
- aura_surface_set_client_surface_id,
+ aura_surface_set_client_surface_id_DEPRECATED,
aura_surface_set_occlusion_tracking,
aura_surface_unset_occlusion_tracking,
aura_surface_activate,
aura_surface_draw_attention,
- aura_surface_set_fullscreen_mode};
+ aura_surface_set_fullscreen_mode,
+ aura_surface_set_client_surface_str_id};
} // namespace
@@ -206,7 +219,7 @@ void AuraSurface::SetApplicationId(const char* application_id) {
surface_->SetApplicationId(application_id);
}
-void AuraSurface::SetClientSurfaceId(int client_surface_id) {
+void AuraSurface::SetClientSurfaceId(const char* client_surface_id) {
if (surface_)
surface_->SetClientSurfaceId(client_surface_id);
}
@@ -456,6 +469,51 @@ class AuraOutput : public WaylandDisplayObserver {
////////////////////////////////////////////////////////////////////////////////
// aura_shell_interface:
+#if defined(OS_CHROMEOS)
+// Implements aura shell interface and monitors workspace state needed
+// for the aura shell interface.
+class WaylandAuraShell : public ash::TabletModeObserver {
+ public:
+ explicit WaylandAuraShell(wl_resource* aura_shell_resource)
+ : aura_shell_resource_(aura_shell_resource) {
+ WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
+ helper->AddTabletModeObserver(this);
+ if (wl_resource_get_version(aura_shell_resource_) >=
+ ZAURA_SHELL_LAYOUT_MODE_SINCE_VERSION) {
+ auto layout_mode = helper->InTabletMode()
+ ? ZAURA_SHELL_LAYOUT_MODE_TABLET
+ : ZAURA_SHELL_LAYOUT_MODE_WINDOWED;
+ zaura_shell_send_layout_mode(aura_shell_resource_, layout_mode);
+ }
+ }
+ WaylandAuraShell(const WaylandAuraShell&) = delete;
+ WaylandAuraShell& operator=(const WaylandAuraShell&) = delete;
+ ~WaylandAuraShell() override {
+ WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
+ helper->RemoveTabletModeObserver(this);
+ }
+
+ // Overridden from ash::TabletModeObserver:
+ void OnTabletModeStarted() override {
+ if (wl_resource_get_version(aura_shell_resource_) >=
+ ZAURA_SHELL_LAYOUT_MODE_SINCE_VERSION)
+ zaura_shell_send_layout_mode(aura_shell_resource_,
+ ZAURA_SHELL_LAYOUT_MODE_TABLET);
+ }
+ void OnTabletModeEnding() override {
+ if (wl_resource_get_version(aura_shell_resource_) >=
+ ZAURA_SHELL_LAYOUT_MODE_SINCE_VERSION)
+ zaura_shell_send_layout_mode(aura_shell_resource_,
+ ZAURA_SHELL_LAYOUT_MODE_WINDOWED);
+ }
+ void OnTabletModeEnded() override {}
+
+ private:
+ // The aura shell resource associated with observer.
+ wl_resource* const aura_shell_resource_;
+};
+#endif // OS_CHROMEOS)
+
void aura_shell_get_aura_surface(wl_client* client,
wl_resource* resource,
uint32_t id,
@@ -505,8 +563,13 @@ void bind_aura_shell(wl_client* client,
wl_resource_create(client, &zaura_shell_interface,
std::min(version, kZAuraShellVersion), id);
+#if defined(OS_CHROMEOS)
+ SetImplementation(resource, &aura_shell_implementation,
+ std::make_unique<WaylandAuraShell>(resource));
+#else
wl_resource_set_implementation(resource, &aura_shell_implementation, nullptr,
nullptr);
+#endif
}
} // namespace wayland
diff --git a/chromium/components/exo/wayland/zaura_shell.h b/chromium/components/exo/wayland/zaura_shell.h
index a8b2d199819..246aa4303b0 100644
--- a/chromium/components/exo/wayland/zaura_shell.h
+++ b/chromium/components/exo/wayland/zaura_shell.h
@@ -17,7 +17,7 @@ struct wl_resource;
namespace exo {
namespace wayland {
-constexpr uint32_t kZAuraShellVersion = 10;
+constexpr uint32_t kZAuraShellVersion = 12;
// Adds bindings to the Aura Shell. Normally this implies Ash on ChromeOS
// builds. On non-ChromeOS builds the protocol provides access to Aura windowing
@@ -38,7 +38,7 @@ class AuraSurface : public SurfaceObserver,
void SetParent(AuraSurface* parent, const gfx::Point& position);
void SetStartupId(const char* startup_id);
void SetApplicationId(const char* application_id);
- void SetClientSurfaceId(int client_surface_id);
+ void SetClientSurfaceId(const char* client_surface_id);
void SetOcclusionTracking(bool tracking);
void Activate();
void DrawAttention();
diff --git a/chromium/components/exo/wayland/zcr_extended_drag.cc b/chromium/components/exo/wayland/zcr_extended_drag.cc
index d6b7dc9222c..88f78acf9f8 100644
--- a/chromium/components/exo/wayland/zcr_extended_drag.cc
+++ b/chromium/components/exo/wayland/zcr_extended_drag.cc
@@ -48,12 +48,12 @@ class ZcrExtendedDragSourceDelegate : public ExtendedDragSource::Delegate {
return settings_ & ZCR_EXTENDED_DRAG_V1_OPTIONS_LOCK_CURSOR;
}
- void OnSwallowed(std::string mime_type) override {
+ void OnSwallowed(const std::string& mime_type) override {
zcr_extended_drag_source_v1_send_swallow(resource_, mime_type.c_str());
wl_client_flush(wl_resource_get_client(resource_));
}
- void OnUnswallowed(std::string mime_type,
+ void OnUnswallowed(const std::string& mime_type,
const gfx::Vector2d& offset) override {
zcr_extended_drag_source_v1_send_unswallow(resource_, mime_type.c_str(),
offset.x(), offset.y());
@@ -143,7 +143,6 @@ void extended_drag_get_extended_drag_source(wl_client* client,
uint32_t id,
wl_resource* data_source_resource,
uint32_t settings) {
- Display* display = GetUserDataAs<Display>(resource);
DataSource* source = GetUserDataAs<DataSource>(data_source_resource);
wl_resource* extended_drag_source_resource =
@@ -153,9 +152,8 @@ void extended_drag_get_extended_drag_source(wl_client* client,
SetImplementation(extended_drag_source_resource,
&extended_drag_source_implementation,
std::make_unique<ExtendedDragSource>(
- source, display->seat(),
- new ZcrExtendedDragSourceDelegate(
- extended_drag_source_resource, settings)));
+ source, new ZcrExtendedDragSourceDelegate(
+ extended_drag_source_resource, settings)));
}
void extended_drag_get_extended_drag_offer(wl_client* client,
diff --git a/chromium/components/exo/wayland/zcr_remote_shell.cc b/chromium/components/exo/wayland/zcr_remote_shell.cc
index 3746e609e0d..ce5af3481bd 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell.cc
@@ -10,7 +10,6 @@
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/tablet_mode_observer.h"
-#include "ash/public/cpp/window_pin_type.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_layout_manager.h"
@@ -24,6 +23,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ui/base/window_pin_type.h"
#include "components/exo/client_controlled_shell_surface.h"
#include "components/exo/display.h"
#include "components/exo/input_method_surface.h"
@@ -56,6 +56,8 @@ constexpr char kForceRemoteShellScale[] = "force-remote-shell-scale";
} // namespace switches
+using chromeos::WindowStateType;
+
// We don't send configure immediately after tablet mode switch
// because layout can change due to orientation lock state or accelerometer.
constexpr int kConfigureDelayAfterLayoutSwitchMs = 300;
@@ -138,6 +140,20 @@ ash::ShelfLayoutManager* GetShelfLayoutManagerForDisplay(
return ash::Shelf::ForWindow(root)->shelf_layout_manager();
}
+int SystemUiVisibility(const display::Display& display) {
+ auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
+ switch (shelf_layout_manager->visibility_state()) {
+ case ash::SHELF_VISIBLE:
+ return ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE;
+ case ash::SHELF_AUTO_HIDE:
+ case ash::SHELF_HIDDEN:
+ return ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY;
+ }
+ NOTREACHED() << "Got unexpected shelf visibility state "
+ << shelf_layout_manager->visibility_state();
+ return 0;
+}
+
int Component(uint32_t direction) {
switch (direction) {
case ZCR_REMOTE_SURFACE_V1_RESIZE_DIRECTION_NONE:
@@ -316,13 +332,13 @@ void remote_surface_pin(wl_client* client,
wl_resource* resource,
int32_t trusted) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
- trusted ? ash::WindowPinType::kTrustedPinned
- : ash::WindowPinType::kPinned);
+ trusted ? chromeos::WindowPinType::kTrustedPinned
+ : chromeos::WindowPinType::kPinned);
}
void remote_surface_unpin(wl_client* client, wl_resource* resource) {
GetUserDataAs<ClientControlledShellSurface>(resource)->SetPinned(
- ash::WindowPinType::kNone);
+ chromeos::WindowPinType::kNone);
}
void remote_surface_set_system_modal(wl_client* client, wl_resource* resource) {
@@ -803,11 +819,7 @@ class WaylandRemoteOutput : public WaylandDisplayObserver {
resource_, stable_insets_in_pixel.left(), stable_insets_in_pixel.top(),
stable_insets_in_pixel.right(), stable_insets_in_pixel.bottom());
- auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
- int systemui_visibility =
- shelf_layout_manager->visibility_state() == ash::SHELF_AUTO_HIDE
- ? ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY
- : ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE;
+ int systemui_visibility = SystemUiVisibility(display);
zcr_remote_output_v1_send_systemui_visibility(resource_,
systemui_visibility);
@@ -837,6 +849,7 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
helper->AddTabletModeObserver(this);
helper->AddActivationObserver(this);
display::Screen::GetScreen()->AddObserver(this);
+ helper->AddFrameThrottlingObserver();
layout_mode_ = helper->InTabletMode()
? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
@@ -862,6 +875,7 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
helper->RemoveTabletModeObserver(this);
helper->RemoveActivationObserver(this);
display::Screen::GetScreen()->RemoveObserver(this);
+ helper->RemoveFrameThrottlingObserver();
}
std::unique_ptr<ClientControlledShellSurface> CreateShellSurface(
@@ -1028,8 +1042,6 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
}
if (wl_resource_get_version(remote_shell_resource_) >= 20) {
- auto* shelf_layout_manager = GetShelfLayoutManagerForDisplay(display);
-
// Apply the scale factor used on the remote shell client (ARC).
const gfx::Rect& bounds = display.bounds();
@@ -1055,10 +1067,7 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
MaybeApplyCTSHack(layout_mode_, size_in_pixel, &insets_in_client_pixel,
&stable_insets_in_client_pixel);
- int systemui_visibility =
- shelf_layout_manager->visibility_state() == ash::SHELF_AUTO_HIDE
- ? ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_AUTOHIDE_NON_STICKY
- : ZCR_REMOTE_SURFACE_V1_SYSTEMUI_VISIBILITY_STATE_VISIBLE;
+ int systemui_visibility = SystemUiVisibility(display);
zcr_remote_shell_v1_send_workspace_info(
remote_shell_resource_, display_id_hi, display_id_lo, x_px, y_px,
@@ -1131,19 +1140,18 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
void HandleRemoteSurfaceBoundsChangedCallback(
wl_resource* resource,
- ash::WindowStateType current_state,
- ash::WindowStateType requested_state,
+ WindowStateType current_state,
+ WindowStateType requested_state,
int64_t display_id,
const gfx::Rect& bounds_in_display,
bool resize,
int bounds_change) {
zcr_remote_surface_v1_bounds_change_reason reason =
ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_RESIZE;
- if (!resize) {
- reason = current_state == ash::WindowStateType::kPip
- ? ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE_PIP
- : ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE;
- }
+ if (!resize)
+ reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_MOVE;
+ if (current_state == WindowStateType::kPip)
+ reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_PIP;
if (bounds_change & ash::WindowResizer::kBoundsChange_Resizes) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_DRAG_RESIZE;
} else if (bounds_change & ash::WindowResizer::kBoundsChange_Repositions) {
@@ -1152,9 +1160,9 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
// Override the reason only if the window enters snapped mode. If the window
// resizes by dragging in snapped mode, we need to keep the original reason.
if (requested_state != current_state) {
- if (requested_state == ash::WindowStateType::kLeftSnapped) {
+ if (requested_state == WindowStateType::kLeftSnapped) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_LEFT;
- } else if (requested_state == ash::WindowStateType::kRightSnapped) {
+ } else if (requested_state == WindowStateType::kRightSnapped) {
reason = ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGE_REASON_SNAP_TO_RIGHT;
}
}
@@ -1199,10 +1207,9 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
bounds_in_display.height(), reason);
}
- void HandleRemoteSurfaceStateChangedCallback(
- wl_resource* resource,
- ash::WindowStateType old_state_type,
- ash::WindowStateType new_state_type) {
+ void HandleRemoteSurfaceStateChangedCallback(wl_resource* resource,
+ WindowStateType old_state_type,
+ WindowStateType new_state_type) {
DCHECK_NE(old_state_type, new_state_type);
LOG_IF(ERROR, pending_bounds_changes_.count(resource) > 0)
<< "Sending window state while there is a pending bounds change. This "
@@ -1210,28 +1217,28 @@ class WaylandRemoteShell : public ash::TabletModeObserver,
uint32_t state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_NORMAL;
switch (new_state_type) {
- case ash::WindowStateType::kMinimized:
+ case WindowStateType::kMinimized:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MINIMIZED;
break;
- case ash::WindowStateType::kMaximized:
+ case WindowStateType::kMaximized:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_MAXIMIZED;
break;
- case ash::WindowStateType::kFullscreen:
+ case WindowStateType::kFullscreen:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_FULLSCREEN;
break;
- case ash::WindowStateType::kPinned:
+ case WindowStateType::kPinned:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PINNED;
break;
- case ash::WindowStateType::kTrustedPinned:
+ case WindowStateType::kTrustedPinned:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_TRUSTED_PINNED;
break;
- case ash::WindowStateType::kLeftSnapped:
+ case WindowStateType::kLeftSnapped:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_LEFT_SNAPPED;
break;
- case ash::WindowStateType::kRightSnapped:
+ case WindowStateType::kRightSnapped:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED;
break;
- case ash::WindowStateType::kPip:
+ case WindowStateType::kPip:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP;
break;
default:
diff --git a/chromium/components/exo/wayland/zcr_remote_shell_unittest.cc b/chromium/components/exo/wayland/zcr_remote_shell_unittest.cc
index 493e9107aa2..650bfed10ac 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell_unittest.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell_unittest.cc
@@ -7,6 +7,7 @@
#include "components/exo/test/exo_test_base.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/widget/widget.h"
@@ -19,11 +20,11 @@ TEST_F(ZcrRemoteShellTest, GetWorkAreaInsetsInPixel) {
auto display = display::Screen::GetScreen()->GetPrimaryDisplay();
const float device_scale_factor = display.device_scale_factor();
- EXPECT_EQ(2.25f, device_scale_factor);
+ EXPECT_EQ(display::kDsf_2_252, device_scale_factor);
gfx::Insets insets = wayland::GetWorkAreaInsetsInPixel(
display, device_scale_factor, display.GetSizeInPixel(),
display.work_area());
- EXPECT_EQ(gfx::Insets(0, 0, 110, 0).ToString(), insets.ToString());
+ EXPECT_EQ(gfx::Insets(0, 0, 108, 0).ToString(), insets.ToString());
auto secondary_display = GetSecondaryDisplay();
gfx::Size secondary_size(secondary_display.size());
@@ -42,7 +43,7 @@ TEST_F(ZcrRemoteShellTest, GetWorkAreaInsetsInPixel) {
gfx::Insets stable_insets = wayland::GetWorkAreaInsetsInPixel(
display, device_scale_factor, display.GetSizeInPixel(),
wayland::GetStableWorkArea(display));
- EXPECT_EQ(gfx::Insets(0, 0, 110, 0).ToString(), stable_insets.ToString());
+ EXPECT_EQ(gfx::Insets(0, 0, 108, 0).ToString(), stable_insets.ToString());
gfx::Insets secondary_stable_insets = wayland::GetWorkAreaInsetsInPixel(
secondary_display, device_scale_factor, secondary_size_in_pixel,
wayland::GetStableWorkArea(secondary_display));
diff --git a/chromium/components/exo/wayland/zwp_text_input_manager.cc b/chromium/components/exo/wayland/zwp_text_input_manager.cc
index 927c0605096..d3edb610d3d 100644
--- a/chromium/components/exo/wayland/zwp_text_input_manager.cc
+++ b/chromium/components/exo/wayland/zwp_text_input_manager.cc
@@ -9,12 +9,14 @@
#include <wayland-server-protocol-core.h>
#include <xkbcommon/xkbcommon.h>
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/display.h"
#include "components/exo/text_input.h"
#include "components/exo/wayland/serial_tracker.h"
#include "components/exo/wayland/server_util.h"
#include "components/exo/xkb_tracker.h"
+#include "ui/base/ime/utf_offset.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
@@ -77,17 +79,22 @@ class WaylandTextInputDelegate : public TextInput::Delegate {
style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT;
break;
}
- const size_t start =
- OffsetFromUTF16Offset(composition.text, span.start_offset);
- const size_t end =
- OffsetFromUTF16Offset(composition.text, span.end_offset);
- zwp_text_input_v1_send_preedit_styling(text_input_, start, end - start,
+ const auto start =
+ ui::Utf8OffsetFromUtf16Offset(composition.text, span.start_offset);
+ if (!start)
+ continue;
+ const auto end =
+ ui::Utf8OffsetFromUtf16Offset(composition.text, span.end_offset);
+ if (!end)
+ continue;
+ zwp_text_input_v1_send_preedit_styling(text_input_, *start, *end - *start,
style);
}
- const size_t pos =
- OffsetFromUTF16Offset(composition.text, composition.selection.start());
- zwp_text_input_v1_send_preedit_cursor(text_input_, pos);
+ const auto pos = ui::Utf8OffsetFromUtf16Offset(
+ composition.text, composition.selection.start());
+ if (pos)
+ zwp_text_input_v1_send_preedit_cursor(text_input_, *pos);
const std::string utf8 = base::UTF16ToUTF8(composition.text);
zwp_text_input_v1_send_preedit_string(
@@ -224,9 +231,14 @@ void text_input_set_surrounding_text(wl_client* client,
uint32_t cursor,
uint32_t anchor) {
TextInput* text_input = GetUserDataAs<TextInput>(resource);
- text_input->SetSurroundingText(base::UTF8ToUTF16(text),
- OffsetFromUTF8Offset(text, cursor),
- OffsetFromUTF8Offset(text, anchor));
+ auto utf16_cursor = ui::Utf16OffsetFromUtf8Offset(text, cursor);
+ if (!utf16_cursor)
+ return;
+ auto utf16_anchor = ui::Utf16OffsetFromUtf8Offset(text, anchor);
+ if (!utf16_anchor)
+ return;
+ text_input->SetSurroundingText(base::UTF8ToUTF16(text), *utf16_cursor,
+ *utf16_anchor);
}
void text_input_set_content_type(wl_client* client,
diff --git a/chromium/components/exo/wayland/zxdg_shell.cc b/chromium/components/exo/wayland/zxdg_shell.cc
index a4284484676..1a3e0fa4c65 100644
--- a/chromium/components/exo/wayland/zxdg_shell.cc
+++ b/chromium/components/exo/wayland/zxdg_shell.cc
@@ -10,9 +10,9 @@
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
-#include "ash/public/cpp/window_state_type.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
+#include "chromeos/ui/base/window_state_type.h"
#include "components/exo/display.h"
#include "components/exo/wayland/serial_tracker.h"
#include "components/exo/wayland/server_util.h"
@@ -144,7 +144,7 @@ int XdgToplevelV6ResizeComponent(uint32_t edges) {
using XdgSurfaceConfigureCallback =
base::RepeatingCallback<void(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated)>;
@@ -153,7 +153,7 @@ uint32_t HandleXdgSurfaceV6ConfigureCallback(
SerialTracker* serial_tracker,
const XdgSurfaceConfigureCallback& callback,
const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated,
const gfx::Vector2d& origin_offset) {
@@ -290,14 +290,14 @@ class WaylandToplevel : public aura::WindowObserver {
}
void OnConfigure(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated) {
wl_array states;
wl_array_init(&states);
- if (state_type == ash::WindowStateType::kMaximized)
+ if (state_type == chromeos::WindowStateType::kMaximized)
AddState(&states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED);
- if (state_type == ash::WindowStateType::kFullscreen)
+ if (state_type == chromeos::WindowStateType::kFullscreen)
AddState(&states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN);
if (resizing)
AddState(&states, ZXDG_TOPLEVEL_V6_STATE_RESIZING);
@@ -467,7 +467,7 @@ class WaylandPopup : aura::WindowObserver {
}
void OnConfigure(const gfx::Size& size,
- ash::WindowStateType state_type,
+ chromeos::WindowStateType state_type,
bool resizing,
bool activated) {
// Nothing to do here as popups don't have additional configure state.
diff --git a/chromium/components/exo/wm_helper_chromeos.cc b/chromium/components/exo/wm_helper_chromeos.cc
index 4086f953a96..d2372f31c19 100644
--- a/chromium/components/exo/wm_helper_chromeos.cc
+++ b/chromium/components/exo/wm_helper_chromeos.cc
@@ -5,6 +5,7 @@
#include "components/exo/wm_helper_chromeos.h"
#include "components/exo/wm_helper.h"
+#include "ash/frame_throttler/frame_throttling_controller.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -61,6 +62,16 @@ void WMHelperChromeOS::RemoveDisplayConfigurationObserver(
ash::Shell::Get()->window_tree_host_manager()->RemoveObserver(observer);
}
+void WMHelperChromeOS::AddFrameThrottlingObserver() {
+ ash::Shell::Get()->frame_throttling_controller()->AddArcObserver(
+ &vsync_timing_manager_);
+}
+
+void WMHelperChromeOS::RemoveFrameThrottlingObserver() {
+ ash::Shell::Get()->frame_throttling_controller()->RemoveArcObserver(
+ &vsync_timing_manager_);
+}
+
void WMHelperChromeOS::AddActivationObserver(
wm::ActivationChangeObserver* observer) {
ash::Shell::Get()->activation_client()->AddObserver(observer);
diff --git a/chromium/components/exo/wm_helper_chromeos.h b/chromium/components/exo/wm_helper_chromeos.h
index b84beec6359..9dadb0556a3 100644
--- a/chromium/components/exo/wm_helper_chromeos.h
+++ b/chromium/components/exo/wm_helper_chromeos.h
@@ -60,6 +60,8 @@ class WMHelperChromeOS : public WMHelper, public VSyncTimingManager::Delegate {
ash::WindowTreeHostManager::Observer* observer);
void RemoveDisplayConfigurationObserver(
ash::WindowTreeHostManager::Observer* observer);
+ void AddFrameThrottlingObserver();
+ void RemoveFrameThrottlingObserver();
// Overridden from WMHelper
void AddActivationObserver(wm::ActivationChangeObserver* observer) override;
diff --git a/chromium/components/exo/wm_helper_chromeos_unittest.cc b/chromium/components/exo/wm_helper_chromeos_unittest.cc
new file mode 100644
index 00000000000..27adc015190
--- /dev/null
+++ b/chromium/components/exo/wm_helper_chromeos_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2020 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/exo/wm_helper_chromeos.h"
+#include "ash/frame_throttler/frame_throttling_controller.h"
+#include "ash/shell.h"
+#include "components/exo/mock_vsync_timing_observer.h"
+#include "components/exo/test/exo_test_base.h"
+
+namespace exo {
+
+using WMHelperChromeOSTest = test::ExoTestBase;
+
+TEST_F(WMHelperChromeOSTest, FrameThrottling) {
+ WMHelperChromeOS* wm_helper_chromeos =
+ static_cast<WMHelperChromeOS*>(wm_helper());
+ wm_helper_chromeos->AddFrameThrottlingObserver();
+ VSyncTimingManager& vsync_timing_manager =
+ wm_helper_chromeos->GetVSyncTimingManager();
+ MockVSyncTimingObserver observer;
+ vsync_timing_manager.AddObserver(&observer);
+ ash::FrameThrottlingController* ftc =
+ ash::Shell::Get()->frame_throttling_controller();
+
+ // Throttling should be off by default.
+ EXPECT_EQ(vsync_timing_manager.throttled_interval(), base::TimeDelta());
+
+ // Create two arc windows.
+ std::unique_ptr<aura::Window> arc_window_1 =
+ CreateAppWindow(gfx::Rect(), ash::AppType::ARC_APP);
+ std::unique_ptr<aura::Window> arc_window_2 =
+ CreateAppWindow(gfx::Rect(), ash::AppType::ARC_APP);
+
+ // Starting throttling on one of the two arc windows will have no effect on
+ // vsync time.
+ EXPECT_CALL(observer, OnUpdateVSyncParameters(testing::_, testing::_))
+ .Times(0);
+ ftc->StartThrottling({arc_window_1.get()});
+ EXPECT_EQ(vsync_timing_manager.throttled_interval(), base::TimeDelta());
+
+ // Both windows are to be throttled, vsync timing will be adjusted.
+ base::TimeDelta throttled_interval =
+ base::TimeDelta::FromSeconds(1) / ftc->throttled_fps();
+ EXPECT_CALL(observer,
+ OnUpdateVSyncParameters(testing::_, throttled_interval));
+ ftc->StartThrottling({arc_window_1.get(), arc_window_2.get()});
+ EXPECT_EQ(vsync_timing_manager.throttled_interval(), throttled_interval);
+
+ EXPECT_CALL(observer,
+ OnUpdateVSyncParameters(testing::_,
+ viz::BeginFrameArgs::DefaultInterval()));
+ ftc->EndThrottling();
+ EXPECT_EQ(vsync_timing_manager.throttled_interval(), base::TimeDelta());
+
+ vsync_timing_manager.RemoveObserver(&observer);
+ wm_helper_chromeos->RemoveFrameThrottlingObserver();
+}
+} // namespace exo
diff --git a/chromium/components/favicon/android/BUILD.gn b/chromium/components/favicon/android/BUILD.gn
new file mode 100644
index 00000000000..6da8dd4ce7d
--- /dev/null
+++ b/chromium/components/favicon/android/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2020 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("//build/config/android/rules.gni")
+
+android_library("java") {
+ sources = [ "java/src/org/chromium/components/favicon/LargeIconBridge.java" ]
+
+ deps = [
+ "//base:base_java",
+ "//base:jni_java",
+ "//components/browser_ui/util/android:java",
+ "//components/embedder_support/android:browser_context_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//url:gurl_java",
+ ]
+
+ srcjar_deps = [ "//components/favicon_base:favicon_base_enums_java" ]
+
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+}
+
+generate_jni("jni_headers") {
+ sources = [ "java/src/org/chromium/components/favicon/LargeIconBridge.java" ]
+}
+
+source_set("android") {
+ sources = [
+ "large_icon_bridge.cc",
+ "large_icon_bridge.h",
+ ]
+
+ deps = [
+ ":jni_headers",
+ "//base",
+ "//components/embedder_support/android:browser_context",
+ "//components/favicon/content",
+ "//components/favicon/core",
+ "//components/favicon_base",
+ "//skia",
+ "//ui/gfx",
+ "//url",
+ "//url:gurl_android",
+ ]
+}
diff --git a/chromium/components/favicon/android/DEPS b/chromium/components/favicon/android/DEPS
new file mode 100644
index 00000000000..04f37a975b4
--- /dev/null
+++ b/chromium/components/favicon/android/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/browser_ui/util",
+ "+components/embedder_support",
+ "+third_party/skia",
+]
diff --git a/chromium/components/favicon/android/large_icon_bridge.cc b/chromium/components/favicon/android/large_icon_bridge.cc
new file mode 100644
index 00000000000..159aa4de831
--- /dev/null
+++ b/chromium/components/favicon/android/large_icon_bridge.cc
@@ -0,0 +1,103 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/favicon/android/large_icon_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "components/embedder_support/android/browser_context/browser_context_handle.h"
+#include "components/favicon/android/jni_headers/LargeIconBridge_jni.h"
+#include "components/favicon/content/large_favicon_provider_getter.h"
+#include "components/favicon/core/core_favicon_service.h"
+#include "components/favicon/core/large_favicon_provider.h"
+#include "components/favicon/core/large_icon_worker.h"
+#include "components/favicon_base/fallback_icon_style.h"
+#include "components/favicon_base/favicon_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "url/android/gurl_android.h"
+#include "url/gurl.h"
+
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace favicon {
+
+namespace {
+
+void OnLargeIconAvailable(const JavaRef<jobject>& j_callback,
+ const favicon_base::LargeIconResult& result) {
+ JNIEnv* env = AttachCurrentThread();
+
+ // Convert the result to a Java Bitmap.
+ SkBitmap bitmap;
+ ScopedJavaLocalRef<jobject> j_bitmap;
+ if (result.bitmap.is_valid()) {
+ if (gfx::PNGCodec::Decode(result.bitmap.bitmap_data->front(),
+ result.bitmap.bitmap_data->size(), &bitmap))
+ j_bitmap = gfx::ConvertToJavaBitmap(bitmap);
+ }
+
+ favicon_base::FallbackIconStyle fallback;
+ if (result.fallback_icon_style)
+ fallback = *result.fallback_icon_style;
+
+ Java_LargeIconCallback_onLargeIconAvailable(
+ env, j_callback, j_bitmap, fallback.background_color,
+ fallback.is_default_background_color,
+ static_cast<int>(result.bitmap.icon_type));
+}
+
+} // namespace
+
+static jlong JNI_LargeIconBridge_Init(JNIEnv* env) {
+ return reinterpret_cast<intptr_t>(new LargeIconBridge());
+}
+
+LargeIconBridge::LargeIconBridge() = default;
+LargeIconBridge::~LargeIconBridge() = default;
+
+void LargeIconBridge::Destroy(JNIEnv* env) {
+ delete this;
+}
+
+jboolean LargeIconBridge::GetLargeIconForURL(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& j_browser_context,
+ const JavaParamRef<jobject>& j_page_url,
+ jint min_source_size_px,
+ const JavaParamRef<jobject>& j_callback) {
+ content::BrowserContext* browser_context =
+ browser_context::BrowserContextFromJavaHandle(j_browser_context);
+ if (!browser_context)
+ return false;
+
+ LargeFaviconProvider* favicon_provider =
+ GetLargeFaviconProvider(browser_context);
+ if (!favicon_provider)
+ return false;
+
+ favicon_base::LargeIconCallback callback_runner = base::BindOnce(
+ &OnLargeIconAvailable, ScopedJavaGlobalRef<jobject>(env, j_callback));
+
+ std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_page_url);
+
+ // Use desired_size = 0 for getting the icon from the cache (so that
+ // the icon is not poorly rescaled by LargeIconService).
+ LargeIconWorker::GetLargeIconRawBitmap(
+ favicon_provider, *url, min_source_size_px,
+ /*desired_size_in_pixel=*/0, std::move(callback_runner), {},
+ &cancelable_task_tracker_);
+
+ return true;
+}
+
+} // namespace favicon
diff --git a/chromium/components/favicon/android/large_icon_bridge.h b/chromium/components/favicon/android/large_icon_bridge.h
new file mode 100644
index 00000000000..21422f4e8e7
--- /dev/null
+++ b/chromium/components/favicon/android/large_icon_bridge.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FAVICON_ANDROID_LARGE_ICON_BRIDGE_H_
+#define COMPONENTS_FAVICON_ANDROID_LARGE_ICON_BRIDGE_H_
+
+#include <jni.h>
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/task/cancelable_task_tracker.h"
+
+namespace favicon {
+
+// The C++ counterpart to Java's LargeIconBridge. Together these classes expose
+// LargeIconService to Java.
+class LargeIconBridge {
+ public:
+ LargeIconBridge();
+ LargeIconBridge(const LargeIconBridge& bridge) = delete;
+ LargeIconBridge& operator=(const LargeIconBridge& bridge) = delete;
+
+ void Destroy(JNIEnv* env);
+ jboolean GetLargeIconForURL(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& j_profile,
+ const base::android::JavaParamRef<jobject>& j_page_url,
+ jint min_source_size_px,
+ const base::android::JavaParamRef<jobject>& j_callback);
+
+ private:
+ virtual ~LargeIconBridge();
+
+ base::CancelableTaskTracker cancelable_task_tracker_;
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_ANDROID_LARGE_ICON_BRIDGE_H_
diff --git a/chromium/components/favicon/content/BUILD.gn b/chromium/components/favicon/content/BUILD.gn
index 99ea6d523c9..7ae7a3ff16e 100644
--- a/chromium/components/favicon/content/BUILD.gn
+++ b/chromium/components/favicon/content/BUILD.gn
@@ -8,6 +8,8 @@ static_library("content") {
"content_favicon_driver.h",
"favicon_url_util.cc",
"favicon_url_util.h",
+ "large_favicon_provider_getter.cc",
+ "large_favicon_provider_getter.h",
]
public_deps = [
diff --git a/chromium/components/favicon/content/content_favicon_driver_unittest.cc b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
index fd984874830..a7ae1b51611 100644
--- a/chromium/components/favicon/content/content_favicon_driver_unittest.cc
+++ b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/favicon/core/favicon_client.h"
#include "components/favicon/core/favicon_handler.h"
diff --git a/chromium/components/favicon/content/large_favicon_provider_getter.cc b/chromium/components/favicon/content/large_favicon_provider_getter.cc
new file mode 100644
index 00000000000..606d3bbe141
--- /dev/null
+++ b/chromium/components/favicon/content/large_favicon_provider_getter.cc
@@ -0,0 +1,30 @@
+// Copyright 2020 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/favicon/content/large_favicon_provider_getter.h"
+
+#include "base/no_destructor.h"
+
+namespace favicon {
+
+namespace {
+
+LargeFaviconProviderGetter* GetGetter() {
+ static base::NoDestructor<LargeFaviconProviderGetter> getter;
+ return getter.get();
+}
+
+} // namespace
+
+void SetLargeFaviconProviderGetter(const LargeFaviconProviderGetter& getter) {
+ *GetGetter() = getter;
+}
+
+// static
+LargeFaviconProvider* GetLargeFaviconProvider(
+ content::BrowserContext* context) {
+ return GetGetter()->Run(context);
+}
+
+} // namespace favicon
diff --git a/chromium/components/favicon/content/large_favicon_provider_getter.h b/chromium/components/favicon/content/large_favicon_provider_getter.h
new file mode 100644
index 00000000000..7fb2f2394b6
--- /dev/null
+++ b/chromium/components/favicon/content/large_favicon_provider_getter.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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_FAVICON_CONTENT_LARGE_FAVICON_PROVIDER_GETTER_H_
+#define COMPONENTS_FAVICON_CONTENT_LARGE_FAVICON_PROVIDER_GETTER_H_
+
+#include "base/callback.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace favicon {
+
+class LargeFaviconProvider;
+
+using LargeFaviconProviderGetter =
+ base::RepeatingCallback<LargeFaviconProvider*(content::BrowserContext*)>;
+
+// Sets a callback that returns the LargeIconProvider for a given
+// BrowserContext. This allows code in //components, such as LargeIconBridge, to
+// obtain an implementation of LargeIconProvider even though the
+// implementation's factory is unique to each embedder.
+void SetLargeFaviconProviderGetter(const LargeFaviconProviderGetter& getter);
+LargeFaviconProvider* GetLargeFaviconProvider(content::BrowserContext* context);
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CONTENT_LARGE_FAVICON_PROVIDER_GETTER_H_
diff --git a/chromium/components/favicon/core/BUILD.gn b/chromium/components/favicon/core/BUILD.gn
index 462d30a979d..e281da5a8aa 100644
--- a/chromium/components/favicon/core/BUILD.gn
+++ b/chromium/components/favicon/core/BUILD.gn
@@ -24,9 +24,12 @@ static_library("core") {
"history_ui_favicon_request_handler.h",
"history_ui_favicon_request_handler_impl.cc",
"history_ui_favicon_request_handler_impl.h",
+ "large_favicon_provider.h",
"large_icon_service.h",
"large_icon_service_impl.cc",
"large_icon_service_impl.h",
+ "large_icon_worker.cc",
+ "large_icon_worker.h",
]
deps = [
diff --git a/chromium/components/favicon/core/favicon_handler.cc b/chromium/components/favicon/core/favicon_handler.cc
index 3d278c8e7cb..0d53f634fb7 100644
--- a/chromium/components/favicon/core/favicon_handler.cc
+++ b/chromium/components/favicon/core/favicon_handler.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
diff --git a/chromium/components/favicon/core/favicon_handler_unittest.cc b/chromium/components/favicon/core/favicon_handler_unittest.cc
index 94bb2499479..0fc6b3035e8 100644
--- a/chromium/components/favicon/core/favicon_handler_unittest.cc
+++ b/chromium/components/favicon/core/favicon_handler_unittest.cc
@@ -12,11 +12,10 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "components/favicon/core/favicon_driver.h"
diff --git a/chromium/components/favicon/core/favicon_service.h b/chromium/components/favicon/core/favicon_service.h
index 34acdbd93c1..e6053d1cf13 100644
--- a/chromium/components/favicon/core/favicon_service.h
+++ b/chromium/components/favicon/core/favicon_service.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/favicon/core/core_favicon_service.h"
+#include "components/favicon/core/large_favicon_provider.h"
#include "components/favicon_base/favicon_callback.h"
#include "components/favicon_base/favicon_types.h"
#include "components/favicon_base/favicon_usage_data.h"
@@ -18,7 +19,7 @@ class GURL;
namespace favicon {
-class FaviconService : public CoreFaviconService {
+class FaviconService : public CoreFaviconService, public LargeFaviconProvider {
public:
//////////////////////////////////////////////////////////////////////////////
// Methods to request favicon bitmaps from the history backend for |icon_url|.
@@ -81,14 +82,6 @@ class FaviconService : public CoreFaviconService {
favicon_base::FaviconRawBitmapCallback callback,
base::CancelableTaskTracker* tracker) = 0;
- // See HistoryService::GetLargestFaviconForPageURL().
- virtual base::CancelableTaskTracker::TaskId GetLargestRawFaviconForPageURL(
- const GURL& page_url,
- const std::vector<favicon_base::IconTypeSet>& icon_types,
- int minimum_size_in_pixels,
- favicon_base::FaviconRawBitmapCallback callback,
- base::CancelableTaskTracker* tracker) = 0;
-
// Used to request a bitmap for the favicon with |favicon_id| which is not
// resized from the size it is stored at in the database. If there are
// multiple favicon bitmaps for |favicon_id|, the largest favicon bitmap is
diff --git a/chromium/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc b/chromium/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
index dee24c1680e..5776be2d58c 100644
--- a/chromium/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
+++ b/chromium/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
diff --git a/chromium/components/favicon/core/large_favicon_provider.h b/chromium/components/favicon/core/large_favicon_provider.h
new file mode 100644
index 00000000000..54d571504d1
--- /dev/null
+++ b/chromium/components/favicon/core/large_favicon_provider.h
@@ -0,0 +1,41 @@
+// Copyright 2020 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_FAVICON_CORE_LARGE_FAVICON_PROVIDER_H_
+#define COMPONENTS_FAVICON_CORE_LARGE_FAVICON_PROVIDER_H_
+
+#include <vector>
+
+#include "base/task/cancelable_task_tracker.h"
+#include "components/favicon_base/favicon_callback.h"
+#include "components/favicon_base/favicon_types.h"
+
+class GURL;
+
+namespace favicon {
+
+// An interface used to look up large favicons. It's used by LargeIconBridge and
+// LargeIconService, and embedders provide an implementation via
+// SetLargeFaviconProviderGetter(), allowing code in //components to access the
+// provider for a given BrowserContext.
+class LargeFaviconProvider {
+ public:
+ // This searches for icons by IconType. Each element of |icon_types| is a
+ // bitmask of IconTypes indicating the types to search for. If the largest
+ // icon of |icon_types[0]| is not larger than |minimum_size_in_pixel|, the
+ // next icon types of |icon_types| will be searched and so on. If no icon is
+ // larger than |minimum_size_in_pixel|, the largest one of all icon types in
+ // |icon_types| is returned. This feature is especially useful when some types
+ // of icon is preferred as long as its size is larger than a specific value.
+ virtual base::CancelableTaskTracker::TaskId GetLargestRawFaviconForPageURL(
+ const GURL& page_url,
+ const std::vector<favicon_base::IconTypeSet>& icon_types,
+ int minimum_size_in_pixels,
+ favicon_base::FaviconRawBitmapCallback callback,
+ base::CancelableTaskTracker* tracker) = 0;
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CORE_LARGE_FAVICON_PROVIDER_H_
diff --git a/chromium/components/favicon/core/large_icon_service_impl.cc b/chromium/components/favicon/core/large_icon_service_impl.cc
index 3e5399d09c3..8958b136113 100644
--- a/chromium/components/favicon/core/large_icon_service_impl.cc
+++ b/chromium/components/favicon/core/large_icon_service_impl.cc
@@ -8,12 +8,9 @@
#include <string>
#include "base/bind.h"
-#include "base/containers/flat_map.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
@@ -21,14 +18,10 @@
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_service.h"
-#include "components/favicon_base/fallback_icon_style.h"
+#include "components/favicon/core/large_icon_worker.h"
#include "components/favicon_base/favicon_util.h"
#include "components/image_fetcher/core/request_metadata.h"
#include "net/base/network_change_notifier.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "skia/ext/image_operations.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/geometry/size.h"
#include "url/url_canon.h"
namespace favicon {
@@ -53,8 +46,6 @@ const double kGoogleServerV2DesiredToMaxSizeFactor = 2.0;
const int kGoogleServerV2MinimumMaxSizeInPixel = 256;
-const int kInvalidOrganizationId = -1;
-
GURL TrimPageUrlForGoogleServer(const GURL& page_url,
bool should_trim_page_url_path) {
if (!page_url.SchemeIsHTTPOrHTTPS() || page_url.HostIsIPAddress())
@@ -92,85 +83,6 @@ GURL GetRequestUrlForGoogleServerV2(
return GURL(request_url);
}
-bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
- int min_source_size) {
- return db_result.is_valid() &&
- db_result.pixel_size.width() == db_result.pixel_size.height() &&
- db_result.pixel_size.width() >= min_source_size;
-}
-
-// Wraps the PNG data in |db_result| in a gfx::Image. If |desired_size| is not
-// 0, the image gets decoded and resized to |desired_size| (in px). Must run on
-// a background thread in production.
-gfx::Image ResizeLargeIconOnBackgroundThread(
- const favicon_base::FaviconRawBitmapResult& db_result,
- int desired_size) {
- gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
- db_result.bitmap_data->front(), db_result.bitmap_data->size());
-
- if (desired_size == 0 || db_result.pixel_size.width() == desired_size) {
- return image;
- }
-
- SkBitmap resized = skia::ImageOperations::Resize(
- image.AsBitmap(), skia::ImageOperations::RESIZE_LANCZOS3, desired_size,
- desired_size);
- return gfx::Image::CreateFrom1xBitmap(resized);
-}
-
-// Processes the |db_result| and writes the result into |raw_result| if
-// |raw_result| is not nullptr or to |bitmap|, otherwise. If |db_result| is not
-// valid or is smaller than |min_source_size|, the resulting fallback style is
-// written into |fallback_icon_style|.
-void ProcessIconOnBackgroundThread(
- const favicon_base::FaviconRawBitmapResult& db_result,
- int min_source_size,
- int desired_size,
- favicon_base::FaviconRawBitmapResult* raw_result,
- SkBitmap* bitmap,
- GURL* icon_url,
- favicon_base::FallbackIconStyle* fallback_icon_style) {
- if (IsDbResultAdequate(db_result, min_source_size)) {
- gfx::Image image;
- image = ResizeLargeIconOnBackgroundThread(db_result, desired_size);
-
- if (!image.IsEmpty()) {
- if (raw_result) {
- *raw_result = db_result;
- if (desired_size != 0)
- raw_result->pixel_size = gfx::Size(desired_size, desired_size);
- raw_result->bitmap_data = image.As1xPNGBytes();
- }
- if (bitmap) {
- *bitmap = image.AsBitmap();
- }
- if (icon_url) {
- *icon_url = db_result.icon_url;
- }
- return;
- }
- }
-
- if (!fallback_icon_style)
- return;
-
- *fallback_icon_style = favicon_base::FallbackIconStyle();
- int fallback_icon_size = 0;
- if (db_result.is_valid()) {
- favicon_base::SetDominantColorAsBackground(db_result.bitmap_data,
- fallback_icon_style);
- // The size must be positive, we cap to 128 to avoid the sparse histogram
- // to explode (having too many different values, server-side). Size 128
- // already indicates that there is a problem in the code, 128 px _should_ be
- // enough in all current UI surfaces.
- fallback_icon_size = db_result.pixel_size.width();
- DCHECK_GT(fallback_icon_size, 0);
- fallback_icon_size = std::min(fallback_icon_size, 128);
- }
- base::UmaHistogramSparse("Favicons.LargeIconService.FallbackSize",
- fallback_icon_size);
-}
-
void FinishServerRequestAsynchronously(
favicon_base::GoogleFaviconServerCallback callback,
favicon_base::GoogleFaviconServerRequestStatus status) {
@@ -178,203 +90,6 @@ void FinishServerRequestAsynchronously(
FROM_HERE, base::BindOnce(std::move(callback), status));
}
-// Singleton map keyed by organization-identifying domain (excludes registrar
-// portion, e.g. final ".com") and a value that represents an ID for the
-// organization.
-class DomainToOrganizationIdMap {
- public:
- // Returns singleton instance.
- static const DomainToOrganizationIdMap* GetInstance();
-
- // Returns a unique ID representing a known organization, or
- // |kInvalidOrganizationId| in case the URL is not known.
- int GetCanonicalOrganizationId(const GURL& url) const;
-
- private:
- friend struct base::DefaultSingletonTraits<const DomainToOrganizationIdMap>;
-
- DomainToOrganizationIdMap();
- ~DomainToOrganizationIdMap();
-
- // Helper function to populate the data during construction.
- static base::flat_map<std::string, int> BuildData();
-
- // Actual data.
- const base::flat_map<std::string, int> data_;
-
- DISALLOW_COPY_AND_ASSIGN(DomainToOrganizationIdMap);
-};
-
-// static
-const DomainToOrganizationIdMap* DomainToOrganizationIdMap::GetInstance() {
- return base::Singleton<const DomainToOrganizationIdMap>::get();
-}
-
-int DomainToOrganizationIdMap::GetCanonicalOrganizationId(
- const GURL& url) const {
- auto it = data_.find(LargeIconServiceImpl::GetOrganizationNameForUma(url));
- return it == data_.end() ? kInvalidOrganizationId : it->second;
-}
-
-DomainToOrganizationIdMap::DomainToOrganizationIdMap() : data_(BuildData()) {}
-
-DomainToOrganizationIdMap::~DomainToOrganizationIdMap() {}
-
-// static
-base::flat_map<std::string, int> DomainToOrganizationIdMap::BuildData() {
- // Each row in the matrix below represents an organization and lists some
- // known domains (not necessarily all), for the purpose of logging UMA
- // metrics. The idea is that <pageUrl, iconUrl> pairs should not mix different
- // rows (otherwise there is likely a bug).
- const std::vector<std::vector<std::string>> kOrganizationTable = {
- {"amazon", "ssl-images-amazon"},
- {"cnn"},
- {"espn", "espncdn"},
- {"facebook", "fbcdn"},
- {"google", "gstatic"},
- {"live", "gfx"},
- {"nytimes"},
- {"twitter", "twimg"},
- {"washingtonpost"},
- {"wikipedia"},
- {"yahoo", "yimg"},
- {"youtube"},
- };
- base::flat_map<std::string, int> result;
- for (int row = 0; row < static_cast<int>(kOrganizationTable.size()); ++row) {
- for (const std::string& organization : kOrganizationTable[row]) {
- result[organization] = row + 1;
- }
- }
- return result;
-}
-
-// Processes the bitmap data returned from the FaviconService as part of a
-// LargeIconService request.
-class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
- public:
- // Exactly one of the callbacks is expected to be non-null.
- LargeIconWorker(int min_source_size_in_pixel,
- int desired_size_in_pixel,
- favicon_base::LargeIconCallback raw_bitmap_callback,
- favicon_base::LargeIconImageCallback image_callback,
- base::CancelableTaskTracker* tracker);
-
- // Must run on the owner (UI) thread in production.
- // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes
- // ProcessIconOnBackgroundThread() so we do not perform complex image
- // operations on the UI thread.
- void OnIconLookupComplete(
- const GURL& page_url,
- const favicon_base::FaviconRawBitmapResult& db_result);
-
- private:
- friend class base::RefCountedThreadSafe<LargeIconWorker>;
-
- ~LargeIconWorker();
-
- // Must run on the owner (UI) thread in production.
- // Invoked when ProcessIconOnBackgroundThread() is done.
- void OnIconProcessingComplete();
-
- // Logs UMA metrics that reflect suspicious page-URL / icon-URL pairs, because
- // we know they shouldn't be hosting their favicons in each other.
- void LogSuspiciousURLMismatches(
- const GURL& page_url,
- const favicon_base::FaviconRawBitmapResult& db_result);
-
- int min_source_size_in_pixel_;
- int desired_size_in_pixel_;
- favicon_base::LargeIconCallback raw_bitmap_callback_;
- favicon_base::LargeIconImageCallback image_callback_;
- scoped_refptr<base::TaskRunner> background_task_runner_;
- base::CancelableTaskTracker* tracker_;
-
- favicon_base::FaviconRawBitmapResult raw_bitmap_result_;
- SkBitmap bitmap_result_;
- GURL icon_url_;
- std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style_;
-
- DISALLOW_COPY_AND_ASSIGN(LargeIconWorker);
-};
-
-LargeIconWorker::LargeIconWorker(
- int min_source_size_in_pixel,
- int desired_size_in_pixel,
- favicon_base::LargeIconCallback raw_bitmap_callback,
- favicon_base::LargeIconImageCallback image_callback,
- base::CancelableTaskTracker* tracker)
- : min_source_size_in_pixel_(min_source_size_in_pixel),
- desired_size_in_pixel_(desired_size_in_pixel),
- raw_bitmap_callback_(std::move(raw_bitmap_callback)),
- image_callback_(std::move(image_callback)),
- background_task_runner_(base::ThreadPool::CreateTaskRunner(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
- tracker_(tracker),
- fallback_icon_style_(
- std::make_unique<favicon_base::FallbackIconStyle>()) {}
-
-LargeIconWorker::~LargeIconWorker() {}
-
-void LargeIconWorker::OnIconLookupComplete(
- const GURL& page_url_for_uma,
- const favicon_base::FaviconRawBitmapResult& db_result) {
- LogSuspiciousURLMismatches(page_url_for_uma, db_result);
- tracker_->PostTaskAndReply(
- background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&ProcessIconOnBackgroundThread, db_result,
- min_source_size_in_pixel_, desired_size_in_pixel_,
- raw_bitmap_callback_ ? &raw_bitmap_result_ : nullptr,
- image_callback_ ? &bitmap_result_ : nullptr,
- image_callback_ ? &icon_url_ : nullptr,
- fallback_icon_style_.get()),
- base::BindOnce(&LargeIconWorker::OnIconProcessingComplete, this));
-}
-
-void LargeIconWorker::OnIconProcessingComplete() {
- // If |raw_bitmap_callback_| is provided, return the raw result.
- if (raw_bitmap_callback_) {
- if (raw_bitmap_result_.is_valid()) {
- std::move(raw_bitmap_callback_)
- .Run(favicon_base::LargeIconResult(raw_bitmap_result_));
- return;
- }
- std::move(raw_bitmap_callback_)
- .Run(favicon_base::LargeIconResult(fallback_icon_style_.release()));
- return;
- }
-
- if (!bitmap_result_.isNull()) {
- std::move(image_callback_)
- .Run(favicon_base::LargeIconImageResult(
- gfx::Image::CreateFrom1xBitmap(bitmap_result_), icon_url_));
- return;
- }
- std::move(image_callback_)
- .Run(favicon_base::LargeIconImageResult(fallback_icon_style_.release()));
-}
-
-void LargeIconWorker::LogSuspiciousURLMismatches(
- const GURL& page_url_for_uma,
- const favicon_base::FaviconRawBitmapResult& db_result) {
- const int page_organization_id =
- DomainToOrganizationIdMap::GetInstance()->GetCanonicalOrganizationId(
- page_url_for_uma);
-
- // Ignore trivial cases.
- if (!db_result.is_valid() || page_organization_id == kInvalidOrganizationId)
- return;
-
- const int icon_organization_id =
- DomainToOrganizationIdMap::GetInstance()->GetCanonicalOrganizationId(
- db_result.icon_url);
- const bool mismatch_found = page_organization_id != icon_organization_id &&
- icon_organization_id != kInvalidOrganizationId;
- UMA_HISTOGRAM_BOOLEAN("Favicons.LargeIconService.BlacklistedURLMismatch",
- mismatch_found);
-}
-
void ReportDownloadedSize(int size) {
UMA_HISTOGRAM_COUNTS_1000("Favicons.LargeIconService.DownloadedSize", size);
}
@@ -448,10 +163,6 @@ LargeIconServiceImpl::LargeIconServiceImpl(
icon_type_for_server_requests_(icon_type_for_server_requests),
google_server_client_param_(google_server_client_param),
server_url_(kGoogleServerV2Url) {
- large_icon_types_.push_back({favicon_base::IconType::kWebManifestIcon});
- large_icon_types_.push_back({favicon_base::IconType::kFavicon});
- large_icon_types_.push_back({favicon_base::IconType::kTouchIcon});
- large_icon_types_.push_back({favicon_base::IconType::kTouchPrecomposedIcon});
// TODO(jkrcal): Add non-null image_fetcher into remaining unit-tests and add
// a DCHECK(image_fetcher_) here.
}
@@ -502,9 +213,7 @@ LargeIconServiceImpl::GetLargeIconRawBitmapOrFallbackStyleForIconUrl(
std::max(desired_size_in_pixel, min_source_size_in_pixel);
return favicon_service_->GetRawFavicon(
icon_url, favicon_base::IconType::kFavicon, max_size_in_pixel,
- base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker,
- /*page_url_for_uma=*/GURL()),
- tracker);
+ base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
}
base::CancelableTaskTracker::TaskId
@@ -522,9 +231,7 @@ LargeIconServiceImpl::GetIconRawBitmapOrFallbackStyleForPageUrl(
return favicon_service_->GetRawFaviconForPageURL(
page_url, {favicon_base::IconType::kFavicon}, desired_size_in_pixel,
/*fallback_to_host=*/true,
- base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker,
- /*page_url_for_uma=*/GURL()),
- tracker);
+ base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
}
void LargeIconServiceImpl::
@@ -595,25 +302,6 @@ void LargeIconServiceImpl::SetServerUrlForTesting(
server_url_ = server_url_for_testing;
}
-// static
-std::string LargeIconServiceImpl::GetOrganizationNameForUma(const GURL& url) {
- const size_t registry_length =
- net::registry_controlled_domains::GetRegistryLength(
- url, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
- net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
- std::string organization =
- net::registry_controlled_domains::GetDomainAndRegistry(
- url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
- if (registry_length == 0 || registry_length == std::string::npos ||
- registry_length >= organization.size()) {
- return std::string();
- }
-
- // Strip final registry as well as the preceding dot.
- organization.resize(organization.size() - registry_length - 1);
- return organization;
-}
-
base::CancelableTaskTracker::TaskId
LargeIconServiceImpl::GetLargeIconOrFallbackStyleImpl(
const GURL& page_url,
@@ -622,23 +310,10 @@ LargeIconServiceImpl::GetLargeIconOrFallbackStyleImpl(
favicon_base::LargeIconCallback raw_bitmap_callback,
favicon_base::LargeIconImageCallback image_callback,
base::CancelableTaskTracker* tracker) {
- DCHECK_LE(1, min_source_size_in_pixel);
- DCHECK_LE(0, desired_size_in_pixel);
-
- scoped_refptr<LargeIconWorker> worker = new LargeIconWorker(
- min_source_size_in_pixel, desired_size_in_pixel,
- std::move(raw_bitmap_callback), std::move(image_callback), tracker);
-
- int max_size_in_pixel =
- std::max(desired_size_in_pixel, min_source_size_in_pixel);
- // TODO(beaudoin): For now this is just a wrapper around
- // GetLargestRawFaviconForPageURL. Add the logic required to select the
- // best possible large icon. Also add logic to fetch-on-demand when the
- // URL of a large icon is known but its bitmap is not available.
- return favicon_service_->GetLargestRawFaviconForPageURL(
- page_url, large_icon_types_, max_size_in_pixel,
- base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker, page_url),
- tracker);
+ return LargeIconWorker::GetLargeIconRawBitmap(
+ favicon_service_, page_url, min_source_size_in_pixel,
+ desired_size_in_pixel, std::move(raw_bitmap_callback),
+ std::move(image_callback), tracker);
}
void LargeIconServiceImpl::OnCanSetOnDemandFaviconComplete(
diff --git a/chromium/components/favicon/core/large_icon_service_impl.h b/chromium/components/favicon/core/large_icon_service_impl.h
index 16c62903eed..344d858c733 100644
--- a/chromium/components/favicon/core/large_icon_service_impl.h
+++ b/chromium/components/favicon/core/large_icon_service_impl.h
@@ -6,7 +6,6 @@
#define COMPONENTS_FAVICON_CORE_LARGE_ICON_SERVICE_IMPL_H_
#include <memory>
-#include <vector>
#include "base/feature_list.h"
#include "base/macros.h"
@@ -79,11 +78,6 @@ class LargeIconServiceImpl : public LargeIconService {
// testing.
void SetServerUrlForTesting(const GURL& server_url_for_testing);
- // Extracts the organization-identifying domain from |url| which excludes
- // registrar portion (e.g. final ".com"). Used for logging UMA metrics.
- // Exposed publicly for testing.
- static std::string GetOrganizationNameForUma(const GURL& url);
-
private:
base::CancelableTaskTracker::TaskId GetLargeIconOrFallbackStyleImpl(
const GURL& page_url,
@@ -110,11 +104,6 @@ class LargeIconServiceImpl : public LargeIconService {
const std::string google_server_client_param_;
- // A pre-populated list of icon types to consider when looking for large
- // icons. This is an optimization over populating an icon type vector on each
- // request.
- std::vector<favicon_base::IconTypeSet> large_icon_types_;
-
// URL of the Google favicon server (overridable by tests).
GURL server_url_;
diff --git a/chromium/components/favicon/core/large_icon_service_impl_unittest.cc b/chromium/components/favicon/core/large_icon_service_impl_unittest.cc
index 32bfa2387ca..19b1acd1dc4 100644
--- a/chromium/components/favicon/core/large_icon_service_impl_unittest.cc
+++ b/chromium/components/favicon/core/large_icon_service_impl_unittest.cc
@@ -14,7 +14,6 @@
#include "base/task/cancelable_task_tracker.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -42,7 +41,6 @@ namespace {
using image_fetcher::MockImageFetcher;
using testing::_;
-using testing::ElementsAre;
using testing::Eq;
using testing::HasSubstr;
using testing::IsEmpty;
@@ -96,14 +94,6 @@ favicon_base::FaviconRawBitmapResult CreateTestBitmapResult(int w,
return result;
}
-favicon_base::FaviconRawBitmapResult CreateTestBitmapResultWithIconUrl(
- const GURL& icon_url) {
- favicon_base::FaviconRawBitmapResult result =
- CreateTestBitmapResult(64, 64, kTestColor);
- result.icon_url = icon_url;
- return result;
-}
-
bool HasBackgroundColor(
const favicon_base::FallbackIconStyle& fallback_icon_style,
SkColor color) {
@@ -584,96 +574,6 @@ TEST_P(LargeIconServiceGetterTest, FallbackSinceTooPicky) {
24, /*expected_count=*/1);
}
-// Tests UMA metric BlacklistedURLMismatch ignores unknown page URLs.
-TEST_P(LargeIconServiceGetterTest,
- ShouldNotRecordUrlMismatchesForUnknownPages) {
- const std::string kUmaMetricName =
- "Favicons.LargeIconService.BlacklistedURLMismatch";
- const GURL kUnknownPageUrl1("http://www.foo.com/path");
- const GURL kUnknownPageUrl2("http://www.bar.com/path");
- const GURL kUnknownPageUrl3("http://com/path");
- const GURL kUnknownIconUrl1("http://www.foo.com/favicon.ico");
- const GURL kUnknownIconUrl2("http://www.bar.com/favicon.ico");
- const GURL kUnknownIconUrl3("http://com/favicon.ico");
- const GURL kKnownIconUrl("http://www.google.com/favicon.ico");
-
- // Only URLs in the list of known organizations contribute to the histogram,
- // so neither of the sites below should be logged.
- InjectMockResult(kUnknownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kUnknownIconUrl1));
- InjectMockResult(kUnknownPageUrl3,
- CreateTestBitmapResultWithIconUrl(kUnknownIconUrl3));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kUnknownPageUrl1, 1, 0);
- GetLargeIconOrFallbackStyleAndWaitForCallback(kUnknownPageUrl3, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName), IsEmpty());
-
- // Even if there is a mismatch, it's irrelevant if none of the URLs are known.
- InjectMockResult(kUnknownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kUnknownIconUrl2));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kUnknownPageUrl1, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName), IsEmpty());
-
- // If a unknown site uses a known icon, it's still ignored.
- InjectMockResult(kUnknownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kKnownIconUrl));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kUnknownPageUrl1, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName), IsEmpty());
-}
-
-// Tests UMA metric BlacklistedURLMismatch emits records for known page URLs.
-TEST_P(LargeIconServiceGetterTest, ShouldRecordUrlMismatchesForKnownPages) {
- const std::string kUmaMetricName =
- "Favicons.LargeIconService.BlacklistedURLMismatch";
- const GURL kKnownPageUrl1("http://www.google.com/path");
- const GURL kKnownPageUrl2("http://www.youtube.com/path");
- const GURL kKnownIconUrl1("http://www.google.com/favicon.ico");
- const GURL kKnownIconUrl2("http://www.youtube.com/favicon.ico");
- const GURL kUnknownIconUrl("http://www.foo.com/favicon.ico");
-
- // Mismatch between a known organization and an unknown one should contribute
- // to bucket 0, although we're unsure if it's legit (false positives ok).
- InjectMockResult(kKnownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kUnknownIconUrl));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kKnownPageUrl1, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
-
- // Matching pairs within known organizations should contribute to bucket 0.
- InjectMockResult(kKnownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kKnownIconUrl1));
- InjectMockResult(kKnownPageUrl2,
- CreateTestBitmapResultWithIconUrl(kKnownIconUrl2));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kKnownPageUrl1, 1, 0);
- GetLargeIconOrFallbackStyleAndWaitForCallback(kKnownPageUrl2, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3)));
-
- // Mismatch between a known organization and another known one should
- // contribute to bucket 1.
- InjectMockResult(kKnownPageUrl1,
- CreateTestBitmapResultWithIconUrl(kKnownIconUrl2));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kKnownPageUrl1, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
- base::Bucket(/*min=*/1, /*count=*/1)));
-}
-
-// Tests UMA metric BlacklistedURLMismatch treats different URLs corresponding
-// to the same organization as matches.
-TEST_P(LargeIconServiceGetterTest, ShouldRecordMatchesDespiteDifferentUrls) {
- const std::string kUmaMetricName =
- "Favicons.LargeIconService.BlacklistedURLMismatch";
- const GURL kKnownPageUrl("http://www.google.de/path");
- const GURL kKnownIconUrl("http://www.google.com/favicon.ico");
-
- // Matching pairs within known organizations should contribute to bucket 0.
- InjectMockResult(kKnownPageUrl,
- CreateTestBitmapResultWithIconUrl(kKnownIconUrl));
- GetLargeIconOrFallbackStyleAndWaitForCallback(kKnownPageUrl, 1, 0);
- EXPECT_THAT(histogram_tester_.GetAllSamples(kUmaMetricName),
- ElementsAre(base::Bucket(/*min=*/0, /*count=*/1)));
-}
-
// Every test will appear with suffix /0 (param false) and /1 (param true), e.g.
// LargeIconServiceGetterTest.FallbackSinceTooPicky/0: get image.
// LargeIconServiceGetterTest.FallbackSinceTooPicky/1: get raw bitmap.
@@ -681,22 +581,5 @@ INSTANTIATE_TEST_SUITE_P(All, // Empty instatiation name.
LargeIconServiceGetterTest,
::testing::Values(false, true));
-TEST(LargeIconServiceOrganizationNameTest, ShouldGetOrganizationNameForUma) {
- EXPECT_EQ("", LargeIconServiceImpl::GetOrganizationNameForUma(GURL()));
- EXPECT_EQ("",
- LargeIconServiceImpl::GetOrganizationNameForUma(GURL("http://")));
- EXPECT_EQ("", LargeIconServiceImpl::GetOrganizationNameForUma(GURL("com")));
- EXPECT_EQ(
- "", LargeIconServiceImpl::GetOrganizationNameForUma(GURL("http://com")));
- EXPECT_EQ("", LargeIconServiceImpl::GetOrganizationNameForUma(
- GURL("http://google")));
- EXPECT_EQ("google", LargeIconServiceImpl::GetOrganizationNameForUma(
- GURL("http://google.com")));
- EXPECT_EQ("google", LargeIconServiceImpl::GetOrganizationNameForUma(
- GURL("http://google.de")));
- EXPECT_EQ("google", LargeIconServiceImpl::GetOrganizationNameForUma(
- GURL("http://foo.google.com")));
-}
-
} // namespace
} // namespace favicon
diff --git a/chromium/components/favicon/core/large_icon_worker.cc b/chromium/components/favicon/core/large_icon_worker.cc
new file mode 100644
index 00000000000..00f6fed286e
--- /dev/null
+++ b/chromium/components/favicon/core/large_icon_worker.cc
@@ -0,0 +1,197 @@
+// Copyright 2020 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/favicon/core/large_icon_worker.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/favicon/core/large_favicon_provider.h"
+#include "components/favicon_base/fallback_icon_style.h"
+#include "skia/ext/image_operations.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace favicon {
+
+namespace {
+
+bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
+ int min_source_size) {
+ return db_result.is_valid() &&
+ db_result.pixel_size.width() == db_result.pixel_size.height() &&
+ db_result.pixel_size.width() >= min_source_size;
+}
+
+// Wraps the PNG data in |db_result| in a gfx::Image. If |desired_size| is not
+// 0, the image gets decoded and resized to |desired_size| (in px). Must run on
+// a background thread in production.
+gfx::Image ResizeLargeIconOnBackgroundThread(
+ const favicon_base::FaviconRawBitmapResult& db_result,
+ int desired_size) {
+ gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
+ db_result.bitmap_data->front(), db_result.bitmap_data->size());
+
+ if (desired_size == 0 || db_result.pixel_size.width() == desired_size) {
+ return image;
+ }
+
+ SkBitmap resized = skia::ImageOperations::Resize(
+ image.AsBitmap(), skia::ImageOperations::RESIZE_LANCZOS3, desired_size,
+ desired_size);
+ return gfx::Image::CreateFrom1xBitmap(resized);
+}
+
+// Processes the |db_result| and writes the result into |raw_result| if
+// |raw_result| is not nullptr or to |bitmap|, otherwise. If |db_result| is not
+// valid or is smaller than |min_source_size|, the resulting fallback style is
+// written into |fallback_icon_style|.
+void ProcessIconOnBackgroundThread(
+ const favicon_base::FaviconRawBitmapResult& db_result,
+ int min_source_size,
+ int desired_size,
+ favicon_base::FaviconRawBitmapResult* raw_result,
+ SkBitmap* bitmap,
+ GURL* icon_url,
+ favicon_base::FallbackIconStyle* fallback_icon_style) {
+ if (IsDbResultAdequate(db_result, min_source_size)) {
+ gfx::Image image;
+ image = ResizeLargeIconOnBackgroundThread(db_result, desired_size);
+
+ if (!image.IsEmpty()) {
+ if (raw_result) {
+ *raw_result = db_result;
+ if (desired_size != 0)
+ raw_result->pixel_size = gfx::Size(desired_size, desired_size);
+ raw_result->bitmap_data = image.As1xPNGBytes();
+ }
+ if (bitmap) {
+ *bitmap = image.AsBitmap();
+ }
+ if (icon_url) {
+ *icon_url = db_result.icon_url;
+ }
+ return;
+ }
+ }
+
+ if (!fallback_icon_style)
+ return;
+
+ *fallback_icon_style = favicon_base::FallbackIconStyle();
+ int fallback_icon_size = 0;
+ if (db_result.is_valid()) {
+ favicon_base::SetDominantColorAsBackground(db_result.bitmap_data,
+ fallback_icon_style);
+ // The size must be positive, we cap to 128 to avoid the sparse histogram
+ // to explode (having too many different values, server-side). Size 128
+ // already indicates that there is a problem in the code, 128 px _should_ be
+ // enough in all current UI surfaces.
+ fallback_icon_size = db_result.pixel_size.width();
+ DCHECK_GT(fallback_icon_size, 0);
+ fallback_icon_size = std::min(fallback_icon_size, 128);
+ }
+ base::UmaHistogramSparse("Favicons.LargeIconService.FallbackSize",
+ fallback_icon_size);
+}
+
+} // namespace
+
+LargeIconWorker::LargeIconWorker(
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
+ base::CancelableTaskTracker* tracker)
+ : min_source_size_in_pixel_(min_source_size_in_pixel),
+ desired_size_in_pixel_(desired_size_in_pixel),
+ raw_bitmap_callback_(std::move(raw_bitmap_callback)),
+ image_callback_(std::move(image_callback)),
+ background_task_runner_(base::ThreadPool::CreateTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
+ tracker_(tracker),
+ fallback_icon_style_(
+ std::make_unique<favicon_base::FallbackIconStyle>()) {}
+
+LargeIconWorker::~LargeIconWorker() = default;
+
+void LargeIconWorker::OnIconLookupComplete(
+ const favicon_base::FaviconRawBitmapResult& db_result) {
+ tracker_->PostTaskAndReply(
+ background_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&ProcessIconOnBackgroundThread, db_result,
+ min_source_size_in_pixel_, desired_size_in_pixel_,
+ raw_bitmap_callback_ ? &raw_bitmap_result_ : nullptr,
+ image_callback_ ? &bitmap_result_ : nullptr,
+ image_callback_ ? &icon_url_ : nullptr,
+ fallback_icon_style_.get()),
+ base::BindOnce(&LargeIconWorker::OnIconProcessingComplete, this));
+}
+
+// static
+base::CancelableTaskTracker::TaskId LargeIconWorker::GetLargeIconRawBitmap(
+ LargeFaviconProvider* provider,
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK_LE(1, min_source_size_in_pixel);
+ DCHECK_LE(0, desired_size_in_pixel);
+
+ auto worker = base::MakeRefCounted<LargeIconWorker>(
+ min_source_size_in_pixel, desired_size_in_pixel,
+ std::move(raw_bitmap_callback), std::move(image_callback), tracker);
+
+ int max_size_in_pixel =
+ std::max(desired_size_in_pixel, min_source_size_in_pixel);
+
+ static const base::NoDestructor<std::vector<favicon_base::IconTypeSet>>
+ large_icon_types({{favicon_base::IconType::kWebManifestIcon},
+ {favicon_base::IconType::kFavicon},
+ {favicon_base::IconType::kTouchIcon},
+ {favicon_base::IconType::kTouchPrecomposedIcon}});
+
+ // TODO(beaudoin): For now this is just a wrapper around
+ // GetLargestRawFaviconForPageURL. Add the logic required to select the
+ // best possible large icon. Also add logic to fetch-on-demand when the
+ // URL of a large icon is known but its bitmap is not available.
+ return provider->GetLargestRawFaviconForPageURL(
+ page_url, *large_icon_types, max_size_in_pixel,
+ base::BindOnce(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
+}
+
+void LargeIconWorker::OnIconProcessingComplete() {
+ // If |raw_bitmap_callback_| is provided, return the raw result.
+ if (raw_bitmap_callback_) {
+ if (raw_bitmap_result_.is_valid()) {
+ std::move(raw_bitmap_callback_)
+ .Run(favicon_base::LargeIconResult(raw_bitmap_result_));
+ return;
+ }
+ std::move(raw_bitmap_callback_)
+ .Run(favicon_base::LargeIconResult(fallback_icon_style_.release()));
+ return;
+ }
+
+ if (!bitmap_result_.isNull()) {
+ std::move(image_callback_)
+ .Run(favicon_base::LargeIconImageResult(
+ gfx::Image::CreateFrom1xBitmap(bitmap_result_), icon_url_));
+ return;
+ }
+ std::move(image_callback_)
+ .Run(favicon_base::LargeIconImageResult(fallback_icon_style_.release()));
+}
+
+} // namespace favicon
diff --git a/chromium/components/favicon/core/large_icon_worker.h b/chromium/components/favicon/core/large_icon_worker.h
new file mode 100644
index 00000000000..6d65f4c6bb3
--- /dev/null
+++ b/chromium/components/favicon/core/large_icon_worker.h
@@ -0,0 +1,74 @@
+// Copyright 2020 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_FAVICON_CORE_LARGE_ICON_WORKER_H_
+#define COMPONENTS_FAVICON_CORE_LARGE_ICON_WORKER_H_
+
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "components/favicon/core/large_icon_service.h"
+#include "components/favicon_base/favicon_callback.h"
+#include "components/favicon_base/favicon_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace favicon {
+
+class LargeFaviconProvider;
+
+// Processes the png data returned from the FaviconService as part of a
+// LargeIconService request (resizing and decoding from PNG format).
+class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
+ public:
+ // Exactly one of the callbacks is expected to be non-null.
+ LargeIconWorker(int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
+ base::CancelableTaskTracker* tracker);
+ LargeIconWorker(const LargeIconWorker& worker) = delete;
+ LargeIconWorker& operator=(const LargeIconWorker& worker) = delete;
+
+ // Must run on the owner (UI) thread in production.
+ // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes
+ // ProcessIconOnBackgroundThread() so we do not perform complex image
+ // operations on the UI thread.
+ void OnIconLookupComplete(
+ const favicon_base::FaviconRawBitmapResult& db_result);
+
+ static base::CancelableTaskTracker::TaskId GetLargeIconRawBitmap(
+ LargeFaviconProvider* provider,
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ favicon_base::LargeIconCallback raw_bitmap_callback,
+ favicon_base::LargeIconImageCallback image_callback,
+ base::CancelableTaskTracker* tracker);
+
+ private:
+ friend class base::RefCountedThreadSafe<LargeIconWorker>;
+
+ ~LargeIconWorker();
+
+ // Must run on the owner (UI) thread in production.
+ // Invoked when ProcessIconOnBackgroundThread() is done.
+ void OnIconProcessingComplete();
+
+ int min_source_size_in_pixel_;
+ int desired_size_in_pixel_;
+ favicon_base::LargeIconCallback raw_bitmap_callback_;
+ favicon_base::LargeIconImageCallback image_callback_;
+ scoped_refptr<base::TaskRunner> background_task_runner_;
+ base::CancelableTaskTracker* tracker_;
+
+ favicon_base::FaviconRawBitmapResult raw_bitmap_result_;
+ SkBitmap bitmap_result_;
+ GURL icon_url_;
+ std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style_;
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CORE_LARGE_ICON_WORKER_H_
diff --git a/chromium/components/favicon_base/favicon_types.h b/chromium/components/favicon_base/favicon_types.h
index fa1d53c1147..93ac1fdde59 100644
--- a/chromium/components/favicon_base/favicon_types.h
+++ b/chromium/components/favicon_base/favicon_types.h
@@ -32,7 +32,7 @@ using FaviconID = int64_t;
// data is returned.
//
// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ui.favicon
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.favicon
enum class IconType {
kInvalid = 0,
kFavicon,
diff --git a/chromium/components/favicon_base/favicon_util.cc b/chromium/components/favicon_base/favicon_util.cc
index 44f90a73541..2458d92db77 100644
--- a/chromium/components/favicon_base/favicon_util.cc
+++ b/chromium/components/favicon_base/favicon_util.cc
@@ -127,7 +127,7 @@ SkBitmap ResizeBitmapByDownsamplingIfPossible(
if (!best_bitmap.isOpaque())
bitmap.eraseARGB(0, 0, 0, 0);
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.drawBitmapRect(best_bitmap,
SkRect::MakeIWH(desired_size, desired_size), nullptr);
return bitmap;
diff --git a/chromium/components/favicon_base/select_favicon_frames.cc b/chromium/components/favicon_base/select_favicon_frames.cc
index 90b58e62149..6694ddd6f95 100644
--- a/chromium/components/favicon_base/select_favicon_frames.cc
+++ b/chromium/components/favicon_base/select_favicon_frames.cc
@@ -43,7 +43,7 @@ SkBitmap SampleNearestNeighbor(const SkBitmap& contents, int desired_size) {
bitmap.eraseARGB(0, 0, 0, 0);
{
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.drawBitmapRect(contents, SkRect::MakeIWH(desired_size, desired_size),
nullptr);
}
diff --git a/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
index adf3ee4f567..6416a7eebc5 100644
--- a/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
@@ -13,6 +13,7 @@
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "components/feature_engagement/internal/jni_headers/TrackerImpl_jni.h"
@@ -35,13 +36,13 @@ TrackerImplAndroid::FeatureMap CreateMapFromNameToFeature(
return feature_map;
}
-TrackerImplAndroid* FromTrackerImpl(Tracker* feature_engagement) {
- TrackerImpl* impl = static_cast<TrackerImpl*>(feature_engagement);
+TrackerImplAndroid* FromTracker(Tracker* tracker) {
TrackerImplAndroid* impl_android = static_cast<TrackerImplAndroid*>(
- impl->GetUserData(kTrackerImplAndroidKey));
+ tracker->GetUserData(kTrackerImplAndroidKey));
if (!impl_android) {
- impl_android = new TrackerImplAndroid(impl, GetAllFeatures());
- impl->SetUserData(kTrackerImplAndroidKey, base::WrapUnique(impl_android));
+ impl_android = new TrackerImplAndroid(tracker, GetAllFeatures());
+ tracker->SetUserData(kTrackerImplAndroidKey,
+ base::WrapUnique(impl_android));
}
return impl_android;
}
@@ -61,13 +62,11 @@ TrackerImplAndroid* TrackerImplAndroid::FromJavaObject(
// static
base::android::ScopedJavaLocalRef<jobject> Tracker::GetJavaObject(
Tracker* feature_engagement) {
- return FromTrackerImpl(feature_engagement)->GetJavaObject();
+ return FromTracker(feature_engagement)->GetJavaObject();
}
-TrackerImplAndroid::TrackerImplAndroid(TrackerImpl* tracker_impl,
- FeatureVector features)
- : features_(CreateMapFromNameToFeature(features)),
- tracker_impl_(tracker_impl) {
+TrackerImplAndroid::TrackerImplAndroid(Tracker* tracker, FeatureVector features)
+ : features_(CreateMapFromNameToFeature(features)), tracker_(tracker) {
JNIEnv* env = base::android::AttachCurrentThread();
java_obj_.Reset(
@@ -89,7 +88,7 @@ void TrackerImplAndroid::NotifyEvent(
const base::android::JavaRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jevent) {
std::string event = ConvertJavaStringToUTF8(env, jevent);
- tracker_impl_->NotifyEvent(event);
+ tracker_->NotifyEvent(event);
}
bool TrackerImplAndroid::ShouldTriggerHelpUI(
@@ -99,7 +98,7 @@ bool TrackerImplAndroid::ShouldTriggerHelpUI(
std::string feature = ConvertJavaStringToUTF8(env, jfeature);
DCHECK(features_.find(feature) != features_.end());
- return tracker_impl_->ShouldTriggerHelpUI(*features_[feature]);
+ return tracker_->ShouldTriggerHelpUI(*features_[feature]);
}
bool TrackerImplAndroid::WouldTriggerHelpUI(
@@ -109,7 +108,7 @@ bool TrackerImplAndroid::WouldTriggerHelpUI(
std::string feature = ConvertJavaStringToUTF8(env, jfeature);
DCHECK(features_.find(feature) != features_.end());
- return tracker_impl_->WouldTriggerHelpUI(*features_[feature]);
+ return tracker_->WouldTriggerHelpUI(*features_[feature]);
}
bool TrackerImplAndroid::HasEverTriggered(
@@ -120,7 +119,7 @@ bool TrackerImplAndroid::HasEverTriggered(
std::string feature = ConvertJavaStringToUTF8(env, jfeature);
DCHECK(features_.find(feature) != features_.end());
- return tracker_impl_->HasEverTriggered(*features_[feature], j_from_window);
+ return tracker_->HasEverTriggered(*features_[feature], j_from_window);
}
jint TrackerImplAndroid::GetTriggerState(
@@ -130,7 +129,7 @@ jint TrackerImplAndroid::GetTriggerState(
std::string feature = ConvertJavaStringToUTF8(env, jfeature);
DCHECK(features_.find(feature) != features_.end());
- return static_cast<int>(tracker_impl_->GetTriggerState(*features_[feature]));
+ return static_cast<int>(tracker_->GetTriggerState(*features_[feature]));
}
void TrackerImplAndroid::Dismissed(
@@ -140,7 +139,7 @@ void TrackerImplAndroid::Dismissed(
std::string feature = ConvertJavaStringToUTF8(env, jfeature);
DCHECK(features_.find(feature) != features_.end());
- tracker_impl_->Dismissed(*features_[feature]);
+ tracker_->Dismissed(*features_[feature]);
}
base::android::ScopedJavaLocalRef<jobject>
@@ -148,7 +147,7 @@ TrackerImplAndroid::AcquireDisplayLock(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj) {
std::unique_ptr<DisplayLockHandle> lock_handle =
- tracker_impl_->AcquireDisplayLock();
+ tracker_->AcquireDisplayLock();
if (!lock_handle)
return nullptr;
@@ -163,14 +162,14 @@ TrackerImplAndroid::AcquireDisplayLock(
bool TrackerImplAndroid::IsInitialized(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj) {
- return tracker_impl_->IsInitialized();
+ return tracker_->IsInitialized();
}
void TrackerImplAndroid::AddOnInitializedCallback(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj,
const base::android::JavaParamRef<jobject>& j_callback_obj) {
- tracker_impl_->AddOnInitializedCallback(base::BindOnce(
+ tracker_->AddOnInitializedCallback(base::BindOnce(
&base::android::RunBooleanCallbackAndroid,
base::android::ScopedJavaGlobalRef<jobject>(j_callback_obj)));
}
diff --git a/chromium/components/feature_engagement/internal/android/tracker_impl_android.h b/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
index 7a028314cc7..41ad55ed3ff 100644
--- a/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
@@ -61,12 +61,12 @@ class TrackerImplAndroid : public base::SupportsUserData::Data {
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj);
- TrackerImplAndroid(TrackerImpl* tracker_impl, FeatureVector features);
+ TrackerImplAndroid(Tracker* tracker, FeatureVector features);
~TrackerImplAndroid() override;
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
- TrackerImpl* tracker_impl() { return tracker_impl_; }
+ Tracker* tracker() { return tracker_; }
// Tracker JNI bridge implementation.
virtual void NotifyEvent(JNIEnv* env,
@@ -108,8 +108,8 @@ class TrackerImplAndroid : public base::SupportsUserData::Data {
// class as well, we should remove this mapping.
FeatureMap features_;
- // The TrackerImpl this is a JNI bridge for.
- TrackerImpl* tracker_impl_;
+ // The Tracker this is a JNI bridge for.
+ Tracker* tracker_;
// The Java-side of this JNI bridge.
base::android::ScopedJavaGlobalRef<jobject> java_obj_;
diff --git a/chromium/components/feature_engagement/internal/tracker_impl.cc b/chromium/components/feature_engagement/internal/tracker_impl.cc
index 763bd31f631..5c383914707 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl.cc
@@ -8,12 +8,14 @@
#include <utility>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/user_metrics.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "components/feature_engagement/internal/availability_model_impl.h"
#include "components/feature_engagement/internal/chrome_variations_configuration.h"
#include "components/feature_engagement/internal/display_lock_controller_impl.h"
diff --git a/chromium/components/feature_engagement/internal/tracker_impl.h b/chromium/components/feature_engagement/internal/tracker_impl.h
index 016301868f0..83218427014 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl.h
+++ b/chromium/components/feature_engagement/internal/tracker_impl.h
@@ -12,7 +12,6 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/supports_user_data.h"
#include "components/feature_engagement/public/tracker.h"
namespace feature_engagement {
@@ -25,7 +24,7 @@ class EventModel;
class TimeProvider;
// The internal implementation of the Tracker.
-class TrackerImpl : public Tracker, public base::SupportsUserData {
+class TrackerImpl : public Tracker {
public:
TrackerImpl(std::unique_ptr<EventModel> event_model,
std::unique_ptr<AvailabilityModel> availability_model,
diff --git a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
index 4b43ade6f1a..ec839093dec 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
@@ -9,7 +9,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/components/feature_engagement/public/BUILD.gn b/chromium/components/feature_engagement/public/BUILD.gn
index 090e85188ef..1165356f5e2 100644
--- a/chromium/components/feature_engagement/public/BUILD.gn
+++ b/chromium/components/feature_engagement/public/BUILD.gn
@@ -28,6 +28,15 @@ source_set("public") {
"//components/flags_ui",
"//components/keyed_service/core",
]
+
+ if (is_android) {
+ sources += [
+ "android/wrapping_test_tracker.cc",
+ "android/wrapping_test_tracker.h",
+ ]
+
+ deps += [ "//components/feature_engagement/public:jni_headers" ]
+ }
}
source_set("unit_tests") {
@@ -48,15 +57,18 @@ source_set("unit_tests") {
if (is_android) {
android_library("public_java") {
sources = [
+ "android/java/src/org/chromium/components/feature_engagement/CppWrappedTestTracker.java",
"android/java/src/org/chromium/components/feature_engagement/EventConstants.java",
"android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java",
"android/java/src/org/chromium/components/feature_engagement/Tracker.java",
]
deps = [
+ ":jni_headers",
"//base:base_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
srcjar_deps = [ ":public_java_enums_srcjar" ]
}
@@ -66,4 +78,8 @@ if (is_android) {
sources = [ "tracker.h" ]
}
+
+ generate_jni("jni_headers") {
+ sources = [ "android/java/src/org/chromium/components/feature_engagement/CppWrappedTestTracker.java" ]
+ }
}
diff --git a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc
new file mode 100644
index 00000000000..2ba4bf8db42
--- /dev/null
+++ b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc
@@ -0,0 +1,89 @@
+// Copyright 2020 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/feature_engagement/public/android/wrapping_test_tracker.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/android/jni_string.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/feature_engagement/public/jni_headers/CppWrappedTestTracker_jni.h"
+
+namespace feature_engagement {
+
+WrappingTestTracker::WrappingTestTracker(
+ const base::android::JavaRef<jobject>& jtracker)
+ : java_tracker_(jtracker) {}
+WrappingTestTracker::~WrappingTestTracker() {}
+
+void WrappingTestTracker::NotifyEvent(const std::string& event) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jevent(
+ base::android::ConvertUTF8ToJavaString(env, event.c_str()));
+ Java_CppWrappedTestTracker_notifyEvent(base::android::AttachCurrentThread(),
+ java_tracker_, jevent);
+}
+
+bool WrappingTestTracker::ShouldTriggerHelpUI(const base::Feature& feature) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jfeature(
+ base::android::ConvertUTF8ToJavaString(env, feature.name));
+ return Java_CppWrappedTestTracker_shouldTriggerHelpUI(
+ base::android::AttachCurrentThread(), java_tracker_, jfeature);
+}
+
+bool WrappingTestTracker::WouldTriggerHelpUI(
+ const base::Feature& feature) const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jfeature(
+ base::android::ConvertUTF8ToJavaString(env, feature.name));
+ return Java_CppWrappedTestTracker_wouldTriggerHelpUI(
+ base::android::AttachCurrentThread(), java_tracker_, jfeature);
+}
+
+bool WrappingTestTracker::HasEverTriggered(const base::Feature& feature,
+ bool from_window) const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jfeature(
+ base::android::ConvertUTF8ToJavaString(env, feature.name));
+ return Java_CppWrappedTestTracker_hasEverTriggered(
+ base::android::AttachCurrentThread(), java_tracker_, jfeature,
+ from_window);
+}
+
+Tracker::TriggerState WrappingTestTracker::GetTriggerState(
+ const base::Feature& feature) const {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jfeature(
+ base::android::ConvertUTF8ToJavaString(env, feature.name));
+ return static_cast<Tracker::TriggerState>(
+ Java_CppWrappedTestTracker_getTriggerState(
+ base::android::AttachCurrentThread(), java_tracker_, jfeature));
+}
+
+void WrappingTestTracker::Dismissed(const base::Feature& feature) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jfeature(
+ base::android::ConvertUTF8ToJavaString(env, feature.name));
+ Java_CppWrappedTestTracker_dismissed(base::android::AttachCurrentThread(),
+ java_tracker_, jfeature);
+}
+
+std::unique_ptr<DisplayLockHandle> WrappingTestTracker::AcquireDisplayLock() {
+ return nullptr;
+}
+
+bool WrappingTestTracker::IsInitialized() const {
+ return Java_CppWrappedTestTracker_isInitialized(
+ base::android::AttachCurrentThread(), java_tracker_);
+}
+
+void WrappingTestTracker::AddOnInitializedCallback(
+ OnInitializedCallback callback) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), IsInitialized()));
+}
+
+} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h
new file mode 100644
index 00000000000..1fb51465920
--- /dev/null
+++ b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h
@@ -0,0 +1,44 @@
+// Copyright 2020 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_FEATURE_ENGAGEMENT_PUBLIC_ANDROID_WRAPPING_TEST_TRACKER_H_
+#define COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_ANDROID_WRAPPING_TEST_TRACKER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/feature_engagement/public/tracker.h"
+
+namespace feature_engagement {
+// This class wraps a Tracker from Java and forwards to it all calls received.
+class WrappingTestTracker : public Tracker {
+ public:
+ explicit WrappingTestTracker(const base::android::JavaRef<jobject>& jtracker);
+ ~WrappingTestTracker() override;
+
+ // TrackerImpl:
+
+ void NotifyEvent(const std::string& event) override;
+ bool ShouldTriggerHelpUI(const base::Feature& feature) override;
+ bool WouldTriggerHelpUI(const base::Feature& feature) const override;
+ bool HasEverTriggered(const base::Feature& feature,
+ bool from_window) const override;
+ TriggerState GetTriggerState(const base::Feature& feature) const override;
+ void Dismissed(const base::Feature& feature) override;
+ std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() override;
+ bool IsInitialized() const override;
+ void AddOnInitializedCallback(OnInitializedCallback callback) override;
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> java_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(WrappingTestTracker);
+};
+
+} // namespace feature_engagement
+
+#endif // COMPONENTS_FEATURE_ENGAGEMENT_PUBLIC_ANDROID_WRAPPING_TEST_TRACKER_H_
diff --git a/chromium/components/feature_engagement/public/event_constants.cc b/chromium/components/feature_engagement/public/event_constants.cc
index 01ef02ba89b..dff395e0d98 100644
--- a/chromium/components/feature_engagement/public/event_constants.cc
+++ b/chromium/components/feature_engagement/public/event_constants.cc
@@ -32,6 +32,8 @@ const char kFocusModeConditionsMet[] = "focus_mode_conditions_met";
const char kWebUITabStripClosed[] = "webui_tab_strip_closed";
const char kWebUITabStripOpened[] = "webui_tab_strip_opened";
+
+const char kDesktopPwaInstalled[] = "desktop_pwa_installed";
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
@@ -45,6 +47,10 @@ const char kBottomToolbarOpened[] = "bottom_toolbar_opened";
const char kDiscoverFeedLoaded[] = "discover_feed_loaded";
#endif // defined(OS_IOS)
+#if defined(OS_ANDROID)
+const char kPwaInstallMenuSelected[] = "pwa_install_menu_clicked";
+#endif // defined(OS_ANDROID)
+
} // namespace events
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/public/event_constants.h b/chromium/components/feature_engagement/public/event_constants.h
index 433e25fe356..967bdff5149 100644
--- a/chromium/components/feature_engagement/public/event_constants.h
+++ b/chromium/components/feature_engagement/public/event_constants.h
@@ -54,6 +54,9 @@ extern const char kWebUITabStripClosed[];
// The WebUI tab strip was opened by the user.
extern const char kWebUITabStripOpened[];
+// The PWA was installed by the user.
+extern const char kDesktopPwaInstalled[];
+
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
@@ -80,6 +83,12 @@ extern const char kBottomToolbarOpened[];
extern const char kDiscoverFeedLoaded[];
#endif // defined(OS_IOS)
+// Android.
+#if defined(OS_ANDROID)
+// The user has explicitly used the Install menu item under the App Menu.
+extern const char kPwaInstallMenuSelected[];
+#endif // defined(OS_ANDROID)
+
} // namespace events
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/public/feature_constants.cc b/chromium/components/feature_engagement/public/feature_constants.cc
index 952866f3f63..9050024b720 100644
--- a/chromium/components/feature_engagement/public/feature_constants.cc
+++ b/chromium/components/feature_engagement/public/feature_constants.cc
@@ -30,6 +30,8 @@ const base::Feature kIPHWebUITabStripFeature{"IPH_WebUITabStrip",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHDesktopSnoozeFeature{"IPH_DesktopSnoozeFeature",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHDesktopPwaInstallFeature{
+ "IPH_DesktopPwaInstall", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
@@ -73,6 +75,12 @@ const base::Feature kIPHDownloadInfoBarDownloadsAreFasterFeature{
"IPH_DownloadInfoBarDownloadsAreFaster", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHQuietNotificationPromptsFeature{
"IPH_QuietNotificationPrompts", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHReadLaterContextMenuFeature{
+ "IPH_ReadLaterContextMenu", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHReadLaterAppMenuBookmarkThisPageFeature{
+ "IPH_ReadLaterAppMenuBookmarkThisPage", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHReadLaterAppMenuBookmarksFeature{
+ "IPH_ReadLaterAppMenuBookmarks", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHEphemeralTabFeature{"IPH_EphemeralTab",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHFeedCardMenuFeature{"IPH_FeedCardMenu",
@@ -89,6 +97,8 @@ const base::Feature kIPHKeyboardAccessoryPasswordFillingFeature{
"IPH_KeyboardAccessoryPasswordFilling", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHKeyboardAccessoryPaymentFillingFeature{
"IPH_KeyboardAccessoryPaymentFilling", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHNewTabPageHomeButtonFeature{
+ "IPH_NewTabPageHomeButton", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHPreviewsOmniboxUIFeature{
"IPH_PreviewsOmniboxUI", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHTabGroupsQuicklyComparePagesFeature{
@@ -99,12 +109,20 @@ const base::Feature kIPHTabGroupsYourTabsAreTogetherFeature{
"IPH_TabGroupsYourTabsTogether", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHTabGroupsDragAndDropFeature{
"IPH_TabGroupsDragAndDrop", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHTabSwitcherButtonFeature{
+ "IPH_TabSwitcherButton", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHTranslateMenuButtonFeature{
"IPH_TranslateMenuButton", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kIPHVideoTutorialDownloadFeature{
- "IPH_VideoTutorial_Download", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kIPHVideoTutorialSearchFeature{
- "IPH_VideoTutorial_Search", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHVideoTutorialNTPChromeIntroFeature{
+ "IPH_VideoTutorial_NTP_ChromeIntro", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHVideoTutorialNTPDownloadFeature{
+ "IPH_VideoTutorial_NTP_Download", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHVideoTutorialNTPSearchFeature{
+ "IPH_VideoTutorial_NTP_Search", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHVideoTutorialNTPVoiceSearchFeature{
+ "IPH_VideoTutorial_NTP_VoiceSearch", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHVideoTutorialNTPSummaryFeature{
+ "IPH_VideoTutorial_NTP_Summary", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHExploreSitesTileFeature{
"IPH_ExploreSitesTile", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHFeedHeaderMenuFeature{
@@ -115,6 +133,8 @@ const base::Feature kIPHChromeReengagementNotification2Feature{
"IPH_ChromeReengagementNotification2", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHChromeReengagementNotification3Feature{
"IPH_ChromeReengagementNotification3", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHPwaInstallAvailableFeature{
+ "IPH_PwaInstallAvailable", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)
diff --git a/chromium/components/feature_engagement/public/feature_constants.h b/chromium/components/feature_engagement/public/feature_constants.h
index cb86cccde1e..139b5dc701b 100644
--- a/chromium/components/feature_engagement/public/feature_constants.h
+++ b/chromium/components/feature_engagement/public/feature_constants.h
@@ -26,6 +26,7 @@ extern const base::Feature kIPHPasswordsAccountStorageFeature;
extern const base::Feature kIPHReopenTabFeature;
extern const base::Feature kIPHWebUITabStripFeature;
extern const base::Feature kIPHDesktopSnoozeFeature;
+extern const base::Feature kIPHDesktopPwaInstallFeature;
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
@@ -61,21 +62,29 @@ extern const base::Feature kIPHKeyboardAccessoryAddressFillingFeature;
extern const base::Feature kIPHKeyboardAccessoryBarSwipingFeature;
extern const base::Feature kIPHKeyboardAccessoryPasswordFillingFeature;
extern const base::Feature kIPHKeyboardAccessoryPaymentFillingFeature;
-extern const base::Feature kIPHNewTabPageButtonFeature;
+extern const base::Feature kIPHNewTabPageHomeButtonFeature;
extern const base::Feature kIPHPreviewsOmniboxUIFeature;
extern const base::Feature kIPHQuietNotificationPromptsFeature;
+extern const base::Feature kIPHReadLaterContextMenuFeature;
+extern const base::Feature kIPHReadLaterAppMenuBookmarkThisPageFeature;
+extern const base::Feature kIPHReadLaterAppMenuBookmarksFeature;
extern const base::Feature kIPHTabGroupsQuicklyComparePagesFeature;
extern const base::Feature kIPHTabGroupsTapToSeeAnotherTabFeature;
extern const base::Feature kIPHTabGroupsYourTabsAreTogetherFeature;
extern const base::Feature kIPHTabGroupsDragAndDropFeature;
+extern const base::Feature kIPHTabSwitcherButtonFeature;
extern const base::Feature kIPHTranslateMenuButtonFeature;
-extern const base::Feature kIPHVideoTutorialDownloadFeature;
-extern const base::Feature kIPHVideoTutorialSearchFeature;
+extern const base::Feature kIPHVideoTutorialNTPChromeIntroFeature;
+extern const base::Feature kIPHVideoTutorialNTPDownloadFeature;
+extern const base::Feature kIPHVideoTutorialNTPSearchFeature;
+extern const base::Feature kIPHVideoTutorialNTPVoiceSearchFeature;
+extern const base::Feature kIPHVideoTutorialNTPSummaryFeature;
extern const base::Feature kIPHExploreSitesTileFeature;
extern const base::Feature kIPHFeedHeaderMenuFeature;
extern const base::Feature kIPHChromeReengagementNotification1Feature;
extern const base::Feature kIPHChromeReengagementNotification2Feature;
extern const base::Feature kIPHChromeReengagementNotification3Feature;
+extern const base::Feature kIPHPwaInstallAvailableFeature;
#endif // defined(OS_ANDROID)
#if defined(OS_IOS)
diff --git a/chromium/components/feature_engagement/public/feature_list.cc b/chromium/components/feature_engagement/public/feature_list.cc
index 988b29bacd1..5580aeb3966 100644
--- a/chromium/components/feature_engagement/public/feature_list.cc
+++ b/chromium/components/feature_engagement/public/feature_list.cc
@@ -45,15 +45,24 @@ const base::Feature* const kAllFeatures[] = {
&kIPHKeyboardAccessoryBarSwipingFeature,
&kIPHKeyboardAccessoryPasswordFillingFeature,
&kIPHKeyboardAccessoryPaymentFillingFeature,
+ &kIPHNewTabPageHomeButtonFeature,
&kIPHPreviewsOmniboxUIFeature,
+ &kIPHPwaInstallAvailableFeature,
&kIPHQuietNotificationPromptsFeature,
+ &kIPHReadLaterContextMenuFeature,
+ &kIPHReadLaterAppMenuBookmarkThisPageFeature,
+ &kIPHReadLaterAppMenuBookmarksFeature,
&kIPHTabGroupsQuicklyComparePagesFeature,
&kIPHTabGroupsTapToSeeAnotherTabFeature,
&kIPHTabGroupsYourTabsAreTogetherFeature,
&kIPHTabGroupsDragAndDropFeature,
+ &kIPHTabSwitcherButtonFeature,
&kIPHTranslateMenuButtonFeature,
- &kIPHVideoTutorialDownloadFeature,
- &kIPHVideoTutorialSearchFeature,
+ &kIPHVideoTutorialNTPChromeIntroFeature,
+ &kIPHVideoTutorialNTPDownloadFeature,
+ &kIPHVideoTutorialNTPSearchFeature,
+ &kIPHVideoTutorialNTPVoiceSearchFeature,
+ &kIPHVideoTutorialNTPSummaryFeature,
&kIPHExploreSitesTileFeature,
&kIPHFeedHeaderMenuFeature,
#endif // defined(OS_ANDROID)
@@ -75,6 +84,7 @@ const base::Feature* const kAllFeatures[] = {
&kIPHPasswordsAccountStorageFeature,
&kIPHReopenTabFeature,
&kIPHWebUITabStripFeature,
+ &kIPHDesktopPwaInstallFeature,
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
};
diff --git a/chromium/components/feature_engagement/public/feature_list.h b/chromium/components/feature_engagement/public/feature_list.h
index 9ab05a75ae0..bc3e77f94be 100644
--- a/chromium/components/feature_engagement/public/feature_list.h
+++ b/chromium/components/feature_engagement/public/feature_list.h
@@ -93,9 +93,18 @@ DEFINE_VARIATION_PARAM(kIPHKeyboardAccessoryPasswordFillingFeature,
"IPH_KeyboardAccessoryPasswordFilling");
DEFINE_VARIATION_PARAM(kIPHKeyboardAccessoryPaymentFillingFeature,
"IPH_KeyboardAccessoryPaymentFilling");
+DEFINE_VARIATION_PARAM(kIPHNewTabPageButtonFeature, "IPH_NewTabPageHomeButton");
DEFINE_VARIATION_PARAM(kIPHPreviewsOmniboxUIFeature, "IPH_PreviewsOmniboxUI");
+DEFINE_VARIATION_PARAM(kIPHPwaInstallAvailableFeature,
+ "IPH_PwaInstallAvailableFeature");
DEFINE_VARIATION_PARAM(kIPHQuietNotificationPromptsFeature,
"IPH_QuietNotificationPrompts");
+DEFINE_VARIATION_PARAM(kIPHReadLaterContextMenuFeature,
+ "IPH_ReadLaterContextMenu");
+DEFINE_VARIATION_PARAM(kIPHReadLaterAppMenuBookmarkThisPageFeature,
+ "IPH_ReadLaterAppMenuBookmarkThisPage");
+DEFINE_VARIATION_PARAM(kIPHReadLaterAppMenuBookmarksFeature,
+ "IPH_ReadLaterAppMenuBookmarks");
DEFINE_VARIATION_PARAM(kIPHTabGroupsQuicklyComparePagesFeature,
"IPH_TabGroupsQuicklyComparePages");
DEFINE_VARIATION_PARAM(kIPHTabGroupsTapToSeeAnotherTabFeature,
@@ -104,12 +113,19 @@ DEFINE_VARIATION_PARAM(kIPHTabGroupsYourTabsAreTogetherFeature,
"IPH_TabGroupsYourTabsTogether");
DEFINE_VARIATION_PARAM(kIPHTabGroupsDragAndDropFeature,
"IPH_TabGroupsDragAndDrop");
+DEFINE_VARIATION_PARAM(kIPHTabSwitcherButtonFeature, "IPH_TabSwitcherButton");
DEFINE_VARIATION_PARAM(kIPHTranslateMenuButtonFeature,
"IPH_TranslateMenuButton");
-DEFINE_VARIATION_PARAM(kIPHVideoTutorialDownloadFeature,
- "IPH_VideoTutorial_Download");
-DEFINE_VARIATION_PARAM(kIPHVideoTutorialSearchFeature,
- "IPH_VideoTutorial_Search");
+DEFINE_VARIATION_PARAM(kIPHVideoTutorialNTPChromeIntroFeature,
+ "IPH_VideoTutorial_NTP_ChromeIntro");
+DEFINE_VARIATION_PARAM(kIPHVideoTutorialNTPDownloadFeature,
+ "IPH_VideoTutorial_NTP_Download");
+DEFINE_VARIATION_PARAM(kIPHVideoTutorialNTPSearchFeature,
+ "IPH_VideoTutorial_NTP_Search");
+DEFINE_VARIATION_PARAM(kIPHVideoTutorialNTPVoiceSearchFeature,
+ "IPH_VideoTutorial_NTP_VoiceSearch");
+DEFINE_VARIATION_PARAM(kIPHVideoTutorialNTPSummaryFeature,
+ "IPH_VideoTutorial_NTP_Summary");
DEFINE_VARIATION_PARAM(kIPHExploreSitesTileFeature, "IPH_ExploreSitesTile");
DEFINE_VARIATION_PARAM(kIPHFeedHeaderMenuFeature, "IPH_FeedHeaderMenu");
#endif // defined(OS_ANDROID)
@@ -137,6 +153,7 @@ DEFINE_VARIATION_PARAM(kIPHPasswordsAccountStorageFeature,
"IPH_PasswordsAccountStorage");
DEFINE_VARIATION_PARAM(kIPHReopenTabFeature, "IPH_ReopenTab");
DEFINE_VARIATION_PARAM(kIPHWebUITabStripFeature, "IPH_WebUITabStrip");
+DEFINE_VARIATION_PARAM(kIPHDesktopPwaInstallFeature, "IPH_DesktopPwaInstall");
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
@@ -177,15 +194,24 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHKeyboardAccessoryBarSwipingFeature),
VARIATION_ENTRY(kIPHKeyboardAccessoryPasswordFillingFeature),
VARIATION_ENTRY(kIPHKeyboardAccessoryPaymentFillingFeature),
+ VARIATION_ENTRY(kIPHNewTabPageButtonFeature),
VARIATION_ENTRY(kIPHPreviewsOmniboxUIFeature),
+ VARIATION_ENTRY(kIPHPwaInstallAvailableFeature),
VARIATION_ENTRY(kIPHQuietNotificationPromptsFeature),
+ VARIATION_ENTRY(kIPHReadLaterContextMenuFeature),
+ VARIATION_ENTRY(kIPHReadLaterAppMenuBookmarkThisPageFeature),
+ VARIATION_ENTRY(kIPHReadLaterAppMenuBookmarksFeature),
VARIATION_ENTRY(kIPHTabGroupsQuicklyComparePagesFeature),
VARIATION_ENTRY(kIPHTabGroupsTapToSeeAnotherTabFeature),
VARIATION_ENTRY(kIPHTabGroupsYourTabsAreTogetherFeature),
VARIATION_ENTRY(kIPHTabGroupsDragAndDropFeature),
+ VARIATION_ENTRY(kIPHTabSwitcherButtonFeature),
VARIATION_ENTRY(kIPHTranslateMenuButtonFeature),
- VARIATION_ENTRY(kIPHVideoTutorialDownloadFeature),
- VARIATION_ENTRY(kIPHVideoTutorialSearchFeature),
+ VARIATION_ENTRY(kIPHVideoTutorialNTPChromeIntroFeature),
+ VARIATION_ENTRY(kIPHVideoTutorialNTPDownloadFeature),
+ VARIATION_ENTRY(kIPHVideoTutorialNTPSearchFeature),
+ VARIATION_ENTRY(kIPHVideoTutorialNTPVoiceSearchFeature),
+ VARIATION_ENTRY(kIPHVideoTutorialNTPSummaryFeature),
VARIATION_ENTRY(kIPHExploreSitesTileFeature),
VARIATION_ENTRY(kIPHFeedHeaderMenuFeature),
#elif defined(OS_IOS)
@@ -205,6 +231,7 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHPasswordsAccountStorageFeature),
VARIATION_ENTRY(kIPHReopenTabFeature),
VARIATION_ENTRY(kIPHWebUITabStripFeature),
+ VARIATION_ENTRY(kIPHDesktopPwaInstallFeature),
#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)
};
diff --git a/chromium/components/feature_engagement/public/tracker.h b/chromium/components/feature_engagement/public/tracker.h
index 83b6c0f92ea..3fa02b8d0eb 100644
--- a/chromium/components/feature_engagement/public/tracker.h
+++ b/chromium/components/feature_engagement/public/tracker.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "base/supports_user_data.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -47,7 +48,7 @@ class DisplayLockHandle {
// input about user behavior. Whenever the frontend gives a trigger signal that
// IPH could be displayed, the backend will provide an answer to whether it is
// appropriate to show it or not.
-class Tracker : public KeyedService {
+class Tracker : public KeyedService, public base::SupportsUserData {
public:
// Describes the state of whether in-product helps has already been displayed
// enough times or not within the bounds of the configuration for a
diff --git a/chromium/components/federated_learning/BUILD.gn b/chromium/components/federated_learning/BUILD.gn
index c87dc270e4f..6ea6732aafb 100644
--- a/chromium/components/federated_learning/BUILD.gn
+++ b/chromium/components/federated_learning/BUILD.gn
@@ -4,8 +4,6 @@
static_library("federated_learning") {
sources = [
- "floc_blocklist_service.cc",
- "floc_blocklist_service.h",
"floc_constants.cc",
"floc_constants.h",
"floc_id.cc",
@@ -16,10 +14,7 @@ static_library("federated_learning") {
"sim_hash.h",
]
- public_deps = [
- "//components/federated_learning/proto:federated_learning",
- "//third_party/protobuf:protobuf_lite",
- ]
+ public_deps = [ "//third_party/protobuf:protobuf_lite" ]
deps = [ "//base" ]
}
@@ -27,7 +22,7 @@ static_library("federated_learning") {
source_set("unit_tests") {
testonly = true
sources = [
- "floc_blocklist_service_unittest.cc",
+ "floc_id_unittest.cc",
"floc_sorting_lsh_clusters_service_unittest.cc",
"sim_hash_unittest.cc",
]
diff --git a/chromium/components/federated_learning/floc_blocklist_service.cc b/chromium/components/federated_learning/floc_blocklist_service.cc
deleted file mode 100644
index ffd98e78471..00000000000
--- a/chromium/components/federated_learning/floc_blocklist_service.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2020 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/federated_learning/floc_blocklist_service.h"
-
-#include <utility>
-
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/task/post_task.h"
-#include "base/task_runner_util.h"
-#include "components/federated_learning/floc_constants.h"
-#include "components/federated_learning/proto/blocklist.pb.h"
-#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-namespace federated_learning {
-
-namespace {
-
-class CopyingFileInputStream : public google::protobuf::io::CopyingInputStream {
- public:
- explicit CopyingFileInputStream(base::File file) : file_(std::move(file)) {}
-
- CopyingFileInputStream(const CopyingFileInputStream&) = delete;
- CopyingFileInputStream& operator=(const CopyingFileInputStream&) = delete;
-
- ~CopyingFileInputStream() override = default;
-
- // google::protobuf::io::CopyingInputStream:
- int Read(void* buffer, int size) override {
- return file_.ReadAtCurrentPosNoBestEffort(static_cast<char*>(buffer), size);
- }
-
- private:
- base::File file_;
-};
-
-FlocBlocklistService::LoadedBlocklist LoadBlockListOnBackgroundThread(
- const base::FilePath& file_path) {
- base::File blocklist_file(file_path,
- base::File::FLAG_OPEN | base::File::FLAG_READ);
- if (!blocklist_file.IsValid())
- return FlocBlocklistService::LoadedBlocklist();
-
- CopyingFileInputStream copying_stream(std::move(blocklist_file));
- google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
- &copying_stream);
-
- proto::Blocklist blocklist_proto;
- if (!blocklist_proto.ParseFromZeroCopyStream(&zero_copy_stream_adaptor))
- return FlocBlocklistService::LoadedBlocklist();
-
- std::unordered_set<uint64_t> blocklist;
- for (uint64_t entry : blocklist_proto.entries())
- blocklist.insert(entry);
-
- return blocklist;
-}
-
-} // namespace
-
-FlocBlocklistService::FlocBlocklistService()
- : background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {}
-
-FlocBlocklistService::~FlocBlocklistService() = default;
-
-void FlocBlocklistService::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void FlocBlocklistService::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void FlocBlocklistService::OnBlocklistFileReady(
- const base::FilePath& file_path) {
- base::PostTaskAndReplyWithResult(
- background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&LoadBlockListOnBackgroundThread, file_path),
- base::BindOnce(&FlocBlocklistService::OnBlocklistLoadResult,
- AsWeakPtr()));
-}
-
-void FlocBlocklistService::SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
- background_task_runner_ = background_task_runner;
-}
-
-bool FlocBlocklistService::BlocklistLoaded() const {
- return loaded_blocklist_.has_value();
-}
-
-bool FlocBlocklistService::ShouldBlockFloc(uint64_t floc_id) const {
- // If the blocklist hasn't been loaded or if there was a load failure, we
- // block all flocs.
- if (!loaded_blocklist_)
- return true;
-
- return loaded_blocklist_->find(floc_id) != loaded_blocklist_->end();
-}
-
-void FlocBlocklistService::OnBlocklistLoadResult(LoadedBlocklist blocklist) {
- loaded_blocklist_ = std::move(blocklist);
-
- if (loaded_blocklist_) {
- for (auto& observer : observers_)
- observer.OnBlocklistLoaded();
- }
-}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_blocklist_service.h b/chromium/components/federated_learning/floc_blocklist_service.h
deleted file mode 100644
index 81847e9ff06..00000000000
--- a/chromium/components/federated_learning/floc_blocklist_service.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2020 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_FEDERATED_LEARNING_FLOC_BLOCKLIST_SERVICE_H_
-#define COMPONENTS_FEDERATED_LEARNING_FLOC_BLOCKLIST_SERVICE_H_
-
-#include <stdint.h>
-
-#include <unordered_set>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/optional.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-} // namespace base
-
-namespace federated_learning {
-
-// Responsible for loading the blocklist of flocs that are downloaded through
-// the component updater.
-//
-// File reading and parsing is posted to |background_task_runner_|.
-class FlocBlocklistService
- : public base::SupportsWeakPtr<FlocBlocklistService> {
- public:
- class Observer {
- public:
- virtual void OnBlocklistLoaded() = 0;
- };
-
- using LoadedBlocklist = base::Optional<std::unordered_set<uint64_t>>;
-
- FlocBlocklistService();
- virtual ~FlocBlocklistService();
-
- FlocBlocklistService(const FlocBlocklistService&) = delete;
- FlocBlocklistService& operator=(const FlocBlocklistService&) = delete;
-
- // Adds/Removes an Observer.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- // Virtual for testing.
- virtual void OnBlocklistFileReady(const base::FilePath& file_path);
-
- void SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner);
-
- bool BlocklistLoaded() const;
- bool ShouldBlockFloc(uint64_t floc_id) const;
-
- protected:
- // Virtual for testing.
- virtual void OnBlocklistLoadResult(LoadedBlocklist blocklist);
-
- private:
- friend class MockFlocBlocklistService;
- friend class FlocIdProviderUnitTest;
- friend class FlocIdProviderWithCustomizedServicesBrowserTest;
-
- // Runner for tasks that do not influence user experience.
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-
- base::ObserverList<Observer>::Unchecked observers_;
-
- LoadedBlocklist loaded_blocklist_;
-};
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_BLOCKLIST_SERVICE_H_
diff --git a/chromium/components/federated_learning/floc_blocklist_service_unittest.cc b/chromium/components/federated_learning/floc_blocklist_service_unittest.cc
deleted file mode 100644
index 77742221c12..00000000000
--- a/chromium/components/federated_learning/floc_blocklist_service_unittest.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2020 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/federated_learning/floc_blocklist_service.h"
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_simple_task_runner.h"
-#include "components/federated_learning/proto/blocklist.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace federated_learning {
-
-// The purpose of this class is to expose the loaded_blocklist_ member and to
-// allow monitoring the OnBlocklistLoadResult method calls.
-class MockFlocBlocklistService : public FlocBlocklistService {
- public:
- using FlocBlocklistService::FlocBlocklistService;
-
- void OnBlocklistLoadResult(LoadedBlocklist blocklist) override {
- FlocBlocklistService::OnBlocklistLoadResult(std::move(blocklist));
-
- ++load_result_count_;
-
- if (load_result_count_ == expected_load_result_count_)
- run_loop_.Quit();
- }
-
- const LoadedBlocklist& loaded_blocklist() { return loaded_blocklist_; }
-
- void WaitForExpectedLoadResultCount(size_t expected_load_result_count) {
- DCHECK(!run_loop_.running());
- if (expected_load_result_count_ >= expected_load_result_count)
- return;
-
- expected_load_result_count_ = expected_load_result_count;
- run_loop_.Run();
- }
-
- private:
- size_t load_result_count_ = 0;
- size_t expected_load_result_count_ = 0;
- base::RunLoop run_loop_;
-};
-
-class FlocBlocklistServiceTest : public ::testing::Test {
- public:
- FlocBlocklistServiceTest()
- : background_task_runner_(
- base::MakeRefCounted<base::TestSimpleTaskRunner>()) {}
-
- FlocBlocklistServiceTest(const FlocBlocklistServiceTest&) = delete;
- FlocBlocklistServiceTest& operator=(const FlocBlocklistServiceTest&) = delete;
-
- protected:
- void SetUp() override {
- service_ = std::make_unique<MockFlocBlocklistService>();
- service_->SetBackgroundTaskRunnerForTesting(background_task_runner_);
- }
-
- base::FilePath GetUniqueTemporaryPath() {
- CHECK(scoped_temp_dir_.IsValid() || scoped_temp_dir_.CreateUniqueTempDir());
- return scoped_temp_dir_.GetPath().AppendASCII(
- base::NumberToString(next_unique_file_suffix_++));
- }
-
- base::FilePath CreateTestBlocklistProtoFile(
- const std::vector<uint64_t>& blocklist) {
- base::FilePath file_path = GetUniqueTemporaryPath();
-
- federated_learning::proto::Blocklist blocklist_proto;
- for (uint64_t n : blocklist)
- blocklist_proto.add_entries(n);
-
- std::string contents;
- CHECK(blocklist_proto.SerializeToString(&contents));
-
- CHECK_EQ(static_cast<int>(contents.size()),
- base::WriteFile(file_path, contents.data(),
- static_cast<int>(contents.size())));
- return file_path;
- }
-
- base::FilePath CreateCorruptedTestBlocklistProtoFile() {
- base::FilePath file_path = GetUniqueTemporaryPath();
- std::string contents = "1234\n5678\n";
- CHECK_EQ(static_cast<int>(contents.size()),
- base::WriteFile(file_path, contents.data(),
- static_cast<int>(contents.size())));
- return file_path;
- }
-
- MockFlocBlocklistService* service() { return service_.get(); }
-
- protected:
- base::test::TaskEnvironment task_environment_;
- base::ScopedTempDir scoped_temp_dir_;
- int next_unique_file_suffix_ = 1;
-
- scoped_refptr<base::TestSimpleTaskRunner> background_task_runner_;
-
- std::unique_ptr<MockFlocBlocklistService> service_;
-};
-
-TEST_F(FlocBlocklistServiceTest, Startup_NoBlocklistNotNotified) {
- EXPECT_FALSE(service()->loaded_blocklist().has_value());
-}
-
-TEST_F(FlocBlocklistServiceTest, NewEmptyBlocklist_Loaded) {
- base::FilePath file_path = CreateTestBlocklistProtoFile({});
- service()->OnBlocklistFileReady(file_path);
-
- background_task_runner_->RunPendingTasks();
- service()->WaitForExpectedLoadResultCount(1u);
-
- EXPECT_TRUE(service()->loaded_blocklist().has_value());
- EXPECT_EQ(service()->loaded_blocklist()->size(), 0u);
-}
-
-TEST_F(FlocBlocklistServiceTest, NewNonEmptyBlocklist_Loaded) {
- base::FilePath file_path = CreateTestBlocklistProtoFile({1, 2, 3, 0});
- service()->OnBlocklistFileReady(file_path);
-
- background_task_runner_->RunPendingTasks();
- service()->WaitForExpectedLoadResultCount(1u);
-
- EXPECT_TRUE(service()->loaded_blocklist().has_value());
- EXPECT_EQ(service()->loaded_blocklist()->size(), 4u);
- EXPECT_TRUE(service()->loaded_blocklist()->count(0));
- EXPECT_TRUE(service()->loaded_blocklist()->count(1));
- EXPECT_TRUE(service()->loaded_blocklist()->count(2));
- EXPECT_TRUE(service()->loaded_blocklist()->count(3));
-}
-
-TEST_F(FlocBlocklistServiceTest, NonExistentBlocklist_NotLoaded) {
- base::FilePath file_path = GetUniqueTemporaryPath();
- service()->OnBlocklistFileReady(file_path);
-
- background_task_runner_->RunPendingTasks();
- service()->WaitForExpectedLoadResultCount(1u);
-
- EXPECT_FALSE(service()->loaded_blocklist().has_value());
-}
-
-TEST_F(FlocBlocklistServiceTest, CorruptedBlocklist_NotLoaded) {
- base::FilePath file_path = CreateCorruptedTestBlocklistProtoFile();
- service()->OnBlocklistFileReady(file_path);
-
- background_task_runner_->RunPendingTasks();
- service()->WaitForExpectedLoadResultCount(1u);
-
- EXPECT_FALSE(service()->loaded_blocklist().has_value());
-}
-
-TEST_F(FlocBlocklistServiceTest, MultipleUpdate_LatestOneLoaded) {
- base::FilePath file_path1 = CreateTestBlocklistProtoFile({1, 2, 3, 0});
- base::FilePath file_path2 = CreateTestBlocklistProtoFile({4});
- service()->OnBlocklistFileReady(file_path1);
- service()->OnBlocklistFileReady(file_path2);
-
- EXPECT_FALSE(service()->loaded_blocklist().has_value());
-
- background_task_runner_->RunPendingTasks();
- service()->WaitForExpectedLoadResultCount(2u);
-
- EXPECT_TRUE(service()->loaded_blocklist().has_value());
- EXPECT_EQ(service()->loaded_blocklist()->size(), 1u);
- EXPECT_TRUE(service()->loaded_blocklist()->count(4));
-}
-
-} // namespace federated_learning \ No newline at end of file
diff --git a/chromium/components/federated_learning/floc_constants.cc b/chromium/components/federated_learning/floc_constants.cc
index 6d1e77b1795..df66e5dccd1 100644
--- a/chromium/components/federated_learning/floc_constants.cc
+++ b/chromium/components/federated_learning/floc_constants.cc
@@ -16,14 +16,17 @@ static_assert(kMaxNumberOfBitsInFloc > 0 &&
const char kManifestFlocComponentFormatKey[] = "floc_component_format";
-const int kCurrentFlocComponentFormatVersion = 1;
+const int kCurrentFlocComponentFormatVersion = 3;
+
+const uint8_t kSortingLshMaxBits = 7;
+
+const uint32_t kSortingLshBlockedMask = 0b1000000;
+
+const uint32_t kSortingLshSizeMask = 0b0111111;
const base::FilePath::CharType kTopLevelDirectoryName[] =
FILE_PATH_LITERAL("Floc");
-const base::FilePath::CharType kBlocklistFileName[] =
- FILE_PATH_LITERAL("Blocklist");
-
const base::FilePath::CharType kSortingLshClustersFileName[] =
FILE_PATH_LITERAL("SortingLshClusters");
diff --git a/chromium/components/federated_learning/floc_constants.h b/chromium/components/federated_learning/floc_constants.h
index 6d9ef09a8cd..61e393dfb33 100644
--- a/chromium/components/federated_learning/floc_constants.h
+++ b/chromium/components/federated_learning/floc_constants.h
@@ -15,6 +15,12 @@ extern const char kManifestFlocComponentFormatKey[];
extern const int kCurrentFlocComponentFormatVersion;
+extern const uint8_t kSortingLshMaxBits;
+
+extern const uint32_t kSortingLshBlockedMask;
+
+extern const uint32_t kSortingLshSizeMask;
+
// The name of the top-level directory under the user data directory that
// contains all files and subdirectories related to the floc.
extern const base::FilePath::CharType kTopLevelDirectoryName[];
@@ -22,9 +28,6 @@ extern const base::FilePath::CharType kTopLevelDirectoryName[];
// Paths under |kTopLevelDirectoryName|
// ------------------------------------
-// The name of the file that stores the blocklist.
-extern const base::FilePath::CharType kBlocklistFileName[];
-
// The name of the file that stores the sorting-lsh clusters.
extern const base::FilePath::CharType kSortingLshClustersFileName[];
diff --git a/chromium/components/federated_learning/floc_id.cc b/chromium/components/federated_learning/floc_id.cc
index 423e2e65420..122536d5177 100644
--- a/chromium/components/federated_learning/floc_id.cc
+++ b/chromium/components/federated_learning/floc_id.cc
@@ -13,19 +13,27 @@ namespace federated_learning {
namespace {
-constexpr char kFlocVersion[] = "1.0.0";
+// Domain one-hot + sim hash + sorting-lsh (behind a feature flag)
+const uint32_t kChromeFlocIdVersion = 1;
} // namespace
// static
-FlocId FlocId::CreateFromHistory(
+uint64_t FlocId::SimHashHistory(
const std::unordered_set<std::string>& domains) {
- return FlocId(SimHashStrings(domains, kMaxNumberOfBitsInFloc));
+ return SimHashStrings(domains, kMaxNumberOfBitsInFloc);
}
FlocId::FlocId() = default;
-FlocId::FlocId(uint64_t id) : id_(id) {}
+FlocId::FlocId(uint64_t id,
+ base::Time history_begin_time,
+ base::Time history_end_time,
+ uint32_t sorting_lsh_version)
+ : id_(id),
+ history_begin_time_(history_begin_time),
+ history_end_time_(history_end_time),
+ sorting_lsh_version_(sorting_lsh_version) {}
FlocId::FlocId(const FlocId& id) = default;
@@ -40,27 +48,21 @@ bool FlocId::IsValid() const {
}
bool FlocId::operator==(const FlocId& other) const {
- return id_ == other.id_;
+ return id_ == other.id_ && history_begin_time_ == other.history_begin_time_ &&
+ history_end_time_ == other.history_end_time_ &&
+ sorting_lsh_version_ == other.sorting_lsh_version_;
}
bool FlocId::operator!=(const FlocId& other) const {
return !(*this == other);
}
-uint64_t FlocId::ToUint64() const {
+std::string FlocId::ToStringForJsApi() const {
DCHECK(id_.has_value());
- return id_.value();
-}
-
-std::string FlocId::ToDebugHeaderValue() const {
- if (!id_.has_value())
- return "null";
- return ToString();
-}
-std::string FlocId::ToString() const {
- DCHECK(id_.has_value());
- return base::StrCat({base::NumberToString(id_.value()), ".", kFlocVersion});
+ return base::StrCat({base::NumberToString(id_.value()), ".",
+ base::NumberToString(kChromeFlocIdVersion), ".",
+ base::NumberToString(sorting_lsh_version_)});
}
} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_id.h b/chromium/components/federated_learning/floc_id.h
index 81701b4ed19..7e3154e372a 100644
--- a/chromium/components/federated_learning/floc_id.h
+++ b/chromium/components/federated_learning/floc_id.h
@@ -6,6 +6,8 @@
#define COMPONENTS_FEDERATED_LEARNING_FLOC_ID_H_
#include "base/optional.h"
+#include "base/time/time.h"
+#include "base/version.h"
#include <stdint.h>
@@ -19,13 +21,17 @@ namespace federated_learning {
// https://github.com/jkarlin/floc/blob/master/README.md
class FlocId {
public:
- static FlocId CreateFromHistory(
+ static uint64_t SimHashHistory(
const std::unordered_set<std::string>& domains);
FlocId();
- explicit FlocId(uint64_t id);
- FlocId(const FlocId& id);
+ explicit FlocId(uint64_t id,
+ base::Time history_begin_time,
+ base::Time history_end_time,
+ uint32_t sorting_lsh_version);
+
+ FlocId(const FlocId& id);
~FlocId();
FlocId& operator=(const FlocId& id);
FlocId& operator=(FlocId&& id);
@@ -34,18 +40,26 @@ class FlocId {
bool operator!=(const FlocId& other) const;
bool IsValid() const;
- uint64_t ToUint64() const;
- // The id followed by a version number. "null" if |id_| is invalid. To be
- // deprecated soon.
- std::string ToDebugHeaderValue() const;
+ // The id, followed by the chrome floc version, followed by the async floc
+ // component versions (i.e. model and sorting-lsh). This is the format to be
+ // exposed to the JS API. Precondition: |id_| must be valid.
+ std::string ToStringForJsApi() const;
- // The id followed by a version number, which is the format be exposed to HTTP
- // headers or JS API. Precondition: |id_| must be valid.
- std::string ToString() const;
+ base::Time history_begin_time() const { return history_begin_time_; }
+
+ base::Time history_end_time() const { return history_end_time_; }
private:
base::Optional<uint64_t> id_;
+
+ // The time range of the actual history used to compute the floc. This should
+ // always be within the time range of each history query.
+ base::Time history_begin_time_;
+ base::Time history_end_time_;
+
+ // The main version (i.e. 1st int) of the sorting lsh component version.
+ uint32_t sorting_lsh_version_ = 0;
};
} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_id_unittest.cc b/chromium/components/federated_learning/floc_id_unittest.cc
new file mode 100644
index 00000000000..b2f6be0f036
--- /dev/null
+++ b/chromium/components/federated_learning/floc_id_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright 2020 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/federated_learning/floc_id.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace federated_learning {
+
+const base::Time kTime0 = base::Time();
+const base::Time kTime1 = base::Time::FromTimeT(1);
+const base::Time kTime2 = base::Time::FromTimeT(2);
+
+TEST(FlocIdTest, IsValid) {
+ EXPECT_FALSE(FlocId().IsValid());
+ EXPECT_TRUE(FlocId(0, kTime0, kTime0, 0).IsValid());
+ EXPECT_TRUE(FlocId(0, kTime1, kTime2, 1).IsValid());
+}
+
+TEST(FlocIdTest, Comparison) {
+ EXPECT_EQ(FlocId(), FlocId());
+
+ EXPECT_EQ(FlocId(0, kTime0, kTime0, 0), FlocId(0, kTime0, kTime0, 0));
+ EXPECT_EQ(FlocId(0, kTime1, kTime1, 1), FlocId(0, kTime1, kTime1, 1));
+ EXPECT_EQ(FlocId(0, kTime1, kTime2, 1), FlocId(0, kTime1, kTime2, 1));
+
+ EXPECT_NE(FlocId(), FlocId(0, kTime0, kTime0, 0));
+ EXPECT_NE(FlocId(0, kTime0, kTime0, 0), FlocId(1, kTime0, kTime0, 0));
+ EXPECT_NE(FlocId(0, kTime0, kTime1, 0), FlocId(0, kTime1, kTime1, 0));
+ EXPECT_NE(FlocId(0, kTime0, kTime0, 0), FlocId(0, kTime0, kTime0, 1));
+}
+
+TEST(FlocIdTest, ToStringForJsApi) {
+ EXPECT_EQ("0.1.0", FlocId(0, kTime0, kTime0, 0).ToStringForJsApi());
+ EXPECT_EQ("12345.1.0", FlocId(12345, kTime0, kTime0, 0).ToStringForJsApi());
+ EXPECT_EQ("12345.1.2", FlocId(12345, kTime1, kTime1, 2).ToStringForJsApi());
+}
+
+} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc
index e9bc065043f..29beb4ba479 100644
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc
+++ b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc
@@ -36,13 +36,13 @@ class CopyingFileInputStream : public google::protobuf::io::CopyingInputStream {
base::File file_;
};
-FlocId ApplySortingLshOnBackgroundThread(const FlocId& raw_floc_id,
- const base::FilePath& file_path) {
- DCHECK(raw_floc_id.IsValid());
+base::Optional<uint64_t> ApplySortingLshOnBackgroundThread(
+ uint64_t sim_hash,
+ const base::FilePath& file_path) {
base::File sorting_lsh_clusters_file(
file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!sorting_lsh_clusters_file.IsValid())
- return FlocId();
+ return base::nullopt;
CopyingFileInputStream copying_stream(std::move(sorting_lsh_clusters_file));
google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
@@ -51,51 +51,70 @@ FlocId ApplySortingLshOnBackgroundThread(const FlocId& raw_floc_id,
google::protobuf::io::CodedInputStream input_stream(
&zero_copy_stream_adaptor);
- // The file should contain a list of integers within the range [0,
- // MaxNumberOfBitsInFloc]. Suppose the list is l, then 2^(l[i]) represents the
- // the number of hashes that can be associated with this floc id. The
- // cumulative sum of 2^(l[i]) represents the boundary floc values in
- // |raw_floc_id|'s space. We will use the higher index to encode
- // |raw_floc_id|, i.e. if raw_floc_id is within range
- // [CumSum(2^(l[i-1])), CumSum(2^(l[i]))), |i| will be output floc.
+ // The file should contain a list of integers. The 7th-order bit represents
+ // whether the cohort should be blocked. The number represented by the 1st-6th
+ // bits should be within the range [0, MaxNumberOfBitsInFloc]. Suppose the
+ // list is l, then S(i) = 2^(l[i] & 0b111111) represents the the number of
+ // hashes that can be associated with this floc id. The cumulative sum of S(i)
+ // represents the boundary sim_hash values. We will use the higher index to
+ // encode |sim_hash|, i.e. if sim_hash is within range
+ // [CumSum(S(i-1)), CumSum(S(i))), |i| will be output floc.
//
// 0 is always an implicit CumSum boundary, i.e. if
- // 0 <= |raw_floc_id| < 2^(l[0]), then the index 0 will be the output floc.
+ // 0 <= |sim_hash| < 2^(l[0]), then the index 0 will be the output floc.
//
+ // However, if the is_blocked bit (i.e. l[i] & 0b1000000) indicates that the
+ // cohort should be blocked, we will output an invalid floc id.
+
// Input sanitization: As we compute on the fly, we will check to make sure
- // each encountered entry is within [0, MaxNumberOfBitsInFloc]. Besides, the
- // cumulative sum should be no greater than 2^MaxNumberOfBitsInFloc at any
- // given time. If we cannot find an index i, it means the the final cumulative
- // sum is less than 2^MaxNumberOfBitsInFloc, while we expect it to be exactly
+ // each encountered entry, after dropping the is_blocked bit, is within
+ // [0, MaxNumberOfBitsInFloc]. Besides, the cumulative sum should be no
+ // greater than 2^MaxNumberOfBitsInFloc at any given time. If we cannot find
+ // an index i, it means the the final cumulative sum is less than
+ // 2^MaxNumberOfBitsInFloc, while we expect it to be exactly
// 2^MaxNumberOfBitsInFloc, and we should also fail in this case. When some
- // check fails, we will output an invalid floc id.
+ // check fails, we will also output an invalid floc id.
//
// A stricter sanitization would be to always stream all numbers and check
// properties. We skip doing this to save some computation cost.
- uint64_t raw_floc_id_as_int = raw_floc_id.ToUint64();
const uint64_t kExpectedFinalCumulativeSum = (1ULL << kMaxNumberOfBitsInFloc);
- DCHECK(raw_floc_id_as_int < kExpectedFinalCumulativeSum);
+ DCHECK_LT(sim_hash, kExpectedFinalCumulativeSum);
uint64_t cumulative_sum = 0;
- uint32_t next;
+ uint32_t next_combined;
+
+ // TODO(yaoxia): Add metrics for when the file has unexpected format.
+
+ for (uint64_t index = 0; input_stream.ReadVarint32(&next_combined); ++index) {
+ // Sanitizing error: the entry used more than |kSortingLshMaxBits| bits.
+ if ((next_combined >> kSortingLshMaxBits) > 0)
+ return base::nullopt;
- // TODO: Add metrics for when we return an invalid floc, which indicates a
- // wrong/corrupted file.
+ bool is_blocked = next_combined & kSortingLshBlockedMask;
+ uint32_t next = next_combined & kSortingLshSizeMask;
- for (uint64_t index = 0; input_stream.ReadVarint32(&next); ++index) {
+ // Sanitizing error
if (next > kMaxNumberOfBitsInFloc)
- return FlocId();
+ return base::nullopt;
cumulative_sum += (1ULL << next);
+ // Sanitizing error
if (cumulative_sum > kExpectedFinalCumulativeSum)
- return FlocId();
+ return base::nullopt;
- if (cumulative_sum > raw_floc_id_as_int)
- return FlocId(index);
+ // Found the sim-hash upper bound. Use the index as the new floc.
+ if (cumulative_sum > sim_hash) {
+ if (is_blocked)
+ return base::nullopt;
+
+ return index;
+ }
}
- return FlocId();
+ // Sanitizing error: we didn't find a sim-hash upper bound, but we expect to
+ // always find it after finish iterating through the list.
+ return base::nullopt;
}
} // namespace
@@ -116,29 +135,45 @@ void FlocSortingLshClustersService::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-void FlocSortingLshClustersService::SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
- background_task_runner_ = background_task_runner;
+bool FlocSortingLshClustersService::IsSortingLshClustersFileReady() const {
+ return first_file_ready_seen_;
+}
+
+void FlocSortingLshClustersService::OnSortingLshClustersFileReady(
+ const base::FilePath& file_path,
+ const base::Version& version) {
+ sorting_lsh_clusters_file_path_ = file_path;
+ sorting_lsh_clusters_version_ = version;
+ first_file_ready_seen_ = true;
+
+ for (auto& observer : observers_)
+ observer.OnSortingLshClustersFileReady();
}
void FlocSortingLshClustersService::ApplySortingLsh(
- const FlocId& raw_floc_id,
+ uint64_t sim_hash,
ApplySortingLshCallback callback) {
- DCHECK(raw_floc_id.IsValid());
- DCHECK(sorting_lsh_clusters_file_path_.has_value());
+ DCHECK(first_file_ready_seen_);
+
base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&ApplySortingLshOnBackgroundThread, raw_floc_id,
- sorting_lsh_clusters_file_path_.value()),
- std::move(callback));
+ base::BindOnce(&ApplySortingLshOnBackgroundThread, sim_hash,
+ sorting_lsh_clusters_file_path_),
+ base::BindOnce(&FlocSortingLshClustersService::DidApplySortingLsh,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ sorting_lsh_clusters_version_));
}
-void FlocSortingLshClustersService::OnSortingLshClustersFileReady(
- const base::FilePath& file_path) {
- sorting_lsh_clusters_file_path_ = file_path;
+void FlocSortingLshClustersService::SetBackgroundTaskRunnerForTesting(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ background_task_runner_ = background_task_runner;
+}
- for (auto& observer : observers_)
- observer.OnSortingLshClustersFileReady();
+void FlocSortingLshClustersService::DidApplySortingLsh(
+ ApplySortingLshCallback callback,
+ base::Version version,
+ base::Optional<uint64_t> final_hash) {
+ std::move(callback).Run(std::move(final_hash), std::move(version));
}
} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h
index 8db88631de6..43d6f625b50 100644
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h
+++ b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
+#include "base/version.h"
#include "components/federated_learning/floc_id.h"
namespace base {
@@ -28,7 +29,8 @@ namespace federated_learning {
// File reading and parsing is posted to |background_task_runner_|.
class FlocSortingLshClustersService {
public:
- using ApplySortingLshCallback = base::OnceCallback<void(FlocId)>;
+ using ApplySortingLshCallback =
+ base::OnceCallback<void(base::Optional<uint64_t>, base::Version)>;
class Observer {
public:
@@ -46,24 +48,34 @@ class FlocSortingLshClustersService {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- void SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner);
+ bool IsSortingLshClustersFileReady() const;
- void ApplySortingLsh(const FlocId& raw_floc_id,
- ApplySortingLshCallback callback);
+ // Virtual for testing.
+ virtual void OnSortingLshClustersFileReady(const base::FilePath& file_path,
+ const base::Version& version);
// Virtual for testing.
- virtual void OnSortingLshClustersFileReady(const base::FilePath& file_path);
+ virtual void ApplySortingLsh(uint64_t sim_hash,
+ ApplySortingLshCallback callback);
+
+ void SetBackgroundTaskRunnerForTesting(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
private:
friend class FlocSortingLshClustersServiceTest;
+ void DidApplySortingLsh(ApplySortingLshCallback callback,
+ base::Version version,
+ base::Optional<uint64_t> final_hash);
+
// Runner for tasks that do not influence user experience.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
base::ObserverList<Observer>::Unchecked observers_;
- base::Optional<base::FilePath> sorting_lsh_clusters_file_path_;
+ bool first_file_ready_seen_ = false;
+ base::FilePath sorting_lsh_clusters_file_path_;
+ base::Version sorting_lsh_clusters_version_;
base::WeakPtrFactory<FlocSortingLshClustersService> weak_ptr_factory_;
};
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc
index 82b66404c23..bf89c1c91a5 100644
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc
+++ b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc
@@ -11,7 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "components/federated_learning/floc_constants.h"
@@ -23,6 +23,8 @@ namespace federated_learning {
namespace {
+const uint64_t kMaxSimHash = (1ULL << kMaxNumberOfBitsInFloc) - 1;
+
class CopyingFileOutputStream
: public google::protobuf::io::CopyingOutputStream {
public:
@@ -43,6 +45,11 @@ class CopyingFileOutputStream
base::File file_;
};
+struct ApplySortingLshResult {
+ base::Optional<uint64_t> final_hash;
+ base::Version version;
+};
+
} // namespace
class FlocSortingLshClustersServiceTest : public ::testing::Test {
@@ -69,7 +76,7 @@ class FlocSortingLshClustersServiceTest : public ::testing::Test {
}
base::FilePath CreateTestSortingLshClustersFile(
- const std::vector<uint32_t>& sorting_lsh_clusters) {
+ const std::vector<std::pair<uint32_t, bool>>& sorting_lsh_clusters) {
base::FilePath file_path = GetUniqueTemporaryPath();
base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ |
base::File::FLAG_WRITE);
@@ -82,8 +89,14 @@ class FlocSortingLshClustersServiceTest : public ::testing::Test {
google::protobuf::io::CodedOutputStream output_stream(
&zero_copy_stream_adaptor);
- for (uint32_t next : sorting_lsh_clusters)
+ for (const auto& p : sorting_lsh_clusters) {
+ uint32_t next = p.first;
+ bool is_blocked = p.second;
+ if (is_blocked) {
+ next |= kSortingLshBlockedMask;
+ }
output_stream.WriteVarint32(next);
+ }
CHECK(!output_stream.HadError());
@@ -91,32 +104,36 @@ class FlocSortingLshClustersServiceTest : public ::testing::Test {
}
base::FilePath InitializeSortingLshClustersFile(
- const std::vector<uint32_t>& sorting_lsh_clusters) {
+ const std::vector<std::pair<uint32_t, bool>>& sorting_lsh_clusters,
+ const base::Version& version) {
base::FilePath file_path =
CreateTestSortingLshClustersFile(sorting_lsh_clusters);
- service()->OnSortingLshClustersFileReady(file_path);
+ service()->OnSortingLshClustersFileReady(file_path, version);
EXPECT_TRUE(sorting_lsh_clusters_file_path().has_value());
return file_path;
}
- FlocId MaxFlocId() { return FlocId((1ULL << kMaxNumberOfBitsInFloc) - 1); }
-
FlocSortingLshClustersService* service() { return service_.get(); }
- const base::Optional<base::FilePath>& sorting_lsh_clusters_file_path() {
+ base::Optional<base::FilePath> sorting_lsh_clusters_file_path() {
+ if (!service()->first_file_ready_seen_)
+ return base::nullopt;
+
return service()->sorting_lsh_clusters_file_path_;
}
- FlocId ApplySortingLsh(const FlocId& floc_id) {
- FlocId result;
+ ApplySortingLshResult ApplySortingLsh(uint64_t sim_hash) {
+ ApplySortingLshResult result;
base::RunLoop run_loop;
- auto cb = base::BindLambdaForTesting([&](FlocId floc_id) {
- result = floc_id;
- run_loop.Quit();
- });
-
- service()->ApplySortingLsh(floc_id, std::move(cb));
+ auto cb = base::BindLambdaForTesting(
+ [&](base::Optional<uint64_t> final_hash, base::Version version) {
+ result.final_hash = final_hash;
+ result.version = version;
+ run_loop.Quit();
+ });
+
+ service()->ApplySortingLsh(sim_hash, std::move(cb));
background_task_runner_->RunPendingTasks();
run_loop.Run();
@@ -138,91 +155,118 @@ TEST_F(FlocSortingLshClustersServiceTest, NoFilePath) {
}
TEST_F(FlocSortingLshClustersServiceTest, EmptyList) {
- InitializeSortingLshClustersFile({});
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+ InitializeSortingLshClustersFile({}, base::Version("2.3.4"));
+
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(0).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(1).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_0) {
- InitializeSortingLshClustersFile({0});
+ InitializeSortingLshClustersFile({{0, false}}, base::Version("2.3.4"));
+
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(base::Version("2.3.4"), ApplySortingLsh(0).version);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(1).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
+}
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+TEST_F(FlocSortingLshClustersServiceTest, List_0_Blocked) {
+ InitializeSortingLshClustersFile({{0, true}}, base::Version("2.3.4"));
+
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(0).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(1).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
+}
+
+TEST_F(FlocSortingLshClustersServiceTest, List_UnexpectedNumber) {
+ InitializeSortingLshClustersFile({{1 << 8, false}}, base::Version("2.3.4"));
+
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(0).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(1).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_1) {
- InitializeSortingLshClustersFile({1});
+ InitializeSortingLshClustersFile({{1, false}}, base::Version("2.3.4"));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(2)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(2).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_0_0) {
- InitializeSortingLshClustersFile({0, 0});
+ InitializeSortingLshClustersFile({{0, false}, {0, false}},
+ base::Version("2.3.4"));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(2)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(2).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_0_1) {
- InitializeSortingLshClustersFile({0, 1});
-
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(2)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(3)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+ InitializeSortingLshClustersFile({{0, false}, {1, false}},
+ base::Version("2.3.4"));
+
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(2).final_hash.value());
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(3).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_1_0) {
- InitializeSortingLshClustersFile({1, 0});
-
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(2)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(FlocId(3)));
- EXPECT_EQ(FlocId(), ApplySortingLsh(MaxFlocId()));
+ InitializeSortingLshClustersFile({{1, false}, {0, false}},
+ base::Version("2.3.4"));
+
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(2).final_hash.value());
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(3).final_hash);
+ EXPECT_EQ(base::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
}
TEST_F(FlocSortingLshClustersServiceTest, List_SingleCluster) {
- InitializeSortingLshClustersFile({kMaxNumberOfBitsInFloc});
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(12345)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(MaxFlocId()));
+ InitializeSortingLshClustersFile({{kMaxNumberOfBitsInFloc, false}},
+ base::Version("2.3.4"));
+
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(12345).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(kMaxSimHash).final_hash.value());
}
TEST_F(FlocSortingLshClustersServiceTest, List_TwoClustersEqualSize) {
- InitializeSortingLshClustersFile(
- {kMaxNumberOfBitsInFloc - 1, kMaxNumberOfBitsInFloc - 1});
+ InitializeSortingLshClustersFile({{kMaxNumberOfBitsInFloc - 1, false},
+ {kMaxNumberOfBitsInFloc - 1, false}},
+ base::Version("2.3.4"));
uint64_t middle_value = (1ULL << (kMaxNumberOfBitsInFloc - 1));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(1)));
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(middle_value - 1)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(middle_value)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(FlocId(middle_value + 1)));
- EXPECT_EQ(FlocId(1), ApplySortingLsh(MaxFlocId()));
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
+ EXPECT_EQ(0u, ApplySortingLsh(middle_value - 1).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(middle_value).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(middle_value + 1).final_hash.value());
+ EXPECT_EQ(1u, ApplySortingLsh(kMaxSimHash).final_hash.value());
}
TEST_F(FlocSortingLshClustersServiceTest,
FileDeletedAfterSortingLshTaskScheduled) {
- base::FilePath file_path = InitializeSortingLshClustersFile({0});
+ base::FilePath file_path =
+ InitializeSortingLshClustersFile({{0, false}}, base::Version("2.3.4"));
base::RunLoop run_loop;
- auto cb = base::BindLambdaForTesting([&](FlocId floc_id) {
- // Since the file has been deleted, expect an invalid floc id.
- EXPECT_EQ(FlocId(), floc_id);
- run_loop.Quit();
- });
-
- service()->ApplySortingLsh(FlocId(0), std::move(cb));
+ auto cb = base::BindLambdaForTesting(
+ [&](base::Optional<uint64_t> final_hash, base::Version version) {
+ // Since the file has been deleted, expect an invalid final_hash.
+ EXPECT_EQ(base::nullopt, final_hash);
+ EXPECT_EQ(base::Version("2.3.4"), version);
+ run_loop.Quit();
+ });
+
+ service()->ApplySortingLsh(/*sim_hash=*/0, std::move(cb));
base::DeleteFile(file_path);
background_task_runner_->RunPendingTasks();
@@ -230,9 +274,11 @@ TEST_F(FlocSortingLshClustersServiceTest,
}
TEST_F(FlocSortingLshClustersServiceTest, MultipleUpdate_LatestOneUsed) {
- InitializeSortingLshClustersFile({});
- InitializeSortingLshClustersFile({0});
- EXPECT_EQ(FlocId(0), ApplySortingLsh(FlocId(0)));
+ InitializeSortingLshClustersFile({}, base::Version("2.3.4"));
+ InitializeSortingLshClustersFile({{0, false}}, base::Version("6.7.8.9"));
+
+ EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
+ EXPECT_EQ(base::Version("6.7.8.9"), ApplySortingLsh(0).version);
}
} // namespace federated_learning
diff --git a/chromium/components/federated_learning/proto/BUILD.gn b/chromium/components/federated_learning/proto/BUILD.gn
deleted file mode 100644
index e3154e9be25..00000000000
--- a/chromium/components/federated_learning/proto/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2020 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("//third_party/protobuf/proto_library.gni")
-
-proto_library("federated_learning") {
- sources = [ "blocklist.proto" ]
-}
diff --git a/chromium/components/federated_learning/proto/blocklist.proto b/chromium/components/federated_learning/proto/blocklist.proto
deleted file mode 100644
index f31f26712c4..00000000000
--- a/chromium/components/federated_learning/proto/blocklist.proto
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2020 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.
-
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-package federated_learning.proto;
-option java_package = "org.chromium.components.federated_learning.proto";
-
-message Blocklist {
- repeated int64 entries = 1 [packed = true];
-}
diff --git a/chromium/components/feed/core/common/pref_names.cc b/chromium/components/feed/core/common/pref_names.cc
index a50a96ff852..70cd1594940 100644
--- a/chromium/components/feed/core/common/pref_names.cc
+++ b/chromium/components/feed/core/common/pref_names.cc
@@ -36,6 +36,9 @@ const char kHostOverrideBlessNonce[] = "feed.host_override.bless_nonce";
const char kHasReachedClickAndViewActionsUploadConditions[] =
"feed.clicks_and_views_upload_conditions_reached";
const char kLastFetchHadNoticeCard[] = "feed.last_fetch_had_notice_card";
+const char kLastRefreshWasSignedIn[] = "feed.last_refresh_was_signed_in";
+const char kNoticeCardViewsCount[] = "feed.notice_card_views_count";
+const char kNoticeCardClicksCount[] = "feed.notice_card_clicks_count";
const char kThrottlerRequestCountListPrefName[] =
"feedv2.request_throttler.request_counts";
@@ -68,6 +71,9 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
feed::prefs::kHasReachedClickAndViewActionsUploadConditions, false);
registry->RegisterBooleanPref(feed::prefs::kLastFetchHadNoticeCard, true);
+ registry->RegisterBooleanPref(feed::prefs::kLastRefreshWasSignedIn, false);
+ registry->RegisterIntegerPref(feed::prefs::kNoticeCardViewsCount, 0);
+ registry->RegisterIntegerPref(feed::prefs::kNoticeCardClicksCount, 0);
UserClassifier::RegisterProfilePrefs(registry);
}
diff --git a/chromium/components/feed/core/common/pref_names.h b/chromium/components/feed/core/common/pref_names.h
index 9c381483e65..93116f51d2e 100644
--- a/chromium/components/feed/core/common/pref_names.h
+++ b/chromium/components/feed/core/common/pref_names.h
@@ -46,16 +46,26 @@ extern const char kHostOverrideBlessNonce[];
// to enable the upload of click and view actions in the feed with the notice
// card when using the feature kInterestFeedConditionalClickAndViewActionUpload.
// This is for when the privacy notice card is at the second position in the
-// feed. Currently only used in V1.
+// feed.
extern const char kHasReachedClickAndViewActionsUploadConditions[];
// The pref name for the bit that determines whether the notice card was present
// in the feed in the last fetch of content. The notice card is considered as
// present by default to make sure that the upload of click and view actions
// doesn't take place when the notice card is present but has not yet been
-// detected. Currently only used in V1.
+// detected.
extern const char kLastFetchHadNoticeCard[];
+// The pref name for the bit that determines whether the last refresh request
+// was signed in. Currently only used in V1.
+extern const char kLastRefreshWasSignedIn[];
+
+// The pref name for the counter for the number of views on the notice card.
+extern const char kNoticeCardViewsCount[];
+
+// The pref name for the counter for the number of clicks on the notice card.
+extern const char kNoticeCardClicksCount[];
+
// The following prefs are used only by v2.
// The pref name for the request throttler counts.
diff --git a/chromium/components/feed/core/feed_networking_host.cc b/chromium/components/feed/core/feed_networking_host.cc
index e6ab4ac9321..b6104f523d7 100644
--- a/chromium/components/feed/core/feed_networking_host.cc
+++ b/chromium/components/feed/core/feed_networking_host.cc
@@ -345,7 +345,8 @@ void NetworkFetch::OnSimpleLoaderComplete(
static_cast<int>(response_body.size() / 1024));
}
- std::move(done_callback_).Run(status_code, std::move(response_body));
+ std::move(done_callback_)
+ .Run(status_code, std::move(response_body), !access_token_.empty());
}
FeedNetworkingHost::FeedNetworkingHost(
@@ -388,12 +389,13 @@ void FeedNetworkingHost::NetworkFetchFinished(
NetworkFetch* fetch,
ResponseCallback callback,
int32_t http_code,
- std::vector<uint8_t> response_body) {
+ std::vector<uint8_t> response_body,
+ bool is_signed_in) {
auto fetch_iterator = pending_requests_.find(fetch);
CHECK(fetch_iterator != pending_requests_.end());
pending_requests_.erase(fetch_iterator);
- std::move(callback).Run(http_code, std::move(response_body));
+ std::move(callback).Run(http_code, std::move(response_body), is_signed_in);
}
} // namespace feed
diff --git a/chromium/components/feed/core/feed_networking_host.h b/chromium/components/feed/core/feed_networking_host.h
index f20873554e7..dcfec632efd 100644
--- a/chromium/components/feed/core/feed_networking_host.h
+++ b/chromium/components/feed/core/feed_networking_host.h
@@ -45,7 +45,8 @@ class FeedNetworkingHost {
// status code(if the request succeeded in reaching the server).
using ResponseCallback =
base::OnceCallback<void(int32_t status_code,
- std::vector<uint8_t> response_bytes)>;
+ std::vector<uint8_t> response_bytes,
+ bool is_signed_in)>;
FeedNetworkingHost(
signin::IdentityManager* identity_manager,
@@ -74,7 +75,8 @@ class FeedNetworkingHost {
void NetworkFetchFinished(NetworkFetch* fetch,
ResponseCallback callback,
int32_t http_code,
- std::vector<uint8_t> response_body);
+ std::vector<uint8_t> response_body,
+ bool isSignedIn);
base::flat_set<std::unique_ptr<NetworkFetch>, base::UniquePtrComparator>
pending_requests_;
diff --git a/chromium/components/feed/core/feed_networking_host_unittest.cc b/chromium/components/feed/core/feed_networking_host_unittest.cc
index 9361ec2dd7d..da5af8defdc 100644
--- a/chromium/components/feed/core/feed_networking_host_unittest.cc
+++ b/chromium/components/feed/core/feed_networking_host_unittest.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
@@ -46,16 +46,20 @@ class MockResponseDoneCallback {
public:
MockResponseDoneCallback() : has_run(false), code(0) {}
- void Done(int32_t http_code, std::vector<uint8_t> response) {
+ void Done(int32_t http_code,
+ std::vector<uint8_t> response,
+ bool is_signed_in) {
EXPECT_FALSE(has_run);
has_run = true;
code = http_code;
response_bytes = std::move(response);
+ is_signed_in_result = is_signed_in;
}
bool has_run;
int32_t code;
std::vector<uint8_t> response_bytes;
+ bool is_signed_in_result;
};
} // namespace
@@ -266,6 +270,15 @@ TEST_F(FeedNetworkingHostTest, ShouldSetHeadersCorrectly) {
EXPECT_EQ(authorization, "Bearer access_token");
}
+TEST_F(FeedNetworkingHostTest, ProvideIsSignedInBitInResult) {
+ MockResponseDoneCallback done_callback;
+ SendRequestAndRespond("http://foobar.com/feed", "POST", "body", "",
+ net::HTTP_OK, network::URLLoaderCompletionStatus(),
+ &done_callback);
+
+ EXPECT_TRUE(done_callback.is_signed_in_result);
+}
+
TEST_F(FeedNetworkingHostTest, ShouldNotSendContentEncodingForEmptyBody) {
MockResponseDoneCallback done_callback;
net::HttpRequestHeaders headers;
diff --git a/chromium/components/feed/core/proto/BUILD.gn b/chromium/components/feed/core/proto/BUILD.gn
index 2ff52bed0fc..9244b9aebc5 100644
--- a/chromium/components/feed/core/proto/BUILD.gn
+++ b/chromium/components/feed/core/proto/BUILD.gn
@@ -28,7 +28,9 @@ proto_library("proto_v2") {
"v2/ui.proto",
"v2/wire/action_payload.proto",
"v2/wire/capability.proto",
+ "v2/wire/chrome_client_info.proto",
"v2/wire/chrome_feed_response_metadata.proto",
+ "v2/wire/chrome_fulfillment_info.proto",
"v2/wire/client_info.proto",
"v2/wire/consistency_token.proto",
"v2/wire/content_id.proto",
@@ -92,6 +94,7 @@ if (is_android) {
"wire/action_request.proto",
"wire/action_type.proto",
"wire/capability.proto",
+ "wire/chrome_fulfillment_info.proto",
"wire/client_info.proto",
"wire/consistency_token.proto",
"wire/content_id.proto",
diff --git a/chromium/components/feed/core/proto/v2/store.proto b/chromium/components/feed/core/proto/v2/store.proto
index 29ba828c4ea..206d90596db 100644
--- a/chromium/components/feed/core/proto/v2/store.proto
+++ b/chromium/components/feed/core/proto/v2/store.proto
@@ -51,15 +51,24 @@ message StreamData {
bool logging_enabled = 8;
// Has the privacy notice been fulfilled?
bool privacy_notice_fulfilled = 9;
+
reserved 3, 5;
}
// Data that doesn't belong to a stream.
message Metadata {
+ // Session identifier used for signed-out feed requests and interactions.
+ message SessionID {
+ string token = 1;
+ int64 expiry_time_ms = 2;
+ }
+
// Token used to read or write to the same storage.
bytes consistency_token = 1;
// ID for the next pending action.
int32 next_action_id = 2;
+ // The most recent session identifier.
+ SessionID session_id = 3;
}
// A set of StreamStructures that should be applied to a stream.
diff --git a/chromium/components/feed/core/proto/v2/wire/chrome_client_info.proto b/chromium/components/feed/core/proto/v2/wire/chrome_client_info.proto
new file mode 100644
index 00000000000..26f71a2b690
--- /dev/null
+++ b/chromium/components/feed/core/proto/v2/wire/chrome_client_info.proto
@@ -0,0 +1,17 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package feedwire;
+
+option optimize_for = LITE_RUNTIME;
+
+// Information about the client performing the request, relevant only to Chrome
+// surfaces.
+message ChromeClientInfo {
+ // The signed-out session identifier (Zwieback) token, for clients which embed
+ // this information in-band instead of using an HTTP Cookie.
+ optional string session_id = 3;
+}
diff --git a/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto b/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
index c6ec3fcdbe7..2eb9cad7263 100644
--- a/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
+++ b/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
@@ -11,4 +11,5 @@ option optimize_for = LITE_RUNTIME;
message ChromeFeedResponseMetadata {
optional bool privacy_notice_fulfilled = 1;
optional bool logging_enabled = 2;
+ optional string session_id = 3;
}
diff --git a/chromium/components/feed/core/proto/v2/wire/chrome_fulfillment_info.proto b/chromium/components/feed/core/proto/v2/wire/chrome_fulfillment_info.proto
new file mode 100644
index 00000000000..22ea6991dcb
--- /dev/null
+++ b/chromium/components/feed/core/proto/v2/wire/chrome_fulfillment_info.proto
@@ -0,0 +1,17 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package feedwire;
+
+option optimize_for = LITE_RUNTIME;
+
+// Information on how to do content fulfillment for Chrome.
+message ChromeFulfillmentInfo {
+ // Whether the notice card has already been acknowledged by the user based on
+ // their views and clicks on the card. This is different from when the user
+ // explicitly dismiss the notice card by touching the button.
+ optional bool notice_card_acknowledged = 1;
+}
diff --git a/chromium/components/feed/core/proto/v2/wire/client_info.proto b/chromium/components/feed/core/proto/v2/wire/client_info.proto
index 40eaca72c48..a54ae75ec48 100644
--- a/chromium/components/feed/core/proto/v2/wire/client_info.proto
+++ b/chromium/components/feed/core/proto/v2/wire/client_info.proto
@@ -8,6 +8,7 @@ package feedwire;
option optimize_for = LITE_RUNTIME;
+import "components/feed/core/proto/v2/wire/chrome_client_info.proto";
import "components/feed/core/proto/v2/wire/display_info.proto";
import "components/feed/core/proto/v2/wire/version.proto";
@@ -58,4 +59,8 @@ message ClientInfo {
// this comes from GServices check-in which uses the SIM card MCC (mobile
// country code), with fallback to IP geo lookup.
optional string device_country = 9;
+
+ // Information about the client performing the request, relevant only to
+ // Chrome surfaces.
+ optional ChromeClientInfo chrome_client_info = 338478298;
}
diff --git a/chromium/components/feed/core/proto/v2/wire/feed_query.proto b/chromium/components/feed/core/proto/v2/wire/feed_query.proto
index e69e919fae6..0cc218f07bb 100644
--- a/chromium/components/feed/core/proto/v2/wire/feed_query.proto
+++ b/chromium/components/feed/core/proto/v2/wire/feed_query.proto
@@ -8,6 +8,7 @@ package feedwire;
option optimize_for = LITE_RUNTIME;
+import "components/feed/core/proto/v2/wire/chrome_fulfillment_info.proto";
import "components/feed/core/proto/v2/wire/token.proto";
message FeedQuery {
@@ -48,5 +49,8 @@ message FeedQuery {
Tokens in_place_update_tokens = 5;
}
+ // Information on how to do content fulfillment for Chrome.
+ optional ChromeFulfillmentInfo chrome_fulfillment_info = 341477699;
+
reserved 2;
}
diff --git a/chromium/components/feed/core/proto/wire/chrome_fulfillment_info.proto b/chromium/components/feed/core/proto/wire/chrome_fulfillment_info.proto
new file mode 100644
index 00000000000..e78acbaedcb
--- /dev/null
+++ b/chromium/components/feed/core/proto/wire/chrome_fulfillment_info.proto
@@ -0,0 +1,20 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package feedwire1;
+
+option optimize_for = LITE_RUNTIME;
+
+option java_package = "org.chromium.components.feed.core.proto.wire";
+option java_outer_classname = "ChromeFulfillmentInfoProto";
+
+// Information on how to do content fulfillment for Chrome.
+message ChromeFulfillmentInfo {
+ // Whether the notice card has already been acknowledged by the user based on
+ // their views and clicks on the card. This is different from when the user
+ // explicitly dismiss the notice card by touching the button.
+ optional bool notice_card_acknowledged = 1;
+}
diff --git a/chromium/components/feed/core/proto/wire/feed_query.proto b/chromium/components/feed/core/proto/wire/feed_query.proto
index 2620819c328..e105058af93 100644
--- a/chromium/components/feed/core/proto/wire/feed_query.proto
+++ b/chromium/components/feed/core/proto/wire/feed_query.proto
@@ -11,6 +11,8 @@ option optimize_for = LITE_RUNTIME;
option java_package = "org.chromium.components.feed.core.proto.wire";
option java_outer_classname = "FeedQueryProto";
+import "components/feed/core/proto/wire/chrome_fulfillment_info.proto";
+
message FeedQuery {
enum RequestReason {
// Bucket for any not listed. Should not be used (prefer adding a new
@@ -49,4 +51,7 @@ message FeedQuery {
// Used to fetch the next page when scrolling copied from
// Token.next_page_token
optional bytes page_token = 2;
+
+ // Information on how to do content fulfillment for Chrome.
+ optional ChromeFulfillmentInfo chrome_fulfillment_info = 3;
}
diff --git a/chromium/components/feed/core/v2/BUILD.gn b/chromium/components/feed/core/v2/BUILD.gn
index 3de0962ba05..6331e2eceda 100644
--- a/chromium/components/feed/core/v2/BUILD.gn
+++ b/chromium/components/feed/core/v2/BUILD.gn
@@ -27,6 +27,8 @@ source_set("feed_core_v2") {
"image_fetcher.h",
"metrics_reporter.cc",
"metrics_reporter.h",
+ "notice_card_tracker.cc",
+ "notice_card_tracker.h",
"offline_page_spy.cc",
"offline_page_spy.h",
"prefs.cc",
@@ -63,6 +65,8 @@ source_set("feed_core_v2") {
"tasks/load_stream_from_store_task.h",
"tasks/load_stream_task.cc",
"tasks/load_stream_task.h",
+ "tasks/prefetch_images_task.cc",
+ "tasks/prefetch_images_task.h",
"tasks/upload_actions_task.cc",
"tasks/upload_actions_task.h",
"tasks/wait_for_store_initialize_task.cc",
@@ -71,6 +75,7 @@ source_set("feed_core_v2") {
"types.h",
]
deps = [
+ ":common",
"//components/feed/core:feed_core",
"//components/feed/core/common:feed_core_common",
"//components/history/core/browser",
@@ -97,6 +102,11 @@ source_set("feed_core_v2") {
]
}
+source_set("common") {
+ sources = [ "common_enums.h" ]
+ deps = []
+}
+
source_set("core_unit_tests") {
testonly = true
sources = [
@@ -106,6 +116,7 @@ source_set("core_unit_tests") {
"feed_stream_unittest.cc",
"image_fetcher_unittest.cc",
"metrics_reporter_unittest.cc",
+ "notice_card_tracker_unittest.cc",
"proto_util_unittest.cc",
"protocol_translator_unittest.cc",
"public/feed_service_unittest.cc",
@@ -122,6 +133,7 @@ source_set("core_unit_tests") {
]
deps = [
+ ":common",
":feed_core_v2",
":unit_tests_bundle_data",
"//base",
diff --git a/chromium/components/feed/core/v2/common_enums.h b/chromium/components/feed/core/v2/common_enums.h
new file mode 100644
index 00000000000..070dfc83916
--- /dev/null
+++ b/chromium/components/feed/core/v2/common_enums.h
@@ -0,0 +1,86 @@
+// Copyright 2020 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_FEED_CORE_V2_COMMON_ENUMS_H_
+#define COMPONENTS_FEED_CORE_V2_COMMON_ENUMS_H_
+
+// Unlike most code from feed/core, these enums are used by both iOS and
+// Android.
+namespace feed {
+
+// Values for the UMA ContentSuggestions.Feed.EngagementType
+// histogram. These values are persisted to logs. Entries should not be
+// renumbered and numeric values should never be reused. This must be kept
+// in sync with FeedEngagementType in enums.xml.
+enum class FeedEngagementType {
+ kFeedEngaged = 0,
+ kFeedEngagedSimple = 1,
+ kFeedInteracted = 2,
+ kDeprecatedFeedScrolled = 3,
+ kFeedScrolled = 4,
+ kMaxValue = kFeedScrolled,
+};
+
+// Values for the UMA ContentSuggestions.Feed.UserActions
+// histogram. These values are persisted to logs. Entries should not be
+// renumbered and numeric values should never be reused. This must be kept
+// in sync with FeedUserActionType in enums.xml.
+// Note: Most of these have a corresponding UserMetricsAction reported here.
+// Exceptions are described below.
+enum class FeedUserActionType {
+ // User tapped on card, opening the article in the same tab.
+ kTappedOnCard = 0,
+ // This is not an actual user action, so there will be no UserMetricsAction
+ // reported for this.
+ kShownCard = 1,
+ // User tapped on 'Send Feedback' in the back of card menu.
+ kTappedSendFeedback = 2,
+ // Discover feed header menu 'Learn More' tapped.
+ kTappedLearnMore = 3,
+ // User Tapped Hide Story in the back of card menu.
+ kTappedHideStory = 4,
+ // User Tapped Not Interested In X in the back of card menu.
+ kTappedNotInterestedIn = 5,
+ // Discover feed header menu 'Manage Interests' tapped.
+ kTappedManageInterests = 6,
+ kTappedDownload = 7,
+ // User opened the article in a new tab from the back of card menu.
+ kTappedOpenInNewTab = 8,
+ // User opened the back of card menu.
+ kOpenedContextMenu = 9,
+ // User action not reported here. See Suggestions.SurfaceVisible.
+ kOpenedFeedSurface = 10,
+ // User opened the article in an incognito tab from the back of card menu.
+ kTappedOpenInNewIncognitoTab = 11,
+ // Ephemeral change, likely due to hide story or not interested in.
+ kEphemeralChange = 12,
+ // Ephemeral change undone, likely due to pressing 'undo' on the snackbar.
+ kEphemeralChangeRejected = 13,
+ // Discover feed visibility toggled from header menu.
+ kTappedTurnOn = 14,
+ kTappedTurnOff = 15,
+ // Discover feed header menu 'Manage Activity' tapped.
+ kTappedManageActivity = 16,
+ // User added article to 'Read Later' list.
+ kAddedToReadLater = 17,
+ // User closed the back of card menu.
+ kClosedContextMenu = 18,
+ // Ephemeral change committed, likely due to dismissing an 'undo' snackbar.
+ kEphemeralChangeCommited = 19,
+ // User opened a Dialog. e.g. Report content Dialog. User action not reported
+ // here.
+ kOpenedDialog = 20,
+ // User closed a Dialog. e.g. Report content Dialog.
+ kClosedDialog = 21,
+ // User action caused a snackbar to be shown. User action not reported here.
+ kShowSnackbar = 22,
+ // User opened the native back of card menu.
+ kOpenedNativeContextMenu = 23,
+ // Highest enumerator. Recommended by Histogram metrics best practices.
+ kMaxValue = kOpenedNativeContextMenu,
+};
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_COMMON_ENUMS_H_
diff --git a/chromium/components/feed/core/v2/config.cc b/chromium/components/feed/core/v2/config.cc
index 753f275f00b..309e4583b89 100644
--- a/chromium/components/feed/core/v2/config.cc
+++ b/chromium/components/feed/core/v2/config.cc
@@ -76,6 +76,21 @@ void OverrideWithFinch(Config* config) {
kInterestFeedV2, "upload_actions_on_enter_background",
config->upload_actions_on_enter_background);
+ config->send_signed_out_session_logs =
+ base::GetFieldTrialParamByFeatureAsBool(
+ kInterestFeedV2, "send_signed_out_session_logs",
+ config->send_signed_out_session_logs);
+
+ config->session_id_max_age =
+ base::TimeDelta::FromDays(base::GetFieldTrialParamByFeatureAsInt(
+ kInterestFeedV2, "session_id_max_age_days",
+ config->session_id_max_age.InDays()));
+
+ config->max_prefetch_image_requests_per_refresh =
+ base::GetFieldTrialParamByFeatureAsInt(
+ kInterestFeedV2, "max_prefetch_image_requests_per_refresh",
+ config->max_prefetch_image_requests_per_refresh);
+
// Erase any capabilities with "enable_CAPABILITY = false" set.
base::EraseIf(config->experimental_capabilities, CapabilityDisabled);
}
diff --git a/chromium/components/feed/core/v2/config.h b/chromium/components/feed/core/v2/config.h
index 2789d0cd219..1eb0d612c12 100644
--- a/chromium/components/feed/core/v2/config.h
+++ b/chromium/components/feed/core/v2/config.h
@@ -38,6 +38,12 @@ struct Config {
int load_more_trigger_lookahead = 5;
// Whether to attempt uploading actions when Chrome is hidden.
bool upload_actions_on_enter_background = true;
+ // Whether to send (pseudonymous) logs for signed-out sessions.
+ bool send_signed_out_session_logs = false;
+ // The max age of a signed-out session token.
+ base::TimeDelta session_id_max_age = base::TimeDelta::FromDays(30);
+ // Maximum number of images prefetched per refresh.
+ int max_prefetch_image_requests_per_refresh = 50;
// Set of optional capabilities included in requests. See
// CreateFeedQueryRequest() for required capabilities.
base::flat_set<feedwire::Capability> experimental_capabilities = {
diff --git a/chromium/components/feed/core/v2/feed_network.h b/chromium/components/feed/core/v2/feed_network.h
index b0836218f4f..a5676de45a4 100644
--- a/chromium/components/feed/core/v2/feed_network.h
+++ b/chromium/components/feed/core/v2/feed_network.h
@@ -30,6 +30,8 @@ class FeedNetwork {
NetworkResponseInfo response_info;
// Response body if one was received.
std::unique_ptr<feedwire::Response> response_body;
+ // Whether the request was signed in.
+ bool was_signed_in;
};
// Result of SendActionRequest.
diff --git a/chromium/components/feed/core/v2/feed_network_impl.cc b/chromium/components/feed/core/v2/feed_network_impl.cc
index 4cc86a94c45..5f2c68ad471 100644
--- a/chromium/components/feed/core/v2/feed_network_impl.cc
+++ b/chromium/components/feed/core/v2/feed_network_impl.cc
@@ -12,6 +12,7 @@
#include "base/containers/flat_set.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "components/feed/core/common/pref_names.h"
@@ -39,6 +40,9 @@
#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
#include "third_party/zlib/google/compression_utils.h"
+// Token override for Feedv2NewTabPageCardInstrumentationTest.java:
+// #define TOKEN_OVERRIDE_FOR_TESTING "put-test-token-here"
+
namespace feed {
namespace {
constexpr char kApplicationXProtobuf[] = "application/x-protobuf";
@@ -312,8 +316,12 @@ class FeedNetworkImpl::NetworkFetch {
variations::SignedIn signed_in_status = variations::SignedIn::kNo;
if (!access_token_.empty()) {
+ base::StringPiece token = access_token_;
+#ifdef TOKEN_OVERRIDE_FOR_TESTING
+ token = TOKEN_OVERRIDE_FOR_TESTING;
+#endif
request.headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
- "Bearer " + access_token_);
+ base::StrCat({"Bearer ", token}));
signed_in_status = variations::SignedIn::kYes;
}
@@ -329,6 +337,7 @@ class FeedNetworkImpl::NetworkFetch {
tick_clock_->NowTicks() - entire_send_start_ticks_;
response_info.fetch_time = base::Time::Now();
response_info.base_request_url = GetUrlWithoutQuery(url_);
+ response_info.was_signed_in = !access_token_.empty();
// If overriding the feed host, try to grab the Bless nonce. This is
// strictly informational, and only displayed in snippets-internals.
diff --git a/chromium/components/feed/core/v2/feed_network_impl_unittest.cc b/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
index 6d759773629..c6ad6e97a6e 100644
--- a/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
+++ b/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h"
@@ -277,6 +277,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) {
"https://www.google.com/httpservice/retry/TrellisClankService/FeedQuery",
result.response_info.base_request_url);
EXPECT_NE(base::Time(), result.response_info.fetch_time);
+ EXPECT_TRUE(result.response_info.was_signed_in);
EXPECT_EQ(GetTestFeedResponse().response_version(),
result.response_body->response_version());
}
diff --git a/chromium/components/feed/core/v2/feed_store.cc b/chromium/components/feed/core/v2/feed_store.cc
index bb0add49a8e..65eafb55d54 100644
--- a/chromium/components/feed/core/v2/feed_store.cc
+++ b/chromium/components/feed/core/v2/feed_store.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
@@ -501,7 +501,7 @@ void FeedStore::RemoveActions(std::vector<LocalActionId> ids,
database_->UpdateEntries(
/*entries_to_save=*/std::make_unique<
std::vector<std::pair<std::string, feedstore::Record>>>(),
- /*key_to_remove=*/std::move(keys), std::move(callback));
+ /*keys_to_remove=*/std::move(keys), std::move(callback));
}
void FeedStore::Write(std::vector<feedstore::Record> records,
diff --git a/chromium/components/feed/core/v2/feed_store_unittest.cc b/chromium/components/feed/core/v2/feed_store_unittest.cc
index db7473c2d58..fe2a1ecd19c 100644
--- a/chromium/components/feed/core/v2/feed_store_unittest.cc
+++ b/chromium/components/feed/core/v2/feed_store_unittest.cc
@@ -11,7 +11,7 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/feed/core/proto/v2/wire/content_id.pb.h"
#include "components/feed/core/v2/protocol_translator.h"
diff --git a/chromium/components/feed/core/v2/feed_stream.cc b/chromium/components/feed/core/v2/feed_stream.cc
index 022579bcb33..a2794afa866 100644
--- a/chromium/components/feed/core/v2/feed_stream.cc
+++ b/chromium/components/feed/core/v2/feed_stream.cc
@@ -34,6 +34,7 @@
#include "components/feed/core/v2/tasks/clear_all_task.h"
#include "components/feed/core/v2/tasks/get_prefetch_suggestions_task.h"
#include "components/feed/core/v2/tasks/load_stream_task.h"
+#include "components/feed/core/v2/tasks/prefetch_images_task.h"
#include "components/feed/core/v2/tasks/upload_actions_task.h"
#include "components/feed/core/v2/tasks/wait_for_store_initialize_task.h"
#include "components/feed/feed_feature_list.h"
@@ -113,7 +114,7 @@ void FeedStream::Metadata::Populate(feedstore::Metadata metadata) {
metadata_ = std::move(metadata);
}
-std::string FeedStream::Metadata::GetConsistencyToken() const {
+const std::string& FeedStream::Metadata::GetConsistencyToken() const {
return metadata_.consistency_token();
}
@@ -122,6 +123,36 @@ void FeedStream::Metadata::SetConsistencyToken(std::string consistency_token) {
store_->WriteMetadata(metadata_, base::DoNothing());
}
+const std::string& FeedStream::Metadata::GetSessionIdToken() const {
+ return metadata_.session_id().token();
+}
+
+base::Time FeedStream::Metadata::GetSessionIdExpiryTime() const {
+ return base::Time::FromDeltaSinceWindowsEpoch(
+ base::TimeDelta::FromMilliseconds(
+ metadata_.session_id().expiry_time_ms()));
+}
+
+void FeedStream::Metadata::SetSessionId(std::string token,
+ base::Time expiry_time) {
+ feedstore::Metadata::SessionID* session_id = metadata_.mutable_session_id();
+ session_id->set_token(std::move(token));
+ session_id->set_expiry_time_ms(
+ expiry_time.ToDeltaSinceWindowsEpoch().InMilliseconds());
+ store_->WriteMetadata(metadata_, base::DoNothing());
+}
+
+void FeedStream::Metadata::MaybeUpdateSessionId(
+ base::Optional<std::string> token,
+ const base::Clock* clock) {
+ if (token && metadata_.session_id().token() != *token) {
+ base::Time expiry_time =
+ token->empty() ? base::Time()
+ : clock->Now() + GetFeedConfig().session_id_max_age;
+ SetSessionId(*token, expiry_time);
+ }
+}
+
LocalActionId FeedStream::Metadata::GetNextActionId() {
uint32_t id = metadata_.next_action_id();
// Never use 0, as that's an invalid LocalActionId.
@@ -157,7 +188,8 @@ FeedStream::FeedStream(RefreshTaskScheduler* refresh_task_scheduler,
chrome_info_(chrome_info),
task_queue_(this),
request_throttler_(profile_prefs, clock),
- metadata_(feed_store) {
+ metadata_(feed_store),
+ notice_card_tracker_(profile_prefs) {
static WireResponseTranslator default_translator;
wire_response_translator_ = &default_translator;
@@ -238,13 +270,32 @@ bool FeedStream::IsActivityLoggingEnabled() const {
void FeedStream::UpdateIsActivityLoggingEnabled() {
is_activity_logging_enabled_ =
- model_ && model_->signed_in() && model_->logging_enabled();
+ model_ &&
+ ((model_->signed_in() && model_->logging_enabled()) ||
+ (!model_->signed_in() && GetFeedConfig().send_signed_out_session_logs));
+}
+
+std::string FeedStream::GetSessionId() const {
+ return GetMetadata()->GetSessionIdToken();
+}
+
+void FeedStream::PrefetchImage(const GURL& url) {
+ delegate_->PrefetchImage(url);
}
void FeedStream::AttachSurface(SurfaceInterface* surface) {
metrics_reporter_->SurfaceOpened(surface->GetSurfaceId());
+
+ // Skip normal processing when overriding stream data from the internals page.
+ if (forced_stream_update_for_debugging_.updated_slices_size() > 0) {
+ surface_updater_->SurfaceAdded(surface);
+ surface->StreamUpdate(forced_stream_update_for_debugging_);
+ return;
+ }
+
TriggerStreamLoad();
surface_updater_->SurfaceAdded(surface);
+
// Cancel any scheduled model unload task.
++unload_on_detach_sequence_number_;
UpdateCanUploadActionsWithNoticeCard();
@@ -292,7 +343,7 @@ bool FeedStream::IsArticlesListVisible() {
return profile_prefs_->GetBoolean(prefs::kArticlesListVisible);
}
-std::string FeedStream::GetClientInstanceId() {
+std::string FeedStream::GetClientInstanceId() const {
return prefs::GetClientInstanceId(*profile_prefs_);
}
@@ -455,6 +506,11 @@ std::string FeedStream::DumpStateForDebugging() {
return ss.str();
}
+void FeedStream::SetForcedStreamUpdateForDebugging(
+ const feedui::StreamUpdate& stream_update) {
+ forced_stream_update_for_debugging_ = stream_update;
+}
+
base::Time FeedStream::GetLastFetchTime() {
const base::Time fetch_time =
profile_prefs_->GetTime(feed::prefs::kLastFetchAttemptTime);
@@ -556,12 +612,38 @@ bool FeedStream::ShouldForceSignedOutFeedQueryRequest() const {
return base::TimeTicks::Now() < signed_out_refreshes_until_;
}
-RequestMetadata FeedStream::GetRequestMetadata() {
+RequestMetadata FeedStream::GetRequestMetadata(bool is_for_next_page) const {
RequestMetadata result;
result.chrome_info = chrome_info_;
result.display_metrics = delegate_->GetDisplayMetrics();
result.language_tag = delegate_->GetLanguageTag();
- result.client_instance_id = GetClientInstanceId();
+ result.notice_card_acknowledged =
+ notice_card_tracker_.HasAcknowledgedNoticeCard();
+
+ if (is_for_next_page) {
+ // If we are continuing an existing feed, use whatever session continuity
+ // mechanism is currently associated with the stream: client-instance-id
+ // for signed-in feed, session_id token for signed-out.
+ DCHECK(model_);
+ if (model_->signed_in()) {
+ result.client_instance_id = GetClientInstanceId();
+ } else {
+ result.session_id = GetMetadata()->GetSessionIdToken();
+ }
+ } else {
+ // The request is for the first page of the feed. Use client_instance_id
+ // for signed in requests and session_id token (if any, and not expired)
+ // for signed-out.
+ if (delegate_->IsSignedIn() && !ShouldForceSignedOutFeedQueryRequest()) {
+ result.client_instance_id = GetClientInstanceId();
+ } else if (!GetMetadata()->GetSessionIdToken().empty() &&
+ GetMetadata()->GetSessionIdExpiryTime() > clock_->Now()) {
+ result.session_id = GetMetadata()->GetSessionIdToken();
+ }
+ }
+
+ DCHECK(result.session_id.empty() || result.client_instance_id.empty());
+
return result;
}
@@ -626,6 +708,10 @@ void FeedStream::BackgroundRefreshComplete(LoadStreamTask::Result result) {
if (result.loaded_new_content_from_network && prefetch_service_)
prefetch_service_->NewSuggestionsAvailable();
+ // Add prefetch images to task queue without waiting to finish
+ // since we treat them as best-effort.
+ task_queue_.AddTask(std::make_unique<PrefetchImagesTask>(this));
+
refresh_task_scheduler_->RefreshTaskComplete();
}
@@ -693,19 +779,22 @@ void FeedStream::UnloadModel() {
surface_updater_->SetModel(nullptr);
model_.reset();
}
-
void FeedStream::ReportOpenAction(const std::string& slice_id) {
int index = surface_updater_->GetSliceIndexFromSliceId(slice_id);
- if (index >= 0)
- metrics_reporter_->OpenAction(index);
+ if (index < 0)
+ index = MetricsReporter::kUnknownCardIndex;
+ metrics_reporter_->OpenAction(index);
+ notice_card_tracker_.OnOpenAction(index);
}
void FeedStream::ReportOpenVisitComplete(base::TimeDelta visit_time) {
metrics_reporter_->OpenVisitComplete(visit_time);
}
void FeedStream::ReportOpenInNewTabAction(const std::string& slice_id) {
int index = surface_updater_->GetSliceIndexFromSliceId(slice_id);
- if (index >= 0)
- metrics_reporter_->OpenInNewTabAction(index);
+ if (index < 0)
+ index = MetricsReporter::kUnknownCardIndex;
+ metrics_reporter_->OpenInNewTabAction(index);
+ notice_card_tracker_.OnOpenAction(index);
}
void FeedStream::ReportOpenInNewIncognitoTabAction() {
metrics_reporter_->OpenInNewIncognitoTabAction();
@@ -715,9 +804,11 @@ void FeedStream::ReportSliceViewed(SurfaceId surface_id,
int index = surface_updater_->GetSliceIndexFromSliceId(slice_id);
if (index >= 0) {
UpdateShownSlicesUploadCondition(index);
+ notice_card_tracker_.OnSliceViewed(index);
metrics_reporter_->ContentSliceViewed(surface_id, index);
}
}
+// TODO(crbug/1147237): Rename this method and related members?
bool FeedStream::CanUploadActions() const {
return can_upload_actions_with_notice_card_ ||
!prefs::GetLastFetchHadNoticeCard(*profile_prefs_);
@@ -746,11 +837,16 @@ void FeedStream::DeclareHasReachedConditionsToUploadActionsWithNoticeCard() {
void FeedStream::UpdateShownSlicesUploadCondition(int viewed_slice_index) {
constexpr int kShownSlicesThreshold = 2;
+ DCHECK(model_) << "Model was unloaded while handling a viewed slice";
+
// Don't take shown slices into consideration when the upload conditions has
// already been reached.
if (HasReachedConditionsToUploadActionsWithNoticeCard())
return;
+ if (!model_->signed_in())
+ return;
+
if (viewed_slice_index + 1 >= kShownSlicesThreshold)
DeclareHasReachedConditionsToUploadActionsWithNoticeCard();
}
diff --git a/chromium/components/feed/core/v2/feed_stream.h b/chromium/components/feed/core/v2/feed_stream.h
index 0b3082a4211..7b7fd04e6e7 100644
--- a/chromium/components/feed/core/v2/feed_stream.h
+++ b/chromium/components/feed/core/v2/feed_stream.h
@@ -16,8 +16,10 @@
#include "base/version.h"
#include "components/feed/core/common/enums.h"
#include "components/feed/core/common/user_classifier.h"
+#include "components/feed/core/proto/v2/ui.pb.h"
#include "components/feed/core/proto/v2/wire/response.pb.h"
#include "components/feed/core/v2/enums.h"
+#include "components/feed/core/v2/notice_card_tracker.h"
#include "components/feed/core/v2/protocol_translator.h"
#include "components/feed/core/v2/public/feed_stream_api.h"
#include "components/feed/core/v2/request_throttler.h"
@@ -68,6 +70,7 @@ class FeedStream : public FeedStreamApi,
virtual std::string GetLanguageTag() = 0;
virtual void ClearAll() = 0;
virtual bool IsSignedIn() = 0;
+ virtual void PrefetchImage(const GURL& url) = 0;
};
// Forwards to |feed::TranslateWireResponse()| by default. Can be overridden
@@ -90,9 +93,15 @@ class FeedStream : public FeedStreamApi,
void Populate(feedstore::Metadata metadata);
- std::string GetConsistencyToken() const;
+ const std::string& GetConsistencyToken() const;
void SetConsistencyToken(std::string consistency_token);
+ const std::string& GetSessionIdToken() const;
+ base::Time GetSessionIdExpiryTime() const;
+ void SetSessionId(std::string token, base::Time expiry_time);
+ void MaybeUpdateSessionId(base::Optional<std::string> token,
+ const base::Clock* clock);
+
LocalActionId GetNextActionId();
private:
@@ -123,11 +132,12 @@ class FeedStream : public FeedStreamApi,
// FeedStreamApi.
bool IsActivityLoggingEnabled() const override;
+ std::string GetSessionId() const override;
void AttachSurface(SurfaceInterface*) override;
void DetachSurface(SurfaceInterface*) override;
void SetArticlesListVisible(bool is_visible) override;
bool IsArticlesListVisible() override;
- std::string GetClientInstanceId() override;
+ std::string GetClientInstanceId() const override;
void ExecuteRefreshTask() override;
ImageFetchId FetchImage(
const GURL& url,
@@ -148,6 +158,8 @@ class FeedStream : public FeedStreamApi,
DebugStreamData GetDebugStreamData() override;
void ForceRefreshForDebugging() override;
std::string DumpStateForDebugging() override;
+ void SetForcedStreamUpdateForDebugging(
+ const feedui::StreamUpdate& stream_update) override;
void ReportSliceViewed(SurfaceId surface_id,
const std::string& slice_id) override;
@@ -211,8 +223,11 @@ class FeedStream : public FeedStreamApi,
FeedStore* GetStore() { return store_; }
RequestThrottler* GetRequestThrottler() { return &request_throttler_; }
Metadata* GetMetadata() { return &metadata_; }
+ const Metadata* GetMetadata() const { return &metadata_; }
MetricsReporter* GetMetricsReporter() const { return metrics_reporter_; }
+ void PrefetchImage(const GURL& url);
+
// Returns the time of the last content fetch.
base::Time GetLastFetchTime();
@@ -252,7 +267,7 @@ class FeedStream : public FeedStreamApi,
const base::Clock* GetClock() const { return clock_; }
const base::TickClock* GetTickClock() const { return tick_clock_; }
- RequestMetadata GetRequestMetadata();
+ RequestMetadata GetRequestMetadata(bool is_for_next_page) const;
const WireResponseTranslator* GetWireResponseTranslator() const {
return wire_response_translator_;
@@ -354,6 +369,12 @@ class FeedStream : public FeedStreamApi,
// To allow tests to wait on task queue idle.
base::RepeatingClosure idle_callback_;
+ // Stream update forced to use for new surfaces. This is provided in feed
+ // internals page for debugging purpose.
+ feedui::StreamUpdate forced_stream_update_for_debugging_;
+
+ NoticeCardTracker notice_card_tracker_;
+
base::WeakPtrFactory<FeedStream> weak_ptr_factory_{this};
};
diff --git a/chromium/components/feed/core/v2/feed_stream_unittest.cc b/chromium/components/feed/core/v2/feed_stream_unittest.cc
index ffbb96cc550..43831c0aa58 100644
--- a/chromium/components/feed/core/v2/feed_stream_unittest.cc
+++ b/chromium/components/feed/core/v2/feed_stream_unittest.cc
@@ -18,7 +18,7 @@
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_run_loop_timeout.h"
@@ -29,6 +29,7 @@
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/ui.pb.h"
+#include "components/feed/core/proto/v2/wire/chrome_client_info.pb.h"
#include "components/feed/core/proto/v2/wire/request.pb.h"
#include "components/feed/core/proto/v2/wire/there_and_back_again_data.pb.h"
#include "components/feed/core/proto/v2/xsurface.pb.h"
@@ -303,6 +304,7 @@ class TestFeedNetwork : public FeedNetwork {
result.response_info.status_code = 200;
result.response_info.response_body_bytes = 100;
result.response_info.fetch_duration = base::TimeDelta::FromMilliseconds(42);
+ result.response_info.was_signed_in = true;
if (injected_response_) {
result.response_body = std::make_unique<feedwire::Response>(
std::move(injected_response_.value()));
@@ -387,9 +389,12 @@ class TestWireResponseTranslator : public FeedStream::WireResponseTranslator {
return FeedStream::WireResponseTranslator::TranslateWireResponse(
std::move(response), source, was_signed_in_request, current_time);
}
- void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response) {
+ void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response,
+ base::Optional<std::string> session_id = base::nullopt) {
+ DCHECK(!response->stream_data.signed_in() || !session_id);
RefreshResponseData data;
data.model_update_request = std::move(response);
+ data.session_id = std::move(session_id);
InjectResponse(std::move(data));
}
void InjectResponse(RefreshResponseData response_data) {
@@ -573,10 +578,7 @@ class FeedStreamTest : public testing::Test, public FeedStream::Delegate {
CreateStream();
}
- virtual void SetupFeatures() {
- scoped_feature_list_.InitAndDisableFeature(
- feed::kInterestFeedV2ClicksAndViewsConditionalUpload);
- }
+ virtual void SetupFeatures() {}
void TearDown() override {
// Ensure the task queue can return to idle. Failure to do so may be due
@@ -600,6 +602,10 @@ class FeedStreamTest : public testing::Test, public FeedStream::Delegate {
std::string GetLanguageTag() override { return "en-US"; }
void ClearAll() override {}
bool IsSignedIn() override { return is_signed_in_; }
+ void PrefetchImage(const GURL& url) override {
+ prefetched_images_.push_back(url);
+ prefetch_image_call_count_++;
+ }
// For tests.
@@ -690,6 +696,8 @@ class FeedStreamTest : public testing::Test, public FeedStream::Delegate {
bool is_offline_ = false;
bool is_signed_in_ = true;
base::test::ScopedFeatureList scoped_feature_list_;
+ int prefetch_image_call_count_ = 0;
+ std::vector<GURL> prefetched_images_;
};
class FeedStreamConditionalActionsUploadTest : public FeedStreamTest {
@@ -742,6 +750,21 @@ TEST_F(FeedStreamTest, BackgroundRefreshSuccess) {
EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
}
+TEST_F(FeedStreamTest, BackgroundRefreshPrefetchesImages) {
+ // Trigger a background refresh.
+ response_translator_.InjectResponse(MakeTypicalInitialModelState());
+ stream_->ExecuteRefreshTask();
+ EXPECT_EQ(0, prefetch_image_call_count_);
+ WaitForIdleTaskQueue();
+
+ std::vector<GURL> expected_fetches(
+ {GURL("http://image0/"), GURL("http://favicon0/"), GURL("http://image1/"),
+ GURL("http://favicon1/")});
+ // Verify that images were prefetched.
+ EXPECT_EQ(4, prefetch_image_call_count_);
+ EXPECT_EQ(expected_fetches, prefetched_images_);
+}
+
TEST_F(FeedStreamTest, BackgroundRefreshNotAttemptedWhenModelIsLoading) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestSurface surface(stream_.get());
@@ -1089,14 +1112,78 @@ TEST_F(FeedStreamTest, LoadStreamAfterEulaIsAccepted) {
TEST_F(FeedStreamTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
stream_->OnAllHistoryDeleted();
+
+ const std::string kSessionId = "session-id";
+
+ // This test injects response post translation/parsing. We have to configure
+ // the response data that should come out of the translator, which should
+ // mark the request/response as having been made from the signed-out state.
+ StreamModelUpdateRequestGenerator model_generator;
+ model_generator.signed_in = false;
+
+ // Advance the clock, but not past the end of the forced-signed-out period.
task_environment_.FastForwardBy(kSuppressRefreshDuration -
base::TimeDelta::FromSeconds(1));
- response_translator_.InjectResponse(MakeTypicalInitialModelState());
+
+ // Refresh the feed, queuing up a signed-out response.
+ response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+ kSessionId);
TestSurface surface(stream_.get());
WaitForIdleTaskQueue();
+ // Validate that the network request was sent as signed out.
+ ASSERT_EQ(1, network_.send_query_call_count);
+ EXPECT_TRUE(network_.forced_signed_out_request);
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id()
+ .empty());
+
+ // Validate the downstream consumption of the response.
EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+ EXPECT_EQ(kSessionId, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_FALSE(stream_->GetModel()->signed_in());
+
+ // Advance the clock beyond the forced signed out period.
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+ EXPECT_FALSE(stream_->GetModel()->signed_in());
+
+ // Requests for subsequent pages continue the use existing session.
+ // Subsequent responses may omit the session id.
+ response_translator_.InjectResponse(model_generator.MakeNextPage());
+ stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ // Validate that the network request was sent as signed out and
+ // contained the session id.
+ ASSERT_EQ(2, network_.send_query_call_count);
EXPECT_TRUE(network_.forced_signed_out_request);
+ EXPECT_EQ(kSessionId, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id(),
+ kSessionId);
+
+ // The model should still be in the signed-out state.
+ EXPECT_FALSE(stream_->GetModel()->signed_in());
+
+ // Force a refresh of the feed by clearing the cache. The request for the
+ // first page should revert back to signed-in. The response data will denote
+ // a signed-in response with no session_id.
+ model_generator.signed_in = true;
+ response_translator_.InjectResponse(model_generator.MakeFirstPage());
+ stream_->OnCacheDataCleared();
+ WaitForIdleTaskQueue();
+
+ // Validate that a signed-in request was sent.
+ ASSERT_EQ(3, network_.send_query_call_count);
+ EXPECT_FALSE(network_.forced_signed_out_request);
+
+ // The model should now be in the signed-in state.
+ EXPECT_TRUE(stream_->GetModel()->signed_in());
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty());
}
TEST_F(FeedStreamTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
@@ -1109,6 +1196,7 @@ TEST_F(FeedStreamTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
EXPECT_FALSE(network_.forced_signed_out_request);
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty());
}
TEST_F(FeedStreamTest, ShouldMakeFeedQueryRequestConsumesQuota) {
@@ -1809,6 +1897,29 @@ TEST_F(FeedStreamTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
1, 1);
}
+TEST_F(FeedStreamConditionalActionsUploadTest,
+ DontTriggerActionsUploadWhenWasNotSignedIn) {
+ auto update_request = MakeTypicalInitialModelState();
+ update_request->stream_data.set_signed_in(false);
+ response_translator_.InjectResponse(std::move(update_request));
+ TestSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
+ // Try to reach conditions.
+ stream_->ReportSliceViewed(
+ surface.GetSurfaceId(),
+ surface.initial_state->updated_slices(1).slice().slice_id());
+
+ // Try to trigger an upload through a query.
+ stream_->OnEnterBackground();
+ WaitForIdleTaskQueue();
+
+ // Verify that even if the conditions were reached, the pref that enables the
+ // upload wasn't set to true because the latest refresh request wasn't signed
+ // in.
+ ASSERT_FALSE(stream_->CanUploadActions());
+}
+
TEST_F(FeedStreamTest, LoadStreamFromNetworkUploadsActions) {
stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
WaitForIdleTaskQueue();
@@ -1893,7 +2004,14 @@ TEST_F(FeedStreamTest, LoadMoreUpdatesIsActivityLoggingEnabled) {
CallbackReceiver<bool> callback;
stream_->LoadMore(surface.GetSurfaceId(), callback.Bind());
WaitForIdleTaskQueue();
- EXPECT_EQ(stream_->IsActivityLoggingEnabled(), signed_in && waa_on);
+ EXPECT_EQ(
+ stream_->IsActivityLoggingEnabled(),
+ (signed_in && waa_on) ||
+ (!signed_in && GetFeedConfig().send_signed_out_session_logs))
+ << "signed_in=" << signed_in << " waa_on=" << waa_on
+ << " privacy_notice_fulfilled=" << privacy_notice_fulfilled
+ << " send_signed_out_session_logs="
+ << GetFeedConfig().send_signed_out_session_logs;
}
}
}
@@ -1911,7 +2029,6 @@ TEST_F(FeedStreamConditionalActionsUploadTest,
response_translator_.InjectResponse(MakeTypicalNextPageState(
/* first_cluster_id= */ 0,
/* last_added_time= */ kTestTimeEpoch,
- /* signed_in= */ true,
/* logging_enabled= */ true,
/* privacy_notice_fulfilled= */ false));
@@ -2055,7 +2172,8 @@ TEST_F(FeedStreamTest, UploadActionsErasesStaleActionsByAttempts) {
TEST_F(FeedStreamTest, MetadataLoadedWhenDatabaseInitialized) {
ASSERT_TRUE(stream_->GetMetadata());
- // Set the token and increment next action ID.
+ const auto kExpiry = kTestTimeEpoch + base::TimeDelta::FromDays(1234);
+ stream_->GetMetadata()->SetSessionId("session-id", kExpiry);
stream_->GetMetadata()->SetConsistencyToken("token");
EXPECT_EQ(1, stream_->GetMetadata()->GetNextActionId().GetUnsafeValue());
@@ -2063,6 +2181,8 @@ TEST_F(FeedStreamTest, MetadataLoadedWhenDatabaseInitialized) {
CreateStream();
ASSERT_TRUE(stream_->GetMetadata());
+ EXPECT_EQ("session-id", stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiry, stream_->GetMetadata()->GetSessionIdExpiryTime());
EXPECT_EQ("token", stream_->GetMetadata()->GetConsistencyToken());
EXPECT_EQ(2, stream_->GetMetadata()->GetNextActionId().GetUnsafeValue());
}
@@ -2335,6 +2455,13 @@ TEST_F(FeedStreamTest, SendsClientInstanceId) {
.client_instance_id();
EXPECT_NE("", first_instance_id);
+ // No signed-out session id was in the request.
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id()
+ .empty());
+
// LoadMore, and verify the same token is used.
response_translator_.InjectResponse(MakeTypicalNextPageState(2));
stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
@@ -2345,15 +2472,311 @@ TEST_F(FeedStreamTest, SendsClientInstanceId) {
.client_info()
.client_instance_id());
+ // No signed-out session id was in the request.
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id()
+ .empty());
+
// Trigger a ClearAll to verify the instance ID changes.
stream_->OnSignedOut();
WaitForIdleTaskQueue();
+ EXPECT_FALSE(stream_->GetModel());
+ const bool is_for_next_page = false; // No model so no first page yet.
const std::string new_instance_id =
- stream_->GetRequestMetadata().client_instance_id;
+ stream_->GetRequestMetadata(is_for_next_page).client_instance_id;
ASSERT_NE("", new_instance_id);
ASSERT_NE(first_instance_id, new_instance_id);
}
+TEST_F(FeedStreamTest, LoadStreamSendsNoticeCardAcknowledgement) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+
+ store_->OverwriteStream(MakeTypicalInitialModelState(), base::DoNothing());
+ TestSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
+ // Generate 3 view actions and 1 click action to trigger the acknowledgement
+ // of the notice card.
+ const int notice_card_index = 0;
+ std::string slice_id =
+ surface.initial_state->updated_slices(notice_card_index)
+ .slice()
+ .slice_id();
+ stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id);
+ stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id);
+ stream_->ReportSliceViewed(surface.GetSurfaceId(), slice_id);
+ stream_->ReportOpenAction(slice_id);
+
+ response_translator_.InjectResponse(MakeTypicalInitialModelState());
+ refresh_scheduler_.Clear();
+ stream_->UnloadModel();
+ stream_->ExecuteRefreshTask();
+ WaitForIdleTaskQueue();
+
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .feed_query()
+ .chrome_fulfillment_info()
+ .notice_card_acknowledged());
+}
+
+TEST_F(FeedStreamTest, GetSetAndUpdateSessionId) {
+ const std::string kToken1 = "token1";
+ const std::string kToken2 = "token2";
+ const base::Time kExpiryTime1 =
+ kTestTimeEpoch + base::TimeDelta::FromHours(2);
+ const base::Time kExpiryTime2 =
+ kTestTimeEpoch + GetFeedConfig().session_id_max_age;
+ ASSERT_NE(kExpiryTime1, kExpiryTime2);
+
+ // The stream metadata is initialized with an empty token and expiry time.
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty());
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdExpiryTime().is_null());
+
+ // Verify that directly calling SetSessionId works as expected.
+ stream_->GetMetadata()->SetSessionId(kToken1, kExpiryTime1);
+ EXPECT_EQ(kToken1, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiryTime1, stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // Updating the token with nullopt is a NOP.
+ stream_->GetMetadata()->MaybeUpdateSessionId(base::nullopt,
+ stream_->GetClock());
+ EXPECT_EQ(kToken1, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiryTime1, stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // Updating the token with the same value is a NOP.
+ stream_->GetMetadata()->MaybeUpdateSessionId(kToken1, stream_->GetClock());
+ EXPECT_EQ(kToken1, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiryTime1, stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // Updating the token with a different value resets the token and assigns a
+ // new expiry time.
+ stream_->GetMetadata()->MaybeUpdateSessionId(kToken2, stream_->GetClock());
+ EXPECT_EQ(kToken2, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiryTime2, stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // Updating the token with the empty string clears its value.
+ stream_->GetMetadata()->MaybeUpdateSessionId("", stream_->GetClock());
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty());
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdExpiryTime().is_null());
+}
+
+TEST_F(FeedStreamTest, SignedOutSessionIdConsistency) {
+ const std::string kSessionToken1("session-token-1");
+ const std::string kSessionToken2("session-token-2");
+
+ is_signed_in_ = false;
+
+ StreamModelUpdateRequestGenerator model_generator;
+ model_generator.signed_in = false;
+
+ // (1) Do an initial load of the store
+ // - this should trigger a network request
+ // - the request should not include client-instance-id
+ // - the request should not include a session-id
+ // - the stream should capture the session-id token from the response
+ response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+ kSessionToken1);
+ TestSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(1, network_.send_query_call_count);
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .client_instance_id()
+ .empty());
+ EXPECT_FALSE(network_.query_request_sent->feed_request()
+ .client_info()
+ .has_chrome_client_info());
+ EXPECT_EQ(kSessionToken1, stream_->GetMetadata()->GetSessionIdToken());
+ const base::Time kSessionToken1ExpiryTime =
+ stream_->GetMetadata()->GetSessionIdExpiryTime();
+
+ // (2) LoadMore: the server returns the same session-id token
+ // - this should trigger a network request
+ // - the request should not include client-instance-id
+ // - the request should include the first session-id
+ // - the stream should retain the first session-id
+ // - the session-id's expiry time should be unchanged
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+ response_translator_.InjectResponse(model_generator.MakeNextPage(2),
+ kSessionToken1);
+ stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(2, network_.send_query_call_count);
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .client_instance_id()
+ .empty());
+ EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id());
+ EXPECT_EQ(kSessionToken1, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kSessionToken1ExpiryTime,
+ stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // (3) LoadMore: the server omits returning a session-id token
+ // - this should trigger a network request
+ // - the request should not include client-instance-id
+ // - the request should include the first session-id
+ // - the stream should retain the first session-id
+ // - the session-id's expiry time should be unchanged
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+ response_translator_.InjectResponse(model_generator.MakeNextPage(3));
+ stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(3, network_.send_query_call_count);
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .client_instance_id()
+ .empty());
+ EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id());
+ EXPECT_EQ(kSessionToken1, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kSessionToken1ExpiryTime,
+ stream_->GetMetadata()->GetSessionIdExpiryTime());
+
+ // (4) LoadMore: the server returns new session id.
+ // - this should trigger a network request
+ // - the request should not include client-instance-id
+ // - the request should include the first session-id
+ // - the stream should retain the second session-id
+ // - the new session-id's expiry time should be updated
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+ response_translator_.InjectResponse(model_generator.MakeNextPage(4),
+ kSessionToken2);
+ stream_->LoadMore(surface.GetSurfaceId(), base::DoNothing());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(4, network_.send_query_call_count);
+ EXPECT_TRUE(network_.query_request_sent->feed_request()
+ .client_info()
+ .client_instance_id()
+ .empty());
+ EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id());
+ EXPECT_EQ(kSessionToken2, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kSessionToken1ExpiryTime + base::TimeDelta::FromSeconds(3),
+ stream_->GetMetadata()->GetSessionIdExpiryTime());
+}
+
+TEST_F(FeedStreamTest, ClearAllResetsSessionId) {
+ is_signed_in_ = false;
+
+ // Initialize a session id.
+ stream_->GetMetadata()->MaybeUpdateSessionId("session-id",
+ stream_->GetClock());
+ ASSERT_FALSE(stream_->GetMetadata()->GetSessionIdToken().empty());
+ ASSERT_FALSE(stream_->GetMetadata()->GetSessionIdExpiryTime().is_null());
+
+ // Trigger a ClearAll.
+ stream_->OnCacheDataCleared();
+ WaitForIdleTaskQueue();
+
+ // Session-ID should be wiped.
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdToken().empty());
+ EXPECT_TRUE(stream_->GetMetadata()->GetSessionIdExpiryTime().is_null());
+}
+
+TEST_F(FeedStreamTest, SignedOutSessionIdExpiry) {
+ const std::string kSessionToken1("session-token-1");
+ const std::string kSessionToken2("session-token-2");
+
+ is_signed_in_ = false;
+
+ StreamModelUpdateRequestGenerator model_generator;
+ model_generator.signed_in = false;
+
+ // (1) Do an initial load of the store
+ // - this should trigger a network request
+ // - the request should not include a session-id
+ // - the stream should capture the session-id token from the response
+ response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+ kSessionToken1);
+ TestSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(1, network_.send_query_call_count);
+ EXPECT_FALSE(network_.query_request_sent->feed_request()
+ .client_info()
+ .has_chrome_client_info());
+ EXPECT_EQ(kSessionToken1, stream_->GetMetadata()->GetSessionIdToken());
+
+ // (2) Reload the stream from the network:
+ // - Detach the surface, advance the clock beyond the stale content
+ // threshold, re-attach the surface.
+ // - this should trigger a network request
+ // - the request should include kSessionToken1
+ // - the stream should retain the original session-id
+ surface.Detach();
+ task_environment_.FastForwardBy(GetFeedConfig().stale_content_threshold +
+ base::TimeDelta::FromSeconds(1));
+ response_translator_.InjectResponse(model_generator.MakeFirstPage());
+ surface.Attach(stream_.get());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(2, network_.send_query_call_count);
+ EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+ .client_info()
+ .chrome_client_info()
+ .session_id());
+ EXPECT_EQ(kSessionToken1, stream_->GetMetadata()->GetSessionIdToken());
+
+ // (3) Reload the stream from the network:
+ // - Detach the surface, advance the clock beyond the session id max age
+ // threshold, re-attach the surface.
+ // - this should trigger a network request
+ // - the request should not include a session-id
+ // - the stream should get a new session-id
+ surface.Detach();
+ task_environment_.FastForwardBy(GetFeedConfig().session_id_max_age -
+ GetFeedConfig().stale_content_threshold);
+ ASSERT_LT(stream_->GetMetadata()->GetSessionIdExpiryTime(),
+ task_environment_.GetMockClock()->Now());
+ response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+ kSessionToken2);
+ surface.Attach(stream_.get());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(3, network_.send_query_call_count);
+ EXPECT_FALSE(network_.query_request_sent->feed_request()
+ .client_info()
+ .has_chrome_client_info());
+ EXPECT_EQ(kSessionToken2, stream_->GetMetadata()->GetSessionIdToken());
+}
+
+TEST_F(FeedStreamTest, SessionIdPersistsAcrossStreamLoads) {
+ const std::string kSessionToken("session-token-ftw");
+ const base::Time kExpiryTime =
+ kTestTimeEpoch + GetFeedConfig().session_id_max_age;
+
+ StreamModelUpdateRequestGenerator model_generator;
+ model_generator.signed_in = false;
+ is_signed_in_ = false;
+
+ // (1) Do an initial load of the store
+ // - this should trigger a network request
+ // - the stream should capture the session-id token from the response
+ response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+ kSessionToken);
+ TestSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(1, network_.send_query_call_count);
+
+ // (2) Reload the metadata from disk.
+ // - the network query call count should be unchanged
+ // - the session token and expiry time should have been reloaded.
+ surface.Detach();
+ CreateStream();
+ WaitForIdleTaskQueue();
+ ASSERT_EQ(1, network_.send_query_call_count);
+ EXPECT_EQ(kSessionToken, stream_->GetMetadata()->GetSessionIdToken());
+ EXPECT_EQ(kExpiryTime, stream_->GetMetadata()->GetSessionIdExpiryTime());
+}
+
} // namespace
} // namespace feed
diff --git a/chromium/components/feed/core/v2/image_fetcher_unittest.cc b/chromium/components/feed/core/v2/image_fetcher_unittest.cc
index ba2dbe4f548..185945c7d89 100644
--- a/chromium/components/feed/core/v2/image_fetcher_unittest.cc
+++ b/chromium/components/feed/core/v2/image_fetcher_unittest.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/feed/core/v2/public/types.h"
diff --git a/chromium/components/feed/core/v2/metrics_reporter.cc b/chromium/components/feed/core/v2/metrics_reporter.cc
index d23a99f17b9..df136e67a40 100644
--- a/chromium/components/feed/core/v2/metrics_reporter.cc
+++ b/chromium/components/feed/core/v2/metrics_reporter.cc
@@ -11,12 +11,13 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
+#include "components/feed/core/v2/common_enums.h"
#include "components/feed/core/v2/prefs.h"
namespace feed {
namespace {
-using feed::internal::FeedEngagementType;
-using feed::internal::FeedUserActionType;
+using feed::FeedEngagementType;
+using feed::FeedUserActionType;
const int kMaxSuggestionsTotal = 50;
// Maximum time to wait before declaring a load operation failed.
// For both ContentSuggestions.Feed.UserJourney.OpenFeed
diff --git a/chromium/components/feed/core/v2/metrics_reporter.h b/chromium/components/feed/core/v2/metrics_reporter.h
index 31489456ead..21515c8697f 100644
--- a/chromium/components/feed/core/v2/metrics_reporter.h
+++ b/chromium/components/feed/core/v2/metrics_reporter.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_FEED_CORE_V2_METRICS_REPORTER_H_
#define COMPONENTS_FEED_CORE_V2_METRICS_REPORTER_H_
+#include <climits>
#include <map>
#include "base/memory/weak_ptr.h"
@@ -17,50 +18,16 @@ namespace base {
class TickClock;
} // namespace base
namespace feed {
-namespace internal {
-// This enum is used for a UMA histogram. Keep in sync with FeedEngagementType
-// in enums.xml.
-enum class FeedEngagementType {
- kFeedEngaged = 0,
- kFeedEngagedSimple = 1,
- kFeedInteracted = 2,
- kDeprecatedFeedScrolled = 3,
- kFeedScrolled = 4,
- kMaxValue = FeedEngagementType::kFeedScrolled,
-};
-
-// This enum must match FeedUserActionType in enums.xml.
-// Note that most of these have a corresponding UserMetricsAction reported here.
-// Exceptions are described below.
-enum class FeedUserActionType {
- kTappedOnCard = 0,
- // This is not an actual user action, so there will be no UserMetricsAction
- // reported for this.
- kShownCard = 1,
- kTappedSendFeedback = 2,
- kTappedLearnMore = 3,
- kTappedHideStory = 4,
- kTappedNotInterestedIn = 5,
- kTappedManageInterests = 6,
- kTappedDownload = 7,
- kTappedOpenInNewTab = 8,
- kOpenedContextMenu = 9,
- // User action not reported here. See Suggestions.SurfaceVisible.
- kOpenedFeedSurface = 10,
- kTappedOpenInNewIncognitoTab = 11,
- kEphemeralChange = 12,
- kEphemeralChangeRejected = 13,
- kTappedTurnOn = 14,
- kTappedTurnOff = 15,
- kMaxValue = kTappedTurnOff,
-};
-
-} // namespace internal
// Reports UMA metrics for feed.
// Note this is inherited only for testing.
class MetricsReporter {
public:
+ // For 'index_in_stream' parameters, when the card index is unknown.
+ // This is most likely to happen when the action originates from the bottom
+ // sheet.
+ static const int kUnknownCardIndex = INT_MAX;
+
explicit MetricsReporter(const base::TickClock* clock,
PrefService* profile_prefs);
virtual ~MetricsReporter();
diff --git a/chromium/components/feed/core/v2/metrics_reporter_unittest.cc b/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
index c38bdb43cad..e768420fa4c 100644
--- a/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
+++ b/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
@@ -12,12 +12,11 @@
#include "base/test/task_environment.h"
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/shared_prefs/pref_names.h"
+#include "components/feed/core/v2/common_enums.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace feed {
-using feed::internal::FeedEngagementType;
-using feed::internal::FeedUserActionType;
constexpr SurfaceId kSurfaceId = SurfaceId(5);
const base::TimeDelta kEpsilon = base::TimeDelta::FromMilliseconds(1);
diff --git a/chromium/components/feed/core/v2/notice_card_tracker.cc b/chromium/components/feed/core/v2/notice_card_tracker.cc
new file mode 100644
index 00000000000..cb318c8678e
--- /dev/null
+++ b/chromium/components/feed/core/v2/notice_card_tracker.cc
@@ -0,0 +1,97 @@
+// Copyright 2020 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/feed/core/v2/notice_card_tracker.h"
+
+#include "components/feed/core/v2/prefs.h"
+#include "components/feed/feed_feature_list.h"
+#include "components/prefs/pref_service.h"
+
+namespace feed {
+namespace {
+
+int GetNoticeCardIndex() {
+ // Infer that the notice card is at the 2nd position when the feature related
+ // to putting the notice card at the second position is enabled.
+ if (base::FeatureList::IsEnabled(
+ feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) {
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace
+
+NoticeCardTracker::NoticeCardTracker(PrefService* profile_prefs)
+ : profile_prefs_(profile_prefs) {
+ DCHECK(profile_prefs_);
+}
+
+void NoticeCardTracker::OnSliceViewed(int index) {
+ MaybeUpdateNoticeCardViewsCount(index);
+}
+
+void NoticeCardTracker::OnOpenAction(int index) {
+ MaybeUpdateNoticeCardClicksCount(index);
+}
+
+bool NoticeCardTracker::HasAcknowledgedNoticeCard() const {
+ if (!base::FeatureList::IsEnabled(feed::kInterestFeedNoticeCardAutoDismiss))
+ return false;
+
+ int views_count_threshold = base::GetFieldTrialParamByFeatureAsInt(
+ feed::kInterestFeedNoticeCardAutoDismiss,
+ kNoticeCardViewsCountThresholdParamName, 3);
+ DCHECK(views_count_threshold >= 0);
+ int clicks_count_threshold = base::GetFieldTrialParamByFeatureAsInt(
+ feed::kInterestFeedNoticeCardAutoDismiss,
+ kNoticeCardClicksCountThresholdParamName, 1);
+ DCHECK(clicks_count_threshold >= 0);
+
+ DCHECK(views_count_threshold > 0 || clicks_count_threshold > 0)
+ << "all notice card auto-dismiss thresholds are set to 0 when there "
+ "should be at least one threshold above 0";
+
+ if (views_count_threshold > 0 &&
+ prefs::GetNoticeCardViewsCount(*profile_prefs_) >=
+ views_count_threshold) {
+ return true;
+ }
+
+ if (clicks_count_threshold > 0 &&
+ prefs::GetNoticeCardClicksCount(*profile_prefs_) >=
+ clicks_count_threshold) {
+ return true;
+ }
+
+ return false;
+}
+
+bool NoticeCardTracker::HasNoticeCardActionsCountPrerequisites(int index) {
+ if (!base::FeatureList::IsEnabled(feed::kInterestFeedNoticeCardAutoDismiss))
+ return false;
+
+ if (!prefs::GetLastFetchHadNoticeCard(*profile_prefs_)) {
+ return false;
+ }
+
+ if (index != GetNoticeCardIndex()) {
+ return false;
+ }
+ return true;
+}
+void NoticeCardTracker::MaybeUpdateNoticeCardViewsCount(int index) {
+ if (!HasNoticeCardActionsCountPrerequisites(index))
+ return;
+
+ prefs::IncrementNoticeCardViewsCount(*profile_prefs_);
+}
+void NoticeCardTracker::MaybeUpdateNoticeCardClicksCount(int index) {
+ if (!HasNoticeCardActionsCountPrerequisites(index))
+ return;
+
+ prefs::IncrementNoticeCardClicksCount(*profile_prefs_);
+}
+
+} // namespace feed \ No newline at end of file
diff --git a/chromium/components/feed/core/v2/notice_card_tracker.h b/chromium/components/feed/core/v2/notice_card_tracker.h
new file mode 100644
index 00000000000..db9f71815d1
--- /dev/null
+++ b/chromium/components/feed/core/v2/notice_card_tracker.h
@@ -0,0 +1,47 @@
+// Copyright 2020 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_FEED_CORE_V2_NOTICE_CARD_TRACKER_H_
+#define COMPONENTS_FEED_CORE_V2_NOTICE_CARD_TRACKER_H_
+
+class PrefService;
+
+namespace feed {
+
+constexpr char kNoticeCardViewsCountThresholdParamName[] =
+ "notice-card-views-count-threshold";
+constexpr char kNoticeCardClicksCountThresholdParamName[] =
+ "notice-card-clicks-count-threshold";
+
+// Tracker for the notice card related actions that also provide signals based
+// on those.
+class NoticeCardTracker {
+ public:
+ explicit NoticeCardTracker(PrefService* profile_prefs);
+
+ NoticeCardTracker(const NoticeCardTracker&) = delete;
+ NoticeCardTracker& operator=(const NoticeCardTracker&) = delete;
+
+ // Capture the actions.
+
+ void OnSliceViewed(int index);
+ void OnOpenAction(int index);
+
+ // Get signals based on the actions.
+
+ // Indicates whether there were enough views or clicks done on the notice
+ // card to consider it as acknowledged by the user.
+ bool HasAcknowledgedNoticeCard() const;
+
+ private:
+ bool HasNoticeCardActionsCountPrerequisites(int index);
+ void MaybeUpdateNoticeCardViewsCount(int index);
+ void MaybeUpdateNoticeCardClicksCount(int index);
+
+ PrefService* profile_prefs_;
+};
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_NOTICE_CARD_TRACKER_H_ \ No newline at end of file
diff --git a/chromium/components/feed/core/v2/notice_card_tracker_unittest.cc b/chromium/components/feed/core/v2/notice_card_tracker_unittest.cc
new file mode 100644
index 00000000000..60efb9d10aa
--- /dev/null
+++ b/chromium/components/feed/core/v2/notice_card_tracker_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2020 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/feed/core/v2/notice_card_tracker.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/feed/core/common/pref_names.h"
+#include "components/feed/core/v2/prefs.h"
+#include "components/feed/feed_feature_list.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+namespace {
+
+class NoticeCardTrackerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ feed::RegisterProfilePrefs(profile_prefs_.registry());
+ ;
+ }
+
+ protected:
+ TestingPrefServiceSimple profile_prefs_;
+};
+
+TEST_F(NoticeCardTrackerTest,
+ TrackingNoticeCardActionsDoesntUpdateCountsWhenNoNoticeCard) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+ NoticeCardTracker tracker(&profile_prefs_);
+
+ prefs::SetLastFetchHadNoticeCard(profile_prefs_, false);
+
+ // Generate enough views to reach the acknowlegement threshold, but there was
+ // no notice card in the feed.
+ const int notice_card_index = 0;
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ TrackingNoticeCardActionsDoesntUpdateCountsForNonNoticeCard) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+ NoticeCardTracker tracker(&profile_prefs_);
+
+ // Generate enough views to reach the acknowlegement threshold, but the views
+ // were not on the notice card.
+ const int non_notice_card_index = 1;
+ tracker.OnSliceViewed(non_notice_card_index);
+ tracker.OnSliceViewed(non_notice_card_index);
+ tracker.OnSliceViewed(non_notice_card_index);
+
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ AcknowledgedNoticeCardWhenEnoughViewsAndNoticeCardAt1stPos) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+ NoticeCardTracker tracker(&profile_prefs_);
+
+ const int notice_card_index = 0;
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+
+ EXPECT_TRUE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ AcknowledgedNoticeCardWhenEnoughViewsAndNoticeCardAt2ndPos) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ /*enabled_features=*/{feed::kInterestFeedNoticeCardAutoDismiss,
+ feed::
+ kInterestFeedV2ClicksAndViewsConditionalUpload},
+ /*disabled_features=*/{});
+ NoticeCardTracker tracker(&profile_prefs_);
+
+ const int notice_card_index = 1;
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+
+ EXPECT_TRUE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ DontAcknowledgedNoticeCardWhenNotEnoughViewsNorClicks) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+ NoticeCardTracker tracker(&profile_prefs_);
+
+ // Generate views but not enough to reach the threshold.
+ const int notice_card_index = 0;
+ tracker.OnSliceViewed(notice_card_index);
+ tracker.OnSliceViewed(notice_card_index);
+
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest, DontAcknowledgedNoticeCardWhenFeatureDisabled) {
+ // Generate enough views and clicks on the notice card to reach the threshold,
+ // but the feature is disabled.
+ prefs::IncrementNoticeCardClicksCount(profile_prefs_);
+ prefs::IncrementNoticeCardViewsCount(profile_prefs_);
+ prefs::IncrementNoticeCardViewsCount(profile_prefs_);
+ prefs::IncrementNoticeCardViewsCount(profile_prefs_);
+
+ NoticeCardTracker tracker(&profile_prefs_);
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ DontAcknowledgedNoticeCardFromViewsCountWhenThresholdIsZero) {
+ base::FieldTrialParams params;
+ params[kNoticeCardViewsCountThresholdParamName] = "0";
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ feed::kInterestFeedNoticeCardAutoDismiss, params);
+
+ NoticeCardTracker tracker(&profile_prefs_);
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+TEST_F(NoticeCardTrackerTest,
+ DontAcknowledgedNoticeCardFromClicksCountWhenThresholdIsZero) {
+ base::FieldTrialParams params;
+ params[kNoticeCardClicksCountThresholdParamName] = "0";
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ feed::kInterestFeedNoticeCardAutoDismiss, params);
+
+ NoticeCardTracker tracker(&profile_prefs_);
+ EXPECT_FALSE(tracker.HasAcknowledgedNoticeCard());
+}
+
+} // namespace
+} // namespace feed \ No newline at end of file
diff --git a/chromium/components/feed/core/v2/prefs.cc b/chromium/components/feed/core/v2/prefs.cc
index 562ff7d9c4f..49ef37fd3fe 100644
--- a/chromium/components/feed/core/v2/prefs.cc
+++ b/chromium/components/feed/core/v2/prefs.cc
@@ -106,6 +106,24 @@ bool GetHasReachedClickAndViewActionsUploadConditions(
feed::prefs::kHasReachedClickAndViewActionsUploadConditions);
}
+void IncrementNoticeCardViewsCount(PrefService& pref_service) {
+ int count = pref_service.GetInteger(feed::prefs::kNoticeCardViewsCount);
+ pref_service.SetInteger(feed::prefs::kNoticeCardViewsCount, count + 1);
+}
+
+int GetNoticeCardViewsCount(const PrefService& pref_service) {
+ return pref_service.GetInteger(feed::prefs::kNoticeCardViewsCount);
+}
+
+void IncrementNoticeCardClicksCount(PrefService& pref_service) {
+ int count = pref_service.GetInteger(feed::prefs::kNoticeCardClicksCount);
+ pref_service.SetInteger(feed::prefs::kNoticeCardClicksCount, count + 1);
+}
+
+int GetNoticeCardClicksCount(const PrefService& pref_service) {
+ return pref_service.GetInteger(feed::prefs::kNoticeCardClicksCount);
+}
+
} // namespace prefs
} // namespace feed
diff --git a/chromium/components/feed/core/v2/prefs.h b/chromium/components/feed/core/v2/prefs.h
index 634bddb16c6..e16befa3e47 100644
--- a/chromium/components/feed/core/v2/prefs.h
+++ b/chromium/components/feed/core/v2/prefs.h
@@ -52,6 +52,16 @@ void SetHasReachedClickAndViewActionsUploadConditions(PrefService& pref_service,
bool GetHasReachedClickAndViewActionsUploadConditions(
const PrefService& pref_service);
+// Increment the stored notice card views count by 1.
+void IncrementNoticeCardViewsCount(PrefService& pref_service);
+
+int GetNoticeCardViewsCount(const PrefService& pref_service);
+
+// Increment the stored notice card clicks count by 1.
+void IncrementNoticeCardClicksCount(PrefService& pref_service);
+
+int GetNoticeCardClicksCount(const PrefService& pref_service);
+
} // namespace prefs
} // namespace feed
diff --git a/chromium/components/feed/core/v2/proto_util.cc b/chromium/components/feed/core/v2/proto_util.cc
index aa21f4a1b93..d680ecfcf3f 100644
--- a/chromium/components/feed/core/v2/proto_util.cc
+++ b/chromium/components/feed/core/v2/proto_util.cc
@@ -13,10 +13,12 @@
#include "build/build_config.h"
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/wire/capability.pb.h"
+#include "components/feed/core/proto/v2/wire/chrome_client_info.pb.h"
#include "components/feed/core/proto/v2/wire/feed_request.pb.h"
#include "components/feed/core/proto/v2/wire/request.pb.h"
#include "components/feed/core/v2/config.h"
#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/feed_feature_list.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
@@ -124,9 +126,15 @@ feedwire::Request CreateFeedQueryRequest(
*feed_request.mutable_client_info() = CreateClientInfo(request_metadata);
feedwire::FeedQuery& query = *feed_request.mutable_feed_query();
query.set_reason(request_reason);
- if (!consistency_token.empty()) {
+
+ // |consistency_token|, for action reporting, is only applicable to signed-in
+ // requests. The presence of |client_instance_id|, also signed-in only, can be
+ // used a proxy for checking if we're creating a signed-in request.
+ if (!consistency_token.empty() &&
+ !request_metadata.client_instance_id.empty()) {
feed_request.mutable_consistency_token()->set_token(consistency_token);
}
+
if (!next_page_token.empty()) {
DCHECK_EQ(request_reason, feedwire::FeedQuery::NEXT_PAGE_SCROLL);
query.mutable_next_page_token()
@@ -136,6 +144,16 @@ feedwire::Request CreateFeedQueryRequest(
return request;
}
+void SetNoticeCardAcknowledged(feedwire::Request* request,
+ const RequestMetadata& request_metadata) {
+ if (request_metadata.notice_card_acknowledged) {
+ request->mutable_feed_request()
+ ->mutable_feed_query()
+ ->mutable_chrome_fulfillment_info()
+ ->set_notice_card_acknowledged(true);
+ }
+}
+
} // namespace
std::string ContentIdString(const feedwire::ContentId& content_id) {
@@ -176,7 +194,6 @@ bool CompareContent(const feedstore::Content& a, const feedstore::Content& b) {
feedwire::ClientInfo CreateClientInfo(const RequestMetadata& request_metadata) {
feedwire::ClientInfo client_info;
- client_info.set_client_instance_id(request_metadata.client_instance_id);
feedwire::DisplayInfo& display_info = *client_info.add_display_info();
display_info.set_screen_density(request_metadata.display_metrics.density);
@@ -196,6 +213,19 @@ feedwire::ClientInfo CreateClientInfo(const RequestMetadata& request_metadata) {
*client_info.mutable_platform_version() = GetPlatformVersionMessage();
*client_info.mutable_app_version() =
GetAppVersionMessage(request_metadata.chrome_info);
+
+ // client_instance_id and session_id should not both be set at the same time.
+ DCHECK(request_metadata.client_instance_id.empty() ||
+ request_metadata.session_id.empty());
+
+ // Populate client_instance_id, session_id, or neither.
+ if (!request_metadata.client_instance_id.empty()) {
+ client_info.set_client_instance_id(request_metadata.client_instance_id);
+ } else if (!request_metadata.session_id.empty()) {
+ client_info.mutable_chrome_client_info()->set_session_id(
+ request_metadata.session_id);
+ }
+
return client_info;
}
@@ -203,8 +233,10 @@ feedwire::Request CreateFeedQueryRefreshRequest(
feedwire::FeedQuery::RequestReason request_reason,
const RequestMetadata& request_metadata,
const std::string& consistency_token) {
- return CreateFeedQueryRequest(request_reason, request_metadata,
- consistency_token, std::string());
+ feedwire::Request request = CreateFeedQueryRequest(
+ request_reason, request_metadata, consistency_token, std::string());
+ SetNoticeCardAcknowledged(&request, request_metadata);
+ return request;
}
feedwire::Request CreateFeedQueryLoadMoreRequest(
diff --git a/chromium/components/feed/core/v2/proto_util_unittest.cc b/chromium/components/feed/core/v2/proto_util_unittest.cc
index 53eecb56451..8d53ebe00fa 100644
--- a/chromium/components/feed/core/v2/proto_util_unittest.cc
+++ b/chromium/components/feed/core/v2/proto_util_unittest.cc
@@ -108,5 +108,31 @@ TEST(ProtoUtilTest, DisableCapabilitiesWithFinch) {
EXPECT_TRUE(HasCapability(request, feedwire::Capability::PREFETCH_METADATA));
}
+TEST(ProtoUtilTest, NoticeCardAcknowledged) {
+ RequestMetadata request_metadata;
+ request_metadata.notice_card_acknowledged = true;
+ feedwire::Request request = CreateFeedQueryRefreshRequest(
+ feedwire::FeedQuery::MANUAL_REFRESH, request_metadata,
+ /*consistency_token=*/std::string());
+
+ EXPECT_TRUE(request.feed_request()
+ .feed_query()
+ .chrome_fulfillment_info()
+ .notice_card_acknowledged());
+}
+
+TEST(ProtoUtilTest, NoticeCardNotAcknowledged) {
+ RequestMetadata request_metadata;
+ request_metadata.notice_card_acknowledged = false;
+ feedwire::Request request = CreateFeedQueryRefreshRequest(
+ feedwire::FeedQuery::MANUAL_REFRESH, request_metadata,
+ /*consistency_token=*/std::string());
+
+ EXPECT_FALSE(request.feed_request()
+ .feed_query()
+ .chrome_fulfillment_info()
+ .notice_card_acknowledged());
+}
+
} // namespace
} // namespace feed
diff --git a/chromium/components/feed/core/v2/protocol_translator.cc b/chromium/components/feed/core/v2/protocol_translator.cc
index db128746859..ea69442f531 100644
--- a/chromium/components/feed/core/v2/protocol_translator.cc
+++ b/chromium/components/feed/core/v2/protocol_translator.cc
@@ -306,6 +306,18 @@ RefreshResponseData TranslateWireResponse(
result->stream_data.set_privacy_notice_fulfilled(
response_metadata.privacy_notice_fulfilled());
+ base::Optional<std::string> session_id = base::nullopt;
+ if (was_signed_in_request) {
+ // Signed-in requests don't use session_id tokens; set an empty value to
+ // ensure that there are no old session_id tokens left hanging around.
+ session_id = std::string();
+ } else if (response_metadata.has_session_id()) {
+ // Signed-out requests can set a new session token; otherwise, we leave
+ // the default base::nullopt value to keep whatever token is already in
+ // play.
+ session_id = response_metadata.session_id();
+ }
+
MetricsReporter::ActivityLoggingEnabled(response_metadata.logging_enabled());
MetricsReporter::NoticeCardFulfilledObsolete(
response_metadata.privacy_notice_fulfilled());
@@ -313,6 +325,7 @@ RefreshResponseData TranslateWireResponse(
RefreshResponseData response_data;
response_data.model_update_request = std::move(result);
response_data.request_schedule = std::move(global_data.request_schedule);
+ response_data.session_id = std::move(session_id);
return response_data;
}
diff --git a/chromium/components/feed/core/v2/protocol_translator.h b/chromium/components/feed/core/v2/protocol_translator.h
index 3728e1e5dc4..b83a23fdecf 100644
--- a/chromium/components/feed/core/v2/protocol_translator.h
+++ b/chromium/components/feed/core/v2/protocol_translator.h
@@ -64,6 +64,9 @@ struct RefreshResponseData {
// Server-defined request schedule, if provided.
base::Optional<RequestSchedule> request_schedule;
+
+ // Server-defined session id token, if provided.
+ base::Optional<std::string> session_id;
};
base::Optional<feedstore::DataOperation> TranslateDataOperation(
diff --git a/chromium/components/feed/core/v2/public/feed_service.cc b/chromium/components/feed/core/v2/public/feed_service.cc
index 7e7a59776ee..b5836074240 100644
--- a/chromium/components/feed/core/v2/public/feed_service.cc
+++ b/chromium/components/feed/core/v2/public/feed_service.cc
@@ -121,6 +121,9 @@ class FeedService::StreamDelegateImpl : public FeedStream::Delegate {
return service_delegate_->GetLanguageTag();
}
void ClearAll() override { service_delegate_->ClearAll(); }
+ void PrefetchImage(const GURL& url) override {
+ service_delegate_->PrefetchImage(url);
+ }
bool IsSignedIn() override { return identity_manager_->HasPrimaryAccount(); }
private:
diff --git a/chromium/components/feed/core/v2/public/feed_service.h b/chromium/components/feed/core/v2/public/feed_service.h
index ae3b5ddefb0..d8c1f2aa222 100644
--- a/chromium/components/feed/core/v2/public/feed_service.h
+++ b/chromium/components/feed/core/v2/public/feed_service.h
@@ -67,6 +67,8 @@ class FeedService : public KeyedService {
virtual DisplayMetrics GetDisplayMetrics() = 0;
// Clear all stored data.
virtual void ClearAll() = 0;
+ // Fetch the image and store it in the disk cache.
+ virtual void PrefetchImage(const GURL& url) = 0;
};
// Construct a FeedService given an already constructed FeedStream.
diff --git a/chromium/components/feed/core/v2/public/feed_stream_api.h b/chromium/components/feed/core/v2/public/feed_stream_api.h
index d3bfabc34de..b33d9e87239 100644
--- a/chromium/components/feed/core/v2/public/feed_stream_api.h
+++ b/chromium/components/feed/core/v2/public/feed_stream_api.h
@@ -63,9 +63,14 @@ class FeedStreamApi {
// as the feed is refreshed or the user signs in/out.
virtual bool IsActivityLoggingEnabled() const = 0;
- // Returns the client_instance_id. This value is reset whenever the feed
- // stream is cleared (on sign-in, sign-out, and some data clear events).
- virtual std::string GetClientInstanceId() = 0;
+ // Returns the signed-in client_instance_id. This value is reset whenever the
+ // feed stream is cleared (on sign-in, sign-out, and some data clear events).
+ virtual std::string GetClientInstanceId() const = 0;
+
+ // Returns the client's signed-out session id. This value is reset whenever
+ // the feed stream is cleared (on sign-in, sign-out, and some data clear
+ // events).
+ virtual std::string GetSessionId() const = 0;
// Invoked by RefreshTaskScheduler's scheduled task.
virtual void ExecuteRefreshTask() = 0;
@@ -170,6 +175,9 @@ class FeedStreamApi {
virtual void ForceRefreshForDebugging() = 0;
// Dumps some state information for debugging.
virtual std::string DumpStateForDebugging() = 0;
+ // Forces to render a StreamUpdate on all subsequent surface attaches.
+ virtual void SetForcedStreamUpdateForDebugging(
+ const feedui::StreamUpdate& stream_update) = 0;
};
} // namespace feed
diff --git a/chromium/components/feed/core/v2/public/types.h b/chromium/components/feed/core/v2/public/types.h
index 7680ef75813..0bdc72e7f07 100644
--- a/chromium/components/feed/core/v2/public/types.h
+++ b/chromium/components/feed/core/v2/public/types.h
@@ -48,6 +48,7 @@ struct NetworkResponseInfo {
std::string bless_nonce;
GURL base_request_url;
size_t response_body_bytes = 0;
+ bool was_signed_in = false;
};
struct NetworkResponse {
diff --git a/chromium/components/feed/core/v2/tasks/load_more_task.cc b/chromium/components/feed/core/v2/tasks/load_more_task.cc
index 8c6dc6370aa..6afb90d4780 100644
--- a/chromium/components/feed/core/v2/tasks/load_more_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_more_task.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/time/clock.h"
#include "base/time/tick_clock.h"
@@ -48,22 +48,34 @@ void LoadMoreTask::Run() {
}
void LoadMoreTask::UploadActionsComplete(UploadActionsTask::Result result) {
+ StreamModel* model = stream_->GetModel();
+ DCHECK(model) << "Model was unloaded outside of a Task";
+
+ // Determine whether the load more request should be forced signed-out
+ // regardless of the live sign-in state of the client.
+ //
+ // The signed-in state of the model is used instead of using
+ // FeedStream#ShouldForceSignedOutFeedQueryRequest because the load more
+ // requests should be in the same signed-in state as the prior requests that
+ // filled the model to have consistent data.
+ //
+ // The sign-in state of the load stream request that brings the initial
+ // content determines the sign-in state of the subsequent load more requests.
+ // This avoids a possible situation where there would be a mix of signed-in
+ // and signed-out content, which we don't want.
+ bool force_signed_out_request = !model->signed_in();
// Send network request.
- bool force_signed_out_request =
- stream_->ShouldForceSignedOutFeedQueryRequest();
fetch_start_time_ = stream_->GetTickClock()->NowTicks();
stream_->GetNetwork()->SendQueryRequest(
CreateFeedQueryLoadMoreRequest(
- stream_->GetRequestMetadata(),
+ stream_->GetRequestMetadata(/*is_for_next_page=*/true),
stream_->GetMetadata()->GetConsistencyToken(),
stream_->GetModel()->GetNextPageToken()),
force_signed_out_request,
- base::BindOnce(&LoadMoreTask::QueryRequestComplete, GetWeakPtr(),
- force_signed_out_request));
+ base::BindOnce(&LoadMoreTask::QueryRequestComplete, GetWeakPtr()));
}
void LoadMoreTask::QueryRequestComplete(
- bool was_forced_signed_out_request,
FeedNetwork::QueryRequestResult result) {
StreamModel* model = stream_->GetModel();
DCHECK(model) << "Model was unloaded outside of a Task";
@@ -71,20 +83,21 @@ void LoadMoreTask::QueryRequestComplete(
if (!result.response_body)
return Done(LoadStreamStatus::kNoResponseBody);
- bool was_signed_in_request =
- !was_forced_signed_out_request && stream_->IsSignedIn();
-
RefreshResponseData translated_response =
stream_->GetWireResponseTranslator()->TranslateWireResponse(
*result.response_body,
StreamModelUpdateRequest::Source::kNetworkLoadMore,
- was_signed_in_request, stream_->GetClock()->Now());
+ result.response_info.was_signed_in, stream_->GetClock()->Now());
if (!translated_response.model_update_request)
return Done(LoadStreamStatus::kProtoTranslationFailed);
loaded_new_content_from_network_ =
!translated_response.model_update_request->stream_structures.empty();
+
+ stream_->GetMetadata()->MaybeUpdateSessionId(translated_response.session_id,
+ stream_->GetClock());
+
model->Update(std::move(translated_response.model_update_request));
if (translated_response.request_schedule)
diff --git a/chromium/components/feed/core/v2/tasks/load_more_task.h b/chromium/components/feed/core/v2/tasks/load_more_task.h
index 397c4eb1cab..538fcf9c75d 100644
--- a/chromium/components/feed/core/v2/tasks/load_more_task.h
+++ b/chromium/components/feed/core/v2/tasks/load_more_task.h
@@ -44,8 +44,7 @@ class LoadMoreTask : public offline_pages::Task {
}
void UploadActionsComplete(UploadActionsTask::Result result);
- void QueryRequestComplete(bool was_signed_in_request,
- FeedNetwork::QueryRequestResult result);
+ void QueryRequestComplete(FeedNetwork::QueryRequestResult result);
void Done(LoadStreamStatus status);
FeedStream* stream_; // Unowned.
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
index 71fff522a38..999d5f6fae9 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
@@ -126,8 +126,6 @@ void LoadStreamFromStoreTask::Complete(LoadStreamStatus status) {
if (status == LoadStreamStatus::kLoadedFromStore &&
load_type_ == LoadType::kFullLoad) {
task_result.update_request = std::move(update_request_);
- } else {
- task_result.consistency_token = consistency_token_;
}
std::move(result_callback_).Run(std::move(task_result));
TaskComplete();
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
index 61dee09d676..fef672dc9ac 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
+++ b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
@@ -76,7 +76,6 @@ class LoadStreamFromStoreTask : public offline_pages::Task {
// Data to be stuffed into the Result when the task is complete.
std::unique_ptr<StreamModelUpdateRequest> update_request_;
- std::string consistency_token_;
std::vector<feedstore::StoredAction> pending_actions_;
base::WeakPtrFactory<LoadStreamFromStoreTask> weak_ptr_factory_{this};
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_task.cc b/chromium/components/feed/core/v2/tasks/load_stream_task.cc
index c061f9d91bf..9b4f04b1e69 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_stream_task.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/time/clock.h"
#include "base/time/tick_clock.h"
@@ -123,15 +123,14 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
latencies_->StepComplete(LoadLatencyTimes::kUploadActions);
stream_->GetNetwork()->SendQueryRequest(
CreateFeedQueryRefreshRequest(
- GetRequestReason(load_type_), stream_->GetRequestMetadata(),
+ GetRequestReason(load_type_),
+ stream_->GetRequestMetadata(/*is_for_next_page=*/false),
stream_->GetMetadata()->GetConsistencyToken()),
force_signed_out_request,
- base::BindOnce(&LoadStreamTask::QueryRequestComplete, GetWeakPtr(),
- force_signed_out_request));
+ base::BindOnce(&LoadStreamTask::QueryRequestComplete, GetWeakPtr()));
}
void LoadStreamTask::QueryRequestComplete(
- bool was_forced_signed_out_request,
FeedNetwork::QueryRequestResult result) {
latencies_->StepComplete(LoadLatencyTimes::kQueryRequest);
@@ -149,14 +148,11 @@ void LoadStreamTask::QueryRequestComplete(
return Done(LoadStreamStatus::kNoResponseBody);
}
- bool was_signed_in_request =
- !was_forced_signed_out_request && stream_->IsSignedIn();
-
RefreshResponseData response_data =
stream_->GetWireResponseTranslator()->TranslateWireResponse(
*result.response_body,
StreamModelUpdateRequest::Source::kNetworkUpdate,
- was_signed_in_request, stream_->GetClock()->Now());
+ result.response_info.was_signed_in, stream_->GetClock()->Now());
if (!response_data.model_update_request)
return Done(LoadStreamStatus::kProtoTranslationFailed);
@@ -172,6 +168,9 @@ void LoadStreamTask::QueryRequestComplete(
stream_->SetLastStreamLoadHadNoticeCard(isNoticeCardFulfilled);
MetricsReporter::NoticeCardFulfilled(isNoticeCardFulfilled);
+ stream_->GetMetadata()->MaybeUpdateSessionId(response_data.session_id,
+ stream_->GetClock());
+
if (load_type_ != LoadType::kBackgroundRefresh) {
auto model = std::make_unique<StreamModel>();
model->Update(std::move(response_data.model_update_request));
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_task.h b/chromium/components/feed/core/v2/tasks/load_stream_task.h
index 6e8993959ac..dd4c210db73 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_task.h
+++ b/chromium/components/feed/core/v2/tasks/load_stream_task.h
@@ -74,8 +74,7 @@ class LoadStreamTask : public offline_pages::Task {
void LoadFromStoreComplete(LoadStreamFromStoreTask::Result result);
void UploadActionsComplete(UploadActionsTask::Result result);
- void QueryRequestComplete(bool was_signed_in_request,
- FeedNetwork::QueryRequestResult result);
+ void QueryRequestComplete(FeedNetwork::QueryRequestResult result);
void Done(LoadStreamStatus status);
LoadType load_type_;
diff --git a/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc b/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc
new file mode 100644
index 00000000000..f8a927ba6af
--- /dev/null
+++ b/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc
@@ -0,0 +1,100 @@
+// Copyright 2020 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/feed/core/v2/tasks/prefetch_images_task.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "components/feed/core/proto/v2/wire/stream_structure.pb.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/feed_store.h"
+#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/core/v2/stream_model.h"
+#include "components/feed/core/v2/tasks/load_stream_from_store_task.h"
+
+namespace feed {
+namespace {
+
+// Converts a URL string into a GURL. If the string is not a valid URL, returns
+// an empty GURL. Since GURL::spec() asserts on invalid URLs, this is necessary
+// to scrub the incoming data from the wire.
+GURL SpecToGURL(const std::string& url_string) {
+ GURL url(url_string);
+ if (!url.is_valid())
+ url = GURL();
+ return url;
+}
+
+} // namespace
+
+PrefetchImagesTask::PrefetchImagesTask(FeedStream* stream) : stream_(stream) {
+ max_images_per_refresh_ =
+ GetFeedConfig().max_prefetch_image_requests_per_refresh;
+}
+
+PrefetchImagesTask::~PrefetchImagesTask() = default;
+
+void PrefetchImagesTask::Run() {
+ if (stream_->GetModel()) {
+ PrefetchImagesFromModel(*stream_->GetModel());
+ return;
+ }
+
+ load_from_store_task_ = std::make_unique<LoadStreamFromStoreTask>(
+ LoadStreamFromStoreTask::LoadType::kFullLoad, stream_->GetStore(),
+ stream_->GetClock(),
+ base::BindOnce(&PrefetchImagesTask::LoadStreamComplete,
+ base::Unretained(this)));
+
+ load_from_store_task_->Execute(base::DoNothing());
+}
+
+void PrefetchImagesTask::LoadStreamComplete(
+ LoadStreamFromStoreTask::Result result) {
+ if (!result.update_request) {
+ TaskComplete();
+ return;
+ }
+
+ // It is a bit dangerous to retain the model loaded here. The normal
+ // LoadStreamTask flow has various considerations for metrics and signalling
+ // surfaces to update. For this reason, we're not going to retain the loaded
+ // model for use outside of this task.
+ StreamModel model;
+ model.Update(std::move(result.update_request));
+ PrefetchImagesFromModel(model);
+}
+
+void PrefetchImagesTask::PrefetchImagesFromModel(const StreamModel& model) {
+ for (ContentRevision rev : model.GetContentList()) {
+ const feedstore::Content* content = model.FindContent(rev);
+ if (!content)
+ continue;
+ for (const feedwire::PrefetchMetadata& metadata :
+ content->prefetch_metadata()) {
+ MaybePrefetchImage(SpecToGURL(metadata.image_url()));
+ MaybePrefetchImage(SpecToGURL(metadata.favicon_url()));
+ for (const std::string& url : metadata.additional_image_urls()) {
+ MaybePrefetchImage(SpecToGURL(url));
+ }
+ }
+ }
+
+ TaskComplete();
+}
+
+void PrefetchImagesTask::MaybePrefetchImage(const GURL& gurl) {
+ // If we've already fetched this url, or we've hit the max number of fetches,
+ // then don't send a fetch request.
+ if (!gurl.is_valid() ||
+ (previously_fetched_.find(gurl.spec()) != previously_fetched_.end()) ||
+ previously_fetched_.size() >= max_images_per_refresh_)
+ return;
+ previously_fetched_.insert(gurl.spec());
+ stream_->PrefetchImage(gurl);
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/tasks/prefetch_images_task.h b/chromium/components/feed/core/v2/tasks/prefetch_images_task.h
new file mode 100644
index 00000000000..ddc24a6cc76
--- /dev/null
+++ b/chromium/components/feed/core/v2/tasks/prefetch_images_task.h
@@ -0,0 +1,51 @@
+// Copyright 2020 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_FEED_CORE_V2_TASKS_PREFETCH_IMAGES_TASK_H_
+#define COMPONENTS_FEED_CORE_V2_TASKS_PREFETCH_IMAGES_TASK_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/feed/core/v2/tasks/load_stream_from_store_task.h"
+#include "components/offline_pages/task/task.h"
+
+namespace feed {
+class FeedStream;
+class StreamModel;
+
+// Prefetch the images in the model.
+class PrefetchImagesTask : public offline_pages::Task {
+ public:
+ explicit PrefetchImagesTask(FeedStream* stream);
+ ~PrefetchImagesTask() override;
+ PrefetchImagesTask(const PrefetchImagesTask&) = delete;
+ PrefetchImagesTask& operator=(const PrefetchImagesTask&) = delete;
+
+ private:
+ base::WeakPtr<PrefetchImagesTask> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ // offline_pages::Task.
+ void Run() override;
+
+ void LoadStreamComplete(LoadStreamFromStoreTask::Result result);
+
+ void PrefetchImagesFromModel(const StreamModel& model);
+
+ void MaybePrefetchImage(const GURL& gurl);
+
+ FeedStream* stream_;
+ std::unordered_set<std::string> previously_fetched_;
+ unsigned long max_images_per_refresh_;
+
+ std::unique_ptr<LoadStreamFromStoreTask> load_from_store_task_;
+
+ base::WeakPtrFactory<PrefetchImagesTask> weak_ptr_factory_{this};
+};
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_TASKS_PREFETCH_IMAGES_TASK_H_
diff --git a/chromium/components/feed/core/v2/types.h b/chromium/components/feed/core/v2/types.h
index 883effa2bfb..508e56c98e4 100644
--- a/chromium/components/feed/core/v2/types.h
+++ b/chromium/components/feed/core/v2/types.h
@@ -39,7 +39,9 @@ struct RequestMetadata {
ChromeInfo chrome_info;
std::string language_tag;
std::string client_instance_id;
+ std::string session_id;
DisplayMetrics display_metrics;
+ bool notice_card_acknowledged = false;
};
// Data internal to MetricsReporter which is persisted to Prefs.
diff --git a/chromium/components/feed/features.gni b/chromium/components/feed/features.gni
index 022f876896e..627f7d7bf52 100644
--- a/chromium/components/feed/features.gni
+++ b/chromium/components/feed/features.gni
@@ -2,12 +2,28 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/android/channel.gni")
+
# Chrome can be built with any combination of v1/v2 enabled.
# When both are enabled, we use the InterestFeedV2 feature to select which
# one is used at runtime.
# If both are false, some of the Feed V2 UI classes are still used to display
# the NTP.
declare_args() {
+ # Whether version 1 of the NTP feed is enabled in the build.
enable_feed_v1 = is_android
+
+ # Whether version 2 of the NTP feed is enabled in the build.
enable_feed_v2 = is_android
+
+ # Whether to include Feed V2 in ChromeModern builds.
+ enable_feed_v2_modern = true
+
+ # Whether to include Feed V2 as a DFM in ChromeModern builds.
+ dfmify_feed_v2_modern = false
+}
+
+if (is_android && android_channel != "default") {
+ # You probably don't want to build without either version in a Clank release.
+ assert(enable_feed_v1 || enable_feed_v2)
}
diff --git a/chromium/components/feed/feed_feature_list.cc b/chromium/components/feed/feed_feature_list.cc
index 8065e083e04..f9cf11aba5e 100644
--- a/chromium/components/feed/feed_feature_list.cc
+++ b/chromium/components/feed/feed_feature_list.cc
@@ -30,9 +30,6 @@ const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess{
&kInterestFeedContentSuggestions,
"only_set_last_refresh_attempt_on_success", true};
-const base::Feature kInterestFeedFeedback{"InterestFeedFeedback",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kReportFeedUserActions{"ReportFeedUserActions",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -47,6 +44,15 @@ const base::Feature kInterestFeedV2ClicksAndViewsConditionalUpload{
"InterestFeedV2ClickAndViewActionsConditionalUpload",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Feature that allows the client to automatically dismiss the notice card based
+// on the clicks and views on the notice card.
+const base::Feature kInterestFeedNoticeCardAutoDismiss{
+ "InterestFeedNoticeCardAutoDismiss", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Used for A:B testing of a bug fix (crbug.com/1151391).
+const base::Feature kInterestFeedSpinnerAlwaysAnimate{
+ "InterestFeedSpinnerAlwaysAnimate", base::FEATURE_DISABLED_BY_DEFAULT};
+
const char kDefaultReferrerUrl[] =
"https://www.googleapis.com/auth/chrome-content-suggestions";
diff --git a/chromium/components/feed/feed_feature_list.h b/chromium/components/feed/feed_feature_list.h
index 3fd0e3cb300..432ba988ff8 100644
--- a/chromium/components/feed/feed_feature_list.h
+++ b/chromium/components/feed/feed_feature_list.h
@@ -24,8 +24,6 @@ extern const base::FeatureParam<int> kTimeoutDurationSeconds;
extern const base::FeatureParam<bool> kThrottleBackgroundFetches;
extern const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess;
-extern const base::Feature kInterestFeedFeedback;
-
// Indicates if user card clicks and views in Chrome's feed should be reported
// for personalization. Also enables the feed header menu to manage the feed.
extern const base::Feature kReportFeedUserActions;
@@ -33,6 +31,10 @@ extern const base::Feature kReportFeedUserActions;
extern const base::Feature kInterestFeedV1ClicksAndViewsConditionalUpload;
extern const base::Feature kInterestFeedV2ClicksAndViewsConditionalUpload;
+extern const base::Feature kInterestFeedNoticeCardAutoDismiss;
+
+extern const base::Feature kInterestFeedSpinnerAlwaysAnimate;
+
std::string GetFeedReferrerUrl();
} // namespace feed
diff --git a/chromium/components/feedback/BUILD.gn b/chromium/components/feedback/BUILD.gn
index 3fa9e8bfa62..1def6918706 100644
--- a/chromium/components/feedback/BUILD.gn
+++ b/chromium/components/feedback/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//testing/libfuzzer/fuzzer_test.gni")
+
static_library("feedback") {
sources = [
"feedback_common.cc",
@@ -76,3 +78,9 @@ source_set("unit_tests") {
"//testing/gtest",
]
}
+
+fuzzer_test("redaction_tool_fuzzer") {
+ sources = [ "redaction_tool_fuzzer.cc" ]
+ deps = [ ":feedback" ]
+ dict = "redaction_tool_fuzzer.dict"
+}
diff --git a/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc b/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc
index aa66eef5fe4..49b410f38d7 100644
--- a/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_dispatch_unittest.cc
@@ -11,7 +11,7 @@
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/feedback/feedback_uploader_factory.h"
#include "components/variations/net/variations_http_headers.h"
#include "components/variations/variations_associated_data.h"
diff --git a/chromium/components/feedback/redaction_tool_fuzzer.cc b/chromium/components/feedback/redaction_tool_fuzzer.cc
new file mode 100644
index 00000000000..16e5858101b
--- /dev/null
+++ b/chromium/components/feedback/redaction_tool_fuzzer.cc
@@ -0,0 +1,46 @@
+// Copyright 2020 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "components/feedback/redaction_tool.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider provider(data, size);
+
+ int first_party_extension_id_count = provider.ConsumeIntegralInRange(-1, 50);
+ // This is the storage for the strings inside first_party_extension_ids. This
+ // is to make sure the char *'s we pass to the RedactionTool constructor are
+ // deleted correctly -- they must be deleted after redactor is destructed, but
+ // not leaked.
+ std::vector<std::string> first_party_extension_id_store;
+ // The first_party_extension_ids we pass to the RedactionTool constructor.
+ // This owns the array but not the pointed-to strings. Note that if
+ // first_party_extension_id_count is -1, this is not set so we pass nullptr to
+ // the constructor; that's deliberate.
+ std::unique_ptr<const char*[]> first_party_extension_ids;
+ if (first_party_extension_id_count >= 0) {
+ first_party_extension_id_store.reserve(first_party_extension_id_count);
+ first_party_extension_ids =
+ std::make_unique<const char*[]>(first_party_extension_id_count + 1);
+ for (int i = 0; i < first_party_extension_id_count; ++i) {
+ constexpr int kArbitraryMaxNameLength = 4096;
+ first_party_extension_id_store.emplace_back(
+ provider.ConsumeRandomLengthString(kArbitraryMaxNameLength));
+ first_party_extension_ids[i] = first_party_extension_id_store[i].c_str();
+ }
+ first_party_extension_ids[first_party_extension_id_count] = nullptr;
+ }
+
+ feedback::RedactionTool redactor(first_party_extension_ids.get());
+ redactor.Redact(provider.ConsumeRemainingBytesAsString());
+ return 0;
+}
diff --git a/chromium/components/feedback/redaction_tool_fuzzer.dict b/chromium/components/feedback/redaction_tool_fuzzer.dict
new file mode 100644
index 00000000000..38104450ef4
--- /dev/null
+++ b/chromium/components/feedback/redaction_tool_fuzzer.dict
@@ -0,0 +1,42 @@
+# Copyright 2020 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.
+
+# Literals from kCustomPatternsWithContext strings
+CellID="Cell ID:"
+LocAC="Location area code:"
+SSID1="ssid"
+SSIDHex="SSID - hexdump"
+SSID1="SSID"
+Serial1="serial number"
+Serial2="Serial Number"
+GAIA="gaia_id"
+GAIAId="id:"
+GAIAEmail=", email"
+UUID="UUID="
+UUIDEnd="xxx"
+VolumeLabel="LABEL="
+VolumeLabel2="/media/removable/"
+
+# Literals from kCustomPatternsWithoutContext, and other things that look like
+# URLS and Emails
+URL1="http://"
+URL2="https://"
+URL3="ftp://"
+URL4="chrome://"
+URL5="chrome-extension://"
+URL6="android://"
+URL7="rtsp://"
+URLHost="foo.com"
+URLPort=":80"
+URLQuery="?"
+URLFragment="#"
+
+# Email Symbols
+EMailAt="@"
+EMailDot="."
+EMailExample="a@b.c"
+
+# MAC Symbols
+MACColon=":"
+MACExample="10:fd:b5:ec:b1:3e"
diff --git a/chromium/components/feedback/system_logs/system_logs_fetcher.cc b/chromium/components/feedback/system_logs/system_logs_fetcher.cc
index e3466baf2af..1ef38394b9c 100644
--- a/chromium/components/feedback/system_logs/system_logs_fetcher.cc
+++ b/chromium/components/feedback/system_logs/system_logs_fetcher.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "content/public/browser/browser_task_traits.h"
diff --git a/chromium/components/find_in_page/find_result_observer.h b/chromium/components/find_in_page/find_result_observer.h
index 9dde58eebe2..1125d5d3cce 100644
--- a/chromium/components/find_in_page/find_result_observer.h
+++ b/chromium/components/find_in_page/find_result_observer.h
@@ -19,6 +19,7 @@ class FindResultObserver : public base::CheckedObserver {
public:
virtual void OnFindResultAvailable(content::WebContents* web_contents) = 0;
+ virtual void OnFindEmptyText(content::WebContents* web_contents) {}
virtual void OnFindTabHelperDestroyed(FindTabHelper* helper) {}
};
diff --git a/chromium/components/find_in_page/find_tab_helper.cc b/chromium/components/find_in_page/find_tab_helper.cc
index 87db8748dac..72da4ba7dbc 100644
--- a/chromium/components/find_in_page/find_tab_helper.cc
+++ b/chromium/components/find_in_page/find_tab_helper.cc
@@ -51,17 +51,18 @@ void FindTabHelper::StartFinding(base::string16 search_string,
const base::char16 kInvalidChars[] = {'\r', 0};
base::RemoveChars(search_string, kInvalidChars, &search_string);
- // If search_string is empty, it means FindNext was pressed with a keyboard
- // shortcut so unless we have something to search for we return early.
- if (search_string.empty() && find_text_.empty()) {
- search_string = GetInitialSearchText();
+ // Keep track of what the last search was across the tabs.
+ if (delegate_)
+ delegate_->SetLastSearchText(search_string);
- if (search_string.empty())
- return;
+ if (search_string.empty()) {
+ StopFinding(find_in_page::SelectionAction::kClear);
+ for (auto& observer : observers_)
+ observer.OnFindEmptyText(web_contents_);
+ return;
}
- // NB: search_string will be empty when using the FindNext keyboard shortcut.
- bool new_session = (find_text_ != search_string && !search_string.empty()) ||
+ bool new_session = find_text_ != search_string ||
(last_search_case_sensitive_ != case_sensitive) ||
find_op_aborted_;
@@ -70,24 +71,16 @@ void FindTabHelper::StartFinding(base::string16 search_string,
if (!new_session && !find_match)
return;
- // Keep track of the previous search.
- previous_find_text_ = find_text_;
-
current_find_request_id_ = find_request_id_counter_++;
if (new_session)
current_find_session_id_ = current_find_request_id_;
- if (!search_string.empty())
- find_text_ = search_string;
+ previous_find_text_ = find_text_;
+ find_text_ = search_string;
last_search_case_sensitive_ = case_sensitive;
-
find_op_aborted_ = false;
should_find_match_ = find_match;
- // Keep track of what the last search was across the tabs.
- if (delegate_)
- delegate_->SetLastSearchText(find_text_);
-
auto options = blink::mojom::FindOptions::New();
options->forward = forward_direction;
options->match_case = case_sensitive;
diff --git a/chromium/components/flags_ui/resources/flags.html b/chromium/components/flags_ui/resources/flags.html
index 191373be342..830cbe252e4 100644
--- a/chromium/components/flags_ui/resources/flags.html
+++ b/chromium/components/flags_ui/resources/flags.html
@@ -2,6 +2,7 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+<meta name="color-scheme" content="light dark">
<if expr="not is_ios">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
@@ -19,6 +20,7 @@
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="strings.js"></script>
diff --git a/chromium/components/games/core/catalog_store_unittest.cc b/chromium/components/games/core/catalog_store_unittest.cc
index f5ee1213c8f..9673bfd04cd 100644
--- a/chromium/components/games/core/catalog_store_unittest.cc
+++ b/chromium/components/games/core/catalog_store_unittest.cc
@@ -9,7 +9,7 @@
#include "base/files/file_path.h"
#include "base/optional.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/games/core/games_types.h"
#include "components/games/core/games_utils.h"
diff --git a/chromium/components/games/core/games_service_impl_unittest.cc b/chromium/components/games/core/games_service_impl_unittest.cc
index 8bc9958798c..1953e5b25ae 100644
--- a/chromium/components/games/core/games_service_impl_unittest.cc
+++ b/chromium/components/games/core/games_service_impl_unittest.cc
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/games/core/data_files_parser.h"
#include "components/games/core/games_prefs.h"
diff --git a/chromium/components/games/core/highlighted_games_store_unittest.cc b/chromium/components/games/core/highlighted_games_store_unittest.cc
index b9d81646633..17a778931fe 100644
--- a/chromium/components/games/core/highlighted_games_store_unittest.cc
+++ b/chromium/components/games/core/highlighted_games_store_unittest.cc
@@ -9,7 +9,7 @@
#include "base/barrier_closure.h"
#include "base/files/file_path.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/games/core/games_types.h"
#include "components/games/core/games_utils.h"
diff --git a/chromium/components/google/core/common/google_util.cc b/chromium/components/google/core/common/google_util.cc
index 19db3d00ba3..9789be38166 100644
--- a/chromium/components/google/core/common/google_util.cc
+++ b/chromium/components/google/core/common/google_util.cc
@@ -343,4 +343,42 @@ const std::vector<std::string>& GetGoogleRegistrableDomains() {
return *kGoogleRegisterableDomains;
}
+GURL AppendToAsyncQueryParam(const GURL& url,
+ const std::string& key,
+ const std::string& value) {
+ const std::string param_name = "async";
+ const std::string key_value = key + ":" + value;
+ bool replaced = false;
+ const std::string input = url.query();
+ url::Component cursor(0, input.size());
+ std::string output;
+ url::Component key_range, value_range;
+ while (url::ExtractQueryKeyValue(input.data(), &cursor, &key_range,
+ &value_range)) {
+ const base::StringPiece key(input.data() + key_range.begin, key_range.len);
+ std::string key_value_pair(input, key_range.begin,
+ value_range.end() - key_range.begin);
+ if (!replaced && key == param_name) {
+ // Check |replaced| as only the first match should be replaced.
+ replaced = true;
+ key_value_pair += "," + key_value;
+ }
+ if (!output.empty()) {
+ output += "&";
+ }
+
+ output += key_value_pair;
+ }
+ if (!replaced) {
+ if (!output.empty()) {
+ output += "&";
+ }
+
+ output += (param_name + "=" + key_value);
+ }
+ GURL::Replacements replacements;
+ replacements.SetQueryStr(output);
+ return url.ReplaceComponents(replacements);
+}
+
} // namespace google_util
diff --git a/chromium/components/google/core/common/google_util.h b/chromium/components/google/core/common/google_util.h
index e84acb5bf12..5642e29b343 100644
--- a/chromium/components/google/core/common/google_util.h
+++ b/chromium/components/google/core/common/google_util.h
@@ -115,6 +115,19 @@ bool IsGoogleAssociatedDomainUrl(const GURL& url);
// unregistering themselves.
const std::vector<std::string>& GetGoogleRegistrableDomains();
+// Appends the provided |key| and |value| pair to the "async" query param list,
+// according to the format used by the Google servers:
+//
+// "async=<other key>:<other value>,<key>:<value>"
+//
+// If |url| does not have an "async" query param list it will be added.
+// Derived from net::AppendOrReplaceQueryParameter, that can't be used because
+// it escapes ":" to "%3A", but the servers requires the colon not to be
+// escaped. See: http://crbug.com/413845.
+GURL AppendToAsyncQueryParam(const GURL& url,
+ const std::string& key,
+ const std::string& value);
+
} // namespace google_util
#endif // COMPONENTS_GOOGLE_CORE_COMMON_GOOGLE_UTIL_H_
diff --git a/chromium/components/google/core/common/google_util_unittest.cc b/chromium/components/google/core/common/google_util_unittest.cc
index d0df4185240..4e1079ab339 100644
--- a/chromium/components/google/core/common/google_util_unittest.cc
+++ b/chromium/components/google/core/common/google_util_unittest.cc
@@ -469,3 +469,20 @@ TEST(GoogleUtilTest, GoogleAssociatedDomains) {
GURL("https://daily0-myapi-pa.sandbox.googleapis.com/v1/"
"myservice?k1=v1&k2=v2")));
}
+
+TEST(GoogleUtilTest, AppendToAsyncQueryParam) {
+ // Append to plain URL.
+ EXPECT_EQ(GURL("https://foo.com?async=bar:baz"),
+ google_util::AppendToAsyncQueryParam(GURL("https://foo.com"), "bar",
+ "baz"));
+
+ // Append to async param.
+ EXPECT_EQ(GURL("https://foo.com?async=bar:baz,hello:world"),
+ google_util::AppendToAsyncQueryParam(
+ GURL("https://foo.com?async=bar:baz"), "hello", "world"));
+
+ // Append to same async param.
+ EXPECT_EQ(GURL("https://foo.com?async=bar:baz,bar:buz"),
+ google_util::AppendToAsyncQueryParam(
+ GURL("https://foo.com?async=bar:baz"), "bar", "buz"));
+}
diff --git a/chromium/components/grpc_support/bidirectional_stream.cc b/chromium/components/grpc_support/bidirectional_stream.cc
index a4a34a10f54..4a421f694dd 100644
--- a/chromium/components/grpc_support/bidirectional_stream.cc
+++ b/chromium/components/grpc_support/bidirectional_stream.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -29,7 +29,6 @@
#include "net/http/http_transaction_factory.h"
#include "net/http/http_util.h"
#include "net/ssl/ssl_info.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
@@ -177,7 +176,7 @@ void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
}
void BidirectionalStream::OnHeadersReceived(
- const spdy::SpdyHeaderBlock& response_headers) {
+ const spdy::Http2HeaderBlock& response_headers) {
DCHECK(IsOnNetworkThread());
DCHECK_EQ(STARTED, read_state_);
if (!bidi_stream_)
@@ -241,7 +240,7 @@ void BidirectionalStream::OnDataSent() {
}
void BidirectionalStream::OnTrailersReceived(
- const spdy::SpdyHeaderBlock& response_trailers) {
+ const spdy::Http2HeaderBlock& response_trailers) {
DCHECK(IsOnNetworkThread());
if (!bidi_stream_)
return;
diff --git a/chromium/components/grpc_support/bidirectional_stream.h b/chromium/components/grpc_support/bidirectional_stream.h
index 0981b68b8e5..b8767fb5587 100644
--- a/chromium/components/grpc_support/bidirectional_stream.h
+++ b/chromium/components/grpc_support/bidirectional_stream.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "net/http/bidirectional_stream.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
#include "net/url_request/url_request_context_getter.h"
namespace base {
@@ -41,14 +42,14 @@ class BidirectionalStream : public net::BidirectionalStream::Delegate {
virtual void OnStreamReady() = 0;
virtual void OnHeadersReceived(
- const spdy::SpdyHeaderBlock& response_headers,
+ const spdy::Http2HeaderBlock& response_headers,
const char* negotiated_protocol) = 0;
virtual void OnDataRead(char* data, int size) = 0;
virtual void OnDataSent(const char* data) = 0;
- virtual void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers) = 0;
+ virtual void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) = 0;
virtual void OnSucceeded() = 0;
@@ -173,10 +174,10 @@ class BidirectionalStream : public net::BidirectionalStream::Delegate {
// net::BidirectionalStream::Delegate implementations:
void OnStreamReady(bool request_headers_sent) override;
void OnHeadersReceived(
- const spdy::SpdyHeaderBlock& response_headers) override;
+ const spdy::Http2HeaderBlock& response_headers) override;
void OnDataRead(int bytes_read) override;
void OnDataSent() override;
- void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers) override;
+ void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) override;
void OnFailed(int error) override;
// Helper method to derive OnSucceeded.
void MaybeOnSucceded();
diff --git a/chromium/components/grpc_support/bidirectional_stream_c.cc b/chromium/components/grpc_support/bidirectional_stream_c.cc
index 51b637a5203..bdb8dc94b1f 100644
--- a/chromium/components/grpc_support/bidirectional_stream_c.cc
+++ b/chromium/components/grpc_support/bidirectional_stream_c.cc
@@ -38,7 +38,7 @@ namespace {
class HeadersArray : public bidirectional_stream_header_array {
public:
- explicit HeadersArray(const spdy::SpdyHeaderBlock& header_block);
+ explicit HeadersArray(const spdy::Http2HeaderBlock& header_block);
~HeadersArray();
private:
@@ -46,7 +46,7 @@ class HeadersArray : public bidirectional_stream_header_array {
DISALLOW_COPY_AND_ASSIGN(HeadersArray);
};
-HeadersArray::HeadersArray(const spdy::SpdyHeaderBlock& header_block)
+HeadersArray::HeadersArray(const spdy::Http2HeaderBlock& header_block)
: headers_strings_(header_block.size()) {
// Split coalesced headers by '\0' and copy them into |header_strings_|.
for (const auto& it : header_block) {
@@ -93,14 +93,15 @@ class BidirectionalStreamAdapter
void OnStreamReady() override;
- void OnHeadersReceived(const spdy::SpdyHeaderBlock& headers_block,
+ void OnHeadersReceived(const spdy::Http2HeaderBlock& headers_block,
const char* negotiated_protocol) override;
void OnDataRead(char* data, int size) override;
void OnDataSent(const char* data) override;
- void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers_block) override;
+ void OnTrailersReceived(
+ const spdy::Http2HeaderBlock& trailers_block) override;
void OnSucceeded() override;
@@ -149,7 +150,7 @@ void BidirectionalStreamAdapter::OnStreamReady() {
}
void BidirectionalStreamAdapter::OnHeadersReceived(
- const spdy::SpdyHeaderBlock& headers_block,
+ const spdy::Http2HeaderBlock& headers_block,
const char* negotiated_protocol) {
DCHECK(c_callback_->on_response_headers_received);
HeadersArray response_headers(headers_block);
@@ -168,7 +169,7 @@ void BidirectionalStreamAdapter::OnDataSent(const char* data) {
}
void BidirectionalStreamAdapter::OnTrailersReceived(
- const spdy::SpdyHeaderBlock& trailers_block) {
+ const spdy::Http2HeaderBlock& trailers_block) {
DCHECK(c_callback_->on_response_trailers_received);
HeadersArray response_trailers(trailers_block);
c_callback_->on_response_trailers_received(c_stream(), &response_trailers);
diff --git a/chromium/components/guest_os/OWNERS b/chromium/components/guest_os/OWNERS
index dc48383c44d..c25a8fc30c3 100644
--- a/chromium/components/guest_os/OWNERS
+++ b/chromium/components/guest_os/OWNERS
@@ -1 +1,3 @@
file://chrome/browser/chromeos/guest_os/OWNERS
+
+# COMPONENT: UI>Shell>Containers
diff --git a/chromium/components/guest_view/browser/guest_view_base.cc b/chromium/components/guest_view/browser/guest_view_base.cc
index 66a137d8254..807d58c18ed 100644
--- a/chromium/components/guest_view/browser/guest_view_base.cc
+++ b/chromium/components/guest_view/browser/guest_view_base.cc
@@ -410,24 +410,12 @@ void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
DidAttachToEmbedder();
// Inform the associated GuestViewContainer that the contentWindow is ready.
- GetOwnerRenderWidgetHost()->Send(new GuestViewMsg_GuestAttached(
+ GetOwnerRenderWidgetHost()->GetProcess()->Send(new GuestViewMsg_GuestAttached(
element_instance_id_, guest_proxy_routing_id));
SendQueuedEvents();
}
-// TODO(wjmaclean): Delete this when browser plugin goes away;
-// https://crbug.com/533069 .
-void GuestViewBase::DidDetach() {
- GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(this);
- StopTrackingEmbedderZoomLevel();
- owner_web_contents()->GetRenderViewHost()->Send(
- new GuestViewMsg_GuestDetached(element_instance_id_));
- element_instance_id_ = kInstanceIDNone;
- if (ShouldDestroyOnDetach())
- Destroy(true);
-}
-
WebContents* GuestViewBase::GetOwnerWebContents() {
return owner_web_contents_;
}
@@ -567,7 +555,8 @@ double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const {
}
void GuestViewBase::DidStopLoading() {
- content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
+ content::RenderViewHost* rvh =
+ web_contents()->GetMainFrame()->GetRenderViewHost();
if (IsPreferredSizeModeEnabled())
rvh->EnablePreferredSizeMode();
diff --git a/chromium/components/guest_view/browser/guest_view_base.h b/chromium/components/guest_view/browser/guest_view_base.h
index 920ff3ac845..aafca346221 100644
--- a/chromium/components/guest_view/browser/guest_view_base.h
+++ b/chromium/components/guest_view/browser/guest_view_base.h
@@ -339,7 +339,6 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
// TODO(533069): Remove since BrowserPlugin has been removed.
void DidAttach(int guest_proxy_routing_id);
- void DidDetach();
void WillAttach(content::WebContents* embedder_web_contents,
int browser_plugin_instance_id,
bool is_full_page_plugin,
diff --git a/chromium/components/guest_view/common/guest_view_messages.h b/chromium/components/guest_view/common/guest_view_messages.h
index 43dcc4f8902..4acd85e4ac1 100644
--- a/chromium/components/guest_view/common/guest_view_messages.h
+++ b/chromium/components/guest_view/common/guest_view_messages.h
@@ -24,13 +24,6 @@ IPC_MESSAGE_CONTROL2(GuestViewMsg_GuestAttached,
int /* element_instance_id */,
int /* source_routing_id */)
-// This IPC tells the browser process to detach the provided
-// |element_instance_id| from a GuestViewBase if it is attached to one.
-// In other words, routing of input and graphics will no longer flow through
-// the container associated with the provided ID.
-IPC_MESSAGE_CONTROL1(GuestViewMsg_GuestDetached,
- int /* element_instance_id*/)
-
// Messages sent from the renderer to the browser.
// Sent by the renderer to set initialization parameters of a Browser Plugin
diff --git a/chromium/components/guest_view/renderer/guest_view_request.cc b/chromium/components/guest_view/renderer/guest_view_request.cc
index 6142c232e68..265471323fe 100644
--- a/chromium/components/guest_view/renderer/guest_view_request.cc
+++ b/chromium/components/guest_view/renderer/guest_view_request.cc
@@ -101,23 +101,4 @@ void GuestViewAttachRequest::HandleResponse(const IPC::Message& message) {
ExecuteCallbackIfAvailable(argc, std::move(argv));
}
-GuestViewDetachRequest::GuestViewDetachRequest(
- GuestViewContainer* container,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate)
- : GuestViewRequest(container, callback, isolate) {
-}
-
-GuestViewDetachRequest::~GuestViewDetachRequest() {
-}
-
-void GuestViewDetachRequest::PerformRequest() {
- // TODO(wjmaclean): Remove this function.
-}
-
-void GuestViewDetachRequest::HandleResponse(const IPC::Message& message) {
- DCHECK(message.type() == GuestViewMsg_GuestDetached::ID);
- ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
-}
-
} // namespace guest_view
diff --git a/chromium/components/guest_view/renderer/guest_view_request.h b/chromium/components/guest_view/renderer/guest_view_request.h
index 1055f2c5c8a..3f41dd83ce2 100644
--- a/chromium/components/guest_view/renderer/guest_view_request.h
+++ b/chromium/components/guest_view/renderer/guest_view_request.h
@@ -78,23 +78,6 @@ class GuestViewAttachRequest : public GuestViewRequest {
DISALLOW_COPY_AND_ASSIGN(GuestViewAttachRequest);
};
-// This class represents a DetachGuest request from Javascript. The Detach
-// operation may not execute immediately, if the container is not ready or if
-// there are other GuestViewRequests in flight.
-class GuestViewDetachRequest : public GuestViewRequest {
- public:
- GuestViewDetachRequest(GuestViewContainer* container,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate);
- ~GuestViewDetachRequest() override;
-
- void PerformRequest() override;
- void HandleResponse(const IPC::Message& message) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(GuestViewDetachRequest);
-};
-
} // namespace guest_view
#endif // COMPONENTS_GUEST_VIEW_RENDERER_GUEST_VIEW_CONTAINER_H_
diff --git a/chromium/components/gwp_asan/client/BUILD.gn b/chromium/components/gwp_asan/client/BUILD.gn
index 17a315aeca0..e4e59ea9b1b 100644
--- a/chromium/components/gwp_asan/client/BUILD.gn
+++ b/chromium/components/gwp_asan/client/BUILD.gn
@@ -4,25 +4,21 @@
import("//base/allocator/allocator.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
component("client") {
output_name = "gwp_asan_client"
sources = [
"export.h",
"guarded_page_allocator.cc",
"guarded_page_allocator.h",
- "guarded_page_allocator_win.cc",
"gwp_asan.cc",
"gwp_asan.h",
"sampling_state.h",
]
+ if (is_win) {
+ sources += [ "guarded_page_allocator_win.cc" ]
+ }
+
if (is_posix) {
sources += [ "guarded_page_allocator_posix.cc" ]
}
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator.h b/chromium/components/gwp_asan/client/guarded_page_allocator.h
index 2709754dfa0..00966299f69 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator.h
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator.h
@@ -111,7 +111,7 @@ class GWP_ASAN_EXPORT GuardedPageAllocator {
// SimpleFreeList is specifically designed to pre-allocate data in Initialize
// so that it never recurses into malloc/free during Allocate/Free.
template <typename T>
- class SimpleFreeList : public FreeList<T> {
+ class SimpleFreeList final : public FreeList<T> {
public:
~SimpleFreeList() final = default;
void Initialize(T max_entries) final;
@@ -139,7 +139,8 @@ class GWP_ASAN_EXPORT GuardedPageAllocator {
// first-come first-serve basis, this makes it likely that all slots will be
// used up by common types first. Set aside a fixed amount of slots (~5%) for
// one-off partitions so that we make sure to sample rare types as well.
- class PartitionAllocSlotFreeList : public FreeList<AllocatorState::SlotIdx> {
+ class PartitionAllocSlotFreeList final
+ : public FreeList<AllocatorState::SlotIdx> {
public:
PartitionAllocSlotFreeList();
~PartitionAllocSlotFreeList() final;
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc b/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
index 60aa7c75c82..868617af679 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
@@ -7,6 +7,7 @@
#include <sys/mman.h>
#include "base/check.h"
+#include "base/posix/eintr_wrapper.h"
namespace gwp_asan {
namespace internal {
@@ -25,7 +26,8 @@ void GuardedPageAllocator::UnmapRegion() {
}
void GuardedPageAllocator::MarkPageReadWrite(void* ptr) {
- int err = mprotect(ptr, state_.page_size, PROT_READ | PROT_WRITE);
+ int err =
+ HANDLE_EINTR(mprotect(ptr, state_.page_size, PROT_READ | PROT_WRITE));
PCHECK(err == 0) << "mprotect";
}
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc b/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
index 2161f7ed022..870eacf46bd 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
@@ -12,7 +12,7 @@
#include "base/bits.h"
#include "base/process/process_metrics.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/threading/simple_thread.h"
#include "build/build_config.h"
diff --git a/chromium/components/gwp_asan/client/gwp_asan.cc b/chromium/components/gwp_asan/client/gwp_asan.cc
index e2de4b59e49..a838cac6ef1 100644
--- a/chromium/components/gwp_asan/client/gwp_asan.cc
+++ b/chromium/components/gwp_asan/client/gwp_asan.cc
@@ -9,7 +9,7 @@
#include <limits>
#include "base/allocator/buildflags.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/debug/crash_logging.h"
#include "base/feature_list.h"
#include "base/logging.h"
diff --git a/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc b/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
index 33a8ccd9b15..d64c2feacdb 100644
--- a/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
+++ b/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
@@ -10,7 +10,7 @@
#include <string>
#include "base/allocator/allocator_shim.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/process/process_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gtest_util.h"
@@ -28,17 +28,17 @@
#if defined(OS_WIN)
#include <malloc.h>
-static size_t GetAllocatedSize(void* mem) {
+static size_t GetUsableSize(void* mem) {
return _msize(mem);
}
#elif defined(OS_APPLE)
#include <malloc/malloc.h>
-static size_t GetAllocatedSize(void* mem) {
+static size_t GetUsableSize(void* mem) {
return malloc_size(mem);
}
#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
#include <malloc.h>
-static size_t GetAllocatedSize(void* mem) {
+static size_t GetUsableSize(void* mem) {
return malloc_usable_size(mem);
}
#endif
@@ -257,7 +257,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
std::unique_ptr<void, decltype(&free)> alloc(malloc(kAllocationSize), free);
CHECK_NE(alloc.get(), nullptr);
- size_t alloc_sz = GetAllocatedSize(alloc.get());
+ size_t alloc_sz = GetUsableSize(alloc.get());
if (GetMallocGpaForTesting().PointerIsMine(alloc.get()))
CHECK_EQ(alloc_sz, kAllocationSize);
else
diff --git a/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc b/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
index 9b89505d1e7..af85f462dc5 100644
--- a/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
+++ b/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
@@ -11,7 +11,8 @@
#include <string>
#include "base/allocator/partition_allocator/partition_alloc.h"
-#include "base/bind_helpers.h"
+#include "base/allocator/partition_allocator/partition_root.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/partition_alloc_buildflags.h"
#include "base/process/process_metrics.h"
@@ -51,6 +52,11 @@ constexpr size_t kLoopIterations = kSamplingFrequency * 4;
constexpr int kSuccess = 0;
constexpr int kFailure = 1;
+constexpr base::PartitionOptions kAllocatorOptions = {
+ base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::PCScan::kAlwaysDisabled};
+
static void HandleOOM(size_t unused_size) {
LOG(FATAL) << "Out of memory.";
}
@@ -79,7 +85,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
BasicFunctionality,
SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
base::PartitionAllocator allocator;
- allocator.init();
+ allocator.init(kAllocatorOptions);
for (size_t i = 0; i < kLoopIterations; i++) {
void* ptr = allocator.root()->Alloc(1, kFakeType);
if (GetPartitionAllocGpaForTesting().PointerIsMine(ptr))
@@ -99,7 +105,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
Realloc,
SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
base::PartitionAllocator allocator;
- allocator.init();
+ allocator.init(kAllocatorOptions);
void* alloc = GetPartitionAllocGpaForTesting().Allocate(base::GetPageSize());
CHECK_NE(alloc, nullptr);
@@ -128,7 +134,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
DifferentTypesDontOverlap,
SamplingPartitionAllocShimsTest::multiprocessTestSetup) {
base::PartitionAllocator allocator;
- allocator.init();
+ allocator.init(kAllocatorOptions);
std::set<void*> type1, type2;
for (size_t i = 0; i < kLoopIterations * AllocatorState::kMaxSlots; i++) {
diff --git a/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc b/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
index 826833491c3..ada2af86ab6 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
@@ -9,7 +9,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/debug/stack_trace.h"
#include "base/test/gtest_util.h"
#include "base/test/metrics/histogram_tester.h"
diff --git a/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc b/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
index baa4f7c3643..dc160204bf2 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
@@ -9,7 +9,7 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc b/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
index a3c6c2a44d0..eb4c10d2bbc 100644
--- a/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
+++ b/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
@@ -5,7 +5,7 @@
#include "components/heap_profiling/in_process/heap_profiler_controller.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
diff --git a/chromium/components/heap_profiling/multi_process/test_driver.cc b/chromium/components/heap_profiling/multi_process/test_driver.cc
index cf61046f830..05039765fa0 100644
--- a/chromium/components/heap_profiling/multi_process/test_driver.cc
+++ b/chromium/components/heap_profiling/multi_process/test_driver.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <string>
+#include "base/allocator/partition_allocator/partition_root.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
@@ -15,8 +16,9 @@
#include "base/run_loop.h"
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/platform_thread.h"
+#include "base/trace_event/heap_profiler.h"
#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -341,7 +343,9 @@ TestDriver::TestDriver()
: wait_for_ui_thread_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
base::PartitionAllocGlobalInit(HandleOOM);
- partition_allocator_.init();
+ partition_allocator_.init({base::PartitionOptions::Alignment::kRegular,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::PCScan::kAlwaysDisabled});
}
TestDriver::~TestDriver() {
base::PartitionAllocGlobalUninitForTesting();
diff --git a/chromium/components/history/README.md b/chromium/components/history/README.md
new file mode 100644
index 00000000000..5cb913c43e0
--- /dev/null
+++ b/chromium/components/history/README.md
@@ -0,0 +1,17 @@
+# History Component
+
+Component that manages visited URLs history.
+
+## History services
+
+There are 3 different history services that fulfill different requirements:
+
+* [HistoryService](/components/history/core/browser/history_service.h): manages
+and allows access to local-only history.
+* [WebHistoryService](/components/history/core/browser/web_history_service.h):
+handles queries to history servers providing overall history access (local and
+remote), potentially including from other devices synced to the same account.
+* [BrowsingHistoryService](/components/history/core/browser/browsing_history_service.h):
+is a layer on top of the two services above and
+[SyncService](/components/sync/driver/sync_service.h) that works transparently
+for both sync'ing and non-sync'ing users.
diff --git a/chromium/components/history/core/browser/android/android_cache_database.cc b/chromium/components/history/core/browser/android/android_cache_database.cc
index b9413345a25..734369e4cfd 100644
--- a/chromium/components/history/core/browser/android/android_cache_database.cc
+++ b/chromium/components/history/core/browser/android/android_cache_database.cc
@@ -178,16 +178,14 @@ bool AndroidCacheDatabase::CreateDatabase(const base::FilePath& db_name) {
sql::Database::Delete(db_name_);
// Using a new connection, otherwise we can not create the database.
- sql::Database connection;
-
+ //
// The db doesn't store too much data, so we don't need that big a page
// size or cache.
- connection.set_page_size(2048);
- connection.set_cache_size(32);
-
- // Run the database in exclusive mode. Nobody else should be accessing the
+ //
+ // The database is open in exclusive mode. Nobody else should be accessing the
// database while we're running, and this will give somewhat improved perf.
- connection.set_exclusive_locking();
+ sql::Database connection(
+ {.exclusive_locking = true, .page_size = 2048, .cache_size = 32});
if (!connection.Open(db_name_)) {
LOG(ERROR) << connection.GetErrorMessage();
diff --git a/chromium/components/history/core/browser/browsing_history_service.cc b/chromium/components/history/core/browser/browsing_history_service.cc
index 7c456bf405a..a3d65d9e884 100644
--- a/chromium/components/history/core/browser/browsing_history_service.cc
+++ b/chromium/components/history/core/browser/browsing_history_service.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
@@ -173,12 +173,12 @@ BrowsingHistoryService::BrowsingHistoryService(
// Get notifications when history is cleared.
if (local_history_)
- history_service_observer_.Add(local_history_);
+ history_service_observation_.Observe(local_history_);
// Get notifications when web history is deleted.
WebHistoryService* web_history = driver_->GetWebHistoryService();
if (web_history) {
- web_history_service_observer_.Add(web_history);
+ web_history_service_observation_.Observe(web_history);
} else if (sync_service_) {
// If |web_history| is not available, it means that history sync is
// disabled. If |sync_service_| is not null, it means that syncing is
@@ -187,7 +187,7 @@ BrowsingHistoryService::BrowsingHistoryService(
// observing. This is okay because sync will never start for us, for example
// it may be disabled by flag or we're part of an incognito/guest mode
// window.
- sync_service_observer_.Add(sync_service_);
+ sync_service_observation_.Observe(sync_service_);
}
}
@@ -201,9 +201,9 @@ void BrowsingHistoryService::OnStateChanged(syncer::SyncService* sync) {
// This method should not be called after we already added the observer.
WebHistoryService* web_history = driver_->GetWebHistoryService();
if (web_history) {
- DCHECK(!web_history_service_observer_.IsObserving(web_history));
- web_history_service_observer_.Add(web_history);
- sync_service_observer_.RemoveAll();
+ DCHECK(!web_history_service_observation_.IsObserving());
+ web_history_service_observation_.Observe(web_history);
+ sync_service_observation_.RemoveObservation();
}
}
diff --git a/chromium/components/history/core/browser/browsing_history_service.h b/chromium/components/history/core/browser/browsing_history_service.h
index f2d32ac56fd..a6906c627b0 100644
--- a/chromium/components/history/core/browser/browsing_history_service.h
+++ b/chromium/components/history/core/browser/browsing_history_service.h
@@ -17,7 +17,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/clock.h"
@@ -227,16 +227,16 @@ class BrowsingHistoryService : public HistoryServiceObserver,
std::unique_ptr<base::OneShotTimer> web_history_timer_;
// HistoryService (local history) observer.
- ScopedObserver<HistoryService, HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<HistoryService, HistoryServiceObserver>
+ history_service_observation_{this};
// WebHistoryService (synced history) observer.
- ScopedObserver<WebHistoryService, WebHistoryServiceObserver>
- web_history_service_observer_{this};
+ base::ScopedObservation<WebHistoryService, WebHistoryServiceObserver>
+ web_history_service_observation_{this};
// SyncService observer listens to late initialization of history sync.
- ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
- sync_service_observer_{this};
+ base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
+ sync_service_observation_{this};
// Whether the last call to Web History returned synced results.
bool has_synced_results_ = false;
diff --git a/chromium/components/history/core/browser/browsing_history_service_unittest.cc b/chromium/components/history/core/browser/browsing_history_service_unittest.cc
index c769b82241d..61d6009fdfb 100644
--- a/chromium/components/history/core/browser/browsing_history_service_unittest.cc
+++ b/chromium/components/history/core/browser/browsing_history_service_unittest.cc
@@ -6,8 +6,8 @@
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
diff --git a/chromium/components/history/core/browser/expire_history_backend_unittest.cc b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
index 4454ff1b0d2..bcbb6376529 100644
--- a/chromium/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
@@ -17,12 +17,11 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/favicon/core/favicon_database.h"
#include "components/history/core/browser/history_backend_client.h"
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index e77a60217fd..3a338a24a42 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -14,7 +14,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/files/file_enumerator.h"
diff --git a/chromium/components/history/core/browser/history_backend_db_unittest.cc b/chromium/components/history/core/browser/history_backend_db_unittest.cc
index f9f3e03a830..d923de5e8b6 100644
--- a/chromium/components/history/core/browser/history_backend_db_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_db_unittest.cc
@@ -25,7 +25,7 @@
#include <unordered_set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/format_macros.h"
#include "base/guid.h"
#include "base/i18n/case_conversion.h"
diff --git a/chromium/components/history/core/browser/history_querying_unittest.cc b/chromium/components/history/core/browser/history_querying_unittest.cc
index e301dd2f498..b441746e790 100644
--- a/chromium/components/history/core/browser/history_querying_unittest.cc
+++ b/chromium/components/history/core/browser/history_querying_unittest.cc
@@ -5,7 +5,7 @@
#include <stddef.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -13,7 +13,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/cancelable_task_tracker.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/history/core/browser/history_database_params.h"
#include "components/history/core/browser/history_service.h"
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index c871ba31133..9d365a80bbe 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -17,8 +17,8 @@
#include "components/history/core/browser/history_service.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/feature_list.h"
diff --git a/chromium/components/history/core/browser/history_service_unittest.cc b/chromium/components/history/core/browser/history_service_unittest.cc
index 8d6edc5c03a..ecf94f6db01 100644
--- a/chromium/components/history/core/browser/history_service_unittest.cc
+++ b/chromium/components/history/core/browser/history_service_unittest.cc
@@ -34,7 +34,7 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -43,14 +43,14 @@
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/test/database_test_utils.h"
#include "components/history/core/test/test_history_database.h"
-#include "components/sync/model/fake_sync_change_processor.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_change_processor.h"
-#include "components/sync/model/sync_change_processor_wrapper_for_test.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/protocol/history_delete_directive_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/fake_sync_change_processor.h"
+#include "components/sync/test/model/sync_change_processor_wrapper_for_test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace history {
diff --git a/chromium/components/history/core/browser/in_memory_history_backend.cc b/chromium/components/history/core/browser/in_memory_history_backend.cc
index f31784866a6..01801ea579b 100644
--- a/chromium/components/history/core/browser/in_memory_history_backend.cc
+++ b/chromium/components/history/core/browser/in_memory_history_backend.cc
@@ -27,7 +27,7 @@ void InMemoryHistoryBackend::AttachToHistoryService(
HistoryService* history_service) {
DCHECK(db_);
DCHECK(history_service);
- history_service_observer_.Add(history_service);
+ history_service_observation_.Observe(history_service);
}
void InMemoryHistoryBackend::DeleteAllSearchTermsForKeyword(
diff --git a/chromium/components/history/core/browser/in_memory_history_backend.h b/chromium/components/history/core/browser/in_memory_history_backend.h
index fc42b7e01c3..813de79e7fc 100644
--- a/chromium/components/history/core/browser/in_memory_history_backend.h
+++ b/chromium/components/history/core/browser/in_memory_history_backend.h
@@ -25,7 +25,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/history/core/browser/keyword_id.h"
@@ -91,8 +91,8 @@ class InMemoryHistoryBackend : public HistoryServiceObserver {
std::unique_ptr<InMemoryDatabase> db_;
- ScopedObserver<HistoryService, HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<HistoryService, HistoryServiceObserver>
+ history_service_observation_{this};
DISALLOW_COPY_AND_ASSIGN(InMemoryHistoryBackend);
};
diff --git a/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc b/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
index 3561c10b6ac..35d85181866 100644
--- a/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
+++ b/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
@@ -19,9 +19,9 @@
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/in_memory_history_backend.h"
#include "components/history/core/test/test_history_database.h"
-#include "components/sync/model/fake_sync_change_processor.h"
-#include "components/sync/model/sync_change_processor_wrapper_for_test.h"
#include "components/sync/model/sync_error_factory.h"
+#include "components/sync/test/model/fake_sync_change_processor.h"
+#include "components/sync/test/model/sync_change_processor_wrapper_for_test.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc b/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
index eed221869ac..0720af2f621 100644
--- a/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
+++ b/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.cc
@@ -7,24 +7,36 @@
#include <utility>
#include "base/bind.h"
-#include "components/sync/driver/sync_client.h"
+#include "base/memory/weak_ptr.h"
+#include "components/history/core/browser/history_service.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "components/sync/model/model_type_store_service.h"
-namespace browser_sync {
+namespace history {
+
+namespace {
+
+base::WeakPtr<syncer::SyncableService> GetSyncableServiceFromHistoryService(
+ HistoryService* history_service) {
+ if (history_service) {
+ return history_service->GetDeleteDirectivesSyncableService();
+ }
+ return nullptr;
+}
+
+} // namespace
HistoryDeleteDirectivesModelTypeController::
HistoryDeleteDirectivesModelTypeController(
const base::RepeatingClosure& dump_stack,
syncer::SyncService* sync_service,
syncer::ModelTypeStoreService* model_type_store_service,
- syncer::SyncClient* sync_client)
+ HistoryService* history_service)
: SyncableServiceBasedModelTypeController(
syncer::HISTORY_DELETE_DIRECTIVES,
model_type_store_service->GetStoreFactory(),
- sync_client->GetSyncableServiceForType(
- syncer::HISTORY_DELETE_DIRECTIVES),
+ GetSyncableServiceFromHistoryService(history_service),
dump_stack),
sync_service_(sync_service) {}
@@ -68,4 +80,4 @@ void HistoryDeleteDirectivesModelTypeController::OnStateChanged(
sync_service_->DataTypePreconditionChanged(type());
}
-} // namespace browser_sync
+} // namespace history
diff --git a/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.h b/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
index 8141c718cc1..16801b465c4 100644
--- a/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
+++ b/chromium/components/history/core/browser/sync/history_delete_directives_model_type_controller.h
@@ -12,11 +12,12 @@
namespace syncer {
class ModelTypeStoreService;
-class SyncClient;
class SyncService;
} // namespace syncer
-namespace browser_sync {
+namespace history {
+
+class HistoryService;
// A controller for delete directives, which cannot sync when full encryption
// is enabled.
@@ -24,13 +25,13 @@ class HistoryDeleteDirectivesModelTypeController
: public syncer::SyncableServiceBasedModelTypeController,
public syncer::SyncServiceObserver {
public:
- // |sync_service| and |sync_client| must not be null and must outlive this
+ // |sync_service| and |history_service| must not be null and must outlive this
// object.
HistoryDeleteDirectivesModelTypeController(
const base::RepeatingClosure& dump_stack,
syncer::SyncService* sync_service,
syncer::ModelTypeStoreService* model_type_store_service,
- syncer::SyncClient* sync_client);
+ HistoryService* history_service);
~HistoryDeleteDirectivesModelTypeController() override;
// DataTypeController overrides.
@@ -49,6 +50,6 @@ class HistoryDeleteDirectivesModelTypeController
DISALLOW_COPY_AND_ASSIGN(HistoryDeleteDirectivesModelTypeController);
};
-} // namespace browser_sync
+} // namespace history
#endif // COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_DELETE_DIRECTIVES_MODEL_TYPE_CONTROLLER_H_
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
index e376287a630..b46b238ed06 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
@@ -436,7 +436,7 @@ void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
void TypedURLSyncBridge::Init() {
DCHECK(sequence_checker_.CalledOnValidSequence());
- history_backend_observer_.Add(history_backend_);
+ history_backend_observation_.Observe(history_backend_);
LoadMetadata();
}
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
index 84548c00464..af10e38296b 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
@@ -12,7 +12,7 @@
#include <utility>
#include <vector>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/history/core/browser/history_backend.h"
#include "components/history/core/browser/history_backend_observer.h"
#include "components/history/core/browser/sync/typed_url_sync_metadata_database.h"
@@ -247,8 +247,8 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Tracks observed history backend, for receiving updates from history
// backend.
- ScopedObserver<HistoryBackend, HistoryBackendObserver>
- history_backend_observer_{this};
+ base::ScopedObservation<HistoryBackend, HistoryBackendObserver>
+ history_backend_observation_{this};
DISALLOW_COPY_AND_ASSIGN(TypedURLSyncBridge);
};
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc b/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
index 69f4aa8dcb5..bd59563792c 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
@@ -20,8 +20,9 @@
#include "components/history/core/browser/in_memory_history_backend.h"
#include "components/history/core/test/test_history_database.h"
#include "components/sync/model/data_batch.h"
-#include "components/sync/model/recording_model_type_change_processor.h"
#include "components/sync/model/sync_metadata_store.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
@@ -34,7 +35,13 @@ using syncer::EntityData;
using syncer::KeyAndData;
using syncer::MetadataBatch;
using syncer::MetadataChangeList;
-using syncer::RecordingModelTypeChangeProcessor;
+using syncer::MockModelTypeChangeProcessor;
+using testing::_;
+using testing::AllOf;
+using testing::Mock;
+using testing::NiceMock;
+using testing::Pointee;
+using testing::Return;
namespace history {
@@ -55,6 +62,32 @@ const char kTitle2[] = "cookie";
const char kURL[] = "http://pie.com/";
const char kURL2[] = "http://cookie.com/";
+// Action SaveArgPointeeMove<k>(pointer) saves the value pointed to by the k-th
+// (0-based) argument of the mock function by moving it to *pointer.
+ACTION_TEMPLATE(SaveArgPointeeMove,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = std::move(*testing::get<k>(args));
+}
+
+// Matches that TypedUrlSpecifics has expected URL.
+MATCHER_P(HasURLInSpecifics, url, "") {
+ return arg.specifics.typed_url().url() == url;
+}
+
+// Matches that TypedUrlSpecifics has expected title.
+MATCHER_P(HasTitleInSpecifics, title, "") {
+ return arg.specifics.typed_url().title() == title;
+}
+
+MATCHER(HasTypedUrlInSpecifics, "") {
+ return arg.specifics.has_typed_url();
+}
+
+MATCHER(IsValidStorageKey, "") {
+ return TypedURLSyncMetadataDatabase::StorageKeyToURLID(arg) > 0;
+}
+
Time SinceEpoch(int64_t microseconds_since_epoch) {
return Time::FromDeltaSinceWindowsEpoch(
TimeDelta::FromMicroseconds(microseconds_since_epoch));
@@ -199,7 +232,7 @@ void VerifyDataBatch(std::map<std::string, TypedUrlSpecifics> expected,
EXPECT_TRUE(expected.empty());
}
-std::string IntToStroageKey(int id) {
+std::string IntToStorageKey(int id) {
std::string storage_key(sizeof(URLID), 0);
base::WriteBigEndian<URLID>(&storage_key[0], id);
return storage_key;
@@ -269,33 +302,30 @@ class TestHistoryBackend : public HistoryBackend {
class TypedURLSyncBridgeTest : public testing::Test {
public:
- TypedURLSyncBridgeTest() : typed_url_sync_bridge_(nullptr) {}
- ~TypedURLSyncBridgeTest() override {}
-
void SetUp() override {
fake_history_backend_ = new TestHistoryBackend();
ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
fake_history_backend_->Init(
false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath()));
- std::unique_ptr<TypedURLSyncBridge> bridge = std::make_unique<
- TypedURLSyncBridge>(
- fake_history_backend_.get(), fake_history_backend_->db(),
- RecordingModelTypeChangeProcessor::CreateProcessorAndAssignRawPointer(
- &processor_));
+ std::unique_ptr<TypedURLSyncBridge> bridge =
+ std::make_unique<TypedURLSyncBridge>(
+ fake_history_backend_.get(), fake_history_backend_->db(),
+ mock_processor_.CreateForwardingProcessor());
typed_url_sync_bridge_ = bridge.get();
typed_url_sync_bridge_->Init();
- typed_url_sync_bridge_->history_backend_observer_.RemoveAll();
+ if (typed_url_sync_bridge_->history_backend_observation_.IsObserving())
+ typed_url_sync_bridge_->history_backend_observation_.RemoveObservation();
fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge));
}
void TearDown() override {
- VerifyProcessorReceivedValidEntityData();
fake_history_backend_->Closing();
}
// Starts sync for |typed_url_sync_bridge_| with |initial_data| as the
// initial sync data.
void StartSyncing(const std::vector<TypedUrlSpecifics>& specifics) {
+ ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(true));
// Set change processor.
const auto error =
bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
@@ -304,23 +334,22 @@ class TypedURLSyncBridgeTest : public testing::Test {
EXPECT_FALSE(error);
}
- bool BuildAndPushLocalChanges(unsigned int num_typed_urls,
- unsigned int num_reload_urls,
+ void BuildAndPushLocalChanges(size_t num_typed_urls,
+ size_t num_reload_urls,
const std::vector<std::string>& urls,
URLRows* rows,
std::vector<VisitVector>* visit_vectors) {
- unsigned int total_urls = num_typed_urls + num_reload_urls;
+ const size_t total_urls = num_typed_urls + num_reload_urls;
DCHECK(urls.size() >= total_urls);
- if (!bridge())
- return false;
+ DCHECK(bridge());
if (total_urls) {
// Create new URL rows, populate the mock backend with its visits, and
// send to the sync service.
URLRows changed_urls;
- for (unsigned int i = 0; i < total_urls; ++i) {
- int typed = i < num_typed_urls ? 1 : 0;
+ for (size_t i = 0; i < total_urls; ++i) {
+ const int typed = i < num_typed_urls ? 1 : 0;
VisitVector visits;
visit_vectors->push_back(visits);
rows->push_back(MakeTypedUrlRow(urls[i], kTitle, typed, i + 3, false,
@@ -333,11 +362,6 @@ class TypedURLSyncBridgeTest : public testing::Test {
bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls,
/*is_from_expiration=*/false);
}
-
- // Check that communication with sync was successful.
- if (num_typed_urls != processor().put_multimap().size())
- return false;
- return true;
}
VisitVector ApplyUrlAndVisitsChange(const std::string& url,
@@ -385,10 +409,12 @@ class TypedURLSyncBridgeTest : public testing::Test {
}
void AddObserver() {
- bridge()->history_backend_observer_.Add(fake_history_backend_.get());
+ bridge()->history_backend_observation_.Observe(fake_history_backend_.get());
}
- void RemoveObserver() { bridge()->history_backend_observer_.RemoveAll(); }
+ void RemoveObserver() {
+ bridge()->history_backend_observation_.RemoveObservation();
+ }
// Fills |specifics| with the sync data for |url| and |visits|.
static bool WriteToTypedUrlSpecifics(const URLRow& url,
@@ -438,26 +464,6 @@ class TypedURLSyncBridgeTest : public testing::Test {
base::BindOnce(&VerifyDataBatch, ExpectedMap(expected)));
}
- void VerifyProcessorReceivedValidEntityData() {
- for (const auto& it : processor().put_multimap()) {
- EXPECT_GT(TypedURLSyncMetadataDatabase::StorageKeyToURLID(it.first), 0);
- EXPECT_TRUE(it.second->specifics.has_typed_url());
- }
- }
-
- sync_pb::TypedUrlSpecifics GetLastUpdateForURL(const std::string& url) {
- const std::string storage_key = GetStorageKey(url);
- auto eq_range = processor().put_multimap().equal_range(storage_key);
- if (eq_range.first == eq_range.second)
- return sync_pb::TypedUrlSpecifics();
-
- auto recorded_specifics_iterator = --eq_range.second;
- EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator);
- EXPECT_TRUE(recorded_specifics_iterator->second->specifics.has_typed_url());
-
- return recorded_specifics_iterator->second->specifics.typed_url();
- }
-
static void DiffVisits(const VisitVector& history_visits,
const sync_pb::TypedUrlSpecifics& sync_specifics,
std::vector<VisitInfo>* new_visits,
@@ -509,16 +515,12 @@ class TypedURLSyncBridgeTest : public testing::Test {
return bridge()->sync_metadata_database_;
}
- RecordingModelTypeChangeProcessor& processor() { return *processor_; }
-
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
base::ScopedTempDir test_dir_;
scoped_refptr<TestHistoryBackend> fake_history_backend_;
- TypedURLSyncBridge* typed_url_sync_bridge_;
- // A non-owning pointer to the processor given to the bridge. Will be null
- // before being given to the bridge, to make ownership easier.
- RecordingModelTypeChangeProcessor* processor_ = nullptr;
+ TypedURLSyncBridge* typed_url_sync_bridge_ = nullptr;
+ NiceMock<MockModelTypeChangeProcessor> mock_processor_;
};
// Add two typed urls locally and verify bridge can get them from GetAllData.
@@ -557,8 +559,8 @@ TEST_F(TypedURLSyncBridgeTest, GetData) {
WriteToTypedUrlSpecifics(row2, visits2, &typed_url2);
// Check that the local cache is still correct.
- VerifyGetData({IntToStroageKey(1)}, {typed_url1});
- VerifyGetData({IntToStroageKey(2)}, {typed_url2});
+ VerifyGetData({IntToStorageKey(1)}, {typed_url1});
+ VerifyGetData({IntToStorageKey(2)}, {typed_url2});
}
// Add a typed url locally and one to sync with the same data. Starting sync
@@ -574,19 +576,16 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) {
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(row, visits, typed_url);
- StartSyncing({*typed_url});
- EXPECT_TRUE(processor().put_multimap().empty());
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
// Even Sync already know the url, bridge still need to tell sync about
// storage keys.
- EXPECT_EQ(1u, processor().update_multimap().size());
-
- // Verify processor receive correct upate storage key.
- const auto& it = processor().update_multimap().begin();
- EXPECT_EQ(it->first, IntToStroageKey(1));
- EXPECT_TRUE(it->second->specifics.has_typed_url());
- EXPECT_EQ(it->second->specifics.typed_url().url(), kURL);
- EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle);
+ const std::string expected_storage_key = IntToStorageKey(1);
+ EXPECT_CALL(mock_processor_,
+ UpdateStorageKey(
+ AllOf(HasURLInSpecifics(kURL), HasTitleInSpecifics(kTitle)),
+ expected_storage_key, _));
+ StartSyncing({*typed_url});
// Check that the local cache was is still correct.
VerifyAllLocalHistoryData({*typed_url});
@@ -603,8 +602,8 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlNoTypedUrl) {
row.set_typed_count(1);
fake_history_backend_->SetVisitsForUrl(&row, visits);
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
StartSyncing(std::vector<TypedUrlSpecifics>());
- EXPECT_TRUE(processor().put_multimap().empty());
MetadataBatch metadata_batch;
metadata_store()->GetAllSyncMetadata(&metadata_batch);
@@ -618,6 +617,9 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptySync) {
URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&row, visits);
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
StartSyncing(std::vector<TypedUrlSpecifics>());
// Check that the local cache was is still correct.
@@ -627,18 +629,14 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptySync) {
VerifyAllLocalHistoryData({*typed_url});
// Check that the server was updated correctly.
- ASSERT_EQ(1U, processor().put_multimap().size());
- auto recorded_specifics_iterator =
- processor().put_multimap().find(GetStorageKey(typed_url->url()));
- EXPECT_NE(processor().put_multimap().end(), recorded_specifics_iterator);
- TypedUrlSpecifics recorded_specifics =
- recorded_specifics_iterator->second->specifics.typed_url();
-
- ASSERT_EQ(1, recorded_specifics.visits_size());
- EXPECT_EQ(3, recorded_specifics.visits(0));
- ASSERT_EQ(1, recorded_specifics.visit_transitions_size());
+ const TypedUrlSpecifics& committed_specifics =
+ entity_data.specifics.typed_url();
+
+ ASSERT_EQ(1, committed_specifics.visits_size());
+ EXPECT_EQ(3, committed_specifics.visits(0));
+ ASSERT_EQ(1, committed_specifics.visit_transitions_size());
EXPECT_EQ(static_cast<const int>(visits[0].transition),
- recorded_specifics.visit_transitions(0));
+ committed_specifics.visit_transitions(0));
}
// Starting sync with no local data should just push the synced url into the
@@ -651,16 +649,13 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(row, visits, typed_url);
+ // Verify processor receive correct update storage key.
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
+ EXPECT_CALL(mock_processor_,
+ UpdateStorageKey(
+ AllOf(HasURLInSpecifics(kURL), HasTitleInSpecifics(kTitle)),
+ IntToStorageKey(1), _));
StartSyncing({*typed_url});
- EXPECT_EQ(0u, processor().put_multimap().size());
- EXPECT_EQ(1u, processor().update_multimap().size());
-
- // Verify processor receive correct upate storage key.
- const auto& it = processor().update_multimap().begin();
- EXPECT_EQ(it->first, IntToStroageKey(1));
- EXPECT_TRUE(it->second->specifics.has_typed_url());
- EXPECT_EQ(it->second->specifics.typed_url().url(), kURL);
- EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle);
// Check that the backend was updated correctly.
VisitVector all_visits;
@@ -693,6 +688,10 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
sync_pb::EntitySpecifics entity_specifics;
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
StartSyncing({*typed_url});
// Check that the backend was updated correctly.
@@ -712,9 +711,8 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
// Check that the sync was updated correctly.
// The local history visit should not be added to sync because it is older
// than sync's oldest visit.
- ASSERT_EQ(1U, processor().put_multimap().size());
-
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
ASSERT_EQ(1, url_specifics.visits_size());
EXPECT_EQ(6, url_specifics.visits(0));
ASSERT_EQ(1, url_specifics.visit_transitions_size());
@@ -740,6 +738,10 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) {
sync_pb::EntitySpecifics entity_specifics;
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
StartSyncing({*typed_url});
// Check that the backend was not updated.
@@ -754,9 +756,8 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) {
// Check that the server was updated correctly.
// The local history visit should not be added to sync because it is older
// than sync's oldest visit.
- ASSERT_EQ(1U, processor().put_multimap().size());
-
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
ASSERT_EQ(1, url_specifics.visits_size());
EXPECT_EQ(3, url_specifics.visits(0));
EXPECT_EQ(kTitle2, url_specifics.title());
@@ -785,15 +786,16 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlsWithUsernameAndPassword) {
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(server_row, server_visits, typed_url);
+ // Check username/password url is not synced.
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _));
+
// Make sure there is no crash when merge two urls.
StartSyncing({*typed_url});
// Notify typed url sync service of the update.
bridge()->OnURLVisited(fake_history_backend_.get(), ui::PAGE_TRANSITION_TYPED,
server_row, RedirectList(), SinceEpoch(7));
-
- // Check username/password url is not synced.
- ASSERT_EQ(1U, processor().put_multimap().size());
}
// Starting sync with both local and sync have same typed URL, but different
@@ -811,8 +813,9 @@ TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
WriteToTypedUrlSpecifics(row2, visits2, typed_url);
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _));
StartSyncing({*typed_url});
- EXPECT_EQ(1u, processor().put_multimap().size());
// Check that the backend was updated correctly.
VisitVector all_visits;
@@ -838,18 +841,18 @@ TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) {
std::vector<std::string> urls;
urls.push_back(kURL);
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(IsValidStorageKey(), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors));
+ BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
VisitVector visits = visit_vectors.front();
- // Check change processor.
- ASSERT_EQ(1U, processor().put_multimap().size());
-
// Get typed url specifics.
- auto it = processor().put_multimap().begin();
- sync_pb::TypedUrlSpecifics url_specifics = it->second->specifics.typed_url();
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
EXPECT_TRUE(URLsEqual(url_row, url_specifics));
ASSERT_EQ(1, url_specifics.visits_size());
@@ -880,13 +883,14 @@ TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) {
changed_urls.push_back(url_row);
// Notify typed url sync service of the update.
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(0U, changes_multimap.size());
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls,
/*is_from_expiration=*/false);
- ASSERT_EQ(1U, changes_multimap.size());
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
EXPECT_TRUE(URLsEqual(url_row, url_specifics));
ASSERT_EQ(3, url_specifics.visits_size());
@@ -909,13 +913,15 @@ TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) {
TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) {
URLRows url_rows;
std::vector<VisitVector> visit_vectors;
- std::vector<std::string> urls;
- urls.push_back(kURL);
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(1U, changes_multimap.size());
+
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _));
+ BuildAndPushLocalChanges(1, 0, {kURL}, &url_rows, &visit_vectors);
+
+ // Check that Put method has been already called.
+ Mock::VerifyAndClearExpectations(&mock_processor_);
// Update the URL row, adding another typed visit to the visit vector.
URLRow url_row = url_rows.front();
@@ -930,7 +936,6 @@ TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) {
ui::PAGE_TRANSITION_RELOAD, url_row, RedirectList(),
SinceEpoch(7));
// No change pass to processor
- ASSERT_EQ(1U, changes_multimap.size());
}
// Appends a LINK visit to an existing typed url. Check that sync does not
@@ -942,9 +947,12 @@ TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
urls.push_back(kURL);
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(1U, changes_multimap.size());
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _));
+ BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors);
+
+ // Check that Put method has been already called.
+ Mock::VerifyAndClearExpectations(&mock_processor_);
// Update the URL row, adding a non-typed visit to the visit vector.
URLRow url_row = url_rows.front();
@@ -957,7 +965,6 @@ TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
RedirectList(), SinceEpoch(6));
// No change pass to processor
- ASSERT_EQ(1U, changes_multimap.size());
}
// Appends a series of LINK visits followed by a TYPED one to an existing typed
@@ -979,14 +986,15 @@ TEST_F(TypedURLSyncBridgeTest, TypedVisitLocalTypedUrl) {
fake_history_backend_->SetVisitsForUrl(&url_row, visits);
// Notify typed url sync service of typed visit.
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(0U, changes_multimap.size());
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
RedirectList(), Time());
- ASSERT_EQ(1U, changes_multimap.size());
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
EXPECT_TRUE(URLsEqual(url_row, url_specifics));
EXPECT_EQ(4, url_specifics.visits_size());
@@ -1014,32 +1022,27 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
urls.push_back("http://foo.com/");
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(4, 0, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(4U, changes_multimap.size());
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _))
+ .Times(4);
+ BuildAndPushLocalChanges(4, 0, urls, &url_rows, &visit_vectors);
// Delete some urls from backend and create deleted row vector.
URLRows rows;
std::set<std::string> deleted_storage_keys;
for (size_t i = 0; i < 3u; ++i) {
- std::string storage_key = GetStorageKey(url_rows[i].url().spec());
+ const std::string storage_key = GetStorageKey(url_rows[i].url().spec());
deleted_storage_keys.insert(storage_key);
fake_history_backend_->DeleteURL(url_rows[i].url());
rows.push_back(url_rows[i]);
}
// Notify typed url sync service.
+ for (const std::string& storage_key : deleted_storage_keys) {
+ EXPECT_CALL(mock_processor_, Delete(storage_key, _));
+ }
bridge()->OnURLsDeleted(fake_history_backend_.get(), false, false, rows,
std::set<GURL>());
-
- const auto& delete_set = processor().delete_set();
- ASSERT_EQ(3U, delete_set.size());
- for (const std::string& storage_key : delete_set) {
- EXPECT_TRUE(deleted_storage_keys.find(storage_key) !=
- deleted_storage_keys.end());
- deleted_storage_keys.erase(storage_key);
- }
- ASSERT_TRUE(deleted_storage_keys.empty());
}
// Delete the last typed visit for one (but not all) local typed urls. Check
@@ -1067,12 +1070,9 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrlVisit) {
URLRow row1_updated;
ASSERT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &row1_updated));
URLRows changed_urls{row1_updated};
+ EXPECT_CALL(mock_processor_, Delete(GetStorageKey(kURL), _));
bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls,
/*is_from_expiration=*/false);
-
- const auto& delete_set = processor().delete_set();
- EXPECT_EQ(1U, delete_set.size());
- EXPECT_EQ(1U, delete_set.count(GetStorageKey(kURL)));
}
// Expire several (but not all) local typed urls. This has only impact on local
@@ -1090,9 +1090,11 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLocalTypedUrl) {
urls.push_back("http://bar.com/");
// Add the URLs into the history db and notify the bridge.
- ASSERT_TRUE(BuildAndPushLocalChanges(5, 0, urls, &url_rows, &visit_vectors));
- ASSERT_EQ(5U, processor().put_multimap().size());
- int previous_put_size = processor().put_multimap().size();
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _))
+ .Times(urls.size());
+ EXPECT_CALL(mock_processor_, UntrackEntityForStorageKey(_)).Times(0);
+ BuildAndPushLocalChanges(urls.size(), 0, urls, &url_rows, &visit_vectors);
// Store the typed_urls incl. metadata into the bridge's database.
for (const std::string& url : urls) {
ApplyUrlAndVisitsChange(url, kTitle, /*typed_count=*/1, /*last_visit=*/3,
@@ -1103,30 +1105,27 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLocalTypedUrl) {
// Check all the metadata is here, no need to untrack anything so far.
MetadataBatch metadata_batch;
metadata_store()->GetAllSyncMetadata(&metadata_batch);
- ASSERT_EQ(5u, metadata_batch.TakeAllMetadata().size());
- ASSERT_EQ(0U, processor().untrack_for_storage_key_set().size());
+ ASSERT_EQ(urls.size(), metadata_batch.TakeAllMetadata().size());
// Simulate expiration - delete some urls from the backend and create deleted
// row vector.
URLRows rows;
std::set<std::string> deleted_storage_keys;
for (size_t i = 0; i < 3u; ++i) {
- std::string storage_key = GetStorageKey(url_rows[i].url().spec());
+ const std::string storage_key = GetStorageKey(url_rows[i].url().spec());
deleted_storage_keys.insert(storage_key);
fake_history_backend_->DeleteURL(url_rows[i].url());
rows.push_back(url_rows[i]);
}
// Notify typed url sync service of these URLs getting expired.
+ EXPECT_CALL(mock_processor_, Delete(_, _)).Times(0);
+ for (const std::string& storage_key : deleted_storage_keys) {
+ EXPECT_CALL(mock_processor_, UntrackEntityForStorageKey(storage_key));
+ }
bridge()->OnURLsDeleted(fake_history_backend_.get(), /*all_history=*/false,
/*expired=*/true, rows, std::set<GURL>());
- // This does not propagate to the processor.
- EXPECT_EQ(0U, processor().put_multimap().size() - previous_put_size);
- EXPECT_EQ(0U, processor().delete_set().size());
- // The processor is still informed to clear its in-memory maps.
- EXPECT_EQ(3U, processor().untrack_for_storage_key_set().size());
-
// The urls are removed from the metadata store.
MetadataBatch smaller_metadata_batch;
metadata_store()->GetAllSyncMetadata(&smaller_metadata_batch);
@@ -1146,10 +1145,9 @@ TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
std::vector<std::string> urls;
urls.push_back(kURL);
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(0U, changes_multimap.size());
+ BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
VisitVector visits;
@@ -1167,12 +1165,15 @@ TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
fake_history_backend_->SetVisitsForUrl(&url_row, visits);
// Notify typed url sync service of typed visit.
- ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ const ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
RedirectList(), Time());
- ASSERT_EQ(1U, changes_multimap.size());
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
ASSERT_EQ(kMaxTypedUrlVisits, url_specifics.visits_size());
// Check that each visit has been translated/communicated correctly.
@@ -1202,10 +1203,9 @@ TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
std::vector<std::string> urls;
urls.push_back(kURL);
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(0U, changes_multimap.size());
+ BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
VisitVector visits;
@@ -1222,9 +1222,6 @@ TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
RedirectList(), Time());
- // Should throttle, so sync and local cache should not update.
- ASSERT_EQ(0U, changes_multimap.size());
-
visits.clear();
for (; i % kVisitThrottleMultiple != 1; ++i)
AddNewestVisit(ui::PAGE_TRANSITION_TYPED, i, &url_row, &visits);
@@ -1232,34 +1229,31 @@ TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
fake_history_backend_->SetVisitsForUrl(&url_row, visits);
// Notify typed url sync service of typed visit.
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
bridge()->OnURLVisited(fake_history_backend_.get(), transition, url_row,
RedirectList(), Time());
- ASSERT_EQ(1U, changes_multimap.size());
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
- ASSERT_EQ(i, url_specifics.visits_size());
+ ASSERT_EQ(i, entity_data.specifics.typed_url().visits_size());
}
// Create a remote typed URL and visit, then send to sync bridge after sync
// has started. Check that local DB is received the new URL and visit.
TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) {
StartSyncing(std::vector<TypedUrlSpecifics>());
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
+ EXPECT_CALL(mock_processor_, UntrackEntityForStorageKey(_)).Times(0);
+
+ EXPECT_CALL(mock_processor_,
+ UpdateStorageKey(
+ AllOf(HasURLInSpecifics(kURL), HasTitleInSpecifics(kTitle)),
+ IntToStorageKey(1), _));
VisitVector visits = ApplyUrlAndVisitsChange(
kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
/*hidden=*/false,
/*update_metadata=*/false, EntityChange::ACTION_ADD);
- ASSERT_EQ(0U, processor().put_multimap().size());
- ASSERT_EQ(1U, processor().update_multimap().size());
- ASSERT_EQ(0U, processor().untrack_for_client_tag_hash_set().size());
-
- // Verify processor receive correct upate storage key.
- const auto& it = processor().update_multimap().begin();
- EXPECT_EQ(it->first, IntToStroageKey(1));
- EXPECT_TRUE(it->second->specifics.has_typed_url());
- EXPECT_EQ(it->second->specifics.typed_url().url(), kURL);
- EXPECT_EQ(it->second->specifics.typed_url().title(), kTitle);
-
Time visit_time = SinceEpoch(3);
VisitVector all_visits;
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
@@ -1278,17 +1272,16 @@ TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) {
// sync has started. Check that local DB did not receive the expired URL and
// visit.
TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) {
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
+ EXPECT_CALL(mock_processor_, UpdateStorageKey(_, _, _)).Times(0);
+
+ EXPECT_CALL(mock_processor_, UntrackEntityForClientTagHash(_));
StartSyncing(std::vector<TypedUrlSpecifics>());
- VisitVector visits = ApplyUrlAndVisitsChange(
+ ApplyUrlAndVisitsChange(
kURL, kTitle, /*typed_count=*/1, /*last_visit=*/kExpiredVisit,
/*hidden=*/false, /*update_metadata=*/false, EntityChange::ACTION_ADD);
- ASSERT_EQ(0U, processor().put_multimap().size());
- ASSERT_EQ(0U, processor().update_multimap().size());
- ASSERT_EQ(1U, processor().untrack_for_client_tag_hash_set().size());
-
- URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
- ASSERT_EQ(0, url_id);
+ ASSERT_EQ(0, fake_history_backend_->GetIdByUrl(GURL(kURL)));
}
// Update a remote typed URL and create a new visit that is already synced, then
@@ -1344,9 +1337,9 @@ TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
urls.push_back(kURL);
StartSyncing(std::vector<TypedUrlSpecifics>());
- ASSERT_TRUE(BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors));
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(1U, changes_multimap.size());
+ EXPECT_CALL(mock_processor_,
+ Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _));
+ BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors);
Time visit_time = SinceEpoch(3);
VisitVector all_visits;
@@ -1372,10 +1365,6 @@ TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
EXPECT_FALSE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_EQ(0, url_id);
-
- // Check TypedUrlSyncBridge did not receive update since the update is
- // trigered by it.
- ASSERT_EQ(1U, changes_multimap.size());
}
// Create two set of visits for history DB and sync DB, two same set of visits
@@ -1686,26 +1675,26 @@ TEST_F(TypedURLSyncBridgeTest, LocalExpiredTypedUrlDoNotSync) {
row = MakeTypedUrlRow(kURL, kTitle, 1, kExpiredVisit, false, &visits);
fake_history_backend_->SetVisitsForUrl(&row, visits);
- StartSyncing(std::vector<TypedUrlSpecifics>());
-
// Check change processor did not receive expired typed URL.
- const auto& changes_multimap = processor().put_multimap();
- ASSERT_EQ(0U, changes_multimap.size());
+ EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(0);
+ StartSyncing(std::vector<TypedUrlSpecifics>());
// Add a non expired typed URL to local.
row = MakeTypedUrlRow(kURL, kTitle, 2, 1, false, &visits);
fake_history_backend_->SetVisitsForUrl(&row, visits);
changed_urls.push_back(row);
+ // Check change processor did not receive expired typed URL.
+ EntityData entity_data;
+ EXPECT_CALL(mock_processor_, Put(GetStorageKey(kURL), _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&entity_data));
// Notify typed url sync service of the update.
bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls,
/*is_from_expiration=*/false);
- // Check change processor did not receive expired typed URL.
- ASSERT_EQ(1U, changes_multimap.size());
-
// Get typed url specifics. Verify only a non-expired visit received.
- sync_pb::TypedUrlSpecifics url_specifics = GetLastUpdateForURL(kURL);
+ const sync_pb::TypedUrlSpecifics& url_specifics =
+ entity_data.specifics.typed_url();
EXPECT_TRUE(URLsEqual(row, url_specifics));
ASSERT_EQ(1, url_specifics.visits_size());
@@ -1718,8 +1707,8 @@ TEST_F(TypedURLSyncBridgeTest, LocalExpiredTypedUrlDoNotSync) {
// Tests that database error gets reported to processor as model type error.
TEST_F(TypedURLSyncBridgeTest, DatabaseError) {
+ EXPECT_CALL(mock_processor_, ReportError(_));
bridge()->OnDatabaseError();
- EXPECT_TRUE(processor().GetError().has_value());
}
} // namespace history
diff --git a/chromium/components/history/core/browser/top_sites_backend.cc b/chromium/components/history/core/browser/top_sites_backend.cc
index 4b9dbfeda7c..d8373b95b7f 100644
--- a/chromium/components/history/core/browser/top_sites_backend.cc
+++ b/chromium/components/history/core/browser/top_sites_backend.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/logging.h"
diff --git a/chromium/components/history/core/browser/top_sites_impl.cc b/chromium/components/history/core/browser/top_sites_impl.cc
index f48ddae6c80..1c47b727b08 100644
--- a/chromium/components/history/core/browser/top_sites_impl.cc
+++ b/chromium/components/history/core/browser/top_sites_impl.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/hash/md5.h"
#include "base/location.h"
@@ -214,7 +214,8 @@ void TopSitesImpl::OnNavigationCommitted(const GURL& url) {
void TopSitesImpl::ShutdownOnUIThread() {
history_service_ = nullptr;
- history_service_observer_.RemoveAll();
+ if (history_service_observation_.IsObserving())
+ history_service_observation_.RemoveObservation();
// Cancel all requests so that the service doesn't callback to us after we've
// invoked Shutdown (this could happen if we have a pending request and
// Shutdown is invoked).
@@ -398,7 +399,7 @@ void TopSitesImpl::MoveStateToLoaded() {
std::move(callback).Run(urls);
if (history_service_)
- history_service_observer_.Add(history_service_);
+ history_service_observation_.Observe(history_service_);
NotifyTopSitesLoaded();
}
diff --git a/chromium/components/history/core/browser/top_sites_impl.h b/chromium/components/history/core/browser/top_sites_impl.h
index 043df9d45c4..168912b2d3d 100644
--- a/chromium/components/history/core/browser/top_sites_impl.h
+++ b/chromium/components/history/core/browser/top_sites_impl.h
@@ -14,7 +14,7 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/synchronization/lock.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/threading/thread_checker.h"
@@ -210,8 +210,8 @@ class TopSitesImpl : public TopSites, public HistoryServiceObserver {
// The histogram should only be recorded once for each Chrome execution.
static bool histogram_recorded_;
- ScopedObserver<HistoryService, HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<HistoryService, HistoryServiceObserver>
+ history_service_observation_{this};
DISALLOW_COPY_AND_ASSIGN(TopSitesImpl);
};
diff --git a/chromium/components/history/core/browser/url_database.h b/chromium/components/history/core/browser/url_database.h
index b233f4be894..29cab2c2826 100644
--- a/chromium/components/history/core/browser/url_database.h
+++ b/chromium/components/history/core/browser/url_database.h
@@ -246,13 +246,6 @@ class URLDatabase {
// removed once data is collected from experiment.
virtual bool GetVisitsForUrl2(URLID url_id, VisitVector* visits);
- // Migration -----------------------------------------------------------------
-
- // Do to a bug we were setting the favicon of about:blank. This forces
- // about:blank to have no icon or title. Returns true on success, false if
- // the favicon couldn't be updated.
- bool MigrateFromVersion11ToVersion12();
-
protected:
friend class VisitDatabase;
diff --git a/chromium/components/history/core/test/BUILD.gn b/chromium/components/history/core/test/BUILD.gn
index 2f067c62667..5bec5400196 100644
--- a/chromium/components/history/core/test/BUILD.gn
+++ b/chromium/components/history/core/test/BUILD.gn
@@ -2,13 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("test") {
testonly = true
sources = [
@@ -27,9 +20,7 @@ static_library("test") {
"test_history_database.cc",
"test_history_database.h",
"thumbnail-inl.h",
- "thumbnail.cc",
"thumbnail.h",
- "thumbnail_ios.mm",
"wait_top_sites_loaded_observer.cc",
"wait_top_sites_loaded_observer.h",
]
@@ -49,6 +40,8 @@ static_library("test") {
]
if (is_ios) {
- sources -= [ "thumbnail.cc" ]
+ sources += [ "thumbnail_ios.mm" ]
+ } else {
+ sources += [ "thumbnail.cc" ]
}
}
diff --git a/chromium/components/image_fetcher/core/cache/image_cache.cc b/chromium/components/image_fetcher/core/cache/image_cache.cc
index 02ea9261a65..7737d6dcd51 100644
--- a/chromium/components/image_fetcher/core/cache/image_cache.cc
+++ b/chromium/components/image_fetcher/core/cache/image_cache.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/hash/sha1.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
diff --git a/chromium/components/image_fetcher/core/cached_image_fetcher.cc b/chromium/components/image_fetcher/core/cached_image_fetcher.cc
index c056c970a2f..7f4e524a176 100644
--- a/chromium/components/image_fetcher/core/cached_image_fetcher.cc
+++ b/chromium/components/image_fetcher/core/cached_image_fetcher.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
diff --git a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
index db17f2d2635..e072adb29ca 100644
--- a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
+++ b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/image_fetcher/core/request_metadata.h"
diff --git a/chromium/components/image_fetcher/core/image_fetcher_impl_unittest.cc b/chromium/components/image_fetcher/core/image_fetcher_impl_unittest.cc
index 6ddd9b77c6c..99c23258cfd 100644
--- a/chromium/components/image_fetcher/core/image_fetcher_impl_unittest.cc
+++ b/chromium/components/image_fetcher/core/image_fetcher_impl_unittest.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/image_fetcher/core/fake_image_decoder.h"
diff --git a/chromium/components/infobars/android/confirm_infobar.cc b/chromium/components/infobars/android/confirm_infobar.cc
index e44f3ef17c6..0796c5df145 100644
--- a/chromium/components/infobars/android/confirm_infobar.cc
+++ b/chromium/components/infobars/android/confirm_infobar.cc
@@ -51,7 +51,7 @@ ScopedJavaLocalRef<jobject> ConfirmInfoBar::CreateRenderInfoBar(JNIEnv* env) {
ScopedJavaLocalRef<jobject> java_bitmap;
if (delegate->GetIconId() == infobars::InfoBarDelegate::kNoIconID &&
!delegate->GetIcon().IsEmpty()) {
- java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
+ java_bitmap = gfx::ConvertToJavaBitmap(*delegate->GetIcon().ToSkBitmap());
}
return Java_ConfirmInfoBar_create(env, GetJavaIconId(), java_bitmap,
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.cc b/chromium/components/infobars/core/confirm_infobar_delegate.cc
index 4227d19a8a2..1177aab9e01 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.cc
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.cc
@@ -4,6 +4,7 @@
#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "build/build_config.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"
@@ -26,6 +27,10 @@ ConfirmInfoBarDelegate::GetInfoBarAutomationType() const {
return CONFIRM_INFOBAR;
}
+base::string16 ConfirmInfoBarDelegate::GetTitleText() const {
+ return base::string16();
+}
+
gfx::ElideBehavior ConfirmInfoBarDelegate::GetMessageElideBehavior() const {
return gfx::ELIDE_TAIL;
}
@@ -44,6 +49,12 @@ bool ConfirmInfoBarDelegate::OKButtonTriggersUACPrompt() const {
return false;
}
+#if defined(OS_IOS)
+bool ConfirmInfoBarDelegate::UseIconBackgroundTint() const {
+ return true;
+}
+#endif
+
bool ConfirmInfoBarDelegate::Accept() {
return true;
}
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.h b/chromium/components/infobars/core/confirm_infobar_delegate.h
index df7a53372b8..998fa02fd0c 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.h
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.h
@@ -6,6 +6,7 @@
#define COMPONENTS_INFOBARS_CORE_CONFIRM_INFOBAR_DELEGATE_H_
#include "base/strings/string16.h"
+#include "build/build_config.h"
#include "components/infobars/core/infobar_delegate.h"
#include "components/infobars/core/infobar_manager.h"
#include "ui/gfx/text_constants.h"
@@ -35,6 +36,10 @@ class ConfirmInfoBarDelegate : public infobars::InfoBarDelegate {
// Returns the InfoBar type to be displayed for the InfoBar.
InfoBarAutomationType GetInfoBarAutomationType() const override;
+ // Returns the title string to be displayed for the InfoBar.
+ // Defaults to having not title. Currently only used on iOS.
+ virtual base::string16 GetTitleText() const;
+
// Returns the message string to be displayed for the InfoBar.
virtual base::string16 GetMessageText() const = 0;
@@ -53,6 +58,12 @@ class ConfirmInfoBarDelegate : public infobars::InfoBarDelegate {
// Windows.
virtual bool OKButtonTriggersUACPrompt() const;
+#if defined(OS_IOS)
+ // Returns whether or not a tint should be applied to the icon background.
+ // Defaults to true.
+ virtual bool UseIconBackgroundTint() const;
+#endif
+
// Called when the OK button is pressed. If this function returns true, the
// infobar is then immediately closed. Subclasses MUST NOT return true if in
// handling this call something triggers the infobar to begin closing.
diff --git a/chromium/components/infobars/core/infobar_delegate.h b/chromium/components/infobars/core/infobar_delegate.h
index 34e468a758f..d32451e392a 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -158,17 +158,18 @@ class InfoBarDelegate {
MODULE_INSTALL_FAILURE_INFOBAR_ANDROID = 88,
INLINE_UPDATE_READY_INFOBAR_ANDROID = 89,
INLINE_UPDATE_FAILED_INFOBAR_ANDROID = 90,
- FLASH_DEPRECATION_INFOBAR_DELEGATE = 91,
+ // Removed: FLASH_DEPRECATION_INFOBAR_DELEGATE = 91,
SEND_TAB_TO_SELF_INFOBAR_DELEGATE = 92,
TAB_SHARING_INFOBAR_DELEGATE = 93,
SAFETY_TIP_INFOBAR_DELEGATE = 94,
- SMS_RECEIVER_INFOBAR_DELEGATE = 95,
+ WEBOTP_SERVICE_INFOBAR_DELEGATE = 95,
KNOWN_INTERCEPTION_DISCLOSURE_INFOBAR_DELEGATE = 96,
SYNC_ERROR_INFOBAR_DELEGATE_ANDROID = 97,
MIXED_CONTENT_DOWNLOAD_INFOBAR_DELEGATE_ANDROID = 98,
CONDITIONAL_TAB_STRIP_INFOBAR_ANDROID = 99,
LITE_MODE_HTTPS_IMAGE_COMPRESSION_INFOBAR_ANDROID = 100,
SYSTEM_INFOBAR_DELEGATE_MAC = 101,
+ EXPERIMENTAL_INFOBAR_DELEGATE_LACROS = 102,
ROSETTA_REQUIRED_INFOBAR_DELEGATE = 103,
};
diff --git a/chromium/components/javascript_dialogs/android/BUILD.gn b/chromium/components/javascript_dialogs/android/BUILD.gn
index faeebe8c943..6fe6f1d561b 100644
--- a/chromium/components/javascript_dialogs/android/BUILD.gn
+++ b/chromium/components/javascript_dialogs/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
android_library("java") {
sources = [
diff --git a/chromium/components/keyed_service/core/keyed_service.h b/chromium/components/keyed_service/core/keyed_service.h
index f9fd7ab138f..2bd32cf2167 100644
--- a/chromium/components/keyed_service/core/keyed_service.h
+++ b/chromium/components/keyed_service/core/keyed_service.h
@@ -17,6 +17,11 @@
// should *not* request other services from their factories via the relevant
// Context object (e.g., Profile), as the association between that Context
// object and its keyed services is dropped after the shutdown phase.
+// Shutdown of KeyedServices is generally initiated by the embedder's
+// destruction of Profile (or analogous object).
+// CAVEAT: Not all embedders destroy the Profiles (or Profile analogs) as part
+// of embedder shutdown, so it is not guaranteed that the keyed service shutdown
+// process will run at shutdown of a given embedder.
class KEYED_SERVICE_EXPORT KeyedService {
public:
KeyedService();
diff --git a/chromium/components/language/content/browser/geo_language_model_unittest.cc b/chromium/components/language/content/browser/geo_language_model_unittest.cc
index 28287ac6849..617cf159407 100644
--- a/chromium/components/language/content/browser/geo_language_model_unittest.cc
+++ b/chromium/components/language/content/browser/geo_language_model_unittest.cc
@@ -5,7 +5,7 @@
#include "components/language/content/browser/geo_language_model.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/test/task_environment.h"
#include "base/timer/timer.h"
diff --git a/chromium/components/language/content/browser/geo_language_provider_unittest.cc b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
index a5d6aca37ba..fb9193ef6b2 100644
--- a/chromium/components/language/content/browser/geo_language_provider_unittest.cc
+++ b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/language/core/browser/language_prefs_unittest.cc b/chromium/components/language/core/browser/language_prefs_unittest.cc
index 3484aa1e925..3e232a968b7 100644
--- a/chromium/components/language/core/browser/language_prefs_unittest.cc
+++ b/chromium/components/language/core/browser/language_prefs_unittest.cc
@@ -11,7 +11,6 @@
#include <vector>
#include "base/json/json_reader.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/values.h"
#include "build/build_config.h"
diff --git a/chromium/components/language/core/common/language_experiments.cc b/chromium/components/language/core/common/language_experiments.cc
index ad4827b6396..0a254848c3f 100644
--- a/chromium/components/language/core/common/language_experiments.cc
+++ b/chromium/components/language/core/common/language_experiments.cc
@@ -32,6 +32,10 @@ const base::Feature kNotifySyncOnLanguageDetermined{
"NotifySyncOnLanguageDetermined", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kDetailedLanguageSettings{
"DetailedLanguageSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTranslateAssistContent{"TranslateAssistContent",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTranslateIntent{"TranslateIntent",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// Params:
const char kBackoffThresholdKey[] = "backoff_threshold";
diff --git a/chromium/components/language/core/common/language_experiments.h b/chromium/components/language/core/common/language_experiments.h
index 283be886afe..f64815312cd 100644
--- a/chromium/components/language/core/common/language_experiments.h
+++ b/chromium/components/language/core/common/language_experiments.h
@@ -39,6 +39,12 @@ extern const base::Feature kUseButtonTranslateBubbleUi;
// This feature enables setting the application language on Android.
extern const base::Feature kDetailedLanguageSettings;
+// This feature enables providing Translate data to Assistant.
+extern const base::Feature kTranslateAssistContent;
+
+// This feature enables an intent that starts translating the foreground tab.
+extern const base::Feature kTranslateIntent;
+
enum class OverrideLanguageModel {
DEFAULT,
FLUENT,
diff --git a/chromium/components/language_usage_metrics/BUILD.gn b/chromium/components/language_usage_metrics/BUILD.gn
index 960319f5a2f..26155effd10 100644
--- a/chromium/components/language_usage_metrics/BUILD.gn
+++ b/chromium/components/language_usage_metrics/BUILD.gn
@@ -8,7 +8,10 @@ static_library("language_usage_metrics") {
"language_usage_metrics.h",
]
- deps = [ "//base" ]
+ deps = [
+ "//base",
+ "//components/language/core/browser:browser",
+ ]
}
source_set("unit_tests") {
@@ -17,6 +20,9 @@ source_set("unit_tests") {
deps = [
":language_usage_metrics",
+ "//base",
+ "//components/language/core/browser:browser",
+ "//components/prefs:test_support",
"//testing/gtest",
]
}
diff --git a/chromium/components/language_usage_metrics/DEPS b/chromium/components/language_usage_metrics/DEPS
new file mode 100644
index 00000000000..27895b9531f
--- /dev/null
+++ b/chromium/components/language_usage_metrics/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+components/language",
+]
+
+specific_include_rules = {
+ ".*unittest.cc": [
+ "+components/prefs",
+ ],
+}
diff --git a/chromium/components/language_usage_metrics/language_usage_metrics.cc b/chromium/components/language_usage_metrics/language_usage_metrics.cc
index b123be35e4a..4f9dd2f8af9 100644
--- a/chromium/components/language_usage_metrics/language_usage_metrics.cc
+++ b/chromium/components/language_usage_metrics/language_usage_metrics.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_tokenizer.h"
+#include "components/language/core/browser/url_language_histogram.h"
namespace language_usage_metrics {
@@ -26,6 +27,27 @@ void LanguageUsageMetrics::RecordAcceptLanguages(
}
// static
+void LanguageUsageMetrics::RecordPageLanguages(
+ const language::UrlLanguageHistogram& language_counts) {
+ const float kMinLanguageFrequency = 0.05;
+ std::vector<language::UrlLanguageHistogram::LanguageInfo> top_languages =
+ language_counts.GetTopLanguages();
+
+ for (const language::UrlLanguageHistogram::LanguageInfo& language_info :
+ top_languages) {
+ if (language_info.frequency < kMinLanguageFrequency) {
+ continue;
+ }
+
+ const int language_code = ToLanguageCode(language_info.language_code);
+ if (language_code != 0) {
+ base::UmaHistogramSparse("LanguageUsage.MostFrequentPageLanguages",
+ language_code);
+ }
+ }
+}
+
+// static
void LanguageUsageMetrics::RecordApplicationLanguage(
base::StringPiece application_locale) {
const int language_code = ToLanguageCode(application_locale);
diff --git a/chromium/components/language_usage_metrics/language_usage_metrics.h b/chromium/components/language_usage_metrics/language_usage_metrics.h
index 7cea6f66419..f350bec471b 100644
--- a/chromium/components/language_usage_metrics/language_usage_metrics.h
+++ b/chromium/components/language_usage_metrics/language_usage_metrics.h
@@ -11,6 +11,10 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
+namespace language {
+class UrlLanguageHistogram;
+}
+
namespace language_usage_metrics {
// Methods to record language usage as UMA histograms.
@@ -23,6 +27,13 @@ class LanguageUsageMetrics {
// identical and recorded once.
static void RecordAcceptLanguages(base::StringPiece accept_languages);
+ // Records detected page language history as a UMA histogram.
+ // |UrlLanguageHistogram| is a mapping of page language to frequency. Country
+ // codes are ignored for page language. Each language is counted once
+ // regardless of frequency. Languages with a frequency below 0.05 are ignored.
+ static void RecordPageLanguages(
+ const language::UrlLanguageHistogram& language_counts);
+
// Records the application language as a UMA histogram. |application_locale|
// is a case-insensitive locale string of either xx, xx-YY, or xx_YY format.
// Only the language part (xx in the example) is considered.
diff --git a/chromium/components/language_usage_metrics/language_usage_metrics_unittest.cc b/chromium/components/language_usage_metrics/language_usage_metrics_unittest.cc
index 74344eb3294..03195fc1623 100644
--- a/chromium/components/language_usage_metrics/language_usage_metrics_unittest.cc
+++ b/chromium/components/language_usage_metrics/language_usage_metrics_unittest.cc
@@ -4,10 +4,188 @@
#include "components/language_usage_metrics/language_usage_metrics.h"
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "components/language/core/browser/url_language_histogram.h"
+#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::HistogramBase;
+using base::HistogramSamples;
+using base::SampleCountIterator;
+using base::StatisticsRecorder;
+using language::UrlLanguageHistogram;
+
namespace language_usage_metrics {
+namespace {
+
+class MetricsRecorder {
+ public:
+ explicit MetricsRecorder(const char* key) : key_(key) {
+ HistogramBase* histogram = StatisticsRecorder::FindHistogram(key_);
+ if (histogram)
+ base_samples_ = histogram->SnapshotSamples();
+ }
+
+ void CheckTotalCount(int count) {
+ Snapshot();
+ EXPECT_EQ(count, GetTotalCount());
+ }
+
+ void CheckValueCount(HistogramBase::Sample value, int count) {
+ Snapshot();
+ EXPECT_EQ(count, GetCountWithoutSnapshot(value));
+ }
+
+ private:
+ void Snapshot() {
+ HistogramBase* histogram = StatisticsRecorder::FindHistogram(key_);
+ if (!histogram)
+ return;
+ samples_ = histogram->SnapshotSamples();
+ }
+
+ HistogramBase::Count GetCountWithoutSnapshot(HistogramBase::Sample value) {
+ if (!samples_)
+ return 0;
+ HistogramBase::Count count = samples_->GetCount(value);
+ if (!base_samples_)
+ return count;
+ return count - base_samples_->GetCount(value);
+ }
+
+ HistogramBase::Count GetTotalCount() {
+ if (!samples_)
+ return 0;
+ HistogramBase::Count count = samples_->TotalCount();
+ if (!base_samples_)
+ return count;
+ return count - base_samples_->TotalCount();
+ }
+
+ std::string key_;
+ std::unique_ptr<HistogramSamples> base_samples_;
+ std::unique_ptr<HistogramSamples> samples_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsRecorder);
+};
+
+void RecordPageLanguageVisits(UrlLanguageHistogram& language_histogram,
+ std::string language,
+ int count) {
+ for (int i = 0; i < count; i++) {
+ language_histogram.OnPageVisited(language);
+ }
+}
+
+struct LanguageCodeHash {
+ LanguageCodeHash() = default;
+ LanguageCodeHash(const std::string& code, int hash)
+ : code(code), hash(hash) {}
+ std::string code;
+ int hash;
+};
+
+} // namespace
+
+TEST(LanguageUsageMetricsTest, RecordPageLanguageCounts) {
+ const LanguageCodeHash EN("en", 25966);
+ const LanguageCodeHash ES("es", 25971);
+ const LanguageCodeHash JP("ja", 27233);
+
+ TestingPrefServiceSimple prefs;
+ UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+ UrlLanguageHistogram url_hist(&prefs);
+
+ // Initialize recorder
+ MetricsRecorder recorder("LanguageUsage.MostFrequentPageLanguages");
+ recorder.CheckTotalCount(0);
+
+ // Check that nothing is recorded if less than 10 page visits.
+ RecordPageLanguageVisits(url_hist, EN.code, 8);
+ RecordPageLanguageVisits(url_hist, ES.code, 1);
+ LanguageUsageMetrics::RecordPageLanguages(url_hist);
+ recorder.CheckTotalCount(0);
+
+ // Check that recording works at 10 page visits.
+ RecordPageLanguageVisits(url_hist, EN.code, 1);
+ LanguageUsageMetrics::RecordPageLanguages(url_hist);
+ recorder.CheckTotalCount(2);
+ recorder.CheckValueCount(EN.hash, 1);
+ recorder.CheckValueCount(ES.hash, 1);
+
+ // Check that languages with frequency below 0.05 are not recorded.
+ RecordPageLanguageVisits(url_hist, EN.code, 28); // 37/40
+ RecordPageLanguageVisits(url_hist, ES.code, 1); // 2/40 -> exactly 0.05
+ RecordPageLanguageVisits(url_hist, JP.code, 1); // 1/40 -> below 0.05
+ LanguageUsageMetrics::RecordPageLanguages(url_hist);
+ recorder.CheckTotalCount(4);
+ recorder.CheckValueCount(EN.hash, 2);
+ recorder.CheckValueCount(ES.hash, 2);
+ recorder.CheckValueCount(JP.hash, 0);
+}
+
+TEST(LanguageUsageMetricsTest, RecordAcceptLanguages) {
+ const LanguageCodeHash EN("en", 25966);
+ const LanguageCodeHash ES("es", 25971);
+ const LanguageCodeHash JP("ja", 27233);
+
+ // Initialize recorders
+ MetricsRecorder recorder("LanguageUsage.AcceptLanguage");
+ MetricsRecorder recorder_count("LanguageUsage.AcceptLanguage.Count");
+ recorder.CheckTotalCount(0);
+ recorder_count.CheckTotalCount(0);
+
+ LanguageUsageMetrics::RecordAcceptLanguages("en");
+ LanguageUsageMetrics::RecordAcceptLanguages("en");
+ recorder.CheckTotalCount(2);
+ recorder.CheckValueCount(EN.hash, 2);
+ recorder_count.CheckTotalCount(2);
+ recorder_count.CheckValueCount(1, 2);
+
+ LanguageUsageMetrics::RecordAcceptLanguages("en,es");
+ recorder.CheckTotalCount(4);
+ recorder.CheckValueCount(EN.hash, 3);
+ recorder.CheckValueCount(ES.hash, 1);
+ recorder_count.CheckTotalCount(3);
+ recorder_count.CheckValueCount(1, 2);
+ recorder_count.CheckValueCount(2, 1);
+
+ LanguageUsageMetrics::RecordAcceptLanguages("en,es,ja-JP");
+ recorder.CheckTotalCount(7);
+ recorder.CheckTotalCount(7);
+ recorder.CheckValueCount(EN.hash, 4);
+ recorder.CheckValueCount(ES.hash, 2);
+ recorder.CheckValueCount(JP.hash, 1);
+ recorder_count.CheckTotalCount(4);
+ recorder_count.CheckValueCount(1, 2);
+ recorder_count.CheckValueCount(2, 1);
+ recorder_count.CheckValueCount(3, 1);
+}
+
+TEST(LanguageUsageMetricsTest, RecordApplicationLanguage) {
+ const LanguageCodeHash EN("en", 25966);
+ const LanguageCodeHash ES("es", 25971);
+
+ // Initialize recorder
+ MetricsRecorder recorder("LanguageUsage.ApplicationLanguage");
+
+ LanguageUsageMetrics::RecordApplicationLanguage("en");
+ LanguageUsageMetrics::RecordApplicationLanguage("en-US");
+ LanguageUsageMetrics::RecordApplicationLanguage("en-UK");
+ recorder.CheckTotalCount(3);
+ recorder.CheckValueCount(EN.hash, 3);
+
+ LanguageUsageMetrics::RecordApplicationLanguage("es");
+ LanguageUsageMetrics::RecordApplicationLanguage("es-ES");
+ LanguageUsageMetrics::RecordApplicationLanguage("es-419");
+ recorder.CheckTotalCount(6);
+ recorder.CheckValueCount(ES.hash, 3);
+}
+
TEST(LanguageUsageMetricsTest, ParseAcceptLanguages) {
std::set<int> language_set;
std::set<int>::const_iterator it;
diff --git a/chromium/components/leveldb_proto/internal/leveldb_proto_feature_list.cc b/chromium/components/leveldb_proto/internal/leveldb_proto_feature_list.cc
index 5b302bac462..a4b482567b1 100644
--- a/chromium/components/leveldb_proto/internal/leveldb_proto_feature_list.cc
+++ b/chromium/components/leveldb_proto/internal/leveldb_proto_feature_list.cc
@@ -7,6 +7,6 @@
namespace leveldb_proto {
const base::Feature kProtoDBSharedMigration{"ProtoDBSharedMigration",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace leveldb_proto
diff --git a/chromium/components/leveldb_proto/internal/proto_database_perftest.cc b/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
index 9ed1a87f252..b86daa8e3b3 100644
--- a/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
+++ b/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
@@ -14,7 +14,7 @@
#include "base/timer/elapsed_timer.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database.cc b/chromium/components/leveldb_proto/internal/shared_proto_database.cc
index 04e129209ab..2ff7ac41995 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database.cc
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database.h b/chromium/components/leveldb_proto/internal/shared_proto_database.h
index 8303ad02a76..1d9c4237ae7 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database.h
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/component_export.h"
#include "base/containers/queue.h"
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc b/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
index c61847d8e8b..71565da1e56 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
@@ -8,7 +8,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/string_util.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/leveldb_proto/internal/unique_proto_database_unittest.cc b/chromium/components/leveldb_proto/internal/unique_proto_database_unittest.cc
index 5b277fd451c..b6bda4c06d3 100644
--- a/chromium/components/leveldb_proto/internal/unique_proto_database_unittest.cc
+++ b/chromium/components/leveldb_proto/internal/unique_proto_database_unittest.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
diff --git a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
index 1b374773b27..eae251db285 100644
--- a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
+++ b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
@@ -80,8 +80,8 @@ std::string SharedProtoDatabaseClientList::ProtoDbTypeToString(
return "PrintJobDatabase";
case ProtoDbType::FEED_STREAM_DATABASE:
return "FeedStreamDatabase";
- case ProtoDbType::TAB_STATE_DATABASE:
- return "TabStateDatabase";
+ case ProtoDbType::PERSISTED_STATE_DATABASE:
+ return "PersistedStateDatabase";
case ProtoDbType::UPBOARDING_QUERY_TILE_STORE:
return "UpboardingQueryTileStore";
case ProtoDbType::NEARBY_SHARE_PUBLIC_CERTIFICATE_DATABASE:
diff --git a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
index 3e694d5a055..57d6886bcb1 100644
--- a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
+++ b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -49,7 +49,7 @@ enum class ProtoDbType {
// DB Used by shared database, will always be unique.
SHARED_DB_METADATA = 25,
FEED_STREAM_DATABASE = 26,
- TAB_STATE_DATABASE = 27,
+ PERSISTED_STATE_DATABASE = 27,
UPBOARDING_QUERY_TILE_STORE = 28,
NEARBY_SHARE_PUBLIC_CERTIFICATE_DATABASE = 29,
VIDEO_TUTORIALS_DATABASE = 30,
@@ -64,7 +64,7 @@ constexpr ProtoDbType kWhitelistedDbForSharedImpl[]{
ProtoDbType::NOTIFICATION_SCHEDULER_NOTIFICATION_STORE,
ProtoDbType::PRINT_JOB_DATABASE,
ProtoDbType::FEED_STREAM_DATABASE,
- ProtoDbType::TAB_STATE_DATABASE,
+ ProtoDbType::PERSISTED_STATE_DATABASE,
ProtoDbType::UPBOARDING_QUERY_TILE_STORE,
ProtoDbType::NEARBY_SHARE_PUBLIC_CERTIFICATE_DATABASE,
ProtoDbType::VIDEO_TUTORIALS_DATABASE,
diff --git a/chromium/components/lookalikes/core/features.cc b/chromium/components/lookalikes/core/features.cc
index 99d9c417d37..dc362a97a1b 100644
--- a/chromium/components/lookalikes/core/features.cc
+++ b/chromium/components/lookalikes/core/features.cc
@@ -11,7 +11,7 @@ const base::Feature kDetectTargetEmbeddingLookalikes{
"TargetEmbeddingLookalikes", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kLookalikeInterstitialForPunycode{
- "LookalikeInterstitialForPunycode", base::FEATURE_DISABLED_BY_DEFAULT};
+ "LookalikeInterstitialForPunycode", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace lookalikes
diff --git a/chromium/components/lookalikes/core/lookalike_url_util.cc b/chromium/components/lookalikes/core/lookalike_url_util.cc
index 6092d94ccfe..3e8fcddc395 100644
--- a/chromium/components/lookalikes/core/lookalike_url_util.cc
+++ b/chromium/components/lookalikes/core/lookalike_url_util.cc
@@ -35,7 +35,7 @@
namespace lookalikes {
-const char kHistogramName[] = "NavigationSuggestion.Event";
+const char kHistogramName[] = "NavigationSuggestion.Event2";
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterListPref(prefs::kLookalikeWarningAllowlistDomains);
@@ -759,13 +759,11 @@ bool IsEmojiRelatedCodepoint(UChar32 codepoint) {
// check this for non-ASCII scripts as well (e.g. Cyrillic + emoji), but such
// usage isn't common.
bool IsASCIIAndEmojiOnly(const base::StringPiece16& text) {
- base::i18n::UTF16CharIterator iter(text.data(), text.length());
- while (!iter.end()) {
+ for (base::i18n::UTF16CharIterator iter(text); !iter.end(); iter.Advance()) {
const UChar32 codepoint = iter.get();
if (!IsASCII(codepoint) && !IsEmojiRelatedCodepoint(codepoint)) {
return false;
}
- iter.Advance();
}
return true;
}
diff --git a/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc b/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
index 4b951b7d58e..c0f049a1528 100644
--- a/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
+++ b/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/lookalikes/core/features.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/management/resources/management.html b/chromium/components/management/resources/management.html
index 51cd925a0eb..11121271a60 100644
--- a/chromium/components/management/resources/management.html
+++ b/chromium/components/management/resources/management.html
@@ -9,6 +9,7 @@
<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
<script src="chrome://resources/js/ios/web_ui.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="strings.js"></script>
<script src="management.js"></script>
@@ -37,4 +38,4 @@
<div id="unmanaged-info" class="hidden">$i18n{unmanagedInfo}</div>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/chromium/components/media_message_center/media_controls_progress_view_unittest.cc b/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
index 78008be2c57..a611b7c6f4d 100644
--- a/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
+++ b/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
diff --git a/chromium/components/media_message_center/media_notification_background_ash_impl.cc b/chromium/components/media_message_center/media_notification_background_ash_impl.cc
index 091d78fe26c..88422c5a6be 100644
--- a/chromium/components/media_message_center/media_notification_background_ash_impl.cc
+++ b/chromium/components/media_message_center/media_notification_background_ash_impl.cc
@@ -22,11 +22,11 @@ constexpr int kArtworkRightMargin = 16;
constexpr int kArtworkCornerRadius = 4;
gfx::Size ScaleToFitSize(const gfx::Size& image_size) {
- if ((image_size.width() > kArtworkSize.width() ||
+ if ((image_size.width() > kArtworkSize.width() &&
image_size.height() > kArtworkSize.height()) ||
- (image_size.width() < kArtworkSize.width() &&
+ (image_size.width() < kArtworkSize.width() ||
image_size.height() < kArtworkSize.height())) {
- const float scale = std::min(
+ const float scale = std::max(
kArtworkSize.width() / static_cast<float>(image_size.width()),
kArtworkSize.height() / static_cast<float>(image_size.height()));
return gfx::ScaleToFlooredSize(image_size, scale);
@@ -41,26 +41,40 @@ gfx::Rect MediaNotificationBackgroundAshImpl::GetArtworkBounds(
const gfx::Rect& view_bounds) const {
gfx::Size target_size = ScaleToFitSize(artwork_.size());
- int vertical_offset = (kArtworkSize.height() - target_size.height()) / 2;
- int horizontal_offset = (kArtworkSize.width() - target_size.width()) / 2;
+ int vertical_offset = (target_size.height() - kArtworkSize.height()) / 2;
+ int horizontal_offset = (target_size.width() - kArtworkSize.width()) / 2;
- return gfx::Rect(view_bounds.right() - kArtworkRightMargin -
- kArtworkSize.width() + horizontal_offset,
+ int bounds_x = base::i18n::IsRTL()
+ ? view_bounds.x() + kArtworkRightMargin - horizontal_offset
+ : view_bounds.right() - kArtworkRightMargin -
+ kArtworkSize.width() - horizontal_offset;
+
+ return gfx::Rect(bounds_x,
view_bounds.bottom() - kArtworkBottomMargin -
- kArtworkSize.height() + vertical_offset,
+ kArtworkSize.height() - vertical_offset,
target_size.width(), target_size.height());
}
+SkPath MediaNotificationBackgroundAshImpl::GetArtworkClipPath(
+ const gfx::Rect& view_bounds) const {
+ int x = base::i18n::IsRTL() ? view_bounds.x() + kArtworkRightMargin
+ : view_bounds.right() - kArtworkRightMargin -
+ kArtworkSize.width();
+ int y = view_bounds.bottom() - kArtworkBottomMargin - kArtworkSize.height();
+
+ SkPath path;
+ path.addRoundRect(gfx::RectToSkRect(gfx::Rect(x, y, kArtworkSize.width(),
+ kArtworkSize.height())),
+ kArtworkCornerRadius, kArtworkCornerRadius);
+ return path;
+}
+
void MediaNotificationBackgroundAshImpl::Paint(gfx::Canvas* canvas,
views::View* view) const {
gfx::Rect source_bounds(0, 0, artwork_.width(), artwork_.height());
gfx::Rect target_bounds = GetArtworkBounds(view->GetContentsBounds());
- SkPath path;
- path.addRoundRect(gfx::RectToSkRect(target_bounds), kArtworkCornerRadius,
- kArtworkCornerRadius);
-
- canvas->ClipPath(path, true);
+ canvas->ClipPath(GetArtworkClipPath(view->GetContentsBounds()), true);
canvas->DrawImageInt(
artwork_, source_bounds.x(), source_bounds.y(), source_bounds.width(),
diff --git a/chromium/components/media_message_center/media_notification_background_ash_impl.h b/chromium/components/media_message_center/media_notification_background_ash_impl.h
index 6742e6f4eff..02c8d7a06fc 100644
--- a/chromium/components/media_message_center/media_notification_background_ash_impl.h
+++ b/chromium/components/media_message_center/media_notification_background_ash_impl.h
@@ -38,6 +38,8 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationBackgroundAshImpl
gfx::Rect GetArtworkBounds(const gfx::Rect& view_bounds) const;
+ SkPath GetArtworkClipPath(const gfx::Rect& view_bounds) const;
+
gfx::ImageSkia artwork_;
};
diff --git a/chromium/components/media_message_center/media_notification_background_ash_impl_unittest.cc b/chromium/components/media_message_center/media_notification_background_ash_impl_unittest.cc
index 87bc0bfe085..25e553e9a60 100644
--- a/chromium/components/media_message_center/media_notification_background_ash_impl_unittest.cc
+++ b/chromium/components/media_message_center/media_notification_background_ash_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "components/media_message_center/media_notification_background_ash_impl.h"
+#include "base/i18n/rtl.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media_message_center {
@@ -37,14 +38,18 @@ class MediaNotificationBackgroundAshImplTest : public testing::Test {
TEST_F(MediaNotificationBackgroundAshImplTest, ArtworkBoundsTest) {
gfx::Rect parent_bounds(0, 0, 100, 100);
- background()->UpdateArtwork(CreateTestImage(160, 60));
- EXPECT_EQ(GetArtworkBounds(parent_bounds).size(), gfx::Size(80, 30));
+ background()->UpdateArtwork(CreateTestImage(120, 60));
+ EXPECT_EQ(GetArtworkBounds(parent_bounds), gfx::Rect(-36, 4, 160, 80));
- background()->UpdateArtwork(CreateTestImage(60, 160));
- EXPECT_EQ(GetArtworkBounds(parent_bounds).size(), gfx::Size(30, 80));
+ background()->UpdateArtwork(CreateTestImage(40, 50));
+ EXPECT_EQ(GetArtworkBounds(parent_bounds), gfx::Rect(4, -6, 80, 100));
- background()->UpdateArtwork(CreateTestImage(40, 20));
- EXPECT_EQ(GetArtworkBounds(parent_bounds).size(), gfx::Size(80, 40));
+ background()->UpdateArtwork(CreateTestImage(80, 120));
+ EXPECT_EQ(GetArtworkBounds(parent_bounds), gfx::Rect(4, -16, 80, 120));
+
+ base::i18n::SetRTLForTesting(true);
+ background()->UpdateArtwork(CreateTestImage(80, 40));
+ EXPECT_EQ(GetArtworkBounds(parent_bounds), gfx::Rect(-24, 4, 160, 80));
}
} // namespace media_message_center
diff --git a/chromium/components/media_message_center/media_notification_item.h b/chromium/components/media_message_center/media_notification_item.h
index 3b402a4b61a..6a939cc39ab 100644
--- a/chromium/components/media_message_center/media_notification_item.h
+++ b/chromium/components/media_message_center/media_notification_item.h
@@ -16,6 +16,13 @@
namespace media_message_center {
+enum class SourceType {
+ kLocalMediaSession,
+ kCast,
+ kPresentationRequest,
+ kMaxValue = kPresentationRequest,
+};
+
class MediaNotificationView;
// MediaNotificationItem manages hiding/showing a MediaNotificationView.
@@ -58,8 +65,8 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationItem {
// Hides the media notification.
virtual void Dismiss() = 0;
- // Return true if this item belongs to a cast media session, false otherwise.
- virtual bool SourceIsCast() = 0;
+ // Returns the type of source.
+ virtual media_message_center::SourceType SourceType() = 0;
};
} // namespace media_message_center
diff --git a/chromium/components/media_message_center/media_notification_view_impl.cc b/chromium/components/media_message_center/media_notification_view_impl.cc
index a03909f33e5..f541170978c 100644
--- a/chromium/components/media_message_center/media_notification_view_impl.cc
+++ b/chromium/components/media_message_center/media_notification_view_impl.cc
@@ -24,6 +24,7 @@
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/views/notification_header_view.h"
#include "ui/views/controls/button/image_button_factory.h"
+#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/style/typography.h"
#include "ui/views/view_class_properties.h"
@@ -55,6 +56,22 @@ constexpr gfx::Size kMediaNotificationButtonRowSize =
gfx::Size(124, kMediaButtonSize.height());
constexpr gfx::Size kPipButtonSeparatorViewSize = gfx::Size(20, 24);
+// Dimensions for CrOS.
+constexpr int kCrOSTitleLineHeight = 20;
+constexpr int kCrOSArtistLineHeight = 16;
+constexpr int kCrOSMediaButtonRowSeparator = 8;
+constexpr int kCrOSHeaderRowSeparator = 16;
+constexpr gfx::Size kCrOSMediaButtonSize = gfx::Size(32, 32);
+constexpr gfx::Insets kCrOSMediaTitleArtistInsets = gfx::Insets(0, 8, 12, 0);
+constexpr gfx::Size kCrOSMediaNotificationButtonRowSize =
+ gfx::Size(124, kCrOSMediaButtonSize.height());
+constexpr gfx::Size kCrOSPipButtonSeparatorViewSize = gfx::Size(1, 20);
+constexpr gfx::Insets kCrOSHeaderRowInsets = gfx::Insets(16, 16, 0, 16);
+constexpr gfx::Insets kCrOSMainRowInsetsWithArtwork =
+ gfx::Insets(12, 8, 16, 111);
+constexpr gfx::Insets kCrOSMainRowInsetsWithoutArtwork =
+ gfx::Insets(12, 8, 16, 16);
+
void RecordMetadataHistogram(MediaNotificationViewImpl::Metadata metadata) {
UMA_HISTOGRAM_ENUMERATION(MediaNotificationViewImpl::kMetadataHistogramName,
metadata);
@@ -112,37 +129,22 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
const base::string16& default_app_name,
int notification_width,
bool should_show_icon,
- BackgroundStyle background_style)
+ base::Optional<NotificationTheme> theme)
: container_(container),
item_(std::move(item)),
default_app_name_(default_app_name),
- notification_width_(notification_width) {
+ notification_width_(notification_width),
+ theme_(theme),
+ is_cros_(theme.has_value()) {
DCHECK(container_);
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0));
- auto header_row =
- std::make_unique<message_center::NotificationHeaderView>(this);
-
- if (header_row_controls_view) {
- header_row_controls_view_ =
- header_row->AddChildView(std::move(header_row_controls_view));
- }
-
- header_row->SetAppName(default_app_name_);
-
- if (should_show_icon) {
- header_row->ClearAppIcon();
- header_row->SetProperty(views::kMarginsKey,
- kIconMediaNotificationHeaderInsets);
- } else {
- header_row->SetAppIconVisible(false);
- header_row->SetProperty(views::kMarginsKey,
- kIconlessMediaNotificationHeaderInsets);
- }
-
- header_row_ = AddChildView(std::move(header_row));
+ if (is_cros_)
+ CreateCrOSHeaderRow(std::move(header_row_controls_view));
+ else
+ CreateHeaderRow(std::move(header_row_controls_view), should_show_icon);
// |main_row_| holds the main content of the notification.
auto main_row = std::make_unique<views::View>();
@@ -152,8 +154,8 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
auto title_artist_row = std::make_unique<views::View>();
title_artist_row_layout_ =
title_artist_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
- views::BoxLayout::Orientation::kVertical, kMediaTitleArtistInsets,
- 0));
+ views::BoxLayout::Orientation::kVertical,
+ is_cros_ ? kCrOSMediaTitleArtistInsets : kMediaTitleArtistInsets, 0));
title_artist_row_layout_->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
title_artist_row_layout_->set_cross_axis_alignment(
@@ -166,14 +168,16 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
const gfx::FontList& base_font_list = views::Label::GetDefaultFontList();
title_label->SetFontList(base_font_list.Derive(
0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::MEDIUM));
- title_label->SetLineHeight(kTitleArtistLineHeight);
+ title_label->SetLineHeight(is_cros_ ? kCrOSTitleLineHeight
+ : kTitleArtistLineHeight);
title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
title_label_ = title_artist_row_->AddChildView(std::move(title_label));
auto artist_label = std::make_unique<views::Label>(
base::string16(), views::style::CONTEXT_LABEL,
views::style::STYLE_PRIMARY);
- artist_label->SetLineHeight(kTitleArtistLineHeight);
+ artist_label->SetLineHeight(is_cros_ ? kCrOSArtistLineHeight
+ : kTitleArtistLineHeight);
artist_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
artist_label_ = title_artist_row_->AddChildView(std::move(artist_label));
@@ -182,10 +186,11 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
auto* button_row_layout =
button_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
- kMediaButtonRowSeparator));
+ is_cros_ ? kCrOSMediaButtonRowSeparator : kMediaButtonRowSeparator));
button_row_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
- button_row->SetPreferredSize(kMediaNotificationButtonRowSize);
+ button_row->SetPreferredSize(is_cros_ ? kCrOSMediaNotificationButtonRowSize
+ : kMediaNotificationButtonRowSize);
button_row_ = main_row_->AddChildView(std::move(button_row));
auto playback_button_container = std::make_unique<views::View>();
@@ -193,7 +198,8 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
playback_button_container->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
- kMediaButtonRowSeparator));
+ is_cros_ ? kCrOSMediaButtonRowSeparator
+ : kMediaButtonRowSeparator));
playback_button_container_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
// Media playback controls should always be presented left-to-right,
@@ -212,15 +218,20 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_SEEK_BACKWARD));
// |play_pause_button_| toggles playback.
- auto play_pause_button = views::CreateVectorToggleImageButton(this);
+ auto play_pause_button =
+ views::CreateVectorToggleImageButton(views::Button::PressedCallback());
+ play_pause_button->SetCallback(
+ base::BindRepeating(&MediaNotificationViewImpl::ButtonPressed,
+ base::Unretained(this), play_pause_button.get()));
play_pause_button->set_tag(static_cast<int>(MediaSessionAction::kPlay));
- play_pause_button->SetPreferredSize(kMediaButtonSize);
+ play_pause_button->SetPreferredSize(is_cros_ ? kCrOSMediaButtonSize
+ : kMediaButtonSize);
play_pause_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
play_pause_button->SetTooltipText(l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PLAY));
play_pause_button->SetToggledTooltipText(l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PAUSE));
- play_pause_button->EnableCanvasFlippingForRTLUI(false);
+ play_pause_button->SetFlipCanvasOnPaintForRTLUI(false);
play_pause_button_ =
playback_button_container_->AddChildView(std::move(play_pause_button));
@@ -242,33 +253,44 @@ MediaNotificationViewImpl::MediaNotificationViewImpl(
views::BoxLayout::MainAxisAlignment::kCenter);
pip_button_separator_view_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
- pip_button_separator_view->SetPreferredSize(kPipButtonSeparatorViewSize);
+ pip_button_separator_view->SetPreferredSize(
+ is_cros_ ? kCrOSPipButtonSeparatorViewSize : kPipButtonSeparatorViewSize);
auto pip_button_separator_stroke = std::make_unique<views::View>();
pip_button_separator_stroke->SetPreferredSize(
- gfx::Size(1, kPipButtonSeparatorViewSize.height()));
+ gfx::Size(1, is_cros_ ? kCrOSPipButtonSeparatorViewSize.height()
+ : kPipButtonSeparatorViewSize.height()));
pip_button_separator_view->AddChildView(
std::move(pip_button_separator_stroke));
pip_button_separator_view_ =
button_row_->AddChildView(std::move(pip_button_separator_view));
- auto picture_in_picture_button = views::CreateVectorToggleImageButton(this);
+ auto picture_in_picture_button =
+ views::CreateVectorToggleImageButton(views::Button::PressedCallback());
+ picture_in_picture_button->SetCallback(base::BindRepeating(
+ &MediaNotificationViewImpl::ButtonPressed, base::Unretained(this),
+ picture_in_picture_button.get()));
picture_in_picture_button->set_tag(
static_cast<int>(MediaSessionAction::kEnterPictureInPicture));
- picture_in_picture_button->SetPreferredSize(kMediaButtonSize);
+ picture_in_picture_button->SetPreferredSize(is_cros_ ? kCrOSMediaButtonSize
+ : kMediaButtonSize);
picture_in_picture_button->SetFocusBehavior(
views::View::FocusBehavior::ALWAYS);
picture_in_picture_button->SetTooltipText(l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_ENTER_PIP));
picture_in_picture_button->SetToggledTooltipText(l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_EXIT_PIP));
- picture_in_picture_button->EnableCanvasFlippingForRTLUI(false);
+ picture_in_picture_button->SetFlipCanvasOnPaintForRTLUI(false);
picture_in_picture_button_ =
button_row_->AddChildView(std::move(picture_in_picture_button));
- if (background_style == BackgroundStyle::kAshStyle) {
+ // Use ash style background if we do have a theme.
+ if (is_cros_) {
SetBackground(std::make_unique<MediaNotificationBackgroundAshImpl>());
+
+ for (views::View* button : GetButtons())
+ views::InstallCircleHighlightPathGenerator(button);
} else {
SetBackground(std::make_unique<MediaNotificationBackgroundImpl>(
message_center::kNotificationCornerRadius,
@@ -321,7 +343,8 @@ void MediaNotificationViewImpl::SetForcedExpandedState(
forced_expanded_state_ = base::nullopt;
}
- header_row_->SetExpandButtonEnabled(IsExpandable());
+ if (header_row_)
+ header_row_->SetExpandButtonEnabled(IsExpandable());
UpdateViewForExpandedState();
}
@@ -337,25 +360,6 @@ void MediaNotificationViewImpl::GetAccessibleNodeData(
node_data->SetName(accessible_name_);
}
-void MediaNotificationViewImpl::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (sender == header_row_) {
- SetExpanded(!expanded_);
- container_->OnHeaderClicked();
- return;
- }
-
- if (sender->parent() == button_row_ ||
- sender->parent() == playback_button_container_) {
- if (item_) {
- item_->OnMediaSessionActionButtonPressed(GetActionFromButtonTag(*sender));
- }
- return;
- }
-
- NOTREACHED();
-}
-
void MediaNotificationViewImpl::UpdateWithMediaSessionInfo(
const media_session::mojom::MediaSessionInfoPtr& session_info) {
bool playing =
@@ -388,12 +392,18 @@ void MediaNotificationViewImpl::UpdateWithMediaSessionInfo(
void MediaNotificationViewImpl::UpdateWithMediaMetadata(
const media_session::MediaMetadata& metadata) {
- header_row_->SetAppName(metadata.source_title.empty()
- ? default_app_name_
- : metadata.source_title);
+ auto& app_name =
+ metadata.source_title.empty() ? default_app_name_ : metadata.source_title;
+
+ if (header_row_) {
+ header_row_->SetAppName(app_name);
+ header_row_->SetSummaryText(metadata.album);
+ } else {
+ cros_header_label_->SetText(app_name);
+ }
+
title_label_->SetText(metadata.title);
artist_label_->SetText(metadata.artist);
- header_row_->SetSummaryText(metadata.album);
accessible_name_ = GetAccessibleNameFromMetadata(metadata);
@@ -431,7 +441,8 @@ void MediaNotificationViewImpl::UpdateWithMediaActions(
const base::flat_set<media_session::mojom::MediaSessionAction>& actions) {
enabled_actions_ = actions;
- header_row_->SetExpandButtonEnabled(IsExpandable());
+ if (header_row_)
+ header_row_->SetExpandButtonEnabled(IsExpandable());
UpdateViewForExpandedState();
PreferredSizeChanged();
@@ -466,6 +477,9 @@ void MediaNotificationViewImpl::UpdateWithFavicon(const gfx::ImageSkia& icon) {
void MediaNotificationViewImpl::UpdateWithVectorIcon(
const gfx::VectorIcon& vector_icon) {
+ if (!header_row_)
+ return;
+
vector_header_icon_ = &vector_icon;
const SkColor foreground =
GetMediaNotificationBackground()->GetForegroundColor(*this);
@@ -492,7 +506,8 @@ views::Button* MediaNotificationViewImpl::GetHeaderRowForTesting() const {
}
base::string16 MediaNotificationViewImpl::GetSourceTitleForTesting() const {
- return header_row_->app_name_for_testing();
+ return header_row_ ? header_row_->app_name_for_testing() // IN-TEST
+ : cros_header_label_->GetText();
}
void MediaNotificationViewImpl::UpdateActionButtonsVisibility() {
@@ -537,7 +552,18 @@ void MediaNotificationViewImpl::UpdateViewForExpandedState() {
// Adjust the layout of the |main_row_| based on the expanded state. If the
// notification is expanded then the buttons should be below the title/artist
// information. If it is collapsed then the buttons will be to the right.
- if (expanded) {
+ if (is_cros_) {
+ static_cast<views::BoxLayout*>(button_row_->GetLayoutManager())
+ ->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
+
+ main_row_
+ ->SetLayoutManager(std::make_unique<views::BoxLayout>(
+ views::BoxLayout::Orientation::kVertical,
+ has_artwork_ ? kCrOSMainRowInsetsWithArtwork
+ : kCrOSMainRowInsetsWithoutArtwork,
+ 0))
+ ->SetDefaultFlex(1);
+ } else if (expanded) {
static_cast<views::BoxLayout*>(button_row_->GetLayoutManager())
->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
@@ -573,7 +599,8 @@ void MediaNotificationViewImpl::UpdateViewForExpandedState() {
SchedulePaint();
}
- header_row_->SetExpanded(expanded);
+ if (header_row_)
+ header_row_->SetExpanded(expanded);
container_->OnExpanded(expanded);
UpdateActionButtonsVisibility();
@@ -582,16 +609,80 @@ void MediaNotificationViewImpl::UpdateViewForExpandedState() {
void MediaNotificationViewImpl::CreateMediaButton(
MediaSessionAction action,
const base::string16& accessible_name) {
- auto button = views::CreateVectorImageButton(this);
+ auto button =
+ views::CreateVectorImageButton(views::Button::PressedCallback());
+ button->SetCallback(
+ base::BindRepeating(&MediaNotificationViewImpl::ButtonPressed,
+ base::Unretained(this), button.get()));
button->set_tag(static_cast<int>(action));
- button->SetPreferredSize(kMediaButtonSize);
+ button->SetPreferredSize(is_cros_ ? kCrOSMediaButtonSize : kMediaButtonSize);
button->SetAccessibleName(accessible_name);
button->SetTooltipText(accessible_name);
button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
- button->EnableCanvasFlippingForRTLUI(false);
+ button->SetFlipCanvasOnPaintForRTLUI(false);
playback_button_container_->AddChildView(std::move(button));
}
+void MediaNotificationViewImpl::CreateHeaderRow(
+ std::unique_ptr<views::View> header_row_controls_view,
+ bool should_show_icon) {
+ auto header_row = std::make_unique<message_center::NotificationHeaderView>(
+ base::BindRepeating(
+ [](MediaNotificationViewImpl* view) {
+ view->SetExpanded(!view->expanded_);
+ view->container_->OnHeaderClicked();
+ },
+ base::Unretained(this)));
+
+ if (header_row_controls_view) {
+ header_row_controls_view_ =
+ header_row->AddChildView(std::move(header_row_controls_view));
+ }
+
+ header_row->SetAppName(default_app_name_);
+
+ if (should_show_icon) {
+ header_row->ClearAppIcon();
+ header_row->SetProperty(views::kMarginsKey,
+ kIconMediaNotificationHeaderInsets);
+ } else {
+ header_row->SetAppIconVisible(false);
+ header_row->SetProperty(views::kMarginsKey,
+ kIconlessMediaNotificationHeaderInsets);
+ }
+
+ header_row_ = AddChildView(std::move(header_row));
+}
+
+void MediaNotificationViewImpl::CreateCrOSHeaderRow(
+ std::unique_ptr<views::View> header_row_controls_view) {
+ auto cros_header_row = std::make_unique<views::View>();
+ auto* header_row_layout =
+ cros_header_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
+ views::BoxLayout::Orientation::kHorizontal, kCrOSHeaderRowInsets,
+ kCrOSHeaderRowSeparator));
+
+ auto header_label = std::make_unique<views::Label>(
+ default_app_name_, views::style::CONTEXT_LABEL,
+ views::style::STYLE_PRIMARY);
+ const gfx::FontList& base_font_list = views::Label::GetDefaultFontList();
+ header_label->SetFontList(base_font_list.Derive(
+ 0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::MEDIUM));
+ header_label->SetLineHeight(kCrOSTitleLineHeight);
+ header_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ header_label->SetAutoColorReadabilityEnabled(false);
+
+ cros_header_label_ = cros_header_row->AddChildView(std::move(header_label));
+ header_row_layout->SetFlexForView(cros_header_label_, 1);
+
+ if (header_row_controls_view) {
+ header_row_controls_view_ =
+ cros_header_row->AddChildView(std::move(header_row_controls_view));
+ }
+
+ AddChildView(std::move(cros_header_row));
+}
+
MediaNotificationBackground*
MediaNotificationViewImpl::GetMediaNotificationBackground() {
return static_cast<MediaNotificationBackground*>(background());
@@ -624,43 +715,61 @@ void MediaNotificationViewImpl::UpdateForegroundColor() {
GetMediaNotificationBackground()->GetBackgroundColor(*this);
const SkColor foreground =
GetMediaNotificationBackground()->GetForegroundColor(*this);
- const SkColor separator_color = SkColorSetA(foreground, 0x1F);
- const SkColor disabled_icon_color =
- SkColorSetA(foreground, gfx::kDisabledControlAlpha);
-
- title_label_->SetEnabledColor(foreground);
- artist_label_->SetEnabledColor(foreground);
- header_row_->SetAccentColor(foreground);
- if (vector_header_icon_) {
+
+ NotificationTheme theme;
+ if (theme_.has_value()) {
+ theme = *theme_;
+ } else {
+ theme.primary_text_color = foreground;
+ theme.secondary_text_color = foreground;
+ theme.enabled_icon_color = foreground;
+ theme.disabled_icon_color =
+ SkColorSetA(foreground, gfx::kDisabledControlAlpha);
+ theme.separator_color = SkColorSetA(foreground, 0x1F);
+ }
+
+ title_label_->SetEnabledColor(theme.primary_text_color);
+ artist_label_->SetEnabledColor(theme.secondary_text_color);
+
+ if (header_row_) {
+ header_row_->SetAccentColor(theme.primary_text_color);
+ header_row_->SetBackgroundColor(background);
+ } else {
+ cros_header_label_->SetEnabledColor(theme.primary_text_color);
+ }
+
+ if (vector_header_icon_ && header_row_) {
header_row_->SetAppIcon(gfx::CreateVectorIcon(
- *vector_header_icon_, message_center::kSmallImageSizeMD, foreground));
+ *vector_header_icon_, message_center::kSmallImageSizeMD,
+ theme.enabled_icon_color));
}
title_label_->SetBackgroundColor(background);
artist_label_->SetBackgroundColor(background);
- header_row_->SetBackgroundColor(background);
pip_button_separator_view_->children().front()->SetBackground(
- views::CreateSolidBackground(separator_color));
+ views::CreateSolidBackground(theme.separator_color));
// Update play/pause button images.
views::SetImageFromVectorIconWithColor(
play_pause_button_,
*GetVectorIconForMediaAction(MediaSessionAction::kPlay),
- kMediaButtonIconSize, foreground);
+ kMediaButtonIconSize, theme.enabled_icon_color);
views::SetToggledImageFromVectorIconWithColor(
play_pause_button_,
*GetVectorIconForMediaAction(MediaSessionAction::kPause),
- kMediaButtonIconSize, foreground, disabled_icon_color);
+ kMediaButtonIconSize, theme.enabled_icon_color,
+ theme.disabled_icon_color);
views::SetImageFromVectorIconWithColor(
picture_in_picture_button_,
*GetVectorIconForMediaAction(MediaSessionAction::kEnterPictureInPicture),
- kMediaButtonIconSize, foreground);
+ kMediaButtonIconSize, theme.enabled_icon_color);
views::SetToggledImageFromVectorIconWithColor(
picture_in_picture_button_,
*GetVectorIconForMediaAction(MediaSessionAction::kExitPictureInPicture),
- kMediaButtonIconSize, foreground, disabled_icon_color);
+ kMediaButtonIconSize, theme.enabled_icon_color,
+ theme.disabled_icon_color);
// Update action buttons.
for (views::View* child : playback_button_container_->children()) {
@@ -672,12 +781,17 @@ void MediaNotificationViewImpl::UpdateForegroundColor() {
views::SetImageFromVectorIconWithColor(
button, *GetVectorIconForMediaAction(GetActionFromButtonTag(*button)),
- kMediaButtonIconSize, foreground);
+ kMediaButtonIconSize, theme.enabled_icon_color);
button->SchedulePaint();
}
- container_->OnColorsChanged(foreground, background);
+ container_->OnColorsChanged(theme.enabled_icon_color, background);
+}
+
+void MediaNotificationViewImpl::ButtonPressed(views::Button* button) {
+ if (item_)
+ item_->OnMediaSessionActionButtonPressed(GetActionFromButtonTag(*button));
}
std::vector<views::View*> MediaNotificationViewImpl::GetButtons() {
@@ -696,4 +810,5 @@ std::vector<views::View*> MediaNotificationViewImpl::GetButtons() {
buttons.end());
return buttons;
}
+
} // namespace media_message_center
diff --git a/chromium/components/media_message_center/media_notification_view_impl.h b/chromium/components/media_message_center/media_notification_view_impl.h
index 4c8eaeda792..a6ee20c5c6a 100644
--- a/chromium/components/media_message_center/media_notification_view_impl.h
+++ b/chromium/components/media_message_center/media_notification_view_impl.h
@@ -10,7 +10,6 @@
#include "base/optional.h"
#include "components/media_message_center/media_notification_view.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
-#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/label.h"
@@ -20,6 +19,7 @@ class NotificationHeaderView;
namespace views {
class BoxLayout;
+class Button;
class ToggleImageButton;
} // namespace views
@@ -29,9 +29,16 @@ class MediaNotificationBackground;
class MediaNotificationContainer;
class MediaNotificationItem;
+struct COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) NotificationTheme {
+ SkColor primary_text_color = 0;
+ SkColor secondary_text_color = 0;
+ SkColor enabled_icon_color = 0;
+ SkColor disabled_icon_color = 0;
+ SkColor separator_color = 0;
+};
+
class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
- : public MediaNotificationView,
- public views::ButtonListener {
+ : public MediaNotificationView {
public:
// The name of the histogram used when recorded whether the artwork was
// present.
@@ -52,12 +59,6 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
kMaxValue = kSource,
};
- // Allow MediaNotificationViewImpl show different styled background.
- enum class BackgroundStyle {
- kDefault,
- kAshStyle,
- };
-
MediaNotificationViewImpl(
MediaNotificationContainer* container,
base::WeakPtr<MediaNotificationItem> item,
@@ -65,15 +66,12 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
const base::string16& default_app_name,
int notification_width,
bool should_show_icon,
- BackgroundStyle background_style = BackgroundStyle::kDefault);
+ base::Optional<NotificationTheme> theme = base::nullopt);
~MediaNotificationViewImpl() override;
// views::View:
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
- // views::ButtonListener:
- void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
// MediaNotificationView:
void SetExpanded(bool expanded) override;
void UpdateCornerRadius(int top_radius, int bottom_radius) override;
@@ -119,6 +117,11 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
void CreateMediaButton(media_session::mojom::MediaSessionAction action,
const base::string16& accessible_name);
+ void CreateHeaderRow(std::unique_ptr<views::View> header_row_controls_view,
+ bool should_show_icon);
+ void CreateCrOSHeaderRow(
+ std::unique_ptr<views::View> header_row_controls_view);
+
void UpdateActionButtonsVisibility();
void UpdateViewForExpandedState();
@@ -129,6 +132,8 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
void UpdateForegroundColor();
+ void ButtonPressed(views::Button* button);
+
// Returns the buttons contained in the button row and playback button
// container.
std::vector<views::View*> GetButtons();
@@ -167,6 +172,7 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
// Container views directly attached to this view.
message_center::NotificationHeaderView* header_row_ = nullptr;
+ views::Label* cros_header_label_ = nullptr;
views::View* button_row_ = nullptr;
views::View* playback_button_container_ = nullptr;
views::View* pip_button_separator_view_ = nullptr;
@@ -181,6 +187,10 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewImpl
views::BoxLayout* title_artist_row_layout_ = nullptr;
const gfx::VectorIcon* vector_header_icon_ = nullptr;
+ base::Optional<NotificationTheme> theme_;
+
+ const bool is_cros_;
+
DISALLOW_COPY_AND_ASSIGN(MediaNotificationViewImpl);
};
diff --git a/chromium/components/media_message_center/media_notification_view_impl_unittest.cc b/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
index 1b9b81789bc..a1e99409bf6 100644
--- a/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
+++ b/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
@@ -34,6 +34,7 @@
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/message_center/views/notification_header_view.h"
#include "ui/views/controls/image_view.h"
+#include "ui/views/test/button_test_api.h"
#include "ui/views/test/views_test_base.h"
namespace media_message_center {
@@ -267,16 +268,15 @@ class MediaNotificationViewImplTest : public views::ViewsTestBase {
views::Button* button = GetButtonForAction(action);
EXPECT_TRUE(button->GetVisible());
- view()->ButtonPressed(
- button, ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EventTimeForNow(), 0, 0));
+ views::test::ButtonTestApi(button).NotifyClick(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), 0, 0));
}
void SimulateHeaderClick() {
- view()->ButtonPressed(
- header_row(),
- ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EventTimeForNow(), 0, 0));
+ views::test::ButtonTestApi(header_row())
+ .NotifyClick(ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(),
+ gfx::Point(), ui::EventTimeForNow(), 0, 0));
}
void SimulateTab() {
diff --git a/chromium/components/media_message_center/media_notification_view_modern_impl.cc b/chromium/components/media_message_center/media_notification_view_modern_impl.cc
index 16fa2155197..798b3e65ca7 100644
--- a/chromium/components/media_message_center/media_notification_view_modern_impl.cc
+++ b/chromium/components/media_message_center/media_notification_view_modern_impl.cc
@@ -249,8 +249,11 @@ MediaNotificationViewModernImpl::MediaNotificationViewModernImpl(
{
// The picture-in-picture button appears directly under the media
// labels.
- auto picture_in_picture_button =
- views::CreateVectorToggleImageButton(this);
+ auto picture_in_picture_button = views::CreateVectorToggleImageButton(
+ views::Button::PressedCallback());
+ picture_in_picture_button->SetCallback(base::BindRepeating(
+ &MediaNotificationViewModernImpl::ButtonPressed,
+ base::Unretained(this), picture_in_picture_button.get()));
picture_in_picture_button->set_tag(
static_cast<int>(MediaSessionAction::kEnterPictureInPicture));
picture_in_picture_button->SetPreferredSize(kPipButtonSize);
@@ -261,7 +264,7 @@ MediaNotificationViewModernImpl::MediaNotificationViewModernImpl(
picture_in_picture_button->SetToggledTooltipText(
l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_EXIT_PIP));
- picture_in_picture_button->EnableCanvasFlippingForRTLUI(false);
+ picture_in_picture_button->SetFlipCanvasOnPaintForRTLUI(false);
views::SetImageFromVectorIconWithColor(
picture_in_picture_button.get(),
*GetVectorIconForMediaAction(
@@ -321,7 +324,11 @@ MediaNotificationViewModernImpl::MediaNotificationViewModernImpl(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_SEEK_BACKWARD));
{
- auto play_pause_button = views::CreateVectorToggleImageButton(this);
+ auto play_pause_button = views::CreateVectorToggleImageButton(
+ views::Button::PressedCallback());
+ play_pause_button->SetCallback(
+ base::BindRepeating(&MediaNotificationViewModernImpl::ButtonPressed,
+ base::Unretained(this), play_pause_button.get()));
play_pause_button->set_tag(static_cast<int>(MediaSessionAction::kPlay));
play_pause_button->SetPreferredSize(kMediaButtonSize);
play_pause_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
@@ -329,7 +336,7 @@ MediaNotificationViewModernImpl::MediaNotificationViewModernImpl(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PLAY));
play_pause_button->SetToggledTooltipText(l10n_util::GetStringUTF16(
IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_PAUSE));
- play_pause_button->EnableCanvasFlippingForRTLUI(false);
+ play_pause_button->SetFlipCanvasOnPaintForRTLUI(false);
play_pause_button_ =
media_controls_container->AddChildView(std::move(play_pause_button));
}
@@ -376,13 +383,6 @@ void MediaNotificationViewModernImpl::GetAccessibleNodeData(
node_data->SetName(accessible_name_);
}
-void MediaNotificationViewModernImpl::ButtonPressed(views::Button* sender,
- const ui::Event& event) {
- if (item_) {
- item_->OnMediaSessionActionButtonPressed(GetActionFromButtonTag(*sender));
- }
-}
-
void MediaNotificationViewModernImpl::UpdateWithMediaSessionInfo(
const media_session::mojom::MediaSessionInfoPtr& session_info) {
bool playing =
@@ -523,13 +523,17 @@ void MediaNotificationViewModernImpl::CreateMediaButton(
views::View* parent_view,
MediaSessionAction action,
const base::string16& accessible_name) {
- auto button = views::CreateVectorImageButton(this);
+ auto button =
+ views::CreateVectorImageButton(views::Button::PressedCallback());
+ button->SetCallback(
+ base::BindRepeating(&MediaNotificationViewModernImpl::ButtonPressed,
+ base::Unretained(this), button.get()));
button->set_tag(static_cast<int>(action));
button->SetPreferredSize(kMediaButtonSize);
button->SetAccessibleName(accessible_name);
button->SetTooltipText(accessible_name);
button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
- button->EnableCanvasFlippingForRTLUI(false);
+ button->SetFlipCanvasOnPaintForRTLUI(false);
parent_view->AddChildView(std::move(button));
}
@@ -592,4 +596,9 @@ void MediaNotificationViewModernImpl::UpdateForegroundColor() {
container_->OnColorsChanged(foreground, background);
}
+void MediaNotificationViewModernImpl::ButtonPressed(views::Button* button) {
+ if (item_)
+ item_->OnMediaSessionActionButtonPressed(GetActionFromButtonTag(*button));
+}
+
} // namespace media_message_center
diff --git a/chromium/components/media_message_center/media_notification_view_modern_impl.h b/chromium/components/media_message_center/media_notification_view_modern_impl.h
index 96b0291da44..96c82130126 100644
--- a/chromium/components/media_message_center/media_notification_view_modern_impl.h
+++ b/chromium/components/media_message_center/media_notification_view_modern_impl.h
@@ -12,12 +12,12 @@
#include "base/optional.h"
#include "components/media_message_center/media_notification_view.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
-#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
namespace views {
+class Button;
class ToggleImageButton;
} // namespace views
@@ -32,8 +32,7 @@ class MediaNotificationContainer;
class MediaNotificationItem;
class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewModernImpl
- : public MediaNotificationView,
- public views::ButtonListener {
+ : public MediaNotificationView {
public:
// The name of the histogram used when recording whether the artwork was
// present.
@@ -69,9 +68,6 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewModernImpl
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void OnThemeChanged() override;
- // views::ButtonListener:
- void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
// MediaNotificationView
void SetForcedExpandedState(bool* forced_expanded_state) override {}
void SetExpanded(bool expanded) override {}
@@ -120,6 +116,8 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationViewModernImpl
void UpdateForegroundColor();
+ void ButtonPressed(views::Button* button);
+
// Container that receives events.
MediaNotificationContainer* const container_;
diff --git a/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc b/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
index 6fa81fba794..cd2404fca6d 100644
--- a/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
+++ b/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
@@ -35,6 +35,7 @@
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/message_center/views/notification_header_view.h"
#include "ui/views/controls/image_view.h"
+#include "ui/views/test/button_test_api.h"
#include "ui/views/test/views_test_base.h"
namespace media_message_center {
@@ -254,9 +255,9 @@ class MediaNotificationViewModernImplTest : public views::ViewsTestBase {
views::Button* button = GetButtonForAction(action);
EXPECT_TRUE(button->GetVisible());
- view()->ButtonPressed(
- button, ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- ui::EventTimeForNow(), 0, 0));
+ views::test::ButtonTestApi(button).NotifyClick(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), 0, 0));
}
void SimulateTab() {
diff --git a/chromium/components/media_message_center/media_session_notification_item.cc b/chromium/components/media_message_center/media_session_notification_item.cc
index 805590d1a7e..f62ab0ebc15 100644
--- a/chromium/components/media_message_center/media_session_notification_item.cc
+++ b/chromium/components/media_message_center/media_session_notification_item.cc
@@ -165,8 +165,8 @@ void MediaSessionNotificationItem::Dismiss() {
controller_->RemoveItem(request_id_);
}
-bool MediaSessionNotificationItem::SourceIsCast() {
- return false;
+media_message_center::SourceType MediaSessionNotificationItem::SourceType() {
+ return media_message_center::SourceType::kLocalMediaSession;
}
void MediaSessionNotificationItem::SetController(
diff --git a/chromium/components/media_message_center/media_session_notification_item.h b/chromium/components/media_message_center/media_session_notification_item.h
index 1403db035dc..3149469539f 100644
--- a/chromium/components/media_message_center/media_session_notification_item.h
+++ b/chromium/components/media_message_center/media_session_notification_item.h
@@ -68,7 +68,7 @@ class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaSessionNotificationItem
// This will stop the media session associated with this item. The item will
// then call |MediaNotificationController::RemoveItem()| to ensure removal.
void Dismiss() override;
- bool SourceIsCast() override;
+ media_message_center::SourceType SourceType() override;
base::WeakPtr<MediaSessionNotificationItem> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
diff --git a/chromium/components/media_message_center/vector_icons/BUILD.gn b/chromium/components/media_message_center/vector_icons/BUILD.gn
index 9b6608faabb..c782bae87b7 100644
--- a/chromium/components/media_message_center/vector_icons/BUILD.gn
+++ b/chromium/components/media_message_center/vector_icons/BUILD.gn
@@ -4,7 +4,7 @@
import("//components/vector_icons/vector_icons.gni")
-aggregate_vector_icons2("media_vector_icons") {
+aggregate_vector_icons("media_vector_icons") {
icon_directory = "."
sources = [
diff --git a/chromium/components/media_router/OWNERS b/chromium/components/media_router/OWNERS
index 7290593df4a..33073086e1f 100644
--- a/chromium/components/media_router/OWNERS
+++ b/chromium/components/media_router/OWNERS
@@ -2,4 +2,5 @@ mfoltz@chromium.org
btolsch@chromium.org
takumif@chromium.org
+# TEAM: media-dev@chromium.org
# COMPONENT: Internals>Cast
diff --git a/chromium/components/media_router/browser/android/BUILD.gn b/chromium/components/media_router/browser/android/BUILD.gn
index de523d781c4..fda7b57bfd7 100644
--- a/chromium/components/media_router/browser/android/BUILD.gn
+++ b/chromium/components/media_router/browser/android/BUILD.gn
@@ -5,6 +5,7 @@
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
android_library("java") {
resources_package = "org.chromium.components.media_router"
@@ -57,7 +58,6 @@ android_library("java") {
"java/src/org/chromium/components/media_router/caf/CafMessageHandler.java",
"java/src/org/chromium/components/media_router/caf/CafNotificationController.java",
"java/src/org/chromium/components/media_router/caf/CastMediaSource.java",
- "java/src/org/chromium/components/media_router/caf/CastOptionsProvider.java",
"java/src/org/chromium/components/media_router/caf/CastSessionController.java",
"java/src/org/chromium/components/media_router/caf/CastUtils.java",
"java/src/org/chromium/components/media_router/caf/CreateRouteRequestInfo.java",
@@ -72,6 +72,14 @@ android_library("java") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
+android_library("cast_options_provider_java") {
+ sources = [ "java/src/org/chromium/components/media_router/caf/CastOptionsProvider.java" ]
+ deps = [
+ "$google_play_services_package:google_play_services_cast_framework_java",
+ "$google_play_services_package:google_play_services_cast_java",
+ ]
+}
+
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/components/media_router/BrowserMediaRouter.java",
@@ -86,16 +94,20 @@ android_library("test_support_java") {
sources = [
"java/src/org/chromium/components/media_router/TestMediaRouterClient.java",
"javatests/src/org/chromium/components/media_router/MockMediaRouteProvider.java",
+ "javatests/src/org/chromium/components/media_router/RouterTestUtils.java",
]
deps = [
":java",
":test_jni_headers",
"//base:base_java",
+ "//base:base_java_test_support",
"//components/browser_ui/media/android:java",
"//content/public/android:content_java",
+ "//content/public/test/android:content_java_test_support",
"//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:androidx_fragment_fragment_java",
+ "//third_party/hamcrest:hamcrest_java",
]
}
@@ -168,7 +180,6 @@ android_resources("java_resources") {
"java/res/drawable/ic_cast_dark_chrome.xml",
"java/res/layout/caf_controller_media_route_button.xml",
"java/res/layout/expanded_cast_controller.xml",
- "java/res/values/ids.xml",
"java/res/values/styles.xml",
]
deps = [
diff --git a/chromium/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java b/chromium/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
new file mode 100644
index 00000000000..f480fd62db3
--- /dev/null
+++ b/chromium/components/media_router/browser/android/javatests/src/org/chromium/components/media_router/RouterTestUtils.java
@@ -0,0 +1,97 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.media_router;
+
+import android.app.Dialog;
+import android.view.View;
+
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentManager;
+
+import org.hamcrest.Matchers;
+
+import org.chromium.base.Log;
+import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.CriteriaNotSatisfiedException;
+import org.chromium.third_party.android.media.R;
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+
+/**
+ * Test utils for MediaRouter.
+ */
+public class RouterTestUtils {
+ private static final String TAG = "RouterTestUtils";
+
+ private static final int VIEW_TIMEOUT_MS = 2000;
+ private static final int VIEW_RETRY_MS = 100;
+
+ public static View waitForRouteButton(
+ final FragmentManager fragmentManager, final String chromecastName) {
+ return waitForView(new Callable<View>() {
+ @Override
+ public View call() {
+ Dialog mediaRouteListDialog = getDialog(fragmentManager);
+ if (mediaRouteListDialog == null) {
+ Log.w(TAG, "Cannot find device selection dialog");
+ return null;
+ }
+ View mediaRouteList = mediaRouteListDialog.findViewById(R.id.mr_chooser_list);
+ if (mediaRouteList == null) {
+ Log.w(TAG, "Cannot find device list");
+ return null;
+ }
+ ArrayList<View> routesWanted = new ArrayList<View>();
+ mediaRouteList.findViewsWithText(
+ routesWanted, chromecastName, View.FIND_VIEWS_WITH_TEXT);
+ if (routesWanted.size() == 0) {
+ Log.w(TAG, "Cannot find wanted device");
+ return null;
+ }
+ Log.i(TAG, "Found wanted device");
+ return routesWanted.get(0);
+ }
+ });
+ }
+
+ public static Dialog waitForDialog(final FragmentManager fragmentManager) {
+ try {
+ CriteriaHelper.pollUiThread(() -> {
+ try {
+ Criteria.checkThat(getDialog(fragmentManager), Matchers.notNullValue());
+ } catch (Exception e) {
+ throw new CriteriaNotSatisfiedException(e);
+ }
+ }, VIEW_TIMEOUT_MS, VIEW_RETRY_MS);
+ return getDialog(fragmentManager);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static Dialog getDialog(FragmentManager fragmentManager) {
+ DialogFragment fragment = (DialogFragment) fragmentManager.findFragmentByTag(
+ "android.support.v7.mediarouter:MediaRouteChooserDialogFragment");
+ if (fragment == null) return null;
+ return fragment.getDialog();
+ }
+
+ private static View waitForView(final Callable<View> getViewCallable) {
+ try {
+ CriteriaHelper.pollUiThread(() -> {
+ try {
+ Criteria.checkThat(getViewCallable.call(), Matchers.notNullValue());
+ } catch (Exception e) {
+ throw new CriteriaNotSatisfiedException(e);
+ }
+ }, VIEW_TIMEOUT_MS, VIEW_RETRY_MS);
+ return getViewCallable.call();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/chromium/components/media_router/browser/android/media_router_android.cc b/chromium/components/media_router/browser/android/media_router_android.cc
index 3187844e3bd..f130a35c268 100644
--- a/chromium/components/media_router/browser/android/media_router_android.cc
+++ b/chromium/components/media_router/browser/android/media_router_android.cc
@@ -9,7 +9,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/logging.h"
#include "base/stl_util.h"
diff --git a/chromium/components/media_router/browser/android/media_router_android_unittest.cc b/chromium/components/media_router/browser/android/media_router_android_unittest.cc
index 62a09ead63f..bd62843350c 100644
--- a/chromium/components/media_router/browser/android/media_router_android_unittest.cc
+++ b/chromium/components/media_router/browser/android/media_router_android_unittest.cc
@@ -5,7 +5,7 @@
#include <memory>
#include "base/android/jni_android.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/mock_callback.h"
#include "components/media_router/browser/android/media_router_android.h"
#include "components/media_router/browser/android/media_router_android_bridge.h"
diff --git a/chromium/components/media_router/browser/presentation/local_presentation_manager.cc b/chromium/components/media_router/browser/presentation/local_presentation_manager.cc
index 7630ae8df6c..6119191ec4c 100644
--- a/chromium/components/media_router/browser/presentation/local_presentation_manager.cc
+++ b/chromium/components/media_router/browser/presentation/local_presentation_manager.cc
@@ -66,10 +66,11 @@ void LocalPresentationManager::UnregisterLocalPresentationController(
void LocalPresentationManager::OnLocalPresentationReceiverCreated(
const PresentationInfo& presentation_info,
- const content::ReceiverConnectionAvailableCallback& receiver_callback) {
+ const content::ReceiverConnectionAvailableCallback& receiver_callback,
+ content::WebContents* receiver_web_contents) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto* presentation = GetOrCreateLocalPresentation(presentation_info);
- presentation->RegisterReceiver(receiver_callback);
+ presentation->RegisterReceiver(receiver_callback, receiver_web_contents);
}
void LocalPresentationManager::OnLocalPresentationReceiverTerminated(
@@ -83,6 +84,15 @@ bool LocalPresentationManager::IsLocalPresentation(
return base::Contains(local_presentations_, presentation_id);
}
+bool LocalPresentationManager::IsLocalPresentation(
+ content::WebContents* web_contents) {
+ for (auto& local_presentation : local_presentations_) {
+ if (local_presentation.second->receiver_web_contents_ == web_contents)
+ return true;
+ }
+ return false;
+}
+
const MediaRoute* LocalPresentationManager::GetRoute(
const std::string& presentation_id) {
auto it = local_presentations_.find(presentation_id);
@@ -124,8 +134,10 @@ void LocalPresentationManager::LocalPresentation::UnregisterController(
}
void LocalPresentationManager::LocalPresentation::RegisterReceiver(
- const content::ReceiverConnectionAvailableCallback& receiver_callback) {
+ const content::ReceiverConnectionAvailableCallback& receiver_callback,
+ content::WebContents* receiver_web_contents) {
DCHECK(receiver_callback_.is_null());
+ DCHECK(receiver_web_contents);
for (auto& controller : pending_controllers_) {
receiver_callback.Run(
PresentationInfo::New(presentation_info_),
@@ -133,6 +145,7 @@ void LocalPresentationManager::LocalPresentation::RegisterReceiver(
std::move(controller.second->receiver_connection_receiver));
}
receiver_callback_ = receiver_callback;
+ receiver_web_contents_ = receiver_web_contents;
pending_controllers_.clear();
}
diff --git a/chromium/components/media_router/browser/presentation/local_presentation_manager.h b/chromium/components/media_router/browser/presentation/local_presentation_manager.h
index 14d59ddb73f..aad2cfcd84c 100644
--- a/chromium/components/media_router/browser/presentation/local_presentation_manager.h
+++ b/chromium/components/media_router/browser/presentation/local_presentation_manager.h
@@ -21,6 +21,10 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
+namespace content {
+class WebContents;
+}
+
namespace media_router {
// Manages all local presentations started in the associated Profile and
// facilitates communication between the controllers and the receiver of a
@@ -132,10 +136,12 @@ class LocalPresentationManager : public KeyedService {
const std::string& presentation_id,
const content::GlobalFrameRoutingId& render_frame_id);
- // Registers |receiver_callback| to presentation with |presentation_info|.
+ // Registers |receiver_callback| and set |receiver_web_contents| to
+ // presentation with |presentation_info|.
virtual void OnLocalPresentationReceiverCreated(
const blink::mojom::PresentationInfo& presentation_info,
- const content::ReceiverConnectionAvailableCallback& receiver_callback);
+ const content::ReceiverConnectionAvailableCallback& receiver_callback,
+ content::WebContents* receiver_web_contents);
// Unregisters ReceiverConnectionAvailableCallback associated with
// |presentation_id|.
@@ -146,6 +152,9 @@ class LocalPresentationManager : public KeyedService {
// |presentation_id|.
virtual bool IsLocalPresentation(const std::string& presentation_id);
+ // Returns true if this class has a local presentation with |web_contents|.
+ virtual bool IsLocalPresentation(content::WebContents* web_contents);
+
// Returns nullptr if |presentation_id| is not associated with a local
// presentation.
virtual const MediaRoute* GetRoute(const std::string& presentation_id);
@@ -181,12 +190,13 @@ class LocalPresentationManager : public KeyedService {
void UnregisterController(
const content::GlobalFrameRoutingId& render_frame_id);
- // Register |receiver_callback| to current local_presentation object.
- // For each controller in |pending_controllers_| map, invoke
- // |receiver_callback| with controller as parameter. Clear
+ // Register |receiver_callback| and set |receiver_web_contents| to current
+ // local_presentation object. For each controller in |pending_controllers_|
+ // map, invoke |receiver_callback| with controller as parameter. Clear
// |pending_controllers_| map afterwards.
void RegisterReceiver(
- const content::ReceiverConnectionAvailableCallback& receiver_callback);
+ const content::ReceiverConnectionAvailableCallback& receiver_callback,
+ content::WebContents* receiver_web_contents);
private:
friend class LocalPresentationManagerTest;
@@ -198,6 +208,7 @@ class LocalPresentationManager : public KeyedService {
const blink::mojom::PresentationInfo presentation_info_;
base::Optional<MediaRoute> route_;
+ content::WebContents* receiver_web_contents_ = nullptr;
// Callback to invoke whenever a receiver connection is available.
content::ReceiverConnectionAvailableCallback receiver_callback_;
diff --git a/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc b/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
index f186f8c848c..b6140f0451a 100644
--- a/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
+++ b/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
@@ -9,6 +9,7 @@
#include "base/stl_util.h"
#include "components/media_router/browser/presentation/local_presentation_manager.h"
#include "components/media_router/browser/test/test_helper.h"
+#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -36,7 +37,7 @@ class MockReceiverConnectionAvailableCallback {
mojo::PendingReceiver<blink::mojom::PresentationConnection>));
};
-class LocalPresentationManagerTest : public ::testing::Test {
+class LocalPresentationManagerTest : public content::RenderViewHostTestHarness {
public:
LocalPresentationManagerTest()
: render_frame_host_id_(1, 1),
@@ -101,7 +102,8 @@ class LocalPresentationManagerTest : public ::testing::Test {
PresentationInfo(GURL(kPresentationUrl), presentation_id),
base::BindRepeating(&MockReceiverConnectionAvailableCallback::
OnReceiverConnectionAvailable,
- base::Unretained(&receiver_callback)));
+ base::Unretained(&receiver_callback)),
+ web_contents());
}
void UnregisterController(
@@ -319,13 +321,21 @@ TEST_F(LocalPresentationManagerTest, TwoPresentations) {
VerifyPresentationsSize(1);
}
-TEST_F(LocalPresentationManagerTest, TestIsLocalPresentation) {
+TEST_F(LocalPresentationManagerTest,
+ TestIsLocalPresentationWithPresentationId) {
EXPECT_FALSE(manager()->IsLocalPresentation(kPresentationId));
mojo::PendingRemote<blink::mojom::PresentationConnection> controller1;
RegisterController(kPresentationId, std::move(controller1));
EXPECT_TRUE(manager()->IsLocalPresentation(kPresentationId));
}
+TEST_F(LocalPresentationManagerTest, TestIsLocalPresentationWithWebContents) {
+ EXPECT_FALSE(manager()->IsLocalPresentation(web_contents()));
+ MockReceiverConnectionAvailableCallback receiver_callback;
+ RegisterReceiver(receiver_callback);
+ EXPECT_TRUE(manager()->IsLocalPresentation(web_contents()));
+}
+
TEST_F(LocalPresentationManagerTest, TestRegisterAndGetRoute) {
MediaSource source("source_1");
MediaRoute route("route_1", source, "sink_1", "", false, false);
diff --git a/chromium/components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.cc b/chromium/components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.cc
index dc59f27083b..45006dc491b 100644
--- a/chromium/components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.cc
+++ b/chromium/components/media_router/browser/presentation/receiver_presentation_service_delegate_impl.cc
@@ -73,7 +73,7 @@ void ReceiverPresentationServiceDelegateImpl::
local_presentation_manager_->OnLocalPresentationReceiverCreated(
blink::mojom::PresentationInfo(web_contents_->GetLastCommittedURL(),
presentation_id_),
- receiver_available_callback);
+ receiver_available_callback, web_contents_);
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(ReceiverPresentationServiceDelegateImpl)
diff --git a/chromium/components/media_router/common/BUILD.gn b/chromium/components/media_router/common/BUILD.gn
index 17caf2f4422..d72b987056c 100644
--- a/chromium/components/media_router/common/BUILD.gn
+++ b/chromium/components/media_router/common/BUILD.gn
@@ -54,9 +54,12 @@ static_library("test_support") {
deps = [
"//base",
"//base/test:test_support",
+ "//components/media_router/common/mojom:logger",
]
public_deps = [ ":common" ]
sources = [
+ "test/mock_logger.cc",
+ "test/mock_logger.h",
"test/test_helper.cc",
"test/test_helper.h",
]
diff --git a/chromium/components/media_router/common/DEPS b/chromium/components/media_router/common/DEPS
index 674b34dfca8..356dd7fdb63 100644
--- a/chromium/components/media_router/common/DEPS
+++ b/chromium/components/media_router/common/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+url",
+ "+mojo",
]
diff --git a/chromium/components/media_router/common/mojom/media_router.mojom b/chromium/components/media_router/common/mojom/media_router.mojom
index 6e0e857e1f0..1ef0e2805c7 100644
--- a/chromium/components/media_router/common/mojom/media_router.mojom
+++ b/chromium/components/media_router/common/mojom/media_router.mojom
@@ -212,7 +212,8 @@ enum RouteRequestResultCode {
NO_SUPPORTED_PROVIDER,
CANCELLED,
ROUTE_ALREADY_EXISTS,
- DESKTOP_PICKER_FAILED
+ DESKTOP_PICKER_FAILED,
+ ROUTE_ALREADY_TERMINATED
// New values must be added here.
};
diff --git a/chromium/components/media_router/common/mojom/media_router_mojom_traits.h b/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
index 535164cb11f..c625fc093d3 100644
--- a/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
+++ b/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
@@ -440,6 +440,9 @@ struct EnumTraits<media_router::mojom::RouteRequestResultCode,
case media_router::RouteRequestResult::DESKTOP_PICKER_FAILED:
return media_router::mojom::RouteRequestResultCode::
DESKTOP_PICKER_FAILED;
+ case media_router::RouteRequestResult::ROUTE_ALREADY_TERMINATED:
+ return media_router::mojom::RouteRequestResultCode::
+ ROUTE_ALREADY_TERMINATED;
default:
NOTREACHED() << "Unknown RouteRequestResultCode "
<< static_cast<int>(code);
@@ -483,6 +486,10 @@ struct EnumTraits<media_router::mojom::RouteRequestResultCode,
case media_router::mojom::RouteRequestResultCode::DESKTOP_PICKER_FAILED:
*output = media_router::RouteRequestResult::DESKTOP_PICKER_FAILED;
return true;
+ case media_router::mojom::RouteRequestResultCode::
+ ROUTE_ALREADY_TERMINATED:
+ *output = media_router::RouteRequestResult::ROUTE_ALREADY_TERMINATED;
+ return true;
}
return false;
}
diff --git a/chromium/components/media_router/common/route_request_result.h b/chromium/components/media_router/common/route_request_result.h
index 8caab7765a2..e6953014d9b 100644
--- a/chromium/components/media_router/common/route_request_result.h
+++ b/chromium/components/media_router/common/route_request_result.h
@@ -47,9 +47,10 @@ class RouteRequestResult {
CANCELLED = 8,
ROUTE_ALREADY_EXISTS = 9,
DESKTOP_PICKER_FAILED = 10,
+ ROUTE_ALREADY_TERMINATED = 11,
// New values must be added here.
- TOTAL_COUNT = 11 // The total number of values.
+ TOTAL_COUNT = 12 // The total number of values.
};
static std::unique_ptr<RouteRequestResult> FromSuccess(
diff --git a/chromium/components/media_router/test/android/cast_emulator/BUILD.gn b/chromium/components/media_router/test/android/cast_emulator/BUILD.gn
new file mode 100644
index 00000000000..610908abdc6
--- /dev/null
+++ b/chromium/components/media_router/test/android/cast_emulator/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+android_library("cast_emulator_java") {
+ chromium_code = true
+
+ sources = [
+ "src/org/chromium/components/media_router/cast_emulator/RoutePublisher.java",
+ "src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProvider.java",
+ "src/org/chromium/components/media_router/cast_emulator/TestMediaRouteProviderService.java",
+ "src/org/chromium/components/media_router/cast_emulator/remote/DummyPlayer.java",
+ "src/org/chromium/components/media_router/cast_emulator/remote/LocalSessionManager.java",
+ "src/org/chromium/components/media_router/cast_emulator/remote/MediaItem.java",
+ "src/org/chromium/components/media_router/cast_emulator/remote/RemotePlaybackRoutePublisher.java",
+ "src/org/chromium/components/media_router/cast_emulator/remote/RemoteSessionManager.java",
+ "src/org/chromium/components/media_router/cast_emulator/router/DummyRoutePublisher.java",
+ ]
+ deps = [
+ "$google_play_services_package:google_play_services_cast_java",
+ "//base:base_java",
+ "//third_party/android_deps:android_support_v7_appcompat_java",
+ "//third_party/android_deps:androidx_mediarouter_mediarouter_java",
+ ]
+}
diff --git a/chromium/components/media_router/test/android/media_router_test_support/BUILD.gn b/chromium/components/media_router/test/android/media_router_test_support/BUILD.gn
new file mode 100644
index 00000000000..0bb27498706
--- /dev/null
+++ b/chromium/components/media_router/test/android/media_router_test_support/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2020 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("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+android_apk("media_router_test_support_apk") {
+ # Used as an additional_apk in test scripts.
+ never_incremental = true
+
+ # Multidex requires a custom Application class to initialize it. Simpler to
+ # just disable it.
+ enable_multidex = false
+
+ deps = [
+ "//components/media_router/test/android/cast_emulator:cast_emulator_java",
+ ]
+
+ apk_name = "MediaRouterTestSupportApk"
+ android_manifest = "AndroidManifest.xml"
+}
diff --git a/chromium/components/messages/OWNERS b/chromium/components/messages/OWNERS
index ea0fc8128c0..9150fab741f 100644
--- a/chromium/components/messages/OWNERS
+++ b/chromium/components/messages/OWNERS
@@ -3,5 +3,5 @@ twellington@chromium.org
mdjones@chromium.org
lazzzis@google.com
-# TEAM: chrome-android-app@chromium.org
+# TEAM: clank-app-team@google.com
# COMPONENT: UI>Browser>Mobile>Messages \ No newline at end of file
diff --git a/chromium/components/messages/android/BUILD.gn b/chromium/components/messages/android/BUILD.gn
index da349bdde4d..9895bbcced5 100644
--- a/chromium/components/messages/android/BUILD.gn
+++ b/chromium/components/messages/android/BUILD.gn
@@ -5,22 +5,37 @@
import("//build/config/android/rules.gni")
import("//chrome/android/features/android_library_factory_tmpl.gni")
+# TODO(sinansahin): Decide which classes should stay in the public target, and
+# probably move MessageBanner* classes to internal/.
android_library("java") {
sources = [
+ "java/src/org/chromium/components/messages/MessageAutoDismissTimer.java",
+ "java/src/org/chromium/components/messages/MessageBannerCoordinator.java",
+ "java/src/org/chromium/components/messages/MessageBannerMediator.java",
"java/src/org/chromium/components/messages/MessageBannerProperties.java",
"java/src/org/chromium/components/messages/MessageBannerView.java",
"java/src/org/chromium/components/messages/MessageBannerViewBinder.java",
"java/src/org/chromium/components/messages/MessageContainer.java",
- "java/src/org/chromium/components/messages/MessageQueueManager.java",
+ "java/src/org/chromium/components/messages/MessageDispatcher.java",
+ "java/src/org/chromium/components/messages/MessageDispatcherBridge.java",
+ "java/src/org/chromium/components/messages/MessageDispatcherProvider.java",
"java/src/org/chromium/components/messages/MessageStateHandler.java",
+ "java/src/org/chromium/components/messages/MessageUtils.java",
+ "java/src/org/chromium/components/messages/MessageUtilsBridge.java",
+ "java/src/org/chromium/components/messages/MessageWrapper.java",
"java/src/org/chromium/components/messages/SingleActionMessage.java",
]
resources_package = "org.chromium.components.messages"
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
deps = [
":java_resources",
"//base:base_java",
+ "//base:jni_java",
"//components/browser_ui/banners/android:java",
+ "//components/browser_ui/widget/android:java",
+ "//content/public/android:content_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
"//ui/android:ui_java",
]
}
@@ -38,18 +53,68 @@ android_resources("java_resources") {
]
}
+generate_jni("jni_headers") {
+ sources = [
+ "java/src/org/chromium/components/messages/MessageDispatcherBridge.java",
+ "java/src/org/chromium/components/messages/MessageUtilsBridge.java",
+ "java/src/org/chromium/components/messages/MessageWrapper.java",
+ ]
+}
+
+static_library("android") {
+ sources = [
+ "message_dispatcher_bridge.cc",
+ "message_dispatcher_bridge.h",
+ "message_utils_bridge.cc",
+ "message_utils_bridge.h",
+ "message_wrapper.cc",
+ "message_wrapper.h",
+ ]
+ deps = [
+ ":jni_headers",
+ "//base",
+ "//content/public/browser",
+ ]
+}
+
+# Build target for Messages manager code, that owns and initializes
+# MessageDispatcher.
+android_library("manager_java") {
+ sources = [
+ "java/src/org/chromium/components/messages/ManagedMessageDispatcher.java",
+ "java/src/org/chromium/components/messages/MessageQueueDelegate.java",
+ ]
+ deps = [ ":java" ]
+}
+
+android_library_factory("factory_java") {
+ sources = [
+ "internal/java/src/org/chromium/components/messages/MessagesFactory.java",
+ ]
+
+ deps = [
+ ":java",
+ ":manager_java",
+ "//ui/android:ui_full_java",
+ ]
+}
+
static_library("feature_flags") {
sources = [
"messages_feature.cc",
"messages_feature.h",
]
- deps = [ "//base" ]
+ deps = [
+ ":android",
+ "//base",
+ ]
}
android_library("javatests") {
testonly = true
sources = [
"java/src/org/chromium/components/messages/MessageBannerRenderTest.java",
+ "java/src/org/chromium/components/messages/MessageBannerViewTest.java",
"java/src/org/chromium/components/messages/SingleActionMessageTest.java",
]
resources_package = "org.chromium.components.messages"
@@ -64,21 +129,32 @@ android_library("javatests") {
"//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
"//third_party/android_deps:androidx_core_core_java",
"//third_party/android_deps:androidx_test_runner_java",
+ "//third_party/android_deps:espresso_java",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit",
+ "//third_party/mockito:mockito_java",
"//ui/android:ui_java",
"//ui/android:ui_java_test_support",
]
}
-android_library_factory("factory_java") {
+java_library("junit") {
+ # Skip platform checks since Robolectric depends on requires_android targets.
+ bypass_platform_checks = true
+ testonly = true
sources = [
- "internal/java/src/org/chromium/components/messages/MessagesFactory.java",
+ "java/src/org/chromium/components/messages/MessageAutoDismissTimerTest.java",
+ "java/src/org/chromium/components/messages/MessageWrapperTest.java",
]
-
deps = [
":java",
- "//ui/android:ui_full_java",
+ "//base:base_java_test_support",
+ "//base:base_junit_test_support",
+ "//third_party/android_deps:androidx_test_runner_java",
+ "//third_party/android_deps:robolectric_all_java",
+ "//third_party/junit",
+ "//third_party/mockito:mockito_java",
+ "//ui/android:ui_java",
]
}
diff --git a/chromium/components/messages/android/DEPS b/chromium/components/messages/android/DEPS
index b22bb39efb5..4c4b4115b2b 100644
--- a/chromium/components/messages/android/DEPS
+++ b/chromium/components/messages/android/DEPS
@@ -1,6 +1,9 @@
include_rules = [
"+ui/android",
"+base/test/android",
+ "+content/public/android",
+ "+content/public/browser",
"+content/public/test/android",
"+components/browser_ui/banners/android",
+ "+components/browser_ui/widget/android",
]
diff --git a/chromium/components/messages/android/internal/BUILD.gn b/chromium/components/messages/android/internal/BUILD.gn
index e31cdf60a18..30525f9f088 100644
--- a/chromium/components/messages/android/internal/BUILD.gn
+++ b/chromium/components/messages/android/internal/BUILD.gn
@@ -6,12 +6,14 @@ import("//build/config/android/rules.gni")
android_library("java") {
sources = [
- "java/src/org/chromium/components/messages/MessageQueueManagerImpl.java",
+ "java/src/org/chromium/components/messages/MessageDispatcherImpl.java",
+ "java/src/org/chromium/components/messages/MessageQueueManager.java",
"java/src/org/chromium/components/messages/MessagesFactory.java",
]
deps = [
"..:java",
+ "..:manager_java",
"//base:base_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
"//ui/android:ui_full_java",
@@ -22,10 +24,13 @@ java_library("junit") {
# Skip platform checks since Robolectric depends on requires_android targets.
bypass_platform_checks = true
testonly = true
- sources = [ "java/src/org/chromium/components/messages/MessageQueueManagerImplTest.java" ]
+ sources = [
+ "java/src/org/chromium/components/messages/MessageQueueManagerTest.java",
+ ]
deps = [
":java",
"..:java",
+ "..:manager_java",
"//base:base_junit_test_support",
"//third_party/android_deps:androidx_test_runner_java",
"//third_party/junit",
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherImpl.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherImpl.java
new file mode 100644
index 00000000000..ee79a341f01
--- /dev/null
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageDispatcherImpl.java
@@ -0,0 +1,62 @@
+// Copyright 2020 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.components.messages;
+
+import org.chromium.base.supplier.Supplier;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * This class implements public MessageDispatcher interface, delegating the actual work to
+ * MessageQueueManager.
+ */
+public class MessageDispatcherImpl implements ManagedMessageDispatcher {
+ private final MessageQueueManager mMessageQueueManager = new MessageQueueManager();
+ private final MessageContainer mMessageContainer;
+ private final Supplier<Integer> mMessageMaxTranslationSupplier;
+
+ /**
+ * Build a new message dispatcher
+ * @param messageContainer A container view for displaying message banners.
+ * @param messageMaxTranslationSupplier A {@link Supplier} that supplies the maximum translation
+ * Y value the message banner can have as a result of the animations or the gestures.
+ */
+ public MessageDispatcherImpl(
+ MessageContainer messageContainer, Supplier<Integer> messageMaxTranslation) {
+ mMessageContainer = messageContainer;
+ mMessageMaxTranslationSupplier = messageMaxTranslation;
+ }
+
+ @Override
+ public void enqueueMessage(PropertyModel messageProperties) {
+ MessageStateHandler messageStateHandler = new SingleActionMessage(mMessageContainer,
+ messageProperties, this::dismissMessage, mMessageMaxTranslationSupplier);
+ mMessageQueueManager.enqueueMessage(messageStateHandler, messageProperties);
+ }
+
+ @Override
+ public void dismissMessage(PropertyModel messageProperties) {
+ mMessageQueueManager.dismissMessage(messageProperties);
+ }
+
+ @Override
+ public void dismissAllMessages() {
+ mMessageQueueManager.dismissAllMessages();
+ }
+
+ @Override
+ public int suspend() {
+ return mMessageQueueManager.suspend();
+ }
+
+ @Override
+ public void resume(int token) {
+ mMessageQueueManager.resume(token);
+ }
+
+ @Override
+ public void setDelegate(MessageQueueDelegate delegate) {
+ mMessageQueueManager.setDelegate(delegate);
+ }
+}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java
new file mode 100644
index 00000000000..a2c121e0384
--- /dev/null
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManager.java
@@ -0,0 +1,129 @@
+// Copyright 2020 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.components.messages;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.ui.util.TokenHolder;
+
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+
+/**
+ * A class managing the queue of messages. Its primary role is to decide when to show/hide current
+ * message and which message to show next.
+ */
+class MessageQueueManager {
+ private final Queue<MessageStateHandler> mMessageQueue = new ArrayDeque<>();
+ private final Map<Object, MessageStateHandler> mMessageMap = new HashMap<>();
+ @Nullable
+ private MessageStateHandler mCurrentDisplayedMessage;
+ private MessageQueueDelegate mMessageQueueDelegate;
+ private final TokenHolder mTokenHolder;
+
+ public MessageQueueManager() {
+ mTokenHolder = new TokenHolder(this::updateCurrentDisplayedMessage);
+ }
+
+ /**
+ * Enqueues a message. Associates the message with its key; the key is used later to dismiss the
+ * message. Displays the message if there is no other message shown.
+ * @param message The message to enqueue
+ * @param key The key to associate with this message.
+ */
+ public void enqueueMessage(MessageStateHandler message, Object key) {
+ if (mMessageMap.containsKey(key)) {
+ throw new IllegalStateException("Message with the given key has already been enqueued");
+ }
+ mMessageMap.put(key, message);
+ mMessageQueue.add(message);
+ updateCurrentDisplayedMessage();
+ }
+
+ /**
+ * Dismisses a message specified by its key. Hdes the message if it is currently displayed.
+ * Displays the next message in the queue if available.
+ * @param key The key associated with the message to dismiss.
+ */
+ public void dismissMessage(Object key) {
+ MessageStateHandler message = mMessageMap.get(key);
+ if (message == null) return;
+ mMessageMap.remove(key);
+ mMessageQueue.remove(message);
+ Runnable onAnimationFinished = () -> {
+ message.dismiss();
+ updateCurrentDisplayedMessage();
+ };
+ if (mCurrentDisplayedMessage == message) {
+ mCurrentDisplayedMessage.hide(true, () -> {
+ mMessageQueueDelegate.onFinishHiding();
+ mCurrentDisplayedMessage = null;
+ onAnimationFinished.run();
+ });
+ } else {
+ onAnimationFinished.run();
+ }
+ }
+
+ public int suspend() {
+ return mTokenHolder.acquireToken();
+ }
+
+ public void resume(int token) {
+ mTokenHolder.releaseToken(token);
+ }
+
+ public void setDelegate(MessageQueueDelegate delegate) {
+ mMessageQueueDelegate = delegate;
+ }
+
+ private void updateCurrentDisplayedMessage() {
+ // TODO(crbug.com/1123947): may only call delegate when message system goes from
+ // no shown message to showing first message or the opposite.
+ if (mMessageQueue.isEmpty()) {
+ assert mCurrentDisplayedMessage
+ == null : "No message should be displayed when the queue is empty.";
+ return;
+ }
+ if (mCurrentDisplayedMessage == null && !mTokenHolder.hasTokens()) {
+ mCurrentDisplayedMessage = mMessageQueue.element();
+ mMessageQueueDelegate.onStartShowing(mCurrentDisplayedMessage::show);
+ } else if (mCurrentDisplayedMessage != null && mTokenHolder.hasTokens()) {
+ mCurrentDisplayedMessage.hide(false, () -> {
+ mMessageQueueDelegate.onFinishHiding();
+ mCurrentDisplayedMessage = null;
+ });
+ }
+ }
+
+ void dismissAllMessages() {
+ if (mCurrentDisplayedMessage != null) {
+ mMessageQueue.remove(mCurrentDisplayedMessage);
+ mCurrentDisplayedMessage.hide(false, () -> {
+ mMessageQueueDelegate.onFinishHiding();
+ mCurrentDisplayedMessage.dismiss();
+ mCurrentDisplayedMessage = null;
+ });
+ }
+ for (MessageStateHandler h : mMessageQueue) {
+ h.dismiss();
+ }
+ mMessageMap.clear();
+ mMessageQueue.clear();
+ }
+
+ @VisibleForTesting
+ Queue<MessageStateHandler> getMessageQueueForTesting() {
+ return mMessageQueue;
+ }
+
+ @VisibleForTesting
+ Map<Object, MessageStateHandler> getMessageMapForTesting() {
+ return mMessageMap;
+ }
+}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImpl.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImpl.java
deleted file mode 100644
index 4a04b47bef6..00000000000
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImpl.java
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020 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.components.messages;
-
-import androidx.annotation.Nullable;
-
-import org.chromium.base.UnownedUserData;
-import org.chromium.base.UnownedUserDataKey;
-import org.chromium.ui.base.WindowAndroid;
-
-import java.util.ArrayDeque;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Queue;
-
-/**
- * A class managing the queue of messages. Its primary role is to decide when to show/hide current
- * message and which message to show next.
- */
-class MessageQueueManagerImpl implements MessageQueueManager, UnownedUserData {
- private static final UnownedUserDataKey<MessageQueueManagerImpl> KEY =
- new UnownedUserDataKey<>(MessageQueueManagerImpl.class);
-
- private final Queue<MessageStateHandler> mMessageQueue = new ArrayDeque<>();
- private final Map<Object, MessageStateHandler> mMessageMap = new HashMap<>();
- @Nullable
- private MessageStateHandler mCurrentDisplayedMessage;
-
- /**
- * Get the activity's MessageQueueManager from the provided WindowAndroid.
- * @param window The window to get the manager from.
- * @return The activity's MessageQueueManager.
- */
- public static MessageQueueManagerImpl from(WindowAndroid window) {
- return KEY.retrieveDataFromHost(window.getUnownedUserDataHost());
- }
-
- public MessageQueueManagerImpl() {}
-
- /**
- * Attaches MessageQueueManager to a given window. This window will be used later to retrieve
- * activity's MessageQueueManager.
- * @param window The window to attach to.
- */
- public void attachToWindowAndroid(WindowAndroid window) {
- KEY.attachToHost(window.getUnownedUserDataHost(), this);
- }
-
- /**
- * Destroys MessageQueueManager, detaching it from the WindowAndroid it was attached to.
- */
- @Override
- public void destroy() {
- KEY.detachFromAllHosts(this);
- }
-
- /**
- * Enqueues a message. Associates the message with its key; the key is used later to dismiss the
- * message. Displays the message if there is no other message shown.
- * @param message The message to enqueue
- * @param key The key to associate with this message.
- */
- public void enqueueMessage(MessageStateHandler message, Object key) {
- if (mMessageMap.containsKey(key)) {
- throw new IllegalStateException("Message with the given key has already been enqueued");
- }
- mMessageMap.put(key, message);
- mMessageQueue.add(message);
- updateCurrentDisplayedMessage();
- }
-
- /**
- * Dismisses a message specified by its key. Hdes the message if it is currently displayed.
- * Displays the next message in the queue if available.
- * @param key The key associated with the message to dismiss.
- */
- public void dismissMessage(Object key) {
- MessageStateHandler message = mMessageMap.get(key);
- if (message == null) return;
- mMessageMap.remove(key);
- mMessageQueue.remove(message);
- if (mCurrentDisplayedMessage == message) {
- mCurrentDisplayedMessage.hide();
- mCurrentDisplayedMessage = null;
- }
- message.dismiss();
- updateCurrentDisplayedMessage();
- }
-
- private void updateCurrentDisplayedMessage() {
- if (mCurrentDisplayedMessage != null) return;
- if (mMessageQueue.isEmpty()) return;
- mCurrentDisplayedMessage = mMessageQueue.element();
- mCurrentDisplayedMessage.show();
- }
-}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImplTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImplTest.java
deleted file mode 100644
index 928d08ff8ab..00000000000
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerImplTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2020 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.components.messages;
-
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-
-/**
- * Unit tests for MessageQueueManagerImpl.
- */
-@RunWith(BaseRobolectricTestRunner.class)
-public class MessageQueueManagerImplTest {
- /**
- * Tests lifecycle of a single message:
- * - enqueueMessage() calls show()
- * - dismissMessage() calls hide() and dismiss()
- */
- @Test
- @SmallTest
- public void testEnqueueMessage() {
- MessageQueueManagerImpl queueManager = new MessageQueueManagerImpl();
- MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
- MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
-
- queueManager.enqueueMessage(m1, m1);
- verify(m1).show();
- queueManager.dismissMessage(m1);
- verify(m1).hide();
- verify(m1).dismiss();
-
- queueManager.enqueueMessage(m2, m2);
- verify(m2).show();
- queueManager.dismissMessage(m2);
- verify(m2).hide();
- verify(m2).dismiss();
- }
-
- /**
- * Tests that, with multiple enqueued messages, only one message is shown at a time.
- */
- @Test
- @SmallTest
- public void testOneMessageShownAtATime() {
- MessageQueueManagerImpl queueManager = new MessageQueueManagerImpl();
- MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
- MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
-
- queueManager.enqueueMessage(m1, m1);
- queueManager.enqueueMessage(m2, m2);
- verify(m1).show();
- verify(m2, never()).show();
-
- queueManager.dismissMessage(m1);
- verify(m1).hide();
- verify(m1).dismiss();
- verify(m2).show();
- }
-
- /**
- * Tests that, when the message is dismissed before it was shown, neither show() nor hide() is
- * called.
- */
- @Test
- @SmallTest
- public void testDismissBeforeShow() {
- MessageQueueManagerImpl queueManager = new MessageQueueManagerImpl();
- MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
- MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
-
- queueManager.enqueueMessage(m1, m1);
- queueManager.enqueueMessage(m2, m2);
- verify(m1).show();
- verify(m2, never()).show();
-
- queueManager.dismissMessage(m2);
- verify(m2).dismiss();
-
- queueManager.dismissMessage(m1);
- verify(m2, never()).show();
- verify(m2, never()).hide();
- }
-
- /**
- * Tests that enqueueing two messages with the same key is not allowed, it results in
- * IllegalStateException.
- */
- @Test(expected = IllegalStateException.class)
- @SmallTest
- public void testEnqueueDuplicateKey() {
- MessageQueueManagerImpl queueManager = new MessageQueueManagerImpl();
- MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
- MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
- Object key = new Object();
-
- queueManager.enqueueMessage(m1, key);
- queueManager.enqueueMessage(m2, key);
- }
-
- /**
- * Tests that dismissing a message more than once is handled correctly.
- */
- @Test
- @SmallTest
- public void testDismissMessageTwice() {
- MessageQueueManagerImpl queueManager = new MessageQueueManagerImpl();
- MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
- queueManager.enqueueMessage(m1, m1);
- queueManager.dismissMessage(m1);
- queueManager.dismissMessage(m1);
- verify(m1, times(1)).dismiss();
- }
-}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java
new file mode 100644
index 00000000000..d359fde8487
--- /dev/null
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageQueueManagerTest.java
@@ -0,0 +1,230 @@
+// Copyright 2020 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.components.messages;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+/**
+ * Unit tests for MessageQueueManager.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+public class MessageQueueManagerTest {
+ private MessageQueueDelegate mEmptyDelegate = new MessageQueueDelegate() {
+ @Override
+ public void onStartShowing(Runnable callback) {
+ callback.run();
+ }
+
+ @Override
+ public void onFinishHiding() {}
+ };
+
+ private class EmptyMessageStateHandler implements MessageStateHandler {
+ @Override
+ public void show() {}
+
+ @Override
+ public void hide(boolean animate, Runnable hiddenCallback) {
+ hiddenCallback.run();
+ }
+
+ @Override
+ public void dismiss() {}
+ }
+
+ /**
+ * Tests lifecycle of a single message:
+ * - enqueueMessage() calls show()
+ * - dismissMessage() calls hide() and dismiss()
+ */
+ @Test
+ @SmallTest
+ public void testEnqueueMessage() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ MessageStateHandler m1 = Mockito.spy(new EmptyMessageStateHandler());
+ MessageStateHandler m2 = Mockito.spy(new EmptyMessageStateHandler());
+
+ queueManager.enqueueMessage(m1, m1);
+ verify(m1).show();
+ queueManager.dismissMessage(m1);
+ verify(m1).hide(anyBoolean(), any());
+ verify(m1).dismiss();
+
+ queueManager.enqueueMessage(m2, m2);
+ verify(m2).show();
+ queueManager.dismissMessage(m2);
+ verify(m2).hide(anyBoolean(), any());
+ verify(m2).dismiss();
+ }
+
+ /**
+ * Tests that, with multiple enqueued messages, only one message is shown at a time.
+ */
+ @Test
+ @SmallTest
+ public void testOneMessageShownAtATime() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ MessageStateHandler m1 = Mockito.spy(new EmptyMessageStateHandler());
+ MessageStateHandler m2 = Mockito.spy(new EmptyMessageStateHandler());
+
+ queueManager.enqueueMessage(m1, m1);
+ queueManager.enqueueMessage(m2, m2);
+ verify(m1).show();
+ verify(m2, never()).show();
+
+ queueManager.dismissMessage(m1);
+ verify(m1).hide(anyBoolean(), any());
+ verify(m1).dismiss();
+ verify(m2).show();
+ }
+
+ /**
+ * Tests that, when the message is dismissed before it was shown, neither show() nor hide() is
+ * called.
+ */
+ @Test
+ @SmallTest
+ public void testDismissBeforeShow() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
+ MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
+
+ queueManager.enqueueMessage(m1, m1);
+ queueManager.enqueueMessage(m2, m2);
+ verify(m1).show();
+ verify(m2, never()).show();
+
+ queueManager.dismissMessage(m2);
+ verify(m2).dismiss();
+
+ queueManager.dismissMessage(m1);
+ verify(m2, never()).show();
+ verify(m2, never()).hide(anyBoolean(), any());
+ }
+
+ /**
+ * Tests that enqueueing two messages with the same key is not allowed, it results in
+ * IllegalStateException.
+ */
+ @Test(expected = IllegalStateException.class)
+ @SmallTest
+ public void testEnqueueDuplicateKey() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
+ MessageStateHandler m2 = Mockito.mock(MessageStateHandler.class);
+ Object key = new Object();
+
+ queueManager.enqueueMessage(m1, key);
+ queueManager.enqueueMessage(m2, key);
+ }
+
+ /**
+ * Tests that dismissing a message more than once is handled correctly.
+ */
+ @Test
+ @SmallTest
+ public void testDismissMessageTwice() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ MessageStateHandler m1 = Mockito.spy(new EmptyMessageStateHandler());
+ queueManager.enqueueMessage(m1, m1);
+ queueManager.dismissMessage(m1);
+ queueManager.dismissMessage(m1);
+ verify(m1, times(1)).dismiss();
+ }
+
+ /**
+ * Tests that all messages can be dismissed correctly.
+ */
+ @Test
+ @SmallTest
+ public void testDismissAllMessages() {
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(mEmptyDelegate);
+ final int count = 10;
+ MessageStateHandler handlers[] = new MessageStateHandler[count];
+ for (int i = 0; i < count; i++) {
+ handlers[i] = Mockito.spy(new EmptyMessageStateHandler());
+ queueManager.enqueueMessage(handlers[i], handlers[i]);
+ }
+ queueManager.dismissAllMessages();
+ for (MessageStateHandler h : handlers) {
+ verify(h).dismiss();
+ }
+ Assert.assertEquals("Map should be cleared after all messages are dismissed", 0,
+ queueManager.getMessageMapForTesting().size());
+ Assert.assertEquals("Queue should be cleared after all messages are dismissed", 0,
+ queueManager.getMessageQueueForTesting().size());
+ }
+
+ /**
+ * Tests that delegate methods are properly called when queue is suspended
+ * and resumed.
+ */
+ @Test
+ @SmallTest
+ public void testSuspendAndResumeQueue() {
+ MessageQueueDelegate delegate = Mockito.spy(mEmptyDelegate);
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(delegate);
+ int token = queueManager.suspend();
+ MessageStateHandler m1 = Mockito.spy(new EmptyMessageStateHandler());
+ queueManager.enqueueMessage(m1, m1);
+ verify(delegate, never()).onStartShowing(any());
+ verify(delegate, never()).onFinishHiding();
+ verify(m1, never()).show();
+ verify(m1, never()).hide(anyBoolean(), any());
+
+ queueManager.resume(token);
+ verify(delegate).onStartShowing(any());
+ verify(m1).show();
+
+ queueManager.suspend();
+ verify(delegate).onFinishHiding();
+ verify(m1).hide(anyBoolean(), any());
+ }
+
+ /**
+ * Tests that delegate methods are properly called to show/hide message
+ * when queue is suspended.
+ */
+ @Test
+ @SmallTest
+ public void testDismissOnSuspend() {
+ MessageQueueDelegate delegate = Mockito.spy(mEmptyDelegate);
+ MessageQueueManager queueManager = new MessageQueueManager();
+ queueManager.setDelegate(delegate);
+ queueManager.suspend();
+ MessageStateHandler m1 = Mockito.mock(MessageStateHandler.class);
+ queueManager.enqueueMessage(m1, m1);
+ verify(delegate, never()).onStartShowing(any());
+ verify(delegate, never()).onFinishHiding();
+ verify(m1, never()).show();
+ verify(m1, never()).hide(anyBoolean(), any());
+
+ queueManager.dismissMessage(m1);
+ verify(delegate, never()).onStartShowing(any());
+ verify(delegate, never()).onFinishHiding();
+ verify(m1, never()).show();
+ verify(m1, never()).hide(anyBoolean(), any());
+ }
+}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesFactory.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesFactory.java
index 176cdc0089c..39b1eb05302 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesFactory.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesFactory.java
@@ -4,18 +4,42 @@
package org.chromium.components.messages;
+import org.chromium.base.supplier.Supplier;
import org.chromium.ui.base.WindowAndroid;
/** A factory for constructing different Messages related objects. */
public class MessagesFactory {
/**
- * Creates an instance of MessageQueueManager and attaches it to WindowAndroid.
- * @param windowAndroid The WindowAndroid to attach MessageQueueManager to.
- * @return The constructed MessageQueueManager.
+ * Creates an instance of ManagedMessageDispatcher.
+ * @param container The MessageContainer for displaying message banners.
+ * @param messageMaxTranslation A {@link Supplier} that supplies the maximum translation Y value
+ * the message banner can have as a result of the animations or the gestures, relative
+ * to the MessageContainer. When messages are shown, they will be animated down the
+ * screen, starting at the negative |messageMaxTranslation| y translation to the resting
+ * position in the MessageContainer.
+ * @return The constructed ManagedMessageDispatcher.
*/
- public static MessageQueueManager createMessageQueueManager(WindowAndroid windowAndroid) {
- MessageQueueManagerImpl messageQueueManager = new MessageQueueManagerImpl();
- messageQueueManager.attachToWindowAndroid(windowAndroid);
- return messageQueueManager;
+ public static ManagedMessageDispatcher createMessageDispatcher(
+ MessageContainer container, Supplier<Integer> messageMaxTranslation) {
+ return new MessageDispatcherImpl(container, messageMaxTranslation);
}
-} \ No newline at end of file
+
+ /**
+ * Attaches MessageDispatcher as UnownedUserData to WindowAndroid making it accessible to
+ * components outside of chrome/android.
+ * @param windowAndroid The WindowAndroid to attach ManagedMessageDispatcher to.
+ * @param messageDispatcher The MessageDispatcher to attach.
+ */
+ public static void attachMessageDispatcher(
+ WindowAndroid windowAndroid, ManagedMessageDispatcher messageDispatcher) {
+ MessageDispatcherProvider.attach(windowAndroid, messageDispatcher);
+ }
+
+ /**
+ * Detaches MessageDispatcher from WindowAndroid.
+ * @param messageDispatcher The MessageDispatcher to detach from WindowAndroid.
+ */
+ public static void detachMessageDispatcher(ManagedMessageDispatcher messageDispatcher) {
+ MessageDispatcherProvider.detach(messageDispatcher);
+ }
+}
diff --git a/chromium/components/messages/android/message_dispatcher_bridge.cc b/chromium/components/messages/android/message_dispatcher_bridge.cc
new file mode 100644
index 00000000000..f5f2c9447ba
--- /dev/null
+++ b/chromium/components/messages/android/message_dispatcher_bridge.cc
@@ -0,0 +1,43 @@
+// Copyright 2020 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/messages/android/message_dispatcher_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "components/messages/android/jni_headers/MessageDispatcherBridge_jni.h"
+#include "content/public/browser/web_contents.h"
+
+namespace messages {
+
+// static
+void MessageDispatcherBridge::EnqueueMessage(
+ MessageWrapper* message,
+ content::WebContents* web_contents) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_MessageDispatcherBridge_enqueueMessage(
+ env, message->GetJavaMessageWrapper(),
+ web_contents->GetJavaWebContents());
+}
+
+// static
+void MessageDispatcherBridge::DismissMessage(
+ MessageWrapper* message,
+ content::WebContents* web_contents) {
+ base::android::ScopedJavaLocalRef<jobject> jmessage(
+ message->GetJavaMessageWrapper());
+ JNIEnv* env = base::android::AttachCurrentThread();
+ message->HandleDismissCallback(env);
+ // DismissMessage can be called in the process of WebContents destruction.
+ // In this case WebContentsAndroid is already torn down. We shouldn't call
+ // GetJavaWebContents() because it recreates WebContentsAndroid.
+ if (!web_contents->IsBeingDestroyed()) {
+ Java_MessageDispatcherBridge_dismissMessage(
+ env, jmessage, web_contents->GetJavaWebContents());
+ }
+}
+
+} // namespace messages \ No newline at end of file
diff --git a/chromium/components/messages/android/message_dispatcher_bridge.h b/chromium/components/messages/android/message_dispatcher_bridge.h
new file mode 100644
index 00000000000..3940a11c7ac
--- /dev/null
+++ b/chromium/components/messages/android/message_dispatcher_bridge.h
@@ -0,0 +1,28 @@
+// Copyright 2020 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_MESSAGES_ANDROID_MESSAGE_DISPATCHER_BRIDGE_H_
+#define COMPONENTS_MESSAGES_ANDROID_MESSAGE_DISPATCHER_BRIDGE_H_
+
+#include "components/messages/android/message_wrapper.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace messages {
+
+// C++ counterpart to MessageDispatcherBridge.java. Enables C++ feature code to
+// enqueue/dismiss messages with MessageDispatcher.java.
+class MessageDispatcherBridge {
+ public:
+ static void EnqueueMessage(MessageWrapper* message,
+ content::WebContents* web_contents);
+ static void DismissMessage(MessageWrapper* message,
+ content::WebContents* web_contents);
+};
+
+} // namespace messages
+
+#endif // COMPONENTS_MESSAGES_ANDROID_MESSAGE_DISPATCHER_BRIDGE_H_ \ No newline at end of file
diff --git a/chromium/components/messages/android/message_utils_bridge.cc b/chromium/components/messages/android/message_utils_bridge.cc
new file mode 100644
index 00000000000..03ea3a42bbd
--- /dev/null
+++ b/chromium/components/messages/android/message_utils_bridge.cc
@@ -0,0 +1,20 @@
+// Copyright 2020 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/messages/android/message_utils_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "components/messages/android/jni_headers/MessageUtilsBridge_jni.h"
+
+namespace messages {
+
+// static
+bool MessageUtilsBridge::IsA11yEnabled() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_MessageUtilsBridge_isA11yEnabled(env);
+}
+
+} // namespace messages \ No newline at end of file
diff --git a/chromium/components/messages/android/message_utils_bridge.h b/chromium/components/messages/android/message_utils_bridge.h
new file mode 100644
index 00000000000..2b7dd1304c3
--- /dev/null
+++ b/chromium/components/messages/android/message_utils_bridge.h
@@ -0,0 +1,18 @@
+// Copyright 2020 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_MESSAGES_ANDROID_MESSAGE_UTILS_BRIDGE_H_
+#define COMPONENTS_MESSAGES_ANDROID_MESSAGE_UTILS_BRIDGE_H_
+
+namespace messages {
+
+// C++ counterpart to MessageUtilsBridge.java.
+class MessageUtilsBridge {
+ public:
+ static bool IsA11yEnabled();
+};
+
+} // namespace messages
+
+#endif // COMPONENTS_MESSAGES_ANDROID_MESSAGE_UTILS_BRIDGE_H_ \ No newline at end of file
diff --git a/chromium/components/messages/android/message_wrapper.cc b/chromium/components/messages/android/message_wrapper.cc
new file mode 100644
index 00000000000..67782711988
--- /dev/null
+++ b/chromium/components/messages/android/message_wrapper.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 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/messages/android/message_wrapper.h"
+
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+#include "components/messages/android/jni_headers/MessageWrapper_jni.h"
+#include "content/public/browser/web_contents.h"
+
+namespace messages {
+
+MessageWrapper::MessageWrapper(base::OnceClosure action_callback,
+ base::OnceClosure dismiss_callback)
+ : action_callback_(std::move(action_callback)),
+ dismiss_callback_(std::move(dismiss_callback)),
+ message_dismissed_(false) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ java_message_wrapper_ =
+ Java_MessageWrapper_create(env, reinterpret_cast<int64_t>(this));
+}
+
+MessageWrapper::~MessageWrapper() {
+ CHECK(message_dismissed_);
+}
+
+base::string16 MessageWrapper::GetTitle() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jtitle =
+ Java_MessageWrapper_getTitle(env, java_message_wrapper_);
+ return jtitle.is_null() ? base::string16()
+ : base::android::ConvertJavaStringToUTF16(jtitle);
+}
+
+void MessageWrapper::SetTitle(const base::string16& title) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jtitle =
+ base::android::ConvertUTF16ToJavaString(env, title);
+ Java_MessageWrapper_setTitle(env, java_message_wrapper_, jtitle);
+}
+
+base::string16 MessageWrapper::GetDescription() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jdescription =
+ Java_MessageWrapper_getDescription(env, java_message_wrapper_);
+ return jdescription.is_null()
+ ? base::string16()
+ : base::android::ConvertJavaStringToUTF16(jdescription);
+}
+
+void MessageWrapper::SetDescription(const base::string16& description) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jdescription =
+ base::android::ConvertUTF16ToJavaString(env, description);
+ Java_MessageWrapper_setDescription(env, java_message_wrapper_, jdescription);
+}
+
+base::string16 MessageWrapper::GetPrimaryButtonText() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jprimary_button_text =
+ Java_MessageWrapper_getPrimaryButtonText(env, java_message_wrapper_);
+ return jprimary_button_text.is_null()
+ ? base::string16()
+ : base::android::ConvertJavaStringToUTF16(jprimary_button_text);
+}
+
+void MessageWrapper::SetPrimaryButtonText(
+ const base::string16& primary_button_text) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jprimary_button_text =
+ base::android::ConvertUTF16ToJavaString(env, primary_button_text);
+ Java_MessageWrapper_setPrimaryButtonText(env, java_message_wrapper_,
+ jprimary_button_text);
+}
+
+base::string16 MessageWrapper::GetSecondaryActionText() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jsecondary_action_text =
+ Java_MessageWrapper_getSecondaryActionText(env, java_message_wrapper_);
+ return jsecondary_action_text.is_null()
+ ? base::string16()
+ : base::android::ConvertJavaStringToUTF16(jsecondary_action_text);
+}
+
+void MessageWrapper::SetSecondaryActionText(
+ const base::string16& secondary_action_text) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> jsecondary_action_text =
+ base::android::ConvertUTF16ToJavaString(env, secondary_action_text);
+ Java_MessageWrapper_setSecondaryActionText(env, java_message_wrapper_,
+ jsecondary_action_text);
+}
+
+int MessageWrapper::GetIconResourceId() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_MessageWrapper_getIconResourceId(env, java_message_wrapper_);
+}
+
+void MessageWrapper::SetIconResourceId(int resource_id) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_MessageWrapper_setIconResourceId(env, java_message_wrapper_,
+ resource_id);
+}
+
+int MessageWrapper::GetSecondaryIconResourceId() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_MessageWrapper_getSecondaryIconResourceId(env,
+ java_message_wrapper_);
+}
+
+void MessageWrapper::SetSecondaryIconResourceId(int resource_id) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_MessageWrapper_setSecondaryIconResourceId(env, java_message_wrapper_,
+ resource_id);
+}
+
+void MessageWrapper::SetSecondaryActionCallback(base::OnceClosure callback) {
+ secondary_action_callback_ = std::move(callback);
+}
+
+void MessageWrapper::HandleActionClick(JNIEnv* env) {
+ if (!action_callback_.is_null())
+ std::move(action_callback_).Run();
+}
+
+void MessageWrapper::HandleSecondaryActionClick(JNIEnv* env) {
+ if (!secondary_action_callback_.is_null())
+ std::move(secondary_action_callback_).Run();
+}
+
+void MessageWrapper::HandleDismissCallback(JNIEnv* env) {
+ // Make sure message dismissed callback is called exactly once.
+ CHECK(!message_dismissed_);
+ message_dismissed_ = true;
+ Java_MessageWrapper_clearNativePtr(env, java_message_wrapper_);
+ if (!dismiss_callback_.is_null())
+ std::move(dismiss_callback_).Run();
+ // Dismiss callback typically deletes the instance of MessageWrapper,
+ // invalidating |this| pointer. Don't call any methods after dismiss_callback_
+ // is invoked.
+}
+
+const base::android::JavaRef<jobject>& MessageWrapper::GetJavaMessageWrapper()
+ const {
+ return java_message_wrapper_;
+}
+
+} // namespace messages \ No newline at end of file
diff --git a/chromium/components/messages/android/message_wrapper.h b/chromium/components/messages/android/message_wrapper.h
new file mode 100644
index 00000000000..a9e02466ed2
--- /dev/null
+++ b/chromium/components/messages/android/message_wrapper.h
@@ -0,0 +1,71 @@
+// Copyright 2020 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_MESSAGES_ANDROID_MESSAGE_WRAPPER_H_
+#define COMPONENTS_MESSAGES_ANDROID_MESSAGE_WRAPPER_H_
+
+#include <jni.h>
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/strings/string16.h"
+
+namespace messages {
+
+// |MessagesWrapper| represents a message for native feature code. It accepts
+// callbacks for action and dismiss events and provides methods for setting
+// message properties. After setting message's properties feature code can
+// enqueue the message through |MessageDispatcherBridge|.
+class MessageWrapper {
+ public:
+ MessageWrapper(base::OnceClosure action_callback,
+ base::OnceClosure dismiss_callback);
+ ~MessageWrapper();
+
+ MessageWrapper(const MessageWrapper&) = delete;
+ MessageWrapper& operator=(const MessageWrapper&) = delete;
+
+ // Methods to manipulate message properties. On Android the values are
+ // propagated to Java and stored in |PropertyModel|.
+ // TODO(pavely): Reevaluate if propagating values to Java immediately is
+ // really necessary. Alternatively we could collect all the values in native
+ // and pass them to Java when enqueueing the message.
+ base::string16 GetTitle();
+ void SetTitle(const base::string16& title);
+ base::string16 GetDescription();
+ void SetDescription(const base::string16& description);
+ base::string16 GetPrimaryButtonText();
+ void SetPrimaryButtonText(const base::string16& primary_button_text);
+ base::string16 GetSecondaryActionText();
+ void SetSecondaryActionText(const base::string16& secondary_action_text);
+
+ // When setting a message icon use ResourceMapper::MapToJavaDrawableId to
+ // translate from chromium resource_id to Android drawable resource_id.
+ int GetIconResourceId();
+ void SetIconResourceId(int resource_id);
+ int GetSecondaryIconResourceId();
+ void SetSecondaryIconResourceId(int resource_id);
+
+ void SetSecondaryActionCallback(base::OnceClosure callback);
+
+ // Following methods forward calls from java to provided callbacks.
+ void HandleActionClick(JNIEnv* env);
+ void HandleSecondaryActionClick(JNIEnv* env);
+ void HandleDismissCallback(JNIEnv* env);
+
+ const base::android::JavaRef<jobject>& GetJavaMessageWrapper() const;
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> java_message_wrapper_;
+ base::OnceClosure action_callback_;
+ base::OnceClosure secondary_action_callback_;
+ base::OnceClosure dismiss_callback_;
+ bool message_dismissed_;
+};
+
+} // namespace messages
+
+#endif // COMPONENTS_MESSAGES_ANDROID_MESSAGE_WRAPPER_H_ \ No newline at end of file
diff --git a/chromium/components/messages/android/messages_feature.cc b/chromium/components/messages/android/messages_feature.cc
index 7dfcb8e2010..a6e946a1733 100644
--- a/chromium/components/messages/android/messages_feature.cc
+++ b/chromium/components/messages/android/messages_feature.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "components/messages/android/messages_feature.h"
+#include "components/messages/android/message_utils_bridge.h"
namespace messages {
@@ -14,7 +15,8 @@ const base::Feature kMessagesForAndroidPasswords{
bool IsPasswordMessagesUiEnabled() {
return base::FeatureList::IsEnabled(kMessagesForAndroidInfrastructure) &&
- base::FeatureList::IsEnabled(kMessagesForAndroidPasswords);
+ base::FeatureList::IsEnabled(kMessagesForAndroidPasswords) &&
+ !messages::MessageUtilsBridge::IsA11yEnabled();
}
} // namespace messages
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 956176ed571..cbc77b40788 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -8,22 +8,6 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-static_library("demographic_metrics_provider") {
- sources = [
- "demographic_metrics_provider.cc",
- "demographic_metrics_provider.h",
- ]
-
- public_deps = [ "//third_party/metrics_proto" ]
-
- deps = [
- ":metrics",
- "//base",
- "//components/sync/base",
- "//components/sync/driver",
- ]
-}
-
static_library("metrics") {
sources = [
"android_metrics_provider.cc",
@@ -397,26 +381,6 @@ static_library("test_support") {
deps = [ "//base" ]
}
-static_library("demographics_test_support") {
- testonly = true
- sources = [
- "test/demographic_metrics_test_utils.cc",
- "test/demographic_metrics_test_utils.h",
- ]
-
- deps = [
- ":metrics",
- "//base",
- "//components/network_time",
- "//components/prefs",
- "//components/sync",
- "//components/sync/base",
- "//components/sync/test/fake_server",
- "//third_party/metrics_proto",
- "//third_party/zlib/google:compression_utils",
- ]
-}
-
if (is_linux || is_chromeos) {
static_library("serialization") {
sources = [
@@ -442,7 +406,6 @@ source_set("unit_tests") {
"daily_event_unittest.cc",
"data_use_tracker_unittest.cc",
"date_changed_helper_unittest.cc",
- "demographic_metrics_provider_unittest.cc",
"drive_metrics_provider_unittest.cc",
"entropy_state_provider_unittest.cc",
"entropy_state_unittest.cc",
@@ -474,7 +437,6 @@ source_set("unit_tests") {
deps = [
":call_stack_profile_builder",
":component_metrics",
- ":demographic_metrics_provider",
":library_support",
":metrics",
":net",
@@ -545,6 +507,7 @@ test("metrics_unittests") {
sources = [ "//components/test/run_all_unittests.cc" ]
deps = [
":unit_tests",
+ "//components/metrics/demographics:unit_tests",
"//components/test:test_support",
]
}
diff --git a/chromium/components/metrics/DEPS b/chromium/components/metrics/DEPS
index 2793e4217f4..cc84be49559 100644
--- a/chromium/components/metrics/DEPS
+++ b/chromium/components/metrics/DEPS
@@ -4,11 +4,8 @@ include_rules = [
"-components",
"+components/browser_watcher",
"+components/component_updater",
- "+components/compression",
"+components/metrics",
- "+components/network_time",
"+components/prefs",
- "+components/sync",
"+components/variations",
"+components/version_info",
"+content/public/test",
diff --git a/chromium/components/metrics/call_stack_profile_builder_unittest.cc b/chromium/components/metrics/call_stack_profile_builder_unittest.cc
index 752fc567c38..f3b5578c93a 100644
--- a/chromium/components/metrics/call_stack_profile_builder_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_builder_unittest.cc
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "base/profiler/module_cache.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/time/time.h"
#include "build/build_config.h"
diff --git a/chromium/components/metrics/call_stack_profile_encoding.cc b/chromium/components/metrics/call_stack_profile_encoding.cc
index 72811b7576d..d10052a02ed 100644
--- a/chromium/components/metrics/call_stack_profile_encoding.cc
+++ b/chromium/components/metrics/call_stack_profile_encoding.cc
@@ -27,8 +27,6 @@ Process ToExecutionContextProcess(CallStackProfileParams::Process process) {
return SANDBOX_HELPER_PROCESS;
case CallStackProfileParams::PPAPI_PLUGIN_PROCESS:
return PPAPI_PLUGIN_PROCESS;
- case CallStackProfileParams::PPAPI_BROKER_PROCESS:
- return PPAPI_BROKER_PROCESS;
}
NOTREACHED();
return UNKNOWN_PROCESS;
diff --git a/chromium/components/metrics/call_stack_profile_params.h b/chromium/components/metrics/call_stack_profile_params.h
index 5be7a145c44..7fc8f61711f 100644
--- a/chromium/components/metrics/call_stack_profile_params.h
+++ b/chromium/components/metrics/call_stack_profile_params.h
@@ -21,7 +21,6 @@ struct CallStackProfileParams {
ZYGOTE_PROCESS,
SANDBOX_HELPER_PROCESS,
PPAPI_PLUGIN_PROCESS,
- PPAPI_BROKER_PROCESS,
NETWORK_SERVICE_PROCESS,
MAX_PROCESS = NETWORK_SERVICE_PROCESS,
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider.cc b/chromium/components/metrics/content/content_stability_metrics_provider.cc
index 9a3deef8afe..e4aa390d2f5 100644
--- a/chromium/components/metrics/content/content_stability_metrics_provider.cc
+++ b/chromium/components/metrics/content/content_stability_metrics_provider.cc
@@ -28,12 +28,7 @@ namespace metrics {
ContentStabilityMetricsProvider::ContentStabilityMetricsProvider(
PrefService* local_state,
std::unique_ptr<ExtensionsHelper> extensions_helper)
- :
-#if defined(OS_ANDROID)
- scoped_observer_(this),
-#endif // defined(OS_ANDROID)
- helper_(local_state),
- extensions_helper_(std::move(extensions_helper)) {
+ : helper_(local_state), extensions_helper_(std::move(extensions_helper)) {
BrowserChildProcessObserver::Add(this);
registrar_.Add(this, content::NOTIFICATION_LOAD_START,
@@ -48,7 +43,7 @@ ContentStabilityMetricsProvider::ContentStabilityMetricsProvider(
#if defined(OS_ANDROID)
auto* crash_manager = crash_reporter::CrashMetricsReporter::GetInstance();
DCHECK(crash_manager);
- scoped_observer_.Add(crash_manager);
+ scoped_observation_.Observe(crash_manager);
#endif // defined(OS_ANDROID)
}
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider.h b/chromium/components/metrics/content/content_stability_metrics_provider.h
index b2b26fe8545..3710e37e5a5 100644
--- a/chromium/components/metrics/content/content_stability_metrics_provider.h
+++ b/chromium/components/metrics/content/content_stability_metrics_provider.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/gtest_prod_util.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/stability_metrics_helper.h"
@@ -84,9 +84,9 @@ class ContentStabilityMetricsProvider
const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet&
reported_counts) override;
- ScopedObserver<crash_reporter::CrashMetricsReporter,
- crash_reporter::CrashMetricsReporter::Observer>
- scoped_observer_;
+ base::ScopedObservation<crash_reporter::CrashMetricsReporter,
+ crash_reporter::CrashMetricsReporter::Observer>
+ scoped_observation_{this};
#endif // defined(OS_ANDROID)
StabilityMetricsHelper helper_;
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider.cc b/chromium/components/metrics/content/subprocess_metrics_provider.cc
index 0692a186b23..765582051a6 100644
--- a/chromium/components/metrics/content/subprocess_metrics_provider.cc
+++ b/chromium/components/metrics/content/subprocess_metrics_provider.cc
@@ -162,8 +162,8 @@ void SubprocessMetricsProvider::OnRenderProcessHostCreated(
content::RenderProcessHost* host) {
// Sometimes, the same host will cause multiple notifications in tests so
// could possibly do the same in a release build.
- if (!scoped_observer_.IsObserving(host))
- scoped_observer_.Add(host);
+ if (!scoped_observations_.IsObservingSource(host))
+ scoped_observations_.AddObservation(host);
}
void SubprocessMetricsProvider::RenderProcessReady(
@@ -198,7 +198,7 @@ void SubprocessMetricsProvider::RenderProcessHostDestroyed(
// destruction of the host. If both get called, no harm is done.
DeregisterSubprocessAllocator(host->GetID());
- scoped_observer_.Remove(host);
+ scoped_observations_.RemoveObservation(host);
}
// static
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider.h b/chromium/components/metrics/content/subprocess_metrics_provider.h
index 4ee89b4516f..14e51b0e9a4 100644
--- a/chromium/components/metrics/content/subprocess_metrics_provider.h
+++ b/chromium/components/metrics/content/subprocess_metrics_provider.h
@@ -12,7 +12,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/statistics_recorder.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "base/threading/thread_checker.h"
#include "components/metrics/metrics_provider.h"
#include "content/public/browser/browser_child_process_observer.h"
@@ -109,8 +109,9 @@ class SubprocessMetricsProvider
AllocatorByIdMap allocators_by_id_;
// Track all observed render processes to un-observe them on exit.
- ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
- scoped_observer_{this};
+ base::ScopedMultiSourceObservation<content::RenderProcessHost,
+ content::RenderProcessHostObserver>
+ scoped_observations_{this};
base::WeakPtrFactory<SubprocessMetricsProvider> weak_ptr_factory_{this};
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider_browsertest.cc b/chromium/components/metrics/content/subprocess_metrics_provider_browsertest.cc
index c8f315bafe9..df52b0bc7d0 100644
--- a/chromium/components/metrics/content/subprocess_metrics_provider_browsertest.cc
+++ b/chromium/components/metrics/content/subprocess_metrics_provider_browsertest.cc
@@ -66,10 +66,10 @@ class SubprocessMetricsProviderBrowserTest
return provider_->allocators_by_id_;
}
- ScopedObserver<content::RenderProcessHost,
- content::RenderProcessHostObserver>&
- get_scoped_observer() {
- return provider_->scoped_observer_;
+ base::ScopedMultiSourceObservation<content::RenderProcessHost,
+ content::RenderProcessHostObserver>&
+ get_scoped_observations() {
+ return provider_->scoped_observations_;
}
base::PersistentHistogramAllocator* GetMainFrameAllocator() {
@@ -114,7 +114,7 @@ IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
RegisterExistingNotReadyRenderProcesses) {
ASSERT_TRUE(GetRenderProcessHostCount() > 0);
CreateSubprocessMetricsProvider();
- EXPECT_EQ(get_scoped_observer().GetSourcesCount(),
+ EXPECT_EQ(get_scoped_observations().GetSourcesCount(),
GetRenderProcessHostCount());
EXPECT_EQ(get_allocators_by_id().size(), 0u);
@@ -123,7 +123,7 @@ IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
// Verify that the number of scoped observer matches the number of
// RenderProcessHost and the main frame allocator exists.
- EXPECT_EQ(get_scoped_observer().GetSourcesCount(),
+ EXPECT_EQ(get_scoped_observations().GetSourcesCount(),
GetRenderProcessHostCount());
auto* main_frame_allocator = GetMainFrameAllocator();
EXPECT_TRUE(main_frame_allocator);
@@ -156,7 +156,8 @@ IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
shell()->web_contents()->GetMainFrame()->GetProcess();
SimulateRenderProcessHostDestroyed();
// Verify the observer removed.
- EXPECT_FALSE(get_scoped_observer().IsObserving(main_frame_process_host));
+ EXPECT_FALSE(
+ get_scoped_observations().IsObservingSource(main_frame_process_host));
}
IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
@@ -169,7 +170,7 @@ IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
// Verify that the number of scoped observer matches the number of
// RenderProcessHost and the main frame allocator exists.
- EXPECT_EQ(get_scoped_observer().GetSourcesCount(),
+ EXPECT_EQ(get_scoped_observations().GetSourcesCount(),
GetRenderProcessHostCount());
auto* main_frame_allocator = GetMainFrameAllocator();
EXPECT_TRUE(main_frame_allocator);
@@ -202,7 +203,8 @@ IN_PROC_BROWSER_TEST_F(SubprocessMetricsProviderBrowserTest,
shell()->web_contents()->GetMainFrame()->GetProcess();
SimulateRenderProcessHostDestroyed();
// Verify the observer removed.
- EXPECT_FALSE(get_scoped_observer().IsObserving(main_frame_process_host));
+ EXPECT_FALSE(
+ get_scoped_observations().IsObservingSource(main_frame_process_host));
}
} // namespace metrics
diff --git a/chromium/components/metrics/demographic_metrics_provider_unittest.cc b/chromium/components/metrics/demographic_metrics_provider_unittest.cc
deleted file mode 100644
index 101c77e8995..00000000000
--- a/chromium/components/metrics/demographic_metrics_provider_unittest.cc
+++ /dev/null
@@ -1,219 +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 "components/metrics/demographic_metrics_provider.h"
-
-#include <memory>
-
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/simple_test_clock.h"
-#include "base/time/time.h"
-#include "components/metrics/metrics_log_uploader.h"
-#include "components/sync/base/sync_prefs.h"
-#include "components/sync/base/user_demographics.h"
-#include "components/sync/driver/test_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
-#include "third_party/metrics_proto/ukm/report.pb.h"
-
-namespace metrics {
-namespace {
-
-// Profile client for testing that gets fake Profile information and services.
-class TestProfileClient : public DemographicMetricsProvider::ProfileClient {
- public:
- ~TestProfileClient() override = default;
-
- TestProfileClient(std::unique_ptr<syncer::SyncService> sync_service,
- int number_of_profiles)
- : sync_service_(std::move(sync_service)),
- number_of_profiles_(number_of_profiles) {}
-
- int GetNumberOfProfilesOnDisk() override { return number_of_profiles_; }
-
- syncer::SyncService* GetSyncService() override { return sync_service_.get(); }
-
- base::Time GetNetworkTime() const override {
- base::Time time;
- auto result = base::Time::FromString("17 Jun 2019 00:00:00 UDT", &time);
- DCHECK(result);
- return time;
- }
-
- private:
- std::unique_ptr<syncer::SyncService> sync_service_;
- const int number_of_profiles_;
- base::SimpleTestClock clock_;
-
- DISALLOW_COPY_AND_ASSIGN(TestProfileClient);
-};
-
-// Make arbitrary user demographics to provide.
-syncer::UserDemographicsResult GetDemographics() {
- syncer::UserDemographics user_demographics;
- user_demographics.birth_year = 1983;
- user_demographics.gender = UserDemographicsProto::GENDER_FEMALE;
- return syncer::UserDemographicsResult::ForValue(std::move(user_demographics));
-}
-
-std::unique_ptr<TestProfileClient> MakeTestProfileClient(
- const syncer::UserDemographicsResult& user_demographics_result,
- int number_of_profiles,
- bool has_sync_service) {
- std::unique_ptr<syncer::TestSyncService> sync_service = nullptr;
- if (has_sync_service) {
- sync_service = std::make_unique<syncer::TestSyncService>();
- sync_service->SetUserDemographics(user_demographics_result);
- }
- return std::make_unique<TestProfileClient>(std::move(sync_service),
- number_of_profiles);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled) {
- base::HistogramTester histogram;
-
- // Run demographics provider.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(GetDemographics(), /*number_of_profiles=*/1,
- /*has_sync_service=*/true),
- MetricsLogUploader::MetricServiceType::UMA);
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
-
- // Verify provided demographics.
- EXPECT_EQ(GetDemographics().value().birth_year,
- uma_proto.user_demographics().birth_year());
- EXPECT_EQ(GetDemographics().value().gender,
- uma_proto.user_demographics().gender());
-
- // Verify histograms.
- histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
- syncer::UserDemographicsStatus::kSuccess, 1);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService) {
- base::HistogramTester histogram;
-
- // Run demographics provider.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(GetDemographics(),
- /*number_of_profiles=*/1,
- /*has_sync_service=*/false),
- MetricsLogUploader::MetricServiceType::UMA);
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
-
- // Expect the proto fields to be not set and left to default.
- EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
- EXPECT_FALSE(uma_proto.user_demographics().has_gender());
-
- // Verify histograms.
- histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
- syncer::UserDemographicsStatus::kNoSyncService,
- 1);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled) {
- // Disable demographics reporting feature.
- base::test::ScopedFeatureList local_feature;
- local_feature.InitAndDisableFeature(
- DemographicMetricsProvider::kDemographicMetricsReporting);
-
- base::HistogramTester histogram;
-
- // Run demographics provider.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(GetDemographics(), /*number_of_profiles=*/1,
- /*has_sync_service=*/true),
- MetricsLogUploader::MetricServiceType::UMA);
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
-
- // Expect that the UMA proto is untouched.
- EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
- EXPECT_FALSE(uma_proto.user_demographics().has_gender());
-
- // Verify that there are no histograms for user demographics.
- histogram.ExpectTotalCount("UMA.UserDemographics.Status", 0);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile) {
- base::HistogramTester histogram;
-
- // Run demographics provider with not exactly one Profile on disk.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(GetDemographics(), /*number_of_profiles=*/2,
- /*has_sync_service=*/true),
- MetricsLogUploader::MetricServiceType::UMA);
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
-
- // Expect that the UMA proto is untouched.
- EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
- EXPECT_FALSE(uma_proto.user_demographics().has_gender());
-
- // Verify histograms.
- histogram.ExpectUniqueSample(
- "UMA.UserDemographics.Status",
- syncer::UserDemographicsStatus::kMoreThanOneProfile, 1);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics) {
- base::HistogramTester histogram;
-
- // Run demographics provider with a ProfileClient that does not provide
- // demographics because of some error.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(
- syncer::UserDemographicsResult::ForStatus(
- syncer::UserDemographicsStatus::kIneligibleDemographicsData),
- /*number_of_profiles=*/1,
- /*has_sync_service=*/true),
- MetricsLogUploader::MetricServiceType::UMA);
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
-
- // Expect that the UMA proto is untouched.
- EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
- EXPECT_FALSE(uma_proto.user_demographics().has_gender());
-
- // Verify that there are no histograms for user demographics. We expect
- // histograms to be logged by the sync libraries.
- histogram.ExpectUniqueSample(
- "UMA.UserDemographics.Status",
- syncer::UserDemographicsStatus::kIneligibleDemographicsData, 1);
-}
-
-TEST(DemographicMetricsProviderTest,
- ProvideSyncedUserNoisedBirthYearAndGenderToReport) {
- base::HistogramTester histogram;
-
- // Run demographics provider.
- DemographicMetricsProvider provider(
- MakeTestProfileClient(GetDemographics(), /*number_of_profiles=*/1,
- /*has_sync_service=*/true),
- MetricsLogUploader::MetricServiceType::UKM);
- ukm::Report report;
- provider.ProvideSyncedUserNoisedBirthYearAndGenderToReport(&report);
-
- // Verify provided demographics.
- EXPECT_EQ(GetDemographics().value().birth_year,
- report.user_demographics().birth_year());
- EXPECT_EQ(GetDemographics().value().gender,
- report.user_demographics().gender());
-
- // Verify histograms.
- histogram.ExpectUniqueSample("UKM.UserDemographics.Status",
- syncer::UserDemographicsStatus::kSuccess, 1);
-}
-
-} // namespace
-} // namespace metrics
diff --git a/chromium/components/metrics/demographics/BUILD.gn b/chromium/components/metrics/demographics/BUILD.gn
new file mode 100644
index 00000000000..270e31f5114
--- /dev/null
+++ b/chromium/components/metrics/demographics/BUILD.gn
@@ -0,0 +1,67 @@
+# Copyright 2020 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("//testing/test.gni")
+
+static_library("demographics") {
+ sources = [
+ "demographic_metrics_provider.cc",
+ "demographic_metrics_provider.h",
+ "user_demographics.cc",
+ "user_demographics.h",
+ ]
+
+ public_deps = [ "//third_party/metrics_proto" ]
+
+ deps = [
+ "//base",
+ "//components/metrics",
+ "//components/pref_registry",
+ "//components/prefs",
+ "//components/sync/base",
+ "//components/sync/driver",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "demographic_metrics_provider_unittest.cc",
+ "user_demographics_unittest.cc",
+ ]
+ deps = [
+ ":demographics",
+ "//base",
+ "//base/test:test_support",
+ "//components/metrics",
+ "//components/sync/base",
+ "//components/sync/driver",
+ "//components/sync/driver:test_support",
+ "//components/sync_preferences:test_support",
+ "//google_apis",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/metrics_proto",
+ ]
+}
+
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "demographic_metrics_test_utils.cc",
+ "demographic_metrics_test_utils.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/metrics",
+ "//components/metrics/demographics",
+ "//components/network_time",
+ "//components/prefs",
+ "//components/sync",
+ "//components/sync/test/fake_server",
+ "//third_party/metrics_proto",
+ "//third_party/zlib/google:compression_utils",
+ ]
+}
diff --git a/chromium/components/metrics/demographics/DEPS b/chromium/components/metrics/demographics/DEPS
new file mode 100644
index 00000000000..0a460787141
--- /dev/null
+++ b/chromium/components/metrics/demographics/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ "+components/network_time",
+ "+components/pref_registry",
+ "+components/prefs",
+ "+components/sync",
+ "+components/sync_preferences",
+ "+google_apis",
+]
diff --git a/chromium/components/metrics/demographic_metrics_provider.cc b/chromium/components/metrics/demographics/demographic_metrics_provider.cc
index 126080d9af9..763a78704fa 100644
--- a/chromium/components/metrics/demographic_metrics_provider.cc
+++ b/chromium/components/metrics/demographics/demographic_metrics_provider.cc
@@ -2,17 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/metrics/demographic_metrics_provider.h"
+#include "components/metrics/demographics/demographic_metrics_provider.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/optional.h"
-#include "components/sync/base/sync_prefs.h"
-#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_service_utils.h"
#include "third_party/metrics_proto/ukm/report.pb.h"
namespace metrics {
+namespace {
+
+bool CanUploadDemographicsToGoogle(syncer::SyncService* sync_service) {
+ DCHECK(sync_service);
+
+ // Require that the user has opted into sync the feature, without just relying
+ // on PRIORITY_PREFERENCES start sync-ing.
+ if (!sync_service->IsSyncFeatureEnabled()) {
+ return false;
+ }
+
+ switch (GetUploadToGoogleState(sync_service, syncer::PRIORITY_PREFERENCES)) {
+ case syncer::UploadState::NOT_ACTIVE:
+ return false;
+ case syncer::UploadState::INITIALIZING:
+ // Note that INITIALIZING is considered good enough, because sync is known
+ // to be enabled, and transient errors don't really matter here.
+ case syncer::UploadState::ACTIVE:
+ return true;
+ }
+}
+
+} // namespace
+
// static
const base::Feature DemographicMetricsProvider::kDemographicMetricsReporting = {
"DemographicMetricsReporting", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -27,7 +50,7 @@ DemographicMetricsProvider::DemographicMetricsProvider(
DemographicMetricsProvider::~DemographicMetricsProvider() {}
-base::Optional<syncer::UserDemographics>
+base::Optional<UserDemographics>
DemographicMetricsProvider::ProvideSyncedUserNoisedBirthYearAndGender() {
// Skip if feature disabled.
if (!base::FeatureList::IsEnabled(kDemographicMetricsReporting))
@@ -38,7 +61,7 @@ DemographicMetricsProvider::ProvideSyncedUserNoisedBirthYearAndGender() {
// cannot determine if there is more than 1 distinct user using the Profile.
if (profile_client_->GetNumberOfProfilesOnDisk() != 1) {
LogUserDemographicsStatusInHistogram(
- syncer::UserDemographicsStatus::kMoreThanOneProfile);
+ UserDemographicsStatus::kMoreThanOneProfile);
return base::nullopt;
}
@@ -46,13 +69,19 @@ DemographicMetricsProvider::ProvideSyncedUserNoisedBirthYearAndGender() {
// Skip if no sync service.
if (!sync_service) {
LogUserDemographicsStatusInHistogram(
- syncer::UserDemographicsStatus::kNoSyncService);
+ UserDemographicsStatus::kNoSyncService);
+ return base::nullopt;
+ }
+
+ if (!CanUploadDemographicsToGoogle(sync_service)) {
+ LogUserDemographicsStatusInHistogram(
+ UserDemographicsStatus::kSyncNotEnabled);
return base::nullopt;
}
- syncer::UserDemographicsResult demographics_result =
- sync_service->GetUserNoisedBirthYearAndGender(
- profile_client_->GetNetworkTime());
+ UserDemographicsResult demographics_result =
+ GetUserNoisedBirthYearAndGenderFromPrefs(
+ profile_client_->GetNetworkTime(), profile_client_->GetPrefService());
LogUserDemographicsStatusInHistogram(demographics_result.status());
if (demographics_result.IsSuccess())
@@ -72,7 +101,7 @@ void DemographicMetricsProvider::
}
void DemographicMetricsProvider::LogUserDemographicsStatusInHistogram(
- syncer::UserDemographicsStatus status) {
+ UserDemographicsStatus status) {
switch (metrics_service_type_) {
case MetricsLogUploader::MetricServiceType::UMA:
base::UmaHistogramEnumeration("UMA.UserDemographics.Status", status);
diff --git a/chromium/components/metrics/demographic_metrics_provider.h b/chromium/components/metrics/demographics/demographic_metrics_provider.h
index 0091122f692..b52b05b3628 100644
--- a/chromium/components/metrics/demographic_metrics_provider.h
+++ b/chromium/components/metrics/demographics/demographic_metrics_provider.h
@@ -2,20 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_METRICS_DEMOGRAPHIC_METRICS_PROVIDER_H_
-#define COMPONENTS_METRICS_DEMOGRAPHIC_METRICS_PROVIDER_H_
+#ifndef COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_PROVIDER_H_
#include <memory>
#include "base/time/time.h"
+#include "components/metrics/demographics/user_demographics.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/ukm_demographic_metrics_provider.h"
-#include "components/sync/base/user_demographics.h"
#include "components/sync/driver/sync_service.h"
#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
#include "third_party/metrics_proto/user_demographics.pb.h"
+class PrefService;
+
namespace base {
struct Feature;
}
@@ -42,9 +44,14 @@ class DemographicMetricsProvider : public MetricsProvider,
// for the browser.
virtual int GetNumberOfProfilesOnDisk() = 0;
- // Gets a weak pointer to the ProfileSyncService of the Profile.
+ // Gets a pointer to the SyncService of the profile, which is required to
+ // determine whether priority preferences carrying demographics information
+ // is being synced.
virtual syncer::SyncService* GetSyncService() = 0;
+ // Gets a pointer to the PrefService of the profile.
+ virtual PrefService* GetPrefService() = 0;
+
// Gets the network time that represents now.
virtual base::Time GetNetworkTime() const = 0;
};
@@ -63,7 +70,7 @@ class DemographicMetricsProvider : public MetricsProvider,
void ProvideSyncedUserNoisedBirthYearAndGender(ReportType* report) {
DCHECK(report);
- base::Optional<syncer::UserDemographics> user_demographics =
+ base::Optional<UserDemographics> user_demographics =
ProvideSyncedUserNoisedBirthYearAndGender();
if (user_demographics.has_value()) {
report->mutable_user_demographics()->set_birth_year(
@@ -84,15 +91,11 @@ class DemographicMetricsProvider : public MetricsProvider,
// Feature switch to report user's noised birth year and gender.
static const base::Feature kDemographicMetricsReporting;
- protected:
- // Provides the synced user's noised birth year and gender. Virtual for
- // testing.
- virtual base::Optional<syncer::UserDemographics>
- ProvideSyncedUserNoisedBirthYearAndGender();
-
private:
- void LogUserDemographicsStatusInHistogram(
- syncer::UserDemographicsStatus status);
+ // Provides the synced user's noised birth year and gender.
+ base::Optional<UserDemographics> ProvideSyncedUserNoisedBirthYearAndGender();
+
+ void LogUserDemographicsStatusInHistogram(UserDemographicsStatus status);
std::unique_ptr<ProfileClient> profile_client_;
@@ -105,4 +108,4 @@ class DemographicMetricsProvider : public MetricsProvider,
} // namespace metrics
-#endif // COMPONENTS_METRICS_DEMOGRAPHIC_METRICS_PROVIDER_H_ \ No newline at end of file
+#endif // COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_PROVIDER_H_
diff --git a/chromium/components/metrics/demographics/demographic_metrics_provider_unittest.cc b/chromium/components/metrics/demographics/demographic_metrics_provider_unittest.cc
new file mode 100644
index 00000000000..87b38a62540
--- /dev/null
+++ b/chromium/components/metrics/demographics/demographic_metrics_provider_unittest.cc
@@ -0,0 +1,352 @@
+// 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 "components/metrics/demographics/demographic_metrics_provider.h"
+
+#include <memory>
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/metrics/demographics/user_demographics.h"
+#include "components/metrics/metrics_log_uploader.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/driver/test_sync_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+#include "third_party/metrics_proto/ukm/report.pb.h"
+
+namespace metrics {
+namespace {
+
+constexpr int kTestBirthYear = 1983;
+constexpr UserDemographicsProto::Gender kTestGender =
+ UserDemographicsProto::GENDER_FEMALE;
+
+enum TestSyncServiceState {
+ NULL_SYNC_SERVICE,
+ SYNC_FEATURE_NOT_ENABLED,
+ SYNC_FEATURE_ENABLED,
+ SYNC_FEATURE_ENABLED_BUT_PAUSED,
+ SYNC_FEATURE_TEMPORARILY_DISABLED,
+};
+
+// Profile client for testing that gets fake Profile information and services.
+class TestProfileClient : public DemographicMetricsProvider::ProfileClient {
+ public:
+ ~TestProfileClient() override = default;
+
+ TestProfileClient(int number_of_profiles,
+ TestSyncServiceState sync_service_state)
+ : number_of_profiles_(number_of_profiles) {
+ RegisterDemographicsProfilePrefs(pref_service_.registry());
+
+ switch (sync_service_state) {
+ case NULL_SYNC_SERVICE:
+ break;
+
+ case SYNC_FEATURE_NOT_ENABLED:
+ sync_service_ = std::make_unique<syncer::TestSyncService>();
+ // Mimic sync-the-feature being disabled.
+ sync_service_->SetFirstSetupComplete(false);
+ break;
+
+ case SYNC_FEATURE_ENABLED:
+ // TestSyncService by default behaves as everything enabled/active.
+ sync_service_ = std::make_unique<syncer::TestSyncService>();
+
+ CHECK(sync_service_->GetUserSettings()->IsSyncRequested());
+ CHECK(sync_service_->GetDisableReasons().Empty());
+ CHECK_EQ(syncer::SyncService::TransportState::ACTIVE,
+ sync_service_->GetTransportState());
+ break;
+
+ case SYNC_FEATURE_ENABLED_BUT_PAUSED:
+ sync_service_ = std::make_unique<syncer::TestSyncService>();
+ // Mimic the user signing out from content are (sync paused).
+ sync_service_->SetAuthError(
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT));
+ sync_service_->SetTransportState(
+ syncer::SyncService::TransportState::PAUSED);
+
+ CHECK(sync_service_->GetUserSettings()->IsSyncRequested());
+ CHECK(sync_service_->GetDisableReasons().Empty());
+ CHECK_EQ(syncer::SyncService::TransportState::PAUSED,
+ sync_service_->GetTransportState());
+ break;
+
+ case SYNC_FEATURE_TEMPORARILY_DISABLED:
+ sync_service_ = std::make_unique<syncer::TestSyncService>();
+ // Temporarily disable sync without turning it off.
+ sync_service_->GetUserSettings()->SetSyncRequested(false);
+
+ CHECK(!sync_service_->GetUserSettings()->IsSyncRequested());
+ CHECK(syncer::SyncService::DisableReasonSet(
+ syncer::SyncService::DISABLE_REASON_USER_CHOICE) ==
+ sync_service_->GetDisableReasons());
+ break;
+ }
+ }
+
+ int GetNumberOfProfilesOnDisk() override { return number_of_profiles_; }
+
+ syncer::SyncService* GetSyncService() override { return sync_service_.get(); }
+
+ PrefService* GetPrefService() override { return &pref_service_; }
+
+ base::Time GetNetworkTime() const override {
+ base::Time time;
+ auto result = base::Time::FromString("17 Jun 2019 00:00:00 UDT", &time);
+ DCHECK(result);
+ return time;
+ }
+
+ void SetDemographicsInPrefs(int birth_year,
+ metrics::UserDemographicsProto_Gender gender) {
+ base::DictionaryValue dict;
+ dict.SetIntPath(kSyncDemographicsBirthYearPath, birth_year);
+ dict.SetIntPath(kSyncDemographicsGenderPath, static_cast<int>(gender));
+ pref_service_.Set(kSyncDemographicsPrefName, dict);
+ }
+
+ private:
+ sync_preferences::TestingPrefServiceSyncable pref_service_;
+ std::unique_ptr<syncer::TestSyncService> sync_service_;
+ const int number_of_profiles_;
+ base::SimpleTestClock clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestProfileClient);
+};
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ SYNC_FEATURE_ENABLED);
+ client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
+
+ // Set birth year noise offset to not have it randomized.
+ const int kBirthYearOffset = 3;
+ client->GetPrefService()->SetInteger(kSyncDemographicsBirthYearOffsetPrefName,
+ kBirthYearOffset);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Verify provided demographics.
+ EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
+ uma_proto.user_demographics().birth_year());
+ EXPECT_EQ(kTestGender, uma_proto.user_demographics().gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kSuccess, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ NULL_SYNC_SERVICE);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect the proto fields to be not set and left to default.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kNoSyncService, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_SyncEnabledButPaused) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(
+ /*number_of_profiles=*/1, SYNC_FEATURE_ENABLED_BUT_PAUSED);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect the proto fields to be not set and left to default.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kSyncNotEnabled, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_SyncTemporarilyDisabled) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(
+ /*number_of_profiles=*/1, SYNC_FEATURE_TEMPORARILY_DISABLED);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect the proto fields to be not set and left to default.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kSyncNotEnabled, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_SyncNotEnabled) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ SYNC_FEATURE_NOT_ENABLED);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect the proto fields to be not set and left to default.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kSyncNotEnabled, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled) {
+ // Disable demographics reporting feature.
+ base::test::ScopedFeatureList local_feature;
+ local_feature.InitAndDisableFeature(
+ DemographicMetricsProvider::kDemographicMetricsReporting);
+
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ SYNC_FEATURE_ENABLED);
+ client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect that the UMA proto is untouched.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify that there are no histograms for user demographics.
+ histogram.ExpectTotalCount("UMA.UserDemographics.Status", 0);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/2,
+ SYNC_FEATURE_ENABLED);
+ client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
+
+ // Run demographics provider with not exactly one Profile on disk.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect that the UMA proto is untouched.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
+ UserDemographicsStatus::kMoreThanOneProfile, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ SYNC_FEATURE_ENABLED);
+ // Set some ineligible values to prefs.
+ client->SetDemographicsInPrefs(/*birth_year=*/-17,
+ UserDemographicsProto::GENDER_UNKNOWN);
+
+ // Run demographics provider with a ProfileClient that does not provide
+ // demographics because of some error.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UMA);
+ ChromeUserMetricsExtension uma_proto;
+ provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
+
+ // Expect that the UMA proto is untouched.
+ EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
+ EXPECT_FALSE(uma_proto.user_demographics().has_gender());
+
+ // Verify that there are no histograms for user demographics.
+ histogram.ExpectUniqueSample(
+ "UMA.UserDemographics.Status",
+ UserDemographicsStatus::kIneligibleDemographicsData, 1);
+}
+
+TEST(DemographicMetricsProviderTest,
+ ProvideSyncedUserNoisedBirthYearAndGenderToUkmReport) {
+ base::HistogramTester histogram;
+
+ auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
+ SYNC_FEATURE_ENABLED);
+ client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
+
+ // Set birth year noise offset to not have it randomized.
+ const int kBirthYearOffset = 3;
+ client->GetPrefService()->SetInteger(kSyncDemographicsBirthYearOffsetPrefName,
+ kBirthYearOffset);
+
+ // Run demographics provider.
+ DemographicMetricsProvider provider(
+ std::move(client), MetricsLogUploader::MetricServiceType::UKM);
+ ukm::Report report;
+ provider.ProvideSyncedUserNoisedBirthYearAndGenderToReport(&report);
+
+ // Verify provided demographics.
+ EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
+ report.user_demographics().birth_year());
+ EXPECT_EQ(kTestGender, report.user_demographics().gender());
+
+ // Verify histograms.
+ histogram.ExpectUniqueSample("UKM.UserDemographics.Status",
+ UserDemographicsStatus::kSuccess, 1);
+}
+
+} // namespace
+} // namespace metrics
diff --git a/chromium/components/metrics/demographics/demographic_metrics_test_utils.cc b/chromium/components/metrics/demographics/demographic_metrics_test_utils.cc
new file mode 100644
index 00000000000..594399ef655
--- /dev/null
+++ b/chromium/components/metrics/demographics/demographic_metrics_test_utils.cc
@@ -0,0 +1,106 @@
+// 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 "components/metrics/demographics/demographic_metrics_test_utils.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/time/default_clock.h"
+#include "base/time/default_tick_clock.h"
+#include "components/metrics/demographics/user_demographics.h"
+#include "components/metrics/log_decoder.h"
+#include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+
+namespace metrics {
+namespace test {
+
+void AddUserBirthYearAndGenderToSyncServer(
+ base::WeakPtr<fake_server::FakeServer> fake_server,
+ int birth_year,
+ UserDemographicsProto::Gender gender) {
+ sync_pb::EntitySpecifics specifics;
+ specifics.mutable_priority_preference()->mutable_preference()->set_name(
+ kSyncDemographicsPrefName);
+ specifics.mutable_priority_preference()->mutable_preference()->set_value(
+ base::StringPrintf("{\"birth_year\":%d,\"gender\":%d}", birth_year,
+ static_cast<int>(gender)));
+ fake_server->InjectEntity(
+ syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
+ /*non_unique_name=*/kSyncDemographicsPrefName,
+ /*client_tag=*/specifics.preference().name(), specifics,
+ /*creation_time=*/0,
+ /*last_modified_time=*/0));
+}
+
+void UpdateNetworkTime(const base::Time& now,
+ network_time::NetworkTimeTracker* time_tracker) {
+ // Simulate the latency in the network to get the network time from the remote
+ // server.
+ constexpr base::TimeDelta kLatency = base::TimeDelta::FromMilliseconds(10);
+
+ // Simulate the time taken to call UpdateNetworkTime() since the moment the
+ // callback was created. When not testing with the fake sync server, the
+ // callback is called when doing an HTTP request to the sync server.
+ constexpr base::TimeDelta kCallbackDelay =
+ base::TimeDelta::FromMilliseconds(10);
+
+ // Simulate a network time that is a bit earlier than the now time.
+ base::Time network_time = now - kCallbackDelay - kLatency;
+
+ // Simulate the time in ticks at the moment the UpdateNetworkTime callback
+ // function is created, which time should be at least 1 millisecond behind the
+ // moment the callback is run to pass the DCHECK.
+ base::TimeTicks post_time = base::TimeTicks::Now() - kCallbackDelay;
+
+ time_tracker->UpdateNetworkTime(
+ network_time, /*resolution=*/base::TimeDelta::FromMilliseconds(1),
+ kLatency, post_time);
+}
+
+int GetMaximumEligibleBirthYear(const base::Time& now) {
+ constexpr int kEligibleAge = kUserDemographicsMinAgeInYears +
+ kUserDemographicsBirthYearNoiseOffsetRange;
+
+ base::Time::Exploded exploded_time;
+ now.UTCExplode(&exploded_time);
+
+ // Return the maximum birth year that is eligible for reporting the user's
+ // birth year and gender. The -1 year is the extra buffer that Sync uses to
+ // make sure that the user is at least 20 years old because the user gives
+ // only the year of their birth date. E.g., if today's date is 05 Jan 2020
+ // and the user was born 05 Mar 2000, the user's age would be computed as 20
+ // years old using the year resolution, but the user is in fact 19.
+ return exploded_time.year - kEligibleAge - 1;
+}
+
+int GetNoisedBirthYear(const PrefService& pref_service, int raw_birth_year) {
+ int birth_year_offset =
+ pref_service.GetInteger(kSyncDemographicsBirthYearOffsetPrefName);
+ return birth_year_offset + raw_birth_year;
+}
+
+void BuildAndStoreLog(MetricsService* metrics_service) {
+ metrics_service->StageCurrentLogForTest();
+}
+
+bool HasUnsentLogs(MetricsService* metrics_service) {
+ return metrics_service->LogStoreForTest()->has_unsent_logs();
+}
+
+// Returns an UMA log if the MetricsService has a staged log.
+std::unique_ptr<ChromeUserMetricsExtension> GetLastUmaLog(
+ MetricsService* metrics_service) {
+ // Decompress and deserialize the staged log.
+ std::unique_ptr<ChromeUserMetricsExtension> log =
+ std::make_unique<ChromeUserMetricsExtension>();
+ if (!DecodeLogDataToProto(metrics_service->LogStoreForTest()->staged_log(),
+ log.get())) {
+ return nullptr;
+ }
+ return log;
+}
+
+} // namespace test
+} // namespace metrics
diff --git a/chromium/components/metrics/demographics/demographic_metrics_test_utils.h b/chromium/components/metrics/demographics/demographic_metrics_test_utils.h
new file mode 100644
index 00000000000..84a6576d3e9
--- /dev/null
+++ b/chromium/components/metrics/demographics/demographic_metrics_test_utils.h
@@ -0,0 +1,76 @@
+// 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 COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_TEST_UTILS_H_
+#define COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_TEST_UTILS_H_
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "components/metrics/metrics_log_store.h"
+#include "components/metrics/metrics_service.h"
+#include "components/network_time/network_time_tracker.h"
+#include "components/prefs/pref_service.h"
+#include "components/sync/test/fake_server/fake_server.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+#include "third_party/metrics_proto/user_demographics.pb.h"
+
+// Helpers to support testing the reporting of user demographic metrics in
+// browser tests.
+
+namespace metrics {
+namespace test {
+
+// Parameters for the parameterized tests.
+struct DemographicsTestParams {
+ // Enable the feature to report the user's birth year and gender.
+ bool enable_feature = false;
+ // Expectation for the user's noised birth year and gender to be reported.
+ // Having |enable_feature| set to true does not necessarily mean that
+ // |expect_reported_demographics| will be true because other conditions might
+ // stop the reporting of the user's noised birth year and gender, e.g.,
+ // sync is turned off.
+ bool expect_reported_demographics = false;
+};
+
+// Adds the User Demographic priority pref to the sync |fake_server|, which
+// contains the synced test user's raw, i.e. un-noised, |birth_year| and
+// |gender|.
+void AddUserBirthYearAndGenderToSyncServer(
+ base::WeakPtr<fake_server::FakeServer> fake_server,
+ int birth_year,
+ UserDemographicsProto::Gender gender);
+
+// Updates the network time to approximately |now|.
+void UpdateNetworkTime(const base::Time& now,
+ network_time::NetworkTimeTracker* time_tracker);
+
+// Returns the maximum eligible birth year for the given time. The returned year
+// is inclusive; i.e. years <= the returned year are eligible. In order to
+// compute the synced test user's age, the network time should have already been
+// set to |now|.
+int GetMaximumEligibleBirthYear(const base::Time& now);
+
+// Gets the noised birth year of the user, where the |raw_birth_year|
+// is the true birth year, pre-noise, and |pref_service| is the service with the
+// user's noise pref. This function should be run only after a
+// DemographicMetricsProvider has provided user demographics to a report.
+int GetNoisedBirthYear(const PrefService& pref_service, int raw_birth_year);
+
+// If data are available, creates an UMA log and stores it in the
+// MetricsService's MetricsLogStore.
+void BuildAndStoreLog(MetricsService* metrics_service);
+
+// Returns true if |metrics_service|'s log store has logs to send.
+bool HasUnsentLogs(MetricsService* metrics_service);
+
+// Returns an UMA log if the MetricsService has a staged log.
+std::unique_ptr<ChromeUserMetricsExtension> GetLastUmaLog(
+ MetricsService* metrics_service);
+
+} // namespace test
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_DEMOGRAPHICS_DEMOGRAPHIC_METRICS_TEST_UTILS_H_
diff --git a/chromium/components/metrics/demographics/user_demographics.cc b/chromium/components/metrics/demographics/user_demographics.cc
new file mode 100644
index 00000000000..6ad61d4fa62
--- /dev/null
+++ b/chromium/components/metrics/demographics/user_demographics.cc
@@ -0,0 +1,253 @@
+// 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 "components/metrics/demographics/user_demographics.h"
+
+#include <utility>
+
+#include "base/check.h"
+#include "base/optional.h"
+#include "base/rand_util.h"
+#include "base/values.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+
+namespace metrics {
+
+// Root dictionary pref to store the user's birth year and gender that are
+// provided by the sync server. This is a read-only syncable priority pref, sent
+// from the sync server to the client.
+const char kSyncDemographicsPrefName[] = "sync.demographics";
+
+// Stores a "secret" offset that is used to randomize the birth year for metrics
+// reporting. This value should not be logged to UMA directly; instead, it
+// should be summed with the kSyncDemographicsBirthYear. This value is generated
+// locally on the client the first time a user begins to merge birth year data
+// into their UMA reports. The value is synced to the user's other devices so
+// that the user consistently uses the same offset across login/logout events
+// and after clearing their other browser data.
+const char kSyncDemographicsBirthYearOffsetPrefName[] =
+ "sync.demographics_birth_year_offset";
+
+// This pref value is subordinate to the kSyncDemographics dictionary pref and
+// is synced to the client. It stores the self-reported birth year of the
+// syncing user. as provided by the sync server. This value should not be logged
+// to UMA directly; instead, it should be summed with the
+// kSyncDemographicsBirthYearNoiseOffset.
+const char kSyncDemographicsBirthYearPath[] = "birth_year";
+
+// This pref value is subordinate to the kSyncDemographics dictionary pref and
+// is synced to the client. It stores the self-reported gender of the syncing
+// user, as provided by the sync server. The gender is encoded using the Gender
+// enum defined in UserDemographicsProto
+// (see third_party/metrics_proto/user_demographics.proto).
+const char kSyncDemographicsGenderPath[] = "gender";
+
+namespace {
+
+// Gets an offset to add noise to the birth year. If not present in prefs, the
+// offset will be randomly generated within the offset range and cached in
+// syncable prefs.
+int GetBirthYearOffset(PrefService* pref_service) {
+ int offset =
+ pref_service->GetInteger(kSyncDemographicsBirthYearOffsetPrefName);
+ if (offset == kUserDemographicsBirthYearNoiseOffsetDefaultValue) {
+ // Generate a random offset when not cached in prefs.
+ offset = base::RandInt(-kUserDemographicsBirthYearNoiseOffsetRange,
+ kUserDemographicsBirthYearNoiseOffsetRange);
+ pref_service->SetInteger(kSyncDemographicsBirthYearOffsetPrefName, offset);
+ }
+ return offset;
+}
+
+// Determines whether the synced user has provided a birth year to Google which
+// is eligible, once aggregated and anonymized, to measure usage of Chrome
+// features by age groups. See doc of DemographicMetricsProvider in
+// demographic_metrics_provider.h for more details.
+bool HasEligibleBirthYear(base::Time now, int user_birth_year, int offset) {
+ // Compute user age.
+ base::Time::Exploded exploded_now_time;
+ now.LocalExplode(&exploded_now_time);
+ int user_age = exploded_now_time.year - (user_birth_year + offset);
+
+ // Verify if the synced user's age has a population size in the age
+ // distribution of the society that is big enough to not raise the entropy of
+ // the demographics too much. At a certain point, as the age increase, the
+ // size of the population starts declining sharply as you can see in this
+ // approximate representation of the age distribution:
+ // | ________ max age
+ // |______/ \_________ |
+ // | |\
+ // | | \
+ // +--------------------------|---------
+ // 0 10 20 30 40 50 60 70 80 90 100+
+ if (user_age > kUserDemographicsMaxAgeInYears)
+ return false;
+
+ // Verify if the synced user is old enough. Use > rather than >= because we
+ // want to be sure that the user is at least |kUserDemographicsMinAgeInYears|
+ // without disclosing their birth date, which requires to add an extra year
+ // margin to the minimal age to be safe. For example, if we are in 2019-07-10
+ // (now) and the user was born in 1999-08-10, the user is not yet 20 years old
+ // (minimal age) but we cannot know that because we only have access to the
+ // year of the dates (2019 and 1999 respectively). If we make sure that the
+ // minimal age (computed at year granularity) is at least 21, we are 100% sure
+ // that the user will be at least 20 years old when providing the user’s birth
+ // year and gender.
+ return user_age > kUserDemographicsMinAgeInYears;
+}
+
+// Gets the synced user's birth year from synced prefs, see doc of
+// DemographicMetricsProvider in demographic_metrics_provider.h for more
+// details.
+base::Optional<int> GetUserBirthYear(
+ const base::DictionaryValue* demographics) {
+ const base::Value* value =
+ demographics->FindPath(kSyncDemographicsBirthYearPath);
+ int birth_year = (value != nullptr && value->is_int())
+ ? value->GetInt()
+ : kUserDemographicsBirthYearDefaultValue;
+
+ // Verify that there is a birth year.
+ if (birth_year == kUserDemographicsBirthYearDefaultValue)
+ return base::nullopt;
+
+ return birth_year;
+}
+
+// Gets the synced user's gender from synced prefs, see doc of
+// DemographicMetricsProvider in demographic_metrics_provider.h for more
+// details.
+base::Optional<UserDemographicsProto_Gender> GetUserGender(
+ const base::DictionaryValue* demographics) {
+ const base::Value* value =
+ demographics->FindPath(kSyncDemographicsGenderPath);
+ int gender_int = (value != nullptr && value->is_int())
+ ? value->GetInt()
+ : kUserDemographicsGenderDefaultValue;
+
+ // Verify that the gender is not default.
+ if (gender_int == kUserDemographicsGenderDefaultValue)
+ return base::nullopt;
+
+ // Verify that the gender number is a valid UserDemographicsProto_Gender
+ // encoding.
+ if (!UserDemographicsProto_Gender_IsValid(gender_int))
+ return base::nullopt;
+
+ auto gender = UserDemographicsProto_Gender(gender_int);
+
+ // Verify that the gender is in a large enough population set to preserve
+ // anonymity.
+ if (gender != UserDemographicsProto::GENDER_FEMALE &&
+ gender != UserDemographicsProto::GENDER_MALE) {
+ return base::nullopt;
+ }
+
+ return gender;
+}
+
+} // namespace
+
+// static
+UserDemographicsResult UserDemographicsResult::ForValue(
+ UserDemographics value) {
+ return UserDemographicsResult(std::move(value),
+ UserDemographicsStatus::kSuccess);
+}
+
+// static
+UserDemographicsResult UserDemographicsResult::ForStatus(
+ UserDemographicsStatus status) {
+ DCHECK(status != UserDemographicsStatus::kSuccess);
+ return UserDemographicsResult(UserDemographics(), status);
+}
+
+bool UserDemographicsResult::IsSuccess() const {
+ return status_ == UserDemographicsStatus::kSuccess;
+}
+
+UserDemographicsStatus UserDemographicsResult::status() const {
+ return status_;
+}
+
+const UserDemographics& UserDemographicsResult::value() const {
+ return value_;
+}
+
+UserDemographicsResult::UserDemographicsResult(UserDemographics value,
+ UserDemographicsStatus status)
+ : value_(std::move(value)), status_(status) {}
+
+void RegisterDemographicsProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterDictionaryPref(
+ kSyncDemographicsPrefName,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+ registry->RegisterIntegerPref(
+ kSyncDemographicsBirthYearOffsetPrefName,
+ kUserDemographicsBirthYearNoiseOffsetDefaultValue,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+void ClearDemographicsPrefs(PrefService* pref_service) {
+ // Clear user's birth year and gender.
+ // Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes
+ // syncing, causing these prefs to be recreated, we don't want them to start
+ // reporting a different randomized birth year as this could narrow down or
+ // even reveal their true birth year.
+ pref_service->ClearPref(kSyncDemographicsPrefName);
+}
+
+UserDemographicsResult GetUserNoisedBirthYearAndGenderFromPrefs(
+ base::Time now,
+ PrefService* pref_service) {
+ // Verify that the now time is available. There are situations where the now
+ // time cannot be provided.
+ if (now.is_null()) {
+ return UserDemographicsResult::ForStatus(
+ UserDemographicsStatus::kCannotGetTime);
+ }
+
+ // Get the synced user’s noised birth year and gender from synced prefs. Only
+ // one error status code should be used to represent the case where
+ // demographics are ineligible, see doc of UserDemographicsStatus in
+ // user_demographics.h for more details.
+
+ // Get the pref that contains the user's birth year and gender.
+ const base::DictionaryValue* demographics =
+ pref_service->GetDictionary(kSyncDemographicsPrefName);
+ DCHECK(demographics != nullptr);
+
+ // Get the user's birth year.
+ base::Optional<int> birth_year = GetUserBirthYear(demographics);
+ if (!birth_year.has_value()) {
+ return UserDemographicsResult::ForStatus(
+ UserDemographicsStatus::kIneligibleDemographicsData);
+ }
+
+ // Get the user's gender.
+ base::Optional<UserDemographicsProto_Gender> gender =
+ GetUserGender(demographics);
+ if (!gender.has_value()) {
+ return UserDemographicsResult::ForStatus(
+ UserDemographicsStatus::kIneligibleDemographicsData);
+ }
+
+ // Get the offset and do one last check that the birth year is eligible.
+ int offset = GetBirthYearOffset(pref_service);
+ if (!HasEligibleBirthYear(now, *birth_year, offset)) {
+ return UserDemographicsResult::ForStatus(
+ UserDemographicsStatus::kIneligibleDemographicsData);
+ }
+
+ // Set gender and noised birth year in demographics.
+ UserDemographics user_demographics;
+ user_demographics.gender = *gender;
+ user_demographics.birth_year = *birth_year + offset;
+
+ return UserDemographicsResult::ForValue(std::move(user_demographics));
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/demographics/user_demographics.h b/chromium/components/metrics/demographics/user_demographics.h
new file mode 100644
index 00000000000..de2249ba3e1
--- /dev/null
+++ b/chromium/components/metrics/demographics/user_demographics.h
@@ -0,0 +1,139 @@
+// 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 COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_
+#define COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_
+
+#include "base/time/time.h"
+#include "third_party/metrics_proto/user_demographics.pb.h"
+
+class PrefService;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+} // namespace user_prefs
+
+namespace metrics {
+
+// Default value for user gender when no value has been set.
+constexpr int kUserDemographicsGenderDefaultValue = -1;
+
+// Default value for user gender enum when no value has been set.
+constexpr UserDemographicsProto_Gender kUserDemographicGenderDefaultEnumValue =
+ UserDemographicsProto_Gender_Gender_MIN;
+
+// Default value for user gender when no value has been set.
+constexpr int kUserDemographicsBirthYearDefaultValue = -1;
+
+// Default value for birth year offset when no value has been set. Set to a
+// really high value that |kUserDemographicsBirthYearNoiseOffsetRange| will
+// never go over.
+constexpr int kUserDemographicsBirthYearNoiseOffsetDefaultValue = 100;
+
+// Boundary of the +/- range in years within witch to randomly pick an offset to
+// add to the user birth year. This adds noise to the birth year to not allow
+// someone to accurately know a user's age. Possible offsets range from -2 to 2.
+constexpr int kUserDemographicsBirthYearNoiseOffsetRange = 2;
+
+// Minimal user age in years to provide demographics for.
+constexpr int kUserDemographicsMinAgeInYears = 20;
+
+// Max user age to provide demopgrahics for.
+constexpr int kUserDemographicsMaxAgeInYears = 85;
+
+// Syncable preference names, exposed publicly for testing.
+extern const char kSyncDemographicsPrefName[];
+extern const char kSyncDemographicsBirthYearOffsetPrefName[];
+
+// These are not prefs, they are paths inside of kSyncDemographics.
+extern const char kSyncDemographicsBirthYearPath[];
+extern const char kSyncDemographicsGenderPath[];
+
+// Container of user demographics.
+struct UserDemographics {
+ int birth_year = 0;
+ UserDemographicsProto_Gender gender = UserDemographicsProto::Gender_MIN;
+};
+
+// Represents the status of providing user demographics (noised birth year and
+// gender) that are logged to UMA. Entries of the enum should not be renumbered
+// and numeric values should never be reused. Please keep in sync with
+// "UserDemographicsStatus" in src/tools/metrics/histograms/enums.xml. There
+// should only be one entry representing demographic data that is ineligible to
+// be provided. A finer grained division of kIneligibleDemographicsData (e.g.,
+// INVALID_BIRTH_YEAR) might help inferring categories of demographics that
+// should not be exposed to protect privacy.
+enum class UserDemographicsStatus {
+ // Could get the user's noised birth year and gender.
+ kSuccess = 0,
+ // Sync is not enabled.
+ kSyncNotEnabled = 1,
+ // User's birth year and gender are ineligible to be provided either because
+ // some of them don't exist (missing data) or some of them are not eligible to
+ // be provided.
+ kIneligibleDemographicsData = 2,
+ // Could not get the time needed to compute the user's age.
+ kCannotGetTime = 3,
+ // There is more than one Profile for the Chrome browser. This entry is used
+ // by the DemographicMetricsProvider client.
+ kMoreThanOneProfile = 4,
+ // There is no sync service available for the loaded Profile. This entry is
+ // used by the DemographicMetricsProvider client.
+ kNoSyncService = 5,
+ // Upper boundary of the enum that is needed for the histogram.
+ kMaxValue = kNoSyncService
+};
+
+// Container and handler for data related to the retrieval of user demographics.
+// Holds either valid demographics data or an error code.
+class UserDemographicsResult {
+ public:
+ // Builds a UserDemographicsResult that contains user demographics and has a
+ // UserDemographicsStatus::kSuccess status.
+ static UserDemographicsResult ForValue(UserDemographics value);
+
+ // Builds a UserDemographicsResult that does not have user demographics (only
+ // default values) and has a status other than
+ // UserDemographicsStatus::kSuccess.
+ static UserDemographicsResult ForStatus(UserDemographicsStatus status);
+
+ // Determines whether demographics could be successfully retrieved.
+ bool IsSuccess() const;
+
+ // Gets the status of the result.
+ UserDemographicsStatus status() const;
+
+ // Gets the value of the result which will contain data when status() is
+ // UserDemographicsStatus::kSuccess.
+ const UserDemographics& value() const;
+
+ private:
+ UserDemographicsResult(UserDemographics value, UserDemographicsStatus status);
+
+ UserDemographics value_;
+ UserDemographicsStatus status_ = UserDemographicsStatus::kMaxValue;
+};
+
+// Registers the profile preferences that are needed to persist demographics
+// information exposed via GetUserNoisedBirthYearAndGenderFromPrefs().
+void RegisterDemographicsProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry);
+
+// Clears the profile's demographics-related preferences containing user data.
+// This excludes the internal bith year offset.
+void ClearDemographicsPrefs(PrefService* pref_service);
+
+// Gets the synced user’s noised birth year and gender from preferences, see doc
+// of metrics::DemographicMetricsProvider in
+// components/metrics/demographic_metrics_provider.h for more details. Returns
+// an error status with an empty value when the user's birth year or gender
+// cannot be provided. You need to provide an accurate |now| time that
+// represents the current time.
+UserDemographicsResult GetUserNoisedBirthYearAndGenderFromPrefs(
+ base::Time now,
+ PrefService* pref_service);
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_
diff --git a/chromium/components/metrics/demographics/user_demographics_unittest.cc b/chromium/components/metrics/demographics/user_demographics_unittest.cc
new file mode 100644
index 00000000000..301819f1302
--- /dev/null
+++ b/chromium/components/metrics/demographics/user_demographics_unittest.cc
@@ -0,0 +1,259 @@
+// 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 "components/metrics/demographics/user_demographics.h"
+
+#include <utility>
+
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/user_demographics.pb.h"
+
+namespace metrics {
+
+namespace {
+
+// Gets the now time used for testing demographics.
+base::Time GetNowTime() {
+ constexpr char kNowTimeInStringFormat[] = "22 Jul 2019 00:00:00 UDT";
+
+ base::Time now;
+ bool result = base::Time::FromString(kNowTimeInStringFormat, &now);
+ DCHECK(result);
+ return now;
+}
+
+} // namespace
+
+TEST(UserDemographicsTest, UserDemographicsResult_ForValue) {
+ int user_birth_year = 1982;
+ UserDemographicsProto_Gender user_gender = UserDemographicsProto::GENDER_MALE;
+
+ UserDemographics user_demographics;
+ user_demographics.birth_year = user_birth_year;
+ user_demographics.gender = user_gender;
+ UserDemographicsResult user_demographics_result =
+ UserDemographicsResult::ForValue(std::move(user_demographics));
+
+ EXPECT_TRUE(user_demographics_result.IsSuccess());
+ EXPECT_EQ(UserDemographicsStatus::kSuccess,
+ user_demographics_result.status());
+ EXPECT_EQ(user_birth_year, user_demographics_result.value().birth_year);
+ EXPECT_EQ(user_gender, user_demographics_result.value().gender);
+}
+
+TEST(UserDemographicsTest, UserDemographicsResult_ForStatus) {
+ UserDemographicsStatus error_status =
+ UserDemographicsStatus::kIneligibleDemographicsData;
+ UserDemographicsResult user_demographics_result =
+ UserDemographicsResult::ForStatus(error_status);
+
+ EXPECT_FALSE(user_demographics_result.IsSuccess());
+ EXPECT_EQ(error_status, user_demographics_result.status());
+}
+
+class UserDemographicsPrefsTest : public testing::Test {
+ protected:
+ UserDemographicsPrefsTest() {
+ RegisterDemographicsProfilePrefs(pref_service_.registry());
+ }
+
+ void SetDemographics(int birth_year, UserDemographicsProto::Gender gender) {
+ base::DictionaryValue dict;
+ dict.SetIntPath(kSyncDemographicsBirthYearPath, birth_year);
+ dict.SetIntPath(kSyncDemographicsGenderPath, static_cast<int>(gender));
+ pref_service_.Set(kSyncDemographicsPrefName, dict);
+ }
+
+ sync_preferences::TestingPrefServiceSyncable pref_service_;
+};
+
+TEST_F(UserDemographicsPrefsTest, ReadDemographicsWithRandomOffset) {
+ int user_demographics_birth_year = 1983;
+ UserDemographicsProto_Gender user_demographics_gender =
+ UserDemographicsProto::GENDER_MALE;
+
+ // Set user demographic prefs.
+ SetDemographics(user_demographics_birth_year, user_demographics_gender);
+
+ int provided_birth_year;
+ {
+ UserDemographicsResult demographics_result =
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
+ ASSERT_TRUE(demographics_result.IsSuccess());
+ EXPECT_EQ(user_demographics_gender, demographics_result.value().gender);
+ // Verify that the provided birth year is within the range.
+ provided_birth_year = demographics_result.value().birth_year;
+ int delta = provided_birth_year - user_demographics_birth_year;
+ EXPECT_LE(delta, kUserDemographicsBirthYearNoiseOffsetRange);
+ EXPECT_GE(delta, -kUserDemographicsBirthYearNoiseOffsetRange);
+ }
+
+ // Verify that the offset is cached and that the randomized birth year is the
+ // same when doing more that one read of the birth year.
+ {
+ ASSERT_TRUE(
+ pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
+ UserDemographicsResult demographics_result =
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
+ ASSERT_TRUE(demographics_result.IsSuccess());
+ EXPECT_EQ(provided_birth_year, demographics_result.value().birth_year);
+ }
+}
+
+TEST_F(UserDemographicsPrefsTest, ReadAndClearUserDemographicPreferences) {
+ // Verify demographic prefs are not available when there is nothing set.
+ ASSERT_FALSE(
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
+ .IsSuccess());
+
+ // Set demographic prefs directly from the pref service interface because
+ // demographic prefs will only be set on the server-side. The SyncPrefs
+ // interface cannot set demographic prefs.
+ SetDemographics(1983, UserDemographicsProto::GENDER_FEMALE);
+
+ // Set birth year noise offset to not have it randomized.
+ pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName, 2);
+
+ // Verify that demographics are provided.
+ {
+ UserDemographicsResult demographics_result =
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
+ ASSERT_TRUE(demographics_result.IsSuccess());
+ }
+
+ ClearDemographicsPrefs(&pref_service_);
+
+ // Verify that demographics are not provided and kSyncDemographics is cleared.
+ // Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes
+ // syncing, causing these prefs to be recreated, we don't want them to start
+ // reporting a different randomized birth year as this could narrow down or
+ // even reveal their true birth year.
+ EXPECT_FALSE(
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
+ .IsSuccess());
+ EXPECT_FALSE(pref_service_.HasPrefPath(kSyncDemographicsPrefName));
+ EXPECT_TRUE(
+ pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
+}
+
+struct DemographicsTestParam {
+ // Birth year of the user.
+ int birth_year = kUserDemographicsBirthYearDefaultValue;
+
+ // Non-random offset to apply to |birth_year| as noise.
+ int birth_year_offset = kUserDemographicsBirthYearNoiseOffsetDefaultValue;
+
+ // Gender of the user.
+ UserDemographicsProto_Gender gender = kUserDemographicGenderDefaultEnumValue;
+
+ // Status of the retrieval of demographics.
+ UserDemographicsStatus status = UserDemographicsStatus::kMaxValue;
+};
+
+// Extend UserDemographicsPrefsTest fixture for parameterized tests on
+// demographics.
+class UserDemographicsPrefsTestWithParam
+ : public UserDemographicsPrefsTest,
+ public testing::WithParamInterface<DemographicsTestParam> {};
+
+TEST_P(UserDemographicsPrefsTestWithParam, ReadDemographics_OffsetIsNotRandom) {
+ DemographicsTestParam param = GetParam();
+
+ // Set user demographic prefs.
+ SetDemographics(param.birth_year, param.gender);
+
+ // Set birth year noise offset to not have it randomized.
+ pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName,
+ param.birth_year_offset);
+
+ // Verify provided demographics for the different parameterized test cases.
+ UserDemographicsResult demographics_result =
+ GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
+ if (param.status == UserDemographicsStatus::kSuccess) {
+ ASSERT_TRUE(demographics_result.IsSuccess());
+ EXPECT_EQ(param.birth_year + param.birth_year_offset,
+ demographics_result.value().birth_year);
+ EXPECT_EQ(param.gender, demographics_result.value().gender);
+ } else {
+ ASSERT_FALSE(demographics_result.IsSuccess());
+ EXPECT_EQ(param.status, demographics_result.status());
+ }
+}
+
+// Test suite composed of different test cases of getting user demographics.
+// The now time in each test case is "22 Jul 2019 00:00:00 UDT" which falls into
+// the year bucket of 2018. Users need at most a |birth_year| +
+// |birth_year_offset| of 1998 to be able to provide demographics.
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ UserDemographicsPrefsTestWithParam,
+ ::testing::Values(
+ // Test where birth year should not be provided because |birth_year| + 2
+ // > 1998.
+ DemographicsTestParam{
+ /*birth_year=*/1997,
+ /*birth_year_offset=*/2,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
+ // Test where birth year should not be provided because |birth_year| - 2
+ // > 1998.
+ DemographicsTestParam{
+ /*birth_year=*/2001,
+ /*birth_year_offset=*/-2,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
+ // Test where birth year should not be provided because age of user is
+ // |kUserDemographicsMaxAge| + 1, which is over the max age.
+ DemographicsTestParam{
+ /*birth_year=*/1933,
+ /*birth_year_offset=*/0,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
+ // Test where gender should not be provided because it has a low
+ // population that can have their privacy compromised because of high
+ // entropy.
+ DemographicsTestParam{
+ /*birth_year=*/1986,
+ /*birth_year_offset=*/0,
+ /*gender=*/UserDemographicsProto::GENDER_CUSTOM_OR_OTHER,
+ /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
+ // Test where birth year can be provided because |birth_year| + 2 ==
+ // 1998.
+ DemographicsTestParam{/*birth_year=*/1996,
+ /*birth_year_offset=*/2,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kSuccess},
+ // Test where birth year can be provided because |birth_year| - 2 ==
+ // 1998.
+ DemographicsTestParam{/*birth_year=*/2000,
+ /*birth_year_offset=*/-2,
+ /*gender=*/UserDemographicsProto::GENDER_MALE,
+ /*status=*/UserDemographicsStatus::kSuccess},
+ // Test where birth year can be provided because |birth_year| + 2 <
+ // 1998.
+ DemographicsTestParam{/*birth_year=*/1995,
+ /*birth_year_offset=*/2,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kSuccess},
+ // Test where birth year can be provided because |birth_year| - 2 <
+ // 1998.
+ DemographicsTestParam{/*birth_year=*/1999,
+ /*birth_year_offset=*/-2,
+ /*gender=*/UserDemographicsProto::GENDER_MALE,
+ /*status=*/UserDemographicsStatus::kSuccess},
+ // Test where gender can be provided because it is part of a large
+ // population with a low entropy.
+ DemographicsTestParam{/*birth_year=*/1986,
+ /*birth_year_offset=*/0,
+ /*gender=*/UserDemographicsProto::GENDER_FEMALE,
+ /*status=*/UserDemographicsStatus::kSuccess},
+ // Test where gender can be provided because it is part of a large
+ // population with a low entropy.
+ DemographicsTestParam{/*birth_year=*/1986,
+ /*birth_year_offset=*/0,
+ /*gender=*/UserDemographicsProto::GENDER_MALE,
+ /*status=*/UserDemographicsStatus::kSuccess}));
+
+} // namespace metrics
diff --git a/chromium/components/metrics/expired_histogram_util.cc b/chromium/components/metrics/expired_histogram_util.cc
index 17844e77213..fc591963582 100644
--- a/chromium/components/metrics/expired_histogram_util.cc
+++ b/chromium/components/metrics/expired_histogram_util.cc
@@ -15,20 +15,27 @@ namespace {
const base::Feature kExpiredHistogramLogicFeature{
"ExpiredHistogramLogic", base::FEATURE_DISABLED_BY_DEFAULT};
+// TODO(jwd): Remove when the study config is updated with the new param.
const base::FeatureParam<std::string> kWhitelistParam{
&kExpiredHistogramLogicFeature, "whitelist", ""};
+const base::FeatureParam<std::string> kAllowlistParam{
+ &kExpiredHistogramLogicFeature, "allowlist", ""};
+
} // namespace
void EnableExpiryChecker(const uint64_t* expired_histograms_hashes,
size_t num_expired_histograms) {
DCHECK(base::FeatureList::GetInstance());
if (base::FeatureList::IsEnabled(kExpiredHistogramLogicFeature)) {
+ std::string allowlist = kAllowlistParam.Get();
+ // TODO(jwd): Remove when the study config is updated with the new param.
+ if (allowlist.empty())
+ allowlist = kWhitelistParam.Get();
base::StatisticsRecorder::SetRecordChecker(
- std::make_unique<ExpiredHistogramsChecker>(expired_histograms_hashes,
- num_expired_histograms,
- kWhitelistParam.Get()));
+ std::make_unique<ExpiredHistogramsChecker>(
+ expired_histograms_hashes, num_expired_histograms, allowlist));
}
}
-} // namespace metrics \ No newline at end of file
+} // namespace metrics
diff --git a/chromium/components/metrics/expired_histograms_checker.cc b/chromium/components/metrics/expired_histograms_checker.cc
index 43a6e05560d..f83b3698cfc 100644
--- a/chromium/components/metrics/expired_histograms_checker.cc
+++ b/chromium/components/metrics/expired_histograms_checker.cc
@@ -15,27 +15,28 @@
namespace metrics {
ExpiredHistogramsChecker::ExpiredHistogramsChecker(
- const uint64_t* array,
+ const uint64_t* expired_histogram_hashes,
size_t size,
- const std::string& whitelist_str)
- : array_(array), size_(size) {
- InitWhitelist(whitelist_str);
+ const std::string& allowlist_str)
+ : expired_histogram_hashes_(expired_histogram_hashes), size_(size) {
+ InitAllowlist(allowlist_str);
}
ExpiredHistogramsChecker::~ExpiredHistogramsChecker() {}
bool ExpiredHistogramsChecker::ShouldRecord(uint64_t histogram_hash) const {
- // If histogram is whitelisted then it should always be recorded.
- if (base::Contains(whitelist_, histogram_hash))
+ // If histogram is explicitly allowed then it should always be recorded.
+ if (base::Contains(allowlist_, histogram_hash))
return true;
- return !std::binary_search(array_, array_ + size_, histogram_hash);
+ return !std::binary_search(expired_histogram_hashes_,
+ expired_histogram_hashes_ + size_, histogram_hash);
}
-void ExpiredHistogramsChecker::InitWhitelist(const std::string& whitelist_str) {
- std::vector<base::StringPiece> whitelist_names = base::SplitStringPiece(
- whitelist_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- for (base::StringPiece name : whitelist_names)
- whitelist_.insert(base::HashMetricName(name));
+void ExpiredHistogramsChecker::InitAllowlist(const std::string& allowlist_str) {
+ std::vector<base::StringPiece> allowlist_names = base::SplitStringPiece(
+ allowlist_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ for (base::StringPiece name : allowlist_names)
+ allowlist_.insert(base::HashMetricName(name));
}
} // namespace metrics
diff --git a/chromium/components/metrics/expired_histograms_checker.h b/chromium/components/metrics/expired_histograms_checker.h
index b3ca4a7612a..510d4441709 100644
--- a/chromium/components/metrics/expired_histograms_checker.h
+++ b/chromium/components/metrics/expired_histograms_checker.h
@@ -18,30 +18,31 @@ namespace metrics {
// to avoid recording expired metrics.
class ExpiredHistogramsChecker final : public base::RecordHistogramChecker {
public:
- // Takes sorted in nondecreasing order array of histogram hashes, its size and
- // list of whitelisted histogram names concatenated as a comma-separated
- // string.
- ExpiredHistogramsChecker(const uint64_t* array,
+ // Takes a sorted array of histogram hashes in ascending order, its size and a
+ // list of explicitly allowed histogram names as a comma-separated string.
+ // Histograms in the |allowlist_str| are logged even if their hash is in the
+ // |expired_histograms_hashes|.
+ ExpiredHistogramsChecker(const uint64_t* expired_histogram_hashes,
size_t size,
- const std::string& whitelist_str);
+ const std::string& allowlist_str);
~ExpiredHistogramsChecker() override;
// Checks if the given |histogram_hash| corresponds to an expired histogram.
bool ShouldRecord(uint64_t histogram_hash) const override;
private:
- // Initializes the |whitelist_| array of histogram hashes that should be
+ // Initializes the |allowlist_| array of histogram hashes that should be
// recorded regardless of their expiration.
- void InitWhitelist(const std::string& whitelist_str);
+ void InitAllowlist(const std::string& allowlist_str);
// Array of expired histogram hashes.
- const uint64_t* const array_;
+ const uint64_t* const expired_histogram_hashes_;
- // Size of the |array_|.
+ // Size of the |expired_histogram_hashes_|.
const size_t size_;
- // List of expired histogram hashes that should be recorded.
- std::set<uint64_t> whitelist_;
+ // Set of expired histogram hashes that should be recorded.
+ std::set<uint64_t> allowlist_;
DISALLOW_COPY_AND_ASSIGN(ExpiredHistogramsChecker);
};
diff --git a/chromium/components/metrics/expired_histograms_checker_unittest.cc b/chromium/components/metrics/expired_histograms_checker_unittest.cc
index 13aa77d87f2..4ae6ba23d91 100644
--- a/chromium/components/metrics/expired_histograms_checker_unittest.cc
+++ b/chromium/components/metrics/expired_histograms_checker_unittest.cc
@@ -12,14 +12,14 @@ namespace metrics {
TEST(ExpiredHistogramsCheckerTests, BasicTest) {
uint64_t expired_hashes[] = {1, 2, 3};
size_t size = 3;
- std::string whitelist_str = "";
- ExpiredHistogramsChecker checker(expired_hashes, size, whitelist_str);
+ std::string allowlist_str = "";
+ ExpiredHistogramsChecker checker(expired_hashes, size, allowlist_str);
EXPECT_TRUE(checker.ShouldRecord(0));
EXPECT_FALSE(checker.ShouldRecord(3));
}
-TEST(ExpiredHistogramsCheckerTests, WhitelistTest) {
+TEST(ExpiredHistogramsCheckerTests, AllowlistTest) {
std::string hist1 = "hist1";
std::string hist2 = "hist2";
std::string hist3 = "hist3";
@@ -28,8 +28,8 @@ TEST(ExpiredHistogramsCheckerTests, WhitelistTest) {
uint64_t expired_hashes[] = {base::HashMetricName(hist1),
base::HashMetricName(hist2)};
size_t size = 2;
- std::string whitelist_str = hist2 + "," + hist4;
- ExpiredHistogramsChecker checker(expired_hashes, size, whitelist_str);
+ std::string allowlist_str = hist2 + "," + hist4;
+ ExpiredHistogramsChecker checker(expired_hashes, size, allowlist_str);
EXPECT_FALSE(checker.ShouldRecord(base::HashMetricName(hist1)));
EXPECT_TRUE(checker.ShouldRecord(base::HashMetricName(hist2)));
@@ -37,4 +37,4 @@ TEST(ExpiredHistogramsCheckerTests, WhitelistTest) {
EXPECT_TRUE(checker.ShouldRecord(base::HashMetricName(hist4)));
}
-} // namespace metrics \ No newline at end of file
+} // namespace metrics
diff --git a/chromium/components/metrics/generate_expired_histograms_array.gni b/chromium/components/metrics/generate_expired_histograms_array.gni
index a1f74355e3e..dc75fe9f352 100644
--- a/chromium/components/metrics/generate_expired_histograms_array.gni
+++ b/chromium/components/metrics/generate_expired_histograms_array.gni
@@ -6,6 +6,10 @@
# produce an output file and a source_set to build it.
#
# Parameters:
+# inputs:
+# List of file name to read. Each file should be a .xml file with
+# histogram descriptions and should be a path starting with
+# //tools/metrics/histograms/
#
# namespace (optional):
# Namespace in which the generated code should be scoped. If left empty,
@@ -27,6 +31,129 @@ template("generate_expired_histograms_array") {
script = "//tools/metrics/histograms/generate_expired_histograms_array.py"
outputs = [ header_filename ]
+ inputs = [
+ "//tools/metrics/histograms/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/accessibility/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/android/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/apps/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/arc/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/ash/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/assistant/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/auth/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/auto/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/autofill/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/background/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/blink/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/borealis/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/browser/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/chrome/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/chromeos/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/cloud/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/compositing/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/content/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/cookie/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/cras/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/cros/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/crostini/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/crypt/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/dev/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/diagnostics/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/direct/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/disk/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/dom/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/download/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/enterprise/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/event/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/extension/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/extensions/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/file/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/gcm/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/geolocation/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/google/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/gpu/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/hang_watcher/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml",
+ "//tools/metrics/histograms/histograms_xml/history/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/holding_space/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/image/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/input/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/installer/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/instant/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/interstitial/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/ios/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/local/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/login/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/media/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/memory/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/mobile/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/multi_device/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/na_cl/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/navigation/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/net/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/network/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/notifications/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/offline/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/omnibox/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/oobe/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/optimization/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/others/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/page/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/password/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/payment/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/permissions/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/phonehub/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/platform/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/plugin/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/power/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/print/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/printing/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/profile/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/quickoffice/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/quota/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/renderer/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/renderer4/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/sb_client/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/scheduler/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/search/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/security/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/service/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/session/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/settings/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/sharing/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/signin/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/simple/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/smart/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/software/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/stability/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/startup/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/storage/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/subresource/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/sync/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/tab/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/translate/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/ukm/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/uma/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/update_engine/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/v8/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/variations/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/web_apk/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/web_audio/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/web_core/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/weblayer/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/windows/histograms.xml",
+ "//tools/metrics/histograms/histograms_xml/obsolete_histograms.xml",
+ "//tools/metrics/histograms/enums.xml",
+ ]
+
major_branch_date_filepath = invoker.major_branch_date_filepath
milestone_filepath = invoker.milestone_filepath
@@ -37,10 +164,10 @@ template("generate_expired_histograms_array") {
}
args += [
- "-o" + rebase_path(root_gen_dir, root_build_dir),
- "-H" + rebase_path(header_filename, root_gen_dir),
- "-d" + rebase_path(major_branch_date_filepath, root_build_dir),
- "-m" + rebase_path(milestone_filepath, root_build_dir),
- ]
+ "-o" + rebase_path(root_gen_dir, root_build_dir),
+ "-H" + rebase_path(header_filename, root_gen_dir),
+ "-d" + rebase_path(major_branch_date_filepath, root_build_dir),
+ "-m" + rebase_path(milestone_filepath, root_build_dir),
+ ] + rebase_path(inputs, root_build_dir)
}
}
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index 5aeefc9fff2..a70998dc432 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -77,6 +77,19 @@ static int64_t ToMonotonicSeconds(base::TimeTicks time_ticks) {
} // namespace
+namespace internal {
+
+SystemProfileProto::InstallerPackage ToInstallerPackage(
+ base::StringPiece installer_package_name) {
+ if (installer_package_name.empty())
+ return SystemProfileProto::INSTALLER_PACKAGE_NONE;
+ if (installer_package_name == "com.android.vending")
+ return SystemProfileProto::INSTALLER_PACKAGE_GOOGLE_PLAY_STORE;
+ return SystemProfileProto::INSTALLER_PACKAGE_OTHER;
+}
+
+} // namespace internal
+
MetricsLog::IndependentMetricsLoader::IndependentMetricsLoader(
std::unique_ptr<MetricsLog> log)
: log_(std::move(log)),
@@ -163,6 +176,7 @@ void MetricsLog::RecordUserAction(const std::string& key,
UserActionEventProto* user_action = uma_proto_.add_user_action_event();
user_action->set_name_hash(Hash(key));
user_action->set_time_sec(ToMonotonicSeconds(action_time));
+ base::UmaHistogramBoolean("UMA.UserActionsCount", true);
}
// static
@@ -231,10 +245,12 @@ void MetricsLog::RecordCoreSystemProfile(
#endif
#if defined(OS_ANDROID)
- os->set_build_fingerprint(
- base::android::BuildInfo::GetInstance()->android_build_fp());
+ const auto* build_info = base::android::BuildInfo::GetInstance();
+ os->set_build_fingerprint(build_info->android_build_fp());
if (!package_name.empty() && package_name != "com.android.chrome")
system_profile->set_app_package_name(package_name);
+ system_profile->set_installer_package(
+ internal::ToInstallerPackage(build_info->installer_package_name()));
#elif defined(OS_IOS)
os->set_build_number(base::SysInfo::GetIOSBuildNumber());
#endif
diff --git a/chromium/components/metrics/metrics_log.h b/chromium/components/metrics/metrics_log.h
index 6a265aa0618..284dc540957 100644
--- a/chromium/components/metrics/metrics_log.h
+++ b/chromium/components/metrics/metrics_log.h
@@ -14,11 +14,14 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/metrics/histogram_base.h"
+#include "base/strings/string_piece_forward.h"
#include "base/time/time.h"
-#include "components/metrics/metrics_service_client.h"
+#include "components/metrics/metrics_reporting_default_state.h"
#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+#include "third_party/metrics_proto/system_profile.pb.h"
class PrefService;
@@ -31,12 +34,16 @@ class HistogramSnapshotManager;
namespace metrics {
class MetricsProvider;
+class MetricsServiceClient;
class DelegatingProvider;
namespace internal {
// Maximum number of events before truncation.
constexpr int kOmniboxEventLimit = 5000;
constexpr int kUserActionEventLimit = 5000;
+
+SystemProfileProto::InstallerPackage ToInstallerPackage(
+ base::StringPiece installer_package_name);
} // namespace internal
class MetricsLog {
@@ -160,9 +167,7 @@ class MetricsLog {
// record. Must only be called after CloseLog() has been called.
void GetEncodedLog(std::string* encoded_log);
- const base::TimeTicks& creation_time() const {
- return creation_time_;
- }
+ const base::TimeTicks& creation_time() const { return creation_time_; }
LogType log_type() const { return log_type_; }
@@ -180,9 +185,7 @@ class MetricsLog {
// Exposed to allow subclass to access to export the uma_proto. Can be used
// by external components to export logs to Chrome.
- const ChromeUserMetricsExtension* uma_proto() const {
- return &uma_proto_;
- }
+ const ChromeUserMetricsExtension* uma_proto() const { return &uma_proto_; }
private:
// Write the default state of the enable metrics checkbox.
diff --git a/chromium/components/metrics/metrics_log_manager_unittest.cc b/chromium/components/metrics/metrics_log_manager_unittest.cc
index 116acb1f42a..2eab9e59fec 100644
--- a/chromium/components/metrics/metrics_log_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_log_manager_unittest.cc
@@ -25,7 +25,8 @@ namespace {
class MetricsLogManagerTest : public testing::Test {
public:
- MetricsLogManagerTest() : log_store_(&pref_service_, 0, std::string()) {
+ MetricsLogManagerTest()
+ : log_store_(&pref_service_, client_.GetStorageLimits(), std::string()) {
MetricsLogStore::RegisterPrefs(pref_service_.registry());
log_store()->LoadPersistedUnsentLogs();
}
diff --git a/chromium/components/metrics/metrics_log_store.cc b/chromium/components/metrics/metrics_log_store.cc
index 81b30e0fe9a..6fdcc7e5b9e 100644
--- a/chromium/components/metrics/metrics_log_store.cc
+++ b/chromium/components/metrics/metrics_log_store.cc
@@ -5,35 +5,12 @@
#include "components/metrics/metrics_log_store.h"
#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service_client.h"
#include "components/metrics/unsent_log_store_metrics_impl.h"
#include "components/prefs/pref_registry_simple.h"
namespace metrics {
-namespace {
-
-// The number of "initial" logs to save, and hope to send during a future Chrome
-// session. Initial logs contain crash stats, and are pretty small.
-const size_t kInitialLogsSaveLimit = 20;
-
-// The number of ongoing logs to save persistently, and hope to
-// send during a this or future sessions. Note that each log may be pretty
-// large, as presumably the related "initial" log wasn't sent (probably nothing
-// was, as the user was probably off-line). As a result, the log probably kept
-// accumulating while the "initial" log was stalled, and couldn't be sent. As a
-// result, we don't want to save too many of these mega-logs.
-// A "standard shutdown" will create a small log, including just the data that
-// was not yet been transmitted, and that is normal (to have exactly one
-// ongoing_log_ at startup).
-const size_t kOngoingLogsSaveLimit = 8;
-
-// The number of bytes of logs to save of each type (initial/ongoing).
-// This ensures that a reasonable amount of history will be stored even if there
-// is a long series of very small logs.
-const size_t kStorageByteLimitPerLogType = 300 * 1000; // ~300kB
-
-} // namespace
-
// static
void MetricsLogStore::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(prefs::kMetricsInitialLogs);
@@ -43,24 +20,24 @@ void MetricsLogStore::RegisterPrefs(PrefRegistrySimple* registry) {
}
MetricsLogStore::MetricsLogStore(PrefService* local_state,
- size_t max_ongoing_log_size,
+ StorageLimits storage_limits,
const std::string& signing_key)
: unsent_logs_loaded_(false),
initial_log_queue_(std::make_unique<UnsentLogStoreMetricsImpl>(),
local_state,
prefs::kMetricsInitialLogs,
prefs::kMetricsInitialLogsMetadata,
- kInitialLogsSaveLimit,
- kStorageByteLimitPerLogType,
- 0,
+ storage_limits.min_initial_log_queue_count,
+ storage_limits.min_initial_log_queue_size,
+ 0, // Each individual initial log can be any size.
signing_key),
ongoing_log_queue_(std::make_unique<UnsentLogStoreMetricsImpl>(),
local_state,
prefs::kMetricsOngoingLogs,
prefs::kMetricsOngoingLogsMetadata,
- kOngoingLogsSaveLimit,
- kStorageByteLimitPerLogType,
- max_ongoing_log_size,
+ storage_limits.min_ongoing_log_queue_count,
+ storage_limits.min_ongoing_log_queue_size,
+ storage_limits.max_ongoing_log_size,
signing_key) {}
MetricsLogStore::~MetricsLogStore() {}
diff --git a/chromium/components/metrics/metrics_log_store.h b/chromium/components/metrics/metrics_log_store.h
index 3394f377439..ed0ee01b26a 100644
--- a/chromium/components/metrics/metrics_log_store.h
+++ b/chromium/components/metrics/metrics_log_store.h
@@ -19,18 +19,42 @@ class PrefRegistrySimple;
namespace metrics {
+class MetricsServiceClient;
+
// A LogStore implementation for storing UMA logs.
// This implementation keeps track of two types of logs, initial and ongoing,
// each stored in UnsentLogStore. It prioritizes staging initial logs over
// ongoing logs.
class MetricsLogStore : public LogStore {
public:
+ // Configurable limits for ensuring and restricting local log storage.
+ //
+ // |min_{initial,ongoing}_log_queue_count| are the minimum numbers of unsent
+ // logs that UnsentLogStore must persist before deleting old logs.
+ //
+ // |min_{initial,ongoing}_log_queue_size| are the minimum numbers of bytes in
+ // total across all logs within the initial or ongoing log queue that
+ // UnsentLogStore must persist before deleting old logs.
+ //
+ // If both |min_..._log_queue_count| and |min_..._log_queue_size| are 0, then
+ // this LogStore won't persist unsent logs to local storage.
+ //
+ // |max_ongoing_log_size| is the maximum size of any individual ongoing log.
+ // When set to 0, no limits are imposed, i.e. individual logs can be any size.
+ struct StorageLimits {
+ size_t min_initial_log_queue_count = 0;
+ size_t min_initial_log_queue_size = 0;
+ size_t min_ongoing_log_queue_count = 0;
+ size_t min_ongoing_log_queue_size = 0;
+ size_t max_ongoing_log_size = 0;
+ };
+
// Constructs a MetricsLogStore that persists data into |local_state|.
- // If max_log_size is non-zero, it will not persist ongoing logs larger than
- // |max_ongoing_log_size| bytes. |signing_key| is used to generate a signature
- // of a log, which will be uploaded to validate data integrity.
+ // |storage_limits| provides log count and size limits to enforce when
+ // persisting logs to local storage. |signing_key| is used to generate a
+ // signature of a log, which will be uploaded to validate data integrity.
MetricsLogStore(PrefService* local_state,
- size_t max_ongoing_log_size,
+ StorageLimits storage_limits,
const std::string& signing_key);
~MetricsLogStore();
diff --git a/chromium/components/metrics/metrics_log_store_unittest.cc b/chromium/components/metrics/metrics_log_store_unittest.cc
index 039d443c1cb..e90b25e0ab2 100644
--- a/chromium/components/metrics/metrics_log_store_unittest.cc
+++ b/chromium/components/metrics/metrics_log_store_unittest.cc
@@ -42,7 +42,8 @@ class MetricsLogStoreTest : public testing::Test {
} // namespace
TEST_F(MetricsLogStoreTest, StandardFlow) {
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
// Make sure a new manager has a clean slate.
@@ -66,7 +67,8 @@ TEST_F(MetricsLogStoreTest, StoreAndLoad) {
// Set up some in-progress logging in a scoped log manager simulating the
// leadup to quitting, then persist as would be done on quit.
{
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
EXPECT_FALSE(log_store.has_unsent_logs());
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, base::nullopt);
@@ -77,7 +79,8 @@ TEST_F(MetricsLogStoreTest, StoreAndLoad) {
// Relaunch load and store more logs.
{
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_store.has_unsent_logs());
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
@@ -98,7 +101,8 @@ TEST_F(MetricsLogStoreTest, StoreAndLoad) {
// Relaunch and verify that once logs are handled they are not re-persisted.
{
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_store.has_unsent_logs());
@@ -132,7 +136,8 @@ TEST_F(MetricsLogStoreTest, StoreAndLoad) {
TEST_F(MetricsLogStoreTest, StoreStagedOngoingLog) {
// Ensure that types are preserved when storing staged logs.
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, base::nullopt);
log_store.StageNextLog();
@@ -144,7 +149,8 @@ TEST_F(MetricsLogStoreTest, StoreStagedOngoingLog) {
TEST_F(MetricsLogStoreTest, StoreStagedInitialLog) {
// Ensure that types are preserved when storing staged logs.
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG, base::nullopt);
log_store.StageNextLog();
@@ -156,7 +162,9 @@ TEST_F(MetricsLogStoreTest, StoreStagedInitialLog) {
TEST_F(MetricsLogStoreTest, LargeLogDiscarding) {
// Set the size threshold very low, to verify that it's honored.
- MetricsLogStore log_store(&pref_service_, 1, std::string());
+ client_.set_max_ongoing_log_size(1);
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("persisted", MetricsLog::INITIAL_STABILITY_LOG,
@@ -172,7 +180,8 @@ TEST_F(MetricsLogStoreTest, LargeLogDiscarding) {
TEST_F(MetricsLogStoreTest, DiscardOrder) {
// Ensure that the correct log is discarded if new logs are pushed while
// a log is staged.
- MetricsLogStore log_store(&pref_service_, 0, std::string());
+ MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
+ std::string());
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, base::nullopt);
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index ac659478a59..9609b2dd7b9 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -214,6 +214,10 @@ TEST_F(MetricsLogTest, BasicRecord) {
// Hard to mock.
system_profile->set_build_timestamp(
parsed.system_profile().build_timestamp());
+#if defined(OS_ANDROID)
+ system_profile->set_installer_package(
+ parsed.system_profile().installer_package());
+#endif
EXPECT_EQ(expected.SerializeAsString(), encoded);
}
@@ -420,4 +424,13 @@ TEST_F(MetricsLogTest, TruncateEvents) {
EXPECT_EQ(internal::kOmniboxEventLimit, log.uma_proto().omnibox_event_size());
}
+TEST_F(MetricsLogTest, ToInstallerPackage) {
+ using internal::ToInstallerPackage;
+ EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_NONE, ToInstallerPackage(""));
+ EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_GOOGLE_PLAY_STORE,
+ ToInstallerPackage("com.android.vending"));
+ EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_OTHER,
+ ToInstallerPackage("foo"));
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index 5109925af49..4a037ed5c23 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -118,16 +118,6 @@ const char kStabilityCrashCount[] =
const char kStabilityCrashCountDueToGmsCoreUpdate[] =
"user_experience_metrics.stability.crash_count_due_to_gms_core_update";
-// Number of times the initial stability log upload was deferred to the next
-// startup.
-const char kStabilityDeferredCount[] =
- "user_experience_metrics.stability.deferred_count";
-
-// Number of times stability data was discarded. This is accumulated since the
-// last report, even across versions.
-const char kStabilityDiscardCount[] =
- "user_experience_metrics.stability.discard_count";
-
// Number of times the browser has been run under a debugger.
const char kStabilityDebuggerPresent[] =
"user_experience_metrics.stability.debugger_present";
@@ -233,11 +223,6 @@ const char kStabilityStatsVersion[] =
const char kStabilitySystemCrashCount[] =
"user_experience_metrics.stability.system_crash_count";
-// Number of times the version number stored in prefs did not match the
-// serialized system profile version number.
-const char kStabilityVersionMismatchCount[] =
- "user_experience_metrics.stability.version_mismatch_count";
-
// The keys below are strictly increasing counters over the lifetime of
// a chrome installation. They are (optionally) sent up to the uninstall
// survey in the event of uninstallation.
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index bbaa4a3040f..2e4719ae1e4 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -42,8 +42,6 @@ extern const char kStabilityCrashCount[];
extern const char kStabilityCrashCountDueToGmsCoreUpdate[];
extern const char kStabilityDebuggerNotPresent[];
extern const char kStabilityDebuggerPresent[];
-extern const char kStabilityDeferredCount[];
-extern const char kStabilityDiscardCount[];
extern const char kStabilityExitedCleanly[];
extern const char kStabilityExtensionRendererCrashCount[];
extern const char kStabilityExtensionRendererFailedLaunchCount[];
@@ -65,7 +63,6 @@ extern const char kStabilitySessionEndCompleted[];
extern const char kStabilityStatsBuildTime[];
extern const char kStabilityStatsVersion[];
extern const char kStabilitySystemCrashCount[];
-extern const char kStabilityVersionMismatchCount[];
// Preferences for generating metrics at uninstall time.
extern const char kUninstallLaunchCount[];
diff --git a/chromium/components/metrics/metrics_reporting_service.cc b/chromium/components/metrics/metrics_reporting_service.cc
index ea9fd9c5807..9470b44c580 100644
--- a/chromium/components/metrics/metrics_reporting_service.cc
+++ b/chromium/components/metrics/metrics_reporting_service.cc
@@ -11,22 +11,13 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service_client.h"
#include "components/metrics/unsent_log_store_metrics_impl.h"
#include "components/metrics/url_constants.h"
#include "components/prefs/pref_registry_simple.h"
namespace metrics {
-namespace {
-
-// If an upload fails, and the transmission was over this byte count, then we
-// will discard the log, and not try to retransmit it. We also don't persist
-// the log to the prefs for transmission during the next chrome session if this
-// limit is exceeded.
-const size_t kUploadLogAvoidRetransmitSize = 100 * 1024;
-
-} // namespace
-
// static
void MetricsReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
ReportingService::RegisterPrefs(registry);
@@ -35,9 +26,11 @@ void MetricsReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
MetricsReportingService::MetricsReportingService(MetricsServiceClient* client,
PrefService* local_state)
- : ReportingService(client, local_state, kUploadLogAvoidRetransmitSize),
+ : ReportingService(client,
+ local_state,
+ client->GetStorageLimits().max_ongoing_log_size),
metrics_log_store_(local_state,
- kUploadLogAvoidRetransmitSize,
+ client->GetStorageLimits(),
client->GetUploadSigningKey()) {}
MetricsReportingService::~MetricsReportingService() {}
@@ -87,11 +80,13 @@ void MetricsReportingService::LogResponseOrErrorCode(int response_code,
}
}
-void MetricsReportingService::LogSuccess(size_t log_size) {
+void MetricsReportingService::LogSuccessLogSize(size_t log_size) {
UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024);
}
-void MetricsReportingService::LogLargeRejection(size_t log_size) {
-}
+void MetricsReportingService::LogSuccessMetadata(
+ const std::string& staged_log) {}
+
+void MetricsReportingService::LogLargeRejection(size_t log_size) {}
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_reporting_service.h b/chromium/components/metrics/metrics_reporting_service.h
index 3304b045583..e6b23a15e31 100644
--- a/chromium/components/metrics/metrics_reporting_service.h
+++ b/chromium/components/metrics/metrics_reporting_service.h
@@ -55,7 +55,8 @@ class MetricsReportingService : public ReportingService {
void LogResponseOrErrorCode(int response_code,
int error_code,
bool was_https) override;
- void LogSuccess(size_t log_size) override;
+ void LogSuccessLogSize(size_t log_size) override;
+ void LogSuccessMetadata(const std::string& staged_log) override;
void LogLargeRejection(size_t log_size) override;
MetricsLogStore metrics_log_store_;
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index a63c847d5de..7ca198daa65 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -299,7 +299,7 @@ void MetricsService::DisableReporting() {
reporting_service_.DisableReporting();
}
-std::string MetricsService::GetClientId() {
+std::string MetricsService::GetClientId() const {
return state_manager_->client_id();
}
@@ -396,6 +396,7 @@ void MetricsService::RecordCompletedSessionEnd() {
#if defined(OS_ANDROID) || defined(OS_IOS)
void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
+ is_in_foreground_ = false;
if (!keep_recording_in_background) {
rotation_scheduler_->Stop();
reporting_service_.Stop();
@@ -422,6 +423,7 @@ void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
}
void MetricsService::OnAppEnterForeground(bool force_open_new_log) {
+ is_in_foreground_ = true;
state_manager_->clean_exit_beacon()->WriteBeaconValue(false);
StartSchedulerIfNecessary();
@@ -509,8 +511,6 @@ void MetricsService::InitializeMetricsState() {
// provided UMA is enabled.
if (state_manager_->IsMetricsReportingEnabled()) {
has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
- if (!has_initial_stability_log)
- provider.LogStabilityLogDeferred();
}
}
@@ -520,10 +520,8 @@ void MetricsService::InitializeMetricsState() {
// number of different edge cases, such as if the last version crashed before
// it could save off a system profile or if UMA reporting is disabled (which
// normally results in stats being accumulated).
- if (version_changed && !has_initial_stability_log) {
+ if (version_changed && !has_initial_stability_log)
ClearSavedStabilityMetrics();
- provider.LogStabilityDataDiscarded();
- }
// If the version changed, the system profile is obsolete and needs to be
// cleared. This is to avoid the stability data misattribution that could
@@ -754,8 +752,6 @@ bool MetricsService::PrepareInitialStabilityLog(
local_state_, &system_profile_app_version)) {
return false;
}
- if (system_profile_app_version != prefs_previous_version)
- StabilityMetricsProvider(local_state_).LogStabilityVersionMismatch();
log_manager_.PauseCurrentLog();
log_manager_.BeginLoggingWithLog(std::move(initial_stability_log));
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index b42bb611318..596c5f19438 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -96,7 +96,7 @@ class MetricsService : public base::HistogramFlattener {
// Returns the client ID for this client, or the empty string if metrics
// recording is not currently running.
- std::string GetClientId();
+ std::string GetClientId() const;
// Returns the install date of the application, in seconds since the epoch.
int64_t GetInstallDate();
@@ -182,6 +182,14 @@ class MetricsService : public base::HistogramFlattener {
// Test hook to safely stage the current log in the log store.
bool StageCurrentLogForTest();
+ DelegatingProvider* GetDelegatingProviderForTesting() {
+ return &delegating_provider_;
+ }
+
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ bool IsInForegroundForTesting() const { return is_in_foreground_; }
+#endif
+
protected:
// Sets the persistent system profile. Virtual for tests.
virtual void SetPersistentSystemProfile(const std::string& serialized_proto,
@@ -394,6 +402,12 @@ class MetricsService : public base::HistogramFlattener {
// Indicates if loading of independent metrics is currently active.
bool independent_loader_active_ = false;
+#if defined(OS_ANDROID) || defined(OS_IOS)
+ // Indicates whether OnAppEnterForeground() (true) or OnAppEnterBackground
+ // (false) was called.
+ bool is_in_foreground_ = false;
+#endif
+
// Redundant marker to check that we completed our shutdown, and set the
// exited-cleanly bit in the prefs.
static ShutdownCleanliness clean_shutdown_status_;
diff --git a/chromium/components/metrics/metrics_service_client.cc b/chromium/components/metrics/metrics_service_client.cc
index c838a0c3a18..9ad8361748c 100644
--- a/chromium/components/metrics/metrics_service_client.cc
+++ b/chromium/components/metrics/metrics_service_client.cc
@@ -21,6 +21,33 @@ namespace {
// The minimum time in seconds between consecutive metrics report uploads.
constexpr int kMetricsUploadIntervalSecMinimum = 20;
+// If a metrics log upload fails, and the transmission is over this byte count,
+// then we will discard the log, and not try to retransmit it. We also don't
+// persist the log to the prefs for transmission during the next chrome session
+// if this limit is exceeded.
+constexpr size_t kMaxOngoingLogSize = 100 * 1024; // 100 KiB
+
+// The number of bytes of logs to save of each type (initial/ongoing). This
+// ensures that a reasonable amount of history will be stored even if there is a
+// long series of very small logs.
+constexpr size_t kMinLogQueueSize = 300 * 1024; // 300 KiB
+
+// The minimum number of "initial" logs to save, and hope to send during a
+// future Chrome session. Initial logs contain crash stats, and are pretty
+// small.
+constexpr size_t kMinInitialLogQueueCount = 20;
+
+// The minimum number of ongoing logs to save persistently, and hope to send
+// during a this or future sessions. Note that each log may be pretty large, as
+// presumably the related "initial" log wasn't sent (probably nothing was, as
+// the user was probably off-line). As a result, the log probably kept
+// accumulating while the "initial" log was stalled, and couldn't be sent. As a
+// result, we don't want to save too many of these mega-logs. A "standard
+// shutdown" will create a small log, including just the data that was not yet
+// been transmitted, and that is normal (to have exactly one ongoing_log_ at
+// startup).
+constexpr size_t kMinOngoingLogQueueCount = 8;
+
} // namespace
MetricsServiceClient::MetricsServiceClient() {}
@@ -102,6 +129,16 @@ bool MetricsServiceClient::ShouldResetClientIdsOnClonedInstall() {
return false;
}
+MetricsLogStore::StorageLimits MetricsServiceClient::GetStorageLimits() const {
+ return {
+ /*min_initial_log_queue_count=*/kMinInitialLogQueueCount,
+ /*min_initial_log_queue_size=*/kMinLogQueueSize,
+ /*min_ongoing_log_queue_count=*/kMinOngoingLogQueueCount,
+ /*min_ongoing_log_queue_size=*/kMinLogQueueSize,
+ /*max_ongoing_log_size=*/kMaxOngoingLogSize,
+ };
+}
+
void MetricsServiceClient::SetUpdateRunningServicesCallback(
const base::RepeatingClosure& callback) {
update_running_services_ = callback;
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index ea907d78820..922b610d545 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "components/metrics/metrics_log_store.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_reporting_default_state.h"
#include "third_party/metrics_proto/system_profile.pb.h"
@@ -159,6 +160,9 @@ class MetricsServiceClient {
// Checks if the cloned install detector says that client ids should be reset.
virtual bool ShouldResetClientIdsOnClonedInstall();
+ // Specifies local log storage requirements and restrictions.
+ virtual MetricsLogStore::StorageLimits GetStorageLimits() const;
+
// Sets the callback to run MetricsServiceManager::UpdateRunningServices.
void SetUpdateRunningServicesCallback(const base::RepeatingClosure& callback);
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index f692dc701e4..3229da7384b 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -216,6 +216,10 @@ int64_t MetricsStateManager::GetInstallDate() const {
return ReadInstallDate(local_state_);
}
+int MetricsStateManager::GetLowEntropySource() {
+ return entropy_state_.GetLowEntropySource();
+}
+
void MetricsStateManager::ForceClientIdCreation() {
// TODO(asvitkine): Ideally, all tests would actually set up consent properly,
// so the command-line check wouldn't be needed here.
@@ -375,10 +379,6 @@ std::string MetricsStateManager::GetHighEntropySource() {
return entropy_state_.GetHighEntropySource(initial_client_id_);
}
-int MetricsStateManager::GetLowEntropySource() {
- return entropy_state_.GetLowEntropySource();
-}
-
int MetricsStateManager::GetOldLowEntropySource() {
return entropy_state_.GetOldLowEntropySource();
}
diff --git a/chromium/components/metrics/metrics_state_manager.h b/chromium/components/metrics/metrics_state_manager.h
index d3f1f8fbddf..1f6b58222db 100644
--- a/chromium/components/metrics/metrics_state_manager.h
+++ b/chromium/components/metrics/metrics_state_manager.h
@@ -57,6 +57,9 @@ class MetricsStateManager final {
// not opted in to metrics reporting.
const std::string& client_id() const { return client_id_; }
+ // Returns the low entropy source for this client.
+ int GetLowEntropySource();
+
// The CleanExitBeacon, used to determine whether the previous Chrome browser
// session terminated gracefully.
CleanExitBeacon* clean_exit_beacon() { return &clean_exit_beacon_; }
@@ -153,9 +156,6 @@ class MetricsStateManager final {
// |provisional_client_id_| must be set before calling this.
std::string GetHighEntropySource();
- // Returns the low entropy source for this client.
- int GetLowEntropySource();
-
// Returns the old low entropy source for this client.
int GetOldLowEntropySource();
diff --git a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
index 542f4a2dc49..e12be7f7e4f 100644
--- a/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
+++ b/chromium/components/metrics/net/net_metrics_log_uploader_unittest.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/encrypted_messages/encrypted_message.pb.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc
index 79ceddcf1b5..08ca707ca83 100644
--- a/chromium/components/metrics/net/network_metrics_provider.cc
+++ b/chromium/components/metrics/net/network_metrics_provider.cc
@@ -12,8 +12,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
diff --git a/chromium/components/metrics/persistent_histograms.cc b/chromium/components/metrics/persistent_histograms.cc
index 2bb4ec104b3..7d2cc362186 100644
--- a/chromium/components/metrics/persistent_histograms.cc
+++ b/chromium/components/metrics/persistent_histograms.cc
@@ -5,7 +5,7 @@
#include "components/metrics/persistent_histograms.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/metrics/field_trial.h"
diff --git a/chromium/components/metrics/reporting_service.cc b/chromium/components/metrics/reporting_service.cc
index f374a8dfbc6..6131d4b1232 100644
--- a/chromium/components/metrics/reporting_service.cc
+++ b/chromium/components/metrics/reporting_service.cc
@@ -181,9 +181,11 @@ void ReportingService::OnLogUploadComplete(int response_code,
if (log_store()->has_staged_log()) {
// Provide boolean for error recovery (allow us to ignore response_code).
bool discard_log = false;
- const size_t log_size = log_store()->staged_log().length();
+ const std::string& staged_log = log_store()->staged_log();
+ const size_t log_size = staged_log.length();
if (upload_succeeded) {
- LogSuccess(log_size);
+ LogSuccessLogSize(log_size);
+ LogSuccessMetadata(staged_log);
} else if (log_size > max_retransmit_size_) {
LogLargeRejection(log_size);
discard_log = true;
diff --git a/chromium/components/metrics/reporting_service.h b/chromium/components/metrics/reporting_service.h
index d46f954a0fd..acddc48e547 100644
--- a/chromium/components/metrics/reporting_service.h
+++ b/chromium/components/metrics/reporting_service.h
@@ -90,7 +90,8 @@ class ReportingService {
virtual void LogResponseOrErrorCode(int response_code,
int error_code,
bool was_https) {}
- virtual void LogSuccess(size_t log_size) {}
+ virtual void LogSuccessLogSize(size_t log_size) {}
+ virtual void LogSuccessMetadata(const std::string& staged_log) {}
virtual void LogLargeRejection(size_t log_size) {}
// If recording is enabled, begins uploading the next completed log from
diff --git a/chromium/components/metrics/stability_metrics_provider.cc b/chromium/components/metrics/stability_metrics_provider.cc
index ed9c7ee6e37..c9ade4e526b 100644
--- a/chromium/components/metrics/stability_metrics_provider.cc
+++ b/chromium/components/metrics/stability_metrics_provider.cc
@@ -66,9 +66,6 @@ void StabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
0);
registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
- registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0);
- registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0);
- registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityFileMetricsUnsentFilesCount,
0);
registry->RegisterIntegerPref(prefs::kStabilityFileMetricsUnsentSamplesCount,
@@ -101,10 +98,6 @@ void StabilityMetricsProvider::ClearSavedStabilityMetrics() {
local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
- local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
- // Note: kStabilityDiscardCount is not cleared as its intent is to measure
- // the number of times data is discarded, even across versions.
- local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
// The 0 is a valid value for the below prefs, clears pref instead
// of setting to default value.
@@ -154,25 +147,6 @@ void StabilityMetricsProvider::ProvideStabilityMetrics(
if (GetAndClearPrefValue(prefs::kStabilityDebuggerNotPresent, &pref_value))
stability->set_debugger_not_present_count(pref_value);
- // Note: only logging the following histograms for non-zero values.
- if (GetAndClearPrefValue(prefs::kStabilityDeferredCount, &pref_value)) {
- UMA_STABILITY_HISTOGRAM_COUNTS_100(
- "Stability.Internals.InitialStabilityLogDeferredCount", pref_value);
- }
-
- // Note: only logging the following histograms for non-zero values.
- if (GetAndClearPrefValue(prefs::kStabilityDiscardCount, &pref_value)) {
- UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount",
- pref_value);
- }
-
- // Note: only logging the following histograms for non-zero values.
- if (GetAndClearPrefValue(prefs::kStabilityVersionMismatchCount,
- &pref_value)) {
- UMA_STABILITY_HISTOGRAM_COUNTS_100(
- "Stability.Internals.VersionMismatchCount", pref_value);
- }
-
if (local_state_->HasPrefPath(prefs::kStabilityFileMetricsUnsentFilesCount)) {
UMA_STABILITY_HISTOGRAM_COUNTS_100(
"Stability.Internals.FileMetricsProvider.BrowserMetrics."
@@ -246,22 +220,10 @@ void StabilityMetricsProvider::LogCrash(base::Time last_live_timestamp) {
#endif
}
-void StabilityMetricsProvider::LogStabilityLogDeferred() {
- IncrementPrefValue(prefs::kStabilityDeferredCount);
-}
-
-void StabilityMetricsProvider::LogStabilityDataDiscarded() {
- IncrementPrefValue(prefs::kStabilityDiscardCount);
-}
-
void StabilityMetricsProvider::LogLaunch() {
IncrementPrefValue(prefs::kStabilityLaunchCount);
}
-void StabilityMetricsProvider::LogStabilityVersionMismatch() {
- IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
-}
-
#if defined(OS_WIN)
bool StabilityMetricsProvider::IsUncleanSystemSession(
base::Time last_live_timestamp) {
diff --git a/chromium/components/metrics/stability_metrics_provider.h b/chromium/components/metrics/stability_metrics_provider.h
index 65cde34ce1f..6556885cda1 100644
--- a/chromium/components/metrics/stability_metrics_provider.h
+++ b/chromium/components/metrics/stability_metrics_provider.h
@@ -31,10 +31,7 @@ class StabilityMetricsProvider : public MetricsProvider {
void MarkSessionEndCompleted(bool end_completed);
void LogCrash(base::Time last_live_timestamp);
- void LogStabilityLogDeferred();
- void LogStabilityDataDiscarded();
void LogLaunch();
- void LogStabilityVersionMismatch();
private:
#if defined(OS_WIN)
diff --git a/chromium/components/metrics/structured/BUILD.gn b/chromium/components/metrics/structured/BUILD.gn
index f0065dc2eba..0408de8e3a5 100644
--- a/chromium/components/metrics/structured/BUILD.gn
+++ b/chromium/components/metrics/structured/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
import("//testing/test.gni")
# Structured metrics is subcomponent of UMA that gathers and reports structured
@@ -31,7 +32,8 @@ static_library("structured") {
]
}
-action("gen_structured_events") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("gen_structured_events") {
script = "//tools/metrics/structured/gen_events.py"
# Re-generate the outputs if the codegen code changes:
diff --git a/chromium/components/metrics/ukm_demographic_metrics_provider.h b/chromium/components/metrics/ukm_demographic_metrics_provider.h
index 0eb1cb90b1c..83706c8ccd1 100644
--- a/chromium/components/metrics/ukm_demographic_metrics_provider.h
+++ b/chromium/components/metrics/ukm_demographic_metrics_provider.h
@@ -20,7 +20,7 @@ namespace metrics {
// Interface of the provider of the synced user’s noised birth year and gender
// to the UKM metrics server. For more details, see the documentation of
// DemographicMetricsProvider at
-// components/metrics/demographic_metrics_provider.h.
+// components/metrics/demographics/demographic_metrics_provider.h.
class UkmDemographicMetricsProvider {
public:
virtual ~UkmDemographicMetricsProvider() = default;
diff --git a/chromium/components/metrics/unsent_log_store.cc b/chromium/components/metrics/unsent_log_store.cc
index 5175649dca9..928dd664812 100644
--- a/chromium/components/metrics/unsent_log_store.cc
+++ b/chromium/components/metrics/unsent_log_store.cc
@@ -162,6 +162,7 @@ void UnsentLogStore::MarkStagedLogAsSent() {
DCHECK_LT(static_cast<size_t>(staged_log_index_), list_.size());
if (list_[staged_log_index_]->samples_count.has_value())
total_samples_sent_ += list_[staged_log_index_]->samples_count.value();
+ metrics_->RecordSentLog();
}
void UnsentLogStore::TrimAndPersistUnsentLogs() {
@@ -303,6 +304,7 @@ void UnsentLogStore::TrimLogs() {
size_t dropped_logs_count = list_.size() - trimmed_list.size();
if (dropped_logs_count > 0)
metrics_->RecordDroppedLogsNum(dropped_logs_count);
+ metrics_->RecordIntendingToSentLogs(trimmed_list.size());
// Put the trimmed list in the correct place.
list_.swap(trimmed_list);
diff --git a/chromium/components/metrics/unsent_log_store_metrics.cc b/chromium/components/metrics/unsent_log_store_metrics.cc
index 426f4fc6b6d..de1622e1bb8 100644
--- a/chromium/components/metrics/unsent_log_store_metrics.cc
+++ b/chromium/components/metrics/unsent_log_store_metrics.cc
@@ -22,6 +22,10 @@ void UnsentLogStoreMetrics::RecordDroppedLogSize(size_t size) {}
void UnsentLogStoreMetrics::RecordDroppedLogsNum(int dropped_logs_num) {}
+void UnsentLogStoreMetrics::RecordIntendingToSentLogs(int num) {}
+
+void UnsentLogStoreMetrics::RecordSentLog() {}
+
void UnsentLogStoreMetrics::RecordLastUnsentLogMetadataMetrics(
int unsent_samples_count,
int sent_samples_count,
diff --git a/chromium/components/metrics/unsent_log_store_metrics.h b/chromium/components/metrics/unsent_log_store_metrics.h
index 013a0651f2e..69ef2ffc7d1 100644
--- a/chromium/components/metrics/unsent_log_store_metrics.h
+++ b/chromium/components/metrics/unsent_log_store_metrics.h
@@ -40,10 +40,21 @@ class UnsentLogStoreMetrics {
virtual void RecordCompressionRatio(size_t compressed_size,
size_t original_size);
+ // Records the size of a dropped log in bytes.
virtual void RecordDroppedLogSize(size_t size);
+ // Record the number of logs that were dropped (not staged). These include
+ // logs that were dropped due to be being too large and also logs that were
+ // dropped because there were too many.
virtual void RecordDroppedLogsNum(int dropped_logs_num);
+ // Records the number of logs that were not dropped and instead staged /
+ // intended to be sent.
+ virtual void RecordIntendingToSentLogs(int num);
+
+ // Record when a single staged log was sent.
+ virtual void RecordSentLog();
+
virtual void RecordLastUnsentLogMetadataMetrics(int unsent_samples_count,
int sent_samples_count,
int persisted_size_in_kb);
diff --git a/chromium/components/metrics/unsent_log_store_metrics_impl.cc b/chromium/components/metrics/unsent_log_store_metrics_impl.cc
index f533bc4b1c6..54f140081a8 100644
--- a/chromium/components/metrics/unsent_log_store_metrics_impl.cc
+++ b/chromium/components/metrics/unsent_log_store_metrics_impl.cc
@@ -15,20 +15,30 @@ void UnsentLogStoreMetricsImpl::RecordLogReadStatus(
UnsentLogStoreMetrics::END_RECALL_STATUS);
}
-void UnsentLogStoreMetricsImpl::RecordCompressionRatio(
- size_t compressed_size, size_t original_size) {
- base::UmaHistogramPercentage(
+void UnsentLogStoreMetricsImpl::RecordCompressionRatio(size_t compressed_size,
+ size_t original_size) {
+ base::UmaHistogramPercentageObsoleteDoNotUse(
"UMA.ProtoCompressionRatio",
static_cast<int>(100 * compressed_size / original_size));
}
void UnsentLogStoreMetricsImpl::RecordDroppedLogSize(size_t size) {
+ base::UmaHistogramCounts1M("UMA.UnsentLogs.DroppedSize",
+ static_cast<int>(size));
}
void UnsentLogStoreMetricsImpl::RecordDroppedLogsNum(int dropped_logs_num) {
base::UmaHistogramCounts1M("UMA.UnsentLogs.Dropped", dropped_logs_num);
}
+void RecordIntendingToSentLogs(int num) {
+ base::UmaHistogramExactLinear("UMA.UnsentLogs.IntendingToSend", num, 22);
+}
+
+void RecordSentLog() {
+ base::UmaHistogramBoolean("UMA.UnsentLogs.Sent", true);
+}
+
void UnsentLogStoreMetricsImpl::RecordLastUnsentLogMetadataMetrics(
int unsent_samples_count,
int sent_samples_count,
@@ -50,9 +60,10 @@ void UnsentLogStoreMetricsImpl::RecordLastUnsentLogMetadataMetrics(
persisted_size_in_kb);
if (sent_samples_count == 0 && unsent_samples_count == 0) {
- base::UmaHistogramPercentage("UMA.UnsentLogs.UnsentPercentage", 0);
+ base::UmaHistogramPercentageObsoleteDoNotUse(
+ "UMA.UnsentLogs.UnsentPercentage", 0);
} else {
- base::UmaHistogramPercentage(
+ base::UmaHistogramPercentageObsoleteDoNotUse(
"UMA.UnsentLogs.UnsentPercentage",
100 * unsent_samples_count /
(unsent_samples_count + sent_samples_count));
diff --git a/chromium/components/metrics/unsent_log_store_metrics_impl_unittest.cc b/chromium/components/metrics/unsent_log_store_metrics_impl_unittest.cc
index 8027cb6b9c4..1cc1a2b8e36 100644
--- a/chromium/components/metrics/unsent_log_store_metrics_impl_unittest.cc
+++ b/chromium/components/metrics/unsent_log_store_metrics_impl_unittest.cc
@@ -10,6 +10,22 @@
namespace metrics {
+TEST(UnsentLogStoreMetricsImplTest, RecordDroppedLogSize) {
+ UnsentLogStoreMetricsImpl impl;
+ base::HistogramTester histogram_tester;
+
+ impl.RecordDroppedLogSize(99999);
+ histogram_tester.ExpectBucketCount("UMA.UnsentLogs.DroppedSize", 99999, 1);
+}
+
+TEST(UnsentLogStoreMetricsImplTest, RecordDroppedLogsNum) {
+ UnsentLogStoreMetricsImpl impl;
+ base::HistogramTester histogram_tester;
+
+ impl.RecordDroppedLogsNum(17);
+ histogram_tester.ExpectBucketCount("UMA.UnsentLogs.Dropped", 17, 1);
+}
+
TEST(UnsentLogStoreMetricsImplTest, RecordLastUnsentLogMetadataMetrics) {
base::test::ScopedFeatureList feature_override;
feature_override.InitAndEnableFeature(
diff --git a/chromium/components/mirroring/service/BUILD.gn b/chromium/components/mirroring/service/BUILD.gn
index f81ff53e27f..fd23c82a21a 100644
--- a/chromium/components/mirroring/service/BUILD.gn
+++ b/chromium/components/mirroring/service/BUILD.gn
@@ -39,6 +39,7 @@ component("mirroring_service") {
public_deps = [ "//base" ]
deps = [
+ "//build:chromeos_buildflags",
"//components/mirroring/mojom:service",
"//components/openscreen_platform",
"//components/openscreen_platform:openscreen_platform_network_service",
diff --git a/chromium/components/mirroring/service/message_dispatcher.cc b/chromium/components/mirroring/service/message_dispatcher.cc
index da5de2c03a0..8503563e6dd 100644
--- a/chromium/components/mirroring/service/message_dispatcher.cc
+++ b/chromium/components/mirroring/service/message_dispatcher.cc
@@ -5,7 +5,7 @@
#include "components/mirroring/service/message_dispatcher.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/timer/timer.h"
diff --git a/chromium/components/mirroring/service/remoting_sender.cc b/chromium/components/mirroring/service/remoting_sender.cc
index 66765368548..a9159700b3f 100644
--- a/chromium/components/mirroring/service/remoting_sender.cc
+++ b/chromium/components/mirroring/service/remoting_sender.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/time/default_tick_clock.h"
#include "media/cast/constants.h"
@@ -104,6 +104,10 @@ void RemotingSender::ProcessNextInputTask() {
void RemotingSender::ReadFrame(uint32_t size) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!is_reading_);
+
+ if (HadError()) {
+ return;
+ }
if (!data_pipe_reader_->IsPipeValid()) {
VLOG(1) << "Data pipe handle no longer valid.";
OnRemotingDataStreamError();
@@ -206,10 +210,16 @@ void RemotingSender::OnInputTaskComplete() {
}
void RemotingSender::OnRemotingDataStreamError() {
+ // NOTE: This method must be idemptotent as it may be called more than once.
data_pipe_reader_.reset();
stream_sender_.reset();
if (!error_callback_.is_null())
std::move(error_callback_).Run();
}
+bool RemotingSender::HadError() const {
+ DCHECK_EQ(!data_pipe_reader_, !stream_sender_.is_bound());
+ return !data_pipe_reader_;
+}
+
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/remoting_sender.h b/chromium/components/mirroring/service/remoting_sender.h
index 51c7c4d097c..ac3ac21de5d 100644
--- a/chromium/components/mirroring/service/remoting_sender.h
+++ b/chromium/components/mirroring/service/remoting_sender.h
@@ -81,6 +81,9 @@ class COMPONENT_EXPORT(MIRRORING_SERVICE) RemotingSender final
void OnRemotingDataStreamError();
+ // Returns true if OnRemotingDataStreamError was called.
+ bool HadError() const;
+
SEQUENCE_CHECKER(sequence_checker_);
const base::TickClock* clock_;
diff --git a/chromium/components/mirroring/service/remoting_sender_unittest.cc b/chromium/components/mirroring/service/remoting_sender_unittest.cc
index 0ce5ba55111..d27c48a2eec 100644
--- a/chromium/components/mirroring/service/remoting_sender_unittest.cc
+++ b/chromium/components/mirroring/service/remoting_sender_unittest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/run_loop.h"
diff --git a/chromium/components/mirroring/service/rtp_stream_unittest.cc b/chromium/components/mirroring/service/rtp_stream_unittest.cc
index 739559772da..a6202c271cb 100644
--- a/chromium/components/mirroring/service/rtp_stream_unittest.cc
+++ b/chromium/components/mirroring/service/rtp_stream_unittest.cc
@@ -4,7 +4,7 @@
#include "components/mirroring/service/rtp_stream.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/simple_test_tick_clock.h"
@@ -92,7 +92,7 @@ TEST_F(RtpStreamTest, VideoStreaming) {
auto video_sender = std::make_unique<media::cast::VideoSender>(
cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
base::DoNothing(), base::DoNothing(), base::DoNothing(), &transport_,
- base::DoNothing());
+ base::DoNothing(), base::DoNothing());
VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr());
{
base::RunLoop run_loop;
diff --git a/chromium/components/mirroring/service/session.cc b/chromium/components/mirroring/service/session.cc
index 27624971fc1..a517aae7b08 100644
--- a/chromium/components/mirroring/service/session.cc
+++ b/chromium/components/mirroring/service/session.cc
@@ -11,10 +11,12 @@
#include <vector>
#include "base/bind.h"
+#include "base/cpu.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -27,6 +29,7 @@
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/mirroring/service/captured_audio_input.h"
#include "components/mirroring/service/udp_socket_client.h"
#include "components/mirroring/service/video_capture_client.h"
@@ -152,6 +155,15 @@ bool IsHardwareVP8EncodingSupported(
bool IsHardwareH264EncodingSupported(
const std::vector<media::VideoEncodeAccelerator::SupportedProfile>&
profiles) {
+// TODO(b/169533953): Look into chromecast fails to decode bitstreams produced
+// by the AMD HW encoder.
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+ static const base::NoDestructor<base::CPU> cpuid;
+ static const bool is_amd = cpuid->vendor_name() == "AuthenticAMD";
+ if (is_amd)
+ return false;
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+
// TODO(crbug.com/1015482): Look into why H.264 hardware encoder on MacOS is
// broken.
// TODO(crbug.com/1015482): Look into HW encoder initialization issues on Win.
@@ -771,6 +783,8 @@ void Session::OnAnswer(const std::vector<FrameSenderConfig>& audio_configs,
weak_factory_.GetWeakPtr()),
cast_transport_.get(),
base::BindRepeating(&Session::SetTargetPlayoutDelay,
+ weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&Session::ProcessFeedback,
weak_factory_.GetWeakPtr()));
video_stream_ = std::make_unique<VideoRtpStream>(
std::move(video_sender), weak_factory_.GetWeakPtr());
@@ -834,6 +848,12 @@ void Session::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
video_stream_->SetTargetPlayoutDelay(playout_delay);
}
+void Session::ProcessFeedback(const media::VideoFrameFeedback& feedback) {
+ if (video_capture_client_) {
+ video_capture_client_->ProcessFeedback(feedback);
+ }
+}
+
// TODO(issuetracker.google.com/159352836): Refactor to use libcast's
// OFFER message format.
void Session::CreateAndSendOffer() {
diff --git a/chromium/components/mirroring/service/session.h b/chromium/components/mirroring/service/session.h
index 6231e7318e9..63f7dafbce7 100644
--- a/chromium/components/mirroring/service/session.h
+++ b/chromium/components/mirroring/service/session.h
@@ -20,6 +20,7 @@
#include "components/mirroring/service/rtp_stream.h"
#include "components/mirroring/service/wifi_status_monitor.h"
#include "gpu/config/gpu_info.h"
+#include "media/base/video_frame_feedback.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/mojo/mojom/video_encode_accelerator.mojom.h"
@@ -141,6 +142,9 @@ class COMPONENT_EXPORT(MIRRORING_SERVICE) Session final
// Callback by media::cast::VideoSender to set a new target playout delay.
void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
+ // Callback by media::cast::VideoSender to report resource utilization.
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback);
+
media::VideoEncodeAccelerator::SupportedProfiles GetSupportedVeaProfiles();
// Create and send OFFER message.
diff --git a/chromium/components/mirroring/service/video_capture_client.cc b/chromium/components/mirroring/service/video_capture_client.cc
index b5e59b60f12..3e9a2656a41 100644
--- a/chromium/components/mirroring/service/video_capture_client.cc
+++ b/chromium/components/mirroring/service/video_capture_client.cc
@@ -235,7 +235,7 @@ void VideoCaptureClient::OnBufferReady(int32_t buffer_id,
}
frame->AddDestructionObserver(
base::BindOnce(&VideoCaptureClient::DidFinishConsumingFrame,
- frame->feedback(), std::move(buffer_finished_callback)));
+ std::move(buffer_finished_callback)));
frame->set_metadata(info->metadata);
if (info->color_space.has_value())
@@ -258,8 +258,7 @@ void VideoCaptureClient::OnBufferDestroyed(int32_t buffer_id) {
void VideoCaptureClient::OnClientBufferFinished(
int buffer_id,
- base::ReadOnlySharedMemoryMapping mapping,
- media::VideoFrameFeedback feedback) {
+ base::ReadOnlySharedMemoryMapping mapping) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(3) << __func__ << ": buffer_id=" << buffer_id;
@@ -269,17 +268,23 @@ void VideoCaptureClient::OnClientBufferFinished(
return;
}
- video_capture_host_->ReleaseBuffer(DeviceId(), buffer_id, feedback);
+ video_capture_host_->ReleaseBuffer(DeviceId(), buffer_id, feedback_);
+ feedback_ = media::VideoFrameFeedback();
}
// static
void VideoCaptureClient::DidFinishConsumingFrame(
- const media::VideoFrameFeedback* feedback,
BufferFinishedCallback callback) {
// Note: This function may be called on any thread by the VideoFrame
- // destructor. |feedback| is still valid for read-access at this point.
+ // destructor.
DCHECK(!callback.is_null());
- std::move(callback).Run(*feedback);
+ std::move(callback).Run();
+}
+
+void VideoCaptureClient::ProcessFeedback(
+ const media::VideoFrameFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ feedback_ = feedback;
}
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/video_capture_client.h b/chromium/components/mirroring/service/video_capture_client.h
index 35d0bc39bb9..10bb39e7820 100644
--- a/chromium/components/mirroring/service/video_capture_client.h
+++ b/chromium/components/mirroring/service/video_capture_client.h
@@ -48,6 +48,9 @@ class COMPONENT_EXPORT(MIRRORING_SERVICE) VideoCaptureClient
void Resume(FrameDeliverCallback deliver_callback);
+ // Feedback callback.
+ void ProcessFeedback(const media::VideoFrameFeedback& feedback);
+
// Requests to receive a refreshed captured video frame. Do nothing if the
// capturing device is not started or the capturing is paused.
void RequestRefreshFrame();
@@ -61,16 +64,13 @@ class COMPONENT_EXPORT(MIRRORING_SERVICE) VideoCaptureClient
void OnBufferDestroyed(int32_t buffer_id) override;
private:
- using BufferFinishedCallback =
- base::OnceCallback<void(media::VideoFrameFeedback)>;
+ using BufferFinishedCallback = base::OnceCallback<void()>;
// Called by the VideoFrame destructor.
- static void DidFinishConsumingFrame(const media::VideoFrameFeedback* feedback,
- BufferFinishedCallback callback);
+ static void DidFinishConsumingFrame(BufferFinishedCallback callback);
// Reports the utilization, unmaps the shared memory, and returns the buffer.
void OnClientBufferFinished(int buffer_id,
- base::ReadOnlySharedMemoryMapping mapping,
- media::VideoFrameFeedback feedback);
+ base::ReadOnlySharedMemoryMapping mapping);
const media::VideoCaptureParams params_;
const mojo::Remote<media::mojom::VideoCaptureHost> video_capture_host_;
@@ -104,6 +104,9 @@ class COMPONENT_EXPORT(MIRRORING_SERVICE) VideoCaptureClient
// |buffer_id| is the key to this map.
MappingMap mapped_buffers_;
+ // Latest received feedback.
+ media::VideoFrameFeedback feedback_;
+
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<VideoCaptureClient> weak_factory_{this};
diff --git a/chromium/components/mirroring/service/video_capture_client_unittest.cc b/chromium/components/mirroring/service/video_capture_client_unittest.cc
index 888dd404354..c3fa4bddb8a 100644
--- a/chromium/components/mirroring/service/video_capture_client_unittest.cc
+++ b/chromium/components/mirroring/service/video_capture_client_unittest.cc
@@ -61,7 +61,7 @@ class VideoCaptureClientTest : public ::testing::Test,
MOCK_METHOD1(OnFrameReceived, void(const gfx::Size&));
void OnFrameReady(scoped_refptr<media::VideoFrame> video_frame) {
- *video_frame->feedback() = kFeedback;
+ client_->ProcessFeedback(kFeedback);
OnFrameReceived(video_frame->coded_size());
}
diff --git a/chromium/components/module_installer/android/module.cc b/chromium/components/module_installer/android/module.cc
index 1a6d2455270..f7b41ca39b3 100644
--- a/chromium/components/module_installer/android/module.cc
+++ b/chromium/components/module_installer/android/module.cc
@@ -77,9 +77,9 @@ void RegisterJni(JNIEnv* env, void* library_handle, const std::string& name) {
CHECK(registration_function(env)) << "JNI registration failed: " << name;
}
-void LoadResources(const std::string& pak) {
+void LoadResources(const std::string& pak, const std::string& name) {
module_installer::ScopedAllowModulePakLoad scoped_allow_module_pak_load;
- ui::LoadPackFileFromApk("assets/" + pak);
+ ui::LoadPackFileFromApk("assets/" + pak, name);
}
} // namespace
@@ -107,7 +107,7 @@ static void JNI_Module_LoadNative(
std::vector<std::string> paks;
base::android::AppendJavaStringArrayToStringVector(env, jpaks, &paks);
for (const auto& pak : paks) {
- LoadResources(pak);
+ LoadResources(pak, name);
}
}
diff --git a/chromium/components/nacl/browser/BUILD.gn b/chromium/components/nacl/browser/BUILD.gn
index f34a2c74aaa..d9b9976ce74 100644
--- a/chromium/components/nacl/browser/BUILD.gn
+++ b/chromium/components/nacl/browser/BUILD.gn
@@ -4,23 +4,12 @@
import("//components/nacl/features.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
assert(enable_nacl)
static_library("browser") {
sources = [
"bad_message.cc",
"bad_message.h",
- "nacl_broker_host_win.cc",
- "nacl_broker_host_win.h",
- "nacl_broker_service_win.cc",
- "nacl_broker_service_win.h",
"nacl_browser.cc",
"nacl_browser.h",
"nacl_file_host.cc",
@@ -60,6 +49,15 @@ static_library("browser") {
data_deps = []
+ if (is_win) {
+ sources += [
+ "nacl_broker_host_win.cc",
+ "nacl_broker_host_win.h",
+ "nacl_broker_service_win.cc",
+ "nacl_broker_service_win.h",
+ ]
+ }
+
if (is_linux || is_chromeos) {
sources += [
"../zygote/nacl_fork_delegate_linux.cc",
diff --git a/chromium/components/nacl/common/BUILD.gn b/chromium/components/nacl/common/BUILD.gn
index 984b636d8d5..4755bdb73d6 100644
--- a/chromium/components/nacl/common/BUILD.gn
+++ b/chromium/components/nacl/common/BUILD.gn
@@ -6,13 +6,6 @@ import("//build/buildflag_header.gni")
import("//components/nacl/features.gni")
import("//mojo/public/tools/bindings/mojom.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
if (enable_nacl) {
# This is separate so it can be used by ../broker:nacl64.
static_library("minimal") {
@@ -99,12 +92,16 @@ if (enable_nacl) {
}
source_set("debug_exception_handler") {
- sources = [
- "nacl_debug_exception_handler_win.cc",
- "nacl_debug_exception_handler_win.h",
- ]
+ sources = []
deps = [ "//base" ]
+
+ if (is_win) {
+ sources += [
+ "nacl_debug_exception_handler_win.cc",
+ "nacl_debug_exception_handler_win.h",
+ ]
+ }
}
source_set("nacl_error_code") {
diff --git a/chromium/components/nacl/loader/BUILD.gn b/chromium/components/nacl/loader/BUILD.gn
index b21b3d1537f..f1f943c33e4 100644
--- a/chromium/components/nacl/loader/BUILD.gn
+++ b/chromium/components/nacl/loader/BUILD.gn
@@ -8,13 +8,6 @@ import("//build/config/nacl/config.gni")
import("//components/nacl/features.gni")
import("//testing/test.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
assert(enable_nacl)
# This is separate so it can be used by ../broker:nacl64.
@@ -26,9 +19,6 @@ source_set("minimal") {
"nacl_listener.h",
"nacl_main.cc",
"nacl_main_platform_delegate.h",
- "nacl_main_platform_delegate_linux.cc",
- "nacl_main_platform_delegate_mac.mm",
- "nacl_main_platform_delegate_win.cc",
"nacl_trusted_listener.cc",
"nacl_trusted_listener.h",
"nacl_validation_db.h",
@@ -50,6 +40,18 @@ source_set("minimal") {
"//sandbox",
"//services/service_manager/public/cpp",
]
+
+ if (is_win) {
+ sources += [ "nacl_main_platform_delegate_win.cc" ]
+ }
+
+ if (is_mac) {
+ sources += [ "nacl_main_platform_delegate_mac.mm" ]
+ }
+
+ if (is_linux || is_chromeos) {
+ sources += [ "nacl_main_platform_delegate_linux.cc" ]
+ }
}
# This exists just to make 'gn check' happy with :minimal and
@@ -61,11 +63,14 @@ source_set("minimal_content_dummy") {
sources = [
"//content/public/common/main_function_params.h",
"//content/public/common/sandbox_init.h",
- "//content/public/common/zygote/sandbox_support_linux.h",
]
# Deps required by the above headers.
deps = [ "//media:media_buildflags" ]
+
+ if (is_linux || is_chromeos) {
+ sources += [ "//content/public/common/zygote/sandbox_support_linux.h" ]
+ }
}
source_set("loader") {
@@ -210,7 +215,6 @@ if (is_win && target_cpu == "x86" && current_cpu == "x64") {
if (is_nacl_nonsfi) {
executable("nacl_helper_nonsfi_nexe") {
output_name = "nacl_helper_nonsfi"
- set_sources_assignment_filter([])
sources = [
"nacl_helper_linux.cc",
"nacl_helper_linux.h",
@@ -247,7 +251,6 @@ if (is_nacl_nonsfi) {
}
source_set("nacl_helper_nonsfi_sandbox") {
- set_sources_assignment_filter([])
sources = [
"nonsfi/nonsfi_sandbox.cc",
"nonsfi/nonsfi_sandbox.h",
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
index 968a335690f..b61f1756c69 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/navigation_interception/navigation_params.h"
diff --git a/chromium/components/net_log/chrome_net_log.cc b/chromium/components/net_log/chrome_net_log.cc
index 5a902747059..b0cdd069149 100644
--- a/chromium/components/net_log/chrome_net_log.cc
+++ b/chromium/components/net_log/chrome_net_log.cc
@@ -4,27 +4,16 @@
#include "components/net_log/chrome_net_log.h"
+#include <utility>
+
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/values.h"
#include "components/version_info/version_info.h"
-#include "net/log/net_log_util.h"
namespace net_log {
-base::Value GetConstantsForNetLog(
- const base::CommandLine::StringType& command_line_string,
- const std::string& channel_string) {
- base::Value constants_dict = net::GetNetConstants();
-
- auto platform_dict =
- GetPlatformConstantsForNetLog(command_line_string, channel_string);
- if (platform_dict)
- constants_dict.MergeDictionary(platform_dict.get());
- return constants_dict;
-}
-
std::unique_ptr<base::DictionaryValue> GetPlatformConstantsForNetLog(
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string) {
diff --git a/chromium/components/net_log/chrome_net_log.h b/chromium/components/net_log/chrome_net_log.h
index 5b5a93eea5a..cb5a56eb89b 100644
--- a/chromium/components/net_log/chrome_net_log.h
+++ b/chromium/components/net_log/chrome_net_log.h
@@ -13,23 +13,11 @@
namespace base {
class DictionaryValue;
-class Value;
}
namespace net_log {
-// Returns all the constants to include in NetLog files. This includes both
-// platform-specific details (GetPlatformConstantsForNetLog()) as well as the
-// basic src/net constants (net::GetNetConstants()) for things like symbolic
-// names of error codes.
-//
-// Safe to call on any thread.
-base::Value GetConstantsForNetLog(
- const base::CommandLine::StringType& command_line_string,
- const std::string& channel_string);
-
-// Returns constants to include in NetLog files for debugging purposes, which
-// includes information such as:
+// Returns constants to include in NetLog files including information such as:
//
// * The version and build of Chrome
// * The command line arguments Chrome was launched with
diff --git a/chromium/components/net_log/net_export_file_writer.cc b/chromium/components/net_log/net_export_file_writer.cc
index 72e588ae750..f430b2e9450 100644
--- a/chromium/components/net_log/net_export_file_writer.cc
+++ b/chromium/components/net_log/net_export_file_writer.cc
@@ -9,8 +9,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
diff --git a/chromium/components/net_log/net_log_proxy_source_unittest.cc b/chromium/components/net_log/net_log_proxy_source_unittest.cc
index 9e51088b74e..9ce7a1a8d24 100644
--- a/chromium/components/net_log/net_log_proxy_source_unittest.cc
+++ b/chromium/components/net_log/net_log_proxy_source_unittest.cc
@@ -6,7 +6,7 @@
#include "base/run_loop.h"
#include "base/synchronization/lock.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "net/log/net_log.h"
#include "net/log/net_log_with_source.h"
diff --git a/chromium/components/net_log/resources/net_export.html b/chromium/components/net_log/resources/net_export.html
index d76294355f5..3f10870a7cd 100644
--- a/chromium/components/net_log/resources/net_export.html
+++ b/chromium/components/net_log/resources/net_export.html
@@ -11,11 +11,13 @@
<script src="chrome://resources/js/ios/web_ui.js"></script>
</if>
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://net-export/net_export.js"></script>
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="net_export.css">
+<link rel="icon" id="fav-icon">
<title>Network Log Export</title>
</head>
<body>
@@ -43,9 +45,17 @@
<div class="section-container">
Click the button to start logging future network activity to a file on
- disk. The log includes details of network activity from all of Chrome,
+ disk.
+ <if expr="not(is_ios)">
+ The log includes details of network activity from all of Chrome,
including incognito and non-incognito tabs, visited URLs, and
information about the network configuration.
+ </if>
+ <if expr="is_ios">
+ The log includes details of network activity handled by Chrome's
+ internal network stack. Note, this does not include network requests
+ for ordinary web content, which are instead handled by WKWebView.
+ </if>
<a href="https://dev.chromium.org/for-testers/providing-network-details"
target="_blank">
See the Chromium website for more detailed instructions.</a>
@@ -180,7 +190,7 @@
<b><span class="warning">PRIVACY</span></b>: Be aware when
sharing your network logs that they may contain private information. At
a minimum, they list the URLs and hostnames of sites visited while
- logging was enabled.
+ logging was enabled.
<a href="#" id="privacy-read-more-link">Read more...</a>
<div id="privacy-read-more">
diff --git a/chromium/components/net_log/resources/net_export.js b/chromium/components/net_log/resources/net_export.js
index 5d4ca989e90..520fce30207 100644
--- a/chromium/components/net_log/resources/net_export.js
+++ b/chromium/components/net_log/resources/net_export.js
@@ -210,7 +210,10 @@ const NetExportView = (function() {
*/
renderLogging_(info) {
this.showStateDiv_(kIdStateDivLogging);
-
+ this.setFavicon_(
+ 'data:image/svg+xml,<svg version="1.1" ' +
+ 'xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">' +
+ '<circle cx="16" cy="16" r="14" fill="red" stroke="black" /></svg>');
$(kIdStopLoggingButton).onclick = this.onStopLogging_.bind(this);
$(kIdCaptureModeLogging).textContent = this.getCaptureModeText_(info);
$(kIdFilePathLogging).textContent = info.file;
@@ -220,6 +223,7 @@ const NetExportView = (function() {
* Updates the UI to display the state when logging has stopped.
*/
renderStoppedLogging_(info) {
+ this.setFavicon_('data:image/x-icon;base64,');
this.showStateDiv_(kIdStateDivStopped);
// The email button is only available in the mobile UI.
@@ -287,6 +291,13 @@ const NetExportView = (function() {
$(curDivId).hidden = divId !== curDivId;
}
},
+
+ /**
+ * Sets the icon for the tab to reflect current capturing state.
+ */
+ setFavicon_(dataUrl) {
+ document.getElementById('fav-icon').href = dataUrl;
+ }
};
return NetExportView;
diff --git a/chromium/components/neterror/resources/neterror.html b/chromium/components/neterror/resources/neterror.html
index 804f41ca5b8..d3cbee72270 100644
--- a/chromium/components/neterror/resources/neterror.html
+++ b/chromium/components/neterror/resources/neterror.html
@@ -2,6 +2,7 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#fff">
<meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=no">
@@ -47,7 +48,6 @@
</div>
</div>
</div>
- <div id="diagnose-frame" class="hidden"></div>
<div id="download-links-wrapper" class="hidden">
<div id="download-link-wrapper">
<a id="download-link" class="link-button"
diff --git a/chromium/components/neterror/resources/neterror.js b/chromium/components/neterror/resources/neterror.js
index 3b124862f4d..34261064359 100644
--- a/chromium/components/neterror/resources/neterror.js
+++ b/chromium/components/neterror/resources/neterror.js
@@ -56,18 +56,9 @@ function toggleHelpBox() {
}
function diagnoseErrors() {
-// <if expr="not chromeos">
-if (window.errorPageController) {
- errorPageController.diagnoseErrorsButtonClick();
-}
-// </if>
-// <if expr="chromeos">
- const extensionId = 'idddmepepmjcgiedknnmlbadcokidhoa';
- const diagnoseFrame = document.getElementById('diagnose-frame');
- diagnoseFrame.innerHTML =
- '<iframe src="chrome-extension://' + extensionId +
- '/index.html"></iframe>';
-// </if>
+ if (window.errorPageController) {
+ errorPageController.diagnoseErrorsButtonClick();
+ }
}
// Subframes use a different layout but the same html file. This is to make it
diff --git a/chromium/components/network_session_configurator/OWNERS b/chromium/components/network_session_configurator/OWNERS
index a04a69bfbef..29292e8c62a 100644
--- a/chromium/components/network_session_configurator/OWNERS
+++ b/chromium/components/network_session_configurator/OWNERS
@@ -1,5 +1,4 @@
bnc@chromium.org
-zhongyi@chromium.org
file://net/OWNERS
file://net/quic/OWNERS # For QUICHE rolls only.
# COMPONENT: Internals>Network
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator.cc b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
index 701d81933c3..8e63649f305 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
@@ -23,6 +23,7 @@
#include "components/network_session_configurator/common/network_features.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/variations/variations_associated_data.h"
+#include "components/variations/variations_switches.h"
#include "net/base/host_mapping_rules.h"
#include "net/http/http_stream_factory.h"
#include "net/quic/platform/impl/quic_flags_impl.h"
@@ -458,9 +459,10 @@ size_t GetQuicMaxPacketLength(const VariationParameters& quic_trial_params) {
quic::ParsedQuicVersionVector GetQuicVersions(
const VariationParameters& quic_trial_params) {
+ std::string trial_versions_str =
+ GetVariationParam(quic_trial_params, "quic_version");
quic::ParsedQuicVersionVector trial_versions =
- quic::ParseQuicVersionVectorString(
- GetVariationParam(quic_trial_params, "quic_version"));
+ quic::ParseQuicVersionVectorString(trial_versions_str);
const bool obsolete_versions_allowed = base::LowerCaseEqualsASCII(
GetVariationParam(quic_trial_params, "obsolete_versions_allowed"),
"true");
@@ -468,12 +470,18 @@ quic::ParsedQuicVersionVector GetQuicVersions(
quic::ParsedQuicVersionVector filtered_versions;
quic::ParsedQuicVersionVector obsolete_versions =
net::ObsoleteQuicVersions();
+ bool found_obsolete_version = false;
for (const quic::ParsedQuicVersion& version : trial_versions) {
if (std::find(obsolete_versions.begin(), obsolete_versions.end(),
version) == obsolete_versions.end()) {
filtered_versions.push_back(version);
+ } else {
+ found_obsolete_version = true;
}
}
+ if (found_obsolete_version) {
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.FinchObsoleteVersion", true);
+ }
trial_versions = filtered_versions;
}
return trial_versions;
@@ -486,7 +494,44 @@ bool ShouldEnableServerPushCancelation(
"true");
}
-void ConfigureQuicParams(base::StringPiece quic_trial_group,
+bool AreQuicParamsValid(const base::CommandLine& command_line,
+ base::StringPiece quic_trial_group,
+ const VariationParameters& quic_trial_params) {
+ if (command_line.HasSwitch(variations::switches::kForceFieldTrialParams)) {
+ // Skip validation of params from the command line.
+ return true;
+ }
+ if (!base::LowerCaseEqualsASCII(
+ GetVariationParam(quic_trial_params, "enable_quic"), "true")) {
+ // Params that don't explicitly enable QUIC do not carry channel or epoch.
+ return true;
+ }
+ const std::string channel_string =
+ GetVariationParam(quic_trial_params, "channel");
+ if (channel_string.length() != 1) {
+ // Params without a valid channel are invalid.
+ return false;
+ }
+ const std::string epoch_string =
+ GetVariationParam(quic_trial_params, "epoch");
+ if (epoch_string.length() != 8) {
+ // Params without a valid epoch are invalid.
+ return false;
+ }
+ int epoch;
+ if (!base::StringToInt(epoch_string, &epoch)) {
+ // Failed to parse epoch as int.
+ return false;
+ }
+ if (epoch < 20201019) {
+ // All channels currently have an epoch of at least 20201019.
+ return false;
+ }
+ return true;
+}
+
+void ConfigureQuicParams(const base::CommandLine& command_line,
+ base::StringPiece quic_trial_group,
const VariationParameters& quic_trial_params,
bool is_quic_force_disabled,
const std::string& quic_user_agent_id,
@@ -497,6 +542,14 @@ void ConfigureQuicParams(base::StringPiece quic_trial_group,
params->enable_quic = false;
}
+ const bool params_are_valid =
+ AreQuicParamsValid(command_line, quic_trial_group, quic_trial_params);
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.FinchConfigIsValid", params_are_valid);
+ if (!params_are_valid) {
+ // Skip parsing of invalid params.
+ return;
+ }
+
params->enable_server_push_cancellation =
ShouldEnableServerPushCancelation(quic_trial_params);
@@ -638,7 +691,7 @@ void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line,
VariationParameters quic_trial_params;
if (!variations::GetVariationParams(kQuicFieldTrialName, &quic_trial_params))
quic_trial_params.clear();
- ConfigureQuicParams(quic_trial_group, quic_trial_params,
+ ConfigureQuicParams(command_line, quic_trial_group, quic_trial_params,
is_quic_force_disabled, quic_user_agent_id, params,
quic_params);
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index 6cf480e0ed7..16cb126fe36 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -146,6 +146,45 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromParams) {
EXPECT_TRUE(params_.enable_quic);
}
+TEST_F(NetworkSessionConfiguratorTest, ValidQuicParams) {
+ quic::ParsedQuicVersion version = quic::ParsedQuicVersion::Draft29();
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["enable_quic"] = "true";
+ field_trial_params["channel"] = "T";
+ field_trial_params["epoch"] = "20201019";
+ field_trial_params["quic_version"] = quic::AlpnForVersion(version);
+ variations::AssociateVariationParams("QUIC", "ValidQuicParams",
+ field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "ValidQuicParams");
+
+ ParseFieldTrials();
+
+ EXPECT_TRUE(params_.enable_quic);
+ EXPECT_EQ(quic_params_.supported_versions,
+ quic::ParsedQuicVersionVector{version});
+ EXPECT_NE(quic_params_.supported_versions,
+ net::DefaultSupportedQuicVersions());
+}
+
+TEST_F(NetworkSessionConfiguratorTest, InvalidQuicParams) {
+ quic::ParsedQuicVersion version = quic::ParsedQuicVersion::Draft29();
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["enable_quic"] = "true";
+ // These params are missing channel and epoch.
+ field_trial_params["quic_version"] = quic::AlpnForVersion(version);
+ variations::AssociateVariationParams("QUIC", "InvalidQuicParams",
+ field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("QUIC", "InvalidQuicParams");
+
+ ParseFieldTrials();
+
+ EXPECT_TRUE(params_.enable_quic);
+ EXPECT_EQ(quic_params_.supported_versions,
+ net::DefaultSupportedQuicVersions());
+ EXPECT_NE(quic_params_.supported_versions,
+ quic::ParsedQuicVersionVector{version});
+}
+
TEST_F(NetworkSessionConfiguratorTest, EnableQuicForDataReductionProxy) {
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
base::FieldTrialList::CreateFieldTrial("DataReductionProxyUseQuic",
diff --git a/chromium/components/new_or_sad_tab_strings.grdp b/chromium/components/new_or_sad_tab_strings.grdp
index d33b2dccbd6..764ba88947f 100644
--- a/chromium/components/new_or_sad_tab_strings.grdp
+++ b/chromium/components/new_or_sad_tab_strings.grdp
@@ -177,4 +177,56 @@
When on, sites can't use cookies that track you across the web. Features on some sites may break.
</message>
+ <!-- Ephemeral Guest Tab strings -->
+ <!-- TODO(crbug.com/1125474): Rename strings to *GUEST* instead of *EPHEMERAL_GUEST* once all audit is done and all instances of non-ephemeral Guest profiles are deprecated.-->
+
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_OUT"
+ desc="This is a greeting message that apprears when the user opens a new ephemeral guest tab while they are signed out of chrome guest session.">
+ You’re browsing as a Guest
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_IN"
+ desc="This is greeting message with the user's name, appears when user opens a new ephemeral guest tab while they are signed in to chrome guest session.">
+ Hi <ph name="USERNAME">%s<ex>Mariam</ex></ph>,
+ <ph name="BR">&lt;br&gt;</ph>
+ You’re browsing as a Guest
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_OUT"
+ desc="This is a message displayed on the ephemeral guest NTP when the user is signed out of chrome guest session emphasing that no chrome profile info will be available unless the user chooses to sign in. The user can click on 'sign in' to start the sign in to chrome guest session flow.">
+ You won't see any Chrome profile's info in Guest mode. You can <ph name="LINK_BEGIN">&lt;a id="change-sign-in-status"&gt;</ph>sign in<ph name="LINK_END">&lt;/a&gt;</ph> to access your Google account info like passwords and payment methods.
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_IN"
+ desc="This is a message displayed on the ephemeral guest NTP when the user is signed in to chrome guest session to encourage closing all open guest windows in order to delete their browsing activity from the device in use.">
+ Close all Guest windows so your browsing activity is deleted from this device.
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_OUT"
+ desc="A list of bullet points that appears on the ephemeral guest NTP listing data that won't be saved on the device after closing all guest windows. This shows when the user is signed out of chrome guest session.">
+ <ph name="BEGIN_BOLD">&lt;b&gt;</ph>
+ Activity that won't stay on this device:
+ <ph name="END_BOLD">&lt;/b&gt;</ph>
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Pages you view in this window
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Cookies and site data
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_IN"
+ desc="A list of bullet points that appears on the ephemeral guest NTP listing data that won't be saved on the device after closing all guest windows. The user can click 'sign out' to sign out of the guest session. This shows when the user is signed in to chrome guest session.">
+ <ph name="BEGIN_BOLD">&lt;b&gt;</ph>
+ Activity that won't stay on this device:
+ <ph name="END_BOLD">&lt;/b&gt;</ph>
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Pages you view in this window
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Cookies and site data
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Account information (<ph name="LINK_BEGIN">&lt;a id="change-sign-in-status"&gt;</ph>sign out<ph name="LINK_END">&lt;/a&gt;</ph>)
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ <message name="IDS_NEW_TAB_EPHEMERAL_GUEST_SAVED"
+ desc="A list of bullet points that appears on the ephemeral guest NTP listing data that will be saved on the device after closing all guest windows.">
+ <ph name="BEGIN_BOLD">&lt;b&gt;</ph>
+ Your activity that stays on this device:
+ <ph name="END_BOLD">&lt;/b&gt;</ph>
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Any files you download in this window
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+
</grit-part>
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_IN.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_IN.png.sha1
new file mode 100644
index 00000000000..2dcfe7b3d63
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_IN.png.sha1
@@ -0,0 +1 @@
+86bfc1bb0860fe4e7c5087945f3aaa62c3bc4b67 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_OUT.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_OUT.png.sha1
new file mode 100644
index 00000000000..b6f8535e6bc
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_NOT_SAVED_SIGNED_OUT.png.sha1
@@ -0,0 +1 @@
+3cd7f2320f25ed84487cbcd1cc1b0680daa9f0cd \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SAVED.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SAVED.png.sha1
new file mode 100644
index 00000000000..459b37dced9
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SAVED.png.sha1
@@ -0,0 +1 @@
+e73c15ea0f9910de922dc6dc8d06eac889489fcc \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_IN.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_IN.png.sha1
new file mode 100644
index 00000000000..1bf51edcea1
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_IN.png.sha1
@@ -0,0 +1 @@
+d731e5c7c6e773abe9af1af80049eb500548d53e \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_OUT.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_OUT.png.sha1
new file mode 100644
index 00000000000..2959fd4fa58
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_DESCRIPTION_SIGNED_OUT.png.sha1
@@ -0,0 +1 @@
+ef61e15824eef4f640f141dfd77d53816632b5b4 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_IN.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_IN.png.sha1
new file mode 100644
index 00000000000..7842be74ea5
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_IN.png.sha1
@@ -0,0 +1 @@
+cedc5f231aa87da951a6304cda2a4c8691731df8 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_OUT.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_OUT.png.sha1
new file mode 100644
index 00000000000..dd4fa4ad1e8
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_EPHEMERAL_GUEST_SESSION_HEADING_SIGNED_OUT.png.sha1
@@ -0,0 +1 @@
+37cbba8cdf1208db309f787af580f30dc981ccca \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/OWNERS b/chromium/components/new_or_sad_tab_strings_grdp/OWNERS
index 690a9f1a025..1436736eb62 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/OWNERS
+++ b/chromium/components/new_or_sad_tab_strings_grdp/OWNERS
@@ -1,5 +1,4 @@
-estade@chromium.org
-rbyers@chromium.org
+file://chrome/browser/ui/webui/ntp/OWNERS
# TEAM: ntp-dev@chromium.org
# COMPONENT: UI>Browser>NewTabPage
diff --git a/chromium/components/prerender/OWNERS b/chromium/components/no_state_prefetch/OWNERS
index 705d4d52107..559aefc1064 100644
--- a/chromium/components/prerender/OWNERS
+++ b/chromium/components/no_state_prefetch/OWNERS
@@ -1,3 +1,5 @@
+falken@chromium.org
+nhiroki@chromium.org
robertogden@chromium.org
ryansturm@chromium.org
tbansal@chromium.org
diff --git a/chromium/components/prerender/browser/BUILD.gn b/chromium/components/no_state_prefetch/browser/BUILD.gn
index 45e92cc7576..e3702c1eacc 100644
--- a/chromium/components/prerender/browser/BUILD.gn
+++ b/chromium/components/no_state_prefetch/browser/BUILD.gn
@@ -34,8 +34,8 @@ static_library("browser") {
deps = [
"//components/content_settings/core/browser",
"//components/google/core/common",
- "//components/prerender/common",
- "//components/prerender/common:mojo_bindings",
+ "//components/no_state_prefetch/common",
+ "//components/no_state_prefetch/common:mojo_bindings",
"//content/public/browser",
"//net",
"//services/metrics/public/cpp:ukm_builders",
diff --git a/chromium/components/prerender/browser/DEPS b/chromium/components/no_state_prefetch/browser/DEPS
index 85f97c046eb..85f97c046eb 100644
--- a/chromium/components/prerender/browser/DEPS
+++ b/chromium/components/no_state_prefetch/browser/DEPS
diff --git a/chromium/components/prerender/browser/prerender_config.cc b/chromium/components/no_state_prefetch/browser/prerender_config.cc
index 22f422714ec..7208299720b 100644
--- a/chromium/components/prerender/browser/prerender_config.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_config.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 "components/prerender/browser/prerender_config.h"
+#include "components/no_state_prefetch/browser/prerender_config.h"
namespace prerender {
diff --git a/chromium/components/prerender/browser/prerender_config.h b/chromium/components/no_state_prefetch/browser/prerender_config.h
index 41559bdf286..3daca1ce1d4 100644
--- a/chromium/components/prerender/browser/prerender_config.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_config.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONFIG_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONFIG_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONFIG_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONFIG_H_
#include <stddef.h>
@@ -55,4 +55,4 @@ struct Config {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONFIG_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONFIG_H_
diff --git a/chromium/components/prerender/browser/prerender_contents.cc b/chromium/components/no_state_prefetch/browser/prerender_contents.cc
index a1d64cda298..3ad1ba499b6 100644
--- a/chromium/components/prerender/browser/prerender_contents.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_contents.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 "components/prerender/browser/prerender_contents.h"
+#include "components/no_state_prefetch/browser/prerender_contents.h"
#include <stddef.h>
@@ -15,11 +15,11 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "build/build_config.h"
-#include "components/prerender/browser/prerender_contents_delegate.h"
-#include "components/prerender/browser/prerender_manager.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_util.h"
-#include "components/prerender/common/render_frame_prerender_messages.mojom.h"
+#include "components/no_state_prefetch/browser/prerender_contents_delegate.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_util.h"
+#include "components/no_state_prefetch/common/render_frame_prerender_messages.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -33,7 +33,6 @@
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/frame_navigate_params.h"
#include "net/http/http_response_headers.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/service_manager/public/cpp/binder_registry.h"
@@ -441,21 +440,16 @@ void PrerenderContents::DidFinishLoad(
void PrerenderContents::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
- !navigation_handle->HasCommitted() || navigation_handle->IsErrorPage()) {
+ !navigation_handle->HasCommitted()) {
return;
}
- if (navigation_handle->GetResponseHeaders() &&
- navigation_handle->GetResponseHeaders()->response_code() >= 400) {
+ if (navigation_handle->IsErrorPage()) {
// Maintain same behavior as old navigation API when the URL is unreachable
- // and leads to an error page. While there will be a subsequent navigation
- // that has navigation_handle->IsErrorPage(), it'll be too late to wait for
- // it as the renderer side will consider this prerender complete. This
- // object would therefore have been destructed already and so instead look
- // for the error response code now.
- // Also maintain same final status code that previous navigation API
- // returned, which was reached because the URL for the error page was
- // kUnreachableWebDataURL and that was interpreted as unsupported scheme.
+ // and leads to an error page. Also maintain same final status code that
+ // previous navigation API returned, which was reached because the URL for
+ // the error page was kUnreachableWebDataURL and that was interpreted as
+ // unsupported scheme.
Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
return;
}
@@ -550,8 +544,9 @@ std::unique_ptr<WebContents> PrerenderContents::ReleasePrerenderContents() {
}
RenderViewHost* PrerenderContents::GetRenderViewHost() {
- return prerender_contents_ ? prerender_contents_->GetRenderViewHost()
- : nullptr;
+ return prerender_contents_
+ ? prerender_contents_->GetMainFrame()->GetRenderViewHost()
+ : nullptr;
}
std::unique_ptr<base::DictionaryValue> PrerenderContents::GetAsValue() const {
diff --git a/chromium/components/prerender/browser/prerender_contents.h b/chromium/components/no_state_prefetch/browser/prerender_contents.h
index 1c866503dbf..10acee2f2df 100644
--- a/chromium/components/prerender/browser/prerender_contents.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_contents.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_H_
#include <stdint.h>
@@ -18,11 +18,11 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "base/values.h"
-#include "components/prerender/browser/prerender_contents_delegate.h"
-#include "components/prerender/common/prerender_canceler.mojom.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_origin.h"
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/browser/prerender_contents_delegate.h"
+#include "components/no_state_prefetch/common/prerender_canceler.mojom.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
@@ -335,4 +335,4 @@ class PrerenderContents : public content::NotificationObserver,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_H_
diff --git a/chromium/components/prerender/browser/prerender_contents_delegate.cc b/chromium/components/no_state_prefetch/browser/prerender_contents_delegate.cc
index ddac1785b79..5ea7fa55557 100644
--- a/chromium/components/prerender/browser/prerender_contents_delegate.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_contents_delegate.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 "components/prerender/browser/prerender_contents_delegate.h"
+#include "components/no_state_prefetch/browser/prerender_contents_delegate.h"
namespace prerender {
diff --git a/chromium/components/prerender/browser/prerender_contents_delegate.h b/chromium/components/no_state_prefetch/browser/prerender_contents_delegate.h
index 556573eecdb..1c3debaa791 100644
--- a/chromium/components/prerender/browser/prerender_contents_delegate.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_contents_delegate.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
#include "content/public/browser/render_frame_host.h"
namespace content {
@@ -30,4 +30,4 @@ class PrerenderContentsDelegate {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_CONTENTS_DELEGATE_H_
diff --git a/chromium/components/no_state_prefetch/browser/prerender_field_trial.cc b/chromium/components/no_state_prefetch/browser/prerender_field_trial.cc
new file mode 100644
index 00000000000..3cd14efa0b2
--- /dev/null
+++ b/chromium/components/no_state_prefetch/browser/prerender_field_trial.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 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/no_state_prefetch/browser/prerender_field_trial.h"
+
+#include <string>
+
+#include "base/metrics/field_trial.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
+
+namespace prerender {
+
+const base::Feature kGWSPrefetchHoldback{"GWSPrefetchHoldback",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kNavigationPredictorPrefetchHoldback{
+ "NavigationPredictorPrefetchHoldback", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace prerender
diff --git a/chromium/components/prerender/browser/prerender_field_trial.h b/chromium/components/no_state_prefetch/browser/prerender_field_trial.h
index 2325862d426..baffc14713a 100644
--- a/chromium/components/prerender/browser/prerender_field_trial.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_field_trial.h
@@ -2,27 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_BROWSER_PRERENDER_FIELD_TRIAL_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_FIELD_TRIAL_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_FIELD_TRIAL_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_FIELD_TRIAL_H_
#include "base/feature_list.h"
namespace prerender {
-// These Finch feature and parameter strings exposed for for testing.
-extern const base::Feature kNoStatePrefetchFeature;
-
// Preconnects instead of prefetching from GWS.
extern const base::Feature kGWSPrefetchHoldback;
// Preconnects instead of prefetching from NavigationPredictor.
extern const base::Feature kNavigationPredictorPrefetchHoldback;
-// Configures global state using kNoStatePrefetchFeature.
-void ConfigureNoStatePrefetch();
-
-bool IsNoStatePrefetchEnabled();
-
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_FIELD_TRIAL_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_FIELD_TRIAL_H_
diff --git a/chromium/components/prerender/browser/prerender_handle.cc b/chromium/components/no_state_prefetch/browser/prerender_handle.cc
index 17757deb723..5d22c471581 100644
--- a/chromium/components/prerender/browser/prerender_handle.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_handle.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/browser/prerender_handle.h"
+#include "components/no_state_prefetch/browser/prerender_handle.h"
#include <algorithm>
#include "base/check_op.h"
-#include "components/prerender/browser/prerender_contents.h"
+#include "components/no_state_prefetch/browser/prerender_contents.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
diff --git a/chromium/components/prerender/browser/prerender_handle.h b/chromium/components/no_state_prefetch/browser/prerender_handle.h
index a9a8fadf76f..38a1461ff4e 100644
--- a/chromium/components/prerender/browser/prerender_handle.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_handle.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_BROWSER_PRERENDER_HANDLE_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_HANDLE_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HANDLE_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HANDLE_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/prerender/browser/prerender_manager.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
namespace prerender {
@@ -103,4 +103,4 @@ class PrerenderHandle : public PrerenderContents::Observer {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_HANDLE_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HANDLE_H_
diff --git a/chromium/components/prerender/browser/prerender_histograms.cc b/chromium/components/no_state_prefetch/browser/prerender_histograms.cc
index b38223941c5..04a993b4fc1 100644
--- a/chromium/components/prerender/browser/prerender_histograms.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_histograms.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 "components/prerender/browser/prerender_histograms.h"
+#include "components/no_state_prefetch/browser/prerender_histograms.h"
#include <string>
@@ -14,7 +14,7 @@
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "components/google/core/common/google_util.h"
-#include "components/prerender/common/prerender_util.h"
+#include "components/no_state_prefetch/common/prerender_util.h"
#include "net/http/http_cache.h"
namespace prerender {
diff --git a/chromium/components/prerender/browser/prerender_histograms.h b/chromium/components/no_state_prefetch/browser/prerender_histograms.h
index 1ff83e0c318..0c98f790bbe 100644
--- a/chromium/components/prerender/browser/prerender_histograms.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_histograms.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTOGRAMS_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTOGRAMS_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTOGRAMS_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTOGRAMS_H_
#include <stddef.h>
#include <stdint.h>
@@ -13,8 +13,8 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
#include "url/gurl.h"
namespace prerender {
@@ -85,4 +85,4 @@ class PrerenderHistograms {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTOGRAMS_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTOGRAMS_H_
diff --git a/chromium/components/prerender/browser/prerender_history.cc b/chromium/components/no_state_prefetch/browser/prerender_history.cc
index 98b2ee5dfe6..5204bae4df6 100644
--- a/chromium/components/prerender/browser/prerender_history.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_history.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 "components/prerender/browser/prerender_history.h"
+#include "components/no_state_prefetch/browser/prerender_history.h"
#include <memory>
#include <utility>
diff --git a/chromium/components/prerender/browser/prerender_history.h b/chromium/components/no_state_prefetch/browser/prerender_history.h
index 3971e820ef5..5f0520a4ab7 100644
--- a/chromium/components/prerender/browser/prerender_history.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_history.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTORY_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTORY_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTORY_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTORY_H_
#include <stddef.h>
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
#include "url/gurl.h"
namespace base {
@@ -80,4 +80,4 @@ class PrerenderHistory {
};
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_HISTORY_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_HISTORY_H_
diff --git a/chromium/components/prerender/browser/prerender_history_unittest.cc b/chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc
index 69dbb6d6e4c..52b796cbcf1 100644
--- a/chromium/components/prerender/browser/prerender_history_unittest.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_history_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 "components/prerender/browser/prerender_history.h"
+#include "components/no_state_prefetch/browser/prerender_history.h"
#include <stddef.h>
diff --git a/chromium/components/prerender/browser/prerender_link_manager.cc b/chromium/components/no_state_prefetch/browser/prerender_link_manager.cc
index 6a8c2b550e2..30639e25031 100644
--- a/chromium/components/prerender/browser/prerender_link_manager.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_link_manager.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 "components/prerender/browser/prerender_link_manager.h"
+#include "components/no_state_prefetch/browser/prerender_link_manager.h"
#include <functional>
#include <limits>
@@ -14,9 +14,9 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
-#include "components/prerender/browser/prerender_contents.h"
-#include "components/prerender/browser/prerender_handle.h"
-#include "components/prerender/browser/prerender_manager.h"
+#include "components/no_state_prefetch/browser/prerender_contents.h"
+#include "components/no_state_prefetch/browser/prerender_handle.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/session_storage_namespace.h"
@@ -125,9 +125,8 @@ base::Optional<int> PrerenderLinkManager::OnStartPrerender(
std::move(attributes), initiator_origin, std::move(processor_client),
manager_->GetCurrentTimeTicks(), prerender_contents);
- // Observe disconnect of the client and treat as equivalent to explicit
- // abandonment. Similar to above, the raw pointer to |this| is safe because
- // |prerender| is owned by |this|.
+ // Observe disconnect of the client to abandon the running prerender. The raw
+ // pointer to |this| is safe because |prerender| is owned by |this|.
prerender->remote_processor_client.set_disconnect_handler(
base::BindOnce(&PrerenderLinkManager::OnAbandonPrerender,
base::Unretained(this), prerender->prerender_id));
diff --git a/chromium/components/prerender/browser/prerender_link_manager.h b/chromium/components/no_state_prefetch/browser/prerender_link_manager.h
index ce8b8eb9571..5fe79e12985 100644
--- a/chromium/components/prerender/browser/prerender_link_manager.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_link_manager.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_LINK_MANAGER_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_LINK_MANAGER_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_LINK_MANAGER_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_LINK_MANAGER_H_
#include <stddef.h>
#include <stdint.h>
@@ -16,7 +16,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "components/prerender/browser/prerender_handle.h"
+#include "components/no_state_prefetch/browser/prerender_handle.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -161,4 +161,4 @@ class PrerenderLinkManager : public KeyedService,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_LINK_MANAGER_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_LINK_MANAGER_H_
diff --git a/chromium/components/prerender/browser/prerender_manager.cc b/chromium/components/no_state_prefetch/browser/prerender_manager.cc
index 8664f88907f..2ba361ac84b 100644
--- a/chromium/components/prerender/browser/prerender_manager.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_manager.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 "components/prerender/browser/prerender_manager.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
#include <stddef.h>
@@ -13,7 +13,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/macros.h"
@@ -31,15 +31,15 @@
#include "base/timer/elapsed_timer.h"
#include "base/values.h"
#include "components/content_settings/core/browser/cookie_settings.h"
-#include "components/prerender/browser/prerender_contents.h"
-#include "components/prerender/browser/prerender_field_trial.h"
-#include "components/prerender/browser/prerender_handle.h"
-#include "components/prerender/browser/prerender_histograms.h"
-#include "components/prerender/browser/prerender_history.h"
-#include "components/prerender/browser/prerender_manager_delegate.h"
-#include "components/prerender/browser/prerender_util.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/browser/prerender_contents.h"
+#include "components/no_state_prefetch/browser/prerender_field_trial.h"
+#include "components/no_state_prefetch/browser/prerender_handle.h"
+#include "components/no_state_prefetch/browser/prerender_histograms.h"
+#include "components/no_state_prefetch/browser/prerender_history.h"
+#include "components/no_state_prefetch/browser/prerender_manager_delegate.h"
+#include "components/no_state_prefetch/browser/prerender_util.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/render_frame_host.h"
@@ -115,10 +115,6 @@ class PrerenderManager::OnCloseWebContentsDeleter
PrerenderManagerObserver::~PrerenderManagerObserver() = default;
-// static
-PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
- PRERENDER_MODE_NOSTATE_PREFETCH;
-
struct PrerenderManager::NavigationRecord {
NavigationRecord(const GURL& url, base::TimeTicks time, Origin origin)
: url(url), time(time), origin(origin) {}
@@ -221,8 +217,6 @@ PrerenderManager::AddPrerenderFromNavigationPredictor(
const GURL& url,
SessionStorageNamespace* session_storage_namespace,
const gfx::Size& size) {
- DCHECK(IsNoStatePrefetchEnabled());
-
return AddPrerenderWithPreconnectFallback(
ORIGIN_NAVIGATION_PREDICTOR, url, content::Referrer(), base::nullopt,
gfx::Rect(size), session_storage_namespace);
@@ -232,8 +226,6 @@ std::unique_ptr<PrerenderHandle> PrerenderManager::AddIsolatedPrerender(
const GURL& url,
SessionStorageNamespace* session_storage_namespace,
const gfx::Size& size) {
- DCHECK(IsNoStatePrefetchEnabled());
-
// The preconnect fallback won't happen.
return AddPrerenderWithPreconnectFallback(
ORIGIN_ISOLATED_PRERENDER, url, content::Referrer(), base::nullopt,
@@ -290,36 +282,6 @@ bool PrerenderManager::IsWebContentsPrerendering(
return GetPrerenderContents(web_contents);
}
-bool PrerenderManager::HasPrerenderedUrl(
- GURL url,
- content::WebContents* web_contents) const {
- content::SessionStorageNamespace* session_storage_namespace =
- web_contents->GetController().GetDefaultSessionStorageNamespace();
-
- for (const auto& prerender_data : active_prerenders_) {
- PrerenderContents* prerender_contents = prerender_data->contents();
- if (prerender_contents->Matches(url, session_storage_namespace))
- return true;
- }
- return false;
-}
-
-bool PrerenderManager::HasPrerenderedAndFinishedLoadingUrl(
- GURL url,
- content::WebContents* web_contents) const {
- content::SessionStorageNamespace* session_storage_namespace =
- web_contents->GetController().GetDefaultSessionStorageNamespace();
-
- for (const auto& prerender_data : active_prerenders_) {
- PrerenderContents* prerender_contents = prerender_data->contents();
- if (prerender_contents->Matches(url, session_storage_namespace) &&
- prerender_contents->has_finished_loading()) {
- return true;
- }
- }
- return false;
-}
-
PrerenderContents* PrerenderManager::GetPrerenderContents(
const content::WebContents* web_contents) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -352,19 +314,6 @@ PrerenderContents* PrerenderManager::GetPrerenderContentsForRoute(
return web_contents ? GetPrerenderContents(web_contents) : nullptr;
}
-PrerenderContents* PrerenderManager::GetPrerenderContentsForProcess(
- int render_process_id) const {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- for (auto& prerender_data : active_prerenders_) {
- PrerenderContents* prerender_contents = prerender_data->contents();
- if (prerender_contents->GetRenderViewHost()->GetProcess()->GetID() ==
- render_process_id) {
- return prerender_contents;
- }
- }
- return nullptr;
-}
-
std::vector<WebContents*>
PrerenderManager::GetAllNoStatePrefetchingContentsForTesting() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -542,6 +491,14 @@ PrerenderManager::AddPrerenderWithPreconnectFallback(
SessionStorageNamespace* session_storage_namespace) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Disallow NSPing link-rel:next URLs.
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=1158209.
+ if (origin == ORIGIN_LINK_REL_NEXT) {
+ SkipPrerenderContentsAndMaybePreconnect(
+ url_arg, origin, FINAL_STATUS_LINK_REL_NEXT_NOT_ALLOWED);
+ return nullptr;
+ }
+
// Disallow prerendering on low end devices.
if (IsLowEndDevice()) {
SkipPrerenderContentsAndMaybePreconnect(url_arg, origin,
@@ -579,17 +536,15 @@ PrerenderManager::AddPrerenderWithPreconnectFallback(
return base::WrapUnique(new PrerenderHandle(preexisting_prerender_data));
}
- if (IsNoStatePrefetchEnabled()) {
- base::TimeDelta prefetch_age;
- GetPrefetchInformation(url, &prefetch_age, nullptr /* final_status*/,
- nullptr /* origin */);
- if (!prefetch_age.is_zero() &&
- prefetch_age <
- base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins)) {
- SkipPrerenderContentsAndMaybePreconnect(url, origin,
- FINAL_STATUS_DUPLICATE);
- return nullptr;
- }
+ base::TimeDelta prefetch_age;
+ GetPrefetchInformation(url, &prefetch_age, nullptr /* final_status*/,
+ nullptr /* origin */);
+ if (!prefetch_age.is_zero() &&
+ prefetch_age <
+ base::TimeDelta::FromMinutes(net::HttpCache::kPrefetchReuseMins)) {
+ SkipPrerenderContentsAndMaybePreconnect(url, origin,
+ FINAL_STATUS_DUPLICATE);
+ return nullptr;
}
// Do not prerender if there are too many render processes, and we would
@@ -625,12 +580,6 @@ PrerenderManager::AddPrerenderWithPreconnectFallback(
// enable metrics comparisons.
prefetches_.emplace_back(url, GetCurrentTimeTicks(), origin);
- if (GetMode() == PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT) {
- // Exit after adding the url to prefetches_, so that no prefetching occurs
- // but the page is still tracked as "would have been prefetched".
- return nullptr;
- }
-
// If this is GWS and we are in the holdback, skip the prefetch. Record the
// status as holdback, so we can analyze via UKM.
if (origin == ORIGIN_GWS_PRERENDER &&
@@ -658,10 +607,8 @@ PrerenderManager::AddPrerenderWithPreconnectFallback(
CreatePrerenderContents(url, referrer, initiator_origin, origin);
DCHECK(prerender_contents);
PrerenderContents* prerender_contents_ptr = prerender_contents.get();
- if (IsNoStatePrefetchEnabled()) {
- prerender_contents_ptr->SetPrerenderMode(
- prerender::mojom::PrerenderMode::kPrefetchOnly);
- }
+ prerender_contents_ptr->SetPrerenderMode(
+ prerender::mojom::PrerenderMode::kPrefetchOnly);
active_prerenders_.push_back(
std::make_unique<PrerenderData>(this, std::move(prerender_contents),
GetExpiryTimeForNewPrerender(origin)));
@@ -973,11 +920,14 @@ void PrerenderManager::SkipPrerenderContentsAndMaybePreconnect(
histograms_->RecordFinalStatus(origin, final_status);
if (origin == ORIGIN_ISOLATED_PRERENDER) {
- // Isolated Prerenders should not preconnect since that can't be done in a
- // fully isolated way.
+ // Prefetch Proxy should not preconnect since that can't be done in a fully
+ // isolated way.
return;
}
+ if (origin == ORIGIN_LINK_REL_NEXT)
+ return;
+
if (final_status == FINAL_STATUS_LOW_END_DEVICE ||
final_status == FINAL_STATUS_CELLULAR_NETWORK ||
final_status == FINAL_STATUS_DUPLICATE ||
@@ -986,14 +936,12 @@ void PrerenderManager::SkipPrerenderContentsAndMaybePreconnect(
}
static_assert(
- FINAL_STATUS_MAX == FINAL_STATUS_NAVIGATION_PREDICTOR_HOLDBACK + 1,
+ FINAL_STATUS_MAX == FINAL_STATUS_LINK_REL_NEXT_NOT_ALLOWED + 1,
"Consider whether a failed prerender should fallback to preconnect");
}
void PrerenderManager::RecordNetworkBytesConsumed(Origin origin,
int64_t prerender_bytes) {
- if (!IsNoStatePrefetchEnabled())
- return;
int64_t recent_browser_context_bytes =
browser_context_network_bytes_ -
last_recorded_browser_context_network_bytes_;
@@ -1034,6 +982,15 @@ void PrerenderManager::ClearPrefetchInformationForTesting() {
prefetches_.clear();
}
+std::unique_ptr<PrerenderHandle>
+PrerenderManager::AddPrerenderWithPreconnectFallbackForTesting(
+ Origin origin,
+ const GURL& url,
+ const base::Optional<url::Origin>& initiator_origin) {
+ return AddPrerenderWithPreconnectFallback(
+ origin, url, content::Referrer(), initiator_origin, gfx::Rect(), nullptr);
+}
+
void PrerenderManager::SetPrerenderContentsFactoryForTest(
PrerenderContents::Factory* prerender_contents_factory) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chromium/components/prerender/browser/prerender_manager.h b/chromium/components/no_state_prefetch/browser/prerender_manager.h
index 0a802c189a0..5921099f11a 100644
--- a/chromium/components/prerender/browser/prerender_manager.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_manager.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_H_
#include <stdint.h>
@@ -19,12 +19,12 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "components/prerender/browser/prerender_config.h"
-#include "components/prerender/browser/prerender_contents.h"
-#include "components/prerender/browser/prerender_histograms.h"
-#include "components/prerender/browser/prerender_manager_delegate.h"
-#include "components/prerender/common/prerender_final_status.h"
-#include "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/browser/prerender_config.h"
+#include "components/no_state_prefetch/browser/prerender_contents.h"
+#include "components/no_state_prefetch/browser/prerender_histograms.h"
+#include "components/no_state_prefetch/browser/prerender_manager_delegate.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
#include "content/public/browser/render_process_host_observer.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
#include "url/gurl.h"
@@ -74,16 +74,6 @@ class PrerenderManagerObserver {
class PrerenderManager : public content::RenderProcessHostObserver,
public KeyedService {
public:
- enum PrerenderManagerMode {
- // For each request to prerender performs a NoStatePrefetch for the same URL
- // instead.
- PRERENDER_MODE_NOSTATE_PREFETCH,
-
- // Ignores requests to prerender, but keeps track of pages that would have
- // been prerendered and records metrics for comparison with other modes.
- PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT
- };
-
// One or more of these flags must be passed to ClearData() to specify just
// what data to clear. See function declaration for more information.
enum ClearFlags {
@@ -169,25 +159,11 @@ class PrerenderManager : public content::RenderProcessHostObserver,
virtual void MoveEntryToPendingDelete(PrerenderContents* entry,
FinalStatus final_status);
- static PrerenderManagerMode GetMode() { return mode_; }
- static void SetMode(PrerenderManagerMode mode) { mode_ = mode; }
-
// Query the list of current prerender pages to see if the given web contents
// is prerendering a page.
bool IsWebContentsPrerendering(
const content::WebContents* web_contents) const;
- // Whether the PrerenderManager has an active prerender with the given url and
- // SessionStorageNamespace associated with the given WebContents.
- bool HasPrerenderedUrl(GURL url, content::WebContents* web_contents) const;
-
- // Whether the PrerenderManager has an active prerender with the given url and
- // SessionStorageNamespace associated with the given WebContents, and that
- // prerender has finished loading..
- bool HasPrerenderedAndFinishedLoadingUrl(
- GURL url,
- content::WebContents* web_contents) const;
-
// Returns the PrerenderContents object for the given web_contents, otherwise
// returns NULL. Note that the PrerenderContents may have been Destroy()ed,
// but not yet deleted.
@@ -200,11 +176,6 @@ class PrerenderManager : public content::RenderProcessHostObserver,
virtual PrerenderContents* GetPrerenderContentsForRoute(int child_id,
int route_id) const;
- // Returns the PrerenderContents object that is found in active prerenders to
- // match the |render_process_id|. Otherwise returns a nullptr.
- PrerenderContents* GetPrerenderContentsForProcess(
- int render_process_id) const;
-
// Returns a list of all WebContents being prerendered.
std::vector<content::WebContents*> GetAllPrerenderingContents() const;
@@ -295,6 +266,14 @@ class PrerenderManager : public content::RenderProcessHostObserver,
// Returns true iff the |url| is found in the list of recent prefetches.
bool HasRecentlyPrefetchedUrlForTesting(const GURL& url);
+ // Adds a prerender for |url| from |initiator_origin|. The |origin| specifies
+ // how the prerender was added. Returns a PrerenderHandle or nullptr. Only for
+ // testing.
+ std::unique_ptr<PrerenderHandle> AddPrerenderWithPreconnectFallbackForTesting(
+ Origin origin,
+ const GURL& url,
+ const base::Optional<url::Origin>& initiator_origin);
+
protected:
class PrerenderData : public base::SupportsWeakPtr<PrerenderData> {
public:
@@ -511,8 +490,6 @@ class PrerenderManager : public content::RenderProcessHostObserver,
std::unique_ptr<PrerenderContents::Factory> prerender_contents_factory_;
- static PrerenderManagerMode mode_;
-
// RepeatingTimer to perform periodic cleanups of pending prerendered
// pages.
base::RepeatingTimer repeating_timer_;
@@ -553,4 +530,4 @@ class PrerenderManager : public content::RenderProcessHostObserver,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_H_
diff --git a/chromium/components/prerender/browser/prerender_manager_delegate.cc b/chromium/components/no_state_prefetch/browser/prerender_manager_delegate.cc
index 8e3bd995af9..0c2017736ec 100644
--- a/chromium/components/prerender/browser/prerender_manager_delegate.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_manager_delegate.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 "components/prerender/browser/prerender_manager_delegate.h"
+#include "components/no_state_prefetch/browser/prerender_manager_delegate.h"
namespace prerender {
diff --git a/chromium/components/prerender/browser/prerender_manager_delegate.h b/chromium/components/no_state_prefetch/browser/prerender_manager_delegate.h
index 36cdd20298a..dc7712e8f05 100644
--- a/chromium/components/prerender/browser/prerender_manager_delegate.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_manager_delegate.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
#include "base/memory/scoped_refptr.h"
-#include "components/prerender/browser/prerender_contents_delegate.h"
-#include "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/browser/prerender_contents_delegate.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
#include "url/gurl.h"
namespace content_settings {
@@ -48,4 +48,4 @@ class PrerenderManagerDelegate {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_MANAGER_DELEGATE_H_
diff --git a/chromium/components/prerender/browser/prerender_processor_impl.cc b/chromium/components/no_state_prefetch/browser/prerender_processor_impl.cc
index 1068f6654b1..7649241fb18 100644
--- a/chromium/components/prerender/browser/prerender_processor_impl.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_processor_impl.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/browser/prerender_processor_impl.h"
+#include "components/no_state_prefetch/browser/prerender_processor_impl.h"
-#include "components/prerender/browser/prerender_link_manager.h"
+#include "components/no_state_prefetch/browser/prerender_link_manager.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
@@ -79,14 +79,6 @@ void PrerenderProcessorImpl::Cancel() {
link_manager->OnCancelPrerender(*prerender_id_);
}
-void PrerenderProcessorImpl::Abandon() {
- if (!prerender_id_)
- return;
- auto* link_manager = GetPrerenderLinkManager();
- if (link_manager)
- link_manager->OnAbandonPrerender(*prerender_id_);
-}
-
PrerenderLinkManager* PrerenderProcessorImpl::GetPrerenderLinkManager() {
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
diff --git a/chromium/components/prerender/browser/prerender_processor_impl.h b/chromium/components/no_state_prefetch/browser/prerender_processor_impl.h
index 8866a50d019..09620613444 100644
--- a/chromium/components/prerender/browser/prerender_processor_impl.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_processor_impl.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
-#include "components/prerender/browser/prerender_processor_impl_delegate.h"
+#include "components/no_state_prefetch/browser/prerender_processor_impl_delegate.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
#include "url/origin.h"
@@ -34,7 +34,6 @@ class PrerenderProcessorImpl : public blink::mojom::PrerenderProcessor {
mojo::PendingRemote<blink::mojom::PrerenderProcessorClient> client)
override;
void Cancel() override;
- void Abandon() override;
private:
PrerenderLinkManager* GetPrerenderLinkManager();
@@ -51,4 +50,4 @@ class PrerenderProcessorImpl : public blink::mojom::PrerenderProcessor {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_H_
diff --git a/chromium/components/prerender/browser/prerender_processor_impl_delegate.h b/chromium/components/no_state_prefetch/browser/prerender_processor_impl_delegate.h
index 370996887cf..0279307a449 100644
--- a/chromium/components/prerender/browser/prerender_processor_impl_delegate.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_processor_impl_delegate.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
namespace content {
class BrowserContext;
@@ -24,4 +24,4 @@ class PrerenderProcessorImplDelegate {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_PROCESSOR_IMPL_DELEGATE_H_
diff --git a/chromium/components/prerender/browser/prerender_util.cc b/chromium/components/no_state_prefetch/browser/prerender_util.cc
index 027445bede0..9aafb8792fe 100644
--- a/chromium/components/prerender/browser/prerender_util.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_util.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/browser/prerender_util.h"
+#include "components/no_state_prefetch/browser/prerender_util.h"
#include "base/metrics/histogram_macros.h"
#include "components/google/core/common/google_util.h"
-#include "components/prerender/browser/prerender_manager.h"
+#include "components/no_state_prefetch/browser/prerender_manager.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "services/metrics/public/cpp/metrics_utils.h"
diff --git a/chromium/components/prerender/browser/prerender_util.h b/chromium/components/no_state_prefetch/browser/prerender_util.h
index 038940bd2fc..b25c8ec2d57 100644
--- a/chromium/components/prerender/browser/prerender_util.h
+++ b/chromium/components/no_state_prefetch/browser/prerender_util.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 COMPONENTS_PRERENDER_BROWSER_PRERENDER_UTIL_H_
-#define COMPONENTS_PRERENDER_BROWSER_PRERENDER_UTIL_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_UTIL_H_
+#define COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_UTIL_H_
#include "services/metrics/public/cpp/ukm_source_id.h"
@@ -20,12 +20,6 @@ class PrerenderManager;
// Indicates whether the URL provided is a GWS origin.
bool IsGoogleOriginURL(const GURL& origin_url);
-// Report a URL was canceled due to trying to handle an external URL.
-void ReportPrerenderExternalURL();
-
-// Report a URL was canceled due to unsupported prerender scheme.
-void ReportUnsupportedPrerenderScheme(const GURL& url);
-
// Records the metrics for the nostate prefetch to an event with UKM source ID
// |source_id|.
void RecordNoStatePrefetchMetrics(
@@ -35,4 +29,4 @@ void RecordNoStatePrefetchMetrics(
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_BROWSER_PRERENDER_UTIL_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_BROWSER_PRERENDER_UTIL_H_
diff --git a/chromium/components/prerender/browser/prerender_util_unittest.cc b/chromium/components/no_state_prefetch/browser/prerender_util_unittest.cc
index 9cfc4df8062..aa06da196c8 100644
--- a/chromium/components/prerender/browser/prerender_util_unittest.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_util_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 "components/prerender/browser/prerender_util.h"
+#include "components/no_state_prefetch/browser/prerender_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/components/prerender/common/BUILD.gn b/chromium/components/no_state_prefetch/common/BUILD.gn
index 45f5fcb709d..45f5fcb709d 100644
--- a/chromium/components/prerender/common/BUILD.gn
+++ b/chromium/components/no_state_prefetch/common/BUILD.gn
diff --git a/chromium/components/prerender/common/DEPS b/chromium/components/no_state_prefetch/common/DEPS
index 2cfa3620fa8..2cfa3620fa8 100644
--- a/chromium/components/prerender/common/DEPS
+++ b/chromium/components/no_state_prefetch/common/DEPS
diff --git a/chromium/components/prerender/common/OWNERS b/chromium/components/no_state_prefetch/common/OWNERS
index d8469177c4e..d8469177c4e 100644
--- a/chromium/components/prerender/common/OWNERS
+++ b/chromium/components/no_state_prefetch/common/OWNERS
diff --git a/chromium/components/prerender/common/prerender_canceler.mojom b/chromium/components/no_state_prefetch/common/prerender_canceler.mojom
index 8d0be5e5c3e..8d0be5e5c3e 100644
--- a/chromium/components/prerender/common/prerender_canceler.mojom
+++ b/chromium/components/no_state_prefetch/common/prerender_canceler.mojom
diff --git a/chromium/components/prerender/common/prerender_final_status.cc b/chromium/components/no_state_prefetch/common/prerender_final_status.cc
index 51f7c29fc0b..be22d0f899c 100644
--- a/chromium/components/prerender/common/prerender_final_status.cc
+++ b/chromium/components/no_state_prefetch/common/prerender_final_status.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 "components/prerender/common/prerender_final_status.h"
+#include "components/no_state_prefetch/common/prerender_final_status.h"
#include "base/check_op.h"
#include "base/stl_util.h"
@@ -74,6 +74,8 @@ const char* kFinalStatusNames[] = {
"GWS Holdback",
"Unknown",
"Navigation Predictor Holdback",
+ "Single Process Mode",
+ "Link Rel Next Not Allowed",
"Max",
};
static_assert(base::size(kFinalStatusNames) == FINAL_STATUS_MAX + 1,
diff --git a/chromium/components/prerender/common/prerender_final_status.h b/chromium/components/no_state_prefetch/common/prerender_final_status.h
index ffcddd3edbe..04a463f4781 100644
--- a/chromium/components/prerender/common/prerender_final_status.h
+++ b/chromium/components/no_state_prefetch/common/prerender_final_status.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_COMMON_PRERENDER_FINAL_STATUS_H_
-#define COMPONENTS_PRERENDER_COMMON_PRERENDER_FINAL_STATUS_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_FINAL_STATUS_H_
+#define COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_FINAL_STATUS_H_
-#include "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
namespace prerender {
@@ -79,6 +79,8 @@ enum FinalStatus {
FINAL_STATUS_GWS_HOLDBACK = 59,
FINAL_STATUS_UNKNOWN = 60,
FINAL_STATUS_NAVIGATION_PREDICTOR_HOLDBACK = 61,
+ FINAL_STATUS_SINGLE_PROCESS = 62,
+ FINAL_STATUS_LINK_REL_NEXT_NOT_ALLOWED = 63,
FINAL_STATUS_MAX,
};
@@ -88,4 +90,4 @@ const char* NameFromFinalStatus(FinalStatus final_status);
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_COMMON_PRERENDER_FINAL_STATUS_H_ \ No newline at end of file
+#endif // COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_FINAL_STATUS_H_ \ No newline at end of file
diff --git a/chromium/components/prerender/common/prerender_origin.cc b/chromium/components/no_state_prefetch/common/prerender_origin.cc
index ccb6d437a84..4d0c63b2c21 100644
--- a/chromium/components/prerender/common/prerender_origin.cc
+++ b/chromium/components/no_state_prefetch/common/prerender_origin.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 "components/prerender/common/prerender_origin.h"
+#include "components/no_state_prefetch/common/prerender_origin.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
diff --git a/chromium/components/prerender/common/prerender_origin.h b/chromium/components/no_state_prefetch/common/prerender_origin.h
index 861d7bb1ede..8de35dc9423 100644
--- a/chromium/components/prerender/common/prerender_origin.h
+++ b/chromium/components/no_state_prefetch/common/prerender_origin.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 COMPONENTS_PRERENDER_COMMON_PRERENDER_ORIGIN_H_
-#define COMPONENTS_PRERENDER_COMMON_PRERENDER_ORIGIN_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_ORIGIN_H_
+#define COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_ORIGIN_H_
namespace prerender {
@@ -40,4 +40,4 @@ const char* NameFromOrigin(Origin origin);
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_COMMON_PRERENDER_ORIGIN_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_ORIGIN_H_
diff --git a/chromium/components/prerender/common/prerender_types.mojom b/chromium/components/no_state_prefetch/common/prerender_types.mojom
index 747a9d9913f..747a9d9913f 100644
--- a/chromium/components/prerender/common/prerender_types.mojom
+++ b/chromium/components/no_state_prefetch/common/prerender_types.mojom
diff --git a/chromium/components/prerender/common/prerender_url_loader_throttle.cc b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc
index d3bf2e04a95..f8f5b5ca600 100644
--- a/chromium/components/prerender/common/prerender_url_loader_throttle.cc
+++ b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/common/prerender_url_loader_throttle.h"
+#include "components/no_state_prefetch/common/prerender_url_loader_throttle.h"
#include "base/bind.h"
#include "build/build_config.h"
-#include "components/prerender/common/prerender_util.h"
+#include "components/no_state_prefetch/common/prerender_util.h"
#include "content/public/common/content_constants.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/load_flags.h"
diff --git a/chromium/components/prerender/common/prerender_url_loader_throttle.h b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.h
index ad5ef195959..bdd702426b7 100644
--- a/chromium/components/prerender/common/prerender_url_loader_throttle.h
+++ b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.h
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
-#define COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#define COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/timer/timer.h"
-#include "components/prerender/common/prerender_canceler.mojom.h"
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/common/prerender_canceler.mojom.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
#include "net/base/request_priority.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
@@ -75,4 +75,4 @@ class PrerenderURLLoaderThrottle
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
diff --git a/chromium/components/prerender/common/prerender_util.cc b/chromium/components/no_state_prefetch/common/prerender_util.cc
index cf60258cdbd..64a4cac8229 100644
--- a/chromium/components/prerender/common/prerender_util.cc
+++ b/chromium/components/no_state_prefetch/common/prerender_util.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 "components/prerender/common/prerender_util.h"
+#include "components/no_state_prefetch/common/prerender_util.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
diff --git a/chromium/components/prerender/common/prerender_util.h b/chromium/components/no_state_prefetch/common/prerender_util.h
index 964eb1258c5..4c383838e29 100644
--- a/chromium/components/prerender/common/prerender_util.h
+++ b/chromium/components/no_state_prefetch/common/prerender_util.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_COMMON_PRERENDER_UTIL_H_
-#define COMPONENTS_PRERENDER_COMMON_PRERENDER_UTIL_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_UTIL_H_
+#define COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_UTIL_H_
#include <string>
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
class GURL;
@@ -43,4 +43,4 @@ void RecordPrefetchRedirectCount(const std::string& histogram_prefix,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_COMMON_PRERENDER_UTIL_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_COMMON_PRERENDER_UTIL_H_
diff --git a/chromium/components/prerender/common/render_frame_prerender_messages.mojom b/chromium/components/no_state_prefetch/common/render_frame_prerender_messages.mojom
index 10fa405a29d..327917c9dd6 100644
--- a/chromium/components/prerender/common/render_frame_prerender_messages.mojom
+++ b/chromium/components/no_state_prefetch/common/render_frame_prerender_messages.mojom
@@ -4,7 +4,7 @@
module prerender.mojom;
-import "components/prerender/common/prerender_types.mojom";
+import "components/no_state_prefetch/common/prerender_types.mojom";
// Prerender messages sent from the browser to the render frame.
interface PrerenderMessages {
diff --git a/chromium/components/prerender/renderer/BUILD.gn b/chromium/components/no_state_prefetch/renderer/BUILD.gn
index c58fad43a15..44122a64b4b 100644
--- a/chromium/components/prerender/renderer/BUILD.gn
+++ b/chromium/components/no_state_prefetch/renderer/BUILD.gn
@@ -18,8 +18,8 @@ static_library("renderer") {
]
deps = [
- "//components/prerender/common",
- "//components/prerender/common:mojo_bindings",
+ "//components/no_state_prefetch/common",
+ "//components/no_state_prefetch/common:mojo_bindings",
"//content/public/common",
"//content/public/renderer",
"//third_party/blink/public:blink_headers",
diff --git a/chromium/components/prerender/renderer/DEPS b/chromium/components/no_state_prefetch/renderer/DEPS
index f94db2aa8cb..f94db2aa8cb 100644
--- a/chromium/components/prerender/renderer/DEPS
+++ b/chromium/components/no_state_prefetch/renderer/DEPS
diff --git a/chromium/components/prerender/renderer/prerender_helper.cc b/chromium/components/no_state_prefetch/renderer/prerender_helper.cc
index e18c74ae909..de57da94bfe 100644
--- a/chromium/components/prerender/renderer/prerender_helper.cc
+++ b/chromium/components/no_state_prefetch/renderer/prerender_helper.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/renderer/prerender_helper.h"
+#include "components/no_state_prefetch/renderer/prerender_helper.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
-#include "components/prerender//common/prerender_url_loader_throttle.h"
+#include "components/no_state_prefetch//common/prerender_url_loader_throttle.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
diff --git a/chromium/components/prerender/renderer/prerender_helper.h b/chromium/components/no_state_prefetch/renderer/prerender_helper.h
index 8cc2821af83..1aba2aa6e09 100644
--- a/chromium/components/prerender/renderer/prerender_helper.h
+++ b/chromium/components/no_state_prefetch/renderer/prerender_helper.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_HELPER_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_HELPER_H_
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
-#include "components/prerender/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_frame_observer_tracker.h"
@@ -72,4 +72,4 @@ class PrerenderHelper
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDER_HELPER_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_HELPER_H_
diff --git a/chromium/components/prerender/renderer/prerender_observer.h b/chromium/components/no_state_prefetch/renderer/prerender_observer.h
index eb31c25eb57..f946f0653ce 100644
--- a/chromium/components/prerender/renderer/prerender_observer.h
+++ b/chromium/components/no_state_prefetch/renderer/prerender_observer.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 COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_H_
#include "base/observer_list_types.h"
@@ -20,4 +20,4 @@ class PrerenderObserver : public base::CheckedObserver {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_H_
diff --git a/chromium/components/prerender/renderer/prerender_observer_list.cc b/chromium/components/no_state_prefetch/renderer/prerender_observer_list.cc
index 078970667f0..6a8d5fa6e03 100644
--- a/chromium/components/prerender/renderer/prerender_observer_list.cc
+++ b/chromium/components/no_state_prefetch/renderer/prerender_observer_list.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/renderer/prerender_observer_list.h"
+#include "components/no_state_prefetch/renderer/prerender_observer_list.h"
-#include "components/prerender/renderer/prerender_observer.h"
+#include "components/no_state_prefetch/renderer/prerender_observer.h"
#include "content/public/renderer/render_frame.h"
namespace prerender {
diff --git a/chromium/components/prerender/renderer/prerender_observer_list.h b/chromium/components/no_state_prefetch/renderer/prerender_observer_list.h
index 23514ab98dd..370b1a6c45d 100644
--- a/chromium/components/prerender/renderer/prerender_observer_list.h
+++ b/chromium/components/no_state_prefetch/renderer/prerender_observer_list.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 COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_LIST_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_LIST_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_LIST_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_LIST_H_
#include "base/observer_list.h"
#include "base/supports_user_data.h"
@@ -47,4 +47,4 @@ class PrerenderObserverList : public base::SupportsUserData::Data {
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDER_OBSERVER_LIST_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_OBSERVER_LIST_H_
diff --git a/chromium/components/prerender/renderer/prerender_render_frame_observer.cc b/chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.cc
index 5bdc228c8b4..466a9a66498 100644
--- a/chromium/components/prerender/renderer/prerender_render_frame_observer.cc
+++ b/chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/renderer/prerender_render_frame_observer.h"
+#include "components/no_state_prefetch/renderer/prerender_render_frame_observer.h"
-#include "components/prerender/common/prerender_types.mojom.h"
-#include "components/prerender/renderer/prerender_helper.h"
-#include "components/prerender/renderer/prerender_observer_list.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/renderer/prerender_helper.h"
+#include "components/no_state_prefetch/renderer/prerender_observer_list.h"
#include "content/public/renderer/render_frame.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
diff --git a/chromium/components/prerender/renderer/prerender_render_frame_observer.h b/chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.h
index a14b5cbb81b..1715d64be21 100644
--- a/chromium/components/prerender/renderer/prerender_render_frame_observer.h
+++ b/chromium/components/no_state_prefetch/renderer/prerender_render_frame_observer.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PRERENDER_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_
-#include "components/prerender/common/prerender_types.mojom.h"
-#include "components/prerender/common/render_frame_prerender_messages.mojom.h"
+#include "components/no_state_prefetch/common/prerender_types.mojom.h"
+#include "components/no_state_prefetch/common/render_frame_prerender_messages.mojom.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -41,4 +41,4 @@ class PrerenderRenderFrameObserver
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_ \ No newline at end of file
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_RENDER_FRAME_OBSERVER_H_ \ No newline at end of file
diff --git a/chromium/components/prerender/renderer/prerender_utils.cc b/chromium/components/no_state_prefetch/renderer/prerender_utils.cc
index c7bab17a609..151c245c037 100644
--- a/chromium/components/prerender/renderer/prerender_utils.cc
+++ b/chromium/components/no_state_prefetch/renderer/prerender_utils.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/renderer/prerender_utils.h"
+#include "components/no_state_prefetch/renderer/prerender_utils.h"
-#include "components/prerender/renderer/prerender_helper.h"
+#include "components/no_state_prefetch/renderer/prerender_helper.h"
#include "content/public/common/page_visibility_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
diff --git a/chromium/components/prerender/renderer/prerender_utils.h b/chromium/components/no_state_prefetch/renderer/prerender_utils.h
index e03ddf2f7f6..c16c3b3e667 100644
--- a/chromium/components/prerender/renderer/prerender_utils.h
+++ b/chromium/components/no_state_prefetch/renderer/prerender_utils.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 COMPONENTS_PRERENDER_RENDERER_PRERENDER_UTILS_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDER_UTILS_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_UTILS_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_UTILS_H_
#include "base/callback_forward.h"
@@ -22,4 +22,4 @@ bool DeferMediaLoad(content::RenderFrame* render_frame,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDER_UTILS_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDER_UTILS_H_
diff --git a/chromium/components/prerender/renderer/prerenderer_client.cc b/chromium/components/no_state_prefetch/renderer/prerenderer_client.cc
index 874036994e6..781efe55959 100644
--- a/chromium/components/prerender/renderer/prerenderer_client.cc
+++ b/chromium/components/no_state_prefetch/renderer/prerenderer_client.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/prerender/renderer/prerenderer_client.h"
+#include "components/no_state_prefetch/renderer/prerenderer_client.h"
#include "base/logging.h"
-#include "components/prerender/renderer/prerender_helper.h"
+#include "components/no_state_prefetch/renderer/prerender_helper.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "third_party/blink/public/web/web_view.h"
diff --git a/chromium/components/prerender/renderer/prerenderer_client.h b/chromium/components/no_state_prefetch/renderer/prerenderer_client.h
index ec546c522a9..69978bceac2 100644
--- a/chromium/components/prerender/renderer/prerenderer_client.h
+++ b/chromium/components/no_state_prefetch/renderer/prerenderer_client.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 COMPONENTS_PRERENDER_RENDERER_PRERENDERER_CLIENT_H_
-#define COMPONENTS_PRERENDER_RENDERER_PRERENDERER_CLIENT_H_
+#ifndef COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDERER_CLIENT_H_
+#define COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDERER_CLIENT_H_
#include "base/compiler_specific.h"
#include "content/public/renderer/render_view_observer.h"
@@ -28,4 +28,4 @@ class PrerendererClient : public content::RenderViewObserver,
} // namespace prerender
-#endif // COMPONENTS_PRERENDER_RENDERER_PRERENDERER_CLIENT_H_
+#endif // COMPONENTS_NO_STATE_PREFETCH_RENDERER_PRERENDERER_CLIENT_H_
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index 71b3f5620f8..aff4032f1c2 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -56,8 +56,6 @@ ContentSuggestionsService::ContentSuggestionsService(
std::unique_ptr<UserClassifier> user_classifier,
std::unique_ptr<RemoteSuggestionsScheduler> remote_suggestions_scheduler)
: state_(state),
- identity_manager_observer_(this),
- history_service_observer_(this),
remote_suggestions_provider_(nullptr),
large_icon_service_(large_icon_service),
pref_service_(pref_service),
@@ -66,11 +64,11 @@ ContentSuggestionsService::ContentSuggestionsService(
category_ranker_(std::move(category_ranker)) {
// Can be null in tests.
if (identity_manager) {
- identity_manager_observer_.Add(identity_manager);
+ identity_manager_observation_.Observe(identity_manager);
}
if (history_service) {
- history_service_observer_.Add(history_service);
+ history_service_observation_.Observe(history_service);
}
RestoreDismissedCategoriesFromPrefs();
@@ -552,7 +550,8 @@ void ContentSuggestionsService::OnURLsDeleted(
void ContentSuggestionsService::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_service_observer_.RemoveAll();
+ DCHECK(history_service_observation_.IsObservingSource(history_service));
+ history_service_observation_.RemoveObservation();
}
bool ContentSuggestionsService::TryRegisterProviderForCategory(
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
index 81eee3d0f42..e942e70d834 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -14,7 +14,7 @@
#include "base/callback_forward.h"
#include "base/observer_list.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
@@ -378,13 +378,15 @@ class ContentSuggestionsService : public KeyedService,
// Observer for the IdentityManager. All observers are notified when the
// signin state changes so that they can refresh their list of suggestions.
- ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
- identity_manager_observer_;
+ base::ScopedObservation<signin::IdentityManager,
+ signin::IdentityManager::Observer>
+ identity_manager_observation_{this};
// Observer for the HistoryService. All providers are notified when history is
// deleted.
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_service_observer_;
+ base::ScopedObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_service_observation_{this};
base::ObserverList<Observer>::Unchecked observers_;
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
index c4add3a5b75..40408cdd6ef 100644
--- a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.cc
@@ -43,7 +43,7 @@ ReadingListSuggestionsProvider::ReadingListSuggestionsProvider(
// If the ReadingListModel is loaded, this will trigger a call to
// ReadingListModelLoaded. Keep it as last instruction.
- scoped_observer_.Add(reading_list_model_);
+ scoped_observation_.Observe(reading_list_model_);
}
ReadingListSuggestionsProvider::~ReadingListSuggestionsProvider() {}
@@ -160,7 +160,8 @@ void ReadingListSuggestionsProvider::ReadingListModelLoaded(
void ReadingListSuggestionsProvider::ReadingListModelBeingDeleted(
const ReadingListModel* model) {
DCHECK(model == reading_list_model_);
- scoped_observer_.Remove(reading_list_model_);
+ DCHECK(scoped_observation_.IsObservingSource(reading_list_model_));
+ scoped_observation_.RemoveObservation();
reading_list_model_ = nullptr;
}
diff --git a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h
index 97c443d02a6..1ffbe7a3def 100644
--- a/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/reading_list/reading_list_suggestions_provider.h
@@ -8,7 +8,7 @@
#include <set>
#include <string>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/ntp_snippets/callbacks.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_info.h"
@@ -74,8 +74,8 @@ class ReadingListSuggestionsProvider : public ContentSuggestionsProvider,
const Category provided_category_;
ReadingListModel* reading_list_model_;
- ScopedObserver<ReadingListModel, ReadingListModelObserver> scoped_observer_{
- this};
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(ReadingListSuggestionsProvider);
};
diff --git a/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc b/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
index bb0bd8c2c54..a45809c6e39 100644
--- a/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
+++ b/chromium/components/ntp_snippets/remote/cached_image_fetcher.cc
@@ -5,7 +5,7 @@
#include "components/ntp_snippets/remote/cached_image_fetcher.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/image_fetcher.h"
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
index 29b30fa55a3..028e3aaee40 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service.h
@@ -6,7 +6,7 @@
#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_H_
#include "base/callback.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/prefs/pref_change_registrar.h"
namespace ntp_snippets {
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h
index 03808844778..edf537adafc 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_status_service_impl.h
@@ -6,7 +6,7 @@
#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_STATUS_SERVICE_IMPL_H_
#include "base/callback.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/ntp_snippets/remote/remote_suggestions_status_service.h"
#include "components/prefs/pref_change_registrar.h"
diff --git a/chromium/components/ntp_snippets_strings.grdp b/chromium/components/ntp_snippets_strings.grdp
index fdca4e064d4..90d7754bf38 100644
--- a/chromium/components/ntp_snippets_strings.grdp
+++ b/chromium/components/ntp_snippets_strings.grdp
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <if expr="is_android or is_ios">
+ <if expr="enable_feed_v1 or is_ios">
<message name="IDS_NTP_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title text explaining there is no content." formatter_data="android_java">
That’s all for now
</message>
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index ea2d83a6e8e..b5401929987 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -6,19 +6,10 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("ntp_tiles") {
sources = [
"constants.cc",
"constants.h",
- "country_code_ios.h",
- "country_code_ios.mm",
"custom_links_manager.h",
"custom_links_manager_impl.cc",
"custom_links_manager_impl.h",
@@ -69,6 +60,7 @@ static_library("ntp_tiles") {
"//components/prefs",
"//components/rappor/public",
"//components/resources",
+ "//components/search",
"//components/search_engines",
"//components/strings",
"//components/url_formatter",
@@ -78,6 +70,13 @@ static_library("ntp_tiles") {
"//services/network/public/cpp",
"//ui/base",
]
+
+ if (is_ios) {
+ sources += [
+ "country_code_ios.h",
+ "country_code_ios.mm",
+ ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/ntp_tiles/DEPS b/chromium/components/ntp_tiles/DEPS
index 3742e149693..41e17b9b281 100644
--- a/chromium/components/ntp_tiles/DEPS
+++ b/chromium/components/ntp_tiles/DEPS
@@ -1,15 +1,16 @@
include_rules = [
- "+components/favicon",
"+components/favicon_base",
+ "+components/favicon",
"+components/google/core",
"+components/grit",
- "+components/image_fetcher",
"+components/history/core/browser",
"+components/history/core/test",
+ "+components/image_fetcher",
"+components/pref_registry",
"+components/prefs",
"+components/rappor",
"+components/search_engines",
+ "+components/search",
"+components/strings/grit/components_strings.h",
"+components/suggestions",
"+components/sync_preferences",
@@ -20,6 +21,6 @@ include_rules = [
"+services/data_decoder/public",
"+services/network/public/cpp",
"+services/network/test",
- "+ui/gfx",
"+ui/base",
+ "+ui/gfx",
]
diff --git a/chromium/components/ntp_tiles/constants.cc b/chromium/components/ntp_tiles/constants.cc
index ed849b2bf3c..01bd94d04e0 100644
--- a/chromium/components/ntp_tiles/constants.cc
+++ b/chromium/components/ntp_tiles/constants.cc
@@ -8,8 +8,8 @@ namespace ntp_tiles {
const size_t kMaxNumCustomLinks = 10;
-// Because the custom links feature has an additional "Add shortcut" button, 9
-// tiles are required to balance the Most Visited rows on the NTP.
-const int kMaxNumMostVisited = 9;
+// If custom links are enabled, an additional tile may be returned making up to
+// kMaxNumCustomLinks custom links including the "Add shortcut" button.
+const size_t kMaxNumMostVisited = 8;
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/constants.h b/chromium/components/ntp_tiles/constants.h
index eb7a95f0b1a..755a0ecbcf4 100644
--- a/chromium/components/ntp_tiles/constants.h
+++ b/chromium/components/ntp_tiles/constants.h
@@ -15,7 +15,7 @@ namespace ntp_tiles {
extern const size_t kMaxNumCustomLinks;
// Maximum number of Most Visited sites that will be generated. Used on desktop.
-extern const int kMaxNumMostVisited;
+extern const size_t kMaxNumMostVisited;
// Maximum number of tiles that can be shown on the NTP.
const int kMaxNumTiles = 10;
diff --git a/chromium/components/ntp_tiles/custom_links_manager_impl.cc b/chromium/components/ntp_tiles/custom_links_manager_impl.cc
index 1783dc361a4..70a90e17074 100644
--- a/chromium/components/ntp_tiles/custom_links_manager_impl.cc
+++ b/chromium/components/ntp_tiles/custom_links_manager_impl.cc
@@ -20,10 +20,10 @@ namespace ntp_tiles {
CustomLinksManagerImpl::CustomLinksManagerImpl(
PrefService* prefs,
history::HistoryService* history_service)
- : prefs_(prefs), store_(prefs), history_service_observer_(this) {
+ : prefs_(prefs), store_(prefs) {
DCHECK(prefs);
if (history_service)
- history_service_observer_.Add(history_service);
+ history_service_observation_.Observe(history_service);
if (IsInitialized())
current_links_ = store_.RetrieveLinks();
@@ -226,7 +226,7 @@ void CustomLinksManagerImpl::OnURLsDeleted(
void CustomLinksManagerImpl::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_service_observer_.RemoveAll();
+ history_service_observation_.RemoveObservation();
}
void CustomLinksManagerImpl::OnPreferenceChanged() {
diff --git a/chromium/components/ntp_tiles/custom_links_manager_impl.h b/chromium/components/ntp_tiles/custom_links_manager_impl.h
index cdc3d1c3f38..d89a14649bf 100644
--- a/chromium/components/ntp_tiles/custom_links_manager_impl.h
+++ b/chromium/components/ntp_tiles/custom_links_manager_impl.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/ntp_tiles/custom_links_manager.h"
@@ -95,8 +95,9 @@ class CustomLinksManagerImpl : public CustomLinksManager,
base::CallbackList<void()> callback_list_;
// Observer for the HistoryService.
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_service_observer_;
+ base::ScopedObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_service_observation_{this};
// Observer for Chrome sync changes to |prefs::kCustomLinksList| and
// |prefs::kCustomLinksInitialized|.
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index b44a11f0e62..4e6dd1c2216 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_set.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
diff --git a/chromium/components/ntp_tiles/metrics.cc b/chromium/components/ntp_tiles/metrics.cc
index 720b3fb23ea..567baf3d12b 100644
--- a/chromium/components/ntp_tiles/metrics.cc
+++ b/chromium/components/ntp_tiles/metrics.cc
@@ -8,6 +8,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "components/ntp_tiles/constants.h"
@@ -28,6 +29,7 @@ const char kHistogramWhitelistName[] = "whitelist";
const char kHistogramHomepageName[] = "homepage";
const char kHistogramCustomLinksName[] = "custom_links";
const char kHistogramExploreName[] = "explore";
+const char kHistogramRepeatableQueryName[] = "repeatable_query";
// Suffixes for the various icon types.
const char kTileTypeSuffixIconColor[] = "IconsColor";
@@ -58,6 +60,8 @@ std::string GetSourceHistogramName(TileSource source) {
return kHistogramCustomLinksName;
case TileSource::EXPLORE:
return kHistogramExploreName;
+ case TileSource::REPEATABLE_QUERIES_SERVICE:
+ return kHistogramRepeatableQueryName;
}
NOTREACHED();
return std::string();
@@ -148,6 +152,7 @@ void RecordTileImpression(const NTPTileImpression& impression) {
void RecordTileClick(const NTPTileImpression& impression) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.MostVisited", impression.index,
kMaxNumTiles);
+ base::RecordAction(base::UserMetricsAction("NewTabPage.MostVisited.Clicked"));
std::string source_name = GetSourceHistogramName(impression.source);
base::UmaHistogramExactLinear(
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index d9e725b29db..c6bff3bf06c 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -10,8 +10,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
@@ -26,6 +26,7 @@
#include "components/ntp_tiles/switches.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
+#include "components/search/ntp_features.h"
using history::TopSites;
using suggestions::ChromeSuggestion;
@@ -120,6 +121,7 @@ base::string16 GenerateShortTitle(const base::string16& title) {
MostVisitedSites::MostVisitedSites(
PrefService* prefs,
scoped_refptr<history::TopSites> top_sites,
+ RepeatableQueriesService* repeatable_queries,
SuggestionsService* suggestions,
std::unique_ptr<PopularSites> popular_sites,
std::unique_ptr<CustomLinksManager> custom_links,
@@ -127,6 +129,7 @@ MostVisitedSites::MostVisitedSites(
std::unique_ptr<MostVisitedSitesSupervisor> supervisor)
: prefs_(prefs),
top_sites_(top_sites),
+ repeatable_queries_(repeatable_queries),
suggestions_service_(suggestions),
popular_sites_(std::move(popular_sites)),
custom_links_(std::move(custom_links)),
@@ -179,6 +182,8 @@ bool MostVisitedSites::DoesSourceExist(TileSource source) const {
return custom_links_ != nullptr;
case TileSource::EXPLORE:
return explore_sites_client_ != nullptr;
+ case TileSource::REPEATABLE_QUERIES_SERVICE:
+ return false;
}
NOTREACHED();
return false;
@@ -196,14 +201,14 @@ void MostVisitedSites::SetExploreSitesClient(
}
void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
- size_t num_sites) {
+ size_t max_num_sites) {
DCHECK(observer);
observer_ = observer;
- max_num_sites_ = num_sites;
+ max_num_sites_ = max_num_sites;
// The order for this condition is important, ShouldShowPopularSites() should
// always be called last to keep metrics as relevant as possible.
- if (popular_sites_ && NeedPopularSites(prefs_, max_num_sites_) &&
+ if (popular_sites_ && NeedPopularSites(prefs_, GetMaxNumSites()) &&
ShouldShowPopularSites()) {
popular_sites_->MaybeStartFetch(
false, base::BindOnce(&MostVisitedSites::OnPopularSitesDownloaded,
@@ -213,7 +218,11 @@ void MostVisitedSites::SetMostVisitedURLsObserver(Observer* observer,
if (top_sites_) {
// Register as TopSitesObserver so that we can update ourselves when the
// TopSites changes.
- top_sites_observer_.Add(top_sites_.get());
+ top_sites_observation_.Observe(top_sites_.get());
+ }
+
+ if (repeatable_queries_) {
+ repeatable_queries_observation_.Observe(repeatable_queries_);
}
if (custom_links_) {
@@ -242,6 +251,10 @@ void MostVisitedSites::Refresh() {
top_sites_->SyncWithHistory();
}
+ if (repeatable_queries_) {
+ repeatable_queries_->Refresh();
+ }
+
suggestions_service_->FetchSuggestionsData();
}
@@ -387,6 +400,13 @@ void MostVisitedSites::AddOrRemoveBlockedUrl(const GURL& url, bool add_url) {
base::UserMetricsAction("Suggestions.Site.RemovalUndone"));
}
+ if (repeatable_queries_) {
+ if (add_url)
+ repeatable_queries_->DeleteQueryWithDestinationURL(url);
+ else
+ NOTREACHED() << "Deleted repeatable queries cannot be restored.";
+ }
+
if (top_sites_) {
if (add_url)
top_sites_->AddBlockedUrl(url);
@@ -422,6 +442,10 @@ void MostVisitedSites::RegisterProfilePrefs(
registry->RegisterIntegerPref(prefs::kNumPersonalTiles, 0);
}
+size_t MostVisitedSites::GetMaxNumSites() const {
+ return max_num_sites_ + (custom_links_ && custom_links_enabled_ ? 1 : 0);
+}
+
void MostVisitedSites::InitiateTopSitesQuery() {
if (!top_sites_)
return;
@@ -452,7 +476,7 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
}
NTPTilesVector tiles;
- size_t num_tiles = std::min(visited_list.size(), max_num_sites_);
+ size_t num_tiles = std::min(visited_list.size(), GetMaxNumSites());
for (size_t i = 0; i < num_tiles; ++i) {
const history::MostVisitedURL& visited = visited_list[i];
if (visited.url.is_empty())
@@ -475,7 +499,37 @@ void MostVisitedSites::OnMostVisitedURLsAvailable(
}
mv_source_ = TileSource::TOP_SITES;
- InitiateNotificationForNewTiles(std::move(tiles));
+ InitiateNotificationForNewTiles(InsertRepeatableQueryTiles(std::move(tiles)));
+}
+
+NTPTilesVector MostVisitedSites::InsertRepeatableQueryTiles(
+ NTPTilesVector tiles) {
+ if (!repeatable_queries_)
+ return tiles;
+
+ const std::vector<RepeatableQuery>& repeatable_queries =
+ repeatable_queries_->repeatable_queries();
+
+ // Make room for the repeatable query tiles, if necessary.
+ int num_overflow_tiles =
+ tiles.size() + repeatable_queries.size() - GetMaxNumSites();
+ if (num_overflow_tiles > 0)
+ tiles.resize(tiles.size() - num_overflow_tiles);
+
+ auto insert_position = (ntp_features::GetRepeatableQueriesInsertPosition() ==
+ ntp_features::RepeatableQueriesInsertPosition::kStart)
+ ? tiles.begin()
+ : tiles.end();
+ for (const auto& repeatable_query : repeatable_queries) {
+ NTPTile tile;
+ tile.title = repeatable_query.query;
+ tile.url = repeatable_query.destination_url;
+ tile.source = TileSource::REPEATABLE_QUERIES_SERVICE;
+
+ auto inserted_position = tiles.insert(insert_position, tile);
+ insert_position = inserted_position + 1;
+ }
+ return tiles;
}
void MostVisitedSites::OnSuggestionsProfileChanged(
@@ -512,8 +566,8 @@ void MostVisitedSites::BuildCurrentTilesGivenSuggestionsProfile(
InitiateTopSitesQuery();
return;
}
- if (max_num_sites_ < num_tiles)
- num_tiles = max_num_sites_;
+ if (GetMaxNumSites() < num_tiles)
+ num_tiles = GetMaxNumSites();
const base::Time profile_timestamp =
base::Time::UnixEpoch() +
@@ -559,7 +613,7 @@ NTPTilesVector MostVisitedSites::CreateWhitelistEntryPointTiles(
NTPTilesVector whitelist_tiles;
for (const auto& whitelist : supervisor_->GetWhitelists()) {
- if (whitelist_tiles.size() + num_actual_tiles >= max_num_sites_)
+ if (whitelist_tiles.size() + num_actual_tiles >= GetMaxNumSites())
break;
// Skip blocked sites.
@@ -607,7 +661,7 @@ MostVisitedSites::CreatePopularSitesSections(
SectionType type = section_type_and_sites.first;
const PopularSites::SitesVector& sites = section_type_and_sites.second;
if (type == SectionType::PERSONALIZED) {
- size_t num_required_tiles = max_num_sites_ - num_actual_tiles;
+ size_t num_required_tiles = GetMaxNumSites() - num_actual_tiles;
sections[type] =
CreatePopularSitesTiles(/*popular_sites=*/sites,
/*hosts_to_skip=*/used_hosts,
@@ -616,7 +670,7 @@ MostVisitedSites::CreatePopularSitesSections(
sections[type] =
CreatePopularSitesTiles(/*popular_sites=*/sites,
/*hosts_to_skip=*/no_hosts,
- /*num_max_tiles=*/max_num_sites_);
+ /*num_max_tiles=*/GetMaxNumSites());
}
}
return sections;
@@ -673,14 +727,14 @@ NTPTilesVector MostVisitedSites::InsertHomeTile(
NTPTilesVector tiles,
const base::string16& title) const {
DCHECK(homepage_client_);
- DCHECK_GT(max_num_sites_, 0u);
+ DCHECK_GT(GetMaxNumSites(), 0u);
const GURL& homepage_url = homepage_client_->GetHomepageUrl();
NTPTilesVector new_tiles;
bool homepage_tile_added = false;
for (auto& tile : tiles) {
- if (new_tiles.size() >= max_num_sites_) {
+ if (new_tiles.size() >= GetMaxNumSites()) {
break;
}
@@ -697,7 +751,7 @@ NTPTilesVector MostVisitedSites::InsertHomeTile(
if (!homepage_tile_added) {
// Make room for the homepage tile.
- if (new_tiles.size() >= max_num_sites_) {
+ if (new_tiles.size() >= GetMaxNumSites()) {
new_tiles.pop_back();
}
NTPTile homepage_tile;
@@ -792,7 +846,7 @@ void MostVisitedSites::MergeMostVisitedTiles(NTPTilesVector personal_tiles) {
// The explore sites tile may have taken a space that was utilized by the
// personal tiles.
- if (personal_tiles.size() + num_actual_tiles > max_num_sites_) {
+ if (personal_tiles.size() + num_actual_tiles > GetMaxNumSites()) {
personal_tiles.pop_back();
}
AddToHostsAndTotalCount(personal_tiles, &used_hosts, &num_actual_tiles);
@@ -882,8 +936,22 @@ void MostVisitedSites::TopSitesChanged(TopSites* top_sites,
}
}
+void MostVisitedSites::OnRepeatableQueriesUpdated() {
+ // Repeatable Queries are shown along with the most visited URLs only.
+ // Simulate a change to the most visited urls. This will result in
+ // MostVisitedSites::OnMostVisitedURLsAvailable to be called synchronously or
+ // asynchronously depending on whether the most visited URLs are cached.
+ if (top_sites_) {
+ TopSitesChanged(top_sites_.get(), ChangeReason::MOST_VISITED);
+ }
+}
+
+void MostVisitedSites::OnRepeatableQueriesServiceShuttingDown() {
+ repeatable_queries_observation_.RemoveObservation();
+}
+
bool MostVisitedSites::ShouldAddHomeTile() const {
- return max_num_sites_ > 0u &&
+ return GetMaxNumSites() > 0u &&
homepage_client_ && // No platform-specific implementation - no tile.
homepage_client_->IsHomepageTileEnabled() &&
!homepage_client_->GetHomepageUrl().is_empty() &&
@@ -898,7 +966,7 @@ void MostVisitedSites::AddToHostsAndTotalCount(const NTPTilesVector& new_tiles,
hosts->insert(tile.url.host());
}
*total_tile_count += new_tiles.size();
- DCHECK_LE(*total_tile_count, max_num_sites_);
+ DCHECK_LE(*total_tile_count, GetMaxNumSites());
}
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/most_visited_sites.h b/chromium/components/ntp_tiles/most_visited_sites.h
index c8a3c65adc5..f21c76e11dd 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.h
+++ b/chromium/components/ntp_tiles/most_visited_sites.h
@@ -21,7 +21,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/string16.h"
#include "components/history/core/browser/history_types.h"
#include "components/history/core/browser/top_sites.h"
@@ -31,6 +31,8 @@
#include "components/ntp_tiles/popular_sites.h"
#include "components/ntp_tiles/section_type.h"
#include "components/ntp_tiles/tile_source.h"
+#include "components/search/repeatable_queries/repeatable_queries_service.h"
+#include "components/search/repeatable_queries/repeatable_queries_service_observer.h"
#include "components/suggestions/proto/suggestions.pb.h"
#include "components/suggestions/suggestions_service.h"
#include "url/gurl.h"
@@ -82,7 +84,8 @@ class MostVisitedSitesSupervisor {
// Tracks the list of most visited sites.
class MostVisitedSites : public history::TopSitesObserver,
- public MostVisitedSitesSupervisor::Observer {
+ public MostVisitedSitesSupervisor::Observer,
+ public RepeatableQueriesServiceObserver {
public:
// The observer to be notified when the list of most visited sites changes.
class Observer {
@@ -123,6 +126,7 @@ class MostVisitedSites : public history::TopSitesObserver,
// optional and if null, the associated features will be disabled.
MostVisitedSites(PrefService* prefs,
scoped_refptr<history::TopSites> top_sites,
+ RepeatableQueriesService* repeatable_queries,
suggestions::SuggestionsService* suggestions,
std::unique_ptr<PopularSites> popular_sites,
std::unique_ptr<CustomLinksManager> custom_links,
@@ -146,8 +150,9 @@ class MostVisitedSites : public history::TopSitesObserver,
// Sets the observer, and immediately fetches the current suggestions.
// Does not take ownership of |observer|, which must outlive this object and
- // must not be null.
- void SetMostVisitedURLsObserver(Observer* observer, size_t num_sites);
+ // must not be null. |max_num_sites| indicates the the maximum number of most
+ // visited sites to return.
+ void SetMostVisitedURLsObserver(Observer* observer, size_t max_num_sites);
// Sets the client that provides platform-specific homepage preferences.
// When used to replace an existing client, the new client will first be
@@ -241,6 +246,13 @@ class MostVisitedSites : public history::TopSitesObserver,
const std::set<std::string>& hosts_to_skip,
const std::string& host);
+ // Returns the maximum number of most visited sites to return. The return
+ // value is |max_num_sites_| which is ntp_tiles::kMaxNumMostVisited for
+ // Desktop, unless custom links are enabled in which case an additional tile
+ // may be returned making up to ntp_tiles::kMaxNumCustomLinks custom links
+ // including the "Add shortcut" button.
+ size_t GetMaxNumSites() const;
+
// Initialize the query to Top Sites. Called if the SuggestionsService
// returned no data.
void InitiateTopSitesQuery();
@@ -252,6 +264,8 @@ class MostVisitedSites : public history::TopSitesObserver,
void OnMostVisitedURLsAvailable(
const history::MostVisitedURLList& visited_list);
+ NTPTilesVector InsertRepeatableQueryTiles(NTPTilesVector tiles);
+
// Callback for when an update is reported by the SuggestionsService.
void OnSuggestionsProfileChanged(
const suggestions::SuggestionsProfile& suggestions_profile);
@@ -333,8 +347,13 @@ class MostVisitedSites : public history::TopSitesObserver,
void TopSitesChanged(history::TopSites* top_sites,
ChangeReason change_reason) override;
+ // RepeatableQueriesServiceObserver implementation.
+ void OnRepeatableQueriesUpdated() override;
+ void OnRepeatableQueriesServiceShuttingDown() override;
+
PrefService* prefs_;
scoped_refptr<history::TopSites> top_sites_;
+ RepeatableQueriesService* repeatable_queries_;
suggestions::SuggestionsService* suggestions_service_;
std::unique_ptr<PopularSites> const popular_sites_;
std::unique_ptr<CustomLinksManager> const custom_links_;
@@ -346,6 +365,7 @@ class MostVisitedSites : public history::TopSitesObserver,
Observer* observer_;
// The maximum number of most visited sites to return.
+ // Do not use directly. Use GetMaxNumSites() instead.
size_t max_num_sites_;
// False if custom links is disabled and Most Visited sites should be returned
@@ -359,8 +379,12 @@ class MostVisitedSites : public history::TopSitesObserver,
suggestions::SuggestionsService::ResponseCallbackList::Subscription>
suggestions_subscription_;
- ScopedObserver<history::TopSites, history::TopSitesObserver>
- top_sites_observer_{this};
+ base::ScopedObservation<history::TopSites, history::TopSitesObserver>
+ top_sites_observation_{this};
+
+ base::ScopedObservation<RepeatableQueriesService,
+ RepeatableQueriesServiceObserver>
+ repeatable_queries_observation_{this};
std::unique_ptr<base::CallbackList<void()>::Subscription>
custom_links_subscription_;
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index 1ccd776b7e4..f7a7da189b4 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -474,9 +474,9 @@ class MostVisitedSitesTest
EXPECT_CALL(*icon_cacher, StartFetchMostLikely(_, _)).Times(AtLeast(0));
most_visited_sites_ = std::make_unique<MostVisitedSites>(
- &pref_service_, mock_top_sites_, &mock_suggestions_service_,
- popular_sites_factory_.New(), std::move(mock_custom_links),
- std::move(icon_cacher),
+ &pref_service_, mock_top_sites_, /*repeatable_queries=*/nullptr,
+ &mock_suggestions_service_, popular_sites_factory_.New(),
+ std::move(mock_custom_links), std::move(icon_cacher),
/*supervisor=*/nullptr);
}
@@ -1158,9 +1158,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
// Initialize custom links and rebuild tiles. Tiles should be custom links.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
@@ -1183,9 +1184,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
.WillOnce(SaveArg<0>(&sections));
most_visited_sites_->UninitializeCustomLinks();
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
}
TEST_P(MostVisitedSitesWithCustomLinksTest,
@@ -1206,9 +1208,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
// Initialize custom links and rebuild tiles. Tiles should be custom links.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
@@ -1248,9 +1251,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl,
- TileSource::SUGGESTIONS_SERVICE)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0], MatchesTile(kTestTitle, kTestUrl,
+ TileSource::SUGGESTIONS_SERVICE));
// Initialize custom links and rebuild tiles. Tiles should be custom links.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
@@ -1287,14 +1291,16 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl,
- TileSource::SUGGESTIONS_SERVICE)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0], MatchesTile(kTestTitle, kTestUrl,
+ TileSource::SUGGESTIONS_SERVICE));
- // Disable custom links. Tiles should rebuild but not send an update.
+ // Disable custom links. Tiles should rebuild.
EXPECT_CALL(mock_suggestions_service_, GetSuggestionsDataFromCache())
.WillOnce(Return(MakeProfile({MakeSuggestion(kTestTitle, kTestUrl)})));
- EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0);
+ EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
+ .Times(IsPopularSitesFeatureEnabled() ? 1 : 0);
most_visited_sites_->EnableCustomLinks(false);
base::RunLoop().RunUntilIdle();
@@ -1378,17 +1384,21 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(
- MatchesTile(/* The short title generated by the heuristic */ "IMDb",
- kTestUrl1, TileSource::TOP_SITES),
- MatchesTile(
- /* The short title generated by the heuristic */ "Google Drive",
- kTestUrl2, TileSource::TOP_SITES),
- MatchesTile(
- /* The short title generated by the heuristic */ "Amazon.com",
- kTestUrl3, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(3ul));
+ ASSERT_THAT(
+ tiles[0],
+ MatchesTile(/* The short title generated by the heuristic */ "IMDb",
+ kTestUrl1, TileSource::TOP_SITES));
+ ASSERT_THAT(
+ tiles[1],
+ MatchesTile(
+ /* The short title generated by the heuristic */ "Google Drive",
+ kTestUrl2, TileSource::TOP_SITES));
+ ASSERT_THAT(tiles[2],
+ MatchesTile(
+ /* The short title generated by the heuristic */ "Amazon.com",
+ kTestUrl3, TileSource::TOP_SITES));
}
TEST_P(MostVisitedSitesWithCustomLinksTest,
@@ -1414,17 +1424,21 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
/*num_sites=*/3);
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(
- MatchesTile(/* The short title generated by the heuristic */ "IMDb",
- kTestUrl1, TileSource::SUGGESTIONS_SERVICE),
- MatchesTile(
- /* The short title generated by the heuristic */ "Google Drive",
- kTestUrl2, TileSource::SUGGESTIONS_SERVICE),
- MatchesTile(
- /* The short title generated by the heuristic */ "Amazon.com",
- kTestUrl3, TileSource::SUGGESTIONS_SERVICE)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(3ul));
+ ASSERT_THAT(
+ tiles[0],
+ MatchesTile(/* The short title generated by the heuristic */ "IMDb",
+ kTestUrl1, TileSource::SUGGESTIONS_SERVICE));
+ ASSERT_THAT(
+ tiles[1],
+ MatchesTile(
+ /* The short title generated by the heuristic */ "Google Drive",
+ kTestUrl2, TileSource::SUGGESTIONS_SERVICE));
+ ASSERT_THAT(tiles[2],
+ MatchesTile(
+ /* The short title generated by the heuristic */ "Amazon.com",
+ kTestUrl3, TileSource::SUGGESTIONS_SERVICE));
}
TEST_P(MostVisitedSitesWithCustomLinksTest,
@@ -1447,9 +1461,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
base::RunLoop().RunUntilIdle();
// Both cases should not crash and generate an empty title tile.
- EXPECT_THAT(sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile("", kTestUrl1, TileSource::TOP_SITES),
- MatchesTile("", kTestUrl2, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(2ul));
+ ASSERT_THAT(tiles[0], MatchesTile("", kTestUrl1, TileSource::TOP_SITES));
+ ASSERT_THAT(tiles[1], MatchesTile("", kTestUrl2, TileSource::TOP_SITES));
}
TEST_P(MostVisitedSitesWithCustomLinksTest,
@@ -1469,9 +1484,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
// Initialize custom links and complete a custom link action.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
@@ -1501,9 +1517,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
.WillOnce(SaveArg<0>(&sections));
most_visited_sites_->UndoCustomLinkAction();
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
}
TEST_P(MostVisitedSitesWithCustomLinksTest,
@@ -1523,9 +1540,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
// Initialize custom links and complete a custom link action.
EXPECT_CALL(*mock_custom_links_, Initialize(_)).WillOnce(Return(true));
@@ -1580,9 +1598,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest,
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle, kTestUrl, TileSource::TOP_SITES));
// Fail to add a custom link. This should not initialize custom links nor
// notify.
@@ -1652,9 +1671,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest, RebuildTilesOnCustomLinksChanged) {
most_visited_sites_->SetMostVisitedURLsObserver(&mock_observer_,
/*num_sites=*/1);
base::RunLoop().RunUntilIdle();
- ASSERT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES)));
+ NTPTilesVector tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES));
// Notify that there is a new set of custom links. This should replace the
// current tiles with custom links.
@@ -1683,9 +1703,10 @@ TEST_P(MostVisitedSitesWithCustomLinksTest, RebuildTilesOnCustomLinksChanged) {
.WillOnce(SaveArg<0>(&sections));
custom_links_callback.Run();
base::RunLoop().RunUntilIdle();
- EXPECT_THAT(
- sections.at(SectionType::PERSONALIZED),
- ElementsAre(MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES)));
+ tiles = sections.at(SectionType::PERSONALIZED);
+ ASSERT_THAT(tiles.size(), Ge(1ul));
+ ASSERT_THAT(tiles[0],
+ MatchesTile(kTestTitle1, kTestUrl1, TileSource::TOP_SITES));
}
// These tests expect Most Likely to be enabled, and exclude Android and iOS,
diff --git a/chromium/components/ntp_tiles/tile_source.h b/chromium/components/ntp_tiles/tile_source.h
index d4670041184..9376b086d20 100644
--- a/chromium/components/ntp_tiles/tile_source.h
+++ b/chromium/components/ntp_tiles/tile_source.h
@@ -28,8 +28,10 @@ enum class TileSource {
HOMEPAGE,
// Tile comes from explore sites list.
EXPLORE,
+ // Tile comes from the repeatable queries service, based on search history.
+ REPEATABLE_QUERIES_SERVICE,
- LAST = EXPLORE
+ LAST = REPEATABLE_QUERIES_SERVICE
};
} // namespace ntp_tiles
diff --git a/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html b/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
index ea76d561e5b..ef7da4b50b3 100644
--- a/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
+++ b/chromium/components/ntp_tiles/webui/resources/ntp_tiles_internals.html
@@ -17,6 +17,7 @@ found in the LICENSE file.
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<if expr="is_ios">
<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
diff --git a/chromium/components/offline_items_collection/core/android/offline_item_visuals_bridge.cc b/chromium/components/offline_items_collection/core/android/offline_item_visuals_bridge.cc
index 36123b7a00d..ad9cd4a232a 100644
--- a/chromium/components/offline_items_collection/core/android/offline_item_visuals_bridge.cc
+++ b/chromium/components/offline_items_collection/core/android/offline_item_visuals_bridge.cc
@@ -24,7 +24,7 @@ ScopedJavaLocalRef<jobject> OfflineItemVisualsBridge::CreateOfflineItemVisuals(
base::android::ScopedJavaLocalRef<jobject> j_icon;
if (!visuals->icon.IsEmpty())
- j_icon = gfx::ConvertToJavaBitmap(visuals->icon.ToSkBitmap());
+ j_icon = gfx::ConvertToJavaBitmap(*visuals->icon.ToSkBitmap());
return Java_OfflineItemVisualsBridge_createOfflineItemVisuals(env, j_icon);
}
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
index 60a970e3fed..964a4fd3e44 100644
--- a/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
@@ -7,7 +7,7 @@
#include <map>
#include "base/bind.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_items_collection/core/offline_item.h"
diff --git a/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc b/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
index f5b977c2771..79e5bb0c105 100644
--- a/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc b/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
index 5857a3b2dc2..4300c07b885 100644
--- a/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
@@ -8,7 +8,7 @@
#include <set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/offliner_policy.h"
diff --git a/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc b/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
index 6355f9307c0..e9f98f2b329 100644
--- a/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc b/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
index a62a228c753..64e94c4b13b 100644
--- a/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
index b0a2e5c741b..4c9c1ccd506 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/change_requests_state_task.h"
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
index a66e68d9f9b..2a4dba37063 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/offline_pages/core/background/request_queue_store.h"
#include "components/offline_pages/core/background/request_queue_task_test_base.h"
#include "components/offline_pages/core/background/test_request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
index eac1ad1ef2e..f48de0eefa4 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
index 792437e036d..a4601c4dc3c 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/circular_deque.h"
#include "base/time/time.h"
#include "components/offline_pages/core/background/device_conditions.h"
diff --git a/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc b/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
index 47308aa9ac3..02e7458c01b 100644
--- a/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
@@ -8,7 +8,7 @@
#include <set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_coordinator.h"
diff --git a/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc b/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
index de815d12d50..a022f2d9a38 100644
--- a/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/background/request_queue_store.h"
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.cc b/chromium/components/offline_pages/core/background/request_coordinator.cc
index 13607b0177d..4fbc2f18942 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
diff --git a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
index a703d90b63e..3ab671ab1c0 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -10,14 +10,13 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/circular_deque.h"
#include "base/location.h"
#include "base/synchronization/waitable_event.h"
#include "base/system/sys_info.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
diff --git a/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc b/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
index b1455972579..9141dea0490 100644
--- a/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/guid.h"
#include "base/metrics/histogram_macros.h"
diff --git a/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index 4cef6a87c56..abf9bd1eea7 100644
--- a/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -13,14 +13,14 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/test_mock_time_task_runner.h"
diff --git a/chromium/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc b/chromium/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc
index d69ca8a21b1..e2b71fe5fcf 100644
--- a/chromium/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc
+++ b/chromium/components/offline_pages/core/downloads/offline_item_conversions_unittest.cc
@@ -5,7 +5,6 @@
#include "components/offline_pages/core/downloads/offline_item_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/offline_pages/core/background/save_page_request.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/offline_page_item.h"
diff --git a/chromium/components/offline_pages/core/model/cleanup_visuals_task_unittest.cc b/chromium/components/offline_pages/core/model/cleanup_visuals_task_unittest.cc
index a84197ad3a4..6bf524731eb 100644
--- a/chromium/components/offline_pages/core/model/cleanup_visuals_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/cleanup_visuals_task_unittest.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "base/bind_helpers.h"
-#include "base/test/bind_test_util.h"
+#include "base/callback_helpers.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/model/get_visuals_task.h"
diff --git a/chromium/components/offline_pages/core/model/get_visuals_task_unittest.cc b/chromium/components/offline_pages/core/model/get_visuals_task_unittest.cc
index c39494130d5..42eddb005f3 100644
--- a/chromium/components/offline_pages/core/model/get_visuals_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/get_visuals_task_unittest.cc
@@ -6,9 +6,9 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/model/model_task_test_base.h"
#include "components/offline_pages/core/model/offline_page_item_generator.h"
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc b/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
index cbcf3a6c147..1735f1a23b3 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/logging.h"
@@ -231,10 +231,6 @@ void OfflinePageModelTaskified::SavePage(
create_archive_params.use_page_problem_detectors =
save_page_params.use_page_problem_detectors;
- // Set on-the-fly hashing if enabled.
- create_archive_params.use_on_the_fly_hash_computation =
- IsOnTheFlyMhtmlHashComputationEnabled();
-
// Save directly to public location if on-the-fly enabled.
//
// TODO(crbug.com/999247): We would like to skip renaming the file if
@@ -365,8 +361,6 @@ const base::FilePath& OfflinePageModelTaskified::GetArchiveDirectory(
const std::string& name_space) const {
if (GetPolicy(name_space).lifetime_type == LifetimeType::TEMPORARY)
return archive_manager_->GetTemporaryArchivesDir();
- if (IsOnTheFlyMhtmlHashComputationEnabled())
- return archive_manager_->GetPublicArchivesDir();
return archive_manager_->GetPrivateArchivesDir();
}
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 81f6129ac41..f0401946185 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -12,10 +12,9 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/clock.h"
diff --git a/chromium/components/offline_pages/core/model/store_visuals_task_unittest.cc b/chromium/components/offline_pages/core/model/store_visuals_task_unittest.cc
index bc1a6454979..1c683e1381b 100644
--- a/chromium/components/offline_pages/core/model/store_visuals_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/store_visuals_task_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/model/get_visuals_task.h"
#include "components/offline_pages/core/model/model_task_test_base.h"
diff --git a/chromium/components/offline_pages/core/model/visuals_availability_task_unittest.cc b/chromium/components/offline_pages/core/model/visuals_availability_task_unittest.cc
index c3a3604d923..abaf4b608a4 100644
--- a/chromium/components/offline_pages/core/model/visuals_availability_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/visuals_availability_task_unittest.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "base/bind_helpers.h"
-#include "base/test/bind_test_util.h"
+#include "base/callback_helpers.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/model/model_task_test_base.h"
#include "components/offline_pages/core/model/store_visuals_task.h"
diff --git a/chromium/components/offline_pages/core/offline_page_archiver.h b/chromium/components/offline_pages/core/offline_page_archiver.h
index 9efe6540697..4f5e7b237b9 100644
--- a/chromium/components/offline_pages/core/offline_page_archiver.h
+++ b/chromium/components/offline_pages/core/offline_page_archiver.h
@@ -72,9 +72,6 @@ class OfflinePageArchiver {
// Run page problem detectors while generating MTHML if true.
bool use_page_problem_detectors = false;
-
- // Whether to enable on-the-fly hash computation.
- bool use_on_the_fly_hash_computation = false;
};
// Callback for the final result of an attempt to generate of offline page
diff --git a/chromium/components/offline_pages/core/offline_page_feature.cc b/chromium/components/offline_pages/core/offline_page_feature.cc
index a21206a255b..6728c0ffcc1 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature.cc
@@ -65,9 +65,6 @@ const base::Feature kOfflineIndicatorFeature{"OfflineIndicator",
const base::Feature kOfflineIndicatorAlwaysHttpProbeFeature{
"OfflineIndicatorAlwaysHttpProbe", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kOnTheFlyMhtmlHashComputationFeature{
- "OnTheFlyMhtmlHashComputation", base::FEATURE_DISABLED_BY_DEFAULT};
-
const char kPrefetchingOfflinePagesExperimentsOption[] = "exp";
bool IsOffliningRecentPagesEnabled() {
@@ -148,7 +145,7 @@ bool IsOfflineIndicatorAlwaysHttpProbeEnabled() {
}
bool IsOnTheFlyMhtmlHashComputationEnabled() {
- return base::FeatureList::IsEnabled(kOnTheFlyMhtmlHashComputationFeature);
+ return false;
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_test_util.cc b/chromium/components/offline_pages/core/offline_page_metadata_store_test_util.cc
index 59c2502d32b..37ec48c698d 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_test_util.cc
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_test_util.cc
@@ -7,12 +7,12 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/model/add_page_task.h"
#include "components/offline_pages/core/model/get_pages_task.h"
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc
index af2a877b8fd..43d34eb2413 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -16,7 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/client_namespace_constants.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 219491e8198..4e52df18d14 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
index 5dc8dfa207f..1c927b53c21 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -8,14 +8,14 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
index 78130e7c4df..548117bc4e8 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
@@ -4,7 +4,7 @@
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory_impl.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/test_simple_task_runner.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc b/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
index 90648315c2e..66c2aeb1fcf 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
@@ -8,7 +8,7 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/task_environment.h"
#include "components/offline_pages/core/offline_page_feature.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc
index 1d022ff1bb1..e1205466691 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_impl.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "components/image_fetcher/core/image_fetcher.h"
#include "components/offline_pages/core/client_id.h"
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
index 22e4f3fbf2e..76a46f04900 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
@@ -9,7 +9,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h"
diff --git a/chromium/components/offline_pages/core/prefetch/tasks/download_archives_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/tasks/download_archives_task_unittest.cc
index 001cd47d021..43703322094 100644
--- a/chromium/components/offline_pages/core/prefetch/tasks/download_archives_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/tasks/download_archives_task_unittest.cc
@@ -10,7 +10,6 @@
#include "base/guid.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/prefetch/prefetch_prefs.h"
diff --git a/chromium/components/offline_pages/core/prefetch/tasks/get_operation_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/tasks/get_operation_task_unittest.cc
index 569e1c507ab..5e1d8be596f 100644
--- a/chromium/components/offline_pages/core/prefetch/tasks/get_operation_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/tasks/get_operation_task_unittest.cc
@@ -4,7 +4,7 @@
#include "components/offline_pages/core/prefetch/tasks/get_operation_task.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/prefetch/get_operation_request.h"
#include "components/offline_pages/core/prefetch/prefetch_item.h"
diff --git a/chromium/components/offline_pages/core/prefetch/test_download_service.cc b/chromium/components/offline_pages/core/prefetch/test_download_service.cc
index d468d146051..5ae7f988191 100644
--- a/chromium/components/offline_pages/core/prefetch/test_download_service.cc
+++ b/chromium/components/offline_pages/core/prefetch/test_download_service.cc
@@ -9,7 +9,7 @@
#include "base/files/file_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/download/public/background_service/download_metadata.h"
#include "components/download/public/background_service/service_config.h"
diff --git a/chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc b/chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc
index 73967272813..78502c43021 100644
--- a/chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc
+++ b/chromium/components/offline_pages/core/renovations/page_renovator_unittest.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/mock_callback.h"
#include "base/values.h"
#include "components/offline_pages/core/renovations/script_injector.h"
diff --git a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
index e0a74e06fc5..7d29c5f31f1 100644
--- a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
diff --git a/chromium/components/offline_pages/task/task_unittest.cc b/chromium/components/offline_pages/task/task_unittest.cc
index 3bc87c1e988..1ef860dd9c4 100644
--- a/chromium/components/offline_pages/task/task_unittest.cc
+++ b/chromium/components/offline_pages/task/task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/task/test_task.h"
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index 4c4e4745c6c..40ee7e58f16 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -18,7 +18,7 @@ buildflag_header("buildflags") {
flags = [ "ENABLE_VR=$enable_vr" ]
}
-aggregate_vector_icons2("omnibox_vector_icons") {
+aggregate_vector_icons("omnibox_vector_icons") {
icon_directory = "vector_icons"
sources = [
@@ -125,6 +125,10 @@ static_library("browser") {
"in_memory_url_index.h",
"in_memory_url_index_types.cc",
"in_memory_url_index_types.h",
+ "inline_autocompletion_util.cc",
+ "inline_autocompletion_util.h",
+ "intranet_redirector_state.cc",
+ "intranet_redirector_state.h",
"keyword_extensions_delegate.cc",
"keyword_extensions_delegate.h",
"keyword_provider.cc",
@@ -132,6 +136,8 @@ static_library("browser") {
"local_history_zero_suggest_provider.cc",
"local_history_zero_suggest_provider.h",
"match_compare.h",
+ "most_visited_sites_provider.cc",
+ "most_visited_sites_provider.h",
"omnibox_client.cc",
"omnibox_client.h",
"omnibox_controller.cc",
@@ -163,6 +169,8 @@ static_library("browser") {
"omnibox_popup_view.h",
"omnibox_prefs.cc",
"omnibox_prefs.h",
+ "omnibox_triggered_feature_service.cc",
+ "omnibox_triggered_feature_service.h",
"omnibox_view.cc",
"omnibox_view.h",
"on_device_head_model.cc",
@@ -432,6 +440,7 @@ static_library("test_support") {
"//components/bookmarks/test",
"//components/history/core/browser",
"//components/history/core/test",
+ "//components/prefs:test_support",
"//components/query_tiles/test:test_support",
"//components/resources",
"//components/search_engines",
@@ -487,9 +496,11 @@ source_set("unit_tests") {
"history_url_provider_unittest.cc",
"in_memory_url_index_types_unittest.cc",
"in_memory_url_index_unittest.cc",
+ "inline_autocompletion_util_unittest.cc",
"keyword_provider_unittest.cc",
"local_history_zero_suggest_provider_unittest.cc",
"location_bar_model_impl_unittest.cc",
+ "most_visited_sites_provider_unittest.cc",
"omnibox_controller_unittest.cc",
"omnibox_edit_model_unittest.cc",
"omnibox_field_trial_unittest.cc",
diff --git a/chromium/components/omnibox_strings.grdp b/chromium/components/omnibox_strings.grdp
index 1ff6a0c8e23..372d959ec7e 100644
--- a/chromium/components/omnibox_strings.grdp
+++ b/chromium/components/omnibox_strings.grdp
@@ -251,7 +251,7 @@
<message name="IDS_ACC_MULTIPLE_ACTIONS_SUFFIX" desc="Suffix for spoken suggestion description with multiple actions available (pedals, switch tab, keyword search) to indicate that this suggestion has multiple actions available.">
<ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, multiple actions are available, press Tab to cycle through them
</message>
- <message name="IDS_ACC_KEYWORD_SUFFIX" desc="Suffix for spoken keyword suggestion description to explain keystroke used to search.">
+ <message name="IDS_ACC_KEYWORD_SUFFIX" desc="Suffix for spoken keyword suggestion description to explain keystroke used to search.">
<ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to search
</message>
<message name="IDS_ACC_KEYWORD_MODE" desc="Announcement when entering keyword search mode.">
@@ -259,6 +259,9 @@
</message>
<!-- Accessibility suffix for suggestions when the remove button is focused. -->
+ <message name="IDS_ACC_REMOVE_SUGGESTION_SUFFIX" desc="Suffix for suggestions with remove suggestion button to explain keystroke used to remove suggestion.">
+ <ph name="REMOVE_SUGGESTION_SUFFIX">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to Remove Suggestion.
+ </message>
<message name="IDS_ACC_REMOVE_SUGGESTION_FOCUSED_PREFIX" desc="Announcement when remove suggestion button is focused.">
Remove Suggestion button, press Enter to remove, <ph name="REMOVE_BUTTON_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>
</message>
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ACC_REMOVE_SUGGESTION_SUFFIX.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ACC_REMOVE_SUGGESTION_SUFFIX.png.sha1
new file mode 100644
index 00000000000..22cb6b566d4
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ACC_REMOVE_SUGGESTION_SUFFIX.png.sha1
@@ -0,0 +1 @@
+a05ef99c963e4207852804ed29b9cb314e29d1fa \ No newline at end of file
diff --git a/chromium/components/on_load_script_injector/browser/BUILD.gn b/chromium/components/on_load_script_injector/browser/BUILD.gn
index 247857a343f..8d44eab2aae 100644
--- a/chromium/components/on_load_script_injector/browser/BUILD.gn
+++ b/chromium/components/on_load_script_injector/browser/BUILD.gn
@@ -12,9 +12,13 @@ component("browser") {
defines = [ "ON_LOAD_SCRIPT_INJECTOR_IMPLEMENTATION" ]
- deps = [
+ public_deps = [
"//base",
"//components/on_load_script_injector:export",
+ "//url",
+ ]
+
+ deps = [
"//components/on_load_script_injector:on_load_script_injector_mojom",
"//content/public/browser",
"//mojo/public/cpp/bindings",
diff --git a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
index a9c4564f74f..c02a296e275 100644
--- a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
+++ b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
@@ -6,6 +6,13 @@
#include <utility>
+#include "base/numerics/safe_math.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/on_load_script_injector/on_load_script_injector.mojom.h"
+#include "content/public/browser/render_frame_host.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+
namespace on_load_script_injector {
OriginScopedScript::OriginScopedScript() = default;
@@ -22,4 +29,104 @@ OriginScopedScript& OriginScopedScript::operator=(OriginScopedScript&& other) {
OriginScopedScript::~OriginScopedScript() = default;
+template <typename ScriptId>
+OnLoadScriptInjectorHost<ScriptId>::OnLoadScriptInjectorHost() = default;
+template <typename ScriptId>
+OnLoadScriptInjectorHost<ScriptId>::~OnLoadScriptInjectorHost() = default;
+
+template <typename ScriptId>
+void OnLoadScriptInjectorHost<ScriptId>::AddScript(
+ ScriptId id,
+ std::vector<url::Origin> origins_to_inject,
+ base::StringPiece script) {
+ // If there is no script with the identifier |id|, then create a place for
+ // it at the end of the injection sequence.
+ if (before_load_scripts_.find(id) == before_load_scripts_.end())
+ before_load_scripts_order_.push_back(id);
+
+ // Convert script to UTF-16.
+ base::string16 script_utf16 = base::UTF8ToUTF16(script);
+ size_t script_utf16_size =
+ (base::CheckedNumeric<size_t>(script_utf16.size()) * sizeof(base::char16))
+ .ValueOrDie();
+ base::WritableSharedMemoryRegion script_shared_memory =
+ base::WritableSharedMemoryRegion::Create(script_utf16_size);
+ memcpy(script_shared_memory.Map().memory(), script_utf16.data(),
+ script_utf16_size);
+
+ base::ReadOnlySharedMemoryRegion script_shared_memory_readonly =
+ base::WritableSharedMemoryRegion::ConvertToReadOnly(
+ std::move(script_shared_memory));
+ CHECK(script_shared_memory_readonly.IsValid());
+
+ before_load_scripts_[id] = OriginScopedScript(
+ origins_to_inject, std::move(script_shared_memory_readonly));
+}
+
+template <typename ScriptId>
+void OnLoadScriptInjectorHost<ScriptId>::AddScriptForAllOrigins(
+ ScriptId id,
+ base::StringPiece script) {
+ AddScript(id, {kMatchAllOrigins}, script);
+}
+
+template <typename ScriptId>
+void OnLoadScriptInjectorHost<ScriptId>::RemoveScript(ScriptId id) {
+ before_load_scripts_.erase(id);
+
+ for (auto script_id_iter = before_load_scripts_order_.begin();
+ script_id_iter != before_load_scripts_order_.end(); ++script_id_iter) {
+ if (*script_id_iter == id) {
+ before_load_scripts_order_.erase(script_id_iter);
+ return;
+ }
+ }
+
+ LOG(WARNING) << "Ignoring attempt to remove unknown OnLoad script: " << id;
+}
+
+template <typename ScriptId>
+void OnLoadScriptInjectorHost<ScriptId>::InjectScriptsForURL(
+ const GURL& url,
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(url.is_valid());
+
+ mojo::AssociatedRemote<mojom::OnLoadScriptInjector> injector;
+ render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&injector);
+
+ injector->ClearOnLoadScripts();
+
+ if (before_load_scripts_.empty())
+ return;
+
+ // Provision the renderer's ScriptInjector with the scripts associated with
+ // |url|.
+ for (ScriptId script_id : before_load_scripts_order_) {
+ const OriginScopedScript& script = before_load_scripts_[script_id];
+ if (IsUrlMatchedByOriginList(url, script.origins()))
+ injector->AddOnLoadScript(script.script().Duplicate());
+ }
+}
+
+template <typename ScriptId>
+bool OnLoadScriptInjectorHost<ScriptId>::IsUrlMatchedByOriginList(
+ const GURL& url,
+ const std::vector<url::Origin>& allowed_origins) {
+ url::Origin url_origin = url::Origin::Create(url);
+
+ for (const url::Origin& allowed_origin : allowed_origins) {
+ if (allowed_origin == kMatchAllOrigins)
+ return true;
+
+ DCHECK(!allowed_origin.opaque());
+ if (url_origin.IsSameOriginWith(allowed_origin))
+ return true;
+ }
+
+ return false;
+}
+
+template class OnLoadScriptInjectorHost<std::string>;
+template class OnLoadScriptInjectorHost<uint64_t>;
+
} // namespace on_load_script_injector
diff --git a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.h b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.h
index 0c7f552c772..5e36a806f99 100644
--- a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.h
+++ b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.h
@@ -10,17 +10,13 @@
#include <vector>
#include "base/memory/read_only_shared_memory_region.h"
-#include "base/numerics/safe_math.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
#include "components/on_load_script_injector/export.h"
-#include "components/on_load_script_injector/on_load_script_injector.mojom.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "mojo/public/cpp/bindings/associated_remote.h"
-#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "url/origin.h"
+namespace content {
+class RenderFrameHost;
+} // namespace content
+
namespace on_load_script_injector {
class ON_LOAD_SCRIPT_INJECTOR_EXPORT OriginScopedScript {
@@ -44,10 +40,10 @@ class ON_LOAD_SCRIPT_INJECTOR_EXPORT OriginScopedScript {
// Manages the set of scripts to be injected into document just prior to
// document load.
template <typename ScriptId>
-class OnLoadScriptInjectorHost {
+class ON_LOAD_SCRIPT_INJECTOR_EXPORT OnLoadScriptInjectorHost {
public:
- OnLoadScriptInjectorHost() = default;
- ~OnLoadScriptInjectorHost() = default;
+ OnLoadScriptInjectorHost();
+ ~OnLoadScriptInjectorHost();
OnLoadScriptInjectorHost(const OnLoadScriptInjectorHost&) = delete;
OnLoadScriptInjectorHost& operator=(const OnLoadScriptInjectorHost&) = delete;
@@ -60,92 +56,23 @@ class OnLoadScriptInjectorHost {
// All entries of |origins_to_inject| must be valid/not opaque.
void AddScript(ScriptId id,
std::vector<url::Origin> origins_to_inject,
- base::StringPiece script) {
- // If there is no script with the identifier |id|, then create a place for
- // it at the end of the injection sequence.
- if (before_load_scripts_.find(id) == before_load_scripts_.end())
- before_load_scripts_order_.push_back(id);
-
- // Convert script to UTF-16.
- base::string16 script_utf16 = base::UTF8ToUTF16(script);
- size_t script_utf16_size =
- (base::CheckedNumeric<size_t>(script_utf16.size()) *
- sizeof(base::char16))
- .ValueOrDie();
- base::WritableSharedMemoryRegion script_shared_memory =
- base::WritableSharedMemoryRegion::Create(script_utf16_size);
- memcpy(script_shared_memory.Map().memory(), script_utf16.data(),
- script_utf16_size);
-
- base::ReadOnlySharedMemoryRegion script_shared_memory_readonly =
- base::WritableSharedMemoryRegion::ConvertToReadOnly(
- std::move(script_shared_memory));
- CHECK(script_shared_memory_readonly.IsValid());
-
- before_load_scripts_[id] = OriginScopedScript(
- origins_to_inject, std::move(script_shared_memory_readonly));
- }
+ base::StringPiece script);
// Same as AddScript(), except that scripts are injected for all pages.
- void AddScriptForAllOrigins(ScriptId id, base::StringPiece script) {
- AddScript(id, {kMatchAllOrigins}, script);
- }
+ void AddScriptForAllOrigins(ScriptId id, base::StringPiece script);
// Removes the script |id|.
- void RemoveScript(ScriptId id) {
- before_load_scripts_.erase(id);
-
- for (auto script_id_iter = before_load_scripts_order_.begin();
- script_id_iter != before_load_scripts_order_.end(); ++script_id_iter) {
- if (*script_id_iter == id) {
- before_load_scripts_order_.erase(script_id_iter);
- return;
- }
- }
-
- LOG(WARNING) << "Ignoring attempt to remove unknown OnLoad script: " << id;
- }
+ void RemoveScript(ScriptId id);
// Injects the scripts associated with the origin of |url| into the document
// hosted by |render_frame_host|.
void InjectScriptsForURL(const GURL& url,
- content::RenderFrameHost* render_frame_host) {
- DCHECK(url.is_valid());
-
- mojo::AssociatedRemote<mojom::OnLoadScriptInjector> injector;
- render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&injector);
-
- injector->ClearOnLoadScripts();
-
- if (before_load_scripts_.empty())
- return;
-
- // Provision the renderer's ScriptInjector with the scripts associated with
- // |url|.
- for (ScriptId script_id : before_load_scripts_order_) {
- const OriginScopedScript& script = before_load_scripts_[script_id];
- if (IsUrlMatchedByOriginList(url, script.origins()))
- injector->AddOnLoadScript(script.script().Duplicate());
- }
- }
+ content::RenderFrameHost* render_frame_host);
private:
bool IsUrlMatchedByOriginList(
const GURL& url,
- const std::vector<url::Origin>& allowed_origins) {
- url::Origin url_origin = url::Origin::Create(url);
-
- for (const url::Origin& allowed_origin : allowed_origins) {
- if (allowed_origin == kMatchAllOrigins)
- return true;
-
- DCHECK(!allowed_origin.opaque());
- if (url_origin.IsSameOriginWith(allowed_origin))
- return true;
- }
-
- return false;
- }
+ const std::vector<url::Origin>& allowed_origins);
// An opaque Origin that, when specified, allows script injection on all URLs
// regardless of origin.
diff --git a/chromium/components/open_from_clipboard/DEPS b/chromium/components/open_from_clipboard/DEPS
index 8f338becba5..9ce97fe4d69 100644
--- a/chromium/components/open_from_clipboard/DEPS
+++ b/chromium/components/open_from_clipboard/DEPS
@@ -3,6 +3,7 @@ include_rules = [
"+net",
"+third_party/skia",
"+ui/base/clipboard",
+ "+ui/base/data_transfer_policy",
"+ui/base/test",
"+ui/gfx/image",
]
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
index 35abfa5b867..b729d63e57f 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
namespace {
// Schemes appropriate for suggestion by ClipboardRecentContent.
@@ -45,8 +46,10 @@ ClipboardRecentContentGeneric::GetRecentURLFromClipboard() {
// Get and clean up the clipboard before processing.
std::string gurl_string;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
- clipboard->ReadAsciiText(ui::ClipboardBuffer::kCopyPaste,
- /* data_dst = */ nullptr, &gurl_string);
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
+ clipboard->ReadAsciiText(ui::ClipboardBuffer::kCopyPaste, &data_dst,
+ &gurl_string);
base::TrimWhitespaceASCII(gurl_string, base::TrimPositions::TRIM_ALL,
&gurl_string);
@@ -64,8 +67,8 @@ ClipboardRecentContentGeneric::GetRecentURLFromClipboard() {
// Fall back to unicode / UTF16, as some URLs may use international domain
// names, not punycode.
base::string16 gurl_string16;
- clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste,
- /* data_dst = */ nullptr, &gurl_string16);
+ clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &data_dst,
+ &gurl_string16);
base::TrimWhitespace(gurl_string16, base::TrimPositions::TRIM_ALL,
&gurl_string16);
if (gurl_string16.find_first_of(base::kWhitespaceUTF16) !=
@@ -86,9 +89,10 @@ ClipboardRecentContentGeneric::GetRecentTextFromClipboard() {
return base::nullopt;
base::string16 text_from_clipboard;
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
ui::Clipboard::GetForCurrentThread()->ReadText(
- ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr,
- &text_from_clipboard);
+ ui::ClipboardBuffer::kCopyPaste, &data_dst, &text_from_clipboard);
base::TrimWhitespace(text_from_clipboard, base::TrimPositions::TRIM_ALL,
&text_from_clipboard);
if (text_from_clipboard.empty()) {
@@ -103,9 +107,10 @@ void ClipboardRecentContentGeneric::GetRecentImageFromClipboard(
if (GetClipboardContentAge() > MaximumAgeOfClipboard())
return;
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
ui::Clipboard::GetForCurrentThread()->ReadImage(
- ui::ClipboardBuffer::kCopyPaste,
- /* data_dst = */ nullptr,
+ ui::ClipboardBuffer::kCopyPaste, &data_dst,
base::BindOnce(&OnGetRecentImageFromClipboard, std::move(callback)));
}
@@ -113,9 +118,11 @@ bool ClipboardRecentContentGeneric::HasRecentImageFromClipboard() {
if (GetClipboardContentAge() > MaximumAgeOfClipboard())
return false;
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
ui::ClipboardFormatType::GetBitmapType(), ui::ClipboardBuffer::kCopyPaste,
- /* data_dst = */ nullptr);
+ &data_dst);
}
void ClipboardRecentContentGeneric::HasRecentContentFromClipboard(
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc b/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
index c7c81d47ce0..6bd094e9eb2 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
@@ -11,7 +11,6 @@
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/test/test_clipboard.h"
diff --git a/chromium/components/openscreen_platform/tls_client_connection.h b/chromium/components/openscreen_platform/tls_client_connection.h
index 6c88480a57f..b124ae4b722 100644
--- a/chromium/components/openscreen_platform/tls_client_connection.h
+++ b/chromium/components/openscreen_platform/tls_client_connection.h
@@ -17,7 +17,7 @@
namespace openscreen_platform {
-class TlsClientConnection : public openscreen::TlsConnection {
+class TlsClientConnection final : public openscreen::TlsConnection {
public:
TlsClientConnection(
openscreen::TaskRunner* task_runner,
diff --git a/chromium/components/openscreen_platform/tls_connection_factory.h b/chromium/components/openscreen_platform/tls_connection_factory.h
index 2aaad8642ab..4804c63392d 100644
--- a/chromium/components/openscreen_platform/tls_connection_factory.h
+++ b/chromium/components/openscreen_platform/tls_connection_factory.h
@@ -31,7 +31,7 @@ struct TlsListenOptions;
namespace openscreen_platform {
-class TlsConnectionFactory : public openscreen::TlsConnectionFactory {
+class TlsConnectionFactory final : public openscreen::TlsConnectionFactory {
public:
TlsConnectionFactory(openscreen::TlsConnectionFactory::Client* client,
openscreen::TaskRunner* task_runner);
diff --git a/chromium/components/openscreen_platform/udp_socket.h b/chromium/components/openscreen_platform/udp_socket.h
index 6f385cf0a3c..002fd30ff64 100644
--- a/chromium/components/openscreen_platform/udp_socket.h
+++ b/chromium/components/openscreen_platform/udp_socket.h
@@ -23,8 +23,8 @@ class IPEndPoint;
namespace openscreen_platform {
-class UdpSocket : public openscreen::UdpSocket,
- network::mojom::UDPSocketListener {
+class UdpSocket final : public openscreen::UdpSocket,
+ network::mojom::UDPSocketListener {
public:
UdpSocket(Client* client,
const openscreen::IPEndpoint& local_endpoint,
diff --git a/chromium/components/optimization_guide/hints_processing_util.cc b/chromium/components/optimization_guide/hints_processing_util.cc
index 2a25df24299..b29324fdad9 100644
--- a/chromium/components/optimization_guide/hints_processing_util.cc
+++ b/chromium/components/optimization_guide/hints_processing_util.cc
@@ -51,6 +51,8 @@ std::string GetStringNameForOptimizationType(
return "DelayCompetingLowPriorityRequests";
case proto::OptimizationType::LITE_VIDEO:
return "LiteVideo";
+ case proto::OptimizationType::LINK_PERFORMANCE:
+ return "LinkPerformance";
}
NOTREACHED();
return std::string();
diff --git a/chromium/components/optimization_guide/optimization_guide_store.cc b/chromium/components/optimization_guide/optimization_guide_store.cc
index f68269d86f0..4692c2d9ccb 100644
--- a/chromium/components/optimization_guide/optimization_guide_store.cc
+++ b/chromium/components/optimization_guide/optimization_guide_store.cc
@@ -5,7 +5,7 @@
#include "components/optimization_guide/optimization_guide_store.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequence_checker.h"
diff --git a/chromium/components/optimization_guide/optimization_metadata.h b/chromium/components/optimization_guide/optimization_metadata.h
index 6d2f3d0da22..46942601ee9 100644
--- a/chromium/components/optimization_guide/optimization_metadata.h
+++ b/chromium/components/optimization_guide/optimization_metadata.h
@@ -57,7 +57,9 @@ class OptimizationMetadata {
return metadata;
return base::nullopt;
}
- base::Optional<proto::Any> any_metadata() const { return any_metadata_; }
+ const base::Optional<proto::Any>& any_metadata() const {
+ return any_metadata_;
+ }
void set_any_metadata(const proto::Any& any_metadata) {
any_metadata_ = any_metadata;
}
@@ -65,15 +67,15 @@ class OptimizationMetadata {
// used for testing purposes.
void SetAnyMetadataForTesting(const google::protobuf::MessageLite& metadata);
- base::Optional<proto::PreviewsMetadata> previews_metadata() const {
+ const base::Optional<proto::PreviewsMetadata>& previews_metadata() const {
return previews_metadata_;
}
void set_previews_metadata(const proto::PreviewsMetadata& previews_metadata) {
previews_metadata_ = previews_metadata;
}
- base::Optional<proto::PerformanceHintsMetadata> performance_hints_metadata()
- const {
+ const base::Optional<proto::PerformanceHintsMetadata>&
+ performance_hints_metadata() const {
return performance_hints_metadata_;
}
void set_performance_hints_metadata(
@@ -81,7 +83,8 @@ class OptimizationMetadata {
performance_hints_metadata_ = performance_hints_metadata;
}
- base::Optional<proto::PublicImageMetadata> public_image_metadata() const {
+ const base::Optional<proto::PublicImageMetadata>& public_image_metadata()
+ const {
return public_image_metadata_;
}
void set_public_image_metadata(
@@ -89,8 +92,8 @@ class OptimizationMetadata {
public_image_metadata_ = public_image_metadata;
}
- base::Optional<proto::LoadingPredictorMetadata> loading_predictor_metadata()
- const {
+ const base::Optional<proto::LoadingPredictorMetadata>&
+ loading_predictor_metadata() const {
return loading_predictor_metadata_;
}
void set_loading_predictor_metadata(
diff --git a/chromium/components/optimization_guide/proto/hints.proto b/chromium/components/optimization_guide/proto/hints.proto
index b72723f9e64..2af77bf9122 100644
--- a/chromium/components/optimization_guide/proto/hints.proto
+++ b/chromium/components/optimization_guide/proto/hints.proto
@@ -131,6 +131,9 @@ enum OptimizationType {
// This optimization provides information about how to throttle meda requests
// to reduce the bitrate of adaptively streamed media.
LITE_VIDEO = 13;
+ // This optimization is used to provide aggregated performance information
+ // about pages linked to from the current page.
+ LINK_PERFORMANCE = 14;
}
// Presents semantics for how page load URLs should be matched.
@@ -167,6 +170,8 @@ message Optimization {
//
// It is expected that the client and server have agreed upon the appropriate
// metadata type for the optimization type.
+ //
+ // New clients should utilize any_metadata rather than adding another field.
oneof metadata {
PreviewsMetadata previews_metadata = 10;
PerformanceHintsMetadata performance_hints_metadata = 11;
diff --git a/chromium/components/optimization_guide/proto/models.proto b/chromium/components/optimization_guide/proto/models.proto
index a518ebf3f5d..dabc1cdb04e 100644
--- a/chromium/components/optimization_guide/proto/models.proto
+++ b/chromium/components/optimization_guide/proto/models.proto
@@ -18,6 +18,8 @@ message Model {
oneof model {
DecisionTree decision_tree = 1;
Ensemble ensemble = 2;
+ // The URL that the model can be downloaded from.
+ string download_url = 5;
}
// The tag number is high to allow models to be added and an uncommon number
// in case the proto this is generated from adds a similar functionality.
diff --git a/chromium/components/optimization_guide/proto/performance_hints_metadata.proto b/chromium/components/optimization_guide/proto/performance_hints_metadata.proto
index 871fb138a1d..5b0b6745002 100644
--- a/chromium/components/optimization_guide/proto/performance_hints_metadata.proto
+++ b/chromium/components/optimization_guide/proto/performance_hints_metadata.proto
@@ -42,6 +42,9 @@ message PerformanceHintsMetadata {
// An ordered set of performance hints.
//
// Only the first matching hint should be applied to a given URL.
+ //
+ // These will be omitted if LINK_PERFORMANCE hints are requested. Instead,
+ // link hints will be included in LinkPerformanceMetadata, below.
repeated PerformanceHint performance_hints = 1;
// The PerformanceHint for the page pattern that matched the parent
@@ -51,3 +54,13 @@ message PerformanceHintsMetadata {
// the pattern matching is done by OptimizationGuide.
optional PerformanceHint page_hint = 2;
}
+
+// Optimization metadata associated with Link Performance Hints.
+//
+// This is only populated for the LINK_PERFORMANCE optimization type.
+message LinkPerformanceMetadata {
+ // An ordered set of hints for the most popular links for this key.
+ //
+ // Only the first matching hint should be applied to a given link URL.
+ repeated PerformanceHint link_hints = 1;
+}
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index 380c8a719e3..e2321183217 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/BUILD.gn
@@ -49,8 +49,7 @@ component("os_crypt") {
defines = [ "IS_OS_CRYPT_IMPL" ]
- if ((is_posix || is_fuchsia) && !is_apple &&
- (!is_desktop_linux || is_chromecast)) {
+ if ((is_posix || is_fuchsia) && !is_apple && (!is_linux || is_chromecast)) {
sources += [ "os_crypt_posix.cc" ]
}
@@ -67,7 +66,7 @@ component("os_crypt") {
libs = [ "crypt32.lib" ]
}
- if (is_desktop_linux && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"key_storage_config_linux.cc",
"key_storage_config_linux.h",
@@ -123,7 +122,7 @@ static_library("test_support") {
"//base",
"//testing/gtest",
]
- if (is_desktop_linux && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"os_crypt_mocker_linux.cc",
"os_crypt_mocker_linux.h",
@@ -160,7 +159,7 @@ source_set("unit_tests") {
sources += [ "keychain_password_mac_unittest.mm" ]
}
- if (is_desktop_linux && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"key_storage_linux_unittest.cc",
"key_storage_util_linux_unittest.cc",
diff --git a/chromium/components/os_crypt/features.gni b/chromium/components/os_crypt/features.gni
index f67c8b9728d..e9f9acf6e03 100644
--- a/chromium/components/os_crypt/features.gni
+++ b/chromium/components/os_crypt/features.gni
@@ -7,5 +7,5 @@ import("//build/config/ui.gni")
declare_args() {
# Whether to use libgnome-keyring (deprecated by libsecret).
# See http://crbug.com/466975 and http://crbug.com/355223.
- use_gnome_keyring = is_desktop_linux && use_glib
+ use_gnome_keyring = is_linux && use_glib
}
diff --git a/chromium/components/os_crypt/keychain_password_mac.mm b/chromium/components/os_crypt/keychain_password_mac.mm
index 3b8543488d0..6654c46eb0a 100644
--- a/chromium/components/os_crypt/keychain_password_mac.mm
+++ b/chromium/components/os_crypt/keychain_password_mac.mm
@@ -80,6 +80,6 @@ std::string KeychainPassword::GetPassword() const {
return password;
}
- OSSTATUS_DLOG(ERROR, error) << "Keychain lookup failed";
+ OSSTATUS_LOG(ERROR, error) << "Keychain lookup failed";
return std::string();
}
diff --git a/chromium/components/ownership/owner_settings_service.cc b/chromium/components/ownership/owner_settings_service.cc
index d6e2f7aa71b..90be5e8f568 100644
--- a/chromium/components/ownership/owner_settings_service.cc
+++ b/chromium/components/ownership/owner_settings_service.cc
@@ -148,8 +148,8 @@ bool OwnerSettingsService::SetString(const std::string& setting,
}
void OwnerSettingsService::ReloadKeypair() {
- ReloadKeypairImpl(base::BindRepeating(&OwnerSettingsService::OnKeypairLoaded,
- as_weak_ptr()));
+ ReloadKeypairImpl(
+ base::BindOnce(&OwnerSettingsService::OnKeypairLoaded, as_weak_ptr()));
}
void OwnerSettingsService::OnKeypairLoaded(
diff --git a/chromium/components/ownership/owner_settings_service.h b/chromium/components/ownership/owner_settings_service.h
index f57362caef7..b573f987422 100644
--- a/chromium/components/ownership/owner_settings_service.h
+++ b/chromium/components/ownership/owner_settings_service.h
@@ -126,9 +126,10 @@ class OWNERSHIP_EXPORT OwnerSettingsService : public KeyedService {
const scoped_refptr<PrivateKey>& private_key);
// Platform-specific keypair loading algorithm.
- virtual void ReloadKeypairImpl(const base::Callback<
- void(const scoped_refptr<PublicKey>& public_key,
- const scoped_refptr<PrivateKey>& private_key)>& callback) = 0;
+ virtual void ReloadKeypairImpl(
+ base::OnceCallback<void(const scoped_refptr<PublicKey>& public_key,
+ const scoped_refptr<PrivateKey>& private_key)>
+ callback) = 0;
// Plafrom-specific actions which should be performed when keypair is loaded.
virtual void OnPostKeypairLoadedActions() = 0;
diff --git a/chromium/components/page_info/android/BUILD.gn b/chromium/components/page_info/android/BUILD.gn
index 7d6dd1d1547..c34a66ab268 100644
--- a/chromium/components/page_info/android/BUILD.gn
+++ b/chromium/components/page_info/android/BUILD.gn
@@ -48,12 +48,15 @@ android_resources("java_resources") {
"java/res/drawable-xxxhdpi/pageinfo_good.png",
"java/res/drawable-xxxhdpi/pageinfo_warning.png",
"java/res/drawable/ic_tune_24dp.xml",
+ "java/res/drawable/page_info_bg.xml",
"java/res/layout/connection_info.xml",
+ "java/res/layout/connection_info_v2.xml",
"java/res/layout/cookie_controls_view.xml",
"java/res/layout/page_info.xml",
"java/res/layout/page_info_container.xml",
"java/res/layout/page_info_permission_row.xml",
"java/res/layout/page_info_row.xml",
+ "java/res/layout/page_info_summary.xml",
"java/res/layout/page_info_v2.xml",
"java/res/values/colors.xml",
"java/res/values/dimens.xml",
diff --git a/chromium/components/page_info/android/connection_info_view_android.cc b/chromium/components/page_info/android/connection_info_view_android.cc
index bcea8271c60..b3e1b8ced50 100644
--- a/chromium/components/page_info/android/connection_info_view_android.cc
+++ b/chromium/components/page_info/android/connection_info_view_android.cc
@@ -85,6 +85,8 @@ void ConnectionInfoViewAndroid::SetIdentityInfo(
{
int icon_id = page_info_client_->GetJavaResourceId(
PageInfoUI::GetIdentityIconID(identity_info.identity_status));
+ int icon_color_id = page_info_client_->GetJavaResourceId(
+ PageInfoUI::GetIdentityIconColorID(identity_info.identity_status));
// The headline and the certificate dialog link of the site's identity
// section is only displayed if the site's identity was verified. If the
@@ -110,7 +112,8 @@ void ConnectionInfoViewAndroid::SetIdentityInfo(
Java_ConnectionInfoView_addCertificateSection(
env, popup_jobject_, icon_id, ConvertUTF8ToJavaString(env, headline),
- description, ConvertUTF16ToJavaString(env, certificate_label));
+ description, ConvertUTF16ToJavaString(env, certificate_label),
+ icon_color_id);
if (identity_info.show_ssl_decision_revoke_button) {
base::string16 reset_button_label = l10n_util::GetStringUTF16(
@@ -124,11 +127,13 @@ void ConnectionInfoViewAndroid::SetIdentityInfo(
{
int icon_id = page_info_client_->GetJavaResourceId(
PageInfoUI::GetConnectionIconID(identity_info.connection_status));
+ int icon_color_id = page_info_client_->GetJavaResourceId(
+ PageInfoUI::GetConnectionIconColorID(identity_info.connection_status));
ScopedJavaLocalRef<jstring> description = ConvertUTF8ToJavaString(
env, identity_info.connection_status_description);
- Java_ConnectionInfoView_addDescriptionSection(env, popup_jobject_, icon_id,
- nullptr, description);
+ Java_ConnectionInfoView_addDescriptionSection(
+ env, popup_jobject_, icon_id, nullptr, description, icon_color_id);
}
Java_ConnectionInfoView_addMoreInfoLink(
diff --git a/chromium/components/page_info/android/page_info_controller_android.cc b/chromium/components/page_info/android/page_info_controller_android.cc
index fca3cc37261..6ef2e95daeb 100644
--- a/chromium/components/page_info/android/page_info_controller_android.cc
+++ b/chromium/components/page_info/android/page_info_controller_android.cc
@@ -200,6 +200,11 @@ base::Optional<ContentSetting> PageInfoControllerAndroid::GetSettingToDisplay(
// setting should show up in Page Info is in ShouldShowPermission in
// page_info.cc.
return permission.default_setting;
+ } else if (permission.type == ContentSettingsType::JAVASCRIPT &&
+ base::FeatureList::IsEnabled(page_info::kPageInfoV2)) {
+ // The javascript content setting should show up if it is blocked globally
+ // to give users an easy way to create exceptions.
+ return permission.default_setting;
} else if (permission.type == ContentSettingsType::SOUND) {
// The sound content setting should always show up when the tab has played
// audio since last navigation.
diff --git a/chromium/components/page_info/page_info.cc b/chromium/components/page_info/page_info.cc
index 94c8320c48f..3de10082bfa 100644
--- a/chromium/components/page_info/page_info.cc
+++ b/chromium/components/page_info/page_info.cc
@@ -48,7 +48,6 @@
#include "components/safe_browsing/content/password_protection/password_protection_service.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
#include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h"
-#include "components/security_state/core/features.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/ssl_errors/error_info.h"
#include "components/strings/grit/components_chromium_strings.h"
@@ -160,12 +159,9 @@ bool ShouldShowPermission(const PageInfo::PermissionInfo& info,
if (info.type == ContentSettingsType::FILE_SYSTEM_WRITE_GUARD)
return false;
#else
- // Flash is shown if the user has ever changed its setting for |site_url|.
- if (info.type == ContentSettingsType::PLUGINS &&
- content_settings->GetWebsiteSetting(site_url, site_url,
- ContentSettingsType::PLUGINS_DATA,
- std::string(), nullptr) != nullptr) {
- return true;
+ // Flash is deprecated and should never be shown.
+ if (info.type == ContentSettingsType::PLUGINS) {
+ return false;
}
// NFC is Android-only at the moment.
@@ -182,8 +178,7 @@ bool ShouldShowPermission(const PageInfo::PermissionInfo& info,
// Hide camera if camera PTZ is granted or blocked.
if (info.type == ContentSettingsType::MEDIASTREAM_CAMERA) {
std::unique_ptr<base::Value> value = content_settings->GetWebsiteSetting(
- site_url, site_url, ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
- std::string(), nullptr);
+ site_url, site_url, ContentSettingsType::CAMERA_PAN_TILT_ZOOM, nullptr);
DCHECK(value.get());
ContentSetting camera_ptz_setting =
content_settings::ValueToContentSetting(value.get());
@@ -509,7 +504,8 @@ void PageInfo::UpdatePermissions() {
}
void PageInfo::OnSitePermissionChanged(ContentSettingsType type,
- ContentSetting setting) {
+ ContentSetting setting,
+ bool is_one_time) {
ContentSettingChangedViaPageInfo(type);
// Count how often a permission for a specific content type is changed using
@@ -560,8 +556,12 @@ void PageInfo::OnSitePermissionChanged(ContentSettingsType type,
delegate_->GetPermissionDecisionAutoblocker()->RemoveEmbargoAndResetCounts(
site_url_, type);
}
- content_settings->SetNarrowestContentSetting(site_url_, site_url_, type,
- setting);
+ using Constraints = content_settings::ContentSettingConstraints;
+ content_settings->SetNarrowestContentSetting(
+ site_url_, site_url_, type, setting,
+ is_one_time
+ ? Constraints{base::Time(), content_settings::SessionModel::OneTime}
+ : Constraints{});
// When the sound setting is changed, no reload is necessary.
if (type != ContentSettingsType::SOUND)
@@ -795,7 +795,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
safety_tip_info_ = visible_security_state.safety_tip_info;
#if defined(OS_ANDROID)
- if (base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) {
+ if (security_state::IsSafetyTipUIFeatureEnabled()) {
// identity_status_description_android_ is only displayed on Android when
// the user taps "Details" link on the page info. Reuse the description from
// page info UI.
@@ -922,7 +922,7 @@ void PageInfo::PresentSitePermissions() {
// TODO(crbug.com/1030245) Investigate why the value is queried from the low
// level routine GetWebsiteSettings.
std::unique_ptr<base::Value> value = content_settings->GetWebsiteSetting(
- site_url_, site_url_, permission_info.type, std::string(), &info);
+ site_url_, site_url_, permission_info.type, &info);
DCHECK(value.get());
if (value->type() == base::Value::Type::INTEGER) {
permission_info.setting =
@@ -934,6 +934,8 @@ void PageInfo::PresentSitePermissions() {
permission_info.source = info.source;
permission_info.is_incognito =
web_contents()->GetBrowserContext()->IsOffTheRecord();
+ permission_info.is_one_time =
+ (info.session_model == content_settings::SessionModel::OneTime);
if (info.primary_pattern == ContentSettingsPattern::Wildcard() &&
info.secondary_pattern == ContentSettingsPattern::Wildcard()) {
@@ -1024,7 +1026,7 @@ void PageInfo::PresentSiteIdentity() {
info.connection_status_description = UTF16ToUTF8(site_connection_details_);
info.identity_status = site_identity_status_;
info.safe_browsing_status = safe_browsing_status_;
- if (base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) {
+ if (security_state::IsSafetyTipUIFeatureEnabled()) {
info.safety_tip_info = safety_tip_info_;
}
#if defined(OS_ANDROID)
diff --git a/chromium/components/page_info/page_info.h b/chromium/components/page_info/page_info.h
index 7312d901222..630d4d225ea 100644
--- a/chromium/components/page_info/page_info.h
+++ b/chromium/components/page_info/page_info.h
@@ -165,6 +165,7 @@ class PageInfo : public content::WebContentsObserver {
content_settings::SETTING_SOURCE_NONE;
// Whether we're in incognito mode.
bool is_incognito = false;
+ bool is_one_time = false;
};
// Creates a PageInfo for the passed |url| using the given |ssl| status
@@ -204,7 +205,9 @@ class PageInfo : public content::WebContentsObserver {
void UpdatePermissions();
// This method is called when ever a permission setting is changed.
- void OnSitePermissionChanged(ContentSettingsType type, ContentSetting value);
+ void OnSitePermissionChanged(ContentSettingsType type,
+ ContentSetting value,
+ bool is_one_time);
// This method is called whenever access to an object is revoked.
void OnSiteChosenObjectDeleted(const ChooserUIInfo& ui_info,
diff --git a/chromium/components/page_info/page_info_ui.cc b/chromium/components/page_info/page_info_ui.cc
index 982612bcb93..a3c71cbd301 100644
--- a/chromium/components/page_info/page_info_ui.cc
+++ b/chromium/components/page_info/page_info_ui.cc
@@ -211,18 +211,27 @@ std::unique_ptr<PageInfoUI::SecurityDescription> CreateSecurityDescription(
}
std::unique_ptr<PageInfoUI::SecurityDescription>
-CreateSecurityDescriptionForLookalikeSafetyTip(const GURL& safe_url) {
+CreateSecurityDescriptionForSafetyTip(
+ const security_state::SafetyTipStatus& safety_tip_status,
+ const GURL& safe_url) {
auto security_description =
std::make_unique<PageInfoUI::SecurityDescription>();
security_description->summary_style = PageInfoUI::SecuritySummaryColor::RED;
- const base::string16 safe_host =
- security_interstitials::common_string_util::GetFormattedHostName(
- safe_url);
- security_description->summary = l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_TITLE, safe_host);
+ if (safety_tip_status == security_state::SafetyTipStatus::kBadReputation ||
+ safety_tip_status ==
+ security_state::SafetyTipStatus::kBadReputationIgnored) {
+ security_description->summary = l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_TITLE);
+ } else {
+ const base::string16 safe_host =
+ security_interstitials::common_string_util::GetFormattedHostName(
+ safe_url);
+ security_description->summary = l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_TITLE, safe_host);
+ }
security_description->details =
- l10n_util::GetStringUTF16(IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_DESCRIPTION);
+ l10n_util::GetStringUTF16(IDS_PAGE_INFO_SAFETY_TIP_DESCRIPTION);
security_description->type = PageInfoUI::SecurityDescriptionType::SAFETY_TIP;
return security_description;
}
@@ -270,6 +279,10 @@ PageInfoUI::PageFeatureInfo::PageFeatureInfo()
std::unique_ptr<PageInfoUI::SecurityDescription>
PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const {
+ bool page_info_v2_enabled = false;
+#if defined(OS_ANDROID)
+ page_info_v2_enabled = base::FeatureList::IsEnabled(page_info::kPageInfoV2);
+#endif
switch (identity_info.safe_browsing_status) {
case PageInfo::SAFE_BROWSING_STATUS_NONE:
break;
@@ -329,29 +342,37 @@ PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const {
case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
switch (identity_info.connection_status) {
case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE:
- return CreateSecurityDescription(SecuritySummaryColor::RED,
- IDS_PAGE_INFO_NOT_SECURE_SUMMARY,
- IDS_PAGE_INFO_NOT_SECURE_DETAILS,
- SecurityDescriptionType::CONNECTION);
+ return CreateSecurityDescription(
+ SecuritySummaryColor::RED,
+ page_info_v2_enabled ? IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT
+ : IDS_PAGE_INFO_NOT_SECURE_SUMMARY,
+ IDS_PAGE_INFO_NOT_SECURE_DETAILS,
+ SecurityDescriptionType::CONNECTION);
case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION:
- return CreateSecurityDescription(SecuritySummaryColor::RED,
- IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
- IDS_PAGE_INFO_NOT_SECURE_DETAILS,
- SecurityDescriptionType::CONNECTION);
+ return CreateSecurityDescription(
+ SecuritySummaryColor::RED,
+ page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT
+ : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
+ IDS_PAGE_INFO_NOT_SECURE_DETAILS,
+ SecurityDescriptionType::CONNECTION);
case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE:
- return CreateSecurityDescription(SecuritySummaryColor::RED,
- IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
- IDS_PAGE_INFO_MIXED_CONTENT_DETAILS,
- SecurityDescriptionType::CONNECTION);
+ return CreateSecurityDescription(
+ SecuritySummaryColor::RED,
+ page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT
+ : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
+ IDS_PAGE_INFO_MIXED_CONTENT_DETAILS,
+ SecurityDescriptionType::CONNECTION);
case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS:
- return CreateSecurityDescription(SecuritySummaryColor::RED,
- IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
- IDS_PAGE_INFO_LEGACY_TLS_DETAILS,
- SecurityDescriptionType::CONNECTION);
+ return CreateSecurityDescription(
+ SecuritySummaryColor::RED,
+ page_info_v2_enabled ? IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT
+ : IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY,
+ IDS_PAGE_INFO_LEGACY_TLS_DETAILS,
+ SecurityDescriptionType::CONNECTION);
default:
int secure_details = IDS_PAGE_INFO_SECURE_DETAILS;
#if defined(OS_ANDROID)
- if (base::FeatureList::IsEnabled(page_info::kPageInfoV2)) {
+ if (page_info_v2_enabled) {
// Do not show details for secure connections.
secure_details = 0;
}
@@ -364,10 +385,12 @@ PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const {
case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN:
case PageInfo::SITE_IDENTITY_STATUS_NO_CERT:
default:
- return CreateSecurityDescription(SecuritySummaryColor::RED,
- IDS_PAGE_INFO_NOT_SECURE_SUMMARY,
- IDS_PAGE_INFO_NOT_SECURE_DETAILS,
- SecurityDescriptionType::CONNECTION);
+ return CreateSecurityDescription(
+ SecuritySummaryColor::RED,
+ page_info_v2_enabled ? IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT
+ : IDS_PAGE_INFO_NOT_SECURE_SUMMARY,
+ IDS_PAGE_INFO_NOT_SECURE_DETAILS,
+ SecurityDescriptionType::CONNECTION);
}
}
@@ -389,7 +412,8 @@ base::string16 PageInfoUI::PermissionActionToUIString(
ContentSettingsType type,
ContentSetting setting,
ContentSetting default_setting,
- content_settings::SettingSource source) {
+ content_settings::SettingSource source,
+ bool is_one_time) {
ContentSetting effective_setting =
GetEffectiveSetting(type, setting, default_setting);
const int* button_text_ids = nullptr;
@@ -413,7 +437,6 @@ base::string16 PageInfoUI::PermissionActionToUIString(
break;
}
#endif
-
button_text_ids = kPermissionButtonTextIDDefaultSetting;
break;
}
@@ -427,7 +450,6 @@ base::string16 PageInfoUI::PermissionActionToUIString(
break;
}
#endif
-
button_text_ids = kPermissionButtonTextIDUserManaged;
break;
case content_settings::SETTING_SOURCE_ALLOWLIST:
@@ -437,6 +459,13 @@ base::string16 PageInfoUI::PermissionActionToUIString(
return base::string16();
}
int button_text_id = button_text_ids[effective_setting];
+
+ if (is_one_time) {
+ DCHECK_EQ(source, content_settings::SETTING_SOURCE_USER);
+ DCHECK_EQ(type, ContentSettingsType::GEOLOCATION);
+ DCHECK_EQ(button_text_id, IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_BY_USER);
+ button_text_id = IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER;
+ }
DCHECK_NE(button_text_id, kInvalidResourceID);
return l10n_util::GetStringUTF16(button_text_id);
}
@@ -494,6 +523,23 @@ SkColor PageInfoUI::GetSecondaryTextColor() {
#if defined(OS_ANDROID)
// static
int PageInfoUI::GetIdentityIconID(PageInfo::SiteIdentityStatus status) {
+ if (base::FeatureList::IsEnabled(page_info::kPageInfoV2)) {
+ switch (status) {
+ case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN:
+ case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE:
+ case PageInfo::SITE_IDENTITY_STATUS_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_EV_CERT:
+ return IDR_PAGEINFO_GOOD_V2;
+ case PageInfo::SITE_IDENTITY_STATUS_NO_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_ERROR:
+ case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM:
+ return IDR_PAGEINFO_BAD_V2;
+ }
+
+ return 0;
+ }
+
int resource_id = IDR_PAGEINFO_INFO;
switch (status) {
case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN:
@@ -519,12 +565,31 @@ int PageInfoUI::GetIdentityIconID(PageInfo::SiteIdentityStatus status) {
NOTREACHED();
break;
}
+
return resource_id;
}
// static
int PageInfoUI::GetConnectionIconID(PageInfo::SiteConnectionStatus status) {
+ if (base::FeatureList::IsEnabled(page_info::kPageInfoV2)) {
+ switch (status) {
+ case PageInfo::SITE_CONNECTION_STATUS_UNKNOWN:
+ case PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE:
+ case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED:
+ return IDR_PAGEINFO_GOOD_V2;
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE:
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION:
+ case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS:
+ case PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED:
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE:
+ case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR:
+ return IDR_PAGEINFO_BAD_V2;
+ }
+
+ return 0;
+ }
int resource_id = IDR_PAGEINFO_INFO;
+
switch (status) {
case PageInfo::SITE_CONNECTION_STATUS_UNKNOWN:
case PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE:
@@ -545,8 +610,46 @@ int PageInfoUI::GetConnectionIconID(PageInfo::SiteConnectionStatus status) {
resource_id = IDR_PAGEINFO_BAD;
break;
}
+
return resource_id;
}
+
+int PageInfoUI::GetIdentityIconColorID(PageInfo::SiteIdentityStatus status) {
+ switch (status) {
+ case PageInfo::SITE_IDENTITY_STATUS_UNKNOWN:
+ case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE:
+ case PageInfo::SITE_IDENTITY_STATUS_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_EV_CERT:
+ return IDR_PAGEINFO_GOOD_COLOR;
+ case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_NO_CERT:
+ case PageInfo::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM:
+ return IDR_PAGEINFO_WARNING_COLOR;
+ case PageInfo::SITE_IDENTITY_STATUS_ERROR:
+ return IDR_PAGEINFO_BAD_COLOR;
+ }
+ return 0;
+}
+
+int PageInfoUI::GetConnectionIconColorID(
+ PageInfo::SiteConnectionStatus status) {
+ switch (status) {
+ case PageInfo::SITE_CONNECTION_STATUS_UNKNOWN:
+ case PageInfo::SITE_CONNECTION_STATUS_INTERNAL_PAGE:
+ case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED:
+ return IDR_PAGEINFO_GOOD_COLOR;
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE:
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_FORM_ACTION:
+ case PageInfo::SITE_CONNECTION_STATUS_LEGACY_TLS:
+ case PageInfo::SITE_CONNECTION_STATUS_UNENCRYPTED:
+ return IDR_PAGEINFO_WARNING_COLOR;
+ case PageInfo::SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE:
+ case PageInfo::SITE_CONNECTION_STATUS_ENCRYPTED_ERROR:
+ return IDR_PAGEINFO_BAD_COLOR;
+ }
+ return 0;
+}
+
#else // !defined(OS_ANDROID)
// static
const gfx::ImageSkia PageInfoUI::GetPermissionIcon(
@@ -743,14 +846,9 @@ PageInfoUI::CreateSafetyTipSecurityDescription(
switch (info.status) {
case security_state::SafetyTipStatus::kBadReputation:
case security_state::SafetyTipStatus::kBadReputationIgnored:
- return CreateSecurityDescription(
- SecuritySummaryColor::RED,
- IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_TITLE,
- IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION,
- PageInfoUI::SecurityDescriptionType::SAFETY_TIP);
case security_state::SafetyTipStatus::kLookalike:
case security_state::SafetyTipStatus::kLookalikeIgnored:
- return CreateSecurityDescriptionForLookalikeSafetyTip(info.safe_url);
+ return CreateSecurityDescriptionForSafetyTip(info.status, info.safe_url);
case security_state::SafetyTipStatus::kBadKeyword:
// Keyword safety tips are only used to collect metrics for now and are
diff --git a/chromium/components/page_info/page_info_ui.h b/chromium/components/page_info/page_info_ui.h
index aab23f46a27..be0e97786db 100644
--- a/chromium/components/page_info/page_info_ui.h
+++ b/chromium/components/page_info/page_info_ui.h
@@ -167,7 +167,8 @@ class PageInfoUI {
ContentSettingsType type,
ContentSetting setting,
ContentSetting default_setting,
- content_settings::SettingSource source);
+ content_settings::SettingSource source,
+ bool is_one_time);
// Returns a string indicating whether the permission was blocked via an
// extension, enterprise policy, or embargo.
@@ -185,6 +186,12 @@ class PageInfoUI {
// Returns the connection icon ID for the given connection |status|.
static int GetConnectionIconID(PageInfo::SiteConnectionStatus status);
+
+ // Returns the identity icon color ID for the given identity |status|.
+ static int GetIdentityIconColorID(PageInfo::SiteIdentityStatus status);
+
+ // Returns the connection icon color ID for the given connection |status|.
+ static int GetConnectionIconColorID(PageInfo::SiteConnectionStatus status);
#else // !defined(OS_ANDROID)
// Returns icons for the given PageInfo::PermissionInfo |info|. If |info|'s
// current setting is CONTENT_SETTING_DEFAULT, it will return the icon for
diff --git a/chromium/components/page_info_strings.grdp b/chromium/components/page_info_strings.grdp
index e4f6268b248..616b96fff92 100644
--- a/chromium/components/page_info_strings.grdp
+++ b/chromium/components/page_info_strings.grdp
@@ -7,9 +7,15 @@
<message name="IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if the connection to the current website is using mainly using a secure connection but has some insecure parts (like insecurely loaded images).">
Your connection to this site is not fully secure
</message>
+ <message name="IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if the connection to the current website is using mainly using a secure connection but has some insecure parts (like insecurely loaded images).">
+ Connection is not fully secure
+ </message>
<message name="IDS_PAGE_INFO_NOT_SECURE_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if the connection to the current website is not secure.">
Your connection to this site is not secure
</message>
+ <message name="IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT" desc="A shorter one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if the connection to the current website is not secure.">
+ Connection is not secure
+ </message>
<message name="IDS_PAGE_INFO_MALWARE_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if the current website has been flagged as containing malware.">
This site contains malware
</message>
@@ -42,9 +48,6 @@
<message name="IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_TITLE" desc="Message to display in the page info bubble when the page you are on triggered a safety tip.">
Suspicious site
</message>
- <message name="IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION" desc="Body of message to display in the page info bubble when you are viewing a page that triggered a safety tip.">
- This site could be fake or fraudulent. Chrome recommends leaving now.
- </message>
<message name="IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_LEAVE_BUTTON" desc="Text of button to leave a suspicious page. Shown on the safety tip page info bubble.">
Leave site
</message>
@@ -57,7 +60,7 @@
<message name="IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_TITLE" desc="Title of Safety Tip infobar on a domain that looks like another domain.">
Did you mean <ph name='LOOKALIKE_DOMAIN'>$1<ex>google.com</ex></ph>?
</message>
- <message name="IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_DESCRIPTION" desc="Body of a warning when the user visits a page that triggered a Safety Tip because the domain looked like another domain.">
+ <message name="IDS_PAGE_INFO_SAFETY_TIP_DESCRIPTION" desc="Body of a warning when the user visits a page that triggered a Safety Tip.">
Attackers sometimes mimic sites by making hard-to-see changes to the web address.
</message>
@@ -246,7 +249,7 @@
Background Sync
</message>
<message name="IDS_PAGE_INFO_TYPE_IDLE_DETECTION" desc="The label used for the idle detection permission controlls in the Page Info popup.">
- User presence
+ Your presence
</message>
<message name="IDS_PAGE_INFO_TYPE_IMAGES" desc="The label used for images permission controls in the Page Info popup.">
Images
@@ -329,6 +332,9 @@
<message name="IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_BY_USER" desc="The Page Info popup contains several buttons for opening dropdown menus and changing site permissions. This is the text of such a button if the permission controlled by the button was explicitly set to allow by the user.">
Allow
</message>
+ <message name="IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER" desc="The Page Info popup contains several buttons for opening dropdown menus and changing site permissions. This is the text of such a button if the permission controlled by the button was explicitly set to allow once by the user.">
+ Only this time
+ </message>
<message name="IDS_PAGE_INFO_BUTTON_TEXT_BLOCKED_BY_USER" desc="The Page Info popup contains several buttons for opening dropdown menus and changing site permissions. This is the text of such a button if the permission controlled by the button was explicitly set to block by the user.">
Block
</message>
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER.png.sha1
new file mode 100644
index 00000000000..93e116a20d0
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_BUTTON_TEXT_ALLOWED_ONCE_BY_USER.png.sha1
@@ -0,0 +1 @@
+8fb550773c424b5e67c65347aef814af36abb648 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT.png.sha1
new file mode 100644
index 00000000000..90ad79e2354
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_MIXED_CONTENT_SUMMARY_SHORT.png.sha1
@@ -0,0 +1 @@
+d0d83402a1de0ea948910b38b7d78ef520adbec3 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT.png.sha1
new file mode 100644
index 00000000000..c757a821e68
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_NOT_SECURE_SUMMARY_SHORT.png.sha1
@@ -0,0 +1 @@
+a8051e99f745f42e4ab337204d97378e892892df \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1
deleted file mode 100644
index c3b63e34aae..00000000000
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_BAD_REPUTATION_DESCRIPTION.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b34b7304a8ffb374af8016eb3068dbbb88ba4ede \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_DESCRIPTION.png.sha1
index 2d294471680..2d294471680 100644
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_LOOKALIKE_DESCRIPTION.png.sha1
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_SAFETY_TIP_DESCRIPTION.png.sha1
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_TYPE_IDLE_DETECTION.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_TYPE_IDLE_DETECTION.png.sha1
index 75935102c13..cd5b425cfcd 100644
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_TYPE_IDLE_DETECTION.png.sha1
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_TYPE_IDLE_DETECTION.png.sha1
@@ -1 +1 @@
-53f9e5e5cfe6078d4f9c94abfb7fd164bf5b19e4 \ No newline at end of file
+8772f25cc08e3695b2c8915c260b81207d32bd22 \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/BUILD.gn b/chromium/components/page_load_metrics/browser/BUILD.gn
index ce601841e23..07518ded1d6 100644
--- a/chromium/components/page_load_metrics/browser/BUILD.gn
+++ b/chromium/components/page_load_metrics/browser/BUILD.gn
@@ -6,6 +6,8 @@ import("//testing/test.gni")
source_set("browser") {
sources = [
+ "layout_shift_normalization.cc",
+ "layout_shift_normalization.h",
"metrics_navigation_throttle.cc",
"metrics_navigation_throttle.h",
"metrics_web_contents_observer.cc",
@@ -20,6 +22,8 @@ source_set("browser") {
"observers/core/uma_page_load_metrics_observer.h",
"observers/layout_page_load_metrics_observer.cc",
"observers/layout_page_load_metrics_observer.h",
+ "observers/prerender_page_load_metrics_observer.cc",
+ "observers/prerender_page_load_metrics_observer.h",
"observers/use_counter/ukm_features.cc",
"observers/use_counter_page_load_metrics_observer.cc",
"observers/use_counter_page_load_metrics_observer.h",
@@ -83,11 +87,13 @@ source_set("test_support") {
source_set("unit_tests") {
testonly = true
sources = [
+ "layout_shift_normalization_unittest.cc",
"metrics_web_contents_observer_unittest.cc",
"observers/click_input_tracker_unittest.cc",
"observers/core/uma_page_load_metrics_observer_unittest.cc",
"observers/page_load_metrics_observer_content_test_harness.cc",
"observers/page_load_metrics_observer_content_test_harness.h",
+ "observers/prerender_page_load_metrics_observer_unittest.cc",
"observers/use_counter_page_load_metrics_observer_unittest.cc",
"page_load_metrics_util_unittest.cc",
"resource_tracker_unittest.cc",
diff --git a/chromium/components/page_load_metrics/browser/layout_shift_normalization.cc b/chromium/components/page_load_metrics/browser/layout_shift_normalization.cc
new file mode 100644
index 00000000000..aa1b07f3f89
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/layout_shift_normalization.cc
@@ -0,0 +1,191 @@
+// Copyright 2020 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/page_load_metrics/browser/layout_shift_normalization.h"
+
+namespace page_load_metrics {
+constexpr auto NEW_SHIFT_BUFFER_WINDOW_DURATION =
+ base::TimeDelta::FromSeconds(5);
+constexpr auto MAX_SHIFT_BUFFER_SIZE = 300;
+
+LayoutShiftNormalization::LayoutShiftNormalization() = default;
+LayoutShiftNormalization::~LayoutShiftNormalization() = default;
+
+void LayoutShiftNormalization::AddNewLayoutShifts(
+ const std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts,
+ base::TimeTicks current_time,
+ double cumulative_layout_shift_score) {
+ if (new_shifts.empty() || normalized_cls_data_.data_tainted)
+ return;
+
+ if ((current_time - new_shifts[0]->layout_shift_time >
+ NEW_SHIFT_BUFFER_WINDOW_DURATION) ||
+ (recent_layout_shifts_.size() + new_shifts.size() >
+ MAX_SHIFT_BUFFER_SIZE)) {
+ // We can't keep all layout shifts all the time especially for long lived
+ // pages. So we allow a layout shift to be delivered to the browser
+ // process within 5 seconds and set a limit for the number of shifts we can
+ // store in the browser process. If the delivery latency of a layout shift
+ // is bigger than 5s, we can't process this layout shift and get the correct
+ // normalization results, which means we should not report the results in
+ // UKM.
+ normalized_cls_data_.data_tainted = true;
+ return;
+ }
+
+ // Append all shift data.
+ for (const auto& layout_shift : new_shifts) {
+ recent_layout_shifts_.emplace_back(layout_shift->layout_shift_time,
+ layout_shift->layout_shift_score);
+ }
+
+ // At this point, the vector contains two sorted subvectors, and we can do an
+ // in-place merge to create a sorted vector.
+ std::inplace_merge(recent_layout_shifts_.begin(),
+ recent_layout_shifts_.end() - new_shifts.size(),
+ recent_layout_shifts_.end());
+
+ // Now that we have a single sorted list of shifts, we can find the partition
+ // point for old shifts which we are ready to delete
+ auto first_non_stale = std::upper_bound(
+ recent_layout_shifts_.begin(), recent_layout_shifts_.end(),
+ current_time - NEW_SHIFT_BUFFER_WINDOW_DURATION,
+ [](auto time, auto const& shift) { return time < shift.first; });
+
+ // Update sliding and session window CLS.
+ UpdateWindowCLS(current_time, recent_layout_shifts_.begin(), first_non_stale,
+ recent_layout_shifts_.end(), cumulative_layout_shift_score);
+
+ // Finally, remove the stale shifts at this point.
+ recent_layout_shifts_.erase(recent_layout_shifts_.begin(), first_non_stale);
+}
+
+void LayoutShiftNormalization::UpdateSlidingWindow(
+ std::vector<SlidingWindow>* sliding_windows,
+ base::TimeDelta duration,
+ base::TimeTicks current_time,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator end,
+ double& max_score) {
+ for (auto it = begin; it != end; ++it) {
+ for (SlidingWindow& window : *sliding_windows) {
+ if (it->first - window.start_time <= duration) {
+ window.layout_shift_score += it->second;
+ max_score = std::max(max_score, window.layout_shift_score);
+ }
+ }
+ sliding_windows->emplace_back(SlidingWindow{it->first, it->second});
+ max_score = std::max(max_score, it->second);
+ }
+ // Erase stale sliding windows.
+ auto first_non_stale_window = std::upper_bound(
+ sliding_windows->begin(), sliding_windows->end(),
+ current_time - NEW_SHIFT_BUFFER_WINDOW_DURATION - duration,
+ [](auto time, auto const& window) { return time < window.start_time; });
+ sliding_windows->erase(sliding_windows->begin(), first_non_stale_window);
+}
+void LayoutShiftNormalization::UpdateSessionWindow(
+ SessionWindow* session_window,
+ base::TimeDelta gap,
+ base::TimeDelta max_duration,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator end,
+ double& max_score,
+ uint32_t& count) {
+ for (auto it = begin; it != end; ++it) {
+ if ((it->first - session_window->last_time > gap) ||
+ (it->first - session_window->start_time > max_duration)) {
+ session_window->start_time = it->first;
+ session_window->layout_shift_score = 0;
+ ++count;
+ }
+ session_window->last_time = it->first;
+ session_window->layout_shift_score += it->second;
+ max_score = std::max(max_score, session_window->layout_shift_score);
+ }
+}
+
+// This function will update layout shift normalization results for sliding
+// windows and session windows twice. The first update is processing stale
+// layout shifts (current_time - layout_shift_time >= 5s) in
+// recent_layout_shifts_. The second update is continuing the first update by
+// processing remaining layout shifts in recent_layout_shifts_. Processing
+// layout shifts in order is very important to our algorithm or we may
+// miscalculate the number of windows or layout shift score for a window.
+// We assume the browser process can receive any layout shift within 5 seconds,
+// so there might be some non-stale layout shifts on the way and a newer layout
+// shift can be received earlier than an old one. This is one reason why we
+// update layout shift normalization twice. Another reason is we can't updating
+// normalization on demand when we record UKM because of constant class objects.
+// The first update is for updating the normalization for all stale layout shift
+// we received. The second update is for all layout shifts we received so far in
+// case we need to record UKM right away.
+void LayoutShiftNormalization::UpdateWindowCLS(
+ base::TimeTicks current_time,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator first,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator
+ first_non_stale,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator last,
+ double cumulative_layout_shift_score) {
+ double dummy_max = 0.0;
+ uint32_t dummy_count = 0;
+ // Update Sliding Windows.
+ UpdateSlidingWindow(
+ &sliding_300ms_, base::TimeDelta::FromMilliseconds(300), current_time,
+ first, first_non_stale,
+ normalized_cls_data_.sliding_windows_duration300ms_max_cls);
+ UpdateSlidingWindow(
+ &sliding_1000ms_, base::TimeDelta::FromMilliseconds(1000), current_time,
+ first, first_non_stale,
+ normalized_cls_data_.sliding_windows_duration1000ms_max_cls);
+ auto tmp_sliding_300ms = sliding_300ms_;
+ auto tmp_sliding_1000ms = sliding_1000ms_;
+
+ // Update Session Windows.
+ UpdateSessionWindow(
+ &session_gap1000ms_max5000ms_, base::TimeDelta::FromMilliseconds(1000),
+ base::TimeDelta::FromMilliseconds(5000), first, first_non_stale,
+ normalized_cls_data_.session_windows_gap1000ms_max5000ms_max_cls,
+ dummy_count);
+ UpdateSessionWindow(
+ &session_gap1000ms_, base::TimeDelta::FromMilliseconds(1000),
+ base::TimeDelta::Max(), first, first_non_stale,
+ normalized_cls_data_.session_windows_gap1000ms_maxMax_max_cls,
+ dummy_count);
+ UpdateSessionWindow(&session_gap5000ms_,
+ base::TimeDelta::FromMilliseconds(5000),
+ base::TimeDelta::Max(), first, first_non_stale, dummy_max,
+ session_gap5000ms_count_);
+ auto tmp_session_gap1000ms_max5000ms = session_gap1000ms_max5000ms_;
+ auto tmp_session_gap1000ms_ = session_gap1000ms_;
+ auto tmp_session_gap5000ms_ = session_gap5000ms_;
+ auto tmp_session_gap5000ms_count_ = session_gap5000ms_count_;
+
+ UpdateSlidingWindow(
+ &tmp_sliding_300ms, base::TimeDelta::FromMilliseconds(300), current_time,
+ first_non_stale, last,
+ normalized_cls_data_.sliding_windows_duration300ms_max_cls);
+ UpdateSlidingWindow(
+ &tmp_sliding_1000ms, base::TimeDelta::FromMilliseconds(1000),
+ current_time, first_non_stale, last,
+ normalized_cls_data_.sliding_windows_duration1000ms_max_cls);
+ UpdateSessionWindow(
+ &tmp_session_gap1000ms_max5000ms, base::TimeDelta::FromMilliseconds(1000),
+ base::TimeDelta::FromMilliseconds(5000), first_non_stale, last,
+ normalized_cls_data_.session_windows_gap1000ms_max5000ms_max_cls,
+ dummy_count);
+ UpdateSessionWindow(
+ &tmp_session_gap1000ms_, base::TimeDelta::FromMilliseconds(1000),
+ base::TimeDelta::Max(), first_non_stale, last,
+ normalized_cls_data_.session_windows_gap1000ms_maxMax_max_cls,
+ dummy_count);
+ UpdateSessionWindow(&tmp_session_gap5000ms_,
+ base::TimeDelta::FromMilliseconds(5000),
+ base::TimeDelta::Max(), first_non_stale, last, dummy_max,
+ tmp_session_gap5000ms_count_);
+
+ normalized_cls_data_.session_windows_gap5000ms_maxMax_average_cls =
+ cumulative_layout_shift_score / tmp_session_gap5000ms_count_;
+}
+} // namespace page_load_metrics \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/layout_shift_normalization.h b/chromium/components/page_load_metrics/browser/layout_shift_normalization.h
new file mode 100644
index 00000000000..48431ea0ba5
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/layout_shift_normalization.h
@@ -0,0 +1,86 @@
+// Copyright 2020 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_PAGE_LOAD_METRICS_BROWSER_LAYOUT_SHIFT_NORMALIZATION_H_
+#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_LAYOUT_SHIFT_NORMALIZATION_H_
+
+#include "base/time/time.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace page_load_metrics {
+
+// LayoutShiftNormalization implements some experimental strategies for
+// normalizing layout shift. Instead of adding all layout shift scores together
+// like what we do in Cumulative Layout Shift(CLS), we aggregate layout shifts
+// window by window. For more information, see go/layoutshiftnorm.
+class LayoutShiftNormalization {
+ public:
+ LayoutShiftNormalization();
+ ~LayoutShiftNormalization();
+ const NormalizedCLSData& normalized_cls_data() const {
+ return normalized_cls_data_;
+ }
+
+ void AddNewLayoutShifts(
+ const std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts,
+ base::TimeTicks current_time,
+ /*Whole page CLS*/ double cumulative_layout_shift_score);
+
+ private:
+ struct SlidingWindow {
+ base::TimeTicks start_time;
+ double layout_shift_score = 0.0;
+ };
+
+ struct SessionWindow {
+ base::TimeTicks start_time;
+ base::TimeTicks last_time;
+ double layout_shift_score = 0.0;
+ };
+
+ void UpdateWindowCLS(
+ base::TimeTicks current_time,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator first,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator
+ first_non_stale,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator last,
+ double cumulative_layout_shift_score);
+
+ void UpdateSlidingWindow(
+ std::vector<SlidingWindow>* sliding_windows,
+ base::TimeDelta duration,
+ base::TimeTicks current_time,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator end,
+ double& max_score);
+
+ void UpdateSessionWindow(
+ SessionWindow* session_window,
+ base::TimeDelta gap,
+ base::TimeDelta max_duration,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator begin,
+ std::vector<std::pair<base::TimeTicks, double>>::const_iterator end,
+ double& max_score,
+ uint32_t& count);
+
+ // CLS normalization
+ NormalizedCLSData normalized_cls_data_;
+
+ // This vector is maintained in sorted order.
+ std::vector<std::pair<base::TimeTicks, double>> recent_layout_shifts_;
+
+ // Sliding window vectors are maintained in sorted order.
+ std::vector<SlidingWindow> sliding_300ms_;
+ std::vector<SlidingWindow> sliding_1000ms_;
+ SessionWindow session_gap1000ms_max5000ms_;
+ SessionWindow session_gap1000ms_;
+ SessionWindow session_gap5000ms_;
+ uint32_t session_gap5000ms_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(LayoutShiftNormalization);
+};
+
+} // namespace page_load_metrics
+
+#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_LAYOUT_SHIFT_NORMALIZATION_H_
diff --git a/chromium/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc b/chromium/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc
new file mode 100644
index 00000000000..eecb3de0541
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/layout_shift_normalization_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2020 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/page_load_metrics/browser/layout_shift_normalization.h"
+#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+constexpr auto NEW_SHIFT_BUFFER_WINDOW_DURATION = 5000;
+
+class LayoutShiftNormalizationTest : public testing::Test {
+ public:
+ LayoutShiftNormalizationTest() = default;
+
+ void AddNewLayoutShifts(
+ const std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts,
+ base::TimeTicks current_time) {
+ // Update layout shift normalization.
+ layout_shift_normalization_.AddNewLayoutShifts(
+ new_shifts, current_time, cumulative_layoutshift_score_);
+ }
+ const page_load_metrics::NormalizedCLSData& normalized_cls_data() const {
+ return layout_shift_normalization_.normalized_cls_data();
+ }
+
+ void InsertNewLayoutShifts(
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr>& new_shifts,
+ base::TimeTicks current_time,
+ std::vector<std::pair<int, double>> shifts_data) {
+ for (auto shift : shifts_data) {
+ new_shifts.emplace_back(page_load_metrics::mojom::LayoutShift::New(
+ current_time - base::TimeDelta::FromMilliseconds(std::get<0>(shift)),
+ std::get<1>(shift)));
+ // Update CLS.
+ cumulative_layoutshift_score_ += std::get<1>(shift);
+ }
+ }
+
+ private:
+ page_load_metrics::LayoutShiftNormalization layout_shift_normalization_;
+ double cumulative_layoutshift_score_ = 0.0;
+};
+
+TEST_F(LayoutShiftNormalizationTest, MultipleShifts) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts;
+ // Insert new layout shifts. The insertion order matters.
+ InsertNewLayoutShifts(new_shifts, current_time,
+ {{2100, 1.5}, {1800, 1.5}, {1300, 1.5}, {1000, 1.5}});
+ // Update CLS normalization data.
+ AddNewLayoutShifts(new_shifts, current_time);
+
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration300ms_max_cls, 3.0);
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration1000ms_max_cls, 4.5);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_max5000ms_max_cls,
+ 6.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_maxMax_max_cls,
+ 6.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap5000ms_maxMax_average_cls,
+ 6.0);
+ EXPECT_EQ(normalized_cls_data().data_tainted, false);
+}
+
+TEST_F(LayoutShiftNormalizationTest, MultipleShiftsWithOneStaleShift) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts;
+ // Insert new layout shifts. The insertion order matters.
+ // Insert the stale shift.
+ InsertNewLayoutShifts(new_shifts, current_time,
+ {{NEW_SHIFT_BUFFER_WINDOW_DURATION + 100, 1.5}});
+
+ // Insert non-stale shifts
+ InsertNewLayoutShifts(new_shifts, current_time,
+ {{1800, 1.5}, {1300, 1.5}, {1000, 1.5}});
+ // Update CLS normalization data.
+ AddNewLayoutShifts(new_shifts, current_time);
+
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration300ms_max_cls, 0.0);
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration1000ms_max_cls, 0.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_max5000ms_max_cls,
+ 0.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_maxMax_max_cls,
+ 0.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap5000ms_maxMax_average_cls,
+ 0.0);
+ EXPECT_EQ(normalized_cls_data().data_tainted, true);
+}
+
+TEST_F(LayoutShiftNormalizationTest, MultipleShiftsFromTwoRenderers) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ // Insert new layout shifts from one renderer. The insertion order matters.
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts_1;
+ InsertNewLayoutShifts(new_shifts_1, current_time, {{2100, 1.5}, {1800, 1.5}});
+ AddNewLayoutShifts(new_shifts_1, current_time);
+
+ // Insert new layout shifts from the other renderer. The insertion order
+ // matters.
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts_2;
+ InsertNewLayoutShifts(new_shifts_2, current_time, {{4100, 4.0}, {1000, 1.5}});
+ AddNewLayoutShifts(new_shifts_2, current_time);
+
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration300ms_max_cls, 4.0);
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration1000ms_max_cls, 4.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_max5000ms_max_cls,
+ 4.5);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_maxMax_max_cls,
+ 4.5);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap5000ms_maxMax_average_cls,
+ 8.5);
+ EXPECT_EQ(normalized_cls_data().data_tainted, false);
+}
+
+TEST_F(LayoutShiftNormalizationTest, MultipleShiftsFromDifferentTimes) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ // Insert the first set of new layout shifts. The insertion order matters.
+ auto current_time_1 = current_time - base::TimeDelta::FromMilliseconds(5000);
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts_1;
+ InsertNewLayoutShifts(new_shifts_1, current_time_1,
+ {{2100, 1.5}, {1800, 1.5}});
+ AddNewLayoutShifts(new_shifts_1, current_time_1);
+
+ // Insert the second set of new layout shifts. The insertion order
+ // matters.
+ auto current_time_2 = current_time;
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts_2;
+ InsertNewLayoutShifts(new_shifts_2, current_time_2,
+ {{4100, 2.0}, {1000, 1.5}});
+ AddNewLayoutShifts(new_shifts_2, current_time);
+
+ // Insert the third set of new layout shifts. The insertion order
+ // matters.
+ auto current_time_3 = current_time + base::TimeDelta::FromMilliseconds(6000);
+ std::vector<page_load_metrics::mojom::LayoutShiftPtr> new_shifts_3;
+ InsertNewLayoutShifts(new_shifts_3, current_time_3, {{0, 0.5}});
+ AddNewLayoutShifts(new_shifts_3, current_time_3);
+
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration300ms_max_cls, 3.0);
+ EXPECT_EQ(normalized_cls_data().sliding_windows_duration1000ms_max_cls, 3.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_max5000ms_max_cls,
+ 3.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap1000ms_maxMax_max_cls,
+ 3.0);
+ EXPECT_EQ(normalized_cls_data().session_windows_gap5000ms_maxMax_average_cls,
+ 3.5);
+ EXPECT_EQ(normalized_cls_data().data_tainted, false);
+} \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 72c2baf6bd5..98c35d1195a 100644
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -35,6 +35,7 @@
#include "net/base/net_errors.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/common/mobile_metrics/mobile_friendliness.h"
#include "ui/base/page_transition_types.h"
namespace page_load_metrics {
@@ -635,6 +636,9 @@ void MetricsWebContentsObserver::FinalizeCurrentlyCommittedLoad(
if (is_non_user_initiated_client_redirect) {
committed_load_->NotifyClientRedirectTo(newly_committed_navigation);
}
+
+ // Ensure that any pending update gets dispatched.
+ committed_load_->metrics_update_dispatcher()->FlushPendingTimingUpdates();
}
}
@@ -803,7 +807,8 @@ void MetricsWebContentsObserver::OnTimingUpdated(
mojom::FrameRenderDataUpdatePtr render_data,
mojom::CpuTimingPtr cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta) {
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness) {
// We may receive notifications from frames that have been navigated away
// from. We simply ignore them.
// TODO(crbug.com/1061060): We should not ignore page timings if the page is
@@ -826,7 +831,7 @@ void MetricsWebContentsObserver::OnTimingUpdated(
render_frame_host, std::move(timing), std::move(metadata),
std::move(new_features), resources, std::move(render_data),
std::move(cpu_timing), std::move(new_deferred_resource_data),
- std::move(input_timing_delta));
+ std::move(input_timing_delta), std::move(mobile_friendliness));
}
}
@@ -858,13 +863,15 @@ void MetricsWebContentsObserver::UpdateTiming(
mojom::FrameRenderDataUpdatePtr render_data,
mojom::CpuTimingPtr cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta) {
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness) {
content::RenderFrameHost* render_frame_host =
page_load_metrics_receiver_.GetCurrentTargetFrame();
OnTimingUpdated(render_frame_host, std::move(timing), std::move(metadata),
std::move(new_features), resources, std::move(render_data),
std::move(cpu_timing), std::move(new_deferred_resource_data),
- std::move(input_timing_delta));
+ std::move(input_timing_delta),
+ std::move(mobile_friendliness));
}
void MetricsWebContentsObserver::SetUpSharedMemoryForSmoothness(
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h
index 0cbee5e01a7..da3dad35c09 100644
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -27,6 +27,10 @@
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
+namespace blink {
+struct MobileFriendliness;
+} // namespace blink
+
namespace content {
class NavigationHandle;
class RenderFrameHost;
@@ -162,7 +166,8 @@ class MetricsWebContentsObserver
mojom::FrameRenderDataUpdatePtr render_data,
mojom::CpuTimingPtr cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta);
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness);
// Informs the observers of the currently committed load that the event
// corresponding to |event_key| has occurred. This should not be called within
@@ -181,14 +186,17 @@ class MetricsWebContentsObserver
content::NavigationHandle* navigation_handle);
// page_load_metrics::mojom::PageLoadMetrics implementation.
- void UpdateTiming(mojom::PageLoadTimingPtr timing,
- mojom::FrameMetadataPtr metadata,
- mojom::PageLoadFeaturesPtr new_features,
- std::vector<mojom::ResourceDataUpdatePtr> resources,
- mojom::FrameRenderDataUpdatePtr render_data,
- mojom::CpuTimingPtr cpu_timing,
- mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing) override;
+ void UpdateTiming(
+ mojom::PageLoadTimingPtr timing,
+ mojom::FrameMetadataPtr metadata,
+ mojom::PageLoadFeaturesPtr new_features,
+ std::vector<mojom::ResourceDataUpdatePtr> resources,
+ mojom::FrameRenderDataUpdatePtr render_data,
+ mojom::CpuTimingPtr cpu_timing,
+ mojom::DeferredResourceCountsPtr new_deferred_resource_data,
+ mojom::InputTimingPtr input_timing,
+ const blink::MobileFriendliness& mobile_friendliness) override;
+
void SetUpSharedMemoryForSmoothness(
base::ReadOnlySharedMemoryRegion shared_memory) override;
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index 0a218b62c25..121cc7f1a8f 100644
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -113,7 +113,7 @@ class MetricsWebContentsObserverTest
std::vector<mojom::ResourceDataUpdatePtr>(),
mojom::FrameRenderDataUpdatePtr(base::in_place), timing.Clone(),
mojom::DeferredResourceCountsPtr(base::in_place),
- mojom::InputTimingPtr(base::in_place));
+ mojom::InputTimingPtr(base::in_place), blink::MobileFriendliness());
}
void SimulateTimingUpdate(const mojom::PageLoadTiming& timing,
@@ -139,7 +139,7 @@ class MetricsWebContentsObserverTest
mojom::FrameRenderDataUpdatePtr(base::in_place),
mojom::CpuTimingPtr(base::in_place),
mojom::DeferredResourceCountsPtr(base::in_place),
- mojom::InputTimingPtr(base::in_place));
+ mojom::InputTimingPtr(base::in_place), blink::MobileFriendliness());
}
void AttachObserver() {
diff --git a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
index 10cf71935d5..ec62fe13657 100644
--- a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
@@ -12,6 +12,12 @@ namespace internal {
const char kHistogramFirstPaintAfterBackForwardCacheRestore[] =
"PageLoad.PaintTiming.NavigationToFirstPaint.AfterBackForwardCacheRestore";
+const char kHistogramFirstRequestAnimationFrameAfterBackForwardCacheRestore[] =
+ "PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillFirst";
+const char kHistogramSecondRequestAnimationFrameAfterBackForwardCacheRestore[] =
+ "PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillSecond";
+const char kHistogramThirdRequestAnimationFrameAfterBackForwardCacheRestore[] =
+ "PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfillThird";
const char kHistogramFirstInputDelayAfterBackForwardCacheRestore[] =
"PageLoad.InteractiveTiming.FirstInputDelay.AfterBackForwardCacheRestore";
extern const char
@@ -98,6 +104,27 @@ void BackForwardCachePageLoadMetricsObserver::
}
void BackForwardCachePageLoadMetricsObserver::
+ OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+ const page_load_metrics::mojom::BackForwardCacheTiming& timing) {
+ auto request_animation_frames =
+ timing.request_animation_frames_after_back_forward_cache_restore;
+ DCHECK_EQ(request_animation_frames.size(), 3u);
+
+ PAGE_LOAD_HISTOGRAM(
+ internal::
+ kHistogramFirstRequestAnimationFrameAfterBackForwardCacheRestore,
+ request_animation_frames[0]);
+ PAGE_LOAD_HISTOGRAM(
+ internal::
+ kHistogramSecondRequestAnimationFrameAfterBackForwardCacheRestore,
+ request_animation_frames[1]);
+ PAGE_LOAD_HISTOGRAM(
+ internal::
+ kHistogramThirdRequestAnimationFrameAfterBackForwardCacheRestore,
+ request_animation_frames[2]);
+}
+
+void BackForwardCachePageLoadMetricsObserver::
OnFirstInputAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) {
diff --git a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
index 199877ccb6d..a708f5cba23 100644
--- a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h
@@ -35,6 +35,8 @@ class BackForwardCachePageLoadMetricsObserver
void OnFirstPaintAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) override;
+ void OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+ const page_load_metrics::mojom::BackForwardCacheTiming& timing) override;
void OnFirstInputAfterBackForwardCacheRestoreInPage(
const page_load_metrics::mojom::BackForwardCacheTiming& timing,
size_t index) override;
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
index ca11748bda2..c7c3804b5ac 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
@@ -11,7 +11,6 @@
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
-#include "base/power_monitor/power_monitor.h"
#include "components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h"
#include "components/page_load_metrics/browser/page_load_metrics_util.h"
#include "content/public/common/process_type.h"
@@ -129,21 +128,23 @@ const char kHistogramFirstContentfulPaintInitiatingProcess[] =
const char kHistogramFirstMeaningfulPaint[] =
"PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint";
const char kHistogramLargestContentfulPaint[] =
- "PageLoad.PaintTiming.NavigationToLargestContentfulPaint";
+ "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2";
const char kHistogramLargestContentfulPaintContentType[] =
"PageLoad.Internal.PaintTiming.LargestContentfulPaint.ContentType";
const char kHistogramLargestContentfulPaintMainFrame[] =
- "PageLoad.PaintTiming.NavigationToLargestContentfulPaint.MainFrame";
+ "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.MainFrame";
const char kHistogramLargestContentfulPaintMainFrameContentType[] =
"PageLoad.Internal.PaintTiming.LargestContentfulPaint.MainFrame."
"ContentType";
-const char kHistogramExperimentalLargestContentfulPaint[] =
- "PageLoad.PaintTiming.NavigationToExperimentalLargestContentfulPaint";
+// TODO(crbug.com/1045640): Stop reporting these obsolete versions after some
+// time.
+const char kDeprecatedHistogramLargestContentfulPaint[] =
+ "PageLoad.PaintTiming.NavigationToLargestContentfulPaint";
const char kHistogramExperimentalLargestContentfulPaintContentType[] =
"PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
"ContentType";
-const char kHistogramExperimentalLargestContentfulPaintMainFrame[] =
- "PageLoad.PaintTiming.NavigationToExperimentalLargestContentfulPaint."
+const char kDeprecatedHistogramLargestContentfulPaintMainFrame[] =
+ "PageLoad.PaintTiming.NavigationToLargestContentfulPaint."
"MainFrame";
const char kHistogramExperimentalLargestContentfulPaintMainFrameContentType[] =
"PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
@@ -187,11 +188,6 @@ const char kHistogramParseBlockedOnScriptExecutionDocumentWrite[] =
const char kHistogramFirstContentfulPaintNoStore[] =
"PageLoad.PaintTiming.NavigationToFirstContentfulPaint.NoStore";
-const char kHistogramFirstContentfulPaintOnBattery[] =
- "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.OnBattery";
-const char kHistogramFirstContentfulPaintNotOnBattery[] =
- "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.NotOnBattery";
-
const char kHistogramFirstContentfulPaintHiddenWhileFlushing[] =
"PageLoad.PaintTiming.NavigationToFirstContentfulPaint.HiddenWhileFlushing";
@@ -522,14 +518,6 @@ void UmaPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
timing.paint_timing->first_contentful_paint.value());
}
- if (base::PowerMonitor::IsOnBatteryPower()) {
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintOnBattery,
- timing.paint_timing->first_contentful_paint.value());
- } else {
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintNotOnBattery,
- timing.paint_timing->first_contentful_paint.value());
- }
-
// TODO(bmcquade): consider adding a histogram that uses
// UserInputInfo.user_input_event.
if (GetDelegate().GetUserInitiatedInfo().browser_initiated ||
@@ -1000,7 +988,7 @@ void UmaPageLoadMetricsObserver::RecordTimingHistograms(
main_frame_experimental_largest_contentful_paint.Time(),
GetDelegate())) {
PAGE_LOAD_HISTOGRAM(
- internal::kHistogramExperimentalLargestContentfulPaintMainFrame,
+ internal::kDeprecatedHistogramLargestContentfulPaintMainFrame,
main_frame_experimental_largest_contentful_paint.Time().value());
UMA_HISTOGRAM_ENUMERATION(
internal::
@@ -1018,7 +1006,7 @@ void UmaPageLoadMetricsObserver::RecordTimingHistograms(
all_frames_experimental_largest_contentful_paint.Time(),
GetDelegate())) {
PAGE_LOAD_HISTOGRAM(
- internal::kHistogramExperimentalLargestContentfulPaint,
+ internal::kDeprecatedHistogramLargestContentfulPaint,
all_frames_experimental_largest_contentful_paint.Time().value());
UMA_HISTOGRAM_ENUMERATION(
internal::kHistogramExperimentalLargestContentfulPaintContentType,
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
index 61c29c1c2e3..37a37b0751c 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
@@ -31,9 +31,9 @@ extern const char kHistogramLargestContentfulPaint[];
extern const char kHistogramLargestContentfulPaintContentType[];
extern const char kHistogramLargestContentfulPaintMainFrame[];
extern const char kHistogramLargestContentfulPaintMainFrameContentType[];
-extern const char kHistogramExperimentalLargestContentfulPaint[];
+extern const char kDeprecatedHistogramLargestContentfulPaint[];
extern const char kHistogramExperimentalLargestContentfulPaintContentType[];
-extern const char kHistogramExperimentalLargestContentfulPaintMainFrame[];
+extern const char kDeprecatedHistogramLargestContentfulPaintMainFrame[];
extern const char
kHistogramExperimentalLargestContentfulPaintMainFrameContentType[];
extern const char kHistogramParseDuration[];
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
index 2c928a3827e..158503cdb1f 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
@@ -43,14 +43,6 @@ class UmaPageLoadMetricsObserverTest
void SetUp() override {
page_load_metrics::PageLoadMetricsObserverContentTestHarness::SetUp();
page_load_metrics::LargestContentfulPaintHandler::SetTestMode(true);
-
- base::PowerMonitor::Initialize(
- std::make_unique<base::PowerMonitorTestSource>());
- }
-
- void TearDown() override {
- base::PowerMonitor::ShutdownForTesting();
- page_load_metrics::PageLoadMetricsObserverContentTestHarness::TearDown();
}
void OnCpuTimingUpdate(RenderFrameHost* render_frame_host,
@@ -71,11 +63,11 @@ class UmaPageLoadMetricsObserverTest
// Experimental values
tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramExperimentalLargestContentfulPaint, 0);
+ internal::kDeprecatedHistogramLargestContentfulPaint, 0);
tester()->histogram_tester().ExpectTotalCount(
internal::kHistogramExperimentalLargestContentfulPaintContentType, 0);
tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramExperimentalLargestContentfulPaintMainFrame, 0);
+ internal::kDeprecatedHistogramLargestContentfulPaintMainFrame, 0);
tester()->histogram_tester().ExpectTotalCount(
internal::
kHistogramExperimentalLargestContentfulPaintMainFrameContentType,
@@ -93,7 +85,7 @@ class UmaPageLoadMetricsObserverTest
// Experimental values
EXPECT_THAT(tester()->histogram_tester().GetAllSamples(
- internal::kHistogramExperimentalLargestContentfulPaint),
+ internal::kDeprecatedHistogramLargestContentfulPaint),
testing::ElementsAre(base::Bucket(value, 1)));
EXPECT_THAT(
tester()->histogram_tester().GetAllSamples(
@@ -115,7 +107,7 @@ class UmaPageLoadMetricsObserverTest
// Experimental values
EXPECT_THAT(
tester()->histogram_tester().GetAllSamples(
- internal::kHistogramExperimentalLargestContentfulPaintMainFrame),
+ internal::kDeprecatedHistogramLargestContentfulPaintMainFrame),
testing::ElementsAre(base::Bucket(value, 1)));
EXPECT_THAT(
tester()->histogram_tester().GetAllSamples(
@@ -143,7 +135,7 @@ class UmaPageLoadMetricsObserverTest
tester()
->histogram_tester()
.GetAllSamples(
- internal::kHistogramExperimentalLargestContentfulPaintMainFrame)
+ internal::kDeprecatedHistogramLargestContentfulPaintMainFrame)
.empty());
EXPECT_TRUE(
tester()
diff --git a/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
index 0a40945beb4..bfb9c40ea8b 100644
--- a/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
@@ -12,12 +12,12 @@ namespace {
void Record(const PageRenderData& data) {
if (data.all_layout_block_count > 0) {
- base::UmaHistogramPercentage(
+ base::UmaHistogramPercentageObsoleteDoNotUse(
"Blink.Layout.NGRatio.Blocks",
data.ng_layout_block_count * 100 / data.all_layout_block_count);
}
if (data.all_layout_call_count) {
- base::UmaHistogramPercentage(
+ base::UmaHistogramPercentageObsoleteDoNotUse(
"Blink.Layout.NGRatio.Calls",
data.ng_layout_call_count * 100 / data.all_layout_call_count);
}
diff --git a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.cc b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.cc
index 10459904e94..50a26f67fe8 100644
--- a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.cc
+++ b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.cc
@@ -7,7 +7,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/ukm/content/source_url_recorder.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
diff --git a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
index a7ead53e1d2..cf729f28fa2 100644
--- a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
+++ b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
@@ -23,6 +23,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
+#include "third_party/blink/public/mojom/mobile_metrics/mobile_friendliness.mojom.h"
#include "url/gurl.h"
namespace page_load_metrics {
@@ -112,7 +113,8 @@ void PageLoadMetricsObserverTester::SimulateTimingUpdate(
SimulatePageLoadTimingUpdate(
timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(),
mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
- mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh);
+ mojom::DeferredResourceCounts(), mojom::InputTiming(),
+ blink::MobileFriendliness(), rfh);
}
void PageLoadMetricsObserverTester::SimulateCpuTimingUpdate(
@@ -128,7 +130,8 @@ void PageLoadMetricsObserverTester::SimulateCpuTimingUpdate(
SimulatePageLoadTimingUpdate(
*timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(),
mojom::FrameRenderDataUpdate(), cpu_timing,
- mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh);
+ mojom::DeferredResourceCounts(), mojom::InputTiming(),
+ blink::MobileFriendliness(), rfh);
}
void PageLoadMetricsObserverTester::SimulateInputTimingUpdate(
@@ -144,7 +147,8 @@ void PageLoadMetricsObserverTester::SimulateInputTimingUpdate(
SimulatePageLoadTimingUpdate(
*timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(),
mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
- mojom::DeferredResourceCounts(), input_timing, rfh);
+ mojom::DeferredResourceCounts(), input_timing,
+ blink::MobileFriendliness(), rfh);
}
void PageLoadMetricsObserverTester::SimulateTimingAndMetadataUpdate(
@@ -154,7 +158,7 @@ void PageLoadMetricsObserverTester::SimulateTimingAndMetadataUpdate(
timing, metadata, mojom::PageLoadFeatures(),
mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
mojom::DeferredResourceCounts(), mojom::InputTiming(),
- web_contents()->GetMainFrame());
+ blink::MobileFriendliness(), web_contents()->GetMainFrame());
}
void PageLoadMetricsObserverTester::SimulateMetadataUpdate(
@@ -165,7 +169,8 @@ void PageLoadMetricsObserverTester::SimulateMetadataUpdate(
SimulatePageLoadTimingUpdate(
timing, metadata, mojom::PageLoadFeatures(),
mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
- mojom::DeferredResourceCounts(), mojom::InputTiming(), rfh);
+ mojom::DeferredResourceCounts(), mojom::InputTiming(),
+ blink::MobileFriendliness(), rfh);
}
void PageLoadMetricsObserverTester::SimulateFeaturesUpdate(
@@ -174,7 +179,7 @@ void PageLoadMetricsObserverTester::SimulateFeaturesUpdate(
mojom::PageLoadTiming(), mojom::FrameMetadata(), new_features,
mojom::FrameRenderDataUpdate(), mojom::CpuTiming(),
mojom::DeferredResourceCounts(), mojom::InputTiming(),
- web_contents()->GetMainFrame());
+ blink::MobileFriendliness(), web_contents()->GetMainFrame());
}
void PageLoadMetricsObserverTester::SimulateRenderDataUpdate(
@@ -190,7 +195,7 @@ void PageLoadMetricsObserverTester::SimulateRenderDataUpdate(
SimulatePageLoadTimingUpdate(
timing, mojom::FrameMetadata(), mojom::PageLoadFeatures(), render_data,
mojom::CpuTiming(), mojom::DeferredResourceCounts(), mojom::InputTiming(),
- rfh);
+ blink::MobileFriendliness(), rfh);
}
void PageLoadMetricsObserverTester::SimulatePageLoadTimingUpdate(
@@ -201,12 +206,13 @@ void PageLoadMetricsObserverTester::SimulatePageLoadTimingUpdate(
const mojom::CpuTiming& cpu_timing,
const mojom::DeferredResourceCounts& new_deferred_resource_data,
const mojom::InputTiming& input_timing,
+ const blink::MobileFriendliness& mobile_friendliness,
content::RenderFrameHost* rfh) {
metrics_web_contents_observer_->OnTimingUpdated(
rfh, timing.Clone(), metadata.Clone(), new_features.Clone(),
std::vector<mojom::ResourceDataUpdatePtr>(), render_data.Clone(),
cpu_timing.Clone(), new_deferred_resource_data.Clone(),
- input_timing.Clone());
+ input_timing.Clone(), mobile_friendliness);
// If sending the timing update caused the PageLoadMetricsUpdateDispatcher to
// schedule a buffering timer, then fire it now so metrics are dispatched to
// observers.
@@ -232,7 +238,7 @@ void PageLoadMetricsObserverTester::SimulateResourceDataUseUpdate(
mojom::FrameRenderDataUpdatePtr(base::in_place),
mojom::CpuTimingPtr(base::in_place),
mojom::DeferredResourceCountsPtr(base::in_place),
- mojom::InputTimingPtr(base::in_place));
+ mojom::InputTimingPtr(base::in_place), blink::MobileFriendliness());
}
void PageLoadMetricsObserverTester::SimulateLoadedResource(
@@ -306,6 +312,15 @@ void PageLoadMetricsObserverTester::SimulateStorageAccess(
url, first_party_url, blocked_by_policy, storage_type);
}
+void PageLoadMetricsObserverTester::SimulateMobileFriendlinessUpdate(
+ blink::MobileFriendliness& mobile_friendliness) {
+ SimulatePageLoadTimingUpdate(
+ mojom::PageLoadTiming(), mojom::FrameMetadata(),
+ mojom::PageLoadFeatures(), mojom::FrameRenderDataUpdate(),
+ mojom::CpuTiming(), mojom::DeferredResourceCounts(), mojom::InputTiming(),
+ mobile_friendliness, web_contents()->GetMainFrame());
+}
+
const PageLoadMetricsObserverDelegate&
PageLoadMetricsObserverTester::GetDelegateForCommittedLoad() const {
return metrics_web_contents_observer_->GetDelegateForCommittedLoad();
diff --git a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
index f97dfa2659f..5bde3dd8346 100644
--- a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
+++ b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.h
@@ -141,6 +141,9 @@ class PageLoadMetricsObserverTester : public test::WeakMockTimerProvider {
bool blocked_by_policy,
StorageType storage_type);
+ void SimulateMobileFriendlinessUpdate(
+ blink::MobileFriendliness& mobile_friendliness);
+
MetricsWebContentsObserver* metrics_web_contents_observer() {
return metrics_web_contents_observer_;
}
@@ -162,6 +165,7 @@ class PageLoadMetricsObserverTester : public test::WeakMockTimerProvider {
const mojom::CpuTiming& cpu_timing,
const mojom::DeferredResourceCounts& new_deferred_resource_data,
const mojom::InputTiming& input_timing,
+ const blink::MobileFriendliness& mobile_friendliness,
content::RenderFrameHost* rfh);
content::WebContents* web_contents() const { return web_contents_; }
diff --git a/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
new file mode 100644
index 00000000000..8b7c369607f
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
@@ -0,0 +1,48 @@
+// Copyright 2020 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/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h"
+
+#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
+#include "content/public/browser/web_contents.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h"
+
+void PrerenderPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
+ const page_load_metrics::mojom::PageLoadTiming& timing) {
+ did_fcp_ = true;
+}
+
+void PrerenderPageLoadMetricsObserver::OnStorageAccessed(
+ const GURL& url,
+ const GURL& first_party_url,
+ bool blocked_by_policy,
+ page_load_metrics::StorageType access_type) {
+ if (access_type != page_load_metrics::StorageType::kLocalStorage ||
+ did_local_storage_)
+ return;
+
+ // The purpose of this observer is to estimate how many prerendering pages
+ // will use certain features. The plan for prerendering is to delay loading
+ // of cross-origin iframes, so we want to ignore feature uses inside
+ // cross-origin iframes. To do this, just check if the |url| is cross-origin
+ // to |first_party_url|. This may not be an accurate count if a third-party
+ // subframe embeds a first-party subframe, or if there is a way for a frame
+ // to access cross-origin storage, but it's probably not significant.
+ if (!url::IsSameOriginWith(url, first_party_url))
+ return;
+
+ did_local_storage_ = true;
+ RecordFeatureUse(
+ did_fcp_ ? blink::mojom::WebFeature::kLocalStorageFirstUsedAfterFcp
+ : blink::mojom::WebFeature::kLocalStorageFirstUsedBeforeFcp);
+}
+
+void PrerenderPageLoadMetricsObserver::RecordFeatureUse(
+ blink::mojom::WebFeature feature) {
+ page_load_metrics::mojom::PageLoadFeatures page_load_features;
+ page_load_features.features.push_back(feature);
+
+ page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
+ GetDelegate().GetWebContents()->GetMainFrame(), page_load_features);
+}
diff --git a/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h
new file mode 100644
index 00000000000..ee6b0877adc
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h
@@ -0,0 +1,40 @@
+// Copyright 2020 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_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
+#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace blink {
+namespace mojom {
+enum class WebFeature : int32_t;
+} // namespace mojom
+} // namespace blink
+
+// Records metrics relevant to prerendering. Currently it logs feature usage in
+// normal page loads which, when if used during prerendering, may result in
+// cancelling or freezing the prerender, to help estimate the effect on
+// coverage.
+class PrerenderPageLoadMetricsObserver
+ : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+ PrerenderPageLoadMetricsObserver() = default;
+
+ // page_load_metrics::PageLoadMetricsObserver implementation:
+ void OnFirstContentfulPaintInPage(
+ const page_load_metrics::mojom::PageLoadTiming& timing) override;
+ void OnStorageAccessed(const GURL& url,
+ const GURL& first_party_url,
+ bool blocked_by_policy,
+ page_load_metrics::StorageType access_type) override;
+
+ private:
+ void RecordFeatureUse(blink::mojom::WebFeature feature);
+
+ bool did_fcp_ = false;
+ bool did_local_storage_ = false;
+};
+
+#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_PRERENDER_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer_unittest.cc b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer_unittest.cc
new file mode 100644
index 00000000000..ba6455cf4a7
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright 2020 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/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h"
+
+#include <memory>
+
+#include "components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.h"
+#include "components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h"
+#include "components/page_load_metrics/browser/page_load_tracker.h"
+#include "components/page_load_metrics/common/test/page_load_metrics_test_util.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
+
+namespace {
+
+const char kDefaultTestUrl[] = "https://a.test";
+const char kOtherOriginUrl[] = "https://b.test";
+const char kFeaturesHistogramName[] = "Blink.UseCounter.Features";
+
+class PrerenderPageLoadMetricsObserverTest
+ : public page_load_metrics::PageLoadMetricsObserverContentTestHarness {
+ protected:
+ void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
+ // PrerenderPageLoadMetricsObserver requires
+ // UseCounterPageLoadMetricsObserver to log UseCounter to UMA.
+ tracker->AddObserver(std::make_unique<UseCounterPageLoadMetricsObserver>());
+
+ tracker->AddObserver(std::make_unique<PrerenderPageLoadMetricsObserver>());
+ }
+
+ void SimulateFirstContentfulPaint() {
+ page_load_metrics::mojom::PageLoadTiming timing;
+ page_load_metrics::InitPageLoadTimingForTest(&timing);
+ timing.navigation_start = base::Time::Now();
+ timing.parse_timing->parse_stop = base::TimeDelta::FromMilliseconds(50);
+ timing.paint_timing->first_contentful_paint =
+ base::TimeDelta::FromMilliseconds(100);
+ PopulateRequiredTimingFields(&timing);
+ tester()->SimulateTimingUpdate(timing);
+ }
+
+ int GetPageVisits() {
+ return tester()->histogram_tester().GetBucketCount(
+ kFeaturesHistogramName, static_cast<base::Histogram::Sample>(
+ blink::mojom::WebFeature::kPageVisits));
+ }
+
+ int GetLocalStorageBeforeFcpCount() {
+ return tester()->histogram_tester().GetBucketCount(
+ kFeaturesHistogramName,
+ static_cast<base::Histogram::Sample>(
+ blink::mojom::WebFeature::kLocalStorageFirstUsedBeforeFcp));
+ }
+
+ int GetLocalStorageAfterFcpCount() {
+ return tester()->histogram_tester().GetBucketCount(
+ kFeaturesHistogramName,
+ static_cast<base::Histogram::Sample>(
+ blink::mojom::WebFeature::kLocalStorageFirstUsedAfterFcp));
+ }
+};
+
+TEST_F(PrerenderPageLoadMetricsObserverTest, NoLocalStorage) {
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ EXPECT_EQ(GetPageVisits(), 1);
+ EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
+ EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
+}
+
+TEST_F(PrerenderPageLoadMetricsObserverTest, LocalStorageBeforeFcp) {
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ // Access local storage.
+ tester()->SimulateStorageAccess(
+ GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
+ page_load_metrics::StorageType::kLocalStorage);
+
+ // Reach FCP.
+ SimulateFirstContentfulPaint();
+
+ // Access local storage again.
+ tester()->SimulateStorageAccess(
+ GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
+ page_load_metrics::StorageType::kLocalStorage);
+
+ EXPECT_EQ(GetPageVisits(), 1);
+ EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 1);
+ // The UMA counts the first use, so AfterFcp is 0.
+ EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
+}
+
+TEST_F(PrerenderPageLoadMetricsObserverTest, LocalStorageAfterFcp) {
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ // Reach FCP.
+ SimulateFirstContentfulPaint();
+
+ // Access local storage.
+ tester()->SimulateStorageAccess(
+ GURL(kDefaultTestUrl), GURL(kDefaultTestUrl), false,
+ page_load_metrics::StorageType::kLocalStorage);
+
+ EXPECT_EQ(GetPageVisits(), 1);
+ EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
+ EXPECT_EQ(GetLocalStorageAfterFcpCount(), 1);
+}
+
+TEST_F(PrerenderPageLoadMetricsObserverTest, ThirdPartyLocalStorage) {
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ tester()->SimulateStorageAccess(
+ GURL(kOtherOriginUrl), GURL(kDefaultTestUrl), false,
+ page_load_metrics::StorageType::kLocalStorage);
+
+ // Cross-origin local storage is not logged.
+ EXPECT_EQ(GetPageVisits(), 1);
+ EXPECT_EQ(GetLocalStorageBeforeFcpCount(), 0);
+ EXPECT_EQ(GetLocalStorageAfterFcpCount(), 0);
+}
+
+} // namespace
diff --git a/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
index 2ea57abe9d6..5b4c9091d6d 100644
--- a/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
+++ b/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -47,11 +47,8 @@ UseCounterPageLoadMetricsObserver::GetAllowedUkmFeatures() {
WebFeature::kPaymentHandler,
WebFeature::kPaymentRequestShowWithoutGesture,
WebFeature::kHTMLImports,
- WebFeature::kHTMLImportsOnReverseOriginTrials,
WebFeature::kElementCreateShadowRoot,
- WebFeature::kElementCreateShadowRootOnReverseOriginTrials,
WebFeature::kDocumentRegisterElement,
- WebFeature::kDocumentRegisterElementOnReverseOriginTrials,
WebFeature::kCredentialManagerCreatePublicKeyCredential,
WebFeature::kCredentialManagerGetPublicKeyCredential,
WebFeature::kCredentialManagerMakePublicKeyCredentialSuccess,
@@ -167,7 +164,6 @@ UseCounterPageLoadMetricsObserver::GetAllowedUkmFeatures() {
WebFeature::kSchemelesslySameSitePostMessage,
WebFeature::kSchemelesslySameSitePostMessageSecureToInsecure,
WebFeature::kSchemelesslySameSitePostMessageInsecureToSecure,
- WebFeature::kElementAttachInternalsBeforeConstructor,
WebFeature::kAddressSpaceLocalEmbeddedInPrivateSecureContext,
WebFeature::kAddressSpaceLocalEmbeddedInPrivateNonSecureContext,
WebFeature::kAddressSpaceLocalEmbeddedInPublicSecureContext,
@@ -178,7 +174,16 @@ UseCounterPageLoadMetricsObserver::GetAllowedUkmFeatures() {
WebFeature::kAddressSpacePrivateEmbeddedInPublicNonSecureContext,
WebFeature::kAddressSpacePrivateEmbeddedInUnknownSecureContext,
WebFeature::kAddressSpacePrivateEmbeddedInUnknownNonSecureContext,
+ WebFeature::kFileSystemPickerMethod,
+ WebFeature::kV8Window_ShowOpenFilePicker_Method,
+ WebFeature::kV8Window_ShowSaveFilePicker_Method,
+ WebFeature::kV8Window_ShowDirectoryPicker_Method,
+ WebFeature::kV8StorageManager_GetDirectory_Method,
+ WebFeature::kBarcodeDetectorDetect,
+ WebFeature::kFaceDetectorDetect,
+ WebFeature::kTextDetectorDetect,
WebFeature::kV8SharedArrayBufferConstructedWithoutIsolation,
+ WebFeature::kV8HTMLVideoElement_GetVideoPlaybackQuality_Method,
}));
return *opt_in_features;
}
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
index 4b1937578fb..c51ce24f4be 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
@@ -9,6 +9,7 @@
#include "components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.h"
+#include "components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/observers/use_counter_page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
@@ -28,6 +29,11 @@ void PageLoadMetricsEmbedderBase::RegisterObservers(PageLoadTracker* tracker) {
tracker->AddObserver(std::make_unique<UmaPageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<LayoutPageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<UseCounterPageLoadMetricsObserver>());
+
+ // So far, PrerenderPageLoadMetricsObserver is used to gather metrics from
+ // normal (non-prerendering) page loads, to estimate future coverage of
+ // prerendering, so it's in the !IsPrerendering() block.
+ tracker->AddObserver(std::make_unique<PrerenderPageLoadMetricsObserver>());
}
// Allow the embedder to register any embedder-specific observers
RegisterEmbedderObservers(tracker);
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
index df3bb304e6c..44fd749778f 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -94,15 +94,16 @@ struct UserInitiatedInfo {
// Information about how the page rendered during the browsing session.
// Derived from the FrameRenderDataUpdate that is sent via UpdateTiming IPC.
struct PageRenderData {
- PageRenderData()
- : layout_shift_score(0), layout_shift_score_before_input_or_scroll(0) {}
+ PageRenderData() = default;
// How much visible elements on the page shifted (bit.ly/lsm-explainer).
- float layout_shift_score;
+ float layout_shift_score = 0;
// How much visible elements on the page shifted (bit.ly/lsm-explainer),
- // before user input or document scroll.
- float layout_shift_score_before_input_or_scroll;
+ // before user input or document scroll. This field's meaning is context-
+ // dependent (see comments on page_render_data_ and main_frame_render_data_
+ // in PageLoadMetricsUpdateDispatcher).
+ float layout_shift_score_before_input_or_scroll = 0;
// How many LayoutBlock instances were created.
uint64_t all_layout_block_count = 0;
@@ -117,6 +118,32 @@ struct PageRenderData {
uint64_t ng_layout_call_count = 0;
};
+// Information related to layout shift normalization for different strategies.
+struct NormalizedCLSData {
+ NormalizedCLSData() = default;
+
+ // Maximum CLS of 300ms sliding windows.
+ double sliding_windows_duration300ms_max_cls = 0.0;
+
+ // Maximum CLS of 1000ms sliding windows.
+ double sliding_windows_duration1000ms_max_cls = 0.0;
+
+ // Maximum CLS of session windows. The gap between two consecutive shifts is
+ // not bigger than 1000ms and the maximum window size is 5000ms.
+ double session_windows_gap1000ms_max5000ms_max_cls = 0.0;
+
+ // Maximum CLS of session windows. The gap between two consecutive shifts is
+ // not bigger than 1000ms.
+ double session_windows_gap1000ms_maxMax_max_cls = 0.0;
+
+ // The average CLS of session windows. The gap between two consecutive shifts
+ // is not bigger than 5000ms.
+ double session_windows_gap5000ms_maxMax_average_cls = 0.0;
+
+ // If true, will not report the data in UKM.
+ bool data_tainted = false;
+};
+
// Container for various information about a completed request within a page
// load.
struct ExtraRequestCompleteInfo {
@@ -374,6 +401,13 @@ class PageLoadMetricsObserver {
const mojom::BackForwardCacheTiming& timing,
size_t index) {}
+ // This is called several times on requestAnimationFrame after the page is
+ // restored from the back-forward cache. The number of the calls is hard-
+ // coded as WebPerformance::
+ // kRequestAnimationFramesToRecordAfterBackForwardCacheRestore.
+ virtual void OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+ const mojom::BackForwardCacheTiming& timing) {}
+
// Unlike other paint callbacks, OnFirstMeaningfulPaintInMainFrameDocument is
// tracked per document, and is reported for the main frame document only.
virtual void OnFirstMeaningfulPaintInMainFrameDocument(
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h b/chromium/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
index 59b3598b803..88e0d1e8e38 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
@@ -17,6 +17,10 @@ namespace content {
class WebContents;
} // namespace content
+namespace blink {
+struct MobileFriendliness;
+} // namespace blink
+
namespace page_load_metrics {
namespace mojom {
@@ -25,6 +29,7 @@ class FrameMetadata;
struct UserInitiatedInfo;
struct PageRenderData;
+struct NormalizedCLSData;
// This class tracks global state for the page load that should be accessible
// from any PageLoadMetricsObserver.
@@ -117,8 +122,10 @@ class PageLoadMetricsObserverDelegate {
// such as subframe intersections is initialized to defaults.
virtual const mojom::FrameMetadata& GetSubframeMetadata() const = 0;
virtual const PageRenderData& GetPageRenderData() const = 0;
+ virtual const NormalizedCLSData& GetNormalizedCLSData() const = 0;
// InputTiming data accumulated across all frames.
virtual const mojom::InputTiming& GetPageInputTiming() const = 0;
+ virtual const blink::MobileFriendliness& GetMobileFriendliness() const = 0;
virtual const PageRenderData& GetMainFrameRenderData() const = 0;
virtual const ui::ScopedVisibilityTracker& GetVisibilityTracker() const = 0;
virtual const ResourceTracker& GetResourceTracker() const = 0;
@@ -127,7 +134,8 @@ class PageLoadMetricsObserverDelegate {
virtual const LargestContentfulPaintHandler&
GetLargestContentfulPaintHandler() const = 0;
// Returns a LargestContentfulPaintHandler for the experimental version of
- // LCP.
+ // LCP. Note that currently this 'experimental version' is the version that is
+ // being deprecated.
virtual const LargestContentfulPaintHandler&
GetExperimentalLargestContentfulPaintHandler() const = 0;
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index 0dac2b433b0..6bfde8ce0ac 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -40,6 +40,10 @@ void PageLoadMetricsTestWaiter::AddMainFrameIntersectionExpectation(
expected_main_frame_intersection_ = rect;
}
+void PageLoadMetricsTestWaiter::AddMainFrameIntersectionExpectation() {
+ expected_main_frame_intersection_update_ = true;
+}
+
void PageLoadMetricsTestWaiter::AddSubFrameExpectation(TimingField field) {
CHECK_NE(field, TimingField::kLoadTimingInfo)
<< "LOAD_TIMING_INFO should only be used as a page-level expectation";
@@ -200,6 +204,9 @@ void PageLoadMetricsTestWaiter::OnFrameIntersectionUpdate(
content::RenderFrameHost* rfh,
const page_load_metrics::mojom::FrameIntersectionUpdate&
frame_intersection_update) {
+ if (frame_intersection_update.main_frame_intersection_rect)
+ expected_main_frame_intersection_update_ = false;
+
if (expected_main_frame_intersection_ &&
expected_main_frame_intersection_ ==
frame_intersection_update.main_frame_intersection_rect) {
@@ -349,7 +356,8 @@ bool PageLoadMetricsTestWaiter::ExpectationsSatisfied() const {
SubframeNavigationExpectationsSatisfied() &&
SubframeDataExpectationsSatisfied() && expected_frame_sizes_.empty() &&
CpuTimeExpectationsSatisfied() &&
- !expected_main_frame_intersection_.has_value();
+ !expected_main_frame_intersection_.has_value() &&
+ !expected_main_frame_intersection_update_;
}
PageLoadMetricsTestWaiter::WaiterMetricsObserver::~WaiterMetricsObserver() =
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
index fd9dbfa35c0..bf2267b7f81 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
@@ -57,6 +57,10 @@ class PageLoadMetricsTestWaiter
// of |rect|. Subsequent calls overwrite unmet expectations.
void AddMainFrameIntersectionExpectation(const gfx::Rect& rect);
+ // Adds a main frame intersection expectation for any main frame
+ // intersection update for the page load.
+ void AddMainFrameIntersectionExpectation();
+
// Add a single WebFeature expectation.
void AddWebFeatureExpectation(blink::mojom::WebFeature web_feature);
@@ -266,6 +270,7 @@ class PageLoadMetricsTestWaiter
// Expectation for the main frame intersection. Has a value when
// an expectation has not been met.
base::Optional<gfx::Rect> expected_main_frame_intersection_;
+ bool expected_main_frame_intersection_update_ = false;
int current_complete_resources_ = 0;
int64_t current_network_bytes_ = 0;
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
index d530f2cd3d6..020ba1d0482 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h"
+#include "components/page_load_metrics/browser/layout_shift_normalization.h"
#include <ostream>
#include <utility>
@@ -340,10 +341,14 @@ class PageLoadTimingMerger {
navigation_start_offset,
new_paint_timing.first_contentful_paint);
if (is_main_frame) {
- // FMP and FCP++ are only tracked in the main frame.
+ // FMP is only tracked in the main frame.
target_paint_timing->first_meaningful_paint =
new_paint_timing.first_meaningful_paint;
+ // LCP and the first input/scroll timestamp are not merged by us; instead,
+ // PLMUD passes the per-frame data to its client (PageLoadTracker) via
+ // OnTimingChanged and OnSubFrameTimingChanged, and merged results are
+ // calculated and held by the LargestContentfulPaintHandler.
target_paint_timing->largest_contentful_paint =
new_paint_timing.largest_contentful_paint->Clone();
target_paint_timing->experimental_largest_contentful_paint =
@@ -435,7 +440,8 @@ PageLoadMetricsUpdateDispatcher::PageLoadMetricsUpdateDispatcher(
pending_merged_page_timing_(CreatePageLoadTiming()),
main_frame_metadata_(mojom::FrameMetadata::New()),
subframe_metadata_(mojom::FrameMetadata::New()),
- page_input_timing_(mojom::InputTiming()) {}
+ page_input_timing_(mojom::InputTiming()),
+ mobile_friendliness_(blink::MobileFriendliness()) {}
PageLoadMetricsUpdateDispatcher::~PageLoadMetricsUpdateDispatcher() {
ShutDown();
@@ -463,7 +469,8 @@ void PageLoadMetricsUpdateDispatcher::UpdateMetrics(
mojom::FrameRenderDataUpdatePtr render_data,
mojom::CpuTimingPtr new_cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta) {
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness) {
if (embedder_interface_->IsExtensionUrl(
render_frame_host->GetLastCommittedURL())) {
// Extensions can inject child frames into a page. We don't want to track
@@ -480,6 +487,8 @@ void PageLoadMetricsUpdateDispatcher::UpdateMetrics(
// Report new deferral info.
client_->OnNewDeferredResourceCounts(*new_deferred_resource_data);
+ UpdateHasSeenInputOrScroll(*new_timing);
+
bool is_main_frame = IsMainFrame(render_frame_host);
if (is_main_frame) {
UpdateMainFrameMetadata(render_frame_host, std::move(new_metadata));
@@ -490,6 +499,7 @@ void PageLoadMetricsUpdateDispatcher::UpdateMetrics(
UpdateSubFrameTiming(render_frame_host, std::move(new_timing));
}
UpdatePageInputTiming(*input_timing_delta);
+ UpdateMobileFriendliness(mobile_friendliness);
UpdatePageRenderData(*render_data);
if (!is_main_frame) {
// This path is just for the AMP metrics.
@@ -499,6 +509,20 @@ void PageLoadMetricsUpdateDispatcher::UpdateMetrics(
client_->UpdateFeaturesUsage(render_frame_host, *new_features);
}
+void PageLoadMetricsUpdateDispatcher::UpdateHasSeenInputOrScroll(
+ const mojom::PageLoadTiming& new_timing) {
+ const mojom::PaintTiming* paint_timing = new_timing.paint_timing.get();
+ if (!paint_timing)
+ return;
+
+ // NOTE: we cannot use the first input/scroll in current_merged_page_timing_,
+ // because PageLoadTimingMerger ignores this field. We could reach into the
+ // LargestContentfulPaintHandler, but it is simpler to just watch the
+ // per-frame timing updates and remember a boolean.
+ if (paint_timing->first_input_or_scroll_notified_timestamp.has_value())
+ has_seen_input_or_scroll_ = true;
+}
+
void PageLoadMetricsUpdateDispatcher::UpdateFeatures(
content::RenderFrameHost* render_frame_host,
const mojom::PageLoadFeatures& new_features) {
@@ -703,9 +727,26 @@ void PageLoadMetricsUpdateDispatcher::UpdatePageInputTiming(
input_timing_delta.total_adjusted_input_delay;
}
+void PageLoadMetricsUpdateDispatcher::UpdateMobileFriendliness(
+ const blink::MobileFriendliness& mobile_friendliness) {
+ mobile_friendliness_ = mobile_friendliness;
+}
+
void PageLoadMetricsUpdateDispatcher::UpdatePageRenderData(
const mojom::FrameRenderDataUpdate& render_data) {
page_render_data_.layout_shift_score += render_data.layout_shift_delta;
+ layout_shift_normalization_.AddNewLayoutShifts(
+ render_data.new_layout_shifts, base::TimeTicks::Now(),
+ page_render_data_.layout_shift_score);
+
+ // Stop accumulating page-wide layout_shift_score_before_input_or_scroll after
+ // input or scroll in any frame. Note that we can't unconditionally accumulate
+ // layout_shift_delta_before_input_or_scroll, because that field only reflects
+ // input/scroll in the same frame as the shift.
+ if (!has_seen_input_or_scroll_) {
+ page_render_data_.layout_shift_score_before_input_or_scroll +=
+ render_data.layout_shift_delta_before_input_or_scroll;
+ }
page_render_data_.all_layout_block_count +=
render_data.all_layout_block_count_delta;
@@ -720,6 +761,10 @@ void PageLoadMetricsUpdateDispatcher::UpdatePageRenderData(
void PageLoadMetricsUpdateDispatcher::UpdateMainFrameRenderData(
const mojom::FrameRenderDataUpdate& render_data) {
main_frame_render_data_.layout_shift_score += render_data.layout_shift_delta;
+
+ // Track main frame cumulative score up to the first input or scroll in the
+ // main frame. For this we do not care about inputs sent to subframes, so we
+ // should not check has_seen_input_or_scroll_ (but see crbug.com/1136207).
main_frame_render_data_.layout_shift_score_before_input_or_scroll +=
render_data.layout_shift_delta_before_input_or_scroll;
@@ -739,6 +784,14 @@ void PageLoadMetricsUpdateDispatcher::OnSubFrameRenderDataChanged(
client_->OnSubFrameRenderDataChanged(render_frame_host, render_data);
}
+void PageLoadMetricsUpdateDispatcher::FlushPendingTimingUpdates() {
+ // If there's a pending update, dispatch the update now.
+ if (timer_->IsRunning()) {
+ timer_->Stop();
+ DispatchTimingUpdates();
+ }
+}
+
void PageLoadMetricsUpdateDispatcher::MaybeDispatchTimingUpdates(
bool should_buffer_timing_update_callback) {
// If we merged a new timing value, then we should buffer updates for
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
index 6a157935e06..226e72503e6 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
@@ -11,8 +11,10 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "components/page_load_metrics/browser/layout_shift_normalization.h"
#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
+#include "third_party/blink/public/common/mobile_metrics/mobile_friendliness.h"
namespace content {
class NavigationHandle;
@@ -152,7 +154,8 @@ class PageLoadMetricsUpdateDispatcher {
mojom::FrameRenderDataUpdatePtr render_data,
mojom::CpuTimingPtr new_cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta);
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness);
void SetUpSharedMemoryForSmoothness(
content::RenderFrameHost* render_frame_host,
@@ -182,12 +185,21 @@ class PageLoadMetricsUpdateDispatcher {
return *(subframe_metadata_.get());
}
const PageRenderData& page_render_data() const { return page_render_data_; }
+ const NormalizedCLSData& normalized_cls_data() const {
+ return layout_shift_normalization_.normalized_cls_data();
+ }
const PageRenderData& main_frame_render_data() const {
return main_frame_render_data_;
}
const mojom::InputTiming& page_input_timing() const {
return page_input_timing_;
}
+ const blink::MobileFriendliness& mobile_friendliness() const {
+ return mobile_friendliness_;
+ }
+
+ // Ensures all pending updates will get dispatched.
+ void FlushPendingTimingUpdates();
private:
using FrameTreeNodeId = int;
@@ -209,6 +221,8 @@ class PageLoadMetricsUpdateDispatcher {
const mojom::FrameMetadataPtr& frame_metadata);
void UpdatePageRenderData(const mojom::FrameRenderDataUpdate& render_data);
+ void UpdateMobileFriendliness(
+ const blink::MobileFriendliness& mobile_friendliness);
void UpdateMainFrameRenderData(
const mojom::FrameRenderDataUpdate& render_data);
void OnSubFrameRenderDataChanged(
@@ -218,6 +232,8 @@ class PageLoadMetricsUpdateDispatcher {
void MaybeDispatchTimingUpdates(bool did_merge_new_timing_value);
void DispatchTimingUpdates();
+ void UpdateHasSeenInputOrScroll(const mojom::PageLoadTiming& new_timing);
+
// The client is guaranteed to outlive this object.
Client* const client_;
@@ -229,14 +245,15 @@ class PageLoadMetricsUpdateDispatcher {
// Time the navigation for this page load was initiated.
const base::TimeTicks navigation_start_;
- // PageLoadTiming for the currently tracked page. The fields in |paint_timing|
- // are merged across all frames in the document. All other fields are from the
- // main frame document. |current_merged_page_timing_| contains the most recent
- // valid page load timing data, while pending_merged_page_timing_ contains
- // pending updates received since |current_merged_page_timing_| was last
- // dispatched to the client. pending_merged_page_timing_ will be copied to
- // |current_merged_page_timing_| once it is valid, at the time the
- // Client::OnTimingChanged callback is invoked.
+ // PageLoadTiming for the currently tracked page. Some fields, such as FCP,
+ // are merged across all frames in the document, while other fields are from
+ // the main frame only (see PageLoadTimingMerger).
+ //
+ // |current_merged_page_timing_| contains the most recent valid timing data,
+ // while |pending_merged_page_timing_| contains pending updates received since
+ // |current_merged_page_timing_| was last dispatched to the client (see
+ // DispatchTimingUpdates, which invokes the Client::OnTimingChanged callback).
+ //
mojom::PageLoadTimingPtr current_merged_page_timing_;
mojom::PageLoadTimingPtr pending_merged_page_timing_;
@@ -248,6 +265,22 @@ class PageLoadMetricsUpdateDispatcher {
// InputTiming data accumulated across all frames.
mojom::InputTiming page_input_timing_;
+ // MobileFrienddliness data for current view.
+ blink::MobileFriendliness mobile_friendliness_;
+
+ // In general, page_render_data_ contains combined data across all frames on
+ // the page, while main_frame_render_data_ contains data specific to the main
+ // frame.
+ //
+ // The layout_shift_score_before_input_or_scroll field in page_render_data_
+ // represents CLS across all frames (with subframe weighting), measured until
+ // first input/scroll in any frame (including an OOPIF).
+ //
+ // The main frame layout_shift_score_before_input_or_scroll represents CLS
+ // occurring within the main frame, measured until the first input/scroll seen
+ // by the main frame (or an input sent to a same-site subframe, due to
+ // crbug.com/1136207).
+ //
PageRenderData page_render_data_;
PageRenderData main_frame_render_data_;
@@ -256,10 +289,18 @@ class PageLoadMetricsUpdateDispatcher {
std::map<FrameTreeNodeId, mojom::FrameIntersectionUpdate>
frame_intersection_updates_;
+ LayoutShiftNormalization layout_shift_normalization_;
+
// Navigation start offsets for the most recently committed document in each
// frame.
std::map<FrameTreeNodeId, base::TimeDelta> subframe_navigation_start_offset_;
+ // Whether we have seen an input or scroll event in any frame. This comes to
+ // us via PaintTimingDetector::OnInputOrScroll, which triggers on user scrolls
+ // and most input types (but not mousemove or pinch zoom). More comments in
+ // UpdateHasSeenInputOrScroll.
+ bool has_seen_input_or_scroll_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PageLoadMetricsUpdateDispatcher);
};
diff --git a/chromium/components/page_load_metrics/browser/page_load_tracker.cc b/chromium/components/page_load_metrics/browser/page_load_tracker.cc
index 9b699cb6acb..15de080eb83 100644
--- a/chromium/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_tracker.cc
@@ -141,6 +141,18 @@ void DispatchEventsAfterBackForwardCacheRestore(
i);
}
+ auto request_animation_frames =
+ new_timings[i]
+ ->request_animation_frames_after_back_forward_cache_restore;
+ if (request_animation_frames.size() == 3 &&
+ (i >= last_timings.size() ||
+ last_timings[i]
+ ->request_animation_frames_after_back_forward_cache_restore
+ .empty())) {
+ observer->OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+ *new_timings[i]);
+ }
+
auto first_input_delay =
new_timings[i]->first_input_delay_after_back_forward_cache_restore;
if (first_input_delay.has_value() &&
@@ -899,9 +911,17 @@ const PageRenderData& PageLoadTracker::GetPageRenderData() const {
return metrics_update_dispatcher_.page_render_data();
}
+const NormalizedCLSData& PageLoadTracker::GetNormalizedCLSData() const {
+ return metrics_update_dispatcher_.normalized_cls_data();
+}
+
const mojom::InputTiming& PageLoadTracker::GetPageInputTiming() const {
return metrics_update_dispatcher_.page_input_timing();
}
+const blink::MobileFriendliness& PageLoadTracker::GetMobileFriendliness()
+ const {
+ return metrics_update_dispatcher_.mobile_friendliness();
+}
const PageRenderData& PageLoadTracker::GetMainFrameRenderData() const {
return metrics_update_dispatcher_.main_frame_render_data();
diff --git a/chromium/components/page_load_metrics/browser/page_load_tracker.h b/chromium/components/page_load_metrics/browser/page_load_tracker.h
index 2d67878712e..86ddcb0a9ee 100644
--- a/chromium/components/page_load_metrics/browser/page_load_tracker.h
+++ b/chromium/components/page_load_metrics/browser/page_load_tracker.h
@@ -227,7 +227,9 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
const mojom::FrameMetadata& GetMainFrameMetadata() const override;
const mojom::FrameMetadata& GetSubframeMetadata() const override;
const PageRenderData& GetPageRenderData() const override;
+ const NormalizedCLSData& GetNormalizedCLSData() const override;
const mojom::InputTiming& GetPageInputTiming() const override;
+ const blink::MobileFriendliness& GetMobileFriendliness() const override;
const PageRenderData& GetMainFrameRenderData() const override;
const ui::ScopedVisibilityTracker& GetVisibilityTracker() const override;
const ResourceTracker& GetResourceTracker() const override;
@@ -385,7 +387,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
UserInitiatedInfo user_initiated_info,
base::TimeTicks timestamp,
bool is_certainly_browser_timestamp);
-
// If |final_navigation| is null, then this is an "unparented" abort chain,
// and represents a sequence of provisional aborts that never ends with a
// committed load.
@@ -446,6 +447,7 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
const bool started_in_foreground_;
mojom::PageLoadTimingPtr last_dispatched_merged_page_timing_;
+ blink::MobileFriendliness latest_mobile_friendliness_;
ui::PageTransition page_transition_;
diff --git a/chromium/components/page_load_metrics/common/BUILD.gn b/chromium/components/page_load_metrics/common/BUILD.gn
index 560557634ac..3067a47192d 100644
--- a/chromium/components/page_load_metrics/common/BUILD.gn
+++ b/chromium/components/page_load_metrics/common/BUILD.gn
@@ -45,6 +45,7 @@ mojom("page_load_metrics_mojom") {
sources = [ "page_load_metrics.mojom" ]
public_deps = [
"//mojo/public/mojom/base",
+ "//third_party/blink/public/mojom:mobile_metrics",
"//third_party/blink/public/mojom:web_feature_mojo_bindings",
"//ui/gfx/geometry/mojom",
"//url/mojom:url_mojom_origin",
diff --git a/chromium/components/page_load_metrics/common/page_load_metrics.mojom b/chromium/components/page_load_metrics/common/page_load_metrics.mojom
index ea16c735ec4..7b2a4b3d7ad 100644
--- a/chromium/components/page_load_metrics/common/page_load_metrics.mojom
+++ b/chromium/components/page_load_metrics/common/page_load_metrics.mojom
@@ -8,6 +8,8 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
import "mojo/public/mojom/base/shared_memory.mojom";
import "mojo/public/mojom/base/time.mojom";
import "third_party/blink/public/mojom/web_feature/web_feature.mojom";
+import
+ "third_party/blink/public/mojom/mobile_metrics/mobile_friendliness.mojom";
import "third_party/blink/public/mojom/use_counter/css_property_id.mojom";
import "url/mojom/origin.mojom";
@@ -21,14 +23,14 @@ struct DocumentTiming {
};
struct LargestContentfulPaintTiming {
- // Time when the page's largest image is painted. Removed images are excluded.
+ // Time when the page's largest image is painted.
mojo_base.mojom.TimeDelta? largest_image_paint;
// Size of the largest image of the largest image paint, by
// Size = Height * Width. Removed images are excluded.
uint64 largest_image_paint_size;
- // Time when the page's largest text is painted. Removed text is excluded.
+ // Time when the page's largest text is painted.
mojo_base.mojom.TimeDelta? largest_text_paint;
// Size of the largest text of the largest text paint, by
@@ -50,10 +52,10 @@ struct PaintTiming {
// (Experimental) Time when the page's primary content is painted.
mojo_base.mojom.TimeDelta? first_meaningful_paint;
- // Largest contentful paint, which excludes removed content.
+ // Largest contentful paint, which includes removed content.
LargestContentfulPaintTiming largest_contentful_paint;
- // (Experimental) largest contentful paint including removed content.
+ // (Experimental) largest contentful paint excluding removed content.
LargestContentfulPaintTiming experimental_largest_contentful_paint;
// (Experimental) Time when the frame is first eligible to be painted, i.e.
@@ -263,6 +265,12 @@ struct ResourceDataUpdate {
bool completed_before_fcp;
};
+// Timestamp and layout shift score of a layout shift.
+struct LayoutShift {
+ mojo_base.mojom.TimeTicks layout_shift_time;
+ double layout_shift_score;
+};
+
// Metrics about how a RenderFrame rendered since the last UpdateTiming call.
struct FrameRenderDataUpdate {
// How much visible elements in the frame shifted (https://bit.ly/3fQz29y) since
@@ -284,6 +292,9 @@ struct FrameRenderDataUpdate {
// How many times LayoutNG-based LayoutObject::UpdateLayout() is called.
uint32 ng_layout_call_count_delta;
+
+ // New layout shifts with timestamps.
+ array<LayoutShift> new_layout_shifts;
};
// Metrics about the time spent in tasks (cpu time) by a frame.
@@ -334,7 +345,8 @@ interface PageLoadMetrics {
FrameRenderDataUpdate render_data,
CpuTiming cpu_load_timing,
DeferredResourceCounts new_deferred_resource_data,
- InputTiming input_timing_delta);
+ InputTiming input_timing_delta,
+ blink.mojom.MobileFriendliness mobile_friendliness);
// Set up a shared memory used to transfer smoothness data from the renderer
// to the browser. The structure is defined in
@@ -350,6 +362,10 @@ struct BackForwardCacheTiming {
// is restored from the back-forward cache.
mojo_base.mojom.TimeDelta first_paint_after_back_forward_cache_restore;
+ // Times on requestAnimationFrame when the page is restored from the back-
+ // forward cache.
+ array<mojo_base.mojom.TimeDelta> request_animation_frames_after_back_forward_cache_restore;
+
// Queueing Time of the first click, tap, key press, cancellable touchstart,
// or pointer down followed by a pointer up after the time when the page is
// restored from the back-forward cache.
diff --git a/chromium/components/page_load_metrics/common/page_load_metrics_constants.h b/chromium/components/page_load_metrics/common/page_load_metrics_constants.h
index 3b44ddb1b28..221bc589c0c 100644
--- a/chromium/components/page_load_metrics/common/page_load_metrics_constants.h
+++ b/chromium/components/page_load_metrics/common/page_load_metrics_constants.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_METRICS_CONSTANTS_H_
#define COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_METRICS_CONSTANTS_H_
+#include "base/feature_list.h"
+
namespace page_load_metrics {
// Amount of time to delay dispatch of metrics. This allows us to batch and send
@@ -12,6 +14,9 @@ namespace page_load_metrics {
// expensive.
const int kBufferTimerDelayMillis = 1000;
+const base::Feature kPageLoadMetricsTimerDelayFeature{
+ "PageLoadMetricsTimerDelay", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace page_load_metrics
#endif // COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_METRICS_CONSTANTS_H_
diff --git a/chromium/components/page_load_metrics/renderer/OWNERS b/chromium/components/page_load_metrics/renderer/OWNERS
new file mode 100644
index 00000000000..d5fefd82012
--- /dev/null
+++ b/chromium/components/page_load_metrics/renderer/OWNERS
@@ -0,0 +1,2 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.cc b/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.cc
index 09e27c60cac..a68b1df5c37 100644
--- a/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.cc
+++ b/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.cc
@@ -23,10 +23,11 @@ void FakePageTimingSender::SendTiming(
const mojom::FrameRenderDataUpdate& render_data,
const mojom::CpuTimingPtr& cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- const mojom::InputTimingPtr new_input_timing) {
+ const mojom::InputTimingPtr new_input_timing,
+ const blink::MobileFriendliness& mobile_friendliness) {
validator_->UpdateTiming(timing, metadata, new_features, resources,
render_data, cpu_timing, new_deferred_resource_data,
- new_input_timing);
+ new_input_timing, mobile_friendliness);
}
void FakePageTimingSender::SetUpSmoothnessReporting(
@@ -83,6 +84,17 @@ void FakePageTimingSender::PageTimingValidator::VerifyExpectedInputTiming()
actual_input_timing->total_adjusted_input_delay);
}
+void FakePageTimingSender::PageTimingValidator::
+ UpdateExpectedMobileFriendliness(
+ const blink::MobileFriendliness& mobile_friendliness) {
+ expected_mobile_friendliness = mobile_friendliness;
+}
+
+void FakePageTimingSender::PageTimingValidator::
+ VerifyExpectedMobileFriendliness() const {
+ ASSERT_EQ(expected_mobile_friendliness, actual_mobile_friendliness);
+}
+
void FakePageTimingSender::PageTimingValidator::VerifyExpectedCpuTimings()
const {
ASSERT_EQ(actual_cpu_timings_.size(), expected_cpu_timings_.size());
@@ -142,7 +154,9 @@ void FakePageTimingSender::PageTimingValidator::VerifyExpectedCssProperties()
void FakePageTimingSender::PageTimingValidator::VerifyExpectedRenderData()
const {
- EXPECT_FLOAT_EQ(expected_render_data_.layout_shift_delta,
+ EXPECT_FLOAT_EQ(expected_render_data_.is_null()
+ ? 0.0
+ : expected_render_data_->layout_shift_delta,
actual_render_data_.layout_shift_delta);
}
@@ -163,7 +177,8 @@ void FakePageTimingSender::PageTimingValidator::UpdateTiming(
const mojom::FrameRenderDataUpdate& render_data,
const mojom::CpuTimingPtr& cpu_timing,
const mojom::DeferredResourceCountsPtr& new_deferred_resource_data,
- const mojom::InputTimingPtr& new_input_timing) {
+ const mojom::InputTimingPtr& new_input_timing,
+ const blink::MobileFriendliness& mobile_friendliness) {
actual_timings_.push_back(timing.Clone());
if (!cpu_timing->task_time.is_zero()) {
actual_cpu_timings_.push_back(cpu_timing.Clone());
@@ -187,6 +202,7 @@ void FakePageTimingSender::PageTimingValidator::UpdateTiming(
actual_input_timing->total_input_delay += new_input_timing->total_input_delay;
actual_input_timing->total_adjusted_input_delay +=
new_input_timing->total_adjusted_input_delay;
+ actual_mobile_friendliness = mobile_friendliness;
VerifyExpectedTimings();
VerifyExpectedCpuTimings();
@@ -194,6 +210,7 @@ void FakePageTimingSender::PageTimingValidator::UpdateTiming(
VerifyExpectedCssProperties();
VerifyExpectedRenderData();
VerifyExpectedFrameIntersectionUpdate();
+ VerifyExpectedMobileFriendliness();
}
} // namespace page_load_metrics
diff --git a/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.h b/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.h
index cb4f3687887..c5da58eff6a 100644
--- a/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.h
+++ b/chromium/components/page_load_metrics/renderer/fake_page_timing_sender.h
@@ -11,6 +11,7 @@
#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
#include "components/page_load_metrics/common/page_load_timing.h"
#include "components/page_load_metrics/renderer/page_timing_sender.h"
+#include "third_party/blink/public/mojom/mobile_metrics/mobile_friendliness.mojom.h"
namespace page_load_metrics {
@@ -57,6 +58,8 @@ class FakePageTimingSender : public PageTimingSender {
void VerifyExpectedInputTiming() const;
+ void VerifyExpectedMobileFriendliness() const;
+
// PageLoad features that are expected to be sent through SendTiming()
// should be passed via UpdateExpectedPageLoadFeatures.
void UpdateExpectPageLoadFeatures(const blink::mojom::WebFeature feature);
@@ -67,11 +70,14 @@ class FakePageTimingSender : public PageTimingSender {
void UpdateExpectFrameRenderDataUpdate(
const mojom::FrameRenderDataUpdate& render_data) {
- expected_render_data_ = render_data;
+ expected_render_data_ = render_data.Clone();
}
void UpdateExpectedInputTiming(const base::TimeDelta input_delay);
+ void UpdateExpectedMobileFriendliness(
+ const blink::MobileFriendliness& mobile_friendliness);
+
void UpdateExpectFrameIntersectionUpdate(
const mojom::FrameIntersectionUpdate& frame_intersection_update) {
expected_frame_intersection_update_ = frame_intersection_update.Clone();
@@ -101,7 +107,8 @@ class FakePageTimingSender : public PageTimingSender {
const mojom::FrameRenderDataUpdate& render_data,
const mojom::CpuTimingPtr& cpu_timing,
const mojom::DeferredResourceCountsPtr& new_deferred_resource_data,
- const mojom::InputTimingPtr& input_timing);
+ const mojom::InputTimingPtr& input_timing,
+ const blink::MobileFriendliness& mobile_friendliness);
private:
std::vector<mojom::PageLoadTimingPtr> expected_timings_;
@@ -112,25 +119,30 @@ class FakePageTimingSender : public PageTimingSender {
std::set<blink::mojom::WebFeature> actual_features_;
std::set<blink::mojom::CSSSampleId> expected_css_properties_;
std::set<blink::mojom::CSSSampleId> actual_css_properties_;
- mojom::FrameRenderDataUpdate expected_render_data_;
+ mojom::FrameRenderDataUpdatePtr expected_render_data_;
mojom::FrameRenderDataUpdate actual_render_data_;
mojom::FrameIntersectionUpdatePtr expected_frame_intersection_update_;
mojom::FrameIntersectionUpdatePtr actual_frame_intersection_update_;
mojom::InputTimingPtr expected_input_timing;
mojom::InputTimingPtr actual_input_timing;
+ blink::MobileFriendliness expected_mobile_friendliness;
+ blink::MobileFriendliness actual_mobile_friendliness;
DISALLOW_COPY_AND_ASSIGN(PageTimingValidator);
};
explicit FakePageTimingSender(PageTimingValidator* validator);
~FakePageTimingSender() override;
- void SendTiming(const mojom::PageLoadTimingPtr& timing,
- const mojom::FrameMetadataPtr& metadata,
- mojom::PageLoadFeaturesPtr new_features,
- std::vector<mojom::ResourceDataUpdatePtr> resources,
- const mojom::FrameRenderDataUpdate& render_data,
- const mojom::CpuTimingPtr& cpu_timing,
- mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr new_input_timing) override;
+ void SendTiming(
+ const mojom::PageLoadTimingPtr& timing,
+ const mojom::FrameMetadataPtr& metadata,
+ mojom::PageLoadFeaturesPtr new_features,
+ std::vector<mojom::ResourceDataUpdatePtr> resources,
+ const mojom::FrameRenderDataUpdate& render_data,
+ const mojom::CpuTimingPtr& cpu_timing,
+ mojom::DeferredResourceCountsPtr new_deferred_resource_data,
+ mojom::InputTimingPtr new_input_timing,
+ const blink::MobileFriendliness& mobile_friendliness) override;
+
void SetUpSmoothnessReporting(
base::ReadOnlySharedMemoryRegion shared_memory) override;
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
index 7a2faa6efde..76408957736 100644
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -16,6 +16,7 @@
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/common/mobile_metrics/mobile_friendliness.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_document_loader.h"
@@ -49,20 +50,23 @@ class MojoPageTimingSender : public PageTimingSender {
~MojoPageTimingSender() override = default;
- void SendTiming(const mojom::PageLoadTimingPtr& timing,
- const mojom::FrameMetadataPtr& metadata,
- mojom::PageLoadFeaturesPtr new_features,
- std::vector<mojom::ResourceDataUpdatePtr> resources,
- const mojom::FrameRenderDataUpdate& render_data,
- const mojom::CpuTimingPtr& cpu_timing,
- mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta) override {
+ void SendTiming(
+ const mojom::PageLoadTimingPtr& timing,
+ const mojom::FrameMetadataPtr& metadata,
+ mojom::PageLoadFeaturesPtr new_features,
+ std::vector<mojom::ResourceDataUpdatePtr> resources,
+ const mojom::FrameRenderDataUpdate& render_data,
+ const mojom::CpuTimingPtr& cpu_timing,
+ mojom::DeferredResourceCountsPtr new_deferred_resource_data,
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness) override {
DCHECK(page_load_metrics_);
page_load_metrics_->UpdateTiming(
limited_sending_mode_ ? CreatePageLoadTiming() : timing->Clone(),
metadata->Clone(), std::move(new_features), std::move(resources),
render_data.Clone(), cpu_timing->Clone(),
- std::move(new_deferred_resource_data), std::move(input_timing_delta));
+ std::move(new_deferred_resource_data), std::move(input_timing_delta),
+ std::move(mobile_friendliness));
}
void SetUpSmoothnessReporting(
@@ -89,8 +93,7 @@ class MojoPageTimingSender : public PageTimingSender {
MetricsRenderFrameObserver::MetricsRenderFrameObserver(
content::RenderFrame* render_frame)
- : content::RenderFrameObserver(render_frame),
- scoped_ad_resource_observer_(this) {}
+ : content::RenderFrameObserver(render_frame) {}
MetricsRenderFrameObserver::~MetricsRenderFrameObserver() {
if (page_timing_metrics_sender_)
@@ -247,6 +250,30 @@ void MetricsRenderFrameObserver::WillDetach() {
}
}
+void MetricsRenderFrameObserver::DidStartNavigation(
+ const GURL& url,
+ base::Optional<blink::WebNavigationType> navigation_type) {
+ // Send current metrics, as we might create a new RenderFrame later due to
+ // this navigation (that might end up in a different process entirely, and
+ // won't notify us until the current RenderFrameHost in the browser changed).
+ // If that happens, it will be too late to send the metrics from WillDetach
+ // or the destructor, because the browser ignores metrics update from
+ // non-current RenderFrameHosts. See crbug.com/1150242 for more details.
+ // TODO(crbug.com/1150242): Remove this when we have the full fix for the bug.
+ if (page_timing_metrics_sender_)
+ page_timing_metrics_sender_->SendLatest();
+}
+
+void MetricsRenderFrameObserver::DidSetPageLifecycleState() {
+ // Send current metrics, as this RenderFrame might be replaced by a new
+ // RenderFrame or its process might be killed, and this might be the last
+ // point we can send the metrics to the browser. See crbug.com/1150242 for
+ // more details.
+ // TODO(crbug.com/1150242): Remove this when we have the full fix for the bug.
+ if (page_timing_metrics_sender_)
+ page_timing_metrics_sender_->SendLatest();
+}
+
void MetricsRenderFrameObserver::ReadyToCommitNavigation(
blink::WebDocumentLoader* document_loader) {
// Create a new data use tracker for the new document load.
@@ -341,12 +368,13 @@ void MetricsRenderFrameObserver::DidCommitProvisionalLoad(
void MetricsRenderFrameObserver::SetAdResourceTracker(
subresource_filter::AdResourceTracker* ad_resource_tracker) {
// Remove all sources and set a new source for the observer.
- scoped_ad_resource_observer_.RemoveAll();
- scoped_ad_resource_observer_.Add(ad_resource_tracker);
+ if (scoped_ad_resource_observation_.IsObserving())
+ scoped_ad_resource_observation_.RemoveObservation();
+ scoped_ad_resource_observation_.Observe(ad_resource_tracker);
}
void MetricsRenderFrameObserver::OnAdResourceTrackerGoingAway() {
- scoped_ad_resource_observer_.RemoveAll();
+ scoped_ad_resource_observation_.RemoveObservation();
}
void MetricsRenderFrameObserver::OnAdResourceObserved(int request_id) {
@@ -360,6 +388,12 @@ void MetricsRenderFrameObserver::OnMainFrameIntersectionChanged(
main_frame_intersection);
}
+void MetricsRenderFrameObserver::OnMobileFriendlinessChanged(
+ const blink::MobileFriendliness& mf) {
+ if (page_timing_metrics_sender_)
+ page_timing_metrics_sender_->DidObserveMobileFriendlinessChanged(mf);
+}
+
bool MetricsRenderFrameObserver::SetUpSmoothnessReporting(
base::ReadOnlySharedMemoryRegion& shared_memory) {
if (page_timing_metrics_sender_) {
@@ -518,6 +552,13 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming()
->first_paint_after_back_forward_cache_restore =
ClampDelta(first_paint, navigation_start);
}
+ for (double raf : restore_timing.request_animation_frames) {
+ if (!raf)
+ break;
+ back_forward_cache_timing
+ ->request_animation_frames_after_back_forward_cache_restore
+ .push_back(ClampDelta(raf, navigation_start));
+ }
if (first_input_delay.has_value()) {
back_forward_cache_timing
->first_input_delay_after_back_forward_cache_restore =
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
index 4901d4d6aa3..0e042fd82d6 100644
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
+++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
@@ -9,7 +9,7 @@
#include <set>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/page_load_metrics/common/page_load_timing.h"
#include "components/page_load_metrics/renderer/page_resource_data_use.h"
#include "components/page_load_metrics/renderer/page_timing_metadata_recorder.h"
@@ -74,6 +74,11 @@ class MetricsRenderFrameObserver
int64_t encoded_body_length,
const std::string& mime_type,
bool from_archive) override;
+ void DidStartNavigation(
+ const GURL& url,
+ base::Optional<blink::WebNavigationType> navigation_type) override;
+ void DidSetPageLifecycleState() override;
+
void ReadyToCommitNavigation(
blink::WebDocumentLoader* document_loader) override;
void DidFailProvisionalLoad() override;
@@ -95,6 +100,7 @@ class MetricsRenderFrameObserver
void OnMainFrameIntersectionChanged(
const blink::WebRect& main_frame_intersection) override;
+ void OnMobileFriendlinessChanged(const blink::MobileFriendliness&) override;
bool SetUpSmoothnessReporting(
base::ReadOnlySharedMemoryRegion& shared_memory) override;
@@ -145,9 +151,9 @@ class MetricsRenderFrameObserver
std::unique_ptr<PageResourceDataUse> provisional_frame_resource_data_use_;
int provisional_frame_resource_id_ = 0;
- ScopedObserver<subresource_filter::AdResourceTracker,
- subresource_filter::AdResourceTracker::Observer>
- scoped_ad_resource_observer_;
+ base::ScopedObservation<subresource_filter::AdResourceTracker,
+ subresource_filter::AdResourceTracker::Observer>
+ scoped_ad_resource_observation_{this};
// Set containing all request ids that were reported as ads from the renderer.
std::set<int> ad_request_ids_;
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index dc6a862b8b4..5cfde8f66c3 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -13,6 +13,7 @@
#include "base/stl_util.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
#include "components/page_load_metrics/common/page_load_metrics_constants.h"
#include "components/page_load_metrics/renderer/page_timing_sender.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
@@ -21,11 +22,13 @@
namespace page_load_metrics {
+const base::Feature kLayoutShiftNormalizationEmitShiftsForKeyMetrics{
+ "LayoutShiftNormalizationEmitShiftsForKeyMetrics",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
namespace {
const int kInitialTimerDelayMillis = 50;
const int64_t kInputDelayAdjustmentMillis = int64_t(50);
-const base::Feature kPageLoadMetricsTimerDelayFeature{
- "PageLoadMetricsTimerDelay", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace
PageTimingMetricsSender::PageTimingMetricsSender(
@@ -103,6 +106,11 @@ void PageTimingMetricsSender::DidObserveLayoutShift(
bool after_input_or_scroll) {
DCHECK(score > 0);
render_data_.layout_shift_delta += score;
+ if (base::FeatureList::IsEnabled(
+ kLayoutShiftNormalizationEmitShiftsForKeyMetrics)) {
+ render_data_.new_layout_shifts.push_back(
+ mojom::LayoutShift::New(base::TimeTicks::Now(), score));
+ }
if (!after_input_or_scroll)
render_data_.layout_shift_delta_before_input_or_scroll += score;
EnsureSendTimer();
@@ -137,6 +145,12 @@ void PageTimingMetricsSender::DidObserveLazyLoadBehavior(
}
}
+void PageTimingMetricsSender::DidObserveMobileFriendlinessChanged(
+ const blink::MobileFriendliness& mf) {
+ mobile_friendliness_ = mf;
+ EnsureSendTimer();
+}
+
void PageTimingMetricsSender::DidStartResponse(
const GURL& response_url,
int resource_id,
@@ -307,16 +321,18 @@ void PageTimingMetricsSender::SendNow() {
}
}
- sender_->SendTiming(last_timing_, metadata_, std::move(new_features_),
- std::move(resources), render_data_, last_cpu_timing_,
- std::move(new_deferred_resource_data_),
- std::move(input_timing_delta_));
+ sender_->SendTiming(
+ last_timing_, metadata_, std::move(new_features_), std::move(resources),
+ render_data_, last_cpu_timing_, std::move(new_deferred_resource_data_),
+ std::move(input_timing_delta_), std::move(mobile_friendliness_));
+ mobile_friendliness_ = blink::MobileFriendliness();
input_timing_delta_ = mojom::InputTiming::New();
new_deferred_resource_data_ = mojom::DeferredResourceCounts::New();
new_features_ = mojom::PageLoadFeatures::New();
metadata_->intersection_update.reset();
last_cpu_timing_->task_time = base::TimeDelta();
modified_resources_.clear();
+ render_data_.new_layout_shifts.clear();
render_data_.layout_shift_delta = 0;
render_data_.layout_shift_delta_before_input_or_scroll = 0;
render_data_.all_layout_block_count_delta = 0;
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
index 80c438fd9b6..fd673db5601 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -59,6 +59,7 @@ class PageTimingMetricsSender {
uint32_t ng_call_count);
void DidObserveLazyLoadBehavior(
blink::WebLocalFrameClient::LazyLoadBehavior lazy_load_behavior);
+ void DidObserveMobileFriendlinessChanged(const blink::MobileFriendliness&);
void DidStartResponse(const GURL& response_url,
int resource_id,
@@ -106,6 +107,7 @@ class PageTimingMetricsSender {
mojom::PageLoadTimingPtr last_timing_;
mojom::CpuTimingPtr last_cpu_timing_;
mojom::InputTimingPtr input_timing_delta_;
+ blink::MobileFriendliness mobile_friendliness_;
// The the sender keep track of metadata as it comes in, because the sender is
// scoped to a single committed load.
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
index e71159411cc..475adbea07e 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -161,6 +161,26 @@ TEST_F(PageTimingMetricsSenderTest, SendInputEvents) {
validator_.VerifyExpectedInputTiming();
}
+TEST_F(PageTimingMetricsSenderTest, SendMobileFriendlinessEvents) {
+ mojom::PageLoadTiming timing;
+ blink::MobileFriendliness mobile_friendliness;
+ mobile_friendliness.viewport_hardcoded_width = 480;
+ mobile_friendliness.allow_user_zoom = true;
+ InitPageLoadTimingForTest(&timing);
+ metrics_sender_->Update(timing.Clone(),
+ PageTimingMetadataRecorder::MonotonicTiming());
+ validator_.ExpectPageLoadTiming(timing);
+
+ metrics_sender_->DidObserveMobileFriendlinessChanged(mobile_friendliness);
+
+ blink::MobileFriendliness expected_mf;
+ expected_mf.viewport_hardcoded_width = 480;
+ expected_mf.allow_user_zoom = true;
+ validator_.UpdateExpectedMobileFriendliness(expected_mf);
+ metrics_sender_->mock_timer()->Fire();
+ validator_.VerifyExpectedMobileFriendliness();
+}
+
TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) {
mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing);
@@ -405,7 +425,7 @@ TEST_F(PageTimingMetricsSenderTest, SendPageRenderData) {
metrics_sender_->DidObserveLayoutNg(2, 0, 7, 5);
metrics_sender_->DidObserveLayoutShift(0.5, true);
- mojom::FrameRenderDataUpdate render_data(1.5, 1.0, 5, 2, 17, 9);
+ mojom::FrameRenderDataUpdate render_data(1.5, 1.0, 5, 2, 17, 9, {});
validator_.UpdateExpectFrameRenderDataUpdate(render_data);
metrics_sender_->mock_timer()->Fire();
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_sender.h b/chromium/components/page_load_metrics/renderer/page_timing_sender.h
index 9507e467ba0..ca7cfa29cdb 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_sender.h
+++ b/chromium/components/page_load_metrics/renderer/page_timing_sender.h
@@ -22,7 +22,8 @@ class PageTimingSender {
const mojom::FrameRenderDataUpdate& render_data,
const mojom::CpuTimingPtr& cpu_timing,
mojom::DeferredResourceCountsPtr new_deferred_resource_data,
- mojom::InputTimingPtr input_timing_delta) = 0;
+ mojom::InputTimingPtr input_timing_delta,
+ const blink::MobileFriendliness& mobile_friendliness) = 0;
virtual void SetUpSmoothnessReporting(
base::ReadOnlySharedMemoryRegion shared_memory) = 0;
};
diff --git a/chromium/components/paint_preview/README.md b/chromium/components/paint_preview/README.md
index 3215801c4b9..86de0f4eef5 100644
--- a/chromium/components/paint_preview/README.md
+++ b/chromium/components/paint_preview/README.md
@@ -2,11 +2,108 @@
_AKA Freeze Dried Tabs_
-This is a WIP directory that contains code for generating and processing paint
-previews of pages. A paint preview is a collection of Skia Pictures representing
-the visual contents of a page along with the links on the page. The preview can
-be composited and played without a renderer process as a low-fidelity and
-low-cost alternative to a tab in various contexts.
+## What is a Paint Preview?
+
+A paint preview is a collection of Skia Pictures representing the visual
+contents of a webpage along with the links on the webpage stored in a protobuf.
+The preview can be composited and played without a renderer process as a
+low-fidelity and low-overhead alternative to a live page in various contexts.
+
+## Architecture
+
+There are three core components to the paint preview architecture;
+
+* Capture - recording the content and links of a website as Skia Pictures +
+ metadata.
+* Compositing - converting Skia Pictures into bitmap tiles.
+* Player - plays back contents using native UI.
+
+### Capture
+
+A paint preview is captured using a variation of the printing system in Blink.
+The contents of the frame are captured as is. Images are not manipulated, but
+fonts are subset to remove unused glyphs.
+
+Capture supports both in-memory and file based approaches. While
+performance-wise the in-memory approach should be used, on low-end devices the
+memory overhead of capturing a webpage might be very expensive (100 MB+). To
+circumvent this and avoid OOM scenarios, files may be used to store the Skia
+Pictures.
+
+To handle child frames (iframes), the renderer will request the browser
+coordinate with the renderer of each child frame to capture it as an independent
+Skia Picture. To stitch this together later, the parent frame inserts a
+placeholder into its Skia Picture with the clip region of the child frame and an
+ID mapping so that the child content can be inserted correctly during
+compositing.
+
+The child frame behavior applies to both same- and cross-process iframes so that
+the content of each frame can be captured in its entirety. This allows them to
+be scrollable for the purposes of playback. _Note: this only applies to
+same-process iframes when they are scrollable._
+
+As a side-effect of using the printing system there may be some visual
+discrepencies;
+
+* Viewport fixed elements are flattened into their current position in the
+ content.
+* JS driven dynamic elements will be frozen.
+* Some GPU accelerated effect/animations may not be captured.
+* Out-of-viewport content for which resource aren't loaded (e.g. images) may be
+ missing.
+
+### Compositing
+
+To maintain the [Rule Of 2](https://chromium.googlesource.com/chromium/src/+/master/docs/security/rule-of-2.md)
+compositing takes place in a sandboxed utility process. The Skia Pictures are
+loaded into the compositor and from those pictures bitmaps can be generated. A
+caller may elect to request the contents of the frame be turned into a single
+combined Skia Picture or as a collection of independent Skia Pictures. The
+split approach is desirable if scrollable child frames are used.
+
+See `//components/services/paint_preview_compositor/` for more details.
+
+### Playback
+
+Per-architecture playback is possible to avoid the need for a renderer. Using
+the bitmaps from the compoisitor in combination with links it is possible to
+create a low-fidelity and lightweight representation of a webpage.
+
+At present there is only a player available for Android. If something akin to a
+screenshot of the whole webpage is desired it is possible to just use bitmaps
+for it.
+
+## Usage
+
+Capture step is intended to be completed via
+[PaintPreviewBaseService::CapturePaintPreview()](https://source.chromium.org/chromium/chromium/src/+/master:components/paint_preview/browser/paint_preview_base_service.h;bpv=1;bpt=1;l=127)
+, although
+[PaintPreviewClient](https://source.chromium.org/chromium/chromium/src/+/master:components/paint_preview/browser/paint_preview_client.h;bpv=1;bpt=1;l=36)
+can be used directly if preferred.
+
+Compositing should be started using [StartCompositorService()](https://source.chromium.org/chromium/chromium/src/+/master:components/paint_preview/browser/compositor_utils.h;bpv=1;bpt=1;l=16).
+This should be followed by using the PaintPreviewCompositorService to create a
+[PaintPreviewCompositorClient](https://source.chromium.org/chromium/chromium/src/+/master:components/paint_preview/public/paint_preview_compositor_client.h;bpv=1;bpt=1;l=24)
+from which compositing can be controlled.
+
+See the `player/` subdirectory for more details on playback.
+
+## Codebase
+
+Within this directory
+
+* `browser/` - Code related to managing and requesting paint previews.
+* `common/` - Shared code; mojo, protos, and C++ code.
+* `features/` - Feature flags.
+* `player/` - Code for playing back a preview. (Currently for Android).
+* `public/` - Public interfaces for some implementations (refactoring WIP).
+* `renderer/` - Code related to capturing paint previews within the renderer.
+
+Outside of this directory there is some feature code in
+
+* `chrome/android/java/src/org/chromium/chrome/browser/paint_preview/`
+* `chrome/browser/paint_preview/`
+* `components/services/paint_preview_compositor/`
## Why //components?
@@ -21,9 +118,3 @@ directory. Parts of the code are consumed in;
NOTE: This feature depends on working with `//content` and `//third_party/blink`
so it is incompatible with iOS.
-
-## Directory Structure (WIP)
-
-* `browser/` - Code related to managing and requesting paint previews.
-* `common/` - Shared code; mojo, protos, and C++ code.
-* `renderer/` - Code related to capturing paint previews within the renderer.
diff --git a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
index 50fa0b72cba..d8d75868eea 100644
--- a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/strings/strcat.h"
+#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/paint_preview/browser/paint_preview_base_service_test_factory.h"
#include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h"
diff --git a/chromium/components/paint_preview/browser/paint_preview_client.cc b/chromium/components/paint_preview/browser/paint_preview_client.cc
index e80c6300985..1b055c56eb0 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_client.cc
@@ -423,6 +423,7 @@ void PaintPreviewClient::RequestCaptureOnUIThread(
mojom::PaintPreviewStatus status,
mojom::PaintPreviewCaptureParamsPtr capture_params) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
auto it = all_document_data_.find(params.document_guid);
if (it == all_document_data_.end())
return;
@@ -438,8 +439,10 @@ void PaintPreviewClient::RequestCaptureOnUIThread(
// If the render frame host navigated or is no longer around treat this as a
// failure as a navigation occurring during capture is bad.
auto* render_frame_host = content::RenderFrameHost::FromID(render_frame_id);
- if (!render_frame_host || render_frame_host->GetEmbeddingToken().value_or(
- base::UnguessableToken::Null()) != frame_guid) {
+ if (!render_frame_host ||
+ render_frame_host->GetEmbeddingToken().value_or(
+ base::UnguessableToken::Null()) != frame_guid ||
+ !capture_params) {
std::move(document_data->callback)
.Run(params.document_guid, mojom::PaintPreviewStatus::kCaptureFailed,
{});
@@ -462,6 +465,11 @@ void PaintPreviewClient::RequestCaptureOnUIThread(
render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
&interface_ptrs_[frame_guid]);
}
+
+ // For the main frame, apply a clip rect if one is provided.
+ if (params.is_main_frame)
+ capture_params->clip_rect_is_hint = false;
+
interface_ptrs_[frame_guid]->CapturePaintPreview(
std::move(capture_params),
base::BindOnce(&PaintPreviewClient::OnPaintPreviewCapturedCallback,
@@ -547,16 +555,18 @@ void PaintPreviewClient::OnFinished(
// At a minimum one frame was captured successfully, it is up to the
// caller to decide if a partial success is acceptable based on what is
// contained in the proto.
- std::move(document_data->callback)
- .Run(guid,
- document_data->had_error
- ? mojom::PaintPreviewStatus::kPartialSuccess
- : mojom::PaintPreviewStatus::kOk,
- std::move(*document_data).IntoCaptureResult());
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(document_data->callback), guid,
+ document_data->had_error
+ ? mojom::PaintPreviewStatus::kPartialSuccess
+ : mojom::PaintPreviewStatus::kOk,
+ std::move(*document_data).IntoCaptureResult()));
} else {
// A proto could not be created indicating all frames failed to capture.
- std::move(document_data->callback)
- .Run(guid, mojom::PaintPreviewStatus::kFailed, {});
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(document_data->callback), guid,
+ mojom::PaintPreviewStatus::kFailed, nullptr));
}
all_document_data_.erase(guid);
}
diff --git a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
index 32c6304f864..838d159f921 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
@@ -77,6 +77,9 @@ class MockPaintPreviewRecorder : public mojom::PaintPreviewRecorder {
EXPECT_EQ(input_params->guid, expected_params_->guid);
EXPECT_EQ(input_params->clip_rect, expected_params_->clip_rect);
EXPECT_EQ(input_params->is_main_frame, expected_params_->is_main_frame);
+ if (expected_params_->is_main_frame) {
+ EXPECT_FALSE(input_params->clip_rect_is_hint);
+ }
}
base::OnceClosure closure_;
diff --git a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
index 98d581f8a23..51e1ecdb3ac 100644
--- a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
@@ -100,13 +100,25 @@ void PaintPreviewCompositorClientImpl::BitmapForSeparatedFrame(
float scale_factor,
mojom::PaintPreviewCompositor::BitmapForSeparatedFrameCallback callback) {
DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
+
+ auto validate_bitmap = base::BindOnce(
+ [](mojom::PaintPreviewCompositor::BitmapForSeparatedFrameCallback
+ callback,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) {
+ // The paint preview service should be sending us N32 32bpp bitmaps in
+ // reply, otherwise this can lead to out-of-bounds mistakes when
+ // transferring the pixels out of the bitmap into other buffers.
+ CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
+ std::move(callback).Run(status, bitmap);
+ },
+ BindToTaskRunner(default_task_runner_, std::move(callback)));
+
compositor_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(
- &mojom::PaintPreviewCompositor::BitmapForSeparatedFrame,
- base::Unretained(compositor_.get()->get()), frame_guid, clip_rect,
- scale_factor,
- BindToTaskRunner(default_task_runner_, std::move(callback))));
+ base::BindOnce(&mojom::PaintPreviewCompositor::BitmapForSeparatedFrame,
+ base::Unretained(compositor_.get()->get()), frame_guid,
+ clip_rect, scale_factor, std::move(validate_bitmap)));
}
void PaintPreviewCompositorClientImpl::BeginMainFrameComposite(
diff --git a/chromium/components/paint_preview/common/paint_preview_tracker.h b/chromium/components/paint_preview/common/paint_preview_tracker.h
index 4828a9b3a4d..8160031f738 100644
--- a/chromium/components/paint_preview/common/paint_preview_tracker.h
+++ b/chromium/components/paint_preview/common/paint_preview_tracker.h
@@ -92,6 +92,9 @@ class PaintPreviewTracker {
return &picture_context_;
}
TypefaceUsageMap* GetTypefaceUsageMap() { return &typeface_glyph_usage_; }
+ ImageSerializationContext* GetImageSerializationContext() {
+ return &image_context_;
+ }
// Expose links for serialization to a PaintPreviewFrameProto.
const std::vector<mojom::LinkDataPtr>& GetLinks() { return links_; }
@@ -113,6 +116,7 @@ class PaintPreviewTracker {
std::vector<SkMatrix> states_;
std::vector<mojom::LinkDataPtr> links_;
+ ImageSerializationContext image_context_;
PictureSerializationContext picture_context_;
TypefaceUsageMap typeface_glyph_usage_;
base::flat_map<uint32_t, sk_sp<SkPicture>> subframe_pics_;
diff --git a/chromium/components/paint_preview/common/serial_utils.cc b/chromium/components/paint_preview/common/serial_utils.cc
index ff06e2f42d4..8fd6f25be7c 100644
--- a/chromium/components/paint_preview/common/serial_utils.cc
+++ b/chromium/components/paint_preview/common/serial_utils.cc
@@ -73,6 +73,42 @@ sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
return subset_data;
}
+sk_sp<SkData> SerializeImage(SkImage* image, void* ctx) {
+ ImageSerializationContext* context =
+ reinterpret_cast<ImageSerializationContext*>(ctx);
+
+ const SkImageInfo& image_info = image->imageInfo();
+ // If decoding/encoding the image would result in it exceeding the allowable
+ // size, effectively delete it by providing no data.
+ if (context->max_representation_size != 0 &&
+ image_info.computeMinByteSize() > context->max_representation_size) {
+ return SkData::MakeEmpty();
+ }
+
+ // If there already exists encoded data use it directly.
+ sk_sp<SkData> encoded_data = image->refEncodedData();
+ if (!encoded_data) {
+ encoded_data = image->encodeToData();
+ }
+
+ // If encoding failed then no-op.
+ if (!encoded_data)
+ return SkData::MakeEmpty();
+
+ // Ensure the encoded data fits in the restrictions if they are present.
+ if ((context->remaining_image_size == std::numeric_limits<uint64_t>::max() ||
+ context->remaining_image_size >= encoded_data->size()) &&
+ (context->max_representation_size == 0 ||
+ encoded_data->size() < context->max_representation_size)) {
+ if (context->remaining_image_size != std::numeric_limits<uint64_t>::max())
+ context->remaining_image_size -= encoded_data->size();
+
+ return encoded_data;
+ }
+
+ return SkData::MakeEmpty();
+}
+
// Deserializes a clip rect for a subframe within the main SkPicture. These
// represent subframes and require special decoding as they are custom data
// rather than a valid SkPicture.
@@ -155,14 +191,24 @@ sk_sp<SkPicture> MakeEmptyPicture() {
}
SkSerialProcs MakeSerialProcs(PictureSerializationContext* picture_ctx,
- TypefaceSerializationContext* typeface_ctx) {
+ TypefaceSerializationContext* typeface_ctx,
+ ImageSerializationContext* image_ctx) {
SkSerialProcs procs;
procs.fPictureProc = SerializePictureAsRectData;
procs.fPictureCtx = picture_ctx;
procs.fTypefaceProc = SerializeTypeface;
procs.fTypefaceCtx = typeface_ctx;
+
// TODO(crbug/1008875): find a consistently smaller and low-memory overhead
// image downsampling method to use as fImageProc.
+ //
+ // At present this uses the native representation, but skips serializing if
+ // loading to a bitmap for encoding might cause an OOM.
+ if (image_ctx->max_representation_size > 0 ||
+ image_ctx->remaining_image_size != std::numeric_limits<uint64_t>::max()) {
+ procs.fImageProc = SerializeImage;
+ procs.fImageCtx = image_ctx;
+ }
return procs;
}
diff --git a/chromium/components/paint_preview/common/serial_utils.h b/chromium/components/paint_preview/common/serial_utils.h
index e2fddc7ec76..1560a10b96d 100644
--- a/chromium/components/paint_preview/common/serial_utils.h
+++ b/chromium/components/paint_preview/common/serial_utils.h
@@ -52,6 +52,18 @@ struct TypefaceSerializationContext {
base::flat_set<SkFontID> finished; // Should be empty on first use.
};
+struct ImageSerializationContext {
+ // The remaining memory budget for images. This is ignored if the value is the
+ // max value of uint64_t.
+ uint64_t remaining_image_size{std::numeric_limits<uint64_t>::max()};
+
+ // The maximum size of the representation for serialization. Images
+ // that are larger than this when encoded or will need to be inflated to a
+ // bitmap larger than this are skipped to avoid OOMs. If this value is 0 image
+ // procs are skipped and the default behavior is used.
+ uint64_t max_representation_size{0};
+};
+
// Maps a content ID to a clip rect.
using DeserializationContext = base::flat_map<uint32_t, gfx::Rect>;
@@ -81,7 +93,8 @@ sk_sp<SkPicture> MakeEmptyPicture();
// Creates a SkSerialProcs object. The object *does not* copy |picture_ctx| or
// |typeface_ctx| so they must outlive the use of the returned object.
SkSerialProcs MakeSerialProcs(PictureSerializationContext* picture_ctx,
- TypefaceSerializationContext* typeface_ctx);
+ TypefaceSerializationContext* typeface_ctx,
+ ImageSerializationContext* image_ctx);
// Creates a SkDeserialProcs object. The object *does not* copy |ctx| so |ctx|
// must outlive the use of the returned object. |ctx| will be filled as pictures
diff --git a/chromium/components/paint_preview/common/serial_utils_unittest.cc b/chromium/components/paint_preview/common/serial_utils_unittest.cc
index 494d5e4608a..f249210e018 100644
--- a/chromium/components/paint_preview/common/serial_utils_unittest.cc
+++ b/chromium/components/paint_preview/common/serial_utils_unittest.cc
@@ -5,7 +5,12 @@
#include "components/paint_preview/common/serial_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkTypeface.h"
@@ -35,10 +40,13 @@ TEST(PaintPreviewSerialUtils, TestTransformedPictureProcs) {
TypefaceUsageMap usage_map;
TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
- SkSerialProcs serial_procs = MakeSerialProcs(&picture_ctx, &typeface_ctx);
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
EXPECT_EQ(serial_procs.fTypefaceCtx, &typeface_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, nullptr);
DeserializationContext deserial_ctx;
SkDeserialProcs deserial_procs = MakeDeserialProcs(&deserial_ctx);
@@ -63,10 +71,13 @@ TEST(PaintPreviewSerialUtils, TestSerialPictureNotInMap) {
TypefaceUsageMap usage_map;
TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
- SkSerialProcs serial_procs = MakeSerialProcs(&picture_ctx, &typeface_ctx);
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
EXPECT_EQ(serial_procs.fTypefaceCtx, &typeface_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, nullptr);
auto pic = MakeEmptyPicture();
EXPECT_EQ(serial_procs.fPictureProc(pic.get(), serial_procs.fPictureCtx),
@@ -87,10 +98,13 @@ TEST(PaintPreviewSerialUtils, TestSerialTypeface) {
usage_map.insert(std::make_pair(typeface->uniqueID(), std::move(usage)))
.second);
TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
- SkSerialProcs serial_procs = MakeSerialProcs(&picture_ctx, &typeface_ctx);
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
EXPECT_EQ(serial_procs.fTypefaceCtx, &typeface_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, nullptr);
EXPECT_NE(
serial_procs.fTypefaceProc(typeface.get(), serial_procs.fTypefaceCtx),
@@ -104,10 +118,13 @@ TEST(PaintPreviewSerialUtils, TestSerialNoTypefaceInMap) {
auto typeface = SkTypeface::MakeDefault();
TypefaceUsageMap usage_map;
TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
- SkSerialProcs serial_procs = MakeSerialProcs(&picture_ctx, &typeface_ctx);
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
EXPECT_EQ(serial_procs.fTypefaceCtx, &typeface_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, nullptr);
EXPECT_NE(
serial_procs.fTypefaceProc(typeface.get(), serial_procs.fTypefaceCtx),
@@ -119,4 +136,95 @@ TEST(PaintPreviewSerialUtils, TestSerialNoTypefaceInMap) {
nullptr);
}
+TEST(PaintPreviewSerialUtils, TestImageContextLimitBudget) {
+ SkBitmap bitmap1;
+ bitmap1.allocN32Pixels(1, 19);
+ SkCanvas canvas1(bitmap1);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorRED);
+ canvas1.drawRect(SkRect::MakeWH(1, 4), paint);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(40, 40));
+ canvas->drawBitmap(bitmap1, 0, 0);
+ canvas->drawBitmap(bitmap1, 0, 0);
+ canvas->drawBitmap(bitmap1, 0, 0);
+ auto pic = recorder.finishRecordingAsPicture();
+
+ PictureSerializationContext picture_ctx;
+ TypefaceUsageMap usage_map;
+ TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
+ ictx.remaining_image_size = 200;
+
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
+ EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, &ictx);
+ EXPECT_EQ(serial_procs.fImageCtx, &ictx);
+
+ sk_sp<SkData> data = pic->serialize(&serial_procs);
+ EXPECT_NE(data, nullptr);
+ SkDeserialProcs deserial_procs;
+ size_t deserialized_images = 0;
+ deserial_procs.fImageCtx = &deserialized_images;
+ deserial_procs.fImageProc = [](const void* data, size_t length,
+ void* ctx) -> sk_sp<SkImage> {
+ if (length > 0U) {
+ size_t* images = reinterpret_cast<size_t*>(ctx);
+ *images += 1;
+ }
+ return nullptr;
+ };
+ SkPicture::MakeFromData(data.get(), &deserial_procs);
+ EXPECT_EQ(deserialized_images, 2U);
+}
+
+TEST(PaintPreviewSerialUtils, TestImageContextLimitSize) {
+ SkBitmap bitmap1;
+ bitmap1.allocN32Pixels(1, 19);
+ SkCanvas canvas1(bitmap1);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorRED);
+ canvas1.drawRect(SkRect::MakeWH(1, 4), paint);
+ SkBitmap bitmap2;
+ bitmap2.allocN32Pixels(20, 20);
+ SkCanvas canvas2(bitmap2);
+ canvas2.drawRect(SkRect::MakeWH(20, 5), paint);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(40, 40));
+ canvas->drawBitmap(bitmap1, 0, 0);
+ canvas->drawBitmap(bitmap2, 0, 0);
+ auto pic = recorder.finishRecordingAsPicture();
+
+ PictureSerializationContext picture_ctx;
+ TypefaceUsageMap usage_map;
+ TypefaceSerializationContext typeface_ctx(&usage_map);
+ ImageSerializationContext ictx;
+ ictx.max_representation_size = 200;
+
+ SkSerialProcs serial_procs =
+ MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
+ EXPECT_EQ(serial_procs.fPictureCtx, &picture_ctx);
+ EXPECT_EQ(serial_procs.fImageCtx, &ictx);
+ EXPECT_EQ(serial_procs.fImageCtx, &ictx);
+
+ sk_sp<SkData> data = pic->serialize(&serial_procs);
+ EXPECT_NE(data, nullptr);
+ SkDeserialProcs deserial_procs;
+ size_t deserialized_images = 0;
+ deserial_procs.fImageCtx = &deserialized_images;
+ deserial_procs.fImageProc = [](const void* data, size_t length,
+ void* ctx) -> sk_sp<SkImage> {
+ if (length > 0U) {
+ size_t* images = reinterpret_cast<size_t*>(ctx);
+ *images += 1;
+ }
+ return nullptr;
+ };
+ SkPicture::MakeFromData(data.get(), &deserial_procs);
+ EXPECT_EQ(deserialized_images, 1U);
+}
+
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/common/serialized_recording.cc b/chromium/components/paint_preview/common/serialized_recording.cc
index b5bcca91d28..b5db42264c7 100644
--- a/chromium/components/paint_preview/common/serialized_recording.cc
+++ b/chromium/components/paint_preview/common/serialized_recording.cc
@@ -25,7 +25,8 @@ bool SerializeSkPicture(sk_sp<const SkPicture> skp,
SkWStream* out_stream) {
TypefaceSerializationContext typeface_context(tracker->GetTypefaceUsageMap());
auto serial_procs = MakeSerialProcs(tracker->GetPictureSerializationContext(),
- &typeface_context);
+ &typeface_context,
+ tracker->GetImageSerializationContext());
skp->serialize(out_stream, &serial_procs);
out_stream->flush();
diff --git a/chromium/components/paint_preview/common/serialized_recording_unittest.cc b/chromium/components/paint_preview/common/serialized_recording_unittest.cc
index d930225f3ca..0cce745ac9a 100644
--- a/chromium/components/paint_preview/common/serialized_recording_unittest.cc
+++ b/chromium/components/paint_preview/common/serialized_recording_unittest.cc
@@ -75,7 +75,7 @@ SkBitmap CreateBitmapFromPicture(const SkPicture* pic) {
SkBitmap bitmap;
bitmap.allocPixels(
SkImageInfo::MakeN32Premul(cull_rect.width(), cull_rect.height()));
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
SkMatrix matrix;
matrix.setScaleTranslate(1, 1, -cull_rect.x(), -cull_rect.y());
canvas.drawPicture(pic, &matrix, nullptr);
diff --git a/chromium/components/paint_preview/player/BUILD.gn b/chromium/components/paint_preview/player/BUILD.gn
index c3237358302..64ed62f7efb 100644
--- a/chromium/components/paint_preview/player/BUILD.gn
+++ b/chromium/components/paint_preview/player/BUILD.gn
@@ -4,6 +4,8 @@
source_set("player") {
sources = [
+ "bitmap_request.cc",
+ "bitmap_request.h",
"compositor_status.h",
"player_compositor_delegate.cc",
"player_compositor_delegate.h",
@@ -33,6 +35,7 @@ source_set("unit_tests") {
":player",
"//base",
"//base/test:test_support",
+ "//base/util/memory_pressure:test_support",
"//components/paint_preview/browser",
"//components/paint_preview/common",
"//components/paint_preview/common/proto",
diff --git a/chromium/components/paint_preview/player/android/javatests/paint_preview_test_service.cc b/chromium/components/paint_preview/player/android/javatests/paint_preview_test_service.cc
index dc3ef5dd75c..33c7190a325 100644
--- a/chromium/components/paint_preview/player/android/javatests/paint_preview_test_service.cc
+++ b/chromium/components/paint_preview/player/android/javatests/paint_preview_test_service.cc
@@ -84,7 +84,8 @@ bool WriteSkp(sk_sp<SkPicture> skp,
skp_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
TypefaceUsageMap typeface_map;
TypefaceSerializationContext tctx(&typeface_map);
- auto procs = MakeSerialProcs(pctx, &tctx);
+ ImageSerializationContext ictx;
+ auto procs = MakeSerialProcs(pctx, &tctx, &ictx);
skp->serialize(&wstream, &procs);
wstream.Close();
if (wstream.DidWriteFail()) {
diff --git a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
index 12a1e787e6a..ce9a7556662 100644
--- a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
+++ b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -26,11 +26,11 @@ import org.junit.runner.RunWith;
import org.chromium.base.task.PostTask;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.Criteria;
+import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.ScalableTimeout;
import org.chromium.content_public.browser.UiThreadTaskTraits;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.ui.test.util.DummyUiActivityTestCase;
import org.chromium.url.GURL;
@@ -365,6 +365,7 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
mLinkClickHandler = new TestLinkClickHandler();
mRefreshedCallback = new CallbackHelper();
CallbackHelper viewReady = new CallbackHelper();
+ CallbackHelper firstPaint = new CallbackHelper();
mInitializationFailed = false;
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
@@ -389,7 +390,9 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
}
@Override
- public void onFirstPaint() {}
+ public void onFirstPaint() {
+ firstPaint.notifyCalled();
+ }
@Override
public void onUserInteraction() {}
@@ -441,6 +444,12 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
if (mInitializationFailed) {
Assert.fail("Compositor may have crashed.");
}
+
+ try {
+ firstPaint.waitForFirst();
+ } catch (Exception e) {
+ Assert.fail("First paint not issued.");
+ }
}
/*
diff --git a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
index 63a93410f56..fd56112c2c7 100644
--- a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
+++ b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
@@ -175,15 +175,33 @@ public class PlayerFrameMediatorTest {
private class TestPlayerCompositorDelegate implements PlayerCompositorDelegate {
List<RequestedBitmap> mRequestedBitmap = new ArrayList<>();
List<ClickedPoint> mClickedPoints = new ArrayList<>();
+ Runnable mOnMemoryPressureRunnable;
+ private int mNextRequestId;
@Override
- public void requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
+ public void addMemoryPressureListener(Runnable runnable) {
+ mOnMemoryPressureRunnable = runnable;
+ }
+
+ @Override
+ public int requestBitmap(UnguessableToken frameGuid, Rect clipRect, float scaleFactor,
Callback<Bitmap> bitmapCallback, Runnable errorCallback) {
mRequestedBitmap.add(new RequestedBitmap(
frameGuid, new Rect(clipRect), scaleFactor, bitmapCallback, errorCallback));
+ int requestId = mNextRequestId;
+ mNextRequestId++;
+ return requestId;
+ }
+
+ @Override
+ public boolean cancelBitmapRequest(int requestId) {
+ return false;
}
@Override
+ public void cancelAllBitmapRequests() {}
+
+ @Override
public GURL onClick(UnguessableToken frameGuid, int x, int y) {
mClickedPoints.add(new ClickedPoint(frameGuid, x, y));
return null;
@@ -272,7 +290,7 @@ public class PlayerFrameMediatorTest {
// columns. Because we set the initial scale factor to view port width over content width,
// we should have only one column.
CompressibleBitmap[][] bitmapMatrix = mModel.get(PlayerFrameProperties.BITMAP_MATRIX);
- Assert.assertTrue(Arrays.deepEquals(bitmapMatrix, new CompressibleBitmap[4][2]));
+ Assert.assertTrue(Arrays.deepEquals(bitmapMatrix, new CompressibleBitmap[4][1]));
Assert.assertEquals(new ArrayList<Pair<View, Rect>>(),
mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
}
@@ -293,11 +311,11 @@ public class PlayerFrameMediatorTest {
// Below is a schematic of the entire bitmap matrix. Those marked with number should have
// been requested, in the order of numbers.
// -------------------------
- // | 1 | 3 | 6 | | | |
+ // | 1 | 3 | | | | |
// -------------------------
- // | 2 | 4 | 8 | | | |
+ // | 2 | 4 | | | | |
// -------------------------
- // | 5 | 7 | | | | |
+ // | 5 | | | | | |
// -------------------------
// | | | | | | |
// -------------------------
@@ -306,21 +324,15 @@ public class PlayerFrameMediatorTest {
// | | | | | | |
List<RequestedBitmap> expectedRequestedBitmaps = new ArrayList<>();
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 0), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 2), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 1), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 1), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
mScrollController.scrollBy(10, 20);
@@ -335,31 +347,29 @@ public class PlayerFrameMediatorTest {
// Below is a schematic of the entire bitmap matrix. Those marked with number should have
// been requested, in the order of numbers.
// -------------------------
- // | x | x | x | 3 | | |
+ // | x | x | 3 | | | |
// -------------------------
- // | x | x | x | 5 | | |
+ // | x | x | 5 | | | |
// -------------------------
- // | x | x | 1 | 7 | | |
+ // | x | 1 | 6 | | | |
// -------------------------
- // | 2 | 4 | 6 | | | |
+ // | 2 | 4 | | | | |
// -------------------------
// | | | | | | |
// -------------------------
// | | | | | | |
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 2), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 2), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
// Move the view port slightly. It is still covered by the same tiles. Since there were
@@ -375,33 +385,27 @@ public class PlayerFrameMediatorTest {
Assert.assertEquals(expectedViewPort, mModel.get(PlayerFrameProperties.VIEWPORT));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 9, 9), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 9, 4), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 10, 9), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 10, 4), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 11, 9), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 11, 4), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 9, 10), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 9, 5), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 10, 10), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 10, 5), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 11, 10), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 11, 5), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 8, 9), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 8, 4), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 9, 8), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 9, 3), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 10, 8), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 10, 3), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 11, 8), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 11, 3), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 8, 10), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 9, 11), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 10, 11), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 11, 11), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 8, 5), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
}
@@ -415,7 +419,7 @@ public class PlayerFrameMediatorTest {
// Initial view port setup.
mMediator.updateViewportSize(100, 200, 1f);
- boolean[][] expectedRequiredBitmaps = new boolean[12][12];
+ boolean[][] expectedRequiredBitmaps = new boolean[12][6];
// The current view port fully matches the top left bitmap tile.
// Below is a schematic of the entire bitmap matrix. Tiles marked with x are required for
@@ -434,12 +438,9 @@ public class PlayerFrameMediatorTest {
// | | | | | | |
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
- expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true;
- expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
@@ -457,79 +458,65 @@ public class PlayerFrameMediatorTest {
// | | | | | | |
// -------------------------
// | | | | | | |
- expectedRequiredBitmaps[0][3] = true;
- expectedRequiredBitmaps[1][3] = true;
- expectedRequiredBitmaps[2][3] = true;
+ expectedRequiredBitmaps[0][2] = true;
+ expectedRequiredBitmaps[1][2] = true;
+ expectedRequiredBitmaps[2][1] = true;
expectedRequiredBitmaps[2][2] = true;
expectedRequiredBitmaps[3][0] = true;
expectedRequiredBitmaps[3][1] = true;
- expectedRequiredBitmaps[3][2] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
mScrollController.scrollBy(200, 400);
// The current view port contains portions of the middle 9 tiles.
// ---------------------
- // | | x | x | x | |
+ // | | x | x | | |
// ---------------------
- // | x | x | x | x | x |
+ // | x | x | x | x | |
// ---------------------
- // | x | x | x | x | x |
+ // | x | x | x | x | |
// ---------------------
- // | x | x | x | x | x |
+ // | x | x | x | x | |
// ---------------------
- // | | x | x | x | |
+ // | | x | x | | |
// ---------------------
- expectedRequiredBitmaps = new boolean[12][12];
- expectedRequiredBitmaps[3][4] = true;
- expectedRequiredBitmaps[3][5] = true;
- expectedRequiredBitmaps[3][6] = true;
+ expectedRequiredBitmaps = new boolean[12][6];
+ expectedRequiredBitmaps[3][2] = true;
+ expectedRequiredBitmaps[3][3] = true;
+ expectedRequiredBitmaps[4][1] = true;
+ expectedRequiredBitmaps[4][2] = true;
expectedRequiredBitmaps[4][3] = true;
expectedRequiredBitmaps[4][4] = true;
- expectedRequiredBitmaps[4][5] = true;
- expectedRequiredBitmaps[4][6] = true;
- expectedRequiredBitmaps[4][7] = true;
+ expectedRequiredBitmaps[5][1] = true;
+ expectedRequiredBitmaps[5][2] = true;
expectedRequiredBitmaps[5][3] = true;
expectedRequiredBitmaps[5][4] = true;
- expectedRequiredBitmaps[5][5] = true;
- expectedRequiredBitmaps[5][6] = true;
- expectedRequiredBitmaps[5][7] = true;
+ expectedRequiredBitmaps[6][1] = true;
+ expectedRequiredBitmaps[6][2] = true;
expectedRequiredBitmaps[6][3] = true;
expectedRequiredBitmaps[6][4] = true;
- expectedRequiredBitmaps[6][5] = true;
- expectedRequiredBitmaps[6][6] = true;
- expectedRequiredBitmaps[6][7] = true;
- expectedRequiredBitmaps[7][4] = true;
- expectedRequiredBitmaps[7][5] = true;
- expectedRequiredBitmaps[7][6] = true;
+ expectedRequiredBitmaps[7][2] = true;
+ expectedRequiredBitmaps[7][3] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
mScrollController.scrollBy(200, 400);
// The current view port contains portions of the 9 bottom right tiles.
// Tiles marked with x are required for the current view port.
- expectedRequiredBitmaps = new boolean[12][12];
- expectedRequiredBitmaps[7][8] = true;
- expectedRequiredBitmaps[7][9] = true;
- expectedRequiredBitmaps[7][10] = true;
- expectedRequiredBitmaps[8][7] = true;
- expectedRequiredBitmaps[8][8] = true;
- expectedRequiredBitmaps[8][9] = true;
- expectedRequiredBitmaps[8][10] = true;
- expectedRequiredBitmaps[8][11] = true;
- expectedRequiredBitmaps[9][7] = true;
- expectedRequiredBitmaps[9][8] = true;
- expectedRequiredBitmaps[9][9] = true;
- expectedRequiredBitmaps[9][10] = true;
- expectedRequiredBitmaps[9][11] = true;
- expectedRequiredBitmaps[10][7] = true;
- expectedRequiredBitmaps[10][8] = true;
- expectedRequiredBitmaps[10][9] = true;
- expectedRequiredBitmaps[10][10] = true;
- expectedRequiredBitmaps[10][11] = true;
- expectedRequiredBitmaps[11][8] = true;
- expectedRequiredBitmaps[11][9] = true;
- expectedRequiredBitmaps[11][10] = true;
+ expectedRequiredBitmaps = new boolean[12][6];
+ expectedRequiredBitmaps[7][4] = true;
+ expectedRequiredBitmaps[7][5] = true;
+ expectedRequiredBitmaps[8][3] = true;
+ expectedRequiredBitmaps[8][4] = true;
+ expectedRequiredBitmaps[8][5] = true;
+ expectedRequiredBitmaps[9][3] = true;
+ expectedRequiredBitmaps[9][4] = true;
+ expectedRequiredBitmaps[9][5] = true;
+ expectedRequiredBitmaps[10][3] = true;
+ expectedRequiredBitmaps[10][4] = true;
+ expectedRequiredBitmaps[10][5] = true;
+ expectedRequiredBitmaps[11][4] = true;
+ expectedRequiredBitmaps[11][5] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
}
@@ -548,6 +535,7 @@ public class PlayerFrameMediatorTest {
Bitmap bitmap00 = Mockito.mock(Bitmap.class);
Bitmap bitmap10 = Mockito.mock(Bitmap.class);
Bitmap bitmap20 = Mockito.mock(Bitmap.class);
+ Bitmap bitmap30 = Mockito.mock(Bitmap.class);
Bitmap bitmap01 = Mockito.mock(Bitmap.class);
Bitmap bitmap11 = Mockito.mock(Bitmap.class);
Bitmap bitmap21 = Mockito.mock(Bitmap.class);
@@ -555,10 +543,6 @@ public class PlayerFrameMediatorTest {
Bitmap bitmap02 = Mockito.mock(Bitmap.class);
Bitmap bitmap12 = Mockito.mock(Bitmap.class);
Bitmap bitmap22 = Mockito.mock(Bitmap.class);
- Bitmap bitmap32 = Mockito.mock(Bitmap.class);
- Bitmap bitmap03 = Mockito.mock(Bitmap.class);
- Bitmap bitmap13 = Mockito.mock(Bitmap.class);
- Bitmap bitmap23 = Mockito.mock(Bitmap.class);
SequencedTaskRunner mockTaskRunner = Mockito.mock(SequencedTaskRunner.class);
CompressibleBitmap compressibleBitmap00 =
new CompressibleBitmap(bitmap00, mockTaskRunner, true);
@@ -566,6 +550,8 @@ public class PlayerFrameMediatorTest {
new CompressibleBitmap(bitmap10, mockTaskRunner, true);
CompressibleBitmap compressibleBitmap20 =
new CompressibleBitmap(bitmap20, mockTaskRunner, true);
+ CompressibleBitmap compressibleBitmap30 =
+ new CompressibleBitmap(bitmap30, mockTaskRunner, true);
CompressibleBitmap compressibleBitmap01 =
new CompressibleBitmap(bitmap01, mockTaskRunner, true);
CompressibleBitmap compressibleBitmap11 =
@@ -580,24 +566,13 @@ public class PlayerFrameMediatorTest {
new CompressibleBitmap(bitmap12, mockTaskRunner, true);
CompressibleBitmap compressibleBitmap22 =
new CompressibleBitmap(bitmap22, mockTaskRunner, true);
- CompressibleBitmap compressibleBitmap32 =
- new CompressibleBitmap(bitmap32, mockTaskRunner, true);
- CompressibleBitmap compressibleBitmap03 =
- new CompressibleBitmap(bitmap03, mockTaskRunner, true);
- CompressibleBitmap compressibleBitmap13 =
- new CompressibleBitmap(bitmap13, mockTaskRunner, true);
- CompressibleBitmap compressibleBitmap23 =
- new CompressibleBitmap(bitmap23, mockTaskRunner, true);
-
- CompressibleBitmap[][] expectedBitmapMatrix = new CompressibleBitmap[12][8];
+
+ CompressibleBitmap[][] expectedBitmapMatrix = new CompressibleBitmap[12][4];
expectedBitmapMatrix[0][0] = compressibleBitmap00;
expectedBitmapMatrix[0][1] = compressibleBitmap01;
- expectedBitmapMatrix[0][2] = compressibleBitmap02;
expectedBitmapMatrix[1][0] = compressibleBitmap10;
expectedBitmapMatrix[1][1] = compressibleBitmap11;
- expectedBitmapMatrix[1][2] = compressibleBitmap12;
expectedBitmapMatrix[2][0] = compressibleBitmap20;
- expectedBitmapMatrix[2][1] = compressibleBitmap21;
// Call the request callback with mock bitmaps and assert they're added to the model.
mCompositorDelegate.mRequestedBitmap.get(0).mBitmapCallback.onResult(
@@ -607,16 +582,9 @@ public class PlayerFrameMediatorTest {
mCompositorDelegate.mRequestedBitmap.get(2).mBitmapCallback.onResult(
compressibleBitmap01.getBitmap());
mCompositorDelegate.mRequestedBitmap.get(3).mBitmapCallback.onResult(
- compressibleBitmap11.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(4).mBitmapCallback.onResult(
compressibleBitmap20.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(5).mBitmapCallback.onResult(
- compressibleBitmap02.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(6).mBitmapCallback.onResult(
- compressibleBitmap21.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(7).mBitmapCallback.onResult(
- compressibleBitmap12.getBitmap());
- CompressibleBitmap[][] mat = mModel.get(PlayerFrameProperties.BITMAP_MATRIX);
+ mCompositorDelegate.mRequestedBitmap.get(4).mBitmapCallback.onResult(
+ compressibleBitmap11.getBitmap());
Assert.assertTrue(Arrays.deepEquals(
expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX)));
@@ -627,38 +595,36 @@ public class PlayerFrameMediatorTest {
// tiles. See comments on {@link #testBitmapRequest} for details on which tiles will be
// requested.
// Call the request callback with mock bitmaps and assert they're added to the model.
- expectedBitmapMatrix[2][2] = compressibleBitmap22;
- expectedBitmapMatrix[0][3] = compressibleBitmap03;
+ expectedBitmapMatrix[2][1] = compressibleBitmap21;
+ // expectedBitmapMatrix[3][0] = compressibleBitmap30;
+ expectedBitmapMatrix[0][2] = compressibleBitmap02;
+ expectedBitmapMatrix[1][2] = compressibleBitmap12;
expectedBitmapMatrix[3][1] = compressibleBitmap31;
- expectedBitmapMatrix[1][3] = compressibleBitmap13;
- expectedBitmapMatrix[3][2] = compressibleBitmap32;
- expectedBitmapMatrix[2][3] = compressibleBitmap23;
- mCompositorDelegate.mRequestedBitmap.get(8).mBitmapCallback.onResult(
- compressibleBitmap22.getBitmap());
+ expectedBitmapMatrix[2][2] = compressibleBitmap22;
+ mCompositorDelegate.mRequestedBitmap.get(5).mBitmapCallback.onResult(
+ compressibleBitmap21.getBitmap());
// Mock a compositing failure for this tile. No bitmaps should be added.
- mCompositorDelegate.mRequestedBitmap.get(9).mErrorCallback.run();
- mCompositorDelegate.mRequestedBitmap.get(10).mBitmapCallback.onResult(
+ mCompositorDelegate.mRequestedBitmap.get(6).mErrorCallback.run();
+ mCompositorDelegate.mRequestedBitmap.get(7).mBitmapCallback.onResult(
+ compressibleBitmap02.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(8).mBitmapCallback.onResult(
+ compressibleBitmap12.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(9).mBitmapCallback.onResult(
compressibleBitmap31.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(11).mBitmapCallback.onResult(
- compressibleBitmap03.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(12).mBitmapCallback.onResult(
- compressibleBitmap13.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(13).mBitmapCallback.onResult(
- compressibleBitmap32.getBitmap());
- mCompositorDelegate.mRequestedBitmap.get(14).mBitmapCallback.onResult(
- compressibleBitmap23.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(10).mBitmapCallback.onResult(
+ compressibleBitmap22.getBitmap());
Assert.assertTrue(Arrays.deepEquals(
expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX)));
// Assert 15 bitmap requests have been made in total.
- Assert.assertEquals(15, mCompositorDelegate.mRequestedBitmap.size());
+ Assert.assertEquals(11, mCompositorDelegate.mRequestedBitmap.size());
// Move the view port while staying within the current tiles in order to trigger the
// request logic again. Make sure only one new request is added, for the tile with a
// compositing failure.
mScrollController.scrollBy(10, 10);
- Assert.assertEquals(16, mCompositorDelegate.mRequestedBitmap.size());
- Assert.assertEquals(new RequestedBitmap(mFrameGuid, getRectForTile(75, 100, 3, 0), 1f),
+ Assert.assertEquals(12, mCompositorDelegate.mRequestedBitmap.size());
+ Assert.assertEquals(new RequestedBitmap(mFrameGuid, getRectForTile(150, 100, 3, 0), 1f),
mCompositorDelegate.mRequestedBitmap.get(
mCompositorDelegate.mRequestedBitmap.size() - 1));
}
@@ -834,15 +800,12 @@ public class PlayerFrameMediatorTest {
// | | | | | | |
// -------------------------
// | | | | | | |
- boolean[][] expectedRequiredBitmaps = new boolean[12][12];
+ boolean[][] expectedRequiredBitmaps = new boolean[12][6];
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
- expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true;
- expectedRequiredBitmaps[2][1] = true;
mBitmapStateController.swapForTest();
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
@@ -853,15 +816,12 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest();
- expectedRequiredBitmaps = new boolean[23][23];
+ expectedRequiredBitmaps = new boolean[23][12];
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
- expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true;
- expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
@@ -870,15 +830,12 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest();
- expectedRequiredBitmaps = new boolean[12][12];
+ expectedRequiredBitmaps = new boolean[12][6];
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
- expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true;
- expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
}
@@ -891,19 +848,19 @@ public class PlayerFrameMediatorTest {
// Initial view port setup.
mMediator.updateViewportSize(100, 200, 1f);
- boolean[][] expectedRequiredBitmaps = new boolean[12][12];
+ boolean[][] expectedRequiredBitmaps = new boolean[12][6];
// STEP 1: Original request.
// The current view port fully matches the top left bitmap tile.
// Below is a schematic of the entire bitmap matrix. Tiles marked with x are required for
// the current view port.
// -------------------------
- // | x | x | x | | | |
- // -------------------------
- // | x | x | x | | | |
+ // | x | x | | | | |
// -------------------------
// | x | x | | | | |
// -------------------------
+ // | x | | | | | |
+ // -------------------------
// | | | | | | |
// -------------------------
// | | | | | | |
@@ -912,29 +869,20 @@ public class PlayerFrameMediatorTest {
// -------------------------
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
- expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true;
- expectedRequiredBitmaps[2][1] = true;
List<RequestedBitmap> expectedRequestedBitmaps = new ArrayList<>();
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 0), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 0), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 1), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 1), 1f));
// Both matricies should be identity to start.
assertViewportStateIs(1f, 0f, 0f, mMediator.getViewport());
@@ -947,41 +895,39 @@ public class PlayerFrameMediatorTest {
// STEP 2: Scroll slightly.
mScrollController.scrollBy(10, 15);
// -------------------------
- // | x | x | x | x | | |
- // -------------------------
- // | x | x | x | x | | |
+ // | x | x | x | | | |
// -------------------------
- // | x | x | x | x | | |
+ // | x | x | x | | | |
// -------------------------
// | x | x | x | | | |
// -------------------------
+ // | x | x | | | | |
+ // -------------------------
// | | | | | | |
// -------------------------
// | | | | | | |
- expectedRequiredBitmaps[0][3] = true;
- expectedRequiredBitmaps[1][3] = true;
- expectedRequiredBitmaps[2][2] = true;
- expectedRequiredBitmaps[2][3] = true;
+ // -------------------------
expectedRequiredBitmaps[3][0] = true;
expectedRequiredBitmaps[3][1] = true;
- expectedRequiredBitmaps[3][2] = true;
+ expectedRequiredBitmaps[2][1] = true;
+ expectedRequiredBitmaps[2][2] = true;
+ expectedRequiredBitmaps[0][2] = true;
+ expectedRequiredBitmaps[1][2] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 2), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 2), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
// The viewport matrix should track scroll and zoom.
@@ -1014,72 +960,48 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest();
- expectedRequiredBitmaps = new boolean[23][23];
+ expectedRequiredBitmaps = new boolean[23][12];
+ expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
- expectedRequiredBitmaps[0][2] = true;
- expectedRequiredBitmaps[0][3] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
expectedRequiredBitmaps[1][2] = true;
- expectedRequiredBitmaps[1][3] = true;
- expectedRequiredBitmaps[1][4] = true;
expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true;
expectedRequiredBitmaps[2][2] = true;
- expectedRequiredBitmaps[2][3] = true;
- expectedRequiredBitmaps[2][4] = true;
expectedRequiredBitmaps[3][0] = true;
expectedRequiredBitmaps[3][1] = true;
expectedRequiredBitmaps[3][2] = true;
- expectedRequiredBitmaps[3][3] = true;
- expectedRequiredBitmaps[3][4] = true;
+ expectedRequiredBitmaps[4][0] = true;
expectedRequiredBitmaps[4][1] = true;
- expectedRequiredBitmaps[4][2] = true;
- expectedRequiredBitmaps[4][3] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 0), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 0), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 1), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 0), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 2), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 2), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 3), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 4), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 4), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 3), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 4), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 2), 2f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
@@ -1105,55 +1027,43 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest();
- expectedRequiredBitmaps = new boolean[12][12];
+ expectedRequiredBitmaps = new boolean[12][6];
expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[0][2] = true;
- expectedRequiredBitmaps[0][3] = true;
expectedRequiredBitmaps[1][0] = true;
expectedRequiredBitmaps[1][1] = true;
expectedRequiredBitmaps[1][2] = true;
- expectedRequiredBitmaps[1][3] = true;
expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true;
expectedRequiredBitmaps[2][2] = true;
- expectedRequiredBitmaps[2][3] = true;
expectedRequiredBitmaps[3][0] = true;
expectedRequiredBitmaps[3][1] = true;
- expectedRequiredBitmaps[3][2] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 0), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 0), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 2), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 0, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 0), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 2), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 1), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 1), 1f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 0, 3), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 3), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 2), 1f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 3), 1f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 2), 1f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
expectedBitmapMatrix.reset();
@@ -1162,15 +1072,15 @@ public class PlayerFrameMediatorTest {
// Now a scale factor of 2 will be applied. This will happen at a focal point of 100, 200.
// Due to the position of the focal point the required bitmaps will move.
// -------------------------
- // | | x | x | x | | |
+ // | | x | x | | | |
// -------------------------
- // | x | x | x | x | x | |
+ // | x | x | x | x | | |
// -------------------------
- // | x | x | x | x | x | |
+ // | x | x | x | x | | |
// -------------------------
- // | x | x | x | x | x | |
+ // | x | x | x | x | | |
// -------------------------
- // | | x | x | x | | |
+ // | | x | x | | | |
// -------------------------
// | | | | | | |
Assert.assertTrue(mScaleController.scaleBy(2f, 100f, 200f));
@@ -1187,73 +1097,58 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mScaleController.scaleFinished(1f, 0, 0));
mBitmapStateController.swapForTest();
- expectedRequiredBitmaps = new boolean[23][23];
+ expectedRequiredBitmaps = new boolean[23][12];
+ expectedRequiredBitmaps[1][1] = true;
expectedRequiredBitmaps[1][2] = true;
- expectedRequiredBitmaps[1][3] = true;
- expectedRequiredBitmaps[1][4] = true;
+ expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true;
expectedRequiredBitmaps[2][2] = true;
expectedRequiredBitmaps[2][3] = true;
- expectedRequiredBitmaps[2][4] = true;
- expectedRequiredBitmaps[2][5] = true;
+ expectedRequiredBitmaps[3][0] = true;
expectedRequiredBitmaps[3][1] = true;
expectedRequiredBitmaps[3][2] = true;
expectedRequiredBitmaps[3][3] = true;
- expectedRequiredBitmaps[3][4] = true;
- expectedRequiredBitmaps[3][5] = true;
+ expectedRequiredBitmaps[4][0] = true;
expectedRequiredBitmaps[4][1] = true;
expectedRequiredBitmaps[4][2] = true;
expectedRequiredBitmaps[4][3] = true;
- expectedRequiredBitmaps[4][4] = true;
- expectedRequiredBitmaps[4][5] = true;
+ expectedRequiredBitmaps[5][1] = true;
expectedRequiredBitmaps[5][2] = true;
- expectedRequiredBitmaps[5][3] = true;
- expectedRequiredBitmaps[5][4] = true;
Assert.assertTrue(Arrays.deepEquals(
expectedRequiredBitmaps, getVisibleBitmapState().getRequiredBitmapsForTest()));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 4), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 4), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 4), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 5, 1), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 0), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 1, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 5, 2), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 2, 3), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 1), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 3, 3), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 3), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 5, 2), 2f));
expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 5, 3), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 1, 4), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 2, 5), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 3, 5), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 5, 4), 2f));
- expectedRequestedBitmaps.add(
- new RequestedBitmap(mFrameGuid, getRectForTile(50, 100, 4, 5), 2f));
+ new RequestedBitmap(mFrameGuid, getRectForTile(100, 100, 4, 3), 2f));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
expectedBitmapMatrix.reset();
@@ -1449,4 +1344,62 @@ public class PlayerFrameMediatorTest {
expectedBitmapScaleMatrix.postTranslate(-5f, -10f);
Assert.assertEquals(expectedBitmapScaleMatrix, bitmapScaleMatrix);
}
+
+ /**
+ * Tests purging on bitmap responses.
+ */
+ @Test
+ public void testOnMemoryPressure() {
+ // Sets the bitmap tile size to 150x200 and triggers bitmap request for the upper left tiles
+ // and their adjacent tiles.
+ mMediator.updateViewportSize(150, 200, 1f);
+
+ // Create mock bitmaps for response.
+ Bitmap bitmap00 = Mockito.mock(Bitmap.class);
+ Bitmap bitmap10 = Mockito.mock(Bitmap.class);
+ Bitmap bitmap20 = Mockito.mock(Bitmap.class);
+ Bitmap bitmap01 = Mockito.mock(Bitmap.class);
+ Bitmap bitmap11 = Mockito.mock(Bitmap.class);
+ SequencedTaskRunner mockTaskRunner = Mockito.mock(SequencedTaskRunner.class);
+ CompressibleBitmap compressibleBitmap00 =
+ new CompressibleBitmap(bitmap00, mockTaskRunner, true);
+ CompressibleBitmap compressibleBitmap10 =
+ new CompressibleBitmap(bitmap10, mockTaskRunner, true);
+ CompressibleBitmap compressibleBitmap20 =
+ new CompressibleBitmap(bitmap20, mockTaskRunner, true);
+ CompressibleBitmap compressibleBitmap01 =
+ new CompressibleBitmap(bitmap01, mockTaskRunner, true);
+ CompressibleBitmap compressibleBitmap11 =
+ new CompressibleBitmap(bitmap11, mockTaskRunner, true);
+
+ CompressibleBitmap[][] expectedBitmapMatrix = new CompressibleBitmap[12][4];
+ expectedBitmapMatrix[0][0] = compressibleBitmap00;
+ expectedBitmapMatrix[0][1] = compressibleBitmap01;
+ expectedBitmapMatrix[1][0] = compressibleBitmap10;
+ expectedBitmapMatrix[1][1] = compressibleBitmap11;
+ expectedBitmapMatrix[2][0] = compressibleBitmap20;
+
+ // Call the request callback with mock bitmaps and assert they're added to the model.
+ mCompositorDelegate.mRequestedBitmap.get(0).mBitmapCallback.onResult(
+ compressibleBitmap00.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(1).mBitmapCallback.onResult(
+ compressibleBitmap10.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(2).mBitmapCallback.onResult(
+ compressibleBitmap01.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(3).mBitmapCallback.onResult(
+ compressibleBitmap20.getBitmap());
+ mCompositorDelegate.mRequestedBitmap.get(4).mBitmapCallback.onResult(
+ compressibleBitmap11.getBitmap());
+ Assert.assertTrue(Arrays.deepEquals(
+ expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX)));
+
+ expectedBitmapMatrix = new CompressibleBitmap[12][4];
+ expectedBitmapMatrix[0][0] = compressibleBitmap00;
+ expectedBitmapMatrix[1][0] = compressibleBitmap10;
+
+ Assert.assertNotNull(mCompositorDelegate.mOnMemoryPressureRunnable);
+ mCompositorDelegate.mOnMemoryPressureRunnable.run();
+ Assert.assertTrue(Arrays.deepEquals(
+ expectedBitmapMatrix, mModel.get(PlayerFrameProperties.BITMAP_MATRIX)));
+ }
}
diff --git a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
index 95cdca9edf3..382e6f17a81 100644
--- a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
+++ b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
@@ -31,6 +31,10 @@ namespace paint_preview {
namespace {
+// To minimize peak memory usage limit the number of concurrent bitmap requests.
+constexpr size_t kMaxParallelBitmapRequests = 3;
+constexpr size_t kMaxParallelBitmapRequestsLowMemory = 1;
+
ScopedJavaLocalRef<jobjectArray> ToJavaUnguessableTokenArray(
JNIEnv* env,
const std::vector<base::UnguessableToken>& tokens) {
@@ -51,7 +55,7 @@ ScopedJavaLocalRef<jobjectArray> ToJavaUnguessableTokenArray(
ScopedJavaGlobalRef<jobject> ConvertToJavaBitmap(const SkBitmap& sk_bitmap) {
return ScopedJavaGlobalRef<jobject>(
- gfx::ConvertToJavaBitmap(&sk_bitmap, gfx::OomBehavior::kReturnNullOnOom));
+ gfx::ConvertToJavaBitmap(sk_bitmap, gfx::OomBehavior::kReturnNullOnOom));
}
} // namespace
@@ -62,12 +66,14 @@ jlong JNI_PlayerCompositorDelegateImpl_Initialize(
jlong paint_preview_service,
const JavaParamRef<jstring>& j_url_spec,
const JavaParamRef<jstring>& j_directory_key,
- const JavaParamRef<jobject>& j_compositor_error_callback) {
+ const JavaParamRef<jobject>& j_compositor_error_callback,
+ jboolean j_is_low_mem) {
PlayerCompositorDelegateAndroid* delegate =
new PlayerCompositorDelegateAndroid(
env, j_object,
reinterpret_cast<PaintPreviewBaseService*>(paint_preview_service),
- j_url_spec, j_directory_key, j_compositor_error_callback);
+ j_url_spec, j_directory_key, j_compositor_error_callback,
+ j_is_low_mem);
return reinterpret_cast<intptr_t>(delegate);
}
@@ -77,7 +83,8 @@ PlayerCompositorDelegateAndroid::PlayerCompositorDelegateAndroid(
PaintPreviewBaseService* paint_preview_service,
const JavaParamRef<jstring>& j_url_spec,
const JavaParamRef<jstring>& j_directory_key,
- const JavaParamRef<jobject>& j_compositor_error_callback)
+ const JavaParamRef<jobject>& j_compositor_error_callback,
+ jboolean j_is_low_mem)
: PlayerCompositorDelegate(),
request_id_(0),
startup_timestamp_(base::TimeTicks::Now()) {
@@ -88,7 +95,9 @@ PlayerCompositorDelegateAndroid::PlayerCompositorDelegateAndroid(
base::android::ConvertJavaStringToUTF8(env, j_directory_key)},
base::BindOnce(&base::android::RunIntCallbackAndroid,
ScopedJavaGlobalRef<jobject>(j_compositor_error_callback)),
- base::TimeDelta::FromSeconds(15));
+ base::TimeDelta::FromSeconds(15),
+ (static_cast<bool>(j_is_low_mem) ? kMaxParallelBitmapRequestsLowMemory
+ : kMaxParallelBitmapRequests));
java_ref_.Reset(env, j_object);
}
@@ -154,6 +163,18 @@ void PlayerCompositorDelegateAndroid::OnCompositorReady(
j_scroll_offsets, j_subframe_count, j_subframe_ids, j_subframe_rects);
}
+void PlayerCompositorDelegateAndroid::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ // Don't handle the critical case leave that to the base class implementation
+ // which should kill the preview.
+ if (memory_pressure_level ==
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) {
+ Java_PlayerCompositorDelegateImpl_onModerateMemoryPressure(
+ base::android::AttachCurrentThread(), java_ref_);
+ }
+ PlayerCompositorDelegate::OnMemoryPressure(memory_pressure_level);
+}
+
// static
void PlayerCompositorDelegateAndroid::CompositeResponseFramesToVectors(
const base::flat_map<base::UnguessableToken, mojom::FrameDataPtr>& frames,
@@ -190,7 +211,7 @@ void PlayerCompositorDelegateAndroid::CompositeResponseFramesToVectors(
}
}
-void PlayerCompositorDelegateAndroid::RequestBitmap(
+jint PlayerCompositorDelegateAndroid::RequestBitmap(
JNIEnv* env,
const JavaParamRef<jobject>& j_frame_guid,
const JavaParamRef<jobject>& j_bitmap_callback,
@@ -204,7 +225,7 @@ void PlayerCompositorDelegateAndroid::RequestBitmap(
"paint_preview", "PlayerCompositorDelegateAndroid::RequestBitmap",
TRACE_ID_LOCAL(request_id_));
- PlayerCompositorDelegate::RequestBitmap(
+ int32_t id = PlayerCompositorDelegate::RequestBitmap(
base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
env, j_frame_guid),
gfx::Rect(j_clip_x, j_clip_y, j_clip_width, j_clip_height),
@@ -215,6 +236,19 @@ void PlayerCompositorDelegateAndroid::RequestBitmap(
ScopedJavaGlobalRef<jobject>(j_error_callback),
request_id_));
++request_id_;
+
+ return static_cast<jint>(id);
+}
+
+jboolean PlayerCompositorDelegateAndroid::CancelBitmapRequest(
+ JNIEnv* env,
+ jint j_request_id) {
+ return static_cast<jboolean>(PlayerCompositorDelegate::CancelBitmapRequest(
+ static_cast<int32_t>(j_request_id)));
+}
+
+void PlayerCompositorDelegateAndroid::CancelAllBitmapRequests(JNIEnv* env) {
+ PlayerCompositorDelegate::CancelAllBitmapRequests();
}
void PlayerCompositorDelegateAndroid::OnBitmapCallback(
diff --git a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.h b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.h
index 79521512d17..1b5955221da 100644
--- a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.h
+++ b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.h
@@ -23,16 +23,20 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate {
PaintPreviewBaseService* paint_preview_service,
const base::android::JavaParamRef<jstring>& j_url_spec,
const base::android::JavaParamRef<jstring>& j_directory_key,
- const base::android::JavaParamRef<jobject>& j_compositor_error_callback);
+ const base::android::JavaParamRef<jobject>& j_compositor_error_callback,
+ jboolean j_is_low_mem);
void OnCompositorReady(
CompositorStatus compositor_status,
mojom::PaintPreviewBeginCompositeResponsePtr composite_response) override;
+ void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel
+ memory_pressure_level) override;
+
// Called from Java when there is a request for a new bitmap. When the bitmap
// is ready, it will be passed to j_bitmap_callback. In case of any failure,
// j_error_callback will be called.
- void RequestBitmap(
+ jint RequestBitmap(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_frame_guid,
const base::android::JavaParamRef<jobject>& j_bitmap_callback,
@@ -43,6 +47,10 @@ class PlayerCompositorDelegateAndroid : public PlayerCompositorDelegate {
jint j_clip_width,
jint j_clip_height);
+ jboolean CancelBitmapRequest(JNIEnv* env, jint j_request_id);
+
+ void CancelAllBitmapRequests(JNIEnv* env);
+
// Called from Java on touch event on a frame.
base::android::ScopedJavaLocalRef<jstring> OnClick(
JNIEnv* env,
diff --git a/chromium/components/paint_preview/player/bitmap_request.cc b/chromium/components/paint_preview/player/bitmap_request.cc
new file mode 100644
index 00000000000..c15b30c99f2
--- /dev/null
+++ b/chromium/components/paint_preview/player/bitmap_request.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 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/paint_preview/player/bitmap_request.h"
+
+namespace paint_preview {
+
+BitmapRequest::BitmapRequest(const base::UnguessableToken& frame_guid,
+ const gfx::Rect& clip_rect,
+ float scale_factor,
+ BitmapRequestCallback callback)
+ : frame_guid(frame_guid),
+ clip_rect(clip_rect),
+ scale_factor(scale_factor),
+ callback(std::move(callback)) {}
+
+BitmapRequest::~BitmapRequest() = default;
+
+BitmapRequest& BitmapRequest::operator=(BitmapRequest&& other) = default;
+
+BitmapRequest::BitmapRequest(BitmapRequest&& other) = default;
+
+} // namespace paint_preview
diff --git a/chromium/components/paint_preview/player/bitmap_request.h b/chromium/components/paint_preview/player/bitmap_request.h
new file mode 100644
index 00000000000..ef541931c43
--- /dev/null
+++ b/chromium/components/paint_preview/player/bitmap_request.h
@@ -0,0 +1,38 @@
+// Copyright 2020 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_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
+#define COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
+
+#include "base/callback.h"
+#include "base/unguessable_token.h"
+#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace paint_preview {
+
+struct BitmapRequest {
+ using BitmapRequestCallback =
+ base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
+ const SkBitmap&)>;
+
+ BitmapRequest(const base::UnguessableToken& frame_guid,
+ const gfx::Rect& clip_rect,
+ float scale_factor,
+ BitmapRequestCallback callback);
+ ~BitmapRequest();
+
+ BitmapRequest& operator=(BitmapRequest&& other) noexcept;
+ BitmapRequest(BitmapRequest&& other) noexcept;
+
+ base::UnguessableToken frame_guid;
+ gfx::Rect clip_rect;
+ float scale_factor;
+ BitmapRequestCallback callback;
+};
+
+} // namespace paint_preview
+
+#endif // COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
diff --git a/chromium/components/paint_preview/player/compositor_status.h b/chromium/components/paint_preview/player/compositor_status.h
index 1ad18a289f3..2961495e1c9 100644
--- a/chromium/components/paint_preview/player/compositor_status.h
+++ b/chromium/components/paint_preview/player/compositor_status.h
@@ -26,6 +26,8 @@ enum class CompositorStatus : int {
CAPTURE_EXPIRED,
NO_CAPTURE,
TIMED_OUT,
+ STOPPED_DUE_TO_MEMORY_PRESSURE,
+ SKIPPED_DUE_TO_MEMORY_PRESSURE,
COUNT,
};
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate.cc b/chromium/components/paint_preview/player/player_compositor_delegate.cc
index 9d6be426dad..5d653579ee4 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate.cc
+++ b/chromium/components/paint_preview/player/player_compositor_delegate.cc
@@ -10,6 +10,7 @@
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
+#include "base/memory/memory_pressure_monitor.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
@@ -103,7 +104,7 @@ PlayerCompositorDelegate::PlayerCompositorDelegate()
base::OnTaskRunnerDeleter(nullptr)) {}
PlayerCompositorDelegate::~PlayerCompositorDelegate() {
- if (compress_on_close_) {
+ if (compress_on_close_ && paint_preview_service_) {
paint_preview_service_->GetTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(&FileManager::CompressDirectory),
@@ -116,17 +117,32 @@ void PlayerCompositorDelegate::Initialize(
const GURL& expected_url,
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
- base::TimeDelta timeout_duration) {
+ base::TimeDelta timeout_duration,
+ size_t max_requests) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview",
"PlayerCompositorDelegate CreateCompositor",
TRACE_ID_LOCAL(this));
+ auto* memory_monitor = memory_pressure_monitor();
+ // If the device is already under moderate memory pressure abort right away.
+ if (memory_monitor &&
+ memory_monitor->GetCurrentPressureLevel() >=
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(compositor_error),
+ static_cast<int>(
+ CompositorStatus::SKIPPED_DUE_TO_MEMORY_PRESSURE)));
+ return;
+ }
+
paint_preview_compositor_service_ =
WarmCompositor::GetInstance()->GetOrStartCompositorService(base::BindOnce(
&PlayerCompositorDelegate::OnCompositorServiceDisconnected,
weak_factory_.GetWeakPtr()));
InitializeInternal(paint_preview_service, expected_url, key,
- std::move(compositor_error), timeout_duration);
+ std::move(compositor_error), timeout_duration,
+ max_requests);
}
void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
@@ -135,6 +151,7 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration,
+ size_t max_requests,
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
fake_compositor_service) {
paint_preview_compositor_service_ = std::move(fake_compositor_service);
@@ -143,7 +160,8 @@ void PlayerCompositorDelegate::InitializeWithFakeServiceForTest(
weak_factory_.GetWeakPtr()));
InitializeInternal(paint_preview_service, expected_url, key,
- std::move(compositor_error), timeout_duration);
+ std::move(compositor_error), timeout_duration,
+ max_requests);
}
void PlayerCompositorDelegate::InitializeInternal(
@@ -151,10 +169,16 @@ void PlayerCompositorDelegate::InitializeInternal(
const GURL& expected_url,
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
- base::TimeDelta timeout_duration) {
+ base::TimeDelta timeout_duration,
+ size_t max_requests) {
+ max_requests_ = max_requests;
compositor_error_ = std::move(compositor_error);
paint_preview_service_ = paint_preview_service;
key_ = key;
+ memory_pressure_ = std::make_unique<base::MemoryPressureListener>(
+ FROM_HERE,
+ base::BindRepeating(&PlayerCompositorDelegate::OnMemoryPressure,
+ weak_factory_.GetWeakPtr()));
paint_preview_compositor_client_ =
paint_preview_compositor_service_->CreateCompositor(
@@ -173,21 +197,46 @@ void PlayerCompositorDelegate::InitializeInternal(
}
}
-void PlayerCompositorDelegate::RequestBitmap(
+int32_t PlayerCompositorDelegate::RequestBitmap(
const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback) {
DCHECK(IsInitialized());
+ const int32_t request_id = next_request_id_;
+ next_request_id_++;
if (!paint_preview_compositor_client_) {
std::move(callback).Run(
mojom::PaintPreviewCompositor::BitmapStatus::kMissingFrame, SkBitmap());
- return;
+ return request_id;
}
- paint_preview_compositor_client_->BitmapForSeparatedFrame(
- frame_guid, clip_rect, scale_factor, std::move(callback));
+ bitmap_request_queue_.push(request_id);
+ pending_bitmap_requests_.emplace(
+ request_id,
+ BitmapRequest(frame_guid, clip_rect, scale_factor,
+ base::BindOnce(
+ &PlayerCompositorDelegate::BitmapRequestCallbackAdapter,
+ weak_factory_.GetWeakPtr(), std::move(callback))));
+ ProcessBitmapRequestsFromQueue();
+ return request_id;
+}
+
+bool PlayerCompositorDelegate::CancelBitmapRequest(int32_t request_id) {
+ auto it = pending_bitmap_requests_.find(request_id);
+ if (it == pending_bitmap_requests_.end())
+ return false;
+
+ pending_bitmap_requests_.erase(it);
+ return true;
+}
+
+void PlayerCompositorDelegate::CancelAllBitmapRequests() {
+ while (bitmap_request_queue_.size())
+ bitmap_request_queue_.pop();
+
+ pending_bitmap_requests_.clear();
}
std::vector<const GURL*> PlayerCompositorDelegate::OnClick(
@@ -202,6 +251,29 @@ std::vector<const GURL*> PlayerCompositorDelegate::OnClick(
return urls;
}
+void PlayerCompositorDelegate::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ if (memory_pressure_level ==
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ if (paint_preview_compositor_client_)
+ paint_preview_compositor_client_.reset();
+
+ if (paint_preview_compositor_service_)
+ paint_preview_compositor_service_.reset();
+
+ if (compositor_error_) {
+ std::move(compositor_error_)
+ .Run(static_cast<int>(
+ CompositorStatus::STOPPED_DUE_TO_MEMORY_PRESSURE));
+ }
+ }
+}
+
+base::MemoryPressureMonitor*
+PlayerCompositorDelegate::memory_pressure_monitor() {
+ return base::MemoryPressureMonitor::Get();
+}
+
void PlayerCompositorDelegate::OnCompositorReadyStatusAdapter(
mojom::PaintPreviewCompositor::BeginCompositeStatus status,
mojom::PaintPreviewBeginCompositeResponsePtr composite_response) {
@@ -315,6 +387,12 @@ void PlayerCompositorDelegate::SendCompositeRequest(
return;
}
+ // It is possible the client was disconnected while loading the proto.
+ if (!paint_preview_compositor_client_) {
+ OnCompositorReady(CompositorStatus::COMPOSITOR_CLIENT_DISCONNECT, nullptr);
+ return;
+ }
+
paint_preview_compositor_client_->BeginSeparatedFrameComposite(
std::move(begin_composite_request),
base::BindOnce(&PlayerCompositorDelegate::OnCompositorReadyStatusAdapter,
@@ -342,4 +420,38 @@ void PlayerCompositorDelegate::OnCompositorTimeout() {
}
}
+void PlayerCompositorDelegate::ProcessBitmapRequestsFromQueue() {
+ while (active_requests_ < max_requests_ && bitmap_request_queue_.size()) {
+ int request_id = bitmap_request_queue_.front();
+ bitmap_request_queue_.pop();
+
+ auto it = pending_bitmap_requests_.find(request_id);
+ if (it == pending_bitmap_requests_.end())
+ continue;
+
+ BitmapRequest& request = it->second;
+ active_requests_++;
+ // If the client disconnects mid request, just give up as we should be
+ // exiting.
+ if (!paint_preview_compositor_client_)
+ return;
+
+ paint_preview_compositor_client_->BitmapForSeparatedFrame(
+ request.frame_guid, request.clip_rect, request.scale_factor,
+ std::move(request.callback));
+ pending_bitmap_requests_.erase(it);
+ }
+}
+
+void PlayerCompositorDelegate::BitmapRequestCallbackAdapter(
+ base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
+ const SkBitmap&)> callback,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) {
+ std::move(callback).Run(status, bitmap);
+
+ active_requests_--;
+ ProcessBitmapRequestsFromQueue();
+}
+
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate.h b/chromium/components/paint_preview/player/player_compositor_delegate.h
index a77a44abe8d..f08c6272cdf 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate.h
+++ b/chromium/components/paint_preview/player/player_compositor_delegate.h
@@ -8,17 +8,23 @@
#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/containers/flat_map.h"
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/browser/hit_tester.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
+#include "components/paint_preview/player/bitmap_request.h"
#include "components/paint_preview/player/compositor_status.h"
#include "components/paint_preview/public/paint_preview_compositor_client.h"
#include "components/paint_preview/public/paint_preview_compositor_service.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
+namespace base {
+class MemoryPressureMonitor;
+} // namespace base
+
namespace gfx {
class Rect;
} // namespace gfx
@@ -44,7 +50,8 @@ class PlayerCompositorDelegate {
const GURL& url,
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
- base::TimeDelta timeout_duration);
+ base::TimeDelta timeout_duration,
+ size_t max_requests);
// Returns whether initialization has happened.
bool IsInitialized() const { return paint_preview_service_; }
@@ -60,18 +67,32 @@ class PlayerCompositorDelegate {
mojom::PaintPreviewBeginCompositeResponsePtr composite_response) {}
// Called when there is a request for a new bitmap. When the bitmap
- // is ready, it will be passed to callback.
- void RequestBitmap(
+ // is ready, it will be passed to callback. Returns an ID for the request.
+ // Pass this ID to `CancelBitmapRequest(int32_t)` to cancel the request if it
+ // hasn't already been sent.
+ int32_t RequestBitmap(
const base::UnguessableToken& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)> callback);
+ // Cancels the bitmap request associated with `request_id` if possible.
+ // Returns true on success.
+ bool CancelBitmapRequest(int32_t request_id);
+
+ // Cancels all pending bitmap requests.
+ void CancelAllBitmapRequests();
+
// Called on touch event on a frame.
std::vector<const GURL*> OnClick(const base::UnguessableToken& frame_guid,
const gfx::Rect& rect);
+ // Called when under memory pressure. The default implementation kills the
+ // compositor service and client under critical pressure.
+ virtual void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
// Test methods:
// Initializes the compositor without a real service for testing purposes.
@@ -81,6 +102,7 @@ class PlayerCompositorDelegate {
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
base::TimeDelta timeout_duration,
+ size_t max_requests,
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
fake_compositor_service);
@@ -95,12 +117,15 @@ class PlayerCompositorDelegate {
protected:
base::OnceCallback<void(int)> compositor_error_;
+ virtual base::MemoryPressureMonitor* memory_pressure_monitor();
+
private:
void InitializeInternal(PaintPreviewBaseService* paint_preview_service,
const GURL& expected_url,
const DirectoryKey& key,
base::OnceCallback<void(int)> compositor_error,
- base::TimeDelta timeout_duration);
+ base::TimeDelta timeout_duration,
+ size_t max_requests);
void OnCompositorReadyStatusAdapter(
mojom::PaintPreviewCompositor::BeginCompositeStatus status,
@@ -122,18 +147,35 @@ class PlayerCompositorDelegate {
void SendCompositeRequest(
mojom::PaintPreviewBeginCompositeRequestPtr begin_composite_request);
+ void ProcessBitmapRequestsFromQueue();
+ void BitmapRequestCallbackAdapter(
+ base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
+ const SkBitmap&)> callback,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap);
+
PaintPreviewBaseService* paint_preview_service_{nullptr};
DirectoryKey key_;
bool compress_on_close_{true};
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_;
+
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
paint_preview_compositor_service_;
std::unique_ptr<PaintPreviewCompositorClient, base::OnTaskRunnerDeleter>
paint_preview_compositor_client_;
+
base::CancelableOnceClosure timeout_;
+ int max_requests_{1};
+
base::flat_map<base::UnguessableToken, std::unique_ptr<HitTester>>
hit_testers_;
std::unique_ptr<PaintPreviewProto> proto_;
+ int active_requests_{0};
+ int32_t next_request_id_{0};
+ base::queue<int32_t> bitmap_request_queue_;
+ std::map<int32_t, BitmapRequest> pending_bitmap_requests_;
+
base::WeakPtrFactory<PlayerCompositorDelegate> weak_factory_{this};
};
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc b/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
index f30c5e1c32f..e2728a07ba3 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
+++ b/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
@@ -14,6 +14,7 @@
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/unguessable_token.h"
+#include "base/util/memory_pressure/fake_memory_pressure_monitor.h"
#include "components/paint_preview/browser/directory_key.h"
#include "components/paint_preview/browser/file_manager.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
@@ -27,6 +28,8 @@ namespace paint_preview {
namespace {
+constexpr size_t kMaxParallelRequests = 1;
+
class FakePaintPreviewCompositorClient : public PaintPreviewCompositorClient {
public:
explicit FakePaintPreviewCompositorClient(
@@ -181,6 +184,10 @@ class PlayerCompositorDelegateImpl : public PlayerCompositorDelegate {
status_checked_ = false;
}
+ void SetFakeMemoryPressureMonitor(base::MemoryPressureMonitor* monitor) {
+ memory_pressure_monitor_ = monitor;
+ }
+
bool WasStatusChecked() const { return status_checked_; }
void OnCompositorReady(CompositorStatus compositor_status,
@@ -192,7 +199,16 @@ class PlayerCompositorDelegateImpl : public PlayerCompositorDelegate {
status_checked_ = true;
}
+ protected:
+ base::MemoryPressureMonitor* memory_pressure_monitor() override {
+ if (memory_pressure_monitor_)
+ return memory_pressure_monitor_;
+
+ return PlayerCompositorDelegate::memory_pressure_monitor();
+ }
+
private:
+ base::MemoryPressureMonitor* memory_pressure_monitor_{nullptr};
CompositorStatus expected_status_{CompositorStatus::OK};
bool status_checked_{false};
};
@@ -332,7 +348,7 @@ TEST_F(PlayerCompositorDelegateTest, OnClick) {
player_compositor_delegate.SetExpectedStatus(CompositorStatus::OK);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, url, key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
@@ -376,7 +392,7 @@ TEST_F(PlayerCompositorDelegateTest, BadProto) {
CompositorStatus::PROTOBUF_DESERIALIZATION_ERROR);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
}
@@ -396,7 +412,7 @@ TEST_F(PlayerCompositorDelegateTest, OldVersion) {
player_compositor_delegate.SetExpectedStatus(CompositorStatus::OLD_VERSION);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, url, key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
player_compositor_delegate.SetCompressOnClose(false);
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
@@ -417,7 +433,7 @@ TEST_F(PlayerCompositorDelegateTest, URLMismatch) {
CompositorStatus::URL_MISMATCH);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
}
@@ -445,7 +461,8 @@ TEST_F(PlayerCompositorDelegateTest, ServiceDisconnect) {
*called = true;
},
&called),
- base::TimeDelta::Max(), CreateCompositorService());
+ base::TimeDelta::Max(), kMaxParallelRequests,
+ CreateCompositorService());
env.RunUntilIdle();
AsFakeService(player_compositor_delegate.GetCompositorServiceForTest())
->Disconnect();
@@ -476,7 +493,8 @@ TEST_F(PlayerCompositorDelegateTest, ClientDisconnect) {
*called = true;
},
&called),
- base::TimeDelta::Max(), CreateCompositorService());
+ base::TimeDelta::Max(), kMaxParallelRequests,
+ CreateCompositorService());
env.RunUntilIdle();
AsFakeClient(player_compositor_delegate.GetClientForTest())->Disconnect();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
@@ -509,7 +527,7 @@ TEST_F(PlayerCompositorDelegateTest, InvalidCompositeRequest) {
CompositorStatus::INVALID_REQUEST);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, url, key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
}
@@ -529,7 +547,7 @@ TEST_F(PlayerCompositorDelegateTest, CompositorDeserializationError) {
CompositorStatus::COMPOSITOR_DESERIALIZATION_ERROR);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, url, key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
AsFakeClient(player_compositor_delegate.GetClientForTest())
->SetBeginSeparatedFrameResponseStatus(
mojom::PaintPreviewCompositor::BeginCompositeStatus::
@@ -553,7 +571,7 @@ TEST_F(PlayerCompositorDelegateTest, InvalidRootSkp) {
CompositorStatus::INVALID_ROOT_FRAME_SKP);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, url, key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
AsFakeClient(player_compositor_delegate.GetClientForTest())
->SetBeginSeparatedFrameResponseStatus(
mojom::PaintPreviewCompositor::BeginCompositeStatus::
@@ -588,7 +606,7 @@ TEST_F(PlayerCompositorDelegateTest, CompressOnClose) {
player_compositor_delegate.SetExpectedStatus(CompositorStatus::NO_CAPTURE);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
}
@@ -596,7 +614,7 @@ TEST_F(PlayerCompositorDelegateTest, CompressOnClose) {
EXPECT_TRUE(base::PathExists(dir.AddExtensionASCII(".zip")));
}
-TEST_F(PlayerCompositorDelegateTest, RequestBitmapSuccess) {
+TEST_F(PlayerCompositorDelegateTest, RequestBitmapWithCancel) {
auto* service = GetBaseService();
auto file_manager = service->GetFileManager();
auto key = file_manager->CreateKey(1U);
@@ -608,7 +626,130 @@ TEST_F(PlayerCompositorDelegateTest, RequestBitmapSuccess) {
player_compositor_delegate.SetExpectedStatus(CompositorStatus::NO_CAPTURE);
player_compositor_delegate.InitializeWithFakeServiceForTest(
service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
- CreateCompositorService());
+ kMaxParallelRequests, CreateCompositorService());
+ env.RunUntilIdle();
+ EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
+
+ base::RunLoop loop0;
+ int request_0 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](base::OnceClosure quit,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) {
+ EXPECT_EQ(mojom::PaintPreviewCompositor::BitmapStatus::kSuccess,
+ status);
+ std::move(quit).Run();
+ },
+ loop0.QuitClosure()));
+ bool request_1_called = false;
+ int request_1 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](bool* called, mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) { *called = true; },
+ &request_1_called));
+ base::RunLoop loop2;
+ int request_2 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](base::OnceClosure quit,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) {
+ EXPECT_EQ(mojom::PaintPreviewCompositor::BitmapStatus::kSuccess,
+ status);
+ std::move(quit).Run();
+ },
+ loop2.QuitClosure()));
+ bool request_3_called = false;
+ int request_3 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](bool* called, mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) { *called = true; },
+ &request_3_called));
+ EXPECT_EQ(
+ std::set<int>({request_0, request_1, request_2, request_3}).size(), 4U);
+
+ EXPECT_FALSE(player_compositor_delegate.CancelBitmapRequest(request_0));
+ EXPECT_TRUE(player_compositor_delegate.CancelBitmapRequest(request_1));
+ EXPECT_FALSE(player_compositor_delegate.CancelBitmapRequest(request_1));
+ EXPECT_TRUE(player_compositor_delegate.CancelBitmapRequest(request_3));
+
+ loop0.Run();
+ loop2.Run();
+ env.RunUntilIdle();
+ EXPECT_FALSE(request_1_called);
+ EXPECT_FALSE(request_3_called);
+ }
+ env.RunUntilIdle();
+}
+
+TEST_F(PlayerCompositorDelegateTest, RequestBitmapWithCancelAll) {
+ auto* service = GetBaseService();
+ auto file_manager = service->GetFileManager();
+ auto key = file_manager->CreateKey(1U);
+ {
+ // This test skips setting up files as the fakes don't use them. In normal
+ // execution the files are required by the service or no bitmap will be
+ // created.
+ PlayerCompositorDelegateImpl player_compositor_delegate;
+ player_compositor_delegate.SetExpectedStatus(CompositorStatus::NO_CAPTURE);
+ player_compositor_delegate.InitializeWithFakeServiceForTest(
+ service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
+ kMaxParallelRequests, CreateCompositorService());
+ env.RunUntilIdle();
+ EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
+
+ base::RunLoop loop0;
+ int request_0 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](base::OnceClosure quit,
+ mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) {
+ EXPECT_EQ(mojom::PaintPreviewCompositor::BitmapStatus::kSuccess,
+ status);
+ std::move(quit).Run();
+ },
+ loop0.QuitClosure()));
+ bool request_1_called = false;
+ int request_1 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](bool* called, mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) { *called = true; },
+ &request_1_called));
+ bool request_2_called = false;
+ int request_2 = player_compositor_delegate.RequestBitmap(
+ base::UnguessableToken::Create(), gfx::Rect(10, 20, 30, 40), 1.0,
+ base::BindOnce(
+ [](bool* called, mojom::PaintPreviewCompositor::BitmapStatus status,
+ const SkBitmap& bitmap) { *called = true; },
+ &request_2_called));
+ EXPECT_EQ(std::set<int>({request_0, request_1, request_2}).size(), 3U);
+ player_compositor_delegate.CancelAllBitmapRequests();
+ loop0.Run();
+ env.RunUntilIdle();
+ EXPECT_FALSE(request_1_called);
+ EXPECT_FALSE(request_2_called);
+ }
+ env.RunUntilIdle();
+}
+
+TEST_F(PlayerCompositorDelegateTest, RequestBitmapSuccessQueued) {
+ auto* service = GetBaseService();
+ auto file_manager = service->GetFileManager();
+ auto key = file_manager->CreateKey(1U);
+ {
+ // This test skips setting up files as the fakes don't use them. In normal
+ // execution the files are required by the service or no bitmap will be
+ // created.
+ PlayerCompositorDelegateImpl player_compositor_delegate;
+ player_compositor_delegate.SetExpectedStatus(CompositorStatus::NO_CAPTURE);
+ player_compositor_delegate.InitializeWithFakeServiceForTest(
+ service, GURL(), key, base::DoNothing(), base::TimeDelta::Max(),
+ kMaxParallelRequests, CreateCompositorService());
env.RunUntilIdle();
EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
@@ -647,11 +788,80 @@ TEST_F(PlayerCompositorDelegateTest, Timeout) {
std::move(quit).Run();
},
loop.QuitClosure()),
- base::TimeDelta::FromSeconds(1), std::move(compositor_service));
+ base::TimeDelta::FromSeconds(1), kMaxParallelRequests,
+ std::move(compositor_service));
env.FastForwardBy(base::TimeDelta::FromSeconds(5));
loop.Run();
}
env.RunUntilIdle();
}
+TEST_F(PlayerCompositorDelegateTest, CriticalMemoryPressure) {
+ auto* service = GetBaseService();
+ auto file_manager = service->GetFileManager();
+ auto key = file_manager->CreateKey(1U);
+ {
+ // This test skips setting up files as the fakes don't use them. In normal
+ // execution the files are required by the service or no bitmap will be
+ // created.
+ base::RunLoop loop;
+ PlayerCompositorDelegateImpl player_compositor_delegate;
+ player_compositor_delegate.SetExpectedStatus(CompositorStatus::NO_CAPTURE);
+ player_compositor_delegate.InitializeWithFakeServiceForTest(
+ service, GURL(), key,
+ base::BindOnce(
+ [](base::OnceClosure quit, int compositor_status) {
+ EXPECT_EQ(compositor_status,
+ static_cast<int>(
+ CompositorStatus::STOPPED_DUE_TO_MEMORY_PRESSURE));
+ std::move(quit).Run();
+ },
+ loop.QuitClosure()),
+ base::TimeDelta::Max(), kMaxParallelRequests,
+ CreateCompositorService());
+ env.RunUntilIdle();
+ EXPECT_TRUE(player_compositor_delegate.WasStatusChecked());
+
+ player_compositor_delegate.OnMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ loop.Run();
+ }
+ env.RunUntilIdle();
+}
+
+TEST_F(PlayerCompositorDelegateTest, CriticalMemoryPressureBeforeStart) {
+ auto* service = GetBaseService();
+ auto file_manager = service->GetFileManager();
+ auto key = file_manager->CreateKey(1U);
+ {
+ // This test skips setting up files as the fakes don't use them. In normal
+ // execution the files are required by the service or no bitmap will be
+ // created.
+ base::RunLoop loop;
+ PlayerCompositorDelegateImpl player_compositor_delegate;
+ util::test::FakeMemoryPressureMonitor memory_pressure_monitor;
+ memory_pressure_monitor.SetAndNotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ player_compositor_delegate.SetFakeMemoryPressureMonitor(
+ &memory_pressure_monitor);
+ player_compositor_delegate.Initialize(
+ service, GURL(), key,
+ base::BindOnce(
+ [](base::OnceClosure quit, int compositor_status) {
+ EXPECT_EQ(compositor_status,
+ static_cast<int>(
+ CompositorStatus::SKIPPED_DUE_TO_MEMORY_PRESSURE));
+ std::move(quit).Run();
+ },
+ loop.QuitClosure()),
+ base::TimeDelta::Max(), kMaxParallelRequests);
+ env.RunUntilIdle();
+
+ player_compositor_delegate.OnMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ loop.Run();
+ }
+ env.RunUntilIdle();
+}
+
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
index cdad89eb447..71867bc8c08 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
@@ -63,14 +63,16 @@ class PaintPreviewRecorderRenderViewTest : public content::RenderViewTest {
base::FilePath RunCapture(content::RenderFrame* frame,
mojom::PaintPreviewCaptureResponsePtr* out_response,
- bool is_main_frame = true) {
+ bool is_main_frame = true,
+ gfx::Rect clip_rect = gfx::Rect()) {
base::FilePath skp_path = MakeTestFilePath("test.skp");
mojom::PaintPreviewCaptureParamsPtr params =
mojom::PaintPreviewCaptureParams::New();
auto token = base::UnguessableToken::Create();
params->guid = token;
- params->clip_rect = gfx::Rect();
+ params->clip_rect = clip_rect;
+ params->clip_rect_is_hint = false;
params->is_main_frame = is_main_frame;
params->capture_links = true;
base::File skp_file(
@@ -138,7 +140,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndClipping) {
SkBitmap bitmap;
ASSERT_TRUE(bitmap.tryAllocN32Pixels(pic->cullRect().width(),
pic->cullRect().height()));
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.drawPicture(pic);
// This should be inside the top right corner of the first top level div.
// Success means there was no horizontal clipping as this region is red,
@@ -191,7 +193,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameWithScroll) {
SkBitmap bitmap;
ASSERT_TRUE(bitmap.tryAllocN32Pixels(pic->cullRect().width(),
pic->cullRect().height()));
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.drawPicture(pic);
// This should be inside the top right corner of the top div. Success means
// there was no horizontal or vertical clipping as this region is red,
@@ -291,6 +293,52 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureLocalFrame) {
EXPECT_EQ(out_response->content_id_to_embedding_token.size(), 0U);
}
+TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureCustomClipRect) {
+ LoadHTML(
+ "<!doctype html>"
+ "<body>"
+ " <div style='width: 600px; height: 600px; background-color: #0000ff;'>"
+ " <div style='width: 300px; height: 300px; background-color: "
+ " #ffff00; position: relative; left: 150px; top: 150px'></div>"
+ " </div>"
+ " <a style='position: absolute; left: 160px; top: 170px; width: 40px; "
+ " height: 30px;' href='http://www.example.com'>Foo</a>"
+ "</body>");
+
+ auto out_response = mojom::PaintPreviewCaptureResponse::New();
+ content::RenderFrame* frame = GetFrame();
+ gfx::Rect clip_rect = gfx::Rect(150, 150, 300, 300);
+ base::FilePath skp_path = RunCapture(frame, &out_response, true, clip_rect);
+
+ EXPECT_TRUE(out_response->embedding_token.has_value());
+ EXPECT_EQ(frame->GetWebFrame()->GetEmbeddingToken(),
+ out_response->embedding_token.value());
+ EXPECT_EQ(out_response->content_id_to_embedding_token.size(), 0U);
+
+ sk_sp<SkPicture> pic;
+ {
+ base::ScopedAllowBlockingForTesting scope;
+ FileRStream rstream(base::File(
+ skp_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ));
+ pic = SkPicture::MakeFromStream(&rstream, nullptr);
+ }
+ EXPECT_EQ(pic->cullRect().height(), 300);
+ EXPECT_EQ(pic->cullRect().width(), 300);
+ SkBitmap bitmap;
+ ASSERT_TRUE(bitmap.tryAllocN32Pixels(pic->cullRect().width(),
+ pic->cullRect().height()));
+ SkCanvas canvas(bitmap);
+ canvas.drawPicture(pic);
+ EXPECT_EQ(bitmap.getColor(100, 100), 0xFFFFFF00U);
+
+ ASSERT_EQ(out_response->links.size(), 1U);
+ EXPECT_EQ(out_response->links[0]->url, GURL("http://www.example.com"));
+ EXPECT_EQ(out_response->links[0]->rect.x(), 10);
+ EXPECT_EQ(out_response->links[0]->rect.y(), 20);
+ EXPECT_EQ(out_response->links[0]->rect.width(), 40);
+ EXPECT_EQ(out_response->links[0]->rect.height(), 30);
+}
+
TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithTranslate) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
index e00a7f3380f..b01d7d51d4c 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
@@ -163,7 +163,7 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
DCHECK_EQ(is_main_frame_, params->is_main_frame);
// Default to using the clip rect.
- gfx::Rect bounds = gfx::Rect(params->clip_rect.size());
+ gfx::Rect bounds = params->clip_rect;
if (bounds.IsEmpty() || params->clip_rect_is_hint) {
// If the clip rect is empty or only a hint try to use the document size.
auto size = frame->DocumentSize();
@@ -192,6 +192,8 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
cc::PaintRecorder recorder;
cc::PaintCanvas* canvas =
recorder.beginRecording(bounds.width(), bounds.height());
+ canvas->save();
+ canvas->concat(SkMatrix::Translate(-bounds.x(), -bounds.y()));
canvas->SetPaintPreviewTracker(tracker.get());
// Use time ticks manually rather than a histogram macro so as to;
@@ -204,6 +206,7 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
bool success = frame->CapturePaintPreview(
bounds, canvas, /*include_linked_destinations=*/params->capture_links);
TRACE_EVENT_END0("paint_preview", "WebLocalFrame::CapturePaintPreview");
+ canvas->restore();
base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
response->blink_recording_time = capture_time;
@@ -240,6 +243,9 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
max_capture_size = base::nullopt;
} else {
max_capture_size = params->max_capture_size;
+ auto* image_ctx = tracker->GetImageSerializationContext();
+ image_ctx->remaining_image_size = params->max_capture_size;
+ image_ctx->max_representation_size = params->max_capture_size;
}
// This cannot be done async if the recording contains a GPU accelerated
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
index af61ed71140..372f53e559b 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
@@ -106,8 +106,6 @@ sk_sp<const SkPicture> PaintRecordToSkPicture(
base::BindRepeating(&PaintPreviewTracker::CustomDataToSkPictureCallback,
base::Unretained(tracker));
- DCHECK_EQ(bounds.x(), 0);
- DCHECK_EQ(bounds.y(), 0);
auto skp =
ToSkPicture(recording, SkRect::MakeWH(bounds.width(), bounds.height()),
nullptr, custom_callback);
diff --git a/chromium/components/password_manager/content/browser/bad_message.cc b/chromium/components/password_manager/content/browser/bad_message.cc
index 73b6e360b4c..5f876d5d5b2 100644
--- a/chromium/components/password_manager/content/browser/bad_message.cc
+++ b/chromium/components/password_manager/content/browser/bad_message.cc
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/syslog_logging.h"
-#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_form.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
@@ -55,10 +55,9 @@ bool CheckChildProcessSecurityPolicyForURL(content::RenderFrameHost* frame,
return true;
}
-bool CheckChildProcessSecurityPolicy(
- content::RenderFrameHost* frame,
- const autofill::PasswordForm& password_form,
- BadMessageReason reason) {
+bool CheckChildProcessSecurityPolicy(content::RenderFrameHost* frame,
+ const PasswordForm& password_form,
+ BadMessageReason reason) {
return CheckChildProcessSecurityPolicyForURL(frame, password_form.url,
reason) &&
CheckChildProcessSecurityPolicyForURL(
@@ -67,10 +66,9 @@ bool CheckChildProcessSecurityPolicy(
frame, password_form.form_data.url, reason);
}
-bool CheckChildProcessSecurityPolicy(
- content::RenderFrameHost* frame,
- const std::vector<autofill::PasswordForm>& forms,
- BadMessageReason reason) {
+bool CheckChildProcessSecurityPolicy(content::RenderFrameHost* frame,
+ const std::vector<PasswordForm>& forms,
+ BadMessageReason reason) {
for (const auto& form : forms) {
if (!bad_message::CheckChildProcessSecurityPolicy(frame, form, reason))
return false;
diff --git a/chromium/components/password_manager/content/browser/bad_message.h b/chromium/components/password_manager/content/browser/bad_message.h
index 5d1a692f17c..06b2f97f2bd 100644
--- a/chromium/components/password_manager/content/browser/bad_message.h
+++ b/chromium/components/password_manager/content/browser/bad_message.h
@@ -6,17 +6,17 @@
#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_BAD_MESSAGE_H_
#include <vector>
-#include "components/autofill/core/common/form_data.h"
-namespace autofill {
-struct PasswordForm;
-}
+#include "components/autofill/core/common/form_data.h"
namespace content {
class RenderFrameHost;
}
namespace password_manager {
+
+struct PasswordForm;
+
// The browser process often chooses to terminate a renderer if it receives
// a bad IPC message. The reasons are tracked for metrics.
//
@@ -61,17 +61,15 @@ bool CheckChildProcessSecurityPolicyForURL(content::RenderFrameHost* frame,
// on |password_form|. If the origin mismatches, the process for |frame| is
// terminated and the function returns false.
// TODO: Delete this signature after transferring all driver calls to FormData
-bool CheckChildProcessSecurityPolicy(
- content::RenderFrameHost* frame,
- const autofill::PasswordForm& password_form,
- BadMessageReason reason);
+bool CheckChildProcessSecurityPolicy(content::RenderFrameHost* frame,
+ const PasswordForm& password_form,
+ BadMessageReason reason);
// Same as above but checks every form in |forms|.
// TODO: Delete this signature after transferring all driver calls to FormData
-bool CheckChildProcessSecurityPolicy(
- content::RenderFrameHost* frame,
- const std::vector<autofill::PasswordForm>& forms,
- BadMessageReason reason);
+bool CheckChildProcessSecurityPolicy(content::RenderFrameHost* frame,
+ const std::vector<PasswordForm>& forms,
+ BadMessageReason reason);
bool CheckChildProcessSecurityPolicy(
content::RenderFrameHost* frame,
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
index 3a015aa3cb9..a6a92b69ec4 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -11,7 +11,6 @@
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/bad_message.h"
#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -209,10 +208,9 @@ void ContentPasswordManagerDriver::AnnotateFieldsWithParsingResult(
}
void ContentPasswordManagerDriver::GeneratePassword(
- autofill::mojom::PasswordGenerationAgent::
- UserTriggeredGeneratePasswordCallback callback) {
- GetPasswordGenerationAgent()->UserTriggeredGeneratePassword(
- std::move(callback));
+ autofill::mojom::PasswordGenerationAgent::TriggeredGeneratePasswordCallback
+ callback) {
+ GetPasswordGenerationAgent()->TriggeredGeneratePassword(std::move(callback));
}
void ContentPasswordManagerDriver::PasswordFormsParsed(
@@ -274,6 +272,11 @@ void ContentPasswordManagerDriver::SameDocumentNavigation(
LogSiteIsolationMetricsForSubmittedForm(render_frame_host_);
}
+void ContentPasswordManagerDriver::PasswordFormCleared(
+ const autofill::FormData& form_data) {
+ GetPasswordManager()->OnPasswordFormCleared(this, form_data);
+}
+
void ContentPasswordManagerDriver::RecordSavePasswordProgress(
const std::string& log) {
client_->GetLogManager()->LogTextMessage(log);
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
index 0d6354cbbae..23f4bc9c6fa 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
@@ -81,9 +81,9 @@ class ContentPasswordManagerDriver
void AnnotateFieldsWithParsingResult(
const autofill::ParsingResult& parsing_result) override;
- // Notify the renderer that the user wants to generate password manually.
+ // Notify the renderer that the user wants to trigger password generation.
void GeneratePassword(autofill::mojom::PasswordGenerationAgent::
- UserTriggeredGeneratePasswordCallback callback);
+ TriggeredGeneratePasswordCallback callback);
content::RenderFrameHost* render_frame_host() const {
return render_frame_host_;
@@ -103,6 +103,7 @@ class ContentPasswordManagerDriver
void InformAboutUserInput(const autofill::FormData& form_data) override;
void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
submission_indication_event) override;
+ void PasswordFormCleared(const autofill::FormData& form_data) override;
void RecordSavePasswordProgress(const std::string& log) override;
void UserModifiedPasswordField() override;
void UserModifiedNonPasswordField(autofill::FieldRendererId renderer_id,
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index 1d309b25f3a..e49c1ea12d3 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -12,7 +12,6 @@
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/content/browser/form_submission_tracker_util.h"
#include "components/password_manager/core/browser/password_manager_client.h"
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 66ca88b17ce..711d0f25411 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -29,7 +29,6 @@
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
using autofill::ParsingResult;
-using autofill::PasswordForm;
using autofill::PasswordFormFillData;
using base::ASCIIToUTF16;
using testing::_;
@@ -41,7 +40,7 @@ namespace {
class MockLogManager : public autofill::StubLogManager {
public:
- MOCK_CONST_METHOD0(IsLoggingActive, bool(void));
+ MOCK_METHOD(bool, IsLoggingActive, (), (const override));
};
class MockPasswordManagerClient : public StubPasswordManagerClient {
@@ -49,9 +48,12 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MockPasswordManagerClient() = default;
~MockPasswordManagerClient() override = default;
- MOCK_CONST_METHOD0(GetLogManager, const autofill::LogManager*());
+ MOCK_METHOD(const autofill::LogManager*, GetLogManager, (), (const override));
#if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
- MOCK_METHOD2(CheckSafeBrowsingReputation, void(const GURL&, const GURL&));
+ MOCK_METHOD(void,
+ CheckSafeBrowsingReputation,
+ (const GURL&, const GURL&),
+ (override));
#endif
private:
@@ -77,13 +79,20 @@ class FakePasswordAutofillAgent
}
// autofill::mojom::PasswordAutofillAgent:
- MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
- MOCK_METHOD1(InformNoSavedCredentials, void(bool));
- MOCK_METHOD2(FillIntoFocusedField, void(bool, const base::string16&));
- MOCK_METHOD1(TouchToFillClosed, void(bool));
- MOCK_METHOD1(AnnotateFieldsWithParsingResult, void(const ParsingResult&));
-
- MOCK_METHOD0(BlacklistedFormFound, void());
+ MOCK_METHOD(void,
+ FillPasswordForm,
+ (const PasswordFormFillData&),
+ (override));
+ MOCK_METHOD(void, InformNoSavedCredentials, (bool), (override));
+ MOCK_METHOD(void,
+ FillIntoFocusedField,
+ (bool, const base::string16&),
+ (override));
+ MOCK_METHOD(void, TouchToFillClosed, (bool), (override));
+ MOCK_METHOD(void,
+ AnnotateFieldsWithParsingResult,
+ (const ParsingResult&),
+ (override));
private:
void SetLoggingState(bool active) override {
@@ -226,16 +235,6 @@ TEST_F(ContentPasswordManagerDriverTest, ClearPasswordsOnAutofill) {
base::RunLoop().RunUntilIdle();
}
-TEST_F(ContentPasswordManagerDriverTest, NotInformAboutBlacklistedForm) {
- std::unique_ptr<ContentPasswordManagerDriver> driver(
- new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
- &autofill_client_));
-
- PasswordFormFillData fill_data = GetTestPasswordFormFillData();
- EXPECT_CALL(fake_agent_, BlacklistedFormFound()).Times(0);
- driver->FillPasswordForm(fill_data);
-}
-
INSTANTIATE_TEST_SUITE_P(All,
ContentPasswordManagerDriverTest,
testing::Values(true, false));
diff --git a/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc b/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
index 277183e29fd..d59187aa3cd 100644
--- a/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
+++ b/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
@@ -102,6 +102,9 @@ bool EnumTraits<blink::mojom::CredentialManagerError,
case blink::mojom::CredentialManagerError::OPAQUE_DOMAIN:
case blink::mojom::CredentialManagerError::INVALID_PROTOCOL:
case blink::mojom::CredentialManagerError::BAD_RELYING_PARTY_ID:
+ case blink::mojom::CredentialManagerError::CANNOT_READ_AND_WRITE_LARGE_BLOB:
+ case blink::mojom::CredentialManagerError::
+ INVALID_ALLOW_CREDENTIALS_FOR_LARGE_BLOB:
case blink::mojom::CredentialManagerError::UNKNOWN:
*output = password_manager::CredentialManagerError::UNKNOWN;
return true;
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index e3a66b10927..930ff903a00 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -79,6 +79,8 @@ static_library("browser") {
"credential_manager_pending_prevent_silent_access_task.h",
"credential_manager_pending_request_task.cc",
"credential_manager_pending_request_task.h",
+ "credential_manager_utils.cc",
+ "credential_manager_utils.h",
"credentials_cleaner.cc",
"credentials_cleaner.h",
"credentials_cleaner_runner.cc",
@@ -175,6 +177,12 @@ static_library("browser") {
"password_manager_util.h",
"password_requirements_service.cc",
"password_requirements_service.h",
+ "password_reuse_detection_manager.cc",
+ "password_reuse_detection_manager.h",
+ "password_reuse_detector.cc",
+ "password_reuse_detector.h",
+ "password_reuse_detector_consumer.cc",
+ "password_reuse_detector_consumer.h",
"password_save_manager.h",
"password_save_manager_impl.cc",
"password_save_manager_impl.h",
@@ -182,7 +190,6 @@ static_library("browser") {
"password_session_durations_metrics_recorder.h",
"password_store.cc",
"password_store.h",
- "password_store_change.cc",
"password_store_change.h",
"password_store_consumer.cc",
"password_store_consumer.h",
@@ -190,6 +197,8 @@ static_library("browser") {
"password_store_default.h",
"password_store_factory_util.cc",
"password_store_factory_util.h",
+ "password_store_signin_notifier.cc",
+ "password_store_signin_notifier.h",
"password_store_sync.cc",
"password_store_sync.h",
"password_sync_util.cc",
@@ -211,6 +220,8 @@ static_library("browser") {
"site_affiliation/affiliation_service_impl.h",
"site_affiliation/asset_link_data.cc",
"site_affiliation/asset_link_data.h",
+ "site_affiliation/hash_affiliation_fetcher.cc",
+ "site_affiliation/hash_affiliation_fetcher.h",
"sql_table_builder.cc",
"sql_table_builder.h",
"statistics_table.cc",
@@ -253,19 +264,6 @@ static_library("browser") {
all_dependent_configs = [ ":password_reuse_detection_config" ]
- if (password_reuse_detection_support) {
- sources += [
- "password_reuse_detection_manager.cc",
- "password_reuse_detection_manager.h",
- "password_reuse_detector.cc",
- "password_reuse_detector.h",
- "password_reuse_detector_consumer.cc",
- "password_reuse_detector_consumer.h",
- "password_store_signin_notifier.cc",
- "password_store_signin_notifier.h",
- ]
- }
-
public_deps = [
":password_form",
"//base",
@@ -408,10 +406,15 @@ source_set("csv_unittests") {
# cyclic dependencies.
source_set("password_form") {
sources = [
+ "password_form.cc",
"password_form.h",
- "password_form_forward.h",
]
- deps = [ "//components/autofill/core/common" ]
+ deps = [
+ "//base",
+ "//components/autofill/core/common",
+ "//components/autofill/core/common/mojom:mojo_types_shared",
+ "//url",
+ ]
}
static_library("password_generator") {
@@ -508,6 +511,8 @@ static_library("test_support") {
"stub_password_manager_client.h",
"stub_password_manager_driver.cc",
"stub_password_manager_driver.h",
+ "sync_username_test_base.cc",
+ "sync_username_test_base.h",
"test_password_store.cc",
"test_password_store.h",
]
@@ -515,13 +520,18 @@ static_library("test_support") {
public_deps = [
":browser",
":hash_password_manager",
+ ":password_hash_data",
+ "//base/test:test_support",
"//components/autofill/core/browser:test_support",
"//components/keyed_service/core",
"//components/password_manager/core/browser/leak_detection",
"//components/safe_browsing:buildflags",
+ "//components/signin/public/identity_manager:test_support",
+ "//components/sync:test_support",
"//components/ukm",
"//services/network/public/cpp",
"//testing/gmock",
+ "//testing/gtest",
"//url",
]
deps = [
@@ -529,7 +539,6 @@ static_library("test_support") {
"//base",
"//components/autofill/core/common",
"//net:net",
- "//testing/gtest",
]
}
@@ -598,6 +607,7 @@ source_set("unit_tests") {
"credential_manager_password_form_manager_unittest.cc",
"credential_manager_pending_prevent_silent_access_task_unittest.cc",
"credential_manager_pending_request_task_unittest.cc",
+ "credential_manager_utils_unittest.cc",
"credentials_cleaner_runner_unittest.cc",
"credentials_cleaner_unittest.cc",
"export/csv_writer_unittest.cc",
@@ -638,6 +648,8 @@ source_set("unit_tests") {
"password_manager_unittest.cc",
"password_manager_util_unittest.cc",
"password_requirements_service_unittest.cc",
+ "password_reuse_detection_manager_unittest.cc",
+ "password_reuse_detector_unittest.cc",
"password_save_manager_impl_unittest.cc",
"password_store_default_unittest.cc",
"password_store_origin_unittest.h",
@@ -646,15 +658,15 @@ source_set("unit_tests") {
"password_ui_utils_unittest.cc",
"possible_username_data_unittest.cc",
"psl_matching_helper_unittest.cc",
+ "site_affiliation/affiliation_fetcher_factory_impl_unittest.cc",
"site_affiliation/affiliation_service_impl_unittest.cc",
"site_affiliation/asset_link_data_unittest.cc",
+ "site_affiliation/hash_affiliation_fetcher_unittest.cc",
"sql_table_builder_unittest.cc",
"statistics_table_unittest.cc",
"store_metrics_reporter_unittest.cc",
"sync/password_sync_bridge_unittest.cc",
"sync_credentials_filter_unittest.cc",
- "sync_username_test_base.cc",
- "sync_username_test_base.h",
"ui/bulk_leak_check_service_adapter_unittest.cc",
"ui/compromised_credentials_reader_unittest.cc",
"ui/insecure_credentials_manager_unittest.cc",
@@ -677,12 +689,6 @@ source_set("unit_tests") {
} else {
sources += [ "http_credentials_cleaner_unittest.cc" ]
}
- if (password_reuse_detection_support) {
- sources += [
- "password_reuse_detection_manager_unittest.cc",
- "password_reuse_detector_unittest.cc",
- ]
- }
if (is_win || is_mac || is_linux || is_chromeos) {
sources += [ "hash_password_manager_unittest.cc" ]
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
index 6e00bb5774f..e31ac36670e 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
@@ -15,13 +15,13 @@
#include "base/time/time.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/android_affiliation/android_affiliation_service.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
namespace password_manager {
class AndroidAffiliationService;
+struct PasswordForm;
// Interacts with the AndroidAffiliationService on behalf of the PasswordStore.
// For each GetLogins() request, it provides the PasswordStore with a list of
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
index a82165f1df5..3ea45ef34ef 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
@@ -9,7 +9,7 @@
#include <utility>
#include "base/macros.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_move_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/null_task_runner.h"
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/android_affiliation_service.cc b/chromium/components/password_manager/core/browser/android_affiliation/android_affiliation_service.cc
index 21f8d99239e..1f0bc73a114 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/android_affiliation_service.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/android_affiliation_service.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
index 9e9bd6afcdd..b48097fd92a 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
@@ -10,7 +10,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/rand_util.h"
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
index 08682d1c528..907b7eca825 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
@@ -15,8 +15,6 @@ template <typename MessageT>
bool ParseFacets(const std::vector<FacetURI>& requested_facet_uris,
const MessageT& response,
std::vector<std::vector<Facet>>& result) {
- result.reserve(requested_facet_uris.size());
-
std::map<FacetURI, size_t> facet_uri_to_class_index;
for (const auto& equivalence_class : response) {
std::vector<Facet> facets;
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
index 30879d4a4e1..e676d0ef79d 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
+++ b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
@@ -11,13 +11,14 @@
#include "base/macros.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace password_manager {
+struct PasswordForm;
+
class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
public:
// This struct mirrors the corresponding affiliation and branding information
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
index 3cf95836f13..411c6ad3519 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.cc
@@ -5,7 +5,7 @@
#include "components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
namespace password_manager {
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index e6037b494ed..5f1fa0d169d 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -4,7 +4,9 @@
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include <string>
#include <utility>
+#include <vector>
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
@@ -22,6 +24,7 @@
using autofill::AutofillUploadContents;
using autofill::FieldPropertiesFlags;
+using autofill::FieldTypeToStringPiece;
using autofill::FormStructure;
using autofill::PasswordAttribute;
using autofill::ServerFieldType;
@@ -208,16 +211,23 @@ std::string BrowserSavePasswordProgressLogger::FormStructureToFieldsLogString(
", autocomplete=" + ScrubElementID(field->autocomplete_attribute);
if (field->server_type() != autofill::NO_SERVER_DATA) {
+ base::StrAppend(
+ &field_info,
+ {", Server Type: ", FieldTypeToStringPiece(field->server_type())});
+
+ std::vector<std::string> all_predictions;
+ for (const auto& p : field->server_predictions()) {
+ all_predictions.emplace_back(
+ FieldTypeToStringPiece(static_cast<ServerFieldType>(p.type())));
+ }
+
base::StrAppend(&field_info,
- {", SERVER_PREDICTION: ",
- autofill::AutofillType::ServerFieldTypeToString(
- field->server_type())});
+ {", All Server Predictions: [",
+ base::JoinString(all_predictions, ", "), "]"});
}
for (ServerFieldType type : field->possible_types())
- base::StrAppend(
- &field_info,
- {", VOTE: ", autofill::AutofillType::ServerFieldTypeToString(type)});
+ base::StrAppend(&field_info, {", VOTE: ", FieldTypeToStringPiece(type)});
if (field->vote_type())
field_info += ", vote_type=" + VoteTypeToString(field->vote_type());
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
index 4efc573d7d0..6cfbac4b787 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "url/gurl.h"
namespace autofill {
@@ -20,6 +19,8 @@ class LogManager;
namespace password_manager {
+struct PasswordForm;
+
// This is the SavePasswordProgressLogger specialization for the browser code,
// where the LogManager can be directly called.
class BrowserSavePasswordProgressLogger
diff --git a/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc b/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
index 356c26bc91b..4d78678f383 100644
--- a/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
@@ -7,8 +7,8 @@
#include "components/password_manager/core/browser/compromised_credentials_table.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
diff --git a/chromium/components/password_manager/core/browser/credential_cache.h b/chromium/components/password_manager/core/browser/credential_cache.h
index 817f8c8cd10..60c085a2a79 100644
--- a/chromium/components/password_manager/core/browser/credential_cache.h
+++ b/chromium/components/password_manager/core/browser/credential_cache.h
@@ -9,12 +9,12 @@
#include "base/strings/string16.h"
#include "base/util/type_safety/strong_alias.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "url/origin.h"
namespace password_manager {
class OriginCredentialStore;
+struct PasswordForm;
// This class caches and provides credential stores for different origins.
class CredentialCache {
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl.cc b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
index aa5957b8bc2..f755962375e 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -10,6 +10,8 @@
#include "base/bind.h"
#include "base/metrics/user_metrics.h"
#include "components/password_manager/core/browser/credential_manager_logger.h"
+#include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
+#include "components/password_manager/core/browser/credential_manager_utils.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/password_manager_util.h"
@@ -130,7 +132,7 @@ void CredentialManagerImpl::Get(CredentialMediationRequirement mediation,
return;
}
// Return an empty credential while autofill-assistant is running.
- if (client_->GetAutofillAssistantMode() == AutofillAssistantMode::kUIShown) {
+ if (client_->IsAutofillAssistantUIVisible()) {
// Callback with empty credential info.
std::move(callback).Run(CredentialManagerError::SUCCESS, CredentialInfo());
LogCredentialManagerGetResult(
@@ -197,11 +199,7 @@ void CredentialManagerImpl::SendPasswordForm(
const PasswordForm* form) {
CredentialInfo info;
if (form) {
- password_manager::CredentialType type_to_return =
- form->federation_origin.opaque()
- ? CredentialType::CREDENTIAL_TYPE_PASSWORD
- : CredentialType::CREDENTIAL_TYPE_FEDERATED;
- info = CredentialInfo(*form, type_to_return);
+ info = PasswordFormToCredentialInfo(*form);
PasswordStore* store = form->IsUsingAccountStore()
? GetAccountPasswordStore()
: GetProfilePasswordStore();
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 70540be141d..bafaebcef65 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -14,7 +14,7 @@
#include <tuple>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
@@ -22,6 +22,8 @@
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
+#include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
+#include "components/password_manager/core/browser/credential_manager_utils.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
#include "components/password_manager/core/browser/leak_detection/mock_leak_detection_check_factory.h"
@@ -76,7 +78,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
void(const std::vector<const PasswordForm*>&,
const url::Origin&,
const std::vector<const PasswordForm*>*));
- MOCK_CONST_METHOD0(GetAutofillAssistantMode, AutofillAssistantMode());
+ MOCK_CONST_METHOD0(IsAutofillAssistantUIVisible, bool());
explicit MockPasswordManagerClient(PasswordStore* profile_store,
PasswordStore* account_store)
@@ -94,6 +96,8 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
true);
prefs_->registry()->RegisterBooleanPref(::prefs::kSafeBrowsingEnhanced,
false);
+ ON_CALL(*this, IsAutofillAssistantUIVisible)
+ .WillByDefault(testing::Return(false));
}
~MockPasswordManagerClient() override = default;
@@ -410,7 +414,7 @@ TEST_P(CredentialManagerImplTest, IsZeroClickAllowed) {
}
TEST_P(CredentialManagerImplTest, CredentialManagerOnStore) {
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -445,7 +449,7 @@ TEST_P(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
form_.federation_origin = url::Origin::Create(GURL("https://google.com/"));
form_.password_value = base::string16();
form_.signon_realm = "federation://example.com/google.com";
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(form_);
CallStore(info, base::BindOnce(&RespondCallback, &called));
// Allow the PasswordFormManager to talk to the password store, determine
@@ -476,7 +480,7 @@ TEST_P(CredentialManagerImplTest, StoreFederatedAfterPassword) {
federated.federation_origin =
url::Origin::Create(GURL("https://google.com/"));
federated.signon_realm = "federation://example.com/google.com";
- CredentialInfo info(federated, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(federated);
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -513,7 +517,7 @@ TEST_P(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
// Calling 'Store' with a credential that matches |form_| should update
// the password without prompting the user.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
info.password = base::ASCIIToUTF16("Totally new password.");
info.name = base::ASCIIToUTF16("New Name");
info.icon = GURL("https://example.com/icon.png");
@@ -551,7 +555,7 @@ TEST_P(CredentialManagerImplTest,
// Calling 'Store' with a new credential that is a PSL match for an existing
// credential with identical username and password should result in a silent
// save without prompting the user.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -578,7 +582,7 @@ TEST_P(CredentialManagerImplTest,
// Calling 'Store' with a new credential that is a PSL match for an existing
// credential but has a different username should prompt the user and not
// result in a silent save.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -610,7 +614,7 @@ TEST_P(CredentialManagerImplTest,
// Calling 'Store' with a new credential that is a PSL match for an existing
// credential but has a different password should prompt the user and not
// result in a silent save.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
.Times(testing::Exactly(1));
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
@@ -638,7 +642,7 @@ TEST_P(CredentialManagerImplTest, CredentialManagerStoreOverwriteZeroClick) {
// Calling 'Store' with a credential that matches |form_| should update
// the credential without prompting the user.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -663,7 +667,7 @@ TEST_P(CredentialManagerImplTest,
// Calling 'Store' with a credential that matches |form_| should update
// the credential without prompting the user.
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
EXPECT_CALL(*client_, NotifyStorePasswordCalled());
CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -712,7 +716,7 @@ TEST_P(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
TEST_P(CredentialManagerImplTest,
CredentialManagerSignInWithSavingDisabledForCurrentPage) {
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
EXPECT_CALL(*client_, IsSavingAndFillingEnabled(form_.url))
.WillRepeatedly(testing::Return(false));
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
@@ -1453,8 +1457,8 @@ TEST_P(CredentialManagerImplTest, AutofillAssistantZeroClickRequestCredential) {
.Times(testing::Exactly(0));
EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(false));
- EXPECT_CALL(*client_, GetAutofillAssistantMode())
- .WillRepeatedly(testing::Return(AutofillAssistantMode::kUIShown));
+ EXPECT_CALL(*client_, IsAutofillAssistantUIVisible())
+ .WillRepeatedly(testing::Return(true));
ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
@@ -1650,7 +1654,7 @@ TEST_P(CredentialManagerImplTest, GetBlockedPasswordCredential) {
TEST_P(CredentialManagerImplTest, BlockedPasswordCredential) {
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
CallStore(info, base::BindOnce(&RespondCallback, &called));
// Allow the PasswordFormManager to talk to the password store
@@ -1678,7 +1682,7 @@ TEST_P(CredentialManagerImplTest, BlockedFederatedCredential) {
form_.signon_realm = "federation://example.com/example.com";
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
CallStore(info, base::BindOnce(&RespondCallback, &called));
// Allow the PasswordFormManager to talk to the password store
@@ -1709,7 +1713,7 @@ TEST_P(CredentialManagerImplTest, RespecBlockedPasswordCredential) {
blocked_form.signon_realm = blocked_form.url.spec();
store_->AddLogin(blocked_form);
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -1730,7 +1734,7 @@ TEST_P(CredentialManagerImplTest, RespectBlockedFederatedCredential) {
form_.federation_origin = url::Origin::Create(GURL("https://example.com/"));
form_.password_value = base::string16();
form_.signon_realm = "federation://example.com/example.com";
- CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(form_);
bool called = false;
EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -1783,8 +1787,7 @@ TEST_P(CredentialManagerImplTest,
form_.federation_origin = url::Origin::Create(GURL("https://example.com/"));
form_.password_value = base::string16();
form_.signon_realm = "federation://example.com/example.com";
- CallStore({form_, CredentialType::CREDENTIAL_TYPE_FEDERATED},
- base::DoNothing());
+ CallStore(PasswordFormToCredentialInfo(form_), base::DoNothing());
RunAllPendingTasks();
}
@@ -1802,8 +1805,7 @@ TEST_P(CredentialManagerImplTest, StorePasswordCredentialStartsLeakDetection) {
Start(form_.url, form_.username_value, form_.password_value));
EXPECT_CALL(*weak_factory, TryCreateLeakCheck)
.WillOnce(testing::Return(testing::ByMove(std::move(check_instance))));
- CallStore({form_, CredentialType::CREDENTIAL_TYPE_PASSWORD},
- base::DoNothing());
+ CallStore(PasswordFormToCredentialInfo(form_), base::DoNothing());
RunAllPendingTasks();
}
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
index 0c7aec4e009..ff320b5f8c4 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.h
@@ -7,12 +7,12 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_form_manager.h"
namespace password_manager {
class PasswordManagerClient;
+struct PasswordForm;
// A delegate that is notified when CredentialManagerPasswordFormManager
// finishes working with password forms.
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 22dc475dec8..dc9a51e13a2 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -17,6 +17,7 @@
#include "base/metrics/user_metrics.h"
#include "base/stl_util.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
+#include "components/password_manager/core/browser/credential_manager_utils.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_client.h"
@@ -241,10 +242,7 @@ void CredentialManagerPendingRequestTask::ProcessForms(
if (can_use_autosignin && !local_results[0]->skip_zero_click &&
!password_bubble_experiment::ShouldShowAutoSignInPromptFirstRunExperience(
delegate_->client()->GetPrefs())) {
- CredentialInfo info(*local_results[0],
- local_results[0]->federation_origin.opaque()
- ? CredentialType::CREDENTIAL_TYPE_PASSWORD
- : CredentialType::CREDENTIAL_TYPE_FEDERATED);
+ auto info = PasswordFormToCredentialInfo(*local_results[0]);
delegate_->client()->NotifyUserAutoSignin(std::move(local_results),
origin_);
base::RecordAction(base::UserMetricsAction("CredentialManager_Autosignin"));
diff --git a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
index 52bcdf02100..ed4a9ddb69b 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/chromium/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -13,7 +13,6 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "components/password_manager/core/browser/http_password_store_migrator.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/common/credential_manager_types.h"
@@ -23,6 +22,7 @@
namespace password_manager {
struct CredentialInfo;
+struct PasswordForm;
class PasswordManagerClient;
using SendCredentialCallback =
diff --git a/chromium/components/password_manager/core/browser/credential_manager_utils.cc b/chromium/components/password_manager/core/browser/credential_manager_utils.cc
new file mode 100644
index 00000000000..b1212668f0c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/credential_manager_utils.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 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/password_manager/core/browser/credential_manager_utils.h"
+
+#include <memory>
+
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace password_manager {
+
+std::unique_ptr<PasswordForm> CreatePasswordFormFromCredentialInfo(
+ const CredentialInfo& info,
+ const url::Origin& origin) {
+ std::unique_ptr<PasswordForm> form;
+ if (info.type == CredentialType::CREDENTIAL_TYPE_EMPTY)
+ return form;
+
+ form = std::make_unique<PasswordForm>();
+ form->icon_url = info.icon;
+ form->display_name = info.name.value_or(base::string16());
+ form->federation_origin = info.federation;
+ form->url = origin.GetURL();
+ form->password_value = info.password.value_or(base::string16());
+ form->username_value = info.id.value_or(base::string16());
+ form->scheme = PasswordForm::Scheme::kHtml;
+ form->type = PasswordForm::Type::kApi;
+
+ form->signon_realm =
+ info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD
+ ? form->url.spec()
+ : "federation://" + origin.host() + "/" + info.federation.host();
+ return form;
+}
+
+CredentialInfo PasswordFormToCredentialInfo(const PasswordForm& form) {
+ return CredentialInfo(form.federation_origin.opaque()
+ ? CredentialType::CREDENTIAL_TYPE_PASSWORD
+ : CredentialType::CREDENTIAL_TYPE_FEDERATED,
+ form.username_value, form.display_name, form.icon_url,
+ form.password_value, form.federation_origin);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_utils.h b/chromium/components/password_manager/core/browser/credential_manager_utils.h
new file mode 100644
index 00000000000..a11e642bd88
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/credential_manager_utils.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_UTILS_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_UTILS_H_
+
+#include <memory>
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace password_manager {
+
+struct CredentialInfo;
+struct PasswordForm;
+
+// Create a new PasswordForm object based on |info|, valid in the
+// context of |origin|. Returns an empty std::unique_ptr for
+// CREDENTIAL_TYPE_EMPTY.
+std::unique_ptr<PasswordForm> CreatePasswordFormFromCredentialInfo(
+ const CredentialInfo& info,
+ const url::Origin& origin);
+
+// Creates a CredentialInfo object from `form`.
+CredentialInfo PasswordFormToCredentialInfo(const PasswordForm& form);
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CREDENTIAL_MANAGER_UTILS_H_
diff --git a/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_utils_unittest.cc
index 169faefe3b7..a772aefba66 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_utils_unittest.cc
@@ -1,43 +1,41 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2020 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/password_manager/core/common/credential_manager_types.h"
+#include "components/password_manager/core/browser/credential_manager_utils.h"
+
+#include <memory>
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace password_manager {
-class CredentialManagerTypesTest : public testing::Test {
- public:
- CredentialManagerTypesTest()
- : origin_(url::Origin::Create(GURL("https://example.test/"))),
- icon_(GURL("https://fast-cdn.test/icon.png")),
- federation_(url::Origin::Create(GURL("https://federation.test/"))) {}
-
+class CredentialManagerUtilsTest : public testing::Test {
protected:
- url::Origin origin_;
- GURL icon_;
- url::Origin federation_;
+ url::Origin origin_{url::Origin::Create(GURL("https://example.test/"))};
+ GURL icon_{"https://fast-cdn.test/icon.png"};
+ url::Origin federation_{
+ url::Origin::Create(GURL("https://federation.test/"))};
};
-TEST_F(CredentialManagerTypesTest, CreatePasswordFormEmpty) {
+TEST_F(CredentialManagerUtilsTest, CreatePasswordFormEmpty) {
CredentialInfo info;
- std::unique_ptr<autofill::PasswordForm> form;
+ std::unique_ptr<PasswordForm> form;
// Empty CredentialInfo -> nullptr.
form = CreatePasswordFormFromCredentialInfo(info, origin_);
EXPECT_EQ(nullptr, form.get());
}
-TEST_F(CredentialManagerTypesTest, CreatePasswordFormFederation) {
+TEST_F(CredentialManagerUtilsTest, CreatePasswordFormFederation) {
CredentialInfo info;
- std::unique_ptr<autofill::PasswordForm> form;
+ std::unique_ptr<PasswordForm> form;
info.id = base::ASCIIToUTF16("id");
info.name = base::ASCIIToUTF16("name");
@@ -48,11 +46,11 @@ TEST_F(CredentialManagerTypesTest, CreatePasswordFormFederation) {
form = CreatePasswordFormFromCredentialInfo(info, origin_);
ASSERT_NE(nullptr, form.get());
- EXPECT_EQ(autofill::PasswordForm::Type::kApi, form->type);
+ EXPECT_EQ(PasswordForm::Type::kApi, form->type);
EXPECT_EQ(info.icon, form->icon_url);
EXPECT_EQ(info.name, form->display_name);
EXPECT_EQ(origin_.GetURL(), form->url);
- EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
+ EXPECT_EQ(PasswordForm::Scheme::kHtml, form->scheme);
// Federated credentials have empty passwords, non-empty federation_origins,
// and funky signon realms.
@@ -61,9 +59,9 @@ TEST_F(CredentialManagerTypesTest, CreatePasswordFormFederation) {
EXPECT_EQ("federation://example.test/federation.test", form->signon_realm);
}
-TEST_F(CredentialManagerTypesTest, CreatePasswordFormLocal) {
+TEST_F(CredentialManagerUtilsTest, CreatePasswordFormLocal) {
CredentialInfo info;
- std::unique_ptr<autofill::PasswordForm> form;
+ std::unique_ptr<PasswordForm> form;
info.id = base::ASCIIToUTF16("id");
info.name = base::ASCIIToUTF16("name");
@@ -77,7 +75,7 @@ TEST_F(CredentialManagerTypesTest, CreatePasswordFormLocal) {
EXPECT_EQ(info.icon, form->icon_url);
EXPECT_EQ(info.name, form->display_name);
EXPECT_EQ(origin_.GetURL().spec(), form->url);
- EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
+ EXPECT_EQ(PasswordForm::Scheme::kHtml, form->scheme);
// Local credentials have empty federation_origins, non-empty passwords, and
// a signon realm that matches the origin.
diff --git a/chromium/components/password_manager/core/browser/credentials_cleaner.h b/chromium/components/password_manager/core/browser/credentials_cleaner.h
index c0b76ca7b4b..5191f2de862 100644
--- a/chromium/components/password_manager/core/browser/credentials_cleaner.h
+++ b/chromium/components/password_manager/core/browser/credentials_cleaner.h
@@ -8,10 +8,10 @@
#include <memory>
#include <vector>
-#include "components/password_manager/core/browser/password_form_forward.h"
-
namespace password_manager {
+struct PasswordForm;
+
// Interface that allows CredentialsCleanerRunner class to easily manipulate
// credential clean-ups that request credentials from PasswordStore.
// Every clean-up starts when StartCleaning is called and must call
diff --git a/chromium/components/password_manager/core/browser/credentials_cleaner_runner.cc b/chromium/components/password_manager/core/browser/credentials_cleaner_runner.cc
index 74784fdbd1d..2c524584051 100644
--- a/chromium/components/password_manager/core/browser/credentials_cleaner_runner.cc
+++ b/chromium/components/password_manager/core/browser/credentials_cleaner_runner.cc
@@ -23,8 +23,8 @@ bool CredentialsCleanerRunner::HasPendingTasks() const {
}
void CredentialsCleanerRunner::StartCleaning() {
- DCHECK(!cleaning_started_);
- cleaning_started_ = true;
+ if (cleaning_in_progress_)
+ return;
StartCleaningTask();
}
@@ -36,13 +36,15 @@ void CredentialsCleanerRunner::CleaningCompleted() {
}
void CredentialsCleanerRunner::StartCleaningTask() {
- if (!HasPendingTasks()) {
- // Delete the runner if no more clean-up is scheduled.
- delete this;
+ cleaning_in_progress_ = HasPendingTasks();
+ if (!cleaning_in_progress_)
return;
- }
cleaning_tasks_queue_.front()->StartCleaning(this);
}
+base::WeakPtr<CredentialsCleanerRunner> CredentialsCleanerRunner::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credentials_cleaner_runner.h b/chromium/components/password_manager/core/browser/credentials_cleaner_runner.h
index 333bdf4b2cf..dc4c53db85a 100644
--- a/chromium/components/password_manager/core/browser/credentials_cleaner_runner.h
+++ b/chromium/components/password_manager/core/browser/credentials_cleaner_runner.h
@@ -9,6 +9,8 @@
#include "base/containers/queue.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
#include "components/password_manager/core/browser/credentials_cleaner.h"
namespace password_manager {
@@ -17,14 +19,15 @@ namespace password_manager {
// order they are added. The runner is informed by the the clean-up tasks that
// the clean-up is finished when a clean-up task calls CleaningCompleted. This
// class will keep the clean-up object alive until the runner is notified that
-// the clean-up is finished.
+// the clean-up is finished, or until BrowserContext shutdown.
+//
// Usage:
// (1) Add cleaning tasks in the order the have to be executed.
// (2) After all cleaning task are added call StartCleaning().
-// Important note: The object will delete itself once all clean-ups are done,
-// thus it should not be allocated on the stack. Having a non-public destructor
-// enforces this.
-class CredentialsCleanerRunner : public CredentialsCleaner::Observer {
+//
+// Use CredentialsCleanerRunnerFactory to create this object.
+class CredentialsCleanerRunner : public CredentialsCleaner::Observer,
+ public KeyedService {
public:
CredentialsCleanerRunner();
~CredentialsCleanerRunner() override;
@@ -40,13 +43,17 @@ class CredentialsCleanerRunner : public CredentialsCleaner::Observer {
// CredentialsCleaner::Observer:
void CleaningCompleted() override;
+ base::WeakPtr<CredentialsCleanerRunner> GetWeakPtr();
+
private:
void StartCleaningTask();
- bool cleaning_started_ = false;
+ bool cleaning_in_progress_ = false;
base::queue<std::unique_ptr<CredentialsCleaner>> cleaning_tasks_queue_;
+ base::WeakPtrFactory<CredentialsCleanerRunner> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(CredentialsCleanerRunner);
};
diff --git a/chromium/components/password_manager/core/browser/credentials_cleaner_runner_unittest.cc b/chromium/components/password_manager/core/browser/credentials_cleaner_runner_unittest.cc
index 36632b97bb0..0b23a0f2c39 100644
--- a/chromium/components/password_manager/core/browser/credentials_cleaner_runner_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credentials_cleaner_runner_unittest.cc
@@ -25,44 +25,20 @@ class MockCredentialsCleaner : public CredentialsCleaner {
DISALLOW_COPY_AND_ASSIGN(MockCredentialsCleaner);
};
-class DestructionCheckableCleanerRunner : public CredentialsCleanerRunner {
- public:
- // |object_destroyed| is used to inform caller that the object destroyed
- // itself.
- explicit DestructionCheckableCleanerRunner(bool* object_destroyed)
- : object_destroyed_(object_destroyed) {}
-
- private:
- ~DestructionCheckableCleanerRunner() override { *object_destroyed_ = true; }
-
- // The class will assign true to the pointee on destruction.
- bool* object_destroyed_;
-};
-
class CredentialsCleanerRunnerTest : public ::testing::Test {
public:
CredentialsCleanerRunnerTest() = default;
-
- ~CredentialsCleanerRunnerTest() override { EXPECT_TRUE(runner_destroyed_); }
+ ~CredentialsCleanerRunnerTest() override = default;
protected:
- CredentialsCleanerRunner* GetRunner() { return cleaning_tasks_runner_; }
+ CredentialsCleanerRunner* GetRunner() { return &cleaning_tasks_runner_; }
private:
- bool runner_destroyed_ = false;
-
- // This is a non-owning pointer, because the runner will delete itself.
- DestructionCheckableCleanerRunner* cleaning_tasks_runner_ =
- new DestructionCheckableCleanerRunner(&runner_destroyed_);
+ CredentialsCleanerRunner cleaning_tasks_runner_;
DISALLOW_COPY_AND_ASSIGN(CredentialsCleanerRunnerTest);
};
-// This test would fail if the object doesn't delete itself.
-TEST_F(CredentialsCleanerRunnerTest, EmptyTasks) {
- GetRunner()->StartCleaning();
-}
-
// In this test we check that credential clean-ups runner executes the clean-up
// tasks in the order they were added.
TEST_F(CredentialsCleanerRunnerTest, NonEmptyTasks) {
@@ -84,6 +60,61 @@ TEST_F(CredentialsCleanerRunnerTest, NonEmptyTasks) {
cleaning_tasks_runner->StartCleaning();
for (int i = 0; i < kCleanersCount; ++i)
cleaning_tasks_runner->CleaningCompleted();
+
+ EXPECT_FALSE(cleaning_tasks_runner->HasPendingTasks());
+}
+
+// In this test we check that StartCleaning() can be called again after the
+// first one finished.
+TEST_F(CredentialsCleanerRunnerTest, CanBeCalledAgainAfterFinished) {
+ auto* cleaning_tasks_runner = GetRunner();
+
+ auto cleaner1 = std::make_unique<MockCredentialsCleaner>();
+ EXPECT_CALL(*cleaner1, NeedsCleaning).WillOnce(::testing::Return(true));
+
+ auto cleaner2 = std::make_unique<MockCredentialsCleaner>();
+ EXPECT_CALL(*cleaner2, NeedsCleaning).WillOnce(::testing::Return(true));
+
+ ::testing::InSequence dummy;
+ EXPECT_CALL(*cleaner1, StartCleaning(cleaning_tasks_runner));
+ EXPECT_CALL(*cleaner2, StartCleaning(cleaning_tasks_runner));
+
+ cleaning_tasks_runner->MaybeAddCleaningTask(std::move(cleaner1));
+ cleaning_tasks_runner->StartCleaning();
+ cleaning_tasks_runner->CleaningCompleted(); // cleaner1
+
+ cleaning_tasks_runner->MaybeAddCleaningTask(std::move(cleaner2));
+ cleaning_tasks_runner->StartCleaning();
+ cleaning_tasks_runner->CleaningCompleted(); // cleaner2
+
+ EXPECT_FALSE(cleaning_tasks_runner->HasPendingTasks());
+}
+
+// In this test we check that StartCleaning() can be called again before the
+// first one finished.
+TEST_F(CredentialsCleanerRunnerTest, CanBeCalledAgainBeforeFinished) {
+ auto* cleaning_tasks_runner = GetRunner();
+
+ auto cleaner1 = std::make_unique<MockCredentialsCleaner>();
+ EXPECT_CALL(*cleaner1, NeedsCleaning).WillOnce(::testing::Return(true));
+
+ auto cleaner2 = std::make_unique<MockCredentialsCleaner>();
+ EXPECT_CALL(*cleaner2, NeedsCleaning).WillOnce(::testing::Return(true));
+
+ ::testing::InSequence dummy;
+ EXPECT_CALL(*cleaner1, StartCleaning(cleaning_tasks_runner));
+ EXPECT_CALL(*cleaner2, StartCleaning(cleaning_tasks_runner));
+
+ cleaning_tasks_runner->MaybeAddCleaningTask(std::move(cleaner1));
+ cleaning_tasks_runner->StartCleaning();
+
+ cleaning_tasks_runner->MaybeAddCleaningTask(std::move(cleaner2));
+ cleaning_tasks_runner->StartCleaning();
+
+ cleaning_tasks_runner->CleaningCompleted(); // cleaner1
+ cleaning_tasks_runner->CleaningCompleted(); // cleaner2
+
+ EXPECT_FALSE(cleaning_tasks_runner->HasPendingTasks());
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credentials_filter.h b/chromium/components/password_manager/core/browser/credentials_filter.h
index 597e77ba15b..6bd5b6356c6 100644
--- a/chromium/components/password_manager/core/browser/credentials_filter.h
+++ b/chromium/components/password_manager/core/browser/credentials_filter.h
@@ -8,11 +8,11 @@
#include <string>
#include "base/macros.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
class PasswordFormManager;
+struct PasswordForm;
// This interface is used to filter credentials during saving, retrieval from
// PasswordStore, etc.
diff --git a/chromium/components/password_manager/core/browser/export/password_csv_writer.h b/chromium/components/password_manager/core/browser/export/password_csv_writer.h
index 9b179814baf..8d4dc04ac6c 100644
--- a/chromium/components/password_manager/core/browser/export/password_csv_writer.h
+++ b/chromium/components/password_manager/core/browser/export/password_csv_writer.h
@@ -11,10 +11,11 @@
#include <vector>
#include "base/macros.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
+struct PasswordForm;
+
// Static-only class bundling together the API for serializing passwords into
// CSV format.
class PasswordCSVWriter {
diff --git a/chromium/components/password_manager/core/browser/field_info_manager.h b/chromium/components/password_manager/core/browser/field_info_manager.h
index 409d91abdf1..4ad88193419 100644
--- a/chromium/components/password_manager/core/browser/field_info_manager.h
+++ b/chromium/components/password_manager/core/browser/field_info_manager.h
@@ -10,12 +10,12 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/common/signatures.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
namespace password_manager {
class PasswordStore;
+struct PasswordForm;
class FieldInfoManager {
public:
diff --git a/chromium/components/password_manager/core/browser/form_fetcher.h b/chromium/components/password_manager/core/browser/form_fetcher.h
index 82fa929726f..9d473d1a7cf 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher.h
+++ b/chromium/components/password_manager/core/browser/form_fetcher.h
@@ -13,12 +13,12 @@
#include "base/observer_list_types.h"
#include "base/strings/string16.h"
#include "components/autofill/core/common/gaia_id_hash.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
struct CompromisedCredentials;
struct InteractionsStats;
+struct PasswordForm;
// This is an API for providing stored credentials to PasswordFormManager (PFM),
// so that PFM instances do not have to talk to PasswordStore directly. This
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
index 232a274d74b..c2136d4aa5a 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/ranges/algorithm.h"
@@ -22,9 +23,9 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/common/autofill_regex_constants.h"
-#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/password_manager/core/browser/password_form.h"
@@ -200,7 +201,7 @@ struct SignificantFields {
bool is_fallback = false;
// True iff the new password field was found with server hints or autocomplete
- // attributes.
+ // attributes or the kTreatNewPasswordHeuristicsAsReliable feature is enabled.
bool is_new_password_reliable = false;
// True if the current form has only username, but no passwords.
@@ -233,11 +234,7 @@ bool IsFieldInSignificantFields(const SignificantFields& significant_fields,
bool DoesPredictionCorrespondToField(
const FormFieldData& field,
const PasswordFieldPrediction& prediction) {
-#if defined(OS_IOS)
- return field.unique_id == prediction.unique_id;
-#else
return field.unique_renderer_id == prediction.renderer_id;
-#endif
}
// Returns the first element of |fields| which corresponds to |prediction|, or
@@ -807,8 +804,8 @@ void SetFields(const SignificantFields& significant_fields,
// empty values are ignored.
std::vector<ProcessedField> ProcessFields(
const std::vector<FormFieldData>& fields,
- autofill::ValueElementVector* all_possible_passwords,
- autofill::ValueElementVector* all_possible_usernames,
+ ValueElementVector* all_possible_passwords,
+ ValueElementVector* all_possible_usernames,
FormDataParser::Mode mode) {
DCHECK(all_possible_passwords);
DCHECK(all_possible_passwords->empty());
@@ -836,7 +833,7 @@ std::vector<ProcessedField> ProcessFields(
if (!field_value.empty()) {
std::set<base::StringPiece16>& seen_values =
is_password ? seen_password_values : seen_username_values;
- autofill::ValueElementVector* all_possible_fields =
+ ValueElementVector* all_possible_fields =
is_password ? all_possible_passwords : all_possible_usernames;
// Only the field name of the first occurrence is added.
auto insertion = seen_values.insert(field_value);
@@ -892,8 +889,8 @@ bool GetMayUsePrefilledPlaceholder(
std::unique_ptr<PasswordForm> AssemblePasswordForm(
const FormData& form_data,
const SignificantFields& significant_fields,
- autofill::ValueElementVector all_possible_passwords,
- autofill::ValueElementVector all_possible_usernames,
+ ValueElementVector all_possible_passwords,
+ ValueElementVector all_possible_usernames,
const base::Optional<FormPredictions>& form_predictions) {
if (!significant_fields.HasPasswords() &&
!significant_fields.is_single_username) {
@@ -945,8 +942,8 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
return nullptr;
readonly_status_ = ReadonlyPasswordFields::kNoHeuristics;
- autofill::ValueElementVector all_possible_passwords;
- autofill::ValueElementVector all_possible_usernames;
+ ValueElementVector all_possible_passwords;
+ ValueElementVector all_possible_usernames;
std::vector<ProcessedField> processed_fields = ProcessFields(
form_data.fields, &all_possible_passwords, &all_possible_usernames, mode);
@@ -974,16 +971,10 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
}
}
- // Pass the "reliability" information to mark the new-password fields as
- // eligible for automatic password generation. This only makes sense when
- // forms are analysed for filling, because no passwords are generated when the
- // user saves the already entered one.
- if (mode == Mode::kFilling && significant_fields.new_password) {
- significant_fields.is_new_password_reliable = true;
- }
-
// (3) Now try to fill the gaps.
const bool username_found_before_heuristic = significant_fields.username;
+ const bool new_password_found_before_heuristic =
+ significant_fields.new_password;
// Try to parse with base heuristic.
if (!significant_fields.is_single_username) {
@@ -1015,6 +1006,16 @@ std::unique_ptr<PasswordForm> FormDataParser::Parse(const FormData& form_data,
}
}
+ // Pass the "reliability" information to mark the new-password fields as
+ // eligible for automatic password generation. This only makes sense when
+ // forms are analysed for filling, because no passwords are generated when the
+ // user saves the already entered one.
+ significant_fields.is_new_password_reliable =
+ mode == Mode::kFilling && significant_fields.new_password &&
+ (new_password_found_before_heuristic ||
+ base::FeatureList::IsEnabled(
+ features::kTreatNewPasswordHeuristicsAsReliable));
+
base::UmaHistogramEnumeration("PasswordManager.UsernameDetectionMethod",
method);
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser.h b/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
index b0a960d982b..40f900d0870 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser.h
@@ -12,7 +12,6 @@
#include "base/macros.h"
#include "base/optional.h"
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "url/gurl.h"
namespace autofill {
@@ -21,6 +20,8 @@ struct FormData;
namespace password_manager {
+struct PasswordForm;
+
// The susbset of autocomplete flags related to passwords.
enum class AutocompleteFlag {
kNone,
@@ -123,6 +124,8 @@ class FormDataParser {
predictions_ = std::move(predictions);
}
+ void reset_predictions() { predictions_.reset(); }
+
const base::Optional<FormPredictions>& predictions() { return predictions_; }
ReadonlyPasswordFields readonly_status() { return readonly_status_; }
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
index bb3a222a90d..921f859e060 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -10,6 +10,7 @@
#include <set>
#include <utility>
+#include "base/feature_list.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -87,8 +88,8 @@ struct FormParsingTestCase {
int number_of_all_possible_passwords = -1;
int number_of_all_possible_usernames = -1;
// null means no checking
- const autofill::ValueElementVector* all_possible_passwords = nullptr;
- const autofill::ValueElementVector* all_possible_usernames = nullptr;
+ const ValueElementVector* all_possible_passwords = nullptr;
+ const ValueElementVector* all_possible_usernames = nullptr;
bool server_side_classification_successful = true;
bool username_may_use_prefilled_placeholder = false;
base::Optional<FormDataParser::ReadonlyPasswordFields> readonly_status;
@@ -320,7 +321,7 @@ void CheckPasswordFormFields(const PasswordForm& password_form,
// Checks that in a vector of pairs of string16s, all the first parts of the
// pairs (which represent element values) are unique.
-void CheckAllValuesUnique(const autofill::ValueElementVector& v) {
+void CheckAllValuesUnique(const ValueElementVector& v) {
std::set<base::string16> all_values;
for (const auto& pair : v) {
auto insertion = all_values.insert(pair.first);
@@ -449,6 +450,9 @@ TEST(FormParserTest, SkipNotTextFields) {
}
TEST(FormParserTest, OnlyPasswordFields) {
+ const bool kTreatNewPasswordHeuristicsAsReliable =
+ base::FeatureList::IsEnabled(
+ features::kTreatNewPasswordHeuristicsAsReliable);
CheckTestData({
{
.description_for_logging = "1 password field",
@@ -472,7 +476,7 @@ TEST(FormParserTest, OnlyPasswordFields) {
.value = "pw",
.form_control_type = "password"},
},
- .is_new_password_reliable = false,
+ .is_new_password_reliable = kTreatNewPasswordHeuristicsAsReliable,
},
{
.description_for_logging =
@@ -486,7 +490,7 @@ TEST(FormParserTest, OnlyPasswordFields) {
.value = "pw2",
.form_control_type = "password"},
},
- .is_new_password_reliable = false,
+ .is_new_password_reliable = kTreatNewPasswordHeuristicsAsReliable,
},
{
.description_for_logging =
@@ -503,7 +507,7 @@ TEST(FormParserTest, OnlyPasswordFields) {
.value = "pw2",
.form_control_type = "password"},
},
- .is_new_password_reliable = false,
+ .is_new_password_reliable = kTreatNewPasswordHeuristicsAsReliable,
},
{
.description_for_logging = "3 password fields with different values",
@@ -1425,11 +1429,11 @@ TEST(FormParserTest, Interactability) {
}
TEST(FormParserTest, AllPossiblePasswords) {
- const autofill::ValueElementVector kPasswords = {
+ const ValueElementVector kPasswords = {
{ASCIIToUTF16("a"), ASCIIToUTF16("p1")},
{ASCIIToUTF16("b"), ASCIIToUTF16("p3")},
};
- const autofill::ValueElementVector kUsernames = {
+ const ValueElementVector kUsernames = {
{ASCIIToUTF16("b"), ASCIIToUTF16("chosen")},
{ASCIIToUTF16("a"), ASCIIToUTF16("first")},
};
diff --git a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
index c0721cb3fb5..d8e2f03c18b 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
@@ -4,9 +4,11 @@
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
+#include "base/feature_list.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/signatures.h"
+#include "components/password_manager/core/common/password_manager_features.h"
using autofill::AutofillField;
using autofill::FieldSignature;
@@ -18,22 +20,36 @@ namespace password_manager {
namespace {
+bool AreSecondaryPredictionsEnabled() {
+ return base::FeatureList::IsEnabled(
+ features::kSecondaryServerFieldPredictions);
+}
+
ServerFieldType GetServerType(const AutofillField& field) {
- // The main server predictions is in |field.server_type()| but the server can
- // send additional predictions in |field.server_predictions()|. This function
- // chooses relevant for Password Manager predictions.
+ // The main server predictions is in `field.server_type()` but the server can
+ // send additional predictions in `field.server_predictions()`. This function
+ // chooses relevant for Password Manager predictions. Choosing additional
+ // predictions from `field.server_predictions()` is gated on the
+ // `kSecondaryServerFieldPredictions` flag. This is because the server only
+ // recently started to send down these predictions (http://cl/340884706).
+ // Having a feature flag here allows us to run experiments to measure the
+ // impact of these new predictions.
// 1. If there is cvc prediction returns it.
for (const auto& predictions : field.server_predictions()) {
- if (predictions.type() == autofill::CREDIT_CARD_VERIFICATION_CODE)
- return ServerFieldType(predictions.type());
+ if (predictions.type() == autofill::CREDIT_CARD_VERIFICATION_CODE &&
+ AreSecondaryPredictionsEnabled()) {
+ return autofill::CREDIT_CARD_VERIFICATION_CODE;
+ }
}
// 2. If there is password related prediction returns it.
for (const auto& predictions : field.server_predictions()) {
- ServerFieldType type = ServerFieldType(predictions.type());
- if (DeriveFromServerFieldType(type) != CredentialFieldType::kNone)
+ auto type = static_cast<ServerFieldType>(predictions.type());
+ if (DeriveFromServerFieldType(type) != CredentialFieldType::kNone &&
+ AreSecondaryPredictionsEnabled()) {
return type;
+ }
}
// 3. Returns the main prediction.
diff --git a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction_unittest.cc b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction_unittest.cc
index 8ef059230cb..7fbc8c53376 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction_unittest.cc
@@ -8,9 +8,11 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/renderer_id.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -39,7 +41,23 @@ namespace password_manager {
namespace {
-TEST(FormPredictionsTest, ConvertToFormPredictions) {
+// The boolean parameter determines the feature state of
+// `kSecondaryServerFieldPredictions`.
+class FormPredictionsTest : public ::testing::TestWithParam<bool> {
+ public:
+ FormPredictionsTest() {
+ feature_list_.InitWithFeatureState(
+ features::kSecondaryServerFieldPredictions,
+ AreSecondaryPredictionsEnabled());
+ }
+
+ bool AreSecondaryPredictionsEnabled() const { return GetParam(); }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_P(FormPredictionsTest, ConvertToFormPredictions) {
struct TestField {
std::string name;
std::string form_control_type;
@@ -55,13 +73,20 @@ TEST(FormPredictionsTest, ConvertToFormPredictions) {
{"Password", "password", PASSWORD, PASSWORD, false},
{"confirm_password", "password", CONFIRMATION_PASSWORD,
CONFIRMATION_PASSWORD, true},
- // username in |additional_types| takes precedence.
- {"email", "text", EMAIL_ADDRESS, USERNAME, false, {USERNAME}},
- // cvc in |additional_types| takes precedence.
+ // username in |additional_types| takes precedence if the feature is
+ // enabled.
+ {"email",
+ "text",
+ EMAIL_ADDRESS,
+ AreSecondaryPredictionsEnabled() ? USERNAME : EMAIL_ADDRESS,
+ false,
+ {USERNAME}},
+ // cvc in |additional_types| takes precedence if the feature is enabled.
{"cvc",
"password",
PASSWORD,
- CREDIT_CARD_VERIFICATION_CODE,
+ AreSecondaryPredictionsEnabled() ? CREDIT_CARD_VERIFICATION_CODE
+ : PASSWORD,
false,
{CREDIT_CARD_VERIFICATION_CODE}},
// non-password, non-cvc types in |additional_types| are ignored.
@@ -206,7 +231,7 @@ TEST(FormPredictionsTest, DeriveFromServerFieldType) {
DeriveFromServerFieldType(test_case.server_type));
}
}
-
+INSTANTIATE_TEST_SUITE_P(All, FormPredictionsTest, testing::Bool());
} // namespace
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_saver.h b/chromium/components/password_manager/core/browser/form_saver.h
index 2215604c6a9..63567d0d351 100644
--- a/chromium/components/password_manager/core/browser/form_saver.h
+++ b/chromium/components/password_manager/core/browser/form_saver.h
@@ -12,11 +12,12 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/strings/string16.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store.h"
namespace password_manager {
+struct PasswordForm;
+
// This interface allows the caller to save passwords and blacklist entries in
// a password store.
class FormSaver {
diff --git a/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_unittest.cc
index c28087279dc..d12247f9da2 100644
--- a/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_unittest.cc
@@ -4,7 +4,7 @@
#include "components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/proto/password_requirements.pb.h"
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager.h b/chromium/components/password_manager/core/browser/http_auth_manager.h
index 50455afebea..74ab227c06c 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager.h
+++ b/chromium/components/password_manager/core/browser/http_auth_manager.h
@@ -6,12 +6,12 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_AUTH_MANAGER_H_
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
class PasswordManagerClient;
class HttpAuthObserver;
+struct PasswordForm;
// Per-tab password manager for http-auth forms.
// This class is the counterpart to the PasswordManager which manages storing
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc b/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
index 079eee94808..5ff7ca8018c 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/http_auth_manager_impl.cc
@@ -82,8 +82,10 @@ void HttpAuthManagerImpl::Autofill(
void HttpAuthManagerImpl::OnPasswordFormSubmitted(
const PasswordForm& password_form) {
- if (client_->IsSavingAndFillingEnabled(password_form.url))
+ if (client_->IsSavingAndFillingEnabled(password_form.url) &&
+ !password_form.password_value.empty()) {
ProvisionallySaveForm(password_form);
+ }
}
void HttpAuthManagerImpl::OnPasswordFormDismissed() {
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager_impl.h b/chromium/components/password_manager/core/browser/http_auth_manager_impl.h
index 6086a3728e3..be88d5e76af 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager_impl.h
+++ b/chromium/components/password_manager/core/browser/http_auth_manager_impl.h
@@ -13,13 +13,13 @@
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/http_auth_manager.h"
#include "components/password_manager/core/browser/http_auth_observer.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
class PasswordManagerClient;
class PasswordFormManager;
class PasswordFormManagerForUI;
+struct PasswordForm;
// Implementation of the HttpAuthManager as used by the PasswordManagerClient.
class HttpAuthManagerImpl : public HttpAuthManager {
diff --git a/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc b/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
index ba24cef2c24..1a39ed1ca1f 100644
--- a/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_auth_manager_unittest.cc
@@ -13,7 +13,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "build/build_config.h"
@@ -210,6 +209,35 @@ TEST_F(HttpAuthManagerTest, HttpAuthSaving) {
}
}
+TEST_F(HttpAuthManagerTest, DontSaveEmptyPasswords) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+ PasswordForm observed_form;
+ observed_form.scheme = PasswordForm::Scheme::kBasic;
+ observed_form.url = GURL("http://proxy.com/");
+ observed_form.signon_realm = "proxy.com/realm";
+
+ MockHttpAuthObserver observer;
+ EXPECT_CALL(*store_, GetLogins)
+ .WillOnce(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
+
+ // Initiate creating a form manager.
+ httpauth_manager()->SetObserverAndDeliverCredentials(&observer,
+ observed_form);
+ // Emulate that http auth credentials submitted with an empty password.
+ PasswordForm submitted_form = observed_form;
+ submitted_form.username_value = ASCIIToUTF16("user");
+ submitted_form.password_value = base::string16();
+ httpauth_manager()->OnPasswordFormSubmitted(submitted_form);
+ httpauth_manager()->OnPasswordFormDismissed();
+
+ // Expect no save prompt on successful submission.
+ std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr()).Times(0);
+ httpauth_manager()->OnDidFinishMainFrameNavigation();
+ testing::Mock::VerifyAndClearExpectations(&client_);
+ httpauth_manager()->DetachObserver(&observer);
+}
+
TEST_F(HttpAuthManagerTest, NavigationWithoutSubmission) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
diff --git a/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc b/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
index 1853b7d09a5..ad12b310574 100644
--- a/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
+++ b/chromium/components/password_manager/core/browser/http_credentials_cleaner.cc
@@ -52,7 +52,8 @@ void HttpCredentialCleaner::OnGetPasswordStoreResults(
PostHSTSQueryForHostAndNetworkContext(
origin, network_context_getter_.Run(),
base::BindOnce(&HttpCredentialCleaner::OnHSTSQueryResult,
- base::Unretained(this), std::move(form), form_key));
+ weak_ptr_factory_.GetWeakPtr(), std::move(form),
+ form_key));
++total_http_credentials_;
} else { // HTTPS
https_credentials_map_[form_key].insert(form->password_value);
diff --git a/chromium/components/password_manager/core/browser/http_credentials_cleaner.h b/chromium/components/password_manager/core/browser/http_credentials_cleaner.h
index d044be9dde6..822f9adbbe5 100644
--- a/chromium/components/password_manager/core/browser/http_credentials_cleaner.h
+++ b/chromium/components/password_manager/core/browser/http_credentials_cleaner.h
@@ -14,6 +14,7 @@
#include "base/containers/flat_set.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "components/password_manager/core/browser/credentials_cleaner.h"
#include "components/password_manager/core/browser/hsts_query.h"
#include "components/password_manager/core/browser/password_form.h"
@@ -123,6 +124,8 @@ class HttpCredentialCleaner : public PasswordStoreConsumer,
// credentials were processed.
size_t total_http_credentials_ = 0;
+ base::WeakPtrFactory<HttpCredentialCleaner> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(HttpCredentialCleaner);
};
diff --git a/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc b/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
index 0dd8a3b86bd..1a2944fc446 100644
--- a/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
@@ -8,7 +8,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.h b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
index 755d24dad44..13c7065a097 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator.h
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.h
@@ -11,12 +11,13 @@
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "components/password_manager/core/browser/hsts_query.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "url/origin.h"
namespace password_manager {
+struct PasswordForm;
+
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
diff --git a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
index 3dd345f9a77..7a3e9cf2671 100644
--- a/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/import/password_importer_unittest.cc
@@ -5,7 +5,7 @@
#include "components/password_manager/core/browser/import/password_importer.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
index 4695d6ea789..cb20683e932 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
@@ -177,7 +177,7 @@ TEST_F(AuthenticatedLeakCheckTest, GetAccessTokenBeforeEncryption) {
LookupSingleLeak(
_, access_token,
AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
- ElementsAre(-67, 116, -87)),
+ ElementsAre(0xBD, 0x74, 0xA9, 0x20)),
Field(&LookupSingleLeakPayload::encrypted_payload,
testing::Ne(""))),
_));
@@ -211,7 +211,7 @@ TEST_F(AuthenticatedLeakCheckTest, GetAccessTokenAfterEncryption) {
LookupSingleLeak(
_, access_token,
AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
- ElementsAre(-67, 116, -87)),
+ ElementsAre(0xBD, 0x74, 0xA9, 0x20)),
Field(&LookupSingleLeakPayload::encrypted_payload,
testing::Ne(""))),
_));
diff --git a/chromium/components/password_manager/core/browser/leak_detection/bulk_leak_check_impl_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/bulk_leak_check_impl_unittest.cc
index 83f20fb4e23..e8e4a04565e 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/bulk_leak_check_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/bulk_leak_check_impl_unittest.cc
@@ -214,7 +214,7 @@ TEST_F(BulkLeakCheckTest, CheckCredentialsAccessDoesNetworkRequest) {
LookupSingleLeak(
_, kAccessToken,
AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
- ElementsAre(-67, 116, -87)),
+ ElementsAre(0xBD, 0x74, 0xA9, 0x20)),
Field(&LookupSingleLeakPayload::encrypted_payload,
testing::Ne(""))),
_));
diff --git a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
index 8f08d643541..43e64e6347f 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -62,16 +62,25 @@ std::string HashUsername(base::StringPiece canonicalized_username) {
}
std::string BucketizeUsername(base::StringPiece canonicalized_username) {
- static_assert(
- kUsernameHashPrefixLength % CHAR_BIT == 0,
- "The prefix length must be a multiple of the number of bits in a char.");
+ // Compute the number of bytes necessary to store `kUsernameHashPrefixLength`
+ // bits.
+ constexpr size_t kPrefixBytes =
+ (kUsernameHashPrefixLength + CHAR_BIT - 1) / CHAR_BIT;
+ // Compute the remainder, and construct a mask that keeps the first
+ // `kPrefixRemainder` bits.
+ constexpr size_t kPrefixRemainder = kUsernameHashPrefixLength % CHAR_BIT;
+ constexpr size_t kPrefixMask = ((1 << kPrefixRemainder) - 1)
+ << (CHAR_BIT - kPrefixRemainder);
// Check that |canonicalized_username| is actually canonicalized.
// Note: We can't use CanonicalizeUsername() again, since it's not idempotent
// if multiple '@' signs are present in the initial username.
DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username);
- return HashUsername(canonicalized_username)
- .substr(0, kUsernameHashPrefixLength / CHAR_BIT);
+ std::string prefix =
+ HashUsername(canonicalized_username).substr(0, kPrefixBytes);
+ if (kPrefixRemainder != 0)
+ prefix.back() &= kPrefixMask;
+ return prefix;
}
std::string ScryptHashUsernameAndPassword(
diff --git a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.h b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.h
index c4f7550a290..7f96af1afa3 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.h
+++ b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.h
@@ -13,7 +13,7 @@
namespace password_manager {
// Username hash prefix length in bits.
-constexpr size_t kUsernameHashPrefixLength = 24;
+constexpr size_t kUsernameHashPrefixLength = 27;
// Canonicalizes |username| by lower-casing and and stripping a mail-address
// host in case the username is a mail address. |username| must be a UTF-8
diff --git a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
index 99e17c1274b..c2a704d69db 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
@@ -66,7 +66,7 @@ TEST(EncryptionUtils, HashUsername) {
TEST(EncryptionUtils, BucketizeUsername) {
EXPECT_THAT(BucketizeUsername("jonsnow"),
- ElementsAreArray({0x3D, 0x70, 0xD3}));
+ ElementsAreArray({0x3D, 0x70, 0xD3, 0x60}));
}
TEST(EncryptionUtils, ScryptHashUsernameAndPassword) {
diff --git a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
index 5e08095b4b2..59fbeeaea19 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils_unittest.cc
@@ -35,7 +35,7 @@ TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestData) {
Run(AllOf(
Field(&LookupSingleLeakData::payload,
AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
- ElementsAre(61, 112, -45)),
+ ElementsAre(0x3D, 0x70, 0xD3, 0x60)),
Field(&LookupSingleLeakPayload::encrypted_payload,
testing::Ne("")))),
Field(&LookupSingleLeakData::encryption_key, testing::Ne("")))));
@@ -52,7 +52,7 @@ TEST(LeakDetectionRequestUtils, PrepareSingleLeakRequestDataWithKey) {
"jonsnow", "1234", callback.Get());
EXPECT_CALL(callback,
Run(AllOf(Field(&LookupSingleLeakPayload::username_hash_prefix,
- ElementsAre(61, 112, -45)),
+ ElementsAre(0x3D, 0x70, 0xD3, 0x60)),
Field(&LookupSingleLeakPayload::encrypted_payload,
testing::Ne("")))));
task_env.RunUntilIdle();
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate.h b/chromium/components/password_manager/core/browser/leak_detection_delegate.h
index bfc3f5d1e6d..6eb00de6fdd 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate.h
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate.h
@@ -12,7 +12,6 @@
#include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_delegate_interface.h"
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
class PrefService;
@@ -21,6 +20,7 @@ namespace password_manager {
class LeakDetectionCheck;
class LeakDetectionDelegateHelper;
class PasswordManagerClient;
+struct PasswordForm;
// The helper class that encapsulates the requests and their processing.
class LeakDetectionDelegate : public LeakDetectionDelegateInterface {
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
index bd3754b47d8..963025b9d76 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
@@ -284,16 +284,16 @@ struct PasswordChangeParams {
false, false},
{CreateLeakType(IsSaved(false), IsReused(false), IsSyncing(true)), IDS_OK,
false, false},
- {CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(false)), IDS_OK,
- false, false},
+ {CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(false)),
+ IDS_LEAK_CHECK_CREDENTIALS, true, false},
{CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(true)),
IDS_LEAK_CHECK_CREDENTIALS, true, false},
{CreateLeakType(IsSaved(true), IsReused(false), IsSyncing(false)), IDS_OK,
false, false},
{CreateLeakType(IsSaved(true), IsReused(false), IsSyncing(true)),
IDS_PASSWORD_CHANGE, true, true},
- {CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(false)), IDS_OK,
- false, false},
+ {CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(false)),
+ IDS_LEAK_CHECK_CREDENTIALS, true, false},
{CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(true)),
IDS_LEAK_CHECK_CREDENTIALS, true, false}};
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index e490aa5476a..edef850b876 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -63,8 +63,7 @@ const int kCurrentVersionNumber = 28;
// version can still read/write the current database.
const int kCompatibleVersionNumber = 28;
-base::Pickle SerializeValueElementPairs(
- const autofill::ValueElementVector& vec) {
+base::Pickle SerializeValueElementPairs(const ValueElementVector& vec) {
base::Pickle p;
for (const auto& pair : vec) {
p.WriteString16(pair.first);
@@ -73,9 +72,8 @@ base::Pickle SerializeValueElementPairs(
return p;
}
-autofill::ValueElementVector DeserializeValueElementPairs(
- const base::Pickle& p) {
- autofill::ValueElementVector ret;
+ValueElementVector DeserializeValueElementPairs(const base::Pickle& p) {
+ ValueElementVector ret;
base::string16 value;
base::string16 field_name;
@@ -83,7 +81,7 @@ autofill::ValueElementVector DeserializeValueElementPairs(
while (iterator.ReadString16(&value)) {
bool name_success = iterator.ReadString16(&field_name);
DCHECK(name_success);
- ret.push_back(autofill::ValueElementPair(value, field_name));
+ ret.push_back(ValueElementPair(value, field_name));
}
return ret;
}
@@ -594,16 +592,6 @@ PasswordForm GetFormForRemoval(const sql::Statement& statement) {
}
#endif
-// This converts `i` to type `Enum`. Terminates in case `i` is outside the valid
-// ranges for `Enum`. Requires `Enum::kMinValue` and `Enum::kMaxValue` to exist
-// and have correct semantics.
-template <typename Enum>
-Enum ToEnumOrDie(int i) {
- CHECK_LE(static_cast<int>(Enum::kMinValue), i);
- CHECK_GE(static_cast<int>(Enum::kMaxValue), i);
- return static_cast<Enum>(i);
-}
-
} // namespace
struct LoginDatabase::PrimaryKeyAndPassword {
@@ -614,16 +602,15 @@ struct LoginDatabase::PrimaryKeyAndPassword {
LoginDatabase::LoginDatabase(const base::FilePath& db_path,
IsAccountStore is_account_store)
- : db_path_(db_path), is_account_store_(is_account_store) {}
+ : db_path_(db_path),
+ is_account_store_(is_account_store),
+ // Set options for a small, private database (based on WebDatabase).
+ db_({.exclusive_locking = true, .page_size = 2048, .cache_size = 32}) {}
LoginDatabase::~LoginDatabase() = default;
bool LoginDatabase::Init() {
TRACE_EVENT0("passwords", "LoginDatabase::Init");
- // Set pragmas for a small, private database (based on WebDatabase).
- db_.set_page_size(2048);
- db_.set_cache_size(32);
- db_.set_exclusive_locking();
db_.set_histogram_tag("Passwords");
if (!db_.Open(db_path_)) {
@@ -1432,9 +1419,11 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
form->date_created =
base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_CREATED));
form->blocked_by_user = (s.ColumnInt(COLUMN_BLACKLISTED_BY_USER) > 0);
- form->scheme = ToEnumOrDie<PasswordForm::Scheme>(s.ColumnInt(COLUMN_SCHEME));
+ // TODO(crbug.com/1151214): Add metrics to capture how often these values fall
+ // out of the valid enum range.
+ form->scheme = static_cast<PasswordForm::Scheme>(s.ColumnInt(COLUMN_SCHEME));
form->type =
- ToEnumOrDie<PasswordForm::Type>(s.ColumnInt(COLUMN_PASSWORD_TYPE));
+ static_cast<PasswordForm::Type>(s.ColumnInt(COLUMN_PASSWORD_TYPE));
if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAME_PAIRS)) {
base::Pickle pickle(
static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAME_PAIRS)),
@@ -1462,7 +1451,7 @@ LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
url::Origin::Create(GURL(s.ColumnString(COLUMN_FEDERATION_URL)));
form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0);
form->generation_upload_status =
- ToEnumOrDie<PasswordForm::GenerationUploadStatus>(
+ static_cast<PasswordForm::GenerationUploadStatus>(
s.ColumnInt(COLUMN_GENERATION_UPLOAD_STATUS));
form->date_last_used = base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(s.ColumnInt64(COLUMN_DATE_LAST_USED)));
diff --git a/chromium/components/password_manager/core/browser/login_database_unittest.cc b/chromium/components/password_manager/core/browser/login_database_unittest.cc
index f0dec5790d0..915f58e5ed5 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -17,7 +17,6 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -39,8 +38,6 @@
#include "url/origin.h"
using autofill::GaiaIdHash;
-using autofill::ValueElementPair;
-using autofill::ValueElementVector;
using base::ASCIIToUTF16;
using base::UTF16ToASCII;
using ::testing::Eq;
@@ -1343,7 +1340,7 @@ TEST_F(LoginDatabaseTest, UpdateLogin) {
form.action = GURL("http://accounts.google.com/login");
form.password_value = ASCIIToUTF16("my_new_password");
- form.all_possible_usernames.push_back(autofill::ValueElementPair(
+ form.all_possible_usernames.push_back(ValueElementPair(
ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
form.times_used = 20;
form.submit_element = ASCIIToUTF16("submit_element");
@@ -1386,7 +1383,7 @@ TEST_F(LoginDatabaseTest, UpdateLoginWithoutPassword) {
EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
form.action = GURL("http://accounts.google.com/login");
- form.all_possible_usernames.push_back(autofill::ValueElementPair(
+ form.all_possible_usernames.push_back(ValueElementPair(
ASCIIToUTF16("my_new_username"), ASCIIToUTF16("new_username_id")));
form.times_used = 20;
form.submit_element = ASCIIToUTF16("submit_element");
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.h b/chromium/components/password_manager/core/browser/mock_password_store.h
index 5b5eb86bb27..41db3f957b0 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -97,10 +97,11 @@ class MockPasswordStore : public PasswordStore {
MOCK_METHOD0(GetAllFieldInfoImpl, std::vector<FieldInfo>());
MOCK_METHOD2(RemoveFieldInfoByTimeImpl, void(base::Time, base::Time));
MOCK_METHOD0(IsEmpty, bool());
+ MOCK_METHOD1(GetAllLoginsWithAffiliationAndBrandingInformation,
+ void(PasswordStoreConsumer*));
MOCK_CONST_METHOD0(IsAbleToSavePasswords, bool());
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
MOCK_METHOD3(CheckReuse,
void(const base::string16&,
const std::string&,
@@ -115,7 +116,7 @@ class MockPasswordStore : public PasswordStore {
MOCK_METHOD1(ClearGaiaPasswordHash, void(const std::string&));
MOCK_METHOD0(ClearAllGaiaPasswordHash, void());
MOCK_METHOD0(ClearAllEnterprisePasswordHash, void());
-#endif
+
MOCK_METHOD0(BeginTransaction, bool());
MOCK_METHOD0(RollbackTransaction, void());
MOCK_METHOD0(CommitTransaction, bool());
diff --git a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
index 9fef44c29e3..39afdafb34e 100644
--- a/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_password_save_manager.cc
@@ -5,6 +5,7 @@
#include "components/password_manager/core/browser/multi_store_password_save_manager.h"
#include "base/metrics/histogram_functions.h"
+#include "base/ranges/algorithm.h"
#include "components/autofill/core/common/gaia_id_hash.h"
#include "components/password_manager/core/browser/form_fetcher.h"
#include "components/password_manager/core/browser/form_saver.h"
@@ -43,13 +44,11 @@ std::vector<const PasswordForm*> ProfileStoreMatches(
bool AccountStoreMatchesContainForm(
const std::vector<const PasswordForm*>& matches,
const PasswordForm& form) {
- PasswordForm form_in_account_store(form);
- form_in_account_store.in_store = PasswordForm::Store::kAccountStore;
- for (const PasswordForm* match : matches) {
- if (form_in_account_store == *match)
- return true;
- }
- return false;
+ DCHECK(base::ranges::all_of(matches, &PasswordForm::IsUsingAccountStore));
+ return base::ranges::find_if(matches, [&form](const PasswordForm* match) {
+ return ArePasswordFormUniqueKeysEqual(*match, form) &&
+ match->password_value == form.password_value;
+ }) != matches.end();
}
PendingCredentialsState ResolvePendingCredentialsStates(
diff --git a/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc b/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
index 30596035a19..fcb83f6d716 100644
--- a/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
@@ -904,6 +904,30 @@ TEST_F(MultiStorePasswordSaveManagerTest,
password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
}
+TEST_F(
+ MultiStorePasswordSaveManagerTest,
+ MoveCredentialsFromProfileToAccountStoreWhenExistsInBothStoresWithDifferentPassword) {
+ PasswordForm saved_match_in_profile_store(saved_match_);
+ saved_match_in_profile_store.in_store = PasswordForm::Store::kProfileStore;
+ saved_match_in_profile_store.password_value = ASCIIToUTF16("password1");
+ PasswordForm saved_match_in_account_store(saved_match_);
+ saved_match_in_account_store.in_store = PasswordForm::Store::kAccountStore;
+ saved_match_in_account_store.password_value = ASCIIToUTF16("password2");
+ SetNonFederatedAndNotifyFetchCompleted(
+ {&saved_match_in_profile_store, &saved_match_in_account_store});
+
+ password_save_manager()->CreatePendingCredentials(
+ saved_match_in_profile_store, &observed_form_, submitted_form_,
+ /*is_http_auth=*/false,
+ /*is_credential_api_save=*/false);
+
+ EXPECT_CALL(*mock_profile_form_saver(), Remove(saved_match_in_profile_store));
+ EXPECT_CALL(*mock_account_form_saver(),
+ Save(saved_match_in_profile_store, _, _));
+
+ password_save_manager()->MoveCredentialsToAccountStore(kTrigger);
+}
+
TEST_F(MultiStorePasswordSaveManagerTest,
MoveCredentialsFromProfileToAccountStoreWhenPSLMatchExistsInBothStores) {
PasswordForm saved_match_in_profile_store(saved_match_);
diff --git a/chromium/components/password_manager/core/browser/origin_credential_store.h b/chromium/components/password_manager/core/browser/origin_credential_store.h
index b1b604d6abd..7590cfd4196 100644
--- a/chromium/components/password_manager/core/browser/origin_credential_store.h
+++ b/chromium/components/password_manager/core/browser/origin_credential_store.h
@@ -10,12 +10,13 @@
#include "base/containers/span.h"
#include "base/strings/string16.h"
#include "base/util/type_safety/strong_alias.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace password_manager {
+struct PasswordForm;
+
// Encapsulates the data from the password manager backend as used by the UI.
class UiCredential {
public:
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.cc b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
index 08f08a42658..96b0d3faae6 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
@@ -32,6 +32,7 @@
#include "components/autofill/core/common/autofill_data_validation.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/favicon/core/favicon_util.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/password_feature_manager.h"
@@ -54,6 +55,8 @@ namespace password_manager {
namespace {
+using autofill::password_generation::PasswordGenerationType;
+
using AutoselectFirstSuggestion =
autofill::AutofillClient::PopupOpenArgs::AutoselectFirstSuggestion;
using IsLoading = autofill::Suggestion::IsLoading;
@@ -377,7 +380,7 @@ void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
using metrics_util::PasswordDropdownSelectedOption;
if (identifier == autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY) {
- password_client_->GeneratePassword();
+ password_client_->GeneratePassword(PasswordGenerationType::kAutomatic);
metrics_util::LogPasswordDropdownItemSelected(
PasswordDropdownSelectedOption::kGenerate,
password_client_->IsIncognito());
@@ -756,7 +759,7 @@ void PasswordAutofillManager::OnUnlockReauthCompleted(
if (reauth_succeeded) {
if (unlock_item ==
autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE) {
- password_client_->GeneratePassword();
+ password_client_->GeneratePassword(PasswordGenerationType::kAutomatic);
autofill_client_->HideAutofillPopup(
autofill::PopupHidingReason::kAcceptSuggestion);
}
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index a6da3a4d7e6..565234f0532 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -26,6 +26,7 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
@@ -64,6 +65,7 @@ using autofill::SuggestionVectorIconsAre;
using autofill::SuggestionVectorIdsAre;
using autofill::SuggestionVectorLabelsAre;
using autofill::SuggestionVectorValuesAre;
+using autofill::password_generation::PasswordGenerationType;
using favicon_base::FaviconImageCallback;
using gfx::test::AreImagesEqual;
using testing::_;
@@ -144,7 +146,7 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
.WillByDefault(Return(needs_signin));
}
- MOCK_METHOD(void, GeneratePassword, (), (override));
+ MOCK_METHOD(void, GeneratePassword, (PasswordGenerationType), (override));
MOCK_METHOD(void,
TriggerReauthForPrimaryAccount,
(signin_metrics::ReauthAccessPoint,
@@ -802,7 +804,7 @@ TEST_F(PasswordAutofillManagerTest,
EXPECT_CALL(autofill_client,
HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion))
.Times(testing::AtLeast(1));
- EXPECT_CALL(client, GeneratePassword());
+ EXPECT_CALL(client, GeneratePassword(PasswordGenerationType::kAutomatic));
password_autofill_manager_->DidAcceptSuggestion(
test_username_,
@@ -1317,7 +1319,7 @@ TEST_F(PasswordAutofillManagerTest,
GetManagePasswordsTitle())));
// Click "Generate password".
- EXPECT_CALL(client, GeneratePassword());
+ EXPECT_CALL(client, GeneratePassword(PasswordGenerationType::kAutomatic));
EXPECT_CALL(
autofill_client,
HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion));
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/password_manager/core/browser/password_form.cc
index 6585faa88e8..f0c7435496f 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/password_manager/core/browser/password_form.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 "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_form.h"
#include <algorithm>
#include <ostream>
@@ -14,7 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
-namespace autofill {
+namespace password_manager {
namespace {
@@ -209,55 +209,6 @@ bool PasswordForm::HasNonEmptyPasswordValue() const {
return !password_value.empty() || !new_password_value.empty();
}
-bool PasswordForm::operator==(const PasswordForm& form) const {
- return scheme == form.scheme && signon_realm == form.signon_realm &&
- url == form.url && action == form.action &&
- submit_element == form.submit_element &&
- username_element == form.username_element &&
- username_element_renderer_id == form.username_element_renderer_id &&
- username_value == form.username_value &&
- all_possible_usernames == form.all_possible_usernames &&
- all_possible_passwords == form.all_possible_passwords &&
- form_has_autofilled_value == form.form_has_autofilled_value &&
- password_element == form.password_element &&
- password_element_renderer_id == form.password_element_renderer_id &&
- password_value == form.password_value &&
- new_password_element == form.new_password_element &&
- confirmation_password_element_renderer_id ==
- form.confirmation_password_element_renderer_id &&
- confirmation_password_element == form.confirmation_password_element &&
- confirmation_password_element_renderer_id ==
- form.confirmation_password_element_renderer_id &&
- new_password_value == form.new_password_value &&
- date_created == form.date_created && date_synced == form.date_synced &&
- date_last_used == form.date_last_used &&
- blocked_by_user == form.blocked_by_user && type == form.type &&
- times_used == form.times_used &&
- form_data.SameFormAs(form.form_data) &&
- generation_upload_status == form.generation_upload_status &&
- display_name == form.display_name && icon_url == form.icon_url &&
- // We compare the serialization of the origins here, as we want unique
- // origins to compare as '=='.
- federation_origin.Serialize() == form.federation_origin.Serialize() &&
- skip_zero_click == form.skip_zero_click &&
- was_parsed_using_autofill_predictions ==
- form.was_parsed_using_autofill_predictions &&
- is_public_suffix_match == form.is_public_suffix_match &&
- is_affiliation_based_match == form.is_affiliation_based_match &&
- affiliated_web_realm == form.affiliated_web_realm &&
- app_display_name == form.app_display_name &&
- app_icon_url == form.app_icon_url &&
- submission_event == form.submission_event &&
- only_for_fallback == form.only_for_fallback &&
- is_new_password_reliable == form.is_new_password_reliable &&
- in_store == form.in_store &&
- moving_blocked_for_list == form.moving_blocked_for_list;
-}
-
-bool PasswordForm::operator!=(const PasswordForm& form) const {
- return !operator==(form);
-}
-
bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
const PasswordForm& right) {
return (left.signon_realm == right.signon_realm && left.url == right.url &&
@@ -266,6 +217,58 @@ bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
left.password_element == right.password_element);
}
+bool operator==(const PasswordForm& lhs, const PasswordForm& rhs) {
+ return lhs.scheme == rhs.scheme && lhs.signon_realm == rhs.signon_realm &&
+ lhs.url == rhs.url && lhs.action == rhs.action &&
+ lhs.submit_element == rhs.submit_element &&
+ lhs.username_element == rhs.username_element &&
+ lhs.username_element_renderer_id == rhs.username_element_renderer_id &&
+ lhs.username_value == rhs.username_value &&
+ lhs.all_possible_usernames == rhs.all_possible_usernames &&
+ lhs.all_possible_passwords == rhs.all_possible_passwords &&
+ lhs.form_has_autofilled_value == rhs.form_has_autofilled_value &&
+ lhs.password_element == rhs.password_element &&
+ lhs.password_element_renderer_id == rhs.password_element_renderer_id &&
+ lhs.password_value == rhs.password_value &&
+ lhs.new_password_element == rhs.new_password_element &&
+ lhs.confirmation_password_element_renderer_id ==
+ rhs.confirmation_password_element_renderer_id &&
+ lhs.confirmation_password_element ==
+ rhs.confirmation_password_element &&
+ lhs.confirmation_password_element_renderer_id ==
+ rhs.confirmation_password_element_renderer_id &&
+ lhs.new_password_value == rhs.new_password_value &&
+ lhs.date_created == rhs.date_created &&
+ lhs.date_synced == rhs.date_synced &&
+ lhs.date_last_used == rhs.date_last_used &&
+ lhs.blocked_by_user == rhs.blocked_by_user && lhs.type == rhs.type &&
+ lhs.times_used == rhs.times_used &&
+ lhs.form_data.SameFormAs(rhs.form_data) &&
+ lhs.generation_upload_status == rhs.generation_upload_status &&
+ lhs.display_name == rhs.display_name && lhs.icon_url == rhs.icon_url &&
+ // We compare the serialization of the origins here, as we want unique
+ // origins to compare as '=='.
+ lhs.federation_origin.Serialize() ==
+ rhs.federation_origin.Serialize() &&
+ lhs.skip_zero_click == rhs.skip_zero_click &&
+ lhs.was_parsed_using_autofill_predictions ==
+ rhs.was_parsed_using_autofill_predictions &&
+ lhs.is_public_suffix_match == rhs.is_public_suffix_match &&
+ lhs.is_affiliation_based_match == rhs.is_affiliation_based_match &&
+ lhs.affiliated_web_realm == rhs.affiliated_web_realm &&
+ lhs.app_display_name == rhs.app_display_name &&
+ lhs.app_icon_url == rhs.app_icon_url &&
+ lhs.submission_event == rhs.submission_event &&
+ lhs.only_for_fallback == rhs.only_for_fallback &&
+ lhs.is_new_password_reliable == rhs.is_new_password_reliable &&
+ lhs.in_store == rhs.in_store &&
+ lhs.moving_blocked_for_list == rhs.moving_blocked_for_list;
+}
+
+bool operator!=(const PasswordForm& lhs, const PasswordForm& rhs) {
+ return !(lhs == rhs);
+}
+
std::ostream& operator<<(std::ostream& os, PasswordForm::Scheme scheme) {
return os << ToString(scheme);
}
@@ -298,4 +301,4 @@ std::ostream& operator<<(std::ostream& os, PasswordForm* form) {
return os << "&" << *form;
}
-} // namespace autofill
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form.h b/chromium/components/password_manager/core/browser/password_form.h
index dee04bd7015..c0b57683caf 100644
--- a/chromium/components/password_manager/core/browser/password_form.h
+++ b/chromium/components/password_manager/core/browser/password_form.h
@@ -1,17 +1,389 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// 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_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_H_
-#include "components/autofill/core/common/password_form.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/time/time.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/gaia_id_hash.h"
+#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
+#include "components/autofill/core/common/renderer_id.h"
+#include "url/gurl.h"
+#include "url/origin.h"
namespace password_manager {
-// TODO(crbug.com/1067347): Move complete class to password_manager, once all
-// references to `autofill::PasswordForm` are dropped.
-using PasswordForm = autofill::PasswordForm;
+// Pair of a value and the name of the element that contained this value.
+using ValueElementPair = std::pair<base::string16, base::string16>;
+
+// Vector of possible username values and corresponding field names.
+using ValueElementVector = std::vector<ValueElementPair>;
+
+// The PasswordForm struct encapsulates information about a login form,
+// which can be an HTML form or a dialog with username/password text fields.
+//
+// The Web Data database stores saved username/passwords and associated form
+// metdata using a PasswordForm struct, typically one that was created from
+// a parsed HTMLFormElement or LoginDialog, but the saved entries could have
+// also been created by imported data from another browser.
+//
+// The PasswordManager implements a fuzzy-matching algorithm to compare saved
+// PasswordForm entries against PasswordForms that were created from a parsed
+// HTML or dialog form. As one might expect, the more data contained in one
+// of the saved PasswordForms, the better the job the PasswordManager can do
+// in matching it against the actual form it was saved on, and autofill
+// accurately. But it is not always possible, especially when importing from
+// other browsers with different data models, to copy over all the information
+// about a particular "saved password entry" to our PasswordForm
+// representation.
+//
+// The field descriptions in the struct specification below are intended to
+// describe which fields are not strictly required when adding a saved password
+// entry to the database and how they can affect the matching process.
+struct PasswordForm {
+ // Enum to differentiate between HTML form based authentication, and dialogs
+ // using basic or digest schemes. Default is kHtml. Only PasswordForms of the
+ // same Scheme will be matched/autofilled against each other.
+ enum class Scheme {
+ kHtml,
+ kBasic,
+ kDigest,
+ kOther,
+ kUsernameOnly,
+ kMinValue = kHtml,
+ kMaxValue = kUsernameOnly,
+ };
+
+ // Enum to differentiate between manually filled forms, forms with auto-
+ // generated passwords, and forms generated from the DOM API.
+ //
+ // Always append new types at the end. This enum is converted to int and
+ // stored in password store backends, so it is important to keep each
+ // value assigned to the same integer.
+ enum class Type {
+ kManual,
+ kGenerated,
+ kApi,
+ kMinValue = kManual,
+ kMaxValue = kApi,
+ };
+
+ // Enum to keep track of what information has been sent to the server about
+ // this form regarding password generation.
+ enum class GenerationUploadStatus {
+ kNoSignalSent,
+ kPositiveSignalSent,
+ kNegativeSignalSent,
+ kMinValue = kNoSignalSent,
+ kMaxValue = kNegativeSignalSent,
+ };
+
+ Scheme scheme = Scheme::kHtml;
+
+ // The "Realm" for the sign-on. This is scheme, host, port for SCHEME_HTML.
+ // Dialog based forms also contain the HTTP realm. Android based forms will
+ // contain a string of the form "android://<hash of cert>@<package name>"
+ //
+ // The signon_realm is effectively the primary key used for retrieving
+ // data from the database, so it must not be empty.
+ std::string signon_realm;
+
+ // An URL consists of the scheme, host, port and path; the rest is stripped.
+ // This is the primary data used by the PasswordManager to decide (in longest
+ // matching prefix fashion) whether or not a given PasswordForm result from
+ // the database is a good fit for a particular form on a page.
+ //
+ // This should not be empty except for Android based credentials.
+ GURL url;
+
+ // The action target of the form; like |origin| URL consists of the scheme,
+ // host, port and path; the rest is stripped. This is the primary data used by
+ // the PasswordManager for form autofill; that is, the action of the saved
+ // credentials must match the action of the form on the page to be autofilled.
+ // If this is empty / not available, it will result in a "restricted" IE-like
+ // autofill policy, where we wait for the user to type in their username
+ // before autofilling the password. In these cases, after successful login the
+ // action URL will automatically be assigned by the PasswordManager.
+ //
+ // When parsing an HTML form, this must always be set.
+ GURL action;
+
+ // The web realm affiliated with the Android application, if the form is an
+ // Android credential. Otherwise, the string is empty. If there are several
+ // realms affiliated with the application, an arbitrary realm is chosen. The
+ // field is filled out when the PasswordStore injects affiliation and branding
+ // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+ // no prior call to this method, the string is empty.
+ std::string affiliated_web_realm;
+
+ // The display name (e.g. Play Store name) of the Android application if the
+ // form is an Android credential. Otherwise, the string is empty. The field is
+ // filled out when the PasswordStore injects affiliation and branding
+ // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+ // no prior call to this method, the string is empty.
+ std::string app_display_name;
+
+ // The icon URL (e.g. Play Store icon URL) of the Android application if the
+ // form is an Android credential. Otherwise, the URL is empty. The field is
+ // filled out when the PasswordStore injects affiliation and branding
+ // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+ // no prior call to this method, the URL is empty.
+ GURL app_icon_url;
+
+ // The name of the submit button used. Optional; only used in scoring
+ // of PasswordForm results from the database to make matches as tight as
+ // possible.
+ base::string16 submit_element;
+
+ // The name of the username input element.
+ base::string16 username_element;
+
+ // The renderer id of the username input element. It is set during the new
+ // form parsing and not persisted.
+ autofill::FieldRendererId username_element_renderer_id;
+
+ // True if the server-side classification was successful.
+ bool server_side_classification_successful = false;
+
+ // True if the server-side classification believes that the field may be
+ // pre-filled with a placeholder in the value attribute. It is set during
+ // form parsing and not persisted.
+ bool username_may_use_prefilled_placeholder = false;
+
+ // When parsing an HTML form, this is typically empty unless the site
+ // has implemented some form of autofill.
+ base::string16 username_value;
+
+ // This member is populated in cases where we there are multiple input
+ // elements that could possibly be the username. Used when our heuristics for
+ // determining the username are incorrect. Optional.
+ ValueElementVector all_possible_usernames;
+
+ // This member is populated in cases where we there are multiple possible
+ // password values. Used in pending password state, to populate a dropdown
+ // for possible passwords. Contains all possible passwords. Optional.
+ ValueElementVector all_possible_passwords;
+
+ // True if |all_possible_passwords| have autofilled value or its part.
+ bool form_has_autofilled_value = false;
+
+ // The name of the input element corresponding to the current password.
+ // Optional (improves scoring).
+ //
+ // When parsing an HTML form, this will always be set, unless it is a sign-up
+ // form or a change password form that does not ask for the current password.
+ // In these two cases the |new_password_element| will always be set.
+ base::string16 password_element;
+
+ // The renderer id of the password input element. It is set during the new
+ // form parsing and not persisted.
+ autofill::FieldRendererId password_element_renderer_id;
+
+ // The current password. Must be non-empty for PasswordForm instances that are
+ // meant to be persisted to the password store.
+ //
+ // When parsing an HTML form, this is typically empty.
+ base::string16 password_value;
+
+ // The current encrypted password. Must be non-empty for PasswordForm
+ // instances retrieved from the password store or coming in a
+ // PasswordStoreChange that is not of type REMOVE.
+ std::string encrypted_password;
+
+ // If the form was a sign-up or a change password form, the name of the input
+ // element corresponding to the new password. Optional, and not persisted.
+ base::string16 new_password_element;
+
+ // The renderer id of the new password input element. It is set during the new
+ // form parsing and not persisted.
+ autofill::FieldRendererId new_password_element_renderer_id;
+
+ // The confirmation password element. Optional, only set on form parsing, and
+ // not persisted.
+ base::string16 confirmation_password_element;
+
+ // The renderer id of the confirmation password input element. It is set
+ // during the new form parsing and not persisted.
+ autofill::FieldRendererId confirmation_password_element_renderer_id;
+
+ // The new password. Optional, and not persisted.
+ base::string16 new_password_value;
+
+ // When the login was last used by the user to login to the site. Defaults to
+ // |date_created|, except for passwords that were migrated from the now
+ // deprecated |preferred| flag. Their default is set when migrating the login
+ // database to have the "date_last_used" column.
+ //
+ // When parsing an HTML form, this is not used.
+ base::Time date_last_used;
+
+ // When the login was saved (by chrome).
+ //
+ // When parsing an HTML form, this is not used.
+ base::Time date_created;
+
+ // When the login was downloaded from the sync server. For local passwords is
+ // not used.
+ //
+ // When parsing an HTML form, this is not used.
+ base::Time date_synced;
+
+ // Tracks if the user opted to never remember passwords for this form. Default
+ // to false.
+ //
+ // When parsing an HTML form, this is not used.
+ bool blocked_by_user = false;
+
+ // The form type.
+ Type type = Type::kManual;
+
+ // The number of times that this username/password has been used to
+ // authenticate the user.
+ //
+ // When parsing an HTML form, this is not used.
+ int times_used = 0;
+
+ // Autofill representation of this form. Used to communicate with the
+ // Autofill servers if necessary. Currently this is only used to help
+ // determine forms where we can trigger password generation.
+ //
+ // When parsing an HTML form, this is normally set.
+ autofill::FormData form_data;
+
+ // What information has been sent to the Autofill server about this form.
+ GenerationUploadStatus generation_upload_status =
+ GenerationUploadStatus::kNoSignalSent;
+
+ // These following fields are set by a website using the Credential Manager
+ // API. They will be empty and remain unused for sites which do not use that
+ // API.
+ //
+ // User friendly name to show in the UI.
+ base::string16 display_name;
+
+ // The URL of this credential's icon, such as the user's avatar, to display
+ // in the UI.
+ GURL icon_url;
+
+ // The origin of identity provider used for federated login.
+ url::Origin federation_origin;
+
+ // If true, Chrome will not return this credential to a site in response to
+ // 'navigator.credentials.request()' without user interaction.
+ // Once user selects this credential the flag is reseted.
+ bool skip_zero_click = false;
+
+ // If true, this form was parsed using Autofill predictions.
+ bool was_parsed_using_autofill_predictions = false;
+
+ // If true, this match was found using public suffix matching.
+ bool is_public_suffix_match = false;
+
+ // If true, this is a credential saved through an Android application, and
+ // found using affiliation-based match.
+ bool is_affiliation_based_match = false;
+
+ // The type of the event that was taken as an indication that this form is
+ // being or has already been submitted. This field is not persisted and filled
+ // out only for submitted forms.
+ autofill::mojom::SubmissionIndicatorEvent submission_event =
+ autofill::mojom::SubmissionIndicatorEvent::NONE;
+
+ // True iff heuristics declined this form for normal saving or filling (e.g.
+ // only credit card fields were found). But this form can be saved or filled
+ // only with the fallback.
+ bool only_for_fallback = false;
+
+ // True iff the new password field was found with server hints or autocomplete
+ // attributes or the kTreatNewPasswordHeuristicsAsReliable feature is enabled.
+ // Only set on form parsing for filling, and not persisted. Used as signal for
+ // password generation eligibility.
+ bool is_new_password_reliable = false;
+
+ // Serialized to prefs, so don't change numeric values!
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class Store {
+ // Default value.
+ kNotSet = 0,
+ // Credential came from the profile (i.e. local) storage.
+ kProfileStore = 1,
+ // Credential came from the Gaia-account-scoped storage.
+ kAccountStore = 2,
+ kMaxValue = kAccountStore
+ };
+ Store in_store = Store::kNotSet;
+
+ // Vector of hashes of the gaia id for users who prefer not to move this
+ // password form to their account. This list is used to suppress the move
+ // prompt for those users.
+ std::vector<autofill::GaiaIdHash> moving_blocked_for_list;
+
+ // Return true if we consider this form to be a change password form.
+ // We use only client heuristics, so it could include signup forms.
+ bool IsPossibleChangePasswordForm() const;
+
+ // Return true if we consider this form to be a change password form
+ // without username field. We use only client heuristics, so it could
+ // include signup forms.
+ bool IsPossibleChangePasswordFormWithoutUsername() const;
+
+ // Returns true if current password element is set.
+ bool HasUsernameElement() const;
+
+ // Returns true if current password element is set.
+ bool HasPasswordElement() const;
+
+ // Returns true if current password element is set.
+ bool HasNewPasswordElement() const;
+
+ // True iff |federation_origin| isn't empty.
+ bool IsFederatedCredential() const;
+
+ // True if username element is set and password and new password elements are
+ // not set.
+ bool IsSingleUsername() const;
+
+ // Returns whether this form is stored in the account-scoped store, i.e.
+ // whether |in_store == Store::kAccountStore|.
+ bool IsUsingAccountStore() const;
+
+ // Returns true when |password_value| or |new_password_value| are non-empty.
+ bool HasNonEmptyPasswordValue() const;
+
+ PasswordForm();
+ PasswordForm(const PasswordForm& other);
+ PasswordForm(PasswordForm&& other);
+ ~PasswordForm();
+
+ PasswordForm& operator=(const PasswordForm& form);
+ PasswordForm& operator=(PasswordForm&& form);
+};
+
+// True if the unique keys for the forms are the same. The unique key is
+// (origin, username_element, username_value, password_element, signon_realm).
+bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
+ const PasswordForm& right);
+
+// For testing.
+#if defined(UNIT_TEST)
+// An exact equality comparison of all the fields is only useful for tests.
+// Production code should be using `ArePasswordFormUniqueKeysEqual` instead.
+bool operator==(const PasswordForm& lhs, const PasswordForm& rhs);
+bool operator!=(const PasswordForm& lhs, const PasswordForm& rhs);
+
+std::ostream& operator<<(std::ostream& os, PasswordForm::Scheme scheme);
+std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
+std::ostream& operator<<(std::ostream& os, PasswordForm* form);
+#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.cc b/chromium/components/password_manager/core/browser/password_form_filling.cc
index 7f6c5f760f5..a3237754374 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling.cc
@@ -29,6 +29,13 @@ using Logger = autofill::SavePasswordProgressLogger;
namespace password_manager {
namespace {
+
+// Controls whether we should suppress the account storage promos for websites
+// that are blocked by the user.
+const base::Feature kSuppressAccountStoragePromosForBlockedWebsite{
+ "SuppressAccountStoragePromosForBlockedWebsite",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
bool PreferredRealmIsFromAndroid(const PasswordFormFillData& fill_data) {
return FacetURI::FromPotentiallyInvalidSpec(fill_data.preferred_realm)
.IsValidAndroidFacetURI();
@@ -126,6 +133,7 @@ LikelyFormFilling SendFillInformationToRenderer(
const std::vector<const PasswordForm*>& best_matches,
const std::vector<const PasswordForm*>& federated_matches,
const PasswordForm* preferred_match,
+ bool blocked_by_user,
PasswordFormMetricsRecorder* metrics_recorder) {
DCHECK(driver);
DCHECK_EQ(PasswordForm::Scheme::kHtml, observed_form.scheme);
@@ -141,10 +149,15 @@ LikelyFormFilling SendFillInformationToRenderer(
}
if (best_matches.empty()) {
+ bool should_suppres_popup =
+ blocked_by_user && base::FeatureList::IsEnabled(
+ kSuppressAccountStoragePromosForBlockedWebsite);
bool should_show_popup_without_passwords =
- client->GetPasswordFeatureManager()->ShouldShowAccountStorageOptIn() ||
- client->GetPasswordFeatureManager()->ShouldShowAccountStorageReSignin(
- client->GetLastCommittedURL());
+ !should_suppres_popup &&
+ (client->GetPasswordFeatureManager()->ShouldShowAccountStorageOptIn() ||
+ client->GetPasswordFeatureManager()->ShouldShowAccountStorageReSignin(
+ client->GetLastCommittedURL()));
+
driver->InformNoSavedCredentials(should_show_popup_without_passwords);
metrics_recorder->RecordFillEvent(
PasswordFormMetricsRecorder::kManagerFillEventNoCredential);
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.h b/chromium/components/password_manager/core/browser/password_form_filling.h
index 32963800834..bf9da1a367f 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling.h
+++ b/chromium/components/password_manager/core/browser/password_form_filling.h
@@ -9,16 +9,16 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace autofill {
struct PasswordFormFillData;
} // namespace autofill
namespace password_manager {
+class PasswordFormMetricsRecorder;
class PasswordManagerClient;
class PasswordManagerDriver;
-class PasswordFormMetricsRecorder;
+struct PasswordForm;
// Enum detailing the browser process' best belief what kind of credential
// filling is used in the renderer for a given password form.
@@ -46,6 +46,7 @@ LikelyFormFilling SendFillInformationToRenderer(
const std::vector<const PasswordForm*>& best_matches,
const std::vector<const PasswordForm*>& federated_matches,
const PasswordForm* preferred_match,
+ bool blocked_by_user,
PasswordFormMetricsRecorder* metrics_recorder);
// Create a PasswordFormFillData structure in preparation for filling a form
diff --git a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
index f4152ead1d8..77528c6a89d 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -150,7 +150,7 @@ TEST_F(PasswordFormFillingTest, NoSavedCredentials) {
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
- nullptr, metrics_recorder_.get());
+ nullptr, /*blocked_by_user=*/false, metrics_recorder_.get());
EXPECT_EQ(LikelyFormFilling::kNoFilling, likely_form_filling);
}
@@ -169,7 +169,7 @@ TEST_F(PasswordFormFillingTest, Autofill) {
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
- &saved_match_, metrics_recorder_.get());
+ &saved_match_, /*blocked_by_user=*/false, metrics_recorder_.get());
// On Android Touch To Fill will prevent autofilling credentials on page load.
#if defined(OS_ANDROID)
@@ -241,7 +241,7 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form, best_matches, federated_matches_,
- &saved_match_, metrics_recorder_.get());
+ &saved_match_, /*blocked_by_user=*/false, metrics_recorder_.get());
// In all cases where a current password exists, fill on load should be
// permitted. Otherwise, the renderer will not fill anyway and return
@@ -264,8 +264,8 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
// if server side classification thought the username was a placeholder or the
// classification failed. Do not overwrite if username doesn't look like a
// placeholder.
-// Skip for Android since it uses touch to fill (kAutofillTouchToFill), meaning
-// placeholders will never be overwritten.
+// Skip for Android since it uses touch to fill, meaning placeholders will never
+// be overwritten.
#if !defined(OS_ANDROID)
TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestionWithPrefill) {
const struct {
@@ -314,7 +314,7 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestionWithPrefill) {
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form, best_matches, federated_matches_,
- &preferred_match, metrics_recorder_.get());
+ &preferred_match, /*blocked_by_user=*/false, metrics_recorder_.get());
EXPECT_EQ(test_case.likely_form_filling, likely_form_filling);
}
@@ -331,7 +331,7 @@ TEST_F(PasswordFormFillingTest, AutofillPSLMatch) {
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_form_, best_matches, federated_matches_,
- &psl_saved_match_, metrics_recorder_.get());
+ &psl_saved_match_, /*blocked_by_user=*/false, metrics_recorder_.get());
EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
// Check that the message to the renderer (i.e. |fill_data|) is filled
@@ -362,7 +362,7 @@ TEST_F(PasswordFormFillingTest, NoAutofillOnHttp) {
EXPECT_CALL(client_, IsCommittedMainFrameSecure).WillOnce(Return(false));
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
&client_, &driver_, observed_http_form, best_matches, federated_matches_,
- &saved_http_match, metrics_recorder_.get());
+ &saved_http_match, /*blocked_by_user=*/false, metrics_recorder_.get());
EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
}
@@ -370,20 +370,10 @@ TEST_F(PasswordFormFillingTest, NoAutofillOnHttp) {
TEST_F(PasswordFormFillingTest, TouchToFill) {
std::vector<const PasswordForm*> best_matches = {&saved_match_};
- for (bool enable_touch_to_fill : {false, true}) {
- SCOPED_TRACE(testing::Message() << "Enable Touch To Fill: "
- << std::boolalpha << enable_touch_to_fill);
- base::test::ScopedFeatureList features;
- features.InitWithFeatureState(autofill::features::kAutofillTouchToFill,
- enable_touch_to_fill);
-
- LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
- &client_, &driver_, observed_form_, best_matches, federated_matches_,
- &saved_match_, metrics_recorder_.get());
- EXPECT_EQ(enable_touch_to_fill ? LikelyFormFilling::kFillOnAccountSelect
- : LikelyFormFilling::kFillOnPageLoad,
- likely_form_filling);
- }
+ LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
+ &client_, &driver_, observed_form_, best_matches, federated_matches_,
+ &saved_match_, /*blocked_by_user=*/false, metrics_recorder_.get());
+ EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
}
#endif
diff --git a/chromium/components/password_manager/core/browser/password_form_forward.h b/chromium/components/password_manager/core/browser/password_form_forward.h
deleted file mode 100644
index 14b58ad5609..00000000000
--- a/chromium/components/password_manager/core/browser/password_form_forward.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FORWARD_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FORWARD_H_
-
-// While `password_manager::PasswordForm` is just an alias to
-// `autofill::PasswordForm` it is rather awkward to construct a forward
-// declaration for it, since a naive solution such as
-// namespace password_manager { struct PasswordForm; } would break the build.
-// This file aims to make this easier, and classes merely interested in a
-// forward declaration can simply #include this header.
-//
-// TODO(crbug.com/1067347): Remove this file once password_manager::PasswordForm
-// is a real class, and a regular forward declaration does work.
-namespace autofill {
-struct PasswordForm;
-}
-
-namespace password_manager {
-using PasswordForm = autofill::PasswordForm;
-}
-
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FORWARD_H_
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.cc b/chromium/components/password_manager/core/browser/password_form_manager.cc
index bc4a4a06258..b099a24c79c 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form_generation_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/field_info_manager.h"
@@ -50,7 +51,7 @@ using autofill::FormStructure;
using autofill::GaiaIdHash;
using autofill::NOT_USERNAME;
using autofill::SINGLE_USERNAME;
-using autofill::ValueElementPair;
+using autofill::password_generation::PasswordGenerationType;
using base::TimeDelta;
using base::TimeTicks;
@@ -99,6 +100,13 @@ bool FormContainsFieldWithName(const FormData& form,
return false;
}
+// Returns whether reparsing server predictions following a form change is
+// enabled.
+bool IsReparsingServerPredictionsEnabled() {
+ return base::FeatureList::IsEnabled(
+ features::kReparseServerPredictionsFollowingFormChange);
+}
+
bool IsUsernameFirstFlowFeatureEnabled() {
return base::FeatureList::IsEnabled(features::kUsernameFirstFlow);
}
@@ -312,11 +320,6 @@ void PasswordFormManager::Save() {
}
void PasswordFormManager::Update(const PasswordForm& credentials_to_update) {
- metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
- parsed_submitted_form_->submission_event);
- metrics_recorder_->SetSubmissionIndicatorEvent(
- parsed_submitted_form_->submission_event);
-
password_save_manager_->Update(credentials_to_update, observed_form(),
*parsed_submitted_form_);
@@ -487,7 +490,8 @@ bool PasswordFormManager::HasGeneratedPassword() const {
}
void PasswordFormManager::SetGenerationPopupWasShown(
- bool is_manual_generation) {
+ PasswordGenerationType type) {
+ const bool is_manual_generation = type == PasswordGenerationType::kManual;
votes_uploader_.set_generation_popup_was_shown(true);
votes_uploader_.set_is_manual_generation(is_manual_generation);
metrics_recorder_->SetPasswordGenerationPopupShown(true,
@@ -766,15 +770,9 @@ void PasswordFormManager::ProcessServerPredictions(
// predictions again.
return;
}
- FormSignature observed_form_signature =
- CalculateFormSignature(*observed_form());
- auto it = predictions.find(observed_form_signature);
- if (it == predictions.end())
- return;
-
- ReportTimeBetweenStoreAndServerUMA();
- parser_.set_predictions(it->second);
- Fill();
+ UpdatePredictionsForObservedForm(predictions);
+ if (parser_.predictions())
+ Fill();
}
void PasswordFormManager::Fill() {
@@ -801,21 +799,15 @@ void PasswordFormManager::Fill() {
return;
if (observed_password_form->is_new_password_reliable && !IsBlacklisted()) {
+ driver_->FormEligibleForGenerationFound({
#if defined(OS_IOS)
- driver_->FormEligibleForGenerationFound(
- {/*form_renderer_id*/ observed_password_form->form_data
- .unique_renderer_id,
- /*new_password_element_renderer_id*/
- observed_password_form->new_password_element_renderer_id,
- /*confirmation_password_element_renderer_id*/
- observed_password_form->confirmation_password_element_renderer_id});
-#else
- driver_->FormEligibleForGenerationFound(
- {/*new_password_renderer_id*/
- observed_password_form->new_password_element_renderer_id,
- /*confirmation_password_renderer_id*/
- observed_password_form->confirmation_password_element_renderer_id});
+ .form_renderer_id = observed_password_form->form_data.unique_renderer_id,
#endif
+ .new_password_renderer_id =
+ observed_password_form->new_password_element_renderer_id,
+ .confirmation_password_renderer_id =
+ observed_password_form->confirmation_password_element_renderer_id,
+ });
}
#if defined(OS_IOS)
@@ -827,18 +819,26 @@ void PasswordFormManager::Fill() {
SendFillInformationToRenderer(
client_, driver_.get(), *observed_password_form.get(),
form_fetcher_->GetBestMatches(), form_fetcher_->GetFederatedMatches(),
- form_fetcher_->GetPreferredMatch(), metrics_recorder_.get());
+ form_fetcher_->GetPreferredMatch(), form_fetcher_->IsBlacklisted(),
+ metrics_recorder_.get());
}
-void PasswordFormManager::FillForm(const FormData& observed_form_data) {
+void PasswordFormManager::FillForm(
+ const FormData& observed_form_data,
+ const std::map<FormSignature, FormPredictions>& predictions) {
uint32_t differences_bitmask =
FindFormsDifferences(*observed_form(), observed_form_data);
metrics_recorder_->RecordFormChangeBitmask(differences_bitmask);
- if (differences_bitmask)
- *mutable_observed_form() = observed_form_data;
-
- if (!waiting_for_server_predictions_)
+ bool new_predictions_available = false;
+ if (differences_bitmask) {
+ UpdateFormManagerWithFormChanges(observed_form_data, predictions);
+ new_predictions_available =
+ parser_.predictions() && IsReparsingServerPredictionsEnabled();
+ }
+ // Fill the form if relevant form predictions were found or if the
+ // manager is not waiting for new server predictions.
+ if (new_predictions_available || !waiting_for_server_predictions_)
Fill();
}
@@ -1063,4 +1063,29 @@ bool PasswordFormManager::UsePossibleUsername(
#endif // defined(OS_ANDROID)
}
+void PasswordFormManager::UpdatePredictionsForObservedForm(
+ const std::map<FormSignature, FormPredictions>& predictions) {
+ FormSignature observed_form_signature =
+ CalculateFormSignature(*observed_form());
+ auto it = predictions.find(observed_form_signature);
+ if (it == predictions.end())
+ return;
+
+ ReportTimeBetweenStoreAndServerUMA();
+ parser_.set_predictions(it->second);
+}
+
+void PasswordFormManager::UpdateFormManagerWithFormChanges(
+ const FormData& observed_form_data,
+ const std::map<FormSignature, FormPredictions>& predictions) {
+ *mutable_observed_form() = observed_form_data;
+ if (!IsReparsingServerPredictionsEnabled())
+ return;
+
+ // If the observed form has changed, it might be autofilled again.
+ autofills_left_ = kMaxTimesAutofill;
+ parser_.reset_predictions();
+ UpdatePredictionsForObservedForm(predictions);
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.h b/chromium/components/password_manager/core/browser/password_form_manager.h
index 64465eb6533..dceeaa93c85 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -17,6 +17,7 @@
#include "build/build_config.h"
#include "components/autofill/core/common/field_data_manager.h"
#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/form_fetcher.h"
@@ -126,8 +127,11 @@ class PasswordFormManager : public PasswordFormManagerForUI,
// Sends fill data to the renderer.
void Fill();
- // Sends fill data to the renderer to fill |observed_form_data|.
- void FillForm(const autofill::FormData& observed_form_data);
+ // Sends fill data to the renderer to fill |observed_form_data| using
+ // new relevant data from |predictions|.
+ void FillForm(
+ const autofill::FormData& observed_form_data,
+ const std::map<autofill::FormSignature, FormPredictions>& predictions);
void UpdateSubmissionIndicatorEvent(
autofill::mojom::SubmissionIndicatorEvent event);
@@ -176,7 +180,8 @@ class PasswordFormManager : public PasswordFormManagerForUI,
const base::string16& generated_password);
void PasswordNoLongerGenerated();
bool HasGeneratedPassword() const;
- void SetGenerationPopupWasShown(bool is_manual_generation);
+ void SetGenerationPopupWasShown(
+ autofill::password_generation::PasswordGenerationType type);
void SetGenerationElement(autofill::FieldRendererId generation_element);
bool IsPossibleChangePasswordFormWithoutUsername() const;
bool IsPasswordUpdate() const;
@@ -317,6 +322,17 @@ class PasswordFormManager : public PasswordFormManagerForUI,
// looks valid.
bool UsePossibleUsername(const PossibleUsernameData* possible_username);
+ // Updates the predictions stored in |parser_| with predictions relevant for
+ // |observed_form_or_digest_|.
+ void UpdatePredictionsForObservedForm(
+ const std::map<autofill::FormSignature, FormPredictions>& predictions);
+
+ // Updates |observed_form_or_digest_| and form predictions stored in
+ // |parser_| and resets the amount of autofills left.
+ void UpdateFormManagerWithFormChanges(
+ const autofill::FormData& observed_form_data,
+ const std::map<autofill::FormSignature, FormPredictions>& predictions);
+
// The client which implements embedder-specific PasswordManager operations.
PasswordManagerClient* client_;
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
index 3d6c4f9b0a3..5f9e5147b95 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
@@ -10,13 +10,13 @@
#include "base/containers/span.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
namespace password_manager {
struct CompromisedCredentials;
struct InteractionsStats;
+struct PasswordForm;
class PasswordFormMetricsRecorder;
// Interface that contains all methods from PasswordFormManager that are used in
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
index 9a8e3d522d1..7843c7d9228 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -67,6 +67,7 @@ using autofill::PasswordFormGenerationData;
using autofill::ServerFieldType;
using autofill::SINGLE_USERNAME;
using autofill::UNKNOWN_TYPE;
+using autofill::password_generation::PasswordGenerationType;
using base::ASCIIToUTF16;
using testing::_;
using testing::AllOf;
@@ -1421,7 +1422,7 @@ TEST_P(PasswordFormManagerTest, PresaveGeneratedPasswordEmptyStore) {
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
- form_manager_->SetGenerationPopupWasShown(false /* is_manual_generation */);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kAutomatic);
// Check that the generated password is presaved.
PasswordForm saved_form;
@@ -1478,7 +1479,7 @@ TEST_P(PasswordFormManagerTest, PresaveGenerated_ModifiedUsername) {
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
- form_manager_->SetGenerationPopupWasShown(false /* is_manual_generation */);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kAutomatic);
// Check that the generated password is presaved.
PasswordForm saved_form;
@@ -1582,7 +1583,7 @@ TEST_P(PasswordFormManagerTest, PasswordNoLongerGenerated) {
fetcher_->NotifyFetchCompleted();
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
- form_manager_->SetGenerationPopupWasShown(true /* is_manual_generation */);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kManual);
EXPECT_CALL(form_saver, Save(_, _, _));
@@ -1615,7 +1616,7 @@ TEST_P(PasswordFormManagerTest, PresaveGeneratedPasswordExistingCredential) {
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
- form_manager_->SetGenerationPopupWasShown(false /* is_manual_generation */);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kAutomatic);
// Check that the generated password is presaved.
PasswordForm saved_form;
@@ -1712,7 +1713,7 @@ TEST_P(PasswordFormManagerTest, FillForm) {
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
- form_manager_->FillForm(form);
+ form_manager_->FillForm(form, {});
EXPECT_EQ(form.fields[kUsernameFieldIndex].name,
fill_data.username_field.name);
@@ -1746,8 +1747,7 @@ TEST_P(PasswordFormManagerTest, FillFormWaitForServerPredictions) {
// Check that no filling until server predicions or filling timeout
// expiration.
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
- form_manager_->FillForm(changed_form);
- Mock::VerifyAndClearExpectations(&driver_);
+ form_manager_->FillForm(changed_form, {});
// Check that the changed form is filled after the filling timeout expires.
@@ -1854,7 +1854,8 @@ TEST_P(PasswordFormManagerTest, GenerationUploadOnNoInteraction) {
if (generation_popup_shown) {
form_manager_->SetGenerationElement(FieldRendererId(3));
- form_manager_->SetGenerationPopupWasShown(false /*is_manual_generation*/);
+ form_manager_->SetGenerationPopupWasShown(
+ PasswordGenerationType::kAutomatic);
}
EXPECT_TRUE(
form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr));
@@ -1877,7 +1878,8 @@ TEST_P(PasswordFormManagerTest, GenerationUploadOnNeverClicked) {
if (generation_popup_shown) {
form_manager_->SetGenerationElement(FieldRendererId(3));
- form_manager_->SetGenerationPopupWasShown(false /*is_manual_generation*/);
+ form_manager_->SetGenerationPopupWasShown(
+ PasswordGenerationType::kAutomatic);
}
EXPECT_TRUE(
form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr));
@@ -2647,7 +2649,7 @@ TEST_F(PasswordFormManagerTestWithMockedSaver, GetPendingCredentials) {
TEST_F(PasswordFormManagerTestWithMockedSaver, PresaveGeneratedPassword) {
fetcher_->NotifyFetchCompleted();
EXPECT_FALSE(form_manager_->HasGeneratedPassword());
- form_manager_->SetGenerationPopupWasShown(/*is_manual_generation=*/false);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kAutomatic);
PasswordForm form_with_generated_password = parsed_submitted_form_;
FormData& form_data = form_with_generated_password.form_data;
// Check that the generated password is forwarded to the save manager.
@@ -2717,7 +2719,7 @@ TEST_F(PasswordFormManagerTestWithMockedSaver,
TEST_F(PasswordFormManagerTestWithMockedSaver, PasswordNoLongerGenerated) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
fetcher_->NotifyFetchCompleted();
- form_manager_->SetGenerationPopupWasShown(true /* is_manual_generation */);
+ form_manager_->SetGenerationPopupWasShown(PasswordGenerationType::kManual);
EXPECT_CALL(*mock_password_save_manager(), PresaveGeneratedPassword(_));
PasswordForm form = parsed_submitted_form_;
form_manager_->PresaveGeneratedPassword(form.form_data, form.password_value);
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
index 373ace52991..91545c9f523 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -281,6 +281,8 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
if (password_generation_popup_shown_ !=
PasswordGenerationPopupShown::kNotShown) {
+ UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.PopupShown",
+ password_generation_popup_shown_);
ukm_entry_builder_.SetGeneration_PopupShown(
static_cast<int64_t>(password_generation_popup_shown_));
}
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
index 00555143942..00658c869f9 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -18,7 +18,7 @@
#include "base/time/clock.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/signatures.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
+#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -170,6 +170,7 @@ class PasswordFormMetricsRecorder
kNotShown = 0,
kShownAutomatically = 1,
kShownManually = 2,
+ kMaxValue = kShownManually,
};
// Metric: PasswordGeneration.UserDecision
diff --git a/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc b/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
index 5c4867773da..6abd82ba3ee 100644
--- a/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_frame_helper_unittest.cc
@@ -12,7 +12,6 @@
#include "base/metrics/field_trial.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
diff --git a/chromium/components/password_manager/core/browser/password_list_sorter.h b/chromium/components/password_manager/core/browser/password_list_sorter.h
index c21e1a045be..e880e855604 100644
--- a/chromium/components/password_manager/core/browser/password_list_sorter.h
+++ b/chromium/components/password_manager/core/browser/password_list_sorter.h
@@ -11,10 +11,11 @@
#include <vector>
#include "base/util/type_safety/strong_alias.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
+struct PasswordForm;
+
// Multimap from sort key to password forms.
using DuplicatesMap = std::multimap<std::string, std::unique_ptr<PasswordForm>>;
using IgnoreStore = util::StrongAlias<class IgnoreStoreTag, bool>;
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index a1c8efe4861..75fd737fef6 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -13,6 +13,7 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -23,6 +24,7 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/common/form_data_predictions.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/save_password_progress_logger.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
@@ -59,7 +61,7 @@ using autofill::NOT_USERNAME;
using autofill::SINGLE_USERNAME;
using autofill::UNKNOWN_TYPE;
using autofill::USERNAME;
-using autofill::mojom::PasswordFormFieldPredictionType;
+using autofill::mojom::SubmissionIndicatorEvent;
using base::NumberToString;
using BlacklistedStatus =
password_manager::OriginCredentialStore::BlacklistedStatus;
@@ -229,8 +231,6 @@ void PasswordManager::RegisterProfilePrefs(
registry->RegisterTimePref(prefs::kAccountStoreDateLastUsedForFilling,
base::Time());
- registry->RegisterIntegerPref(prefs::kSettingsLaunchedPasswordChecks, 0);
-
#if defined(OS_APPLE)
registry->RegisterIntegerPref(prefs::kKeychainMigrationStatus,
4 /* MIGRATED_DELETED */);
@@ -298,17 +298,17 @@ void PasswordManager::OnPasswordNoLongerGenerated(PasswordManagerDriver* driver,
form_manager->PasswordNoLongerGenerated();
}
-void PasswordManager::SetGenerationElementAndReasonForForm(
+void PasswordManager::SetGenerationElementAndTypeForForm(
password_manager::PasswordManagerDriver* driver,
const FormData& form_data,
FieldRendererId generation_element,
- bool is_manually_triggered) {
+ autofill::password_generation::PasswordGenerationType type) {
DCHECK(client_->IsSavingAndFillingEnabled(form_data.url));
PasswordFormManager* form_manager = GetMatchedManager(driver, form_data);
if (form_manager) {
form_manager->SetGenerationElement(generation_element);
- form_manager->SetGenerationPopupWasShown(is_manually_triggered);
+ form_manager->SetGenerationPopupWasShown(type);
}
}
@@ -575,7 +575,7 @@ void PasswordManager::CreateFormManagers(
// filled values.
// TODO(https://crbug.com/831123): Implement more robust filling and
// remove the next line.
- manager->FillForm(form_data);
+ manager->FillForm(form_data, predictions_);
} else {
new_forms_data.push_back(&form_data);
}
@@ -890,8 +890,8 @@ void PasswordManager::OnPasswordFormsRendered(
}
void PasswordManager::OnLoginSuccessful() {
- if (autofill_assistant_mode_ == AutofillAssistantMode::kUIShown) {
- // Suppress prompts while Autofill Assistant is running.
+ if (client_->IsAutofillAssistantUIVisible()) {
+ // Suppress prompts while Autofill Assistant UI is shown.
return;
}
@@ -1223,23 +1223,51 @@ void PasswordManager::ShowManualFallbackForSaving(
}
}
-void PasswordManager::SetAutofillAssistantMode(AutofillAssistantMode mode) {
- if (autofill_assistant_mode_ == mode) {
+void PasswordManager::ResetPendingCredentials() {
+ for (auto& form_manager : form_managers_)
+ form_manager->ResetState();
+ owned_submitted_form_manager_.reset();
+}
+
+void PasswordManager::OnPasswordFormCleared(
+ PasswordManagerDriver* driver,
+ const autofill::FormData& form_data) {
+ PasswordFormManager* manager = GetMatchedManager(driver, form_data);
+ if (!manager || !manager->is_submitted() ||
+ !manager->GetSubmittedForm()->IsPossibleChangePasswordForm()) {
return;
}
- autofill_assistant_mode_ = mode;
-
- if (autofill_assistant_mode_ == AutofillAssistantMode::kUINotShown) {
- // Reset pending credentials as Autofill Assistant has handled the pending
- // submission.
- for (auto& form_manager : form_managers_)
- form_manager->ResetState();
- owned_submitted_form_manager_.reset();
+ // If a password form was cleared, login is successful.
+ if (form_data.is_form_tag &&
+ base::FeatureList::IsEnabled(
+ password_manager::features::kDetectFormSubmissionOnFormClear)) {
+ manager->UpdateSubmissionIndicatorEvent(
+ SubmissionIndicatorEvent::CHANGE_PASSWORD_FORM_CLEARED);
+ OnLoginSuccessful();
+ return;
+ }
+ // If password fields outside the <form> tag were cleared, it should be
+ // verified that fields are relevant.
+ FieldRendererId new_password_field_id =
+ manager->GetSubmittedForm()->new_password_element_renderer_id;
+ auto it = base::ranges::find(form_data.fields, new_password_field_id,
+ &autofill::FormFieldData::unique_renderer_id);
+ if (it != form_data.fields.end() && it->value.empty() &&
+ base::FeatureList::IsEnabled(
+ features::kDetectFormSubmissionOnFormClear)) {
+ manager->UpdateSubmissionIndicatorEvent(
+ SubmissionIndicatorEvent::CHANGE_PASSWORD_FORM_CLEARED);
+ OnLoginSuccessful();
}
}
-AutofillAssistantMode PasswordManager::GetAutofillAssistantMode() const {
- return autofill_assistant_mode_;
+bool PasswordManager::IsFormManagerPendingPasswordUpdate() const {
+ for (const auto& form_manager : form_managers_) {
+ if (form_manager->IsPasswordUpdate())
+ return true;
+ }
+ return owned_submitted_form_manager_ &&
+ owned_submitted_form_manager_->IsPasswordUpdate();
}
#if defined(OS_IOS)
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index a09eb2f08ed..ebdf9f995bf 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -17,6 +17,7 @@
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/credential_cache.h"
@@ -24,7 +25,6 @@
#include "components/password_manager/core/browser/form_submission_observer.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_check_factory.h"
#include "components/password_manager/core/browser/leak_detection_delegate.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_manager_interface.h"
#include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
#include "components/password_manager/core/browser/possible_username_data.h"
@@ -52,21 +52,9 @@ class PasswordManagerDriver;
class PasswordFormManagerForUI;
class PasswordFormManager;
class PasswordManagerMetricsRecorder;
+struct PasswordForm;
struct PossibleUsernameData;
-// Define the modes of collaboration between Password Manager and Autofill
-// Assistant (who handles form submissions, whether to show prompts or not).
-enum class AutofillAssistantMode {
- // Autofill Assistant UI is not being shown. Password Manager operates in the
- // regular
- // mode - it handles submissions and shows prompts.
- kUINotShown = 0,
- // Autofill Assistant UI is being shown. The password manager
- // is basically off - it does not handle submissions and therefore does not
- // show prompts. The script does all the work instead.
- kUIShown
-};
-
// Per-tab password manager. Handles creation and management of UI elements,
// receiving password form data from the renderer and managing the password
// database through the PasswordStore.
@@ -135,13 +123,12 @@ class PasswordManager : public PasswordManagerInterface {
void OnPasswordNoLongerGenerated(PasswordManagerDriver* driver,
const autofill::FormData& form_data);
- // Update the generation element and whether generation was triggered
- // manually.
- void SetGenerationElementAndReasonForForm(
+ // Update the `generation_element` and `type` for `form_data`.
+ void SetGenerationElementAndTypeForForm(
PasswordManagerDriver* driver,
const autofill::FormData& form_data,
autofill::FieldRendererId generation_element,
- bool is_manually_triggered);
+ autofill::password_generation::PasswordGenerationType type);
// Called upon navigation to persist the state from |CredentialCache|
// used to decide when to record
@@ -219,12 +206,15 @@ class PasswordManager : public PasswordManagerInterface {
// Notifies that Credential Management API function store() is called.
void NotifyStorePasswordCalled();
- // Sets the Autofill Assistant mode to disable prompts while |mode=kRunning|.
- // A script finish will clear pending credentials in all form managers.
- void SetAutofillAssistantMode(AutofillAssistantMode mode);
+ // Resets pending credentials.
+ void ResetPendingCredentials();
+
+ // Notification that password form was cleared by the website.
+ void OnPasswordFormCleared(PasswordManagerDriver* driver,
+ const autofill::FormData& form_data);
- // Returns the currently set autofill-assistant mode.
- AutofillAssistantMode GetAutofillAssistantMode() const;
+ // Returns true if a form manager is processing a password update.
+ bool IsFormManagerPendingPasswordUpdate() const;
private:
FRIEND_TEST_ALL_PREFIXES(
@@ -326,9 +316,6 @@ class PasswordManager : public PasswordManagerInterface {
// Returns the timeout for the disabling Password Manager's prompts.
base::TimeDelta GetTimeoutForDisablingPrompts();
- // Resets |autofill_assistant_mode_| to the default.
- void ResetAutofillAssistantMode();
-
#if defined(OS_IOS)
// Even though the formal submission might not happen, the manager
// could still be provisionally saved on user input or have autofilled data,
@@ -391,11 +378,6 @@ class PasswordManager : public PasswordManagerInterface {
base::Optional<PossibleUsernameData> possible_username_;
- // By default Autofill Assistant is not running. Password Manager handles
- // submissions and shows prompts.
- AutofillAssistantMode autofill_assistant_mode_ =
- AutofillAssistantMode::kUINotShown;
-
DISALLOW_COPY_AND_ASSIGN(PasswordManager);
};
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.cc b/chromium/components/password_manager/core/browser/password_manager_client.cc
index d01fabe30a7..7b73be9e2b7 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_client.cc
@@ -5,6 +5,7 @@
#include <utility>
#include "base/macros.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/http_auth_manager.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_manager_client.h"
@@ -31,11 +32,14 @@ bool PasswordManagerClient::RequiresReauthToFill() {
void PasswordManagerClient::ShowTouchToFill(PasswordManagerDriver* driver) {}
+void PasswordManagerClient::OnPasswordSelected(const base::string16& text) {}
+
BiometricAuthenticator* PasswordManagerClient::GetBiometricAuthenticator() {
return nullptr;
}
-void PasswordManagerClient::GeneratePassword() {}
+void PasswordManagerClient::GeneratePassword(
+ autofill::password_generation::PasswordGenerationType type) {}
void PasswordManagerClient::UpdateCredentialCache(
const url::Origin& origin,
@@ -149,9 +153,4 @@ network::mojom::NetworkContext* PasswordManagerClient::GetNetworkContext()
bool PasswordManagerClient::IsUnderAdvancedProtection() const {
return false;
}
-
-AutofillAssistantMode PasswordManagerClient::GetAutofillAssistantMode() const {
- return GetPasswordManager()->GetAutofillAssistantMode();
-}
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.h b/chromium/components/password_manager/core/browser/password_manager_client.h
index 0d445514af2..1859150bb5d 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -15,12 +15,12 @@
#include "base/util/type_safety/strong_alias.h"
#include "build/build_config.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/hsts_query.h"
#include "components/password_manager/core/browser/http_auth_manager.h"
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
#include "components/password_manager/core/browser/manage_passwords_referrer.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
@@ -59,11 +59,9 @@ class Origin;
class GURL;
-#if defined(ON_FOCUS_PING_ENABLED)
namespace safe_browsing {
class PasswordProtectionService;
}
-#endif
namespace password_manager {
@@ -76,6 +74,7 @@ class PasswordManagerMetricsRecorder;
class HttpAuthManager;
class PasswordRequirementsService;
class PasswordStore;
+struct PasswordForm;
enum SyncState {
NOT_SYNCING,
@@ -173,13 +172,18 @@ class PasswordManagerClient {
// Instructs the client to show the Touch To Fill UI.
virtual void ShowTouchToFill(PasswordManagerDriver* driver);
+ // Informs `PasswordReuseDetectionManager` about reused passwords selected
+ // from the AllPasswordsBottomSheet.
+ virtual void OnPasswordSelected(const base::string16& text);
+
// Returns a pointer to a BiometricAuthenticator. Might be null if
// BiometricAuthentication is not available for a given platform.
virtual BiometricAuthenticator* GetBiometricAuthenticator();
- // Informs the embedder that the user has manually requested to generate a
+ // Informs the embedder that the user has requested to generate a
// password in the focused password field.
- virtual void GeneratePassword();
+ virtual void GeneratePassword(
+ autofill::password_generation::PasswordGenerationType type);
// Informs the embedder that automatic signing in just happened. The form
// returned to the site is |local_forms[0]|. |local_forms| contains all the
@@ -321,11 +325,9 @@ class PasswordManagerClient {
// Returns the current best guess as to the page's display language.
virtual std::string GetPageLanguage() const;
-#if defined(ON_FOCUS_PING_ENABLED) || defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Return the PasswordProtectionService associated with this instance.
virtual safe_browsing::PasswordProtectionService*
GetPasswordProtectionService() const = 0;
-#endif
#if defined(ON_FOCUS_PING_ENABLED)
// Checks the safe browsing reputation of the webpage when the
@@ -335,7 +337,6 @@ class PasswordManagerClient {
const GURL& frame_url) = 0;
#endif
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Checks the safe browsing reputation of the webpage where password reuse
// happens. This is called by the PasswordReuseDetectionManager when a
// protected password is typed on the wrong domain. This may trigger a
@@ -348,7 +349,6 @@ class PasswordManagerClient {
const std::string& username,
const std::vector<MatchingReusedCredential>& matching_reused_credentials,
bool password_field_exists) = 0;
-#endif
#if defined(PASSWORD_REUSE_WARNING_ENABLED)
// Records a Chrome Sync event that GAIA password reuse was detected.
@@ -408,8 +408,8 @@ class PasswordManagerClient {
// Returns a FieldInfoManager associated with the current profile.
virtual FieldInfoManager* GetFieldInfoManager() const = 0;
- // Returns the currently set autofill-assistant mode.
- virtual AutofillAssistantMode GetAutofillAssistantMode() const;
+ // Returns if the Autofill Assistant UI is shown.
+ virtual bool IsAutofillAssistantUIVisible() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient);
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util.cc b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
index 88fadda5145..ad3d2609fb7 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
@@ -40,6 +40,11 @@ bool CanAccountStorageBeEnabled(const syncer::SyncService* sync_service) {
if (!sync_service)
return false;
+ // The account-scoped password storage does not work with LocalSync aka
+ // roaming profiles.
+ if (sync_service->IsLocalSyncEnabled())
+ return false;
+
return true;
}
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
index 0a194116a76..f28c0488373 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util_unittest.cc
@@ -395,6 +395,51 @@ TEST(PasswordFeatureManagerUtil, SyncDisablesAccountStorage) {
PasswordForm::Store::kProfileStore);
}
+TEST(PasswordFeatureManagerUtil, LocalSyncDisablesAccountStorage) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(features::kEnablePasswordsAccountStorage);
+
+ TestingPrefServiceSimple pref_service;
+ pref_service.registry()->RegisterDictionaryPref(
+ prefs::kAccountStoragePerAccountSettings);
+
+ CoreAccountInfo account;
+ account.email = "name@account.com";
+ account.gaia = "name";
+ account.account_id = CoreAccountId::FromGaiaId(account.gaia);
+
+ // The SyncService is running in local-sync mode.
+ syncer::TestSyncService sync_service;
+ // In local-sync mode, there might or might not be an account. Set one for
+ // this test, so that all other conditions for using the account-scoped
+ // storage are fulfilled.
+ sync_service.SetIsAuthenticatedAccountPrimary(false);
+ sync_service.SetAuthenticatedAccountInfo(account);
+ sync_service.SetLocalSyncEnabled(true);
+ ASSERT_EQ(sync_service.GetTransportState(),
+ syncer::SyncService::TransportState::ACTIVE);
+ ASSERT_FALSE(sync_service.IsSyncFeatureEnabled());
+
+ // The account-scoped storage should be unavailable.
+ ASSERT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
+ EXPECT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
+ PasswordForm::Store::kProfileStore);
+
+ // Even if the user is opted in (e.g. from a previous browser run, before
+ // local-sync was enabled), the account-scoped storage should remain
+ // unavailable.
+ OptInToAccountStorage(&pref_service, &sync_service);
+ // The user is *not* considered opted in (even though the corresponding pref
+ // is set) since the account storage is completely unavailable.
+ EXPECT_FALSE(IsOptedInForAccountStorage(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageOptIn(&pref_service, &sync_service));
+ EXPECT_FALSE(ShouldShowAccountStorageBubbleUi(&pref_service, &sync_service));
+ EXPECT_EQ(GetDefaultPasswordStore(&pref_service, &sync_service),
+ PasswordForm::Store::kProfileStore);
+}
+
TEST(PasswordFeatureManagerUtil, OptOutClearsStorePreference) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kEnablePasswordsAccountStorage);
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
index 8a2cd093e8c..671003bb259 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -248,6 +248,20 @@ void LogPasswordsCountFromAccountStoreAfterUnlock(
account_store_passwords_count);
}
+void LogDownloadedPasswordsCountFromAccountStoreAfterUnlock(
+ int account_store_passwords_count) {
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreCredentialsAfterOptIn",
+ account_store_passwords_count);
+}
+
+void LogDownloadedBlocklistedEntriesCountFromAccountStoreAfterUnlock(
+ int blocklist_entries_count) {
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreBlocklistedEntriesAfterOptIn",
+ blocklist_entries_count);
+}
+
void LogPasswordSettingsReauthResult(ReauthResult result) {
base::UmaHistogramEnumeration(
"PasswordManager.ReauthToAccessPasswordInSettings", result);
@@ -284,7 +298,6 @@ void LogGenerationDialogChoice(GenerationDialogChoice choice,
};
} // namespace metrics_util
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void LogGaiaPasswordHashChange(GaiaPasswordHashChange event,
bool is_sync_password) {
if (is_sync_password) {
@@ -332,7 +345,6 @@ void LogProtectedPasswordHashCounts(size_t gaia_hash_count,
}
void LogProtectedPasswordReuse(PasswordType reused_password_type) {}
-#endif
void LogPasswordEditResult(IsUsernameChanged username_changed,
IsPasswordChanged password_changed) {
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
index b0fd2f26975..28166925959 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -262,7 +262,6 @@ enum class DeleteCorruptedPasswordsResult {
kMaxValue = kEncryptionUnavailable,
};
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
enum class GaiaPasswordHashChange {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
@@ -297,7 +296,6 @@ enum class IsSyncPasswordHashSaved {
IS_SYNC_PASSWORD_HASH_SAVED_COUNT = 3,
kMaxValue = IS_SYNC_PASSWORD_HASH_SAVED_COUNT,
};
-#endif
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
@@ -596,8 +594,22 @@ void LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
// Log a frame of a submitted password form.
void LogSubmittedFormFrame(SubmittedFormFrame frame);
-// Logs how many account-stored passwords are available right after unlock.
-void LogPasswordsCountFromAccountStoreAfterUnlock(int account_store_passwords);
+// Logs how many account-stored passwords are available for filling in the
+// current password form right after unlock.
+void LogPasswordsCountFromAccountStoreAfterUnlock(
+ int account_store_passwords_count);
+
+// Logs how many account-stored passwords are downloaded right after unlock.
+// This is different from `LogPasswordsCountFromAccountStoreAfterUnlock` since
+// it records all the downloaded passwords not just those available for filling
+// in a specific password form.
+void LogDownloadedPasswordsCountFromAccountStoreAfterUnlock(
+ int account_store_passwords_count);
+
+// Logs how many blocklisted entries are downloaded to the account store right
+// after unlock.
+void LogDownloadedBlocklistedEntriesCountFromAccountStoreAfterUnlock(
+ int blocklist_entries_count);
// Logs the result of a re-auth challenge in the password settings.
void LogPasswordSettingsReauthResult(ReauthResult result);
@@ -617,7 +629,6 @@ void LogGenerationDialogChoice(
GenerationDialogChoice choice,
autofill::password_generation::PasswordGenerationType type);
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Log a save gaia password change event.
void LogGaiaPasswordHashChange(GaiaPasswordHashChange event,
bool is_sync_password);
@@ -633,8 +644,6 @@ void LogProtectedPasswordHashCounts(size_t gaia_hash_count,
bool does_primary_account_exists,
bool is_signed_in);
-#endif
-
// Log the result of the password edit action.
void LogPasswordEditResult(IsUsernameChanged password_changed,
IsPasswordChanged username_changed);
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
index 18300e7ce77..ca63b5ef1db 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -120,7 +120,6 @@ MockPasswordStoreObserver::MockPasswordStoreObserver() = default;
MockPasswordStoreObserver::~MockPasswordStoreObserver() = default;
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() =
default;
@@ -158,6 +157,4 @@ void PasswordHashDataMatcher::DescribeNegationTo(::std::ostream* os) const {
return ::testing::MakeMatcher(new PasswordHashDataMatcher(expected));
}
-#endif
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.h b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
index 8540eb7942e..2f8081b68ef 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
@@ -12,15 +12,12 @@
#include "base/memory/ref_counted.h"
#include "components/password_manager/core/browser/origin_credential_store.h"
#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_hash_data.h"
+#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
#include "components/password_manager/core/browser/password_store.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "url/gurl.h"
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
-#include "components/password_manager/core/browser/password_hash_data.h" // nogncheck
-#include "components/password_manager/core/browser/password_reuse_detector_consumer.h" // nogncheck
-#endif
-
namespace password_manager {
// This template allows creating methods with signature conforming to
@@ -110,7 +107,6 @@ class MockPasswordStoreObserver : public PasswordStore::Observer {
MOCK_METHOD1(OnLoginsChanged, void(const PasswordStoreChangeList& changes));
};
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
public:
MockPasswordReuseDetectorConsumer();
@@ -145,7 +141,6 @@ class PasswordHashDataMatcher
::testing::Matcher<base::Optional<PasswordHashData>> Matches(
base::Optional<PasswordHashData> expected);
-#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
index d0866249ceb..169de09792b 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -25,6 +25,7 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/autofill/core/common/renderer_id.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/field_info_manager.h"
@@ -69,7 +70,6 @@ using autofill::NOT_USERNAME;
using autofill::PasswordFormFillData;
using autofill::ServerFieldType;
using autofill::SINGLE_USERNAME;
-using autofill::mojom::PasswordFormFieldPredictionType;
using base::ASCIIToUTF16;
using base::Feature;
using base::TestMockTimeTaskRunner;
@@ -142,6 +142,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
.WillByDefault(Return(false));
ON_CALL(filter_, IsSyncAccountEmail(_)).WillByDefault(Return(false));
ON_CALL(*this, IsNewTabPage()).WillByDefault(Return(false));
+ ON_CALL(*this, IsAutofillAssistantUIVisible()).WillByDefault(Return(false));
}
MOCK_METHOD(bool,
@@ -184,6 +185,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
(),
(override));
MOCK_METHOD(bool, IsNewTabPage, (), (const, override));
+ MOCK_METHOD(bool, IsAutofillAssistantUIVisible, (), (const, override));
MOCK_METHOD(SyncState, GetPasswordSyncState, (), (const, override));
MOCK_METHOD(FieldInfoManager*, GetFieldInfoManager, (), (const, override));
@@ -2144,7 +2146,7 @@ TEST_P(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
}
}
-TEST_P(PasswordManagerTest, SetGenerationElementAndReasonForForm) {
+TEST_P(PasswordManagerTest, SetGenerationElementAndTypeForForm) {
PasswordForm form(MakeSimpleForm());
EXPECT_CALL(client_, IsSavingAndFillingEnabled(form.url))
.WillRepeatedly(Return(true));
@@ -2152,9 +2154,9 @@ TEST_P(PasswordManagerTest, SetGenerationElementAndReasonForForm) {
EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _));
manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
- manager()->SetGenerationElementAndReasonForForm(
+ manager()->SetGenerationElementAndTypeForForm(
&driver_, form.form_data, form.form_data.fields[1].unique_renderer_id,
- false);
+ autofill::password_generation::PasswordGenerationType::kAutomatic);
EXPECT_CALL(*store_, AddLogin(_));
manager()->OnPresaveGeneratedPassword(&driver_, form.form_data,
form.password_value);
@@ -3404,9 +3406,7 @@ TEST_P(PasswordManagerTest,
EXPECT_CALL(driver_, FormEligibleForGenerationFound(_))
.WillOnce(SaveArg<0>(&form_generation_data));
manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
-#if !defined(OS_IOS)
EXPECT_EQ(password_field_id, form_generation_data.new_password_renderer_id);
-#endif
}
// Checks that username is saved on username first flow.
@@ -3585,8 +3585,8 @@ TEST_P(PasswordManagerTest, FormSubmittedOnIFrameMainFrameLoaded) {
}
TEST_P(PasswordManagerTest, NoPromptAutofillAssistantManuallyCuratedScript) {
- manager()->SetAutofillAssistantMode(AutofillAssistantMode::kUIShown);
-
+ EXPECT_CALL(client_, IsAutofillAssistantUIVisible)
+ .WillRepeatedly(Return(true));
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, GetLogins)
@@ -3623,7 +3623,6 @@ TEST_P(PasswordManagerTest,
EXPECT_CALL(client_, IsSavingAndFillingEnabled)
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr).Times(0);
- manager()->SetAutofillAssistantMode(AutofillAssistantMode::kUIShown);
// Make several forms ready for saving.
PasswordForm form1(MakeFormWithOnlyNewPasswordField());
@@ -3634,20 +3633,25 @@ TEST_P(PasswordManagerTest,
manager()->OnInformAboutUserInput(&driver_, form2.form_data);
// Simulate submission in different ways depending on whether
- // |owned_submitted_form_manager_| should be set and |form_managers_| should
+ // |owned_submitted_form_manager_| should be set and |form_managers_|should
// be cleared OR the submitted form manager should be in |form_managers_|.
if (set_owned_form_manager)
manager()->DidNavigateMainFrame(true /* form_may_be_submitted */);
else
OnPasswordFormSubmitted(form2.form_data);
- manager()->SetAutofillAssistantMode(AutofillAssistantMode::kUINotShown);
-
+ // Test that Autofill Assistant has finished a script before Password
+ // Manager detected a successful submission. As a script has finished,
+ // pending credentials have reset.
+ manager()->ResetPendingCredentials();
manager()->OnPasswordFormsRendered(&driver_, {} /* observed */,
true /* did stop loading */);
+
// No form manager is ready for saving.
EXPECT_FALSE(manager()->GetSubmittedManagerForTest());
+
Mock::VerifyAndClearExpectations(&client_);
+ EXPECT_CALL(client_, IsAutofillAssistantUIVisible).WillOnce(Return(false));
// A form reappears again and a user submits it manually. Now expect a
// prompt.
@@ -3662,6 +3666,201 @@ TEST_P(PasswordManagerTest,
}
}
+TEST_P(PasswordManagerTest, GenerationOnChangedForm) {
+ const bool kIsReparsingEnabled = GetParam();
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ features::kReparseServerPredictionsFollowingFormChange,
+ kIsReparsingEnabled);
+
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
+
+ // Create FormdData for a form with 1 password field and process it.
+ FormData form_data;
+ form_data.is_form_tag = false;
+ form_data.url = GURL("http://www.testwebsite.com");
+
+ FormFieldData old_password_field;
+ old_password_field.form_control_type = "password";
+ old_password_field.unique_renderer_id = FieldRendererId(0);
+ old_password_field.name = ASCIIToUTF16("oldpass");
+ form_data.fields.push_back(old_password_field);
+
+ manager()->OnPasswordFormsParsed(&driver_, {form_data});
+
+ // Form changes: new and confirmation password fields are added by the
+ // website's scripts.
+ FormFieldData new_password_field;
+ new_password_field.form_control_type = "password";
+ new_password_field.unique_renderer_id = FieldRendererId(1);
+ new_password_field.name = ASCIIToUTF16("newpass");
+ form_data.fields.push_back(new_password_field);
+
+ FormFieldData confirm_password_field;
+ confirm_password_field.form_control_type = "password";
+ confirm_password_field.unique_renderer_id = FieldRendererId(2);
+ confirm_password_field.name = ASCIIToUTF16("confpass");
+ form_data.fields.push_back(confirm_password_field);
+
+ // Server predictions may arrive before the form is parsed by PasswordManager.
+ FormStructure form_structure(form_data);
+ form_structure.field(1)->set_server_type(autofill::ACCOUNT_CREATION_PASSWORD);
+ form_structure.field(2)->set_server_type(autofill::CONFIRMATION_PASSWORD);
+ manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
+
+ autofill::PasswordFormGenerationData form_generation_data;
+ if (kIsReparsingEnabled) {
+ EXPECT_CALL(driver_, FormEligibleForGenerationFound)
+ .WillOnce(SaveArg<0>(&form_generation_data));
+ // The change is discovered by PasswordManager.
+ manager()->OnPasswordFormsParsed(&driver_, {form_data});
+ EXPECT_EQ(new_password_field.unique_renderer_id,
+ form_generation_data.new_password_renderer_id);
+ } else {
+ EXPECT_CALL(driver_, FormEligibleForGenerationFound).Times(0);
+ }
+}
+
+#if !defined(OS_IOS)
+TEST_P(PasswordManagerTest, SubmissionDetectedOnClearedForm) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kDetectFormSubmissionOnFormClear);
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+ PasswordForm saved_match(MakeSavedForm());
+ EXPECT_CALL(*store_, GetLogins)
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_match)));
+
+ // Create FormData for a form with 1 password field and process it.
+ FormData form_data;
+ form_data.unique_renderer_id = FormRendererId(0);
+ form_data.url = GURL("http://www.google.com/a/LoginAuth");
+
+ FormFieldData old_password_field;
+ old_password_field.form_control_type = "password";
+ old_password_field.unique_renderer_id = FieldRendererId(1);
+ old_password_field.name = ASCIIToUTF16("oldpass");
+ old_password_field.value = ASCIIToUTF16("oldpass");
+ form_data.fields.push_back(old_password_field);
+
+ FormFieldData new_password_field;
+ new_password_field.form_control_type = "password";
+ new_password_field.unique_renderer_id = FieldRendererId(2);
+ new_password_field.name = ASCIIToUTF16("newpass");
+ new_password_field.autocomplete_attribute = "new-password";
+ form_data.fields.push_back(new_password_field);
+
+ FormFieldData confirm_password_field;
+ confirm_password_field.form_control_type = "password";
+ confirm_password_field.unique_renderer_id = FieldRendererId(3);
+ confirm_password_field.name = ASCIIToUTF16("confpass");
+ form_data.fields.push_back(confirm_password_field);
+
+ manager()->OnPasswordFormsParsed(&driver_, {form_data});
+
+ form_data.fields[0].value = ASCIIToUTF16("oldpass");
+ form_data.fields[1].value = ASCIIToUTF16("newpass");
+ form_data.fields[2].value = ASCIIToUTF16("newpass");
+
+ manager()->OnInformAboutUserInput(&driver_, form_data);
+
+ std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr)
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ manager()->OnPasswordFormCleared(&driver_, form_data);
+}
+
+TEST_P(PasswordManagerTest, SubmissionDetectedOnClearedFormlessFields) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kDetectFormSubmissionOnFormClear);
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+ PasswordForm saved_match(MakeSavedForm());
+ EXPECT_CALL(*store_, GetLogins)
+ .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_match)));
+
+ for (bool new_password_field_was_cleared : {true, false}) {
+ SCOPED_TRACE(testing::Message("#new password field was cleared = ")
+ << new_password_field_was_cleared);
+
+ // Create FormData for a form with 1 password field and process it.
+ FormData form_data;
+ form_data.is_form_tag = false;
+ form_data.unique_renderer_id = FormRendererId(0);
+ form_data.url = GURL("http://www.google.com/a/LoginAuth");
+
+ FormFieldData old_password_field;
+ old_password_field.form_control_type = "password";
+ old_password_field.unique_renderer_id = FieldRendererId(1);
+ old_password_field.name = ASCIIToUTF16("oldpass");
+ old_password_field.value = ASCIIToUTF16("oldpass");
+ form_data.fields.push_back(old_password_field);
+
+ FormFieldData new_password_field;
+ new_password_field.form_control_type = "password";
+ new_password_field.unique_renderer_id = FieldRendererId(2);
+ new_password_field.name = ASCIIToUTF16("newpass");
+ new_password_field.autocomplete_attribute = "new-password";
+ form_data.fields.push_back(new_password_field);
+
+ FormFieldData confirm_password_field;
+ confirm_password_field.form_control_type = "password";
+ confirm_password_field.unique_renderer_id = FieldRendererId(3);
+ confirm_password_field.name = ASCIIToUTF16("confpass");
+ form_data.fields.push_back(confirm_password_field);
+
+ manager()->OnPasswordFormsParsed(&driver_, {form_data});
+
+ form_data.fields[0].value = ASCIIToUTF16("oldpass");
+ form_data.fields[1].value = ASCIIToUTF16("newpass");
+ form_data.fields[2].value = ASCIIToUTF16("newpass");
+
+ manager()->OnInformAboutUserInput(&driver_, form_data);
+
+ form_data.fields[0].value = base::string16();
+ form_data.fields[2].value = base::string16();
+ if (new_password_field_was_cleared)
+ form_data.fields[1].value = base::string16();
+
+ std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
+ if (new_password_field_was_cleared) {
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr)
+ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+ } else {
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr).Times(0);
+ }
+
+ manager()->OnPasswordFormCleared(&driver_, form_data);
+ }
+}
+#endif // !defined(OS_IOS)
+
+TEST_P(PasswordManagerTest, IsFormManagerPendingPasswordUpdate) {
+ PasswordForm form(MakeSimpleForm());
+ std::vector<FormData> observed = {form.form_data};
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+ EXPECT_CALL(*store_, GetLogins)
+ .WillOnce(WithArg<1>(InvokeConsumer(store_.get(), form)));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ // Password was not updated yet.
+ EXPECT_FALSE(manager()->IsFormManagerPendingPasswordUpdate());
+
+ // The user updates the password.
+ FormData updated_data(form.form_data);
+ updated_data.fields[1].value = ASCIIToUTF16("new_password");
+ manager()->OnInformAboutUserInput(&driver_, updated_data);
+ EXPECT_TRUE(manager()->IsFormManagerPendingPasswordUpdate());
+
+ // The user submits the form.
+ OnPasswordFormSubmitted(updated_data);
+ EXPECT_TRUE(manager()->GetSubmittedManagerForTest());
+ // OnFormManagerPendingPasswordUpdate() still returns true after submission.
+ EXPECT_TRUE(manager()->IsFormManagerPendingPasswordUpdate());
+}
+
INSTANTIATE_TEST_SUITE_P(, PasswordManagerTest, testing::Bool());
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.cc b/chromium/components/password_manager/core/browser/password_manager_util.cc
index d89b88545a5..bb0b9396170 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -40,6 +40,7 @@
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
+using autofill::password_generation::PasswordGenerationType;
using password_manager::PasswordForm;
namespace password_manager_util {
@@ -145,7 +146,7 @@ void UserTriggeredManualGenerationFromContextMenu(
password_manager::PasswordManagerClient* password_manager_client) {
if (!password_manager_client->GetPasswordFeatureManager()
->ShouldShowAccountStorageOptIn()) {
- password_manager_client->GeneratePassword();
+ password_manager_client->GeneratePassword(PasswordGenerationType::kManual);
LogPasswordGenerationEvent(autofill::password_generation::
PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
return;
@@ -159,7 +160,7 @@ void UserTriggeredManualGenerationFromContextMenu(
password_manager::PasswordManagerClient::ReauthSucceeded
succeeded) {
if (succeeded) {
- client->GeneratePassword();
+ client->GeneratePassword(PasswordGenerationType::kManual);
LogPasswordGenerationEvent(
autofill::password_generation::
PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
@@ -171,13 +172,13 @@ void UserTriggeredManualGenerationFromContextMenu(
// TODO(http://crbug.com/890318): Add unitests to check cleaners are correctly
// created.
void RemoveUselessCredentials(
+ password_manager::CredentialsCleanerRunner* cleaning_tasks_runner,
scoped_refptr<password_manager::PasswordStore> store,
PrefService* prefs,
- int delay_in_seconds,
+ base::TimeDelta delay,
base::RepeatingCallback<network::mojom::NetworkContext*()>
network_context_getter) {
- auto cleaning_tasks_runner =
- std::make_unique<password_manager::CredentialsCleanerRunner>();
+ DCHECK(cleaning_tasks_runner);
#if !defined(OS_IOS)
// Can be null for some unittests.
@@ -195,23 +196,19 @@ void RemoveUselessCredentials(
FROM_HERE,
base::BindOnce(
&password_manager::CredentialsCleanerRunner::StartCleaning,
- base::Unretained(cleaning_tasks_runner.release())),
- base::TimeDelta::FromSeconds(delay_in_seconds));
+ cleaning_tasks_runner->GetWeakPtr()),
+ delay);
}
}
base::StringPiece GetSignonRealmWithProtocolExcluded(const PasswordForm& form) {
- base::StringPiece signon_realm_protocol_excluded = form.signon_realm;
+ base::StringPiece signon_realm = form.signon_realm;
// Find the web origin (with protocol excluded) in the signon_realm.
- const size_t after_protocol =
- signon_realm_protocol_excluded.find(form.url.host_piece());
- DCHECK_NE(after_protocol, base::StringPiece::npos);
+ const size_t after_protocol = signon_realm.find(form.url.host_piece());
// Keep the string starting with position |after_protocol|.
- signon_realm_protocol_excluded =
- signon_realm_protocol_excluded.substr(after_protocol);
- return signon_realm_protocol_excluded;
+ return signon_realm.substr(std::min(after_protocol, signon_realm.size()));
}
void FindBestMatches(
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.h b/chromium/components/password_manager/core/browser/password_manager_util.h
index 203ea788b4b..7ad0c76db4a 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_util.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/strings/string16.h"
+#include "base/time/time.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -22,6 +23,7 @@ class NetworkContext;
} // namespace network
namespace password_manager {
+class CredentialsCleanerRunner;
class PasswordManagerDriver;
class PasswordManagerClient;
} // namespace password_manager
@@ -87,9 +89,10 @@ void UserTriggeredManualGenerationFromContextMenu(
// HSTS query is not supported. |network_context_getter| is always null for iOS
// and it can also be null for some unittests.
void RemoveUselessCredentials(
+ password_manager::CredentialsCleanerRunner* cleaning_tasks_runner,
scoped_refptr<password_manager::PasswordStore> store,
PrefService* prefs,
- int delay_in_seconds,
+ base::TimeDelta delay,
base::RepeatingCallback<network::mojom::NetworkContext*()>
network_context_getter);
diff --git a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
index 9d59552e6a8..192e962fb18 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -9,11 +9,12 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -24,6 +25,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using autofill::password_generation::PasswordGenerationType;
using password_manager::PasswordForm;
namespace password_manager_util {
@@ -50,7 +52,7 @@ class MockPasswordManagerClient
base::OnceCallback<void(
password_manager::PasswordManagerClient::ReauthSucceeded)>),
(override));
- MOCK_METHOD(void, GeneratePassword, (), (override));
+ MOCK_METHOD(void, GeneratePassword, (PasswordGenerationType), (override));
};
PasswordForm GetTestAndroidCredential() {
@@ -438,7 +440,7 @@ TEST(PasswordManagerUtil, ManualGenerationShouldNotReauthIfNotNeeded) {
.WillByDefault(Return(false));
EXPECT_CALL(mock_client, TriggerReauthForPrimaryAccount).Times(0);
- EXPECT_CALL(mock_client, GeneratePassword);
+ EXPECT_CALL(mock_client, GeneratePassword(PasswordGenerationType::kManual));
UserTriggeredManualGenerationFromContextMenu(&mock_client);
}
@@ -462,7 +464,7 @@ TEST(PasswordManagerUtil,
std::move(callback).Run(
password_manager::PasswordManagerClient::ReauthSucceeded(true));
});
- EXPECT_CALL(mock_client, GeneratePassword);
+ EXPECT_CALL(mock_client, GeneratePassword(PasswordGenerationType::kManual));
UserTriggeredManualGenerationFromContextMenu(&mock_client);
}
diff --git a/chromium/components/password_manager/core/browser/password_requirements_service_unittest.cc b/chromium/components/password_manager/core/browser/password_requirements_service_unittest.cc
index ab390921753..b51ce0a5133 100644
--- a/chromium/components/password_manager/core/browser/password_requirements_service_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_requirements_service_unittest.cc
@@ -6,7 +6,7 @@
#include <map>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/autofill/core/browser/proto/password_requirements.pb.h"
#include "components/autofill/core/common/signatures.h"
#include "components/password_manager/core/browser/generation/password_requirements_spec_fetcher.h"
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
index 5d90a43ed9b..4ee28fc54ab 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -168,7 +168,6 @@ void PasswordReuseDetectionManager::OnReuseCheckDone(
client_->LogPasswordReuseDetectedEvent();
#endif
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
std::string username = reused_protected_password_hash.has_value()
? reused_protected_password_hash->username
: "";
@@ -177,7 +176,7 @@ void PasswordReuseDetectionManager::OnReuseCheckDone(
reused_password_type, username,
std::move(all_matching_reused_credentials_).extract(),
password_field_detected);
-#endif
+
all_matching_reused_credentials_.clear();
}
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
index fa44a122bdd..b7caf40efcc 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -10,7 +10,6 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
diff --git a/chromium/components/password_manager/core/browser/password_save_manager.h b/chromium/components/password_manager/core/browser/password_save_manager.h
index 9c0714be67b..3eeea71d265 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager.h
+++ b/chromium/components/password_manager/core/browser/password_save_manager.h
@@ -6,7 +6,6 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_SAVE_MANAGER_H_
#include "base/macros.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store.h"
namespace autofill {
@@ -26,6 +25,7 @@ class VotesUploader;
class FormSaver;
class PasswordFormMetricsRecorder;
class PasswordManagerDriver;
+struct PasswordForm;
// Implementations of this interface should encapsulate the password Save/Update
// logic. One implementation of this class will provide the Save/Update logic in
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
index 41be09393aa..4d09e6e84bf 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
@@ -24,7 +24,6 @@ using autofill::FieldRendererId;
using autofill::FormData;
using autofill::FormFieldData;
using autofill::FormStructure;
-using autofill::ValueElementPair;
namespace password_manager {
@@ -496,6 +495,11 @@ base::string16 PasswordSaveManagerImpl::GetOldPassword(
void PasswordSaveManagerImpl::UploadVotesAndMetrics(
const FormData* observed_form,
const PasswordForm& parsed_submitted_form) {
+ metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
+ parsed_submitted_form.submission_event);
+ metrics_recorder_->SetSubmissionIndicatorEvent(
+ parsed_submitted_form.submission_event);
+
if (IsNewLogin()) {
metrics_util::LogNewlySavedPasswordIsGenerated(
pending_credentials_.type == PasswordForm::Type::kGenerated,
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
index 95aac01eeb4..81a3cd6973a 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -28,6 +28,7 @@ using autofill::FormData;
using autofill::FormFieldData;
using autofill::FormStructure;
using autofill::PasswordFormFillData;
+using autofill::mojom::SubmissionIndicatorEvent;
using base::ASCIIToUTF16;
using base::TestMockTimeTaskRunner;
using testing::_;
@@ -576,6 +577,7 @@ TEST_P(PasswordSaveManagerImplTest, ResetPendingCredentials) {
// successfully submitted, then they are saved correctly.
TEST_P(PasswordSaveManagerImplTest, SaveNewCredentials) {
TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner());
+ base::HistogramTester histogram_tester;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
SetNonFederatedAndNotifyFetchCompleted({&saved_match_});
@@ -585,8 +587,13 @@ TEST_P(PasswordSaveManagerImplTest, SaveNewCredentials) {
submitted_form.fields[kUsernameFieldIndex].value = new_username;
submitted_form.fields[kPasswordFieldIndex].value = new_password;
+ PasswordForm parsed_submitted_form = Parse(submitted_form);
+ // Set SubmissionIndicatorEvent to test metrics recording.
+ parsed_submitted_form.submission_event =
+ SubmissionIndicatorEvent::HTML_FORM_SUBMISSION;
+
password_save_manager_impl()->CreatePendingCredentials(
- Parse(submitted_form), &observed_form_, submitted_form,
+ parsed_submitted_form, &observed_form_, submitted_form,
/*is_http_auth=*/false,
/*is_credential_api_save=*/false);
@@ -597,7 +604,7 @@ TEST_P(PasswordSaveManagerImplTest, SaveNewCredentials) {
EXPECT_CALL(*mock_form_saver(), Save(_, _, _))
.WillOnce(DoAll(SaveArg<0>(&saved_form), SaveArg<1>(&best_matches)));
- password_save_manager_impl()->Save(&observed_form_, Parse(submitted_form));
+ password_save_manager_impl()->Save(&observed_form_, parsed_submitted_form);
std::string expected_signon_realm = submitted_form.url.GetOrigin().spec();
EXPECT_EQ(submitted_form.url, saved_form.url);
@@ -611,6 +618,11 @@ TEST_P(PasswordSaveManagerImplTest, SaveNewCredentials) {
saved_form.password_element);
EXPECT_EQ(std::vector<const PasswordForm*>{&saved_match_}, best_matches);
+ // Check histograms.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AcceptedSaveUpdateSubmissionIndicatorEvent",
+ SubmissionIndicatorEvent::HTML_FORM_SUBMISSION, 1);
+
// Check UKM metrics.
DestroySaveManagerAndMetricsRecorder();
ExpectedGenerationUKM expected_metrics = {
@@ -1082,6 +1094,8 @@ TEST_P(PasswordSaveManagerImplTest, UserEventsForGeneration_Clear) {
}
TEST_P(PasswordSaveManagerImplTest, Update) {
+ base::HistogramTester histogram_tester;
+
PasswordForm not_best_saved_match = saved_match_;
PasswordForm saved_match_another_username = saved_match_;
saved_match_another_username.username_value += ASCIIToUTF16("1");
@@ -1094,8 +1108,13 @@ TEST_P(PasswordSaveManagerImplTest, Update) {
submitted_form.fields[kUsernameFieldIndex].value = username;
submitted_form.fields[kPasswordFieldIndex].value = new_password;
+ PasswordForm parsed_submitted_form = Parse(submitted_form);
+ // Set SubmissionIndicatorEvent to test metrics recording.
+ parsed_submitted_form.submission_event =
+ SubmissionIndicatorEvent::HTML_FORM_SUBMISSION;
+
password_save_manager_impl()->CreatePendingCredentials(
- Parse(submitted_form), &observed_form_, submitted_form,
+ parsed_submitted_form, &observed_form_, submitted_form,
/*is_http_auth=*/false,
/*is_credential_api_save=*/false);
@@ -1111,11 +1130,16 @@ TEST_P(PasswordSaveManagerImplTest, Update) {
const base::Time kNow = base::Time::Now();
password_save_manager_impl()->Update(saved_match_, &observed_form_,
- Parse(submitted_form));
+ parsed_submitted_form);
EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form));
EXPECT_EQ(new_password, updated_form.password_value);
EXPECT_GE(updated_form.date_last_used, kNow);
+
+ // Check histograms.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AcceptedSaveUpdateSubmissionIndicatorEvent",
+ SubmissionIndicatorEvent::HTML_FORM_SUBMISSION, 1);
}
TEST_P(PasswordSaveManagerImplTest, HTTPAuthPasswordOverridden) {
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
index 4eac7c5e906..08b50bca1ad 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
@@ -59,10 +59,7 @@ base::flat_set<ParsingResult> ParseDomainSpecificParamaters(
const std::string* min_version = script_config.FindStringKey("min_version");
base::Version version;
if (!min_version) {
- warnings.insert(ParsingResult::kInvalidJson);
- // TODO(crbug.com/1132942): remove this when server side change is in place
- // and return error.
- version = base::Version("0");
+ return {ParsingResult::kInvalidJson};
} else {
version = base::Version(*min_version);
if (!version.IsValid()) {
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
index 1b00d601bf5..9579c2cb19f 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
@@ -180,7 +180,13 @@ TEST_F(PasswordScriptsFetcherImplTest, PrewarmCache) {
EXPECT_EQ(1, GetNumberOfPendingRequests());
// OriginWithScript2 (test.com) is not available anymore.
SimulateResponseWithContent(
- R"({"example.com": {"domains": ["https://example.com"]}})");
+ R"({
+ "example.com":
+ {
+ "domains": ["https://example.com"],
+ "min_version": "86"
+ }
+ })");
base::RunLoop().RunUntilIdle();
EXPECT_THAT(recorded_responses(),
diff --git a/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
index da3a2f450f8..1ff16ddb7b7 100644
--- a/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
@@ -40,7 +40,7 @@ PasswordSessionDurationsMetricsRecorder::
DCHECK(pref_service_);
// |sync_service| can be null if sync is disabled by a command line flag.
if (sync_service_)
- sync_observer_.Add(sync_service_);
+ sync_observation_.Observe(sync_service_);
}
PasswordSessionDurationsMetricsRecorder::
@@ -59,6 +59,13 @@ void PasswordSessionDurationsMetricsRecorder::OnSessionEnded(
// If there was no active session, just ignore this call.
if (!total_session_timer_)
return;
+
+ if (session_length.is_zero()) {
+ // During Profile teardown, this method is called with a |session_length|
+ // of zero.
+ session_length = total_session_timer_->Elapsed();
+ }
+
DCHECK(user_state_session_timer_);
// Record metrics for the just-ended session.
diff --git a/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
index 701139e7aab..d7b2ff2ef0e 100644
--- a/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/timer/elapsed_timer.h"
#include "components/password_manager/core/browser/password_account_storage_settings_watcher.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -52,8 +52,8 @@ class PasswordSessionDurationsMetricsRecorder
PasswordAccountStorageSettingsWatcher settings_watcher_;
- ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
- sync_observer_{this};
+ base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
+ sync_observation_{this};
// Tracks the elapsed active session time while the browser is open. The timer
// is null if there's no active session.
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 6304427c114..5945ef1a891 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/debug/dump_without_crashing.h"
#include "base/location.h"
#include "base/macros.h"
@@ -40,12 +40,9 @@
#include "components/prefs/pref_service.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
-
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
#include "base/strings/string16.h"
#include "components/password_manager/core/browser/password_store_signin_notifier.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
-#endif
namespace password_manager {
@@ -92,7 +89,6 @@ void PasswordStore::DatabaseCompromisedCredentialsObserver::
OnCompromisedCredentialsChanged();
}
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
PasswordStore::CheckReuseRequest::CheckReuseRequest(
PasswordReuseDetectorConsumer* consumer)
: origin_task_runner_(base::SequencedTaskRunnerHandle::Get()),
@@ -116,7 +112,6 @@ void PasswordStore::CheckReuseRequest::OnReuseCheckDone(
matching_reused_credentials, saved_passwords));
TRACE_EVENT_NESTABLE_ASYNC_END0("passwords", "CheckReuseRequest", this);
}
-#endif
PasswordStore::FormDigest::FormDigest(PasswordForm::Scheme new_scheme,
const std::string& new_signon_realm,
@@ -552,7 +547,6 @@ void PasswordStore::SetSyncTaskTimeoutForTest(base::TimeDelta timeout) {
sync_task_timeout_ = timeout;
}
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void PasswordStore::CheckReuse(const base::string16& input,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer) {
@@ -560,9 +554,7 @@ void PasswordStore::CheckReuse(const base::string16& input,
std::make_unique<CheckReuseRequest>(consumer),
input, domain));
}
-#endif
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void PasswordStore::PreparePasswordHashData(const std::string& sync_username,
const bool is_signed_in) {
SchedulePasswordHashUpdate(/*should_log_metrics=*/true,
@@ -677,10 +669,11 @@ void PasswordStore::ScheduleEnterprisePasswordURLUpdate() {
std::move(enterprise_change_password_url)));
}
-#endif
-
PasswordStore::~PasswordStore() {
DCHECK(shutdown_called_);
+ // PasswordSyncBridge should delete on the same sequence where it was created.
+ if (sync_bridge_)
+ background_task_runner_->DeleteSoon(FROM_HERE, std::move(sync_bridge_));
}
scoped_refptr<base::SequencedTaskRunner>
@@ -816,7 +809,6 @@ void PasswordStore::NotifyUnsyncedCredentialsWillBeDeleted(
}
}
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void PasswordStore::CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
const base::string16& input,
const std::string& domain) {
@@ -890,8 +882,6 @@ void PasswordStore::ClearAllNonGmailPasswordHashImpl() {
reuse_detector_->ClearAllNonGmailPasswordHash();
}
-#endif
-
void PasswordStore::OnInitCompleted(bool success) {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
init_status_ = success ? InitStatus::kSuccess : InitStatus::kFailure;
@@ -1389,11 +1379,4 @@ void PasswordStore::DestroyOnBackgroundSequence() {
#endif
}
-std::ostream& operator<<(std::ostream& os,
- const PasswordStore::FormDigest& digest) {
- return os << "FormDigest(scheme: " << digest.scheme
- << ", signon_realm: " << digest.signon_realm
- << ", url: " << digest.url << ")";
-}
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index efc26bab2a6..813f10e370e 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -10,8 +10,8 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/callback_list.h"
#include "base/cancelable_callback.h"
#include "base/gtest_prod_util.h"
@@ -24,16 +24,12 @@
#include "build/build_config.h"
#include "components/keyed_service/core/refcounted_keyed_service.h"
#include "components/password_manager/core/browser/compromised_credentials_table.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/password_manager/core/browser/password_store_sync.h"
-
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
-#endif
class PrefService;
@@ -51,11 +47,11 @@ using StateSubscription =
namespace password_manager {
+struct PasswordForm;
+
using IsAccountStore = util::StrongAlias<class IsAccountStoreTag, bool>;
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
using metrics_util::GaiaPasswordHashChange;
-#endif
class AffiliatedMatchHelper;
class PasswordStoreConsumer;
@@ -66,9 +62,7 @@ struct FieldInfo;
struct InteractionsStats;
struct CompromisedCredentials;
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
using PasswordHashDataList = base::Optional<std::vector<PasswordHashData>>;
-#endif
// Interface for storing form passwords in a platform-specific secure way.
// The login request/manipulation API is not threadsafe and must be used
@@ -379,7 +373,6 @@ class PasswordStore : protected PasswordStoreSync,
void SetSyncTaskTimeoutForTest(base::TimeDelta timeout);
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Immediately called after |Init()| to retrieve password hash data for
// reuse detection.
void PreparePasswordHashData(const std::string& sync_username,
@@ -448,12 +441,9 @@ class PasswordStore : protected PasswordStoreSync,
// These URLs are used in enterprise password reuse detection.
void ScheduleEnterprisePasswordURLUpdate();
-#endif
-
protected:
friend class base::RefCountedThreadSafe<PasswordStore>;
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Represents a single CheckReuse() request. Implements functionality to
// listen to reuse events and propagate them to |consumer| on the sequence on
// which CheckReuseRequest is created.
@@ -478,7 +468,6 @@ class PasswordStore : protected PasswordStoreSync,
DISALLOW_COPY_AND_ASSIGN(CheckReuseRequest);
};
-#endif
// Status of PasswordStore::Init().
enum class InitStatus {
@@ -628,7 +617,6 @@ class PasswordStore : protected PasswordStoreSync,
void InvokeAndNotifyAboutCompromisedPasswordsChange(
base::OnceCallback<bool()> callback);
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
// Saves |username| and a hash of |password| for password reuse checking.
// |is_gaia_password| indicates if it is a Gaia account. |event| is used for
// metric logging. |is_primary_account| is whether account belong to the
@@ -671,7 +659,6 @@ class PasswordStore : protected PasswordStoreSync,
// Synchronous implementation of ClearAllNonGmailPasswordHash().
void ClearAllNonGmailPasswordHashImpl();
-#endif
scoped_refptr<base::SequencedTaskRunner> main_task_runner() const {
return main_task_runner_;
@@ -894,14 +881,13 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
PrefService* prefs_ = nullptr;
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
+
// PasswordReuseDetector can be only destroyed on the background sequence. It
// can't be owned by PasswordStore because PasswordStore can be destroyed on
// the UI thread and DestroyOnBackgroundThread isn't guaranteed to be called.
PasswordReuseDetector* reuse_detector_ = nullptr;
std::unique_ptr<PasswordStoreSigninNotifier> notifier_;
HashPasswordManager hash_password_manager_;
-#endif
std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier_;
@@ -922,9 +908,15 @@ class PasswordStore : protected PasswordStoreSync,
DISALLOW_COPY_AND_ASSIGN(PasswordStore);
};
-// For logging only.
-std::ostream& operator<<(std::ostream& os,
- const PasswordStore::FormDigest& digest);
+// For testing only.
+#if defined(UNIT_TEST)
+inline std::ostream& operator<<(std::ostream& os,
+ const PasswordStore::FormDigest& digest) {
+ return os << "FormDigest(scheme: " << digest.scheme
+ << ", signon_realm: " << digest.signon_realm
+ << ", url: " << digest.url << ")";
+}
+#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_change.cc b/chromium/components/password_manager/core/browser/password_store_change.cc
deleted file mode 100644
index dbdecf015a2..00000000000
--- a/chromium/components/password_manager/core/browser/password_store_change.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/password_manager/core/browser/password_store_change.h"
-
-namespace password_manager {
-
-std::ostream& operator<<(std::ostream& os,
- const PasswordStoreChange& password_store_change) {
- return os << "type: " << password_store_change.type()
- << ", primary key: " << password_store_change.primary_key()
- << ", password change: " << password_store_change.password_changed()
- << ", password form: " << password_store_change.form();
-}
-
-} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_change.h b/chromium/components/password_manager/core/browser/password_store_change.h
index a6fe47e9cee..dd2db7ed41c 100644
--- a/chromium/components/password_manager/core/browser/password_store_change.h
+++ b/chromium/components/password_manager/core/browser/password_store_change.h
@@ -72,8 +72,16 @@ class PasswordStoreChange {
typedef std::vector<PasswordStoreChange> PasswordStoreChangeList;
// For testing.
-std::ostream& operator<<(std::ostream& os,
- const PasswordStoreChange& password_store_change);
+#if defined(UNIT_TEST)
+inline std::ostream& operator<<(
+ std::ostream& os,
+ const PasswordStoreChange& password_store_change) {
+ return os << "type: " << password_store_change.type()
+ << ", primary key: " << password_store_change.primary_key()
+ << ", password change: " << password_store_change.password_changed()
+ << ", password form: " << password_store_change.form();
+}
+#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_consumer.h b/chromium/components/password_manager/core/browser/password_store_consumer.h
index 89bb486a263..7cf533cddfc 100644
--- a/chromium/components/password_manager/core/browser/password_store_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_store_consumer.h
@@ -11,12 +11,12 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
namespace password_manager {
struct FieldInfo;
struct InteractionsStats;
+struct PasswordForm;
class PasswordStore;
// Reads from the PasswordStore are done asynchronously on a separate
diff --git a/chromium/components/password_manager/core/browser/password_store_factory_util.cc b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
index 38dd5c90bea..df8e86aa11d 100644
--- a/chromium/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/chromium/components/password_manager/core/browser/password_store_factory_util.cc
@@ -13,6 +13,7 @@
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/android_affiliation/android_affiliation_service.h"
#include "components/password_manager/core/browser/password_manager_constants.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
@@ -111,6 +112,10 @@ base::FilePath GetLoginDatabaseForAccountStoragePathForTesting(
}
bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service) {
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kUseOfHashAffiliationFetcher)) {
+ return true;
+ }
return sync_service && sync_service->IsSyncFeatureActive() &&
sync_service->GetUserSettings()->GetSelectedTypes().Has(
syncer::UserSelectableType::kPasswords) &&
diff --git a/chromium/components/password_manager/core/browser/password_store_sync.h b/chromium/components/password_manager/core/browser/password_store_sync.h
index 32b9d441596..c2e94207b1d 100644
--- a/chromium/components/password_manager/core/browser/password_store_sync.h
+++ b/chromium/components/password_manager/core/browser/password_store_sync.h
@@ -11,7 +11,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/sync/model/sync_metadata_store.h"
@@ -21,6 +20,8 @@ class MetadataBatch;
namespace password_manager {
+struct PasswordForm;
+
using PrimaryKeyToFormMap = std::map<int, std::unique_ptr<PasswordForm>>;
// This enum is used to determine result status when deleting undecryptable
diff --git a/chromium/components/password_manager/core/browser/password_store_unittest.cc b/chromium/components/password_manager/core/browser/password_store_unittest.cc
index 126ecd2e08e..907cfb2f601 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
diff --git a/chromium/components/password_manager/core/browser/password_sync_util.h b/chromium/components/password_manager/core/browser/password_sync_util.h
index fe71fab8aaf..094c162699d 100644
--- a/chromium/components/password_manager/core/browser/password_sync_util.h
+++ b/chromium/components/password_manager/core/browser/password_sync_util.h
@@ -7,7 +7,6 @@
#include <string>
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/sync_service.h"
@@ -16,6 +15,9 @@ class IdentityManager;
}
namespace password_manager {
+
+struct PasswordForm;
+
namespace sync_util {
// Returns the sync username received from |identity_manager| (if not null).
@@ -47,6 +49,7 @@ bool ShouldSaveEnterprisePasswordHash(const PasswordForm& form,
const PrefService& prefs);
} // namespace sync_util
+
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_SYNC_UTIL_H_
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils.h b/chromium/components/password_manager/core/browser/password_ui_utils.h
index cc89024fb4b..76bbd07c533 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils.h
+++ b/chromium/components/password_manager/core/browser/password_ui_utils.h
@@ -12,12 +12,12 @@
#include "base/strings/string_piece.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "url/origin.h"
namespace password_manager {
class PasswordFormManagerForUI;
+struct PasswordForm;
// Reverses order of labels in hostname.
std::string SplitByDotAndReverse(base::StringPiece host);
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.cc b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.cc
index 38e4707c0a4..fcaff30c463 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.cc
@@ -5,6 +5,8 @@
#include "components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h"
+#include "components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace password_manager {
@@ -16,6 +18,11 @@ std::unique_ptr<AffiliationFetcherInterface>
AffiliationFetcherFactoryImpl::CreateInstance(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate) {
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kUseOfHashAffiliationFetcher)) {
+ return std::make_unique<HashAffiliationFetcher>(
+ std::move(url_loader_factory), delegate);
+ }
return std::make_unique<AffiliationFetcher>(std::move(url_loader_factory),
delegate);
}
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc
new file mode 100644
index 00000000000..57fba51070c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2020 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/password_manager/core/browser/site_affiliation/affiliation_fetcher_factory_impl.h"
+
+#include "base/test/bind.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_interface.h"
+#include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher_delegate.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+class AffiliationFetcherFactoryImplTest : public testing::Test {
+ public:
+ AffiliationFetcherFactoryImplTest() {
+ test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+ [&](const network::ResourceRequest& request) { url_ = request.url; }));
+ }
+
+ void CreateAndStartFetcher() {
+ MockAffiliationFetcherDelegate mock_delegate;
+ std::unique_ptr<AffiliationFetcherInterface> fetcher =
+ fetcher_factory_.CreateInstance(test_shared_loader_factory_,
+ &mock_delegate);
+
+ fetcher->StartRequest({}, {});
+ }
+
+ const GURL& url() const { return url_; }
+
+ void EnableHashAffiliationService() {
+ feature_list_.InitAndEnableFeature(
+ password_manager::features::kUseOfHashAffiliationFetcher);
+ }
+
+ void DisableHashAffiliationService() {
+ feature_list_.InitAndDisableFeature(
+ password_manager::features::kUseOfHashAffiliationFetcher);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ base::test::TaskEnvironment task_env_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_);
+ AffiliationFetcherFactoryImpl fetcher_factory_;
+ GURL url_;
+};
+
+TEST_F(AffiliationFetcherFactoryImplTest, NormalAffiliationFetcher) {
+ DisableHashAffiliationService();
+ CreateAndStartFetcher();
+ EXPECT_TRUE(base::EndsWith(url().path_piece(), "lookup"));
+}
+
+TEST_F(AffiliationFetcherFactoryImplTest, HashAffiliationFetcher) {
+ EnableHashAffiliationService();
+ CreateAndStartFetcher();
+ EXPECT_TRUE(base::EndsWith(url().path_piece(), "lookupByHashPrefix"));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
index c1a4e8ef554..2e8a7b1c2dc 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl_unittest.cc
@@ -5,7 +5,7 @@
#include <memory>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.cc b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.cc
new file mode 100644
index 00000000000..03a47d47a4e
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.cc
@@ -0,0 +1,115 @@
+// Copyright 2020 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/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h"
+
+#include <memory>
+
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "crypto/sha2.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/url_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "url/gurl.h"
+
+namespace {
+const int kPrefixLength = 16;
+
+uint64_t ComputeHashPrefix(const password_manager::FacetURI& uri) {
+ static_assert(kPrefixLength < 64,
+ "Prefix should not be longer than 8 bytes.");
+
+ int bytes_count = kPrefixLength / 8 + (kPrefixLength % 8 != 0);
+
+ uint8_t hash[bytes_count];
+ crypto::SHA256HashString(uri.canonical_spec(), hash, bytes_count);
+ uint64_t result = 0;
+
+ for (int i = 0; i < bytes_count; i++) {
+ result <<= 8;
+ result |= hash[i];
+ }
+
+ int bits_to_clear = kPrefixLength % 8;
+ result &= (~0 << bits_to_clear);
+
+ int bits_to_shift = ((8 - bytes_count) * 8);
+ result <<= bits_to_shift;
+
+ return result;
+}
+
+} // namespace
+
+namespace password_manager {
+
+HashAffiliationFetcher::HashAffiliationFetcher(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ AffiliationFetcherDelegate* delegate)
+ : AffiliationFetcherBase(std::move(url_loader_factory), delegate) {}
+
+HashAffiliationFetcher::~HashAffiliationFetcher() = default;
+
+void HashAffiliationFetcher::StartRequest(
+ const std::vector<FacetURI>& facet_uris,
+ RequestInfo request_info) {
+ requested_facet_uris_ = facet_uris;
+
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("affiliation_lookup_by_hash", R"(
+ semantics {
+ sender: "Hash Affiliation Fetcher"
+ description:
+ " Chrome can obtain information about affiliated and grouped "
+ " websites as well as link to directly change password using this "
+ " request. Chrome sends only hash prefixes of the websites. "
+ trigger: "After triggering change password action"
+ data:
+ "Hash prefixes of websites URLs on which user's credentials were "
+ "compromised."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This feature is used as a substitute for affiliation fetcher "
+ "that sends full facet URLs in a plain form. If the standard "
+ "affiliation fetcher cannot be used for privacy reasons then this "
+ "request is made as an alternative solution."
+ policy_exception_justification:
+ "Not implemented. This request has no limitation as it is intended "
+ "to be used when sync is turned off or passphrase is used. "
+ })");
+
+ // Prepare the payload based on |facet_uris| and |request_info|.
+ affiliation_pb::LookupAffiliationByHashPrefixRequest lookup_request;
+
+ lookup_request.set_hash_prefix_length(kPrefixLength);
+
+ for (const FacetURI& uri : facet_uris)
+ lookup_request.add_hash_prefixes(ComputeHashPrefix(uri));
+
+ *lookup_request.mutable_mask() = CreateLookupMask(request_info);
+
+ std::string serialized_request;
+ bool success = lookup_request.SerializeToString(&serialized_request);
+ DCHECK(success);
+
+ FinalizeRequest(serialized_request, BuildQueryURL(), traffic_annotation);
+}
+
+const std::vector<FacetURI>& HashAffiliationFetcher::GetRequestedFacetURIs()
+ const {
+ return requested_facet_uris_;
+}
+
+// static
+GURL HashAffiliationFetcher::BuildQueryURL() {
+ return net::AppendQueryParameter(
+ GURL("https://www.googleapis.com/affiliation/v1/"
+ "affiliation:lookupByHashPrefix"),
+ "key", google_apis::GetAPIKey());
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h
new file mode 100644
index 00000000000..1539395f19a
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h
@@ -0,0 +1,38 @@
+// Copyright 2020 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_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_HASH_AFFILIATION_FETCHER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_HASH_AFFILIATION_FETCHER_H_
+
+#include "components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.h"
+
+namespace password_manager {
+
+// Fetches authoritative information about facets' affiliations with additional
+// privacy layer. It uses SHA-256 to hash facet URLs and sends only a specified
+// amount of hash prefixes to eventually retrieve a larger group of affiliations
+// including those actually required.
+class HashAffiliationFetcher : public AffiliationFetcherBase {
+ public:
+ HashAffiliationFetcher(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ AffiliationFetcherDelegate* delegate);
+ ~HashAffiliationFetcher() override;
+
+ void StartRequest(const std::vector<FacetURI>& facet_uris,
+ RequestInfo request_info) override;
+
+ // AffiliationFetcherInterface
+ const std::vector<FacetURI>& GetRequestedFacetURIs() const override;
+
+ // Builds the URL for the Affiliation API's lookup method.
+ static GURL BuildQueryURL();
+
+ private:
+ std::vector<FacetURI> requested_facet_uris_;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_HASH_AFFILIATION_FETCHER_H_
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc
new file mode 100644
index 00000000000..3d1ffe8c853
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2020 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/password_manager/core/browser/site_affiliation/hash_affiliation_fetcher.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string_number_conversions_win.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_api.pb.h"
+#include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher_delegate.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+constexpr char k1ExampleURL[] = "https://1.example.com";
+constexpr uint64_t k1ExampleHash16LenPrefix = 10506334980701945856ULL;
+constexpr char k2ExampleURL[] = "https://2.example.com";
+constexpr uint64_t k2ExampleHash16LenPrefix = 9324421553493901312ULL;
+
+class HashAffiliationFetcherTest : public testing::Test {
+ public:
+ HashAffiliationFetcherTest() {
+ test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+ [&](const network::ResourceRequest& request) {
+ intercepted_body_ = network::GetUploadData(request);
+ intercepted_headers_ = request.headers;
+ }));
+ }
+ ~HashAffiliationFetcherTest() override = default;
+
+ protected:
+ void VerifyRequestPayload(const std::vector<uint64_t>& expected_hash_prefixes,
+ HashAffiliationFetcher::RequestInfo request_info);
+ void WaitForResponse() { task_environment_.RunUntilIdle(); }
+
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory() {
+ return test_shared_loader_factory_;
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_);
+ std::string intercepted_body_;
+ net::HttpRequestHeaders intercepted_headers_;
+};
+
+void HashAffiliationFetcherTest::VerifyRequestPayload(
+ const std::vector<uint64_t>& expected_hash_prefixes,
+ HashAffiliationFetcher::RequestInfo request_info) {
+ affiliation_pb::LookupAffiliationByHashPrefixRequest request;
+ ASSERT_TRUE(request.ParseFromString(intercepted_body_));
+
+ std::vector<uint64_t> actual_hash_prefixes;
+ for (const auto prefix : request.hash_prefixes())
+ actual_hash_prefixes.push_back(prefix);
+
+ std::string content_type;
+ intercepted_headers_.GetHeader(net::HttpRequestHeaders::kContentType,
+ &content_type);
+ EXPECT_EQ("application/x-protobuf", content_type);
+ EXPECT_THAT(actual_hash_prefixes,
+ testing::UnorderedElementsAreArray(expected_hash_prefixes));
+
+ // Change password info requires grouping info enabled.
+ EXPECT_EQ(request.mask().grouping_info(), request_info.change_password_info);
+ EXPECT_EQ(request.mask().change_password_info(),
+ request_info.change_password_info);
+}
+
+TEST_F(HashAffiliationFetcherTest, BuildQueryURL) {
+ MockAffiliationFetcherDelegate mock_delegate;
+ HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
+
+ GURL query_url = fetcher.BuildQueryURL();
+
+ EXPECT_EQ("https", query_url.scheme());
+ EXPECT_EQ("www.googleapis.com", query_url.host());
+ EXPECT_EQ("/affiliation/v1/affiliation:lookupByHashPrefix", query_url.path());
+}
+
+TEST_F(HashAffiliationFetcherTest, GetRequestedFacetURIs) {
+ MockAffiliationFetcherDelegate mock_delegate;
+ HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
+ HashAffiliationFetcher::RequestInfo request_info{.change_password_info =
+ true};
+
+ std::vector<FacetURI> requested_uris;
+ requested_uris.push_back(FacetURI::FromCanonicalSpec(k1ExampleURL));
+ requested_uris.push_back(FacetURI::FromCanonicalSpec(k2ExampleURL));
+
+ fetcher.StartRequest(requested_uris, request_info);
+ WaitForResponse();
+
+ EXPECT_THAT(fetcher.GetRequestedFacetURIs(),
+ testing::UnorderedElementsAreArray(requested_uris));
+}
+
+TEST_F(HashAffiliationFetcherTest,
+ VerifyPayloadForMultipleHashesRequestWith16LengthPrefix) {
+ MockAffiliationFetcherDelegate mock_delegate;
+ HashAffiliationFetcher fetcher(test_shared_loader_factory(), &mock_delegate);
+ HashAffiliationFetcher::RequestInfo request_info{.change_password_info =
+ true};
+
+ std::vector<FacetURI> requested_uris;
+ requested_uris.push_back(FacetURI::FromCanonicalSpec(k1ExampleURL));
+ requested_uris.push_back(FacetURI::FromCanonicalSpec(k2ExampleURL));
+
+ fetcher.StartRequest(requested_uris, request_info);
+ WaitForResponse();
+
+ std::vector<uint64_t> hash_prefixes;
+ hash_prefixes.push_back(k1ExampleHash16LenPrefix);
+ hash_prefixes.push_back(k2ExampleHash16LenPrefix);
+
+ ASSERT_NO_FATAL_FAILURE(VerifyRequestPayload(hash_prefixes, request_info));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder.h b/chromium/components/password_manager/core/browser/sql_table_builder.h
index 838b958b666..4430777f0d9 100644
--- a/chromium/components/password_manager/core/browser/sql_table_builder.h
+++ b/chromium/components/password_manager/core/browser/sql_table_builder.h
@@ -9,7 +9,7 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
index f29bd197e63..3a60bd568e0 100644
--- a/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sql_table_builder_unittest.cc
@@ -5,7 +5,7 @@
#include "components/password_manager/core/browser/sql_table_builder.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/test/mock_callback.h"
diff --git a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
index 2ef8c6dea8a..dc4228bd509 100644
--- a/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -7,8 +7,8 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "sql/database.h"
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
index d14617b68ae..d38c48cb028 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -7,6 +7,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/password_manager/core/browser/password_feature_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -45,8 +46,9 @@ class StoreMetricsReporter::MultiStoreMetricsReporter {
public:
MultiStoreMetricsReporter(PasswordStore* profile_store,
PasswordStore* account_store,
+ bool is_opted_in,
base::OnceClosure done_callback)
- : done_callback_(std::move(done_callback)) {
+ : is_opted_in_(is_opted_in), done_callback_(std::move(done_callback)) {
DCHECK(profile_store);
DCHECK(account_store);
profile_store_consumer_ = std::make_unique<Consumer>(
@@ -144,10 +146,24 @@ class StoreMetricsReporter::MultiStoreMetricsReporter {
base::UmaHistogramCounts100(
"PasswordManager.AccountStoreVsProfileStore.Conflicting", conflicting);
+ if (is_opted_in_) {
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore2.Additional", additional);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore2.Missing", missing);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore2.Identical", identical);
+ base::UmaHistogramCounts100(
+ "PasswordManager.AccountStoreVsProfileStore2.Conflicting",
+ conflicting);
+ }
+
std::move(done_callback_).Run();
// Note: |this| might be destroyed now.
}
+ const bool is_opted_in_;
+
base::OnceClosure done_callback_;
std::unique_ptr<Consumer> profile_store_consumer_;
@@ -197,20 +213,23 @@ StoreMetricsReporter::StoreMetricsReporter(
// delayed task runs.
scoped_refptr<PasswordStore> retained_profile_store = profile_store;
scoped_refptr<PasswordStore> retained_account_store = account_store;
+ bool is_opted_in =
+ client->GetPasswordFeatureManager()->IsOptedInForAccountStorage();
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&StoreMetricsReporter::ReportMultiStoreMetrics,
weak_ptr_factory_.GetWeakPtr(), retained_profile_store,
- retained_account_store),
+ retained_account_store, is_opted_in),
base::TimeDelta::FromSeconds(30));
}
}
void StoreMetricsReporter::ReportMultiStoreMetrics(
scoped_refptr<PasswordStore> profile_store,
- scoped_refptr<PasswordStore> account_store) {
+ scoped_refptr<PasswordStore> account_store,
+ bool is_opted_in) {
multi_store_reporter_ = std::make_unique<MultiStoreMetricsReporter>(
- profile_store.get(), account_store.get(),
+ profile_store.get(), account_store.get(), is_opted_in,
base::BindOnce(&StoreMetricsReporter::MultiStoreMetricsDone,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter.h b/chromium/components/password_manager/core/browser/store_metrics_reporter.h
index 5c017fbcf15..0ff5b2a27ce 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter.h
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter.h
@@ -51,7 +51,8 @@ class StoreMetricsReporter {
class MultiStoreMetricsReporter;
void ReportMultiStoreMetrics(scoped_refptr<PasswordStore> profile_store,
- scoped_refptr<PasswordStore> account_store);
+ scoped_refptr<PasswordStore> account_store,
+ bool is_opted_in);
void MultiStoreMetricsDone();
std::unique_ptr<MultiStoreMetricsReporter> multi_store_reporter_;
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index c67e23a8a5f..351e853ec41 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -183,23 +183,52 @@ TEST_F(StoreMetricsReporterTest, MultiStoreMetrics) {
profile_store->AddLogin(
CreateForm(kRealm2, "identicaluser1", "identicalpass1"));
- base::HistogramTester histogram_tester;
-
- StoreMetricsReporter reporter(&client_, sync_service(), identity_manager(),
- &prefs_);
- // Wait for the metrics to get reported. This is delayed by 30 seconds, and
- // then involves queries to the stores, i.e. to background task runners.
- FastForwardBy(base::TimeDelta::FromSeconds(30));
- RunUntilIdle();
-
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore.Additional", 2, 1);
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore.Missing", 4, 1);
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore.Identical", 2, 1);
- histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore.Conflicting", 1, 1);
+ for (bool opted_in : {false, true}) {
+ EXPECT_CALL(*client_.GetPasswordFeatureManager(),
+ IsOptedInForAccountStorage())
+ .WillRepeatedly(Return(opted_in));
+
+ base::HistogramTester histogram_tester;
+
+ StoreMetricsReporter reporter(&client_, sync_service(), identity_manager(),
+ &prefs_);
+ // Wait for the metrics to get reported. This is delayed by 30 seconds, and
+ // then involves queries to the stores, i.e. to background task runners.
+ FastForwardBy(base::TimeDelta::FromSeconds(30));
+ RunUntilIdle();
+
+ // The original version of the metrics (without "2") is still recorded, even
+ // if the user isn't opted in to the account storage.
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Additional", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Missing", 4, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Identical", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore.Conflicting", 1, 1);
+
+ // Version "2" of the metrics is only recorded if the user is opted in.
+ if (opted_in) {
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore2.Additional", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore2.Missing", 4, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore2.Identical", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreVsProfileStore2.Conflicting", 1, 1);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStoreVsProfileStore2.Additional", 0);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStoreVsProfileStore2.Missing", 0);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStoreVsProfileStore2.Identical", 0);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.AccountStoreVsProfileStore2.Conflicting", 0);
+ }
+ }
account_store->ShutdownOnUIThread();
profile_store->ShutdownOnUIThread();
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
index fe63a39b284..acd18e67a9d 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -98,12 +98,10 @@ StubPasswordManagerClient::GetPasswordFeatureManager() {
return &password_feature_manager_;
}
-#if defined(ON_FOCUS_PING_ENABLED) || defined(PASSWORD_REUSE_DETECTION_ENABLED)
safe_browsing::PasswordProtectionService*
StubPasswordManagerClient::GetPasswordProtectionService() const {
return nullptr;
}
-#endif
#if defined(ON_FOCUS_PING_ENABLED)
void StubPasswordManagerClient::CheckSafeBrowsingReputation(
@@ -111,13 +109,11 @@ void StubPasswordManagerClient::CheckSafeBrowsingReputation(
const GURL& frame_url) {}
#endif
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void StubPasswordManagerClient::CheckProtectedPasswordEntry(
metrics_util::PasswordType reused_password_type,
const std::string& username,
const std::vector<MatchingReusedCredential>& matching_reused_credentials,
bool password_field_exists) {}
-#endif
#if defined(PASSWORD_REUSE_WARNING_ENABLED)
void StubPasswordManagerClient::LogPasswordReuseDetectedEvent() {}
@@ -161,4 +157,8 @@ FieldInfoManager* StubPasswordManagerClient::GetFieldInfoManager() const {
return nullptr;
}
+bool StubPasswordManagerClient::IsAutofillAssistantUIVisible() const {
+ return false;
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.h b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
index 36083975fa4..131509a1b8e 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
@@ -62,24 +62,21 @@ class StubPasswordManagerClient : public PasswordManagerClient {
const autofill::LogManager* GetLogManager() const override;
const MockPasswordFeatureManager* GetPasswordFeatureManager() const override;
MockPasswordFeatureManager* GetPasswordFeatureManager();
+ bool IsAutofillAssistantUIVisible() const override;
-#if defined(ON_FOCUS_PING_ENABLED) || defined(PASSWORD_REUSE_DETECTION_ENABLED)
safe_browsing::PasswordProtectionService* GetPasswordProtectionService()
const override;
-#endif
#if defined(ON_FOCUS_PING_ENABLED)
void CheckSafeBrowsingReputation(const GURL& form_action,
const GURL& frame_url) override;
#endif
-#if defined(PASSWORD_REUSE_DETECTION_ENABLED)
void CheckProtectedPasswordEntry(
metrics_util::PasswordType reused_password_type,
const std::string& username,
const std::vector<MatchingReusedCredential>& matching_reused_credentials,
bool password_field_exists) override;
-#endif
#if defined(PASSWORD_REUSE_WARNING_ENABLED)
void LogPasswordReuseDetectedEvent() override;
diff --git a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
index 425ad22f95e..a8e00c032ec 100644
--- a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -14,8 +14,8 @@
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/sync/base/model_type.h"
-#include "components/sync/driver/sync_client.h"
#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_user_settings.h"
#include "components/sync/model/model_type_controller_delegate.h"
namespace password_manager {
@@ -140,6 +140,16 @@ PasswordModelTypeController::GetPreconditionState() const {
: PreconditionState::kMustStopAndClearData;
}
+bool PasswordModelTypeController::ShouldRunInTransportOnlyMode() const {
+ if (!base::FeatureList::IsEnabled(features::kEnablePasswordsAccountStorage)) {
+ return false;
+ }
+ if (sync_service_->GetUserSettings()->IsUsingSecondaryPassphrase()) {
+ return false;
+ }
+ return true;
+}
+
void PasswordModelTypeController::OnStateChanged(syncer::SyncService* sync) {
DCHECK(CalledOnValidThread());
sync_service_->DataTypePreconditionChanged(syncer::PASSWORDS);
diff --git a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
index f5354383492..bc5362b9e4c 100644
--- a/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
+++ b/chromium/components/password_manager/core/browser/sync/password_model_type_controller.h
@@ -49,6 +49,7 @@ class PasswordModelTypeController : public syncer::ModelTypeController,
void Stop(syncer::ShutdownReason shutdown_reason,
StopCallback callback) override;
PreconditionState GetPreconditionState() const override;
+ bool ShouldRunInTransportOnlyMode() const override;
// SyncServiceObserver overrides.
void OnStateChanged(syncer::SyncService* sync) override;
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 8098f2aec6b..9592d28aaa4 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -547,6 +547,22 @@ base::Optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
}
metrics_util::LogPasswordSyncState(metrics_util::SYNCING_OK);
+ if (password_store_sync_->IsAccountStore()) {
+ int password_count = base::ranges::count_if(
+ entity_data,
+ [](const std::unique_ptr<syncer::EntityChange>& entity_change) {
+ return !entity_change->data()
+ .specifics.password()
+ .client_only_encrypted_data()
+ .blacklisted();
+ });
+ metrics_util::LogDownloadedPasswordsCountFromAccountStoreAfterUnlock(
+ password_count);
+ metrics_util::
+ LogDownloadedBlocklistedEntriesCountFromAccountStoreAfterUnlock(
+ entity_data.size() - password_count);
+ }
+
sync_enabled_or_disabled_cb_.Run();
return base::nullopt;
}
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 658c2a75665..92a44b1783b 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -9,9 +9,9 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "build/build_config.h"
@@ -21,9 +21,9 @@
#include "components/sync/model/data_batch.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/metadata_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/model_impl/sync_metadata_store_change_list.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/test_matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -183,42 +183,74 @@ class FakeDatabase {
class MockSyncMetadataStore : public PasswordStoreSync::MetadataStore {
public:
- MOCK_METHOD0(GetAllSyncMetadata, std::unique_ptr<syncer::MetadataBatch>());
- MOCK_METHOD0(DeleteAllSyncMetadata, void());
- MOCK_METHOD3(UpdateSyncMetadata,
- bool(syncer::ModelType,
- const std::string&,
- const sync_pb::EntityMetadata&));
- MOCK_METHOD2(ClearSyncMetadata, bool(syncer::ModelType, const std::string&));
- MOCK_METHOD2(UpdateModelTypeState,
- bool(syncer::ModelType, const sync_pb::ModelTypeState&));
- MOCK_METHOD1(ClearModelTypeState, bool(syncer::ModelType));
- MOCK_METHOD1(SetDeletionsHaveSyncedCallback,
- void(base::RepeatingCallback<void(bool)>));
- MOCK_METHOD0(HasUnsyncedDeletions, bool());
+ MOCK_METHOD(std::unique_ptr<syncer::MetadataBatch>,
+ GetAllSyncMetadata,
+ (),
+ (override));
+ MOCK_METHOD(void, DeleteAllSyncMetadata, (), (override));
+ MOCK_METHOD(bool,
+ UpdateSyncMetadata,
+ (syncer::ModelType,
+ const std::string&,
+ const sync_pb::EntityMetadata&),
+ (override));
+ MOCK_METHOD(bool,
+ ClearSyncMetadata,
+ (syncer::ModelType, const std::string&),
+ (override));
+ MOCK_METHOD(bool,
+ UpdateModelTypeState,
+ (syncer::ModelType, const sync_pb::ModelTypeState&),
+ (override));
+ MOCK_METHOD(bool, ClearModelTypeState, (syncer::ModelType), (override));
+ MOCK_METHOD(void,
+ SetDeletionsHaveSyncedCallback,
+ (base::RepeatingCallback<void(bool)>),
+ (override));
+ MOCK_METHOD(bool, HasUnsyncedDeletions, (), (override));
};
class MockPasswordStoreSync : public PasswordStoreSync {
public:
- MOCK_METHOD1(ReadAllLogins, FormRetrievalResult(PrimaryKeyToFormMap*));
- MOCK_METHOD1(RemoveLoginByPrimaryKeySync, PasswordStoreChangeList(int));
- MOCK_METHOD0(DeleteUndecryptableLogins, DatabaseCleanupResult());
- MOCK_METHOD2(AddLoginSync,
- PasswordStoreChangeList(const PasswordForm&, AddLoginError*));
- MOCK_METHOD2(UpdateLoginSync,
- PasswordStoreChangeList(const PasswordForm&, UpdateLoginError*));
- MOCK_METHOD1(RemoveLoginSync, PasswordStoreChangeList(const PasswordForm&));
- MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&));
- MOCK_METHOD1(NotifyDeletionsHaveSynced, void(bool));
-
- MOCK_METHOD1(NotifyUnsyncedCredentialsWillBeDeleted,
- void(std::vector<PasswordForm> unsynced_credentials));
- MOCK_METHOD0(BeginTransaction, bool());
- MOCK_METHOD0(CommitTransaction, bool());
- MOCK_METHOD0(RollbackTransaction, void());
- MOCK_METHOD0(GetMetadataStore, PasswordStoreSync::MetadataStore*());
- MOCK_CONST_METHOD0(IsAccountStore, bool());
- MOCK_METHOD0(DeleteAndRecreateDatabaseFile, bool());
+ MOCK_METHOD(FormRetrievalResult,
+ ReadAllLogins,
+ (PrimaryKeyToFormMap*),
+ (override));
+ MOCK_METHOD(PasswordStoreChangeList,
+ RemoveLoginByPrimaryKeySync,
+ (int),
+ (override));
+ MOCK_METHOD(DatabaseCleanupResult, DeleteUndecryptableLogins, (), (override));
+ MOCK_METHOD(PasswordStoreChangeList,
+ AddLoginSync,
+ (const PasswordForm&, AddLoginError*),
+ (override));
+ MOCK_METHOD(PasswordStoreChangeList,
+ UpdateLoginSync,
+ (const PasswordForm&, UpdateLoginError*),
+ (override));
+ MOCK_METHOD(PasswordStoreChangeList,
+ RemoveLoginSync,
+ (const PasswordForm&),
+ (override));
+ MOCK_METHOD(void,
+ NotifyLoginsChanged,
+ (const PasswordStoreChangeList&),
+ (override));
+ MOCK_METHOD(void, NotifyDeletionsHaveSynced, (bool), (override));
+ MOCK_METHOD(void,
+ NotifyUnsyncedCredentialsWillBeDeleted,
+ (std::vector<PasswordForm> unsynced_credentials),
+ (override));
+ MOCK_METHOD(bool, BeginTransaction, (), (override));
+ MOCK_METHOD(bool, CommitTransaction, (), (override));
+ MOCK_METHOD(void, RollbackTransaction, (), (override));
+ MOCK_METHOD(PasswordStoreSync::MetadataStore*,
+ GetMetadataStore,
+ (),
+ (override));
+ MOCK_METHOD(bool, IsAccountStore, (), (const override));
+ MOCK_METHOD(bool, DeleteAndRecreateDatabaseFile, (), (override));
};
} // namespace
@@ -1001,4 +1033,37 @@ TEST_F(PasswordSyncBridgeTest,
"PasswordManager.AccountStorage.UnsyncedPasswordsFoundDuringSignOut", 0);
}
+TEST_F(PasswordSyncBridgeTest, ShouldReportDownloadedPasswordsIfAccountStore) {
+ ON_CALL(*mock_password_store_sync(), IsAccountStore())
+ .WillByDefault(Return(true));
+ ON_CALL(mock_processor(), IsTrackingMetadata()).WillByDefault(Return(true));
+
+ syncer::EntityChangeList entity_change_list;
+ entity_change_list.push_back(syncer::EntityChange::CreateAdd(
+ /*storage_key=*/"",
+ SpecificsToEntity(CreateSpecificsWithSignonRealm(kSignonRealm1))));
+ entity_change_list.push_back(syncer::EntityChange::CreateAdd(
+ /*storage_key=*/"",
+ SpecificsToEntity(CreateSpecificsWithSignonRealm(kSignonRealm2))));
+
+ sync_pb::PasswordSpecifics blocklisted_specifics;
+ sync_pb::PasswordSpecificsData* password_data =
+ blocklisted_specifics.mutable_client_only_encrypted_data();
+ password_data->set_origin("http://www.origin.com");
+ password_data->set_signon_realm(kSignonRealm3);
+ password_data->set_blacklisted(true);
+
+ entity_change_list.push_back(syncer::EntityChange::CreateAdd(
+ /*storage_key=*/"", SpecificsToEntity(blocklisted_specifics)));
+
+ base::HistogramTester histogram_tester;
+ base::Optional<syncer::ModelError> error = bridge()->MergeSyncData(
+ bridge()->CreateMetadataChangeList(), std::move(entity_change_list));
+ EXPECT_FALSE(error);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreCredentialsAfterOptIn", 2, 1);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.AccountStoreBlocklistedEntriesAfterOptIn", 1, 1);
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/sync_credentials_filter.h b/chromium/components/password_manager/core/browser/sync_credentials_filter.h
index 90c240bf797..a92d0cdc3a6 100644
--- a/chromium/components/password_manager/core/browser/sync_credentials_filter.h
+++ b/chromium/components/password_manager/core/browser/sync_credentials_filter.h
@@ -12,12 +12,13 @@
#include "base/callback.h"
#include "base/macros.h"
#include "components/password_manager/core/browser/credentials_filter.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/sync/driver/sync_service.h"
namespace password_manager {
+struct PasswordForm;
+
// The sync- and GAIA- aware implementation of the filter.
class SyncCredentialsFilter : public CredentialsFilter {
public:
diff --git a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index 3aa4717007d..b179d4b2231 100644
--- a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -11,7 +11,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/password_manager/core/browser/sync_username_test_base.h b/chromium/components/password_manager/core/browser/sync_username_test_base.h
index 273b88b1c43..f7c82ec1c97 100644
--- a/chromium/components/password_manager/core/browser/sync_username_test_base.h
+++ b/chromium/components/password_manager/core/browser/sync_username_test_base.h
@@ -11,13 +11,14 @@
#include <string>
#include "base/test/task_environment.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/sync/driver/test_sync_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
+struct PasswordForm;
+
class SyncUsernameTestBase : public testing::Test {
public:
SyncUsernameTestBase();
diff --git a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
index 6af5b95d085..6e58f0703ac 100644
--- a/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
+++ b/chromium/components/password_manager/core/browser/ui/bulk_leak_check_service_adapter.h
@@ -7,13 +7,14 @@
#include "components/password_manager/core/browser/bulk_leak_check_service_interface.h"
#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
class PrefService;
namespace password_manager {
+struct PasswordForm;
+
// This class serves as an apdater for the BulkLeakCheckService and exposes an
// API that is intended to be consumed from the settings page.
class BulkLeakCheckServiceAdapter : public SavedPasswordsPresenter::Observer {
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.cc b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.cc
index 3f35c7faff1..11342913773 100644
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.cc
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.cc
@@ -16,9 +16,9 @@ CompromisedCredentialsReader::CompromisedCredentialsReader(
PasswordStore* account_store)
: profile_store_(profile_store), account_store_(account_store) {
DCHECK(profile_store_);
- observed_password_store_.Add(profile_store_);
+ observed_password_stores_.AddObservation(profile_store_);
if (account_store_) {
- observed_password_store_.Add(account_store_);
+ observed_password_stores_.AddObservation(account_store_);
} else {
// Since we aren't expecting any response from the account store, mark it as
// responded not to block responses from the the profile waiting for the
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.h b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.h
index 3f9d085e0dc..e219fdcd0d2 100644
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.h
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader.h
@@ -6,7 +6,7 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_COMPROMISED_CREDENTIALS_READER_H_
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "components/password_manager/core/browser/compromised_credentials_consumer.h"
#include "components/password_manager/core/browser/password_store.h"
@@ -68,11 +68,12 @@ class CompromisedCredentialsReader
// A scoped observer for |profile_store_|, and |account_store_| that listens
// to changes related to CompromisedCredentials only.
- ScopedObserver<PasswordStore,
- PasswordStore::DatabaseCompromisedCredentialsObserver,
- &PasswordStore::AddDatabaseCompromisedCredentialsObserver,
- &PasswordStore::RemoveDatabaseCompromisedCredentialsObserver>
- observed_password_store_{this};
+ base::ScopedMultiSourceObservation<
+ PasswordStore,
+ PasswordStore::DatabaseCompromisedCredentialsObserver,
+ &PasswordStore::AddDatabaseCompromisedCredentialsObserver,
+ &PasswordStore::RemoveDatabaseCompromisedCredentialsObserver>
+ observed_password_stores_{this};
base::ObserverList<Observer, /*check_empty=*/true> observers_;
std::vector<GetCompromisedCredentialsCallback>
diff --git a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader_unittest.cc b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader_unittest.cc
index 3b9dcca123e..662914bc136 100644
--- a/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/compromised_credentials_reader_unittest.cc
@@ -5,7 +5,7 @@
#include "components/password_manager/core/browser/ui/compromised_credentials_reader.h"
#include "base/memory/scoped_refptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/password_manager/core/browser/ui/credential_provider_interface.h b/chromium/components/password_manager/core/browser/ui/credential_provider_interface.h
index fe66dead919..cb4b71d917e 100644
--- a/chromium/components/password_manager/core/browser/ui/credential_provider_interface.h
+++ b/chromium/components/password_manager/core/browser/ui/credential_provider_interface.h
@@ -8,10 +8,10 @@
#include <memory>
#include <vector>
-#include "components/password_manager/core/browser/password_form_forward.h"
-
namespace password_manager {
+struct PasswordForm;
+
// This is a delegate of the ExportFlow interface used to retrieve exportable
// passwords.
// TODO(1047726): Merge this interface with SavedPasswordsPresenter.
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
index 8db07a2f494..131f87ba7a5 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -9,12 +9,14 @@
#include <set>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/metrics/histogram_functions.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
+#include "build/build_config.h"
#include "components/password_manager/core/browser/compromised_credentials_table.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_list_sorter.h"
@@ -226,9 +228,9 @@ InsecureCredentialsManager::InsecureCredentialsManager(
account_store_(std::move(account_store)),
compromised_credentials_reader_(profile_store_.get(),
account_store_.get()) {
- observed_compromised_credentials_reader_.Add(
+ observed_compromised_credentials_reader_.Observe(
&compromised_credentials_reader_);
- observed_saved_password_presenter_.Add(presenter_);
+ observed_saved_password_presenter_.Observe(presenter_);
}
InsecureCredentialsManager::~InsecureCredentialsManager() = default;
@@ -237,13 +239,15 @@ void InsecureCredentialsManager::Init() {
compromised_credentials_reader_.Init();
}
-void InsecureCredentialsManager::StartWeakCheck() {
+void InsecureCredentialsManager::StartWeakCheck(
+ base::OnceClosure on_check_done) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&BulkWeakCheck,
ExtractPasswords(presenter_->GetSavedPasswords())),
base::BindOnce(&InsecureCredentialsManager::OnWeakCheckDone,
- weak_ptr_factory_.GetWeakPtr(), base::ElapsedTimer()));
+ weak_ptr_factory_.GetWeakPtr(), base::ElapsedTimer())
+ .Then(std::move(on_check_done)));
}
void InsecureCredentialsManager::SaveCompromisedCredential(
@@ -338,16 +342,19 @@ void InsecureCredentialsManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-void InsecureCredentialsManager::OnWeakCheckDone(
- base::ElapsedTimer timer_since_weak_check_start,
- base::flat_set<base::string16> weak_passwords) {
- weak_passwords_ = std::move(weak_passwords);
-
+void InsecureCredentialsManager::UpdateInsecureCredentials() {
credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
compromised_credentials_, weak_passwords_,
presenter_->GetSavedPasswords());
+}
+
+void InsecureCredentialsManager::OnWeakCheckDone(
+ base::ElapsedTimer timer_since_weak_check_start,
+ base::flat_set<base::string16> weak_passwords) {
base::UmaHistogramTimes("PasswordManager.WeakCheck.Time",
timer_since_weak_check_start.Elapsed());
+ weak_passwords_ = std::move(weak_passwords);
+ UpdateInsecureCredentials();
NotifyWeakCredentialsChanged();
}
@@ -356,13 +363,27 @@ void InsecureCredentialsManager::OnWeakCheckDone(
void InsecureCredentialsManager::OnCompromisedCredentialsChanged(
const std::vector<CompromisedCredentials>& compromised_credentials) {
compromised_credentials_ = compromised_credentials;
-
- credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
- compromised_credentials_, weak_passwords_,
- presenter_->GetSavedPasswords());
+ UpdateInsecureCredentials();
NotifyCompromisedCredentialsChanged();
}
+void InsecureCredentialsManager::OnEdited(const PasswordForm& form) {
+ // The WeakCheck is a Desktop only feature for now. Disable on Mobile to avoid
+ // pulling in a big dependency on zxcvbn.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ const base::string16& password = form.password_value;
+ if (weak_passwords_.contains(password) || !IsWeak(password)) {
+ // Either the password is already known to be weak, or it is not weak at
+ // all. In both cases there is nothing to do.
+ return;
+ }
+
+ weak_passwords_.insert(password);
+ UpdateInsecureCredentials();
+ NotifyWeakCredentialsChanged();
+#endif
+}
+
// Re-computes the list of insecure credentials with passwords after obtaining a
// new list of saved passwords.
void InsecureCredentialsManager::OnSavedPasswordsChanged(
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
index 3b6dda00684..fedaeec4996 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -8,12 +8,14 @@
#include <map>
#include <vector>
+#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/timer/elapsed_timer.h"
#include "base/util/type_safety/strong_alias.h"
#include "components/password_manager/core/browser/compromised_credentials_consumer.h"
@@ -164,7 +166,7 @@ class InsecureCredentialsManager
// Computes weak credentials in a separate thread and then passes the result
// to OnWeakCheckDone.
- void StartWeakCheck();
+ void StartWeakCheck(base::OnceClosure on_check_done = base::DoNothing());
// Marks all saved credentials which have same username & password as
// compromised.
@@ -198,6 +200,12 @@ class InsecureCredentialsManager
using CredentialPasswordsMap =
std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>;
+ // Recomputes the insecure credentials by making use of information stored in
+ // `compromised_credentials_`, `weak_passwords_` and `presenter_`.
+ // This does not invoke either `NotifyCompromisedCredentialsChanged` or
+ // `NotifyWeakCredentialsChanged`, so that it can be used more generally.
+ void UpdateInsecureCredentials();
+
// Updates |weak_passwords| set and notifies observers that weak credentials
// were changed.
void OnWeakCheckDone(base::ElapsedTimer timer_since_weak_check_start,
@@ -209,6 +217,7 @@ class InsecureCredentialsManager
override;
// SavedPasswordsPresenter::Observer:
+ void OnEdited(const PasswordForm& form) override;
void OnSavedPasswordsChanged(
SavedPasswordsPresenter::SavedPasswordsView passwords) override;
@@ -246,12 +255,13 @@ class InsecureCredentialsManager
// A scoped observer for |compromised_credentials_reader_| to listen changes
// related to CompromisedCredentials only.
- ScopedObserver<CompromisedCredentialsReader,
- CompromisedCredentialsReader::Observer>
+ base::ScopedObservation<CompromisedCredentialsReader,
+ CompromisedCredentialsReader::Observer>
observed_compromised_credentials_reader_{this};
// A scoped observer for |presenter_|.
- ScopedObserver<SavedPasswordsPresenter, SavedPasswordsPresenter::Observer>
+ base::ScopedObservation<SavedPasswordsPresenter,
+ SavedPasswordsPresenter::Observer>
observed_saved_password_presenter_{this};
base::ObserverList<Observer, /*check_empty=*/true> observers_;
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
index 244a1080e60..9ef6d5b2193 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
@@ -8,8 +8,10 @@
#include "base/strings/string_piece_forward.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "base/timer/elapsed_timer.h"
+#include "build/build_config.h"
#include "components/password_manager/core/browser/compromised_credentials_table.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/test_password_store.h"
@@ -508,6 +510,13 @@ TEST_F(InsecureCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
ElementsAreArray(store().stored_passwords().at(kExampleOrg)));
}
+TEST_F(InsecureCredentialsManagerTest, StartWeakCheckNotifiesOnCompletion) {
+ base::MockOnceClosure closure;
+ provider().StartWeakCheck(closure.Get());
+ EXPECT_CALL(closure, Run);
+ RunUntilIdle();
+}
+
TEST_F(InsecureCredentialsManagerTest, StartWeakCheckOnEmptyPasswordsList) {
EXPECT_THAT(
histogram_tester().GetTotalCountsForPrefix("PasswordManager.WeakCheck"),
@@ -778,7 +787,11 @@ TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
RunUntilIdle();
CredentialWithPassword expected =
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ MakeWeakAndCompromisedCredential(password_form, credential);
+#else
MakeCompromisedCredential(password_form, credential);
+#endif
EXPECT_TRUE(provider().UpdateCredential(expected, kPassword2));
RunUntilIdle();
@@ -808,6 +821,30 @@ TEST_F(InsecureCredentialsManagerTest, UpdateWeakPassword) {
kStrongPassword1);
}
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+// Test verifies that editing a weak credential to another weak credential
+// continues to be treated weak.
+TEST_F(InsecureCredentialsManagerTest, UpdatedWeakPasswordRemainsWeak) {
+ PasswordForm password_form =
+ MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
+
+ store().AddLogin(password_form);
+ RunUntilIdle();
+
+ provider().StartWeakCheck();
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeWeakCredential(password_form);
+ EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
+
+ EXPECT_TRUE(provider().UpdateCredential(expected, kWeakPassword2));
+ RunUntilIdle();
+
+ expected.password = base::ASCIIToUTF16(kWeakPassword2);
+ EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
+}
+#endif
+
// Test verifies that editing credential that is weak and compromised via
// provider change the saved password.
TEST_F(InsecureCredentialsManagerTest, UpdateInsecurePassword) {
diff --git a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.cc b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.cc
index 8710eabccc1..9b8e94f3a42 100644
--- a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.cc
+++ b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.cc
@@ -13,6 +13,31 @@
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+
+namespace {
+using password_manager::metrics_util::IsPasswordChanged;
+using password_manager::metrics_util::IsUsernameChanged;
+using SavedPasswordsView =
+ password_manager::SavedPasswordsPresenter::SavedPasswordsView;
+
+bool IsUsernameAlreadyUsed(SavedPasswordsView all_forms,
+ SavedPasswordsView forms_to_check,
+ const base::string16& new_username) {
+ // In case the username changed, make sure that there exists no other
+ // credential with the same signon_realm and username in the same store.
+ auto has_conflicting_username = [&forms_to_check,
+ &new_username](const auto& form) {
+ return new_username == form.username_value &&
+ base::ranges::any_of(forms_to_check, [&form](const auto& old_form) {
+ return form.signon_realm == old_form.signon_realm &&
+ form.IsUsingAccountStore() ==
+ old_form.IsUsingAccountStore();
+ });
+ };
+ return base::ranges::any_of(all_forms, has_conflicting_username);
+}
+} // namespace
namespace password_manager {
@@ -41,7 +66,10 @@ void SavedPasswordsPresenter::Init() {
bool SavedPasswordsPresenter::EditPassword(const PasswordForm& form,
base::string16 new_password) {
- auto found = base::ranges::find(passwords_, form);
+ auto is_equal = [&form](const PasswordForm& form_to_check) {
+ return ArePasswordFormUniqueKeysEqual(form, form_to_check);
+ };
+ auto found = base::ranges::find_if(passwords_, is_equal);
if (found == passwords_.end())
return false;
@@ -53,6 +81,47 @@ bool SavedPasswordsPresenter::EditPassword(const PasswordForm& form,
return true;
}
+bool SavedPasswordsPresenter::EditSavedPasswords(
+ const SavedPasswordsView forms,
+ const base::string16& new_username,
+ const base::string16& new_password) {
+ IsUsernameChanged username_changed(new_username != forms[0].username_value);
+ IsPasswordChanged password_changed(new_password != forms[0].password_value);
+
+ if (new_password.empty())
+ return false;
+ if (username_changed &&
+ IsUsernameAlreadyUsed(passwords_, forms, new_username))
+ return false;
+
+ // An updated username implies a change in the primary key, thus we need to
+ // make sure to call the right API. Update every entry in the equivalence
+ // class.
+ if (username_changed || password_changed) {
+ for (const auto& old_form : forms) {
+ PasswordStore& store =
+ old_form.IsUsingAccountStore() ? *account_store_ : *profile_store_;
+
+ PasswordForm new_form = old_form;
+ new_form.username_value = new_username;
+ new_form.password_value = new_password;
+
+ if (username_changed) {
+ // Changing username requires deleting old form and adding new one. So
+ // the different API should be called.
+ store.UpdateLoginWithPrimaryKey(new_form, old_form);
+ } else {
+ store.UpdateLogin(new_form);
+ }
+ NotifyEdited(new_form);
+ }
+ }
+
+ password_manager::metrics_util::LogPasswordEditResult(username_changed,
+ password_changed);
+ return true;
+}
+
SavedPasswordsPresenter::SavedPasswordsView
SavedPasswordsPresenter::GetSavedPasswords() const {
return passwords_;
diff --git a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.h b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.h
index e1e7c128a2d..9adfe5d8fb0 100644
--- a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.h
+++ b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter.h
@@ -11,12 +11,13 @@
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "base/strings/string_piece_forward.h"
-#include "components/password_manager/core/browser/password_form_forward.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
namespace password_manager {
+struct PasswordForm;
+
// This interface provides a way for clients to obtain a list of all saved
// passwords and register themselves as observers for changes. In contrast to
// simply registering oneself as an observer of a password store directly, this
@@ -69,6 +70,13 @@ class SavedPasswordsPresenter : public PasswordStore::Observer,
// in |passwords_|.
bool EditPassword(const PasswordForm& form, base::string16 new_password);
+ // Modifies provided password forms, with |new_username| and |new_password|.
+ // |forms| must represent single credential, with its duplicates, or the
+ // same form saved on another store type.
+ bool EditSavedPasswords(const SavedPasswordsView forms,
+ const base::string16& new_username,
+ const base::string16& new_password);
+
// Returns a list of the currently saved credentials.
SavedPasswordsView GetSavedPasswords() const;
diff --git a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc
index 02d46bd4c54..0ccc378b41b 100644
--- a/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/saved_passwords_presenter_unittest.cc
@@ -5,10 +5,12 @@
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#include "base/memory/scoped_refptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -142,6 +144,7 @@ TEST_F(SavedPasswordsPresenterTest, EditPassword) {
// Verify that editing a password that does not exist does not triggers
// notifications.
+ form.username_value = base::ASCIIToUTF16("another_username");
EXPECT_CALL(observer, OnEdited).Times(0);
EXPECT_CALL(observer, OnSavedPasswordsChanged).Times(0);
EXPECT_FALSE(presenter().EditPassword(form, new_password));
@@ -150,6 +153,191 @@ TEST_F(SavedPasswordsPresenterTest, EditPassword) {
presenter().RemoveObserver(&observer);
}
+TEST_F(SavedPasswordsPresenterTest, EditOnlyUsername) {
+ PasswordForm form;
+ form.signon_realm = "https://example.com";
+ form.username_value = base::ASCIIToUTF16("test@gmail.com");
+ form.password_value = base::ASCIIToUTF16("password");
+ form.in_store = PasswordForm::Store::kProfileStore;
+
+ StrictMockSavedPasswordsPresenterObserver observer;
+ presenter().AddObserver(&observer);
+
+ EXPECT_CALL(observer, OnSavedPasswordsChanged);
+ store().AddLogin(form);
+ RunUntilIdle();
+ EXPECT_FALSE(store().IsEmpty());
+
+ std::vector<PasswordForm> forms = {form};
+
+ const base::string16 new_username = base::ASCIIToUTF16("new_username");
+ PasswordForm updated_username = form;
+ updated_username.username_value = new_username;
+
+ // Verify that editing a username triggers the right notifications.
+ base::HistogramTester histogram_tester;
+
+ EXPECT_CALL(observer, OnEdited(updated_username));
+ EXPECT_CALL(observer, OnSavedPasswordsChanged(ElementsAre(updated_username)));
+ EXPECT_TRUE(
+ presenter().EditSavedPasswords(forms, new_username, form.password_value));
+ RunUntilIdle();
+ EXPECT_THAT(
+ store().stored_passwords(),
+ ElementsAre(Pair(form.signon_realm, ElementsAre(updated_username))));
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.PasswordEditUpdatedValues",
+ metrics_util::PasswordEditUpdatedValues::kUsername, 1);
+
+ presenter().RemoveObserver(&observer);
+}
+
+TEST_F(SavedPasswordsPresenterTest, EditOnlyPassword) {
+ PasswordForm form;
+ form.signon_realm = "https://example.com";
+ form.username_value = base::ASCIIToUTF16("test@gmail.com");
+ form.password_value = base::ASCIIToUTF16("password");
+ form.in_store = PasswordForm::Store::kProfileStore;
+
+ StrictMockSavedPasswordsPresenterObserver observer;
+ presenter().AddObserver(&observer);
+
+ EXPECT_CALL(observer, OnSavedPasswordsChanged);
+ store().AddLogin(form);
+ RunUntilIdle();
+ EXPECT_FALSE(store().IsEmpty());
+
+ std::vector<PasswordForm> forms = {form};
+
+ const base::string16 new_password = base::ASCIIToUTF16("new_password");
+ PasswordForm updated_password = form;
+ updated_password.password_value = new_password;
+
+ base::HistogramTester histogram_tester;
+ // Verify that editing a password triggers the right notifications.
+ EXPECT_CALL(observer, OnEdited(updated_password));
+ EXPECT_CALL(observer, OnSavedPasswordsChanged(ElementsAre(updated_password)));
+ EXPECT_TRUE(
+ presenter().EditSavedPasswords(forms, form.username_value, new_password));
+ RunUntilIdle();
+ EXPECT_THAT(
+ store().stored_passwords(),
+ ElementsAre(Pair(form.signon_realm, ElementsAre(updated_password))));
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.PasswordEditUpdatedValues",
+ metrics_util::PasswordEditUpdatedValues::kPassword, 1);
+
+ presenter().RemoveObserver(&observer);
+}
+
+TEST_F(SavedPasswordsPresenterTest, EditUsernameAndPassword) {
+ PasswordForm form;
+ form.signon_realm = "https://example.com";
+ form.username_value = base::ASCIIToUTF16("test@gmail.com");
+ form.password_value = base::ASCIIToUTF16("password");
+ form.in_store = PasswordForm::Store::kProfileStore;
+
+ StrictMockSavedPasswordsPresenterObserver observer;
+ presenter().AddObserver(&observer);
+
+ EXPECT_CALL(observer, OnSavedPasswordsChanged);
+ store().AddLogin(form);
+ RunUntilIdle();
+ EXPECT_FALSE(store().IsEmpty());
+
+ std::vector<PasswordForm> forms = {form};
+
+ const base::string16 new_username = base::ASCIIToUTF16("new_username");
+ const base::string16 new_password = base::ASCIIToUTF16("new_password");
+
+ PasswordForm updated_both = form;
+ updated_both.username_value = new_username;
+ updated_both.password_value = new_password;
+
+ base::HistogramTester histogram_tester;
+ // Verify that editing username and password triggers the right notifications.
+ EXPECT_CALL(observer, OnEdited(updated_both));
+ EXPECT_CALL(observer, OnSavedPasswordsChanged(ElementsAre(updated_both)));
+ EXPECT_TRUE(
+ presenter().EditSavedPasswords(forms, new_username, new_password));
+ RunUntilIdle();
+ EXPECT_THAT(store().stored_passwords(),
+ ElementsAre(Pair(form.signon_realm, ElementsAre(updated_both))));
+ histogram_tester.ExpectBucketCount(
+ "PasswordManager.PasswordEditUpdatedValues",
+ metrics_util::PasswordEditUpdatedValues::kBoth, 1);
+
+ presenter().RemoveObserver(&observer);
+}
+
+TEST_F(SavedPasswordsPresenterTest, EditPasswordFails) {
+ PasswordForm form1;
+ form1.signon_realm = "https://example.com";
+ form1.username_value = base::ASCIIToUTF16("test1@gmail.com");
+ form1.password_value = base::ASCIIToUTF16("password");
+ form1.in_store = PasswordForm::Store::kProfileStore;
+
+ PasswordForm form2;
+ form2.signon_realm = "https://example.com";
+ form2.username_value = base::ASCIIToUTF16("test2@gmail.com");
+ form2.password_value = base::ASCIIToUTF16("password");
+ form2.in_store = PasswordForm::Store::kProfileStore;
+
+ store().AddLogin(form1);
+ store().AddLogin(form2);
+ RunUntilIdle();
+ EXPECT_FALSE(store().IsEmpty());
+
+ std::vector<PasswordForm> forms{form1};
+
+ // Updating the form with the username which is already used for same website
+ // fails.
+ const base::string16 new_username = base::ASCIIToUTF16("test2@gmail.com");
+ EXPECT_FALSE(presenter().EditSavedPasswords(forms, new_username,
+ form1.password_value));
+ RunUntilIdle();
+ EXPECT_THAT(store().stored_passwords(),
+ ElementsAre(Pair(form1.signon_realm, ElementsAre(form1, form2))));
+
+ // Updating the form with the empty password fails.
+ EXPECT_FALSE(presenter().EditSavedPasswords(forms, form1.username_value,
+ base::string16()));
+ RunUntilIdle();
+ EXPECT_THAT(store().stored_passwords(),
+ ElementsAre(Pair(form1.signon_realm, ElementsAre(form1, form2))));
+}
+
+TEST_F(SavedPasswordsPresenterTest, EditPasswordWithoutChanges) {
+ PasswordForm form;
+ form.signon_realm = "https://example.com";
+ form.username_value = base::ASCIIToUTF16("test1@gmail.com");
+ form.password_value = base::ASCIIToUTF16("password");
+ form.in_store = PasswordForm::Store::kProfileStore;
+
+ store().AddLogin(form);
+
+ RunUntilIdle();
+ StrictMockSavedPasswordsPresenterObserver observer;
+ presenter().AddObserver(&observer);
+
+ EXPECT_FALSE(store().IsEmpty());
+ // Verify that editing a form without changing the username or password does
+ // not triggers notifications.
+ base::HistogramTester histogram_tester;
+ EXPECT_CALL(observer, OnEdited).Times(0);
+ EXPECT_CALL(observer, OnSavedPasswordsChanged).Times(0);
+ std::vector<PasswordForm> forms = {form};
+ EXPECT_TRUE(presenter().EditSavedPasswords(forms, form.username_value,
+ form.password_value));
+ RunUntilIdle();
+ histogram_tester.ExpectBucketCount(
+ "PasswordManager.PasswordEditUpdatedValues",
+ metrics_util::PasswordEditUpdatedValues::kNone, 1);
+
+ presenter().RemoveObserver(&observer);
+}
+
namespace {
class SavedPasswordsPresenterWithTwoStoresTest : public ::testing::Test {
@@ -231,4 +419,37 @@ TEST_F(SavedPasswordsPresenterWithTwoStoresTest, AddCredentialsToBothStores) {
presenter().RemoveObserver(&observer);
}
+// This tests changing the username of a credentials stored in the profile store
+// to be equal to a username of a credential stored in the account store for the
+// same domain.
+TEST_F(SavedPasswordsPresenterWithTwoStoresTest, EditUsername) {
+ PasswordForm profile_store_form;
+ profile_store_form.username_value = base::ASCIIToUTF16("profile@gmail.com");
+ profile_store_form.password_value = base::ASCIIToUTF16("profile_pass");
+ profile_store_form.in_store = PasswordForm::Store::kProfileStore;
+
+ PasswordForm account_store_form;
+ account_store_form.username_value = base::ASCIIToUTF16("account@gmail.com");
+ account_store_form.password_value = base::ASCIIToUTF16("account_pass");
+ account_store_form.in_store = PasswordForm::Store::kAccountStore;
+
+ profile_store().AddLogin(profile_store_form);
+ account_store().AddLogin(account_store_form);
+ RunUntilIdle();
+
+ EXPECT_THAT(profile_store().stored_passwords(),
+ ElementsAre(Pair(profile_store_form.signon_realm,
+ ElementsAre(profile_store_form))));
+
+ auto new_username = account_store_form.username_value;
+ std::vector<PasswordForm> forms_to_edit{profile_store_form};
+ EXPECT_TRUE(presenter().EditSavedPasswords(
+ forms_to_edit, new_username, profile_store_form.password_value));
+ RunUntilIdle();
+ profile_store_form.username_value = new_username;
+ EXPECT_THAT(profile_store().stored_passwords(),
+ ElementsAre(Pair(profile_store_form.signon_realm,
+ ElementsAre(profile_store_form))));
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/weak_check_utility.cc b/chromium/components/password_manager/core/browser/ui/weak_check_utility.cc
index 567ae29d8cd..02a52bcd5fe 100644
--- a/chromium/components/password_manager/core/browser/ui/weak_check_utility.cc
+++ b/chromium/components/password_manager/core/browser/ui/weak_check_utility.cc
@@ -4,7 +4,9 @@
#include "components/password_manager/core/browser/ui/weak_check_utility.h"
+#include "base/functional/not_fn.h"
#include "base/metrics/histogram_functions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/zxcvbn-cpp/native-src/zxcvbn/matching.hpp"
#include "third_party/zxcvbn-cpp/native-src/zxcvbn/scoring.hpp"
@@ -54,14 +56,15 @@ int PasswordWeakCheck(base::StringPiece16 password16) {
} // namespace
+IsWeakPassword IsWeak(base::StringPiece16 password) {
+ return IsWeakPassword(PasswordWeakCheck(password) <= kLowSeverityScore);
+}
+
base::flat_set<base::string16> BulkWeakCheck(
base::flat_set<base::string16> passwords) {
base::UmaHistogramCounts1000("PasswordManager.WeakCheck.CheckedPasswords",
passwords.size());
- base::EraseIf(passwords, [](const auto& password) {
- return kLowSeverityScore < PasswordWeakCheck(password);
- });
-
+ base::EraseIf(passwords, base::not_fn(&IsWeak));
base::UmaHistogramCounts1000("PasswordManager.WeakCheck.WeakPasswords",
passwords.size());
return passwords;
diff --git a/chromium/components/password_manager/core/browser/ui/weak_check_utility.h b/chromium/components/password_manager/core/browser/ui/weak_check_utility.h
index 17a3390e0f6..cc32d1555cb 100644
--- a/chromium/components/password_manager/core/browser/ui/weak_check_utility.h
+++ b/chromium/components/password_manager/core/browser/ui/weak_check_utility.h
@@ -7,10 +7,16 @@
#include "base/containers/flat_set.h"
#include "base/strings/string16.h"
-#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#include "base/strings/string_piece_forward.h"
+#include "base/util/type_safety/strong_alias.h"
namespace password_manager {
+using IsWeakPassword = util::StrongAlias<class IsWeakPasswordTag, bool>;
+
+// Returns whether `password` is weak.
+IsWeakPassword IsWeak(base::StringPiece16 password);
+
// Checks each password for weakness and removes strong passwords from the
// |passwords|.
base::flat_set<base::string16> BulkWeakCheck(
diff --git a/chromium/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc b/chromium/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc
index ea9538691a9..ecbe0af4d76 100644
--- a/chromium/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc
@@ -23,6 +23,13 @@ using ::testing::ElementsAre;
} // namespace
+TEST(WeakCheckUtilityTest, IsWeak) {
+ EXPECT_TRUE(IsWeak(base::ASCIIToUTF16(kWeakShortPassword)));
+ EXPECT_TRUE(IsWeak(base::ASCIIToUTF16(kWeakLongPassword)));
+ EXPECT_FALSE(IsWeak(base::ASCIIToUTF16(kStrongShortPassword)));
+ EXPECT_FALSE(IsWeak(base::ASCIIToUTF16(kStrongLongPassword)));
+}
+
TEST(WeakCheckUtilityTest, WeakPasswordsNotFound) {
base::flat_set<base::string16> passwords = {
base::ASCIIToUTF16(kStrongShortPassword),
diff --git a/chromium/components/password_manager/core/browser/votes_uploader.cc b/chromium/components/password_manager/core/browser/votes_uploader.cc
index 26ba06aecdf..f6b904d08a2 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader.cc
+++ b/chromium/components/password_manager/core/browser/votes_uploader.cc
@@ -38,7 +38,6 @@ using autofill::FormStructure;
using autofill::RandomizedEncoder;
using autofill::ServerFieldType;
using autofill::ServerFieldTypeSet;
-using autofill::ValueElementPair;
using password_manager_util::FindFormByUsername;
using Logger = autofill::SavePasswordProgressLogger;
diff --git a/chromium/components/password_manager/core/browser/well_known_change_password_state_unittest.cc b/chromium/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
index b9e16319676..c2622d8ed61 100644
--- a/chromium/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
+++ b/chromium/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
@@ -63,7 +63,7 @@ class WellKnownChangePasswordStateTest
WellKnownChangePasswordStateTest() {
auto origin = url::Origin::Create(GURL(kOrigin));
trusted_params_.isolation_info = net::IsolationInfo::CreatePartial(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
net::NetworkIsolationKey(origin, origin));
state_.FetchNonExistingResource(
test_shared_loader_factory_.get(), GURL(kOrigin),
diff --git a/chromium/components/password_manager/core/common/BUILD.gn b/chromium/components/password_manager/core/common/BUILD.gn
index 62282fcf995..f636d815ccd 100644
--- a/chromium/components/password_manager/core/common/BUILD.gn
+++ b/chromium/components/password_manager/core/common/BUILD.gn
@@ -28,21 +28,19 @@ static_library("common") {
]
}
-source_set("unit_tests") {
- testonly = true
- sources = [ "credential_manager_types_unittest.cc" ]
+if (is_ios) {
+ source_set("unit_tests") {
+ testonly = true
+ sources = [ "passwords_directory_util_ios_unittest.cc" ]
- if (is_ios) {
- sources += [ "passwords_directory_util_ios_unittest.cc" ]
+ deps = [
+ ":common",
+ "//base",
+ "//base/test:test_support",
+ "//components/autofill/core/common",
+ "//sql",
+ "//testing/gtest",
+ "//url",
+ ]
}
-
- deps = [
- ":common",
- "//base",
- "//base/test:test_support",
- "//components/autofill/core/common",
- "//sql",
- "//testing/gtest",
- "//url",
- ]
}
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.cc b/chromium/components/password_manager/core/common/credential_manager_types.cc
index ff5a5da4c0f..dd7f47bdedc 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.cc
+++ b/chromium/components/password_manager/core/common/credential_manager_types.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "base/strings/string_number_conversions.h"
-#include "components/autofill/core/common/password_form.h"
namespace password_manager {
@@ -31,15 +30,19 @@ std::ostream& operator<<(std::ostream& os, CredentialType value) {
CredentialInfo::CredentialInfo() : type(CredentialType::CREDENTIAL_TYPE_EMPTY) {
}
-CredentialInfo::CredentialInfo(const autofill::PasswordForm& form,
- CredentialType form_type)
- : type(form_type),
- id(form.username_value),
- name(form.display_name),
- icon(form.icon_url),
- password(form.password_value),
- federation(form.federation_origin) {
- switch (form_type) {
+CredentialInfo::CredentialInfo(CredentialType type,
+ base::Optional<base::string16> id,
+ base::Optional<base::string16> name,
+ GURL icon,
+ base::Optional<base::string16> password,
+ url::Origin federation)
+ : type(type),
+ id(std::move(id)),
+ name(std::move(name)),
+ icon(std::move(icon)),
+ password(std::move(password)),
+ federation(std::move(federation)) {
+ switch (type) {
case CredentialType::CREDENTIAL_TYPE_EMPTY:
password = base::string16();
federation = url::Origin();
@@ -63,28 +66,4 @@ bool CredentialInfo::operator==(const CredentialInfo& rhs) const {
federation.Serialize() == rhs.federation.Serialize());
}
-std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromCredentialInfo(
- const CredentialInfo& info,
- const url::Origin& origin) {
- std::unique_ptr<autofill::PasswordForm> form;
- if (info.type == CredentialType::CREDENTIAL_TYPE_EMPTY)
- return form;
-
- form = std::make_unique<autofill::PasswordForm>();
- form->icon_url = info.icon;
- form->display_name = info.name.value_or(base::string16());
- form->federation_origin = info.federation;
- form->url = origin.GetURL();
- form->password_value = info.password.value_or(base::string16());
- form->username_value = info.id.value_or(base::string16());
- form->scheme = autofill::PasswordForm::Scheme::kHtml;
- form->type = autofill::PasswordForm::Type::kApi;
-
- form->signon_realm =
- info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD
- ? form->url.spec()
- : "federation://" + origin.host() + "/" + info.federation.host();
- return form;
-}
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/credential_manager_types.h b/chromium/components/password_manager/core/common/credential_manager_types.h
index b4fd4e95962..3887e35dc9b 100644
--- a/chromium/components/password_manager/core/common/credential_manager_types.h
+++ b/chromium/components/password_manager/core/common/credential_manager_types.h
@@ -17,10 +17,6 @@
#include "url/gurl.h"
#include "url/origin.h"
-namespace autofill {
-struct PasswordForm;
-}
-
namespace password_manager {
// Limit the size of the federations array that we pass to the browser to
@@ -48,7 +44,13 @@ std::ostream& operator<<(std::ostream& os, CredentialType value);
struct CredentialInfo {
CredentialInfo();
- CredentialInfo(const autofill::PasswordForm& form, CredentialType form_type);
+ CredentialInfo(CredentialType type,
+ base::Optional<base::string16> id,
+ base::Optional<base::string16> name,
+ GURL icon,
+ base::Optional<base::string16> password,
+ url::Origin federation);
+
CredentialInfo(const CredentialInfo& other);
~CredentialInfo();
@@ -75,13 +77,6 @@ struct CredentialInfo {
url::Origin federation;
};
-// Create a new autofill::PasswordForm object based on |info|, valid in the
-// context of |origin|. Returns an empty std::unique_ptr for
-// CREDENTIAL_TYPE_EMPTY.
-std::unique_ptr<autofill::PasswordForm> CreatePasswordFormFromCredentialInfo(
- const CredentialInfo& info,
- const url::Origin& origin);
-
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_CREDENTIAL_MANAGER_TYPES_H_
diff --git a/chromium/components/password_manager/core/common/password_manager_features.cc b/chromium/components/password_manager/core/common/password_manager_features.cc
index 3446abc61cb..9eb607c552a 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -12,8 +12,7 @@ namespace password_manager {
// names, e.g. "MyGreatFeature".
namespace features {
-// Enables Biometrics for the Touch To Fill feature. This only effects Android
-// and requires autofill::features::kAutofillTouchToFill to be enabled as well.
+// Enables Biometrics for the Touch To Fill feature. This only effects Android.
const base::Feature kBiometricTouchToFill = {"BiometricTouchToFill",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -22,10 +21,10 @@ const base::Feature kBiometricTouchToFill = {"BiometricTouchToFill",
const base::Feature kChangePasswordAffiliationInfo = {
"ChangePasswordAffiliationInfo", base::FEATURE_DISABLED_BY_DEFAULT};
-// After saving/updating a password show a bubble reminder about the status of
-// other compromised credentials.
-const base::Feature kCompromisedPasswordsReengagement = {
- "CompromisedPasswordsReengagement", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables submission detection for forms dynamically cleared but not removed
+// from the page.
+const base::Feature kDetectFormSubmissionOnFormClear = {
+ "DetectFormSubmissionOnFormClear", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables the editing of passwords in Chrome settings.
const base::Feature kEditPasswordsInSettings = {
@@ -66,12 +65,7 @@ const base::Feature kPasswordChangeInSettings = {
// Enables the bulk Password Check feature for signed in users.
const base::Feature kPasswordCheck = {"PasswordCheck",
-#if defined(OS_ANDROID) || defined(OS_IOS)
- base::FEATURE_DISABLED_BY_DEFAULT
-#else
- base::FEATURE_ENABLED_BY_DEFAULT
-#endif
-};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Controls the ability to import passwords from Chrome's settings page.
const base::Feature kPasswordImport = {"PasswordImport",
@@ -90,13 +84,32 @@ const base::Feature kPasswordsWeaknessCheck = {
const base::Feature kRecoverFromNeverSaveAndroid = {
"RecoverFromNeverSaveAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables reparsing server predictions once the password form manager notices a
+// dynamic form change.
+const base::Feature kReparseServerPredictionsFollowingFormChange = {
+ "ReparseServerPredictionsFollowingFormChange",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables considering secondary server field predictions during form parsing.
+const base::Feature kSecondaryServerFieldPredictions = {
+ "SecondaryServerFieldPredictions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Treat heuritistics to find new password fields as reliable. This enables
+// password generation on more forms, but could lead to false positives.
+const base::Feature kTreatNewPasswordHeuristicsAsReliable = {
+ "TreatNewPasswordHeuristicsAsReliable", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables use of Hash Affiliation fetcher for all requests.
+const base::Feature kUseOfHashAffiliationFetcher = {
+ "UseOfHashAffiliationFetcher", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables support of filling and saving on username first flow.
const base::Feature kUsernameFirstFlow = {"UsernameFirstFlow",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enable support for .well-known/change-password URLs.
const base::Feature kWellKnownChangePassword = {
- "WellKnownChangePassword", base::FEATURE_DISABLED_BY_DEFAULT};
+ "WellKnownChangePassword", base::FEATURE_ENABLED_BY_DEFAULT};
// Field trial identifier for password generation requirements.
const char kGenerationRequirementsFieldTrial[] =
diff --git a/chromium/components/password_manager/core/common/password_manager_features.h b/chromium/components/password_manager/core/common/password_manager_features.h
index 3a3d401aab9..d1522bb515b 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.h
+++ b/chromium/components/password_manager/core/common/password_manager_features.h
@@ -19,8 +19,8 @@ namespace features {
extern const base::Feature kBiometricTouchToFill;
extern const base::Feature kChangePasswordAffiliationInfo;
-extern const base::Feature kCompromisedPasswordsReengagement;
extern const base::Feature kEditPasswordsInSettings;
+extern const base::Feature kDetectFormSubmissionOnFormClear;
extern const base::Feature kEnableOverwritingPlaceholderUsernames;
extern const base::Feature kEnablePasswordsAccountStorage;
extern const base::Feature KEnablePasswordGenerationForClearTextFields;
@@ -33,6 +33,10 @@ extern const base::Feature kPasswordImport;
extern const base::Feature kPasswordScriptsFetching;
extern const base::Feature kPasswordsWeaknessCheck;
extern const base::Feature kRecoverFromNeverSaveAndroid;
+extern const base::Feature kReparseServerPredictionsFollowingFormChange;
+extern const base::Feature kSecondaryServerFieldPredictions;
+extern const base::Feature kTreatNewPasswordHeuristicsAsReliable;
+extern const base::Feature kUseOfHashAffiliationFetcher;
extern const base::Feature kUsernameFirstFlow;
extern const base::Feature kWellKnownChangePassword;
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.cc b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
index 9c17479240d..1490998a239 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
@@ -11,10 +11,6 @@ namespace prefs {
const char kCredentialsEnableAutosignin[] = "credentials_enable_autosignin";
const char kCredentialsEnableService[] = "credentials_enable_service";
-#if !defined(OS_APPLE) && !defined(OS_CHROMEOS) && defined(OS_POSIX)
-const char kMigrationToLoginDBStep[] = "profile.migration_to_logindb_step";
-#endif
-
#if defined(OS_WIN)
const char kOsPasswordBlank[] = "password_manager.os_password_blank";
const char kOsPasswordLastChanged[] =
@@ -64,8 +60,5 @@ const char kProfileStoreDateLastUsedForFilling[] =
const char kAccountStoreDateLastUsedForFilling[] =
"password_manager.account_store_date_last_used_for_filling";
-const char kSettingsLaunchedPasswordChecks[] =
- "profile.settings_launched_password_checks";
-
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.h b/chromium/components/password_manager/core/common/password_manager_pref_names.h
index 28897b5c2e4..0d281f8d959 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.h
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.h
@@ -24,11 +24,6 @@ extern const char kCredentialsEnableAutosignin[];
// passwords.
extern const char kCredentialsEnableService[];
-#if !defined(OS_APPLE) && !defined(OS_CHROMEOS) && defined(OS_POSIX)
-// The current state of the migration to LoginDB from Keyring/Kwallet on Linux.
-extern const char kMigrationToLoginDBStep[];
-#endif
-
#if defined(OS_WIN)
// Whether the password was blank, only valid if OS password was last changed
// on or before the value contained in kOsPasswordLastChanged.
@@ -100,10 +95,6 @@ extern const char kPasswordLeakDetectionEnabled[];
extern const char kProfileStoreDateLastUsedForFilling[];
extern const char kAccountStoreDateLastUsedForFilling[];
-// Number of times the check for leaked password has been performed from the
-// password settings.
-extern const char kSettingsLaunchedPasswordChecks[];
-
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/ios/js_password_manager.mm b/chromium/components/password_manager/ios/js_password_manager.mm
index f74a8444c7e..0cac3846486 100644
--- a/chromium/components/password_manager/ios/js_password_manager.mm
+++ b/chromium/components/password_manager/ios/js_password_manager.mm
@@ -23,6 +23,16 @@ using autofill::FieldRendererId;
using autofill::kNotSetRendererID;
using base::SysNSStringToUTF8;
+// Converts FormRendererId to int value that can be used in Javascript methods.
+int FormRendererIdToJsParameter(FormRendererId formID) {
+ return formID ? formID.value() : kNotSetRendererID;
+}
+
+// Converts FieldRendererId to int value that can be used in Javascript methods.
+int FieldRendererIdToJsParameter(FieldRendererId fieldID) {
+ return fieldID ? fieldID.value() : kNotSetRendererID;
+}
+
namespace password_manager {
std::unique_ptr<base::Value> SerializeFillData(
@@ -34,14 +44,14 @@ std::unique_ptr<base::Value> SerializeFillData(
const base::string16& password_value) {
auto rootDict = std::make_unique<base::DictionaryValue>();
rootDict->SetString("origin", origin.spec());
- rootDict->SetInteger("unique_renderer_id", form_renderer_id.value());
+ rootDict->SetInteger("unique_renderer_id",
+ FormRendererIdToJsParameter(form_renderer_id));
auto fieldList = std::make_unique<base::ListValue>();
auto usernameField = std::make_unique<base::DictionaryValue>();
- usernameField->SetInteger("unique_renderer_id", username_element
- ? username_element.value()
- : kNotSetRendererID);
+ usernameField->SetInteger("unique_renderer_id",
+ FieldRendererIdToJsParameter(username_element));
usernameField->SetString("value", username_value);
fieldList->Append(std::move(usernameField));
@@ -119,9 +129,10 @@ std::unique_ptr<base::Value> SerializeFillData(
completionHandler:(void (^)(BOOL))completionHandler {
DCHECK(completionHandler);
std::vector<base::Value> parameters;
- parameters.emplace_back(static_cast<int>(formIdentifier.value()));
- parameters.emplace_back(static_cast<int>(newPasswordIdentifier.value()));
- parameters.emplace_back(static_cast<int>(confirmPasswordIdentifier.value()));
+ parameters.emplace_back(FormRendererIdToJsParameter(formIdentifier));
+ parameters.emplace_back(FieldRendererIdToJsParameter(newPasswordIdentifier));
+ parameters.emplace_back(
+ FieldRendererIdToJsParameter(confirmPasswordIdentifier));
parameters.push_back(base::Value(SysNSStringToUTF8(generatedPassword)));
autofill::ExecuteJavaScriptFunction(
"passwords.fillPasswordFormWithGeneratedPassword", parameters, frame,
diff --git a/chromium/components/password_manager/ios/password_form_helper.mm b/chromium/components/password_manager/ios/password_form_helper.mm
index 8ee85f59259..35a098f05ee 100644
--- a/chromium/components/password_manager/ios/password_form_helper.mm
+++ b/chromium/components/password_manager/ios/password_form_helper.mm
@@ -63,9 +63,9 @@ constexpr char kCommandPrefix[] = "passwordForm";
// Parses the |jsonString| which contatins the password forms found on a web
// page to populate the |forms| vector.
-- (void)getPasswordFormsFromJSON:(NSString*)jsonString
- pageURL:(const GURL&)pageURL
- forms:(std::vector<FormData>*)forms;
+- (void)getPasswordForms:(std::vector<FormData>*)forms
+ fromJSON:(NSString*)jsonString
+ pageURL:(const GURL&)pageURL;
@end
@@ -228,11 +228,11 @@ constexpr char kCommandPrefix[] = "passwordForm";
return NO;
}
-- (void)getPasswordFormsFromJSON:(NSString*)jsonString
- pageURL:(const GURL&)pageURL
- forms:(std::vector<FormData>*)forms {
+- (void)getPasswordForms:(std::vector<FormData>*)forms
+ fromJSON:(NSString*)JSONString
+ pageURL:(const GURL&)pageURL {
std::vector<FormData> formsData;
- if (!autofill::ExtractFormsData(jsonString, false, base::string16(), pageURL,
+ if (!autofill::ExtractFormsData(JSONString, false, base::string16(), pageURL,
pageURL.GetOrigin(), &formsData)) {
return;
}
@@ -276,11 +276,11 @@ constexpr char kCommandPrefix[] = "passwordForm";
__weak PasswordFormHelper* weakSelf = self;
[self.jsPasswordManager
findPasswordFormsInFrame:GetMainFrame(_webState)
- completionHandler:^(NSString* jsonString) {
+ completionHandler:^(NSString* JSONString) {
std::vector<FormData> forms;
- [weakSelf getPasswordFormsFromJSON:jsonString
- pageURL:pageURL
- forms:&forms];
+ [weakSelf getPasswordForms:&forms
+ fromJSON:JSONString
+ pageURL:pageURL];
// Find the maximum extracted value.
uint32_t maxID = 0;
for (const auto& form : forms) {
diff --git a/chromium/components/password_manager/ios/password_form_helper_unittest.mm b/chromium/components/password_manager/ios/password_form_helper_unittest.mm
index 956f721d368..c52f823f448 100644
--- a/chromium/components/password_manager/ios/password_form_helper_unittest.mm
+++ b/chromium/components/password_manager/ios/password_form_helper_unittest.mm
@@ -32,7 +32,6 @@ NS_ASSUME_NONNULL_BEGIN
using autofill::FieldRendererId;
using autofill::FormData;
using autofill::FormRendererId;
-using autofill::PasswordForm;
using autofill::PasswordFormFillData;
using base::test::ios::kWaitForJSCompletionTimeout;
using base::test::ios::WaitUntilConditionOrTimeout;
diff --git a/chromium/components/password_manager/ios/password_suggestion_helper.h b/chromium/components/password_manager/ios/password_suggestion_helper.h
index 47d8a88e4a3..623dc3573e0 100644
--- a/chromium/components/password_manager/ios/password_suggestion_helper.h
+++ b/chromium/components/password_manager/ios/password_suggestion_helper.h
@@ -72,7 +72,7 @@ class WebState;
// Retrieves password form fill data for |username| for use in
// |PasswordFormHelper|'s
// -fillPasswordFormWithFillData:completionHandler:.
-- (std::unique_ptr<password_manager::FillData>)getFillDataForUsername:
+- (std::unique_ptr<password_manager::FillData>)passwordFillDataForUsername:
(NSString*)username;
// The following methods should be called to maintain the correct state along
diff --git a/chromium/components/password_manager/ios/password_suggestion_helper.mm b/chromium/components/password_manager/ios/password_suggestion_helper.mm
index 75a9dcc969c..f4a70120f46 100644
--- a/chromium/components/password_manager/ios/password_suggestion_helper.mm
+++ b/chromium/components/password_manager/ios/password_suggestion_helper.mm
@@ -130,7 +130,7 @@ typedef void (^PasswordSuggestionsAvailableCompletion)(
formQuery.uniqueFormID, formQuery.uniqueFieldID, isPasswordField));
}
-- (std::unique_ptr<password_manager::FillData>)getFillDataForUsername:
+- (std::unique_ptr<password_manager::FillData>)passwordFillDataForUsername:
(NSString*)username {
return _fillData.GetFillData(SysNSStringToUTF16(username));
}
diff --git a/chromium/components/password_manager/ios/resources/password_controller.js b/chromium/components/password_manager/ios/resources/password_controller.js
index d31771f0e9e..c14ff98e2f4 100644
--- a/chromium/components/password_manager/ios/resources/password_controller.js
+++ b/chromium/components/password_manager/ios/resources/password_controller.js
@@ -225,11 +225,15 @@ __gCrWeb.passwords['fillPasswordForm'] = function(
__gCrWeb.passwords['fillPasswordFormWithGeneratedPassword'] = function(
formIdentifier, newPasswordIdentifier, confirmPasswordIdentifier,
password) {
+ const hasFormTag =
+ formIdentifier.toString() !== __gCrWeb.fill.RENDERER_ID_NOT_SET;
const form = __gCrWeb.form.getFormElementFromUniqueFormId(formIdentifier);
- if (!form) {
+ if (!form && hasFormTag) {
return false;
}
- const inputs = getFormInputElements(form);
+ const inputs = hasFormTag ?
+ getFormInputElements(form) :
+ __gCrWeb.fill.getUnownedAutofillableFormFieldElements(document.all, []);
const newPasswordField =
findInputByUniqueFieldId(inputs, newPasswordIdentifier);
if (!newPasswordField) {
diff --git a/chromium/components/password_manager/ios/shared_password_controller.mm b/chromium/components/password_manager/ios/shared_password_controller.mm
index d973e40f282..bbdd9ae9ce0 100644
--- a/chromium/components/password_manager/ios/shared_password_controller.mm
+++ b/chromium/components/password_manager/ios/shared_password_controller.mm
@@ -22,7 +22,6 @@
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_data.h"
-#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/autofill/core/common/renderer_id.h"
@@ -56,7 +55,6 @@
using autofill::FormActivityObserverBridge;
using autofill::FormData;
using autofill::PasswordFormGenerationData;
-using autofill::PasswordForm;
using autofill::FormRendererId;
using autofill::FieldRendererId;
using base::SysNSStringToUTF16;
@@ -404,7 +402,7 @@ NSString* const kSuggestionSuffix = @" ••••••••";
NSString* username = [suggestion.value
substringToIndex:suggestion.value.length - kSuggestionSuffix.length];
std::unique_ptr<password_manager::FillData> fillData =
- [self.suggestionHelper getFillDataForUsername:username];
+ [self.suggestionHelper passwordFillDataForUsername:username];
if (!fillData) {
completion();
@@ -526,7 +524,7 @@ NSString* const kSuggestionSuffix = @" ••••••••";
if (![fieldType isEqual:kPasswordFieldType])
return NO;
const PasswordFormGenerationData* generation_data =
- [self getFormForGenerationFromFormId:formIdentifier];
+ [self formForGenerationFromFormID:formIdentifier];
if (!generation_data)
return NO;
@@ -539,7 +537,7 @@ NSString* const kSuggestionSuffix = @" ••••••••";
return NO;
}
-- (const PasswordFormGenerationData*)getFormForGenerationFromFormId:
+- (const PasswordFormGenerationData*)formForGenerationFromFormID:
(FormRendererId)formIdentifier {
if (_formGenerationData.find(formIdentifier) != _formGenerationData.end()) {
return &_formGenerationData[formIdentifier];
@@ -549,7 +547,7 @@ NSString* const kSuggestionSuffix = @" ••••••••";
- (void)generatePasswordForFormId:(FormRendererId)formIdentifier
fieldIdentifier:(FieldRendererId)fieldIdentifier {
- if (![self getFormForGenerationFromFormId:formIdentifier])
+ if (![self formForGenerationFromFormID:formIdentifier])
return;
// TODO(crbug.com/886583): pass correct |max_length|.
@@ -586,7 +584,7 @@ NSString* const kSuggestionSuffix = @" ••••••••";
generatedPassword:(NSString*)generatedPassword
completionHandler:(void (^)())completionHandler {
const autofill::PasswordFormGenerationData* generation_data =
- [self getFormForGenerationFromFormId:formIdentifier];
+ [self formForGenerationFromFormID:formIdentifier];
if (!generation_data)
return;
FieldRendererId newPasswordUniqueId =
diff --git a/chromium/components/password_manager/ios/shared_password_controller_unittest.mm b/chromium/components/password_manager/ios/shared_password_controller_unittest.mm
index f8c552c6503..65622a36b9b 100644
--- a/chromium/components/password_manager/ios/shared_password_controller_unittest.mm
+++ b/chromium/components/password_manager/ios/shared_password_controller_unittest.mm
@@ -315,9 +315,9 @@ TEST_F(SharedPasswordControllerTest,
IsGenerationEnabled)
.WillOnce(Return(true));
- autofill::PasswordFormGenerationData form_generation_data(
+ autofill::PasswordFormGenerationData form_generation_data = {
form_query.uniqueFormID, form_query.uniqueFieldID,
- form_query.uniqueFieldID);
+ form_query.uniqueFieldID};
[controller_ formEligibleForGenerationFound:form_generation_data];
__block BOOL completion_was_called = NO;
[controller_
@@ -340,8 +340,8 @@ TEST_F(SharedPasswordControllerTest,
TEST_F(SharedPasswordControllerTest, SuggestsGeneratedPassword) {
autofill::FormRendererId form_id(0);
autofill::FieldRendererId field_id(1);
- autofill::PasswordFormGenerationData form_generation_data(form_id, field_id,
- field_id);
+ autofill::PasswordFormGenerationData form_generation_data = {
+ form_id, field_id, field_id};
[controller_ formEligibleForGenerationFound:form_generation_data];
FormSuggestion* suggestion = [FormSuggestion
@@ -370,8 +370,8 @@ TEST_F(SharedPasswordControllerTest, SuggestsGeneratedPassword) {
TEST_F(SharedPasswordControllerTest, PresavesGeneratedPassword) {
autofill::FormRendererId form_id(0);
autofill::FieldRendererId field_id(1);
- autofill::PasswordFormGenerationData form_generation_data(form_id, field_id,
- field_id);
+ autofill::PasswordFormGenerationData form_generation_data = {
+ form_id, field_id, field_id};
[controller_ formEligibleForGenerationFound:form_generation_data];
FormSuggestion* suggestion = [FormSuggestion
diff --git a/chromium/components/payments/content/BUILD.gn b/chromium/components/payments/content/BUILD.gn
index 16c9e56ab38..e00eea81364 100644
--- a/chromium/components/payments/content/BUILD.gn
+++ b/chromium/components/payments/content/BUILD.gn
@@ -75,6 +75,7 @@ static_library("content") {
sources += [ "android_app_communication_chrome_os.cc" ]
deps += [
+ "//ash/public/cpp/external_arc:external_arc",
"//components/arc",
"//components/arc/mojom",
]
@@ -220,6 +221,7 @@ source_set("unit_tests") {
sources += [ "android_app_communication_test_support_chrome_os.cc" ]
deps += [
+ "//ash/public/cpp/external_arc:external_arc",
"//components/arc",
"//components/arc:arc_test_support",
"//components/arc/mojom",
diff --git a/chromium/components/payments/content/DEPS b/chromium/components/payments/content/DEPS
index 8af26fdc0b7..64211f61578 100644
--- a/chromium/components/payments/content/DEPS
+++ b/chromium/components/payments/content/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"-components/payments/content/android",
+ "+ash/public/cpp/external_arc/overlay",
"+components/arc",
"+components/autofill",
"+components/keyed_service/content",
diff --git a/chromium/components/payments/content/android/BUILD.gn b/chromium/components/payments/content/android/BUILD.gn
index 8b86d58b378..87a9cfc519f 100644
--- a/chromium/components/payments/content/android/BUILD.gn
+++ b/chromium/components/payments/content/android/BUILD.gn
@@ -17,6 +17,8 @@ static_library("android") {
"error_message_util.cc",
"jni_payment_app.cc",
"jni_payment_app.h",
+ "journey_logger_android.cc",
+ "journey_logger_android.h",
"origin_security_checker_android.cc",
"payment_feature_list.cc",
"payment_feature_list.h",
@@ -41,6 +43,7 @@ static_library("android") {
"//components/payments/content:utils",
"//components/payments/content/utility",
"//components/payments/core",
+ "//components/ukm/content:content",
"//content/public/browser",
"//net",
"//url:gurl_android",
@@ -60,11 +63,9 @@ generate_jni("jni_headers") {
"java/src/org/chromium/components/payments/PaymentHandlerHost.java",
"java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
"java/src/org/chromium/components/payments/PaymentManifestParser.java",
- "java/src/org/chromium/components/payments/PaymentManifestWebDataService.java",
"java/src/org/chromium/components/payments/PaymentRequestSpec.java",
"java/src/org/chromium/components/payments/PaymentRequestUpdateEventListener.java",
"java/src/org/chromium/components/payments/PaymentValidator.java",
- "java/src/org/chromium/components/payments/SslValidityChecker.java",
"java/src/org/chromium/components/payments/UrlUtil.java",
]
}
@@ -73,53 +74,79 @@ android_resources("java_resources") {
sources = payments_java_resources
}
-android_library("java") {
+# Minimal target to depend on PaymentDetailsUpdateService. This should be kept
+# as small as possible, as it will always be included in chrome's base module.
+android_library("service_java") {
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
sources = [
"java/src/org/chromium/components/payments/Address.java",
+ "java/src/org/chromium/components/payments/PackageManagerDelegate.java",
+ "java/src/org/chromium/components/payments/PayerData.java",
+ "java/src/org/chromium/components/payments/PaymentAddressTypeConverter.java",
+ "java/src/org/chromium/components/payments/PaymentDetailsUpdateService.java",
+ "java/src/org/chromium/components/payments/PaymentDetailsUpdateServiceHelper.java",
+ "java/src/org/chromium/components/payments/PaymentFeatureList.java",
+ "java/src/org/chromium/components/payments/PaymentRequestUpdateEventListener.java",
+ "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java",
+ "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java",
+ ]
+ deps = [
+ "//base:base_java",
+ "//base:jni_java",
+ "//components/payments/mojom:mojom_java",
+ "//content/public/android:content_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ ]
+ srcjar_deps = [
+ ":error_strings_generated_srcjar",
+ ":payment_details_update_service_aidl",
+ ]
+}
+
+# TODO(crbug.com/1126301): Rename this back to "java" once references in //clank
+# are updated.
+android_library("all_java") {
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ sources = [
"java/src/org/chromium/components/payments/BasicCardUtils.java",
"java/src/org/chromium/components/payments/BrowserPaymentRequest.java",
"java/src/org/chromium/components/payments/CanMakePaymentQuery.java",
- "java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java",
"java/src/org/chromium/components/payments/CurrencyFormatter.java",
"java/src/org/chromium/components/payments/ErrorMessageUtil.java",
+ "java/src/org/chromium/components/payments/InvalidPaymentRequest.java",
"java/src/org/chromium/components/payments/JniPaymentApp.java",
"java/src/org/chromium/components/payments/JourneyLogger.java",
"java/src/org/chromium/components/payments/MojoPaymentRequestGateKeeper.java",
"java/src/org/chromium/components/payments/MojoStructCollection.java",
"java/src/org/chromium/components/payments/OriginSecurityChecker.java",
- "java/src/org/chromium/components/payments/PackageManagerDelegate.java",
- "java/src/org/chromium/components/payments/PayerData.java",
- "java/src/org/chromium/components/payments/PaymentAddressTypeConverter.java",
"java/src/org/chromium/components/payments/PaymentApp.java",
+ "java/src/org/chromium/components/payments/PaymentAppFactoryDelegate.java",
+ "java/src/org/chromium/components/payments/PaymentAppFactoryInterface.java",
"java/src/org/chromium/components/payments/PaymentAppFactoryParams.java",
+ "java/src/org/chromium/components/payments/PaymentAppService.java",
"java/src/org/chromium/components/payments/PaymentDetailsConverter.java",
- "java/src/org/chromium/components/payments/PaymentDetailsUpdateService.java",
- "java/src/org/chromium/components/payments/PaymentDetailsUpdateServiceHelper.java",
- "java/src/org/chromium/components/payments/PaymentFeatureList.java",
"java/src/org/chromium/components/payments/PaymentHandlerHost.java",
"java/src/org/chromium/components/payments/PaymentManifestDownloader.java",
"java/src/org/chromium/components/payments/PaymentManifestParser.java",
- "java/src/org/chromium/components/payments/PaymentManifestWebDataService.java",
"java/src/org/chromium/components/payments/PaymentOptionsUtils.java",
- "java/src/org/chromium/components/payments/PaymentRequestLifecycleObserver.java",
"java/src/org/chromium/components/payments/PaymentRequestParams.java",
+ "java/src/org/chromium/components/payments/PaymentRequestService.java",
+ "java/src/org/chromium/components/payments/PaymentRequestServiceUtil.java",
"java/src/org/chromium/components/payments/PaymentRequestSpec.java",
- "java/src/org/chromium/components/payments/PaymentRequestUpdateEventListener.java",
+ "java/src/org/chromium/components/payments/PaymentResponseHelperInterface.java",
"java/src/org/chromium/components/payments/PaymentUIsObserver.java",
+ "java/src/org/chromium/components/payments/PaymentUiServiceTestInterface.java",
"java/src/org/chromium/components/payments/PaymentValidator.java",
"java/src/org/chromium/components/payments/SkipToGPayHelper.java",
- "java/src/org/chromium/components/payments/SslValidityChecker.java",
"java/src/org/chromium/components/payments/SupportedDelegations.java",
"java/src/org/chromium/components/payments/UrlUtil.java",
"java/src/org/chromium/components/payments/WebAppManifestSection.java",
"java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java",
- "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java",
- "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java",
"java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperTypeConverter.java",
]
deps = [
":java_resources",
+ ":service_java",
"//base:base_java",
"//base:jni_java",
"//components/autofill/android:autofill_java",
@@ -129,6 +156,7 @@ android_library("java") {
"//content/public/android:content_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
+ "//services/service_manager/public/java:service_manager_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_deps:androidx_collection_collection_java",
"//third_party/blink/public/mojom:android_mojo_bindings_java",
@@ -136,15 +164,21 @@ android_library("java") {
"//url:origin_java",
]
srcjar_deps = [
- ":error_strings_generated_srcjar",
":method_strings_generated_srcjar",
":payment_app_type_generated_enum",
- ":payment_details_update_service_aidl",
":payments_journey_logger_enum_javagen",
+ ":prefs_strings_generated_srcjar",
]
resources_package = "org.chromium.components.payments"
}
+java_group("java") {
+ deps = [
+ ":all_java",
+ ":service_java",
+ ]
+}
+
android_aidl("payment_details_update_service_aidl") {
interface_file = "java/src/org/chromium/components/payments/payment_details_update_service.aidl"
sources = [
@@ -165,6 +199,12 @@ java_cpp_strings("method_strings_generated_srcjar") {
template = "java_templates/MethodStrings.java.tmpl"
}
+java_cpp_strings("prefs_strings_generated_srcjar") {
+ sources = [ "//components/payments/core/payment_prefs.cc" ]
+
+ template = "java_templates/PrefsStrings.java.tmpl"
+}
+
java_cpp_enum("payment_app_type_generated_enum") {
sources = [ "//components/payments/content/payment_app.h" ]
}
diff --git a/chromium/components/payments/content/android/currency_formatter_android.cc b/chromium/components/payments/content/android/currency_formatter_android.cc
index 4572f0c87cd..e0e2201ae02 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.cc
+++ b/chromium/components/payments/content/android/currency_formatter_android.cc
@@ -34,6 +34,12 @@ void CurrencyFormatterAndroid::Destroy(JNIEnv* env,
delete this;
}
+void CurrencyFormatterAndroid::SetMaxFractionalDigits(
+ JNIEnv* env,
+ jint jmax_fractional_digits) {
+ currency_formatter_->SetMaxFractionalDigits(jmax_fractional_digits);
+}
+
base::android::ScopedJavaLocalRef<jstring> CurrencyFormatterAndroid::Format(
JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
diff --git a/chromium/components/payments/content/android/currency_formatter_android.h b/chromium/components/payments/content/android/currency_formatter_android.h
index 76b1577d604..1fe5173e144 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.h
+++ b/chromium/components/payments/content/android/currency_formatter_android.h
@@ -29,6 +29,9 @@ class CurrencyFormatterAndroid {
void Destroy(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller);
+ // Set the maximum number of fractional digits.
+ void SetMaxFractionalDigits(JNIEnv* env, jint jnum_fractional_digits);
+
// Refer to CurrencyFormatter::Format documentation.
base::android::ScopedJavaLocalRef<jstring> Format(
JNIEnv* env,
diff --git a/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl b/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
index ec12dd4e1b0..5e9409ebf07 100644
--- a/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
+++ b/chromium/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
@@ -57,7 +57,12 @@ public abstract class ErrorStrings {{
public static final String MINIMAL_UI_SUPPRESSED = "Payment minimal UI suppressed.";
public static final String UNATHORIZED_SERVICE_REQUEST =
- "Caller's signuature or package name does not match invoked app's.";
+ "Caller's signature or package name does not match invoked app's.";
+
+ public static final String FAIL_TO_SHOW_PAYMENT_REQUEST_UI =
+ "Fails to show payment request UI. Please try again.";
+
+ public static final String NO_FRAME = "The frame that initiated payment is gone.";
// Prevent instantiation.
private ErrorStrings() {{}}
diff --git a/chromium/components/payments/content/android/java_templates/PrefsStrings.java.tmpl b/chromium/components/payments/content/android/java_templates/PrefsStrings.java.tmpl
new file mode 100644
index 00000000000..f990161bab2
--- /dev/null
+++ b/chromium/components/payments/content/android/java_templates/PrefsStrings.java.tmpl
@@ -0,0 +1,17 @@
+// Copyright 2020 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.
+
+// This file is autogenerated by
+// //components/payments/content/android/BUILD.gn
+
+package org.chromium.components.payments;
+
+/** Payment profile prefs strings. */
+public abstract class PrefsStrings {{
+
+{NATIVE_STRINGS}
+
+ // Prevent instantiation.
+ private PrefsStrings() {{}}
+}}
diff --git a/chromium/components/payments/content/android/jni_payment_app.cc b/chromium/components/payments/content/android/jni_payment_app.cc
index 621eacc557c..a96236c08a6 100644
--- a/chromium/components/payments/content/android/jni_payment_app.cc
+++ b/chromium/components/payments/content/android/jni_payment_app.cc
@@ -48,7 +48,7 @@ ScopedJavaLocalRef<jobject> JniPaymentApp::Create(
ScopedJavaLocalRef<jobject> icon;
if (app->payment_app_->icon_bitmap() &&
!app->payment_app_->icon_bitmap()->drawsNothing()) {
- icon = gfx::ConvertToJavaBitmap(app->payment_app_->icon_bitmap());
+ icon = gfx::ConvertToJavaBitmap(*app->payment_app_->icon_bitmap());
}
return Java_JniPaymentApp_Constructor(
@@ -111,7 +111,7 @@ ScopedJavaLocalRef<jstring> JniPaymentApp::GetCountryCode(JNIEnv* env) {
}
bool JniPaymentApp::CanMakePayment(JNIEnv* env) {
- // PaymentRequestImpl.java uses this value to determine whether
+ // ChromePaymentRequestService.java uses this value to determine whether
// PaymentRequest.hasEnrolledInstrument() should return true.
return payment_app_->HasEnrolledInstrument();
}
diff --git a/chromium/components/payments/content/android/journey_logger_android.cc b/chromium/components/payments/content/android/journey_logger_android.cc
new file mode 100644
index 00000000000..71337ee4361
--- /dev/null
+++ b/chromium/components/payments/content/android/journey_logger_android.cc
@@ -0,0 +1,162 @@
+// 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.
+
+#include "components/payments/content/android/journey_logger_android.h"
+
+#include "base/android/jni_string.h"
+#include "components/payments/content/android/jni_headers/JourneyLogger_jni.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "content/public/browser/web_contents.h"
+
+namespace payments {
+namespace {
+
+using ::base::android::ConvertJavaStringToUTF8;
+using ::base::android::JavaParamRef;
+
+} // namespace
+
+JourneyLoggerAndroid::JourneyLoggerAndroid(bool is_incognito,
+ ukm::SourceId source_id)
+ : journey_logger_(is_incognito, source_id) {}
+
+JourneyLoggerAndroid::~JourneyLoggerAndroid() {}
+
+void JourneyLoggerAndroid::Destroy(JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller) {
+ delete this;
+}
+
+void JourneyLoggerAndroid::SetNumberOfSuggestionsShown(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jsection,
+ jint jnumber,
+ jboolean jhas_complete_suggestion) {
+ DCHECK_GE(jsection, 0);
+ DCHECK_LT(jsection, JourneyLogger::Section::SECTION_MAX);
+ journey_logger_.SetNumberOfSuggestionsShown(
+ static_cast<JourneyLogger::Section>(jsection), jnumber,
+ jhas_complete_suggestion);
+}
+
+void JourneyLoggerAndroid::SetCanMakePaymentValue(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean jvalue) {
+ journey_logger_.SetCanMakePaymentValue(jvalue);
+}
+
+void JourneyLoggerAndroid::SetHasEnrolledInstrumentValue(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean jvalue) {
+ journey_logger_.SetHasEnrolledInstrumentValue(jvalue);
+}
+
+void JourneyLoggerAndroid::SetEventOccurred(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jevent) {
+ DCHECK_GE(jevent, 0);
+ DCHECK_LE(static_cast<unsigned int>(jevent),
+ static_cast<unsigned int>(JourneyLogger::Event::EVENT_ENUM_MAX));
+ journey_logger_.SetEventOccurred(static_cast<JourneyLogger::Event>(jevent));
+}
+
+void JourneyLoggerAndroid::SetRequestedInformation(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean requested_shipping,
+ jboolean requested_email,
+ jboolean requested_phone,
+ jboolean requested_name) {
+ journey_logger_.SetRequestedInformation(requested_shipping, requested_email,
+ requested_phone, requested_name);
+}
+
+void JourneyLoggerAndroid::SetRequestedPaymentMethodTypes(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean requested_basic_card,
+ jboolean requested_method_google,
+ jboolean requested_method_other) {
+ // TODO(crbug.com/1110320) : secure=payment-confirmation payment method is not
+ // implemented on Android yet.
+ journey_logger_.SetRequestedPaymentMethodTypes(
+ requested_basic_card, requested_method_google,
+ /*requested_method_secure_payment_confirmation=*/false,
+ requested_method_other);
+}
+
+void JourneyLoggerAndroid::SetCompleted(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller) {
+ journey_logger_.SetCompleted();
+}
+
+void JourneyLoggerAndroid::SetAborted(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jreason) {
+ DCHECK_GE(jreason, 0);
+ DCHECK_LT(jreason, JourneyLogger::AbortReason::ABORT_REASON_MAX);
+ journey_logger_.SetAborted(static_cast<JourneyLogger::AbortReason>(jreason));
+}
+
+void JourneyLoggerAndroid::SetNotShown(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jreason) {
+ DCHECK_GE(jreason, 0);
+ DCHECK_LT(jreason, JourneyLogger::NotShownReason::NOT_SHOWN_REASON_MAX);
+ journey_logger_.SetNotShown(
+ static_cast<JourneyLogger::NotShownReason>(jreason));
+}
+
+void JourneyLoggerAndroid::RecordTransactionAmount(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcurrency,
+ const base::android::JavaParamRef<jstring>& jvalue,
+ jboolean jcompleted) {
+ journey_logger_.RecordTransactionAmount(
+ ConvertJavaStringToUTF8(env, jcurrency),
+ ConvertJavaStringToUTF8(env, jvalue), jcompleted);
+}
+
+void JourneyLoggerAndroid::RecordCheckoutStep(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jstep) {
+ journey_logger_.RecordCheckoutStep(
+ static_cast<JourneyLogger::CheckoutFunnelStep>(jstep));
+}
+
+void JourneyLoggerAndroid::SetTriggerTime(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller) {
+ journey_logger_.SetTriggerTime();
+}
+
+void JourneyLoggerAndroid::SetPaymentAppUkmSourceId(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ ukm::SourceId source_id) {
+ journey_logger_.SetPaymentAppUkmSourceId(source_id);
+}
+
+static jlong JNI_JourneyLogger_InitJourneyLoggerAndroid(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ jboolean jis_incognito,
+ const JavaParamRef<jobject>& jweb_contents) {
+ content::WebContents* web_contents =
+ content::WebContents::FromJavaWebContents(jweb_contents);
+ DCHECK(web_contents); // Verified in Java before invoking this function.
+ return reinterpret_cast<jlong>(new JourneyLoggerAndroid(
+ jis_incognito, ukm::GetSourceIdForWebContentsDocument(web_contents)));
+}
+
+} // namespace payments
diff --git a/chromium/components/payments/content/android/journey_logger_android.h b/chromium/components/payments/content/android/journey_logger_android.h
new file mode 100644
index 00000000000..dd7bf9cc1af
--- /dev/null
+++ b/chromium/components/payments/content/android/journey_logger_android.h
@@ -0,0 +1,87 @@
+// 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.
+
+#ifndef COMPONENTS_PAYMENTS_CONTENT_ANDROID_JOURNEY_LOGGER_ANDROID_H_
+#define COMPONENTS_PAYMENTS_CONTENT_ANDROID_JOURNEY_LOGGER_ANDROID_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "components/payments/core/journey_logger.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+
+namespace payments {
+
+// Forwarding calls to payments::JourneyLogger.
+class JourneyLoggerAndroid {
+ public:
+ JourneyLoggerAndroid(bool is_incognito, ukm::SourceId source_id);
+ ~JourneyLoggerAndroid();
+
+ // Message from Java to destroy this object.
+ void Destroy(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
+
+ void SetNumberOfSuggestionsShown(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jsection,
+ jint jnumber,
+ jboolean jhas_complete_suggestion);
+ void SetCanMakePaymentValue(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean jvalue);
+ void SetHasEnrolledInstrumentValue(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean jvalue);
+ void SetEventOccurred(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jevent);
+ void SetRequestedInformation(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean requested_shipping,
+ jboolean requested_email,
+ jboolean requested_phone,
+ jboolean requested_name);
+ void SetRequestedPaymentMethodTypes(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jboolean requested_basic_card,
+ jboolean requested_method_google,
+ jboolean requested_method_other);
+ void SetCompleted(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
+ void SetAborted(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jreason);
+ void SetNotShown(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jreason);
+ void RecordTransactionAmount(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ const base::android::JavaParamRef<jstring>& jcurrency,
+ const base::android::JavaParamRef<jstring>& jvalue,
+ jboolean jcompleted);
+ void RecordCheckoutStep(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ jint jstep);
+ void SetTriggerTime(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller);
+ void SetPaymentAppUkmSourceId(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& jcaller,
+ ukm::SourceId source_id);
+
+ private:
+ JourneyLogger journey_logger_;
+
+ DISALLOW_COPY_AND_ASSIGN(JourneyLoggerAndroid);
+};
+
+} // namespace payments
+
+#endif // COMPONENTS_PAYMENTS_CONTENT_ANDROID_JOURNEY_LOGGER_ANDROID_H_
diff --git a/chromium/components/payments/content/android/payment_handler_host.h b/chromium/components/payments/content/android/payment_handler_host.h
index 186a2591d7e..cbfc04a36e1 100644
--- a/chromium/components/payments/content/android/payment_handler_host.h
+++ b/chromium/components/payments/content/android/payment_handler_host.h
@@ -19,7 +19,8 @@ namespace android {
// The native bridge for Java to interact with the payment handler host.
// Object relationship diagram:
//
-// PaymentRequestImpl.java --- implements ---> PaymentRequestUpdateEventListener
+// ChromePaymentRequestService.java --- implements --->
+// PaymentRequestUpdateEventListener
// | ^
// owns |________________________
// | |
diff --git a/chromium/components/payments/content/android/payment_request_spec.h b/chromium/components/payments/content/android/payment_request_spec.h
index a728ba192c7..6922b627e6e 100644
--- a/chromium/components/payments/content/android/payment_request_spec.h
+++ b/chromium/components/payments/content/android/payment_request_spec.h
@@ -18,7 +18,7 @@ namespace android {
//
// Object ownership diagram:
//
-// PaymentRequestImpl.java
+// ChromePaymentRequestService.java
// |
// v
// PaymentRequestSpec.java
diff --git a/chromium/components/payments/content/android/payments_java_resources.gni b/chromium/components/payments/content/android/payments_java_resources.gni
index 47a780d59c4..4d9a4a62eff 100644
--- a/chromium/components/payments/content/android/payments_java_resources.gni
+++ b/chromium/components/payments/content/android/payments_java_resources.gni
@@ -17,5 +17,8 @@ payments_java_resources = [
"//components/payments/content/android/java/res/layout/payment_request_spinny.xml",
"//components/payments/content/android/java/res/layout/payments_request_editor_textview.xml",
"//components/payments/content/android/java/res/values-sw600dp/dimens.xml",
+ "//components/payments/content/android/java/res/values/colors.xml",
"//components/payments/content/android/java/res/values/dimens.xml",
+ "//components/payments/content/android/java/res/values/ids.xml",
+ "//components/payments/content/android/java/res/values/styles.xml",
]
diff --git a/chromium/components/payments/content/android_app_communication.h b/chromium/components/payments/content/android_app_communication.h
index d4707c860bd..e85cee933f6 100644
--- a/chromium/components/payments/content/android_app_communication.h
+++ b/chromium/components/payments/content/android_app_communication.h
@@ -21,6 +21,7 @@ class GURL;
namespace content {
class BrowserContext;
+class WebContents;
} // namespace content
namespace payments {
@@ -81,6 +82,7 @@ class AndroidAppCommunication : public base::SupportsUserData::Data {
const GURL& top_level_origin,
const GURL& payment_request_origin,
const std::string& payment_request_id,
+ content::WebContents* web_contents,
InvokePaymentAppCallback callback) = 0;
// Allows usage of a test browser context.
diff --git a/chromium/components/payments/content/android_app_communication_chrome_os.cc b/chromium/components/payments/content/android_app_communication_chrome_os.cc
index 1012d35b2ed..6f2b561ce25 100644
--- a/chromium/components/payments/content/android_app_communication_chrome_os.cc
+++ b/chromium/components/payments/content/android_app_communication_chrome_os.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "ash/public/cpp/external_arc/overlay/arc_overlay_manager.h"
+#include "base/callback_helpers.h"
#include "components/arc/mojom/payment_app.mojom.h"
#include "components/arc/pay/arc_payment_app_bridge.h"
#include "components/payments/core/android_app_description.h"
@@ -13,6 +15,7 @@
#include "components/payments/core/method_strings.h"
#include "components/payments/core/native_error_strings.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
namespace payments {
@@ -100,8 +103,13 @@ void OnIsReadyToPay(AndroidAppCommunication::IsReadyToPayCallback callback,
void OnPaymentAppResponse(
AndroidAppCommunication::InvokePaymentAppCallback callback,
+ base::ScopedClosureRunner overlay_state,
arc::mojom::InvokePaymentAppResultPtr response) {
+ // Dismiss and prevent any further overlays
+ overlay_state.RunAndReset();
+
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
if (response.is_null()) {
std::move(callback).Run(errors::kEmptyResponse,
/*is_activity_result_ok=*/false,
@@ -271,9 +279,23 @@ class AndroidAppCommunicationChromeOS : public AndroidAppCommunication {
const GURL& top_level_origin,
const GURL& payment_request_origin,
const std::string& payment_request_id,
+ content::WebContents* web_contents,
InvokePaymentAppCallback callback) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Create and register a token with ArcOverlayManager for the
+ // browser window. Doing so is required to allow the Android Play Billing
+ // interface to be overlaid on top of the browser window.
+ // TODO(b/172592701): Use base::UnguessableToken::Create().ToString() and
+ // send the same value to the Android service.
+ std::string billing_token =
+ payment_request_origin.spec() + "#" + payment_request_id;
+ ash::ArcOverlayManager* const overlay_manager =
+ ash::ArcOverlayManager::instance();
+ base::ScopedClosureRunner overlay_state =
+ overlay_manager->RegisterHostWindow(std::move(billing_token),
+ web_contents->GetNativeView());
+
base::Optional<std::string> error_message;
if (package_name_for_testing_ == package_name) {
std::move(callback).Run(error_message,
@@ -304,7 +326,8 @@ class AndroidAppCommunicationChromeOS : public AndroidAppCommunication {
payment_app_service->InvokePaymentApp(
std::move(parameters),
- base::BindOnce(&OnPaymentAppResponse, std::move(callback)));
+ base::BindOnce(&OnPaymentAppResponse, std::move(callback),
+ std::move(overlay_state)));
}
// AndroidAppCommunication implementation.
diff --git a/chromium/components/payments/content/android_app_communication_stub.cc b/chromium/components/payments/content/android_app_communication_stub.cc
index b03ab067705..ab159c94068 100644
--- a/chromium/components/payments/content/android_app_communication_stub.cc
+++ b/chromium/components/payments/content/android_app_communication_stub.cc
@@ -48,6 +48,7 @@ class AndroidAppCommunicationStub : public AndroidAppCommunication {
const GURL& top_level_origin,
const GURL& payment_request_origin,
const std::string& payment_request_id,
+ content::WebContents* web_contents,
InvokePaymentAppCallback callback) override {
std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps,
/*is_activity_result_ok=*/false,
diff --git a/chromium/components/payments/content/android_app_communication_test_support_chrome_os.cc b/chromium/components/payments/content/android_app_communication_test_support_chrome_os.cc
index 5cae13e86db..43777527f93 100644
--- a/chromium/components/payments/content/android_app_communication_test_support_chrome_os.cc
+++ b/chromium/components/payments/content/android_app_communication_test_support_chrome_os.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "ash/public/cpp/external_arc/overlay/test/test_arc_overlay_manager.h"
#include "components/arc/mojom/payment_app.mojom.h"
#include "components/arc/pay/arc_payment_app_bridge.h"
#include "components/arc/test/arc_payment_app_bridge_test_support.h"
@@ -145,6 +146,7 @@ class AndroidAppCommunicationTestSupportChromeOS
arc::ArcPaymentAppBridgeTestSupport support_;
std::vector<std::unique_ptr<AndroidAppDescription>> apps_;
+ ash::TestArcOverlayManager overlay_manager_;
};
} // namespace
diff --git a/chromium/components/payments/content/android_app_communication_unittest.cc b/chromium/components/payments/content/android_app_communication_unittest.cc
index 552e46b3234..ba3ad57dc0f 100644
--- a/chromium/components/payments/content/android_app_communication_unittest.cc
+++ b/chromium/components/payments/content/android_app_communication_unittest.cc
@@ -14,6 +14,8 @@
#include "base/optional.h"
#include "components/payments/content/android_app_communication_test_support.h"
#include "components/payments/core/android_app_description.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_web_contents_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -45,7 +47,9 @@ std::vector<std::unique_ptr<AndroidAppDescription>> createApp(
class AndroidAppCommunicationTest : public testing::Test {
public:
AndroidAppCommunicationTest()
- : support_(AndroidAppCommunicationTestSupport::Create()) {}
+ : support_(AndroidAppCommunicationTestSupport::Create()),
+ web_contents_(
+ web_contents_factory_.CreateWebContents(support_->context())) {}
~AndroidAppCommunicationTest() override = default;
AndroidAppCommunicationTest(const AndroidAppCommunicationTest& other) =
@@ -77,6 +81,8 @@ class AndroidAppCommunicationTest : public testing::Test {
}
std::unique_ptr<AndroidAppCommunicationTestSupport> support_;
+ content::TestWebContentsFactory web_contents_factory_;
+ content::WebContents* web_contents_;
base::Optional<std::string> error_;
std::vector<std::unique_ptr<AndroidAppDescription>> apps_;
bool is_ready_to_pay_ = false;
@@ -466,6 +472,7 @@ TEST_F(AndroidAppCommunicationTest, NoArcForInvokePaymentApp) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
@@ -490,6 +497,7 @@ TEST_F(AndroidAppCommunicationTest, TwaPaymentOnlyWithPlayBilling) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
@@ -522,6 +530,7 @@ TEST_F(AndroidAppCommunicationTest, NoPaymentWithMoreThanOnePaymentMethodData) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
@@ -557,6 +566,7 @@ TEST_F(AndroidAppCommunicationTest, PaymentWithEmptyMethodData) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
@@ -589,6 +599,7 @@ TEST_F(AndroidAppCommunicationTest, UserCancelInvokePaymentApp) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
@@ -621,6 +632,7 @@ TEST_F(AndroidAppCommunicationTest, UserConfirmInvokePaymentApp) {
"com.example.app", "com.example.app.Activity", stringified_method_data,
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
+ web_contents_,
base::BindOnce(&AndroidAppCommunicationTest::OnPaymentAppResponse,
base::Unretained(this)));
diff --git a/chromium/components/payments/content/android_payment_app.cc b/chromium/components/payments/content/android_payment_app.cc
index 6871e68e00e..096bbaf5438 100644
--- a/chromium/components/payments/content/android_payment_app.cc
+++ b/chromium/components/payments/content/android_payment_app.cc
@@ -10,6 +10,7 @@
#include "components/payments/core/method_strings.h"
#include "components/payments/core/native_error_strings.h"
#include "components/payments/core/payer_data.h"
+#include "content/public/browser/web_contents.h"
namespace payments {
@@ -21,14 +22,16 @@ AndroidPaymentApp::AndroidPaymentApp(
const GURL& payment_request_origin,
const std::string& payment_request_id,
std::unique_ptr<AndroidAppDescription> description,
- base::WeakPtr<AndroidAppCommunication> communication)
+ base::WeakPtr<AndroidAppCommunication> communication,
+ content::GlobalFrameRoutingId frame_routing_id)
: PaymentApp(/*icon_resource_id=*/0, PaymentApp::Type::NATIVE_MOBILE_APP),
stringified_method_data_(std::move(stringified_method_data)),
top_level_origin_(top_level_origin),
payment_request_origin_(payment_request_origin),
payment_request_id_(payment_request_id),
description_(std::move(description)),
- communication_(communication) {
+ communication_(communication),
+ frame_routing_id_(frame_routing_id) {
DCHECK(!payment_method_names.empty());
DCHECK_EQ(payment_method_names.size(), stringified_method_data_->size());
DCHECK_EQ(*payment_method_names.begin(),
@@ -48,10 +51,19 @@ void AndroidPaymentApp::InvokePaymentApp(Delegate* delegate) {
if (!communication_)
return;
+ content::RenderFrameHost* rfh =
+ content::RenderFrameHost::FromID(frame_routing_id_);
+ if (!rfh || !rfh->IsCurrent())
+ return;
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(rfh);
+ if (!web_contents)
+ return;
+
communication_->InvokePaymentApp(
description_->package, description_->activities.front()->name,
*stringified_method_data_, top_level_origin_, payment_request_origin_,
- payment_request_id_,
+ payment_request_id_, web_contents,
base::BindOnce(&AndroidPaymentApp::OnPaymentAppResponse,
weak_ptr_factory_.GetWeakPtr(), delegate));
}
diff --git a/chromium/components/payments/content/android_payment_app.h b/chromium/components/payments/content/android_payment_app.h
index 0e826e0edfa..5a8ee010949 100644
--- a/chromium/components/payments/content/android_payment_app.h
+++ b/chromium/components/payments/content/android_payment_app.h
@@ -14,6 +14,7 @@
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/payment_app.h"
#include "components/payments/core/android_app_description.h"
+#include "content/public/browser/global_routing_id.h"
#include "url/gurl.h"
namespace payments {
@@ -40,7 +41,8 @@ class AndroidPaymentApp : public PaymentApp {
const GURL& payment_request_origin,
const std::string& payment_request_id,
std::unique_ptr<AndroidAppDescription> description,
- base::WeakPtr<AndroidAppCommunication> communication);
+ base::WeakPtr<AndroidAppCommunication> communication,
+ content::GlobalFrameRoutingId frame_routing_id);
~AndroidPaymentApp() override;
AndroidPaymentApp(const AndroidPaymentApp& other) = delete;
@@ -88,6 +90,7 @@ class AndroidPaymentApp : public PaymentApp {
const std::string payment_request_id_;
const std::unique_ptr<AndroidAppDescription> description_;
base::WeakPtr<AndroidAppCommunication> communication_;
+ content::GlobalFrameRoutingId frame_routing_id_;
base::WeakPtrFactory<AndroidPaymentApp> weak_ptr_factory_{this};
};
diff --git a/chromium/components/payments/content/android_payment_app_factory.cc b/chromium/components/payments/content/android_payment_app_factory.cc
index c8aeac25e03..b31f12854b1 100644
--- a/chromium/components/payments/content/android_payment_app_factory.cc
+++ b/chromium/components/payments/content/android_payment_app_factory.cc
@@ -179,7 +179,8 @@ class AppFinder : public base::SupportsUserData::Data {
DCHECK_LT(0U, number_of_pending_is_ready_to_pay_queries_);
// The browser could be shutting down.
- if (!communication_ || !delegate_ || !delegate_->GetSpec()) {
+ if (!communication_ || !delegate_ || !delegate_->GetSpec() ||
+ !delegate_->GetInitiatorRenderFrameHost()) {
OnDoneCreatingPaymentApps();
return;
}
@@ -191,7 +192,8 @@ class AppFinder : public base::SupportsUserData::Data {
payment_method_names, std::move(stringified_method_data),
delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(),
delegate_->GetSpec()->details().id.value(),
- std::move(app_description), communication_));
+ std::move(app_description), communication_,
+ delegate_->GetInitiatorRenderFrameHost()->GetGlobalFrameRoutingId()));
}
if (--number_of_pending_is_ready_to_pay_queries_ == 0)
diff --git a/chromium/components/payments/content/android_payment_app_factory_unittest.cc b/chromium/components/payments/content/android_payment_app_factory_unittest.cc
index 2716a0bb863..f0a08d16b7d 100644
--- a/chromium/components/payments/content/android_payment_app_factory_unittest.cc
+++ b/chromium/components/payments/content/android_payment_app_factory_unittest.cc
@@ -175,6 +175,9 @@ TEST_F(AndroidPaymentAppFactoryTest, FindAppsThatDoNotHaveReadyToPayService) {
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.example.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
@@ -214,6 +217,9 @@ TEST_F(AndroidPaymentAppFactoryTest,
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.example.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
@@ -250,6 +256,9 @@ TEST_F(AndroidPaymentAppFactoryTest,
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.twa.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
@@ -282,6 +291,9 @@ TEST_F(AndroidPaymentAppFactoryTest, IgnoreAppsThatAreNotReadyToPay) {
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.example.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0);
@@ -309,6 +321,9 @@ TEST_F(AndroidPaymentAppFactoryTest, FindTheCorrectTwaAppInTwaMode) {
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.correct-twa.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
@@ -448,6 +463,9 @@ TEST_F(AndroidPaymentAppFactoryTest,
EXPECT_CALL(delegate_, GetTwaPackageName())
.WillRepeatedly(testing::Return("com.twa.app"));
+ EXPECT_CALL(delegate_, GetInitiatorRenderFrameHost())
+ .WillRepeatedly(
+ testing::Return(delegate_.GetWebContents()->GetMainFrame()));
EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps());
EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0);
EXPECT_CALL(delegate_, OnPaymentAppCreated(PaymentAppMatches(
diff --git a/chromium/components/payments/content/android_payment_app_unittest.cc b/chromium/components/payments/content/android_payment_app_unittest.cc
index cb515a09d53..95c47d13845 100644
--- a/chromium/components/payments/content/android_payment_app_unittest.cc
+++ b/chromium/components/payments/content/android_payment_app_unittest.cc
@@ -18,6 +18,9 @@
#include "components/payments/content/android_app_communication_test_support.h"
#include "components/payments/core/android_app_description.h"
#include "components/payments/core/method_strings.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_web_contents_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -28,7 +31,8 @@ class AndroidPaymentAppTest : public testing::Test,
public PaymentApp::Delegate {
public:
static std::unique_ptr<AndroidPaymentApp> CreateAndroidPaymentApp(
- base::WeakPtr<AndroidAppCommunication> communication) {
+ base::WeakPtr<AndroidAppCommunication> communication,
+ content::WebContents* web_contents) {
std::set<std::string> payment_method_names;
payment_method_names.insert(methods::kGooglePlayBilling);
auto stringified_method_data =
@@ -47,11 +51,14 @@ class AndroidPaymentAppTest : public testing::Test,
payment_method_names, std::move(stringified_method_data),
GURL("https://top-level-origin.com"),
GURL("https://payment-request-origin.com"), "payment-request-id",
- std::move(description), communication);
+ std::move(description), communication,
+ web_contents->GetMainFrame()->GetGlobalFrameRoutingId());
}
AndroidPaymentAppTest()
- : support_(AndroidAppCommunicationTestSupport::Create()) {}
+ : support_(AndroidAppCommunicationTestSupport::Create()),
+ web_contents_(
+ web_contents_factory_.CreateWebContents(support_->context())) {}
~AndroidPaymentAppTest() override = default;
@@ -72,6 +79,8 @@ class AndroidPaymentAppTest : public testing::Test,
}
std::unique_ptr<AndroidAppCommunicationTestSupport> support_;
+ content::TestWebContentsFactory web_contents_factory_;
+ content::WebContents* web_contents_;
std::unique_ptr<AndroidAppCommunicationTestSupport::ScopedInitialization>
scoped_initialization_;
base::WeakPtr<AndroidAppCommunication> communication_;
@@ -87,7 +96,7 @@ TEST_F(AndroidPaymentAppTest, BrowserShutdown) {
support_->ExpectNoPaymentAppInvoke();
- auto app = CreateAndroidPaymentApp(communication_);
+ auto app = CreateAndroidPaymentApp(communication_, web_contents_);
app->InvokePaymentApp(/*delegate=*/this);
EXPECT_TRUE(error_message_.empty());
@@ -103,7 +112,7 @@ TEST_F(AndroidPaymentAppTest, UnableToCommunicateToAndroidApps) {
support_->ExpectNoPaymentAppInvoke();
- auto app = CreateAndroidPaymentApp(communication_);
+ auto app = CreateAndroidPaymentApp(communication_, web_contents_);
app->InvokePaymentApp(/*delegate=*/this);
EXPECT_EQ("Unable to invoke Android apps.", error_message_);
@@ -122,7 +131,7 @@ TEST_F(AndroidPaymentAppTest, OnInstrumentDetailsError) {
/*payment_method_identifier=*/methods::kGooglePlayBilling,
/*stringified_details=*/"{}");
- auto app = CreateAndroidPaymentApp(communication_);
+ auto app = CreateAndroidPaymentApp(communication_, web_contents_);
app->InvokePaymentApp(/*delegate=*/this);
if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
@@ -146,7 +155,7 @@ TEST_F(AndroidPaymentAppTest, OnInstrumentDetailsReady) {
/*payment_method_identifier=*/methods::kGooglePlayBilling,
/*stringified_details=*/"{\"status\": \"ok\"}");
- auto app = CreateAndroidPaymentApp(communication_);
+ auto app = CreateAndroidPaymentApp(communication_, web_contents_);
app->InvokePaymentApp(/*delegate=*/this);
if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
diff --git a/chromium/components/payments/content/installable_payment_app_crawler.cc b/chromium/components/payments/content/installable_payment_app_crawler.cc
index e824dd0f2a2..643bcf07ea5 100644
--- a/chromium/components/payments/content/installable_payment_app_crawler.cc
+++ b/chromium/components/payments/content/installable_payment_app_crawler.cc
@@ -408,7 +408,7 @@ bool InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
manifest_icon.src = icon_src;
manifest_icon.type = base::UTF8ToUTF16(icon.type);
manifest_icon.purpose.emplace_back(
- blink::Manifest::ImageResource::Purpose::ANY);
+ blink::mojom::ManifestImageResource_Purpose::ANY);
// TODO(crbug.com/782270): Parse icon sizes.
manifest_icon.sizes.emplace_back(gfx::Size());
manifest_icons.emplace_back(manifest_icon);
@@ -448,7 +448,7 @@ bool InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
manifest_icons, IconSizeCalculator::IdealIconHeight(native_view),
IconSizeCalculator::MinimumIconHeight(),
content::ManifestIconDownloader::kMaxWidthToHeightRatio,
- blink::Manifest::ImageResource::Purpose::ANY);
+ blink::mojom::ManifestImageResource_Purpose::ANY);
if (!best_icon_url.is_valid()) {
log_.Warn("No suitable icon found in web app manifest \"" +
web_app_manifest_url.spec() +
diff --git a/chromium/components/payments/content/payment_event_response_util.cc b/chromium/components/payments/content/payment_event_response_util.cc
index 4ace52f9ba1..d9ac969b640 100644
--- a/chromium/components/payments/content/payment_event_response_util.cc
+++ b/chromium/components/payments/content/payment_event_response_util.cc
@@ -78,6 +78,11 @@ base::StringPiece ConvertPaymentEventResponseTypeToErrorString(
return errors::kPaymentEventTimeout;
case mojom::PaymentEventResponseType::PAYMENT_HANDLER_INSECURE_NAVIGATION:
return errors::kPaymentHandlerInsecureNavigation;
+ case mojom::PaymentEventResponseType::PAYMENT_HANDLER_ACTIVITY_DIED:
+ return errors::kPaymentHandlerActivityDied;
+ case mojom::PaymentEventResponseType::
+ PAYMENT_HANDLER_FAIL_TO_LOAD_MAIN_FRAME:
+ return errors::kPaymentHandlerFailToLoadMainFrame;
case mojom::PaymentEventResponseType::PAYER_NAME_EMPTY:
return errors::kPayerNameEmpty;
case mojom::PaymentEventResponseType::PAYER_EMAIL_EMPTY:
diff --git a/chromium/components/payments/content/payment_request.cc b/chromium/components/payments/content/payment_request.cc
index d29822bac9e..ebafd3ccf02 100644
--- a/chromium/components/payments/content/payment_request.cc
+++ b/chromium/components/payments/content/payment_request.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/feature_list.h"
+#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "components/payments/content/can_make_payment_query_factory.h"
@@ -68,7 +69,6 @@ mojom::PaymentAddressPtr RedactShippingAddress(
address->address_line.clear();
return address;
}
-
} // namespace
PaymentRequest::PaymentRequest(
@@ -221,6 +221,26 @@ void PaymentRequest::Init(
delegate_->set_dialog_type(
PaymentRequestDelegate::DialogType::SECURE_PAYMENT_CONFIRMATION);
}
+
+ if (VLOG_IS_ON(2)) {
+ std::vector<std::string> payment_method_identifiers(
+ spec_->payment_method_identifiers_set().begin(),
+ spec_->payment_method_identifiers_set().end());
+ std::string total = spec_->details().total
+ ? (spec_->details().total->amount->currency +
+ spec_->details().total->amount->value)
+ : "N/A";
+ VLOG(2) << "Initialized PaymentRequest (" << *spec_->details().id << ")"
+ << "\n Top origin: " << top_level_origin_.spec()
+ << "\n Frame origin: " << frame_origin_.spec()
+ << "\n Requested methods: "
+ << base::JoinString(payment_method_identifiers, ", ")
+ << "\n Total: " << total
+ << "\n Options: shipping = " << spec_->request_shipping()
+ << ", name = " << spec_->request_payer_name()
+ << ", phone = " << spec_->request_payer_phone()
+ << ", email = " << spec_->request_payer_email();
+ }
}
void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) {
@@ -281,7 +301,11 @@ void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) {
spec_->details().total->amount->value, false /*completed*/);
}
- display_handle_->Show(weak_ptr_factory_.GetWeakPtr());
+ // If an app store billing payment method is one of the payment methods being
+ // requested, then don't show any user interface until its known whether it's
+ // possible to skip UI directly into an app store billing payment app.
+ if (!spec_->IsAppStoreBillingAlsoRequested())
+ display_handle_->Show(weak_ptr_factory_.GetWeakPtr());
state_->set_is_show_user_gesture(is_show_user_gesture_);
state_->AreRequestedMethodsSupported(
@@ -311,6 +335,9 @@ void PaymentRequest::Retry(mojom::PaymentValidationErrorsPtr errors) {
return;
}
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << ") retry with error: " << error;
+
state()->SetAvailablePaymentAppForRetry();
spec()->Retry(std::move(errors));
display_handle_->Retry();
@@ -364,8 +391,14 @@ void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) {
spec_->details().total->amount->value, false /*completed*/);
if (SatisfiesSkipUIConstraints()) {
Pay();
- } else if (spec_->request_shipping()) {
- state_->SelectDefaultShippingAddressAndNotifyObservers();
+ } else {
+ // If not skipping UI, then make sure that the browser payment sheet is
+ // being displayed.
+ if (!display_handle_->was_shown())
+ display_handle_->Show(weak_ptr_factory_.GetWeakPtr());
+
+ if (spec_->request_shipping())
+ state_->SelectDefaultShippingAddressAndNotifyObservers();
}
}
}
@@ -446,7 +479,7 @@ void PaymentRequest::Complete(mojom::PaymentComplete result) {
// Failed transactions show an error. Successful and unknown-state
// transactions don't show an error.
if (result == mojom::PaymentComplete::FAIL) {
- delegate_->ShowErrorMessage();
+ ShowErrorMessageAndAbortPayment();
} else {
DCHECK(!has_recorded_completion_);
journey_logger_.SetCompleted();
@@ -567,9 +600,16 @@ void PaymentRequest::AreRequestedMethodsSupportedCallback(
}
if (methods_supported) {
- if (SatisfiesSkipUIConstraints())
+ if (SatisfiesSkipUIConstraints()) {
Pay();
+ } else if (!display_handle_->was_shown()) {
+ // If not skipping UI, then make sure that the browser payment sheet is
+ // being displayed.
+ display_handle_->Show(weak_ptr_factory_.GetWeakPtr());
+ }
} else {
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << "): requested method not supported.";
DCHECK(!has_recorded_completion_);
has_recorded_completion_ = true;
journey_logger_.SetNotShown(
@@ -713,9 +753,7 @@ void PaymentRequest::OnPaymentResponseError(const std::string& error_message) {
RecordFirstAbortReason(JourneyLogger::ABORT_REASON_INSTRUMENT_DETAILS_ERROR);
reject_show_error_message_ = error_message;
- delegate_->ShowErrorMessage();
- // When the user dismisses the error message, UserCancelled() will reject
- // PaymentRequest.show() with |reject_show_error_message_|.
+ ShowErrorMessageAndAbortPayment();
}
void PaymentRequest::OnShippingOptionIdSelected(
@@ -732,7 +770,7 @@ void PaymentRequest::OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) {
client_->OnPayerDetailChange(std::move(payer_info));
}
-void PaymentRequest::UserCancelled() {
+void PaymentRequest::OnUserCancelled() {
// If |client_| is not bound, then the object is already being destroyed as
// a result of a renderer event.
if (!client_.is_bound())
@@ -799,6 +837,16 @@ void PaymentRequest::Pay() {
journey_logger_.RecordCheckoutStep(
JourneyLogger::CheckoutFunnelStep::kPaymentHandlerInvoked);
DCHECK(state_->selected_app());
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << "): paying with app: " << state_->selected_app()->GetLabel();
+
+ if (!display_handle_->was_shown() &&
+ state_->selected_app()->type() != PaymentApp::Type::NATIVE_MOBILE_APP) {
+ // If not paying with a native mobile app (such as app store billing), then
+ // make sure that the browser payment sheet is being displayed.
+ display_handle_->Show(weak_ptr_factory_.GetWeakPtr());
+ }
+
state_->selected_app()->SetPaymentHandlerHost(
payment_handler_host_->AsWeakPtr());
state_->GeneratePaymentResponse();
@@ -836,6 +884,8 @@ void PaymentRequest::RecordFirstAbortReason(
}
void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << "): canMakePayment = " << can_make_payment;
client_->OnCanMakePayment(
can_make_payment ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
: mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
@@ -852,6 +902,9 @@ void PaymentRequest::HasEnrolledInstrumentCallback(
if (!rfh)
return;
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << "): hasEnrolledInstrument = " << has_enrolled_instrument;
+
if (!spec_ || CanMakePaymentQueryFactory::GetInstance()
->GetForContext(rfh->GetBrowserContext())
->CanQuery(top_level_origin_, frame_origin_,
@@ -888,6 +941,8 @@ void PaymentRequest::RespondToHasEnrolledInstrumentQuery(
}
void PaymentRequest::OnAbortResult(bool aborted) {
+ VLOG(2) << "PaymentRequest (" << *spec_->details().id
+ << "): abort = " << aborted;
if (client_.is_bound())
client_->OnAbort(aborted);
@@ -897,4 +952,18 @@ void PaymentRequest::OnAbortResult(bool aborted) {
}
}
+void PaymentRequest::ShowErrorMessageAndAbortPayment() {
+ // Note that both branches of the if-else will invoke the OnUserCancelled()
+ // method.
+ if (display_handle_ && display_handle_->was_shown()) {
+ // Will invoke OnUserCancelled() asynchronously when the user closes the
+ // error message UI.
+ delegate_->ShowErrorMessage();
+ } else {
+ // Only app store billing apps do not display any browser payment UI.
+ DCHECK(spec_->IsAppStoreBillingAlsoRequested());
+ OnUserCancelled();
+ }
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/payment_request.h b/chromium/components/payments/content/payment_request.h
index e394c3cebb7..7dde2025e5f 100644
--- a/chromium/components/payments/content/payment_request.h
+++ b/chromium/components/payments/content/payment_request.h
@@ -105,8 +105,8 @@ class PaymentRequest : public mojom::PaymentRequest,
// Called when the user explicitly cancelled the flow. Will send a message
// to the renderer which will indirectly destroy this object (through
- // OnConnectionTerminated).
- void UserCancelled();
+ // TerminateConnection).
+ void OnUserCancelled();
// Called when the main frame attached to this PaymentRequest is navigating to
// another document, but before the PaymentRequest is destroyed.
@@ -204,6 +204,9 @@ class PaymentRequest : public mojom::PaymentRequest,
void OnAbortResult(bool aborted);
+ // Show an error message in the UI (if available) and abort payment.
+ void ShowErrorMessageAndAbortPayment();
+
const content::GlobalFrameRoutingId initiator_frame_routing_id_;
DeveloperConsoleLogger log_;
std::unique_ptr<ContentPaymentRequestDelegate> delegate_;
diff --git a/chromium/components/payments/content/payment_request_display_manager.cc b/chromium/components/payments/content/payment_request_display_manager.cc
index e92fe714e0f..92a2166e4de 100644
--- a/chromium/components/payments/content/payment_request_display_manager.cc
+++ b/chromium/components/payments/content/payment_request_display_manager.cc
@@ -26,6 +26,7 @@ void PaymentRequestDisplayManager::DisplayHandle::Show(
base::WeakPtr<PaymentRequest> request) {
DCHECK(request);
DCHECK(delegate_);
+ was_shown_ = true;
delegate_->ShowDialog(request);
}
diff --git a/chromium/components/payments/content/payment_request_display_manager.h b/chromium/components/payments/content/payment_request_display_manager.h
index 5a1cec42edf..5225810cbb3 100644
--- a/chromium/components/payments/content/payment_request_display_manager.h
+++ b/chromium/components/payments/content/payment_request_display_manager.h
@@ -43,9 +43,13 @@ class PaymentRequestDisplayManager : public KeyedService {
void DisplayPaymentHandlerWindow(const GURL& url,
PaymentHandlerOpenWindowCallback callback);
+ // Returns true after Show() was called.
+ bool was_shown() const { return was_shown_; }
+
private:
PaymentRequestDisplayManager* display_manager_;
ContentPaymentRequestDelegate* delegate_;
+ bool was_shown_ = false;
DISALLOW_COPY_AND_ASSIGN(DisplayHandle);
};
diff --git a/chromium/components/payments/content/payment_request_spec.cc b/chromium/components/payments/content/payment_request_spec.cc
index f5362a8a3e8..95cbaa8387d 100644
--- a/chromium/components/payments/content/payment_request_spec.cc
+++ b/chromium/components/payments/content/payment_request_spec.cc
@@ -111,6 +111,8 @@ PaymentRequestSpec::PaymentRequestSpec(
ToString(request_payer_phone()), ToString(request_shipping())},
nullptr)};
}
+
+ app_store_billing_methods_.insert(methods::kGooglePlayBilling);
}
PaymentRequestSpec::~PaymentRequestSpec() {}
@@ -366,6 +368,12 @@ bool PaymentRequestSpec::IsSecurePaymentConfirmationRequested() const {
methods::kSecurePaymentConfirmation;
}
+bool PaymentRequestSpec::IsAppStoreBillingAlsoRequested() const {
+ return !base::STLSetIntersection<std::set<std::string>>(
+ app_store_billing_methods_, payment_method_identifiers_set_)
+ .empty();
+}
+
base::WeakPtr<PaymentRequestSpec> PaymentRequestSpec::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
diff --git a/chromium/components/payments/content/payment_request_spec.h b/chromium/components/payments/content/payment_request_spec.h
index f9c2cb8d0e0..768ff332188 100644
--- a/chromium/components/payments/content/payment_request_spec.h
+++ b/chromium/components/payments/content/payment_request_spec.h
@@ -207,6 +207,10 @@ class PaymentRequestSpec : public PaymentOptionsProvider,
bool IsSecurePaymentConfirmationRequested() const;
+ // Returns true if one of the payment methods being requested is an app store
+ // billing method, such as "https://play.google.com/billing".
+ bool IsAppStoreBillingAlsoRequested() const;
+
base::WeakPtr<PaymentRequestSpec> AsWeakPtr();
private:
@@ -256,9 +260,9 @@ class PaymentRequestSpec : public PaymentOptionsProvider,
// |supported_card_networks_set_| to check merchant support.
std::set<std::string> basic_card_specified_networks_;
- // A list of supported url-based payment method identifers specified by the
+ // A list of supported url-based payment method identifiers specified by the
// merchant. This encompasses one of the two types of payment method
- // identifers, the other being standardized payment method identifiers i.e.,
+ // identifiers, the other being standardized payment method identifiers i.e.,
// basic-card.
std::vector<GURL> url_payment_method_identifiers_;
@@ -289,6 +293,8 @@ class PaymentRequestSpec : public PaymentOptionsProvider,
base::string16 retry_error_message_;
mojom::PayerErrorsPtr payer_errors_;
+ std::set<std::string> app_store_billing_methods_;
+
base::WeakPtrFactory<PaymentRequestSpec> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(PaymentRequestSpec);
diff --git a/chromium/components/payments/content/secure_payment_confirmation_app_factory.cc b/chromium/components/payments/content/secure_payment_confirmation_app_factory.cc
index 6cf47434569..989883fab32 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_app_factory.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_app_factory.cc
@@ -72,13 +72,13 @@ void SecurePaymentConfirmationAppFactory::
OnIsUserVerifyingPlatformAuthenticatorAvailable(
base::WeakPtr<PaymentAppFactory::Delegate> delegate,
mojom::SecurePaymentConfirmationRequestPtr request,
- std::unique_ptr<autofill::InternalAuthenticator> authenticator,
bool is_available) {
if (!delegate || !delegate->GetWebContents())
return;
- if (!is_available && !base::FeatureList::IsEnabled(
- features::kSecurePaymentConfirmationDebug)) {
+ if (!authenticator_ ||
+ (!is_available && !base::FeatureList::IsEnabled(
+ features::kSecurePaymentConfirmationDebug))) {
delegate->OnDoneCreatingPaymentApps();
return;
}
@@ -98,8 +98,9 @@ void SecurePaymentConfirmationAppFactory::
WebDataServiceBase::Handle handle =
web_data_service->GetSecurePaymentConfirmationInstruments(
std::move(request->credential_ids), this);
- requests_[handle] = std::make_unique<Request>(
- delegate, web_data_service, std::move(request), std::move(authenticator));
+ requests_[handle] =
+ std::make_unique<Request>(delegate, web_data_service, std::move(request),
+ std::move(authenticator_));
}
SecurePaymentConfirmationAppFactory::SecurePaymentConfirmationAppFactory()
@@ -133,16 +134,16 @@ void SecurePaymentConfirmationAppFactory::Create(
return;
}
- std::unique_ptr<autofill::InternalAuthenticator> authenticator =
- delegate->CreateInternalAuthenticator();
- auto* authenticator_ptr = authenticator.get();
+ // Observe the web contents to ensure the authenticator outlives it.
+ Observe(delegate->GetWebContents());
- authenticator_ptr->IsUserVerifyingPlatformAuthenticatorAvailable(
+ authenticator_ = delegate->CreateInternalAuthenticator();
+
+ authenticator_->IsUserVerifyingPlatformAuthenticatorAvailable(
base::BindOnce(&SecurePaymentConfirmationAppFactory::
OnIsUserVerifyingPlatformAuthenticatorAvailable,
weak_ptr_factory_.GetWeakPtr(), delegate,
- method_data->secure_payment_confirmation.Clone(),
- std::move(authenticator)));
+ method_data->secure_payment_confirmation.Clone()));
return;
}
}
@@ -150,6 +151,14 @@ void SecurePaymentConfirmationAppFactory::Create(
delegate->OnDoneCreatingPaymentApps();
}
+void SecurePaymentConfirmationAppFactory::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ if (authenticator_ &&
+ authenticator_->GetRenderFrameHost() == render_frame_host) {
+ authenticator_.reset();
+ }
+}
+
struct SecurePaymentConfirmationAppFactory::Request
: public content::WebContentsObserver {
Request(
@@ -168,6 +177,15 @@ struct SecurePaymentConfirmationAppFactory::Request
Request(const Request& other) = delete;
Request& operator=(const Request& other) = delete;
+ // WebContentsObserver:
+ void RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) override {
+ if (authenticator &&
+ authenticator->GetRenderFrameHost() == render_frame_host) {
+ authenticator.reset();
+ }
+ }
+
base::WeakPtr<PaymentAppFactory::Delegate> delegate;
scoped_refptr<payments::PaymentManifestWebDataService> web_data_service;
mojom::SecurePaymentConfirmationRequestPtr mojo_request;
@@ -224,7 +242,7 @@ void SecurePaymentConfirmationAppFactory::OnAppIconDecoded(
const SkBitmap& decoded_icon) {
DCHECK(request);
if (!request->delegate || !request->web_contents() ||
- !request->delegate->GetSpec() ||
+ !request->delegate->GetSpec() || !request->authenticator ||
request->authenticator->GetRenderFrameHost() !=
request->web_contents()->GetMainFrame()) {
request->delegate->OnDoneCreatingPaymentApps();
diff --git a/chromium/components/payments/content/secure_payment_confirmation_app_factory.h b/chromium/components/payments/content/secure_payment_confirmation_app_factory.h
index 3eab505598b..a133b339824 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_app_factory.h
+++ b/chromium/components/payments/content/secure_payment_confirmation_app_factory.h
@@ -11,13 +11,16 @@
#include "base/memory/weak_ptr.h"
#include "components/payments/content/payment_app_factory.h"
#include "components/webdata/common/web_data_service_consumer.h"
+#include "content/public/browser/web_contents_observer.h"
namespace payments {
struct SecurePaymentConfirmationInstrument;
-class SecurePaymentConfirmationAppFactory : public PaymentAppFactory,
- public WebDataServiceConsumer {
+class SecurePaymentConfirmationAppFactory
+ : public PaymentAppFactory,
+ public WebDataServiceConsumer,
+ public content::WebContentsObserver {
public:
SecurePaymentConfirmationAppFactory();
~SecurePaymentConfirmationAppFactory() override;
@@ -38,10 +41,12 @@ class SecurePaymentConfirmationAppFactory : public PaymentAppFactory,
WebDataServiceBase::Handle handle,
std::unique_ptr<WDTypedResult> result) override;
+ // WebContentsObserver:
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
void OnIsUserVerifyingPlatformAuthenticatorAvailable(
base::WeakPtr<PaymentAppFactory::Delegate> delegate,
mojom::SecurePaymentConfirmationRequestPtr request,
- std::unique_ptr<autofill::InternalAuthenticator> authenticator,
bool is_available);
void OnAppIconDecoded(
@@ -49,6 +54,8 @@ class SecurePaymentConfirmationAppFactory : public PaymentAppFactory,
std::unique_ptr<Request> request,
const SkBitmap& decoded_image);
+ std::unique_ptr<autofill::InternalAuthenticator> authenticator_;
+
std::map<WebDataServiceBase::Handle, std::unique_ptr<Request>> requests_;
base::WeakPtrFactory<SecurePaymentConfirmationAppFactory> weak_ptr_factory_{
this};
diff --git a/chromium/components/payments/content/secure_payment_confirmation_controller.cc b/chromium/components/payments/content/secure_payment_confirmation_controller.cc
index 2b96947ad68..c84508a8f2c 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_controller.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_controller.cc
@@ -182,7 +182,7 @@ void SecurePaymentConfirmationController::OnCancel() {
return;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&PaymentRequest::UserCancelled, request_));
+ FROM_HERE, base::BindOnce(&PaymentRequest::OnUserCancelled, request_));
}
void SecurePaymentConfirmationController::OnConfirm() {
diff --git a/chromium/components/payments/content/service_worker_payment_app.cc b/chromium/components/payments/content/service_worker_payment_app.cc
index 2e798d4a3c2..7ba63d54ef5 100644
--- a/chromium/components/payments/content/service_worker_payment_app.cc
+++ b/chromium/components/payments/content/service_worker_payment_app.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -233,7 +233,7 @@ void ServiceWorkerPaymentApp::InvokePaymentApp(Delegate* delegate) {
&ServiceWorkerPaymentApp::OnPaymentAppIdentity,
weak_ptr_factory_.GetWeakPtr(),
url::Origin::Create(GURL(installable_web_app_info_->sw_scope))),
- base::BindOnce(&ServiceWorkerPaymentApp::OnPaymentAppInvoked,
+ base::BindOnce(&ServiceWorkerPaymentApp::OnPaymentAppResponse,
weak_ptr_factory_.GetWeakPtr()));
} else {
url::Origin sw_origin =
@@ -242,7 +242,7 @@ void ServiceWorkerPaymentApp::InvokePaymentApp(Delegate* delegate) {
payment_app_provider->InvokePaymentApp(
stored_payment_app_info_->registration_id, sw_origin,
CreatePaymentRequestEventData(),
- base::BindOnce(&ServiceWorkerPaymentApp::OnPaymentAppInvoked,
+ base::BindOnce(&ServiceWorkerPaymentApp::OnPaymentAppResponse,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -344,7 +344,7 @@ ServiceWorkerPaymentApp::CreatePaymentRequestEventData() {
return event_data;
}
-void ServiceWorkerPaymentApp::OnPaymentAppInvoked(
+void ServiceWorkerPaymentApp::OnPaymentAppResponse(
mojom::PaymentHandlerResponsePtr response) {
if (!delegate_)
return;
diff --git a/chromium/components/payments/content/service_worker_payment_app.h b/chromium/components/payments/content/service_worker_payment_app.h
index af150fdc4ae..031cebf3e0d 100644
--- a/chromium/components/payments/content/service_worker_payment_app.h
+++ b/chromium/components/payments/content/service_worker_payment_app.h
@@ -115,7 +115,7 @@ class ServiceWorkerPaymentApp : public PaymentApp,
private:
friend class ServiceWorkerPaymentAppTest;
- void OnPaymentAppInvoked(mojom::PaymentHandlerResponsePtr response);
+ void OnPaymentAppResponse(mojom::PaymentHandlerResponsePtr response);
mojom::PaymentRequestEventDataPtr CreatePaymentRequestEventData();
mojom::CanMakePaymentEventDataPtr CreateCanMakePaymentEventData();
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
index a62150282f3..5f874952567 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
diff --git a/chromium/components/payments/core/can_make_payment_query.cc b/chromium/components/payments/core/can_make_payment_query.cc
index 1f955334ae7..8e379265716 100644
--- a/chromium/components/payments/core/can_make_payment_query.cc
+++ b/chromium/components/payments/core/can_make_payment_query.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/components/payments/core/currency_formatter.cc b/chromium/components/payments/core/currency_formatter.cc
index df23c63dbca..68dc6c9621f 100644
--- a/chromium/components/payments/core/currency_formatter.cc
+++ b/chromium/components/payments/core/currency_formatter.cc
@@ -85,6 +85,10 @@ CurrencyFormatter::CurrencyFormatter(const std::string& currency_code,
CurrencyFormatter::~CurrencyFormatter() {}
+void CurrencyFormatter::SetMaxFractionalDigits(const int maxFractionalDigits) {
+ icu_formatter_->setMaximumFractionDigits(maxFractionalDigits);
+}
+
base::string16 CurrencyFormatter::Format(const std::string& amount) {
// It's possible that the ICU formatter didn't initialize properly.
if (!icu_formatter_ || !icu_formatter_->getCurrency())
diff --git a/chromium/components/payments/core/currency_formatter.h b/chromium/components/payments/core/currency_formatter.h
index 26443e18e92..4352ffcfd65 100644
--- a/chromium/components/payments/core/currency_formatter.h
+++ b/chromium/components/payments/core/currency_formatter.h
@@ -27,6 +27,10 @@ class CurrencyFormatter {
const std::string& locale_name);
~CurrencyFormatter();
+ // Set the maximum number of fractional digits. (kMaximumNumFractionalDigits
+ // is the default if unset)
+ void SetMaxFractionalDigits(const int maxFractionalDigits);
+
// Formats the |amount| according to the currency code that was set. The
// result will NOT contain the currency code, nor a subset of it. Rather, the
// caller of this function should display the currency code separately. The
diff --git a/chromium/components/payments/core/journey_logger.h b/chromium/components/payments/core/journey_logger.h
index 4b0262125d2..b5718b20d19 100644
--- a/chromium/components/payments/core/journey_logger.h
+++ b/chromium/components/payments/core/journey_logger.h
@@ -187,7 +187,7 @@ class JourneyLogger {
// Sets the number of suggestions shown for the specified section.
void SetNumberOfSuggestionsShown(Section section,
int number,
- bool has_valid_suggestion);
+ bool has_complete_suggestion);
// Records the fact that the merchant called CanMakePayment and records its
// return value.
diff --git a/chromium/components/payments/core/journey_logger_unittest.cc b/chromium/components/payments/core/journey_logger_unittest.cc
index 468e4e71750..ffe2c5dc405 100644
--- a/chromium/components/payments/core/journey_logger_unittest.cc
+++ b/chromium/components/payments/core/journey_logger_unittest.cc
@@ -6,7 +6,6 @@
#include "base/metrics/metrics_hashes.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
diff --git a/chromium/components/payments/core/native_error_strings.cc b/chromium/components/payments/core/native_error_strings.cc
index 477f11da3da..f21be764416 100644
--- a/chromium/components/payments/core/native_error_strings.cc
+++ b/chromium/components/payments/core/native_error_strings.cc
@@ -134,6 +134,12 @@ const char kPaymentHandlerInsecureNavigation[] =
"The payment handler navigated to a page with insecure context, invalid "
"certificate state, or malicious content.";
+const char kPaymentHandlerActivityDied[] =
+ "The payment handler is closed because the Android activity is destroyed.";
+
+const char kPaymentHandlerFailToLoadMainFrame[] =
+ "The payment handler fails to load the page.";
+
const char kSinglePaymentMethodNotSupportedFormat[] =
"The payment method $ is not supported.";
diff --git a/chromium/components/payments/core/native_error_strings.h b/chromium/components/payments/core/native_error_strings.h
index e1f6a0465a2..9cdeaa0a884 100644
--- a/chromium/components/payments/core/native_error_strings.h
+++ b/chromium/components/payments/core/native_error_strings.h
@@ -148,6 +148,12 @@ extern const char kPaymentEventTimeout[];
// malicious content.
extern const char kPaymentHandlerInsecureNavigation[];
+// The payment handler is closed because the Android activity is destroyed.
+extern const char kPaymentHandlerActivityDied[];
+
+// The payment handler fails to load the page.
+extern const char kPaymentHandlerFailToLoadMainFrame[];
+
// Payment handler encountered an internal error when handling the
// "paymentrequest" event.
extern const char kPaymentEventInternalError[];
diff --git a/chromium/components/payments/core/strings_util.cc b/chromium/components/payments/core/strings_util.cc
index 61e4c3f2694..41e8171c886 100644
--- a/chromium/components/payments/core/strings_util.cc
+++ b/chromium/components/payments/core/strings_util.cc
@@ -15,7 +15,7 @@
namespace payments {
-base::string16 GetShippingAddressLabelFormAutofillProfile(
+base::string16 GetShippingAddressLabelFromAutofillProfile(
const autofill::AutofillProfile& profile,
const std::string& locale) {
// Name, phone number, and country are not included in the shipping address
diff --git a/chromium/components/payments/core/strings_util.h b/chromium/components/payments/core/strings_util.h
index 3fcd43a6039..8146a689545 100644
--- a/chromium/components/payments/core/strings_util.h
+++ b/chromium/components/payments/core/strings_util.h
@@ -20,7 +20,7 @@ class AutofillProfile;
namespace payments {
// Helper function to create a shipping address label from an autofill profile.
-base::string16 GetShippingAddressLabelFormAutofillProfile(
+base::string16 GetShippingAddressLabelFromAutofillProfile(
const autofill::AutofillProfile& profile,
const std::string& locale);
diff --git a/chromium/components/payments_strings_grdp/OWNERS b/chromium/components/payments_strings_grdp/OWNERS
index 3d4ca5fda72..616d55333e6 100644
--- a/chromium/components/payments_strings_grdp/OWNERS
+++ b/chromium/components/payments_strings_grdp/OWNERS
@@ -1,4 +1 @@
-# TEAM: payments-dev@chromium.org
-# COMPONENT: UI>Browser>Payments
-
file://components/payments/OWNERS
diff --git a/chromium/components/pdf_strings.grdp b/chromium/components/pdf_strings.grdp
index 091531d80e9..304e6e8d81f 100644
--- a/chromium/components/pdf_strings.grdp
+++ b/chromium/components/pdf_strings.grdp
@@ -7,6 +7,9 @@
<message name="IDS_PDF_DOWNLOAD_EDITED" desc="The label for the menu option to download the edited PDF document (with user's changes).">
With your changes
</message>
+ <message name="IDS_PDF_FULLSCREEN" desc="The label for the menu option to switch to fullscreen mode.">
+ Full screen
+ </message>
<message name="IDS_PDF_NEED_PASSWORD" desc="A message asking the user for a password to open a PDF file.">
This document is password protected. Please enter a password.
</message>
diff --git a/chromium/components/pdf_strings_grdp/IDS_PDF_FULLSCREEN.png.sha1 b/chromium/components/pdf_strings_grdp/IDS_PDF_FULLSCREEN.png.sha1
new file mode 100644
index 00000000000..b7ed385ceeb
--- /dev/null
+++ b/chromium/components/pdf_strings_grdp/IDS_PDF_FULLSCREEN.png.sha1
@@ -0,0 +1 @@
+63b8c9b6924406cdbc617e3209fbade2e54b1fe3 \ No newline at end of file
diff --git a/chromium/components/performance_manager/BUILD.gn b/chromium/components/performance_manager/BUILD.gn
index 64fee2fd68c..6db79a000bd 100644
--- a/chromium/components/performance_manager/BUILD.gn
+++ b/chromium/components/performance_manager/BUILD.gn
@@ -10,6 +10,8 @@ proto_library("site_data_proto") {
static_library("performance_manager") {
sources = [
+ "decorators/frame_visibility_decorator.cc",
+ "decorators/frame_visibility_decorator.h",
"decorators/page_live_state_decorator.cc",
"decorators/page_load_tracker_decorator.cc",
"decorators/page_load_tracker_decorator.h",
@@ -23,11 +25,13 @@ static_library("performance_manager") {
"execution_context/execution_context_impl.h",
"execution_context/execution_context_registry_impl.cc",
"execution_context/execution_context_registry_impl.h",
+ "execution_context_priority/boosting_vote_aggregator.cc",
+ "execution_context_priority/execution_context_priority.cc",
+ "execution_context_priority/max_vote_aggregator.cc",
+ "execution_context_priority/override_vote_aggregator.cc",
"features.cc",
- "frame_priority/boosting_vote_aggregator.cc",
- "frame_priority/frame_priority.cc",
- "frame_priority/max_vote_aggregator.cc",
- "frame_priority/override_vote_aggregator.cc",
+ "freezing/freezing_vote_aggregator.cc",
+ "freezing/freezing_vote_aggregator.h",
"graph/frame_node.cc",
"graph/frame_node_impl.cc",
"graph/frame_node_impl.h",
@@ -89,12 +93,13 @@ static_library("performance_manager") {
"public/decorators/page_load_tracker_decorator_helper.h",
"public/decorators/tab_properties_decorator.h",
"public/execution_context/execution_context.h",
+ "public/execution_context/execution_context_attached_data.h",
"public/execution_context/execution_context_registry.h",
+ "public/execution_context_priority/boosting_vote_aggregator.h",
+ "public/execution_context_priority/execution_context_priority.h",
+ "public/execution_context_priority/max_vote_aggregator.h",
+ "public/execution_context_priority/override_vote_aggregator.h",
"public/features.h",
- "public/frame_priority/boosting_vote_aggregator.h",
- "public/frame_priority/frame_priority.h",
- "public/frame_priority/max_vote_aggregator.h",
- "public/frame_priority/override_vote_aggregator.h",
"public/graph/frame_node.h",
"public/graph/graph.h",
"public/graph/graph_operations.h",
@@ -120,7 +125,9 @@ static_library("performance_manager") {
"public/render_frame_host_proxy.h",
"public/render_process_host_id.h",
"public/render_process_host_proxy.h",
- "public/v8_memory/v8_per_frame_memory_decorator.h",
+ "public/v8_memory/v8_detailed_memory.h",
+ "public/v8_memory/web_memory.h",
+ "public/voting/voting.h",
"public/web_contents_proxy.h",
"registered_objects.h",
"render_frame_host_proxy.cc",
@@ -133,11 +140,15 @@ static_library("performance_manager") {
"service_worker_context_adapter.h",
"tab_helper_frame_node_source.cc",
"tab_helper_frame_node_source.h",
+ "v8_memory/v8_context_tracker.cc",
+ "v8_memory/v8_context_tracker.h",
"v8_memory/v8_context_tracker_helpers.cc",
"v8_memory/v8_context_tracker_helpers.h",
- "v8_memory/v8_context_tracker_types.cc",
- "v8_memory/v8_context_tracker_types.h",
- "v8_memory/v8_per_frame_memory_decorator.cc",
+ "v8_memory/v8_context_tracker_internal.cc",
+ "v8_memory/v8_context_tracker_internal.h",
+ "v8_memory/v8_detailed_memory.cc",
+ "v8_memory/web_memory_aggregator.cc",
+ "v8_memory/web_memory_aggregator.h",
"web_contents_proxy.cc",
"web_contents_proxy_impl.cc",
"web_contents_proxy_impl.h",
@@ -198,14 +209,17 @@ source_set("unit_tests") {
sources = [
"decorators/decorators_utils_unittest.cc",
+ "decorators/frame_visibility_decorator_unittest.cc",
"decorators/page_live_state_decorator_unittest.cc",
"decorators/page_load_tracker_decorator_unittest.cc",
"decorators/tab_properties_decorator_unittest.cc",
+ "execution_context/execution_context_attached_data_unittest.cc",
"execution_context/execution_context_registry_impl_unittest.cc",
- "frame_priority/boosting_vote_aggregator_unittest.cc",
- "frame_priority/frame_priority_unittest.cc",
- "frame_priority/max_vote_aggregator_unittest.cc",
- "frame_priority/override_vote_aggregator_unittest.cc",
+ "execution_context_priority/boosting_vote_aggregator_unittest.cc",
+ "execution_context_priority/execution_context_priority_unittest.cc",
+ "execution_context_priority/max_vote_aggregator_unittest.cc",
+ "execution_context_priority/override_vote_aggregator_unittest.cc",
+ "freezing/freezing_vote_aggregator_unittest.cc",
"graph/frame_node_impl_unittest.cc",
"graph/graph_impl_operations_unittest.cc",
"graph/graph_impl_unittest.cc",
@@ -227,8 +241,15 @@ source_set("unit_tests") {
"performance_manager_tab_helper_unittest.cc",
"performance_manager_unittest.cc",
"registered_objects_unittest.cc",
+ "render_process_host_id_unittest.cc",
"v8_memory/v8_context_tracker_helpers_unittest.cc",
- "v8_memory/v8_per_frame_memory_decorator_unittest.cc",
+ "v8_memory/v8_context_tracker_internal_unittest.cc",
+ "v8_memory/v8_context_tracker_unittest.cc",
+ "v8_memory/v8_detailed_memory_unittest.cc",
+ "v8_memory/v8_memory_test_helpers.cc",
+ "v8_memory/v8_memory_test_helpers.h",
+ "v8_memory/web_memory_aggregator_unittest.cc",
+ "voting_unittest.cc",
"web_contents_proxy_unittest.cc",
"worker_watcher_unittest.cc",
]
@@ -270,6 +291,7 @@ source_set("browser_tests") {
"mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc",
"performance_manager_browsertest.cc",
"render_process_host_proxy_browsertest.cc",
+ "v8_memory/v8_context_tracker_browsertest.cc",
]
deps = [
diff --git a/chromium/components/performance_manager/DEPS b/chromium/components/performance_manager/DEPS
index eb9f102bb79..ae079ef1ff9 100644
--- a/chromium/components/performance_manager/DEPS
+++ b/chromium/components/performance_manager/DEPS
@@ -8,10 +8,12 @@ include_rules = [
"+net/test",
"+services/metrics/public/cpp",
"+services/service_manager/public/cpp",
+ "+third_party/blink/public/common/features.h",
"+third_party/blink/public/common/tokens",
"+third_party/blink/public/mojom/favicon",
"+third_party/blink/public/mojom/performance_manager",
"+third_party/blink/public/mojom/service_worker",
"+third_party/blink/public/mojom/tokens",
"+third_party/leveldatabase",
+ "+ui/gfx/geometry",
]
diff --git a/chromium/components/performance_manager/decorators/decorators_utils_unittest.cc b/chromium/components/performance_manager/decorators/decorators_utils_unittest.cc
index c65db07fe2c..f494a86a84d 100644
--- a/chromium/components/performance_manager/decorators/decorators_utils_unittest.cc
+++ b/chromium/components/performance_manager/decorators/decorators_utils_unittest.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/graph/node_attached_data_impl.h"
#include "components/performance_manager/test_support/performance_manager_test_harness.h"
#include "content/public/browser/web_contents.h"
diff --git a/chromium/components/performance_manager/decorators/frame_visibility_decorator.cc b/chromium/components/performance_manager/decorators/frame_visibility_decorator.cc
new file mode 100644
index 00000000000..283960d8909
--- /dev/null
+++ b/chromium/components/performance_manager/decorators/frame_visibility_decorator.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 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/performance_manager/decorators/frame_visibility_decorator.h"
+
+#include "components/performance_manager/graph/frame_node_impl.h"
+#include "components/performance_manager/graph/page_node_impl.h"
+
+namespace performance_manager {
+
+namespace {
+
+FrameNode::Visibility GetFrameNodeVisibility(FrameNodeImpl* frame_node,
+ bool is_page_visible) {
+ // All frames of a page are not visible if the page is not visible.
+ if (!is_page_visible)
+ return FrameNode::Visibility::kNotVisible;
+
+ // A main frame is always visible if the page is visible.
+ if (frame_node->IsMainFrame())
+ return FrameNode::Visibility::kVisible;
+
+ // No viewport intersection. Can't determine the visibility.
+ if (!frame_node->viewport_intersection().has_value())
+ return FrameNode::Visibility::kUnknown;
+
+ // A non-empty viewport intersection denotes a visible frame.
+ if (!frame_node->viewport_intersection()->IsEmpty())
+ return FrameNode::Visibility::kVisible;
+
+ // Empty viewport intersection. The frame is thus not visible.
+ return FrameNode::Visibility::kNotVisible;
+}
+
+// Update a frame node's visibility following a change in the page visibility.
+void UpdateFrameVisibility(FrameNodeImpl* frame_node, bool is_page_visible) {
+ FrameNode::Visibility visibility =
+ GetFrameNodeVisibility(frame_node, is_page_visible);
+
+ frame_node->SetVisibility(visibility);
+
+ for (FrameNodeImpl* child_frame_node : frame_node->child_frame_nodes())
+ UpdateFrameVisibility(child_frame_node, is_page_visible);
+}
+
+} // namespace
+
+FrameVisibilityDecorator::FrameVisibilityDecorator() = default;
+
+FrameVisibilityDecorator::~FrameVisibilityDecorator() = default;
+
+void FrameVisibilityDecorator::OnPassedToGraph(Graph* graph) {
+ DCHECK(graph->IsEmpty());
+ graph->AddPageNodeObserver(this);
+ graph->AddFrameNodeObserver(this);
+}
+
+void FrameVisibilityDecorator::OnTakenFromGraph(Graph* graph) {
+ graph->RemoveFrameNodeObserver(this);
+ graph->RemovePageNodeObserver(this);
+}
+
+void FrameVisibilityDecorator::OnIsVisibleChanged(const PageNode* page_node) {
+ PageNodeImpl* page_node_impl = PageNodeImpl::FromNode(page_node);
+
+ // A page can sometimes have no main frame.
+ FrameNodeImpl* main_frame_node = page_node_impl->GetMainFrameNodeImpl();
+ if (!main_frame_node)
+ return;
+
+ UpdateFrameVisibility(main_frame_node, page_node_impl->is_visible());
+}
+
+void FrameVisibilityDecorator::OnViewportIntersectionChanged(
+ const FrameNode* frame_node) {
+ DCHECK(!frame_node->IsMainFrame());
+ DCHECK(frame_node->GetViewportIntersection().has_value());
+
+ FrameNodeImpl* frame_node_impl = FrameNodeImpl::FromNode(frame_node);
+ FrameNode::Visibility visibility = GetFrameNodeVisibility(
+ frame_node_impl, frame_node_impl->page_node()->is_visible());
+
+ // Compare to the old value.
+ if (visibility == frame_node_impl->visibility())
+ return;
+
+ frame_node_impl->SetVisibility(visibility);
+}
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/decorators/frame_visibility_decorator.h b/chromium/components/performance_manager/decorators/frame_visibility_decorator.h
new file mode 100644
index 00000000000..4eb3780cb5f
--- /dev/null
+++ b/chromium/components/performance_manager/decorators/frame_visibility_decorator.h
@@ -0,0 +1,44 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_DECORATORS_FRAME_VISIBILITY_DECORATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_DECORATORS_FRAME_VISIBILITY_DECORATOR_H_
+
+#include "components/performance_manager/public/graph/frame_node.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/page_node.h"
+
+namespace performance_manager {
+
+// A decorator that observes changes to the visibility of all pages, and the
+// viewport intersection of all frames, and decorates each frame with their
+// visibility.
+//
+// Currently, all frame nodes are added with an empty viewport intersection.
+// Shorty after creation, a OnViewportIntersectionChanged() notification is
+// expected.
+class FrameVisibilityDecorator : public GraphOwnedDefaultImpl,
+ public FrameNode::ObserverDefaultImpl,
+ public PageNode::ObserverDefaultImpl {
+ public:
+ FrameVisibilityDecorator();
+ ~FrameVisibilityDecorator() override;
+
+ FrameVisibilityDecorator(const FrameVisibilityDecorator&) = delete;
+ FrameVisibilityDecorator& operator=(const FrameVisibilityDecorator&) = delete;
+
+ // GraphOwned:
+ void OnPassedToGraph(Graph* graph) override;
+ void OnTakenFromGraph(Graph* graph) override;
+
+ // PageNodeObserver:
+ void OnIsVisibleChanged(const PageNode* page_node) override;
+
+ // FrameNodeObserver:
+ void OnViewportIntersectionChanged(const FrameNode* frame_node) override;
+};
+
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_DECORATORS_FRAME_VISIBILITY_DECORATOR_H_
diff --git a/chromium/components/performance_manager/decorators/frame_visibility_decorator_unittest.cc b/chromium/components/performance_manager/decorators/frame_visibility_decorator_unittest.cc
new file mode 100644
index 00000000000..ced899faaa6
--- /dev/null
+++ b/chromium/components/performance_manager/decorators/frame_visibility_decorator_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright 2020 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/performance_manager/decorators/frame_visibility_decorator.h"
+
+#include <memory>
+
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace performance_manager {
+
+namespace {
+
+static constexpr gfx::Rect kEmptyIntersection(0, 0, 0, 0);
+static constexpr gfx::Rect kNonEmptyIntersection(0, 0, 10, 10);
+
+} // namespace
+
+class FrameVisibilityDecoratorTest : public GraphTestHarness {
+ public:
+ FrameVisibilityDecoratorTest() = default;
+ ~FrameVisibilityDecoratorTest() override = default;
+
+ void SetUp() override {
+ graph()->PassToGraph(std::make_unique<FrameVisibilityDecorator>());
+
+ process_node_ = CreateNode<ProcessNodeImpl>();
+ }
+
+ ProcessNodeImpl* process_node() const { return process_node_.get(); }
+
+ private:
+ TestNodeWrapper<ProcessNodeImpl> process_node_;
+};
+
+TEST_F(FrameVisibilityDecoratorTest, SetPageVisible) {
+ auto page_node = CreateNode<PageNodeImpl>();
+ EXPECT_FALSE(page_node->is_visible());
+
+ // Create a frame node.
+ auto frame_node = CreateFrameNodeAutoId(process_node(), page_node.get());
+
+ // Starts not visible because the page is not visible.
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kNotVisible);
+
+ // Make the page visible.
+ page_node->SetIsVisible(true);
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kVisible);
+
+ // Make the page not visible again.
+ page_node->SetIsVisible(false);
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kNotVisible);
+}
+
+TEST_F(FrameVisibilityDecoratorTest, SetPageVisibleWithChildNodes) {
+ auto page_node = CreateNode<PageNodeImpl>();
+ EXPECT_FALSE(page_node->is_visible());
+
+ // Create a main frame node.
+ auto main_frame_node = CreateFrameNodeAutoId(process_node(), page_node.get());
+
+ // Create a child frame node with a non-empty viewport intersection.
+ auto intersecting_child_frame_node = CreateFrameNodeAutoId(
+ process_node(), page_node.get(), main_frame_node.get());
+ intersecting_child_frame_node->SetViewportIntersection(kNonEmptyIntersection);
+
+ // Create a child frame node with an empty viewport intersection.
+ auto non_intersecting_child_frame_node = CreateFrameNodeAutoId(
+ process_node(), page_node.get(), main_frame_node.get());
+ non_intersecting_child_frame_node->SetViewportIntersection(
+ kEmptyIntersection);
+
+ // Create a child frame node with no viewport intersection
+ auto no_intersection_child_frame_node = CreateFrameNodeAutoId(
+ process_node(), page_node.get(), main_frame_node.get());
+
+ // Starts not visible because the page is not visible.
+ EXPECT_EQ(main_frame_node->visibility(), FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(non_intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(no_intersection_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+
+ // Make the page visible.
+ page_node->SetIsVisible(true);
+ EXPECT_EQ(main_frame_node->visibility(), FrameNode::Visibility::kVisible);
+ EXPECT_EQ(intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kVisible);
+ // The frame with an empty viewport intersection is still not visible.
+ EXPECT_EQ(non_intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+ // The frame with no viewport intersection has an unknown visibility.
+ EXPECT_EQ(no_intersection_child_frame_node->visibility(),
+ FrameNode::Visibility::kUnknown);
+
+ // Make the page not visible again.
+ page_node->SetIsVisible(false);
+ EXPECT_EQ(main_frame_node->visibility(), FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(non_intersecting_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+ EXPECT_EQ(no_intersection_child_frame_node->visibility(),
+ FrameNode::Visibility::kNotVisible);
+}
+
+TEST_F(FrameVisibilityDecoratorTest, SetFrameViewportIntersection) {
+ auto page_node = CreateNode<PageNodeImpl>();
+ page_node->SetIsVisible(true);
+ auto main_frame_node = CreateFrameNodeAutoId(process_node(), page_node.get());
+
+ // Create a test frame node with no viewport intersection.
+ auto frame_node = CreateFrameNodeAutoId(process_node(), page_node.get(),
+ main_frame_node.get());
+ EXPECT_FALSE(frame_node->viewport_intersection().has_value());
+
+ // Create a child frame node with no viewport_intersection.
+ auto child_frame_node =
+ CreateFrameNodeAutoId(process_node(), page_node.get(), frame_node.get());
+ EXPECT_FALSE(child_frame_node->viewport_intersection().has_value());
+
+ // Both frames have an unknown visibility because their viewport intersection
+ // hasn't been determined yet.
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kUnknown);
+ EXPECT_EQ(child_frame_node->visibility(), FrameNode::Visibility::kUnknown);
+
+ // Set the viewport intersection of the test frame to a non-empty one.
+ frame_node->SetViewportIntersection(kNonEmptyIntersection);
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kVisible);
+ EXPECT_EQ(child_frame_node->visibility(), FrameNode::Visibility::kUnknown);
+
+ // Set the viewport intersection of the child frame to a non-empty one.
+ child_frame_node->SetViewportIntersection(kNonEmptyIntersection);
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kVisible);
+ EXPECT_EQ(child_frame_node->visibility(), FrameNode::Visibility::kVisible);
+}
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/decorators/site_data_recorder_unittest.cc b/chromium/components/performance_manager/decorators/site_data_recorder_unittest.cc
index bc89aeac045..854d875055b 100644
--- a/chromium/components/performance_manager/decorators/site_data_recorder_unittest.cc
+++ b/chromium/components/performance_manager/decorators/site_data_recorder_unittest.cc
@@ -10,7 +10,7 @@
#include "base/location.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequence_bound.h"
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/persistence/site_data/site_data_cache.h"
@@ -316,7 +316,7 @@ TEST_F(SiteDataRecorderTest, FeatureEventsGetForwardedWhenInBackground) {
EXPECT_CALL(*mock_writer, NotifySiteUnloaded(TabVisibility::kBackground));
}));
- NavigatePageNodeOnUIThread(web_contents(), GURL("about://blank"));
+ NavigatePageNodeOnUIThread(web_contents(), GURL("about:blank"));
}
TEST_F(SiteDataRecorderTest, FeatureEventsIgnoredWhenLoadingInBackground) {
diff --git a/chromium/components/performance_manager/embedder/performance_manager_lifetime.h b/chromium/components/performance_manager/embedder/performance_manager_lifetime.h
index 09594171792..ee195fb331d 100644
--- a/chromium/components/performance_manager/embedder/performance_manager_lifetime.h
+++ b/chromium/components/performance_manager/embedder/performance_manager_lifetime.h
@@ -26,6 +26,10 @@ class PerformanceManagerLifetime {
PerformanceManagerLifetime(Decorators, GraphCreatedCallback);
~PerformanceManagerLifetime();
+ // Allows specifying an additional callback that will be invoked in tests.
+ static void SetAdditionalGraphCreatedCallbackForTesting(
+ GraphCreatedCallback graph_created_callback);
+
private:
std::unique_ptr<PerformanceManager> performance_manager_;
std::unique_ptr<PerformanceManagerRegistry> performance_manager_registry_;
diff --git a/chromium/components/performance_manager/execution_context/execution_context_attached_data_unittest.cc b/chromium/components/performance_manager/execution_context/execution_context_attached_data_unittest.cc
new file mode 100644
index 00000000000..e7749d0cd06
--- /dev/null
+++ b/chromium/components/performance_manager/execution_context/execution_context_attached_data_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright 2020 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/performance_manager/public/execution_context/execution_context_attached_data.h"
+
+#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "components/performance_manager/test_support/mock_graphs.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace execution_context {
+
+namespace {
+
+class FakeData : public ExecutionContextAttachedData<FakeData> {
+ public:
+ FakeData() = default;
+ explicit FakeData(const ExecutionContext* ec) {}
+ ~FakeData() override = default;
+};
+
+class ExecutionContextAttachedDataTest : public GraphTestHarness {
+ public:
+ using Super = GraphTestHarness;
+
+ ExecutionContextAttachedDataTest() = default;
+ ExecutionContextAttachedDataTest(const ExecutionContextAttachedDataTest&) =
+ delete;
+ ExecutionContextAttachedDataTest& operator=(
+ const ExecutionContextAttachedDataTest&) = delete;
+ ~ExecutionContextAttachedDataTest() override = default;
+
+ void SetUp() override {
+ Super::SetUp();
+ graph()->PassToGraph(std::make_unique<ExecutionContextRegistryImpl>());
+ registry_ = GraphRegisteredImpl<ExecutionContextRegistryImpl>::GetFromGraph(
+ graph());
+ ASSERT_TRUE(registry_);
+ }
+
+ protected:
+ ExecutionContextRegistryImpl* registry_ = nullptr;
+};
+
+} // namespace
+
+TEST_F(ExecutionContextAttachedDataTest, AdapterWorks) {
+ MockMultiplePagesAndWorkersWithMultipleProcessesGraph mock_graph(graph());
+
+ auto* ec1 =
+ registry_->GetExecutionContextForFrameNode(mock_graph.frame.get());
+ auto* ec2 =
+ registry_->GetExecutionContextForWorkerNode(mock_graph.worker.get());
+
+ EXPECT_FALSE(FakeData::Destroy(ec1));
+ FakeData* fd1 = FakeData::Get(ec1);
+ EXPECT_FALSE(fd1);
+ fd1 = FakeData::GetOrCreate(ec1);
+ EXPECT_TRUE(fd1);
+ EXPECT_EQ(fd1, FakeData::Get(ec1));
+ EXPECT_TRUE(FakeData::Destroy(ec1));
+ EXPECT_FALSE(FakeData::Get(ec1));
+
+ EXPECT_FALSE(FakeData::Destroy(ec2));
+ FakeData* fd2 = FakeData::Get(ec2);
+ EXPECT_FALSE(fd2);
+ fd2 = FakeData::GetOrCreate(ec2);
+ EXPECT_TRUE(fd2);
+ EXPECT_EQ(fd2, FakeData::Get(ec2));
+ EXPECT_TRUE(FakeData::Destroy(ec2));
+ EXPECT_FALSE(FakeData::Get(ec2));
+}
+
+} // namespace execution_context
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/execution_context/execution_context_impl.cc b/chromium/components/performance_manager/execution_context/execution_context_impl.cc
index ac101581054..b3a6321c0f1 100644
--- a/chromium/components/performance_manager/execution_context/execution_context_impl.cc
+++ b/chromium/components/performance_manager/execution_context/execution_context_impl.cc
@@ -68,17 +68,20 @@ class ExecutionContextImpl : public ExecutionContext,
return node_->process_node();
}
+ // Returns the current priority of the execution context, and the reason for
+ // the execution context having that particular priority.
+ const PriorityAndReason& GetPriorityAndReason() const override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return node_->priority_and_reason();
+ }
+
const FrameNode* GetFrameNode() const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (std::is_same<FrameNodeImpl, NodeImplType>::value)
- return reinterpret_cast<const FrameNode*>(node_);
return nullptr;
}
const WorkerNode* GetWorkerNode() const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (std::is_same<WorkerNodeImpl, NodeImplType>::value)
- return reinterpret_cast<const WorkerNodeImpl*>(node_);
return nullptr;
}
@@ -113,6 +116,11 @@ class FrameExecutionContext
return blink::ExecutionContextToken(node_->frame_token());
}
+ const FrameNode* GetFrameNode() const override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return node_;
+ }
+
protected:
friend class NodeAttachedDataImpl<FrameExecutionContext>;
explicit FrameExecutionContext(const FrameNodeImpl* frame_node)
@@ -136,6 +144,11 @@ class WorkerExecutionContext
return ToExecutionContextToken(node_->worker_token());
}
+ const WorkerNode* GetWorkerNode() const override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return node_;
+ }
+
protected:
friend class NodeAttachedDataImpl<WorkerExecutionContext>;
explicit WorkerExecutionContext(const WorkerNodeImpl* worker_node)
diff --git a/chromium/components/performance_manager/execution_context/execution_context_registry_impl.cc b/chromium/components/performance_manager/execution_context/execution_context_registry_impl.cc
index d3e2a701172..c3d7d85c909 100644
--- a/chromium/components/performance_manager/execution_context/execution_context_registry_impl.cc
+++ b/chromium/components/performance_manager/execution_context/execution_context_registry_impl.cc
@@ -52,6 +52,12 @@ class DummyExecutionContextForLookup : public ExecutionContext {
return nullptr;
}
+ const PriorityAndReason& GetPriorityAndReason() const override {
+ NOTREACHED();
+ static const PriorityAndReason kPriorityAndReason;
+ return kPriorityAndReason;
+ }
+
const FrameNode* GetFrameNode() const override {
NOTREACHED();
return nullptr;
@@ -74,7 +80,6 @@ class DummyExecutionContextForLookup : public ExecutionContext {
ExecutionContextRegistry::ExecutionContextRegistry() = default;
ExecutionContextRegistry::~ExecutionContextRegistry() = default;
-
// static
ExecutionContextRegistry* ExecutionContextRegistry::GetFromGraph(Graph* graph) {
return GraphRegisteredImpl<ExecutionContextRegistryImpl>::GetFromGraph(graph);
@@ -93,6 +98,12 @@ void ExecutionContextRegistryImpl::AddObserver(
observers_.AddObserver(observer);
}
+bool ExecutionContextRegistryImpl::HasObserver(
+ ExecutionContextObserver* observer) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return observers_.HasObserver(observer);
+}
+
void ExecutionContextRegistryImpl::RemoveObserver(
ExecutionContextObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -143,6 +154,21 @@ ExecutionContextRegistryImpl::GetExecutionContextForWorkerNode(
return GetOrCreateExecutionContextForWorkerNode(worker_node);
}
+void ExecutionContextRegistryImpl::OnPassedToGraph(Graph* graph) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(graph->IsEmpty());
+ graph->RegisterObject(this);
+ graph->AddFrameNodeObserver(this);
+ graph->AddWorkerNodeObserver(this);
+}
+
+void ExecutionContextRegistryImpl::OnTakenFromGraph(Graph* graph) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ graph->RemoveWorkerNodeObserver(this);
+ graph->RemoveFrameNodeObserver(this);
+ graph->UnregisterObject(this);
+}
+
void ExecutionContextRegistryImpl::OnFrameNodeAdded(
const FrameNode* frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -165,19 +191,14 @@ void ExecutionContextRegistryImpl::OnBeforeFrameNodeRemoved(
DCHECK_EQ(1u, erased);
}
-void ExecutionContextRegistryImpl::OnPassedToGraph(Graph* graph) {
+void ExecutionContextRegistryImpl::OnPriorityAndReasonChanged(
+ const FrameNode* frame_node,
+ const PriorityAndReason& previous_value) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(graph->IsEmpty());
- graph->RegisterObject(this);
- graph->AddFrameNodeObserver(this);
- graph->AddWorkerNodeObserver(this);
-}
-
-void ExecutionContextRegistryImpl::OnTakenFromGraph(Graph* graph) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- graph->RemoveWorkerNodeObserver(this);
- graph->RemoveFrameNodeObserver(this);
- graph->UnregisterObject(this);
+ auto* ec = GetOrCreateExecutionContextForFrameNode(frame_node);
+ DCHECK(ec);
+ for (auto& observer : observers_)
+ observer.OnPriorityAndReasonChanged(ec, previous_value);
}
void ExecutionContextRegistryImpl::OnWorkerNodeAdded(
@@ -205,6 +226,16 @@ void ExecutionContextRegistryImpl::OnBeforeWorkerNodeRemoved(
DCHECK_EQ(1u, erased);
}
+void ExecutionContextRegistryImpl::OnPriorityAndReasonChanged(
+ const WorkerNode* worker_node,
+ const PriorityAndReason& previous_value) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auto* ec = GetOrCreateExecutionContextForWorkerNode(worker_node);
+ DCHECK(ec);
+ for (auto& observer : observers_)
+ observer.OnPriorityAndReasonChanged(ec, previous_value);
+}
+
////////////////////////////////////////////////////////////////////////////////
// ExecutionContextRegistryImpl::ExecutionContextHash
diff --git a/chromium/components/performance_manager/execution_context/execution_context_registry_impl.h b/chromium/components/performance_manager/execution_context/execution_context_registry_impl.h
index 838877d24c7..129f29ee173 100644
--- a/chromium/components/performance_manager/execution_context/execution_context_registry_impl.h
+++ b/chromium/components/performance_manager/execution_context/execution_context_registry_impl.h
@@ -25,9 +25,9 @@ class ExecutionContext;
// to any nodes being created.
class ExecutionContextRegistryImpl
: public ExecutionContextRegistry,
- public FrameNode::ObserverDefaultImpl,
public GraphOwned,
public GraphRegisteredImpl<ExecutionContextRegistryImpl>,
+ public FrameNode::ObserverDefaultImpl,
public WorkerNode::ObserverDefaultImpl {
public:
ExecutionContextRegistryImpl();
@@ -38,6 +38,7 @@ class ExecutionContextRegistryImpl
// ExecutionContextRegistry implementation:
void AddObserver(ExecutionContextObserver* observer) override;
+ bool HasObserver(ExecutionContextObserver* observer) const override;
void RemoveObserver(ExecutionContextObserver* observer) override;
const ExecutionContext* GetExecutionContextByToken(
const blink::ExecutionContextToken& token) override;
@@ -55,17 +56,23 @@ class ExecutionContextRegistryImpl
}
private:
- // FrameNode::ObserverDefaultImpl implementation:
- void OnFrameNodeAdded(const FrameNode* frame_node) override;
- void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override;
-
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override;
void OnTakenFromGraph(Graph* graph) override;
+ // FrameNode::ObserverDefaultImpl implementation:
+ void OnFrameNodeAdded(const FrameNode* frame_node) override;
+ void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override;
+ void OnPriorityAndReasonChanged(
+ const FrameNode* frame_node,
+ const PriorityAndReason& previous_value) override;
+
// WorkerNode::ObserverDefaultImpl implementation:
void OnWorkerNodeAdded(const WorkerNode* worker_node) override;
void OnBeforeWorkerNodeRemoved(const WorkerNode* worker_node) override;
+ void OnPriorityAndReasonChanged(
+ const WorkerNode* worker_node,
+ const PriorityAndReason& previous_value) override;
// Maintains the collection of all currently known ExecutionContexts in the
// Graph. It is expected that there are O(100s) to O(1000s) of these being
@@ -84,7 +91,9 @@ class ExecutionContextRegistryImpl
ExecutionContextKeyEqual>
execution_contexts_;
- base::ObserverList<ExecutionContextObserver, /* check_empty = */ true>
+ base::ObserverList<ExecutionContextObserver,
+ /* check_empty = */ true,
+ /* allow_reentrancy */ false>
observers_;
SEQUENCE_CHECKER(sequence_checker_);
@@ -93,4 +102,4 @@ class ExecutionContextRegistryImpl
} // namespace execution_context
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_REGISTRY_H_ \ No newline at end of file
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_REGISTRY_H_
diff --git a/chromium/components/performance_manager/execution_context/execution_context_registry_impl_unittest.cc b/chromium/components/performance_manager/execution_context/execution_context_registry_impl_unittest.cc
index 1dcb9f1389d..7c61304bc99 100644
--- a/chromium/components/performance_manager/execution_context/execution_context_registry_impl_unittest.cc
+++ b/chromium/components/performance_manager/execution_context/execution_context_registry_impl_unittest.cc
@@ -35,6 +35,11 @@ class LenientMockExecutionContextObserver : public ExecutionContextObserver {
OnBeforeExecutionContextRemoved,
(const ExecutionContext*),
());
+ MOCK_METHOD(void,
+ OnPriorityAndReasonChanged,
+ (const ExecutionContext*,
+ const PriorityAndReason& previous_value),
+ ());
};
using MockExecutionContextObserver =
testing::StrictMock<LenientMockExecutionContextObserver>;
@@ -70,29 +75,16 @@ TEST_F(ExecutionContextRegistryImplTest, RegistryWorks) {
// Ensure that the public getter works.
EXPECT_EQ(registry_, ExecutionContextRegistry::GetFromGraph(graph()));
- // Create an observer.
- MockExecutionContextObserver obs;
- registry_->AddObserver(&obs);
-
// Create some mock nodes. This creates a graph with 1 page containing 2
// frames in 1 process.
- std::vector<const ExecutionContext*> ecs;
- EXPECT_CALL(obs, OnExecutionContextAdded(testing::_))
- .Times(2)
- .WillRepeatedly(
- [&ecs](const ExecutionContext* ec) { ecs.push_back(ec); });
MockMultiplePagesInSingleProcessGraph mock_graph(graph());
// Only the frames are in the map at this point.
- EXPECT_EQ(2u, ecs.size());
EXPECT_EQ(2u, registry_->GetExecutionContextCountForTesting());
// Creating a worker should create another entry in the map.
- EXPECT_CALL(obs, OnExecutionContextAdded(testing::_))
- .WillOnce([&ecs](const ExecutionContext* ec) { ecs.push_back(ec); });
auto worker_node = CreateNode<WorkerNodeImpl>(
WorkerNode::WorkerType::kDedicated, mock_graph.process.get());
- EXPECT_EQ(3u, ecs.size());
EXPECT_EQ(3u, registry_->GetExecutionContextCountForTesting());
auto* frame1 = mock_graph.frame.get();
@@ -104,11 +96,6 @@ TEST_F(ExecutionContextRegistryImplTest, RegistryWorks) {
auto* frame2_ec = GetOrCreateExecutionContextForFrameNode(frame2);
auto* worker_ec = GetOrCreateExecutionContextForWorkerNode(worker);
- // Expect them to match those that were seen by the observer.
- EXPECT_EQ(ecs[0], frame1_ec);
- EXPECT_EQ(ecs[1], frame2_ec);
- EXPECT_EQ(ecs[2], worker_ec);
-
// Expect the FrameExecutionContext implementation to work.
EXPECT_EQ(ExecutionContextType::kFrameNode, frame1_ec->GetType());
EXPECT_EQ(frame1->frame_token().value(), frame1_ec->GetToken().value());
@@ -152,15 +139,45 @@ TEST_F(ExecutionContextRegistryImplTest, RegistryWorks) {
registry_->GetExecutionContextByToken(blink::ExecutionContextToken()));
EXPECT_FALSE(registry_->GetFrameNodeByFrameToken(blink::LocalFrameToken()));
EXPECT_FALSE(registry_->GetWorkerNodeByWorkerToken(blink::WorkerToken()));
+}
+
+TEST_F(ExecutionContextRegistryImplTest, Observers) {
+ // Create an observer.
+ MockExecutionContextObserver obs;
+ EXPECT_FALSE(registry_->HasObserver(&obs));
+ registry_->AddObserver(&obs);
+ EXPECT_TRUE(registry_->HasObserver(&obs));
+
+ // Create some mock nodes. This creates a graph with 1 page containing 1 frame
+ // and 1 worker in a single process.
+ EXPECT_CALL(obs, OnExecutionContextAdded(testing::_)).Times(2);
+ MockSinglePageWithFrameAndWorkerInSingleProcessGraph mock_graph(graph());
+
+ // The registry has 2 entries: the frame and the worker.
+ EXPECT_EQ(2u, registry_->GetExecutionContextCountForTesting());
+
+ auto* frame = mock_graph.frame.get();
+ auto* worker = mock_graph.worker.get();
+
+ // Get the execution contexts for each node directly.
+ auto* frame_ec = GetOrCreateExecutionContextForFrameNode(frame);
+ auto* worker_ec = GetOrCreateExecutionContextForWorkerNode(worker);
+
+ // Set the priority and reason of the frame and expect a notification.
+ EXPECT_CALL(obs, OnPriorityAndReasonChanged(frame_ec, testing::_));
+ frame->SetPriorityAndReason(
+ PriorityAndReason(base::TaskPriority::HIGHEST, "frame reason"));
+
+ // Set the priority and reason of the worker and expect a notification.
+ EXPECT_CALL(obs, OnPriorityAndReasonChanged(worker_ec, testing::_));
+ worker->SetPriorityAndReason(
+ PriorityAndReason(base::TaskPriority::HIGHEST, "worker reason"));
// Destroy nodes one by one and expect observer notifications.
EXPECT_CALL(obs, OnBeforeExecutionContextRemoved(worker_ec));
- worker_node.reset();
- EXPECT_EQ(2u, registry_->GetExecutionContextCountForTesting());
- EXPECT_CALL(obs, OnBeforeExecutionContextRemoved(frame2_ec));
- mock_graph.other_frame.reset();
+ mock_graph.DeleteWorker();
EXPECT_EQ(1u, registry_->GetExecutionContextCountForTesting());
- EXPECT_CALL(obs, OnBeforeExecutionContextRemoved(frame1_ec));
+ EXPECT_CALL(obs, OnBeforeExecutionContextRemoved(frame_ec));
mock_graph.frame.reset();
EXPECT_EQ(0u, registry_->GetExecutionContextCountForTesting());
diff --git a/chromium/components/performance_manager/frame_priority/boosting_vote_aggregator.cc b/chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator.cc
index bbe5caf8490..051345b1dbb 100644
--- a/chromium/components/performance_manager/frame_priority/boosting_vote_aggregator.cc
+++ b/chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator.cc
@@ -2,28 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
-
-#include "components/performance_manager/public/frame_priority/boosting_vote_aggregator.h"
+#include "components/performance_manager/public/execution_context_priority/boosting_vote_aggregator.h"
#include <algorithm>
#include <tuple>
#include <utility>
#include "base/stl_util.h"
-#include "components/performance_manager/public/graph/frame_node.h"
+#include "components/performance_manager/public/execution_context/execution_context.h"
// This voter allows expressing "priority boosts" which are used to resolve
// priority inversions. These priority inversions are a result of resource
-// contention. For example, consider frames f0 and f1, where f0 holds a WebLock
-// and f1 is waiting to acquire that WebLock. If the priority of f0 is below
-// that of frame f1 then its priority needs to be boosted in order to prevent
-// a priority inversion.
+// contention. For example, consider execution contexts ec0 and ec1, where ec0
+// holds a WebLock and ec1 is waiting to acquire that WebLock. If the priority
+// of ec0 is below that of execution context ec1 then its priority needs to be
+// boosted in order to prevent a priority inversion.
//
// We represent this resource contention relationship with a directed edge from
-// f1 -> f0, which expresses the fact that f1 is waiting on a resource held by
-// f0. We instrument APIs that provide shared access to resources (WebLocks,
+// ec1 -> ec0, which expresses the fact that ec1 is waiting on a resource held
+// by ec0. We instrument APIs that provide shared access to resources (WebLocks,
// IndexedDB, etc) and they serve as factories of edges, expressing their "wait
// lists" to the BoostingVoteAggregator. This graph will in general be quite
// sparse and consist of directed acyclic components (one per shared resource),
@@ -31,13 +28,14 @@
// effectively indicates web content that has expressed a dead lock, so while
// possible it is unlikely.)
//
-// Nodes in the graph represent frames, which themselves have baseline
-// priorities that are calculated based on a variety of factors (visibility,
-// type of content, ...). These priorities flow along edges if the next node has
-// a lower priority, "boosting" the priority of the destination node in order to
-// resolve priority inversions. Since the graph is finite and the flow is in one
-// direction only this process is guaranteed to converge for any given graph and
-// set of baseline priorities. We call this graph the "priority flow graph".
+// Nodes in the graph represent execution contexts, which themselves have
+// baseline priorities that are calculated based on a variety of factors
+// (visibility, type of content, ...). These priorities flow along edges if the
+// next node has a lower priority, "boosting" the priority of the destination
+// node in order to resolve priority inversions. Since the graph is finite and
+// the flow is in one direction only this process is guaranteed to converge for
+// any given graph and set of baseline priorities. We call this graph the
+// "priority flow graph".
//
// We break this down into a separate graph problem per priority level. We
// define a virtual "source" node, and create directed edges from that source
@@ -89,7 +87,7 @@
// the tree relationship rather than creating simple cycles.
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
namespace {
@@ -111,18 +109,18 @@ static constexpr uint32_t kLastLayerBit =
PriorityToBit(base::TaskPriority::HIGHEST);
static_assert(kFirstLayerBit < kLastLayerBit, "expect more than 1 layer");
-static const FrameNode* kMaxFrameNode =
- reinterpret_cast<const FrameNode*>(static_cast<uintptr_t>(0) - 1);
+static const ExecutionContext* kMaxExecutionContext =
+ reinterpret_cast<const ExecutionContext*>(static_cast<uintptr_t>(0) - 1);
} // namespace
BoostingVote::BoostingVote(BoostingVoteAggregator* aggregator,
- const FrameNode* input_frame,
- const FrameNode* output_frame,
+ const ExecutionContext* input_execution_context,
+ const ExecutionContext* output_execution_context,
const char* reason)
: aggregator_(aggregator),
- input_frame_(input_frame),
- output_frame_(output_frame),
+ input_execution_context_(input_execution_context),
+ output_execution_context_(output_execution_context),
reason_(reason) {
aggregator_->SubmitBoostingVote(this);
}
@@ -137,8 +135,10 @@ BoostingVote& BoostingVote::operator=(BoostingVote&& rhs) {
// Take the aggregator.
aggregator_ = std::exchange(rhs.aggregator_, nullptr);
- input_frame_ = std::exchange(rhs.input_frame_, nullptr);
- output_frame_ = std::exchange(rhs.output_frame_, nullptr);
+ input_execution_context_ =
+ std::exchange(rhs.input_execution_context_, nullptr);
+ output_execution_context_ =
+ std::exchange(rhs.output_execution_context_, nullptr);
reason_ = std::exchange(rhs.reason_, nullptr);
return *this;
@@ -167,6 +167,10 @@ void BoostingVoteAggregator::ActiveLayers::SetInactive(uint32_t layer_bit) {
active_layers_ &= ~layer_bit;
}
+BoostingVoteAggregator::NodeData::NodeData() = default;
+BoostingVoteAggregator::NodeData::NodeData(NodeData&& rhs) = default;
+BoostingVoteAggregator::NodeData::~NodeData() = default;
+
base::TaskPriority BoostingVoteAggregator::NodeData::GetEffectivePriorityLevel()
const {
if (IsActive(PriorityToBit(base::TaskPriority::HIGHEST)))
@@ -187,9 +191,10 @@ void BoostingVoteAggregator::NodeData::DecrementEdgeCount() {
VoteReceipt BoostingVoteAggregator::NodeData::SetIncomingVote(
VoteConsumer* consumer,
- VoterId voter_id,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
const Vote& vote) {
- incoming_ = AcceptedVote(consumer, voter_id, vote);
+ incoming_ = AcceptedVote(consumer, voter_id, execution_context, vote);
return incoming_.IssueReceipt();
}
@@ -251,7 +256,7 @@ BoostingVoteAggregator::~BoostingVoteAggregator() {
VotingChannel BoostingVoteAggregator::GetVotingChannel() {
DCHECK(nodes_.empty());
- DCHECK_EQ(kInvalidVoterId, input_voter_id_);
+ DCHECK_EQ(voting::kInvalidVoterId<Vote>, input_voter_id_);
DCHECK_GT(1u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
input_voter_id_ = channel.voter_id();
@@ -266,7 +271,7 @@ void BoostingVoteAggregator::SetUpstreamVotingChannel(VotingChannel&& channel) {
}
bool BoostingVoteAggregator::IsSetup() const {
- return input_voter_id_ != kInvalidVoterId && channel_.IsValid();
+ return input_voter_id_ != voting::kInvalidVoterId<Vote> && channel_.IsValid();
}
void BoostingVoteAggregator::SubmitBoostingVote(
@@ -296,8 +301,10 @@ void BoostingVoteAggregator::SubmitBoostingVote(
if (!is_new_edge)
return;
- auto src_node_data_it = FindOrCreateNodeData(boosting_vote->input_frame());
- auto dst_node_data_it = FindOrCreateNodeData(boosting_vote->output_frame());
+ auto src_node_data_it =
+ FindOrCreateNodeData(boosting_vote->input_execution_context());
+ auto dst_node_data_it =
+ FindOrCreateNodeData(boosting_vote->output_execution_context());
src_node_data_it->second.IncrementEdgeCount();
dst_node_data_it->second.IncrementEdgeCount();
@@ -337,8 +344,10 @@ void BoostingVoteAggregator::CancelBoostingVote(
bool active_reason_changed =
fwd_edge_it->second.RemoveReason(boosting_vote->reason());
- auto src_node_data_it = FindNodeData(boosting_vote->input_frame());
- auto dst_node_data_it = FindNodeData(boosting_vote->output_frame());
+ auto src_node_data_it =
+ FindNodeData(boosting_vote->input_execution_context());
+ auto dst_node_data_it =
+ FindNodeData(boosting_vote->output_execution_context());
// If the edge's active reason changed, and the edge is active in any layer,
// then the destination node might need to have its vote updated.
@@ -386,22 +395,25 @@ void BoostingVoteAggregator::CancelBoostingVote(
}
}
-VoteReceipt BoostingVoteAggregator::SubmitVote(VoterId voter_id,
- const Vote& vote) {
+VoteReceipt BoostingVoteAggregator::SubmitVote(
+ util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) {
DCHECK(IsSetup());
DCHECK_EQ(input_voter_id_, voter_id);
DCHECK(vote.IsValid());
// Store the vote.
- auto node_data_it = FindOrCreateNodeData(vote.frame_node());
- VoteReceipt receipt =
- node_data_it->second.SetIncomingVote(this, voter_id, vote);
+ auto node_data_it = FindOrCreateNodeData(execution_context);
+ VoteReceipt receipt = node_data_it->second.SetIncomingVote(
+ this, voter_id, execution_context, vote);
NodeDataPtrSet changes;
// Update the reachability tree for the new vote if necessary.
- if (vote.priority() != base::TaskPriority::LOWEST) {
- uint32_t layer_bit = PriorityToBit(vote.priority());
+ if (vote.value() != base::TaskPriority::LOWEST) {
+ uint32_t layer_bit = PriorityToBit(vote.value());
OnVoteAdded(layer_bit, &(*node_data_it), &changes);
}
@@ -410,12 +422,12 @@ VoteReceipt BoostingVoteAggregator::SubmitVote(VoterId voter_id,
return receipt;
}
-VoteReceipt BoostingVoteAggregator::ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) {
+void BoostingVoteAggregator::ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) {
// Remember the old and new priorities before committing any changes.
- base::TaskPriority old_priority = old_vote->vote().priority();
- base::TaskPriority new_priority = new_vote.priority();
+ base::TaskPriority old_priority = old_vote->vote().value();
+ base::TaskPriority new_priority = new_vote.value();
// Update the vote in place.
auto node_data_it = GetNodeDataByVote(old_vote);
@@ -438,14 +450,12 @@ VoteReceipt BoostingVoteAggregator::ChangeVote(VoteReceipt receipt,
}
UpstreamChanges(changes);
-
- // Return the original receipt, as its still valid.
- return receipt;
}
-void BoostingVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
+void BoostingVoteAggregator::VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) {
auto node_data_it = GetNodeDataByVote(vote);
- base::TaskPriority old_priority = vote->vote().priority();
+ base::TaskPriority old_priority = vote->vote().value();
NodeDataPtrSet changes;
@@ -465,10 +475,11 @@ void BoostingVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
}
template <typename Function>
-void BoostingVoteAggregator::ForEachIncomingEdge(const FrameNode* node,
+void BoostingVoteAggregator::ForEachIncomingEdge(const ExecutionContext* node,
Function&& function) {
auto edges_begin = reverse_edges_.lower_bound(ReverseEdge(nullptr, node));
- auto edges_end = reverse_edges_.upper_bound(ReverseEdge(kMaxFrameNode, node));
+ auto edges_end =
+ reverse_edges_.upper_bound(ReverseEdge(kMaxExecutionContext, node));
for (auto edge_it = edges_begin; edge_it != edges_end; ++edge_it) {
if (!function(edge_it))
return;
@@ -476,10 +487,11 @@ void BoostingVoteAggregator::ForEachIncomingEdge(const FrameNode* node,
}
template <typename Function>
-void BoostingVoteAggregator::ForEachOutgoingEdge(const FrameNode* node,
+void BoostingVoteAggregator::ForEachOutgoingEdge(const ExecutionContext* node,
Function&& function) {
auto edges_begin = forward_edges_.lower_bound(ForwardEdge(node, nullptr));
- auto edges_end = forward_edges_.upper_bound(ForwardEdge(node, kMaxFrameNode));
+ auto edges_end =
+ forward_edges_.upper_bound(ForwardEdge(node, kMaxExecutionContext));
for (auto edge_it = edges_begin; edge_it != edges_end; ++edge_it) {
if (!function(edge_it))
return;
@@ -495,24 +507,24 @@ BoostingVoteAggregator::GetNodeDataByVote(AcceptedVote* vote) {
DCHECK(vote->voter_id() == input_voter_id_);
DCHECK(IsSetup());
- auto it = nodes_.find(vote->vote().frame_node());
+ auto it = nodes_.find(vote->context());
DCHECK(it != nodes_.end());
DCHECK_EQ(vote, &it->second.incoming());
return it;
}
BoostingVoteAggregator::NodeDataMap::iterator
-BoostingVoteAggregator::FindOrCreateNodeData(const FrameNode* frame_node) {
- auto it = nodes_.lower_bound(frame_node);
- if (it->first == frame_node)
+BoostingVoteAggregator::FindOrCreateNodeData(const ExecutionContext* node) {
+ auto it = nodes_.lower_bound(node);
+ if (it->first == node)
return it;
- it = nodes_.insert(it, std::make_pair(frame_node, NodeData()));
+ it = nodes_.insert(it, std::make_pair(node, NodeData()));
return it;
}
BoostingVoteAggregator::NodeDataMap::iterator
-BoostingVoteAggregator::FindNodeData(const FrameNode* frame_node) {
- auto it = nodes_.lower_bound(frame_node);
+BoostingVoteAggregator::FindNodeData(const ExecutionContext* node) {
+ auto it = nodes_.lower_bound(node);
DCHECK(it != nodes_.end());
return it;
}
@@ -531,7 +543,7 @@ const char* BoostingVoteAggregator::GetVoteReason(
// preferentially use that reason.
if (node_data.HasIncomingVote()) {
const Vote& incoming = node_data.incoming().vote();
- if (priority == incoming.priority()) {
+ if (priority == incoming.value()) {
// This node will not have an active incoming edge in this case.
DCHECK(GetActiveInboundEdge(layer_bit, node) == reverse_edges_.end());
return incoming.reason();
@@ -548,13 +560,13 @@ const char* BoostingVoteAggregator::GetVoteReason(
void BoostingVoteAggregator::UpstreamVoteIfNeeded(
NodeDataMap::value_type* node) {
- const FrameNode* frame_node = node->first;
+ const ExecutionContext* execution_context = node->first;
NodeData* node_data = &node->second;
auto priority = node_data->GetEffectivePriorityLevel();
// We specifically don't upstream lowest priority votes, as that is the
- // default priority level of every frame in the absence of any specific higher
- // votes.
+ // default priority level of every execution context in the absence of any
+ // specific higher votes.
if (priority == base::TaskPriority::LOWEST) {
if (node_data->HasOutgoingVote())
node_data->CancelOutgoingVote();
@@ -573,7 +585,7 @@ void BoostingVoteAggregator::UpstreamVoteIfNeeded(
// Create an outgoing vote.
node_data->SetOutgoingVoteReceipt(
- channel_.SubmitVote(Vote(frame_node, priority, reason)));
+ channel_.SubmitVote(execution_context, Vote(priority, reason)));
}
void BoostingVoteAggregator::UpstreamChanges(const NodeDataPtrSet& changes) {
@@ -645,7 +657,7 @@ BoostingVoteAggregator::GetNearestActiveAncestor(
[&](ReverseEdges::iterator edge_it) -> bool {
// None of the edges should be active, by definition.
DCHECK(!edge_it->second->IsActive(layer_bit));
- const FrameNode* src_node = edge_it->first.src();
+ const ExecutionContext* src_node = edge_it->first.src();
auto src_node_it = FindNodeData(src_node);
if (!src_node_it->second.IsActive(layer_bit))
@@ -680,27 +692,27 @@ void BoostingVoteAggregator::MarkNodesActiveFromSearchFront(
active_search_front->erase(active_search_front->begin());
DCHECK(current_node->second.IsActive(layer_bit));
- ForEachOutgoingEdge(current_node->first,
- [&](ForwardEdges::iterator edge_it) -> bool {
- // Ignore active edges.
- if (edge_it->second.IsActive(layer_bit))
- return true;
-
- // Ignore active destination nodes.
- const FrameNode* dst_node = edge_it->first.dst();
- auto dst_node_it = FindNodeData(dst_node);
- if (dst_node_it->second.IsActive(layer_bit))
- return true;
-
- // Mark the edge and the node as active, and add the
- // node both to the search front and to the set of
- // nodes that became active as a part of this search.
- edge_it->second.SetActive(layer_bit);
- dst_node_it->second.SetActive(layer_bit);
- active_search_front->insert(&(*dst_node_it));
- activated->insert(&(*dst_node_it));
- return true;
- });
+ ForEachOutgoingEdge(
+ current_node->first, [&](ForwardEdges::iterator edge_it) -> bool {
+ // Ignore active edges.
+ if (edge_it->second.IsActive(layer_bit))
+ return true;
+
+ // Ignore active destination nodes.
+ const ExecutionContext* dst_node = edge_it->first.dst();
+ auto dst_node_it = FindNodeData(dst_node);
+ if (dst_node_it->second.IsActive(layer_bit))
+ return true;
+
+ // Mark the edge and the node as active, and add the
+ // node both to the search front and to the set of
+ // nodes that became active as a part of this search.
+ edge_it->second.SetActive(layer_bit);
+ dst_node_it->second.SetActive(layer_bit);
+ active_search_front->insert(&(*dst_node_it));
+ activated->insert(&(*dst_node_it));
+ return true;
+ });
}
}
@@ -752,7 +764,5 @@ void BoostingVoteAggregator::OnVoteRemoved(uint32_t layer_bit,
ReprocessSubtree(layer_bit, node, changes);
}
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
-
-#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator_unittest.cc b/chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator_unittest.cc
new file mode 100644
index 00000000000..0a85b8c0808
--- /dev/null
+++ b/chromium/components/performance_manager/execution_context_priority/boosting_vote_aggregator_unittest.cc
@@ -0,0 +1,659 @@
+// 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 "components/performance_manager/public/execution_context_priority/boosting_vote_aggregator.h"
+
+#include "components/performance_manager/test_support/voting.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace execution_context_priority {
+
+namespace {
+
+using DummyVoter = voting::test::DummyVoter<Vote>;
+using DummyVoteConsumer = voting::test::DummyVoteConsumer<Vote>;
+
+// Some dummy execution contexts.
+const ExecutionContext* kExecutionContext0 =
+ reinterpret_cast<const ExecutionContext*>(0xF5A33000);
+const ExecutionContext* kExecutionContext1 =
+ reinterpret_cast<const ExecutionContext*>(0xF5A33001);
+const ExecutionContext* kExecutionContext2 =
+ reinterpret_cast<const ExecutionContext*>(0xF5A33002);
+const ExecutionContext* kExecutionContext3 =
+ reinterpret_cast<const ExecutionContext*>(0xF5A33003);
+const ExecutionContext* kExecutionContext4 =
+ reinterpret_cast<const ExecutionContext*>(0xF5A33004);
+
+static constexpr base::TaskPriority kPriority0 = base::TaskPriority::LOWEST;
+static constexpr base::TaskPriority kPriority1 =
+ base::TaskPriority::USER_VISIBLE;
+static constexpr base::TaskPriority kPriority2 = base::TaskPriority::HIGHEST;
+
+static_assert(kPriority0 < kPriority1 && kPriority1 < kPriority2,
+ "priorities must be well ordered");
+
+static const char kReason0[] = "a reason";
+static const char kReason1[] = "another reason";
+static const char kReason2[] = "yet another reason";
+static const char kReasonBoost[] = "boosted!";
+
+class TestBoostingVoteAggregator : public BoostingVoteAggregator {
+ public:
+ using BoostingVoteAggregator::forward_edges_;
+ using BoostingVoteAggregator::NodeData;
+ using BoostingVoteAggregator::nodes_;
+ using BoostingVoteAggregator::reverse_edges_;
+};
+
+using NodeData = TestBoostingVoteAggregator::NodeData;
+
+class BoostingVoteAggregatorTest : public testing::Test {
+ public:
+ void SetUp() override {
+ // Set up the chain such that |voter_| provides votes to |agg_|, which
+ // upstreams them to |consumer_|.
+ auto channel = consumer_.voting_channel_factory_.BuildVotingChannel();
+ voter_id_ = channel.voter_id();
+ agg_.SetUpstreamVotingChannel(std::move(channel));
+ voter_.SetVotingChannel(agg_.GetVotingChannel());
+ EXPECT_TRUE(agg_.nodes_.empty());
+ EXPECT_TRUE(agg_.forward_edges_.empty());
+ EXPECT_TRUE(agg_.reverse_edges_.empty());
+ }
+
+ void ExpectEdges(size_t count) {
+ EXPECT_EQ(count, agg_.forward_edges_.size());
+ EXPECT_EQ(count, agg_.reverse_edges_.size());
+ }
+
+ void ExpectIsActive(const NodeData& node_data,
+ bool mid_priority,
+ bool high_priority) {
+ EXPECT_EQ(mid_priority, node_data.IsActive(1));
+ EXPECT_EQ(high_priority, node_data.IsActive(2));
+ }
+
+ // The id of |agg_| as seen by its upstream |consumer_|.
+ voting::VoterId<Vote> voter_id_;
+ DummyVoteConsumer consumer_;
+ TestBoostingVoteAggregator agg_;
+ DummyVoter voter_;
+};
+
+} // namespace
+
+TEST_F(BoostingVoteAggregatorTest, VotesUpstreamingWorks) {
+ // Submit a default vote to the boosting aggregator, and expect it not to be
+ // upstreamed.
+ voter_.EmitVote(kExecutionContext0, kPriority0, kReason0);
+ EXPECT_EQ(1u, agg_.nodes_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote());
+ ExpectEdges(0);
+ EXPECT_TRUE(consumer_.votes_.empty());
+
+ // Submit a non-default vote to the boosting aggregator, and expect it to be
+ // upstreamed.
+ voter_.EmitVote(kExecutionContext1, kPriority1, kReason1);
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(1u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReason1);
+
+ // Make vote 0 non-default and expect it to be upstreamed.
+ voter_.receipts_[0].ChangeVote(kPriority2, kReason2);
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority2,
+ kReason2);
+
+ // Make vote 1 default and expect the upstream vote to be canceled.
+ voter_.receipts_[1].ChangeVote(kPriority0, kReason0);
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectInvalidVote(0);
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority2,
+ kReason2);
+
+ // Change the reason but not the priority of vote 0 and expect the upstream
+ // vote to change as well.
+ voter_.receipts_[0].ChangeVote(kPriority2, kReason0);
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectInvalidVote(0);
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority2,
+ kReason0);
+
+ // Cancel vote 0 and expect it to be canceled upstream.
+ voter_.receipts_[0].Reset();
+ EXPECT_EQ(1u, agg_.nodes_.size());
+ EXPECT_FALSE(voter_.receipts_[0].HasVote());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectInvalidVote(0);
+ consumer_.ExpectInvalidVote(1);
+
+ // Cancel vote 1 and expect no change to the upstream votes.
+ voter_.receipts_[1].Reset();
+ EXPECT_EQ(0u, agg_.nodes_.size());
+ EXPECT_FALSE(voter_.receipts_[0].HasVote());
+ EXPECT_FALSE(voter_.receipts_[1].HasVote());
+ ExpectEdges(0);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectInvalidVote(0);
+ consumer_.ExpectInvalidVote(1);
+}
+
+TEST_F(BoostingVoteAggregatorTest, BoostingWorks) {
+ // Add a boosting vote, with no actual incoming votes. This should produce
+ // the two nodes associated with the edge but not upstream any votes.
+ BoostingVote boost01a(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ const auto& data0 = agg_.nodes_.find(kExecutionContext0)->second;
+ const auto& data1 = agg_.nodes_.find(kExecutionContext1)->second;
+ EXPECT_TRUE(voter_.receipts_.empty());
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_TRUE(consumer_.votes_.empty());
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+
+ // Create a second boosting vote. This duplicates the edge.
+ BoostingVote boost01b(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ EXPECT_TRUE(voter_.receipts_.empty());
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_TRUE(consumer_.votes_.empty());
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+
+ // Create a mid priority vote for execution context 1. This should cause a
+ // single vote to be emitted for that node.
+ voter_.EmitVote(kExecutionContext1, kPriority1, kReason1);
+ EXPECT_EQ(1u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[0].HasVote()); // kExecutionContext1.
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(1u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReason1);
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, true, false);
+
+ // Create a mid priority vote for execution context 0. This should cause
+ // another vote to be emitted.
+ voter_.EmitVote(kExecutionContext0, kPriority1, kReason1);
+ EXPECT_EQ(2u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_TRUE(voter_.receipts_[0].HasVote()); // kExecutionContext1.
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReason1);
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+
+ // Cancel the priority 1 vote for execution context 1. The boosting should
+ // maintain the output priority for that node.
+ voter_.receipts_[0].Reset(); // kExecutionContext1.
+ EXPECT_EQ(2u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReasonBoost);
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+
+ // Create a default vote for a third execution context. Other than creating
+ // the node data and the vote this shouldn't do anything.
+ voter_.EmitVote(kExecutionContext2, kPriority0, kReason0);
+ const auto& data2 = agg_.nodes_.find(kExecutionContext2)->second;
+ EXPECT_EQ(3u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReasonBoost);
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(0u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Create a boosting vote from execution context 2 to execution context 0.
+ // This should create an edge.
+ BoostingVote boost20(&agg_, kExecutionContext2, kExecutionContext0,
+ kReasonBoost);
+ EXPECT_EQ(3u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(2u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReasonBoost);
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Emit a highest priority vote for execution context 2. This should boost
+ // execution contexts 0 and 1 as well.
+ voter_.receipts_[2].ChangeVote(kPriority2, kReason2); // kExecutionContext2.
+ EXPECT_EQ(3u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority2,
+ kReasonBoost);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority2,
+ kReasonBoost);
+ consumer_.ExpectValidVote(2, voter_id_, kExecutionContext2, kPriority2,
+ kReason2);
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, true);
+ ExpectIsActive(data1, true, true);
+ ExpectIsActive(data2, false, true);
+
+ // Emit a highest priority vote for execution context 1. This should change
+ // the vote reason.
+ voter_.EmitVote(kExecutionContext1, kPriority2, kReason2);
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[3].HasVote()); // kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority2,
+ kReasonBoost); // kExecutionContext0.
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority2,
+ kReason2); // kExecutionContext1.
+ consumer_.ExpectValidVote(2, voter_id_, kExecutionContext2, kPriority2,
+ kReason2); // kExecutionContext2.
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, true);
+ ExpectIsActive(data1, true, true);
+ ExpectIsActive(data2, false, true);
+
+ // Kill the vote for execution context 2. This should kill the upstream vote
+ // for execution context 2 entirely, reduce the priority of execution context
+ // 0, and keep execution context 1 the same.
+ voter_.receipts_[2].Reset(); // kExecutionContext2.
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_TRUE(voter_.receipts_[3].HasVote()); // kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority2,
+ kReason2);
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, true);
+ ExpectIsActive(data2, false, false);
+
+ // Kill the direct vote for execution context 1 so it goes back to being
+ // boosted by execution context 0.
+ voter_.receipts_[3].Reset();
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReasonBoost);
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Kill the first boosting vote from 0 to 1. This should do nothing but change
+ // edge the multiplicity of the edge.
+ boost01a.Reset();
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectEdges(2);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectValidVote(0, voter_id_, kExecutionContext1, kPriority1,
+ kReasonBoost);
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(2u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data1.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data1, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Kill the second boosting vote from 0 to 1. This should change edge counts,
+ // and remove both the vote and the node data. The variable |data1| is now
+ // invalid.
+ boost01b.Reset();
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectInvalidVote(0); // Old kExecutionContext1.
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Move the boosting vote. The move should not cause any outwardly visible
+ // changes.
+ BoostingVote boost20b(std::move(boost20));
+ EXPECT_EQ(&agg_, boost20b.aggregator());
+ EXPECT_EQ(kExecutionContext2, boost20b.input_execution_context());
+ EXPECT_EQ(kExecutionContext0, boost20b.output_execution_context());
+ EXPECT_EQ(kReasonBoost, boost20b.reason());
+ EXPECT_FALSE(boost20.aggregator());
+ EXPECT_FALSE(boost20.input_execution_context());
+ EXPECT_FALSE(boost20.output_execution_context());
+ EXPECT_FALSE(boost20.reason());
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(2u, agg_.nodes_.size());
+ ExpectEdges(1);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectInvalidVote(0); // Old kExecutionContext1.
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(1u, data0.edge_count_for_testing());
+ EXPECT_EQ(1u, data2.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+ ExpectIsActive(data2, false, false);
+
+ // Remove the boosting vote from 2 to 0. This should change edge counts, and
+ // also remove the node data associated with node 2. |data2| is now invalid.
+ boost20b.Reset();
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(1u, agg_.nodes_.size());
+ ExpectEdges(0);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectValidVote(1, voter_id_, kExecutionContext0, kPriority1,
+ kReason1);
+ consumer_.ExpectInvalidVote(0); // Old kExecutionContext1.
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+ EXPECT_EQ(0u, data0.edge_count_for_testing());
+ ExpectIsActive(data0, true, false);
+
+ // Finally remove the last vote. The aggregator should effectively be empty at
+ // this point. |data0| also becomes invalid after this.
+ voter_.receipts_[1].Reset();
+ EXPECT_EQ(4u, voter_.receipts_.size());
+ EXPECT_FALSE(voter_.receipts_[1].HasVote()); // Old kExecutionContext0.
+ EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kExecutionContext1.
+ EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kExecutionContext2.
+ EXPECT_EQ(0u, agg_.nodes_.size());
+ ExpectEdges(0);
+ EXPECT_EQ(3u, consumer_.votes_.size());
+ consumer_.ExpectInvalidVote(1); // Old kExecutionContext0.
+ consumer_.ExpectInvalidVote(0); // Old kExecutionContext1.
+ consumer_.ExpectInvalidVote(2); // Old kExecutionContext2.
+}
+
+TEST_F(BoostingVoteAggregatorTest, DiamondPattern) {
+ // Create a diamond boosting vote pattern:
+ //
+ // 1
+ // / \
+ // 0 3
+ // \ /
+ // 2
+ BoostingVote boost01(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ BoostingVote boost02(&agg_, kExecutionContext0, kExecutionContext2,
+ kReasonBoost);
+ BoostingVote boost13(&agg_, kExecutionContext1, kExecutionContext3,
+ kReasonBoost);
+ BoostingVote boost23(&agg_, kExecutionContext2, kExecutionContext3,
+ kReasonBoost);
+
+ const auto& data0 = agg_.nodes_.find(kExecutionContext0)->second;
+ const auto& data1 = agg_.nodes_.find(kExecutionContext1)->second;
+ const auto& data2 = agg_.nodes_.find(kExecutionContext2)->second;
+ const auto& data3 = agg_.nodes_.find(kExecutionContext3)->second;
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+ ExpectIsActive(data2, false, false);
+ ExpectIsActive(data3, false, false);
+
+ // Add a vote to node 0. This should cause all nodes to be boosted.
+ voter_.EmitVote(kExecutionContext0, kPriority2, kReason2);
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, true);
+ ExpectIsActive(data2, false, true);
+ ExpectIsActive(data3, false, true);
+
+ // Cancel the vote. All boosting should disappear.
+ voter_.receipts_.clear();
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+ ExpectIsActive(data2, false, false);
+ ExpectIsActive(data3, false, false);
+}
+
+TEST_F(BoostingVoteAggregatorTest, DiamondPatternMultipleVotes) {
+ // Create another diamond boosting vote pattern:
+ //
+ // 1
+ // / \
+ // 4 - 0 3
+ // \ /
+ // 2
+ BoostingVote boost01(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ BoostingVote boost02(&agg_, kExecutionContext0, kExecutionContext2,
+ kReasonBoost);
+ BoostingVote boost13(&agg_, kExecutionContext1, kExecutionContext3,
+ kReasonBoost);
+ BoostingVote boost23(&agg_, kExecutionContext2, kExecutionContext3,
+ kReasonBoost);
+
+ const auto& data0 = agg_.nodes_.find(kExecutionContext0)->second;
+ const auto& data1 = agg_.nodes_.find(kExecutionContext1)->second;
+ const auto& data2 = agg_.nodes_.find(kExecutionContext2)->second;
+ const auto& data3 = agg_.nodes_.find(kExecutionContext3)->second;
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+ ExpectIsActive(data2, false, false);
+ ExpectIsActive(data3, false, false);
+
+ // Add a vote to node 0. This should cause all downstream nodes to be boosted.
+ voter_.EmitVote(kExecutionContext0, kPriority2, kReason2);
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, true);
+ ExpectIsActive(data2, false, true);
+ ExpectIsActive(data3, false, true);
+
+ // Add a lower vote to execution context 0 via execution context 4. This
+ // should also propagate through the network in a similar way.
+ BoostingVote boost40(&agg_, kExecutionContext4, kExecutionContext0,
+ kReasonBoost);
+ const auto& data4 = agg_.nodes_.find(kExecutionContext4)->second;
+ voter_.EmitVote(kExecutionContext4, kPriority1, kReason1);
+ ExpectIsActive(data0, true, true);
+ ExpectIsActive(data1, true, true);
+ ExpectIsActive(data2, true, true);
+ ExpectIsActive(data3, true, true);
+ ExpectIsActive(data4, true, false);
+}
+
+TEST_F(BoostingVoteAggregatorTest, RemoveEdgeFromCycle) {
+ BoostingVote boost01(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ BoostingVote boost12(&agg_, kExecutionContext1, kExecutionContext2,
+ kReasonBoost);
+ BoostingVote boost23(&agg_, kExecutionContext2, kExecutionContext3,
+ kReasonBoost);
+ BoostingVote boost30(&agg_, kExecutionContext3, kExecutionContext0,
+ kReasonBoost);
+
+ const auto& data0 = agg_.nodes_.find(kExecutionContext0)->second;
+ const auto& data1 = agg_.nodes_.find(kExecutionContext1)->second;
+ const auto& data2 = agg_.nodes_.find(kExecutionContext2)->second;
+ const auto& data3 = agg_.nodes_.find(kExecutionContext3)->second;
+ ExpectIsActive(data0, false, false);
+ ExpectIsActive(data1, false, false);
+ ExpectIsActive(data2, false, false);
+ ExpectIsActive(data3, false, false);
+
+ // Add a vote to node 0.
+ voter_.EmitVote(kExecutionContext0, kPriority2, kReason2);
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, true);
+ ExpectIsActive(data2, false, true);
+ ExpectIsActive(data3, false, true);
+
+ // Remove an edge from the cycle. The first half of the cycle should still
+ // be boosted, the second half should not.
+ boost12.Reset();
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, true);
+ ExpectIsActive(data2, false, false);
+ ExpectIsActive(data3, false, false);
+}
+
+TEST_F(BoostingVoteAggregatorTest, MoveCancelsPreviousBoostingVote) {
+ BoostingVote boost01(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ BoostingVote boost12(&agg_, kExecutionContext1, kExecutionContext2,
+ kReasonBoost);
+
+ // Expect nodes to have been created for all nodes involved in boosting votes.
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext0));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext1));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext2));
+
+ // Move one boosting vote into the other. This should cause the latter to be
+ // canceled. In this case that means node0 should be removed.
+ boost01 = std::move(boost12);
+ EXPECT_FALSE(agg_.nodes_.count(kExecutionContext0));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext1));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext2));
+}
+
+TEST_F(BoostingVoteAggregatorTest, BoostingVoteAfterNormalVotes) {
+ voter_.EmitVote(kExecutionContext0, kPriority2, kReason2);
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext0));
+ EXPECT_EQ(1u, agg_.nodes_.size());
+ const auto& data0 = agg_.nodes_.find(kExecutionContext0)->second;
+ ExpectIsActive(data0, false, true);
+
+ BoostingVote boost12(&agg_, kExecutionContext1, kExecutionContext2,
+ kReasonBoost);
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext0));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext1));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext2));
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ const auto& data1 = agg_.nodes_.find(kExecutionContext1)->second;
+ const auto& data2 = agg_.nodes_.find(kExecutionContext2)->second;
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, false);
+ ExpectIsActive(data2, false, false);
+
+ BoostingVote boost01(&agg_, kExecutionContext0, kExecutionContext1,
+ kReasonBoost);
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext0));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext1));
+ EXPECT_TRUE(agg_.nodes_.count(kExecutionContext2));
+ EXPECT_EQ(3u, agg_.nodes_.size());
+ ExpectIsActive(data0, false, true);
+ ExpectIsActive(data1, false, true);
+ ExpectIsActive(data2, false, true);
+}
+
+} // namespace execution_context_priority
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/execution_context_priority/execution_context_priority.cc b/chromium/components/performance_manager/execution_context_priority/execution_context_priority.cc
new file mode 100644
index 00000000000..c17112b3fab
--- /dev/null
+++ b/chromium/components/performance_manager/execution_context_priority/execution_context_priority.cc
@@ -0,0 +1,58 @@
+// 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 "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
+
+#include <cstring>
+
+namespace performance_manager {
+namespace execution_context_priority {
+
+int ReasonCompare(const char* reason1, const char* reason2) {
+ if (reason1 == reason2)
+ return 0;
+ if (reason1 == nullptr)
+ return -1;
+ if (reason2 == nullptr)
+ return 1;
+ return ::strcmp(reason1, reason2);
+}
+
+/////////////////////////////////////////////////////////////////////
+// PriorityAndReason
+
+int PriorityAndReason::Compare(const PriorityAndReason& other) const {
+ if (priority_ > other.priority_)
+ return 1;
+ if (priority_ < other.priority_)
+ return -1;
+ return ReasonCompare(reason_, other.reason_);
+}
+
+bool PriorityAndReason::operator==(const PriorityAndReason& other) const {
+ return Compare(other) == 0;
+}
+
+bool PriorityAndReason::operator!=(const PriorityAndReason& other) const {
+ return Compare(other) != 0;
+}
+
+bool PriorityAndReason::operator<=(const PriorityAndReason& other) const {
+ return Compare(other) <= 0;
+}
+
+bool PriorityAndReason::operator>=(const PriorityAndReason& other) const {
+ return Compare(other) >= 0;
+}
+
+bool PriorityAndReason::operator<(const PriorityAndReason& other) const {
+ return Compare(other) < 0;
+}
+
+bool PriorityAndReason::operator>(const PriorityAndReason& other) const {
+ return Compare(other) > 0;
+}
+
+} // namespace execution_context_priority
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/frame_priority_unittest.cc b/chromium/components/performance_manager/execution_context_priority/execution_context_priority_unittest.cc
index 5db3a6c4578..8de808cb78e 100644
--- a/chromium/components/performance_manager/frame_priority/frame_priority_unittest.cc
+++ b/chromium/components/performance_manager/execution_context_priority/execution_context_priority_unittest.cc
@@ -2,19 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
-#include "components/performance_manager/test_support/frame_priority.h"
+#include "components/performance_manager/test_support/voting.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
namespace {
-// Some dummy frames.
-const FrameNode* kDummyFrame1 = reinterpret_cast<const FrameNode*>(0xDEADBEEF);
-const FrameNode* kDummyFrame2 = reinterpret_cast<const FrameNode*>(0xBAADF00D);
+using DummyVoter = voting::test::DummyVoter<Vote>;
+using DummyVoteConsumer = voting::test::DummyVoteConsumer<Vote>;
+
+// Some dummy execution contexts.
+const ExecutionContext* kDummyExecutionContext1 =
+ reinterpret_cast<const ExecutionContext*>(0xDEADBEEF);
+const ExecutionContext* kDummyExecutionContext2 =
+ reinterpret_cast<const ExecutionContext*>(0xBAADF00D);
void ExpectEntangled(const VoteReceipt& receipt, const AcceptedVote& vote) {
EXPECT_TRUE(receipt.HasVote(&vote));
@@ -34,7 +39,7 @@ static const char kReason3[] = "reason1"; // Equal to kReason1 on purpose!
} // namespace
-TEST(FramePriorityTest, ReasonCompare) {
+TEST(ExecutionContextPriorityTest, ReasonCompare) {
// Comparison with nullptr.
EXPECT_GT(0, ReasonCompare(nullptr, kReason1));
EXPECT_EQ(0, ReasonCompare(nullptr, nullptr));
@@ -52,7 +57,7 @@ TEST(FramePriorityTest, ReasonCompare) {
EXPECT_EQ(0, ReasonCompare(kReason1, kReason3));
}
-TEST(FramePriorityTest, PriorityAndReason) {
+TEST(ExecutionContextPriorityTest, PriorityAndReason) {
// Default constructor
PriorityAndReason par1;
EXPECT_EQ(base::TaskPriority::LOWEST, par1.priority());
@@ -111,28 +116,28 @@ TEST(FramePriorityTest, PriorityAndReason) {
EXPECT_EQ(kReason3, par1.reason());
}
-TEST(FramePriorityTest, DefaultAcceptedVoteIsInvalid) {
+TEST(ExecutionContextPriorityTest, DefaultAcceptedVoteIsInvalid) {
AcceptedVote vote;
EXPECT_FALSE(vote.IsValid());
}
-TEST(FramePriorityTest, VoteReceiptsWork) {
- test::DummyVoteConsumer consumer;
- test::DummyVoter voter;
+TEST(ExecutionContextPriorityTest, VoteReceiptsWork) {
+ DummyVoteConsumer consumer;
+ DummyVoter voter;
EXPECT_FALSE(voter.voting_channel_.IsValid());
voter.SetVotingChannel(consumer.voting_channel_factory_.BuildVotingChannel());
EXPECT_EQ(&consumer.voting_channel_factory_,
voter.voting_channel_.factory_for_testing());
- EXPECT_NE(kInvalidVoterId, voter.voting_channel_.voter_id());
+ EXPECT_NE(voting::kInvalidVoterId<Vote>, voter.voting_channel_.voter_id());
EXPECT_TRUE(voter.voting_channel_.IsValid());
- voter.EmitVote(kDummyFrame1);
+ voter.EmitVote(kDummyExecutionContext1, base::TaskPriority::LOWEST);
EXPECT_EQ(1u, voter.receipts_.size());
EXPECT_EQ(1u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
EXPECT_EQ(voter.voting_channel_.voter_id(), consumer.votes_[0].voter_id());
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
EXPECT_TRUE(consumer.votes_[0].IsValid());
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
@@ -156,33 +161,33 @@ TEST(FramePriorityTest, VoteReceiptsWork) {
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
}
- voter.EmitVote(kDummyFrame2);
+ voter.EmitVote(kDummyExecutionContext2, base::TaskPriority::LOWEST);
EXPECT_EQ(2u, voter.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
- EXPECT_EQ(kDummyFrame2, consumer.votes_[1].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
+ EXPECT_EQ(kDummyExecutionContext2, consumer.votes_[1].context());
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
ExpectEntangled(voter.receipts_[1], consumer.votes_[1]);
// Change a vote, but making no change.
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
- EXPECT_EQ(base::TaskPriority::LOWEST, consumer.votes_[0].vote().priority());
- EXPECT_EQ(test::DummyVoter::kReason, consumer.votes_[0].vote().reason());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
+ EXPECT_EQ(base::TaskPriority::LOWEST, consumer.votes_[0].vote().value());
+ EXPECT_EQ(DummyVoter::kReason, consumer.votes_[0].vote().reason());
voter.receipts_[0].ChangeVote(base::TaskPriority::LOWEST,
- test::DummyVoter::kReason);
+ DummyVoter::kReason);
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
- EXPECT_EQ(base::TaskPriority::LOWEST, consumer.votes_[0].vote().priority());
- EXPECT_EQ(test::DummyVoter::kReason, consumer.votes_[0].vote().reason());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
+ EXPECT_EQ(base::TaskPriority::LOWEST, consumer.votes_[0].vote().value());
+ EXPECT_EQ(DummyVoter::kReason, consumer.votes_[0].vote().reason());
// Change the vote and expect the change to propagate.
static const char kReason[] = "another reason";
voter.receipts_[0].ChangeVote(base::TaskPriority::HIGHEST, kReason);
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
- EXPECT_EQ(base::TaskPriority::HIGHEST, consumer.votes_[0].vote().priority());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
+ EXPECT_EQ(base::TaskPriority::HIGHEST, consumer.votes_[0].vote().value());
EXPECT_EQ(kReason, consumer.votes_[0].vote().reason());
// Cancel a vote.
@@ -190,8 +195,8 @@ TEST(FramePriorityTest, VoteReceiptsWork) {
EXPECT_EQ(2u, voter.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- EXPECT_EQ(kDummyFrame1, consumer.votes_[0].vote().frame_node());
- EXPECT_EQ(kDummyFrame2, consumer.votes_[1].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext1, consumer.votes_[0].context());
+ EXPECT_EQ(kDummyExecutionContext2, consumer.votes_[1].context());
ExpectNotEntangled(voter.receipts_[0], consumer.votes_[0]);
ExpectEntangled(voter.receipts_[1], consumer.votes_[1]);
@@ -200,7 +205,7 @@ TEST(FramePriorityTest, VoteReceiptsWork) {
EXPECT_EQ(2u, voter.receipts_.size());
EXPECT_EQ(1u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- EXPECT_EQ(kDummyFrame2, consumer.votes_[0].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext2, consumer.votes_[0].context());
EXPECT_FALSE(voter.receipts_[0].HasVote());
ExpectEntangled(voter.receipts_[1], consumer.votes_[0]);
@@ -209,7 +214,7 @@ TEST(FramePriorityTest, VoteReceiptsWork) {
EXPECT_EQ(1u, voter.receipts_.size());
EXPECT_EQ(1u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- EXPECT_EQ(kDummyFrame2, consumer.votes_[0].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext2, consumer.votes_[0].context());
ExpectEntangled(voter.receipts_[0], consumer.votes_[0]);
// Cancel the remaining vote by deleting the receipt.
@@ -217,10 +222,26 @@ TEST(FramePriorityTest, VoteReceiptsWork) {
EXPECT_EQ(0u, voter.receipts_.size());
EXPECT_EQ(1u, consumer.votes_.size());
EXPECT_EQ(0u, consumer.valid_vote_count_);
- EXPECT_EQ(kDummyFrame2, consumer.votes_[0].vote().frame_node());
+ EXPECT_EQ(kDummyExecutionContext2, consumer.votes_[0].context());
EXPECT_FALSE(consumer.votes_[0].HasReceipt());
EXPECT_FALSE(consumer.votes_[0].IsValid());
}
-} // namespace frame_priority
+// Tests that an overwritten vote receipt will property clean up its state.
+TEST(ExecutionContextPriorityTest, OverwriteVoteReceipt) {
+ DummyVoteConsumer consumer;
+
+ VotingChannel voting_channel =
+ consumer.voting_channel_factory_.BuildVotingChannel();
+
+ VoteReceipt receipt = voting_channel.SubmitVote(
+ kDummyExecutionContext1, Vote(base::TaskPriority::HIGHEST, kReason1));
+ receipt = voting_channel.SubmitVote(
+ kDummyExecutionContext2, Vote(base::TaskPriority::HIGHEST, kReason1));
+
+ // The first vote was invalidated because its vote receipt was cleaned up.
+ consumer.ExpectInvalidVote(0);
+}
+
+} // namespace execution_context_priority
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/max_vote_aggregator.cc b/chromium/components/performance_manager/execution_context_priority/max_vote_aggregator.cc
index 90f49177a6f..dac48c75f50 100644
--- a/chromium/components/performance_manager/frame_priority/max_vote_aggregator.cc
+++ b/chromium/components/performance_manager/execution_context_priority/max_vote_aggregator.cc
@@ -2,13 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/frame_priority/max_vote_aggregator.h"
+#include "components/performance_manager/public/execution_context_priority/max_vote_aggregator.h"
#include <algorithm>
#include <tuple>
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
+
+// static
+MaxVoteAggregator::StampedVote*
+MaxVoteAggregator::StampedVote::FromAcceptedVote(AcceptedVote* accepted_vote) {
+ static_assert(offsetof(StampedVote, vote) == 0,
+ "AcceptedVote is expected to be at offset 0 of StampedVote");
+ return reinterpret_cast<StampedVote*>(accepted_vote);
+}
MaxVoteAggregator::MaxVoteAggregator() : factory_(this) {}
@@ -25,16 +33,21 @@ void MaxVoteAggregator::SetUpstreamVotingChannel(VotingChannel&& channel) {
channel_ = std::move(channel);
}
-VoteReceipt MaxVoteAggregator::SubmitVote(VoterId voter_id, const Vote& vote) {
+VoteReceipt MaxVoteAggregator::SubmitVote(
+ util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) {
DCHECK(vote.IsValid());
DCHECK(channel_.IsValid());
// NOTE: We don't currently explicitly worry about having multiple votes for
- // the same frame from a single voter, although such logic could be added.
+ // the same execution context from a single voter, although such logic could
+ // be added.
// Add the new vote.
- VoteData& vote_data = vote_data_map_[vote.frame_node()];
- auto accepted_vote = AcceptedVote(this, voter_id, vote);
+ VoteData& vote_data = vote_data_map_[execution_context];
+ auto accepted_vote = AcceptedVote(this, voter_id, execution_context, vote);
auto receipt = accepted_vote.IssueReceipt();
if (vote_data.AddVote(std::move(accepted_vote), next_vote_id_++))
vote_data.UpstreamVote(&channel_);
@@ -43,10 +56,9 @@ VoteReceipt MaxVoteAggregator::SubmitVote(VoterId voter_id, const Vote& vote) {
return receipt;
}
-VoteReceipt MaxVoteAggregator::ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) {
- DCHECK(receipt.HasVote(old_vote));
+void MaxVoteAggregator::ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) {
DCHECK(old_vote->IsValid());
VoteData& vote_data = GetVoteData(old_vote)->second;
size_t index = vote_data.GetVoteIndex(old_vote);
@@ -55,12 +67,10 @@ VoteReceipt MaxVoteAggregator::ChangeVote(VoteReceipt receipt,
old_vote->UpdateVote(new_vote);
if (vote_data.UpdateVote(index, next_vote_id_++))
vote_data.UpstreamVote(&channel_);
-
- // Return the same receipt back to the user.
- return receipt;
}
-void MaxVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
+void MaxVoteAggregator::VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) {
DCHECK(!vote->IsValid());
auto it = GetVoteData(vote);
VoteData& vote_data = it->second;
@@ -70,12 +80,19 @@ void MaxVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
if (vote_data.RemoveVote(index))
vote_data.UpstreamVote(&channel_);
- // If all the votes for this frame have disappeared then remove the entry
- // entirely. This will automatically cancel our upstream vote.
+ // If all the votes for this execution context have disappeared then remove
+ // the entry entirely. This will automatically cancel our upstream vote.
if (vote_data.IsEmpty())
vote_data_map_.erase(it);
}
+MaxVoteAggregator::StampedVote::StampedVote() = default;
+MaxVoteAggregator::StampedVote::StampedVote(AcceptedVote&& vote,
+ uint32_t vote_id)
+ : vote(std::move(vote)), vote_id(vote_id) {}
+MaxVoteAggregator::StampedVote::StampedVote(StampedVote&&) = default;
+MaxVoteAggregator::StampedVote::~StampedVote() = default;
+
MaxVoteAggregator::VoteDataMap::iterator MaxVoteAggregator::GetVoteData(
AcceptedVote* vote) {
// The vote being retrieved should have us as its consumer, and we should
@@ -84,8 +101,8 @@ MaxVoteAggregator::VoteDataMap::iterator MaxVoteAggregator::GetVoteData(
DCHECK_EQ(this, vote->consumer());
DCHECK(channel_.IsValid());
- // Find the votes associated with this frame.
- auto it = vote_data_map_.find(vote->vote().frame_node());
+ // Find the votes associated with this execution context.
+ auto it = vote_data_map_.find(vote->context());
DCHECK(it != vote_data_map_.end());
return it;
}
@@ -137,9 +154,7 @@ bool MaxVoteAggregator::VoteData::RemoveVote(size_t index) {
}
size_t MaxVoteAggregator::VoteData::GetVoteIndex(AcceptedVote* vote) {
- static_assert(offsetof(StampedVote, vote) == 0,
- "AcceptedVote is expected to be at offset 0 of StampedVote");
- StampedVote* stamped_vote = reinterpret_cast<StampedVote*>(vote);
+ StampedVote* stamped_vote = StampedVote::FromAcceptedVote(vote);
DCHECK_NE(0u, votes_.size());
DCHECK_LE(votes_.data(), stamped_vote);
DCHECK_LT(stamped_vote, votes_.data() + votes_.size());
@@ -149,15 +164,16 @@ size_t MaxVoteAggregator::VoteData::GetVoteIndex(AcceptedVote* vote) {
void MaxVoteAggregator::VoteData::UpstreamVote(VotingChannel* channel) {
DCHECK_NE(0u, votes_.size());
DCHECK(votes_.top().vote.IsValid());
+ const ExecutionContext* execution_context = votes_.top().vote.context();
const Vote& vote = votes_.top().vote.vote();
// Change our existing vote, or create a new one as necessary.
if (receipt_.HasVote()) {
- receipt_.ChangeVote(vote.priority(), vote.reason());
+ receipt_.ChangeVote(vote.value(), vote.reason());
} else {
- receipt_ = channel->SubmitVote(vote);
+ receipt_ = channel->SubmitVote(execution_context, vote);
}
}
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/max_vote_aggregator_unittest.cc b/chromium/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc
index 7db79c9514b..d7f98e28c9e 100644
--- a/chromium/components/performance_manager/frame_priority/max_vote_aggregator_unittest.cc
+++ b/chromium/components/performance_manager/execution_context_priority/max_vote_aggregator_unittest.cc
@@ -2,27 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/frame_priority/max_vote_aggregator.h"
+#include "components/performance_manager/public/execution_context_priority/max_vote_aggregator.h"
#include "base/rand_util.h"
-#include "components/performance_manager/test_support/frame_priority.h"
+#include "components/performance_manager/test_support/voting.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
// Expose the VoteData type for testing.
class MaxVoteAggregatorTestAccess {
public:
using VoteData = MaxVoteAggregator::VoteData;
+ using StampedVote = MaxVoteAggregator::StampedVote;
};
using VoteData = MaxVoteAggregatorTestAccess::VoteData;
+using StampedVote = MaxVoteAggregatorTestAccess::StampedVote;
namespace {
-// Some dummy frames.
-const FrameNode* kFrame0 = reinterpret_cast<const FrameNode*>(0xDEADBEEF);
-const FrameNode* kFrame1 = reinterpret_cast<const FrameNode*>(0xBAADF00D);
+using DummyVoter = voting::test::DummyVoter<Vote>;
+using DummyVoteConsumer = voting::test::DummyVoteConsumer<Vote>;
+
+// Some dummy execution contexts.
+const ExecutionContext* kExecutionContext0 =
+ reinterpret_cast<const ExecutionContext*>(0xDEADBEEF);
+const ExecutionContext* kExecutionContext1 =
+ reinterpret_cast<const ExecutionContext*>(0xBAADF00D);
static constexpr base::TaskPriority kPriority0 = base::TaskPriority::LOWEST;
static constexpr base::TaskPriority kPriority1 =
@@ -58,7 +65,7 @@ const char* RandReason() {
return kReason2;
}
-class FakeVoteConsumer : public test::DummyVoteConsumer {
+class FakeVoteConsumer : public DummyVoteConsumer {
public:
FakeVoteConsumer() = default;
~FakeVoteConsumer() override = default;
@@ -66,7 +73,10 @@ class FakeVoteConsumer : public test::DummyVoteConsumer {
protected:
// Deliberately override VoteInvalidated so that this consumer silently
// ignores these notifications.
- void VoteInvalidated(AcceptedVote* vote) override { return; }
+ void VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) override {
+ return;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(FakeVoteConsumer);
@@ -74,11 +84,18 @@ class FakeVoteConsumer : public test::DummyVoteConsumer {
} // namespace
+TEST(MaxVoteAggregatorTest, StampedVoteCast) {
+ StampedVote stamped_vote;
+
+ EXPECT_EQ(&stamped_vote, StampedVote::FromAcceptedVote(&stamped_vote.vote));
+}
+
TEST(MaxVoteAggregatorTest, VoteDataHeapStressTest) {
- // Build a simple consumer/voter chain so that we generate an actual VoterId.
+ // Build a simple consumer/voter chain so that we generate an actual
+ // voting::VoterId.
FakeVoteConsumer consumer;
- test::DummyVoter voter;
- VoterId voter_id = 0;
+ DummyVoter voter;
+ voting::VoterId<Vote> voter_id;
{
auto channel = consumer.voting_channel_factory_.BuildVotingChannel();
voter_id = channel.voter_id();
@@ -119,9 +136,9 @@ TEST(MaxVoteAggregatorTest, VoteDataHeapStressTest) {
case kInsert: {
auto priority = RandPriority();
auto* reason = RandReason();
- vd.AddVote(
- AcceptedVote(&consumer, voter_id, Vote(kFrame0, priority, reason)),
- next_vote_id++);
+ vd.AddVote(AcceptedVote(&consumer, voter_id, kExecutionContext0,
+ Vote(priority, reason)),
+ next_vote_id++);
} break;
case kMove: {
@@ -130,14 +147,14 @@ TEST(MaxVoteAggregatorTest, VoteDataHeapStressTest) {
auto& vote = vd.GetVoteForTesting(index);
auto priority = RandPriority();
auto* reason = RandReason();
- while (priority == vote.vote().priority() &&
+ while (priority == vote.vote().value() &&
reason == vote.vote().reason()) {
priority = RandPriority();
reason = RandReason();
}
// Update the vote.
- vote.UpdateVote(Vote(vote.vote().frame_node(), priority, reason));
+ vote.UpdateVote(Vote(priority, reason));
vd.UpdateVote(index, next_vote_id++);
} break;
@@ -169,13 +186,13 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
// / | \
// / | \
// voter0 voter1 voter2
- test::DummyVoteConsumer consumer;
+ DummyVoteConsumer consumer;
MaxVoteAggregator agg;
- test::DummyVoter voter0;
- test::DummyVoter voter1;
- test::DummyVoter voter2;
+ DummyVoter voter0;
+ DummyVoter voter1;
+ DummyVoter voter2;
- VoterId agg_id = kInvalidVoterId;
+ voting::VoterId<Vote> agg_id = voting::kInvalidVoterId<Vote>;
{
auto channel = consumer.voting_channel_factory_.BuildVotingChannel();
agg_id = channel.voter_id();
@@ -186,17 +203,17 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
voter1.SetVotingChannel(agg.GetVotingChannel());
voter2.SetVotingChannel(agg.GetVotingChannel());
- // Create some dummy votes for each frame and immediately expect them to
- // propagate upwards.
- voter0.EmitVote(kFrame0, kPriority0, kReason0);
- voter1.EmitVote(kFrame1, kPriority1, kReason0);
+ // Create some dummy votes for each execution context and immediately expect
+ // them to propagate upwards.
+ voter0.EmitVote(kExecutionContext0, kPriority0, kReason0);
+ voter1.EmitVote(kExecutionContext1, kPriority1, kReason0);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(0u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority0, kReason0);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority0, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Change an existing vote, and expect it to propagate upwards.
voter0.receipts_[0].ChangeVote(kPriority0, kReason1);
@@ -205,30 +222,30 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(0u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority0, kReason1);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority0, kReason1);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Submit a new vote with lower priority than the upstream vote and expect no
// change.
- voter2.EmitVote(kFrame1, kPriority0, kReason0);
+ voter2.EmitVote(kExecutionContext1, kPriority0, kReason0);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority0, kReason1);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority0, kReason1);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Submit a new vote with a higher priority than the upstream vote and expect
// it to propagate.
- voter2.EmitVote(kFrame0, kPriority2, kReason0);
+ voter2.EmitVote(kExecutionContext0, kPriority2, kReason0);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(2u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority2, kReason0);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority2, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Invalidate a lower priority vote that is not upstreamed. Expect no
// upstream change.
@@ -238,19 +255,19 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(2u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority2, kReason0);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority2, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
- // Create a third vote for kFrame0 with yet another priority. Expect this not
- // to propagate.
- voter1.EmitVote(kFrame0, kPriority1, kReason0);
+ // Create a third vote for kExecutionContext0 with yet another priority.
+ // Expect this not to propagate.
+ voter1.EmitVote(kExecutionContext0, kPriority1, kReason0);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(2u, voter1.receipts_.size());
EXPECT_EQ(2u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority2, kReason0);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority2, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Invalidate the highest priority vote that is upstreamed. Expect the vote to
// revert to the next highest priority.
@@ -260,8 +277,8 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(0u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority1, kReason0);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority1, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Invalidate the next highest vote and expect it to revert to the lowest
// vote.
@@ -271,11 +288,11 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(0u, voter2.receipts_.size());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(2u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kFrame0, kPriority0, kReason1);
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(0, agg_id, kExecutionContext0, kPriority0, kReason1);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
- // Clear the last vote for |kFrame0| and expect the upstream vote to be
- // invalidated.
+ // Clear the last vote for |kExecutionContext0| and expect the upstream vote
+ // to be invalidated.
voter0.receipts_[0].Reset();
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(2u, voter1.receipts_.size());
@@ -283,7 +300,7 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
EXPECT_FALSE(consumer.votes_[0].IsValid());
- consumer.ExpectValidVote(1, agg_id, kFrame1, kPriority1, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kExecutionContext1, kPriority1, kReason0);
// Clear the last outstanding votes and expect all upstream votes to have
// been canceled.
@@ -298,5 +315,5 @@ TEST(MaxVoteAggregatorTest, BlackboxTest) {
EXPECT_FALSE(consumer.votes_[1].IsValid());
}
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/override_vote_aggregator.cc b/chromium/components/performance_manager/execution_context_priority/override_vote_aggregator.cc
index 74dba9ec812..05b1a6e5ec8 100644
--- a/chromium/components/performance_manager/frame_priority/override_vote_aggregator.cc
+++ b/chromium/components/performance_manager/execution_context_priority/override_vote_aggregator.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/frame_priority/override_vote_aggregator.h"
+#include "components/performance_manager/public/execution_context_priority/override_vote_aggregator.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
OverrideVoteAggregator::OverrideVoteAggregator() : factory_(this) {}
@@ -13,7 +13,7 @@ OverrideVoteAggregator::~OverrideVoteAggregator() = default;
VotingChannel OverrideVoteAggregator::GetOverrideVotingChannel() {
DCHECK(vote_data_map_.empty());
- DCHECK_EQ(kInvalidVoterId, override_voter_id_);
+ DCHECK_EQ(voting::kInvalidVoterId<Vote>, override_voter_id_);
DCHECK_GT(2u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
override_voter_id_ = channel.voter_id();
@@ -22,7 +22,7 @@ VotingChannel OverrideVoteAggregator::GetOverrideVotingChannel() {
VotingChannel OverrideVoteAggregator::GetDefaultVotingChannel() {
DCHECK(vote_data_map_.empty());
- DCHECK_EQ(kInvalidVoterId, default_voter_id_);
+ DCHECK_EQ(voting::kInvalidVoterId<Vote>, default_voter_id_);
DCHECK_GT(2u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
default_voter_id_ = channel.voter_id();
@@ -37,35 +37,40 @@ void OverrideVoteAggregator::SetUpstreamVotingChannel(VotingChannel&& channel) {
}
bool OverrideVoteAggregator::IsSetup() const {
- return override_voter_id_ != kInvalidVoterId &&
- default_voter_id_ != kInvalidVoterId && channel_.IsValid();
+ return override_voter_id_ != voting::kInvalidVoterId<Vote> &&
+ default_voter_id_ != voting::kInvalidVoterId<Vote> &&
+ channel_.IsValid();
}
-VoteReceipt OverrideVoteAggregator::SubmitVote(VoterId voter_id,
- const Vote& vote) {
+VoteReceipt OverrideVoteAggregator::SubmitVote(
+ util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) {
DCHECK(vote.IsValid());
DCHECK(IsSetup());
- VoteData& vote_data = vote_data_map_[vote.frame_node()];
+ VoteData& vote_data = vote_data_map_[execution_context];
if (voter_id == override_voter_id_) {
DCHECK(!vote_data.override_vote.IsValid());
- vote_data.override_vote = AcceptedVote(this, voter_id, vote);
- UpstreamVote(vote, &vote_data);
+ vote_data.override_vote =
+ AcceptedVote(this, voter_id, execution_context, vote);
+ UpstreamVote(execution_context, vote, &vote_data);
return vote_data.override_vote.IssueReceipt();
} else {
DCHECK_EQ(default_voter_id_, voter_id);
DCHECK(!vote_data.default_vote.IsValid());
- vote_data.default_vote = AcceptedVote(this, voter_id, vote);
+ vote_data.default_vote =
+ AcceptedVote(this, voter_id, execution_context, vote);
if (!vote_data.override_vote.IsValid())
- UpstreamVote(vote, &vote_data);
+ UpstreamVote(execution_context, vote, &vote_data);
return vote_data.default_vote.IssueReceipt();
}
}
-VoteReceipt OverrideVoteAggregator::ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) {
- DCHECK(receipt.HasVote(old_vote));
+void OverrideVoteAggregator::ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) {
DCHECK(old_vote->IsValid());
VoteData& vote_data = GetVoteData(old_vote)->second;
@@ -77,14 +82,12 @@ VoteReceipt OverrideVoteAggregator::ChangeVote(VoteReceipt receipt,
// (2) There is no override vote.
if (old_vote == &vote_data.override_vote ||
!vote_data.override_vote.IsValid()) {
- UpstreamVote(new_vote, &vote_data);
+ UpstreamVote(old_vote->context(), new_vote, &vote_data);
}
-
- // Pass the same receipt right back to the user.
- return receipt;
}
-void OverrideVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
+void OverrideVoteAggregator::VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) {
DCHECK(!vote->IsValid());
auto it = GetVoteData(vote);
VoteData& vote_data = it->second;
@@ -113,9 +116,13 @@ void OverrideVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
// being invalidated, and the default is valid. In this case we need to
// upstream a new vote.
if (is_override_vote)
- UpstreamVote(other->vote(), &vote_data);
+ UpstreamVote(other->context(), other->vote(), &vote_data);
}
+OverrideVoteAggregator::VoteData::VoteData() = default;
+OverrideVoteAggregator::VoteData::VoteData(VoteData&& rhs) = default;
+OverrideVoteAggregator::VoteData::~VoteData() = default;
+
OverrideVoteAggregator::VoteDataMap::iterator
OverrideVoteAggregator::GetVoteData(AcceptedVote* vote) {
// The vote being retrieved should have us as its consumer, and have been
@@ -126,19 +133,21 @@ OverrideVoteAggregator::GetVoteData(AcceptedVote* vote) {
vote->voter_id() == default_voter_id_);
DCHECK(IsSetup());
- auto it = vote_data_map_.find(vote->vote().frame_node());
+ auto it = vote_data_map_.find(vote->context());
DCHECK(it != vote_data_map_.end());
return it;
}
-void OverrideVoteAggregator::UpstreamVote(const Vote& vote,
- VoteData* vote_data) {
+void OverrideVoteAggregator::UpstreamVote(
+ const ExecutionContext* execution_context,
+ const Vote& vote,
+ VoteData* vote_data) {
// Change our existing vote, or create a new one as necessary.
if (vote_data->receipt.HasVote())
- vote_data->receipt.ChangeVote(vote.priority(), vote.reason());
+ vote_data->receipt.ChangeVote(vote.value(), vote.reason());
else
- vote_data->receipt = channel_.SubmitVote(vote);
+ vote_data->receipt = channel_.SubmitVote(execution_context, vote);
}
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/override_vote_aggregator_unittest.cc b/chromium/components/performance_manager/execution_context_priority/override_vote_aggregator_unittest.cc
index abec4ba215c..d657633fd12 100644
--- a/chromium/components/performance_manager/frame_priority/override_vote_aggregator_unittest.cc
+++ b/chromium/components/performance_manager/execution_context_priority/override_vote_aggregator_unittest.cc
@@ -2,17 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/frame_priority/override_vote_aggregator.h"
+#include "components/performance_manager/public/execution_context_priority/override_vote_aggregator.h"
-#include "components/performance_manager/test_support/frame_priority.h"
+#include "components/performance_manager/test_support/voting.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
-// Some dummy frames.
-const FrameNode* kDummyFrame1 = reinterpret_cast<const FrameNode*>(0xDEADBEEF);
-const FrameNode* kDummyFrame2 = reinterpret_cast<const FrameNode*>(0xBAADF00D);
+using DummyVoter = voting::test::DummyVoter<Vote>;
+using DummyVoteConsumer = voting::test::DummyVoteConsumer<Vote>;
+
+// Some dummy execution contexts.
+const ExecutionContext* kDummyExecutionContext =
+ reinterpret_cast<const ExecutionContext*>(0xDEADBEEF);
TEST(OverrideVoteAggregatorTest, BlackboxTest) {
// Priorities to use for default and override votes. The override priority is
@@ -33,12 +36,12 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
// / \
// voter0 voter1
// (override) (default)
- test::DummyVoteConsumer consumer;
+ DummyVoteConsumer consumer;
OverrideVoteAggregator agg;
- test::DummyVoter voter0;
- test::DummyVoter voter1;
+ DummyVoter voter0;
+ DummyVoter voter1;
- VoterId agg_id = kInvalidVoterId;
+ voting::VoterId<Vote> agg_id = voting::kInvalidVoterId<Vote>;
{
auto channel = consumer.voting_channel_factory_.BuildVotingChannel();
agg_id = channel.voter_id();
@@ -50,14 +53,14 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_TRUE(agg.IsSetup());
// Submitting a default vote should immediately propagate to the consumer.
- voter1.EmitVote(kDummyFrame1, kDefaultPriority);
+ voter1.EmitVote(kDummyExecutionContext, kDefaultPriority);
EXPECT_EQ(0u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(1u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(0, agg_id, kDummyFrame1, kDefaultPriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(0, agg_id, kDummyExecutionContext, kDefaultPriority,
+ DummyVoter::kReason);
// Canceling the default vote should clear all votes.
voter1.receipts_.clear();
@@ -68,25 +71,25 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(0u, consumer.valid_vote_count_);
// Resubmitting the default vote should propagate to the consumer.
- voter1.EmitVote(kDummyFrame1, kDefaultPriority);
+ voter1.EmitVote(kDummyExecutionContext, kDefaultPriority);
EXPECT_EQ(0u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kDefaultPriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kDefaultPriority,
+ DummyVoter::kReason);
// Submitting an override vote should override it and propagate to the
// consumer. This should update the existing vote in place.
- voter0.EmitVote(kDummyFrame1, kOverridePriority);
+ voter0.EmitVote(kDummyExecutionContext, kOverridePriority);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ DummyVoter::kReason);
// Canceling the override vote should drop back to using the default vote.
// This will again reuse the existing upstream vote.
@@ -96,8 +99,8 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kDefaultPriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kDefaultPriority,
+ DummyVoter::kReason);
// Changing the default vote should propagate, as there's no override vote.
voter1.receipts_[0].ChangeVote(kDefaultPriority, kReason);
@@ -106,28 +109,29 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kDefaultPriority, kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kDefaultPriority,
+ kReason);
// Changing back should also propagate.
- voter1.receipts_[0].ChangeVote(kDefaultPriority, test::DummyVoter::kReason);
+ voter1.receipts_[0].ChangeVote(kDefaultPriority, DummyVoter::kReason);
EXPECT_EQ(0u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kDefaultPriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kDefaultPriority,
+ DummyVoter::kReason);
// Submitting an override vote should override it and propagate to the
// consumer.
- voter0.EmitVote(kDummyFrame1, kOverridePriority);
+ voter0.EmitVote(kDummyExecutionContext, kOverridePriority);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ DummyVoter::kReason);
// Canceling the default vote should do nothing.
voter1.receipts_.clear();
@@ -136,18 +140,18 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ DummyVoter::kReason);
// Submitting another default vote should do nothing.
- voter1.EmitVote(kDummyFrame1, kDefaultPriority);
+ voter1.EmitVote(kDummyExecutionContext, kDefaultPriority);
EXPECT_EQ(1u, voter0.receipts_.size());
EXPECT_EQ(1u, voter1.receipts_.size());
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ DummyVoter::kReason);
// Changing the default vote should do nothing.
voter1.receipts_.back().ChangeVote(kDefaultPriority, kReason);
@@ -155,8 +159,8 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority,
- test::DummyVoter::kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ DummyVoter::kReason);
// Changing the override vote should change the upstream vote.
voter0.receipts_.back().ChangeVote(kOverridePriority, kReason);
@@ -164,7 +168,8 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority, kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ kReason);
// Canceling the default vote should do nothing.
voter1.receipts_.clear();
@@ -173,7 +178,8 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(1u, agg.GetSizeForTesting());
EXPECT_EQ(2u, consumer.votes_.size());
EXPECT_EQ(1u, consumer.valid_vote_count_);
- consumer.ExpectValidVote(1, agg_id, kDummyFrame1, kOverridePriority, kReason);
+ consumer.ExpectValidVote(1, agg_id, kDummyExecutionContext, kOverridePriority,
+ kReason);
// Finally, canceling the override vote should cancel the upstream vote.
voter0.receipts_.clear();
@@ -184,5 +190,5 @@ TEST(OverrideVoteAggregatorTest, BlackboxTest) {
EXPECT_EQ(0u, consumer.valid_vote_count_);
}
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/features.cc b/chromium/components/performance_manager/features.cc
index a5836952e93..747889e40cd 100644
--- a/chromium/components/performance_manager/features.cc
+++ b/chromium/components/performance_manager/features.cc
@@ -46,5 +46,8 @@ TabLoadingFrameNavigationThrottlesParams::GetParams() {
return params;
}
+const base::Feature kServiceWorkerRelationshipsInGraph{
+ "ServiceWorkerRelationshipsInGraph", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/boosting_vote_aggregator_unittest.cc b/chromium/components/performance_manager/frame_priority/boosting_vote_aggregator_unittest.cc
deleted file mode 100644
index 248af97744e..00000000000
--- a/chromium/components/performance_manager/frame_priority/boosting_vote_aggregator_unittest.cc
+++ /dev/null
@@ -1,603 +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 "components/performance_manager/public/frame_priority/boosting_vote_aggregator.h"
-
-#include "components/performance_manager/test_support/frame_priority.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace performance_manager {
-namespace frame_priority {
-
-namespace {
-
-// Some dummy frames.
-const FrameNode* kFrame0 = reinterpret_cast<const FrameNode*>(0xF5A33000);
-const FrameNode* kFrame1 = reinterpret_cast<const FrameNode*>(0xF5A33001);
-const FrameNode* kFrame2 = reinterpret_cast<const FrameNode*>(0xF5A33002);
-const FrameNode* kFrame3 = reinterpret_cast<const FrameNode*>(0xF5A33003);
-const FrameNode* kFrame4 = reinterpret_cast<const FrameNode*>(0xF5A33004);
-
-static constexpr base::TaskPriority kPriority0 = base::TaskPriority::LOWEST;
-static constexpr base::TaskPriority kPriority1 =
- base::TaskPriority::USER_VISIBLE;
-static constexpr base::TaskPriority kPriority2 = base::TaskPriority::HIGHEST;
-
-static_assert(kPriority0 < kPriority1 && kPriority1 < kPriority2,
- "priorities must be well ordered");
-
-static const char kReason0[] = "a reason";
-static const char kReason1[] = "another reason";
-static const char kReason2[] = "yet another reason";
-static const char kReasonBoost[] = "boosted!";
-
-class TestBoostingVoteAggregator : public BoostingVoteAggregator {
- public:
- using BoostingVoteAggregator::forward_edges_;
- using BoostingVoteAggregator::NodeData;
- using BoostingVoteAggregator::nodes_;
- using BoostingVoteAggregator::reverse_edges_;
-};
-
-using NodeData = TestBoostingVoteAggregator::NodeData;
-
-class BoostingVoteAggregatorTest : public testing::Test {
- public:
- void SetUp() override {
- // Set up the chain such that |voter_| provides votes to |agg_|, which
- // upstreams them to |consumer_|.
- auto channel = consumer_.voting_channel_factory_.BuildVotingChannel();
- voter_id_ = channel.voter_id();
- agg_.SetUpstreamVotingChannel(std::move(channel));
- voter_.SetVotingChannel(agg_.GetVotingChannel());
- EXPECT_TRUE(agg_.nodes_.empty());
- EXPECT_TRUE(agg_.forward_edges_.empty());
- EXPECT_TRUE(agg_.reverse_edges_.empty());
- }
-
- void ExpectEdges(size_t count) {
- EXPECT_EQ(count, agg_.forward_edges_.size());
- EXPECT_EQ(count, agg_.reverse_edges_.size());
- }
-
- void ExpectIsActive(const NodeData& node_data,
- bool mid_priority,
- bool high_priority) {
- EXPECT_EQ(mid_priority, node_data.IsActive(1));
- EXPECT_EQ(high_priority, node_data.IsActive(2));
- }
-
- // The id of |agg_| as seen by its upstream |consumer_|.
- VoterId voter_id_ = 0;
- test::DummyVoteConsumer consumer_;
- TestBoostingVoteAggregator agg_;
- test::DummyVoter voter_;
-};
-
-} // namespace
-
-TEST_F(BoostingVoteAggregatorTest, VotesUpstreamingWorks) {
- // Submit a default vote to the boosting aggregator, and expect it not to be
- // upstreamed.
- voter_.EmitVote(kFrame0, kPriority0, kReason0);
- EXPECT_EQ(1u, agg_.nodes_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote());
- ExpectEdges(0);
- EXPECT_TRUE(consumer_.votes_.empty());
-
- // Submit a non-default vote to the boosting aggregator, and expect it to be
- // upstreamed.
- voter_.EmitVote(kFrame1, kPriority1, kReason1);
- EXPECT_EQ(2u, agg_.nodes_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote());
- EXPECT_TRUE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(1u, consumer_.votes_.size());
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReason1);
-
- // Make vote 0 non-default and expect it to be upstreamed.
- voter_.receipts_[0].ChangeVote(kPriority2, kReason2);
- EXPECT_EQ(2u, agg_.nodes_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote());
- EXPECT_TRUE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReason1);
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority2, kReason2);
-
- // Make vote 1 default and expect the upstream vote to be canceled.
- voter_.receipts_[1].ChangeVote(kPriority0, kReason0);
- EXPECT_EQ(2u, agg_.nodes_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote());
- EXPECT_TRUE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectInvalidVote(0);
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority2, kReason2);
-
- // Change the reason but not the priority of vote 0 and expect the upstream
- // vote to change as well.
- voter_.receipts_[0].ChangeVote(kPriority2, kReason0);
- EXPECT_EQ(2u, agg_.nodes_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote());
- EXPECT_TRUE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectInvalidVote(0);
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority2, kReason0);
-
- // Cancel vote 0 and expect it to be canceled upstream.
- voter_.receipts_[0].Reset();
- EXPECT_EQ(1u, agg_.nodes_.size());
- EXPECT_FALSE(voter_.receipts_[0].HasVote());
- EXPECT_TRUE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectInvalidVote(0);
- consumer_.ExpectInvalidVote(1);
-
- // Cancel vote 1 and expect no change to the upstream votes.
- voter_.receipts_[1].Reset();
- EXPECT_EQ(0u, agg_.nodes_.size());
- EXPECT_FALSE(voter_.receipts_[0].HasVote());
- EXPECT_FALSE(voter_.receipts_[1].HasVote());
- ExpectEdges(0);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectInvalidVote(0);
- consumer_.ExpectInvalidVote(1);
-}
-
-TEST_F(BoostingVoteAggregatorTest, BoostingWorks) {
- // Add a boosting vote, with no actual incoming votes. This should produce
- // the two nodes associated with the edge but not upstream any votes.
- BoostingVote boost01a(&agg_, kFrame0, kFrame1, kReasonBoost);
- const auto& data0 = agg_.nodes_.find(kFrame0)->second;
- const auto& data1 = agg_.nodes_.find(kFrame1)->second;
- EXPECT_TRUE(voter_.receipts_.empty());
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_TRUE(consumer_.votes_.empty());
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
-
- // Create a second boosting vote. This duplicates the edge.
- BoostingVote boost01b(&agg_, kFrame0, kFrame1, kReasonBoost);
- EXPECT_TRUE(voter_.receipts_.empty());
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_TRUE(consumer_.votes_.empty());
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
-
- // Create a mid priority vote for frame 1. This should cause a single vote
- // to be emitted for that frame.
- voter_.EmitVote(kFrame1, kPriority1, kReason1);
- EXPECT_EQ(1u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[0].HasVote()); // kFrame1.
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(1u, consumer_.votes_.size());
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReason1);
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, true, false);
-
- // Create a mid priority vote for frame 0. This should cause another vote to
- // be emitted.
- voter_.EmitVote(kFrame0, kPriority1, kReason1);
- EXPECT_EQ(2u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_TRUE(voter_.receipts_[0].HasVote()); // kFrame1.
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReason1);
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
-
- // Cancel the priority 1 vote for frame 1. The boosting should maintain the
- // output priority for that node.
- voter_.receipts_[0].Reset(); // kFrame1.
- EXPECT_EQ(2u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReasonBoost);
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
-
- // Create a default vote for a third frame. Other than creating the node data
- // and the vote this shouldn't do anything.
- voter_.EmitVote(kFrame2, kPriority0, kReason0);
- const auto& data2 = agg_.nodes_.find(kFrame2)->second;
- EXPECT_EQ(3u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReasonBoost);
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(0u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
- ExpectIsActive(data2, false, false);
-
- // Create a boosting vote from frame 2 to frame 0. This should create an edge.
- BoostingVote boost20(&agg_, kFrame2, kFrame0, kReasonBoost);
- EXPECT_EQ(3u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(2u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReasonBoost);
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
- ExpectIsActive(data2, false, false);
-
- // Emit a highest priority vote for frame 2. This should boost frames 0 and
- // 1 as well.
- voter_.receipts_[2].ChangeVote(kPriority2, kReason2); // kFrame2.
- EXPECT_EQ(3u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority2, kReasonBoost);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority2, kReasonBoost);
- consumer_.ExpectValidVote(2, voter_id_, kFrame2, kPriority2, kReason2);
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, true);
- ExpectIsActive(data1, true, true);
- ExpectIsActive(data2, false, true);
-
- // Emit a highest priority vote for frame 1. This should change the vote
- // reason.
- voter_.EmitVote(kFrame1, kPriority2, kReason2);
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_TRUE(voter_.receipts_[3].HasVote()); // kFrame1.
- EXPECT_TRUE(voter_.receipts_[2].HasVote()); // kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority2,
- kReasonBoost); // kFrame0.
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority2,
- kReason2); // kFrame1.
- consumer_.ExpectValidVote(2, voter_id_, kFrame2, kPriority2,
- kReason2); // kFrame2.
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, true);
- ExpectIsActive(data1, true, true);
- ExpectIsActive(data2, false, true);
-
- // Kill the vote for frame 2. This should kill the upstream vote for frame 2
- // entirely, reduce the priority of frame 0, and keep frame 1 the same.
- voter_.receipts_[2].Reset(); // kFrame2.
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_TRUE(voter_.receipts_[3].HasVote()); // kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority2, kReason2);
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, true);
- ExpectIsActive(data2, false, false);
-
- // Kill the direct vote for frame 1 so it goes back to being boosted by
- // frame 0.
- voter_.receipts_[3].Reset();
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReasonBoost);
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
- ExpectIsActive(data2, false, false);
-
- // Kill the first boosting vote from 0 to 1. This should do nothing but change
- // edge the multiplicity of the edge.
- boost01a.Reset();
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectEdges(2);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectValidVote(0, voter_id_, kFrame1, kPriority1, kReasonBoost);
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(2u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data1.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data1, true, false);
- ExpectIsActive(data2, false, false);
-
- // Kill the second boosting vote from 0 to 1. This should change edge counts,
- // and remove both the vote and the node data. The variable |data1| is now
- // invalid.
- boost01b.Reset();
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectInvalidVote(0); // Old kFrame1.
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data2, false, false);
-
- // Move the boosting vote. The move should not cause any outwardly visible
- // changes.
- BoostingVote boost20b(std::move(boost20));
- EXPECT_EQ(&agg_, boost20b.aggregator());
- EXPECT_EQ(kFrame2, boost20b.input_frame());
- EXPECT_EQ(kFrame0, boost20b.output_frame());
- EXPECT_EQ(kReasonBoost, boost20b.reason());
- EXPECT_FALSE(boost20.aggregator());
- EXPECT_FALSE(boost20.input_frame());
- EXPECT_FALSE(boost20.output_frame());
- EXPECT_FALSE(boost20.reason());
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(2u, agg_.nodes_.size());
- ExpectEdges(1);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectInvalidVote(0); // Old kFrame1.
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(1u, data0.edge_count_for_testing());
- EXPECT_EQ(1u, data2.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
- ExpectIsActive(data2, false, false);
-
- // Remove the boosting vote from 2 to 0. This should change edge counts, and
- // also remove the node data associated with node 2. |data2| is now invalid.
- boost20b.Reset();
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_TRUE(voter_.receipts_[1].HasVote()); // kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(1u, agg_.nodes_.size());
- ExpectEdges(0);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectValidVote(1, voter_id_, kFrame0, kPriority1, kReason1);
- consumer_.ExpectInvalidVote(0); // Old kFrame1.
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
- EXPECT_EQ(0u, data0.edge_count_for_testing());
- ExpectIsActive(data0, true, false);
-
- // Finally remove the last vote. The aggregator should effectively be empty at
- // this point. |data0| also becomes invalid after this.
- voter_.receipts_[1].Reset();
- EXPECT_EQ(4u, voter_.receipts_.size());
- EXPECT_FALSE(voter_.receipts_[1].HasVote()); // Old kFrame0.
- EXPECT_FALSE(voter_.receipts_[0].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[3].HasVote()); // Old kFrame1.
- EXPECT_FALSE(voter_.receipts_[2].HasVote()); // Old kFrame2.
- EXPECT_EQ(0u, agg_.nodes_.size());
- ExpectEdges(0);
- EXPECT_EQ(3u, consumer_.votes_.size());
- consumer_.ExpectInvalidVote(1); // Old kFrame0.
- consumer_.ExpectInvalidVote(0); // Old kFrame1.
- consumer_.ExpectInvalidVote(2); // Old kFrame2.
-}
-
-TEST_F(BoostingVoteAggregatorTest, DiamondPattern) {
- // Create a diamond boosting vote pattern:
- //
- // 1
- // / \
- // 0 3
- // \ /
- // 2
- BoostingVote boost01(&agg_, kFrame0, kFrame1, kReasonBoost);
- BoostingVote boost02(&agg_, kFrame0, kFrame2, kReasonBoost);
- BoostingVote boost13(&agg_, kFrame1, kFrame3, kReasonBoost);
- BoostingVote boost23(&agg_, kFrame2, kFrame3, kReasonBoost);
-
- const auto& data0 = agg_.nodes_.find(kFrame0)->second;
- const auto& data1 = agg_.nodes_.find(kFrame1)->second;
- const auto& data2 = agg_.nodes_.find(kFrame2)->second;
- const auto& data3 = agg_.nodes_.find(kFrame3)->second;
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
- ExpectIsActive(data2, false, false);
- ExpectIsActive(data3, false, false);
-
- // Add a vote to node 0. This should cause all nodes to be boosted.
- voter_.EmitVote(kFrame0, kPriority2, kReason2);
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, true);
- ExpectIsActive(data2, false, true);
- ExpectIsActive(data3, false, true);
-
- // Cancel the vote. All boosting should disappear.
- voter_.receipts_.clear();
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
- ExpectIsActive(data2, false, false);
- ExpectIsActive(data3, false, false);
-}
-
-TEST_F(BoostingVoteAggregatorTest, DiamondPatternMultipleVotes) {
- // Create another diamond boosting vote pattern:
- //
- // 1
- // / \
- // 4 - 0 3
- // \ /
- // 2
- BoostingVote boost01(&agg_, kFrame0, kFrame1, kReasonBoost);
- BoostingVote boost02(&agg_, kFrame0, kFrame2, kReasonBoost);
- BoostingVote boost13(&agg_, kFrame1, kFrame3, kReasonBoost);
- BoostingVote boost23(&agg_, kFrame2, kFrame3, kReasonBoost);
-
- const auto& data0 = agg_.nodes_.find(kFrame0)->second;
- const auto& data1 = agg_.nodes_.find(kFrame1)->second;
- const auto& data2 = agg_.nodes_.find(kFrame2)->second;
- const auto& data3 = agg_.nodes_.find(kFrame3)->second;
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
- ExpectIsActive(data2, false, false);
- ExpectIsActive(data3, false, false);
-
- // Add a vote to node 0. This should cause all downstream nodes to be boosted.
- voter_.EmitVote(kFrame0, kPriority2, kReason2);
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, true);
- ExpectIsActive(data2, false, true);
- ExpectIsActive(data3, false, true);
-
- // Add a lower vote to frame0 via frame4. This should also propagate through
- // the network in a similar way.
- BoostingVote boost40(&agg_, kFrame4, kFrame0, kReasonBoost);
- const auto& data4 = agg_.nodes_.find(kFrame4)->second;
- voter_.EmitVote(kFrame4, kPriority1, kReason1);
- ExpectIsActive(data0, true, true);
- ExpectIsActive(data1, true, true);
- ExpectIsActive(data2, true, true);
- ExpectIsActive(data3, true, true);
- ExpectIsActive(data4, true, false);
-}
-
-TEST_F(BoostingVoteAggregatorTest, RemoveEdgeFromCycle) {
- BoostingVote boost01(&agg_, kFrame0, kFrame1, kReasonBoost);
- BoostingVote boost12(&agg_, kFrame1, kFrame2, kReasonBoost);
- BoostingVote boost23(&agg_, kFrame2, kFrame3, kReasonBoost);
- BoostingVote boost30(&agg_, kFrame3, kFrame0, kReasonBoost);
-
- const auto& data0 = agg_.nodes_.find(kFrame0)->second;
- const auto& data1 = agg_.nodes_.find(kFrame1)->second;
- const auto& data2 = agg_.nodes_.find(kFrame2)->second;
- const auto& data3 = agg_.nodes_.find(kFrame3)->second;
- ExpectIsActive(data0, false, false);
- ExpectIsActive(data1, false, false);
- ExpectIsActive(data2, false, false);
- ExpectIsActive(data3, false, false);
-
- // Add a vote to node 0.
- voter_.EmitVote(kFrame0, kPriority2, kReason2);
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, true);
- ExpectIsActive(data2, false, true);
- ExpectIsActive(data3, false, true);
-
- // Remove an edge from the cycle. The first half of the cycle should still
- // be boosted, the second half should not.
- boost12.Reset();
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, true);
- ExpectIsActive(data2, false, false);
- ExpectIsActive(data3, false, false);
-}
-
-TEST_F(BoostingVoteAggregatorTest, MoveCancelsPreviousBoostingVote) {
- BoostingVote boost01(&agg_, kFrame0, kFrame1, kReasonBoost);
- BoostingVote boost12(&agg_, kFrame1, kFrame2, kReasonBoost);
-
- // Expect nodes to have been created for all nodes involved in boosting votes.
- EXPECT_TRUE(agg_.nodes_.count(kFrame0));
- EXPECT_TRUE(agg_.nodes_.count(kFrame1));
- EXPECT_TRUE(agg_.nodes_.count(kFrame2));
-
- // Move one boosting vote into the other. This should cause the latter to be
- // canceled. In this case that means node0 should be removed.
- boost01 = std::move(boost12);
- EXPECT_FALSE(agg_.nodes_.count(kFrame0));
- EXPECT_TRUE(agg_.nodes_.count(kFrame1));
- EXPECT_TRUE(agg_.nodes_.count(kFrame2));
-}
-
-TEST_F(BoostingVoteAggregatorTest, BoostingVoteAfterNormalVotes) {
- voter_.EmitVote(kFrame0, kPriority2, kReason2);
- EXPECT_TRUE(agg_.nodes_.count(kFrame0));
- EXPECT_EQ(1u, agg_.nodes_.size());
- const auto& data0 = agg_.nodes_.find(kFrame0)->second;
- ExpectIsActive(data0, false, true);
-
- BoostingVote boost12(&agg_, kFrame1, kFrame2, kReasonBoost);
- EXPECT_TRUE(agg_.nodes_.count(kFrame0));
- EXPECT_TRUE(agg_.nodes_.count(kFrame1));
- EXPECT_TRUE(agg_.nodes_.count(kFrame2));
- EXPECT_EQ(3u, agg_.nodes_.size());
- const auto& data1 = agg_.nodes_.find(kFrame1)->second;
- const auto& data2 = agg_.nodes_.find(kFrame2)->second;
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, false);
- ExpectIsActive(data2, false, false);
-
- BoostingVote boost01(&agg_, kFrame0, kFrame1, kReasonBoost);
- EXPECT_TRUE(agg_.nodes_.count(kFrame0));
- EXPECT_TRUE(agg_.nodes_.count(kFrame1));
- EXPECT_TRUE(agg_.nodes_.count(kFrame2));
- EXPECT_EQ(3u, agg_.nodes_.size());
- ExpectIsActive(data0, false, true);
- ExpectIsActive(data1, false, true);
- ExpectIsActive(data2, false, true);
-}
-
-} // namespace frame_priority
-} // namespace performance_manager
diff --git a/chromium/components/performance_manager/frame_priority/frame_priority.cc b/chromium/components/performance_manager/frame_priority/frame_priority.cc
deleted file mode 100644
index 119b2874b85..00000000000
--- a/chromium/components/performance_manager/frame_priority/frame_priority.cc
+++ /dev/null
@@ -1,403 +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 "components/performance_manager/public/frame_priority/frame_priority.h"
-
-#include <cstring>
-#include <utility>
-
-namespace performance_manager {
-namespace frame_priority {
-
-int ReasonCompare(const char* reason1, const char* reason2) {
- if (reason1 == reason2)
- return 0;
- if (reason1 == nullptr)
- return -1;
- if (reason2 == nullptr)
- return 1;
- return ::strcmp(reason1, reason2);
-}
-
-/////////////////////////////////////////////////////////////////////
-// PriorityAndReason
-
-int PriorityAndReason::Compare(const PriorityAndReason& other) const {
- if (priority_ > other.priority_)
- return 1;
- if (priority_ < other.priority_)
- return -1;
- return ReasonCompare(reason_, other.reason_);
-}
-
-bool PriorityAndReason::operator==(const PriorityAndReason& other) const {
- return Compare(other) == 0;
-}
-
-bool PriorityAndReason::operator!=(const PriorityAndReason& other) const {
- return Compare(other) != 0;
-}
-
-bool PriorityAndReason::operator<=(const PriorityAndReason& other) const {
- return Compare(other) <= 0;
-}
-
-bool PriorityAndReason::operator>=(const PriorityAndReason& other) const {
- return Compare(other) >= 0;
-}
-
-bool PriorityAndReason::operator<(const PriorityAndReason& other) const {
- return Compare(other) < 0;
-}
-
-bool PriorityAndReason::operator>(const PriorityAndReason& other) const {
- return Compare(other) > 0;
-}
-
-/////////////////////////////////////////////////////////////////////
-// Vote
-
-Vote::Vote() = default;
-
-Vote::Vote(const FrameNode* frame_node,
- base::TaskPriority priority,
- const char* reason)
- : frame_node_(frame_node), priority_(priority), reason_(reason) {}
-
-Vote::Vote(const Vote& rhs) = default;
-
-Vote& Vote::operator=(const Vote& rhs) = default;
-
-Vote::~Vote() = default;
-
-bool Vote::operator==(const Vote& vote) const {
- return frame_node_ == vote.frame_node_ && priority_ == vote.priority_ &&
- ::strcmp(reason_, vote.reason_) == 0;
-}
-
-bool Vote::operator!=(const Vote& vote) const {
- return !(*this == vote);
-}
-
-bool Vote::IsValid() const {
- return frame_node_ && reason_;
-}
-
-/////////////////////////////////////////////////////////////////////
-// VoteReceipt
-
-VoteReceipt::VoteReceipt() = default;
-
-VoteReceipt::VoteReceipt(VoteReceipt&& rhs) {
- Take(std::move(rhs));
-}
-
-VoteReceipt& VoteReceipt::operator=(VoteReceipt&& rhs) {
- Take(std::move(rhs));
- return *this;
-}
-
-VoteReceipt::~VoteReceipt() {
- Reset();
-}
-
-bool VoteReceipt::HasVote() const {
- return vote_;
-}
-
-bool VoteReceipt::HasVote(const AcceptedVote* vote) const {
- return vote_ == vote;
-}
-
-VoteConsumer* VoteReceipt::GetConsumer() const {
- return vote_->consumer();
-}
-
-VoterId VoteReceipt::GetVoterId() const {
- return vote_->voter_id();
-}
-
-const Vote& VoteReceipt::GetVote() const {
- return vote_->vote();
-}
-
-void VoteReceipt::ChangeVote(base::TaskPriority priority, const char* reason) {
- DCHECK(vote_);
-
- // Do nothing if the vote hasn't actually changed.
- const auto& vote = vote_->vote();
- if (vote.priority() == priority && vote.reason() == reason)
- return;
-
- *this = vote_->ChangeVote(std::move(*this), priority, reason);
-}
-
-void VoteReceipt::Reset() {
- if (vote_) {
- vote_->InvalidateVote(this);
- vote_ = nullptr;
- }
-}
-
-void VoteReceipt::MoveVote(AcceptedVote* old_vote, AcceptedVote* new_vote) {
- DCHECK(old_vote);
- DCHECK(new_vote);
- DCHECK_EQ(vote_, old_vote);
- vote_ = new_vote;
-
- // The vote should already be associated with this receipt (as the vote
- // initiated the move).
- DCHECK(vote_->HasReceipt(this));
-}
-
-VoteReceipt::VoteReceipt(AcceptedVote* vote) : vote_(vote) {
- // The vote should be valid and not be associated with any receipt.
- DCHECK(vote->IsValid());
- DCHECK(vote->HasReceipt(nullptr));
-
- // Associate the vote with this newly issued receipt.
- vote->SetReceipt(this);
-}
-
-void VoteReceipt::Take(VoteReceipt&& rhs) {
- vote_ = rhs.vote_;
-
- // Update the back-pointer from the vote.
- if (vote_)
- vote_->MoveReceipt(&rhs, this);
-
- rhs.vote_ = nullptr;
-}
-
-/////////////////////////////////////////////////////////////////////
-// AcceptedVote
-
-AcceptedVote::AcceptedVote() = default;
-
-AcceptedVote::AcceptedVote(VoteConsumer* consumer,
- VoterId voter_id,
- const Vote& vote)
- : consumer_(consumer),
- voter_id_(voter_id),
- vote_(vote),
- invalidated_(false) {
- DCHECK(consumer);
- DCHECK_NE(kInvalidVoterId, voter_id_);
- DCHECK(vote.IsValid());
-}
-
-AcceptedVote::AcceptedVote(AcceptedVote&& rhs) {
- Take(std::move(rhs));
-}
-
-AcceptedVote& AcceptedVote::operator=(AcceptedVote&& rhs) {
- Take(std::move(rhs));
- return *this;
-}
-
-AcceptedVote::~AcceptedVote() {
- // A vote should not be destroyed while it has an outstanding receipt. It is
- // up to Voters to destroy their votes when they go out of scope, and
- // consumers must outlive voters.
- DCHECK(!receipt_);
-}
-
-bool AcceptedVote::HasReceipt() const {
- return receipt_;
-}
-
-bool AcceptedVote::HasReceipt(const VoteReceipt* receipt) const {
- return receipt_ == receipt;
-}
-
-bool AcceptedVote::IsValid() const {
- return consumer_ && voter_id_ != kInvalidVoterId && vote_.IsValid() &&
- !invalidated_;
-}
-
-VoteReceipt AcceptedVote::IssueReceipt() {
- return VoteReceipt(this);
-}
-
-void AcceptedVote::UpdateVote(const Vote& vote) {
- DCHECK_EQ(vote_.frame_node(), vote.frame_node());
- DCHECK(vote_.priority() != vote.priority() ||
- vote_.reason() != vote.reason());
- vote_ = vote;
-}
-
-void AcceptedVote::SetReceipt(VoteReceipt* receipt) {
- // A receipt can only be set on a vote once in its lifetime.
- DCHECK(!receipt_);
- DCHECK(!invalidated_);
- receipt_ = receipt;
-
- // The receipt should already be associated with this vote (the association
- // is initiated by the receipt).
- DCHECK(receipt_->HasVote(this));
-}
-
-void AcceptedVote::MoveReceipt(VoteReceipt* old_receipt,
- VoteReceipt* new_receipt) {
- DCHECK(old_receipt);
- DCHECK(new_receipt);
- DCHECK_EQ(receipt_, old_receipt);
- receipt_ = new_receipt;
-
- // The receipt should already be associated with this vote (its calling for
- // the move).
- DCHECK(receipt_->HasVote(this));
-}
-
-VoteReceipt AcceptedVote::ChangeVote(VoteReceipt receipt,
- base::TaskPriority priority,
- const char* reason) {
- DCHECK_EQ(receipt_, &receipt);
- DCHECK(!invalidated_);
- DCHECK(vote_.priority() != priority || vote_.reason() != reason);
-
- // Explicitly save a copy of |vote_| as the consumer might overwrite it
- // directly.
- Vote old_vote = vote_;
-
- // Notify the consumer of the new vote.
- Vote new_vote = Vote(old_vote.frame_node(), priority, reason);
- receipt = consumer_->ChangeVote(std::move(receipt), this, new_vote);
-
- // Ensure that the returned receipt refers to a vote with the expected
- // properties.
- const Vote& returned_vote = receipt.GetVote();
- DCHECK_EQ(new_vote.frame_node(), returned_vote.frame_node());
- DCHECK_EQ(new_vote.priority(), returned_vote.priority());
- DCHECK_EQ(new_vote.reason(), returned_vote.reason());
-
- return receipt;
-}
-
-void AcceptedVote::InvalidateVote(VoteReceipt* receipt) {
- DCHECK(receipt);
- DCHECK_EQ(receipt_, receipt);
- DCHECK(!invalidated_);
-
- // Care has to be taken not to access |receipt|, as it is running its
- // destructor. It is only passed as a parameter to ensure that the proper
- // receipt is notifying this vote.
- receipt_ = nullptr;
- invalidated_ = true;
- consumer_->VoteInvalidated(this);
-}
-
-void AcceptedVote::Take(AcceptedVote&& rhs) {
- // An AcceptedVote can't be overwritten while it has a pending receipt.
- DCHECK(!receipt_);
-
- consumer_ = std::exchange(rhs.consumer_, nullptr);
- voter_id_ = std::exchange(rhs.voter_id_, kInvalidVoterId);
- vote_ = std::exchange(rhs.vote_, Vote());
- receipt_ = std::exchange(rhs.receipt_, nullptr);
- invalidated_ = std::exchange(rhs.invalidated_, true);
-
- // Update the back-pointer from the receipt.
- if (receipt_)
- receipt_->MoveVote(&rhs, this);
-}
-
-/////////////////////////////////////////////////////////////////////
-// VotingChannel
-
-VotingChannel::VotingChannel() = default;
-
-VotingChannel::VotingChannel(VotingChannel&& rhs) {
- Take(std::move(rhs));
-}
-
-VotingChannel& VotingChannel::operator=(VotingChannel&& rhs) {
- Take(std::move(rhs));
- return *this;
-}
-
-VotingChannel::~VotingChannel() {
- Reset();
-}
-
-VoteReceipt VotingChannel::SubmitVote(const Vote& vote) {
- // Pass the vote along to the consumer with the bound |voter_id_|.
- return factory_->consumer_->SubmitVote(voter_id_, vote);
-}
-
-bool VotingChannel::IsValid() const {
- return factory_ && voter_id_ != kInvalidVoterId;
-}
-
-void VotingChannel::Reset() {
- if (!factory_)
- return;
- DCHECK_NE(kInvalidVoterId, voter_id_);
- factory_->OnVotingChannelDestroyed();
- factory_ = nullptr;
- voter_id_ = kInvalidVoterId;
-}
-
-VotingChannel::VotingChannel(VotingChannelFactory* factory, VoterId voter_id)
- : factory_(factory), voter_id_(voter_id) {}
-
-void VotingChannel::Take(VotingChannel&& rhs) {
- Reset();
- factory_ = std::exchange(rhs.factory_, nullptr);
- voter_id_ = std::exchange(rhs.voter_id_, kInvalidVoterId);
-}
-
-/////////////////////////////////////////////////////////////////////
-// VotingChannelFactory
-
-VotingChannelFactory::VotingChannelFactory(VoteConsumer* consumer)
- : consumer_(consumer) {
- DCHECK(consumer);
-}
-
-VotingChannelFactory::~VotingChannelFactory() {
- // We expect all voters to have severed their VotingChannels before we are
- // torn down.
- DCHECK_EQ(0u, voting_channels_outstanding_);
-}
-
-VotingChannel VotingChannelFactory::BuildVotingChannel() {
- ++voting_channels_outstanding_;
- VoterId new_voter_id = ++voting_channels_issued_;
- return VotingChannel(this, new_voter_id);
-}
-
-void VotingChannelFactory::OnVotingChannelDestroyed() {
- DCHECK_LT(0u, voting_channels_outstanding_);
- --voting_channels_outstanding_;
-}
-
-/////////////////////////////////////////////////////////////////////
-// VoteConsumer
-
-VoteConsumer::VoteConsumer() = default;
-VoteConsumer::~VoteConsumer() = default;
-
-/////////////////////////////////////////////////////////////////////
-// VoteConsumerDefaultImpl
-
-VoteConsumerDefaultImpl::VoteConsumerDefaultImpl() = default;
-VoteConsumerDefaultImpl::~VoteConsumerDefaultImpl() = default;
-
-VoteReceipt VoteConsumerDefaultImpl::ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) {
- // The receipt and vote should be entangled, and the vote should be valid.
- DCHECK(receipt.HasVote(old_vote));
- DCHECK(old_vote->IsValid());
-
- // Tear down the old vote before submitting a new one in order to prevent
- // the voter from having 2 simultaneous votes for the same frame.
- auto voter_id = receipt.GetVoterId();
- receipt.Reset();
- return SubmitVote(voter_id, new_vote);
-}
-
-} // namespace frame_priority
-} // namespace performance_manager
diff --git a/chromium/components/performance_manager/freezing/freezing_vote_aggregator.cc b/chromium/components/performance_manager/freezing/freezing_vote_aggregator.cc
new file mode 100644
index 00000000000..fa3a657c574
--- /dev/null
+++ b/chromium/components/performance_manager/freezing/freezing_vote_aggregator.cc
@@ -0,0 +1,194 @@
+// Copyright 2020 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/performance_manager/freezing/freezing_vote_aggregator.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+
+namespace performance_manager {
+namespace freezing {
+
+FreezingVoteAggregator::FreezingVoteAggregator() : factory_(this) {}
+FreezingVoteAggregator::~FreezingVoteAggregator() = default;
+
+FreezingVotingChannel FreezingVoteAggregator::GetVotingChannel() {
+ return factory_.BuildVotingChannel();
+}
+
+void FreezingVoteAggregator::SetUpstreamVotingChannel(
+ FreezingVotingChannel&& channel) {
+ DCHECK(channel.IsValid());
+ DCHECK(vote_data_map_.empty());
+ DCHECK(!channel_.IsValid());
+ channel_ = std::move(channel);
+}
+
+FreezingVoteReceipt FreezingVoteAggregator::SubmitVote(
+ util::PassKey<FreezingVotingChannel>,
+ voting::VoterId<FreezingVote> voter_id,
+ const PageNode* page_node,
+ const FreezingVote& vote) {
+ DCHECK(vote.IsValid());
+ DCHECK(channel_.IsValid());
+
+ auto& vote_data = vote_data_map_[page_node];
+
+ AcceptedFreezingVote accepted_vote(this, voter_id, page_node, vote);
+ auto receipt = accepted_vote.IssueReceipt();
+ if (vote_data.AddVote(std::move(accepted_vote)) ==
+ FreezingVoteData::UpstreamVoteImpact::kUpstreamVoteChanged) {
+ vote_data.UpstreamVote(&channel_);
+ }
+
+ // Return a vote receipt to our voter for the received vote.
+ return receipt;
+}
+
+void FreezingVoteAggregator::ChangeVote(util::PassKey<AcceptedFreezingVote>,
+ AcceptedFreezingVote* old_vote,
+ const FreezingVote& new_vote) {
+ DCHECK(old_vote->IsValid());
+
+ auto& vote_data = GetVoteData(old_vote->context())->second;
+
+ if (vote_data.UpdateVote(old_vote, new_vote) ==
+ FreezingVoteData::UpstreamVoteImpact::kUpstreamVoteChanged) {
+ vote_data.UpstreamVote(&channel_);
+ }
+}
+
+void FreezingVoteAggregator::VoteInvalidated(
+ util::PassKey<AcceptedFreezingVote>,
+ AcceptedFreezingVote* vote) {
+ DCHECK(!vote->IsValid());
+ auto it = GetVoteData(vote->context());
+ auto& vote_data = it->second;
+
+ auto remove_vote_result = vote_data.RemoveVote(vote);
+ // Remove the vote, and upstream if necessary.
+ if (remove_vote_result ==
+ FreezingVoteData::UpstreamVoteImpact::kUpstreamVoteChanged) {
+ vote_data.UpstreamVote(&channel_);
+ }
+
+ // If all the votes for this PageNode have disappeared then remove the entry
+ // entirely. This will release the receipt that it contains and will cancel
+ // our upstream vote.
+ if (remove_vote_result ==
+ FreezingVoteData::UpstreamVoteImpact::kUpstreamVoteRemoved) {
+ vote_data_map_.erase(it);
+ }
+}
+
+FreezingVoteAggregator::FreezingVoteData::FreezingVoteData() = default;
+FreezingVoteAggregator::FreezingVoteData::FreezingVoteData(FreezingVoteData&&) =
+ default;
+FreezingVoteAggregator::FreezingVoteData&
+FreezingVoteAggregator::FreezingVoteData::operator=(
+ FreezingVoteAggregator::FreezingVoteData&& rhs) = default;
+FreezingVoteAggregator::FreezingVoteData::~FreezingVoteData() = default;
+
+FreezingVoteAggregator::FreezingVoteData::UpstreamVoteImpact
+FreezingVoteAggregator::FreezingVoteData::AddVote(AcceptedFreezingVote&& vote) {
+ auto current_decision = FreezingVoteValue::kCanFreeze;
+ if (accepted_votes_.size())
+ current_decision = GetCurrentVote().vote().value();
+
+ AddVoteToDeque(std::move(vote));
+
+ // Always report the first vote.
+ if (accepted_votes_.size() == 1)
+ return UpstreamVoteImpact::kUpstreamVoteChanged;
+
+ return (current_decision != GetCurrentVote().vote().value())
+ ? UpstreamVoteImpact::kUpstreamVoteChanged
+ : UpstreamVoteImpact::kUpstreamVoteUnchanged;
+}
+
+FreezingVoteAggregator::FreezingVoteData::UpstreamVoteImpact
+FreezingVoteAggregator::FreezingVoteData::UpdateVote(
+ AcceptedFreezingVote* old_vote,
+ const FreezingVote& new_vote) {
+ auto current_decision = GetCurrentVote().vote().value();
+
+ auto it = FindVote(old_vote);
+ DCHECK(it != accepted_votes_.end());
+ auto vote = std::move(*it);
+ accepted_votes_.erase(it);
+ vote.UpdateVote(new_vote);
+ AddVoteToDeque(std::move(vote));
+
+ return (current_decision != GetCurrentVote().vote().value())
+ ? UpstreamVoteImpact::kUpstreamVoteChanged
+ : UpstreamVoteImpact::kUpstreamVoteUnchanged;
+}
+
+FreezingVoteAggregator::FreezingVoteData::UpstreamVoteImpact
+FreezingVoteAggregator::FreezingVoteData::RemoveVote(
+ AcceptedFreezingVote* vote) {
+ auto current_decision = GetCurrentVote().vote().value();
+
+ accepted_votes_.erase(FindVote(vote));
+
+ // Indicate that the upstream vote should be removed.
+ if (accepted_votes_.empty())
+ return UpstreamVoteImpact::kUpstreamVoteRemoved;
+
+ return (current_decision != GetCurrentVote().vote().value())
+ ? UpstreamVoteImpact::kUpstreamVoteChanged
+ : UpstreamVoteImpact::kUpstreamVoteUnchanged;
+}
+
+void FreezingVoteAggregator::FreezingVoteData::UpstreamVote(
+ FreezingVotingChannel* channel) {
+ DCHECK_NE(0u, accepted_votes_.size());
+ auto& vote = GetCurrentVote();
+
+ // Change our existing vote, or create a new one as necessary.
+ if (receipt_.HasVote()) {
+ receipt_.ChangeVote(vote.vote().value(), vote.vote().reason());
+ } else {
+ receipt_ = channel->SubmitVote(vote.context(), vote.vote());
+ }
+}
+
+const AcceptedFreezingVote&
+FreezingVoteAggregator::FreezingVoteData::GetCurrentVote() {
+ DCHECK(!IsEmpty());
+ // The set of votes is ordered and the first one in the set is the one that
+ // should be sent to the consumer.
+ return *accepted_votes_.begin();
+}
+
+FreezingVoteAggregator::FreezingVoteData::AcceptedVotesDeque::iterator
+FreezingVoteAggregator::FreezingVoteData::FindVote(AcceptedFreezingVote* vote) {
+ // TODO(sebmarchand): Consider doing a reverse search for kCanFreeze votes and
+ // a normal one for kCannotFreeze votes.
+
+ auto it = std::find_if(accepted_votes_.begin(), accepted_votes_.end(),
+ [vote](const auto& rhs) { return &rhs == vote; });
+ DCHECK(it != accepted_votes_.end());
+ return it;
+}
+
+void FreezingVoteAggregator::FreezingVoteData::AddVoteToDeque(
+ AcceptedFreezingVote&& vote) {
+ if (vote.vote().value() == FreezingVoteValue::kCannotFreeze) {
+ accepted_votes_.push_front(std::move(vote));
+ } else {
+ accepted_votes_.push_back(std::move(vote));
+ }
+}
+
+FreezingVoteAggregator::VoteDataMap::iterator
+FreezingVoteAggregator::GetVoteData(const PageNode* page_node) {
+ auto it = vote_data_map_.find(page_node);
+ DCHECK(it != vote_data_map_.end());
+ return it;
+}
+
+} // namespace freezing
+} // namespace performance_manager \ No newline at end of file
diff --git a/chromium/components/performance_manager/freezing/freezing_vote_aggregator.h b/chromium/components/performance_manager/freezing/freezing_vote_aggregator.h
new file mode 100644
index 00000000000..d5ee06876a2
--- /dev/null
+++ b/chromium/components/performance_manager/freezing/freezing_vote_aggregator.h
@@ -0,0 +1,151 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_
+
+#include "base/compiler_specific.h"
+#include "base/containers/circular_deque.h"
+#include "base/containers/flat_map.h"
+#include "components/performance_manager/public/voting/voting.h"
+
+namespace performance_manager {
+
+class PageNode;
+
+namespace freezing {
+
+enum class FreezingVoteValue {
+ kCannotFreeze,
+ kCanFreeze,
+};
+
+using FreezingVote =
+ voting::Vote<PageNode, FreezingVoteValue, FreezingVoteValue::kCannotFreeze>;
+using FreezingVoteReceipt = voting::VoteReceipt<FreezingVote>;
+using FreezingVotingChannel = voting::VotingChannel<FreezingVote>;
+using FreezingVoteConsumer = voting::VoteConsumer<FreezingVote>;
+using AcceptedFreezingVote = voting::AcceptedVote<FreezingVote>;
+using FreezingVotingChannelFactory = voting::VotingChannelFactory<FreezingVote>;
+
+// An aggregator for freezing votes. It upstreams an aggregated vote to an
+// upstream channel every time the freezing decision changes for a PageNode. It
+// allows freezing of a given PageNode upon reception of one or several
+// kCanFreeze vote for this node. Any kCannotFreeze vote received will have
+// priority over the kCanFreeze votes and will prevent the PageNode from being
+// frozen.
+class FreezingVoteAggregator final : public FreezingVoteConsumer {
+ public:
+ FreezingVoteAggregator();
+ FreezingVoteAggregator(const FreezingVoteAggregator& rhs) = delete;
+ FreezingVoteAggregator& operator=(const FreezingVoteAggregator& rhs) = delete;
+ ~FreezingVoteAggregator() override;
+
+ // Issues a voting channel (effectively registered a voter).
+ FreezingVotingChannel GetVotingChannel();
+
+ // Sets the upstream voting channel. Should only be called once.
+ void SetUpstreamVotingChannel(FreezingVotingChannel&& channel);
+
+ // VoteConsumer implementation:
+ FreezingVoteReceipt SubmitVote(util::PassKey<FreezingVotingChannel>,
+ voting::VoterId<FreezingVote> voter_id,
+ const PageNode* page_node,
+ const FreezingVote& vote) override;
+ void ChangeVote(util::PassKey<AcceptedFreezingVote>,
+ AcceptedFreezingVote* old_vote,
+ const FreezingVote& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedFreezingVote>,
+ AcceptedFreezingVote* vote) override;
+
+ private:
+ friend class FreezingVoteAggregatorTestAccess;
+
+ // Contains the freezing votes for a given PageNode.
+ class FreezingVoteData {
+ public:
+ // The consequence that adding, removing or updating a vote has on the
+ // upstreamed vote. The caller is responsible for calling UpstreamVote or
+ // invalidating the vote (by destroying the instance of this class that owns
+ // it).
+ enum class UpstreamVoteImpact {
+ // The upstream vote has changed. UpstreamVote should be called.
+ kUpstreamVoteChanged,
+ // The upstream vote has been removed and should be invalidated.
+ kUpstreamVoteRemoved,
+ // The operation had no impact on the upstreamed vote.
+ kUpstreamVoteUnchanged,
+ };
+
+ FreezingVoteData();
+ FreezingVoteData(FreezingVoteData&&);
+ FreezingVoteData& operator=(FreezingVoteData&&);
+ FreezingVoteData(const FreezingVoteData& rhs) = delete;
+ FreezingVoteData& operator=(const FreezingVoteData& rhs) = delete;
+ ~FreezingVoteData();
+
+ // Adds a vote. Returns an UpstreamVoteImpact indicating if the upstreamed
+ // vote should be updated by calling UpstreamVote.
+ UpstreamVoteImpact AddVote(AcceptedFreezingVote&& vote) WARN_UNUSED_RESULT;
+
+ // Updates a vote. Returns an UpstreamVoteImpact indicating if the
+ // upstreamed vote should be updated by calling UpstreamVote.
+ UpstreamVoteImpact UpdateVote(AcceptedFreezingVote* old_vote,
+ const FreezingVote& new_vote)
+ WARN_UNUSED_RESULT;
+
+ // Removes a vote. Returns an UpstreamVoteImpact indicating if the
+ // upstreamed vote should be updated by calling UpstreamVote or invalidated.
+ UpstreamVoteImpact RemoveVote(AcceptedFreezingVote* vote)
+ WARN_UNUSED_RESULT;
+
+ // Upstreams the vote for this vote data, using the given voting |channel|.
+ void UpstreamVote(FreezingVotingChannel* channel);
+
+ bool IsEmpty() { return accepted_votes_.empty(); }
+
+ // Returns the current aggregated vote.
+ const AcceptedFreezingVote& GetCurrentVote();
+
+ friend class FreezingVoteAggregatorTestAccess;
+
+ // The current set of votes.
+ using AcceptedVotesDeque = base::circular_deque<AcceptedFreezingVote>;
+
+ const AcceptedVotesDeque& GetAcceptedVotesForTesting() {
+ return accepted_votes_;
+ }
+
+ // Returns the iterator of |vote| in |accepted_votes_|. |vote| is expected
+ // to be in the deque, this is enforced by a DCHECK.
+ AcceptedVotesDeque::iterator FindVote(AcceptedFreezingVote* vote);
+
+ void AddVoteToDeque(AcceptedFreezingVote&& vote);
+
+ // kCannotFreeze votes are always at the beginning of the deque.
+ AcceptedVotesDeque accepted_votes_;
+
+ // The receipt for the vote we've upstreamed.
+ FreezingVoteReceipt receipt_;
+ };
+ using VoteDataMap = base::flat_map<const PageNode*, FreezingVoteData>;
+
+ // Looks up the VoteData associated with the provided |page_node|. The data is
+ // expected to already exist (enforced by a DCHECK).
+ VoteDataMap::iterator GetVoteData(const PageNode* page_node);
+
+ // A map that associates a PageNode with a FreezingVoteData structure.
+ VoteDataMap vote_data_map_;
+
+ // The channel for upstreaming our votes.
+ FreezingVotingChannel channel_;
+
+ // The factory for providing FreezingVotingChannels to our input voters.
+ FreezingVotingChannelFactory factory_;
+};
+
+} // namespace freezing
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_VOTE_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/freezing/freezing_vote_aggregator_unittest.cc b/chromium/components/performance_manager/freezing/freezing_vote_aggregator_unittest.cc
new file mode 100644
index 00000000000..1b7c89dc476
--- /dev/null
+++ b/chromium/components/performance_manager/freezing/freezing_vote_aggregator_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2020 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/performance_manager/freezing/freezing_vote_aggregator.h"
+
+#include "base/rand_util.h"
+#include "components/performance_manager/test_support/voting.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace freezing {
+
+// Expose the FreezingVoteData type for testing.
+class FreezingVoteAggregatorTestAccess {
+ public:
+ using FreezingVoteData = FreezingVoteAggregator::FreezingVoteData;
+
+ static const FreezingVoteData::AcceptedVotesDeque& GetAllVotes(
+ FreezingVoteAggregator* agg,
+ const PageNode* node) {
+ return agg->GetVoteData(node)->second.GetAcceptedVotesForTesting();
+ }
+};
+using VoteData = FreezingVoteAggregatorTestAccess::FreezingVoteData;
+
+namespace {
+
+using DummyFreezingVoter = voting::test::DummyVoter<FreezingVote>;
+using DummyFreezingVoteConsumer = voting::test::DummyVoteConsumer<FreezingVote>;
+
+// Some dummy page nodes.
+const PageNode* kPageNode0 = reinterpret_cast<const PageNode*>(0xDEADBEEF);
+const PageNode* kPageNode1 = reinterpret_cast<const PageNode*>(0xBAADF00D);
+
+static const char kReason0[] = "a reason";
+static const char kReason1[] = "another reason";
+static const char kReason2[] = "yet another reason";
+
+} // namespace
+
+TEST(FreezingVoteAggregatorTest, EndToEnd) {
+ // Builds the small hierarchy of voters as follows:
+ //
+ // consumer
+ // |
+ // agg
+ // / | \
+ // / | \
+ // voter0 voter1 voter2
+ DummyFreezingVoteConsumer consumer;
+ FreezingVoteAggregator agg;
+ DummyFreezingVoter voter0;
+ DummyFreezingVoter voter1;
+ DummyFreezingVoter voter2;
+
+ voting::VoterId<FreezingVote> agg_id = voting::kInvalidVoterId<FreezingVote>;
+ {
+ auto channel = consumer.voting_channel_factory_.BuildVotingChannel();
+ agg_id = channel.voter_id();
+ agg.SetUpstreamVotingChannel(std::move(channel));
+ }
+
+ voter0.SetVotingChannel(agg.GetVotingChannel());
+ voter1.SetVotingChannel(agg.GetVotingChannel());
+ voter2.SetVotingChannel(agg.GetVotingChannel());
+
+ // Create some dummy votes for each PageNode and immediately expect
+ // them to propagate upwards.
+ voter0.EmitVote(kPageNode0, FreezingVoteValue::kCannotFreeze, kReason0);
+ voter1.EmitVote(kPageNode1, FreezingVoteValue::kCanFreeze, kReason1);
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCannotFreeze => kCannotFreeze
+ // - kPageNode1: 1 x kCanFreeze => kCanFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(0u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0,
+ FreezingVoteValue::kCannotFreeze, kReason0);
+ consumer.ExpectValidVote(1, agg_id, kPageNode1, FreezingVoteValue::kCanFreeze,
+ kReason1);
+
+ // Change an existing vote, and expect it to propagate upwards.
+ voter0.receipts_[0].ChangeVote(FreezingVoteValue::kCanFreeze, kReason2);
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: 1 x kCanFreeze => kCanFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(0u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectValidVote(1, agg_id, kPageNode1, FreezingVoteValue::kCanFreeze,
+ kReason1);
+
+ // Submit a new kCanFreeze vote and expect no change.
+ voter2.EmitVote(kPageNode1, FreezingVoteValue::kCanFreeze, kReason0);
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: 2 x kCanFreeze => kCanFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(1u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectValidVote(1, agg_id, kPageNode1, FreezingVoteValue::kCanFreeze,
+ kReason1);
+
+ // Submit a new vote with a different value and expect it to propagate
+ // upwards.
+ voter2.EmitVote(kPageNode1, FreezingVoteValue::kCannotFreeze, kReason0);
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: 2 x kCanFreeze + 1 x kCannotFreeze => kCannotFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(2u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectValidVote(1, agg_id, kPageNode1,
+ FreezingVoteValue::kCannotFreeze, kReason0);
+
+ // Invalidate the only kCannotFreeze vote for a given PageNode and expect it
+ // to propagate upwards.
+ voter2.receipts_.clear();
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: 1 x kCanFreeze => kCanFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(0u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectValidVote(1, agg_id, kPageNode1, FreezingVoteValue::kCanFreeze,
+ kReason1);
+
+ // Invalidate the remaining vote for one of the PageNode.
+ voter1.receipts_.clear();
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: No vote => Invalidated
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(0u, voter1.receipts_.size());
+ EXPECT_EQ(0u, voter2.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(1u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectInvalidVote(1);
+
+ // Emit a new vote for the PageNode that had no remaining vote
+ voter1.EmitVote(kPageNode1, FreezingVoteValue::kCannotFreeze, kReason2);
+ // Current state and expectations:
+ // - kPageNode0: 1 x kCanFreeze => kCanFreeze
+ // - kPageNode1: 1 x kCanFreeze => kCanFreeze
+ EXPECT_EQ(1u, voter0.receipts_.size());
+ EXPECT_EQ(1u, voter1.receipts_.size());
+ EXPECT_EQ(0u, voter2.receipts_.size());
+ EXPECT_EQ(3u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason2);
+ consumer.ExpectInvalidVote(1);
+ consumer.ExpectValidVote(2, agg_id, kPageNode1,
+ FreezingVoteValue::kCannotFreeze, kReason2);
+}
+
+TEST(FreezingVoteAggregatorTest, VoteIntegrity) {
+ DummyFreezingVoteConsumer consumer;
+ FreezingVoteAggregator agg;
+ DummyFreezingVoter voter0;
+ DummyFreezingVoter voter1;
+
+ voting::VoterId<FreezingVote> agg_id = voting::kInvalidVoterId<FreezingVote>;
+ {
+ auto channel = consumer.voting_channel_factory_.BuildVotingChannel();
+ agg_id = channel.voter_id();
+ agg.SetUpstreamVotingChannel(std::move(channel));
+ }
+
+ voter0.SetVotingChannel(agg.GetVotingChannel());
+ voter1.SetVotingChannel(agg.GetVotingChannel());
+
+ // Submit a first vote, this should be the only vote tracked by the
+ // aggregator.
+ voter0.EmitVote(kPageNode0, FreezingVoteValue::kCanFreeze, kReason0);
+ EXPECT_EQ(
+ 1u,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0).size());
+ EXPECT_EQ(FreezingVoteValue::kCanFreeze,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .front()
+ .vote()
+ .value());
+ EXPECT_EQ(kReason0,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .front()
+ .vote()
+ .reason());
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason0);
+
+ // Emit a second vote that should be ordered before the previous one, ensure
+ // that this is the case.
+ voter1.EmitVote(kPageNode0, FreezingVoteValue::kCannotFreeze, kReason1);
+ EXPECT_EQ(
+ 2u,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0).size());
+ EXPECT_EQ(FreezingVoteValue::kCannotFreeze,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .begin()
+ ->vote()
+ .value());
+ EXPECT_EQ(kReason1,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .begin()
+ ->vote()
+ .reason());
+ EXPECT_EQ(FreezingVoteValue::kCanFreeze,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .back()
+ .vote()
+ .value());
+ EXPECT_EQ(kReason0,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .back()
+ .vote()
+ .reason());
+ consumer.ExpectValidVote(0, agg_id, kPageNode0,
+ FreezingVoteValue::kCannotFreeze, kReason1);
+
+ // Removing the second vote should restore things back to the state they were
+ // before casting it.
+ voter1.receipts_.clear();
+ EXPECT_EQ(
+ 1u,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0).size());
+ EXPECT_EQ(FreezingVoteValue::kCanFreeze,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .front()
+ .vote()
+ .value());
+ EXPECT_EQ(kReason0,
+ FreezingVoteAggregatorTestAccess::GetAllVotes(&agg, kPageNode0)
+ .front()
+ .vote()
+ .reason());
+ consumer.ExpectValidVote(0, agg_id, kPageNode0, FreezingVoteValue::kCanFreeze,
+ kReason0);
+
+ // Removing the last vote should cause the upstreamed vote to be invalidated.
+ voter0.receipts_.clear();
+ consumer.ExpectInvalidVote(0);
+}
+
+} // namespace freezing
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/graph/frame_node_impl.cc b/chromium/components/performance_manager/graph/frame_node_impl.cc
index 9fb8d29eace..f286d121cea 100644
--- a/chromium/components/performance_manager/graph/frame_node_impl.cc
+++ b/chromium/components/performance_manager/graph/frame_node_impl.cc
@@ -11,7 +11,9 @@
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/graph/worker_node_impl.h"
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
+#include "components/performance_manager/public/v8_memory/web_memory.h"
+#include "third_party/blink/public/common/features.h"
namespace performance_manager {
@@ -19,7 +21,7 @@ namespace performance_manager {
constexpr char FrameNodeImpl::kDefaultPriorityReason[] =
"default frame priority";
-using PriorityAndReason = frame_priority::PriorityAndReason;
+using PriorityAndReason = execution_context_priority::PriorityAndReason;
FrameNodeImpl::FrameNodeImpl(ProcessNodeImpl* process_node,
PageNodeImpl* page_node,
@@ -41,8 +43,7 @@ FrameNodeImpl::FrameNodeImpl(ProcessNodeImpl* process_node,
process_node->render_process_host_proxy()
.render_process_host_id()
.value(),
- render_frame_id)),
- weak_factory_(this) {
+ render_frame_id)) {
DETACH_FROM_SEQUENCE(sequence_checker_);
DCHECK(process_node);
DCHECK(page_node);
@@ -230,6 +231,18 @@ bool FrameNodeImpl::is_audible() const {
return is_audible_.value();
}
+const base::Optional<gfx::Rect>& FrameNodeImpl::viewport_intersection() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // The viewport intersection of the main frame is not tracked.
+ DCHECK(!IsMainFrame());
+ return viewport_intersection_.value();
+}
+
+FrameNode::Visibility FrameNodeImpl::visibility() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return visibility_.value();
+}
+
void FrameNodeImpl::SetIsCurrent(bool is_current) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
is_current_.SetAndMaybeNotify(this, is_current);
@@ -275,6 +288,19 @@ void FrameNodeImpl::SetIsAudible(bool is_audible) {
is_audible_.SetAndMaybeNotify(this, is_audible);
}
+void FrameNodeImpl::SetViewportIntersection(
+ const gfx::Rect& viewport_intersection) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // The viewport intersection of the main frame is not tracked.
+ DCHECK(!IsMainFrame());
+ viewport_intersection_.SetAndMaybeNotify(this, viewport_intersection);
+}
+
+void FrameNodeImpl::SetVisibility(Visibility visibility) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ visibility_.SetAndMaybeNotify(this, visibility);
+}
+
void FrameNodeImpl::OnNavigationCommitted(const GURL& url, bool same_document) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -498,6 +524,17 @@ bool FrameNodeImpl::IsAudible() const {
return is_audible();
}
+const base::Optional<gfx::Rect>& FrameNodeImpl::GetViewportIntersection()
+ const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return viewport_intersection();
+}
+
+FrameNode::Visibility FrameNodeImpl::GetVisibility() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return visibility();
+}
+
void FrameNodeImpl::AddChildFrame(FrameNodeImpl* child_frame_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(child_frame_node);
@@ -529,6 +566,12 @@ void FrameNodeImpl::OnJoiningGraph() {
graph()->RegisterFrameNodeForId(process_node_->GetRenderProcessId(),
render_frame_id_, this);
+ // Set the initial frame visibility. This is done on the graph because the
+ // page node must be accessed. OnFrameNodeAdded() has not been called yet for
+ // this frame, so it is important to avoid sending a notification for this
+ // property change.
+ visibility_.Set(GetInitialFrameVisibility());
+
// Wire this up to the other nodes in the graph.
if (parent_frame_node_)
parent_frame_node_->AddChildFrame(this);
@@ -624,6 +667,25 @@ bool FrameNodeImpl::HasFrameNodeInTree(FrameNodeImpl* frame_node) const {
return GetFrameTreeRoot() == frame_node->GetFrameTreeRoot();
}
+FrameNode::Visibility FrameNodeImpl::GetInitialFrameVisibility() const {
+ DCHECK(!viewport_intersection_.value());
+
+ // If the page hosting this frame is not visible, then the frame is also not
+ // visible.
+ if (!page_node()->is_visible())
+ return FrameNode::Visibility::kNotVisible;
+
+ // The visibility of the frame depends on the viewport intersection of said
+ // frame. Since a main frame has no viewport intersection, it is always
+ // visible in the page.
+ if (IsMainFrame())
+ return FrameNode::Visibility::kVisible;
+
+ // Since the viewport intersection of a frame is not initially available, the
+ // visibility of a child frame is initially unknown.
+ return FrameNode::Visibility::kUnknown;
+}
+
FrameNodeImpl::DocumentProperties::DocumentProperties() = default;
FrameNodeImpl::DocumentProperties::~DocumentProperties() = default;
@@ -638,4 +700,12 @@ void FrameNodeImpl::DocumentProperties::Reset(FrameNodeImpl* frame_node,
had_form_interaction.SetAndMaybeNotify(frame_node, false);
}
+void FrameNodeImpl::OnWebMemoryMeasurementRequested(
+ mojom::WebMemoryMeasurement::Mode mode,
+ OnWebMemoryMeasurementRequestedCallback callback) {
+ CHECK(base::FeatureList::IsEnabled(
+ blink::features::kWebMeasureMemoryViaPerformanceManager));
+ v8_memory::WebMeasureMemory(this, mode, std::move(callback));
+}
+
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/graph/frame_node_impl.h b/chromium/components/performance_manager/graph/frame_node_impl.h
index b88f286e97a..198fb1eef7d 100644
--- a/chromium/components/performance_manager/graph/frame_node_impl.h
+++ b/chromium/components/performance_manager/graph/frame_node_impl.h
@@ -15,6 +15,8 @@
#include "components/performance_manager/graph/node_base.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/node_attached_data.h"
+#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/web_memory.mojom.h"
#include "components/performance_manager/public/render_frame_host_proxy.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -59,6 +61,8 @@ class FrameNodeImpl
public TypedNodeBase<FrameNodeImpl, FrameNode, FrameNodeObserver>,
public mojom::DocumentCoordinationUnit {
public:
+ using PassKey = util::PassKey<FrameNodeImpl>;
+
static const char kDefaultPriorityReason[];
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kFrame; }
@@ -82,6 +86,7 @@ class FrameNodeImpl
void SetNetworkAlmostIdle() override;
void SetLifecycleState(LifecycleState state) override;
void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
+ void SetViewportIntersection(const gfx::Rect& viewport_intersection) override;
void SetOriginTrialFreezePolicy(mojom::InterventionPolicy policy) override;
void SetIsAdFrame() override;
void SetHadFormInteraction() override;
@@ -89,6 +94,9 @@ class FrameNodeImpl
void OnFirstContentfulPaint(
base::TimeDelta time_since_navigation_start) override;
const RenderFrameHostProxy& GetRenderFrameHostProxy() const override;
+ void OnWebMemoryMeasurementRequested(
+ mojom::WebMemoryMeasurement::Mode mode,
+ OnWebMemoryMeasurementRequestedCallback callback) override;
// Partial FrameNodbase::TimeDelta time_since_navigatione implementation:
bool IsMainFrame() const override;
@@ -120,12 +128,15 @@ class FrameNodeImpl
const PriorityAndReason& priority_and_reason() const;
bool had_form_interaction() const;
bool is_audible() const;
+ const base::Optional<gfx::Rect>& viewport_intersection() const;
+ Visibility visibility() const;
// Setters are not thread safe.
void SetIsCurrent(bool is_current);
void SetIsHoldingWebLock(bool is_holding_weblock);
void SetIsHoldingIndexedDBLock(bool is_holding_indexeddb_lock);
void SetIsAudible(bool is_audible);
+ void SetVisibility(Visibility visibility);
// Invoked when a navigation is committed in the frame.
void OnNavigationCommitted(const GURL& url, bool same_document);
@@ -159,9 +170,11 @@ class FrameNodeImpl
return &execution_context_;
}
+ static PassKey CreatePassKeyForTesting() { return PassKey(); }
+
private:
+ friend class ExecutionContextPriorityAccess;
friend class FrameNodeImplDescriber;
- friend class FramePriorityAccess;
friend class ProcessNodeImpl;
// Rest of FrameNode implementation. These are private so that users of the
@@ -190,6 +203,8 @@ class FrameNodeImpl
const PriorityAndReason& GetPriorityAndReason() const override;
bool HadFormInteraction() const override;
bool IsAudible() const override;
+ const base::Optional<gfx::Rect>& GetViewportIntersection() const override;
+ Visibility GetVisibility() const override;
// Properties associated with a Document, which are reset when a
// different-document navigation is committed in the frame.
@@ -251,6 +266,10 @@ class FrameNodeImpl
bool HasFrameNodeInDescendants(FrameNodeImpl* frame_node) const;
bool HasFrameNodeInTree(FrameNodeImpl* frame_node) const;
+ // Returns the initial visibility of this frame. Should only be called when
+ // the frame node joins the graph.
+ Visibility GetInitialFrameVisibility() const;
+
mojo::Receiver<mojom::DocumentCoordinationUnit> receiver_{this};
FrameNodeImpl* const parent_frame_node_;
@@ -321,7 +340,7 @@ class FrameNodeImpl
// The child workers of this frame.
base::flat_set<WorkerNodeImpl*> child_worker_nodes_;
- // Frame priority information. Set via FramePriorityDecorator.
+ // Frame priority information. Set via ExecutionContextPriorityDecorator.
ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
PriorityAndReason,
const PriorityAndReason&,
@@ -336,13 +355,32 @@ class FrameNodeImpl
NotifiesOnlyOnChanges<bool, &FrameNodeObserver::OnIsAudibleChanged>
is_audible_{false};
- // Inline storage for FramePriorityDecorator data.
- frame_priority::AcceptedVote accepted_vote_;
+ // Tracks the intersection of this frame with the viewport.
+ //
+ // Note that the viewport intersection for the main frame is always invalid.
+ // This is because the main frame always occupies the entirety of the viewport
+ // so there is no point in tracking it. To avoid programming mistakes, it is
+ // forbidden to query this property for the main frame.
+ ObservedProperty::NotifiesOnlyOnChanges<
+ base::Optional<gfx::Rect>,
+ &FrameNodeObserver::OnViewportIntersectionChanged>
+ viewport_intersection_;
+
+ // Indicates if the frame is visible. This is initialized in
+ // FrameNodeImpl::OnJoiningGraph() and then maintained by
+ // FrameVisibilityDecorator.
+ ObservedProperty::NotifiesOnlyOnChanges<
+ Visibility,
+ &FrameNodeObserver::OnFrameVisibilityChanged>
+ visibility_{Visibility::kUnknown};
// Inline storage for ExecutionContext.
std::unique_ptr<NodeAttachedData> execution_context_;
- base::WeakPtrFactory<FrameNodeImpl> weak_factory_;
+ // Inline storage for ExecutionContextPriorityDecorator data.
+ execution_context_priority::AcceptedVote accepted_vote_;
+
+ base::WeakPtrFactory<FrameNodeImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FrameNodeImpl);
};
diff --git a/chromium/components/performance_manager/graph/frame_node_impl_describer.cc b/chromium/components/performance_manager/graph/frame_node_impl_describer.cc
index 8e1e61c2245..86ce567a54d 100644
--- a/chromium/components/performance_manager/graph/frame_node_impl_describer.cc
+++ b/chromium/components/performance_manager/graph/frame_node_impl_describer.cc
@@ -5,12 +5,14 @@
#include "components/performance_manager/graph/frame_node_impl_describer.h"
#include <sstream>
+#include <string>
+#include <utility>
-#include "base/task/task_traits.h"
#include "base/values.h"
#include "components/performance_manager/graph/frame_node_impl.h"
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
#include "components/performance_manager/public/graph/node_data_describer_registry.h"
+#include "components/performance_manager/public/graph/node_data_describer_util.h"
namespace performance_manager {
@@ -18,32 +20,24 @@ namespace {
const char kDescriberName[] = "FrameNodeImpl";
-// TODO(1077305): Move the following to a public describer_utils helper.
+std::string ViewportIntersectionToString(
+ const base::Optional<gfx::Rect>& viewport_intersection) {
+ if (!viewport_intersection.has_value())
+ return "Nullopt";
-// Mojo enums have std::stream support. This converts them to a std::string.
-template <typename MojoEnum>
-std::string MojoEnumToString(MojoEnum mojo_enum_value) {
- std::stringstream ss;
- ss << mojo_enum_value;
- return ss.str();
+ return viewport_intersection->ToString();
}
-// Converts a string to a base::Value, where null strings go to a null value
-// instead of an empty string.
-base::Value MaybeNullStringToValue(base::StringPiece str) {
- if (str.data() == nullptr)
- return base::Value();
- return base::Value(str);
-}
-
-base::Value PriorityAndReasonToValue(
- const frame_priority::PriorityAndReason& priority_and_reason) {
- base::Value priority(base::Value::Type::DICTIONARY);
- priority.SetStringKey(
- "priority", base::TaskPriorityToString(priority_and_reason.priority()));
- priority.SetPath("reason",
- MaybeNullStringToValue(priority_and_reason.reason()));
- return priority;
+std::string FrameNodeVisibilityToString(FrameNode::Visibility visibility) {
+ switch (visibility) {
+ // using FrameNode::Visibility;
+ case FrameNode::Visibility::kUnknown:
+ return "Unknown";
+ case FrameNode::Visibility::kVisible:
+ return "Visible";
+ case FrameNode::Visibility::kNotVisible:
+ return "Not visible";
+ }
}
} // namespace
@@ -96,6 +90,11 @@ base::Value FrameNodeImplDescriber::DescribeFrameNodeData(
ret.SetKey("priority",
PriorityAndReasonToValue(impl->priority_and_reason_.value()));
ret.SetBoolKey("is_audible", impl->is_audible_.value());
+ ret.SetStringKey(
+ "viewport_intersection",
+ ViewportIntersectionToString(impl->viewport_intersection_.value()));
+ ret.SetStringKey("visibility",
+ FrameNodeVisibilityToString(impl->visibility_.value()));
return ret;
}
diff --git a/chromium/components/performance_manager/graph/frame_node_impl_unittest.cc b/chromium/components/performance_manager/graph/frame_node_impl_unittest.cc
index e2f1e22bd0d..b87b6960138 100644
--- a/chromium/components/performance_manager/graph/frame_node_impl_unittest.cc
+++ b/chromium/components/performance_manager/graph/frame_node_impl_unittest.cc
@@ -150,6 +150,8 @@ class LenientMockObserver : public FrameNodeImpl::Observer {
void(const FrameNode*, const PriorityAndReason& previous_value));
MOCK_METHOD1(OnHadFormInteractionChanged, void(const FrameNode*));
MOCK_METHOD1(OnIsAudibleChanged, void(const FrameNode*));
+ MOCK_METHOD1(OnViewportIntersectionChanged, void(const FrameNode*));
+ MOCK_METHOD1(OnFrameVisibilityChanged, void(const FrameNode*));
MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
MOCK_METHOD2(OnFirstContentfulPaint, void(const FrameNode*, base::TimeDelta));
@@ -278,7 +280,7 @@ TEST_F(FrameNodeImplTest, IsHoldingIndexedDBLock) {
}
TEST_F(FrameNodeImplTest, Priority) {
- using PriorityAndReason = frame_priority::PriorityAndReason;
+ using PriorityAndReason = execution_context_priority::PriorityAndReason;
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
@@ -367,6 +369,43 @@ TEST_F(FrameNodeImplTest, IsAudible) {
graph()->RemoveFrameNodeObserver(&obs);
}
+TEST_F(FrameNodeImplTest, ViewportIntersection) {
+ auto process = CreateNode<ProcessNodeImpl>();
+ auto page = CreateNode<PageNodeImpl>();
+ // A child frame node is used because the main frame does not have a viewport
+ // intersection.
+ auto main_frame_node = CreateFrameNodeAutoId(process.get(), page.get());
+ auto child_frame_node =
+ CreateFrameNodeAutoId(process.get(), page.get(), main_frame_node.get());
+
+ MockObserver obs;
+ graph()->AddFrameNodeObserver(&obs);
+
+ EXPECT_CALL(obs, OnViewportIntersectionChanged(child_frame_node.get()));
+
+ gfx::Rect kViewportIntersection(25, 25, 100, 100);
+ child_frame_node->SetViewportIntersection(kViewportIntersection);
+ EXPECT_EQ(child_frame_node->viewport_intersection(), kViewportIntersection);
+
+ graph()->RemoveFrameNodeObserver(&obs);
+}
+
+TEST_F(FrameNodeImplTest, Visibility) {
+ auto process = CreateNode<ProcessNodeImpl>();
+ auto page = CreateNode<PageNodeImpl>();
+ auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
+
+ MockObserver obs;
+ graph()->AddFrameNodeObserver(&obs);
+
+ EXPECT_CALL(obs, OnFrameVisibilityChanged(frame_node.get()));
+
+ frame_node->SetVisibility(FrameNode::Visibility::kVisible);
+ EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kVisible);
+
+ graph()->RemoveFrameNodeObserver(&obs);
+}
+
TEST_F(FrameNodeImplTest, FirstContentfulPaint) {
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
@@ -386,7 +425,10 @@ TEST_F(FrameNodeImplTest, PublicInterface) {
auto process = CreateNode<ProcessNodeImpl>();
auto page = CreateNode<PageNodeImpl>();
auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
+ auto child_frame_node =
+ CreateFrameNodeAutoId(process.get(), page.get(), frame_node.get());
const FrameNode* public_frame_node = frame_node.get();
+ const FrameNode* public_child_frame_node = child_frame_node.get();
// Simply test that the public interface impls yield the same result as their
// private counterpart.
@@ -427,6 +469,11 @@ TEST_F(FrameNodeImplTest, PublicInterface) {
public_frame_node->IsHoldingIndexedDBLock());
EXPECT_EQ(frame_node->had_form_interaction(),
public_frame_node->HadFormInteraction());
+ // Use the child frame node to test the viewport intersection because the
+ // viewport intersection of the main frame is not tracked.
+ EXPECT_EQ(child_frame_node->viewport_intersection(),
+ public_child_frame_node->GetViewportIntersection());
+ EXPECT_EQ(frame_node->visibility(), public_frame_node->GetVisibility());
}
TEST_F(FrameNodeImplTest, VisitChildFrameNodes) {
diff --git a/chromium/components/performance_manager/graph/graph_impl.cc b/chromium/components/performance_manager/graph/graph_impl.cc
index dd830ec0852..2eaf547b6c6 100644
--- a/chromium/components/performance_manager/graph/graph_impl.cc
+++ b/chromium/components/performance_manager/graph/graph_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
diff --git a/chromium/components/performance_manager/graph/policies/process_priority_policy_unittest.cc b/chromium/components/performance_manager/graph/policies/process_priority_policy_unittest.cc
index c4bf268ec4f..444d6df9e19 100644
--- a/chromium/components/performance_manager/graph/policies/process_priority_policy_unittest.cc
+++ b/chromium/components/performance_manager/graph/policies/process_priority_policy_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/public/performance_manager.h"
@@ -112,7 +112,7 @@ TEST_F(ProcessPriorityPolicyTest, GraphReflectedToRenderProcessHost) {
// Set the active contents in the RenderViewHostTestHarness.
SetContents(CreateTestWebContents());
- auto* rvh = web_contents()->GetRenderViewHost();
+ auto* rvh = web_contents()->GetMainFrame()->GetRenderViewHost();
DCHECK(rvh);
auto* rph = rvh->GetProcess();
DCHECK(rph);
diff --git a/chromium/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc b/chromium/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
index 8e64ebf58a3..106027b43fd 100644
--- a/chromium/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
+++ b/chromium/components/performance_manager/graph/policies/tab_loading_frame_navigation_policy_unittest.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/task/task_traits.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
@@ -266,10 +266,10 @@ TEST_F(TabLoadingFrameNavigationPolicyTest, OnlyHttpContentsThrottled) {
}
{
- // Expect about:// contents not to be throttled.
+ // Expect about:blank contents not to be throttled.
SCOPED_TRACE("about");
content::NavigationSimulator::NavigateAndCommitFromBrowser(
- web_contents(), GURL("about://blank"));
+ web_contents(), GURL("about:blank"));
EXPECT_FALSE(policy()->ShouldThrottleWebContents(web_contents()));
ExpectThrottledPageCount(0);
}
diff --git a/chromium/components/performance_manager/graph/process_node_impl.cc b/chromium/components/performance_manager/graph/process_node_impl.cc
index 15253344a6b..3f0db9ee824 100644
--- a/chromium/components/performance_manager/graph/process_node_impl.cc
+++ b/chromium/components/performance_manager/graph/process_node_impl.cc
@@ -10,6 +10,7 @@
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/graph_impl.h"
#include "components/performance_manager/graph/page_node_impl.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker.h"
namespace performance_manager {
@@ -42,6 +43,27 @@ void ProcessNodeImpl::SetMainThreadTaskLoadIsLow(
main_thread_task_load_is_low);
}
+void ProcessNodeImpl::OnV8ContextCreated(
+ mojom::V8ContextDescriptionPtr description,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) {
+ if (auto* tracker = v8_memory::V8ContextTracker::GetFromGraph(graph())) {
+ tracker->OnV8ContextCreated(PassKey(), this, *description,
+ std::move(iframe_attribution_data));
+ }
+}
+
+void ProcessNodeImpl::OnV8ContextDetached(
+ const blink::V8ContextToken& v8_context_token) {
+ if (auto* tracker = v8_memory::V8ContextTracker::GetFromGraph(graph()))
+ tracker->OnV8ContextDetached(PassKey(), this, v8_context_token);
+}
+
+void ProcessNodeImpl::OnV8ContextDestroyed(
+ const blink::V8ContextToken& v8_context_token) {
+ if (auto* tracker = v8_memory::V8ContextTracker::GetFromGraph(graph()))
+ tracker->OnV8ContextDestroyed(PassKey(), this, v8_context_token);
+}
+
void ProcessNodeImpl::SetProcessExitStatus(int32_t exit_status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This may occur as the first event seen in the case where the process
diff --git a/chromium/components/performance_manager/graph/process_node_impl.h b/chromium/components/performance_manager/graph/process_node_impl.h
index b1356bcfe1a..399acc6251f 100644
--- a/chromium/components/performance_manager/graph/process_node_impl.h
+++ b/chromium/components/performance_manager/graph/process_node_impl.h
@@ -9,15 +9,18 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
+#include "base/util/type_safety/pass_key.h"
#include "components/performance_manager/graph/node_attached_data.h"
#include "components/performance_manager/graph/node_base.h"
#include "components/performance_manager/graph/properties.h"
#include "components/performance_manager/public/graph/process_node.h"
#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
#include "components/performance_manager/public/render_process_host_proxy.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -43,6 +46,8 @@ class ProcessNodeImpl
public TypedNodeBase<ProcessNodeImpl, ProcessNode, ProcessNodeObserver>,
public mojom::ProcessCoordinationUnit {
public:
+ using PassKey = util::PassKey<ProcessNodeImpl>;
+
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kProcess; }
ProcessNodeImpl(content::ProcessType process_type,
@@ -54,6 +59,13 @@ class ProcessNodeImpl
// mojom::ProcessCoordinationUnit implementation:
void SetMainThreadTaskLoadIsLow(bool main_thread_task_load_is_low) override;
+ void OnV8ContextCreated(
+ mojom::V8ContextDescriptionPtr description,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) override;
+ void OnV8ContextDetached(
+ const blink::V8ContextToken& v8_context_token) override;
+ void OnV8ContextDestroyed(
+ const blink::V8ContextToken& v8_context_token) override;
void SetProcessExitStatus(int32_t exit_status);
void SetProcess(base::Process process, base::Time launch_time);
@@ -113,6 +125,12 @@ class ProcessNodeImpl
void OnAllFramesInProcessFrozenForTesting() { OnAllFramesInProcessFrozen(); }
+ base::WeakPtr<ProcessNodeImpl> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ static PassKey CreatePassKeyForTesting() { return PassKey(); }
+
protected:
void SetProcessImpl(base::Process process,
base::ProcessId process_id,
@@ -184,6 +202,8 @@ class ProcessNodeImpl
// Inline storage for ProcessPriorityAggregator user data.
std::unique_ptr<NodeAttachedData> process_priority_data_;
+ base::WeakPtrFactory<ProcessNodeImpl> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(ProcessNodeImpl);
};
diff --git a/chromium/components/performance_manager/graph/process_node_impl_unittest.cc b/chromium/components/performance_manager/graph/process_node_impl_unittest.cc
index a83974a200a..092fbab6a9b 100644
--- a/chromium/components/performance_manager/graph/process_node_impl_unittest.cc
+++ b/chromium/components/performance_manager/graph/process_node_impl_unittest.cc
@@ -5,7 +5,7 @@
#include "components/performance_manager/graph/process_node_impl.h"
#include "base/process/process.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/public/render_process_host_id.h"
#include "components/performance_manager/public/render_process_host_proxy.h"
diff --git a/chromium/components/performance_manager/graph/properties.h b/chromium/components/performance_manager/graph/properties.h
index 6447b860b04..3c199c28824 100644
--- a/chromium/components/performance_manager/graph/properties.h
+++ b/chromium/components/performance_manager/graph/properties.h
@@ -43,6 +43,12 @@ class ObservedPropertyImpl {
((observer)->*(NotifyFunctionPtr))(node);
}
+ // Sets the property without sending a notification.
+ template <typename U = PropertyType>
+ void Set(U&& value) {
+ value_ = std::forward<U>(value);
+ }
+
const PropertyType& value() const { return value_; }
private:
@@ -77,6 +83,12 @@ class ObservedPropertyImpl {
return true;
}
+ // Sets the property without sending a notification.
+ template <typename U = PropertyType>
+ void Set(U&& value) {
+ value_ = std::forward<U>(value);
+ }
+
const PropertyType& value() const { return value_; }
private:
@@ -115,6 +127,12 @@ class ObservedPropertyImpl {
return true;
}
+ // Sets the property without sending a notification.
+ template <typename U = PropertyType>
+ void Set(U&& value) {
+ value_ = std::forward<U>(value);
+ }
+
const PropertyType& value() const { return value_; }
private:
diff --git a/chromium/components/performance_manager/graph/system_node_impl.h b/chromium/components/performance_manager/graph/system_node_impl.h
index c094151b33c..780a249cc6b 100644
--- a/chromium/components/performance_manager/graph/system_node_impl.h
+++ b/chromium/components/performance_manager/graph/system_node_impl.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "components/performance_manager/graph/node_base.h"
@@ -30,7 +31,13 @@ class SystemNodeImpl
// nodes.
void OnProcessMemoryMetricsAvailable();
+ base::WeakPtr<SystemNodeImpl> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
private:
+ base::WeakPtrFactory<SystemNodeImpl> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(SystemNodeImpl);
};
diff --git a/chromium/components/performance_manager/graph/worker_node_impl.cc b/chromium/components/performance_manager/graph/worker_node_impl.cc
index 99a9c9a19df..c828120a9d0 100644
--- a/chromium/components/performance_manager/graph/worker_node_impl.cc
+++ b/chromium/components/performance_manager/graph/worker_node_impl.cc
@@ -9,6 +9,12 @@
namespace performance_manager {
+// static
+constexpr char WorkerNodeImpl::kDefaultPriorityReason[] =
+ "default worker priority";
+
+using PriorityAndReason = execution_context_priority::PriorityAndReason;
+
WorkerNodeImpl::WorkerNodeImpl(const std::string& browser_context_id,
WorkerType worker_type,
ProcessNodeImpl* process_node,
@@ -91,6 +97,12 @@ void WorkerNodeImpl::RemoveClientWorker(WorkerNodeImpl* worker_node) {
DCHECK_EQ(removed, 1u);
}
+void WorkerNodeImpl::SetPriorityAndReason(
+ const PriorityAndReason& priority_and_reason) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ priority_and_reason_.SetAndMaybeNotify(this, priority_and_reason);
+}
+
void WorkerNodeImpl::OnFinalResponseURLDetermined(const GURL& url) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(url_.is_empty());
@@ -140,6 +152,10 @@ const base::flat_set<WorkerNodeImpl*>& WorkerNodeImpl::child_workers() const {
return child_workers_;
}
+const PriorityAndReason& WorkerNodeImpl::priority_and_reason() const {
+ return priority_and_reason_.value();
+}
+
void WorkerNodeImpl::OnJoiningGraph() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -206,6 +222,10 @@ const base::flat_set<const WorkerNode*> WorkerNodeImpl::GetChildWorkers()
return child_workers;
}
+const PriorityAndReason& WorkerNodeImpl::GetPriorityAndReason() const {
+ return priority_and_reason();
+}
+
void WorkerNodeImpl::AddChildWorker(WorkerNodeImpl* worker_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
bool inserted = child_workers_.insert(worker_node).second;
diff --git a/chromium/components/performance_manager/graph/worker_node_impl.h b/chromium/components/performance_manager/graph/worker_node_impl.h
index dc64e8ac7bf..fd830a9ee16 100644
--- a/chromium/components/performance_manager/graph/worker_node_impl.h
+++ b/chromium/components/performance_manager/graph/worker_node_impl.h
@@ -11,6 +11,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/util/type_safety/pass_key.h"
#include "components/performance_manager/graph/node_base.h"
#include "components/performance_manager/public/graph/worker_node.h"
@@ -30,6 +31,7 @@ class WorkerNodeImpl
: public PublicNodeImpl<WorkerNodeImpl, WorkerNode>,
public TypedNodeBase<WorkerNodeImpl, WorkerNode, WorkerNodeObserver> {
public:
+ static const char kDefaultPriorityReason[];
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kWorker; }
WorkerNodeImpl(const std::string& browser_context_id,
@@ -46,6 +48,9 @@ class WorkerNodeImpl
void AddClientWorker(WorkerNodeImpl* worker_node);
void RemoveClientWorker(WorkerNodeImpl* worker_node);
+ // Sets the worker priority, and the reason behind it.
+ void SetPriorityAndReason(const PriorityAndReason& priority_and_reason);
+
// Invoked when the worker script was fetched and the final response URL is
// available.
void OnFinalResponseURLDetermined(const GURL& url);
@@ -61,6 +66,11 @@ class WorkerNodeImpl
const base::flat_set<FrameNodeImpl*>& client_frames() const;
const base::flat_set<WorkerNodeImpl*>& client_workers() const;
const base::flat_set<WorkerNodeImpl*>& child_workers() const;
+ const PriorityAndReason& priority_and_reason() const;
+
+ base::WeakPtr<WorkerNodeImpl> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
// Implementation details below this point.
@@ -71,6 +81,9 @@ class WorkerNodeImpl
}
private:
+ friend class ExecutionContextPriorityAccess;
+ friend class WorkerNodeImplDescriber;
+
void OnJoiningGraph() override;
void OnBeforeLeavingGraph() override;
@@ -84,6 +97,7 @@ class WorkerNodeImpl
const base::flat_set<const FrameNode*> GetClientFrames() const override;
const base::flat_set<const WorkerNode*> GetClientWorkers() const override;
const base::flat_set<const WorkerNode*> GetChildWorkers() const override;
+ const PriorityAndReason& GetPriorityAndReason() const override;
// Invoked when |worker_node| becomes a child of this worker.
void AddChildWorker(WorkerNodeImpl* worker_node);
@@ -121,9 +135,22 @@ class WorkerNodeImpl
// distinction between client workers and child workers.
base::flat_set<WorkerNodeImpl*> child_workers_;
+ // Worker priority information. Set via ExecutionContextPriorityDecorator.
+ ObservedProperty::NotifiesOnlyOnChangesWithPreviousValue<
+ PriorityAndReason,
+ const PriorityAndReason&,
+ &WorkerNodeObserver::OnPriorityAndReasonChanged>
+ priority_and_reason_{PriorityAndReason(base::TaskPriority::LOWEST,
+ kDefaultPriorityReason)};
+
// Used by ExecutionContextRegistry mechanism.
std::unique_ptr<NodeAttachedData> execution_context_;
+ // Inline storage for ExecutionContextPriorityDecorator data.
+ execution_context_priority::AcceptedVote accepted_vote_;
+
+ base::WeakPtrFactory<WorkerNodeImpl> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(WorkerNodeImpl);
};
diff --git a/chromium/components/performance_manager/graph/worker_node_impl_describer.cc b/chromium/components/performance_manager/graph/worker_node_impl_describer.cc
index d861bf44d65..f804a0d4e7c 100644
--- a/chromium/components/performance_manager/graph/worker_node_impl_describer.cc
+++ b/chromium/components/performance_manager/graph/worker_node_impl_describer.cc
@@ -6,10 +6,12 @@
#include "base/strings/string_number_conversions.h"
#include "components/performance_manager/public/graph/node_data_describer_registry.h"
+#include "components/performance_manager/public/graph/node_data_describer_util.h"
namespace performance_manager {
namespace {
+
const char kDescriberName[] = "WorkerNode";
const char* WorkerTypeToString(WorkerNode::WorkerType state) {
@@ -46,6 +48,8 @@ base::Value WorkerNodeImplDescriber::DescribeWorkerNodeData(
ret.SetKey("url", base::Value(impl->url().spec()));
ret.SetKey("worker_type",
base::Value(WorkerTypeToString(impl->worker_type())));
+ ret.SetKey("priority",
+ PriorityAndReasonToValue(impl->priority_and_reason_.value()));
return ret;
}
diff --git a/chromium/components/performance_manager/graph/worker_node_impl_unittest.cc b/chromium/components/performance_manager/graph/worker_node_impl_unittest.cc
index d145febc1ed..748cb10ca7d 100644
--- a/chromium/components/performance_manager/graph/worker_node_impl_unittest.cc
+++ b/chromium/components/performance_manager/graph/worker_node_impl_unittest.cc
@@ -192,6 +192,24 @@ TEST_F(WorkerNodeImplTest, NestedDedicatedWorkers) {
parent_worker->RemoveClientFrame(frame.get());
}
+TEST_F(WorkerNodeImplTest, PriorityAndReason) {
+ auto process = CreateNode<ProcessNodeImpl>();
+ constexpr PriorityAndReason kTestPriorityAndReason(
+ base::TaskPriority::HIGHEST, "Test reason");
+
+ auto worker_impl = CreateNode<WorkerNodeImpl>(WorkerNode::WorkerType::kShared,
+ process.get());
+
+ // Initially the default priority.
+ EXPECT_EQ(worker_impl->priority_and_reason(),
+ PriorityAndReason(base::TaskPriority::LOWEST,
+ WorkerNodeImpl::kDefaultPriorityReason));
+
+ worker_impl->SetPriorityAndReason(kTestPriorityAndReason);
+
+ EXPECT_EQ(worker_impl->priority_and_reason(), kTestPriorityAndReason);
+}
+
class TestWorkerNodeObserver : public WorkerNodeObserver {
public:
TestWorkerNodeObserver() = default;
@@ -201,18 +219,15 @@ class TestWorkerNodeObserver : public WorkerNodeObserver {
EXPECT_TRUE(client_frames_.insert({worker_node, {}}).second);
EXPECT_TRUE(client_workers_.insert({worker_node, {}}).second);
}
-
void OnBeforeWorkerNodeRemoved(const WorkerNode* worker_node) override {
EXPECT_TRUE(client_frames_.empty());
EXPECT_TRUE(client_workers_.empty());
EXPECT_EQ(client_frames_.erase(worker_node), 1u);
EXPECT_EQ(client_workers_.erase(worker_node), 1u);
}
-
void OnFinalResponseURLDetermined(const WorkerNode* worker_node) override {
on_final_response_url_determined_called_ = true;
}
-
void OnClientFrameAdded(const WorkerNode* worker_node,
const FrameNode* client_frame_node) override {
auto& client_frames = client_frames_.find(worker_node)->second;
@@ -234,6 +249,11 @@ class TestWorkerNodeObserver : public WorkerNodeObserver {
auto& client_workers = client_workers_.find(worker_node)->second;
EXPECT_EQ(client_workers.erase(client_worker_node), 1u);
}
+ void OnPriorityAndReasonChanged(
+ const WorkerNode* worker_node,
+ const PriorityAndReason& previous_value) override {
+ on_priority_and_reason_changed_called_ = true;
+ }
bool on_final_response_url_determined_called() const {
return on_final_response_url_determined_called_;
@@ -243,11 +263,16 @@ class TestWorkerNodeObserver : public WorkerNodeObserver {
client_frames() const {
return client_frames_;
}
+
const base::flat_map<const WorkerNode*, base::flat_set<const WorkerNode*>>&
client_workers() const {
return client_workers_;
}
+ bool on_priority_and_reason_changed_called() const {
+ return on_priority_and_reason_changed_called_;
+ }
+
private:
bool on_final_response_url_determined_called_ = false;
@@ -256,6 +281,8 @@ class TestWorkerNodeObserver : public WorkerNodeObserver {
base::flat_map<const WorkerNode*, base::flat_set<const WorkerNode*>>
client_workers_;
+ bool on_priority_and_reason_changed_called_ = false;
+
DISALLOW_COPY_AND_ASSIGN(TestWorkerNodeObserver);
};
@@ -354,4 +381,22 @@ TEST_F(WorkerNodeImplTest, Observer_OnFinalResponseURLDetermined) {
graph()->RemoveWorkerNodeObserver(&worker_node_observer);
}
+TEST_F(WorkerNodeImplTest, Observer_OnPriorityAndReasonChanged) {
+ TestWorkerNodeObserver worker_node_observer;
+ graph()->AddWorkerNodeObserver(&worker_node_observer);
+
+ auto process = CreateNode<ProcessNodeImpl>();
+ auto worker = CreateNode<WorkerNodeImpl>(WorkerNode::WorkerType::kDedicated,
+ process.get());
+
+ EXPECT_FALSE(worker_node_observer.on_priority_and_reason_changed_called());
+ static const PriorityAndReason kPriorityAndReason(base::TaskPriority::HIGHEST,
+ "this is a reason!");
+ worker->SetPriorityAndReason(kPriorityAndReason);
+ EXPECT_TRUE(worker_node_observer.on_priority_and_reason_changed_called());
+ EXPECT_EQ(worker->priority_and_reason(), kPriorityAndReason);
+
+ graph()->RemoveWorkerNodeObserver(&worker_node_observer);
+}
+
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc b/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc
index 1be9f329907..bd25fcb6296 100644
--- a/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc
+++ b/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_browsertest.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/performance_manager_registry_impl.h"
#include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_unittest.cc b/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_unittest.cc
index 25b8ed80d89..d76ed071a5c 100644
--- a/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_unittest.cc
+++ b/chromium/components/performance_manager/mechanisms/tab_loading_frame_navigation_scheduler_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/test_support/performance_manager_test_harness.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
diff --git a/chromium/components/performance_manager/performance_manager.cc b/chromium/components/performance_manager/performance_manager.cc
index e71417f4bdb..ea18b346c57 100644
--- a/chromium/components/performance_manager/performance_manager.cc
+++ b/chromium/components/performance_manager/performance_manager.cc
@@ -8,10 +8,12 @@
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/page_node_impl.h"
+#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/performance_manager_registry_impl.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
#include "components/performance_manager/public/performance_manager_owned.h"
+#include "content/public/browser/render_process_host.h"
namespace performance_manager {
@@ -75,8 +77,40 @@ base::WeakPtr<FrameNode> PerformanceManager::GetFrameNodeForRenderFrameHost(
PerformanceManagerTabHelper::FromWebContents(wc);
if (!helper)
return nullptr;
+ auto* frame_node = helper->GetFrameNode(rfh);
+ if (!frame_node) {
+ // This should only happen if GetFrameNodeForRenderFrameHost is called
+ // before the RenderFrameCreate notification is dispatched.
+ DCHECK(!rfh->IsRenderFrameCreated());
+ return nullptr;
+ }
+ return frame_node->GetWeakPtr();
+}
+
+// static
+base::WeakPtr<ProcessNode>
+PerformanceManager::GetProcessNodeForRenderProcessHost(
+ content::RenderProcessHost* rph) {
+ DCHECK(rph);
+ auto* user_data = RenderProcessUserData::GetForRenderProcessHost(rph);
+ // There is a window after a RenderProcessHost is created before
+ // CreateProcessNodeAndExposeInterfacesToRendererProcess is called, during
+ // which time the RenderProcessUserData is not attached to the RPH yet. (It's
+ // called indirectly from RenderProcessHost::Init.)
+ if (!user_data)
+ return nullptr;
+ return user_data->process_node()->GetWeakPtr();
+}
- return helper->GetFrameNode(rfh)->GetWeakPtr();
+// static
+base::WeakPtr<ProcessNode>
+PerformanceManager::GetProcessNodeForRenderProcessHostId(
+ RenderProcessHostId id) {
+ DCHECK(id);
+ auto* rph = content::RenderProcessHost::FromID(id.value());
+ if (!rph)
+ return nullptr;
+ return GetProcessNodeForRenderProcessHost(rph);
}
// static
diff --git a/chromium/components/performance_manager/performance_manager_browsertest.cc b/chromium/components/performance_manager/performance_manager_browsertest.cc
index 0f4d18895ea..2c8fcc06ea4 100644
--- a/chromium/components/performance_manager/performance_manager_browsertest.cc
+++ b/chromium/components/performance_manager/performance_manager_browsertest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/render_frame_host_proxy.h"
diff --git a/chromium/components/performance_manager/performance_manager_impl_unittest.cc b/chromium/components/performance_manager/performance_manager_impl_unittest.cc
index 00fba995bd1..b6636d2a9dd 100644
--- a/chromium/components/performance_manager/performance_manager_impl_unittest.cc
+++ b/chromium/components/performance_manager/performance_manager_impl_unittest.cc
@@ -6,10 +6,10 @@
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/page_node_impl.h"
diff --git a/chromium/components/performance_manager/performance_manager_lifetime.cc b/chromium/components/performance_manager/performance_manager_lifetime.cc
index 9b05dcdfe56..fb5ffb086df 100644
--- a/chromium/components/performance_manager/performance_manager_lifetime.cc
+++ b/chromium/components/performance_manager/performance_manager_lifetime.cc
@@ -5,8 +5,10 @@
#include "components/performance_manager/embedder/performance_manager_lifetime.h"
#include "base/bind.h"
+#include "base/no_destructor.h"
#include "base/notreached.h"
#include "build/build_config.h"
+#include "components/performance_manager/decorators/frame_visibility_decorator.h"
#include "components/performance_manager/decorators/page_load_tracker_decorator.h"
#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
#include "components/performance_manager/graph/frame_node_impl_describer.h"
@@ -17,6 +19,7 @@
#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
#include "components/performance_manager/public/decorators/tab_properties_decorator.h"
#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker.h"
#if !defined(OS_ANDROID)
#include "components/performance_manager/public/decorators/site_data_recorder.h"
@@ -26,12 +29,19 @@ namespace performance_manager {
namespace {
+GraphCreatedCallback* GetAdditionalGraphCreatedCallback() {
+ static base::NoDestructor<GraphCreatedCallback>
+ additional_graph_created_callback;
+ return additional_graph_created_callback.get();
+}
+
void DefaultGraphCreatedCallback(
GraphCreatedCallback external_graph_created_callback,
GraphImpl* graph) {
graph->PassToGraph(
std::make_unique<execution_context::ExecutionContextRegistryImpl>());
graph->PassToGraph(std::make_unique<FrameNodeImplDescriber>());
+ graph->PassToGraph(std::make_unique<FrameVisibilityDecorator>());
graph->PassToGraph(std::make_unique<PageLiveStateDecorator>());
graph->PassToGraph(std::make_unique<PageLoadTrackerDecorator>());
graph->PassToGraph(std::make_unique<PageNodeImplDescriber>());
@@ -41,13 +51,22 @@ void DefaultGraphCreatedCallback(
#if !defined(OS_ANDROID)
graph->PassToGraph(std::make_unique<SiteDataRecorder>());
#endif
+
+ // This depends on ExecutionContextRegistry, so must be added afterwards.
+ graph->PassToGraph(std::make_unique<v8_memory::V8ContextTracker>());
+
+ // Run graph created callbacks.
std::move(external_graph_created_callback).Run(graph);
+ if (*GetAdditionalGraphCreatedCallback())
+ std::move(*GetAdditionalGraphCreatedCallback()).Run(graph);
}
void NullGraphCreatedCallback(
GraphCreatedCallback external_graph_created_callback,
GraphImpl* graph) {
std::move(external_graph_created_callback).Run(graph);
+ if (*GetAdditionalGraphCreatedCallback())
+ std::move(*GetAdditionalGraphCreatedCallback()).Run(graph);
}
base::OnceCallback<void(GraphImpl*)> AddDecorators(
@@ -82,6 +101,12 @@ PerformanceManagerLifetime::~PerformanceManagerLifetime() {
std::move(performance_manager_));
}
+// static
+void PerformanceManagerLifetime::SetAdditionalGraphCreatedCallbackForTesting(
+ GraphCreatedCallback graph_created_callback) {
+ *GetAdditionalGraphCreatedCallback() = std::move(graph_created_callback);
+}
+
std::unique_ptr<PerformanceManager>
CreatePerformanceManagerWithDefaultDecorators(
GraphCreatedCallback graph_created_callback) {
diff --git a/chromium/components/performance_manager/performance_manager_tab_helper_unittest.cc b/chromium/components/performance_manager/performance_manager_tab_helper_unittest.cc
index 1765ae4a38f..d719633dc94 100644
--- a/chromium/components/performance_manager/performance_manager_tab_helper_unittest.cc
+++ b/chromium/components/performance_manager/performance_manager_tab_helper_unittest.cc
@@ -9,7 +9,7 @@
#include "base/run_loop.h"
#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/graph_impl_operations.h"
#include "components/performance_manager/graph/page_node_impl.h"
diff --git a/chromium/components/performance_manager/performance_manager_unittest.cc b/chromium/components/performance_manager/performance_manager_unittest.cc
index af8ac21c225..382bd529908 100644
--- a/chromium/components/performance_manager/performance_manager_unittest.cc
+++ b/chromium/components/performance_manager/performance_manager_unittest.cc
@@ -7,14 +7,20 @@
#include <utility>
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
+#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/page_node.h"
+#include "components/performance_manager/public/graph/process_node.h"
+#include "components/performance_manager/public/render_frame_host_proxy.h"
+#include "components/performance_manager/public/render_process_host_proxy.h"
#include "components/performance_manager/public/web_contents_proxy.h"
#include "components/performance_manager/test_support/performance_manager_test_harness.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
namespace performance_manager {
@@ -41,42 +47,70 @@ class PerformanceManagerTest : public PerformanceManagerTestHarness {
DISALLOW_COPY_AND_ASSIGN(PerformanceManagerTest);
};
-TEST_F(PerformanceManagerTest, GetPageNodeForWebContents) {
+TEST_F(PerformanceManagerTest, NodeAccessors) {
auto contents = CreateTestWebContents();
+ content::RenderFrameHost* rfh = contents->GetMainFrame();
+ ASSERT_TRUE(rfh);
+ content::RenderProcessHost* rph = rfh->GetProcess();
+ ASSERT_TRUE(rph);
base::WeakPtr<PageNode> page_node =
PerformanceManager::GetPageNodeForWebContents(contents.get());
+ // FrameNode's and ProcessNode's don't exist until an observer fires on
+ // navigation. Verify that looking them up before that returns null instead
+ // of crashing.
+ EXPECT_FALSE(PerformanceManager::GetFrameNodeForRenderFrameHost(rfh));
+ EXPECT_FALSE(PerformanceManager::GetProcessNodeForRenderProcessHost(rph));
+
+ // Simulate a committed navigation to create the nodes.
+ content::NavigationSimulator::NavigateAndCommitFromBrowser(
+ contents.get(), GURL("https://www.example.com/"));
+ base::WeakPtr<FrameNode> frame_node =
+ PerformanceManager::GetFrameNodeForRenderFrameHost(rfh);
+ base::WeakPtr<ProcessNode> process_node =
+ PerformanceManager::GetProcessNodeForRenderProcessHost(rph);
+
// Post a task to the Graph and make it call a function on the UI thread that
- // will ensure that |page_node| is really associated with |contents|.
+ // will ensure that the nodes are really associated with the content objects.
base::RunLoop run_loop;
- auto check_wc_on_main_thread =
- base::BindLambdaForTesting([&](const WebContentsProxy& wc_proxy) {
+ auto check_proxies_on_main_thread =
+ base::BindLambdaForTesting([&](const WebContentsProxy& wc_proxy,
+ const RenderFrameHostProxy& rfh_proxy,
+ const RenderProcessHostProxy& rph_proxy) {
EXPECT_EQ(contents.get(), wc_proxy.Get());
+ EXPECT_EQ(rfh, rfh_proxy.Get());
+ EXPECT_EQ(rph, rph_proxy.Get());
run_loop.Quit();
});
auto call_on_graph_cb = base::BindLambdaForTesting([&]() {
EXPECT_TRUE(page_node.get());
+ EXPECT_TRUE(frame_node.get());
+ EXPECT_TRUE(process_node.get());
content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(std::move(check_wc_on_main_thread),
- page_node->GetContentsProxy()));
+ FROM_HERE, base::BindOnce(std::move(check_proxies_on_main_thread),
+ page_node->GetContentsProxy(),
+ frame_node->GetRenderFrameHostProxy(),
+ process_node->GetRenderProcessHostProxy()));
});
PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb);
- // Wait for |check_wc_on_main_thread| to be called.
+ // Wait for |check_proxies_on_main_thread| to be called.
run_loop.Run();
contents.reset();
- // After deleting |contents| the corresponding PageNode WeakPtr should be
+ // After deleting |contents| the corresponding WeakPtr's should be
// invalid.
base::RunLoop run_loop_after_contents_reset;
auto quit_closure = run_loop_after_contents_reset.QuitClosure();
auto call_on_graph_cb_2 = base::BindLambdaForTesting([&]() {
EXPECT_FALSE(page_node.get());
+ EXPECT_FALSE(frame_node.get());
+ EXPECT_FALSE(process_node.get());
std::move(quit_closure).Run();
});
diff --git a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
index 081d8a81641..1c625d9d168 100644
--- a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
@@ -11,7 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/test/test_file_util.h"
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc b/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
index a8b23f675bf..dc98bd15815 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
@@ -13,7 +13,7 @@
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequence_bound.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "content/public/test/browser_task_environment.h"
@@ -29,9 +29,9 @@ TEST(SiteDataCacheFactoryTest, EndToEnd) {
PerformanceManager::GetTaskRunner());
content::TestBrowserContext browser_context;
- cache_factory.Post(FROM_HERE, &SiteDataCacheFactory::OnBrowserContextCreated,
- browser_context.UniqueId(), browser_context.GetPath(),
- base::nullopt);
+ cache_factory.AsyncCall(&SiteDataCacheFactory::OnBrowserContextCreated)
+ .WithArgs(browser_context.UniqueId(), browser_context.GetPath(),
+ base::nullopt);
{
base::RunLoop run_loop;
@@ -51,9 +51,8 @@ TEST(SiteDataCacheFactoryTest, EndToEnd) {
run_loop.Run();
}
- cache_factory.Post(FROM_HERE,
- &SiteDataCacheFactory::OnBrowserContextDestroyed,
- browser_context.UniqueId());
+ cache_factory.AsyncCall(&SiteDataCacheFactory::OnBrowserContextDestroyed)
+ .WithArgs(browser_context.UniqueId());
{
base::RunLoop run_loop;
cache_factory.PostTaskWithThisObject(
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.h b/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.h
index 40b02cb507f..d4e2422c603 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.h
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.h
@@ -15,7 +15,7 @@
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/sequence_checker.h"
#include "components/performance_manager/persistence/site_data/site_data_cache.h"
#include "components/performance_manager/persistence/site_data/site_data_cache_inspector.h"
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc b/chromium/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc
index f762bf27eda..90edb917b27 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_impl_unittest.cc
@@ -7,7 +7,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/persistence/site_data/unittest_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc b/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
index f308f179c2c..7145a122c99 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
@@ -11,7 +11,7 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/persistence/site_data/site_data_impl.h"
#include "components/performance_manager/persistence/site_data/unittest_utils.h"
diff --git a/chromium/components/performance_manager/persistence/site_data/unittest_utils.cc b/chromium/components/performance_manager/persistence/site_data/unittest_utils.cc
index 3113bb97c99..f60b57222b9 100644
--- a/chromium/components/performance_manager/persistence/site_data/unittest_utils.cc
+++ b/chromium/components/performance_manager/persistence/site_data/unittest_utils.cc
@@ -6,8 +6,8 @@
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "components/performance_manager/performance_manager_impl.h"
namespace performance_manager {
diff --git a/chromium/components/performance_manager/public/execution_context/execution_context.h b/chromium/components/performance_manager/public/execution_context/execution_context.h
index ad8a4d963f7..7b09c843862 100644
--- a/chromium/components/performance_manager/public/execution_context/execution_context.h
+++ b/chromium/components/performance_manager/public/execution_context/execution_context.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_H_
#include "base/observer_list_types.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
#include "third_party/blink/public/common/tokens/tokens.h"
class GURL;
@@ -17,6 +18,8 @@ class Graph;
class ProcessNode;
class WorkerNode;
+using execution_context_priority::PriorityAndReason;
+
namespace execution_context {
class ExecutionContextObserver;
@@ -73,6 +76,10 @@ class ExecutionContext {
// ExecutionContext is hosted. This will never return nullptr.
virtual const ProcessNode* GetProcessNode() const = 0;
+ // Returns the current priority of the execution context, and the reason for
+ // the execution context having that particular priority.
+ virtual const PriorityAndReason& GetPriorityAndReason() const = 0;
+
// Returns the underlying FrameNode, if this context is a FrameNode, or
// nullptr otherwise.
virtual const FrameNode* GetFrameNode() const = 0;
@@ -97,6 +104,11 @@ class ExecutionContextObserver : public base::CheckedObserver {
// Called when an ExecutionContext is about to be removed. The pointer |ec|
// becomes invalid immediately after this returns.
virtual void OnBeforeExecutionContextRemoved(const ExecutionContext* ec) = 0;
+
+ // Invoked when the execution context priority and reason changes.
+ virtual void OnPriorityAndReasonChanged(
+ const ExecutionContext* ec,
+ const PriorityAndReason& previous_value) = 0;
};
// A default implementation of ExecutionContextObserver with empty stubs for all
@@ -113,6 +125,9 @@ class ExecutionContextObserverDefaultImpl : public ExecutionContextObserver {
// ExecutionContextObserver implementation:
void OnExecutionContextAdded(const ExecutionContext* ec) override {}
void OnBeforeExecutionContextRemoved(const ExecutionContext* ec) override {}
+ void OnPriorityAndReasonChanged(
+ const ExecutionContext* ec,
+ const PriorityAndReason& previous_value) override {}
};
// Helper function for converting from a WorkerToken to an
diff --git a/chromium/components/performance_manager/public/execution_context/execution_context_attached_data.h b/chromium/components/performance_manager/public/execution_context/execution_context_attached_data.h
new file mode 100644
index 00000000000..29ab40abc05
--- /dev/null
+++ b/chromium/components/performance_manager/public/execution_context/execution_context_attached_data.h
@@ -0,0 +1,106 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_ATTACHED_DATA_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_ATTACHED_DATA_H_
+
+#include "components/performance_manager/public/execution_context/execution_context.h"
+#include "components/performance_manager/public/execution_context/execution_context_registry.h"
+#include "components/performance_manager/public/graph/frame_node.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/node_attached_data.h"
+#include "components/performance_manager/public/graph/worker_node.h"
+
+namespace performance_manager {
+namespace execution_context {
+
+// An adapter that can be used to associate NodeAttachedData with all node
+// types that represent execution contexts. Under the hood this wraps
+// ExternalNodeAttachedDataImpl for each of the underlying node types.
+// It is expected that UserDataType have a constructor with the signature
+// "UserDataType(const ExecutionContext*)".
+template <typename UserDataType>
+class ExecutionContextAttachedData {
+ public:
+ ExecutionContextAttachedData() = default;
+ ExecutionContextAttachedData(const ExecutionContextAttachedData&) = delete;
+ ExecutionContextAttachedData& operator=(const ExecutionContextAttachedData&) =
+ delete;
+ virtual ~ExecutionContextAttachedData() = default;
+
+ // Gets the user data for the given |node|, creating it if it doesn't yet
+ // exist.
+ static UserDataType* GetOrCreate(const ExecutionContext* ec) {
+ return Dispatch<GetOrCreateFunctor>(ec);
+ }
+
+ // Gets the user data for the given |node|, returning nullptr if it doesn't
+ // exist.
+ static UserDataType* Get(const ExecutionContext* ec) {
+ return Dispatch<GetFunctor>(ec);
+ }
+
+ // Destroys the user data associated with the given node, returning true
+ // on success or false if the user data did not exist to begin with.
+ static bool Destroy(const ExecutionContext* ec) {
+ return Dispatch<DestroyFunctor>(ec);
+ }
+
+ private:
+ // A small adapter for UserDataType that makes it compatible with
+ // underlying node types.
+ class UserDataWrapper : public ExternalNodeAttachedDataImpl<UserDataWrapper>,
+ public UserDataType {
+ public:
+ explicit UserDataWrapper(const FrameNode* frame_node)
+ : UserDataType(
+ ExecutionContextRegistry::GetFromGraph(frame_node->GetGraph())
+ ->GetExecutionContextForFrameNode(frame_node)) {}
+
+ explicit UserDataWrapper(const WorkerNode* worker_node)
+ : UserDataType(
+ ExecutionContextRegistry::GetFromGraph(worker_node->GetGraph())
+ ->GetExecutionContextForWorkerNode(worker_node)) {}
+ };
+
+ // Helpers for dynamic dispatch to various functions based on the underlying
+ // node type.
+ struct GetOrCreateFunctor {
+ using ReturnType = UserDataType*;
+ template <typename NodeType>
+ static UserDataType* Do(const NodeType* node) {
+ return ExternalNodeAttachedDataImpl<UserDataWrapper>::GetOrCreate(node);
+ }
+ };
+ struct GetFunctor {
+ using ReturnType = UserDataType*;
+ template <typename NodeType>
+ static UserDataType* Do(const NodeType* node) {
+ return ExternalNodeAttachedDataImpl<UserDataWrapper>::Get(node);
+ }
+ };
+ struct DestroyFunctor {
+ using ReturnType = bool;
+ template <typename NodeType>
+ static bool Do(const NodeType* node) {
+ return ExternalNodeAttachedDataImpl<UserDataWrapper>::Destroy(node);
+ }
+ };
+
+ // Helper for dynamic dispatching based on underlying node type.
+ template <typename Functor>
+ static typename Functor::ReturnType Dispatch(const ExecutionContext* ec) {
+ switch (ec->GetType()) {
+ case ExecutionContextType::kFrameNode:
+ return Functor::Do(ec->GetFrameNode());
+ case ExecutionContextType::kWorkerNode:
+ return Functor::Do(ec->GetWorkerNode());
+ }
+ }
+};
+
+} // namespace execution_context
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_EXECUTION_CONTEXT_ATTACHED_DATA_H_
diff --git a/chromium/components/performance_manager/public/execution_context/execution_context_registry.h b/chromium/components/performance_manager/public/execution_context/execution_context_registry.h
index a92bb9ec540..faae92cfbc7 100644
--- a/chromium/components/performance_manager/public/execution_context/execution_context_registry.h
+++ b/chromium/components/performance_manager/public/execution_context/execution_context_registry.h
@@ -37,6 +37,9 @@ class ExecutionContextRegistry {
// the registry is torn down.
virtual void AddObserver(ExecutionContextObserver* observer) = 0;
+ // Determines if an observer is in the registry.
+ virtual bool HasObserver(ExecutionContextObserver* observer) const = 0;
+
// Removes an observer from the registry.
virtual void RemoveObserver(ExecutionContextObserver* observer) = 0;
diff --git a/chromium/components/performance_manager/public/frame_priority/boosting_vote_aggregator.h b/chromium/components/performance_manager/public/execution_context_priority/boosting_vote_aggregator.h
index e844023b265..cf7430095cc 100644
--- a/chromium/components/performance_manager/public/frame_priority/boosting_vote_aggregator.h
+++ b/chromium/components/performance_manager/public/execution_context_priority/boosting_vote_aggregator.h
@@ -2,27 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
#include <map>
#include <set>
#include "base/containers/flat_map.h"
#include "base/task/task_traits.h"
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
class BoostingVoteAggregator;
// A BoostingVote is a special kind of relative vote that allows a voter to
-// express that "frame X should have the same or greater priority than frame Y".
-// It allows implementing priority boost semantics to avoid priority inversions
-// for access to shared resources. BoostingVotes must be registered with a
-// BoostingVoteAggregator. Similar to a VoteReceipt, they are a move-only type
-// and their vote will be removed with their destruction.
+// express that "execution context X should have the same or greater priority
+// than execution context Y". It allows implementing priority boost semantics to
+// avoid priority inversions for access to shared resources. BoostingVotes must
+// be registered with a BoostingVoteAggregator. Similar to a VoteReceipt, they
+// are a move-only type and their vote will be removed with their destruction.
//
// A BoostingVote is considered "active" if it is associated with an aggregator
// (the result of calling "aggregator()" is non-null).
@@ -31,11 +31,11 @@ class BoostingVoteAggregator;
class BoostingVote {
public:
// Registers a relative vote with the provided |aggregator|, that ensures that
- // the priority of |output_frame| will be at least as high as that of
- // |input_frame|.
+ // the priority of |output_execution_context| will be at least as high as that
+ // of |input_execution_context|.
BoostingVote(BoostingVoteAggregator* aggregator,
- const FrameNode* input_frame,
- const FrameNode* output_frame,
+ const ExecutionContext* input_execution_context,
+ const ExecutionContext* output_execution_context,
const char* reason);
BoostingVote(const BoostingVote& rhs) = delete;
BoostingVote(BoostingVote&& rhs);
@@ -44,8 +44,12 @@ class BoostingVote {
~BoostingVote();
BoostingVoteAggregator* aggregator() const { return aggregator_; }
- const FrameNode* input_frame() const { return input_frame_; }
- const FrameNode* output_frame() const { return output_frame_; }
+ const ExecutionContext* input_execution_context() const {
+ return input_execution_context_;
+ }
+ const ExecutionContext* output_execution_context() const {
+ return output_execution_context_;
+ }
const char* reason() const { return reason_; }
// Detaches this BoostingVote from its aggregator. After calling this
@@ -54,17 +58,17 @@ class BoostingVote {
private:
BoostingVoteAggregator* aggregator_ = nullptr;
- const FrameNode* input_frame_ = nullptr;
- const FrameNode* output_frame_ = nullptr;
+ const ExecutionContext* input_execution_context_ = nullptr;
+ const ExecutionContext* output_execution_context_ = nullptr;
const char* reason_ = nullptr;
};
// The BoostingVoteAggregator allows for incoming votes to be modified via a
// collection of registered "relative boosting votes" that express relationships
-// such as "frame X should have the same or greater priority than frame Y".
-// It is intended to serve as the root of a tree of voters and aggregators,
-// allowing priority boost semantics to be implemented. This class must outlive
-// all boosting votes registered with it.
+// such as "execution context X should have the same or greater priority than
+// execution context Y". It is intended to serve as the root of a tree of voters
+// and aggregators, allowing priority boost semantics to be implemented. This
+// class must outlive all boosting votes registered with it.
class BoostingVoteAggregator : public VoteConsumer {
public:
BoostingVoteAggregator();
@@ -88,7 +92,7 @@ class BoostingVoteAggregator : public VoteConsumer {
static_assert(static_cast<int>(base::TaskPriority::HIGHEST) == 2,
"expect 3 priority levels");
- using NodePriorityMap = std::map<const FrameNode*, base::TaskPriority>;
+ using NodePriorityMap = std::map<const ExecutionContext*, base::TaskPriority>;
// Small helper class used to endow both edges and nodes with "active" bits
// for each priority layer.
@@ -115,19 +119,20 @@ class BoostingVoteAggregator : public VoteConsumer {
// direct Vote for that node, or as an input or output of a BoostedVote.
class NodeData : public ActiveLayers {
public:
- NodeData() = default;
+ NodeData();
NodeData(const NodeData& rhs) = delete;
- NodeData(NodeData&& rhs) = default;
+ NodeData(NodeData&& rhs);
NodeData& operator=(const NodeData& rhs) = delete;
NodeData& operator=(NodeData&& rhs) = default;
- ~NodeData() = default;
+ ~NodeData();
const AcceptedVote& incoming() const { return incoming_; }
const VoteReceipt& receipt() const { return receipt_; }
// For modifying |incoming_|.
VoteReceipt SetIncomingVote(VoteConsumer* consumer,
- VoterId voter_id,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
const Vote& vote);
void UpdateIncomingVote(const Vote& vote) { incoming_.UpdateVote(vote); }
@@ -178,7 +183,7 @@ class BoostingVoteAggregator : public VoteConsumer {
// NOTE: It is important that NodeDataMap preserve pointers to NodeData
// through insertions and deletions in the map, as we take raw pointers to
// objects in the map.
- using NodeDataMap = std::map<const FrameNode*, NodeData>;
+ using NodeDataMap = std::map<const ExecutionContext*, NodeData>;
using NodeDataPtrSet = std::set<NodeDataMap::value_type*>;
// For any given edge, this maintains the metadata associated with that
@@ -219,10 +224,11 @@ class BoostingVoteAggregator : public VoteConsumer {
template <bool kForward>
class Edge {
public:
- Edge(const FrameNode* src, const FrameNode* dst) : src_(src), dst_(dst) {}
+ Edge(const ExecutionContext* src, const ExecutionContext* dst)
+ : src_(src), dst_(dst) {}
explicit Edge(const BoostingVote* boosting_vote)
- : src_(boosting_vote->input_frame()),
- dst_(boosting_vote->output_frame()) {}
+ : src_(boosting_vote->input_execution_context()),
+ dst_(boosting_vote->output_execution_context()) {}
Edge(const Edge&) = default;
~Edge() {}
@@ -242,12 +248,12 @@ class BoostingVoteAggregator : public VoteConsumer {
return std::tie(dst_, src_) < std::tie(rhs.dst_, rhs.src_);
}
- const FrameNode* src() const { return src_; }
- const FrameNode* dst() const { return dst_; }
+ const ExecutionContext* src() const { return src_; }
+ const ExecutionContext* dst() const { return dst_; }
private:
- const FrameNode* src_ = nullptr;
- const FrameNode* dst_ = nullptr;
+ const ExecutionContext* src_ = nullptr;
+ const ExecutionContext* dst_ = nullptr;
};
using ForwardEdge = Edge<true>;
using ReverseEdge = Edge<false>;
@@ -262,11 +268,15 @@ class BoostingVoteAggregator : public VoteConsumer {
void CancelBoostingVote(const BoostingVote* boosting_vote);
// VoteConsumer implementation:
- VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override;
- VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) override;
- void VoteInvalidated(AcceptedVote* vote) override;
+ VoteReceipt SubmitVote(util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) override;
+ void ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) override;
// Helper functions for enumerating over incoming and outgoing edges.
// |function| should accept a single input parameter that is a
@@ -274,17 +284,17 @@ class BoostingVoteAggregator : public VoteConsumer {
// returns a bool. Returning true indicates the iteration should continue,
// returning false indicates it should terminate.
template <typename Function>
- void ForEachIncomingEdge(const FrameNode* node, Function&& function);
+ void ForEachIncomingEdge(const ExecutionContext* node, Function&& function);
template <typename Function>
- void ForEachOutgoingEdge(const FrameNode* node, Function&& function);
+ void ForEachOutgoingEdge(const ExecutionContext* node, Function&& function);
// Looks up the NodeData associated with the provided |vote|. The data is
// expected to already exist (enforced by a DCHECK).
NodeDataMap::iterator GetNodeDataByVote(AcceptedVote* vote);
// Finds or creates the node data associated with the given node.
- NodeDataMap::iterator FindOrCreateNodeData(const FrameNode* frame_node);
- NodeDataMap::iterator FindNodeData(const FrameNode* frame_node);
+ NodeDataMap::iterator FindOrCreateNodeData(const ExecutionContext* node);
+ NodeDataMap::iterator FindNodeData(const ExecutionContext* node);
// Returns the vote reason that should be associated with the given
// node. This will preferentially select the reason that comes with a direct
@@ -294,7 +304,7 @@ class BoostingVoteAggregator : public VoteConsumer {
// no non-null reasons have been provided.
const char* GetVoteReason(const NodeDataMap::value_type* node_data_value);
- // Upstreams the vote for this |frame_node| via its associated NodeData.
+ // Upstreams the vote for this |node| via its associated NodeData.
void UpstreamVoteIfNeeded(NodeDataMap::value_type* node_data_value);
// Upstreams changes that have been made to the provided set of nodes. This
@@ -356,7 +366,7 @@ class BoostingVoteAggregator : public VoteConsumer {
// Our input voter. We'll only accept votes from this voter otherwise we'll
// DCHECK.
- VoterId input_voter_id_ = kInvalidVoterId;
+ voting::VoterId<Vote> input_voter_id_ = voting::kInvalidVoterId<Vote>;
// Our channel for upstreaming our votes.
VotingChannel channel_;
@@ -378,7 +388,7 @@ class BoostingVoteAggregator : public VoteConsumer {
DISALLOW_COPY_AND_ASSIGN(BoostingVoteAggregator);
};
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_BOOSTING_VOTE_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/public/execution_context_priority/execution_context_priority.h b/chromium/components/performance_manager/public/execution_context_priority/execution_context_priority.h
new file mode 100644
index 00000000000..1f67013acfc
--- /dev/null
+++ b/chromium/components/performance_manager/public/execution_context_priority/execution_context_priority.h
@@ -0,0 +1,67 @@
+// 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 COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_H_
+
+#include "base/task/task_traits.h"
+#include "components/performance_manager/public/voting/voting.h"
+
+// Specialization of a voting system used to get votes related to the
+// TaskPriority of ExecutionContexts.
+
+namespace performance_manager {
+
+namespace execution_context {
+class ExecutionContext;
+}
+
+namespace execution_context_priority {
+
+using execution_context::ExecutionContext;
+
+// Helper function equivalent to strcmp, but that is safe to use with nullptr.
+int ReasonCompare(const char* reason1, const char* reason2);
+
+// Helper class for storing a priority and a reason.
+class PriorityAndReason {
+ public:
+ PriorityAndReason() = default;
+ constexpr PriorityAndReason(base::TaskPriority priority, const char* reason)
+ : priority_(priority), reason_(reason) {}
+ PriorityAndReason(const PriorityAndReason&) = default;
+ PriorityAndReason& operator=(const PriorityAndReason&) = default;
+ ~PriorityAndReason() = default;
+
+ base::TaskPriority priority() const { return priority_; }
+ const char* reason() const { return reason_; }
+
+ // Returns -1, 0 or 1 indicating the outcome of a comparison of this value
+ // and |other|.
+ int Compare(const PriorityAndReason& other) const;
+
+ bool operator==(const PriorityAndReason& other) const;
+ bool operator!=(const PriorityAndReason& other) const;
+ bool operator<=(const PriorityAndReason& other) const;
+ bool operator>=(const PriorityAndReason& other) const;
+ bool operator<(const PriorityAndReason& other) const;
+ bool operator>(const PriorityAndReason& other) const;
+
+ private:
+ base::TaskPriority priority_ = base::TaskPriority::LOWEST;
+ const char* reason_ = nullptr;
+};
+
+using Vote = voting::
+ Vote<ExecutionContext, base::TaskPriority, base::TaskPriority::LOWEST>;
+using VoteReceipt = voting::VoteReceipt<Vote>;
+using VotingChannel = voting::VotingChannel<Vote>;
+using VotingChannelFactory = voting::VotingChannelFactory<Vote>;
+using VoteConsumer = voting::VoteConsumer<Vote>;
+using AcceptedVote = voting::AcceptedVote<Vote>;
+
+} // namespace execution_context_priority
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_H_
diff --git a/chromium/components/performance_manager/public/frame_priority/max_vote_aggregator.h b/chromium/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h
index 102b08b46f1..77433136d98 100644
--- a/chromium/components/performance_manager/public/frame_priority/max_vote_aggregator.h
+++ b/chromium/components/performance_manager/public/execution_context_priority/max_vote_aggregator.h
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_MAX_VOTE_AGGREGATOR_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_MAX_VOTE_AGGREGATOR_H_
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_MAX_VOTE_AGGREGATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_MAX_VOTE_AGGREGATOR_H_
#include <map>
#include <utility>
#include "base/containers/intrusive_heap.h"
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
// Aggregator that allows votes from an arbitrary number of voters, and forwards
// the maximum vote for each frame. The upstream voting channel must be set
@@ -31,11 +31,15 @@ class MaxVoteAggregator : public VoteConsumer {
protected:
// VoteConsumer implementation:
- VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override;
- VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) override;
- void VoteInvalidated(AcceptedVote* vote) override;
+ VoteReceipt SubmitVote(util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) override;
+ void ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) override;
private:
friend class MaxVoteAggregatorTestAccess;
@@ -44,23 +48,26 @@ class MaxVoteAggregator : public VoteConsumer {
// order votes by the order in which they were received. This ensures that
// votes upstreamed by this aggregator remain as stable as possible.
struct StampedVote {
- StampedVote() = default;
- StampedVote(AcceptedVote&& vote, uint32_t vote_id)
- : vote(std::move(vote)), vote_id(vote_id) {}
- StampedVote(StampedVote&&) = default;
+ StampedVote();
+ StampedVote(AcceptedVote&& vote, uint32_t vote_id);
+ StampedVote(StampedVote&&);
StampedVote(const StampedVote&) = delete;
- ~StampedVote() = default;
+ ~StampedVote();
StampedVote& operator=(StampedVote&&) = default;
StampedVote& operator=(const StampedVote&) = delete;
bool operator<(const StampedVote& rhs) const {
- if (vote.vote().priority() != rhs.vote.vote().priority())
- return vote.vote().priority() < rhs.vote.vote().priority();
+ if (vote.vote().value() != rhs.vote.vote().value())
+ return vote.vote().value() < rhs.vote.vote().value();
// Higher |vote_id| values are of lower priority.
return vote_id > rhs.vote_id;
}
+ // Given an AcceptedVote that's embedded in a StampedVote::vote, retrieve
+ // the embedding StampedVote instance.
+ static StampedVote* FromAcceptedVote(AcceptedVote* accepted_vote);
+
// IntrusiveHeap contract. We actually don't need HeapHandles, as we already
// know the positions of the elements in the heap directly, as they are
// tracked with explicit back pointers.
@@ -74,10 +81,10 @@ class MaxVoteAggregator : public VoteConsumer {
uint32_t vote_id = 0;
};
- // The collection of votes for a single frame. This is move-only because all
- // of its members are move-only. Internally it houses the collection of all
- // votes associated with a frame as max-heap, and a receipt for the vote that
- // has been upstreamed.
+ // The collection of votes for a single execution context. This is move-only
+ // because all of its members are move-only. Internally it houses the
+ // collection of all votes associated with a execution context as max-heap,
+ // and a receipt for the vote that has been upstreamed.
class VoteData {
public:
VoteData();
@@ -121,7 +128,7 @@ class MaxVoteAggregator : public VoteConsumer {
VoteReceipt receipt_;
};
- using VoteDataMap = std::map<const FrameNode*, VoteData>;
+ using VoteDataMap = std::map<const ExecutionContext*, VoteData>;
// Looks up the VoteData associated with the provided |vote|. The data is
// expected to already exist (enforced by a DCHECK).
@@ -142,7 +149,7 @@ class MaxVoteAggregator : public VoteConsumer {
DISALLOW_COPY_AND_ASSIGN(MaxVoteAggregator);
};
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_MAX_VOTE_AGGREGATOR_H_
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_MAX_VOTE_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/public/frame_priority/override_vote_aggregator.h b/chromium/components/performance_manager/public/execution_context_priority/override_vote_aggregator.h
index ca9238afb3b..5b51a70dfa4 100644
--- a/chromium/components/performance_manager/public/frame_priority/override_vote_aggregator.h
+++ b/chromium/components/performance_manager/public/execution_context_priority/override_vote_aggregator.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
#include <map>
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
namespace performance_manager {
-namespace frame_priority {
+namespace execution_context_priority {
// Aggregator that allows votes from 2 different Voters, where one of the voters
// is allowed to override the votes of another. This aggregator should be
@@ -32,25 +32,29 @@ class OverrideVoteAggregator : public VoteConsumer {
protected:
// VoteConsumer implementation:
- VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override;
- VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* vote,
- const Vote& old_vote) override;
- void VoteInvalidated(AcceptedVote* vote) override;
+ VoteReceipt SubmitVote(util::PassKey<VotingChannel>,
+ voting::VoterId<Vote> voter_id,
+ const ExecutionContext* execution_context,
+ const Vote& vote) override;
+ void ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const Vote& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) override;
private:
// This is move-only because all of its members are move-only.
struct VoteData {
- VoteData() = default;
+ VoteData();
VoteData(const VoteData& rhs) = delete;
- VoteData(VoteData&& rhs) = default;
+ VoteData(VoteData&& rhs);
VoteData& operator=(const VoteData& rhs) = delete;
VoteData& operator=(VoteData&& rhs) = default;
- ~VoteData() = default;
+ ~VoteData();
- // Each of these IsValid if a vote has been emitted for this frame,
- // otherwise !IsValid. At least one of the votes must be valid, otherwise
- // the entire map entry will be destroyed.
+ // Each of these IsValid if a vote has been emitted for this execution
+ // context, otherwise !IsValid. At least one of the votes must be valid,
+ // otherwise the entire map entry will be destroyed.
AcceptedVote override_vote;
AcceptedVote default_vote;
@@ -58,7 +62,7 @@ class OverrideVoteAggregator : public VoteConsumer {
VoteReceipt receipt;
};
- using VoteDataMap = std::map<const FrameNode*, VoteData>;
+ using VoteDataMap = std::map<const ExecutionContext*, VoteData>;
// Looks up the VoteData associated with the provided |vote|. The data is
// expected to already exist (enforced by a DCHECK).
@@ -66,12 +70,14 @@ class OverrideVoteAggregator : public VoteConsumer {
// Rebrands |vote| as belonging to this voter, and then sends it along to our
// |consumer_|. Stores the resulting receipt in |vote_data|.
- void UpstreamVote(const Vote& vote, VoteData* vote_data);
+ void UpstreamVote(const ExecutionContext* execution_context,
+ const Vote& vote,
+ VoteData* vote_data);
// Our two input voters. We'll only accept votes from these voters otherwise
// we'll DCHECK.
- VoterId override_voter_id_ = kInvalidVoterId;
- VoterId default_voter_id_ = kInvalidVoterId;
+ voting::VoterId<Vote> override_voter_id_ = voting::kInvalidVoterId<Vote>;
+ voting::VoterId<Vote> default_voter_id_ = voting::kInvalidVoterId<Vote>;
// Our channel for upstreaming our votes.
VotingChannel channel_;
@@ -85,7 +91,7 @@ class OverrideVoteAggregator : public VoteConsumer {
DISALLOW_COPY_AND_ASSIGN(OverrideVoteAggregator);
};
-} // namespace frame_priority
+} // namespace execution_context_priority
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_EXECUTION_CONTEXT_PRIORITY_OVERRIDE_VOTE_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/public/features.h b/chromium/components/performance_manager/public/features.h
index 2f22e6d5118..a60df9ed43d 100644
--- a/chromium/components/performance_manager/public/features.h
+++ b/chromium/components/performance_manager/public/features.h
@@ -36,7 +36,11 @@ struct TabLoadingFrameNavigationThrottlesParams {
double fcp_multiple;
};
+// A feature that gates the inclusion of service worker relationships in the
+// graph. This is a temporary feature, see https://crbug.com/1143281.
+extern const base::Feature kServiceWorkerRelationshipsInGraph;
+
} // namespace features
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FEATURES_H_ \ No newline at end of file
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FEATURES_H_
diff --git a/chromium/components/performance_manager/public/frame_priority/frame_priority.h b/chromium/components/performance_manager/public/frame_priority/frame_priority.h
deleted file mode 100644
index 7a33e804168..00000000000
--- a/chromium/components/performance_manager/public/frame_priority/frame_priority.h
+++ /dev/null
@@ -1,432 +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 COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_FRAME_PRIORITY_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_FRAME_PRIORITY_H_
-
-// Declares the various structures and formats associated with the frame
-// priority voting system.
-//
-// There are 6 interrelated classes declared here:
-//
-// (1) Vote - A simple wrapper for a FramePriority vote, unattributed,
-// unsubmittted and unowned. This is a final concrete class.
-// (2) AcceptedVote - A thin wrapper around a Vote, which gives it ownership
-// (by a VoteConsumer) and tracking (via VoteReceipt). This is a final
-// concrete class.
-// (3) VoteReceipt - Counterpart to an AcceptedVote. Issued to a voter when a
-// vote is accepted, and used to allow that voter to change / withdraw /
-// cancel their vote. This is a final concrete class.
-// (4) VoteConsumer - Destination for Votes (making them AcceptedVotes) and
-// issuer of VoteReceipts. This is an interface.
-// (5) VotingChannel - A mechanism by which a voter can submit votes to
-// VoteConsumer, which endows the vote with a unique voter attribution. This
-// is a final concrete class.
-// (6) VotingChannelFactory - Producer and tracker of VotingChannels, meant to
-// be owned by a VoteConsumer. This is a final concrete class.
-//
-// Voters register themselves with VoteConsumers, which issues them a private
-// VotingChannel to use for submitting Votes. Voters then submit raw Votes to
-// VoteConsumers via the VotingChannel, which issues them a VoteReceipt. When a
-// VoteConsumer accepts a vote it becomes an AcceptedVote. AcceptedVotes and
-// VoteReceipts are entangled for their lifetimes, with AcceptedVotes (owned by
-// the consumer) outliving their associated VoteReceipts (owned by the voter).
-// Both types are move-only, ensuring that one vote had exactly one receipt. A
-// AcceptedVote passes through a small lifecycle (no receipt yet issued -> has
-// issued a receipt -> receipt has been destroyed and vote is invalidated).
-//
-// VotingChannels are tracked by a VotingChannelFactory, which itself is owned
-// by the VoteConsumer. The VotingChannelFactory is used to track all
-// outstanding VotingChannels, and helps to ensure that Voters have been
-// torn-down / disconnected before the VoteConsumer disappears.
-//
-// When a vote is invalidated the consumer owning the vote is notified so that
-// they may update internal data structures, aggregates, etc.
-//
-// None of these objects are thread-safe, and they should all be used from a
-// single sequence. In practice this will be the PM sequence.
-//
-// IMPLEMENTATION NOTES:
-//
-// AcceptedVote and VoteReceipt maintain explicit back-pointers to each other,
-// which is what allows them both to be movable and yet not incur a heap
-// allocation. This means that they are both amenable to storage in memory-dense
-// containers (flat_map, flat_set, vector) and won't incur further heap
-// allocations. It is expected that there be O(1000s) of votes lying around, but
-// that they will not often have to move. Thus the pointer maintenance is a
-// reasonable trade-off for memory efficiency.
-//
-// TODO(chrisha): Once workers are added to the graph this should be an
-// "execution context priority" voting system, where an execution context is a
-// worker or a frame (document), and a common base-class of those node types.
-
-#include "base/callback_forward.h"
-#include "base/containers/flat_set.h"
-#include "base/macros.h"
-#include "base/task/task_traits.h"
-
-namespace performance_manager {
-
-class FrameNode;
-
-namespace frame_priority {
-
-class VoteConsumer;
-
-using VoterId = uint32_t;
-constexpr VoterId kInvalidVoterId = 0;
-
-// Helper function equivalent to strcmp, but that is safe to use with nullptr.
-int ReasonCompare(const char* reason1, const char* reason2);
-
-// Helper class for storing a priority and a reason.
-class PriorityAndReason {
- public:
- PriorityAndReason() = default;
- constexpr PriorityAndReason(base::TaskPriority priority, const char* reason)
- : priority_(priority), reason_(reason) {}
- PriorityAndReason(const PriorityAndReason&) = default;
- PriorityAndReason& operator=(const PriorityAndReason&) = default;
- ~PriorityAndReason() = default;
-
- base::TaskPriority priority() const { return priority_; }
- const char* reason() const { return reason_; }
-
- // Returns -1, 0 or 1 indicating the outcome of a comparison of this value
- // and |other|.
- int Compare(const PriorityAndReason& other) const;
-
- bool operator==(const PriorityAndReason& other) const;
- bool operator!=(const PriorityAndReason& other) const;
- bool operator<=(const PriorityAndReason& other) const;
- bool operator>=(const PriorityAndReason& other) const;
- bool operator<(const PriorityAndReason& other) const;
- bool operator>(const PriorityAndReason& other) const;
-
- private:
- base::TaskPriority priority_ = base::TaskPriority::LOWEST;
- const char* reason_ = nullptr;
-};
-
-// Contains a single vote. Specifically allows copying, etc, so as to be STL
-// container friendly.
-class Vote final {
- public:
- Vote();
- Vote(const FrameNode* frame_node,
- base::TaskPriority priority,
- const char* reason);
- Vote(const Vote& rhs);
-
- Vote& operator=(const Vote& rhs);
-
- ~Vote();
-
- const FrameNode* frame_node() const { return frame_node_; }
- base::TaskPriority priority() const { return priority_; }
- const char* reason() const { return reason_; }
-
- bool operator==(const Vote& vote) const;
- bool operator!=(const Vote& vote) const;
-
- bool IsValid() const;
-
- private:
- const FrameNode* frame_node_ = nullptr;
- base::TaskPriority priority_ = base::TaskPriority::LOWEST;
- const char* reason_ = nullptr;
-};
-
-// A raw vote becomes an AcceptedVote once a VoteConsumer receives and stores
-// it, associating it with a VoterId.
-class AcceptedVote;
-
-// An issued vote returns a move-only VoteReceipt. Destroying the vote receipt
-// is equivalent to invalidating the vote.
-class VoteReceipt final {
- public:
- VoteReceipt();
- VoteReceipt(const VoteReceipt& rhs) = delete;
- VoteReceipt(VoteReceipt&& rhs);
-
- VoteReceipt& operator=(const VoteReceipt& rhs) = delete;
- VoteReceipt& operator=(VoteReceipt&& rhs);
-
- ~VoteReceipt();
-
- // Returns true if this receipt is entangled with a vote.
- bool HasVote() const;
- bool HasVote(const AcceptedVote* vote) const;
-
- // Returns the consumer that this vote was submitted to. Can only be called if
- // HasVote returns true.
- VoteConsumer* GetConsumer() const;
-
- // Returns the voter ID associated with this receipt. Can only be called if
- // HasVote returns true.
- VoterId GetVoterId() const;
-
- // Returns the vote corresponding to this receipt. Can only be called if
- // HasVote returns true.
- const Vote& GetVote() const;
-
- // Changes the upstream vote associated with this vote receipt. Can only be
- // called if HasVote returns true.
- void ChangeVote(base::TaskPriority priority, const char* reason);
-
- // Rests the vote receipt, canceling the upstream vote.
- void Reset();
-
- protected:
- // VoteReceipt and AcceptedVote are tightly intertwined, and maintain
- // back-pointers to each other as one or the other is moved. The friendship
- // allows AcceptedVote to reach in and update its VoteReceipt counterpart. No
- // other class needs access to these functions.
- friend class AcceptedVote;
-
- // Allows a AcceptedVote to create an entangled receipt.
- explicit VoteReceipt(AcceptedVote* vote);
-
- // Allows a AcceptedVote to update its backpointer.
- void MoveVote(AcceptedVote* old_vote, AcceptedVote* new_vote);
-
- private:
- void Take(VoteReceipt&& rhs);
-
- // A back-pointer to the accepted vote, so that it can be notified when this
- // receipt is destroyed.
- AcceptedVote* vote_ = nullptr;
-};
-
-// A move-only wrapper for a vote and its associated receipt. AcceptedVotes
-// and VoteReceipts exist in pairs, and they update their pointers to each
-// other. An AcceptedVote goes through the following lifecycle:
-//
-// (1) Initial creation. It has a vote, but no receipt. The vote is considered
-// valid at this point.
-// (2) Association with a receipt. The vote is considered valid at this point.
-// (3) Invalidation. The receipt is destroyed, which reaches back and
-// invalidates the vote. The vote is considered invalid at this point, and
-// no new receipt may be issued.
-//
-// An AcceptedVote must outlive its associated VoteReceipt, much like
-// VoteConsumers must outlive voters. Note that a default constructed
-// AcceptedVote is always in the invalidated state.
-class AcceptedVote final {
- public:
- AcceptedVote();
- AcceptedVote(VoteConsumer* consumer, VoterId voter_id, const Vote& vote);
- AcceptedVote(const AcceptedVote& rhs) = delete;
- AcceptedVote(AcceptedVote&& rhs);
-
- AcceptedVote& operator=(const AcceptedVote& rhs) = delete;
- AcceptedVote& operator=(AcceptedVote&& rhs);
-
- ~AcceptedVote();
-
- // Returns true if this vote is associated with a receipt.
- bool HasReceipt() const;
- bool HasReceipt(const VoteReceipt* receipt) const;
-
- bool IsValid() const;
- VoteReceipt IssueReceipt();
-
- VoteConsumer* consumer() const { return consumer_; }
- VoterId voter_id() const { return voter_id_; }
- const Vote& vote() const { return vote_; }
-
- // Allows an accepted vote to be updated in place.
- void UpdateVote(const Vote& vote);
-
- protected:
- // VoteReceipt and AcceptedVote are tightly intertwined, and maintain
- // back-pointers to each other as one or the other is moved. The friendship
- // allows VoteReceipt to reach in and update its AcceptedVote counterpart. No
- // other class needs access to these functions.
- friend class VoteReceipt;
-
- // Allows a VoteReceipt to associate itself with this vote.
- void SetReceipt(VoteReceipt* receipt);
-
- // Allows a VoteReceipt to update its backpointer.
- void MoveReceipt(VoteReceipt* old_receipt, VoteReceipt* new_receipt);
-
- // Allows a VoteReceipt to change this vote. The vote receipt gives up its
- // receipt only to be returned a new one.
- VoteReceipt ChangeVote(VoteReceipt receipt,
- base::TaskPriority priority,
- const char* reason);
-
- // Allows a VoteReceipt to invalidate this vote.
- void InvalidateVote(VoteReceipt* receipt);
-
- private:
- void Take(AcceptedVote&& rhs);
-
- // The consumer that accepted the vote.
- VoteConsumer* consumer_ = nullptr;
-
- // The ID of the voter that submitted the vote. This is defined by the
- // VoteConsumer.
- VoterId voter_id_ = kInvalidVoterId;
-
- // The vote that is being wrapped.
- Vote vote_;
-
- // The associated vote receipt.
- VoteReceipt* receipt_ = nullptr;
-
- // Set to true when an associated receipt is destroyed.
- bool invalidated_ = true;
-};
-
-class VotingChannelFactory;
-
-// A channel that a voter can use to submit votes to a VoteConsumer. A move-only
-// type so that it can't be shared by multiple voters. This must be destroyed
-// before the issuing VotingChannelFactory.
-class VotingChannel final {
- public:
- VotingChannel();
- VotingChannel(const VotingChannel& rhs) = delete;
- VotingChannel(VotingChannel&& rhs);
- VotingChannel& operator=(const VotingChannel& rhs) = delete;
- VotingChannel& operator=(VotingChannel&& rhs);
- ~VotingChannel();
-
- // Submits a vote through this voting channel. Can only be called if this
- // VotingChannel is valid.
- VoteReceipt SubmitVote(const Vote& vote);
-
- // Returns true if this VotingChannel is valid.
- bool IsValid() const;
-
- // Resets this voting channel.
- void Reset();
-
- VoterId voter_id() const { return voter_id_; }
-
- VotingChannelFactory* factory_for_testing() const { return factory_; }
-
- protected:
- friend class VotingChannelFactory;
-
- // VotingChannelFactory is the sole producer of VotingChannels.
- VotingChannel(VotingChannelFactory* factory, VoterId voter_id);
-
- private:
- void Take(VotingChannel&& rhs);
-
- // Used to reach back into the factory to decrement the outstanding
- // VotingChannel count, and for routing votes to the consumer.
- VotingChannelFactory* factory_ = nullptr;
- VoterId voter_id_ = kInvalidVoterId;
-};
-
-// A helper for creating VotingChannels that binds a unique VoterId (and
-// passes the votes along to the VoteConsumer with that VoterId), and a tracking
-// token to ensure that the voter disconnects from the VoteConsumer before it is
-// itself destroyed. Implementations of VoteConsumers should own an instance of
-// this and use it to emit VotingChannels. This class will DCHECK in its
-// destructor if there are outstanding VotingChannels at its death.
-class VotingChannelFactory final {
- public:
- explicit VotingChannelFactory(VoteConsumer* consumer);
- ~VotingChannelFactory();
-
- // Builds a new VotingChannel that routes votes to the |consumer_|.
- VotingChannel BuildVotingChannel();
-
- size_t voting_channels_issued() const { return voting_channels_issued_; }
- size_t voting_channels_outstanding() const {
- return voting_channels_outstanding_;
- }
-
- protected:
- friend class VotingChannel;
-
- // Used by ~VotingChannel to notify the factory that a channel has been
- // torn down.
- void OnVotingChannelDestroyed();
-
- private:
- // The consumer that owns this factory.
- VoteConsumer* consumer_ = nullptr;
-
- // The number of voting channels issued, and the number that remain
- // outstanding.
- size_t voting_channels_issued_ = 0u;
- size_t voting_channels_outstanding_ = 0u;
-
- DISALLOW_COPY_AND_ASSIGN(VotingChannelFactory);
-};
-
-// A consumer of votes. By convention a VoteConsumer exposes mechanisms for
-// registering voters with the consumer, and providing them a VotingChannel to
-// invoke. This is done via owning a VotingChannelFactory, and building
-// VotingChannels. Consumers must outlive any VotingChannels they have issued.
-class VoteConsumer {
- public:
- VoteConsumer();
- virtual ~VoteConsumer();
-
- protected:
- friend class AcceptedVote;
- friend class VotingChannel;
-
- // Used by a VotingChannel to submit votes to this consumer.
- virtual VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) = 0;
-
- // Used by an AcceptedVote to notify a consumer that a previously issued vote
- // has been changed. Both the |new_vote| and the |receipt| are provided to the
- // consumer, as it may be necessary for the consumer to create an entirely
- // new vote and issue a new receipt for it (although ideally it does not do so
- // for the sake of efficiency). Alternatively, the consumer can choose to
- // update the |old_vote| in-place, using the data from |new_vote|. This is
- // kept protected as it is part of a private contract between an AcceptedVote
- // and a VoteConsumer. A naive implementation of this would be the following:
- //
- // // Tear down the old vote before submitting a new one in order to prevent
- // // the voter from having 2 simultaneous votes for the same frame.
- // auto voter_id = receipt.GetVoterId();
- // receipt.Reset();
- // return SubmitVote(voter_id, new_vote);
- virtual VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) = 0;
-
- // Used by a AcceptedVote to notify a consumer that a previously issued
- // receipt has been destroyed, and the vote is now invalidated. This is kept
- // protected as it is part of a private contract between an AcceptedVote and a
- // VoteConsumer.
- virtual void VoteInvalidated(AcceptedVote* vote) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VoteConsumer);
-};
-
-// Provides a default implementation of VoteConsumer that implements a naive
-// (less efficient) version of "ChangeVote".
-class VoteConsumerDefaultImpl : public VoteConsumer {
- public:
- VoteConsumerDefaultImpl();
- ~VoteConsumerDefaultImpl() override;
-
- // VoteConsumer implementation left to the derived class:
- VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override = 0;
- void VoteInvalidated(AcceptedVote* vote) override = 0;
-
- // VoteConsumer implementation provided by this class:
- VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* existing_vote,
- const Vote& new_vote) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VoteConsumerDefaultImpl);
-};
-
-} // namespace frame_priority
-} // namespace performance_manager
-
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FRAME_PRIORITY_FRAME_PRIORITY_H_
diff --git a/chromium/components/performance_manager/public/graph/frame_node.h b/chromium/components/performance_manager/public/graph/frame_node.h
index f37a7d30737..8a66185e6fc 100644
--- a/chromium/components/performance_manager/public/graph/frame_node.h
+++ b/chromium/components/performance_manager/public/graph/frame_node.h
@@ -7,12 +7,14 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/util/type_safety/strong_alias.h"
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
#include "components/performance_manager/public/graph/node.h"
#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
#include "components/performance_manager/public/mojom/lifecycle.mojom.h"
#include "third_party/blink/public/common/tokens/tokens.h"
+#include "ui/gfx/geometry/rect.h"
class GURL;
@@ -24,6 +26,8 @@ class ProcessNode;
class RenderFrameHostProxy;
class WorkerNode;
+using execution_context_priority::PriorityAndReason;
+
// Frame nodes form a tree structure, each FrameNode at most has one parent that
// is a FrameNode. Conceptually, a frame corresponds to a
// content::RenderFrameHost in the browser, and a content::RenderFrameImpl /
@@ -56,12 +60,17 @@ class FrameNode : public Node {
using LifecycleState = mojom::LifecycleState;
using Observer = FrameNodeObserver;
using PageNodeVisitor = base::RepeatingCallback<bool(const PageNode*)>;
- using PriorityAndReason = frame_priority::PriorityAndReason;
class ObserverDefaultImpl;
static const char* kDefaultPriorityReason;
+ enum class Visibility {
+ kUnknown,
+ kVisible,
+ kNotVisible,
+ };
+
FrameNode();
~FrameNode() override;
@@ -173,6 +182,15 @@ class FrameNode : public Node {
// Returns true if the frame is audible, false otherwise.
virtual bool IsAudible() const = 0;
+ // Returns the intersection of this frame with the viewport. This is initially
+ // null on node creation and is initialized during layout when the viewport
+ // intersection is first calculated. May only be called for a child frame.
+ virtual const base::Optional<gfx::Rect>& GetViewportIntersection() const = 0;
+
+ // Returns true if the frame is visible. This value is based on the viewport
+ // intersection of the frame, and the visibility of the page.
+ virtual Visibility GetVisibility() const = 0;
+
// Returns a proxy to the RenderFrameHost associated with this node. The
// proxy may only be dereferenced on the UI thread.
virtual const RenderFrameHostProxy& GetRenderFrameHostProxy() const = 0;
@@ -186,7 +204,6 @@ class FrameNode : public Node {
class FrameNodeObserver {
public:
using InterventionPolicy = mojom::InterventionPolicy;
- using PriorityAndReason = frame_priority::PriorityAndReason;
FrameNodeObserver();
virtual ~FrameNodeObserver();
@@ -240,6 +257,12 @@ class FrameNodeObserver {
// Invoked when the IsAudible property changes.
virtual void OnIsAudibleChanged(const FrameNode* frame_node) = 0;
+ // Invoked when a frame's intersection with the viewport changes
+ virtual void OnViewportIntersectionChanged(const FrameNode* frame_node) = 0;
+
+ // Invoked when the visibility property changes.
+ virtual void OnFrameVisibilityChanged(const FrameNode* frame_node) = 0;
+
// Events with no property changes.
// Invoked when a non-persistent notification has been issued by the frame.
@@ -287,6 +310,8 @@ class FrameNode::ObserverDefaultImpl : public FrameNodeObserver {
const PriorityAndReason& previous_value) override {}
void OnHadFormInteractionChanged(const FrameNode* frame_node) override {}
void OnIsAudibleChanged(const FrameNode* frame_node) override {}
+ void OnViewportIntersectionChanged(const FrameNode* frame_node) override {}
+ void OnFrameVisibilityChanged(const FrameNode* frame_node) override {}
void OnNonPersistentNotificationCreated(
const FrameNode* frame_node) override {}
void OnFirstContentfulPaint(
diff --git a/chromium/components/performance_manager/public/graph/node_data_describer_util.cc b/chromium/components/performance_manager/public/graph/node_data_describer_util.cc
index 4ed238763cc..2a6fb28f434 100644
--- a/chromium/components/performance_manager/public/graph/node_data_describer_util.cc
+++ b/chromium/components/performance_manager/public/graph/node_data_describer_util.cc
@@ -5,6 +5,7 @@
#include "components/performance_manager/public/graph/node_data_describer_util.h"
#include "base/i18n/time_formatting.h"
+#include "base/task/task_traits.h"
namespace performance_manager {
@@ -18,4 +19,20 @@ base::Value TimeDeltaFromNowToValue(base::TimeTicks time_ticks) {
return base::Value(out);
}
+base::Value MaybeNullStringToValue(base::StringPiece str) {
+ if (str.data() == nullptr)
+ return base::Value();
+ return base::Value(str);
+}
+
+base::Value PriorityAndReasonToValue(
+ const execution_context_priority::PriorityAndReason& priority_and_reason) {
+ base::Value priority(base::Value::Type::DICTIONARY);
+ priority.SetStringKey(
+ "priority", base::TaskPriorityToString(priority_and_reason.priority()));
+ priority.SetPath("reason",
+ MaybeNullStringToValue(priority_and_reason.reason()));
+ return priority;
+}
+
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/public/graph/node_data_describer_util.h b/chromium/components/performance_manager/public/graph/node_data_describer_util.h
index 1b0bbe40a61..db16d8e42b2 100644
--- a/chromium/components/performance_manager/public/graph/node_data_describer_util.h
+++ b/chromium/components/performance_manager/public/graph/node_data_describer_util.h
@@ -8,8 +8,10 @@
#include <sstream>
#include <string>
+#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
namespace performance_manager {
@@ -26,6 +28,13 @@ std::string MojoEnumToString(T value) {
// following format: "x hours, y minutes".
base::Value TimeDeltaFromNowToValue(base::TimeTicks time_ticks);
+// Converts a string to a base::Value, where null strings go to a null value
+// instead of an empty string.
+base::Value MaybeNullStringToValue(base::StringPiece str);
+
+base::Value PriorityAndReasonToValue(
+ const execution_context_priority::PriorityAndReason& priority_and_reason);
+
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_UTIL_H_
diff --git a/chromium/components/performance_manager/public/graph/worker_node.h b/chromium/components/performance_manager/public/graph/worker_node.h
index df9c15c070b..095f2a50a29 100644
--- a/chromium/components/performance_manager/public/graph/worker_node.h
+++ b/chromium/components/performance_manager/public/graph/worker_node.h
@@ -10,6 +10,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/util/type_safety/token_type.h"
+#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
#include "components/performance_manager/public/graph/node.h"
#include "third_party/blink/public/common/tokens/tokens.h"
@@ -21,6 +22,8 @@ class WorkerNodeObserver;
class FrameNode;
class ProcessNode;
+using execution_context_priority::PriorityAndReason;
+
// Represents a running instance of a WorkerGlobalScope.
// See https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope.
//
@@ -94,6 +97,10 @@ class WorkerNode : public Node {
// it handles network requests.
virtual const base::flat_set<const WorkerNode*> GetChildWorkers() const = 0;
+ // Returns the current priority of the worker, and the reason for the worker
+ // having that particular priority.
+ virtual const PriorityAndReason& GetPriorityAndReason() const = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(WorkerNode);
};
@@ -137,6 +144,11 @@ class WorkerNodeObserver {
const WorkerNode* worker_node,
const WorkerNode* client_worker_node) = 0;
+ // Invoked when the worker priority and reason changes.
+ virtual void OnPriorityAndReasonChanged(
+ const WorkerNode* worker_node,
+ const PriorityAndReason& previous_value) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(WorkerNodeObserver);
};
@@ -165,6 +177,9 @@ class WorkerNode::ObserverDefaultImpl : public WorkerNodeObserver {
void OnBeforeClientWorkerRemoved(
const WorkerNode* worker_node,
const WorkerNode* client_worker_node) override {}
+ void OnPriorityAndReasonChanged(
+ const WorkerNode* worker_node,
+ const PriorityAndReason& previous_value) override {}
private:
DISALLOW_COPY_AND_ASSIGN(ObserverDefaultImpl);
diff --git a/chromium/components/performance_manager/public/mojom/BUILD.gn b/chromium/components/performance_manager/public/mojom/BUILD.gn
index 43c1d3f78b7..e2e946082ce 100644
--- a/chromium/components/performance_manager/public/mojom/BUILD.gn
+++ b/chromium/components/performance_manager/public/mojom/BUILD.gn
@@ -5,7 +5,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom_component("mojom") {
- output_prefix = "performace_manager_public_mojom"
+ output_prefix = "performance_manager_public_mojom"
macro_prefix = "PERFORMANCE_MANAGER_PUBLIC_MOJOM"
cpp_only = true
@@ -13,7 +13,13 @@ mojom_component("mojom") {
sources = [
"coordination_unit.mojom",
"lifecycle.mojom",
+ "v8_contexts.mojom",
+ "web_memory.mojom",
]
- public_deps = [ "//mojo/public/mojom/base" ]
+ public_deps = [
+ "//mojo/public/mojom/base",
+ "//third_party/blink/public/mojom/tokens",
+ "//ui/gfx/geometry/mojom",
+ ]
}
diff --git a/chromium/components/performance_manager/public/mojom/coordination_unit.mojom b/chromium/components/performance_manager/public/mojom/coordination_unit.mojom
index 240f02dcb69..212c4c22e17 100644
--- a/chromium/components/performance_manager/public/mojom/coordination_unit.mojom
+++ b/chromium/components/performance_manager/public/mojom/coordination_unit.mojom
@@ -7,6 +7,10 @@ module performance_manager.mojom;
import "mojo/public/mojom/base/process_id.mojom";
import "mojo/public/mojom/base/time.mojom";
import "components/performance_manager/public/mojom/lifecycle.mojom";
+import "components/performance_manager/public/mojom/web_memory.mojom";
+import "components/performance_manager/public/mojom/v8_contexts.mojom";
+import "third_party/blink/public/mojom/tokens/tokens.mojom";
+import "ui/gfx/geometry/mojom/geometry.mojom";
// Any new type here needs to be mirrored between coordination_unit_types.h and
// coordination_unit.mojom, and have mappings between the two defined in
@@ -37,6 +41,7 @@ interface DocumentCoordinationUnit {
SetNetworkAlmostIdle();
SetLifecycleState(LifecycleState state);
SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
+
// Called the first time a form in this document is interacted with.
SetHadFormInteraction();
@@ -48,6 +53,11 @@ interface DocumentCoordinationUnit {
SetIsAdFrame();
+ // Called when the intersection between this frame and the viewport changes.
+ // The viewport is the rectangular area of the top-level document that is
+ // visible. This is used to drive the frame prioritization logic.
+ SetViewportIntersection(gfx.mojom.Rect viewport_intersection);
+
// Event signals.
// Called when the associated frame has caused a non-persistent notification
@@ -61,9 +71,46 @@ interface DocumentCoordinationUnit {
// or if the content is even visible. It will fire at most once for a given
// frame. It will only fire for main-frame nodes.
OnFirstContentfulPaint(mojo_base.mojom.TimeDelta time_since_navigation_start);
+
+ // Invoked when JS in the renderer requests a memory measurement via
+ // the performance.measureMemory API.
+ OnWebMemoryMeasurementRequested(WebMemoryMeasurement.Mode mode) =>
+ (WebMemoryMeasurement measurement);
};
interface ProcessCoordinationUnit {
// Property signals.
SetMainThreadTaskLoadIsLow(bool main_thread_task_load_is_low);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // V8 context tracking.
+
+ // Notifies the browser of a V8Context being created in a renderer
+ // process. If the context is associated with an ExecutionContext (EC) then
+ // |description.execution_context_token| will be provided. If the EC is a
+ // frame, and the parent of that frame is also in the same process, then
+ // |iframe_attribution_data| will be provided, otherwise these will be empty.
+ // See the V8ContextWorldType enum for a description of the relationship
+ // between world types, world names and execution contexts (in
+ // v8_contexts.mojom).
+ OnV8ContextCreated(V8ContextDescription description,
+ IframeAttributionData? iframe_attribution_data);
+
+ // Notifies the browser that a V8Context is now detached from its associated
+ // ExecutionContext (if one was provided during OnV8ContextCreated). If the
+ // context stays detached for a long time this is indicative of a Javascript
+ // leak, with the context being kept alive by a stray reference from another
+ // context. All ExecutionContext-associated V8Contexts will have this method
+ // called before they are destroyed, and it will not be called for other
+ // V8Contexts (they are never considered detached). It is possible that this
+ // is never called for contexts in a renderer processes that crashes or is
+ // otherwise terminated.
+ OnV8ContextDetached(blink.mojom.V8ContextToken v8_context_token);
+
+ // Notifies the browser that a V8Context has been garbage collected. This will
+ // only be called after OnV8ContextDetached if the OnV8ContextCreated had a
+ // non-empty |description.execution_context_token|. It is possible that this
+ // is never called for contexts in a renderer processes that crashes or is
+ // otherwise terminated.
+ OnV8ContextDestroyed(blink.mojom.V8ContextToken v8_context_token);
};
diff --git a/chromium/components/performance_manager/public/mojom/v8_contexts.mojom b/chromium/components/performance_manager/public/mojom/v8_contexts.mojom
new file mode 100644
index 00000000000..7e8faf54025
--- /dev/null
+++ b/chromium/components/performance_manager/public/mojom/v8_contexts.mojom
@@ -0,0 +1,57 @@
+// Copyright 2020 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.
+
+module performance_manager.mojom;
+
+import "third_party/blink/public/mojom/tokens/tokens.mojom";
+
+// Stores information about an iframe element from the point of view of the
+// document that hosts the iframe. This is used for purely informational
+// purposes in the performance.measureMemory API to identify an iframe in memory
+// usage reports.
+struct IframeAttributionData {
+ // The value of the "id" attribute associated with the iframe element.
+ string? id;
+ // The value of the "src" attribute associated with the iframe element. We
+ // don't use an URL because we don't need to parse this, or otherwise use
+ // it as an URL, and URL objects have a large memory footprint.
+ string? src;
+};
+
+// Identifies a V8Context type. Note that this roughly corresponds to the
+// world types defined in blink, but with some simplifications.
+enum V8ContextWorldType {
+ // The main world, corresponding to a frame / document.
+ kMain,
+ // Corresponds to the main world of a worker or worklet.
+ kWorkerOrWorklet,
+ // Corresponds to an extension. Will have a stable extension ID.
+ kExtension,
+ // Corresponds to a non-extension isolated world. Will have a human readable
+ // name.
+ kIsolated,
+ // Corresponds to the devtools inspector. Will not have a human readable
+ // name or a stable id.
+ kInspector,
+ // Corresponds to the regexp world. This world is unique in that it is per
+ // v8::Isolate, and not associated with any individual execution context.
+ // Will not have a human-readable name or stable id.
+ kRegExp,
+};
+
+// Information describing a V8 Context. A context is a unit of accounting for
+// resource usage, and corresponds to a "world" in Blink parlance.
+struct V8ContextDescription {
+ // The unique token that names the world.
+ blink.mojom.V8ContextToken token;
+ // The type of this world.
+ V8ContextWorldType world_type;
+ // Identifies this world. Only set for extension and isolated worlds. For
+ // extension worlds this corresponds to the stable extension ID. For other
+ // isolated worlds this is a human-readable description.
+ string? world_name;
+ // The identity of the execution context that this V8Context is associated
+ // with. This is specified for all world types, except kRegExp worlds.
+ blink.mojom.ExecutionContextToken? execution_context_token;
+}; \ No newline at end of file
diff --git a/chromium/components/performance_manager/public/mojom/web_memory.mojom b/chromium/components/performance_manager/public/mojom/web_memory.mojom
new file mode 100644
index 00000000000..0a753be2e05
--- /dev/null
+++ b/chromium/components/performance_manager/public/mojom/web_memory.mojom
@@ -0,0 +1,65 @@
+// Copyright 2020 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.
+
+module performance_manager.mojom;
+
+// All WebMemory* structs below are used for reporting the memory usage of the
+// page via the performance.measureMemory Web API. These structs roughly follow
+// the structs defined by the specification of the API:
+// https://wicg.github.io/performance-measure-memory/
+//
+// The renderer process invokes the OnWebMemoryMeasurementRequested method of
+// DocumentCoordinationUnit from coordination_unit.mojom to send a memory
+// measurement request to the browser process. The result of the measurement
+// is provided in WebMemoryMeasurement, which attributes the memory usage of
+// the page to ExecutionContexts (iframes and workers).
+//
+// The main invariant is that only the following ExecutionContexts can ever
+// appear in the result:
+// - same-origin contexts, i.e. those that have the same origin as the context
+// that called the MeasureMemory function.
+// - cross-origin contexts with same-origin parent contexts, i.e. iframes that
+// are *immediately* embedded in a same-origin context.
+//
+// The invariant is important to ensure that cross-origin contexts embedded
+// in other cross-origin contexts are not observable to the calling origin.
+
+// Information about ExecutionContext reported in the memory usage breakdown.
+struct WebMemoryAttribution {
+ // Specifies the scope (or type) of the context.
+ // The invariant mentioned above ensures that cross-origin contexts have
+ // type kWindow corresponding to iframes and that information is already
+ // known to the calling origin because it created the iframe.
+ enum Scope {
+ kWindow,
+ // TODO(1085129): Add worker scopes once they are implemented.
+ };
+ Scope scope;
+ // The current URL of the context. It is null for cross-origin contexts.
+ string? url;
+
+ // TODO(1085129): Add src and id fields once they are implemented.
+};
+
+// Describes a memory region and attributes it to a set of contexts.
+// Usually the set consists of a single context. If there are multiple
+// contexts then this means that the memory may be owned by any of them.
+struct WebMemoryBreakdownEntry {
+ uint64 bytes;
+ array<WebMemoryAttribution> attribution;
+
+ // TODO(1085129): Add memory types once they are implemented.
+};
+
+// The result of the MeasureMemory function.
+struct WebMemoryMeasurement {
+ // By default a memory measurement may be performed after some delay because
+ // it is folded into the next garbage collection. The eager mode is used for
+ // testing to force the measurement right away.
+ enum Mode {
+ kDefault,
+ kEager
+ };
+ array<WebMemoryBreakdownEntry> breakdown;
+};
diff --git a/chromium/components/performance_manager/public/performance_manager.h b/chromium/components/performance_manager/public/performance_manager.h
index 0ea87f8c671..c147cbefe2a 100644
--- a/chromium/components/performance_manager/public/performance_manager.h
+++ b/chromium/components/performance_manager/public/performance_manager.h
@@ -12,9 +12,11 @@
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
+#include "components/performance_manager/public/render_process_host_id.h"
namespace content {
class RenderFrameHost;
+class RenderProcessHost;
class WebContents;
}
@@ -24,6 +26,7 @@ class FrameNode;
class Graph;
class GraphOwned;
class PageNode;
+class ProcessNode;
class PerformanceManagerMainThreadMechanism;
class PerformanceManagerMainThreadObserver;
class PerformanceManagerOwned;
@@ -76,13 +79,34 @@ class PerformanceManager {
static base::WeakPtr<PageNode> GetPageNodeForWebContents(
content::WebContents* wc);
- // Returns a WeakPtr to the FrameNode associated with a given RenderFrameHost,
- // or a null WeakPtr if there's no FrameNode for this RFH. Valid to call from
- // the main thread only, the returned WeakPtr should only be dereferenced on
- // the PM sequence (e.g. it can be used in a CallOnGraph callback).
+ // Returns a WeakPtr to the FrameNode associated with a given
+ // RenderFrameHost, or a null WeakPtr if there's no FrameNode for this RFH.
+ // (There is a brief window after the RFH is created before the FrameNode is
+ // added.) Valid to call from the main thread only, the returned WeakPtr
+ // should only be dereferenced on the PM sequence (e.g. it can be used in a
+ // CallOnGraph callback).
static base::WeakPtr<FrameNode> GetFrameNodeForRenderFrameHost(
content::RenderFrameHost* rfh);
+ // Returns a WeakPtr to the ProcessNode associated with a given
+ // RenderProcessHost, or a null WeakPtr if there's no ProcessNode for this
+ // RPH. (There is a brief window after the RPH is created before the
+ // ProcessNode is added.) Valid to call from the main thread only, the
+ // returned WeakPtr should only be dereferenced on the PM sequence (e.g. it
+ // can be used in a CallOnGraph callback).
+ static base::WeakPtr<ProcessNode> GetProcessNodeForRenderProcessHost(
+ content::RenderProcessHost* rph);
+
+ // Returns a WeakPtr to the ProcessNode associated with a given
+ // RenderProcessHostId (which must be valid), or a null WeakPtr if there's no
+ // ProcessNode for this ID. (There may be no RenderProcessHost for this ID,
+ // or it may be during a brief window after the RPH is created but before the
+ // ProcessNode is added.) Valid to call from the main thread only, the
+ // returned WeakPtr should only be dereferenced on the PM sequence (e.g. it
+ // can be used in a CallOnGraph callback).
+ static base::WeakPtr<ProcessNode> GetProcessNodeForRenderProcessHostId(
+ RenderProcessHostId id);
+
// Adds / removes an observer that is notified of PerformanceManager events
// that happen on the main thread. Can only be called on the main thread.
static void AddObserver(PerformanceManagerMainThreadObserver* observer);
diff --git a/chromium/components/performance_manager/public/render_process_host_id.h b/chromium/components/performance_manager/public/render_process_host_id.h
index 8a2f0a8a08f..45152939857 100644
--- a/chromium/components/performance_manager/public/render_process_host_id.h
+++ b/chromium/components/performance_manager/public/render_process_host_id.h
@@ -6,11 +6,33 @@
#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_RENDER_PROCESS_HOST_ID_H_
#include "base/util/type_safety/id_type.h"
+#include "content/public/common/child_process_host.h"
namespace performance_manager {
+using RenderProcessHostIdBase =
+ util::IdType<class RenderProcessHostIdTag,
+ int32_t,
+ content::ChildProcessHost::kInvalidUniqueID,
+ 1>;
+
// A strongly typed wrapper for the id returned by RenderProcessHost::GetID().
-using RenderProcessHostId = util::IdType32<class RenderProcessHostIdTag>;
+//
+// This uses ChildProcessHost::kInvalidUniqueId (-1) as the default invalid id,
+// but also recognizes 0 as an invalid id because there is existing code that
+// uses 0 as an invalid value. It starts generating id's at 1.
+class RenderProcessHostId : public RenderProcessHostIdBase {
+ public:
+ using RenderProcessHostIdBase::RenderProcessHostIdBase;
+
+ // 0 is also an invalid value.
+ constexpr bool is_null() const {
+ return RenderProcessHostIdBase::is_null() || this->value() == 0;
+ }
+
+ // Override operator bool() to call the overridden is_null().
+ constexpr explicit operator bool() const { return !is_null(); }
+};
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h b/chromium/components/performance_manager/public/v8_memory/v8_detailed_memory.h
index 98d4dc6cef9..303645032bd 100644
--- a/chromium/components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h
+++ b/chromium/components/performance_manager/public/v8_memory/v8_detailed_memory.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 COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_PER_FRAME_MEMORY_DECORATOR_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_PER_FRAME_MEMORY_DECORATOR_H_
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_
#include <vector>
@@ -11,8 +11,10 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
+#include "base/threading/sequence_bound.h"
#include "base/time/time.h"
#include "base/util/type_safety/pass_key.h"
#include "components/performance_manager/public/graph/frame_node.h"
@@ -31,99 +33,47 @@ namespace v8_memory {
// A decorator that queries each renderer process for the amount of memory used
// by V8 in each frame.
//
-// To start sampling create a V8PerFrameMemoryRequest object that specifies how
+// To start sampling create a V8DetailedMemoryRequest object that specifies how
// often to request a memory measurement. Delete the object when you no longer
// need measurements. Measurement involves some overhead so choose the lowest
// sampling frequency your use case needs. The decorator will use the highest
// sampling frequency that any caller requests, and stop measurements entirely
-// when no more V8PerFrameMemoryRequest objects exist.
+// when no more V8DetailedMemoryRequest objects exist.
//
// When measurements are available the decorator attaches them to
-// V8PerFrameMemoryFrameData and V8PerFrameMemoryProcessData objects that can
-// be retrieved with V8PerFrameMemoryFrameData::ForFrameNode and
-// V8PerFrameMemoryProcessData::ForProcessNode. V8PerFrameMemoryProcessData
-// objects can be cleaned up when V8PerFrameMemoryRequest objects are deleted
+// V8DetailedMemoryFrameData and V8DetailedMemoryProcessData objects that can
+// be retrieved with V8DetailedMemoryFrameData::ForFrameNode and
+// V8DetailedMemoryProcessData::ForProcessNode. V8DetailedMemoryProcessData
+// objects can be cleaned up when V8DetailedMemoryRequest objects are deleted
// so callers must save the measurements they are interested in before
-// releasing their V8PerFrameMemoryRequest.
+// releasing their V8DetailedMemoryRequest.
//
// Callers can be notified when a request is available by implementing
-// V8PerFrameMemoryObserver.
+// V8DetailedMemoryObserver.
//
-// V8PerFrameMemoryRequest, V8PerFrameMemoryFrameData and
-// V8PerFrameMemoryProcessData must all be accessed on the graph sequence, and
-// V8PerFrameMemoryObserver::OnV8MemoryMeasurementAvailable will be called on
+// V8DetailedMemoryRequest, V8DetailedMemoryFrameData and
+// V8DetailedMemoryProcessData must all be accessed on the graph sequence, and
+// V8DetailedMemoryObserver::OnV8MemoryMeasurementAvailable will be called on
// this sequence. To request memory measurements from another sequence use the
-// V8PerFrameMemoryRequestAnySeq and V8PerFrameMemoryObserverAnySeq wrappers.
+// V8DetailedMemoryRequestAnySeq and V8DetailedMemoryObserverAnySeq wrappers.
//
// Usage:
//
-// Take a memory measurement every 30 seconds and poll for updates:
-//
-// class MemoryPoller {
-// public:
-// MemoryPoller() {
-// PerformanceManager::CallOnGraph(FROM_HERE,
-// base::BindOnce(&Start, base::Unretained(this)));
-// }
-//
-// void Start(Graph* graph) {
-// DCHECK_ON_GRAPH_SEQUENCE(graph);
-// request_ = std::make_unique<V8PerFrameMemoryRequest>(
-// base::TimeDelta::FromSeconds(30));
-// request_->StartMeasurement(graph);
-//
-// // Periodically check Process and Frame nodes for the latest results.
-// timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(30),
-// base::BindRepeating(&GetResults, base::Unretained(this),
-// base::Unretained(graph)));
-// }
-//
-// void GetResults(Graph* graph) {
-// DCHECK_ON_GRAPH_SEQUENCE(graph);
-// for (auto* node : graph->GetAllProcessNodes()) {
-// auto* process_data = V8PerFrameMemoryProcessData::ForProcess(node);
-// if (process_data) {
-// LOG(INFO) << "Process " << node->GetProcessId() <<
-// " reported " << process_data->unassociated_v8_bytes_used() <<
-// " bytes of V8 memory that wasn't associated with a frame.";
-// }
-// for (auto* frame_node : node->GetFrameNodes()) {
-// auto* frame_data = V8PerFrameMemoryFrameData::ForFrame(frame_node);
-// if (frame_data) {
-// LOG(INFO) << "Frame " << frame_node->GetFrameToken().value() <<
-// " reported " << frame_data->v8_bytes_used() <<
-// " bytes of V8 memory in its main world.";
-// }
-// }
-// }
-//
-// void Stop(Graph* graph) {
-// DCHECK_ON_GRAPH_SEQUENCE(graph);
-// // Measurements stop when |request_| is deleted.
-// request_.reset();
-// timer_.Stop();
-// }
-//
-// private:
-// std::unique_ptr<V8PerFrameMemoryRequest> request_;
-// base::RepeatingTimer timer_;
-// };
-//
-// Take a memory measurement every 2 minutes and register an observer for the
+// Take a memory measurement every 30 seconds and register an observer for the
// results:
//
-// class Observer : public V8PerFrameMemoryObserver {
+// class Observer : public V8DetailedMemoryObserver {
// public:
// // Called on the PM sequence for each process.
// void OnV8MemoryMeasurementAvailable(
// const ProcessNode* process_node,
-// const V8PerFrameMemoryProcessData* data) override {
+// const V8DetailedMemoryProcessData* data) override {
// DCHECK(data);
// LOG(INFO) << "Process " << process_node->GetProcessId() <<
// " reported " << data->unassociated_v8_bytes_used() <<
// " bytes of V8 memory that wasn't associated with a frame.";
// for (auto* frame_node : process_node->GetFrameNodes()) {
-// auto* frame_data = V8PerFrameMemoryFrameData::ForFrame(frame_node);
+// auto* frame_data = V8DetailedMemoryFrameData::ForFrame(frame_node);
// if (frame_data) {
// LOG(INFO) << "Frame " << frame_node->GetFrameToken().value() <<
// " reported " << frame_data->v8_bytes_used() <<
@@ -143,9 +93,9 @@ namespace v8_memory {
// void Start(Graph* graph) {
// DCHECK_ON_GRAPH_SEQUENCE(graph);
//
-// // Creating a V8PerFrameMemoryRequest with the |graph| parameter
+// // Creating a V8DetailedMemoryRequest with the |graph| parameter
// // automatically starts measurements.
-// request_ = std::make_unique<V8PerFrameMemoryRequest>(
+// request_ = std::make_unique<V8DetailedMemoryRequest>(
// base::TimeDelta::FromSeconds(30), graph);
// observer_ = std::make_unique<Observer>();
// request_->AddObserver(observer_.get());
@@ -164,19 +114,19 @@ namespace v8_memory {
// }
//
// private:
-// std::unique_ptr<V8PerFrameMemoryRequest> request_;
+// std::unique_ptr<V8DetailedMemoryRequest> request_;
// std::unique_ptr<Observer> observer_;
// };
//
// Same, but from the another thread:
//
-// class Observer : public V8PerFrameMemoryObserverAnySeq {
+// class Observer : public V8DetailedMemoryObserverAnySeq {
// public:
// // Called on the same sequence for each process.
// void OnV8MemoryMeasurementAvailable(
// RenderProcessHostId process_id,
-// const V8PerFrameMemoryProcessData& process_data,
-// const V8PerFrameMemoryObserverAnySeq::FrameDataMap& frame_data)
+// const V8DetailedMemoryProcessData& process_data,
+// const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data)
// override {
// const auto* process = RenderProcessHost::FromID(process_id.value());
// if (!process) {
@@ -188,7 +138,7 @@ namespace v8_memory {
// " bytes of V8 memory that wasn't associated with a frame.";
// for (std::pair<
// content::GlobalFrameRoutingId,
-// V8PerFrameMemoryFrameData
+// V8DetailedMemoryFrameData
// > frame_and_data : frame_data) {
// const auto* frame = RenderFrameHost::FromID(frame_and_data.first);
// if (!frame) {
@@ -211,9 +161,9 @@ namespace v8_memory {
// void Start() {
// DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
//
-// // Creating a V8PerFrameMemoryRequest with the |graph| parameter
+// // Creating a V8DetailedMemoryRequest with the |graph| parameter
// // automatically starts measurements.
-// request_ = std::make_unique<V8PerFrameMemoryRequestAnySeq>(
+// request_ = std::make_unique<V8DetailedMemoryRequestAnySeq>(
// base::TimeDelta::FromMinutes(2));
// observer_ = std::make_unique<Observer>();
// request_->AddObserver(observer_.get());
@@ -232,19 +182,22 @@ namespace v8_memory {
// }
//
// private:
-// std::unique_ptr<V8PerFrameMemoryRequestAnySeq> request_;
+// std::unique_ptr<V8DetailedMemoryRequestAnySeq> request_;
// std::unique_ptr<Observer> observer_;
//
// SEQUENCE_CHECKER(sequence_checker_);
// };
-class V8PerFrameMemoryObserver;
-class V8PerFrameMemoryRequest;
-class V8PerFrameMemoryRequestAnySeq;
+class V8DetailedMemoryObserver;
+class V8DetailedMemoryProcessData;
+class V8DetailedMemoryRequest;
+class V8DetailedMemoryRequestAnySeq;
+class V8DetailedMemoryRequestOneShot;
+class V8DetailedMemoryRequestOneShotAnySeq;
-class V8PerFrameMemoryDecorator
+class V8DetailedMemoryDecorator
: public GraphOwned,
- public GraphRegisteredImpl<V8PerFrameMemoryDecorator>,
+ public GraphRegisteredImpl<V8DetailedMemoryDecorator>,
public ProcessNode::ObserverDefaultImpl,
public NodeDataDescriberDefaultImpl {
public:
@@ -253,11 +206,11 @@ class V8PerFrameMemoryDecorator
// have a queue of requests that measure only that process.
class MeasurementRequestQueue;
- V8PerFrameMemoryDecorator();
- ~V8PerFrameMemoryDecorator() override;
+ V8DetailedMemoryDecorator();
+ ~V8DetailedMemoryDecorator() override;
- V8PerFrameMemoryDecorator(const V8PerFrameMemoryDecorator&) = delete;
- V8PerFrameMemoryDecorator& operator=(const V8PerFrameMemoryDecorator&) =
+ V8DetailedMemoryDecorator(const V8DetailedMemoryDecorator&) = delete;
+ V8DetailedMemoryDecorator& operator=(const V8DetailedMemoryDecorator&) =
delete;
// GraphOwned implementation.
@@ -273,22 +226,22 @@ class V8PerFrameMemoryDecorator
base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
// Returns the next measurement request that should be scheduled.
- const V8PerFrameMemoryRequest* GetNextRequest() const;
+ const V8DetailedMemoryRequest* GetNextRequest() const;
// Returns the next measurement request with mode kBounded or
// kEagerForTesting that should be scheduled.
- const V8PerFrameMemoryRequest* GetNextBoundedRequest() const;
+ const V8DetailedMemoryRequest* GetNextBoundedRequest() const;
// Implementation details below this point.
- // V8PerFrameMemoryRequest objects register themselves with the decorator.
- // If |process_node| is null, the request will be sent to every process,
- // otherwise it will be sent only to |process_node|.
- void AddMeasurementRequest(util::PassKey<V8PerFrameMemoryRequest>,
- V8PerFrameMemoryRequest* request,
+ // V8DetailedMemoryRequest objects register themselves with the decorator.
+ // If |process_node| is null, the request will be sent to every renderer
+ // process, otherwise it will be sent only to |process_node|.
+ void AddMeasurementRequest(util::PassKey<V8DetailedMemoryRequest>,
+ V8DetailedMemoryRequest* request,
const ProcessNode* process_node = nullptr);
- void RemoveMeasurementRequest(util::PassKey<V8PerFrameMemoryRequest>,
- V8PerFrameMemoryRequest* request);
+ void RemoveMeasurementRequest(util::PassKey<V8DetailedMemoryRequest>,
+ V8DetailedMemoryRequest* request);
// Internal helper class that can call NotifyObserversOnMeasurementAvailable
// when a measurement is received.
@@ -314,7 +267,85 @@ class V8PerFrameMemoryDecorator
SEQUENCE_CHECKER(sequence_checker_);
};
-class V8PerFrameMemoryRequest {
+//////////////////////////////////////////////////////////////////////////////
+// The following classes report results from memory measurements.
+
+class V8DetailedMemoryFrameData {
+ public:
+ V8DetailedMemoryFrameData() = default;
+ virtual ~V8DetailedMemoryFrameData() = default;
+
+ bool operator==(const V8DetailedMemoryFrameData& other) const {
+ return v8_bytes_used_ == other.v8_bytes_used_;
+ }
+
+ // Returns the number of bytes used by V8 for this frame at the last
+ // measurement.
+ uint64_t v8_bytes_used() const { return v8_bytes_used_; }
+
+ void set_v8_bytes_used(uint64_t v8_bytes_used) {
+ v8_bytes_used_ = v8_bytes_used;
+ }
+
+ // Returns frame data for the given node, or nullptr if no measurement has
+ // been taken. The returned pointer must only be accessed on the graph
+ // sequence and may go invalid at any time after leaving the calling scope.
+ static const V8DetailedMemoryFrameData* ForFrameNode(const FrameNode* node);
+
+ private:
+ friend class WebMemoryAggregatorTest;
+ // Creates frame data for the given node.
+ static V8DetailedMemoryFrameData* CreateForTesting(const FrameNode* node);
+
+ uint64_t v8_bytes_used_ = 0;
+};
+
+class V8DetailedMemoryProcessData {
+ public:
+ V8DetailedMemoryProcessData() = default;
+ virtual ~V8DetailedMemoryProcessData() = default;
+
+ bool operator==(const V8DetailedMemoryProcessData& other) const {
+ return unassociated_v8_bytes_used_ == other.unassociated_v8_bytes_used_;
+ }
+
+ // Returns the number of bytes used by V8 at the last measurement in this
+ // process that could not be attributed to a frame.
+ uint64_t unassociated_v8_bytes_used() const {
+ return unassociated_v8_bytes_used_;
+ }
+
+ void set_unassociated_v8_bytes_used(uint64_t unassociated_v8_bytes_used) {
+ unassociated_v8_bytes_used_ = unassociated_v8_bytes_used;
+ }
+
+ // Returns process data for the given node, or nullptr if no measurement has
+ // been taken. The returned pointer must only be accessed on the graph
+ // sequence and may go invalid at any time after leaving the calling scope.
+ static const V8DetailedMemoryProcessData* ForProcessNode(
+ const ProcessNode* node);
+
+ private:
+ uint64_t unassociated_v8_bytes_used_ = 0;
+};
+
+class V8DetailedMemoryObserver : public base::CheckedObserver {
+ public:
+ // Called on the PM sequence when a measurement is available for
+ // |process_node|. |process_data| contains the process-level measurements for
+ // the process, and can go invalid at any time after returning from this
+ // method. Per-frame measurements can be read by walking the graph from
+ // |process_node| to find frame nodes, and calling
+ // V8DetailedMemoryFrameData::ForFrameNode to retrieve the measurement data.
+ virtual void OnV8MemoryMeasurementAvailable(
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) = 0;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// The following classes create requests for memory measurements.
+
+class V8DetailedMemoryRequest {
public:
enum class MeasurementMode {
// Measurements will be taken at the next GC after a request is received.
@@ -342,25 +373,25 @@ class V8PerFrameMemoryRequest {
// each repetition. The next GC after each request is received will be
// instrumented, which adds some overhead. |mode| determines whether extra
// GC's can be scheduled, which would add even more overhead.
- explicit V8PerFrameMemoryRequest(
+ explicit V8DetailedMemoryRequest(
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode = MeasurementMode::kDefault);
// Creates a request and calls StartMeasurement with the given |graph| and
// |min_time_between_requests|, using the default measurement mode.
- V8PerFrameMemoryRequest(const base::TimeDelta& min_time_between_requests,
+ V8DetailedMemoryRequest(const base::TimeDelta& min_time_between_requests,
Graph* graph);
// Creates a request and calls StartMeasurement with the given |graph|,
// |min_time_between_requests|, and |mode|.
- V8PerFrameMemoryRequest(const base::TimeDelta& min_time_between_requests,
+ V8DetailedMemoryRequest(const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
Graph* graph);
- ~V8PerFrameMemoryRequest();
+ ~V8DetailedMemoryRequest();
- V8PerFrameMemoryRequest(const V8PerFrameMemoryRequest&) = delete;
- V8PerFrameMemoryRequest& operator=(const V8PerFrameMemoryRequest&) = delete;
+ V8DetailedMemoryRequest(const V8DetailedMemoryRequest&) = delete;
+ V8DetailedMemoryRequest& operator=(const V8DetailedMemoryRequest&) = delete;
const base::TimeDelta& min_time_between_requests() const {
return min_time_between_requests_;
@@ -370,138 +401,172 @@ class V8PerFrameMemoryRequest {
// Requests measurements for all ProcessNode's in |graph|. There must be at
// most one call to this or StartMeasurementForProcess for each
- // V8PerFrameMemoryRequest.
+ // V8DetailedMemoryRequest.
void StartMeasurement(Graph* graph);
// Requests measurements only for the given |process_node|, which must be a
// renderer process. There must be at most one call to this or
- // StartMeasurement for each V8PerFrameMemoryRequest.
+ // StartMeasurement for each V8DetailedMemoryRequest.
void StartMeasurementForProcess(const ProcessNode* process_node);
// Adds/removes an observer.
- void AddObserver(V8PerFrameMemoryObserver* observer);
- void RemoveObserver(V8PerFrameMemoryObserver* observer);
+ void AddObserver(V8DetailedMemoryObserver* observer);
+ void RemoveObserver(V8DetailedMemoryObserver* observer);
// Implementation details below this point.
- // Private constructor for V8PerFrameMemoryRequestAnySeq. Saves
+ // Private constructor for V8DetailedMemoryRequestAnySeq. Saves
// |off_sequence_request| as a pointer to the off-sequence object that
// triggered the request and starts measurements with frequency
- // |min_time_between_requests|.
- V8PerFrameMemoryRequest(
- util::PassKey<V8PerFrameMemoryRequestAnySeq>,
+ // |min_time_between_requests|. If |process_to_measure| is nullopt, the
+ // request will be sent to every renderer process, otherwise it will be sent
+ // only to |process_to_measure|.
+ V8DetailedMemoryRequest(
+ util::PassKey<V8DetailedMemoryRequestAnySeq>,
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
- base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request);
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure,
+ base::WeakPtr<V8DetailedMemoryRequestAnySeq> off_sequence_request);
+
+ // Private constructor for V8DetailedMemoryRequestOneShot. Sets
+ // min_time_between_requests_ to 0, which is not allowed for repeating
+ // requests, and registers |on_owner_unregistered_closure| to be called from
+ // OnOwnerUnregistered.
+ V8DetailedMemoryRequest(util::PassKey<V8DetailedMemoryRequestOneShot>,
+ MeasurementMode mode,
+ base::OnceClosure on_owner_unregistered_closure);
- // V8PerFrameMemoryDecorator::MeasurementRequestQueue calls
+ // V8DetailedMemoryDecorator::MeasurementRequestQueue calls
// OnOwnerUnregistered for all requests in the queue when the owning
// decorator or process node is removed from the graph.
void OnOwnerUnregistered(
- util::PassKey<V8PerFrameMemoryDecorator::MeasurementRequestQueue>);
+ util::PassKey<V8DetailedMemoryDecorator::MeasurementRequestQueue>);
- // V8PerFrameMemoryDecorator::MeasurementRequestQueue calls
+ // V8DetailedMemoryDecorator::MeasurementRequestQueue calls
// NotifyObserversOnMeasurementAvailable when a measurement is received.
void NotifyObserversOnMeasurementAvailable(
- util::PassKey<V8PerFrameMemoryDecorator::MeasurementRequestQueue>,
+ util::PassKey<V8DetailedMemoryDecorator::MeasurementRequestQueue>,
const ProcessNode* process_node) const;
private:
+ void StartMeasurementFromOffSequence(
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure,
+ Graph* graph);
void StartMeasurementImpl(Graph* graph, const ProcessNode* process_node);
base::TimeDelta min_time_between_requests_;
MeasurementMode mode_;
- V8PerFrameMemoryDecorator* decorator_ = nullptr;
- base::ObserverList<V8PerFrameMemoryObserver, /*check_empty=*/true> observers_;
+ V8DetailedMemoryDecorator* decorator_ = nullptr;
+ base::ObserverList<V8DetailedMemoryObserver, /*check_empty=*/true> observers_;
- // Pointer back to the off-sequence V8PerFrameMemoryRequestAnySeq that
+ // Pointer back to the off-sequence V8DetailedMemoryRequestAnySeq that
// created this, if any.
- base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request_;
+ base::WeakPtr<V8DetailedMemoryRequestAnySeq> off_sequence_request_;
// Sequence that |off_sequence_request_| lives on.
scoped_refptr<base::SequencedTaskRunner> off_sequence_request_sequence_;
+ // Additional closure that will be called from OnOwnerUnregistered for
+ // one-shot requests. Used to clean up resources in the
+ // V8DetailedMemoryRequestOneShot wrapper.
+ base::OnceClosure on_owner_unregistered_closure_;
+
SEQUENCE_CHECKER(sequence_checker_);
};
-class V8PerFrameMemoryFrameData {
+class V8DetailedMemoryRequestOneShot final : public V8DetailedMemoryObserver {
public:
- V8PerFrameMemoryFrameData() = default;
- virtual ~V8PerFrameMemoryFrameData() = default;
+ // A callback that will be passed the results of the measurement. |process|
+ // will always match the value passed to the V8DetailedMemoryRequestOneShot
+ // constructor.
+ using MeasurementCallback =
+ base::OnceCallback<void(const ProcessNode* process,
+ const V8DetailedMemoryProcessData* process_data)>;
+
+ using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
+
+ // Creates a one-shot memory measurement request that will be sent when
+ // StartMeasurement is called.
+ explicit V8DetailedMemoryRequestOneShot(
+ MeasurementMode mode = MeasurementMode::kDefault);
- bool operator==(const V8PerFrameMemoryFrameData& other) const {
- return v8_bytes_used_ == other.v8_bytes_used_;
- }
+ // Creates a one-shot memory measurement request and calls StartMeasurement.
+ V8DetailedMemoryRequestOneShot(
+ const ProcessNode* process,
+ MeasurementCallback callback,
+ MeasurementMode mode = MeasurementMode::kDefault);
- // Returns the number of bytes used by V8 for this frame at the last
- // measurement.
- uint64_t v8_bytes_used() const { return v8_bytes_used_; }
+ ~V8DetailedMemoryRequestOneShot() final;
- void set_v8_bytes_used(uint64_t v8_bytes_used) {
- v8_bytes_used_ = v8_bytes_used;
- }
-
- // Returns frame data for the given node, or nullptr if no measurement has
- // been taken. The returned pointer must only be accessed on the graph
- // sequence and may go invalid at any time after leaving the calling scope.
- static const V8PerFrameMemoryFrameData* ForFrameNode(const FrameNode* node);
+ V8DetailedMemoryRequestOneShot(const V8DetailedMemoryRequestOneShot&) =
+ delete;
+ V8DetailedMemoryRequestOneShot& operator=(
+ const V8DetailedMemoryRequestOneShot&) = delete;
- private:
- uint64_t v8_bytes_used_ = 0;
-};
+ // Sends the measurement request to |process| (which must be a renderer
+ // process). The process will perform the measurement during a GC as
+ // determined by the MeasurementMode, and |callback| will be called with the
+ // results.
+ //
+ // |callback| is owned by the request object but will be destroyed after it
+ // is called or once no response can be received (such as if the ProcessNode
+ // is destroyed). It is safe for the callback to own resources that will be
+ // freed when the callback is destroyed. It is even safe for the callback to
+ // own |this|, making the V8DetailedMemoryRequestOneShot self-owning (it will
+ // be deleted along with the callback).
+ void StartMeasurement(const ProcessNode* process,
+ MeasurementCallback callback);
-class V8PerFrameMemoryProcessData {
- public:
- V8PerFrameMemoryProcessData() = default;
- virtual ~V8PerFrameMemoryProcessData() = default;
+ MeasurementMode mode() const { return mode_; }
- bool operator==(const V8PerFrameMemoryProcessData& other) const {
- return unassociated_v8_bytes_used_ == other.unassociated_v8_bytes_used_;
- }
+ // V8DetailedMemoryObserver implementation.
- // Returns the number of bytes used by V8 at the last measurement in this
- // process that could not be attributed to a frame.
- uint64_t unassociated_v8_bytes_used() const {
- return unassociated_v8_bytes_used_;
- }
+ void OnV8MemoryMeasurementAvailable(
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) final;
- void set_unassociated_v8_bytes_used(uint64_t unassociated_v8_bytes_used) {
- unassociated_v8_bytes_used_ = unassociated_v8_bytes_used;
- }
+ // Implementation details below this point.
- // Returns process data for the given node, or nullptr if no measurement has
- // been taken. The returned pointer must only be accessed on the graph
- // sequence and may go invalid at any time after leaving the calling scope.
- static const V8PerFrameMemoryProcessData* ForProcessNode(
- const ProcessNode* node);
+ // Private constructor for V8DetailedMemoryRequestOneShotAnySeq. Will be
+ // called from off-sequence.
+ V8DetailedMemoryRequestOneShot(
+ util::PassKey<V8DetailedMemoryRequestOneShotAnySeq>,
+ base::WeakPtr<ProcessNode> process,
+ MeasurementCallback callback,
+ MeasurementMode mode = MeasurementMode::kDefault);
private:
- uint64_t unassociated_v8_bytes_used_ = 0;
-};
+ void InitializeRequest();
+ void StartMeasurementFromOffSequence(base::WeakPtr<ProcessNode>,
+ MeasurementCallback callback);
+ void DeleteRequest();
+ void OnOwnerUnregistered();
-class V8PerFrameMemoryObserver : public base::CheckedObserver {
- public:
- // Called on the PM sequence when a measurement is available for
- // |process_node|. |process_data| contains the process-level measurements for
- // the process, and can go invalid at any time after returning from this
- // method. Per-frame measurements can be read by walking the graph from
- // |process_node| to find frame nodes, and calling
- // V8PerFrameMemoryFrameData::ForFrameNode to retrieve the measurement data.
- virtual void OnV8MemoryMeasurementAvailable(
- const ProcessNode* process_node,
- const V8PerFrameMemoryProcessData* process_data) = 0;
+#if DCHECK_IS_ON()
+ const ProcessNode* process_;
+#endif
+
+ MeasurementCallback callback_;
+ MeasurementMode mode_;
+ std::unique_ptr<V8DetailedMemoryRequest> request_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
};
+//////////////////////////////////////////////////////////////////////////////
+// The following classes are wrappers that can be called from outside the PM
+// sequence.
+
// Observer that can be created on any sequence, and will be notified on that
// sequence when measurements are available. Register the observer through
-// V8PerFrameMemoryRequestAnySeq::AddObserver. The
-// V8PerFrameMemoryRequestAnySeq must live on the same sequence as the
+// V8DetailedMemoryRequestAnySeq::AddObserver. The
+// V8DetailedMemoryRequestAnySeq must live on the same sequence as the
// observer.
-class V8PerFrameMemoryObserverAnySeq : public base::CheckedObserver {
+class V8DetailedMemoryObserverAnySeq : public base::CheckedObserver {
public:
// TODO(crbug.com/1096617): Should use FrameToken here instead of routing id.
using FrameDataMap =
- base::flat_map<content::GlobalFrameRoutingId, V8PerFrameMemoryFrameData>;
+ base::flat_map<content::GlobalFrameRoutingId, V8DetailedMemoryFrameData>;
// Called on the observer's sequence when a measurement is available for the
// process with ID |render_process_host_id|. The notification includes the
@@ -510,56 +575,131 @@ class V8PerFrameMemoryObserverAnySeq : public base::CheckedObserver {
// need to return to the PM sequence to read it.
virtual void OnV8MemoryMeasurementAvailable(
RenderProcessHostId render_process_host_id,
- const V8PerFrameMemoryProcessData& process_data,
+ const V8DetailedMemoryProcessData& process_data,
const FrameDataMap& frame_data) = 0;
};
-// Wrapper that can instantiate a V8PerFrameMemoryRequest from any sequence.
-class V8PerFrameMemoryRequestAnySeq {
+// Wrapper that can instantiate a V8DetailedMemoryRequest from any sequence.
+class V8DetailedMemoryRequestAnySeq {
public:
- using MeasurementMode = V8PerFrameMemoryRequest::MeasurementMode;
-
- explicit V8PerFrameMemoryRequestAnySeq(
+ using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
+
+ // Creates a memory measurement request that will be sent repeatedly with at
+ // least |min_time_between_requests| between each measurement. The request
+ // will be sent to the process with ID |process_to_measure|, which must be a
+ // renderer process, or to all renderer processes if |process_to_measure| is
+ // nullopt. The process will perform the measurement during a GC as determined
+ // by |mode|.
+ explicit V8DetailedMemoryRequestAnySeq(
const base::TimeDelta& min_time_between_requests,
- MeasurementMode mode = MeasurementMode::kDefault);
- ~V8PerFrameMemoryRequestAnySeq();
+ MeasurementMode mode = MeasurementMode::kDefault,
+ base::Optional<RenderProcessHostId> process_to_measure = base::nullopt);
+ ~V8DetailedMemoryRequestAnySeq();
- V8PerFrameMemoryRequestAnySeq(const V8PerFrameMemoryRequestAnySeq&) = delete;
- V8PerFrameMemoryRequestAnySeq& operator=(
- const V8PerFrameMemoryRequestAnySeq&) = delete;
+ V8DetailedMemoryRequestAnySeq(const V8DetailedMemoryRequestAnySeq&) = delete;
+ V8DetailedMemoryRequestAnySeq& operator=(
+ const V8DetailedMemoryRequestAnySeq&) = delete;
// Returns whether |observer| is in |observers_|.
- bool HasObserver(V8PerFrameMemoryObserverAnySeq* observer);
+ bool HasObserver(V8DetailedMemoryObserverAnySeq* observer);
// Adds an observer that was created on the same sequence as the
- // V8PerFrameMemoryRequestAnySeq.
- void AddObserver(V8PerFrameMemoryObserverAnySeq* observer);
+ // V8DetailedMemoryRequestAnySeq.
+ void AddObserver(V8DetailedMemoryObserverAnySeq* observer);
// Removes an observer that was added with AddObserver.
- void RemoveObserver(V8PerFrameMemoryObserverAnySeq* observer);
+ void RemoveObserver(V8DetailedMemoryObserverAnySeq* observer);
// Implementation details below this point.
- // V8PerFrameMemoryRequest calls NotifyObserversOnMeasurementAvailable when
+ // V8DetailedMemoryRequest calls NotifyObserversOnMeasurementAvailable when
// a measurement is received.
void NotifyObserversOnMeasurementAvailable(
- util::PassKey<V8PerFrameMemoryRequest>,
+ util::PassKey<V8DetailedMemoryRequest>,
RenderProcessHostId render_process_host_id,
- const V8PerFrameMemoryProcessData& process_data,
- const V8PerFrameMemoryObserverAnySeq::FrameDataMap& frame_data) const;
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data) const;
private:
- std::unique_ptr<V8PerFrameMemoryRequest> request_;
- base::ObserverList<V8PerFrameMemoryObserverAnySeq, /*check_empty=*/true>
+ void InitializeWrappedRequest(
+ const base::TimeDelta& min_time_between_requests,
+ MeasurementMode mode,
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure);
+
+ std::unique_ptr<V8DetailedMemoryRequest> request_;
+ base::ObserverList<V8DetailedMemoryObserverAnySeq, /*check_empty=*/true>
observers_;
// This object can live on any sequence but all methods and the destructor
// must be called from that sequence.
SEQUENCE_CHECKER(sequence_checker_);
- base::WeakPtrFactory<V8PerFrameMemoryRequestAnySeq> weak_factory_{this};
+ base::WeakPtrFactory<V8DetailedMemoryRequestAnySeq> weak_factory_{this};
+};
+
+// Wrapper that can instantiate a V8DetailedMemoryRequestOneShot from any
+// sequence.
+class V8DetailedMemoryRequestOneShotAnySeq {
+ public:
+ using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
+
+ using FrameDataMap = V8DetailedMemoryObserverAnySeq::FrameDataMap;
+
+ // A callback that will be called on the request's sequence with the results
+ // of the measurement. |process_id| will always match the value passed to
+ // the V8DetailedMemoryRequestOneShotAnySeq constructor.
+ using MeasurementCallback =
+ base::OnceCallback<void(RenderProcessHostId process_id,
+ const V8DetailedMemoryProcessData& process_data,
+ const FrameDataMap& frame_data)>;
+
+ explicit V8DetailedMemoryRequestOneShotAnySeq(
+ MeasurementMode mode = MeasurementMode::kDefault);
+
+ V8DetailedMemoryRequestOneShotAnySeq(
+ RenderProcessHostId process_id,
+ MeasurementCallback callback,
+ MeasurementMode mode = MeasurementMode::kDefault);
+
+ ~V8DetailedMemoryRequestOneShotAnySeq();
+
+ V8DetailedMemoryRequestOneShotAnySeq(
+ const V8DetailedMemoryRequestOneShotAnySeq&) = delete;
+ V8DetailedMemoryRequestOneShotAnySeq& operator=(
+ const V8DetailedMemoryRequestOneShotAnySeq&) = delete;
+
+ void StartMeasurement(RenderProcessHostId process_id,
+ MeasurementCallback callback);
+
+ private:
+ void InitializeWrappedRequest(MeasurementCallback callback,
+ MeasurementMode mode,
+ base::WeakPtr<ProcessNode>);
+
+ // Called on the PM sequence when a measurement is available.
+ // |sequence_bound_callback| will wrap the callback passed to the
+ // constructor, so it is both called and freed on the request's sequence.
+ static void OnMeasurementAvailable(
+ base::SequenceBound<MeasurementCallback> sequence_bound_callback,
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data);
+
+ MeasurementMode mode_;
+
+ // The wrapped request. Must only be accessed from the PM sequence.
+ std::unique_ptr<V8DetailedMemoryRequestOneShot> request_;
+
+ // This object can live on any sequence but all methods and the destructor
+ // must be called from that sequence.
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<V8DetailedMemoryRequestOneShotAnySeq> weak_factory_{
+ this};
};
+//////////////////////////////////////////////////////////////////////////////
+// The following internal functions are exposed in the header for testing.
+
namespace internal {
// A callback that will bind a V8DetailedMemoryReporter interface to
@@ -569,7 +709,7 @@ using BindV8DetailedMemoryReporterCallback = base::RepeatingCallback<void(
mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>,
RenderProcessHostProxy)>;
-// Sets a callback that will be used to bind the V8PerFrameMemoryReporter
+// Sets a callback that will be used to bind the V8DetailedMemoryReporter
// interface. The callback is owned by the caller and must live until this
// function is called again with nullptr.
void SetBindV8DetailedMemoryReporterCallbackForTesting(
@@ -580,10 +720,13 @@ void SetBindV8DetailedMemoryReporterCallbackForTesting(
// be enabled in tests.
void SetEagerMemoryMeasurementEnabledForTesting(bool enable);
+// Destroys the V8DetailedMemoryDecorator. Exposed for testing.
+void DestroyV8DetailedMemoryDecoratorForTesting(Graph* graph);
+
} // namespace internal
} // namespace v8_memory
} // namespace performance_manager
-#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_PER_FRAME_MEMORY_DECORATOR_H_
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_
diff --git a/chromium/components/performance_manager/public/v8_memory/web_memory.h b/chromium/components/performance_manager/public/v8_memory/web_memory.h
new file mode 100644
index 00000000000..ddf5463544f
--- /dev/null
+++ b/chromium/components/performance_manager/public/v8_memory/web_memory.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_WEB_MEMORY_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_WEB_MEMORY_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/util/type_safety/pass_key.h"
+#include "components/performance_manager/public/mojom/web_memory.mojom.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+
+class FrameNode;
+
+namespace v8_memory {
+
+// Implements mojom::DocumentCoordinationUnit::OnWebMemoryMeasurementRequest.
+// Measures memory usage of each frame in the browsing context group of the
+// given frame and invokes the given callback with the result.
+void WebMeasureMemory(const FrameNode*,
+ mojom::WebMemoryMeasurement::Mode,
+ base::OnceCallback<void(mojom::WebMemoryMeasurementPtr)>);
+
+} // namespace v8_memory
+
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_WEB_MEMORY_H_
diff --git a/chromium/components/performance_manager/public/voting/voting.h b/chromium/components/performance_manager/public/voting/voting.h
new file mode 100644
index 00000000000..e5f61977bee
--- /dev/null
+++ b/chromium/components/performance_manager/public/voting/voting.h
@@ -0,0 +1,922 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_PUBLIC_VOTING_VOTING_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_VOTING_VOTING_H_
+
+// Declares the various structures and formats associated with a templated
+// voting system. This is templated on a vote type (e.g. a priority) and a vote
+// context (e.g. a specific node type).
+//
+// There are 6 interrelated classes declared here:
+//
+// (1) Vote - A simple wrapper for a vote, unattributed, unsubmitted and
+// unowned. This is a final concrete class.
+// (2) AcceptedVote - A thin wrapper around a Vote, which gives it ownership
+// (by a VoteConsumer) and tracking (via VoteReceipt). This is a final
+// concrete class.
+// (3) VoteReceipt - Counterpart to an AcceptedVote. Issued to a voter when a
+// vote is accepted, and used to allow that voter to change / withdraw /
+// cancel their vote. This is a final concrete class.
+// (4) VoteConsumer - Destination for Votes (making them AcceptedVotes) and
+// issuer of VoteReceipts. This is an interface.
+// (5) VotingChannel - A mechanism by which a voter can submit votes to
+// VoteConsumer, which endows the vote with a unique voter attribution. This
+// is a final concrete class.
+// (6) VotingChannelFactory - Producer and tracker of VotingChannels, meant to
+// be owned by a VoteConsumer. This is a final concrete class.
+//
+// Voters register themselves with VoteConsumers, which issues them a private
+// VotingChannel to use for submitting Votes. Voters then submit raw Votes to
+// VoteConsumers via the VotingChannel, which issues them a VoteReceipt. When a
+// VoteConsumer accepts a vote it becomes an AcceptedVote. AcceptedVotes and
+// VoteReceipts are entangled for their lifetimes, with AcceptedVotes (owned by
+// the consumer) outliving their associated VoteReceipts (owned by the voter).
+// Both types are move-only, ensuring that one vote had exactly one receipt. An
+// AcceptedVote passes through a small lifecycle (no receipt yet issued -> has
+// issued a receipt -> receipt has been destroyed and vote is invalidated).
+//
+// VotingChannels are tracked by a VotingChannelFactory, which itself is owned
+// by the VoteConsumer. The VotingChannelFactory is used to track all
+// outstanding VotingChannels, and helps to ensure that Voters have been
+// torn-down / disconnected before the VoteConsumer disappears.
+//
+// When a vote is invalidated the consumer owning the vote is notified so that
+// they may update internal data structures, aggregates, etc.
+//
+// None of these objects are thread-safe, and they should all be used from a
+// single sequence. In practice this will be the PM sequence.
+//
+// IMPLEMENTATION NOTES:
+//
+// AcceptedVote and VoteReceipt maintain explicit back-pointers to each other,
+// which is what allows them both to be movable and yet not incur a heap
+// allocation. This means that they are both amenable to storage in memory-dense
+// containers (flat_map, flat_set, vector) and won't incur further heap
+// allocations. It is expected that there could be up to O(1000s) of votes lying
+// around, but that they will not often have to move. Thus the pointer
+// maintenance is a reasonable trade-off for memory efficiency.
+
+#include <cstring>
+#include <map>
+#include <utility>
+
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/util/type_safety/id_type.h"
+#include "base/util/type_safety/pass_key.h"
+
+namespace performance_manager {
+namespace voting {
+
+template <class VoteImpl>
+class VoteConsumer;
+
+// Contains a single vote. Specifically allows copying, etc, so as to be STL
+// container friendly.
+template <typename TContextType, typename TVoteType, TVoteType DefaultVote>
+class Vote final {
+ public:
+ using ContextType = TContextType;
+ using VoteType = TVoteType;
+
+ Vote();
+ // NOTE: |reason| *must* be a static string.
+ Vote(VoteType vote, const char* reason);
+ Vote(const Vote& rhs);
+
+ Vote& operator=(const Vote& rhs);
+
+ ~Vote();
+
+ VoteType value() const { return vote_; }
+ const char* reason() const { return reason_; }
+
+ bool operator==(const Vote& vote) const;
+ bool operator!=(const Vote& vote) const;
+
+ bool IsValid() const;
+
+ private:
+ VoteType vote_ = DefaultVote;
+ const char* reason_ = nullptr;
+};
+
+template <typename VoteImpl>
+using VoterId = util::IdTypeU32<VoteImpl>;
+template <typename VoteImpl>
+constexpr VoterId<VoteImpl> kInvalidVoterId;
+
+// A raw vote becomes an AcceptedVote once a VoteConsumer receives and stores
+// it, associating it with a VoterId.
+template <class VoteImpl>
+class AcceptedVote;
+
+// An issued vote returns a move-only VoteReceipt. Destroying the vote receipt
+// is equivalent to invalidating the vote.
+template <class VoteImpl>
+class VoteReceipt final {
+ public:
+ using PassKey = util::PassKey<VoteReceipt<VoteImpl>>;
+
+ VoteReceipt();
+ VoteReceipt(const VoteReceipt& rhs) = delete;
+ VoteReceipt(VoteReceipt&& rhs);
+
+ VoteReceipt& operator=(const VoteReceipt& rhs) = delete;
+ VoteReceipt& operator=(VoteReceipt&& rhs);
+
+ ~VoteReceipt();
+
+ // Returns true if this receipt is entangled with a vote.
+ bool HasVote() const;
+ bool HasVote(const AcceptedVote<VoteImpl>* vote) const;
+
+ // Returns the consumer that this vote was submitted to. Can only be called if
+ // HasVote returns true.
+ VoteConsumer<VoteImpl>* GetConsumer() const;
+
+ // Returns the voter ID associated with this receipt. Can only be called if
+ // HasVote returns true.
+ VoterId<VoteImpl> GetVoterId() const;
+
+ // Returns the vote corresponding to this receipt. Can only be called if
+ // HasVote returns true.
+ const VoteImpl& GetVote() const;
+
+ // Changes the upstream vote associated with this vote receipt. Can only be
+ // called if HasVote returns true.
+ void ChangeVote(typename VoteImpl::VoteType vote, const char* reason);
+
+ // Rests the vote receipt, canceling the upstream vote.
+ void Reset();
+
+ // VoteReceipt and AcceptedVote are tightly intertwined, and maintain
+ // back-pointers to each other as one or the other is moved. The 2 following
+ // functions are only meant to be used by AcceptedVote.
+
+ // Allows an AcceptedVote to create an entangled receipt.
+ VoteReceipt(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* vote);
+
+ // Allows an AcceptedVote to update its backpointer.
+ void MoveVote(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* old_vote,
+ AcceptedVote<VoteImpl>* new_vote);
+
+ private:
+ void Take(VoteReceipt&& rhs);
+
+ // A back-pointer to the accepted vote, so that it can be notified when this
+ // receipt is destroyed.
+ AcceptedVote<VoteImpl>* vote_ = nullptr;
+};
+
+// A move-only wrapper for a vote and its associated receipt. AcceptedVotes
+// and VoteReceipts exist in pairs, and they update their pointers to each
+// other. An AcceptedVote goes through the following lifecycle:
+//
+// (1) Initial creation. It has a vote, but no receipt. The vote is considered
+// valid at this point.
+// (2) Association with a receipt. The vote is considered valid at this point.
+// (3) Invalidation. The receipt is destroyed, which reaches back and
+// invalidates the vote. The vote is considered invalid at this point, and
+// no new receipt may be issued.
+//
+// An AcceptedVote must outlive its associated VoteReceipt, much like
+// VoteConsumers must outlive voters. Note that a default constructed
+// AcceptedVote is always in the invalidated state.
+template <class VoteImpl>
+class AcceptedVote final {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+ using PassKey = util::PassKey<AcceptedVote<VoteImpl>>;
+
+ AcceptedVote();
+ AcceptedVote(VoteConsumer<VoteImpl>* consumer,
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote);
+ AcceptedVote(const AcceptedVote& rhs) = delete;
+ AcceptedVote(AcceptedVote&& rhs);
+
+ AcceptedVote& operator=(const AcceptedVote& rhs) = delete;
+ AcceptedVote& operator=(AcceptedVote&& rhs);
+
+ ~AcceptedVote();
+
+ // Returns true if this vote is associated with a receipt.
+ bool HasReceipt() const;
+ bool HasReceipt(const VoteReceipt<VoteImpl>* receipt) const;
+
+ bool IsValid() const;
+ VoteReceipt<VoteImpl> IssueReceipt();
+
+ VoteConsumer<VoteImpl>* consumer() const { return consumer_; }
+ VoterId<VoteImpl> voter_id() const { return voter_id_; }
+ const ContextType* context() const { return context_; }
+ const VoteImpl& vote() const { return vote_; }
+
+ // Allows an accepted vote to be updated in place.
+ void UpdateVote(const VoteImpl& vote);
+
+ // VoteReceipt and AcceptedVote are tightly intertwined, and maintain
+ // back-pointers to each other as one or the other is moved. The following
+ // functions are only meant to be used by VoteReceipt.
+
+ // Allows a VoteReceipt to associate itself with this vote.
+ void SetReceipt(util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* receipt);
+
+ // Allows a VoteReceipt to update its backpointer.
+ void MoveReceipt(util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* old_receipt,
+ VoteReceipt<VoteImpl>* new_receipt);
+
+ // Allows a VoteReceipt to change this vote.
+ void ChangeVote(util::PassKey<VoteReceipt<VoteImpl>>,
+ typename VoteImpl::VoteType vote,
+ const char* reason);
+
+ // Allows a VoteReceipt to invalidate this vote.
+ void InvalidateVote(util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* receipt);
+
+ private:
+ void Take(AcceptedVote&& rhs);
+
+ // The consumer that accepted the vote.
+ VoteConsumer<VoteImpl>* consumer_ = nullptr;
+
+ // The ID of the voter that submitted the vote. This is defined by the
+ // VoteConsumer.
+ VoterId<VoteImpl> voter_id_ = kInvalidVoterId<VoteImpl>;
+
+ const ContextType* context_ = nullptr;
+
+ // The vote that is being wrapped.
+ VoteImpl vote_;
+
+ // The associated vote receipt.
+ VoteReceipt<VoteImpl>* receipt_ = nullptr;
+
+ // Set to true when an associated receipt is destroyed.
+ bool invalidated_ = true;
+};
+
+template <class VoteImpl>
+class VotingChannelFactory;
+
+// A channel that a voter can use to submit votes to a VoteConsumer. A move-only
+// type so that it can't be shared by multiple voters. This must be destroyed
+// before the issuing VotingChannelFactory.
+template <class VoteImpl>
+class VotingChannel final {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+ using PassKey = util::PassKey<VotingChannel<VoteImpl>>;
+
+ VotingChannel();
+ VotingChannel(const VotingChannel& rhs) = delete;
+ VotingChannel(VotingChannel&& rhs);
+ VotingChannel& operator=(const VotingChannel& rhs) = delete;
+ VotingChannel& operator=(VotingChannel&& rhs);
+ ~VotingChannel();
+
+ // Submits a vote through this voting channel. Can only be called if this
+ // VotingChannel is valid.
+ VoteReceipt<VoteImpl> SubmitVote(const ContextType* context,
+ const VoteImpl& vote);
+
+ // Returns true if this VotingChannel is valid.
+ bool IsValid() const;
+
+ // Resets this voting channel.
+ void Reset();
+
+ VoterId<VoteImpl> voter_id() const { return voter_id_; }
+
+ VotingChannelFactory<VoteImpl>* factory_for_testing() const {
+ return factory_;
+ }
+
+ // VotingChannelFactory is the sole producer of VotingChannels.
+ VotingChannel(util::PassKey<VotingChannelFactory<VoteImpl>>,
+ VotingChannelFactory<VoteImpl>* factory,
+ VoterId<VoteImpl> voter_id);
+
+ private:
+ void Take(VotingChannel&& rhs);
+
+ // Used to reach back into the factory to decrement the outstanding
+ // VotingChannel count, and for routing votes to the consumer.
+ VotingChannelFactory<VoteImpl>* factory_ = nullptr;
+ VoterId<VoteImpl> voter_id_ = kInvalidVoterId<VoteImpl>;
+};
+
+// A helper for creating VotingChannels that binds a unique VoterId (and
+// passes the votes along to the VoteConsumer with that VoterId), and a tracking
+// token to ensure that the voter disconnects from the VoteConsumer before it is
+// itself destroyed. Implementations of VoteConsumers should own an instance of
+// this and use it to emit VotingChannels. This class will DCHECK in its
+// destructor if there are outstanding VotingChannels at its death.
+template <class VoteImpl>
+class VotingChannelFactory final {
+ public:
+ explicit VotingChannelFactory(VoteConsumer<VoteImpl>* consumer);
+ ~VotingChannelFactory();
+ VotingChannelFactory(const VotingChannelFactory& rhs) = delete;
+ VotingChannelFactory& operator=(const VotingChannelFactory& rhs) = delete;
+
+ // Builds a new VotingChannel that routes votes to the |consumer_|.
+ VotingChannel<VoteImpl> BuildVotingChannel();
+
+ size_t voting_channels_issued() const { return voting_channels_issued_; }
+ size_t voting_channels_outstanding() const {
+ return voting_channels_outstanding_;
+ }
+
+ // Used by ~VotingChannel to notify the factory that a channel has been
+ // torn down.
+ void OnVotingChannelDestroyed(util::PassKey<VotingChannel<VoteImpl>>);
+
+ VoteConsumer<VoteImpl>* GetConsumer(util::PassKey<VotingChannel<VoteImpl>>) {
+ return consumer_;
+ }
+
+ private:
+ // The consumer that owns this factory.
+ VoteConsumer<VoteImpl>* consumer_ = nullptr;
+
+ // The number of voting channels issued, and the number that remain
+ // outstanding.
+ size_t voting_channels_issued_ = 0u;
+ size_t voting_channels_outstanding_ = 0u;
+};
+
+// A consumer of votes. By convention a VoteConsumer exposes mechanisms for
+// registering voters with the consumer, and providing them a VotingChannel to
+// invoke. This is done via owning a VotingChannelFactory, and building
+// VotingChannels. Consumers must outlive any VotingChannels they have issued.
+template <class VoteImpl>
+class VoteConsumer {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+
+ virtual ~VoteConsumer();
+
+ // Used by a VotingChannel to submit votes to this consumer.
+ virtual VoteReceipt<VoteImpl> SubmitVote(
+ util::PassKey<VotingChannel<VoteImpl>>,
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) = 0;
+
+ // Used by an AcceptedVote to notify a consumer that a previously issued vote
+ // has been changed. The consumer should update |old_vote| in-place using the
+ // data from |new_vote|.
+ virtual void ChangeVote(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* old_vote,
+ const VoteImpl& new_vote) = 0;
+
+ // Used by a AcceptedVote to notify a consumer that a previously issued
+ // receipt has been destroyed, and the vote is now invalidated. This is kept
+ // protected as it is part of a private contract between an AcceptedVote and a
+ // VoteConsumer.
+ virtual void VoteInvalidated(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* vote) = 0;
+};
+
+template <class VoteImpl>
+class VoteConsumerDefaultImpl;
+
+template <class VoteImpl>
+class VoteObserver {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+
+ virtual ~VoteObserver();
+
+ // Invoked when a |vote| is submitted for |context|. |voter_id| identifies the
+ // voting channel.
+ virtual void OnVoteSubmitted(VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) = 0;
+
+ // Invoked when the vote for |context| is changed to |new_vote|. |voter_id|
+ // identifies the voting channel.
+ virtual void OnVoteChanged(VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& new_vote) = 0;
+
+ // Invoked when a vote for |context| is invalided. |voter_id| identifies the
+ // voting channel.
+ virtual void OnVoteInvalidated(VoterId<VoteImpl> voter_id,
+ const ContextType* context) = 0;
+};
+
+template <class VoteImpl>
+class VoteConsumerDefaultImpl : public VoteConsumer<VoteImpl> {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+ using PassKey = util::PassKey<VoteConsumerDefaultImpl>;
+
+ explicit VoteConsumerDefaultImpl(VoteObserver<VoteImpl>* vote_observer);
+ ~VoteConsumerDefaultImpl() override;
+
+ // Builds a new VotingChannel that routes votes to |vote_observer_|.
+ VotingChannel<VoteImpl> BuildVotingChannel();
+
+ size_t voting_channels_issued() const {
+ return voting_channel_factory_.voting_channels_issued();
+ }
+
+ // VoteConsumer:
+ VoteReceipt<VoteImpl> SubmitVote(util::PassKey<VotingChannel<VoteImpl>>,
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) override;
+ void ChangeVote(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* old_vote,
+ const VoteImpl& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* vote) override;
+
+ private:
+ VoteObserver<VoteImpl>* vote_observer_;
+
+ VotingChannelFactory<VoteImpl> voting_channel_factory_;
+
+ std::map<const ContextType*, AcceptedVote<VoteImpl>> accepted_votes_;
+};
+
+/////////////////////////////////////////////////////////////////////
+// Vote
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+Vote<ContextType, VoteType, DefaultVote>::Vote() = default;
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+Vote<ContextType, VoteType, DefaultVote>::Vote(VoteType vote,
+ const char* reason)
+ : vote_(std::move(vote)), reason_(reason) {}
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+Vote<ContextType, VoteType, DefaultVote>::Vote(const Vote& rhs) = default;
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+Vote<ContextType, VoteType, DefaultVote>&
+Vote<ContextType, VoteType, DefaultVote>::operator=(
+ const Vote<ContextType, VoteType, DefaultVote>& rhs) = default;
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+Vote<ContextType, VoteType, DefaultVote>::~Vote() = default;
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+bool Vote<ContextType, VoteType, DefaultVote>::operator==(
+ const Vote<ContextType, VoteType, DefaultVote>& vote) const {
+ DCHECK(reason_);
+ DCHECK(vote.reason_);
+ return vote_ == vote.vote_ && ::strcmp(reason_, vote.reason_) == 0;
+}
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+bool Vote<ContextType, VoteType, DefaultVote>::operator!=(
+ const Vote<ContextType, VoteType, DefaultVote>& vote) const {
+ return !(*this == vote);
+}
+
+template <typename ContextType, typename VoteType, VoteType DefaultVote>
+bool Vote<ContextType, VoteType, DefaultVote>::IsValid() const {
+ return reason_;
+}
+
+/////////////////////////////////////////////////////////////////////
+// VoteReceipt
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl>::VoteReceipt() = default;
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl>::VoteReceipt(VoteReceipt<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl>& VoteReceipt<VoteImpl>::operator=(
+ VoteReceipt<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+ return *this;
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl>::~VoteReceipt() {
+ Reset();
+}
+
+template <class VoteImpl>
+bool VoteReceipt<VoteImpl>::HasVote() const {
+ return vote_;
+}
+
+template <class VoteImpl>
+bool VoteReceipt<VoteImpl>::HasVote(const AcceptedVote<VoteImpl>* vote) const {
+ return vote_ == vote;
+}
+
+template <class VoteImpl>
+VoteConsumer<VoteImpl>* VoteReceipt<VoteImpl>::GetConsumer() const {
+ return vote_->consumer();
+}
+
+template <class VoteImpl>
+VoterId<VoteImpl> VoteReceipt<VoteImpl>::GetVoterId() const {
+ return vote_->voter_id();
+}
+
+template <class VoteImpl>
+const VoteImpl& VoteReceipt<VoteImpl>::GetVote() const {
+ return vote_->vote();
+}
+
+template <class VoteImpl>
+void VoteReceipt<VoteImpl>::ChangeVote(typename VoteImpl::VoteType new_vote,
+ const char* reason) {
+ DCHECK(vote_);
+
+ // Do nothing if the vote hasn't actually changed.
+ const auto& vote = vote_->vote();
+ if (vote.value() == new_vote && vote.reason() == reason)
+ return;
+
+ vote_->ChangeVote(PassKey(), new_vote, reason);
+}
+
+template <class VoteImpl>
+void VoteReceipt<VoteImpl>::Reset() {
+ if (vote_) {
+ vote_->InvalidateVote(PassKey(), this);
+ vote_ = nullptr;
+ }
+}
+
+template <class VoteImpl>
+void VoteReceipt<VoteImpl>::MoveVote(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* old_vote,
+ AcceptedVote<VoteImpl>* new_vote) {
+ DCHECK(old_vote);
+ DCHECK(new_vote);
+ DCHECK_EQ(vote_, old_vote);
+ vote_ = new_vote;
+
+ // The vote should already be associated with this receipt (as the vote
+ // initiated the move).
+ DCHECK(vote_->HasReceipt(this));
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl>::VoteReceipt(util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* vote)
+ : vote_(vote) {
+ // The vote should be valid and not be associated with any receipt.
+ DCHECK(vote->IsValid());
+ DCHECK(vote->HasReceipt(nullptr));
+
+ // Associate the vote with this newly issued receipt.
+ vote->SetReceipt(PassKey(), this);
+}
+
+template <class VoteImpl>
+void VoteReceipt<VoteImpl>::Take(VoteReceipt<VoteImpl>&& rhs) {
+ Reset();
+
+ vote_ = rhs.vote_;
+
+ // Update the back-pointer from the vote.
+ if (vote_)
+ vote_->MoveReceipt(PassKey(), &rhs, this);
+
+ rhs.vote_ = nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////
+// AcceptedVote
+
+template <class VoteImpl>
+AcceptedVote<VoteImpl>::AcceptedVote() = default;
+
+template <class VoteImpl>
+AcceptedVote<VoteImpl>::AcceptedVote(VoteConsumer<VoteImpl>* consumer,
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote)
+ : consumer_(consumer),
+ voter_id_(voter_id),
+ context_(context),
+ vote_(vote),
+ invalidated_(false) {
+ DCHECK(consumer_);
+ DCHECK_NE(voter_id_, kInvalidVoterId<VoteImpl>);
+ DCHECK(context_);
+ DCHECK(vote_.IsValid());
+}
+
+template <class VoteImpl>
+AcceptedVote<VoteImpl>::AcceptedVote(AcceptedVote<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+}
+
+template <class VoteImpl>
+AcceptedVote<VoteImpl>& AcceptedVote<VoteImpl>::operator=(
+ AcceptedVote<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+ return *this;
+}
+
+template <class VoteImpl>
+AcceptedVote<VoteImpl>::~AcceptedVote() {
+ // A vote should not be destroyed while it has an outstanding receipt. It is
+ // up to Voters to destroy their votes when they go out of scope, and
+ // consumers must outlive voters.
+ DCHECK(!receipt_);
+}
+
+template <class VoteImpl>
+bool AcceptedVote<VoteImpl>::HasReceipt() const {
+ return receipt_;
+}
+
+template <class VoteImpl>
+bool AcceptedVote<VoteImpl>::HasReceipt(
+ const VoteReceipt<VoteImpl>* receipt) const {
+ return receipt_ == receipt;
+}
+
+template <class VoteImpl>
+bool AcceptedVote<VoteImpl>::IsValid() const {
+ return consumer_ && voter_id_ != kInvalidVoterId<VoteImpl> &&
+ vote_.IsValid() && !invalidated_;
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl> AcceptedVote<VoteImpl>::IssueReceipt() {
+ return VoteReceipt<VoteImpl>(PassKey(), this);
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::UpdateVote(const VoteImpl& vote) {
+ DCHECK(vote_.value() != vote.value() || vote_.reason() != vote.reason());
+ vote_ = vote;
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::SetReceipt(util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* receipt) {
+ // A receipt can only be set on a vote once in its lifetime.
+ DCHECK(!receipt_);
+ DCHECK(!invalidated_);
+ receipt_ = receipt;
+
+ // The receipt should already be associated with this vote (the association
+ // is initiated by the receipt).
+ DCHECK(receipt_->HasVote(this));
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::MoveReceipt(util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* old_receipt,
+ VoteReceipt<VoteImpl>* new_receipt) {
+ DCHECK(old_receipt);
+ DCHECK(new_receipt);
+ DCHECK_EQ(receipt_, old_receipt);
+ receipt_ = new_receipt;
+
+ // The receipt should already be associated with this vote (its calling for
+ // the move).
+ DCHECK(receipt_->HasVote(this));
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::ChangeVote(util::PassKey<VoteReceipt<VoteImpl>>,
+ typename VoteImpl::VoteType vote,
+ const char* reason) {
+ DCHECK(!invalidated_);
+ DCHECK(vote_.value() != vote || vote_.reason() != reason);
+
+ // Notify the consumer of the new vote.
+ VoteImpl new_vote = VoteImpl(vote, reason);
+ consumer_->ChangeVote(PassKey(), this, new_vote);
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::InvalidateVote(
+ util::PassKey<VoteReceipt<VoteImpl>>,
+ VoteReceipt<VoteImpl>* receipt) {
+ DCHECK(receipt);
+ DCHECK_EQ(receipt_, receipt);
+ DCHECK(!invalidated_);
+
+ // Care has to be taken not to access |receipt|, as it is running its
+ // destructor. It is only passed as a parameter to ensure that the proper
+ // receipt is notifying this vote.
+ receipt_ = nullptr;
+ invalidated_ = true;
+ consumer_->VoteInvalidated(PassKey(), this);
+}
+
+template <class VoteImpl>
+void AcceptedVote<VoteImpl>::Take(AcceptedVote<VoteImpl>&& rhs) {
+ // An AcceptedVote can't be overwritten while it has a pending receipt.
+ DCHECK(!receipt_);
+
+ consumer_ = std::exchange(rhs.consumer_, nullptr);
+ voter_id_ = std::exchange(rhs.voter_id_, kInvalidVoterId<VoteImpl>);
+ context_ = std::exchange(rhs.context_, nullptr);
+ vote_ = std::exchange(rhs.vote_, VoteImpl());
+ receipt_ = std::exchange(rhs.receipt_, nullptr);
+ invalidated_ = std::exchange(rhs.invalidated_, true);
+
+ // Update the back-pointer from the receipt.
+ if (receipt_)
+ receipt_->MoveVote(PassKey(), &rhs, this);
+}
+
+/////////////////////////////////////////////////////////////////////
+// VotingChannel
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>::VotingChannel() = default;
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>::VotingChannel(VotingChannel<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+}
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>& VotingChannel<VoteImpl>::operator=(
+ VotingChannel<VoteImpl>&& rhs) {
+ Take(std::move(rhs));
+ return *this;
+}
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>::~VotingChannel() {
+ Reset();
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl> VotingChannel<VoteImpl>::SubmitVote(
+ const ContextType* context,
+ const VoteImpl& vote) {
+ // Pass the vote along to the consumer with the bound |voter_id_|.
+ return factory_->GetConsumer(PassKey())->SubmitVote(PassKey(), voter_id_,
+ context, vote);
+}
+
+template <class VoteImpl>
+bool VotingChannel<VoteImpl>::IsValid() const {
+ return factory_ && voter_id_ != kInvalidVoterId<VoteImpl>;
+}
+
+template <class VoteImpl>
+void VotingChannel<VoteImpl>::Reset() {
+ if (!factory_)
+ return;
+ DCHECK_NE(kInvalidVoterId<VoteImpl>, voter_id_);
+ factory_->OnVotingChannelDestroyed(PassKey());
+ factory_ = nullptr;
+ voter_id_ = kInvalidVoterId<VoteImpl>;
+}
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>::VotingChannel(
+ util::PassKey<VotingChannelFactory<VoteImpl>>,
+ VotingChannelFactory<VoteImpl>* factory,
+ VoterId<VoteImpl> voter_id)
+ : factory_(factory), voter_id_(voter_id) {}
+
+template <class VoteImpl>
+void VotingChannel<VoteImpl>::Take(VotingChannel<VoteImpl>&& rhs) {
+ Reset();
+ factory_ = std::exchange(rhs.factory_, nullptr);
+ voter_id_ = std::exchange(rhs.voter_id_, kInvalidVoterId<VoteImpl>);
+}
+
+/////////////////////////////////////////////////////////////////////
+// VotingChannelFactory
+template <class VoteImpl>
+VotingChannelFactory<VoteImpl>::VotingChannelFactory(
+ VoteConsumer<VoteImpl>* consumer)
+ : consumer_(consumer) {
+ DCHECK(consumer);
+}
+
+template <class VoteImpl>
+VotingChannelFactory<VoteImpl>::~VotingChannelFactory() {
+ // We expect all voters to have severed their VotingChannels before we are
+ // torn down.
+ DCHECK_EQ(0u, voting_channels_outstanding_);
+}
+
+template <class VoteImpl>
+VotingChannel<VoteImpl> VotingChannelFactory<VoteImpl>::BuildVotingChannel() {
+ ++voting_channels_outstanding_;
+ // TODO(sebmarchand): Use VoterId<VoteImpl>::Generator instead of
+ // FromUnsafeValue.
+ VoterId<VoteImpl> new_voter_id =
+ VoterId<VoteImpl>::FromUnsafeValue(++voting_channels_issued_);
+ return VotingChannel<VoteImpl>(
+ util::PassKey<VotingChannelFactory<VoteImpl>>(), this, new_voter_id);
+}
+
+template <class VoteImpl>
+void VotingChannelFactory<VoteImpl>::OnVotingChannelDestroyed(
+ util::PassKey<VotingChannel<VoteImpl>>) {
+ DCHECK_LT(0u, voting_channels_outstanding_);
+ --voting_channels_outstanding_;
+}
+
+/////////////////////////////////////////////////////////////////////
+// VoteConsumer
+
+template <class VoteImpl>
+VoteConsumer<VoteImpl>::~VoteConsumer() = default;
+
+/////////////////////////////////////////////////////////////////////
+// VoteObserver
+
+template <class VoteImpl>
+VoteObserver<VoteImpl>::~VoteObserver() = default;
+
+/////////////////////////////////////////////////////////////////////
+// VoteConsumerDefaultImpl
+
+template <class VoteImpl>
+VoteConsumerDefaultImpl<VoteImpl>::VoteConsumerDefaultImpl(
+ VoteObserver<VoteImpl>* vote_observer)
+ : vote_observer_(vote_observer), voting_channel_factory_(this) {}
+
+template <class VoteImpl>
+VoteConsumerDefaultImpl<VoteImpl>::~VoteConsumerDefaultImpl() = default;
+
+template <class VoteImpl>
+VotingChannel<VoteImpl>
+VoteConsumerDefaultImpl<VoteImpl>::BuildVotingChannel() {
+ return voting_channel_factory_.BuildVotingChannel();
+}
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl> VoteConsumerDefaultImpl<VoteImpl>::SubmitVote(
+ util::PassKey<VotingChannel<VoteImpl>>,
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) {
+ AcceptedVote<VoteImpl> accepted_vote(this, voter_id, context, vote);
+
+ VoteReceipt<VoteImpl> vote_receipt = accepted_vote.IssueReceipt();
+
+ bool inserted =
+ accepted_votes_.emplace(context, std::move(accepted_vote)).second;
+ DCHECK(inserted);
+
+ vote_observer_->OnVoteSubmitted(voter_id, context, vote);
+
+ return vote_receipt;
+}
+
+template <class VoteImpl>
+void VoteConsumerDefaultImpl<VoteImpl>::ChangeVote(
+ util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* old_vote,
+ const VoteImpl& new_vote) {
+ auto it = accepted_votes_.find(old_vote->context());
+ DCHECK(it != accepted_votes_.end());
+ auto* accepted_vote = &it->second;
+ DCHECK_EQ(accepted_vote, old_vote);
+
+ accepted_vote->UpdateVote(new_vote);
+
+ vote_observer_->OnVoteChanged(accepted_vote->voter_id(),
+ accepted_vote->context(), new_vote);
+}
+
+template <class VoteImpl>
+void VoteConsumerDefaultImpl<VoteImpl>::VoteInvalidated(
+ util::PassKey<AcceptedVote<VoteImpl>>,
+ AcceptedVote<VoteImpl>* vote) {
+ auto it = accepted_votes_.find(vote->context());
+ DCHECK(it != accepted_votes_.end());
+ auto* accepted_vote = &it->second;
+ DCHECK_EQ(accepted_vote, vote);
+
+ vote_observer_->OnVoteInvalidated(accepted_vote->voter_id(),
+ accepted_vote->context());
+
+ accepted_votes_.erase(it);
+}
+
+} // namespace voting
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_VOTING_VOTING_H_
diff --git a/chromium/components/performance_manager/render_process_host_id_unittest.cc b/chromium/components/performance_manager/render_process_host_id_unittest.cc
new file mode 100644
index 00000000000..d9c1763ba21
--- /dev/null
+++ b/chromium/components/performance_manager/render_process_host_id_unittest.cc
@@ -0,0 +1,39 @@
+// 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 "components/performance_manager/public/render_process_host_id.h"
+
+#include "content/public/common/child_process_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+
+TEST(RenderProcessHostIdTest, InvalidValues) {
+ RenderProcessHostId default_id;
+ EXPECT_TRUE(default_id.is_null());
+ EXPECT_FALSE(default_id);
+
+ RenderProcessHostId invalid_id(content::ChildProcessHost::kInvalidUniqueID);
+ EXPECT_TRUE(invalid_id.is_null());
+ EXPECT_FALSE(invalid_id);
+
+ RenderProcessHostId zero_id(0);
+ EXPECT_TRUE(zero_id.is_null());
+ EXPECT_FALSE(zero_id);
+
+ EXPECT_EQ(default_id, invalid_id);
+ EXPECT_NE(default_id, zero_id);
+
+ RenderProcessHostId valid_id(1);
+ EXPECT_FALSE(valid_id.is_null());
+ EXPECT_TRUE(valid_id);
+}
+
+TEST(RenderProcessHostIdTest, Generator) {
+ RenderProcessHostId::Generator generator;
+ EXPECT_EQ(generator.GenerateNextId(), RenderProcessHostId(1));
+ EXPECT_EQ(generator.GenerateNextId(), RenderProcessHostId(2));
+}
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/render_process_host_proxy_browsertest.cc b/chromium/components/performance_manager/render_process_host_proxy_browsertest.cc
index 3c06ec94e91..5e019d65c74 100644
--- a/chromium/components/performance_manager/render_process_host_proxy_browsertest.cc
+++ b/chromium/components/performance_manager/render_process_host_proxy_browsertest.cc
@@ -4,11 +4,12 @@
#include "components/performance_manager/public/render_process_host_proxy.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
+#include "base/run_loop.h"
#include "base/task/task_traits.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/render_process_user_data.h"
diff --git a/chromium/components/performance_manager/service_worker_context_adapter.cc b/chromium/components/performance_manager/service_worker_context_adapter.cc
index 154fff74dfa..efe67ead637 100644
--- a/chromium/components/performance_manager/service_worker_context_adapter.cc
+++ b/chromium/components/performance_manager/service_worker_context_adapter.cc
@@ -6,6 +6,7 @@
#include "base/check_op.h"
#include "base/notreached.h"
+#include "base/scoped_observation.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
@@ -19,10 +20,12 @@ class ServiceWorkerContextAdapter::RunningServiceWorker
: content::RenderProcessHostObserver {
public:
RunningServiceWorker(int64_t version_id,
- content::RenderProcessHost* worker_process_host,
ServiceWorkerContextAdapter* adapter);
~RunningServiceWorker() override;
+ void Subscribe(content::RenderProcessHost* worker_process_host);
+ void Unsubscribe();
+
void RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) override;
@@ -30,31 +33,44 @@ class ServiceWorkerContextAdapter::RunningServiceWorker
private:
// The version ID of the service worker.
- int version_id_;
+ int const version_id_;
// The adapter that owns |this|. Notified when RenderProcessExited() is
// called.
ServiceWorkerContextAdapter* const adapter_;
- ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
- scoped_render_process_host_observer_{this};
+ base::ScopedObservation<content::RenderProcessHost,
+ content::RenderProcessHostObserver>
+ scoped_observation_{this};
};
ServiceWorkerContextAdapter::RunningServiceWorker::RunningServiceWorker(
int64_t version_id,
- content::RenderProcessHost* worker_process_host,
ServiceWorkerContextAdapter* adapter)
- : version_id_(version_id), adapter_(adapter) {
- scoped_render_process_host_observer_.Add(worker_process_host);
+ : version_id_(version_id), adapter_(adapter) {}
+
+ServiceWorkerContextAdapter::RunningServiceWorker::~RunningServiceWorker() {
+ DCHECK(!scoped_observation_.IsObserving());
}
-ServiceWorkerContextAdapter::RunningServiceWorker::~RunningServiceWorker() =
- default;
+void ServiceWorkerContextAdapter::RunningServiceWorker::Subscribe(
+ content::RenderProcessHost* worker_process_host) {
+ DCHECK(!scoped_observation_.IsObserving());
+ scoped_observation_.Observe(worker_process_host);
+}
+
+void ServiceWorkerContextAdapter::RunningServiceWorker::Unsubscribe() {
+ DCHECK(scoped_observation_.IsObserving());
+
+ scoped_observation_.RemoveObservation();
+}
void ServiceWorkerContextAdapter::RunningServiceWorker::RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) {
adapter_->OnRenderProcessExited(version_id_);
+
+ /* This object is deleted inside the above, don't touch "this". */
}
void ServiceWorkerContextAdapter::RunningServiceWorker::
@@ -66,10 +82,15 @@ void ServiceWorkerContextAdapter::RunningServiceWorker::
ServiceWorkerContextAdapter::ServiceWorkerContextAdapter(
content::ServiceWorkerContext* underlying_context) {
- scoped_underlying_context_observer_.Add(underlying_context);
+ scoped_underlying_context_observation_.Observe(underlying_context);
}
-ServiceWorkerContextAdapter::~ServiceWorkerContextAdapter() = default;
+ServiceWorkerContextAdapter::~ServiceWorkerContextAdapter() {
+ // Clean up any outstanding running service worker process subscriptions.
+ for (const auto& item : running_service_workers_)
+ item.second->Unsubscribe();
+ running_service_workers_.clear();
+}
void ServiceWorkerContextAdapter::AddObserver(
content::ServiceWorkerContextObserver* observer) {
@@ -226,7 +247,7 @@ void ServiceWorkerContextAdapter::OnVersionRedundant(int64_t version_id,
void ServiceWorkerContextAdapter::OnVersionStartedRunning(
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) {
- auto* worker_process_host =
+ content::RenderProcessHost* worker_process_host =
content::RenderProcessHost::FromID(running_info.render_process_id);
// It's possible that the renderer is already gone since the notification
@@ -240,19 +261,13 @@ void ServiceWorkerContextAdapter::OnVersionStartedRunning(
return;
}
- bool inserted =
- running_service_workers_
- .emplace(version_id, std::make_unique<RunningServiceWorker>(
- version_id, worker_process_host, this))
- .second;
- DCHECK(inserted);
-
+ AddRunningServiceWorker(version_id, worker_process_host);
for (auto& observer : observer_list_)
observer.OnVersionStartedRunning(version_id, running_info);
}
void ServiceWorkerContextAdapter::OnVersionStoppedRunning(int64_t version_id) {
- size_t removed = running_service_workers_.erase(version_id);
+ bool removed = MaybeRemoveRunningServiceWorker(version_id);
if (!removed) {
#if DCHECK_IS_ON()
// If this service worker could not be found, then it must be because its
@@ -352,8 +367,8 @@ void ServiceWorkerContextAdapter::OnDestruct(ServiceWorkerContext* context) {
}
void ServiceWorkerContextAdapter::OnRenderProcessExited(int64_t version_id) {
- size_t removed = running_service_workers_.erase(version_id);
- DCHECK_EQ(removed, 1u);
+ bool removed = MaybeRemoveRunningServiceWorker(version_id);
+ DCHECK(removed);
for (auto& observer : observer_list_)
observer.OnVersionStoppedRunning(version_id);
@@ -366,4 +381,30 @@ void ServiceWorkerContextAdapter::OnRenderProcessExited(int64_t version_id) {
#endif // DCHECK_IS_ON()
}
+void ServiceWorkerContextAdapter::AddRunningServiceWorker(
+ int64_t version_id,
+ content::RenderProcessHost* worker_process_host) {
+ std::unique_ptr<ServiceWorkerContextAdapter::RunningServiceWorker>
+ running_service_worker =
+ std::make_unique<RunningServiceWorker>(version_id, this);
+
+ running_service_worker->Subscribe(worker_process_host);
+ bool inserted = running_service_workers_
+ .emplace(version_id, std::move(running_service_worker))
+ .second;
+ DCHECK(inserted);
+}
+
+bool ServiceWorkerContextAdapter::MaybeRemoveRunningServiceWorker(
+ int64_t version_id) {
+ auto it = running_service_workers_.find(version_id);
+ if (it == running_service_workers_.end())
+ return false;
+
+ it->second->Unsubscribe();
+ running_service_workers_.erase(it);
+
+ return true;
+}
+
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/service_worker_context_adapter.h b/chromium/components/performance_manager/service_worker_context_adapter.h
index 7805423816f..d925abc9eaf 100644
--- a/chromium/components/performance_manager/service_worker_context_adapter.h
+++ b/chromium/components/performance_manager/service_worker_context_adapter.h
@@ -12,7 +12,7 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/service_worker_context_observer.h"
@@ -123,9 +123,18 @@ class ServiceWorkerContextAdapter
// has exited.
void OnRenderProcessExited(int64_t version_id);
- ScopedObserver<content::ServiceWorkerContext,
- content::ServiceWorkerContextObserver>
- scoped_underlying_context_observer_{this};
+ // Adds a registration to |worker_process_host| that will result in
+ // |OnRenderProcessExited| with |version_id| when it exits.
+ void AddRunningServiceWorker(int64_t version_id,
+ content::RenderProcessHost* worker_process_host);
+
+ // Removes a registration made by |AddRunningServiceWorker| if one exists,
+ // returns true if a registration existed, false otherwise.
+ bool MaybeRemoveRunningServiceWorker(int64_t version_id);
+
+ base::ScopedObservation<content::ServiceWorkerContext,
+ content::ServiceWorkerContextObserver>
+ scoped_underlying_context_observation_{this};
base::ObserverList<content::ServiceWorkerContextObserver, true, false>::
Unchecked observer_list_;
diff --git a/chromium/components/performance_manager/tab_helper_frame_node_source.cc b/chromium/components/performance_manager/tab_helper_frame_node_source.cc
index 01db6deee80..286dae9a51c 100644
--- a/chromium/components/performance_manager/tab_helper_frame_node_source.cc
+++ b/chromium/components/performance_manager/tab_helper_frame_node_source.cc
@@ -12,11 +12,11 @@
namespace performance_manager {
TabHelperFrameNodeSource::TabHelperFrameNodeSource()
- : performance_manager_tab_helper_observers_(this) {}
+ : performance_manager_tab_helper_observations_(this) {}
TabHelperFrameNodeSource::~TabHelperFrameNodeSource() {
DCHECK(observed_frame_nodes_.empty());
- DCHECK(!performance_manager_tab_helper_observers_.IsObservingSources());
+ DCHECK(!performance_manager_tab_helper_observations_.IsObservingAnySource());
}
FrameNodeImpl* TabHelperFrameNodeSource::GetFrameNode(
@@ -57,7 +57,7 @@ void TabHelperFrameNodeSource::SubscribeToFrameNode(
if (AddObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Start observing the tab helper only if this is the first observed frame
// that is associated with it.
- performance_manager_tab_helper_observers_.Add(
+ performance_manager_tab_helper_observations_.AddObservation(
performance_manager_tab_helper);
}
@@ -93,7 +93,7 @@ void TabHelperFrameNodeSource::UnsubscribeFromFrameNode(
if (RemoveObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Stop observing that tab helper if there no longer are any observed
// frames that are associated with it.
- performance_manager_tab_helper_observers_.Remove(
+ performance_manager_tab_helper_observations_.RemoveObservation(
performance_manager_tab_helper);
}
}
@@ -116,7 +116,7 @@ void TabHelperFrameNodeSource::OnBeforeFrameNodeRemoved(
if (RemoveObservedFrameNode(performance_manager_tab_helper, frame_node)) {
// Stop observing that tab helper if there no longer are any observed
// frames that are associated with it.
- performance_manager_tab_helper_observers_.Remove(
+ performance_manager_tab_helper_observations_.RemoveObservation(
performance_manager_tab_helper);
}
}
diff --git a/chromium/components/performance_manager/tab_helper_frame_node_source.h b/chromium/components/performance_manager/tab_helper_frame_node_source.h
index 25737daa21f..7930e3352e2 100644
--- a/chromium/components/performance_manager/tab_helper_frame_node_source.h
+++ b/chromium/components/performance_manager/tab_helper_frame_node_source.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
namespace performance_manager {
@@ -63,9 +63,9 @@ class TabHelperFrameNodeSource : public FrameNodeSource,
observed_frame_nodes_;
// Observes frame node deletions.
- ScopedObserver<PerformanceManagerTabHelper,
- PerformanceManagerTabHelper::Observer>
- performance_manager_tab_helper_observers_;
+ base::ScopedMultiSourceObservation<PerformanceManagerTabHelper,
+ PerformanceManagerTabHelper::Observer>
+ performance_manager_tab_helper_observations_;
DISALLOW_COPY_AND_ASSIGN(TabHelperFrameNodeSource);
};
diff --git a/chromium/components/performance_manager/test_support/BUILD.gn b/chromium/components/performance_manager/test_support/BUILD.gn
index 7b16850fe98..dcfa0158b4d 100644
--- a/chromium/components/performance_manager/test_support/BUILD.gn
+++ b/chromium/components/performance_manager/test_support/BUILD.gn
@@ -10,11 +10,10 @@ source_set("test_support_common") {
sources = [
"decorators_utils.h",
- "frame_priority.cc",
- "frame_priority.h",
"graph_impl.h",
"test_harness_helper.cc",
"test_harness_helper.h",
+ "voting.h",
]
deps = [
diff --git a/chromium/components/performance_manager/test_support/decorators_utils.h b/chromium/components/performance_manager/test_support/decorators_utils.h
index 9610f1a7d60..2b0a1ecaa0f 100644
--- a/chromium/components/performance_manager/test_support/decorators_utils.h
+++ b/chromium/components/performance_manager/test_support/decorators_utils.h
@@ -8,7 +8,7 @@
#include <utility>
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/performance_manager.h"
diff --git a/chromium/components/performance_manager/test_support/frame_priority.cc b/chromium/components/performance_manager/test_support/frame_priority.cc
deleted file mode 100644
index 73799c94de7..00000000000
--- a/chromium/components/performance_manager/test_support/frame_priority.cc
+++ /dev/null
@@ -1,101 +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 "components/performance_manager/test_support/frame_priority.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace performance_manager {
-namespace frame_priority {
-namespace test {
-
-DummyVoteConsumer::DummyVoteConsumer() : voting_channel_factory_(this) {}
-
-DummyVoteConsumer::~DummyVoteConsumer() = default;
-
-VoteReceipt DummyVoteConsumer::SubmitVote(VoterId voter_id, const Vote& vote) {
- // Accept the vote.
- votes_.emplace_back(AcceptedVote(this, voter_id, vote));
- EXPECT_FALSE(votes_.back().HasReceipt());
- EXPECT_TRUE(votes_.back().IsValid());
- ++valid_vote_count_;
- EXPECT_LE(valid_vote_count_, votes_.size());
-
- // Issue a receipt.
- auto receipt = votes_.back().IssueReceipt();
- EXPECT_TRUE(votes_.back().HasReceipt());
- EXPECT_TRUE(votes_.back().IsValid());
- return receipt;
-}
-
-VoteReceipt DummyVoteConsumer::ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) {
- // We should own this vote and it should be valid.
- EXPECT_TRUE(receipt.HasVote(old_vote));
- EXPECT_LE(votes_.data(), old_vote);
- EXPECT_LT(old_vote, votes_.data() + votes_.size());
- EXPECT_TRUE(old_vote->IsValid());
- EXPECT_LT(0u, valid_vote_count_);
-
- // Just update the vote in-place, and return the existing receipt for it.
- old_vote->UpdateVote(new_vote);
- return receipt;
-}
-
-void DummyVoteConsumer::VoteInvalidated(AcceptedVote* vote) {
- // We should own this vote.
- EXPECT_LE(votes_.data(), vote);
- EXPECT_LT(vote, votes_.data() + votes_.size());
- EXPECT_FALSE(vote->IsValid());
- EXPECT_LT(0u, valid_vote_count_);
- --valid_vote_count_;
-}
-
-void DummyVoteConsumer::ExpectInvalidVote(size_t index) {
- EXPECT_LT(index, votes_.size());
- const AcceptedVote& accepted_vote = votes_[index];
- EXPECT_EQ(this, accepted_vote.consumer());
- EXPECT_FALSE(accepted_vote.IsValid());
-}
-
-void DummyVoteConsumer::ExpectValidVote(size_t index,
- VoterId voter_id,
- const FrameNode* frame_node,
- base::TaskPriority priority,
- const char* reason) {
- EXPECT_LT(index, votes_.size());
- const AcceptedVote& accepted_vote = votes_[index];
- EXPECT_EQ(this, accepted_vote.consumer());
- EXPECT_TRUE(accepted_vote.IsValid());
- EXPECT_EQ(voter_id, accepted_vote.voter_id());
- const Vote& vote = accepted_vote.vote();
- EXPECT_EQ(frame_node, vote.frame_node());
- EXPECT_EQ(priority, vote.priority());
- EXPECT_TRUE(vote.reason());
- if (reason)
- EXPECT_EQ(reason, vote.reason());
-}
-
-// static
-const char DummyVoter::kReason[] = "dummmy reason";
-
-DummyVoter::DummyVoter() = default;
-DummyVoter::~DummyVoter() = default;
-
-void DummyVoter::SetVotingChannel(VotingChannel&& voting_channel) {
- voting_channel_ = std::move(voting_channel);
-}
-
-void DummyVoter::EmitVote(const FrameNode* frame_node,
- base::TaskPriority priority,
- const char* reason) {
- EXPECT_TRUE(voting_channel_.IsValid());
- receipts_.emplace_back(
- voting_channel_.SubmitVote(Vote(frame_node, priority, reason)));
-}
-
-} // namespace test
-} // namespace frame_priority
-} // namespace performance_manager
diff --git a/chromium/components/performance_manager/test_support/frame_priority.h b/chromium/components/performance_manager/test_support/frame_priority.h
deleted file mode 100644
index a1a6c2c8157..00000000000
--- a/chromium/components/performance_manager/test_support/frame_priority.h
+++ /dev/null
@@ -1,77 +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 COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
-
-#include "components/performance_manager/public/frame_priority/frame_priority.h"
-
-#include "base/macros.h"
-
-namespace performance_manager {
-namespace frame_priority {
-namespace test {
-
-// A dummy consumer that simply maintains a list of all submitted votes and
-// doesn't explicitly clean them up. New votes are continuously pushed back to
-// the end of |votes_|.
-class DummyVoteConsumer : public VoteConsumer {
- public:
- DummyVoteConsumer();
- ~DummyVoteConsumer() override;
-
- // VoteConsumer implementation:
- VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override;
- VoteReceipt ChangeVote(VoteReceipt receipt,
- AcceptedVote* old_vote,
- const Vote& new_vote) override;
- void VoteInvalidated(AcceptedVote* vote) override;
-
- void ExpectInvalidVote(size_t index);
-
- // Checks that the vote at position |index| is valid, and has the
- // corresponding |voter|, |frame_node| and |priority|. If |reason| is non-null
- // then it will be validated as well.
- void ExpectValidVote(size_t index,
- VoterId voter_id,
- const FrameNode* frame_node,
- base::TaskPriority priority,
- const char* reason = nullptr);
-
- VotingChannelFactory voting_channel_factory_;
- std::vector<AcceptedVote> votes_;
- size_t valid_vote_count_ = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DummyVoteConsumer);
-};
-
-// A dummy voter that allows emitting votes and tracking their receipts.
-class DummyVoter {
- public:
- static const char kReason[];
-
- DummyVoter();
- ~DummyVoter();
-
- void SetVotingChannel(VotingChannel&& voting_channel);
-
- // Causes the voter to emit a vote for the given |frame_node| and with the
- // given |priority|. The receipt is pushed back onto |receipts_|.
- void EmitVote(const FrameNode* frame_node,
- base::TaskPriority priority = base::TaskPriority::LOWEST,
- const char* reason = kReason);
-
- VotingChannel voting_channel_;
- std::vector<VoteReceipt> receipts_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DummyVoter);
-};
-
-} // namespace test
-} // namespace frame_priority
-} // namespace performance_manager
-
-#endif // COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
diff --git a/chromium/components/performance_manager/test_support/mock_graphs.cc b/chromium/components/performance_manager/test_support/mock_graphs.cc
index 5b8515419e0..8affb17fc2c 100644
--- a/chromium/components/performance_manager/test_support/mock_graphs.cc
+++ b/chromium/components/performance_manager/test_support/mock_graphs.cc
@@ -87,4 +87,47 @@ MockMultiplePagesWithMultipleProcessesGraph::
MockMultiplePagesWithMultipleProcessesGraph::
~MockMultiplePagesWithMultipleProcessesGraph() = default;
+MockSinglePageWithFrameAndWorkerInSingleProcessGraph::
+ MockSinglePageWithFrameAndWorkerInSingleProcessGraph(TestGraphImpl* graph)
+ : MockSinglePageInSingleProcessGraph(graph),
+ worker(TestNodeWrapper<WorkerNodeImpl>::Create(
+ graph,
+ WorkerNode::WorkerType::kDedicated,
+ process.get())) {
+ worker->AddClientFrame(frame.get());
+}
+
+MockSinglePageWithFrameAndWorkerInSingleProcessGraph::
+ ~MockSinglePageWithFrameAndWorkerInSingleProcessGraph() {
+ if (worker.get())
+ worker->RemoveClientFrame(frame.get());
+}
+
+void MockSinglePageWithFrameAndWorkerInSingleProcessGraph::DeleteWorker() {
+ DCHECK(worker.get());
+ worker->RemoveClientFrame(frame.get());
+ worker.reset();
+}
+
+MockMultiplePagesAndWorkersWithMultipleProcessesGraph::
+ MockMultiplePagesAndWorkersWithMultipleProcessesGraph(TestGraphImpl* graph)
+ : MockMultiplePagesWithMultipleProcessesGraph(graph),
+ worker(TestNodeWrapper<WorkerNodeImpl>::Create(
+ graph,
+ WorkerNode::WorkerType::kDedicated,
+ process.get())),
+ other_worker(TestNodeWrapper<WorkerNodeImpl>::Create(
+ graph,
+ WorkerNode::WorkerType::kDedicated,
+ other_process.get())) {
+ worker->AddClientFrame(frame.get());
+ other_worker->AddClientFrame(child_frame.get());
+}
+
+MockMultiplePagesAndWorkersWithMultipleProcessesGraph::
+ ~MockMultiplePagesAndWorkersWithMultipleProcessesGraph() {
+ other_worker->RemoveClientFrame(child_frame.get());
+ worker->RemoveClientFrame(frame.get());
+}
+
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/test_support/mock_graphs.h b/chromium/components/performance_manager/test_support/mock_graphs.h
index 1c9d3d28887..ac3ef83731c 100644
--- a/chromium/components/performance_manager/test_support/mock_graphs.h
+++ b/chromium/components/performance_manager/test_support/mock_graphs.h
@@ -116,6 +116,63 @@ struct MockMultiplePagesWithMultipleProcessesGraph
TestNodeWrapper<FrameNodeImpl> child_frame;
};
+// The following graph topology is created to emulate a scenario where a page
+// contains a single frame that creates a single dedicated worker.
+//
+// Pg Pr_
+// \ / |
+// F |
+// \ |
+// W__|
+//
+// Where:
+// Pg: page
+// F: frame(frame_tree_id:0)
+// W: worker
+// Pr: process(pid:1)
+struct MockSinglePageWithFrameAndWorkerInSingleProcessGraph
+ : public MockSinglePageInSingleProcessGraph {
+ explicit MockSinglePageWithFrameAndWorkerInSingleProcessGraph(
+ TestGraphImpl* graph);
+ ~MockSinglePageWithFrameAndWorkerInSingleProcessGraph();
+ TestNodeWrapper<WorkerNodeImpl> worker;
+
+ void DeleteWorker();
+};
+
+// The following graph topology is created to emulate a scenario where multiple
+// pages making use of workers are hosted in multiple processes (e.g.
+// out-of-process iFrames and multiple pages in a process):
+//
+// Pg OPg
+// | |
+// F OF
+// /\ / \
+// W \ / CF
+// \ | / | \
+// Pr | OW
+// | /
+// OPr
+//
+// Where:
+// Pg: page
+// OPg: other_page
+// F: frame(frame_tree_id:0)
+// OF: other_frame(frame_tree_id:1)
+// CF: child_frame(frame_tree_id:3)
+// W: worker
+// OW: other_worker
+// Pr: process(pid:1)
+// OPr: other_process(pid:2)
+struct MockMultiplePagesAndWorkersWithMultipleProcessesGraph
+ : public MockMultiplePagesWithMultipleProcessesGraph {
+ explicit MockMultiplePagesAndWorkersWithMultipleProcessesGraph(
+ TestGraphImpl* graph);
+ ~MockMultiplePagesAndWorkersWithMultipleProcessesGraph();
+ TestNodeWrapper<WorkerNodeImpl> worker;
+ TestNodeWrapper<WorkerNodeImpl> other_worker;
+};
+
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_MOCK_GRAPHS_H_
diff --git a/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.cc b/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.cc
index 28b82af9402..c6b33316622 100644
--- a/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.cc
+++ b/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.cc
@@ -4,8 +4,9 @@
#include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
+#include "components/performance_manager/embedder/performance_manager_lifetime.h"
#include "content/public/common/content_switches.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_content_browser_client.h"
@@ -20,6 +21,16 @@ namespace performance_manager {
PerformanceManagerBrowserTestHarness::~PerformanceManagerBrowserTestHarness() =
default;
+void PerformanceManagerBrowserTestHarness::SetUp() {
+ PerformanceManagerLifetime::SetAdditionalGraphCreatedCallbackForTesting(
+ base::BindLambdaForTesting(
+ [self = this](Graph* graph) { self->OnGraphCreated(graph); }));
+
+ // The PM gets initialized in the following, so this must occur after
+ // setting the callback.
+ Super::SetUp();
+}
+
void PerformanceManagerBrowserTestHarness::PreRunTestOnMainThread() {
Super::PreRunTestOnMainThread();
@@ -37,6 +48,8 @@ void PerformanceManagerBrowserTestHarness::SetUpCommandLine(
"PerformanceManagerInstrumentation");
}
+void PerformanceManagerBrowserTestHarness::OnGraphCreated(Graph* graph) {}
+
content::Shell* PerformanceManagerBrowserTestHarness::CreateShell() {
content::Shell* shell = CreateBrowser();
return shell;
diff --git a/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.h b/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.h
index d727c6d3b50..8df13455b94 100644
--- a/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.h
+++ b/chromium/components/performance_manager/test_support/performance_manager_browsertest_harness.h
@@ -5,10 +5,15 @@
#ifndef COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_PERFORMANCE_MANAGER_BROWSERTEST_HARNESS_H_
#define COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_PERFORMANCE_MANAGER_BROWSERTEST_HARNESS_H_
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "components/performance_manager/public/performance_manager.h"
#include "content/public/test/content_browser_test.h"
namespace performance_manager {
+class Graph;
+
// Like PerformanceManagerTestHarness, but for browser tests. Full process
// trees and live RFHs, etc, are created. Meant to be used from
// components_browsertests and browser_tests.
@@ -24,10 +29,17 @@ class PerformanceManagerBrowserTestHarness
const PerformanceManagerBrowserTestHarness&) = delete;
~PerformanceManagerBrowserTestHarness() override;
+ // gtest::Test:
+ void SetUp() override;
+
// content::BrowserTestBase:
void PreRunTestOnMainThread() override;
void SetUpCommandLine(base::CommandLine* command_line) override;
+ // An additional seam that gets invoked as part of the PM initialization. This
+ // will be invoked on the PM sequence.
+ virtual void OnGraphCreated(Graph* graph);
+
// Creates a content shell with its own window, hosting a single tab that is
// navigated to about:blank. The WebContents will have the PM helpers
// attached. Ownership of the shell rests with this object. Note that such a
@@ -40,6 +52,21 @@ class PerformanceManagerBrowserTestHarness
// Waits for an ongoing navigation to terminate on the given |contents|.
void WaitForLoad(content::WebContents* contents);
+
+ // Helper function for running a task on the graph, and waiting for it to
+ // complete. The signature of OnGraphCallback is expected to be void(Graph*).
+ template <typename OnGraphCallback>
+ void RunInGraph(OnGraphCallback on_graph_callback) {
+ base::RunLoop run_loop;
+ PerformanceManager::CallOnGraph(
+ FROM_HERE,
+ base::BindLambdaForTesting([quit_loop = run_loop.QuitClosure(),
+ &on_graph_callback](Graph* graph) {
+ on_graph_callback(graph);
+ quit_loop.Run();
+ }));
+ run_loop.Run();
+ }
};
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/test_support/voting.h b/chromium/components/performance_manager/test_support/voting.h
new file mode 100644
index 00000000000..c2323969416
--- /dev/null
+++ b/chromium/components/performance_manager/test_support/voting.h
@@ -0,0 +1,279 @@
+// 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 COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_VOTING_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_VOTING_H_
+
+#include "components/performance_manager/public/voting/voting.h"
+
+#include <map>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+namespace voting {
+namespace test {
+
+// A dummy consumer that simply maintains a list of all submitted votes and
+// doesn't explicitly clean them up. New votes are continuously pushed back to
+// the end of |votes_|.
+template <class VoteImpl>
+class DummyVoteConsumer : public VoteConsumer<VoteImpl> {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+ using AcceptedVote = AcceptedVote<VoteImpl>;
+ using VotingChannel = VotingChannel<VoteImpl>;
+
+ DummyVoteConsumer();
+ ~DummyVoteConsumer() override;
+ DummyVoteConsumer(const DummyVoteConsumer& rhs) = delete;
+ DummyVoteConsumer& operator=(const DummyVoteConsumer& rhs) = delete;
+
+ // VoteConsumer implementation:
+ VoteReceipt<VoteImpl> SubmitVote(util::PassKey<VotingChannel>,
+ voting::VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) override;
+ void ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const VoteImpl& new_vote) override;
+ void VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) override;
+
+ void ExpectInvalidVote(size_t index);
+
+ // Checks that the vote at position |index| is valid, and has the
+ // corresponding |voter|, |context| and |vote_value|. If |reason| is
+ // non-null then it will be validated as well.
+ void ExpectValidVote(size_t index,
+ voting::VoterId<VoteImpl> voter_id,
+ const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason = nullptr);
+
+ VotingChannelFactory<VoteImpl> voting_channel_factory_;
+ std::vector<AcceptedVote> votes_;
+ size_t valid_vote_count_ = 0;
+};
+
+// A dummy voter that allows emitting votes and tracking their receipts.
+template <class VoteImpl>
+class DummyVoter {
+ public:
+ static constexpr char kReason[] = "dummmy reason";
+
+ DummyVoter();
+ ~DummyVoter();
+ DummyVoter(const DummyVoter& rhs) = delete;
+ DummyVoter& operator=(const DummyVoter& rhs) = delete;
+
+ void SetVotingChannel(VotingChannel<VoteImpl>&& voting_channel);
+
+ // Causes the voter to emit a vote for the given |context| and with
+ // the given |vote_value|. The receipt is pushed back onto |receipts_|.
+ void EmitVote(const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason = kReason);
+
+ VotingChannel<VoteImpl> voting_channel_;
+ std::vector<VoteReceipt<VoteImpl>> receipts_;
+};
+
+template <class VoteImpl>
+class DummyVoteObserver : public VoteObserver<VoteImpl> {
+ public:
+ using ContextType = typename VoteImpl::ContextType;
+ using VoteConsumerDefaultImpl = VoteConsumerDefaultImpl<VoteImpl>;
+
+ DummyVoteObserver();
+ ~DummyVoteObserver() override;
+
+ // VoteObserver:
+ void OnVoteSubmitted(voting::VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) override;
+ void OnVoteChanged(voting::VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& new_vote) override;
+ void OnVoteInvalidated(voting::VoterId<VoteImpl> voter_id,
+ const ContextType* context) override;
+
+ bool HasVote(voting::VoterId<VoteImpl> voter_id,
+ const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason = nullptr);
+
+ VoteConsumerDefaultImpl vote_consumer_default_impl_{this};
+ std::map<voting::VoterId<VoteImpl>, std::map<const ContextType*, VoteImpl>>
+ votes_by_voter_id_;
+};
+
+// IMPLEMENTATION
+
+template <class VoteImpl>
+DummyVoteConsumer<VoteImpl>::DummyVoteConsumer()
+ : voting_channel_factory_(this) {}
+
+template <class VoteImpl>
+DummyVoteConsumer<VoteImpl>::~DummyVoteConsumer() = default;
+
+template <class VoteImpl>
+VoteReceipt<VoteImpl> DummyVoteConsumer<VoteImpl>::SubmitVote(
+ util::PassKey<VotingChannel>,
+ voting::VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) {
+ // Accept the vote.
+ votes_.emplace_back(AcceptedVote(this, voter_id, context, vote));
+ EXPECT_FALSE(votes_.back().HasReceipt());
+ EXPECT_TRUE(votes_.back().IsValid());
+ ++valid_vote_count_;
+ EXPECT_LE(valid_vote_count_, votes_.size());
+
+ // Issue a receipt.
+ auto receipt = votes_.back().IssueReceipt();
+ EXPECT_TRUE(votes_.back().HasReceipt());
+ EXPECT_TRUE(votes_.back().IsValid());
+ return receipt;
+}
+
+template <class VoteImpl>
+void DummyVoteConsumer<VoteImpl>::ChangeVote(util::PassKey<AcceptedVote>,
+ AcceptedVote* old_vote,
+ const VoteImpl& new_vote) {
+ // We should own this vote and it should be valid.
+ EXPECT_LE(votes_.data(), old_vote);
+ EXPECT_LT(old_vote, votes_.data() + votes_.size());
+ EXPECT_TRUE(old_vote->IsValid());
+ EXPECT_LT(0u, valid_vote_count_);
+
+ // Update the vote in-place.
+ old_vote->UpdateVote(new_vote);
+}
+
+template <class VoteImpl>
+void DummyVoteConsumer<VoteImpl>::VoteInvalidated(util::PassKey<AcceptedVote>,
+ AcceptedVote* vote) {
+ // We should own this vote.
+ EXPECT_LE(votes_.data(), vote);
+ EXPECT_LT(vote, votes_.data() + votes_.size());
+ EXPECT_FALSE(vote->IsValid());
+ EXPECT_LT(0u, valid_vote_count_);
+ --valid_vote_count_;
+}
+
+template <class VoteImpl>
+void DummyVoteConsumer<VoteImpl>::ExpectInvalidVote(size_t index) {
+ EXPECT_LT(index, votes_.size());
+ const auto& accepted_vote = votes_[index];
+ EXPECT_EQ(this, accepted_vote.consumer());
+ EXPECT_FALSE(accepted_vote.IsValid());
+}
+
+template <class VoteImpl>
+void DummyVoteConsumer<VoteImpl>::ExpectValidVote(
+ size_t index,
+ voting::VoterId<VoteImpl> voter_id,
+ const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason) {
+ EXPECT_LT(index, votes_.size());
+ const auto& accepted_vote = votes_[index];
+ EXPECT_EQ(this, accepted_vote.consumer());
+ EXPECT_TRUE(accepted_vote.IsValid());
+ EXPECT_EQ(voter_id, accepted_vote.voter_id());
+ EXPECT_EQ(context, accepted_vote.context());
+ const auto& vote = accepted_vote.vote();
+ EXPECT_EQ(vote_value, vote.value());
+ EXPECT_TRUE(vote.reason());
+ if (reason)
+ EXPECT_EQ(reason, vote.reason());
+}
+
+template <class VoteImpl>
+constexpr char DummyVoter<VoteImpl>::kReason[];
+
+template <class VoteImpl>
+DummyVoter<VoteImpl>::DummyVoter() = default;
+template <class VoteImpl>
+DummyVoter<VoteImpl>::~DummyVoter() = default;
+
+template <class VoteImpl>
+void DummyVoter<VoteImpl>::SetVotingChannel(
+ VotingChannel<VoteImpl>&& voting_channel) {
+ voting_channel_ = std::move(voting_channel);
+}
+
+template <class VoteImpl>
+void DummyVoter<VoteImpl>::EmitVote(
+ const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason) {
+ EXPECT_TRUE(voting_channel_.IsValid());
+ receipts_.emplace_back(
+ voting_channel_.SubmitVote(context, VoteImpl(vote_value, reason)));
+}
+
+template <class VoteImpl>
+DummyVoteObserver<VoteImpl>::DummyVoteObserver() = default;
+
+template <class VoteImpl>
+DummyVoteObserver<VoteImpl>::~DummyVoteObserver() = default;
+
+template <class VoteImpl>
+void DummyVoteObserver<VoteImpl>::OnVoteSubmitted(VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& vote) {
+ bool inserted = votes_by_voter_id_[voter_id].emplace(context, vote).second;
+ DCHECK(inserted);
+}
+
+template <class VoteImpl>
+void DummyVoteObserver<VoteImpl>::OnVoteChanged(VoterId<VoteImpl> voter_id,
+ const ContextType* context,
+ const VoteImpl& new_vote) {
+ auto it = votes_by_voter_id_[voter_id].find(context);
+ DCHECK(it != votes_by_voter_id_[voter_id].end());
+ it->second = new_vote;
+}
+
+template <class VoteImpl>
+void DummyVoteObserver<VoteImpl>::OnVoteInvalidated(
+ VoterId<VoteImpl> voter_id,
+ const ContextType* context) {
+ auto it = votes_by_voter_id_.find(voter_id);
+ DCHECK(it != votes_by_voter_id_.end());
+
+ std::map<const ContextType*, VoteImpl>& votes = it->second;
+ size_t removed = votes.erase(context);
+ DCHECK_EQ(removed, 1u);
+
+ if (votes.empty())
+ votes_by_voter_id_.erase(it);
+}
+
+template <class VoteImpl>
+bool DummyVoteObserver<VoteImpl>::HasVote(
+ voting::VoterId<VoteImpl> voter_id,
+ const typename VoteImpl::ContextType* context,
+ typename VoteImpl::VoteType vote_value,
+ const char* reason) {
+ if (!base::Contains(votes_by_voter_id_, voter_id))
+ return false;
+
+ std::map<const ContextType*, VoteImpl>& votes = votes_by_voter_id_[voter_id];
+
+ if (!base::Contains(votes, context))
+ return false;
+
+ return votes[context] == VoteImpl(vote_value, reason);
+}
+
+} // namespace test
+} // namespace voting
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_VOTING_H_
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker.cc
new file mode 100644
index 00000000000..c7668312aa6
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker.cc
@@ -0,0 +1,511 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task/task_traits.h"
+#include "base/values.h"
+#include "components/performance_manager/graph/frame_node_impl.h"
+#include "components/performance_manager/graph/process_node_impl.h"
+#include "components/performance_manager/public/execution_context/execution_context_registry.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
+#include "components/performance_manager/public/performance_manager.h"
+#include "components/performance_manager/public/render_process_host_id.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker_internal.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "mojo/public/cpp/bindings/message.h"
+
+namespace performance_manager {
+namespace v8_memory {
+
+namespace {
+
+using ExecutionContextData = internal::ExecutionContextData;
+using ProcessData = internal::ProcessData;
+using RemoteFrameData = internal::RemoteFrameData;
+using V8ContextData = internal::V8ContextData;
+
+// A function that can be bound to as a mojo::ReportBadMessage
+// callback. Only used in testing.
+void FakeReportBadMessageForTesting(const std::string& error) {
+ // This is used in DCHECK death tests, so must use a DCHECK.
+ DCHECK(false) << "Bad mojo message: " << error;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextTracker::ExecutionContextState implementation:
+
+V8ContextTracker::ExecutionContextState::ExecutionContextState(
+ const blink::ExecutionContextToken& token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data)
+ : token(token),
+ iframe_attribution_data(std::move(iframe_attribution_data)) {}
+
+V8ContextTracker::ExecutionContextState::~ExecutionContextState() = default;
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextTracker::V8ContextState implementation:
+
+V8ContextTracker::V8ContextState::V8ContextState(
+ const mojom::V8ContextDescription& description,
+ ExecutionContextState* execution_context_state)
+ : description(description),
+ execution_context_state(execution_context_state) {}
+
+V8ContextTracker::V8ContextState::~V8ContextState() = default;
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextTracker implementation:
+
+V8ContextTracker::V8ContextTracker()
+ : data_store_(std::make_unique<DataStore>()) {}
+
+V8ContextTracker::~V8ContextTracker() = default;
+
+const V8ContextTracker::ExecutionContextState*
+V8ContextTracker::GetExecutionContextState(
+ const blink::ExecutionContextToken& token) const {
+ return data_store_->Get(token);
+}
+
+const V8ContextTracker::V8ContextState* V8ContextTracker::GetV8ContextState(
+ const blink::V8ContextToken& token) const {
+ return data_store_->Get(token);
+}
+
+void V8ContextTracker::OnV8ContextCreated(
+ util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const mojom::V8ContextDescription& description,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) {
+ DCHECK_ON_GRAPH_SEQUENCE(process_node->graph());
+
+ // Validate the |description|.
+ {
+ auto result = ValidateV8ContextDescription(description);
+ if (result != V8ContextDescriptionStatus::kValid) {
+ LOG(ERROR) << "V8ContextDescriptionStatus = " << static_cast<int>(result);
+ mojo::ReportBadMessage("invalid V8ContextDescription");
+ return;
+ }
+ }
+
+ // Validate the |iframe_attribution_data|.
+ {
+ base::Optional<bool> result =
+ ExpectIframeAttributionDataForV8ContextDescription(
+ description, process_node->graph());
+ if (result) {
+ bool expected = *result;
+ bool received = static_cast<bool>(iframe_attribution_data);
+ if (expected != received) {
+ LOG(ERROR) << "IframeAttributionData: expected = " << expected
+ << ", received = " << received;
+ mojo::ReportBadMessage("invalid IframeAttributionData");
+ return;
+ }
+ }
+ }
+
+ // Ensure that the V8Context creation notification isn't repeated.
+ if (data_store_->Get(description.token)) {
+ mojo::ReportBadMessage("repeated OnV8ContextCreated notification");
+ return;
+ }
+
+ auto* process_data = ProcessData::GetOrCreate(process_node);
+
+ // Get or create an ExecutionContextData if necessary. If it doesn't get
+ // committed below it will safely tear itself down.
+ std::unique_ptr<ExecutionContextData> ec_data;
+ ExecutionContextData* raw_ec_data = nullptr;
+ if (description.execution_context_token) {
+ raw_ec_data = data_store_->Get(*description.execution_context_token);
+ if (!raw_ec_data) {
+ ec_data = std::make_unique<ExecutionContextData>(
+ process_data, *description.execution_context_token,
+ std::move(iframe_attribution_data));
+ raw_ec_data = ec_data.get();
+ }
+ }
+
+ if (raw_ec_data && raw_ec_data->process_data() != process_data) {
+ mojo::ReportBadMessage(
+ "OnV8ContextCreated refers to an out-of-process ExecutionContext");
+ return;
+ }
+
+ // Create the V8ContextData.
+ std::unique_ptr<V8ContextData> v8_data =
+ std::make_unique<V8ContextData>(process_data, description, raw_ec_data);
+
+ // Try to commit the objects.
+ if (!data_store_->Pass(std::move(v8_data))) {
+ mojo::ReportBadMessage("Multiple main worlds seen for an ExecutionContext");
+ return;
+ }
+ if (ec_data)
+ data_store_->Pass(std::move(ec_data));
+}
+
+void V8ContextTracker::OnV8ContextDetached(
+ util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const blink::V8ContextToken& v8_context_token) {
+ DCHECK_ON_GRAPH_SEQUENCE(process_node->graph());
+
+ auto* process_data = ProcessData::Get(process_node);
+ auto* v8_data = data_store_->Get(v8_context_token);
+ if (!process_data || !v8_data) {
+ mojo::ReportBadMessage("unexpected OnV8ContextDetached");
+ return;
+ }
+
+ if (!data_store_->MarkDetached(v8_data)) {
+ mojo::ReportBadMessage("repeated OnV8ContextDetached");
+ return;
+ }
+}
+
+void V8ContextTracker::OnV8ContextDestroyed(
+ util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const blink::V8ContextToken& v8_context_token) {
+ DCHECK_ON_GRAPH_SEQUENCE(process_node->graph());
+
+ auto* process_data = ProcessData::Get(process_node);
+ auto* v8_data = data_store_->Get(v8_context_token);
+ if (!process_data || !v8_data) {
+ mojo::ReportBadMessage("unexpected OnV8ContextDestroyed");
+ return;
+ }
+ data_store_->Destroy(v8_context_token);
+}
+
+void V8ContextTracker::OnRemoteIframeAttached(
+ util::PassKey<FrameNodeImpl> key,
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) {
+ DCHECK_ON_GRAPH_SEQUENCE(parent_frame_node->graph());
+
+ // RemoteFrameTokens are issued by the browser to a renderer, so if we receive
+ // an IPC from a renderer using that token, then the corresponding
+ // RenderFrameProxyHost is guaranteed to exist, and the token will resolve to
+ // a RenderFrameHost. Similarly, if the RenderFrameHost exists, then we will
+ // have a representation for it in the graph, as we learn about frames from
+ // the UI thread. The only case where this won't be true is if the frame has
+ // subsequently been torn down (the IPC races with frame death), in which
+ // case it doesn't matter as the corresponding graph nodes are in the process
+ // of being torn down.
+
+ // The data that bounces between threads, bundled up for convenience.
+ struct Data {
+ mojo::ReportBadMessageCallback bad_message_callback;
+ blink::RemoteFrameToken remote_frame_token;
+ mojom::IframeAttributionDataPtr iframe_attribution_data;
+ base::WeakPtr<FrameNode> frame_node;
+ };
+ std::unique_ptr<Data> data(
+ new Data{mojo::GetBadMessageCallback(), remote_frame_token,
+ std::move(iframe_attribution_data), nullptr});
+
+ auto on_pm_seq = base::BindOnce([](std::unique_ptr<Data> data, Graph* graph) {
+ DCHECK(data);
+ DCHECK(graph);
+ DCHECK_ON_GRAPH_SEQUENCE(graph);
+ if (data->frame_node) {
+ auto* frame_node = FrameNodeImpl::FromNode(data->frame_node.get());
+ if (auto* tracker = V8ContextTracker::GetFromGraph(graph)) {
+ tracker->OnRemoteIframeAttachedImpl(
+ std::move(data->bad_message_callback), frame_node,
+ data->remote_frame_token, std::move(data->iframe_attribution_data));
+ }
+ }
+ });
+
+ // Looks up a RFH on the UI sequence, and posts back to |on_pm_seq|.
+ auto on_ui_thread = base::BindOnce([](decltype(on_pm_seq) on_pm_seq,
+ std::unique_ptr<Data> data,
+ RenderProcessHostId rph_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(on_pm_seq);
+ DCHECK(data);
+ if (auto* rfh = content::RenderFrameHost::FromPlaceholderToken(
+ rph_id.value(), data->remote_frame_token.value())) {
+ data->frame_node =
+ PerformanceManager::GetFrameNodeForRenderFrameHost(rfh);
+ PerformanceManager::CallOnGraph(
+ FROM_HERE, base::BindOnce(std::move(on_pm_seq), std::move(data)));
+ }
+ });
+
+ // Posts |on_ui_thread| to the UI sequence.
+ auto rph_id = parent_frame_node->process_node()
+ ->render_process_host_proxy()
+ .render_process_host_id();
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(std::move(on_ui_thread), std::move(on_pm_seq),
+ std::move(data), rph_id));
+}
+
+void V8ContextTracker::OnRemoteIframeDetached(
+ util::PassKey<FrameNodeImpl> key,
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token) {
+ DCHECK_ON_GRAPH_SEQUENCE(parent_frame_node->graph());
+
+ // The data that bounces between threads, bundled up for convenience.
+ struct Data {
+ base::WeakPtr<FrameNodeImpl> parent_frame_node;
+ blink::RemoteFrameToken remote_frame_token;
+ };
+ std::unique_ptr<Data> data(
+ new Data{parent_frame_node->GetWeakPtr(), remote_frame_token});
+
+ auto on_pm_seq = base::BindOnce(
+ [](std::unique_ptr<Data> data, Graph* graph) {
+ DCHECK(data);
+ DCHECK(graph);
+ DCHECK_ON_GRAPH_SEQUENCE(graph);
+ // Only dispatch if the tracker and the frame node both still exist.
+ // Our bounce to the UI thread means either or both of these could have
+ // disappeared in the meantime.
+ if (data->parent_frame_node) {
+ if (auto* tracker = V8ContextTracker::GetFromGraph(graph)) {
+ tracker->OnRemoteIframeDetachedImpl(data->parent_frame_node.get(),
+ data->remote_frame_token);
+ }
+ }
+ },
+ std::move(data));
+
+ auto on_ui_seq = base::BindOnce(
+ [](decltype(on_pm_seq) on_pm_seq) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(on_pm_seq);
+ PerformanceManager::CallOnGraph(FROM_HERE, std::move(on_pm_seq));
+ },
+ std::move(on_pm_seq));
+
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(on_ui_seq));
+}
+
+void V8ContextTracker::OnRemoteIframeAttachedForTesting(
+ FrameNodeImpl* frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) {
+ OnRemoteIframeAttachedImpl(base::BindOnce(&FakeReportBadMessageForTesting),
+ frame_node, remote_frame_token,
+ std::move(iframe_attribution_data));
+}
+
+void V8ContextTracker::OnRemoteIframeDetachedForTesting(
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token) {
+ OnRemoteIframeDetachedImpl(parent_frame_node, remote_frame_token);
+}
+
+size_t V8ContextTracker::GetExecutionContextCountForTesting() const {
+ return data_store_->GetExecutionContextDataCount();
+}
+
+size_t V8ContextTracker::GetV8ContextCountForTesting() const {
+ return data_store_->GetV8ContextDataCount();
+}
+
+size_t V8ContextTracker::GetDestroyedExecutionContextCountForTesting() const {
+ return data_store_->GetDestroyedExecutionContextDataCount();
+}
+
+size_t V8ContextTracker::GetDetachedV8ContextCountForTesting() const {
+ return data_store_->GetDetachedV8ContextDataCount();
+}
+
+void V8ContextTracker::OnBeforeExecutionContextRemoved(
+ const execution_context::ExecutionContext* ec) {
+ DCHECK_ON_GRAPH_SEQUENCE(ec->GetGraph());
+ if (auto* ec_data = data_store_->Get(ec->GetToken()))
+ data_store_->MarkDestroyed(ec_data);
+}
+
+void V8ContextTracker::OnBeforeGraphDestroyed(Graph* graph) {
+ DCHECK_ON_GRAPH_SEQUENCE(graph);
+ // Remove ourselves from the execution context registry observer list here as
+ // it may get torn down before our OnTakenFromGraph is called. This is also
+ // called from "OnTakenFromGraph", so it is resistant to the
+ // ExecutionContextRegistry no longer existing.
+ auto* registry =
+ execution_context::ExecutionContextRegistry::GetFromGraph(graph);
+ if (registry && registry->HasObserver(this))
+ registry->RemoveObserver(this);
+}
+
+void V8ContextTracker::OnPassedToGraph(Graph* graph) {
+ DCHECK_ON_GRAPH_SEQUENCE(graph);
+
+ graph->AddGraphObserver(this);
+ graph->AddProcessNodeObserver(this);
+ graph->RegisterObject(this);
+ graph->GetNodeDataDescriberRegistry()->RegisterDescriber(this,
+ "V8ContextTracker");
+ auto* registry =
+ execution_context::ExecutionContextRegistry::GetFromGraph(graph);
+ // We expect the registry to exist before we are passed to the graph.
+ DCHECK(registry);
+ registry->AddObserver(this);
+}
+
+void V8ContextTracker::OnTakenFromGraph(Graph* graph) {
+ DCHECK_ON_GRAPH_SEQUENCE(graph);
+
+ // Call OnBeforeGraphDestroyed as well. This unregisters us from the
+ // ExecutionContextRegistry in case we're being removed from the graph
+ // prior to its destruction.
+ OnBeforeGraphDestroyed(graph);
+
+ graph->GetNodeDataDescriberRegistry()->UnregisterDescriber(this);
+ graph->UnregisterObject(this);
+ graph->RemoveProcessNodeObserver(this);
+ graph->RemoveGraphObserver(this);
+}
+
+base::Value V8ContextTracker::DescribeFrameNodeData(
+ const FrameNode* node) const {
+ DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
+
+ size_t v8_context_count = 0;
+ const auto* ec_data =
+ data_store_->Get(blink::ExecutionContextToken(node->GetFrameToken()));
+ if (ec_data)
+ v8_context_count = ec_data->v8_context_count();
+
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetIntKey("v8_context_count", v8_context_count);
+ return dict;
+}
+
+base::Value V8ContextTracker::DescribeProcessNodeData(
+ const ProcessNode* node) const {
+ DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
+
+ size_t v8_context_count = 0;
+ size_t detached_v8_context_count = 0;
+ size_t execution_context_count = 0;
+ size_t destroyed_execution_context_count = 0;
+ const auto* process_data = ProcessData::Get(ProcessNodeImpl::FromNode(node));
+ if (process_data) {
+ v8_context_count = process_data->GetV8ContextDataCount();
+ detached_v8_context_count = process_data->GetDetachedV8ContextDataCount();
+ execution_context_count = process_data->GetExecutionContextDataCount();
+ destroyed_execution_context_count =
+ process_data->GetDestroyedExecutionContextDataCount();
+ }
+
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetIntKey("v8_context_count", v8_context_count);
+ dict.SetIntKey("detached_v8_context_count", detached_v8_context_count);
+ dict.SetIntKey("execution_context_count", execution_context_count);
+ dict.SetIntKey("destroyed_execution_context_count",
+ destroyed_execution_context_count);
+ return dict;
+}
+
+base::Value V8ContextTracker::DescribeWorkerNodeData(
+ const WorkerNode* node) const {
+ DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
+ size_t v8_context_count = 0;
+ const auto* ec_data =
+ data_store_->Get(ToExecutionContextToken(node->GetWorkerToken()));
+ if (ec_data)
+ v8_context_count = ec_data->v8_context_count();
+
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetIntKey("v8_context_count", v8_context_count);
+ return dict;
+}
+
+void V8ContextTracker::OnBeforeProcessNodeRemoved(const ProcessNode* node) {
+ DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
+ auto* process_node = ProcessNodeImpl::FromNode(node);
+ auto* process_data = ProcessData::Get(process_node);
+ if (process_data)
+ process_data->TearDown();
+}
+
+void V8ContextTracker::OnRemoteIframeAttachedImpl(
+ mojo::ReportBadMessageCallback bad_message_callback,
+ FrameNodeImpl* frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data) {
+ DCHECK(bad_message_callback);
+ DCHECK_ON_GRAPH_SEQUENCE(frame_node->graph());
+
+ if (data_store_->Get(remote_frame_token)) {
+ std::move(bad_message_callback).Run("repeated OnRemoteIframeAttached");
+ return;
+ }
+
+ // Get or create an ExecutionContextData if necessary. If it doesn't get
+ // committed below it will safely tear itself down.
+ auto* process_data = ProcessData::GetOrCreate(frame_node->process_node());
+ std::unique_ptr<ExecutionContextData> ec_data;
+ blink::ExecutionContextToken ec_token(frame_node->frame_token());
+ auto* raw_ec_data = data_store_->Get(ec_token);
+ if (!raw_ec_data) {
+ ec_data =
+ std::make_unique<ExecutionContextData>(process_data, ec_token, nullptr);
+ raw_ec_data = ec_data.get();
+ }
+
+ if (raw_ec_data->remote_frame_data() ||
+ raw_ec_data->iframe_attribution_data) {
+ std::move(bad_message_callback).Run("unexpected OnRemoteIframeAttached");
+ return;
+ }
+
+ // Attach the iframe data to the ExecutionContextData.
+ raw_ec_data->iframe_attribution_data = std::move(iframe_attribution_data);
+
+ // Create the RemoteFrameData reference to this context.
+ auto* parent_process_data =
+ ProcessData::GetOrCreate(frame_node->parent_frame_node()->process_node());
+ std::unique_ptr<RemoteFrameData> rf_data = std::make_unique<RemoteFrameData>(
+ parent_process_data, remote_frame_token, raw_ec_data);
+
+ // Commit the objects.
+ data_store_->Pass(std::move(rf_data));
+ if (ec_data)
+ data_store_->Pass(std::move(ec_data));
+}
+
+void V8ContextTracker::OnRemoteIframeDetachedImpl(
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token) {
+ DCHECK_ON_GRAPH_SEQUENCE(parent_frame_node->graph());
+
+ // Look up the RemoteFrameData. This can fail because the notification to
+ // clean up RemoteFrameData can race with process death, so ignore the message
+ // if the data has already been cleaned up.
+ auto* rf_data = data_store_->Get(remote_frame_token);
+ if (!rf_data)
+ return;
+
+ data_store_->Destroy(remote_frame_token);
+}
+
+} // namespace v8_memory
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker.h
new file mode 100644
index 00000000000..b4feae14b7d
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker.h
@@ -0,0 +1,248 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_H_
+
+#include <memory>
+
+#include "base/util/type_safety/pass_key.h"
+#include "components/performance_manager/public/execution_context/execution_context.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/graph_registered.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
+#include "components/performance_manager/public/graph/process_node.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+
+class FrameNodeImpl;
+class ProcessNodeImpl;
+
+namespace v8_memory {
+
+// Forward declaration.
+namespace internal {
+class V8ContextTrackerDataStore;
+} // namespace internal
+
+// A class that tracks individual V8Contexts in renderers as they go through
+// their lifecycle. This tracks information such as detached (leaked) contexts
+// and remote frame attribution, for surfacing in the performance.measureMemory
+// API. This information is tracked per-process in ProcessNode-attached data.
+// The tracker lets you query a V8ContextToken and retrieve information about
+// that context, including its iframe attributes and associated
+// ExecutionContext.
+//
+// Note that this component relies on the ExecutionContextRegistry having been
+// added to the Graph.
+class V8ContextTracker final
+ : public execution_context::ExecutionContextObserverDefaultImpl,
+ public GraphObserver,
+ public GraphOwned,
+ public GraphRegisteredImpl<V8ContextTracker>,
+ public NodeDataDescriberDefaultImpl,
+ public ProcessNode::ObserverDefaultImpl {
+ public:
+ using DataStore = internal::V8ContextTrackerDataStore;
+
+ // Data about an individual ExecutionContext. Note that this information can
+ // outlive the ExecutionContext itself, and in that case it stores information
+ // about the last known state of the ExecutionContext prior to it being
+ // torn down in a renderer.
+ struct ExecutionContextState {
+ ExecutionContextState() = delete;
+ ExecutionContextState(
+ const blink::ExecutionContextToken& token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+ ExecutionContextState(const ExecutionContextState&) = delete;
+ ExecutionContextState& operator=(const ExecutionContextState&) = delete;
+ virtual ~ExecutionContextState();
+
+ // Returns the associated execution_context::ExecutionContext (which wraps
+ // the underlying FrameNode or WorkerNode associated with this context) *if*
+ // the node is available.
+ const execution_context::ExecutionContext* GetExecutionContext() const;
+
+ // The token identifying this context.
+ const blink::ExecutionContextToken token;
+
+ // The iframe attribution data most recently associated with this context.
+ // This is sometimes only available asynchronously so is optional. Note that
+ // this value can change over time, but will generally reflect the most up
+ // to date data (with some lag).
+ mojom::IframeAttributionDataPtr iframe_attribution_data;
+
+ // Whether or not the corresponding blink::ExecutionContext has been
+ // destroyed. This occurs when the main V8Context associated with this
+ // execution context has itself become detached. This starts as false and
+ // can transition to true exactly once.
+ bool destroyed = false;
+ };
+
+ struct V8ContextState {
+ V8ContextState() = delete;
+ V8ContextState(const mojom::V8ContextDescription& description,
+ ExecutionContextState* execution_context_state);
+ V8ContextState(const V8ContextState&) = delete;
+ V8ContextState& operator=(const V8ContextState&) = delete;
+ virtual ~V8ContextState();
+
+ // The full description of this context.
+ const mojom::V8ContextDescription description;
+
+ // A pointer to the upstream ExecutionContextState that this V8Context is
+ // associated with. Note that this can be nullptr for V8Contexts that are
+ // not associated with an ExecutionContext.
+ ExecutionContextState* const execution_context_state;
+
+ // Whether or not this context is detached. A context becomes detached
+ // when the blink::ExecutionContext it was associated with is torn down.
+ // When a V8Context remains detached for a long time (is not collected by
+ // GC) it is effectively a leak (it is being kept alive by a stray
+ // cross-context reference). This starts as false and can transition to
+ // true exactly once.
+ bool detached = false;
+ };
+
+ V8ContextTracker();
+ ~V8ContextTracker() final;
+
+ DataStore* data_store() const { return data_store_.get(); }
+
+ // Returns the ExecutionContextState for the given token, nullptr if none
+ // exists.
+ const ExecutionContextState* GetExecutionContextState(
+ const blink::ExecutionContextToken& token) const;
+
+ // Returns V8ContextState for the given token, nullptr if none exists.
+ const V8ContextState* GetV8ContextState(
+ const blink::V8ContextToken& token) const;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // The following functions handle inbound IPC, and are only meant to be
+ // called from ProcessNodeImpl and FrameNodeImpl (hence the use of PassKey).
+
+ // Notifies the context tracker of a V8Context being created in a renderer
+ // process. If the context is associated with an ExecutionContext (EC) then
+ // |description.execution_context_token| will be provided. If the EC is a
+ // frame, and the parent of that frame is also in the same process, then
+ // |iframe_attribution_data| will be provided, otherwise these will be empty.
+ // In the case where they are empty the iframe data will be provided by a
+ // separate call to OnIframeAttached() from the process hosting the
+ // parent frame. See the V8ContextWorldType enum for a description of the
+ // relationship between world types, world names and execution contexts.
+ void OnV8ContextCreated(
+ util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const mojom::V8ContextDescription& description,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+
+ // Notifies the tracker that a V8Context is now detached from its associated
+ // ExecutionContext (if one was provided during OnV8ContextCreated). If the
+ // context stays detached for a long time this is indicative of a Javascript
+ // leak, with the context being kept alive by a stray reference from another
+ // context. All ExecutionContext-associated V8Contexts will have this method
+ // called before they are destroyed, and it will not be called for other
+ // V8Contexts (they are never considered detached).
+ void OnV8ContextDetached(util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const blink::V8ContextToken& v8_context_token);
+
+ // Notifies the tracker that a V8Context has been garbage collected. This will
+ // only be called after OnV8ContextDetached if the OnV8ContextCreated had a
+ // non-empty |execution_context_token|.
+ void OnV8ContextDestroyed(util::PassKey<ProcessNodeImpl> key,
+ ProcessNodeImpl* process_node,
+ const blink::V8ContextToken& v8_context_token);
+
+ // Notifies the tracker that a RemoteFrame child with a LocalFrame parent was
+ // created in a renderer, providing the iframe.id and iframe.src from the
+ // parent point of view. This will decorate the ExecutionContextData of the
+ // appropriate child frame. We require the matching OnRemoteIframeDetached to
+ // be called for bookkeeping. This should only be called once for a given
+ // |remote_frame_token|.
+ void OnRemoteIframeAttached(
+ util::PassKey<FrameNodeImpl> key,
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+
+ // TODO(chrisha): Add OnRemoteIframeAttributesChanged support.
+
+ // Notifies the tracker that a RemoteFrame child with a LocalFrame parent was
+ // detached from an iframe element in a renderer. This is used to cleanup
+ // iframe data that is being tracked due to a previous call to
+ // OnIframeAttached, unless the data was adopted by a call to
+ // OnV8ContextCreated. Should only be called once for a given
+ // |remote_frame_token|, and only after a matching "OnRemoteIframeAttached"
+ // call.
+ void OnRemoteIframeDetached(
+ util::PassKey<FrameNodeImpl> key,
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // The following functions are for testing only.
+
+ void OnRemoteIframeAttachedForTesting(
+ FrameNodeImpl* frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+
+ void OnRemoteIframeDetachedForTesting(
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token);
+
+ // System wide metrics.
+ size_t GetExecutionContextCountForTesting() const;
+ size_t GetV8ContextCountForTesting() const;
+ size_t GetDestroyedExecutionContextCountForTesting() const;
+ size_t GetDetachedV8ContextCountForTesting() const;
+
+ private:
+ // Implementation of execution_context::ExecutionContextObserverDefaultImpl.
+ void OnBeforeExecutionContextRemoved(
+ const execution_context::ExecutionContext* ec) final;
+
+ // Implementation of GraphObserver.
+ void OnBeforeGraphDestroyed(Graph* graph) final;
+
+ // Implementation of GraphOwned.
+ void OnPassedToGraph(Graph* graph) final;
+ void OnTakenFromGraph(Graph* graph) final;
+
+ // Implementation of NodeDataDescriber. We have things to say about
+ // execution contexts (frames and workers), as well as processes.
+ base::Value DescribeFrameNodeData(const FrameNode* node) const final;
+ base::Value DescribeProcessNodeData(const ProcessNode* node) const final;
+ base::Value DescribeWorkerNodeData(const WorkerNode* node) const final;
+
+ // Implementation of ProcessNode::ObserverDefaultImpl.
+ void OnBeforeProcessNodeRemoved(const ProcessNode* node) final;
+
+ // OnIframeAttached bounces over to the UI thread to
+ // lookup the RenderFrameHost* associated with a given RemoteFrameToken,
+ // landing here.
+ void OnRemoteIframeAttachedImpl(
+ mojo::ReportBadMessageCallback bad_message_callback,
+ FrameNodeImpl* frame_node,
+ const blink::RemoteFrameToken& remote_frame_token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+
+ // To maintain strict ordering with OnRemoteIframeAttached events, detached
+ // events also detour through the UI thread to arrive here.
+ void OnRemoteIframeDetachedImpl(
+ FrameNodeImpl* parent_frame_node,
+ const blink::RemoteFrameToken& remote_frame_token);
+
+ // Stores Chrome-wide data store used by the tracking.
+ std::unique_ptr<DataStore> data_store_;
+};
+
+} // namespace v8_memory
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_H_
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
new file mode 100644
index 00000000000..ba43fbca138
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
@@ -0,0 +1,113 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker.h"
+
+#include <memory>
+
+#include "base/strings/stringprintf.h"
+#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace performance_manager {
+namespace v8_memory {
+
+class V8ContextTrackerTest : public PerformanceManagerBrowserTestHarness {
+ public:
+ using Super = PerformanceManagerBrowserTestHarness;
+
+ V8ContextTrackerTest() = default;
+ ~V8ContextTrackerTest() override = default;
+
+ void OnGraphCreated(Graph* graph) override {
+ graph->PassToGraph(
+ std::make_unique<execution_context::ExecutionContextRegistryImpl>());
+ graph->PassToGraph(std::make_unique<V8ContextTracker>());
+ }
+
+ void ExpectCounts(size_t v8_context_count,
+ size_t execution_context_count,
+ size_t detached_v8_context_count,
+ size_t destroyed_execution_context_count) {
+ RunInGraph([&](Graph* graph) {
+ auto* v8ct = V8ContextTracker::GetFromGraph(graph);
+ ASSERT_TRUE(v8ct);
+ EXPECT_EQ(v8_context_count, v8ct->GetV8ContextCountForTesting());
+ EXPECT_EQ(execution_context_count,
+ v8ct->GetExecutionContextCountForTesting());
+ EXPECT_EQ(detached_v8_context_count,
+ v8ct->GetDetachedV8ContextCountForTesting());
+ EXPECT_EQ(destroyed_execution_context_count,
+ v8ct->GetDestroyedExecutionContextCountForTesting());
+ });
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, AboutBlank) {
+ ExpectCounts(0, 0, 0, 0);
+ ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
+ ExpectCounts(1, 1, 0, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameDocNavigation) {
+ ExpectCounts(0, 0, 0, 0);
+ GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
+ ASSERT_TRUE(NavigateToURL(shell(), urla));
+ ExpectCounts(2, 2, 0, 0);
+
+ // Get pointers to the RFHs for each frame.
+ auto* contents = shell()->web_contents();
+ content::RenderFrameHost* rfha = contents->GetMainFrame();
+ content::RenderFrameHost* rfhb = nullptr;
+ auto frames = contents->GetAllFrames();
+ ASSERT_EQ(2u, frames.size());
+ for (auto* rfh : contents->GetAllFrames()) {
+ if (rfh != rfha)
+ rfhb = rfh;
+ }
+
+ // Execute a same document navigation in the child frame. This causes a
+ // v8 context to be detached, and new context attached to the execution
+ // context. So there will remain 2 execution contexts, there will be 3
+ // v8 contexts, 1 one of which is detached.
+ GURL urlb(embedded_test_server()->GetURL("b.com", "/b.html?foo=bar"));
+ ASSERT_TRUE(ExecJs(
+ rfhb, base::StringPrintf("location.href = \"%s\"", urlb.spec().c_str())));
+ WaitForLoad(contents);
+
+ ExpectCounts(3, 2, 1, 0);
+}
+
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, DetachedContext) {
+ ExpectCounts(0, 0, 0, 0);
+ GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_a.html"));
+ ASSERT_TRUE(NavigateToURL(shell(), urla));
+ ExpectCounts(2, 2, 0, 0);
+
+ // Get pointers to the RFHs for each frame.
+ auto* contents = shell()->web_contents();
+ content::RenderFrameHost* rfha = contents->GetMainFrame();
+
+ // Keep a pointer to the window associated with the child iframe, but
+ // unload it.
+ ASSERT_TRUE(ExecJs(rfha,
+ "let iframe = document.getElementsByTagName('iframe')[0]; "
+ "document.body.leakyRef = iframe.contentWindow.window; "
+ "iframe.parentNode.removeChild(iframe); "
+ "console.log('detached and leaked iframe');"));
+
+ ExpectCounts(2, 2, 1, 1);
+}
+
+} // namespace v8_memory
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc
index 00b61bdd24e..5406a7eed93 100644
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc
@@ -10,7 +10,7 @@
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/public/execution_context/execution_context.h"
#include "components/performance_manager/public/execution_context/execution_context_registry.h"
-#include "components/performance_manager/v8_memory/v8_context_tracker_types.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
namespace performance_manager {
namespace v8_memory {
@@ -21,14 +21,21 @@ bool IsSynchronousIframeAttributionDataExpected(
const execution_context::ExecutionContext* ec) {
DCHECK(ec);
auto* frame = ec->GetFrameNode();
+ // We only expect iframe data for frames...
if (!frame)
return false;
+ // ... that aren't main frames (have a parent) ...
if (frame->IsMainFrame())
return false;
- // Iframe data is expected if this node is in the same process as its
- // parent.
- return frame->GetProcessNode() ==
- frame->GetParentFrameNode()->GetProcessNode();
+ auto* parent = frame->GetParentFrameNode();
+ DCHECK(parent);
+ // ... where the parent is hosted in the same process ...
+ if (frame->GetProcessNode() != parent->GetProcessNode())
+ return false;
+ // ... and where they are both in the same site instance (implying they are
+ // both in the same frame-tree and know directly of each other's LocalFrame
+ // rather then communicating via a RemoteFrame and a RenderFrameProxy).
+ return frame->GetSiteInstanceId() == parent->GetSiteInstanceId();
}
} // namespace
@@ -76,6 +83,12 @@ bool IsWorkletToken(const blink::ExecutionContextToken& token) {
token.Is<blink::PaintWorkletToken>();
}
+bool IsWorkerToken(const blink::ExecutionContextToken& token) {
+ return token.Is<blink::DedicatedWorkerToken>() ||
+ token.Is<blink::ServiceWorkerToken>() ||
+ token.Is<blink::SharedWorkerToken>();
+}
+
const execution_context::ExecutionContext* GetExecutionContext(
const blink::ExecutionContextToken& token,
Graph* graph) {
@@ -86,9 +99,9 @@ const execution_context::ExecutionContext* GetExecutionContext(
}
V8ContextDescriptionStatus ValidateV8ContextDescription(
- const V8ContextDescription& description) {
+ const mojom::V8ContextDescription& description) {
switch (description.world_type) {
- case V8ContextWorldType::kMain: {
+ case mojom::V8ContextWorldType::kMain: {
if (description.world_name)
return V8ContextDescriptionStatus::kUnexpectedWorldName;
if (!description.execution_context_token)
@@ -97,7 +110,7 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
return V8ContextDescriptionStatus::kMissingLocalFrameToken;
} break;
- case V8ContextWorldType::kWorkerOrWorklet: {
+ case mojom::V8ContextWorldType::kWorkerOrWorklet: {
if (description.world_name)
return V8ContextDescriptionStatus::kUnexpectedWorldName;
if (!description.execution_context_token)
@@ -106,7 +119,7 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
return V8ContextDescriptionStatus::kUnexpectedLocalFrameToken;
} break;
- case V8ContextWorldType::kExtension: {
+ case mojom::V8ContextWorldType::kExtension: {
if (!description.world_name)
return V8ContextDescriptionStatus::kMissingWorldName;
if (!IsValidExtensionId(description.world_name.value()))
@@ -118,7 +131,7 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
return V8ContextDescriptionStatus::kUnexpectedWorkletToken;
} break;
- case V8ContextWorldType::kIsolated: {
+ case mojom::V8ContextWorldType::kIsolated: {
// World names are optional in isolated worlds.
// Only frame and workers can have isolated worlds, *not* worklets.
if (!description.execution_context_token)
@@ -127,7 +140,7 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
return V8ContextDescriptionStatus::kUnexpectedWorkletToken;
} break;
- case V8ContextWorldType::kInspector: {
+ case mojom::V8ContextWorldType::kInspector: {
if (description.world_name)
return V8ContextDescriptionStatus::kUnexpectedWorldName;
// Devtools can only inject into frames and workers, *not* worklets.
@@ -137,7 +150,7 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
return V8ContextDescriptionStatus::kUnexpectedWorkletToken;
} break;
- case V8ContextWorldType::kRegExp: {
+ case mojom::V8ContextWorldType::kRegExp: {
// Regexp worlds have no additional data.
if (description.world_name)
return V8ContextDescriptionStatus::kUnexpectedWorldName;
@@ -150,10 +163,10 @@ V8ContextDescriptionStatus ValidateV8ContextDescription(
}
base::Optional<bool> ExpectIframeAttributionDataForV8ContextDescription(
- const V8ContextDescription& description,
+ const mojom::V8ContextDescription& description,
Graph* graph) {
switch (description.world_type) {
- case V8ContextWorldType::kMain: {
+ case mojom::V8ContextWorldType::kMain: {
// There's no guarantee that the actual ExecutionContext has yet been
// created from our POV as there's a race between V8Context creation
// notifications and node creations. But if it does exist, we sanity check
@@ -167,16 +180,32 @@ base::Optional<bool> ExpectIframeAttributionDataForV8ContextDescription(
}
} break;
- case V8ContextWorldType::kWorkerOrWorklet:
- case V8ContextWorldType::kExtension:
- case V8ContextWorldType::kIsolated:
- case V8ContextWorldType::kInspector:
- case V8ContextWorldType::kRegExp: {
+ case mojom::V8ContextWorldType::kWorkerOrWorklet:
+ case mojom::V8ContextWorldType::kExtension:
+ case mojom::V8ContextWorldType::kIsolated:
+ case mojom::V8ContextWorldType::kInspector:
+ case mojom::V8ContextWorldType::kRegExp: {
} break;
}
return false;
}
+void MarkedObjectCount::Mark() {
+ DCHECK_LT(marked_count_, count_);
+ ++marked_count_;
+}
+
+void MarkedObjectCount::Decrement(bool marked) {
+ DCHECK_LT(0u, count_);
+ if (marked) {
+ DCHECK_LT(0u, marked_count_);
+ --marked_count_;
+ } else {
+ DCHECK_LT(marked_count_, count_);
+ }
+ --count_;
+}
+
} // namespace v8_memory
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
index 0eaca296e44..60d25a1d2c3 100644
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
@@ -20,9 +20,11 @@ namespace execution_context {
class ExecutionContext;
} // namespace execution_context
-namespace v8_memory {
+namespace mojom {
+class V8ContextDescription;
+} // namespace mojom
-struct V8ContextDescription;
+namespace v8_memory {
// Helper function to convert a WorkerToken to an ExecutionContext token.
// TODO(crbug.com/1126285): There should be automatic type conversion for this
@@ -43,6 +45,10 @@ bool IsValidExtensionId(const std::string& s) WARN_UNUSED_RESULT;
bool IsWorkletToken(const blink::ExecutionContextToken& token)
WARN_UNUSED_RESULT;
+// Returns true if an ExecutionContextToken corresponds to a worker.
+bool IsWorkerToken(const blink::ExecutionContextToken& token)
+ WARN_UNUSED_RESULT;
+
// Looks up the execution context corresponding to the given token. Note that
// the ExecutionContextRegistry must be installed on the graph.
const execution_context::ExecutionContext* GetExecutionContext(
@@ -68,16 +74,71 @@ enum class V8ContextDescriptionStatus {
// Validates the given V8ContextDescription.
V8ContextDescriptionStatus ValidateV8ContextDescription(
- const V8ContextDescription& description) WARN_UNUSED_RESULT;
+ const mojom::V8ContextDescription& description) WARN_UNUSED_RESULT;
// Determines whether or not IframeAttributionData is expected to accompany the
// provided V8ContextDescription. This is not always able to be determined, in
// which case base::nullopt will be returned. It is assumed that the
// |description| has previously been validated.
base::Optional<bool> ExpectIframeAttributionDataForV8ContextDescription(
- const V8ContextDescription& description,
+ const mojom::V8ContextDescription& description,
Graph* graph) WARN_UNUSED_RESULT;
+// Small helper class for maintaining a count of objects that are optionally
+// "marked".
+class MarkedObjectCount {
+ public:
+ MarkedObjectCount() = default;
+ MarkedObjectCount(const MarkedObjectCount&) = delete;
+ MarkedObjectCount& operator=(const MarkedObjectCount&) = delete;
+ ~MarkedObjectCount() = default;
+
+ size_t count() const { return count_; }
+ size_t marked_count() const { return marked_count_; }
+
+ void Increment() { ++count_; }
+ void Mark();
+ void Decrement(bool marked);
+
+ private:
+ size_t marked_count_ = 0;
+ size_t count_ = 0;
+};
+
+// Helper class for maintaining a pair of context counts for both
+// ExecutionContexts and V8Contexts.
+class ContextCounts {
+ public:
+ ContextCounts() = default;
+ ContextCounts(const ContextCounts&) = delete;
+ ContextCounts& operator=(const ContextCounts&) = delete;
+ ~ContextCounts() = default;
+
+ size_t GetExecutionContextDataCount() const { return ec_count_.count(); }
+ size_t GetDestroyedExecutionContextDataCount() const {
+ return ec_count_.marked_count();
+ }
+ void IncrementExecutionContextDataCount() { ec_count_.Increment(); }
+ void MarkExecutionContextDataDestroyed() { ec_count_.Mark(); }
+ void DecrementExecutionContextDataCount(bool destroyed) {
+ ec_count_.Decrement(destroyed);
+ }
+
+ size_t GetV8ContextDataCount() const { return v8_count_.count(); }
+ size_t GetDetachedV8ContextDataCount() const {
+ return v8_count_.marked_count();
+ }
+ void IncrementV8ContextDataCount() { v8_count_.Increment(); }
+ void MarkV8ContextDataDetached() { v8_count_.Mark(); }
+ void DecrementV8ContextDataCount(bool detached) {
+ v8_count_.Decrement(detached);
+ }
+
+ private:
+ MarkedObjectCount ec_count_;
+ MarkedObjectCount v8_count_;
+};
+
} // namespace v8_memory
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers_unittest.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers_unittest.cc
index e099e17796c..429ffd11824 100644
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers_unittest.cc
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers_unittest.cc
@@ -8,9 +8,9 @@
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/public/execution_context/execution_context.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
#include "components/performance_manager/test_support/graph_test_harness.h"
#include "components/performance_manager/test_support/mock_graphs.h"
-#include "components/performance_manager/v8_memory/v8_context_tracker_types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
@@ -34,7 +34,7 @@ class V8ContextTrackerHelpersTest : public GraphTestHarness {
execution_context::ExecutionContextRegistry* const registry = nullptr;
MockSinglePageWithMultipleProcessesGraph mock_graph;
- IframeAttributionData fake_iframe_attribution_data;
+ mojom::IframeAttributionData fake_iframe_attribution_data;
};
} // namespace
@@ -107,8 +107,8 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionMainWorld) {
4));
// A valid description of a main frame.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt, mock_graph.frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -116,8 +116,8 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionMainWorld) {
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
// A valid description of a cross-process child frame.
- desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt, mock_graph.child_frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -125,8 +125,8 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionMainWorld) {
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
// A valid description of a same-process child frame.
- desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt, child_frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -136,30 +136,30 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionMainWorld) {
// A valid description of a frame, but one that doesn't have a corresponding
// entry in the graph. In this case its impossible to determine if
// IframeAttributionData should accompany the V8ContextDescription.
- desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt, blink::LocalFrameToken());
EXPECT_EQ(base::nullopt,
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
// A main-world should not have a world name.
EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorldName,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain, kWorldName,
- mock_graph.frame->frame_token())));
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
+ kWorldName, mock_graph.frame->frame_token())));
// A main world must have an |execution_context_token|.
EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt,
/* execution_context_token */ base::nullopt)));
// A main world must have an blink::LocalFrameToken.
blink::ExecutionContextToken worker_token((blink::SharedWorkerToken()));
EXPECT_EQ(V8ContextDescriptionStatus::kMissingLocalFrameToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kMain,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
/* world_name */ base::nullopt, worker_token)));
}
@@ -170,8 +170,8 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionWorkerWorld) {
"browser_context", worker_token);
// A valid worker description.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kWorkerOrWorklet,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
/* world_name */ base::nullopt, worker_token);
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -179,30 +179,33 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionWorkerWorld) {
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
// A worker should not have a world name.
- EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorldName,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kWorkerOrWorklet,
- kWorldName, worker_token)));
+ EXPECT_EQ(
+ V8ContextDescriptionStatus::kUnexpectedWorldName,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
+ kWorldName, worker_token)));
// A worker must have an |execution_context_token|.
- EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kWorkerOrWorklet,
- /* world_name */ base::nullopt,
- /* execution_context_token */ base::nullopt)));
+ EXPECT_EQ(
+ V8ContextDescriptionStatus::kMissingExecutionContextToken,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ base::nullopt)));
// A worker must have a valid worker token, not a LocalFrameToken.
- EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedLocalFrameToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kWorkerOrWorklet,
- /* world_name */ base::nullopt, blink::LocalFrameToken())));
+ EXPECT_EQ(
+ V8ContextDescriptionStatus::kUnexpectedLocalFrameToken,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
+ /* world_name */ base::nullopt, blink::LocalFrameToken())));
}
TEST_F(V8ContextTrackerHelpersTest,
ValidateV8ContextDescriptionExtensionWorld) {
// A valid extension description.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kExtension,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
kValidExtensionWorldName, mock_graph.frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -212,43 +215,43 @@ TEST_F(V8ContextTrackerHelpersTest,
// An extension must have a world name.
EXPECT_EQ(
V8ContextDescriptionStatus::kMissingWorldName,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kExtension,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
/* world_name */ base::nullopt, mock_graph.frame->frame_token())));
// An invalid extension name should fail.
EXPECT_EQ(V8ContextDescriptionStatus::kInvalidExtensionWorldName,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kExtension,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
kInvalidExtensionWorldName, mock_graph.frame->frame_token())));
// An extension must have an |execution_context_token|.
EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kExtension,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
kValidExtensionWorldName,
/* execution_context_token */ base::nullopt)));
// An extension can't inject into a worklet.
EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kExtension,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
kValidExtensionWorldName, blink::AudioWorkletToken())));
}
TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionIsolatedWorld) {
// An isolated world may or may not have a |world_name|.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kIsolated,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
/* world_name */ base::nullopt, mock_graph.frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
EXPECT_EQ(false,
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
- desc = V8ContextDescription::Create(blink::V8ContextToken(),
- V8ContextWorldType::kIsolated, kWorldName,
- mock_graph.frame->frame_token());
+ desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated, kWorldName,
+ mock_graph.frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
EXPECT_EQ(false,
@@ -256,23 +259,23 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionIsolatedWorld) {
// An isolated world must have an |execution_context_token|
EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kIsolated,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
/* world_name */ base::nullopt,
/* execution_context_token */ base::nullopt)));
// An isolated world can not inject into a worklet.
EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kIsolated,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
/* world_name */ base::nullopt, blink::AudioWorkletToken())));
}
TEST_F(V8ContextTrackerHelpersTest,
ValidateV8ContextDescriptionInspectorWorld) {
// A valid inspector world.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kInspector,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
/* world_name */ base::nullopt, mock_graph.frame->frame_token());
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
ValidateV8ContextDescription(desc));
@@ -281,22 +284,22 @@ TEST_F(V8ContextTrackerHelpersTest,
// An inspector world must have an |execution_context_token|
EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kInspector,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
/* world_name */ base::nullopt,
/* execution_context_token */ base::nullopt)));
// An inspector world can not inject into a worklet.
EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kInspector,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
/* world_name */ base::nullopt, blink::AudioWorkletToken())));
}
TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionRegExpWorld) {
// A valid regexp world.
- auto desc = V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kRegExp,
+ auto desc = mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
/* world_name */ base::nullopt,
/* execution_context_token */ base::nullopt);
EXPECT_EQ(V8ContextDescriptionStatus::kValid,
@@ -305,17 +308,17 @@ TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionRegExpWorld) {
ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
// A regexp world must not have a |world_name|.
- EXPECT_EQ(
- V8ContextDescriptionStatus::kUnexpectedWorldName,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kRegExp, kWorldName,
- /* execution_context_token */ base::nullopt)));
+ EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorldName,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
+ kWorldName,
+ /* execution_context_token */ base::nullopt)));
// A regexp world must not have an |execution_context_token|.
EXPECT_EQ(
V8ContextDescriptionStatus::kUnexpectedExecutionContextToken,
- ValidateV8ContextDescription(V8ContextDescription::Create(
- blink::V8ContextToken(), V8ContextWorldType::kRegExp,
+ ValidateV8ContextDescription(mojom::V8ContextDescription(
+ blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
/* world_name */ base::nullopt, mock_graph.frame->frame_token())));
}
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.cc
new file mode 100644
index 00000000000..1866d745f43
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.cc
@@ -0,0 +1,449 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker_internal.h"
+
+#include <utility>
+
+#include "base/check.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
+
+namespace performance_manager {
+namespace v8_memory {
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// ExecutionContextData implementation:
+
+ExecutionContextData::ExecutionContextData(
+ ProcessData* process_data,
+ const blink::ExecutionContextToken& token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data)
+ : ExecutionContextState(token, std::move(iframe_attribution_data)),
+ process_data_(process_data) {}
+
+ExecutionContextData::~ExecutionContextData() {
+ DCHECK(!IsTracked());
+ DCHECK(ShouldDestroy());
+ DCHECK_EQ(0u, main_nondetached_v8_context_count_);
+}
+
+bool ExecutionContextData::IsTracked() const {
+ return previous() || next();
+}
+
+bool ExecutionContextData::ShouldDestroy() const {
+ return v8_context_count_ == 0 && !remote_frame_data_;
+}
+
+void ExecutionContextData::SetRemoteFrameData(
+ util::PassKey<RemoteFrameData>,
+ RemoteFrameData* remote_frame_data) {
+ DCHECK(!remote_frame_data_);
+ DCHECK(remote_frame_data);
+ remote_frame_data_ = remote_frame_data;
+}
+
+bool ExecutionContextData::ClearRemoteFrameData(
+ util::PassKey<RemoteFrameData>) {
+ DCHECK(remote_frame_data_);
+ remote_frame_data_ = nullptr;
+ return ShouldDestroy();
+}
+
+void ExecutionContextData::IncrementV8ContextCount(
+ util::PassKey<V8ContextData>) {
+ ++v8_context_count_;
+}
+
+bool ExecutionContextData::DecrementV8ContextCount(
+ util::PassKey<V8ContextData>) {
+ DCHECK_LT(0u, v8_context_count_);
+ DCHECK_LT(main_nondetached_v8_context_count_, v8_context_count_);
+ --v8_context_count_;
+ return ShouldDestroy();
+}
+
+bool ExecutionContextData::MarkDestroyed(util::PassKey<ProcessData>) {
+ if (destroyed)
+ return false;
+ destroyed = true;
+ return true;
+}
+
+bool ExecutionContextData::MarkMainV8ContextCreated(
+ util::PassKey<V8ContextTrackerDataStore>) {
+ if (main_nondetached_v8_context_count_ >= v8_context_count_)
+ return false;
+ if (main_nondetached_v8_context_count_ >= 1)
+ return false;
+ ++main_nondetached_v8_context_count_;
+ return true;
+}
+
+void ExecutionContextData::MarkMainV8ContextDetached(
+ util::PassKey<V8ContextData>) {
+ DCHECK_LT(0u, main_nondetached_v8_context_count_);
+ --main_nondetached_v8_context_count_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RemoteFrameData implementation:
+
+RemoteFrameData::RemoteFrameData(ProcessData* process_data,
+ const blink::RemoteFrameToken& token,
+ ExecutionContextData* execution_context_data)
+ : process_data_(process_data),
+ token_(token),
+ execution_context_data_(execution_context_data) {
+ DCHECK(process_data);
+ DCHECK(execution_context_data);
+ // This and the ExecutionContext *must* be cross-process.
+ DCHECK_NE(process_data, execution_context_data->process_data());
+ execution_context_data->SetRemoteFrameData(PassKey(), this);
+}
+
+RemoteFrameData::~RemoteFrameData() {
+ DCHECK(!IsTracked());
+
+ // If this is the last reference keeping alive a tracked ExecutionContextData,
+ // then clean it up as well. Untracked ExecutionContextDatas will go out of
+ // scope on their own.
+ if (execution_context_data_->ClearRemoteFrameData(PassKey()) &&
+ execution_context_data_->IsTracked()) {
+ process_data_->data_store()->Destroy(execution_context_data_->GetToken());
+ }
+}
+
+bool RemoteFrameData::IsTracked() const {
+ return previous() || next();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextData implementation:
+
+V8ContextData::V8ContextData(ProcessData* process_data,
+ const mojom::V8ContextDescription& description,
+ ExecutionContextData* execution_context_data)
+ : V8ContextState(description, execution_context_data),
+ process_data_(process_data) {
+ DCHECK(process_data);
+ DCHECK_EQ(static_cast<bool>(execution_context_data),
+ static_cast<bool>(description.execution_context_token));
+ if (execution_context_data) {
+ DCHECK_EQ(execution_context_data->GetToken(),
+ description.execution_context_token.value());
+
+ // These must be same process.
+ DCHECK_EQ(process_data, execution_context_data->process_data());
+ execution_context_data->IncrementV8ContextCount(PassKey());
+ }
+}
+
+V8ContextData::~V8ContextData() {
+ DCHECK(!IsTracked());
+
+ // Mark as detached if necessary so that main world counts are appropriately
+ // updated even during tear down code paths.
+ MarkDetachedImpl();
+
+ // If this is the last reference keeping alive a tracked ExecutionContextData,
+ // then clean it up as well. Untracked ExecutionContextDatas will go out of
+ // scope on their own.
+ if (auto* ecd = GetExecutionContextData()) {
+ if (ecd->DecrementV8ContextCount(PassKey()) && ecd->IsTracked())
+ process_data_->data_store()->Destroy(ecd->GetToken());
+ }
+}
+
+bool V8ContextData::IsTracked() const {
+ return previous() || next();
+}
+
+ExecutionContextData* V8ContextData::GetExecutionContextData() const {
+ return static_cast<ExecutionContextData*>(execution_context_state);
+}
+
+void V8ContextData::SetWasTracked(util::PassKey<V8ContextTrackerDataStore>) {
+ DCHECK(!was_tracked_);
+ was_tracked_ = true;
+}
+
+bool V8ContextData::MarkDetached(util::PassKey<ProcessData>) {
+ return MarkDetachedImpl();
+}
+
+bool V8ContextData::IsMainV8Context() const {
+ auto* ec_data = GetExecutionContextData();
+ if (!ec_data)
+ return false;
+ // ExecutionContexts hosting worklets have no main world (there can be many
+ // worklets sharing an ExecutionContext).
+ if (IsWorkletToken(ec_data->GetToken()))
+ return false;
+
+ // We've already checked sane combinations of ExecutionContextToken types and
+ // world types in ValidateV8ContextDescription, so don't need to be overly
+ // thorough here.
+
+ // Only main frames and workers can be "main" contexts.
+ auto world_type = description.world_type;
+ return world_type == mojom::V8ContextWorldType::kMain ||
+ world_type == mojom::V8ContextWorldType::kWorkerOrWorklet;
+}
+
+bool V8ContextData::MarkDetachedImpl() {
+ if (detached)
+ return false;
+ detached = true;
+ // The EC is notified of the main V8 context only when it is passed to the
+ // data store (at which point |was_tracked_| is set to true). Only do the
+ // symmetric operation if the first occurred.
+ if (IsMainV8Context() && was_tracked_) {
+ if (auto* ec_data = GetExecutionContextData())
+ ec_data->MarkMainV8ContextDetached(PassKey());
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ProcessData implementation:
+
+ProcessData::ProcessData(const ProcessNodeImpl* process_node)
+ : data_store_(GetDataStore(process_node)) {}
+
+ProcessData::~ProcessData() {
+ DCHECK(execution_context_datas_.empty());
+ DCHECK(remote_frame_datas_.empty());
+ DCHECK(v8_context_datas_.empty());
+}
+
+void ProcessData::TearDown() {
+ // First, remove any RemoteFrameData references owned by this ProcessData
+ // that are keeping alive ExecutionContextDatas in other ProcessDatas. This
+ // can cause ExecutionContextDatas to be torn down.
+ while (!remote_frame_datas_.empty()) {
+ auto* node = remote_frame_datas_.head();
+ data_store_->Destroy(node->value()->GetToken());
+ }
+
+ // Drain the list of V8ContextTokens. This will also indirectly clean up and
+ // ExecutionContextDatas that are only being kept alive by V8ContextData
+ // references.
+ while (!v8_context_datas_.empty()) {
+ auto* node = v8_context_datas_.head();
+ data_store_->Destroy(node->value()->GetToken());
+ }
+
+ // Any ExecutionContextDatas still alive are only being kept alive because of
+ // RemoteFrameData references from another ProcessData. Clean those up.
+ while (!execution_context_datas_.empty()) {
+ auto* node = execution_context_datas_.head();
+ auto* ec_data = node->value();
+ auto* rfd = ec_data->remote_frame_data();
+ DCHECK(rfd);
+ DCHECK_EQ(0u, ec_data->v8_context_count());
+ data_store_->Destroy(rfd->GetToken());
+ }
+
+ // We now expect everything to have been cleaned up.
+ DCHECK(execution_context_datas_.empty());
+ DCHECK(remote_frame_datas_.empty());
+ DCHECK(v8_context_datas_.empty());
+}
+
+void ProcessData::Add(util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data) {
+ DCHECK(ec_data);
+ DCHECK_EQ(this, ec_data->process_data());
+ DCHECK(!ec_data->ShouldDestroy());
+ DCHECK(!ec_data->IsTracked());
+ execution_context_datas_.Append(ec_data);
+ counts_.IncrementExecutionContextDataCount();
+}
+
+void ProcessData::Add(util::PassKey<V8ContextTrackerDataStore>,
+ RemoteFrameData* rf_data) {
+ DCHECK(rf_data);
+ DCHECK_EQ(this, rf_data->process_data());
+ DCHECK(!rf_data->IsTracked());
+ remote_frame_datas_.Append(rf_data);
+}
+
+void ProcessData::Add(util::PassKey<V8ContextTrackerDataStore>,
+ V8ContextData* v8_data) {
+ DCHECK(v8_data);
+ DCHECK_EQ(this, v8_data->process_data());
+ DCHECK(!v8_data->IsTracked());
+ v8_context_datas_.Append(v8_data);
+ counts_.IncrementV8ContextDataCount();
+}
+
+void ProcessData::Remove(util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data) {
+ DCHECK(ec_data);
+ DCHECK_EQ(this, ec_data->process_data());
+ DCHECK(ec_data->IsTracked());
+ DCHECK(ec_data->ShouldDestroy());
+ counts_.DecrementExecutionContextDataCount(ec_data->destroyed);
+ ec_data->RemoveFromList();
+}
+
+void ProcessData::Remove(util::PassKey<V8ContextTrackerDataStore>,
+ RemoteFrameData* rf_data) {
+ DCHECK(rf_data);
+ DCHECK_EQ(this, rf_data->process_data());
+ DCHECK(rf_data->IsTracked());
+ rf_data->RemoveFromList();
+}
+
+void ProcessData::Remove(util::PassKey<V8ContextTrackerDataStore>,
+ V8ContextData* v8_data) {
+ DCHECK(v8_data);
+ DCHECK_EQ(this, v8_data->process_data());
+ DCHECK(v8_data->IsTracked());
+ counts_.DecrementV8ContextDataCount(v8_data->detached);
+ v8_data->RemoveFromList();
+}
+
+bool ProcessData::MarkDestroyed(util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data) {
+ bool result = ec_data->MarkDestroyed(PassKey());
+ if (result)
+ counts_.MarkExecutionContextDataDestroyed();
+ return result;
+}
+
+bool ProcessData::MarkDetached(util::PassKey<V8ContextTrackerDataStore>,
+ V8ContextData* v8_data) {
+ bool result = v8_data->MarkDetached(PassKey());
+ if (result)
+ counts_.MarkV8ContextDataDetached();
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextTrackerDataStore implementation:
+
+V8ContextTrackerDataStore::V8ContextTrackerDataStore() = default;
+
+V8ContextTrackerDataStore::~V8ContextTrackerDataStore() {
+ DCHECK(global_execution_context_datas_.empty());
+ DCHECK(global_remote_frame_datas_.empty());
+ DCHECK(global_v8_context_datas_.empty());
+}
+
+void V8ContextTrackerDataStore::Pass(
+ std::unique_ptr<ExecutionContextData> ec_data) {
+ DCHECK(ec_data.get());
+ ec_data->process_data()->Add(PassKey(), ec_data.get());
+ auto result = global_execution_context_datas_.insert(std::move(ec_data));
+ DCHECK(result.second);
+}
+
+void V8ContextTrackerDataStore::Pass(std::unique_ptr<RemoteFrameData> rf_data) {
+ DCHECK(rf_data.get());
+ rf_data->process_data()->Add(PassKey(), rf_data.get());
+ auto result = global_remote_frame_datas_.insert(std::move(rf_data));
+ DCHECK(result.second);
+}
+
+bool V8ContextTrackerDataStore::Pass(std::unique_ptr<V8ContextData> v8_data) {
+ DCHECK(v8_data.get());
+ auto* ec_data = v8_data->GetExecutionContextData();
+ if (ec_data && v8_data->IsMainV8Context()) {
+ if (!ec_data->MarkMainV8ContextCreated(PassKey()))
+ return false;
+ }
+ v8_data->process_data()->Add(PassKey(), v8_data.get());
+ v8_data->SetWasTracked(PassKey());
+ auto result = global_v8_context_datas_.insert(std::move(v8_data));
+ DCHECK(result.second);
+ return true;
+}
+
+ExecutionContextData* V8ContextTrackerDataStore::Get(
+ const blink::ExecutionContextToken& token) {
+ auto it = global_execution_context_datas_.find(token);
+ if (it == global_execution_context_datas_.end())
+ return nullptr;
+ return it->get();
+}
+
+RemoteFrameData* V8ContextTrackerDataStore::Get(
+ const blink::RemoteFrameToken& token) {
+ auto it = global_remote_frame_datas_.find(token);
+ if (it == global_remote_frame_datas_.end())
+ return nullptr;
+ return it->get();
+}
+
+V8ContextData* V8ContextTrackerDataStore::Get(
+ const blink::V8ContextToken& token) {
+ auto it = global_v8_context_datas_.find(token);
+ if (it == global_v8_context_datas_.end())
+ return nullptr;
+ return it->get();
+}
+
+void V8ContextTrackerDataStore::MarkDestroyed(ExecutionContextData* ec_data) {
+ DCHECK(ec_data);
+ if (ec_data->process_data()->MarkDestroyed(PassKey(), ec_data)) {
+ DCHECK_LT(destroyed_execution_context_count_,
+ global_execution_context_datas_.size());
+ ++destroyed_execution_context_count_;
+ }
+}
+
+bool V8ContextTrackerDataStore::MarkDetached(V8ContextData* v8_data) {
+ DCHECK(v8_data);
+ if (v8_data->process_data()->MarkDetached(PassKey(), v8_data)) {
+ DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
+ ++detached_v8_context_count_;
+ return true;
+ }
+ return false;
+}
+
+void V8ContextTrackerDataStore::Destroy(
+ const blink::ExecutionContextToken& token) {
+ auto it = global_execution_context_datas_.find(token);
+ DCHECK(it != global_execution_context_datas_.end());
+ auto* ec_data = it->get();
+ if (ec_data->destroyed) {
+ DCHECK_LT(0u, destroyed_execution_context_count_);
+ --destroyed_execution_context_count_;
+ } else {
+ DCHECK_LT(destroyed_execution_context_count_,
+ global_execution_context_datas_.size());
+ }
+ ec_data->process_data()->Remove(PassKey(), ec_data);
+ global_execution_context_datas_.erase(it);
+}
+
+void V8ContextTrackerDataStore::Destroy(const blink::RemoteFrameToken& token) {
+ auto it = global_remote_frame_datas_.find(token);
+ DCHECK(it != global_remote_frame_datas_.end());
+ auto* rf_data = it->get();
+ rf_data->process_data()->Remove(PassKey(), rf_data);
+ global_remote_frame_datas_.erase(it);
+}
+
+void V8ContextTrackerDataStore::Destroy(const blink::V8ContextToken& token) {
+ auto it = global_v8_context_datas_.find(token);
+ DCHECK(it != global_v8_context_datas_.end());
+ auto* v8_data = it->get();
+ if (v8_data->detached) {
+ DCHECK_LT(0u, detached_v8_context_count_);
+ --detached_v8_context_count_;
+ } else {
+ DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size());
+ }
+ v8_data->process_data()->Remove(PassKey(), v8_data);
+ global_v8_context_datas_.erase(it);
+}
+
+} // namespace internal
+} // namespace v8_memory
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h
new file mode 100644
index 00000000000..f57d4ee1140
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h
@@ -0,0 +1,379 @@
+// Copyright 2020 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.
+
+// Internal data structures used by V8ContextTracker. These are only exposed in
+// a header for testing. Everything in this header lives in an "internal"
+// namespace so as not to pollute the "v8_memory", which houses the actual
+// consumer API.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_
+
+#include <memory>
+#include <set>
+
+#include "base/compiler_specific.h"
+#include "base/containers/linked_list.h"
+#include "base/util/type_safety/pass_key.h"
+#include "components/performance_manager/graph/node_attached_data_impl.h"
+#include "components/performance_manager/graph/process_node_impl.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+namespace v8_memory {
+namespace internal {
+
+using ExecutionContextState = V8ContextTracker::ExecutionContextState;
+using V8ContextState = V8ContextTracker::V8ContextState;
+
+// Forward declarations.
+class ExecutionContextData;
+class ProcessData;
+class RemoteFrameData;
+class V8ContextData;
+class V8ContextTrackerDataStore;
+
+// A comparator for "Data" objects that compares by token.
+template <typename DataType, typename TokenType>
+struct TokenComparator {
+ using is_transparent = int;
+ static const TokenType& GetToken(const TokenType& token) { return token; }
+ static const TokenType& GetToken(const std::unique_ptr<DataType>& data) {
+ return data->GetToken();
+ }
+ template <typename Type1, typename Type2>
+ bool operator()(const Type1& obj1, const Type2& obj2) const {
+ return GetToken(obj1) < GetToken(obj2);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ExecutionContextData declaration:
+
+// Internal wrapper of ExecutionContextState. Augments with additional data
+// needed for the implementation. Since these objects also need to be tracked
+// per-process, they are kept in a process-associated doubly-linked list.
+class ExecutionContextData : public base::LinkNode<ExecutionContextData>,
+ public ExecutionContextState {
+ public:
+ using Comparator =
+ TokenComparator<ExecutionContextData, blink::ExecutionContextToken>;
+
+ ExecutionContextData() = delete;
+ ExecutionContextData(const ExecutionContextData&) = delete;
+ ExecutionContextData(ProcessData* process_data,
+ const blink::ExecutionContextToken& token,
+ mojom::IframeAttributionDataPtr iframe_attribution_data);
+ ExecutionContextData& operator=(const ExecutionContextData&) = delete;
+ ~ExecutionContextData() override;
+
+ // Simple accessors.
+ ProcessData* process_data() const { return process_data_; }
+ RemoteFrameData* remote_frame_data() { return remote_frame_data_; }
+ size_t v8_context_count() const { return v8_context_count_; }
+ size_t main_nondetached_v8_context_count() const {
+ return main_nondetached_v8_context_count_;
+ }
+
+ // For consistency, all Data objects have a GetToken() function.
+ const blink::ExecutionContextToken& GetToken() const { return token; }
+
+ // Returns true if this object is currently being tracked (it is in
+ // ProcessData::execution_context_datas_, and
+ // V8ContextTrackerDataStore::global_execution_context_datas_).
+ WARN_UNUSED_RESULT bool IsTracked() const;
+
+ // Returns true if this object *should* be destroyed (there are no references
+ // to it keeping it alive).
+ WARN_UNUSED_RESULT bool ShouldDestroy() const;
+
+ // Manages remote frame data associated with this ExecutionContextData.
+ void SetRemoteFrameData(util::PassKey<RemoteFrameData>,
+ RemoteFrameData* remote_frame_data);
+ WARN_UNUSED_RESULT bool ClearRemoteFrameData(util::PassKey<RemoteFrameData>);
+
+ // Increments |v8_context_count_|.
+ void IncrementV8ContextCount(util::PassKey<V8ContextData>);
+
+ // Decrements |v8_context_count_|, and returns true if the object has
+ // transitioned to "ShouldDestroy".
+ WARN_UNUSED_RESULT bool DecrementV8ContextCount(util::PassKey<V8ContextData>);
+
+ // Marks this context as destroyed. Returns true if the state changed, false
+ // if it was already destroyed.
+ WARN_UNUSED_RESULT bool MarkDestroyed(util::PassKey<ProcessData>);
+
+ // Used for tracking the total number of non-detached "main" V8Contexts
+ // associated with this ExecutionContext. This should always be no more than
+ // 1. A new context may become the main context during a same-document
+ // navigation of a frame.
+ WARN_UNUSED_RESULT bool MarkMainV8ContextCreated(
+ util::PassKey<V8ContextTrackerDataStore>);
+ void MarkMainV8ContextDetached(util::PassKey<V8ContextData>);
+
+ private:
+ ProcessData* const process_data_;
+
+ RemoteFrameData* remote_frame_data_ = nullptr;
+
+ // The count of V8ContextDatas keeping this object alive.
+ size_t v8_context_count_ = 0;
+
+ // The number of non-detached main worlds that are currently associated with
+ // this ExecutionContext. There can be no more than 1 of these. Once
+ // document and frame lifetime semantics have been cleaned up, there will only
+ // be a single main context per ExecutionContext over its lifetime; right now
+ // there can be multiple due to same-document navigations.
+ size_t main_nondetached_v8_context_count_ = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// RemoteFrameData declaration:
+
+// Represents data about an ExecutionCOntext from the point of view of the
+// parent frame that owns it.
+class RemoteFrameData : public base::LinkNode<RemoteFrameData> {
+ public:
+ using Comparator = TokenComparator<RemoteFrameData, blink::RemoteFrameToken>;
+ using PassKey = util::PassKey<RemoteFrameData>;
+
+ RemoteFrameData() = delete;
+ RemoteFrameData(ProcessData* process_data,
+ const blink::RemoteFrameToken& token,
+ ExecutionContextData* execution_context_data);
+ RemoteFrameData(const RemoteFrameData&) = delete;
+ RemoteFrameData& operator=(const RemoteFrameData&) = delete;
+ ~RemoteFrameData();
+
+ // Simple accessors.
+ ProcessData* process_data() const { return process_data_; }
+ ExecutionContextData* execution_context_data() const {
+ return execution_context_data_;
+ }
+
+ // For consistency, all Data objects have a GetToken() function.
+ const blink::RemoteFrameToken& GetToken() const { return token_; }
+
+ // Returns true if this object is currently being tracked (it is in
+ // ProcessData::remote_frame_datas_, and
+ // V8ContextTrackerDataStore::global_remote_frame_datas_).
+ WARN_UNUSED_RESULT bool IsTracked() const;
+
+ private:
+ ProcessData* const process_data_;
+ const blink::RemoteFrameToken token_;
+ ExecutionContextData* const execution_context_data_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextData declaration:
+
+// Internal wrapper of V8ContextState. Augments with additional data needed for
+// the implementation.
+class V8ContextData : public base::LinkNode<V8ContextData>,
+ public V8ContextState {
+ public:
+ using Comparator = TokenComparator<V8ContextData, blink::V8ContextToken>;
+ using PassKey = util::PassKey<V8ContextData>;
+
+ V8ContextData() = delete;
+ V8ContextData(ProcessData* process_data,
+ const mojom::V8ContextDescription& description,
+ ExecutionContextData* execution_context_data);
+ V8ContextData(const V8ContextData&) = delete;
+ V8ContextData& operator=(const V8ContextData&) = delete;
+ ~V8ContextData() override;
+
+ // Simple accessors.
+ ProcessData* process_data() const { return process_data_; }
+
+ // For consistency, all Data objects have a GetToken() function.
+ const blink::V8ContextToken& GetToken() const { return description.token; }
+
+ // Returns true if this object is currently being tracked (its in
+ // ProcessData::v8_context_datas_, and
+ // V8ContextTrackerDataStore::global_v8_context_datas_).
+ WARN_UNUSED_RESULT bool IsTracked() const;
+
+ // Returns the ExecutionContextData associated with this V8ContextData.
+ ExecutionContextData* GetExecutionContextData() const;
+
+ // Marks this context as having been successfully passed into the data store.
+ void SetWasTracked(util::PassKey<V8ContextTrackerDataStore>);
+
+ // Marks this context as detached. Returns true if the state changed, false
+ // if it was already detached.
+ WARN_UNUSED_RESULT bool MarkDetached(util::PassKey<ProcessData>);
+
+ // Returns true if this is the "main" V8Context for an ExecutionContext.
+ // This will return true if |GetExecutionContextData()| is a frame and
+ // |description.world_type| is kMain, or if |GetExecutionContextData()| is a
+ // worker and |description.world_type| is a kWorkerOrWorklet.
+ bool IsMainV8Context() const;
+
+ private:
+ bool MarkDetachedImpl();
+
+ ProcessData* const process_data_;
+ bool was_tracked_ = false;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ProcessData declaration:
+
+class ProcessData : public NodeAttachedDataImpl<ProcessData> {
+ public:
+ struct Traits : public NodeAttachedDataInMap<ProcessNodeImpl> {};
+
+ using PassKey = util::PassKey<ProcessData>;
+
+ explicit ProcessData(const ProcessNodeImpl* process_node);
+ ~ProcessData() override;
+
+ // Simple accessors.
+ V8ContextTrackerDataStore* data_store() const { return data_store_; }
+
+ // Tears down this ProcessData by ensuring that all associated
+ // ExecutionContextDatas and V8ContextDatas are cleaned up. This must be
+ // called *prior* to the destructor being invoked.
+ void TearDown();
+
+ // Adds the provided object to the list of process-associated objects. The
+ // object must not be part of a list, its process data must match this one,
+ // and it must return false for "ShouldDestroy" (if applicable). For removal,
+ // the object must be part of a list, the process data must match this one and
+ // "ShouldDestroy" must return false.
+ void Add(util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data);
+ void Add(util::PassKey<V8ContextTrackerDataStore>, RemoteFrameData* rf_data);
+ void Add(util::PassKey<V8ContextTrackerDataStore>, V8ContextData* v8_data);
+ void Remove(util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data);
+ void Remove(util::PassKey<V8ContextTrackerDataStore>,
+ RemoteFrameData* rf_data);
+ void Remove(util::PassKey<V8ContextTrackerDataStore>, V8ContextData* v8_data);
+
+ // For marking objects detached/destroyed. Returns true if the state
+ // actually changed, false otherwise.
+ WARN_UNUSED_RESULT bool MarkDestroyed(
+ util::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data);
+ WARN_UNUSED_RESULT bool MarkDetached(util::PassKey<V8ContextTrackerDataStore>,
+ V8ContextData* v8_data);
+
+ size_t GetExecutionContextDataCount() const {
+ return counts_.GetExecutionContextDataCount();
+ }
+ size_t GetDestroyedExecutionContextDataCount() const {
+ return counts_.GetDestroyedExecutionContextDataCount();
+ }
+ size_t GetV8ContextDataCount() const {
+ return counts_.GetV8ContextDataCount();
+ }
+ size_t GetDetachedV8ContextDataCount() const {
+ return counts_.GetDetachedV8ContextDataCount();
+ }
+
+ private:
+ // Used to initialize |data_store_| at construction.
+ static V8ContextTrackerDataStore* GetDataStore(
+ const ProcessNodeImpl* process_node) {
+ return V8ContextTracker::GetFromGraph(process_node->graph())->data_store();
+ }
+
+ // Pointer to the DataStore that implicitly owns us.
+ V8ContextTrackerDataStore* const data_store_;
+
+ // Counts the number of ExecutionContexts and V8Contexts.
+ ContextCounts counts_;
+
+ // List of ExecutionContextDatas associated with this process.
+ base::LinkedList<ExecutionContextData> execution_context_datas_;
+
+ // List of RemoteFrameDatas associated with this process.
+ base::LinkedList<RemoteFrameData> remote_frame_datas_;
+
+ // List of V8ContextDatas associated with this process.
+ base::LinkedList<V8ContextData> v8_context_datas_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// V8ContextTrackerDataStore declaration:
+
+// This class acts as the owner of all tracked objects. Objects are created
+// in isolation, and ownership passed to this object. Management of all
+// per-process lists is centralized through this object.
+class V8ContextTrackerDataStore {
+ public:
+ using PassKey = util::PassKey<V8ContextTrackerDataStore>;
+
+ V8ContextTrackerDataStore();
+ ~V8ContextTrackerDataStore();
+
+ // Passes ownership of an object. An object with the same token must not
+ // already exist ("Get" should return nullptr). Note that when passing an
+ // |ec_data| to the impl that "ShouldDestroy" should return false.
+ void Pass(std::unique_ptr<ExecutionContextData> ec_data);
+ void Pass(std::unique_ptr<RemoteFrameData> rf_data);
+ WARN_UNUSED_RESULT bool Pass(std::unique_ptr<V8ContextData> v8_data);
+
+ // Looks up owned objects by token.
+ ExecutionContextData* Get(const blink::ExecutionContextToken& token);
+ RemoteFrameData* Get(const blink::RemoteFrameToken& token);
+ V8ContextData* Get(const blink::V8ContextToken& token);
+
+ // For marking objects as detached/destroyed. "MarkDetached" returns true if
+ // the object was not previously detached, false otherwise.
+ void MarkDestroyed(ExecutionContextData* ec_data);
+ WARN_UNUSED_RESULT bool MarkDetached(V8ContextData* v8_data);
+
+ // Destroys objects by token. They must exist ("Get" should return non
+ // nullptr).
+ void Destroy(const blink::ExecutionContextToken& token);
+ void Destroy(const blink::RemoteFrameToken& token);
+ void Destroy(const blink::V8ContextToken& token);
+
+ size_t GetDestroyedExecutionContextDataCount() const {
+ return destroyed_execution_context_count_;
+ }
+ size_t GetDetachedV8ContextDataCount() const {
+ return detached_v8_context_count_;
+ }
+
+ size_t GetExecutionContextDataCount() const {
+ return global_execution_context_datas_.size();
+ }
+ size_t GetRemoteFrameDataCount() const {
+ return global_remote_frame_datas_.size();
+ }
+ size_t GetV8ContextDataCount() const {
+ return global_v8_context_datas_.size();
+ }
+
+ private:
+ size_t destroyed_execution_context_count_ = 0;
+ size_t detached_v8_context_count_ = 0;
+
+ // Browser wide registry of ExecutionContextData objects.
+ std::set<std::unique_ptr<ExecutionContextData>,
+ ExecutionContextData::Comparator>
+ global_execution_context_datas_;
+
+ // Browser-wide registry of RemoteFrameData objects.
+ std::set<std::unique_ptr<RemoteFrameData>, RemoteFrameData::Comparator>
+ global_remote_frame_datas_;
+
+ // Browser wide registry of V8ContextData objects.
+ std::set<std::unique_ptr<V8ContextData>, V8ContextData::Comparator>
+ global_v8_context_datas_;
+};
+
+} // namespace internal
+} // namespace v8_memory
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_INTERNAL_H_
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc
new file mode 100644
index 00000000000..d170901e726
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc
@@ -0,0 +1,434 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker_internal.h"
+
+#include <memory>
+
+#include "base/test/gtest_util.h"
+#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "components/performance_manager/test_support/mock_graphs.h"
+#include "components/performance_manager/v8_memory/v8_context_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+namespace v8_memory {
+namespace internal {
+
+namespace {
+
+// A fake extension ID.
+const char kExtensionId[] = "hickenlcldoffnfidnljacmfeielknka";
+
+class V8ContextTrackerInternalTest : public GraphTestHarness {
+ public:
+ V8ContextTrackerInternalTest()
+ : registry_(graph()->PassToGraph(
+ std::make_unique<
+ execution_context::ExecutionContextRegistryImpl>())),
+ tracker_(graph()->PassToGraph(std::make_unique<V8ContextTracker>())),
+ mock_graph_(graph()) {}
+
+ ~V8ContextTrackerInternalTest() override = default;
+
+ V8ContextTrackerDataStore* data_store() const {
+ return tracker_->data_store();
+ }
+
+ execution_context::ExecutionContextRegistry* const registry_ = nullptr;
+ V8ContextTracker* const tracker_ = nullptr;
+ MockSinglePageWithMultipleProcessesGraph mock_graph_;
+};
+
+mojom::V8ContextDescription MakeMatchingV8ContextDescription(
+ ExecutionContextData* ec_data,
+ bool main_world = true) {
+ DCHECK(ec_data);
+ mojom::V8ContextDescription v8_desc;
+ if (main_world) {
+ v8_desc.world_type = mojom::V8ContextWorldType::kMain;
+ } else {
+ v8_desc.world_type = mojom::V8ContextWorldType::kExtension;
+ v8_desc.world_name = kExtensionId;
+ }
+ v8_desc.execution_context_token = ec_data->GetToken();
+ return v8_desc;
+}
+
+using V8ContextTrackerInternalDeathTest = V8ContextTrackerInternalTest;
+
+} // namespace
+
+TEST_F(V8ContextTrackerInternalDeathTest,
+ PassingUnreferencedExecutionContextDataFails) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ EXPECT_TRUE(ec_data->ShouldDestroy());
+ EXPECT_DCHECK_DEATH(data_store()->Pass(std::move(ec_data)));
+}
+
+TEST_F(V8ContextTrackerInternalDeathTest,
+ MultipleMainWorldsForExecutionContextFails) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ EXPECT_TRUE(ec_data->ShouldDestroy());
+ EXPECT_EQ(0u, ec_data->main_nondetached_v8_context_count());
+
+ mojom::V8ContextDescription v8_desc;
+ v8_desc.world_type = mojom::V8ContextWorldType::kMain;
+ v8_desc.execution_context_token = ec_data->GetToken();
+
+ std::unique_ptr<V8ContextData> v8_data =
+ std::make_unique<V8ContextData>(process_data, v8_desc, ec_data.get());
+ EXPECT_TRUE(v8_data->IsMainV8Context());
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data)));
+ EXPECT_EQ(1u, ec_data->main_nondetached_v8_context_count());
+
+ v8_desc.token = blink::V8ContextToken();
+ v8_data =
+ std::make_unique<V8ContextData>(process_data, v8_desc, ec_data.get());
+ EXPECT_TRUE(v8_data->IsMainV8Context());
+ EXPECT_FALSE(data_store()->Pass(std::move(v8_data)));
+
+ data_store()->Pass(std::move(ec_data));
+}
+
+TEST_F(V8ContextTrackerInternalDeathTest, SameProcessRemoteFrameDataExplodes) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ std::unique_ptr<RemoteFrameData> rf_data;
+ EXPECT_DCHECK_DEATH(
+ rf_data = std::make_unique<RemoteFrameData>(
+ process_data, blink::RemoteFrameToken(), ec_data.get()));
+}
+
+TEST_F(V8ContextTrackerInternalDeathTest, CrossProcessV8ContextDataExplodes) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+ auto* other_process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.other_process.get()));
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ std::unique_ptr<V8ContextData> v8_data;
+ EXPECT_DCHECK_DEATH(v8_data = std::make_unique<V8ContextData>(
+ other_process_data,
+ MakeMatchingV8ContextDescription(ec_data.get()),
+ ec_data.get()));
+}
+
+TEST_F(V8ContextTrackerInternalTest, ExecutionContextDataShouldDestroy) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+
+ // With no references "ShouldDestroy" should return true.
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ EXPECT_FALSE(ec_data->remote_frame_data());
+ EXPECT_EQ(0u, ec_data->v8_context_count());
+ EXPECT_TRUE(ec_data->ShouldDestroy());
+
+ // Adding a RemoteFrameData reference should mark "ShouldDestroy" as false.
+ auto* other_process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.other_process.get()));
+ std::unique_ptr<RemoteFrameData> rf_data = std::make_unique<RemoteFrameData>(
+ other_process_data, blink::RemoteFrameToken(), ec_data.get());
+ EXPECT_TRUE(ec_data->remote_frame_data());
+ EXPECT_EQ(0u, ec_data->v8_context_count());
+ EXPECT_FALSE(ec_data->ShouldDestroy());
+
+ // Adding a V8ContextData should also keep the object alive.
+ std::unique_ptr<V8ContextData> v8_data1 = std::make_unique<V8ContextData>(
+ process_data, MakeMatchingV8ContextDescription(ec_data.get()),
+ ec_data.get());
+ EXPECT_TRUE(ec_data->remote_frame_data());
+ EXPECT_EQ(1u, ec_data->v8_context_count());
+ EXPECT_FALSE(ec_data->ShouldDestroy());
+
+ // Add another V8ContextData.
+ std::unique_ptr<V8ContextData> v8_data2 = std::make_unique<V8ContextData>(
+ process_data, MakeMatchingV8ContextDescription(ec_data.get()),
+ ec_data.get());
+ EXPECT_TRUE(ec_data->remote_frame_data());
+ EXPECT_EQ(2u, ec_data->v8_context_count());
+ EXPECT_FALSE(ec_data->ShouldDestroy());
+
+ // Destroy one of the V8ContextDatas.
+ v8_data1.reset();
+ EXPECT_TRUE(ec_data->remote_frame_data());
+ EXPECT_EQ(1u, ec_data->v8_context_count());
+ EXPECT_FALSE(ec_data->ShouldDestroy());
+
+ // Destroy the RemoteFrameData.
+ rf_data.reset();
+ EXPECT_FALSE(ec_data->remote_frame_data());
+ EXPECT_EQ(1u, ec_data->v8_context_count());
+ EXPECT_FALSE(ec_data->ShouldDestroy());
+
+ // Destroy the last V8COntextData.
+ v8_data2.reset();
+ EXPECT_FALSE(ec_data->remote_frame_data());
+ EXPECT_EQ(0u, ec_data->v8_context_count());
+ EXPECT_TRUE(ec_data->ShouldDestroy());
+}
+
+TEST_F(V8ContextTrackerInternalTest,
+ ExecutionContextDataTornDownByRemoteFrameData) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+
+ // Create an ExecutionContextData.
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ auto* raw_ec_data = ec_data.get();
+ EXPECT_FALSE(ec_data->IsTracked());
+
+ // Create a RemoteFrameData.
+ auto* other_process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.other_process.get()));
+ std::unique_ptr<RemoteFrameData> rf_data = std::make_unique<RemoteFrameData>(
+ other_process_data, blink::RemoteFrameToken(), ec_data.get());
+ auto* raw_rf_data = rf_data.get();
+ EXPECT_FALSE(rf_data->IsTracked());
+
+ // Pass both of these to the Impl.
+ data_store()->Pass(std::move(ec_data));
+ data_store()->Pass(std::move(rf_data));
+ EXPECT_TRUE(raw_ec_data->IsTracked());
+ EXPECT_TRUE(raw_rf_data->IsTracked());
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetRemoteFrameDataCount());
+
+ // Ensure that lookup works.
+ auto ec_token = raw_ec_data->GetToken();
+ auto rf_token = raw_rf_data->GetToken();
+ EXPECT_EQ(raw_ec_data, data_store()->Get(ec_token));
+ EXPECT_EQ(raw_rf_data, data_store()->Get(rf_token));
+
+ // Delete the RemoteFrameData, and also expect the ExecutionContextData to
+ // have been cleaned up.
+ data_store()->Destroy(rf_token);
+ EXPECT_EQ(nullptr, data_store()->Get(ec_token));
+ EXPECT_EQ(nullptr, data_store()->Get(rf_token));
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+}
+
+TEST_F(V8ContextTrackerInternalTest,
+ ExecutionContextDataTornDownByV8ContextData) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+
+ // Create an ExecutionContextData.
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ auto* raw_ec_data = ec_data.get();
+ EXPECT_FALSE(ec_data->IsTracked());
+
+ // Create a V8ContextData.
+ std::unique_ptr<V8ContextData> v8_data = std::make_unique<V8ContextData>(
+ process_data, MakeMatchingV8ContextDescription(ec_data.get()),
+ ec_data.get());
+ auto* raw_v8_data = v8_data.get();
+ EXPECT_FALSE(v8_data->IsTracked());
+
+ // Pass both of these to the Impl.
+ data_store()->Pass(std::move(ec_data));
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data)));
+ EXPECT_TRUE(raw_ec_data->IsTracked());
+ EXPECT_TRUE(raw_v8_data->IsTracked());
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetV8ContextDataCount());
+
+ // Ensure that lookup works.
+ auto ec_token = raw_ec_data->GetToken();
+ auto v8_token = raw_v8_data->GetToken();
+ EXPECT_EQ(raw_ec_data, data_store()->Get(ec_token));
+ EXPECT_EQ(raw_v8_data, data_store()->Get(v8_token));
+
+ // Delete the V8ContextData, and also expect the ExecutionContextData to
+ // have been cleaned up.
+ data_store()->Destroy(v8_token);
+ EXPECT_EQ(nullptr, data_store()->Get(ec_token));
+ EXPECT_EQ(nullptr, data_store()->Get(v8_token));
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+}
+
+TEST_F(V8ContextTrackerInternalTest, ContextCounts) {
+ auto* process_data = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data, mock_graph_.frame->frame_token(), nullptr);
+ auto* raw_ec_data = ec_data.get();
+
+ std::unique_ptr<V8ContextData> v8_data1 = std::make_unique<V8ContextData>(
+ process_data, MakeMatchingV8ContextDescription(ec_data.get()),
+ ec_data.get());
+ auto* raw_v8_data1 = v8_data1.get();
+
+ std::unique_ptr<V8ContextData> v8_data2 = std::make_unique<V8ContextData>(
+ process_data,
+ MakeMatchingV8ContextDescription(ec_data.get(), /* main_world */ false),
+ ec_data.get());
+
+ data_store()->Pass(std::move(ec_data));
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data1)));
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data2)));
+
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(2u, data_store()->GetV8ContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount());
+ EXPECT_EQ(1u, process_data->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, process_data->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(2u, process_data->GetV8ContextDataCount());
+ EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount());
+
+ EXPECT_FALSE(raw_ec_data->destroyed);
+ data_store()->MarkDestroyed(raw_ec_data);
+ EXPECT_TRUE(raw_ec_data->destroyed);
+
+ EXPECT_FALSE(raw_v8_data1->detached);
+ EXPECT_TRUE(data_store()->MarkDetached(raw_v8_data1));
+ EXPECT_TRUE(raw_v8_data1->detached);
+ EXPECT_FALSE(data_store()->MarkDetached(raw_v8_data1));
+
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(2u, data_store()->GetV8ContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetDetachedV8ContextDataCount());
+ EXPECT_EQ(1u, process_data->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, process_data->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(2u, process_data->GetV8ContextDataCount());
+ EXPECT_EQ(1u, process_data->GetDetachedV8ContextDataCount());
+
+ data_store()->Destroy(raw_v8_data1->GetToken());
+
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetV8ContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount());
+ EXPECT_EQ(1u, process_data->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, process_data->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(1u, process_data->GetV8ContextDataCount());
+ EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount());
+
+ process_data->TearDown();
+
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount());
+ EXPECT_EQ(0u, process_data->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, process_data->GetDestroyedExecutionContextDataCount());
+ EXPECT_EQ(0u, process_data->GetV8ContextDataCount());
+ EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount());
+}
+
+namespace {
+
+class V8ContextTrackerInternalTearDownOrderTest
+ : public V8ContextTrackerInternalTest {
+ public:
+ using Super = V8ContextTrackerInternalTest;
+
+ void SetUp() override {
+ Super::SetUp();
+
+ process_data_ = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.process.get()));
+ other_process_data_ = ProcessData::GetOrCreate(
+ static_cast<ProcessNodeImpl*>(mock_graph_.other_process.get()));
+
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+
+ // Create an ExecutionContextData.
+ std::unique_ptr<ExecutionContextData> ec_data =
+ std::make_unique<ExecutionContextData>(
+ process_data_, mock_graph_.frame->frame_token(), nullptr);
+ ec_data_ = ec_data.get();
+
+ // Create a RemoteFrameData.
+ std::unique_ptr<RemoteFrameData> rf_data =
+ std::make_unique<RemoteFrameData>(other_process_data_,
+ blink::RemoteFrameToken(), ec_data_);
+
+ // Pass these to the tracker_.
+ data_store()->Pass(std::move(ec_data));
+ data_store()->Pass(std::move(rf_data));
+
+ // Create a couple V8ContextDatas.
+ std::unique_ptr<V8ContextData> v8_data = std::make_unique<V8ContextData>(
+ process_data_, MakeMatchingV8ContextDescription(ec_data_), ec_data_);
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data)));
+ v8_data = std::make_unique<V8ContextData>(
+ process_data_,
+ MakeMatchingV8ContextDescription(ec_data_, /* main_world */ false),
+ ec_data_);
+ EXPECT_TRUE(data_store()->Pass(std::move(v8_data)));
+
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(1u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(2u, data_store()->GetV8ContextDataCount());
+ }
+
+ ProcessData* process_data_ = nullptr;
+ ProcessData* other_process_data_ = nullptr;
+ ExecutionContextData* ec_data_ = nullptr;
+};
+
+} // namespace
+
+TEST_F(V8ContextTrackerInternalTearDownOrderTest, RemoteBeforeLocal) {
+ // Tear down the |other_process| which has "RemoteFrame" entries.
+ other_process_data_->TearDown();
+ EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(2u, data_store()->GetV8ContextDataCount());
+ EXPECT_FALSE(ec_data_->remote_frame_data());
+
+ // Now tear down the main |process|.
+ process_data_->TearDown();
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+}
+
+TEST_F(V8ContextTrackerInternalTearDownOrderTest, LocalBeforeRemote) {
+ // Tear down the main |process|. This should tear down everything.
+ process_data_->TearDown();
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+
+ // Tearing down the |other_process| should do nothing.
+ other_process_data_->TearDown();
+ EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount());
+ EXPECT_EQ(0u, data_store()->GetRemoteFrameDataCount());
+ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount());
+}
+
+} // namespace internal
+} // namespace v8_memory
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.cc
deleted file mode 100644
index 3373dc24f49..00000000000
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker_types.h"
-
-namespace performance_manager {
-namespace v8_memory {
-
-////////////////////////////////////////////////////////////////////////////////
-// IframeAttributionData implementation:
-
-IframeAttributionData::IframeAttributionData() = default;
-
-IframeAttributionData::IframeAttributionData(const IframeAttributionData&) =
- default;
-
-IframeAttributionData& IframeAttributionData::operator=(
- const IframeAttributionData&) = default;
-
-IframeAttributionData::~IframeAttributionData() = default;
-
-// static
-IframeAttributionData IframeAttributionData::Create(
- const base::Optional<std::string>& id,
- const base::Optional<std::string>& src) {
- IframeAttributionData data;
- data.id = id;
- data.src = src;
- return data;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// V8ContextDescription implementation:
-
-V8ContextDescription::V8ContextDescription() = default;
-
-V8ContextDescription::V8ContextDescription(const V8ContextDescription&) =
- default;
-
-V8ContextDescription& V8ContextDescription::operator=(
- const V8ContextDescription&) = default;
-
-V8ContextDescription::~V8ContextDescription() = default;
-
-// static
-V8ContextDescription V8ContextDescription::Create(
- blink::V8ContextToken token,
- V8ContextWorldType world_type,
- const base::Optional<std::string>& world_name,
- const base::Optional<blink::ExecutionContextToken>&
- execution_context_token) {
- V8ContextDescription desc;
- desc.token = token;
- desc.world_type = world_type;
- desc.world_name = world_name;
- desc.execution_context_token = execution_context_token;
- return desc;
-}
-
-} // namespace v8_memory
-} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.h
deleted file mode 100644
index f1bd962d873..00000000000
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_types.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2020 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.
-
-// Defines various types that are used by the V8ContextTracker. Note that all of
-// these will be migrated to mojo types once the browser-side implementation is
-// complete and tested.
-
-#ifndef COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_TYPES_H_
-#define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_TYPES_H_
-
-#include <string>
-
-#include "base/optional.h"
-#include "third_party/blink/public/common/tokens/tokens.h"
-
-namespace performance_manager {
-namespace v8_memory {
-
-// Stores information about an iframe element from the point of view of the
-// document that hosts the iframe. Explicitly allow copy and assign. This is
-// used in the performance.measureMemory API.
-struct IframeAttributionData {
- IframeAttributionData();
- IframeAttributionData(const IframeAttributionData&);
- IframeAttributionData& operator=(const IframeAttributionData&);
- ~IframeAttributionData();
-
- static IframeAttributionData Create(const base::Optional<std::string>& id,
- const base::Optional<std::string>& src);
-
- base::Optional<std::string> id;
- // We don't use a GURL because we don't need to parse this, or otherwise use
- // it as an URL, and GURL has a very large memory footprint.
- base::Optional<std::string> src;
-};
-
-// Identifies a V8Context type. Note that this roughly corresponds to the
-// world types defined in blink, but with some simplifications.
-enum class V8ContextWorldType {
- // The main world, corresponding to a frame / document.
- kMain,
- // Corresponds to the main world of a worker or worklet.
- kWorkerOrWorklet,
- // Corresponds to an extension.
- kExtension,
- // Corresponds to a non-extension isolated world.
- kIsolated,
- // Corresponds to the devtools inspector. Will not have a human readable
- // name or a stable id.
- kInspector,
- // Corresponds to the regexp world. This world is unique in that it is per
- // v8::Isolate, and not associated with any individual execution context.
- // Will not have a human-readable name or stable id.
- kRegExp,
-};
-
-// Information describing a V8 Context. Explicitly allow copy and assign. This
-// is used in IPC related to the performance.measureMemory API.
-struct V8ContextDescription {
- V8ContextDescription();
- V8ContextDescription(const V8ContextDescription&);
- V8ContextDescription& operator=(const V8ContextDescription&);
- ~V8ContextDescription();
-
- static V8ContextDescription Create(
- blink::V8ContextToken token,
- V8ContextWorldType world_type,
- const base::Optional<std::string>& world_name,
- const base::Optional<blink::ExecutionContextToken>&
- execution_context_token);
-
- // The unique token that names this world.
- blink::V8ContextToken token;
- // The type of this world.
- V8ContextWorldType world_type;
- // Identifies this world. Only set for extension and isolated worlds. For
- // extension worlds this corresponds to the stable extension ID. For other
- // isolated worlds this is a human-readable description.
- base::Optional<std::string> world_name;
- // The identity of the execution context that this V8Context is associated
- // with. This is specified for all world types, except kRegExp worlds.
- base::Optional<blink::ExecutionContextToken> execution_context_token;
-};
-
-} // namespace v8_memory
-} // namespace performance_manager
-
-#endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_CONTEXT_TRACKER_TYPES_H_
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_unittest.cc b/chromium/components/performance_manager/v8_memory/v8_context_tracker_unittest.cc
new file mode 100644
index 00000000000..a006b8ea9a6
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_unittest.cc
@@ -0,0 +1,771 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_context_tracker.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/optional.h"
+#include "base/stl_util.h"
+#include "base/test/gtest_util.h"
+#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
+#include "components/performance_manager/graph/frame_node_impl.h"
+#include "components/performance_manager/graph/page_node_impl.h"
+#include "components/performance_manager/graph/process_node_impl.h"
+#include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "components/performance_manager/test_support/mock_graphs.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+namespace v8_memory {
+
+namespace {
+
+using ::testing::AllOf;
+using ::testing::Eq;
+using ::testing::Property;
+
+// Fake iframe attributes.
+const std::string kIframeId("iframe1");
+const std::string kIframeSrc("http://www.fakesite.com/");
+
+// Some tokens for identifying frames and contexts.
+const blink::V8ContextToken kFrameMainWorld;
+const blink::V8ContextToken kChildFrameMainWorld;
+const blink::V8ContextToken kFrameIsolatedWorld;
+const blink::V8ContextToken kChildFrameIsolatedWorld;
+const blink::RemoteFrameToken kChildFrameRemoteToken;
+
+// A fake extension ID.
+const char kExtensionId[] = "hickenlcldoffnfidnljacmfeielknka";
+
+// Helper function for creating an IframeAttributionData.
+mojom::IframeAttributionDataPtr GetFakeIframeAttributionDataPtr() {
+ static const mojom::IframeAttributionData kData(kIframeId, kIframeSrc);
+ mojom::IframeAttributionDataPtr iad = mojom::IframeAttributionData::New();
+ *iad = kData;
+ return iad;
+}
+
+class V8ContextTrackerTest : public GraphTestHarness {
+ public:
+ // Small PassToGraph helper that returns a raw pointer to the object that
+ // became graph owned. Helps write tidy constructors.
+ template <typename DerivedType>
+ DerivedType* PassToGraph(std::unique_ptr<DerivedType> graph_owned) {
+ DerivedType* object = graph_owned.get();
+ graph()->PassToGraph(std::move(graph_owned));
+ return object;
+ }
+
+ V8ContextTrackerTest()
+ : registry(
+ PassToGraph(std::make_unique<
+ execution_context::ExecutionContextRegistryImpl>())),
+ tracker(PassToGraph(std::make_unique<V8ContextTracker>())),
+ mock_graph(graph()) {}
+
+ ~V8ContextTrackerTest() override = default;
+
+ execution_context::ExecutionContextRegistry* const registry = nullptr;
+ V8ContextTracker* const tracker = nullptr;
+ MockSinglePageWithMultipleProcessesGraph mock_graph;
+};
+
+using V8ContextTrackerDeathTest = V8ContextTrackerTest;
+
+auto CountsMatch(size_t v8_context_count, size_t execution_context_count) {
+ return AllOf(Property(&V8ContextTracker::GetV8ContextCountForTesting,
+ Eq(v8_context_count)),
+ Property(&V8ContextTracker::GetExecutionContextCountForTesting,
+ Eq(execution_context_count)));
+}
+
+auto DetachedCountsMatch(size_t detached_v8_context_count,
+ size_t destroyed_execution_context_count) {
+ return AllOf(
+ Property(&V8ContextTracker::GetDetachedV8ContextCountForTesting,
+ Eq(detached_v8_context_count)),
+ Property(&V8ContextTracker::GetDestroyedExecutionContextCountForTesting,
+ Eq(destroyed_execution_context_count)));
+}
+
+} // namespace
+
+TEST_F(V8ContextTrackerDeathTest, MissingExecutionContextForMainFrameExplodes) {
+ // A main-frame should not have iframe data, and it must have an execution
+ // context token. So this should fail.
+ EXPECT_DCHECK_DEATH(tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ base::nullopt),
+ /* iframe_attribution_data */ nullptr));
+}
+
+TEST_F(V8ContextTrackerDeathTest, DoubleCreationExplodes) {
+ auto v8_desc = mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token());
+
+ tracker->OnV8ContextCreated(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), v8_desc, nullptr);
+
+ // Trying to create the context a second time should explode.
+ EXPECT_DCHECK_DEATH(
+ tracker->OnV8ContextCreated(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), v8_desc, nullptr));
+}
+
+TEST_F(V8ContextTrackerDeathTest, MissingContextExplodes) {
+ // There was no OnV8ContextCreated called first, so this should explode.
+ EXPECT_DCHECK_DEATH(
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld));
+
+ // Similarly with a destroyed notification.
+ EXPECT_DCHECK_DEATH(
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld));
+}
+
+TEST_F(V8ContextTrackerDeathTest, DoubleRemoteFrameCreatedExplodes) {
+ tracker->OnRemoteIframeAttachedForTesting(mock_graph.child_frame.get(),
+ kChildFrameRemoteToken,
+ GetFakeIframeAttributionDataPtr());
+
+ EXPECT_DCHECK_DEATH(tracker->OnRemoteIframeAttachedForTesting(
+ mock_graph.child_frame.get(), kChildFrameRemoteToken,
+ GetFakeIframeAttributionDataPtr()));
+}
+
+TEST_F(V8ContextTrackerDeathTest, IframeAttributionDataForMainFrameExplodes) {
+ EXPECT_DCHECK_DEATH(tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ GetFakeIframeAttributionDataPtr()));
+}
+
+TEST_F(V8ContextTrackerDeathTest, IframeAttributionDataForInProcessChildFrame) {
+ // Create a child of mock_graph.frame that is in the same process.
+ TestNodeWrapper<FrameNodeImpl> child2_frame(graph()->CreateFrameNodeAutoId(
+ mock_graph.process.get(), mock_graph.page.get(), mock_graph.frame.get(),
+ 3));
+
+ // Trying to provide IFrameAttribution data via a RemoteFrameAttached
+ // notification should explode because |child2_frame| is in the same process
+ // as its parent.
+ EXPECT_DCHECK_DEATH(tracker->OnRemoteIframeAttachedForTesting(
+ child2_frame.get(), blink::RemoteFrameToken(),
+ GetFakeIframeAttributionDataPtr()));
+
+ // This should succeed because iframe data is provided.
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ child2_frame->frame_token()),
+ GetFakeIframeAttributionDataPtr());
+}
+
+TEST_F(V8ContextTrackerDeathTest,
+ NoIframeAttributionDataForInProcessChildFrameExplodes) {
+ // Create a child of mock_graph.frame that is in the same process.
+ TestNodeWrapper<FrameNodeImpl> child2_frame(graph()->CreateFrameNodeAutoId(
+ mock_graph.process.get(), mock_graph.page.get(), mock_graph.frame.get(),
+ 3));
+ // This should explode because synchronous iframe data is expected, but not
+ // provided.
+ EXPECT_DCHECK_DEATH(tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ child2_frame->frame_token()),
+ /* iframe_attribution_data */ nullptr));
+}
+
+TEST_F(V8ContextTrackerDeathTest, MultipleMainContextsForExecutionContext) {
+ // Create a main-frame with two main worlds.
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+
+ EXPECT_DCHECK_DEATH(tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ blink::V8ContextToken(),
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr));
+}
+
+TEST_F(V8ContextTrackerTest, NormalV8ContextLifecycleWithExecutionContext) {
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+}
+
+TEST_F(V8ContextTrackerTest, NormalV8ContextLifecycleNoExecutionContext) {
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kRegExp,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ base::nullopt),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(1, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(1, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+}
+
+TEST_F(V8ContextTrackerTest, MultipleV8ContextsForExecutionContext) {
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ // Create a main-frame main world context, and an isolated world.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameIsolatedWorld,
+ /* world_type */ mojom::V8ContextWorldType::kExtension,
+ /* world_name */ kExtensionId,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(2, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ // Create a child-frame main world context, and an isolated world. This child
+ // is cross-process so expects no iframe data at creation.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */
+ mock_graph.child_frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(3, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameIsolatedWorld,
+ /* world_type */ mojom::V8ContextWorldType::kExtension,
+ /* world_name */ kExtensionId,
+ /* execution_context_token */
+ mock_graph.child_frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(4, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ // Provide iframe data for the child frame.
+ {
+ SCOPED_TRACE("");
+ tracker->OnRemoteIframeAttachedForTesting(
+ mock_graph.child_frame.get(), kChildFrameRemoteToken,
+ GetFakeIframeAttributionDataPtr());
+ EXPECT_THAT(tracker, CountsMatch(4, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ // Detach the child frame contexts.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ kChildFrameIsolatedWorld);
+ EXPECT_THAT(tracker, CountsMatch(4, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ }
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ kChildFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(4, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(2, 0));
+ }
+
+ // Destroy the child frame main world context.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ kChildFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(3, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ }
+
+ // Detach the main frame contexts, main and isolated.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameMainWorld);
+ EXPECT_THAT(tracker, CountsMatch(3, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(2, 0));
+ }
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDetached(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(), kFrameIsolatedWorld);
+ EXPECT_THAT(tracker, CountsMatch(3, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(3, 0));
+ }
+
+ // Destroy the main frame isolated world.
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.process.get(),
+ kFrameIsolatedWorld);
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(2, 0));
+ }
+
+ // Destroy the child frame isolated world..
+ {
+ SCOPED_TRACE("");
+ tracker->OnV8ContextDestroyed(ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ kChildFrameIsolatedWorld);
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ }
+
+ // Destroy the remote iframe reference to the child frame, which should
+ // finally tear down the ExecutionContext as well.
+ {
+ SCOPED_TRACE("");
+ tracker->OnRemoteIframeDetachedForTesting(mock_graph.frame.get(),
+ kChildFrameRemoteToken);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ }
+}
+
+TEST_F(V8ContextTrackerTest, AllEventOrders) {
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ // Create a main frame. This exists for the duration of the test, and we
+ // repeatedly attach/detach child frames to it.
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ // Bind lambdas for all the events that can occur to a frame in its lifetime.
+ // This test will explore all possible valid combinations of these events.
+
+ // Creates a child frame V8Context.
+ auto v8create = [self = this]() {
+ SCOPED_TRACE("");
+ self->tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ self->mock_graph.other_process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */
+ self->mock_graph.child_frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ };
+
+ // Detaches a child frame V8Context.
+ auto v8detach = [self = this]() {
+ SCOPED_TRACE("");
+ self->tracker->OnV8ContextDetached(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ self->mock_graph.other_process.get(), kChildFrameMainWorld);
+ };
+
+ // Destroys a child frame V8Context.
+ auto v8destroy = [self = this]() {
+ SCOPED_TRACE("");
+ self->tracker->OnV8ContextDestroyed(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ self->mock_graph.other_process.get(), kChildFrameMainWorld);
+ };
+
+ // Attaches a child iframe. This is after frame resolution has occurred so it
+ // is aimed at the frame that is represented by the remote frame token
+ // (hence mock_graph.child_frame). The actual "OnRemoteIframeAttached"
+ // message originally arrives over the parent frame interface.
+ auto iframeattach = [self = this]() {
+ SCOPED_TRACE("");
+ self->tracker->OnRemoteIframeAttachedForTesting(
+ self->mock_graph.child_frame.get(), kChildFrameRemoteToken,
+ GetFakeIframeAttributionDataPtr());
+ };
+
+ // Detaches a child iframe. This message is sent over the interface associated
+ // with the parent frame that hosts the child frame (hence mock_graph.frame).
+ auto iframedetach = [self = this]() {
+ SCOPED_TRACE("");
+ self->tracker->OnRemoteIframeDetachedForTesting(
+ self->mock_graph.frame.get(), kChildFrameRemoteToken);
+ };
+
+ // The following tests look at all 10 possible orderings of the 3 ordered
+ // V8Context events interleaved with the 2 ordered Iframe events.
+
+ {
+ SCOPED_TRACE("Case 1");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 2");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 3");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 4");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 5");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 6");
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 7");
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 8");
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 9");
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+
+ {
+ SCOPED_TRACE("Case 10");
+ iframeattach();
+ EXPECT_THAT(tracker, CountsMatch(1, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ iframedetach();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8create();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ v8detach();
+ EXPECT_THAT(tracker, CountsMatch(2, 2));
+ EXPECT_THAT(tracker, DetachedCountsMatch(1, 0));
+ v8destroy();
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+ }
+}
+
+TEST_F(V8ContextTrackerTest, PublicApi) {
+ EXPECT_THAT(tracker, CountsMatch(0, 0));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ // Create a main frame.
+
+ EXPECT_FALSE(tracker->GetV8ContextState(kFrameMainWorld));
+ EXPECT_FALSE(
+ tracker->GetExecutionContextState(mock_graph.frame->frame_token()));
+
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(), mock_graph.process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */ mock_graph.frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ EXPECT_THAT(tracker, CountsMatch(1, 1));
+ EXPECT_THAT(tracker, DetachedCountsMatch(0, 0));
+
+ const auto* v8_state = tracker->GetV8ContextState(kFrameMainWorld);
+ ASSERT_TRUE(v8_state);
+ EXPECT_EQ(kFrameMainWorld, v8_state->description.token);
+ EXPECT_EQ(mojom::V8ContextWorldType::kMain, v8_state->description.world_type);
+ EXPECT_FALSE(v8_state->description.world_name);
+ ASSERT_TRUE(v8_state->description.execution_context_token);
+ EXPECT_EQ(blink::ExecutionContextToken(mock_graph.frame->frame_token()),
+ v8_state->description.execution_context_token.value());
+ const auto* ec_state =
+ tracker->GetExecutionContextState(mock_graph.frame->frame_token());
+ ASSERT_TRUE(ec_state);
+ EXPECT_EQ(blink::ExecutionContextToken(mock_graph.frame->frame_token()),
+ ec_state->token);
+
+ // Create a child frame.
+
+ ASSERT_FALSE(tracker->GetV8ContextState(kChildFrameMainWorld));
+ ASSERT_FALSE(
+ tracker->GetExecutionContextState(mock_graph.child_frame->frame_token()));
+
+ tracker->OnV8ContextCreated(
+ ProcessNodeImpl::CreatePassKeyForTesting(),
+ mock_graph.other_process.get(),
+ mojom::V8ContextDescription(
+ /* token */ kChildFrameMainWorld,
+ /* world_type */ mojom::V8ContextWorldType::kMain,
+ /* world_name */ base::nullopt,
+ /* execution_context_token */
+ mock_graph.child_frame->frame_token()),
+ /* iframe_attribution_data */ nullptr);
+ v8_state = tracker->GetV8ContextState(kChildFrameMainWorld);
+ ASSERT_TRUE(v8_state);
+ EXPECT_EQ(kChildFrameMainWorld, v8_state->description.token);
+ EXPECT_EQ(mojom::V8ContextWorldType::kMain, v8_state->description.world_type);
+ EXPECT_FALSE(v8_state->description.world_name);
+ ASSERT_TRUE(v8_state->description.execution_context_token);
+ EXPECT_EQ(blink::ExecutionContextToken(mock_graph.child_frame->frame_token()),
+ v8_state->description.execution_context_token.value());
+ ec_state =
+ tracker->GetExecutionContextState(mock_graph.child_frame->frame_token());
+ ASSERT_TRUE(ec_state);
+ EXPECT_EQ(blink::ExecutionContextToken(mock_graph.child_frame->frame_token()),
+ ec_state->token);
+
+ // Provide iframe data for the child frame.
+
+ ASSERT_FALSE(ec_state->iframe_attribution_data);
+ tracker->OnRemoteIframeAttachedForTesting(mock_graph.child_frame.get(),
+ kChildFrameRemoteToken,
+ GetFakeIframeAttributionDataPtr());
+
+ const auto& iad = ec_state->iframe_attribution_data;
+ ASSERT_TRUE(iad);
+ EXPECT_EQ(base::OptionalFromPtr(&kIframeId), iad->id);
+ EXPECT_EQ(base::OptionalFromPtr(&kIframeSrc), iad->src);
+}
+
+} // namespace v8_memory
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc b/chromium/components/performance_manager/v8_memory/v8_detailed_memory.cc
index 3820dd7b05b..0d3fdacf2b6 100644
--- a/chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc
+++ b/chromium/components/performance_manager/v8_memory/v8_detailed_memory.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 "components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h"
+#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
#include <utility>
#include <vector>
@@ -31,20 +31,20 @@ namespace performance_manager {
namespace v8_memory {
-class V8PerFrameMemoryDecorator::MeasurementRequestQueue {
+class V8DetailedMemoryDecorator::MeasurementRequestQueue {
public:
MeasurementRequestQueue() = default;
~MeasurementRequestQueue();
- const V8PerFrameMemoryRequest* GetNextRequest() const;
- const V8PerFrameMemoryRequest* GetNextBoundedRequest() const;
+ const V8DetailedMemoryRequest* GetNextRequest() const;
+ const V8DetailedMemoryRequest* GetNextBoundedRequest() const;
- void AddMeasurementRequest(V8PerFrameMemoryRequest* request);
+ void AddMeasurementRequest(V8DetailedMemoryRequest* request);
// Removes |request| if it is part of this queue, and returns the number of
// elements removed (will be 0 or 1).
- size_t RemoveMeasurementRequest(V8PerFrameMemoryRequest* request);
+ size_t RemoveMeasurementRequest(V8DetailedMemoryRequest* request);
void NotifyObserversOnMeasurementAvailable(
const ProcessNode* process_node) const;
@@ -55,20 +55,23 @@ class V8PerFrameMemoryDecorator::MeasurementRequestQueue {
void Validate();
private:
+ void ApplyToAllRequests(
+ base::RepeatingCallback<void(V8DetailedMemoryRequest*)> callback) const;
+
// Lists of requests sorted by min_time_between_requests (lowest first).
- std::vector<V8PerFrameMemoryRequest*> bounded_measurement_requests_;
- std::vector<V8PerFrameMemoryRequest*> lazy_measurement_requests_;
+ std::vector<V8DetailedMemoryRequest*> bounded_measurement_requests_;
+ std::vector<V8DetailedMemoryRequest*> lazy_measurement_requests_;
SEQUENCE_CHECKER(sequence_checker_);
};
// This class is allowed to access
-// V8PerFrameMemoryDecorator::NotifyObserversOnMeasurementAvailable.
-class V8PerFrameMemoryDecorator::ObserverNotifier {
+// V8DetailedMemoryDecorator::NotifyObserversOnMeasurementAvailable.
+class V8DetailedMemoryDecorator::ObserverNotifier {
public:
void NotifyObserversOnMeasurementAvailable(const ProcessNode* process_node) {
auto* decorator =
- V8PerFrameMemoryDecorator::GetFromGraph(process_node->GetGraph());
+ V8DetailedMemoryDecorator::GetFromGraph(process_node->GetGraph());
if (decorator)
decorator->NotifyObserversOnMeasurementAvailable(
util::PassKey<ObserverNotifier>(), process_node);
@@ -77,7 +80,7 @@ class V8PerFrameMemoryDecorator::ObserverNotifier {
namespace {
-using MeasurementMode = V8PerFrameMemoryRequest::MeasurementMode;
+using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
// Forwards the pending receiver to the RenderProcessHost and binds it on the
// UI thread.
@@ -104,9 +107,9 @@ bool IsMeasurementBounded(MeasurementMode mode) {
// Returns the higher priority request of |a| and |b|, either of which can be
// null, or nullptr if both are null.
-const V8PerFrameMemoryRequest* ChooseHigherPriorityRequest(
- const V8PerFrameMemoryRequest* a,
- const V8PerFrameMemoryRequest* b) {
+const V8DetailedMemoryRequest* ChooseHigherPriorityRequest(
+ const V8DetailedMemoryRequest* a,
+ const V8DetailedMemoryRequest* b) {
if (!a)
return b;
if (!b)
@@ -130,17 +133,17 @@ bool g_test_eager_measurement_requests_enabled = false;
// Per-frame memory measurement involves the following classes that live on the
// PM sequence:
//
-// V8PerFrameMemoryDecorator: Central rendezvous point. Coordinates
-// V8PerFrameMemoryRequest and V8PerFrameMemoryObserver objects. Owned by
+// V8DetailedMemoryDecorator: Central rendezvous point. Coordinates
+// V8DetailedMemoryRequest and V8DetailedMemoryObserver objects. Owned by
// the graph; created the first time
-// V8PerFrameMemoryRequest::StartMeasurement is called.
+// V8DetailedMemoryRequest::StartMeasurement is called.
// TODO(b/1080672): Currently this lives forever; should be cleaned up when
// there are no more measurements scheduled.
//
-// V8PerFrameMemoryRequest: Indicates that a caller wants memory to be measured
+// V8DetailedMemoryRequest: Indicates that a caller wants memory to be measured
// at a specific interval. Owned by the caller but must live on the PM
-// sequence. V8PerFrameMemoryRequest objects register themselves with
-// V8PerFrameMemoryDecorator on creation and unregister themselves on
+// sequence. V8DetailedMemoryRequest objects register themselves with
+// V8DetailedMemoryDecorator on creation and unregister themselves on
// deletion, which cancels the corresponding measurement.
//
// NodeAttachedProcessData: Private class that schedules measurements and holds
@@ -149,7 +152,7 @@ bool g_test_eager_measurement_requests_enabled = false;
// TODO(b/1080672): Currently this lives forever; should be cleaned up when
// there are no more measurements scheduled.
//
-// V8PerFrameMemoryProcessData: Public accessor to the measurement results held
+// V8DetailedMemoryProcessData: Public accessor to the measurement results held
// in a NodeAttachedProcessData, which owns it.
//
// NodeAttachedFrameData: Private class that holds the measurement results for
@@ -158,23 +161,23 @@ bool g_test_eager_measurement_requests_enabled = false;
// TODO(b/1080672): Currently this lives forever; should be cleaned up when
// there are no more measurements scheduled.
//
-// V8PerFrameMemoryFrameData: Public accessor to the measurement results held
+// V8DetailedMemoryFrameData: Public accessor to the measurement results held
// in a NodeAttachedFrameData, which owns it.
//
-// V8PerFrameMemoryObserver: Callers can implement this and register with
-// V8PerFrameMemoryDecorator::AddObserver() to be notified when
+// V8DetailedMemoryObserver: Callers can implement this and register with
+// V8DetailedMemoryDecorator::AddObserver() to be notified when
// measurements are available for a process. Owned by the caller but must
// live on the PM sequence.
//
// Additional wrapper classes can access these classes from other sequences:
//
-// V8PerFrameMemoryRequestAnySeq: Wraps V8PerFrameMemoryRequest. Owned by the
+// V8DetailedMemoryRequestAnySeq: Wraps V8DetailedMemoryRequest. Owned by the
// caller and lives on any sequence.
//
-// V8PerFrameMemoryObserverAnySeq: Callers can implement this and register it
-// with V8PerFrameMemoryRequestAnySeq::AddObserver() to be notified when
+// V8DetailedMemoryObserverAnySeq: Callers can implement this and register it
+// with V8DetailedMemoryRequestAnySeq::AddObserver() to be notified when
// measurements are available for a process. Owned by the caller and lives
-// on the same sequence as the V8PerFrameMemoryRequestAnySeq.
+// on the same sequence as the V8DetailedMemoryRequestAnySeq.
////////////////////////////////////////////////////////////////////////////////
// NodeAttachedFrameData
@@ -188,15 +191,16 @@ class NodeAttachedFrameData
NodeAttachedFrameData(const NodeAttachedFrameData&) = delete;
NodeAttachedFrameData& operator=(const NodeAttachedFrameData&) = delete;
- const V8PerFrameMemoryFrameData* data() const {
+ const V8DetailedMemoryFrameData* data() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return data_available_ ? &data_ : nullptr;
}
private:
friend class NodeAttachedProcessData;
+ friend class performance_manager::v8_memory::V8DetailedMemoryFrameData;
- V8PerFrameMemoryFrameData data_;
+ V8DetailedMemoryFrameData data_;
bool data_available_ = false;
SEQUENCE_CHECKER(sequence_checker_);
};
@@ -220,14 +224,14 @@ class NodeAttachedProcessData
Graph* graph,
base::RepeatingCallback<void(NodeAttachedProcessData*)> callback);
- const V8PerFrameMemoryProcessData* data() const {
+ const V8DetailedMemoryProcessData* data() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return data_available_ ? &data_ : nullptr;
}
void ScheduleNextMeasurement();
- V8PerFrameMemoryDecorator::MeasurementRequestQueue&
+ V8DetailedMemoryDecorator::MeasurementRequestQueue&
process_measurement_requests() {
return process_measurement_requests_;
}
@@ -242,7 +246,7 @@ class NodeAttachedProcessData
const ProcessNode* const process_node_;
// Measurement requests that will be sent to this process only.
- V8PerFrameMemoryDecorator::MeasurementRequestQueue
+ V8DetailedMemoryDecorator::MeasurementRequestQueue
process_measurement_requests_;
mojo::Remote<blink::mojom::V8DetailedMemoryReporter> resource_usage_reporter_;
@@ -271,7 +275,7 @@ class NodeAttachedProcessData
base::OneShotTimer request_timer_;
base::OneShotTimer bounded_upgrade_timer_;
- V8PerFrameMemoryProcessData data_;
+ V8DetailedMemoryProcessData data_;
bool data_available_ = false;
SEQUENCE_CHECKER(sequence_checker_);
@@ -321,10 +325,10 @@ void NodeAttachedProcessData::ScheduleNextMeasurement() {
// Find the next request for this process, checking both the per-process
// queue and the global queue.
- const V8PerFrameMemoryRequest* next_request =
+ const V8DetailedMemoryRequest* next_request =
process_measurement_requests_.GetNextRequest();
auto* decorator =
- V8PerFrameMemoryDecorator::GetFromGraph(process_node_->GetGraph());
+ V8DetailedMemoryDecorator::GetFromGraph(process_node_->GetGraph());
if (decorator) {
next_request =
ChooseHigherPriorityRequest(next_request, decorator->GetNextRequest());
@@ -376,7 +380,7 @@ void NodeAttachedProcessData::StartMeasurement(MeasurementMode mode) {
// cleaned up while a request to a renderer is outstanding. Currently this
// never actually happens (it is destroyed only when the graph is torn down,
// which should happen after renderers are destroyed). Should clean up
- // NodeAttachedProcessData when the last V8PerFrameMemoryRequest is deleted,
+ // NodeAttachedProcessData when the last V8DetailedMemoryRequest is deleted,
// which could happen at any time.
blink::mojom::V8DetailedMemoryReporter::Mode mojo_mode;
switch (mode) {
@@ -387,9 +391,6 @@ void NodeAttachedProcessData::StartMeasurement(MeasurementMode mode) {
mojo_mode = blink::mojom::V8DetailedMemoryReporter::Mode::DEFAULT;
break;
case MeasurementMode::kEagerForTesting:
-#if DCHECK_IS_ON()
- DCHECK(g_test_eager_measurement_requests_enabled);
-#endif
mojo_mode = blink::mojom::V8DetailedMemoryReporter::Mode::EAGER;
break;
}
@@ -403,10 +404,10 @@ void NodeAttachedProcessData::ScheduleUpgradeToBoundedMeasurement() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(state_, State::kMeasuringLazy);
- const V8PerFrameMemoryRequest* bounded_request =
+ const V8DetailedMemoryRequest* bounded_request =
process_measurement_requests_.GetNextBoundedRequest();
auto* decorator =
- V8PerFrameMemoryDecorator::GetFromGraph(process_node_->GetGraph());
+ V8DetailedMemoryDecorator::GetFromGraph(process_node_->GetGraph());
if (decorator) {
bounded_request = ChooseHigherPriorityRequest(
bounded_request, decorator->GetNextBoundedRequest());
@@ -513,7 +514,7 @@ void NodeAttachedProcessData::OnV8MemoryUsage(
process_measurement_requests_.NotifyObserversOnMeasurementAvailable(
process_node_);
- V8PerFrameMemoryDecorator::ObserverNotifier()
+ V8DetailedMemoryDecorator::ObserverNotifier()
.NotifyObserversOnMeasurementAvailable(process_node_);
}
@@ -553,12 +554,18 @@ void SetEagerMemoryMeasurementEnabledForTesting(bool enabled) {
#endif
}
+void DestroyV8DetailedMemoryDecoratorForTesting(Graph* graph) {
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph);
+ if (decorator)
+ graph->TakeFromGraph(decorator);
+}
+
} // namespace internal
////////////////////////////////////////////////////////////////////////////////
-// V8PerFrameMemoryRequest
+// V8DetailedMemoryRequest
-V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
+V8DetailedMemoryRequest::V8DetailedMemoryRequest(
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode)
: min_time_between_requests_(min_time_between_requests), mode_(mode) {
@@ -570,55 +577,69 @@ V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
#endif
}
-V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
+V8DetailedMemoryRequest::V8DetailedMemoryRequest(
const base::TimeDelta& min_time_between_requests,
Graph* graph)
- : V8PerFrameMemoryRequest(min_time_between_requests,
+ : V8DetailedMemoryRequest(min_time_between_requests,
MeasurementMode::kDefault) {
StartMeasurement(graph);
}
-V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
+V8DetailedMemoryRequest::V8DetailedMemoryRequest(
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
Graph* graph)
- : V8PerFrameMemoryRequest(min_time_between_requests, mode) {
+ : V8DetailedMemoryRequest(min_time_between_requests, mode) {
StartMeasurement(graph);
}
-// This constructor is called from the V8PerFrameMemoryRequestAnySeq's
+// This constructor is called from the V8DetailedMemoryRequestAnySeq's
// sequence.
-V8PerFrameMemoryRequest::V8PerFrameMemoryRequest(
- util::PassKey<V8PerFrameMemoryRequestAnySeq>,
+V8DetailedMemoryRequest::V8DetailedMemoryRequest(
+ util::PassKey<V8DetailedMemoryRequestAnySeq>,
const base::TimeDelta& min_time_between_requests,
MeasurementMode mode,
- base::WeakPtr<V8PerFrameMemoryRequestAnySeq> off_sequence_request)
- : V8PerFrameMemoryRequest(min_time_between_requests, mode) {
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure,
+ base::WeakPtr<V8DetailedMemoryRequestAnySeq> off_sequence_request)
+ : V8DetailedMemoryRequest(min_time_between_requests, mode) {
DETACH_FROM_SEQUENCE(sequence_checker_);
off_sequence_request_ = std::move(off_sequence_request);
off_sequence_request_sequence_ = base::SequencedTaskRunnerHandle::Get();
- // Unretained is safe since |this| will be destroyed on the graph sequence.
+ // Unretained is safe since |this| will be destroyed on the graph sequence
+ // from an async task posted after this.
PerformanceManager::CallOnGraph(
- FROM_HERE, base::BindOnce(&V8PerFrameMemoryRequest::StartMeasurement,
- base::Unretained(this)));
+ FROM_HERE,
+ base::BindOnce(&V8DetailedMemoryRequest::StartMeasurementFromOffSequence,
+ base::Unretained(this), std::move(process_to_measure)));
+}
+
+V8DetailedMemoryRequest::V8DetailedMemoryRequest(
+ util::PassKey<V8DetailedMemoryRequestOneShot>,
+ MeasurementMode mode,
+ base::OnceClosure on_owner_unregistered_closure)
+ : min_time_between_requests_(base::TimeDelta()),
+ mode_(mode),
+ on_owner_unregistered_closure_(std::move(on_owner_unregistered_closure)) {
+ // Do not forward to the standard constructor because it disallows the empty
+ // TimeDelta.
}
-V8PerFrameMemoryRequest::~V8PerFrameMemoryRequest() {
+V8DetailedMemoryRequest::~V8DetailedMemoryRequest() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (decorator_)
decorator_->RemoveMeasurementRequest(
- util::PassKey<V8PerFrameMemoryRequest>(), this);
+ util::PassKey<V8DetailedMemoryRequest>(), this);
// TODO(crbug.com/1080672): Delete the decorator and its NodeAttachedData
// when the last request is destroyed. Make sure this doesn't mess up any
// measurement that's already in progress.
}
-void V8PerFrameMemoryRequest::StartMeasurement(Graph* graph) {
+void V8DetailedMemoryRequest::StartMeasurement(Graph* graph) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
StartMeasurementImpl(graph, nullptr);
}
-void V8PerFrameMemoryRequest::StartMeasurementForProcess(
+void V8DetailedMemoryRequest::StartMeasurementForProcess(
const ProcessNode* process_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(process_node);
@@ -626,45 +647,45 @@ void V8PerFrameMemoryRequest::StartMeasurementForProcess(
StartMeasurementImpl(process_node->GetGraph(), process_node);
}
-void V8PerFrameMemoryRequest::AddObserver(V8PerFrameMemoryObserver* observer) {
+void V8DetailedMemoryRequest::AddObserver(V8DetailedMemoryObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observers_.AddObserver(observer);
}
-void V8PerFrameMemoryRequest::RemoveObserver(
- V8PerFrameMemoryObserver* observer) {
+void V8DetailedMemoryRequest::RemoveObserver(
+ V8DetailedMemoryObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(observers_.HasObserver(observer));
observers_.RemoveObserver(observer);
}
-void V8PerFrameMemoryRequest::OnOwnerUnregistered(
- util::PassKey<V8PerFrameMemoryDecorator::MeasurementRequestQueue>) {
+void V8DetailedMemoryRequest::OnOwnerUnregistered(
+ util::PassKey<V8DetailedMemoryDecorator::MeasurementRequestQueue>) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
decorator_ = nullptr;
+ if (on_owner_unregistered_closure_)
+ std::move(on_owner_unregistered_closure_).Run();
}
-void V8PerFrameMemoryRequest::NotifyObserversOnMeasurementAvailable(
- util::PassKey<V8PerFrameMemoryDecorator::MeasurementRequestQueue>,
+void V8DetailedMemoryRequest::NotifyObserversOnMeasurementAvailable(
+ util::PassKey<V8DetailedMemoryDecorator::MeasurementRequestQueue>,
const ProcessNode* process_node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto* process_data =
- V8PerFrameMemoryProcessData::ForProcessNode(process_node);
+ V8DetailedMemoryProcessData::ForProcessNode(process_node);
DCHECK(process_data);
- for (V8PerFrameMemoryObserver& observer : observers_)
- observer.OnV8MemoryMeasurementAvailable(process_node, process_data);
// If this request was made from off-sequence, notify its off-sequence
// observers with a copy of the process and frame data.
if (off_sequence_request_.MaybeValid()) {
using FrameAndData =
- std::pair<content::GlobalFrameRoutingId, V8PerFrameMemoryFrameData>;
+ std::pair<content::GlobalFrameRoutingId, V8DetailedMemoryFrameData>;
std::vector<FrameAndData> all_frame_data;
process_node->VisitFrameNodes(base::BindRepeating(
[](std::vector<FrameAndData>* all_frame_data,
const FrameNode* frame_node) {
const auto* frame_data =
- V8PerFrameMemoryFrameData::ForFrameNode(frame_node);
+ V8DetailedMemoryFrameData::ForFrameNode(frame_node);
if (frame_data) {
all_frame_data->push_back(std::make_pair(
frame_node->GetRenderFrameHostProxy().global_frame_routing_id(),
@@ -675,61 +696,198 @@ void V8PerFrameMemoryRequest::NotifyObserversOnMeasurementAvailable(
base::Unretained(&all_frame_data)));
off_sequence_request_sequence_->PostTask(
FROM_HERE,
- base::BindOnce(&V8PerFrameMemoryRequestAnySeq::
+ base::BindOnce(&V8DetailedMemoryRequestAnySeq::
NotifyObserversOnMeasurementAvailable,
off_sequence_request_,
- util::PassKey<V8PerFrameMemoryRequest>(),
+ util::PassKey<V8DetailedMemoryRequest>(),
process_node->GetRenderProcessHostId(), *process_data,
- V8PerFrameMemoryObserverAnySeq::FrameDataMap(
+ V8DetailedMemoryObserverAnySeq::FrameDataMap(
std::move(all_frame_data))));
}
+
+ // The observer could delete the request so this must be the last thing in
+ // the function.
+ for (V8DetailedMemoryObserver& observer : observers_)
+ observer.OnV8MemoryMeasurementAvailable(process_node, process_data);
+}
+
+void V8DetailedMemoryRequest::StartMeasurementFromOffSequence(
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure,
+ Graph* graph) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!process_to_measure) {
+ // No process was given so measure all renderers in the graph.
+ StartMeasurement(graph);
+ } else if (!process_to_measure.value()) {
+ // V8DetailedMemoryRequestAnySeq was called with a process ID that wasn't
+ // found in the graph, or has already been destroyed. Do nothing.
+ } else {
+ DCHECK_EQ(graph, process_to_measure.value()->GetGraph());
+ StartMeasurementForProcess(process_to_measure.value().get());
+ }
}
-void V8PerFrameMemoryRequest::StartMeasurementImpl(
+void V8DetailedMemoryRequest::StartMeasurementImpl(
Graph* graph,
const ProcessNode* process_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(nullptr, decorator_);
DCHECK(!process_node || graph == process_node->GetGraph());
- decorator_ = V8PerFrameMemoryDecorator::GetFromGraph(graph);
+ decorator_ = V8DetailedMemoryDecorator::GetFromGraph(graph);
if (!decorator_) {
// Create the decorator when the first measurement starts.
- auto decorator_ptr = std::make_unique<V8PerFrameMemoryDecorator>();
+ auto decorator_ptr = std::make_unique<V8DetailedMemoryDecorator>();
decorator_ = decorator_ptr.get();
graph->PassToGraph(std::move(decorator_ptr));
}
- decorator_->AddMeasurementRequest(util::PassKey<V8PerFrameMemoryRequest>(),
+ decorator_->AddMeasurementRequest(util::PassKey<V8DetailedMemoryRequest>(),
this, process_node);
}
////////////////////////////////////////////////////////////////////////////////
-// V8PerFrameMemoryFrameData
+// V8DetailedMemoryRequestOneShot
+
+V8DetailedMemoryRequestOneShot::V8DetailedMemoryRequestOneShot(
+ MeasurementMode mode)
+ : mode_(mode) {
+ InitializeRequest();
+}
+
+V8DetailedMemoryRequestOneShot::V8DetailedMemoryRequestOneShot(
+ const ProcessNode* process,
+ MeasurementCallback callback,
+ MeasurementMode mode)
+ : mode_(mode) {
+ InitializeRequest();
+ StartMeasurement(process, std::move(callback));
+}
+
+V8DetailedMemoryRequestOneShot::~V8DetailedMemoryRequestOneShot() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DeleteRequest();
+}
+
+void V8DetailedMemoryRequestOneShot::StartMeasurement(
+ const ProcessNode* process,
+ MeasurementCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(request_);
+ DCHECK(process);
+ DCHECK_EQ(process->GetProcessType(), content::PROCESS_TYPE_RENDERER);
+#if DCHECK_IS_ON()
+ process_ = process;
+#endif
+
+ callback_ = std::move(callback);
+ request_->StartMeasurementForProcess(process);
+}
+
+void V8DetailedMemoryRequestOneShot::OnV8MemoryMeasurementAvailable(
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+#if DCHECK_IS_ON()
+ DCHECK_EQ(process_node, process_);
+#endif
+
+ // Don't send another request now that a response has been received.
+ DeleteRequest();
+
+ std::move(callback_).Run(process_node, process_data);
+}
+
+// This constructor is called from the V8DetailedMemoryRequestOneShotAnySeq's
+// sequence.
+V8DetailedMemoryRequestOneShot::V8DetailedMemoryRequestOneShot(
+ util::PassKey<V8DetailedMemoryRequestOneShotAnySeq>,
+ base::WeakPtr<ProcessNode> process,
+ MeasurementCallback callback,
+ MeasurementMode mode)
+ : mode_(mode) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ // Unretained is safe since |this| will be destroyed on the graph sequence
+ // from an async task posted after this.
+ PerformanceManager::CallOnGraph(
+ FROM_HERE,
+ base::BindOnce(&V8DetailedMemoryRequestOneShot::InitializeRequest,
+ base::Unretained(this)));
+ PerformanceManager::CallOnGraph(
+ FROM_HERE,
+ base::BindOnce(
+ &V8DetailedMemoryRequestOneShot::StartMeasurementFromOffSequence,
+ base::Unretained(this), std::move(process), std::move(callback)));
+}
+
+void V8DetailedMemoryRequestOneShot::InitializeRequest() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ request_ = std::make_unique<V8DetailedMemoryRequest>(
+ util::PassKey<V8DetailedMemoryRequestOneShot>(), mode_,
+ base::BindOnce(&V8DetailedMemoryRequestOneShot::OnOwnerUnregistered,
+ // Unretained is safe because |this| owns the request
+ // object that will invoke the closure.
+ base::Unretained(this)));
+ request_->AddObserver(this);
+}
+
+void V8DetailedMemoryRequestOneShot::StartMeasurementFromOffSequence(
+ base::WeakPtr<ProcessNode> process,
+ MeasurementCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (process)
+ StartMeasurement(process.get(), std::move(callback));
+}
-const V8PerFrameMemoryFrameData* V8PerFrameMemoryFrameData::ForFrameNode(
+void V8DetailedMemoryRequestOneShot::DeleteRequest() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (request_)
+ request_->RemoveObserver(this);
+ request_.reset();
+}
+
+void V8DetailedMemoryRequestOneShot::OnOwnerUnregistered() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // No results will arrive so clean up the request and callback. This frees
+ // any resources that were owned by the callback.
+ DeleteRequest();
+ std::move(callback_).Reset();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// V8DetailedMemoryFrameData
+
+const V8DetailedMemoryFrameData* V8DetailedMemoryFrameData::ForFrameNode(
const FrameNode* node) {
auto* node_data = NodeAttachedFrameData::Get(node);
return node_data ? node_data->data() : nullptr;
}
+V8DetailedMemoryFrameData* V8DetailedMemoryFrameData::CreateForTesting(
+ const FrameNode* node) {
+ auto* node_data = NodeAttachedFrameData::GetOrCreate(node);
+ node_data->data_available_ = true;
+ return &node_data->data_;
+}
+
////////////////////////////////////////////////////////////////////////////////
-// V8PerFrameMemoryProcessData
+// V8DetailedMemoryProcessData
-const V8PerFrameMemoryProcessData* V8PerFrameMemoryProcessData::ForProcessNode(
+const V8DetailedMemoryProcessData* V8DetailedMemoryProcessData::ForProcessNode(
const ProcessNode* node) {
auto* node_data = NodeAttachedProcessData::Get(node);
return node_data ? node_data->data() : nullptr;
}
////////////////////////////////////////////////////////////////////////////////
-// V8PerFrameMemoryDecorator
+// V8DetailedMemoryDecorator
-V8PerFrameMemoryDecorator::V8PerFrameMemoryDecorator()
+V8DetailedMemoryDecorator::V8DetailedMemoryDecorator()
: measurement_requests_(std::make_unique<MeasurementRequestQueue>()) {}
-V8PerFrameMemoryDecorator::~V8PerFrameMemoryDecorator() = default;
+V8DetailedMemoryDecorator::~V8DetailedMemoryDecorator() = default;
-void V8PerFrameMemoryDecorator::OnPassedToGraph(Graph* graph) {
+void V8DetailedMemoryDecorator::OnPassedToGraph(Graph* graph) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(nullptr, graph_);
graph_ = graph;
@@ -742,10 +900,10 @@ void V8PerFrameMemoryDecorator::OnPassedToGraph(Graph* graph) {
graph->AddProcessNodeObserver(this);
graph->GetNodeDataDescriberRegistry()->RegisterDescriber(
- this, "V8PerFrameMemoryDecorator");
+ this, "V8DetailedMemoryDecorator");
}
-void V8PerFrameMemoryDecorator::OnTakenFromGraph(Graph* graph) {
+void V8DetailedMemoryDecorator::OnTakenFromGraph(Graph* graph) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(graph, graph_);
@@ -759,7 +917,7 @@ void V8PerFrameMemoryDecorator::OnTakenFromGraph(Graph* graph) {
graph_ = nullptr;
}
-void V8PerFrameMemoryDecorator::OnProcessNodeAdded(
+void V8DetailedMemoryDecorator::OnProcessNodeAdded(
const ProcessNode* process_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(nullptr, NodeAttachedProcessData::Get(process_node));
@@ -773,7 +931,7 @@ void V8PerFrameMemoryDecorator::OnProcessNodeAdded(
NodeAttachedProcessData::GetOrCreate(process_node);
}
-void V8PerFrameMemoryDecorator::OnBeforeProcessNodeRemoved(
+void V8DetailedMemoryDecorator::OnBeforeProcessNodeRemoved(
const ProcessNode* process_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Only renderer processes have data.
@@ -785,11 +943,11 @@ void V8PerFrameMemoryDecorator::OnBeforeProcessNodeRemoved(
process_data->process_measurement_requests().OnOwnerUnregistered();
}
-base::Value V8PerFrameMemoryDecorator::DescribeFrameNodeData(
+base::Value V8DetailedMemoryDecorator::DescribeFrameNodeData(
const FrameNode* frame_node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto* const frame_data =
- V8PerFrameMemoryFrameData::ForFrameNode(frame_node);
+ V8DetailedMemoryFrameData::ForFrameNode(frame_node);
if (!frame_data)
return base::Value();
@@ -798,11 +956,11 @@ base::Value V8PerFrameMemoryDecorator::DescribeFrameNodeData(
return dict;
}
-base::Value V8PerFrameMemoryDecorator::DescribeProcessNodeData(
+base::Value V8DetailedMemoryDecorator::DescribeProcessNodeData(
const ProcessNode* process_node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const auto* const process_data =
- V8PerFrameMemoryProcessData::ForProcessNode(process_node);
+ V8DetailedMemoryProcessData::ForProcessNode(process_node);
if (!process_data)
return base::Value();
@@ -814,21 +972,21 @@ base::Value V8PerFrameMemoryDecorator::DescribeProcessNodeData(
return dict;
}
-const V8PerFrameMemoryRequest* V8PerFrameMemoryDecorator::GetNextRequest()
+const V8DetailedMemoryRequest* V8DetailedMemoryDecorator::GetNextRequest()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return measurement_requests_->GetNextRequest();
}
-const V8PerFrameMemoryRequest*
-V8PerFrameMemoryDecorator::GetNextBoundedRequest() const {
+const V8DetailedMemoryRequest*
+V8DetailedMemoryDecorator::GetNextBoundedRequest() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return measurement_requests_->GetNextBoundedRequest();
}
-void V8PerFrameMemoryDecorator::AddMeasurementRequest(
- util::PassKey<V8PerFrameMemoryRequest> key,
- V8PerFrameMemoryRequest* request,
+void V8DetailedMemoryDecorator::AddMeasurementRequest(
+ util::PassKey<V8DetailedMemoryRequest> key,
+ V8DetailedMemoryRequest* request,
const ProcessNode* process_node) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (process_node) {
@@ -841,25 +999,25 @@ void V8PerFrameMemoryDecorator::AddMeasurementRequest(
UpdateProcessMeasurementSchedules();
}
-void V8PerFrameMemoryDecorator::RemoveMeasurementRequest(
- util::PassKey<V8PerFrameMemoryRequest> key,
- V8PerFrameMemoryRequest* request) {
+void V8DetailedMemoryDecorator::RemoveMeasurementRequest(
+ util::PassKey<V8DetailedMemoryRequest> key,
+ V8DetailedMemoryRequest* request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Attempt to remove this request from all process-specific queues and the
// global queue. It will only be in one of them.
size_t removal_count = 0;
- // Unretained is safe because this callback is synchronous.
ApplyToAllRequestQueues(base::BindRepeating(
- [](V8PerFrameMemoryRequest* request, size_t* removal_count,
+ // Raw pointers are safe because this callback is synchronous.
+ [](V8DetailedMemoryRequest* request, size_t* removal_count,
MeasurementRequestQueue* queue) {
(*removal_count) += queue->RemoveMeasurementRequest(request);
},
- base::Unretained(request), base::Unretained(&removal_count)));
+ request, &removal_count));
DCHECK_EQ(removal_count, 1ULL);
UpdateProcessMeasurementSchedules();
}
-void V8PerFrameMemoryDecorator::ApplyToAllRequestQueues(
+void V8DetailedMemoryDecorator::ApplyToAllRequestQueues(
RequestQueueCallback callback) const {
callback.Run(measurement_requests_.get());
NodeAttachedProcessData::ApplyToAllRenderers(
@@ -871,7 +1029,7 @@ void V8PerFrameMemoryDecorator::ApplyToAllRequestQueues(
std::move(callback)));
}
-void V8PerFrameMemoryDecorator::UpdateProcessMeasurementSchedules() const {
+void V8DetailedMemoryDecorator::UpdateProcessMeasurementSchedules() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(graph_);
measurement_requests_->Validate();
@@ -880,20 +1038,20 @@ void V8PerFrameMemoryDecorator::UpdateProcessMeasurementSchedules() const {
base::BindRepeating(&NodeAttachedProcessData::ScheduleNextMeasurement));
}
-void V8PerFrameMemoryDecorator::NotifyObserversOnMeasurementAvailable(
+void V8DetailedMemoryDecorator::NotifyObserversOnMeasurementAvailable(
util::PassKey<ObserverNotifier> key,
const ProcessNode* process_node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
measurement_requests_->NotifyObserversOnMeasurementAvailable(process_node);
}
-V8PerFrameMemoryDecorator::MeasurementRequestQueue::~MeasurementRequestQueue() {
+V8DetailedMemoryDecorator::MeasurementRequestQueue::~MeasurementRequestQueue() {
DCHECK(bounded_measurement_requests_.empty());
DCHECK(lazy_measurement_requests_.empty());
}
-const V8PerFrameMemoryRequest*
-V8PerFrameMemoryDecorator::MeasurementRequestQueue::GetNextRequest() const {
+const V8DetailedMemoryRequest*
+V8DetailedMemoryDecorator::MeasurementRequestQueue::GetNextRequest() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ChooseHigherPriorityRequest(GetNextBoundedRequest(),
lazy_measurement_requests_.empty()
@@ -901,8 +1059,8 @@ V8PerFrameMemoryDecorator::MeasurementRequestQueue::GetNextRequest() const {
: lazy_measurement_requests_.front());
}
-const V8PerFrameMemoryRequest*
-V8PerFrameMemoryDecorator::MeasurementRequestQueue::GetNextBoundedRequest()
+const V8DetailedMemoryRequest*
+V8DetailedMemoryDecorator::MeasurementRequestQueue::GetNextBoundedRequest()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return bounded_measurement_requests_.empty()
@@ -910,19 +1068,19 @@ V8PerFrameMemoryDecorator::MeasurementRequestQueue::GetNextBoundedRequest()
: bounded_measurement_requests_.front();
}
-void V8PerFrameMemoryDecorator::MeasurementRequestQueue::AddMeasurementRequest(
- V8PerFrameMemoryRequest* request) {
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::AddMeasurementRequest(
+ V8DetailedMemoryRequest* request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(request);
- std::vector<V8PerFrameMemoryRequest*>& measurement_requests =
+ std::vector<V8DetailedMemoryRequest*>& measurement_requests =
IsMeasurementBounded(request->mode()) ? bounded_measurement_requests_
: lazy_measurement_requests_;
DCHECK(!base::Contains(measurement_requests, request))
- << "V8PerFrameMemoryRequest object added twice";
+ << "V8DetailedMemoryRequest object added twice";
// Each user of the decorator is expected to issue a single
- // V8PerFrameMemoryRequest, so the size of measurement_requests is too low
+ // V8DetailedMemoryRequest, so the size of measurement_requests is too low
// to make the complexity of real priority queue worthwhile.
- for (std::vector<V8PerFrameMemoryRequest*>::const_iterator it =
+ for (std::vector<V8DetailedMemoryRequest*>::const_iterator it =
measurement_requests.begin();
it != measurement_requests.end(); ++it) {
if (request->min_time_between_requests() <
@@ -935,8 +1093,8 @@ void V8PerFrameMemoryDecorator::MeasurementRequestQueue::AddMeasurementRequest(
}
size_t
-V8PerFrameMemoryDecorator::MeasurementRequestQueue::RemoveMeasurementRequest(
- V8PerFrameMemoryRequest* request) {
+V8DetailedMemoryDecorator::MeasurementRequestQueue::RemoveMeasurementRequest(
+ V8DetailedMemoryRequest* request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(request);
return base::Erase(IsMeasurementBounded(request->mode())
@@ -945,37 +1103,34 @@ V8PerFrameMemoryDecorator::MeasurementRequestQueue::RemoveMeasurementRequest(
request);
}
-void V8PerFrameMemoryDecorator::MeasurementRequestQueue::
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::
NotifyObserversOnMeasurementAvailable(
const ProcessNode* process_node) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- for (const V8PerFrameMemoryRequest* request : bounded_measurement_requests_) {
- request->NotifyObserversOnMeasurementAvailable(
- util::PassKey<MeasurementRequestQueue>(), process_node);
- }
- for (const V8PerFrameMemoryRequest* request : lazy_measurement_requests_) {
- request->NotifyObserversOnMeasurementAvailable(
- util::PassKey<MeasurementRequestQueue>(), process_node);
- }
+
+ // Raw pointers are safe because the callback is synchronous.
+ ApplyToAllRequests(base::BindRepeating(
+ [](const ProcessNode* process_node, V8DetailedMemoryRequest* request) {
+ request->NotifyObserversOnMeasurementAvailable(
+ util::PassKey<MeasurementRequestQueue>(), process_node);
+ },
+ process_node));
}
-void V8PerFrameMemoryDecorator::MeasurementRequestQueue::OnOwnerUnregistered() {
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::OnOwnerUnregistered() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- for (V8PerFrameMemoryRequest* request : bounded_measurement_requests_) {
+ ApplyToAllRequests(base::BindRepeating([](V8DetailedMemoryRequest* request) {
request->OnOwnerUnregistered(util::PassKey<MeasurementRequestQueue>());
- }
+ }));
bounded_measurement_requests_.clear();
- for (V8PerFrameMemoryRequest* request : lazy_measurement_requests_) {
- request->OnOwnerUnregistered(util::PassKey<MeasurementRequestQueue>());
- }
lazy_measurement_requests_.clear();
}
-void V8PerFrameMemoryDecorator::MeasurementRequestQueue::Validate() {
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::Validate() {
#if DCHECK_IS_ON()
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto check_invariants =
- [](const std::vector<V8PerFrameMemoryRequest*>& measurement_requests,
+ [](const std::vector<V8DetailedMemoryRequest*>& measurement_requests,
bool is_bounded) {
for (size_t i = 1; i < measurement_requests.size(); ++i) {
DCHECK(measurement_requests[i - 1]);
@@ -993,63 +1148,212 @@ void V8PerFrameMemoryDecorator::MeasurementRequestQueue::Validate() {
#endif
}
+void V8DetailedMemoryDecorator::MeasurementRequestQueue::ApplyToAllRequests(
+ base::RepeatingCallback<void(V8DetailedMemoryRequest*)> callback) const {
+ // First collect all requests to notify. The callback may add or remove
+ // requests from the queue, invalidating iterators.
+ std::vector<V8DetailedMemoryRequest*> requests_to_notify;
+ requests_to_notify.insert(requests_to_notify.end(),
+ bounded_measurement_requests_.begin(),
+ bounded_measurement_requests_.end());
+ requests_to_notify.insert(requests_to_notify.end(),
+ lazy_measurement_requests_.begin(),
+ lazy_measurement_requests_.end());
+ for (V8DetailedMemoryRequest* request : requests_to_notify) {
+ callback.Run(request);
+ // The callback may have deleted |request| so it is no longer safe to
+ // reference.
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
-// V8PerFrameMemoryRequestAnySeq
+// V8DetailedMemoryRequestAnySeq
-V8PerFrameMemoryRequestAnySeq::V8PerFrameMemoryRequestAnySeq(
+V8DetailedMemoryRequestAnySeq::V8DetailedMemoryRequestAnySeq(
const base::TimeDelta& min_time_between_requests,
- MeasurementMode mode) {
- // |request_| must be initialized in the constructor body so that
- // |weak_factory_| is completely constructed.
- //
- // Can't use make_unique since this calls the private any-sequence
- // constructor. After construction the V8PerFrameMemoryRequest must only be
- // accessed on the graph sequence.
- request_ = base::WrapUnique(new V8PerFrameMemoryRequest(
- util::PassKey<V8PerFrameMemoryRequestAnySeq>(), min_time_between_requests,
- mode, weak_factory_.GetWeakPtr()));
+ MeasurementMode mode,
+ base::Optional<RenderProcessHostId> process_to_measure) {
+ base::Optional<base::WeakPtr<ProcessNode>> process_node;
+ if (process_to_measure) {
+ // GetProcessNodeForRenderProcessHostId must be called from the UI thread.
+ auto ui_task_runner = content::GetUIThreadTaskRunner({});
+ if (!ui_task_runner->RunsTasksInCurrentSequence()) {
+ ui_task_runner->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(
+ &PerformanceManager::GetProcessNodeForRenderProcessHostId,
+ process_to_measure.value()),
+ base::BindOnce(
+ &V8DetailedMemoryRequestAnySeq::InitializeWrappedRequest,
+ weak_factory_.GetWeakPtr(), min_time_between_requests, mode));
+ return;
+ }
+ process_node = PerformanceManager::GetProcessNodeForRenderProcessHostId(
+ process_to_measure.value());
+ }
+ InitializeWrappedRequest(min_time_between_requests, mode,
+ std::move(process_node));
}
-V8PerFrameMemoryRequestAnySeq::~V8PerFrameMemoryRequestAnySeq() {
+V8DetailedMemoryRequestAnySeq::~V8DetailedMemoryRequestAnySeq() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce(
- [](std::unique_ptr<V8PerFrameMemoryRequest> request) {
+ [](std::unique_ptr<V8DetailedMemoryRequest> request) {
request.reset();
},
std::move(request_)));
}
-bool V8PerFrameMemoryRequestAnySeq::HasObserver(
- V8PerFrameMemoryObserverAnySeq* observer) {
+bool V8DetailedMemoryRequestAnySeq::HasObserver(
+ V8DetailedMemoryObserverAnySeq* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return observers_.HasObserver(observer);
}
-void V8PerFrameMemoryRequestAnySeq::AddObserver(
- V8PerFrameMemoryObserverAnySeq* observer) {
+void V8DetailedMemoryRequestAnySeq::AddObserver(
+ V8DetailedMemoryObserverAnySeq* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observers_.AddObserver(observer);
}
-void V8PerFrameMemoryRequestAnySeq::RemoveObserver(
- V8PerFrameMemoryObserverAnySeq* observer) {
+void V8DetailedMemoryRequestAnySeq::RemoveObserver(
+ V8DetailedMemoryObserverAnySeq* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(observers_.HasObserver(observer));
observers_.RemoveObserver(observer);
}
-void V8PerFrameMemoryRequestAnySeq::NotifyObserversOnMeasurementAvailable(
- util::PassKey<V8PerFrameMemoryRequest>,
+void V8DetailedMemoryRequestAnySeq::NotifyObserversOnMeasurementAvailable(
+ util::PassKey<V8DetailedMemoryRequest>,
RenderProcessHostId render_process_host_id,
- const V8PerFrameMemoryProcessData& process_data,
- const V8PerFrameMemoryObserverAnySeq::FrameDataMap& frame_data) const {
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- for (V8PerFrameMemoryObserverAnySeq& observer : observers_)
+ for (V8DetailedMemoryObserverAnySeq& observer : observers_)
observer.OnV8MemoryMeasurementAvailable(render_process_host_id,
process_data, frame_data);
}
+void V8DetailedMemoryRequestAnySeq::InitializeWrappedRequest(
+ const base::TimeDelta& min_time_between_requests,
+ MeasurementMode mode,
+ base::Optional<base::WeakPtr<ProcessNode>> process_to_measure) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Can't use make_unique since this calls the private any-sequence
+ // constructor. After construction the V8DetailedMemoryRequest must only be
+ // accessed on the graph sequence.
+ request_ = base::WrapUnique(new V8DetailedMemoryRequest(
+ util::PassKey<V8DetailedMemoryRequestAnySeq>(), min_time_between_requests,
+ mode, std::move(process_to_measure), weak_factory_.GetWeakPtr()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// V8DetailedMemoryRequestOneShotAnySeq
+
+V8DetailedMemoryRequestOneShotAnySeq::V8DetailedMemoryRequestOneShotAnySeq(
+ MeasurementMode mode)
+ : mode_(mode) {}
+
+V8DetailedMemoryRequestOneShotAnySeq::V8DetailedMemoryRequestOneShotAnySeq(
+ RenderProcessHostId process_id,
+ MeasurementCallback callback,
+ MeasurementMode mode)
+ : mode_(mode) {
+ StartMeasurement(process_id, std::move(callback));
+}
+
+V8DetailedMemoryRequestOneShotAnySeq::~V8DetailedMemoryRequestOneShotAnySeq() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ PerformanceManager::CallOnGraph(
+ FROM_HERE,
+ base::BindOnce(
+ [](std::unique_ptr<V8DetailedMemoryRequestOneShot> request) {
+ request.reset();
+ },
+ std::move(request_)));
+}
+
+void V8DetailedMemoryRequestOneShotAnySeq::StartMeasurement(
+ RenderProcessHostId process_id,
+ MeasurementCallback callback) {
+ // GetProcessNodeForRenderProcessHostId must be called from the UI thread.
+ auto ui_task_runner = content::GetUIThreadTaskRunner({});
+ if (ui_task_runner->RunsTasksInCurrentSequence()) {
+ InitializeWrappedRequest(
+ std::move(callback), mode_,
+ PerformanceManager::GetProcessNodeForRenderProcessHostId(process_id));
+ } else {
+ ui_task_runner->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(
+ &PerformanceManager::GetProcessNodeForRenderProcessHostId,
+ process_id),
+ base::BindOnce(
+ &V8DetailedMemoryRequestOneShotAnySeq::InitializeWrappedRequest,
+ weak_factory_.GetWeakPtr(), std::move(callback), mode_));
+ }
+}
+
+void V8DetailedMemoryRequestOneShotAnySeq::InitializeWrappedRequest(
+ MeasurementCallback callback,
+ MeasurementMode mode,
+ base::WeakPtr<ProcessNode> process_node) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Pass ownership of |callback| to a wrapper, |wrapped_callback|, that will
+ // be owned by the wrapped request. The wrapper will be invoked and destroyed
+ // on the PM sequence. However, |callback| must be both called and destroyed
+ // on this sequence, so indirect all accesses to it through SequenceBound.
+ auto wrapped_callback = base::BindOnce(
+ &V8DetailedMemoryRequestOneShotAnySeq::OnMeasurementAvailable,
+ base::SequenceBound<MeasurementCallback>(
+ base::SequencedTaskRunnerHandle::Get(), std::move(callback)));
+
+ // Can't use make_unique since this calls the private any-sequence
+ // constructor. After construction the V8DetailedMemoryRequestOneShot must
+ // only be accessed on the graph sequence.
+ request_ = base::WrapUnique(new V8DetailedMemoryRequestOneShot(
+ util::PassKey<V8DetailedMemoryRequestOneShotAnySeq>(),
+ std::move(process_node), std::move(wrapped_callback), mode));
+}
+
+// static
+void V8DetailedMemoryRequestOneShotAnySeq::OnMeasurementAvailable(
+ base::SequenceBound<MeasurementCallback> sequence_bound_callback,
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) {
+ DCHECK(process_node);
+ DCHECK_ON_GRAPH_SEQUENCE(process_node->GetGraph());
+
+ using FrameAndData =
+ std::pair<content::GlobalFrameRoutingId, V8DetailedMemoryFrameData>;
+ std::vector<FrameAndData> all_frame_data;
+ process_node->VisitFrameNodes(base::BindRepeating(
+ [](std::vector<FrameAndData>* all_frame_data,
+ const FrameNode* frame_node) {
+ const auto* frame_data =
+ V8DetailedMemoryFrameData::ForFrameNode(frame_node);
+ if (frame_data) {
+ all_frame_data->push_back(std::make_pair(
+ frame_node->GetRenderFrameHostProxy().global_frame_routing_id(),
+ *frame_data));
+ }
+ return true;
+ },
+ base::Unretained(&all_frame_data)));
+
+ sequence_bound_callback.PostTaskWithThisObject(
+ FROM_HERE,
+ base::BindOnce(
+ [](RenderProcessHostId process_id,
+ const V8DetailedMemoryProcessData& process_data,
+ const FrameDataMap& frame_data, MeasurementCallback* callback) {
+ std::move(*callback).Run(process_id, process_data, frame_data);
+ },
+ process_node->GetRenderProcessHostId(), *process_data,
+ std::move(all_frame_data)));
+}
+
} // namespace v8_memory
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc b/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
index 459d4366570..199e278190f 100644
--- a/chromium/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc
+++ b/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
@@ -2,17 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h"
+#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
#include <memory>
#include <tuple>
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/time/time.h"
#include "components/performance_manager/graph/frame_node_impl.h"
@@ -22,245 +25,85 @@
#include "components/performance_manager/public/render_process_host_id.h"
#include "components/performance_manager/public/render_process_host_proxy.h"
#include "components/performance_manager/test_support/graph_test_harness.h"
-#include "components/performance_manager/test_support/performance_manager_test_harness.h"
+#include "components/performance_manager/v8_memory/v8_memory_test_helpers.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/tokens/tokens.h"
-#include "url/gurl.h"
namespace performance_manager {
namespace v8_memory {
using ::testing::_;
-using ::testing::Eq;
using ::testing::InSequence;
-using ::testing::Invoke;
using ::testing::Mock;
-using ::testing::Property;
using ::testing::StrictMock;
-using ::testing::WithArg;
-constexpr RenderProcessHostId kTestProcessID = RenderProcessHostId(0xFAB);
constexpr uint64_t kUnassociatedBytes = 0xABBA;
namespace {
-class LenientMockV8DetailedMemoryReporter
- : public blink::mojom::V8DetailedMemoryReporter {
- public:
- LenientMockV8DetailedMemoryReporter() : receiver_(this) {}
-
- MOCK_METHOD(void,
- GetV8MemoryUsage,
- (Mode mode, GetV8MemoryUsageCallback callback),
- (override));
-
- void Bind(mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
- pending_receiver) {
- return receiver_.Bind(std::move(pending_receiver));
- }
-
- private:
- mojo::Receiver<blink::mojom::V8DetailedMemoryReporter> receiver_;
-};
-
-using MockV8DetailedMemoryReporter =
- StrictMock<LenientMockV8DetailedMemoryReporter>;
-
-class LenientMockV8PerFrameMemoryObserver : public V8PerFrameMemoryObserver {
+class LenientMockV8DetailedMemoryObserver : public V8DetailedMemoryObserver {
public:
MOCK_METHOD(void,
OnV8MemoryMeasurementAvailable,
(const ProcessNode* process_node,
- const V8PerFrameMemoryProcessData* process_data),
+ const V8DetailedMemoryProcessData* process_data),
(override));
void ExpectObservationOnProcess(
const ProcessNode* process_node,
uint64_t expected_unassociated_v8_bytes_used) {
+ using ::testing::Eq;
+ using ::testing::Property;
EXPECT_CALL(
*this,
OnV8MemoryMeasurementAvailable(
process_node,
- Property(&V8PerFrameMemoryProcessData::unassociated_v8_bytes_used,
+ Property(&V8DetailedMemoryProcessData::unassociated_v8_bytes_used,
Eq(expected_unassociated_v8_bytes_used))));
}
};
-using MockV8PerFrameMemoryObserver =
- StrictMock<LenientMockV8PerFrameMemoryObserver>;
+using MockV8DetailedMemoryObserver =
+ StrictMock<LenientMockV8DetailedMemoryObserver>;
-class LenientMockV8PerFrameMemoryObserverAnySeq
- : public V8PerFrameMemoryObserverAnySeq {
+class LenientMockV8DetailedMemoryObserverAnySeq
+ : public V8DetailedMemoryObserverAnySeq {
public:
MOCK_METHOD(void,
OnV8MemoryMeasurementAvailable,
(RenderProcessHostId render_process_host_id,
- const V8PerFrameMemoryProcessData& process_data,
- const V8PerFrameMemoryObserverAnySeq::FrameDataMap& frame_data),
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryObserverAnySeq::FrameDataMap& frame_data),
(override));
};
-using MockV8PerFrameMemoryObserverAnySeq =
- StrictMock<LenientMockV8PerFrameMemoryObserverAnySeq>;
+using MockV8DetailedMemoryObserverAnySeq =
+ StrictMock<LenientMockV8DetailedMemoryObserverAnySeq>;
// The mode enum used in the API.
-using MeasurementMode = V8PerFrameMemoryRequest::MeasurementMode;
-
-// The mode enum used in test expectations.
-using ExpectedMode = MockV8DetailedMemoryReporter::Mode;
+using MeasurementMode = V8DetailedMemoryRequest::MeasurementMode;
-class V8PerFrameMemoryDecoratorTestBase {
+// An arbitrary object used to test object lifetimes with WeakPtr.
+class LifetimeTestObject : public base::SupportsWeakPtr<LifetimeTestObject> {
public:
- static constexpr base::TimeDelta kMinTimeBetweenRequests =
- base::TimeDelta::FromSeconds(30);
-
- V8PerFrameMemoryDecoratorTestBase() {
- internal::SetBindV8DetailedMemoryReporterCallbackForTesting(
- &bind_callback_);
- }
-
- virtual ~V8PerFrameMemoryDecoratorTestBase() {
- internal::SetBindV8DetailedMemoryReporterCallbackForTesting(nullptr);
- }
-
- // Adaptor that calls GetMainThreadTaskRunner for the test harness's task
- // environment.
- virtual scoped_refptr<base::SingleThreadTaskRunner>
- GetMainThreadTaskRunner() = 0;
-
- void ReplyWithData(
- blink::mojom::PerProcessV8MemoryUsagePtr data,
- MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback) {
- std::move(callback).Run(std::move(data));
- }
-
- void DelayedReplyWithData(
- const base::TimeDelta& delay,
- blink::mojom::PerProcessV8MemoryUsagePtr data,
- MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback) {
- GetMainThreadTaskRunner()->PostDelayedTask(
- FROM_HERE, base::BindOnce(std::move(callback), std::move(data)), delay);
- }
-
- void ExpectQuery(
- MockV8DetailedMemoryReporter* mock_reporter,
- base::RepeatingCallback<
- void(MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback)>
- responder,
- ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
- EXPECT_CALL(*mock_reporter, GetV8MemoryUsage(expected_mode, _))
- .WillOnce([this, responder](
- ExpectedMode mode,
- MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback
- callback) {
- this->last_query_time_ = base::TimeTicks::Now();
- responder.Run(std::move(callback));
- });
- }
-
- void ExpectQueryAndReply(MockV8DetailedMemoryReporter* mock_reporter,
- blink::mojom::PerProcessV8MemoryUsagePtr data,
- ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
- ExpectQuery(
- mock_reporter,
- base::BindRepeating(&V8PerFrameMemoryDecoratorTestBase::ReplyWithData,
- base::Unretained(this), base::Passed(&data)),
- expected_mode);
- }
-
- void ExpectQueryAndDelayReply(
- MockV8DetailedMemoryReporter* mock_reporter,
- const base::TimeDelta& delay,
- blink::mojom::PerProcessV8MemoryUsagePtr data,
- ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
- ExpectQuery(mock_reporter,
- base::BindRepeating(
- &V8PerFrameMemoryDecoratorTestBase::DelayedReplyWithData,
- base::Unretained(this), delay, base::Passed(&data)),
- expected_mode);
- }
-
- void ExpectBindAndRespondToQuery(
- MockV8DetailedMemoryReporter* mock_reporter,
- blink::mojom::PerProcessV8MemoryUsagePtr data,
- RenderProcessHostId expected_process_id = kTestProcessID,
- ExpectedMode expected_mode = ExpectedMode::DEFAULT) {
- InSequence seq;
- // Arg 0 is a
- // mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>. Pass it
- // to mock_reporter->Bind().
- //
- // Arg 1 is a RenderProcessHostProxy. Expect it to have the expected
- // process ID.
- EXPECT_CALL(*this,
- BindReceiverWithProxyHost(
- _, Property(&RenderProcessHostProxy::render_process_host_id,
- Eq(expected_process_id))))
- .WillOnce(WithArg<0>(
- Invoke(mock_reporter, &MockV8DetailedMemoryReporter::Bind)));
- ExpectQueryAndReply(mock_reporter, std::move(data), expected_mode);
- }
-
- MOCK_METHOD(void,
- BindReceiverWithProxyHost,
- (mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
- pending_receiver,
- RenderProcessHostProxy proxy),
- (const));
-
- // Always bind the receiver callback on the main sequence.
- internal::BindV8DetailedMemoryReporterCallback bind_callback_ =
- base::BindLambdaForTesting(
- [this](mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
- pending_receiver,
- RenderProcessHostProxy proxy) {
- this->GetMainThreadTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&V8PerFrameMemoryDecoratorTestBase::
- BindReceiverWithProxyHost,
- base::Unretained(this),
- std::move(pending_receiver), proxy));
- });
-
- base::TimeTicks last_query_time_;
+ LifetimeTestObject() = default;
+ ~LifetimeTestObject() = default;
};
-blink::mojom::PerProcessV8MemoryUsagePtr NewPerProcessV8MemoryUsage(
- size_t number_of_isolates) {
- auto data = blink::mojom::PerProcessV8MemoryUsage::New();
- for (size_t i = 0; i < number_of_isolates; ++i) {
- data->isolates.push_back(blink::mojom::PerIsolateV8MemoryUsage::New());
- }
- return data;
-}
-
-void AddPerFrameIsolateMemoryUsage(
- const blink::LocalFrameToken& frame_token,
- uint64_t bytes_used,
- blink::mojom::PerIsolateV8MemoryUsage* isolate) {
- for (auto& entry : isolate->contexts) {
- if (entry->token == blink::ExecutionContextToken(frame_token)) {
- entry->bytes_used = bytes_used;
- return;
- }
- }
-
- auto context = blink::mojom::PerContextV8MemoryUsage::New();
- context->token = blink::ExecutionContextToken(frame_token);
- context->bytes_used = bytes_used;
- isolate->contexts.push_back(std::move(context));
-}
+constexpr base::TimeDelta kMinTimeBetweenRequests =
+ base::TimeDelta::FromSeconds(30);
} // namespace
-class V8PerFrameMemoryDecoratorTest : public GraphTestHarness,
- public V8PerFrameMemoryDecoratorTestBase {
+class V8DetailedMemoryDecoratorTest : public GraphTestHarness,
+ public V8MemoryTestBase {
public:
scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner()
override {
@@ -269,20 +112,20 @@ class V8PerFrameMemoryDecoratorTest : public GraphTestHarness,
};
// kBounded mode and kEagerForTesting mode behave identically as far as
-// V8PerFrameMemoryDecorator is concerned. (The differences are all on the
+// V8DetailedMemoryDecorator is concerned. (The differences are all on the
// renderer side.) So mode tests hardcode kLazy mode and use a parameter to
// choose which of the two to use for bounded mode.
-class V8PerFrameMemoryDecoratorModeTest
- : public V8PerFrameMemoryDecoratorTest,
+class V8DetailedMemoryDecoratorModeTest
+ : public V8DetailedMemoryDecoratorTest,
public ::testing::WithParamInterface<
std::pair<MeasurementMode, ExpectedMode>> {
public:
- V8PerFrameMemoryDecoratorModeTest() {
+ V8DetailedMemoryDecoratorModeTest() {
internal::SetEagerMemoryMeasurementEnabledForTesting(true);
std::tie(bounded_mode_, expected_bounded_mode_) = GetParam();
}
- ~V8PerFrameMemoryDecoratorModeTest() override {
+ ~V8DetailedMemoryDecoratorModeTest() override {
internal::SetEagerMemoryMeasurementEnabledForTesting(false);
}
@@ -294,11 +137,11 @@ class V8PerFrameMemoryDecoratorModeTest
ExpectedMode expected_bounded_mode_;
};
-class V8PerFrameMemoryDecoratorSingleProcessModeTest
- : public V8PerFrameMemoryDecoratorTest,
+class V8DetailedMemoryDecoratorSingleProcessModeTest
+ : public V8DetailedMemoryDecoratorTest,
public ::testing::WithParamInterface<MeasurementMode> {
public:
- V8PerFrameMemoryDecoratorSingleProcessModeTest()
+ V8DetailedMemoryDecoratorSingleProcessModeTest()
: single_process_mode_(GetParam()) {}
protected:
@@ -306,23 +149,12 @@ class V8PerFrameMemoryDecoratorSingleProcessModeTest
MeasurementMode single_process_mode_;
};
-using V8PerFrameMemoryDecoratorDeathTest = V8PerFrameMemoryDecoratorTest;
-
-class V8PerFrameMemoryRequestAnySeqTest
- : public PerformanceManagerTestHarness,
- public V8PerFrameMemoryDecoratorTestBase {
- public:
- scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner()
- override {
- return task_environment()->GetMainThreadTaskRunner();
- }
-};
+using V8DetailedMemoryDecoratorDeathTest = V8DetailedMemoryDecoratorTest;
-constexpr base::TimeDelta
- V8PerFrameMemoryDecoratorTestBase::kMinTimeBetweenRequests;
+using V8DetailedMemoryRequestAnySeqTest = V8MemoryPerformanceManagerTestHarness;
-TEST_F(V8PerFrameMemoryDecoratorTest, InstantiateOnEmptyGraph) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnEmptyGraph) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
MockV8DetailedMemoryReporter mock_reporter;
auto data = NewPerProcessV8MemoryUsage(1);
@@ -335,18 +167,18 @@ TEST_F(V8PerFrameMemoryDecoratorTest, InstantiateOnEmptyGraph) {
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
// Data should not be available until the measurement is taken.
- EXPECT_FALSE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_FALSE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
// Run until idle to make sure the measurement isn't a hard loop.
task_env().RunUntilIdle();
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(kUnassociatedBytes,
- V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
-TEST_F(V8PerFrameMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
+TEST_F(V8DetailedMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
// Instantiate the decorator with an existing process node and validate that
// it gets a request.
auto process = CreateNode<ProcessNodeImpl>(
@@ -358,22 +190,22 @@ TEST_F(V8PerFrameMemoryDecoratorTest, InstantiateOnNonEmptyGraph) {
data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
// Data should not be available until the measurement is taken.
- EXPECT_FALSE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_FALSE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
// Run until idle to make sure the measurement isn't a hard loop.
task_env().RunUntilIdle();
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
EXPECT_EQ(kUnassociatedBytes,
- V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
-TEST_F(V8PerFrameMemoryDecoratorTest, OnlyMeasureRenderers) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, OnlyMeasureRenderers) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
for (int type = content::PROCESS_TYPE_BROWSER;
type < content::PROCESS_TYPE_CONTENT_END; ++type) {
@@ -392,7 +224,194 @@ TEST_F(V8PerFrameMemoryDecoratorTest, OnlyMeasureRenderers) {
}
}
-TEST_F(V8PerFrameMemoryDecoratorTest, QueryRateIsLimited) {
+TEST_F(V8DetailedMemoryDecoratorTest, OneShot) {
+ // Create 2 renderer processes. Create one request that measures both of
+ // them, and a one-shot request that measures only one.
+ constexpr RenderProcessHostId kProcessId1 = RenderProcessHostId(0xFAB);
+ auto process1 = CreateNode<ProcessNodeImpl>(
+ content::PROCESS_TYPE_RENDERER,
+ RenderProcessHostProxy::CreateForTesting(kProcessId1));
+ constexpr RenderProcessHostId kProcessId2 = RenderProcessHostId(0xBAF);
+ auto process2 = CreateNode<ProcessNodeImpl>(
+ content::PROCESS_TYPE_RENDERER,
+ RenderProcessHostProxy::CreateForTesting(kProcessId2));
+
+ // Set the all process request to only send once within the test.
+ V8DetailedMemoryRequest all_process_request(kMinTimeBetweenRequests * 100);
+ all_process_request.StartMeasurement(graph());
+
+ // Create a mock reporter for each process and expect a query and reply on
+ // each.
+ MockV8DetailedMemoryReporter mock_reporter1;
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data), kProcessId1);
+ }
+ MockV8DetailedMemoryReporter mock_reporter2;
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 2ULL;
+ ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data), kProcessId2);
+ }
+
+ task_env().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter1);
+ Mock::VerifyAndClearExpectations(&mock_reporter2);
+
+ // Create a one-shot request for process1 and expect the callback to be
+ // called only for that process.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 3ULL;
+ ExpectQueryAndReply(&mock_reporter1, std::move(data));
+ }
+
+ uint64_t unassociated_v8_bytes_used = 0;
+ V8DetailedMemoryRequestOneShot process1_request;
+ process1_request.StartMeasurement(
+ process1.get(), base::BindLambdaForTesting(
+ [&unassociated_v8_bytes_used, &process1](
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) {
+ ASSERT_TRUE(process_data);
+ EXPECT_EQ(process_node, process1.get());
+ unassociated_v8_bytes_used =
+ process_data->unassociated_v8_bytes_used();
+ }));
+ task_env().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter1);
+ Mock::VerifyAndClearExpectations(&mock_reporter2);
+ EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
+}
+
+TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetime) {
+ auto process = CreateNode<ProcessNodeImpl>(
+ content::PROCESS_TYPE_RENDERER,
+ RenderProcessHostProxy::CreateForTesting(kTestProcessID));
+
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ InSequence seq;
+ ExpectBindReceiver(&mock_reporter);
+
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+
+ // Create a one-shot request, but delete it before the result arrives.
+ auto doomed_request = std::make_unique<V8DetailedMemoryRequestOneShot>(
+ process.get(),
+ base::BindOnce([](const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) {
+ FAIL() << "Callback called after request deleted.";
+ }));
+
+ // Verify that the request is sent but the reply is not yet received.
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+
+ doomed_request.reset();
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+
+ // Create a request that is deleted from within its own callback and make
+ // sure nothing explodes.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 2ULL;
+ ExpectQueryAndReply(&mock_reporter, std::move(data));
+ }
+ uint64_t unassociated_v8_bytes_used = 0;
+ doomed_request = std::make_unique<V8DetailedMemoryRequestOneShot>(
+ process.get(), base::BindLambdaForTesting(
+ [&](const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData* process_data) {
+ doomed_request.reset();
+ ASSERT_TRUE(process_data);
+ unassociated_v8_bytes_used =
+ process_data->unassociated_v8_bytes_used();
+ }));
+ task_env().RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
+
+ // Ensure that resource-owning callbacks are freed when there is no response
+ // because the process dies.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 3ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+ auto lifetime_test = std::make_unique<LifetimeTestObject>();
+ auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+ V8DetailedMemoryRequestOneShot unfinished_request(
+ process.get(),
+ base::BindOnce(
+ [](std::unique_ptr<LifetimeTestObject>, const ProcessNode*,
+ const V8DetailedMemoryProcessData*) {
+ FAIL() << "Callback called after process deleted.";
+ },
+ // Pass ownership to the callback. The object should be deleted if the
+ // callback is not called.
+ std::move(lifetime_test)));
+
+ // Verify that requests are sent but reply is not yet received.
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ ASSERT_TRUE(weak_lifetime_test);
+
+ process.reset();
+
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(weak_lifetime_test);
+}
+
+TEST_F(V8DetailedMemoryDecoratorTest, OneShotLifetimeAtExit) {
+ auto process = CreateNode<ProcessNodeImpl>(
+ content::PROCESS_TYPE_RENDERER,
+ RenderProcessHostProxy::CreateForTesting(kTestProcessID));
+
+ // Ensure that resource-owning callbacks are freed when there is no response
+ // because the browser is exiting (simulated by destroying the decorator).
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ InSequence seq;
+ ExpectBindReceiver(&mock_reporter);
+
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+
+ auto lifetime_test = std::make_unique<LifetimeTestObject>();
+ auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+ V8DetailedMemoryRequestOneShot unfinished_request(
+ process.get(),
+ base::BindOnce(
+ [](std::unique_ptr<LifetimeTestObject>, const ProcessNode*,
+ const V8DetailedMemoryProcessData*) {
+ FAIL() << "Callback called after measurements cancelled.";
+ },
+ // Pass ownership to the callback. The object should be deleted if the
+ // callback is not called.
+ std::move(lifetime_test)));
+
+ // Verify that requests are sent but reply is not yet received.
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ ASSERT_TRUE(weak_lifetime_test);
+
+ internal::DestroyV8DetailedMemoryDecoratorForTesting(graph());
+
+ task_env().FastForwardBy(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(weak_lifetime_test);
+}
+
+TEST_F(V8DetailedMemoryDecoratorTest, QueryRateIsLimited) {
auto process = CreateNode<ProcessNodeImpl>(
content::PROCESS_TYPE_RENDERER,
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
@@ -405,13 +424,13 @@ TEST_F(V8PerFrameMemoryDecoratorTest, QueryRateIsLimited) {
ExpectBindAndRespondToQuery(&mock_reporter, std::move(data));
}
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
// Run until idle to make sure the measurement isn't a hard loop.
task_env().RunUntilIdle();
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(1u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// There shouldn't be an additional request this soon.
@@ -437,8 +456,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, QueryRateIsLimited) {
task_env().FastForwardBy(10 * kMinTimeBetweenRequests);
Mock::VerifyAndClearExpectations(&mock_reporter);
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(1u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// Expect another query once completing the query above.
@@ -460,8 +479,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, QueryRateIsLimited) {
task_env().RunUntilIdle();
// This should have updated all the way to the third response.
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(3u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(3u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// Despite the long delay to respond to request 2, there shouldn't be another
@@ -470,8 +489,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, QueryRateIsLimited) {
Mock::VerifyAndClearExpectations(&mock_reporter);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
// Create a process node and validate that it gets a request.
MockV8DetailedMemoryReporter reporter1;
@@ -503,11 +522,11 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
task_env().RunUntilIdle();
Mock::VerifyAndClearExpectations(&reporter2);
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process1.get()));
- EXPECT_EQ(1u, V8PerFrameMemoryProcessData::ForProcessNode(process1.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
+ EXPECT_EQ(1u, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process2.get()));
- EXPECT_EQ(2u, V8PerFrameMemoryProcessData::ForProcessNode(process2.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process2.get()));
+ EXPECT_EQ(2u, V8DetailedMemoryProcessData::ForProcessNode(process2.get())
->unassociated_v8_bytes_used());
// Capture the request time from each process.
@@ -536,8 +555,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MultipleProcessesHaveDistinctSchedules) {
EXPECT_GT(process2_request_time, process1_request_time);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, MultipleIsolatesInRenderer) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, MultipleIsolatesInRenderer) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
MockV8DetailedMemoryReporter reporter;
@@ -557,33 +576,33 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MultipleIsolatesInRenderer) {
4, frame2_id);
{
auto data = NewPerProcessV8MemoryUsage(2);
- AddPerFrameIsolateMemoryUsage(frame1_id, 1001u, data->isolates[0].get());
- AddPerFrameIsolateMemoryUsage(frame2_id, 1002u, data->isolates[1].get());
+ AddIsolateMemoryUsage(frame1_id, 1001u, data->isolates[0].get());
+ AddIsolateMemoryUsage(frame2_id, 1002u, data->isolates[1].get());
ExpectBindAndRespondToQuery(&reporter, std::move(data));
}
task_env().RunUntilIdle();
Mock::VerifyAndClearExpectations(&reporter);
- ASSERT_TRUE(V8PerFrameMemoryFrameData::ForFrameNode(frame1.get()));
+ ASSERT_TRUE(V8DetailedMemoryFrameData::ForFrameNode(frame1.get()));
EXPECT_EQ(
1001u,
- V8PerFrameMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
- ASSERT_TRUE(V8PerFrameMemoryFrameData::ForFrameNode(frame2.get()));
+ V8DetailedMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
+ ASSERT_TRUE(V8DetailedMemoryFrameData::ForFrameNode(frame2.get()));
EXPECT_EQ(
1002u,
- V8PerFrameMemoryFrameData::ForFrameNode(frame2.get())->v8_bytes_used());
+ V8DetailedMemoryFrameData::ForFrameNode(frame2.get())->v8_bytes_used());
}
-TEST_F(V8PerFrameMemoryDecoratorTest, PerFrameDataIsDistributed) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, DataIsDistributed) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
MockV8DetailedMemoryReporter reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
// Add data for an unknown frame.
- AddPerFrameIsolateMemoryUsage(blink::LocalFrameToken(), 1024u,
- data->isolates[0].get());
+ AddIsolateMemoryUsage(blink::LocalFrameToken(), 1024u,
+ data->isolates[0].get());
ExpectBindAndRespondToQuery(&reporter, std::move(data));
}
@@ -596,8 +615,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, PerFrameDataIsDistributed) {
Mock::VerifyAndClearExpectations(&reporter);
// Since the frame was unknown, the usage should have accrued to unassociated.
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(1024u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(1024u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// Create a couple of frames with specified IDs.
@@ -612,49 +631,49 @@ TEST_F(V8PerFrameMemoryDecoratorTest, PerFrameDataIsDistributed) {
4, frame2_id);
{
auto data = NewPerProcessV8MemoryUsage(1);
- AddPerFrameIsolateMemoryUsage(frame1_id, 1001u, data->isolates[0].get());
- AddPerFrameIsolateMemoryUsage(frame2_id, 1002u, data->isolates[0].get());
+ AddIsolateMemoryUsage(frame1_id, 1001u, data->isolates[0].get());
+ AddIsolateMemoryUsage(frame2_id, 1002u, data->isolates[0].get());
ExpectQueryAndReply(&reporter, std::move(data));
}
task_env().FastForwardBy(kMinTimeBetweenRequests * 1.5);
Mock::VerifyAndClearExpectations(&reporter);
- ASSERT_TRUE(V8PerFrameMemoryFrameData::ForFrameNode(frame1.get()));
+ ASSERT_TRUE(V8DetailedMemoryFrameData::ForFrameNode(frame1.get()));
EXPECT_EQ(
1001u,
- V8PerFrameMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
- ASSERT_TRUE(V8PerFrameMemoryFrameData::ForFrameNode(frame2.get()));
+ V8DetailedMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
+ ASSERT_TRUE(V8DetailedMemoryFrameData::ForFrameNode(frame2.get()));
EXPECT_EQ(
1002u,
- V8PerFrameMemoryFrameData::ForFrameNode(frame2.get())->v8_bytes_used());
+ V8DetailedMemoryFrameData::ForFrameNode(frame2.get())->v8_bytes_used());
// Now verify that data is cleared for any frame that doesn't get an update,
// plus verify that unknown frame data toes to unassociated bytes.
{
auto data = NewPerProcessV8MemoryUsage(1);
- AddPerFrameIsolateMemoryUsage(frame1_id, 1003u, data->isolates[0].get());
- AddPerFrameIsolateMemoryUsage(blink::LocalFrameToken(), 2233u,
- data->isolates[0].get());
+ AddIsolateMemoryUsage(frame1_id, 1003u, data->isolates[0].get());
+ AddIsolateMemoryUsage(blink::LocalFrameToken(), 2233u,
+ data->isolates[0].get());
ExpectQueryAndReply(&reporter, std::move(data));
}
task_env().FastForwardBy(kMinTimeBetweenRequests);
Mock::VerifyAndClearExpectations(&reporter);
- ASSERT_TRUE(V8PerFrameMemoryFrameData::ForFrameNode(frame1.get()));
+ ASSERT_TRUE(V8DetailedMemoryFrameData::ForFrameNode(frame1.get()));
EXPECT_EQ(
1003u,
- V8PerFrameMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
- EXPECT_FALSE(V8PerFrameMemoryFrameData::ForFrameNode(frame2.get()));
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(2233u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ V8DetailedMemoryFrameData::ForFrameNode(frame1.get())->v8_bytes_used());
+ EXPECT_FALSE(V8DetailedMemoryFrameData::ForFrameNode(frame2.get()));
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(2233u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
-TEST_P(V8PerFrameMemoryDecoratorModeTest, LazyRequests) {
+TEST_P(V8DetailedMemoryDecoratorModeTest, LazyRequests) {
constexpr base::TimeDelta kLazyRequestLength =
base::TimeDelta::FromSeconds(30);
- V8PerFrameMemoryRequest lazy_request(kLazyRequestLength,
+ V8DetailedMemoryRequest lazy_request(kLazyRequestLength,
MeasurementMode::kLazy, graph());
MockV8DetailedMemoryReporter reporter;
@@ -675,9 +694,9 @@ TEST_P(V8PerFrameMemoryDecoratorModeTest, LazyRequests) {
// bounded request if one is in the queue.
constexpr base::TimeDelta kLongBoundedRequestLength =
base::TimeDelta::FromSeconds(45);
- V8PerFrameMemoryRequest long_bounded_request(kLongBoundedRequestLength,
+ V8DetailedMemoryRequest long_bounded_request(kLongBoundedRequestLength,
bounded_mode_, graph());
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(decorator->GetNextRequest()->min_time_between_requests(),
@@ -700,7 +719,7 @@ TEST_P(V8PerFrameMemoryDecoratorModeTest, LazyRequests) {
constexpr base::TimeDelta kUpgradeRequestLength =
base::TimeDelta::FromSeconds(40);
- V8PerFrameMemoryRequest bounded_request_upgrade(kUpgradeRequestLength,
+ V8DetailedMemoryRequest bounded_request_upgrade(kUpgradeRequestLength,
bounded_mode_, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(decorator->GetNextRequest()->min_time_between_requests(),
@@ -726,13 +745,13 @@ TEST_P(V8PerFrameMemoryDecoratorModeTest, LazyRequests) {
task_env().FastForwardBy(kUpgradeRequestLength);
Mock::VerifyAndClearExpectations(&reporter);
- EXPECT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(3u, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(3u, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// Bounded requests should be preferred over lazy requests with the same
// min_time_between_requests.
- V8PerFrameMemoryRequest short_bounded_request(kLazyRequestLength,
+ V8DetailedMemoryRequest short_bounded_request(kLazyRequestLength,
bounded_mode_, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(decorator->GetNextRequest()->min_time_between_requests(),
@@ -742,13 +761,13 @@ TEST_P(V8PerFrameMemoryDecoratorModeTest, LazyRequests) {
INSTANTIATE_TEST_SUITE_P(
AllBoundedModes,
- V8PerFrameMemoryDecoratorModeTest,
+ V8DetailedMemoryDecoratorModeTest,
::testing::Values(std::make_pair(MeasurementMode::kBounded,
ExpectedMode::DEFAULT),
std::make_pair(MeasurementMode::kEagerForTesting,
ExpectedMode::EAGER)));
-TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
+TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsSorted) {
// Create some queries with different sample frequencies.
constexpr base::TimeDelta kShortInterval(kMinTimeBetweenRequests);
constexpr base::TimeDelta kMediumInterval(2 * kMinTimeBetweenRequests);
@@ -756,15 +775,15 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Create longer requests first to be sure they sort correctly.
auto medium_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kMediumInterval, graph());
auto short_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kShortInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kShortInterval, graph());
auto long_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kLongInterval, graph());
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
// A single measurement should be taken immediately regardless of the overall
@@ -779,14 +798,14 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
auto process = CreateNode<ProcessNodeImpl>(
content::PROCESS_TYPE_RENDERER,
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
- EXPECT_FALSE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_FALSE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
// All the following FastForwardBy calls will place the clock 1 sec after a
// measurement is expected.
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
// Another measurement should be taken after the shortest interval.
@@ -799,7 +818,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kShortInterval);
- EXPECT_EQ(2U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -815,10 +834,10 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kShortInterval);
- EXPECT_EQ(2U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
task_env().FastForwardBy(kShortInterval);
- EXPECT_EQ(3U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -834,7 +853,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -847,20 +866,20 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
// Create another request. Since this is the first request in an empty queue
// the measurement should be taken immediately.
long_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kLongInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(5U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
{
@@ -869,7 +888,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
- EXPECT_EQ(6U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(6U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -877,7 +896,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
// Make sure a shorter request replaces this (the new interval should cause a
// measurement and the old interval should not).
medium_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kMediumInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
@@ -888,7 +907,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
- EXPECT_EQ(7U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(7U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -900,11 +919,11 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
constexpr base::TimeDelta kRestOfLongInterval =
kLongInterval - kMediumInterval;
task_env().FastForwardBy(kRestOfLongInterval);
- EXPECT_EQ(7U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(7U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
task_env().FastForwardBy(kMediumInterval - kRestOfLongInterval);
- EXPECT_EQ(8U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(8U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -915,7 +934,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
EXPECT_EQ(kLongInterval,
decorator->GetNextRequest()->min_time_between_requests());
medium_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kMediumInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
@@ -926,14 +945,14 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
- EXPECT_EQ(9U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(9U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
// Add another long request. There should still be requests after the medium
// interval.
auto long_memory_request2 =
- std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kLongInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
@@ -944,7 +963,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kMediumInterval);
- EXPECT_EQ(10U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(10U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -961,7 +980,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
- EXPECT_EQ(11U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(11U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
@@ -977,12 +996,12 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsSorted) {
ExpectQueryAndReply(&mock_reporter, std::move(data));
task_env().FastForwardBy(kLongInterval);
- EXPECT_EQ(12U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(12U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
}
-TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
+TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestsWithDelay) {
// Create some queries with different sample frequencies.
constexpr base::TimeDelta kShortInterval(kMinTimeBetweenRequests);
constexpr base::TimeDelta kMediumInterval(2 * kMinTimeBetweenRequests);
@@ -993,9 +1012,9 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
constexpr base::TimeDelta kOneSecond = base::TimeDelta::FromSeconds(1);
auto long_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kLongInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kLongInterval, graph());
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
// Move past the first request since it's complicated to untangle the Bind
@@ -1023,23 +1042,23 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
std::move(data));
}
task_env().FastForwardBy(kLongInterval);
- EXPECT_EQ(last_query_time_, task_env().NowTicks() - kOneSecond)
+ EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
- EXPECT_EQ(0U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(0U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement ended early";
- base::TimeTicks measurement_start_time = last_query_time_;
+ base::TimeTicks measurement_start_time = last_query_time();
auto medium_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMediumInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kMediumInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength);
- ASSERT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ ASSERT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement didn't end when expected";
- EXPECT_EQ(last_query_time_, measurement_start_time);
+ EXPECT_EQ(last_query_time(), measurement_start_time);
// Next measurement should start kMediumInterval secs after the START of the
// last measurement.
@@ -1050,18 +1069,18 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
std::move(data));
}
task_env().FastForwardBy(kMediumInterval - kMeasurementLength);
- EXPECT_EQ(last_query_time_, task_env().NowTicks() - kOneSecond)
+ EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
- EXPECT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement ended early";
- measurement_start_time = last_query_time_;
+ measurement_start_time = last_query_time();
task_env().FastForwardBy(kMeasurementLength);
- EXPECT_EQ(2U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement didn't end when expected";
- EXPECT_EQ(last_query_time_, measurement_start_time);
+ EXPECT_EQ(last_query_time(), measurement_start_time);
// Create a request that would be sent in the middle of a measurement. It
// should start immediately after the measurement finishes.
@@ -1072,19 +1091,19 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
std::move(data));
}
task_env().FastForwardBy(kMediumInterval - kMeasurementLength);
- EXPECT_EQ(last_query_time_, task_env().NowTicks() - kOneSecond)
+ EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
- EXPECT_EQ(2U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement ended early";
- measurement_start_time = last_query_time_;
+ measurement_start_time = last_query_time();
auto short_memory_request =
- std::make_unique<V8PerFrameMemoryRequest>(kShortInterval, graph());
+ std::make_unique<V8DetailedMemoryRequest>(kShortInterval, graph());
ASSERT_TRUE(decorator->GetNextRequest());
EXPECT_EQ(kShortInterval,
decorator->GetNextRequest()->min_time_between_requests());
- EXPECT_EQ(last_query_time_, measurement_start_time);
+ EXPECT_EQ(last_query_time(), measurement_start_time);
{
auto data = NewPerProcessV8MemoryUsage(1);
@@ -1093,12 +1112,12 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
std::move(data));
}
task_env().FastForwardBy(kMeasurementLength);
- EXPECT_EQ(last_query_time_, task_env().NowTicks() - kOneSecond)
+ EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
- EXPECT_EQ(3U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement ended early";
- measurement_start_time = last_query_time_;
+ measurement_start_time = last_query_time();
// Delete the short request. Should update min_time_between_requests but not
// start a new measurement until the existing measurement finishes.
@@ -1107,10 +1126,10 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
EXPECT_EQ(kMediumInterval,
decorator->GetNextRequest()->min_time_between_requests());
task_env().FastForwardBy(kMeasurementLength);
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement didn't end when expected";
- EXPECT_EQ(last_query_time_, measurement_start_time);
+ EXPECT_EQ(last_query_time(), measurement_start_time);
// Delete the last request while a measurement is in process. The
// measurement should finish successfully but no more should be sent.
@@ -1121,31 +1140,31 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestsWithDelay) {
std::move(data));
}
task_env().FastForwardBy(kMediumInterval - kMeasurementLength);
- EXPECT_EQ(last_query_time_, task_env().NowTicks() - kOneSecond)
+ EXPECT_EQ(last_query_time(), task_env().NowTicks() - kOneSecond)
<< "Measurement didn't start when expected";
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement ended early";
- measurement_start_time = last_query_time_;
+ measurement_start_time = last_query_time();
medium_memory_request.reset();
long_memory_request.reset();
EXPECT_FALSE(decorator->GetNextRequest());
task_env().FastForwardBy(kMeasurementLength);
- EXPECT_EQ(5U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ EXPECT_EQ(5U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "Measurement didn't end when expected";
- EXPECT_EQ(last_query_time_, measurement_start_time);
+ EXPECT_EQ(last_query_time(), measurement_start_time);
// No more requests should be sent.
Mock::VerifyAndClearExpectations(this);
task_env().FastForwardBy(kLongInterval);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
MockV8DetailedMemoryReporter mock_reporter;
@@ -1158,7 +1177,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
content::PROCESS_TYPE_RENDERER,
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
task_env().FastForwardBy(base::TimeDelta::FromSeconds(1));
- ASSERT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ ASSERT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used())
<< "First measurement didn't happen when expected";
@@ -1169,11 +1188,11 @@ TEST_F(V8PerFrameMemoryDecoratorTest, MeasurementRequestOutlivesDecorator) {
task_env().FastForwardBy(kMinTimeBetweenRequests);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, NotifyObservers) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, NotifyObservers) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
- MockV8PerFrameMemoryObserver observer1;
- MockV8PerFrameMemoryObserver observer2;
+ MockV8DetailedMemoryObserver observer1;
+ MockV8DetailedMemoryObserver observer2;
memory_request.AddObserver(&observer1);
memory_request.AddObserver(&observer2);
@@ -1257,10 +1276,10 @@ TEST_F(V8PerFrameMemoryDecoratorTest, NotifyObservers) {
memory_request.RemoveObserver(&observer2);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, ObserverOutlivesDecorator) {
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
+TEST_F(V8DetailedMemoryDecoratorTest, ObserverOutlivesDecorator) {
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests, graph());
- MockV8PerFrameMemoryObserver observer;
+ MockV8DetailedMemoryObserver observer;
memory_request.AddObserver(&observer);
// Create a process node and move past the initial request to it.
@@ -1292,7 +1311,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, ObserverOutlivesDecorator) {
// Destroy the decorator before the measurement completes. The observer
// should not be notified.
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph());
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph());
ASSERT_TRUE(decorator);
graph()->TakeFromGraph(decorator);
@@ -1303,7 +1322,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, ObserverOutlivesDecorator) {
memory_request.RemoveObserver(&observer);
}
-TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
+TEST_F(V8DetailedMemoryDecoratorTest, SingleProcessRequest) {
// Create 2 renderer processes. Create one request that measures both of
// them, and one request that measures only one.
constexpr RenderProcessHostId kProcessId1 = RenderProcessHostId(0xFAB);
@@ -1316,11 +1335,11 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
RenderProcessHostProxy::CreateForTesting(kProcessId2));
// Set the all process request to only send once within the test.
- V8PerFrameMemoryRequest all_process_request(kMinTimeBetweenRequests * 100);
+ V8DetailedMemoryRequest all_process_request(kMinTimeBetweenRequests * 100);
all_process_request.StartMeasurement(graph());
auto process1_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMinTimeBetweenRequests);
+ std::make_unique<V8DetailedMemoryRequest>(kMinTimeBetweenRequests);
process1_request->StartMeasurementForProcess(process1.get());
MockV8DetailedMemoryReporter mock_reporter1;
@@ -1343,12 +1362,12 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
testing::Mock::VerifyAndClearExpectations(&mock_reporter1);
testing::Mock::VerifyAndClearExpectations(&mock_reporter2);
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process1.get()));
- EXPECT_EQ(1U, V8PerFrameMemoryProcessData::ForProcessNode(process1.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
+ EXPECT_EQ(1U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process2.get()));
- EXPECT_EQ(2U, V8PerFrameMemoryProcessData::ForProcessNode(process2.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process2.get()));
+ EXPECT_EQ(2U, V8DetailedMemoryProcessData::ForProcessNode(process2.get())
->unassociated_v8_bytes_used());
// After kMinTimeBetweenRequests another request should be sent to process1,
@@ -1370,8 +1389,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
testing::Mock::VerifyAndClearExpectations(&mock_reporter1);
testing::Mock::VerifyAndClearExpectations(&mock_reporter2);
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process1.get()));
- EXPECT_EQ(3U, V8PerFrameMemoryProcessData::ForProcessNode(process1.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
+ EXPECT_EQ(3U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
// Recreate process1 request. The new request will be sent immediately since
@@ -1383,11 +1402,11 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
}
process1_request =
- std::make_unique<V8PerFrameMemoryRequest>(kMinTimeBetweenRequests);
+ std::make_unique<V8DetailedMemoryRequest>(kMinTimeBetweenRequests);
process1_request->StartMeasurementForProcess(process1.get());
// Test observers of single-process requests.
- MockV8PerFrameMemoryObserver mock_observer;
+ MockV8DetailedMemoryObserver mock_observer;
process1_request->AddObserver(&mock_observer);
mock_observer.ExpectObservationOnProcess(process1.get(), 4U);
@@ -1396,8 +1415,8 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
testing::Mock::VerifyAndClearExpectations(&mock_reporter2);
testing::Mock::VerifyAndClearExpectations(&mock_observer);
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process1.get()));
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process1.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process1.get()));
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process1.get())
->unassociated_v8_bytes_used());
// Delete process1 while the request still exists. Nothing should crash.
@@ -1411,7 +1430,7 @@ TEST_F(V8PerFrameMemoryDecoratorTest, SingleProcessRequest) {
process1_request->RemoveObserver(&mock_observer);
}
-TEST_P(V8PerFrameMemoryDecoratorSingleProcessModeTest,
+TEST_P(V8DetailedMemoryDecoratorSingleProcessModeTest,
SingleProcessLazyRequest) {
// Create a single process node so both "all process" and "single process"
// requests will have a single expectation, which reduces boilerplate.
@@ -1419,9 +1438,9 @@ TEST_P(V8PerFrameMemoryDecoratorSingleProcessModeTest,
content::PROCESS_TYPE_RENDERER,
RenderProcessHostProxy::CreateForTesting(kTestProcessID));
- V8PerFrameMemoryRequest lazy_request(kMinTimeBetweenRequests,
+ V8DetailedMemoryRequest lazy_request(kMinTimeBetweenRequests,
MeasurementMode::kLazy);
- V8PerFrameMemoryRequest bounded_request(kMinTimeBetweenRequests * 2,
+ V8DetailedMemoryRequest bounded_request(kMinTimeBetweenRequests * 2,
MeasurementMode::kBounded);
if (single_process_mode_ == MeasurementMode::kLazy) {
// Test that lazy single-process requests can't starve bounded all-process
@@ -1474,146 +1493,127 @@ TEST_P(V8PerFrameMemoryDecoratorSingleProcessModeTest,
task_env().FastForwardBy(kMinTimeBetweenRequests);
testing::Mock::VerifyAndClearExpectations(&mock_reporter);
- ASSERT_TRUE(V8PerFrameMemoryProcessData::ForProcessNode(process.get()));
- EXPECT_EQ(4U, V8PerFrameMemoryProcessData::ForProcessNode(process.get())
+ ASSERT_TRUE(V8DetailedMemoryProcessData::ForProcessNode(process.get()));
+ EXPECT_EQ(4U, V8DetailedMemoryProcessData::ForProcessNode(process.get())
->unassociated_v8_bytes_used());
}
INSTANTIATE_TEST_SUITE_P(SingleProcessLazyOrBounded,
- V8PerFrameMemoryDecoratorSingleProcessModeTest,
+ V8DetailedMemoryDecoratorSingleProcessModeTest,
::testing::Values(MeasurementMode::kLazy,
MeasurementMode::kBounded));
-TEST_F(V8PerFrameMemoryDecoratorDeathTest, MultipleStartMeasurement) {
+TEST_F(V8DetailedMemoryDecoratorDeathTest, MultipleStartMeasurement) {
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequest request(kMinTimeBetweenRequests);
+ V8DetailedMemoryRequest request(kMinTimeBetweenRequests);
request.StartMeasurement(graph());
request.StartMeasurement(graph());
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequest request(kMinTimeBetweenRequests, graph());
+ V8DetailedMemoryRequest request(kMinTimeBetweenRequests, graph());
request.StartMeasurement(graph());
});
}
-TEST_F(V8PerFrameMemoryDecoratorDeathTest, EnforceObserversRemoved) {
+TEST_F(V8DetailedMemoryDecoratorDeathTest, EnforceObserversRemoved) {
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests);
- MockV8PerFrameMemoryObserver observer;
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests);
+ MockV8DetailedMemoryObserver observer;
memory_request.AddObserver(&observer);
// Request should explode if it still has observers registered when it goes
// out of scope.
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests);
- MockV8PerFrameMemoryObserverAnySeq observer;
+ V8DetailedMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests);
+ MockV8DetailedMemoryObserverAnySeq observer;
memory_request.AddObserver(&observer);
// Request should explode if it still has observers registered when it goes
// out of scope.
});
}
-TEST_F(V8PerFrameMemoryDecoratorDeathTest, InvalidParameters) {
+TEST_F(V8DetailedMemoryDecoratorDeathTest, InvalidParameters) {
// Not allowed to use kEagerForTesting mode without calling
// SetEagerMemoryMeasurementEnabledForTesting.
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequest memory_request(kMinTimeBetweenRequests,
+ V8DetailedMemoryRequest memory_request(kMinTimeBetweenRequests,
MeasurementMode::kEagerForTesting);
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequestAnySeq memory_request(
+ V8DetailedMemoryRequestAnySeq memory_request(
kMinTimeBetweenRequests, MeasurementMode::kEagerForTesting);
});
// Zero, negative and infinite TimeDelta's are disallowed.
EXPECT_DCHECK_DEATH({
base::TimeDelta zero;
- V8PerFrameMemoryRequestAnySeq memory_request(zero);
+ V8DetailedMemoryRequestAnySeq memory_request(zero);
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequestAnySeq memory_request(base::TimeDelta::Min());
+ V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Min());
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequestAnySeq memory_request(base::TimeDelta::Max());
+ V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Max());
});
EXPECT_DCHECK_DEATH({
- V8PerFrameMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests * -1);
+ V8DetailedMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests * -1);
});
}
-TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
- // Precondition: CallOnGraph must run on a different sequence. Note that all
- // tasks passed to CallOnGraph will only run when run_loop.Run() is called
- // below.
- ASSERT_TRUE(GetMainThreadTaskRunner()->RunsTasksInCurrentSequence());
- PerformanceManager::CallOnGraph(
- FROM_HERE, base::BindLambdaForTesting([this] {
- EXPECT_FALSE(
- this->GetMainThreadTaskRunner()->RunsTasksInCurrentSequence());
- }));
-
- // Set the active contents and simulate a navigation, which adds nodes to the
- // graph.
- SetContents(CreateTestWebContents());
- content::NavigationSimulator::NavigateAndCommitFromBrowser(
- web_contents(), GURL("https://www.foo.com/"));
-
+TEST_F(V8DetailedMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
// Create some test data to return for a measurement request.
constexpr uint64_t kAssociatedBytes = 0x123;
- content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
- ASSERT_NE(nullptr, main_frame);
- const RenderProcessHostId process_id(main_frame->GetProcess()->GetID());
- const blink::LocalFrameToken frame_token(main_frame->GetFrameToken());
- const content::GlobalFrameRoutingId frame_id(process_id.value(),
- main_frame->GetRoutingID());
-
- V8PerFrameMemoryProcessData expected_process_data;
+ const blink::LocalFrameToken frame_token(main_frame()->GetFrameToken());
+ const content::GlobalFrameRoutingId frame_id(main_process_id().value(),
+ main_frame()->GetRoutingID());
+
+ V8DetailedMemoryProcessData expected_process_data;
expected_process_data.set_unassociated_v8_bytes_used(kUnassociatedBytes);
- V8PerFrameMemoryObserverAnySeq::FrameDataMap expected_frame_data;
+ V8DetailedMemoryObserverAnySeq::FrameDataMap expected_frame_data;
expected_frame_data[frame_id].set_v8_bytes_used(kAssociatedBytes);
MockV8DetailedMemoryReporter reporter;
{
auto data = NewPerProcessV8MemoryUsage(1);
data->isolates[0]->unassociated_bytes_used = kUnassociatedBytes;
- AddPerFrameIsolateMemoryUsage(frame_token, kAssociatedBytes,
- data->isolates[0].get());
- ExpectBindAndRespondToQuery(&reporter, std::move(data), process_id);
+ AddIsolateMemoryUsage(frame_token, kAssociatedBytes,
+ data->isolates[0].get());
+ ExpectBindAndRespondToQuery(&reporter, std::move(data), main_process_id());
}
// Decorator should not exist before creating a request.
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) {
- EXPECT_FALSE(V8PerFrameMemoryDecorator::GetFromGraph(graph));
+ EXPECT_FALSE(V8DetailedMemoryDecorator::GetFromGraph(graph));
}));
// This object is created on the main sequence but should cause a
- // V8PerFrameMemoryRequest to be created on the graph sequence after the
+ // V8DetailedMemoryRequest to be created on the graph sequence after the
// above task.
- auto request = std::make_unique<V8PerFrameMemoryRequestAnySeq>(
- V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests);
- MockV8PerFrameMemoryObserverAnySeq observer;
+ auto request =
+ std::make_unique<V8DetailedMemoryRequestAnySeq>(kMinTimeBetweenRequests);
+ MockV8DetailedMemoryObserverAnySeq observer;
request->AddObserver(&observer);
// Decorator now exists and has the request frequency set, proving that the
- // V8PerFrameMemoryRequest was created.
+ // V8DetailedMemoryRequest was created.
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) {
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph);
ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
- EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests,
+ EXPECT_EQ(kMinTimeBetweenRequests,
decorator->GetNextRequest()->min_time_between_requests());
}));
// The observer should be invoked on the main sequence when a measurement is
// available. Exit the RunLoop when this happens.
base::RunLoop run_loop;
- EXPECT_CALL(observer,
- OnV8MemoryMeasurementAvailable(process_id, expected_process_data,
- expected_frame_data))
- .WillOnce([this, &run_loop, &process_id, &expected_frame_data]() {
+ EXPECT_CALL(observer, OnV8MemoryMeasurementAvailable(main_process_id(),
+ expected_process_data,
+ expected_frame_data))
+ .WillOnce([&]() {
run_loop.Quit();
ASSERT_TRUE(
this->GetMainThreadTaskRunner()->RunsTasksInCurrentSequence())
@@ -1621,8 +1621,8 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
// Verify that the notification parameters can be used to retrieve a
// RenderFrameHost and RenderProcessHost. This is safe on the main
// thread.
- EXPECT_NE(nullptr,
- content::RenderProcessHost::FromID(process_id.value()));
+ EXPECT_NE(nullptr, content::RenderProcessHost::FromID(
+ main_process_id().value()));
const content::GlobalFrameRoutingId frame_id =
expected_frame_data.cbegin()->first;
EXPECT_NE(nullptr, content::RenderFrameHost::FromID(frame_id));
@@ -1635,14 +1635,14 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
Mock::VerifyAndClearExpectations(&observer);
// Destroying the object on the main sequence should cause the wrapped
- // V8PerFrameMemoryRequest to be destroyed on the graph sequence after any
+ // V8DetailedMemoryRequest to be destroyed on the graph sequence after any
// scheduled tasks, which resets the request frequency to zero.
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) {
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph);
ASSERT_TRUE(decorator);
ASSERT_TRUE(decorator->GetNextRequest());
- EXPECT_EQ(V8PerFrameMemoryDecoratorTest::kMinTimeBetweenRequests,
+ EXPECT_EQ(kMinTimeBetweenRequests,
decorator->GetNextRequest()->min_time_between_requests());
}));
@@ -1653,7 +1653,7 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindOnce([](Graph* graph) {
- auto* decorator = V8PerFrameMemoryDecorator::GetFromGraph(graph);
+ auto* decorator = V8DetailedMemoryDecorator::GetFromGraph(graph);
ASSERT_TRUE(decorator);
EXPECT_FALSE(decorator->GetNextRequest());
}));
@@ -1664,6 +1664,255 @@ TEST_F(V8PerFrameMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
run_loop2.Run();
}
+TEST_F(V8DetailedMemoryRequestAnySeqTest, SingleProcessRequest) {
+ CreateCrossProcessChildFrame();
+
+ V8DetailedMemoryProcessData expected_process_data1;
+ expected_process_data1.set_unassociated_v8_bytes_used(1U);
+ V8DetailedMemoryProcessData expected_process_data2;
+ expected_process_data2.set_unassociated_v8_bytes_used(2U);
+
+ MockV8DetailedMemoryReporter mock_reporter1;
+ MockV8DetailedMemoryReporter mock_reporter2;
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1U;
+ ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
+ main_process_id());
+
+ data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 2U;
+ ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
+ child_process_id());
+ }
+
+ // Create one request that measures both processes, and one request that
+ // measures only one.
+ V8DetailedMemoryRequestAnySeq all_process_request(kMinTimeBetweenRequests);
+ MockV8DetailedMemoryObserverAnySeq all_process_observer;
+ all_process_request.AddObserver(&all_process_observer);
+
+ V8DetailedMemoryRequestAnySeq single_process_request(
+ kMinTimeBetweenRequests, MeasurementMode::kBounded, main_process_id());
+ MockV8DetailedMemoryObserverAnySeq single_process_observer;
+ single_process_request.AddObserver(&single_process_observer);
+
+ // When a measurement is available the all process observer should be invoked
+ // for both processes, and the single process observer only for process 1.
+ EXPECT_CALL(all_process_observer,
+ OnV8MemoryMeasurementAvailable(main_process_id(),
+ expected_process_data1, _));
+ EXPECT_CALL(all_process_observer,
+ OnV8MemoryMeasurementAvailable(child_process_id(),
+ expected_process_data2, _));
+ EXPECT_CALL(single_process_observer,
+ OnV8MemoryMeasurementAvailable(main_process_id(),
+ expected_process_data1, _));
+
+ // Now execute all the above tasks.
+ task_environment()->RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter1);
+ Mock::VerifyAndClearExpectations(&mock_reporter2);
+ Mock::VerifyAndClearExpectations(&all_process_observer);
+ Mock::VerifyAndClearExpectations(&single_process_observer);
+
+ // Must remove the observer before destroying the request to avoid a DCHECK
+ // from ObserverList.
+ all_process_request.RemoveObserver(&all_process_observer);
+ single_process_request.RemoveObserver(&single_process_observer);
+}
+
+TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShot) {
+ CreateCrossProcessChildFrame();
+
+ // Set the all process request to only send once within the test.
+ V8DetailedMemoryRequestAnySeq all_process_request(kMinTimeBetweenRequests *
+ 100);
+
+ // Create a mock reporter for each process and expect a query and reply on
+ // each.
+ MockV8DetailedMemoryReporter mock_reporter1;
+
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectBindAndRespondToQuery(&mock_reporter1, std::move(data),
+ main_process_id());
+ }
+
+ MockV8DetailedMemoryReporter mock_reporter2;
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 2ULL;
+ ExpectBindAndRespondToQuery(&mock_reporter2, std::move(data),
+ child_process_id());
+ }
+
+ task_environment()->RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter1);
+ Mock::VerifyAndClearExpectations(&mock_reporter2);
+
+ // Create a one-shot request for process1 and expect the callback to be
+ // called only for that process.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 3ULL;
+ ExpectQueryAndReply(&mock_reporter1, std::move(data));
+ }
+
+ uint64_t unassociated_v8_bytes_used = 0;
+ V8DetailedMemoryRequestOneShotAnySeq process1_request;
+ process1_request.StartMeasurement(
+ main_process_id(),
+ base::BindLambdaForTesting(
+ [&](RenderProcessHostId process_id,
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
+ frame_data) {
+ EXPECT_EQ(process_id, main_process_id());
+ unassociated_v8_bytes_used =
+ process_data.unassociated_v8_bytes_used();
+ }));
+ task_environment()->RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter1);
+ Mock::VerifyAndClearExpectations(&mock_reporter2);
+ EXPECT_EQ(unassociated_v8_bytes_used, 3ULL);
+}
+
+TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetime) {
+ // Measure a child frame so that it can be detached.
+ CreateCrossProcessChildFrame();
+
+ // Create a one-shot request, but delete it before the result arrives.
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ InSequence seq;
+ ExpectBindReceiver(&mock_reporter, child_process_id());
+
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+
+ auto doomed_request = std::make_unique<V8DetailedMemoryRequestOneShotAnySeq>(
+ child_process_id(),
+ base::BindOnce(
+ [](RenderProcessHostId process_id,
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
+ frame_data) {
+ FAIL() << "Callback called after request deleted.";
+ }));
+
+ // Verify that requests are sent but reply is not received.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+
+ doomed_request.reset();
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+
+ // Create a request that is deleted from within its own callback and make
+ // sure nothing explodes.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 2ULL;
+ ExpectQueryAndReply(&mock_reporter, std::move(data));
+ }
+ uint64_t unassociated_v8_bytes_used = 0;
+ doomed_request = std::make_unique<V8DetailedMemoryRequestOneShotAnySeq>(
+ child_process_id(),
+ base::BindLambdaForTesting(
+ [&](RenderProcessHostId process_id,
+ const V8DetailedMemoryProcessData& process_data,
+ const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&
+ frame_data) {
+ doomed_request.reset();
+ unassociated_v8_bytes_used =
+ process_data.unassociated_v8_bytes_used();
+ }));
+ task_environment()->RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ EXPECT_EQ(unassociated_v8_bytes_used, 2ULL);
+
+ // Ensure that resource-owning callbacks are freed when there is no response
+ // because the process dies.
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 3ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+ auto lifetime_test = std::make_unique<LifetimeTestObject>();
+ auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+ V8DetailedMemoryRequestOneShotAnySeq unfinished_request(
+ child_process_id(),
+ base::BindOnce(
+ [](std::unique_ptr<LifetimeTestObject>, RenderProcessHostId,
+ const V8DetailedMemoryProcessData&,
+ const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&) {
+ FAIL() << "Callback called after process deleted.";
+ },
+ // Pass ownership to the callback. The object should be deleted if the
+ // callback is not called.
+ std::move(lifetime_test)));
+
+ // Verify that requests are sent but reply is not yet received.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ ASSERT_TRUE(weak_lifetime_test);
+
+ content::RenderFrameHostTester::For(child_frame())->Detach();
+
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(weak_lifetime_test);
+}
+
+TEST_F(V8DetailedMemoryRequestAnySeqTest, OneShotLifetimeAtExit) {
+ // Ensure that resource-owning callbacks are freed when there is no response
+ // because the browser is exiting (simulated by destroying the decorator).
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ InSequence seq;
+ ExpectBindReceiver(&mock_reporter, main_process_id());
+
+ auto data = NewPerProcessV8MemoryUsage(1);
+ data->isolates[0]->unassociated_bytes_used = 1ULL;
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+
+ auto lifetime_test = std::make_unique<LifetimeTestObject>();
+ auto weak_lifetime_test = lifetime_test->AsWeakPtr();
+ V8DetailedMemoryRequestOneShotAnySeq unfinished_request(
+ main_process_id(),
+ base::BindOnce(
+ [](std::unique_ptr<LifetimeTestObject>, RenderProcessHostId,
+ const V8DetailedMemoryProcessData&,
+ const V8DetailedMemoryRequestOneShotAnySeq::FrameDataMap&) {
+ FAIL() << "Callback called after measurements cancelled.";
+ },
+ // Pass ownership to the callback. The object should be deleted if the
+ // callback is not called.
+ std::move(lifetime_test)));
+
+ // Verify that requests are sent but reply is not yet received.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ Mock::VerifyAndClearExpectations(&mock_reporter);
+ ASSERT_TRUE(weak_lifetime_test);
+
+ base::RunLoop run_loop;
+ PerformanceManager::CallOnGraph(
+ FROM_HERE,
+ base::BindOnce(&internal::DestroyV8DetailedMemoryDecoratorForTesting));
+ // Block in the run loop until the destroy task runs on the PM sequence.
+ PerformanceManager::CallOnGraph(FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ EXPECT_FALSE(weak_lifetime_test);
+}
+
} // namespace v8_memory
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.cc b/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.cc
new file mode 100644
index 00000000000..96759c56bbd
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.cc
@@ -0,0 +1,240 @@
+// Copyright 2020 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/performance_manager/v8_memory/v8_memory_test_helpers.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "components/performance_manager/public/performance_manager.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/test_utils.h"
+#include "url/gurl.h"
+
+namespace performance_manager {
+
+namespace v8_memory {
+
+using ::testing::_;
+
+////////////////////////////////////////////////////////////////////////////////
+// LenientMockV8DetailedMemoryReporter
+
+LenientMockV8DetailedMemoryReporter::LenientMockV8DetailedMemoryReporter() =
+ default;
+
+LenientMockV8DetailedMemoryReporter::~LenientMockV8DetailedMemoryReporter() =
+ default;
+
+void LenientMockV8DetailedMemoryReporter::Bind(
+ mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
+ pending_receiver) {
+ return receiver_.Bind(std::move(pending_receiver));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// V8MemoryTestBase
+
+V8MemoryTestBase::V8MemoryTestBase()
+ : bind_callback_(
+ base::BindRepeating(&V8MemoryTestBase::BindReceiverOnMainSequence,
+ base::Unretained(this))) {
+ internal::SetBindV8DetailedMemoryReporterCallbackForTesting(&bind_callback_);
+}
+
+V8MemoryTestBase::~V8MemoryTestBase() {
+ internal::SetBindV8DetailedMemoryReporterCallbackForTesting(nullptr);
+}
+
+void V8MemoryTestBase::ReplyWithData(
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback) {
+ std::move(callback).Run(std::move(data));
+}
+
+void V8MemoryTestBase::DelayedReplyWithData(
+ const base::TimeDelta& delay,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback) {
+ GetMainThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(data)), delay);
+}
+
+void V8MemoryTestBase::ExpectQuery(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ base::RepeatingCallback<
+ void(MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback)>
+ responder,
+ ExpectedMode expected_mode) {
+ EXPECT_CALL(*mock_reporter, GetV8MemoryUsage(expected_mode, _))
+ .WillOnce(
+ [this, responder](
+ ExpectedMode mode,
+ MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback) {
+ this->last_query_time_ = base::TimeTicks::Now();
+ responder.Run(std::move(callback));
+ });
+}
+
+void V8MemoryTestBase::ExpectQueryAndReply(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ ExpectedMode expected_mode) {
+ ExpectQuery(mock_reporter,
+ base::BindRepeating(&V8MemoryTestBase::ReplyWithData,
+ base::Unretained(this), base::Passed(&data)),
+ expected_mode);
+}
+
+void V8MemoryTestBase::ExpectQueryAndDelayReply(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ const base::TimeDelta& delay,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ ExpectedMode expected_mode) {
+ ExpectQuery(
+ mock_reporter,
+ base::BindRepeating(&V8MemoryTestBase::DelayedReplyWithData,
+ base::Unretained(this), delay, base::Passed(&data)),
+ expected_mode);
+}
+
+void V8MemoryTestBase::ExpectBindReceiver(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ RenderProcessHostId expected_process_id) {
+ using ::testing::Eq;
+ using ::testing::Invoke;
+ using ::testing::Property;
+ using ::testing::WithArg;
+
+ // Arg 0 is a
+ // mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>. Pass it
+ // to mock_reporter->Bind().
+ //
+ // Arg 1 is a RenderProcessHostProxy. Expect it to have the expected
+ // process ID.
+ EXPECT_CALL(*this,
+ BindReceiverWithProxyHost(
+ _, Property(&RenderProcessHostProxy::render_process_host_id,
+ Eq(expected_process_id))))
+ .WillOnce(WithArg<0>(
+ Invoke(mock_reporter, &MockV8DetailedMemoryReporter::Bind)));
+}
+
+void V8MemoryTestBase::ExpectBindAndRespondToQuery(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ RenderProcessHostId expected_process_id,
+ ExpectedMode expected_mode) {
+ ::testing::InSequence seq;
+ ExpectBindReceiver(mock_reporter, expected_process_id);
+ ExpectQueryAndReply(mock_reporter, std::move(data), expected_mode);
+}
+
+void V8MemoryTestBase::BindReceiverOnMainSequence(
+ mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
+ pending_receiver,
+ RenderProcessHostProxy proxy) {
+ GetMainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&V8MemoryTestBase::BindReceiverWithProxyHost,
+ base::Unretained(this),
+ std::move(pending_receiver), proxy));
+}
+
+// Storage for static members.
+constexpr RenderProcessHostId V8MemoryTestBase::kTestProcessID;
+
+////////////////////////////////////////////////////////////////////////////////
+// V8MemoryPerformanceManagerTestHarness
+
+V8MemoryPerformanceManagerTestHarness::V8MemoryPerformanceManagerTestHarness()
+ : PerformanceManagerTestHarness(
+ // Use MOCK_TIME so that ExpectQueryAndDelayReply can be used.
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+V8MemoryPerformanceManagerTestHarness::
+ ~V8MemoryPerformanceManagerTestHarness() = default;
+
+void V8MemoryPerformanceManagerTestHarness::SetUp() {
+ PerformanceManagerTestHarness::SetUp();
+
+ // Precondition: CallOnGraph must run on a different sequence. Note that
+ // all tasks passed to CallOnGraph will only run when run_loop.Run() is
+ // called.
+ ASSERT_TRUE(GetMainThreadTaskRunner()->RunsTasksInCurrentSequence());
+ base::RunLoop run_loop;
+ PerformanceManager::CallOnGraph(
+ FROM_HERE, base::BindLambdaForTesting([&] {
+ EXPECT_FALSE(
+ this->GetMainThreadTaskRunner()->RunsTasksInCurrentSequence());
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+
+ // Set the active contents and simulate a navigation, which adds nodes to
+ // the graph.
+ content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
+ SetContents(CreateTestWebContents());
+ main_frame_ = content::NavigationSimulator::NavigateAndCommitFromBrowser(
+ web_contents(), GURL(kMainFrameUrl));
+ main_process_id_ = RenderProcessHostId(main_frame_->GetProcess()->GetID());
+}
+
+void V8MemoryPerformanceManagerTestHarness::CreateCrossProcessChildFrame() {
+ // Since kMainFrameUrl has a different domain than kChildFrameUrl, the main
+ // and child frames should end up in different processes.
+ child_frame_ =
+ content::RenderFrameHostTester::For(main_frame_)->AppendChild("frame1");
+ child_frame_ = content::NavigationSimulator::NavigateAndCommitFromDocument(
+ GURL(kChildFrameUrl), child_frame_);
+ child_process_id_ = RenderProcessHostId(child_frame_->GetProcess()->GetID());
+ ASSERT_NE(main_process_id_, child_process_id_);
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+V8MemoryPerformanceManagerTestHarness::GetMainThreadTaskRunner() {
+ return task_environment()->GetMainThreadTaskRunner();
+}
+
+// Storage for static members.
+constexpr char V8MemoryPerformanceManagerTestHarness::kMainFrameUrl[];
+constexpr char V8MemoryPerformanceManagerTestHarness::kChildFrameUrl[];
+
+////////////////////////////////////////////////////////////////////////////////
+// Free functions
+
+blink::mojom::PerProcessV8MemoryUsagePtr NewPerProcessV8MemoryUsage(
+ size_t number_of_isolates) {
+ auto data = blink::mojom::PerProcessV8MemoryUsage::New();
+ for (size_t i = 0; i < number_of_isolates; ++i) {
+ data->isolates.push_back(blink::mojom::PerIsolateV8MemoryUsage::New());
+ }
+ return data;
+}
+
+void AddIsolateMemoryUsage(const blink::LocalFrameToken& frame_token,
+ uint64_t bytes_used,
+ blink::mojom::PerIsolateV8MemoryUsage* isolate) {
+ for (auto& entry : isolate->contexts) {
+ if (entry->token == blink::ExecutionContextToken(frame_token)) {
+ entry->bytes_used = bytes_used;
+ return;
+ }
+ }
+
+ auto context = blink::mojom::PerContextV8MemoryUsage::New();
+ context->token = blink::ExecutionContextToken(frame_token);
+ context->bytes_used = bytes_used;
+ isolate->contexts.push_back(std::move(context));
+}
+
+} // namespace v8_memory
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.h b/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.h
new file mode 100644
index 00000000000..028691a368b
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/v8_memory_test_helpers.h
@@ -0,0 +1,225 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_V8_MEMORY_V8_MEMORY_TEST_HELPERS_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_MEMORY_TEST_HELPERS_H_
+
+#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "components/performance_manager/public/render_process_host_id.h"
+#include "components/performance_manager/public/render_process_host_proxy.h"
+#include "components/performance_manager/test_support/performance_manager_test_harness.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/mojom/performance_manager/v8_detailed_memory_reporter.mojom.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace performance_manager {
+namespace v8_memory {
+
+// A fake implementation of the mojo interface that reports memory measurement
+// results.
+class LenientMockV8DetailedMemoryReporter
+ : public blink::mojom::V8DetailedMemoryReporter {
+ public:
+ LenientMockV8DetailedMemoryReporter();
+ ~LenientMockV8DetailedMemoryReporter() override;
+
+ LenientMockV8DetailedMemoryReporter(
+ const LenientMockV8DetailedMemoryReporter& other) = delete;
+ LenientMockV8DetailedMemoryReporter operator=(
+ const LenientMockV8DetailedMemoryReporter& other) = delete;
+
+ MOCK_METHOD(void,
+ GetV8MemoryUsage,
+ (Mode mode, GetV8MemoryUsageCallback callback),
+ (override));
+
+ void Bind(mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
+ pending_receiver);
+
+ private:
+ mojo::Receiver<blink::mojom::V8DetailedMemoryReporter> receiver_{this};
+};
+
+using MockV8DetailedMemoryReporter =
+ ::testing::StrictMock<LenientMockV8DetailedMemoryReporter>;
+
+// The mode enum used in test expectations.
+using ExpectedMode = MockV8DetailedMemoryReporter::Mode;
+
+// A base class with helper functions to set up test expectations and fake mojo
+// connections for V8 memory tests. This can be composed with GraphTestHarness
+// or PerformanceManagerTestHarness to make a full test environment.
+class V8MemoryTestBase {
+ public:
+ // A default process ID to use in tests.
+ static constexpr RenderProcessHostId kTestProcessID =
+ RenderProcessHostId(0xFAB);
+
+ V8MemoryTestBase();
+ virtual ~V8MemoryTestBase();
+
+ // Adaptor that calls GetMainThreadTaskRunner for the test harness's task
+ // environment.
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetMainThreadTaskRunner() = 0;
+
+ protected:
+ // Simulate a renderer process reporting the given |data| over the
+ // mojom::V8DetailedMemoryReporter interface using |callback|.
+ void ReplyWithData(
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback);
+
+ // Simulate a renderer process reporting the given |data| over the
+ // mojom::V8DetailedMemoryReporter interface using |callback|, after a delay
+ // of |delay|.
+ void DelayedReplyWithData(
+ const base::TimeDelta& delay,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback);
+
+ // Add a test expectation that the GetV8MemoryUsage method of |mock_reporter|
+ // will be called with the mode parameter equal to |expected_mode|. When the
+ // method is called, |responder| will be invoked to call the method's
+ // response callback. (ReplyWithData and DelayedReplyWithData are examples of
+ // methods that could be bound into |responder| callbacks.)
+ void ExpectQuery(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ base::RepeatingCallback<
+ void(MockV8DetailedMemoryReporter::GetV8MemoryUsageCallback callback)>
+ responder,
+ ExpectedMode expected_mode = ExpectedMode::DEFAULT);
+
+ // Add a test expectation that the GetV8MemoryUsage method of |mock_reporter|
+ // will be called with the mode parameter equal to |expected_mode|. When the
+ // method is called, its response callback will be called with |data|.
+ void ExpectQueryAndReply(MockV8DetailedMemoryReporter* mock_reporter,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ ExpectedMode expected_mode = ExpectedMode::DEFAULT);
+
+ // Add a test expectation that the GetV8MemoryUsage method of |mock_reporter|
+ // will be called with the mode parameter equal to |expected_mode|. When the
+ // method is called, its response callback will be called with |data| after a
+ // delay of |delay|.
+ void ExpectQueryAndDelayReply(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ const base::TimeDelta& delay,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ ExpectedMode expected_mode = ExpectedMode::DEFAULT);
+
+ // Add a test expectation that
+ // BindReceiverWithProxyHost will be called with the proxy parameter having ID
+ // |expected_process_id|.
+ void ExpectBindReceiver(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ RenderProcessHostId expected_process_id = kTestProcessID);
+
+ // Add test expectations that two methods will be called in sequence:
+ // BindReceiverWithProxyHost (as in ExpectBindReceiver) and GetV8MemoryUsage
+ // (as in ExpectQueryAndReply). This is a useful shorthand because the
+ // receiver is always bound just before sending the first request to a
+ // process.
+ void ExpectBindAndRespondToQuery(
+ MockV8DetailedMemoryReporter* mock_reporter,
+ blink::mojom::PerProcessV8MemoryUsagePtr data,
+ RenderProcessHostId expected_process_id = kTestProcessID,
+ ExpectedMode expected_mode = ExpectedMode::DEFAULT);
+
+ // A mock method that will be called the first time a memory measurement is
+ // requested for a process.
+ MOCK_METHOD(void,
+ BindReceiverWithProxyHost,
+ (mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
+ pending_receiver,
+ RenderProcessHostProxy proxy),
+ (const));
+
+ // The last time one of the query expectations installed by the Expect*
+ // methods was fulfilled.
+ base::TimeTicks last_query_time() const { return last_query_time_; }
+
+ private:
+ // Invokes BindReceiverWithProxyHost on the main sequence.
+ void BindReceiverOnMainSequence(
+ mojo::PendingReceiver<blink::mojom::V8DetailedMemoryReporter>
+ pending_receiver,
+ RenderProcessHostProxy proxy);
+
+ // A callback that will live as long as |this| does. Will be installed with
+ // SetBindV8DetailedMemoryReporterCallbackForTesting.
+ internal::BindV8DetailedMemoryReporterCallback bind_callback_;
+
+ base::TimeTicks last_query_time_;
+};
+
+// A PerformanceManagerTestHarness that exposes the helpers from
+// V8MemoryTestBase and sets up some frames whose memory can be measured.
+class V8MemoryPerformanceManagerTestHarness
+ : public PerformanceManagerTestHarness,
+ public V8MemoryTestBase {
+ public:
+ V8MemoryPerformanceManagerTestHarness();
+ ~V8MemoryPerformanceManagerTestHarness() override;
+
+ static constexpr char kMainFrameUrl[] = "http://a.com/";
+ static constexpr char kChildFrameUrl[] = "http://b.com/";
+
+ void SetUp() override;
+
+ // The main frame, which always exists.
+ content::RenderFrameHost* main_frame() const { return main_frame_; }
+
+ // The ID of the main frame's renderer process.
+ RenderProcessHostId main_process_id() const { return main_process_id_; }
+
+ // A cross-process child frame. Will return nullptr unless
+ // CreateCrossProcessChildFrame is called.
+ content::RenderFrameHost* child_frame() const { return child_frame_; }
+
+ // The ID of the child frame's renderer process. Returns null if the child
+ // frame does not exist.
+ RenderProcessHostId child_process_id() const { return child_process_id_; }
+
+ // Creates a child frame that has its own renderer process. After calling
+ // this the frame can be accessed with child_frame() and child_process_id().
+ void CreateCrossProcessChildFrame();
+
+ // V8MemoryTestBase implementation.
+ scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner()
+ override;
+
+ private:
+ content::RenderFrameHost* main_frame_ = nullptr;
+ content::RenderFrameHost* child_frame_ = nullptr;
+ RenderProcessHostId main_process_id_;
+ RenderProcessHostId child_process_id_;
+};
+
+// Returns a new mojom::PerProcessV8MemoryUsage struct with
+// |number_of_isolates| empty isolates.
+blink::mojom::PerProcessV8MemoryUsagePtr NewPerProcessV8MemoryUsage(
+ size_t number_of_isolates);
+
+// Finds the PerContextV8MemoryUsage in |isolate| whose token is |frame_token|,
+// or creates it if it does not exist, and sets its bytes_used to |bytes_used|.
+void AddIsolateMemoryUsage(const blink::LocalFrameToken& frame_token,
+ uint64_t bytes_used,
+ blink::mojom::PerIsolateV8MemoryUsage* isolate);
+
+} // namespace v8_memory
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_V8_MEMORY_TEST_HELPERS_H_
diff --git a/chromium/components/performance_manager/v8_memory/web_memory_aggregator.cc b/chromium/components/performance_manager/v8_memory/web_memory_aggregator.cc
new file mode 100644
index 00000000000..37fe0178b57
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/web_memory_aggregator.cc
@@ -0,0 +1,120 @@
+// Copyright 2020 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/performance_manager/v8_memory/web_memory_aggregator.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "components/performance_manager/public/graph/frame_node.h"
+#include "components/performance_manager/public/graph/process_node.h"
+#include "components/performance_manager/public/v8_memory/web_memory.h"
+#include "url/gurl.h"
+
+namespace performance_manager {
+
+namespace v8_memory {
+
+namespace {
+
+mojom::WebMemoryMeasurementPtr BuildMemoryUsageResult(
+ const blink::LocalFrameToken& frame_token,
+ const ProcessNode* process_node) {
+ const auto& frame_nodes = process_node->GetFrameNodes();
+
+ // Find the frame that made the request.
+ const FrameNode* requesting_frame = nullptr;
+ for (auto* frame_node : frame_nodes) {
+ if (frame_node->GetFrameToken() == frame_token) {
+ requesting_frame = frame_node;
+ break;
+ }
+ }
+
+ if (!requesting_frame) {
+ // The frame no longer exists.
+ return mojom::WebMemoryMeasurement::New();
+ }
+
+ auto result = mojom::WebMemoryMeasurement::New();
+
+ for (const FrameNode* frame_node : frame_nodes) {
+ if (frame_node->GetBrowsingInstanceId() !=
+ requesting_frame->GetBrowsingInstanceId()) {
+ continue;
+ }
+ if (frame_node->GetURL().GetOrigin() !=
+ requesting_frame->GetURL().GetOrigin()) {
+ continue;
+ }
+ auto* data = v8_memory::V8DetailedMemoryFrameData::ForFrameNode(frame_node);
+ if (!data) {
+ continue;
+ }
+ auto attribution = mojom::WebMemoryAttribution::New();
+ attribution->url = frame_node->GetURL().spec();
+ attribution->scope = mojom::WebMemoryAttribution::Scope::kWindow;
+ auto entry = mojom::WebMemoryBreakdownEntry::New();
+ entry->bytes = data->v8_bytes_used();
+ entry->attribution.push_back(std::move(attribution));
+ result->breakdown.push_back(std::move(entry));
+ }
+ return result;
+}
+
+v8_memory::V8DetailedMemoryRequest::MeasurementMode
+WebMeasurementModeToRequestMeasurementMode(
+ mojom::WebMemoryMeasurement::Mode mode) {
+ switch (mode) {
+ case mojom::WebMemoryMeasurement::Mode::kDefault:
+ return v8_memory::V8DetailedMemoryRequest::MeasurementMode::kDefault;
+ case mojom::WebMemoryMeasurement::Mode::kEager:
+ return v8_memory::V8DetailedMemoryRequest::MeasurementMode::
+ kEagerForTesting;
+ }
+}
+
+} // anonymous namespace
+
+// Implements the public function in public/v8_memory/web_memory.h
+void WebMeasureMemory(
+ const FrameNode* frame_node,
+ mojom::WebMemoryMeasurement::Mode mode,
+ base::OnceCallback<void(mojom::WebMemoryMeasurementPtr)> callback) {
+ auto web_memory_aggregator = std::make_unique<WebMemoryAggregator>(
+ frame_node->GetFrameToken(),
+ WebMeasurementModeToRequestMeasurementMode(mode), std::move(callback));
+
+ // Create a measurement complete callback to own |web_memory_aggregator|. It
+ // will be deleted when the callback is executed or dropped.
+ V8DetailedMemoryRequestOneShot* request = web_memory_aggregator->request();
+ auto measurement_complete_callback =
+ base::BindOnce(&WebMemoryAggregator::MeasurementComplete,
+ std::move(web_memory_aggregator));
+
+ // Start memory measurement for the process of the given frame.
+ request->StartMeasurement(frame_node->GetProcessNode(),
+ std::move(measurement_complete_callback));
+}
+
+WebMemoryAggregator::WebMemoryAggregator(
+ const blink::LocalFrameToken& frame_token,
+ V8DetailedMemoryRequest::MeasurementMode mode,
+ MeasurementCallback callback)
+ : frame_token_(frame_token),
+ callback_(std::move(callback)),
+ request_(std::make_unique<V8DetailedMemoryRequestOneShot>(mode)) {}
+
+WebMemoryAggregator::~WebMemoryAggregator() = default;
+
+void WebMemoryAggregator::MeasurementComplete(
+ const ProcessNode* process_node,
+ const V8DetailedMemoryProcessData*) {
+ std::move(callback_).Run(BuildMemoryUsageResult(frame_token_, process_node));
+}
+
+} // namespace v8_memory
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/v8_memory/web_memory_aggregator.h b/chromium/components/performance_manager/v8_memory/web_memory_aggregator.h
new file mode 100644
index 00000000000..25ae6a01bbe
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/web_memory_aggregator.h
@@ -0,0 +1,49 @@
+// Copyright 2020 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_PERFORMANCE_MANAGER_V8_MEMORY_WEB_MEMORY_AGGREGATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_WEB_MEMORY_AGGREGATOR_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "components/performance_manager/public/mojom/web_memory.mojom.h"
+#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+
+namespace performance_manager {
+
+class ProcessNode;
+
+namespace v8_memory {
+
+// A helper class for implementing WebMeasureMemory().
+class WebMemoryAggregator {
+ public:
+ using MeasurementCallback =
+ base::OnceCallback<void(mojom::WebMemoryMeasurementPtr)>;
+
+ WebMemoryAggregator(const blink::LocalFrameToken&,
+ V8DetailedMemoryRequest::MeasurementMode,
+ MeasurementCallback);
+
+ ~WebMemoryAggregator();
+
+ V8DetailedMemoryRequestOneShot* request() const { return request_.get(); }
+
+ // A callback for V8DetailedMemoryRequestOneShot.
+ void MeasurementComplete(const ProcessNode*,
+ const V8DetailedMemoryProcessData*);
+
+ private:
+ blink::LocalFrameToken frame_token_;
+ MeasurementCallback callback_;
+ std::unique_ptr<V8DetailedMemoryRequestOneShot> request_;
+};
+
+} // namespace v8_memory
+
+} // namespace performance_manager
+
+#endif // COMPONENTS_PERFORMANCE_MANAGER_V8_MEMORY_WEB_MEMORY_AGGREGATOR_H_
diff --git a/chromium/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc b/chromium/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
new file mode 100644
index 00000000000..70530bc7989
--- /dev/null
+++ b/chromium/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright 2020 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/performance_manager/v8_memory/web_memory_aggregator.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "components/performance_manager/graph/frame_node_impl.h"
+#include "components/performance_manager/graph/page_node_impl.h"
+#include "components/performance_manager/graph/process_node_impl.h"
+#include "components/performance_manager/public/performance_manager.h"
+#include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
+#include "components/performance_manager/public/v8_memory/web_memory.h"
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "components/performance_manager/v8_memory/v8_memory_test_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/tokens/tokens.h"
+#include "url/gurl.h"
+
+namespace performance_manager {
+
+namespace v8_memory {
+
+using WebMemoryAggregatorPMTest = V8MemoryPerformanceManagerTestHarness;
+
+class WebMemoryAggregatorTest : public GraphTestHarness {
+ public:
+ // Wrapper for the browsing instance id to improve test readability.
+ struct BrowsingInstance {
+ int id;
+ };
+
+ // Wrapper for memory usage bytes to improve test readability.
+ struct Bytes {
+ uint64_t bytes;
+ bool operator==(const Bytes& other) const { return bytes == other.bytes; }
+ };
+
+ void SetUp() override;
+
+ // Creates and adds a new frame node to the graph.
+ FrameNodeImpl* AddFrameNode(std::string url,
+ BrowsingInstance,
+ Bytes,
+ FrameNodeImpl* parent = nullptr);
+
+ // Invokes memory measurement and verifies that the result matches the
+ // expected memory usage that is provided as a table from a frame URL to
+ // bytes.
+ void MeasureAndVerify(FrameNodeImpl* frame,
+ base::flat_map<std::string, Bytes> expected);
+
+ private:
+ int GetNextUniqueId();
+ TestNodeWrapper<ProcessNodeImpl> process_;
+ TestNodeWrapper<PageNodeImpl> page_;
+ std::vector<TestNodeWrapper<FrameNodeImpl>> frames_;
+ int next_unique_id_ = 0;
+};
+
+void WebMemoryAggregatorTest::SetUp() {
+ process_ = CreateNode<ProcessNodeImpl>();
+ page_ = CreateNode<PageNodeImpl>();
+}
+
+int WebMemoryAggregatorTest::GetNextUniqueId() {
+ return next_unique_id_++;
+}
+
+FrameNodeImpl* WebMemoryAggregatorTest::AddFrameNode(
+ std::string url,
+ BrowsingInstance browsing_instance_id,
+ Bytes memory_usage,
+ FrameNodeImpl* parent) {
+ int frame_tree_node_id = GetNextUniqueId();
+ int frame_routing_id = GetNextUniqueId();
+ auto frame = CreateNode<FrameNodeImpl>(
+ process_.get(), page_.get(), parent, frame_tree_node_id, frame_routing_id,
+ blink::LocalFrameToken(), browsing_instance_id.id);
+ frame->OnNavigationCommitted(GURL(url), /*same document*/ true);
+ V8DetailedMemoryFrameData::CreateForTesting(frame.get())
+ ->set_v8_bytes_used(memory_usage.bytes);
+ frames_.push_back(std::move(frame));
+ return frames_.back().get();
+}
+
+void WebMemoryAggregatorTest::MeasureAndVerify(
+ FrameNodeImpl* frame,
+ base::flat_map<std::string, Bytes> expected) {
+ bool measurement_done = false;
+ WebMemoryAggregator web_memory(
+ frame->frame_token(), V8DetailedMemoryRequest::MeasurementMode::kDefault,
+ base::BindLambdaForTesting([&measurement_done, &expected](
+ mojom::WebMemoryMeasurementPtr result) {
+ base::flat_map<std::string, Bytes> actual;
+ for (const auto& entry : result->breakdown) {
+ EXPECT_EQ(1u, entry->attribution.size());
+ EXPECT_EQ(mojom::WebMemoryAttribution::Scope::kWindow,
+ entry->attribution[0]->scope);
+ actual[*entry->attribution[0]->url] = Bytes{entry->bytes};
+ }
+ EXPECT_EQ(expected, actual);
+ measurement_done = true;
+ }));
+ V8DetailedMemoryProcessData process_data;
+ web_memory.MeasurementComplete(process_.get(), &process_data);
+ EXPECT_TRUE(measurement_done);
+}
+
+TEST_F(WebMemoryAggregatorTest, IncludeSameOriginRelatedFrames) {
+ auto* main = AddFrameNode("http://foo.com/", BrowsingInstance{0}, Bytes{10u});
+
+ AddFrameNode("http://foo.com/iframe", BrowsingInstance{0}, Bytes{20}, main);
+
+ MeasureAndVerify(main, {
+ {"http://foo.com/", Bytes{10u}},
+ {"http://foo.com/iframe", Bytes{20u}},
+ });
+}
+
+TEST_F(WebMemoryAggregatorTest, SkipCrossOriginFrames) {
+ auto* main = AddFrameNode("http://foo.com", BrowsingInstance{0}, Bytes{10u});
+
+ AddFrameNode("http://bar.com/iframe", BrowsingInstance{0}, Bytes{20}, main);
+
+ MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}}});
+}
+
+TEST_F(WebMemoryAggregatorTest, SkipUnrelatedFrames) {
+ auto* main = AddFrameNode("http://foo.com", BrowsingInstance{0}, Bytes{10u});
+
+ AddFrameNode("http://foo.com/unrelated", BrowsingInstance{1}, Bytes{20});
+
+ MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}}});
+}
+
+TEST_F(WebMemoryAggregatorPMTest, WebMeasureMemory) {
+ blink::LocalFrameToken frame_token =
+ blink::LocalFrameToken(main_frame()->GetFrameToken());
+
+ // Call WebMeasureMemory on the performance manager sequence and verify that
+ // the result matches the data provided by the mock reporter.
+ base::RunLoop run_loop;
+ auto measurement_callback =
+ base::BindLambdaForTesting([&](mojom::WebMemoryMeasurementPtr result) {
+ EXPECT_EQ(1u, result->breakdown.size());
+ const auto& entry = result->breakdown[0];
+ EXPECT_EQ(1u, entry->attribution.size());
+ EXPECT_EQ(kMainFrameUrl, *(entry->attribution[0]->url));
+ EXPECT_EQ(1001u, entry->bytes);
+ run_loop.Quit();
+ });
+
+ base::WeakPtr<FrameNode> frame_node_wrapper =
+ PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
+ PerformanceManager::CallOnGraph(
+ FROM_HERE, base::BindLambdaForTesting([&]() {
+ ASSERT_TRUE(frame_node_wrapper);
+ FrameNode* frame_node = frame_node_wrapper.get();
+ WebMeasureMemory(frame_node,
+ mojom::WebMemoryMeasurement::Mode::kDefault,
+ std::move(measurement_callback));
+ }));
+
+ // Set up and bind the mock reporter.
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ auto data = NewPerProcessV8MemoryUsage(1);
+ AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
+ ExpectBindAndRespondToQuery(&mock_reporter, std::move(data),
+ main_process_id());
+ }
+
+ // Finally, run all tasks to verify that the memory measurement callback
+ // is actually invoked. The test will time out if not.
+ run_loop.Run();
+}
+
+TEST_F(WebMemoryAggregatorPMTest, MeasurementInterrupted) {
+ CreateCrossProcessChildFrame();
+
+ blink::LocalFrameToken frame_token =
+ blink::LocalFrameToken(child_frame()->GetFrameToken());
+
+ // Call WebMeasureMemory on the performance manager sequence but delete the
+ // process being measured before the result arrives.
+ auto measurement_callback =
+ base::BindOnce([](mojom::WebMemoryMeasurementPtr result) {
+ FAIL() << "Measurement callback ran unexpectedly";
+ });
+
+ base::WeakPtr<FrameNode> frame_node_wrapper =
+ PerformanceManager::GetFrameNodeForRenderFrameHost(child_frame());
+ PerformanceManager::CallOnGraph(
+ FROM_HERE, base::BindLambdaForTesting([&]() {
+ ASSERT_TRUE(frame_node_wrapper);
+ FrameNode* frame_node = frame_node_wrapper.get();
+ WebMeasureMemory(frame_node,
+ mojom::WebMemoryMeasurement::Mode::kDefault,
+ std::move(measurement_callback));
+ }));
+
+ // Set up and bind the mock reporter.
+ MockV8DetailedMemoryReporter mock_reporter;
+ {
+ ::testing::InSequence seq;
+ ExpectBindReceiver(&mock_reporter, child_process_id());
+
+ auto data = NewPerProcessV8MemoryUsage(1);
+ AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
+ ExpectQueryAndDelayReply(&mock_reporter, base::TimeDelta::FromSeconds(10),
+ std::move(data));
+ }
+
+ // Verify that requests are sent but reply is not yet received.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+ ::testing::Mock::VerifyAndClearExpectations(&mock_reporter);
+
+ // Remove the child frame, which will destroy the child process.
+ content::RenderFrameHostTester::For(child_frame())->Detach();
+
+ // Advance until the reply is expected to make sure nothing explodes.
+ task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(5));
+}
+
+} // namespace v8_memory
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/voting_unittest.cc b/chromium/components/performance_manager/voting_unittest.cc
new file mode 100644
index 00000000000..fa6ec507a90
--- /dev/null
+++ b/chromium/components/performance_manager/voting_unittest.cc
@@ -0,0 +1,201 @@
+// Copyright 2020 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/performance_manager/public/voting/voting.h"
+
+#include "components/performance_manager/test_support/voting.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+
+namespace {
+
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+
+using TestVote = voting::Vote<void, int, 0>;
+using TestVoteReceipt = voting::VoteReceipt<TestVote>;
+using TestVotingChannel = voting::VotingChannel<TestVote>;
+using TestVotingChannelFactory = voting::VotingChannelFactory<TestVote>;
+using TestVoteConsumer = voting::VoteConsumer<TestVote>;
+using TestAcceptedVote = voting::AcceptedVote<TestVote>;
+
+using DummyVoter = voting::test::DummyVoter<TestVote>;
+using DummyVoteConsumer = voting::test::DummyVoteConsumer<TestVote>;
+using DummyVoteObserver = voting::test::DummyVoteObserver<TestVote>;
+
+// Some dummy contexts.
+const void* kDummyContext1 = reinterpret_cast<const void*>(0xDEADBEEF);
+const void* kDummyContext2 = reinterpret_cast<const void*>(0xBAADF00D);
+
+AssertionResult IsEntangled(const TestVoteReceipt& receipt,
+ const TestAcceptedVote& vote) {
+ if (!receipt.HasVote(&vote))
+ return AssertionFailure() << "Receipt has wrong vote";
+ if (!vote.HasReceipt(&receipt))
+ return AssertionFailure() << "Vote has wrong receipt";
+ if (!vote.IsValid())
+ return AssertionFailure() << "Vote is not valid";
+ return AssertionSuccess();
+}
+
+AssertionResult IsNotEntangled(const TestVoteReceipt& receipt,
+ const TestAcceptedVote& vote) {
+ if (receipt.HasVote(&vote))
+ return AssertionFailure() << "Receipt has unexpected vote";
+ if (vote.HasReceipt(&receipt))
+ return AssertionFailure() << "Vote has unexpected receipt";
+ if (vote.IsValid())
+ return AssertionFailure() << "Vote is unexpectedly valid";
+ return AssertionSuccess();
+}
+
+static const char kReason[] = "reason";
+
+} // namespace
+
+TEST(VotingTest, DefaultAcceptedVoteIsInvalid) {
+ TestAcceptedVote vote;
+ EXPECT_FALSE(vote.IsValid());
+}
+
+TEST(VotingTest, VoteReceiptsWork) {
+ DummyVoteConsumer consumer;
+ DummyVoter voter;
+
+ EXPECT_FALSE(voter.voting_channel_.IsValid());
+ voter.SetVotingChannel(consumer.voting_channel_factory_.BuildVotingChannel());
+ EXPECT_EQ(&consumer.voting_channel_factory_,
+ voter.voting_channel_.factory_for_testing());
+ EXPECT_NE(voting::kInvalidVoterId<TestVote>,
+ voter.voting_channel_.voter_id());
+ EXPECT_TRUE(voter.voting_channel_.IsValid());
+
+ voter.EmitVote(kDummyContext1, 0);
+ EXPECT_EQ(1u, voter.receipts_.size());
+ EXPECT_EQ(1u, consumer.votes_.size());
+ EXPECT_EQ(1u, consumer.valid_vote_count_);
+ EXPECT_EQ(voter.voting_channel_.voter_id(), consumer.votes_[0].voter_id());
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_TRUE(consumer.votes_[0].IsValid());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+
+ // Move the vote and the receipt out of their containers and back in.
+ // All should be well.
+ {
+ TestVoteReceipt receipt = std::move(voter.receipts_[0]);
+ EXPECT_FALSE(voter.receipts_[0].HasVote());
+ EXPECT_TRUE(IsEntangled(receipt, consumer.votes_[0]));
+
+ TestAcceptedVote vote = std::move(consumer.votes_[0]);
+ EXPECT_FALSE(consumer.votes_[0].IsValid());
+ EXPECT_TRUE(IsEntangled(receipt, vote));
+
+ voter.receipts_[0] = std::move(receipt);
+ EXPECT_FALSE(receipt.HasVote());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], vote));
+
+ consumer.votes_[0] = std::move(vote);
+ EXPECT_FALSE(vote.IsValid());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+ }
+
+ voter.EmitVote(kDummyContext2, 0);
+ EXPECT_EQ(2u, voter.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(2u, consumer.valid_vote_count_);
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_EQ(kDummyContext2, consumer.votes_[1].context());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+ EXPECT_TRUE(IsEntangled(voter.receipts_[1], consumer.votes_[1]));
+
+ // Change a vote, but making no change.
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_EQ(0, consumer.votes_[0].vote().value());
+ EXPECT_EQ(DummyVoter::kReason, consumer.votes_[0].vote().reason());
+ voter.receipts_[0].ChangeVote(0, DummyVoter::kReason);
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_EQ(0, consumer.votes_[0].vote().value());
+ EXPECT_EQ(DummyVoter::kReason, consumer.votes_[0].vote().reason());
+
+ // Change the vote and expect the change to propagate.
+ static const char kReason[] = "another reason";
+ voter.receipts_[0].ChangeVote(5, kReason);
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_EQ(5, consumer.votes_[0].vote().value());
+ EXPECT_EQ(kReason, consumer.votes_[0].vote().reason());
+
+ // Cancel a vote.
+ voter.receipts_[0].Reset();
+ EXPECT_EQ(2u, voter.receipts_.size());
+ EXPECT_EQ(2u, consumer.votes_.size());
+ EXPECT_EQ(1u, consumer.valid_vote_count_);
+ EXPECT_EQ(kDummyContext1, consumer.votes_[0].context());
+ EXPECT_EQ(kDummyContext2, consumer.votes_[1].context());
+ EXPECT_TRUE(IsNotEntangled(voter.receipts_[0], consumer.votes_[0]));
+ EXPECT_TRUE(IsEntangled(voter.receipts_[1], consumer.votes_[1]));
+
+ // Cause the votes to be moved by deleting the invalid one.
+ consumer.votes_.erase(consumer.votes_.begin());
+ EXPECT_EQ(2u, voter.receipts_.size());
+ EXPECT_EQ(1u, consumer.votes_.size());
+ EXPECT_EQ(1u, consumer.valid_vote_count_);
+ EXPECT_EQ(kDummyContext2, consumer.votes_[0].context());
+ EXPECT_FALSE(voter.receipts_[0].HasVote());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[1], consumer.votes_[0]));
+
+ // Cause the receipts to be moved by deleting the empty one.
+ voter.receipts_.erase(voter.receipts_.begin());
+ EXPECT_EQ(1u, voter.receipts_.size());
+ EXPECT_EQ(1u, consumer.votes_.size());
+ EXPECT_EQ(1u, consumer.valid_vote_count_);
+ EXPECT_EQ(kDummyContext2, consumer.votes_[0].context());
+ EXPECT_TRUE(IsEntangled(voter.receipts_[0], consumer.votes_[0]));
+
+ // Cancel the remaining vote by deleting the receipt.
+ voter.receipts_.clear();
+ EXPECT_EQ(0u, voter.receipts_.size());
+ EXPECT_EQ(1u, consumer.votes_.size());
+ EXPECT_EQ(0u, consumer.valid_vote_count_);
+ EXPECT_EQ(kDummyContext2, consumer.votes_[0].context());
+ EXPECT_FALSE(consumer.votes_[0].HasReceipt());
+ EXPECT_FALSE(consumer.votes_[0].IsValid());
+}
+
+// Tests that an overwritten vote receipt will property clean up its state.
+TEST(VotingTest, OverwriteVoteReceipt) {
+ DummyVoteConsumer consumer;
+
+ TestVotingChannel voting_channel =
+ consumer.voting_channel_factory_.BuildVotingChannel();
+
+ TestVoteReceipt receipt =
+ voting_channel.SubmitVote(kDummyContext1, TestVote(5, kReason));
+ receipt = voting_channel.SubmitVote(kDummyContext2, TestVote(5, kReason));
+
+ // The first vote was invalidated because its vote receipt was cleaned up.
+ consumer.ExpectInvalidVote(0);
+}
+
+TEST(VotingTest, VoteObserver) {
+ DummyVoteObserver observer;
+
+ TestVotingChannel voting_channel =
+ observer.vote_consumer_default_impl_.BuildVotingChannel();
+ voting::VoterId<TestVote> voter_id = voting_channel.voter_id();
+
+ {
+ TestVoteReceipt receipt =
+ voting_channel.SubmitVote(kDummyContext1, TestVote(5, kReason));
+ EXPECT_TRUE(observer.HasVote(voter_id, kDummyContext1, 5, kReason));
+ }
+
+ EXPECT_FALSE(observer.HasVote(voter_id, kDummyContext1, 5, kReason));
+}
+
+} // namespace performance_manager
diff --git a/chromium/components/performance_manager/web_contents_proxy_unittest.cc b/chromium/components/performance_manager/web_contents_proxy_unittest.cc
index b1ac9dbfb14..6e061e4386e 100644
--- a/chromium/components/performance_manager/web_contents_proxy_unittest.cc
+++ b/chromium/components/performance_manager/web_contents_proxy_unittest.cc
@@ -9,7 +9,7 @@
#include "base/run_loop.h"
#include "base/task/task_traits.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
diff --git a/chromium/components/performance_manager/worker_watcher.cc b/chromium/components/performance_manager/worker_watcher.cc
index ccc1ea9550b..71ca863a470 100644
--- a/chromium/components/performance_manager/worker_watcher.cc
+++ b/chromium/components/performance_manager/worker_watcher.cc
@@ -13,6 +13,7 @@
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/process_node_source.h"
+#include "components/performance_manager/public/features.h"
#include "third_party/blink/public/common/tokens/tokens.h"
namespace performance_manager {
@@ -27,8 +28,8 @@ void RecordWorkerClientFound(bool found) {
// Helper function to add |client_frame_node| as a client of |worker_node| on
// the PM sequence.
-void ConnectClientOnGraph(WorkerNodeImpl* worker_node,
- FrameNodeImpl* client_frame_node) {
+void ConnectClientFrameOnGraph(WorkerNodeImpl* worker_node,
+ FrameNodeImpl* client_frame_node) {
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&WorkerNodeImpl::AddClientFrame,
@@ -37,8 +38,8 @@ void ConnectClientOnGraph(WorkerNodeImpl* worker_node,
// Helper function to remove |client_frame_node| as a client of |worker_node|
// on the PM sequence.
-void DisconnectClientOnGraph(WorkerNodeImpl* worker_node,
- FrameNodeImpl* client_frame_node) {
+void DisconnectClientFrameOnGraph(WorkerNodeImpl* worker_node,
+ FrameNodeImpl* client_frame_node) {
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&WorkerNodeImpl::RemoveClientFrame,
@@ -47,8 +48,8 @@ void DisconnectClientOnGraph(WorkerNodeImpl* worker_node,
// Helper function to add |client_worker_node| as a client of |worker_node| on
// the PM sequence.
-void ConnectClientOnGraph(WorkerNodeImpl* worker_node,
- WorkerNodeImpl* client_worker_node) {
+void ConnectClientWorkerOnGraph(WorkerNodeImpl* worker_node,
+ WorkerNodeImpl* client_worker_node) {
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&WorkerNodeImpl::AddClientWorker,
@@ -57,8 +58,8 @@ void ConnectClientOnGraph(WorkerNodeImpl* worker_node,
// Helper function to remove |client_worker_node| as a client of |worker_node|
// on the PM sequence.
-void DisconnectClientOnGraph(WorkerNodeImpl* worker_node,
- WorkerNodeImpl* client_worker_node) {
+void DisconnectClientWorkerOnGraph(WorkerNodeImpl* worker_node,
+ WorkerNodeImpl* client_worker_node) {
PerformanceManagerImpl::CallOnGraphImpl(
FROM_HERE,
base::BindOnce(&WorkerNodeImpl::RemoveClientWorker,
@@ -120,20 +121,20 @@ WorkerWatcher::WorkerWatcher(
DCHECK(process_node_source_);
DCHECK(frame_node_source_);
- dedicated_worker_service_observer_.Add(dedicated_worker_service);
- shared_worker_service_observer_.Add(shared_worker_service);
- service_worker_context_observer_.Add(service_worker_context);
+ dedicated_worker_service_observation_.Observe(dedicated_worker_service);
+ shared_worker_service_observation_.Observe(shared_worker_service);
+ service_worker_context_observation_.Observe(service_worker_context);
}
WorkerWatcher::~WorkerWatcher() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(frame_node_child_workers_.empty());
DCHECK(dedicated_worker_nodes_.empty());
- DCHECK(!dedicated_worker_service_observer_.IsObservingSources());
+ DCHECK(!dedicated_worker_service_observation_.IsObserving());
DCHECK(shared_worker_nodes_.empty());
- DCHECK(!shared_worker_service_observer_.IsObservingSources());
+ DCHECK(!shared_worker_service_observation_.IsObserving());
DCHECK(service_worker_nodes_.empty());
- DCHECK(!service_worker_context_observer_.IsObservingSources());
+ DCHECK(!service_worker_context_observation_.IsObserving());
}
void WorkerWatcher::TearDown() {
@@ -200,9 +201,9 @@ void WorkerWatcher::TearDown() {
PerformanceManagerImpl::BatchDeleteNodes(std::move(nodes));
- dedicated_worker_service_observer_.RemoveAll();
- shared_worker_service_observer_.RemoveAll();
- service_worker_context_observer_.RemoveAll();
+ dedicated_worker_service_observation_.RemoveObservation();
+ shared_worker_service_observation_.RemoveObservation();
+ service_worker_context_observation_.RemoveObservation();
}
void WorkerWatcher::OnWorkerCreated(
@@ -356,19 +357,129 @@ void WorkerWatcher::OnControlleeAdded(
int64_t version_id,
const std::string& client_uuid,
const content::ServiceWorkerClientInfo& client_info) {
- // TODO(pmonette): Handle service worker clients.
+ if (!base::FeatureList::IsEnabled(
+ features::kServiceWorkerRelationshipsInGraph))
+ return;
+
+ switch (client_info.type()) {
+ case blink::mojom::ServiceWorkerClientType::kWindow: {
+ // For window clients, it is necessary to wait until the navigation has
+ // committed to a render frame host.
+ bool inserted = client_frames_awaiting_commit_.insert(client_uuid).second;
+ DCHECK(inserted);
+ break;
+ }
+ case blink::mojom::ServiceWorkerClientType::kDedicatedWorker: {
+ blink::DedicatedWorkerToken dedicated_worker_token =
+ client_info.GetDedicatedWorkerToken();
+
+ bool inserted = service_worker_clients_[version_id]
+ .emplace(client_uuid, dedicated_worker_token)
+ .second;
+ DCHECK(inserted);
+
+ // If the service worker is already started, connect it to the client.
+ WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
+ if (service_worker_node)
+ ConnectDedicatedWorkerClient(service_worker_node,
+ dedicated_worker_token);
+ break;
+ }
+ case blink::mojom::ServiceWorkerClientType::kSharedWorker: {
+ blink::SharedWorkerToken shared_worker_token =
+ client_info.GetSharedWorkerToken();
+
+ bool inserted = service_worker_clients_[version_id]
+ .emplace(client_uuid, shared_worker_token)
+ .second;
+ DCHECK(inserted);
+
+ // If the service worker is already started, connect it to the client.
+ WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
+ if (service_worker_node)
+ ConnectSharedWorkerClient(service_worker_node, shared_worker_token);
+ break;
+ }
+ case blink::mojom::ServiceWorkerClientType::kAll:
+ NOTREACHED();
+ break;
+ }
}
void WorkerWatcher::OnControlleeRemoved(int64_t version_id,
const std::string& client_uuid) {
- // TODO(pmonette): Handle service worker clients.
+ if (!base::FeatureList::IsEnabled(
+ features::kServiceWorkerRelationshipsInGraph))
+ return;
+
+ // Nothing to do for a frame client whose navigation never committed.
+ size_t removed = client_frames_awaiting_commit_.erase(client_uuid);
+ if (removed) {
+#if DCHECK_IS_ON()
+ // |client_uuid| should not be part of this service worker's clients.
+ auto it = service_worker_clients_.find(version_id);
+ if (it != service_worker_clients_.end())
+ DCHECK(!base::Contains(it->second, client_uuid));
+#endif // DCHECK_IS_ON()
+ return;
+ }
+
+ // First get clients for this worker.
+ auto it = service_worker_clients_.find(version_id);
+ DCHECK(it != service_worker_clients_.end());
+
+ base::flat_map<std::string /*client_uuid*/, ServiceWorkerClient>& clients =
+ it->second;
+
+ auto it2 = clients.find(client_uuid);
+ DCHECK(it2 != clients.end());
+ const ServiceWorkerClient client = it2->second;
+ clients.erase(it2);
+
+ if (clients.empty())
+ service_worker_clients_.erase(it);
+
+ // Now disconnect the client if the service worker is still running.
+ WorkerNodeImpl* worker_node = GetServiceWorkerNode(version_id);
+ if (!worker_node)
+ return;
+
+ switch (client.type()) {
+ case blink::mojom::ServiceWorkerClientType::kWindow:
+ DisconnectFrameClient(worker_node, client.GetRenderFrameHostId());
+ break;
+ case blink::mojom::ServiceWorkerClientType::kDedicatedWorker:
+ DisconnectDedicatedWorkerClient(worker_node,
+ client.GetDedicatedWorkerToken());
+ break;
+ case blink::mojom::ServiceWorkerClientType::kSharedWorker:
+ DisconnectSharedWorkerClient(worker_node, client.GetSharedWorkerToken());
+ break;
+ case blink::mojom::ServiceWorkerClientType::kAll:
+ NOTREACHED();
+ break;
+ }
}
void WorkerWatcher::OnControlleeNavigationCommitted(
int64_t version_id,
const std::string& client_uuid,
content::GlobalFrameRoutingId render_frame_host_id) {
- // TODO(pmonette): Handle service worker clients.
+ if (!base::FeatureList::IsEnabled(
+ features::kServiceWorkerRelationshipsInGraph))
+ return;
+
+ size_t removed = client_frames_awaiting_commit_.erase(client_uuid);
+ DCHECK_EQ(removed, 1u);
+
+ bool inserted = service_worker_clients_[version_id]
+ .emplace(client_uuid, render_frame_host_id)
+ .second;
+ DCHECK(inserted);
+
+ WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
+ if (service_worker_node)
+ ConnectFrameClient(service_worker_node, render_frame_host_id);
}
void WorkerWatcher::ConnectFrameClient(
@@ -394,7 +505,7 @@ void WorkerWatcher::ConnectFrameClient(
RecordWorkerClientFound(true);
- ConnectClientOnGraph(worker_node, frame_node);
+ ConnectClientFrameOnGraph(worker_node, frame_node);
// Keep track of the workers that this frame is a client to.
if (AddChildWorker(client_render_frame_host_id, worker_node)) {
@@ -439,7 +550,7 @@ void WorkerWatcher::DisconnectFrameClient(
return;
}
- DisconnectClientOnGraph(worker_node, frame_node);
+ DisconnectClientFrameOnGraph(worker_node, frame_node);
// Remove |worker_node| from the set of workers that this frame is a client
// of.
@@ -452,8 +563,8 @@ void WorkerWatcher::ConnectDedicatedWorkerClient(
blink::DedicatedWorkerToken client_dedicated_worker_token) {
DCHECK(worker_node);
- ConnectClientOnGraph(worker_node,
- GetDedicatedWorkerNode(client_dedicated_worker_token));
+ ConnectClientWorkerOnGraph(
+ worker_node, GetDedicatedWorkerNode(client_dedicated_worker_token));
// Remember that |worker_node| is a child worker of this dedicated worker.
bool inserted = dedicated_worker_child_workers_[client_dedicated_worker_token]
@@ -479,7 +590,7 @@ void WorkerWatcher::DisconnectDedicatedWorkerClient(
if (child_workers.empty())
dedicated_worker_child_workers_.erase(it);
- DisconnectClientOnGraph(
+ DisconnectClientWorkerOnGraph(
worker_node, GetDedicatedWorkerNode(client_dedicated_worker_token));
}
@@ -488,8 +599,8 @@ void WorkerWatcher::ConnectSharedWorkerClient(
blink::SharedWorkerToken client_shared_worker_token) {
DCHECK(worker_node);
- ConnectClientOnGraph(worker_node,
- GetSharedWorkerNode(client_shared_worker_token));
+ ConnectClientWorkerOnGraph(worker_node,
+ GetSharedWorkerNode(client_shared_worker_token));
// Remember that |worker_node| is a child worker of this shared worker.
bool inserted = shared_worker_child_workers_[client_shared_worker_token]
@@ -514,8 +625,8 @@ void WorkerWatcher::DisconnectSharedWorkerClient(
if (child_workers.empty())
shared_worker_child_workers_.erase(it);
- DisconnectClientOnGraph(worker_node,
- GetSharedWorkerNode(client_shared_worker_token));
+ DisconnectClientWorkerOnGraph(
+ worker_node, GetSharedWorkerNode(client_shared_worker_token));
}
void WorkerWatcher::ConnectAllServiceWorkerClients(
diff --git a/chromium/components/performance_manager/worker_watcher.h b/chromium/components/performance_manager/worker_watcher.h
index 7f694244d63..78239b0c219 100644
--- a/chromium/components/performance_manager/worker_watcher.h
+++ b/chromium/components/performance_manager/worker_watcher.h
@@ -12,7 +12,7 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/sequence_checker.h"
#include "components/performance_manager/service_worker_client.h"
#include "content/public/browser/dedicated_worker_service.h"
@@ -177,18 +177,18 @@ class WorkerWatcher : public content::DedicatedWorkerService::Observer,
const std::string browser_context_id_;
// Observes the DedicatedWorkerService for this browser context.
- ScopedObserver<content::DedicatedWorkerService,
- content::DedicatedWorkerService::Observer>
- dedicated_worker_service_observer_{this};
+ base::ScopedObservation<content::DedicatedWorkerService,
+ content::DedicatedWorkerService::Observer>
+ dedicated_worker_service_observation_{this};
// Observes the SharedWorkerService for this browser context.
- ScopedObserver<content::SharedWorkerService,
- content::SharedWorkerService::Observer>
- shared_worker_service_observer_{this};
+ base::ScopedObservation<content::SharedWorkerService,
+ content::SharedWorkerService::Observer>
+ shared_worker_service_observation_{this};
- ScopedObserver<content::ServiceWorkerContext,
- content::ServiceWorkerContextObserver>
- service_worker_context_observer_{this};
+ base::ScopedObservation<content::ServiceWorkerContext,
+ content::ServiceWorkerContextObserver>
+ service_worker_context_observation_{this};
// Used to retrieve an existing process node from its render process ID.
ProcessNodeSource* const process_node_source_;
diff --git a/chromium/components/performance_manager/worker_watcher_unittest.cc b/chromium/components/performance_manager/worker_watcher_unittest.cc
index 24b15d25770..caaee22d3b8 100644
--- a/chromium/components/performance_manager/worker_watcher_unittest.cc
+++ b/chromium/components/performance_manager/worker_watcher_unittest.cc
@@ -8,14 +8,15 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/performance_manager/frame_node_source.h"
#include "components/performance_manager/graph/frame_node_impl.h"
@@ -24,6 +25,7 @@
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/process_node_source.h"
+#include "components/performance_manager/public/features.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/shared_worker_service.h"
#include "content/public/test/fake_service_worker_context.h"
@@ -160,6 +162,7 @@ class TestSharedWorkerService : public content::SharedWorkerService {
bool TerminateWorker(const GURL& url,
const std::string& name,
const url::Origin& constructor_origin) override;
+ void Shutdown() override;
// Creates a new shared worker and returns its token.
blink::SharedWorkerToken CreateSharedWorker(int worker_process_id);
@@ -212,6 +215,11 @@ bool TestSharedWorkerService::TerminateWorker(
return false;
}
+void TestSharedWorkerService::Shutdown() {
+ // Not implemented.
+ ADD_FAILURE();
+}
+
blink::SharedWorkerToken TestSharedWorkerService::CreateSharedWorker(
int worker_process_id) {
// Create a new SharedWorkerToken for the worker and add it to the map.
@@ -306,7 +314,7 @@ class TestServiceWorkerContext : public content::FakeServiceWorkerContext {
// Starts an existing service worker.
void StartServiceWorker(int64_t version_id, int worker_process_id);
- // Destroys a service shared worker.
+ // Stops a service shared worker.
void StopServiceWorker(int64_t version_id);
// Adds a new client to an existing service worker and returns its generated
@@ -685,6 +693,10 @@ class WorkerWatcherTest : public testing::Test {
TestFrameNodeSource* frame_node_source() { return frame_node_source_.get(); }
+ protected:
+ // Test the frame destroyed case with or without service worker relationship
+ void TestFrameDestroyed(bool enable_service_worker_relationships);
+
private:
base::test::TaskEnvironment task_environment_;
@@ -826,10 +838,11 @@ TEST_F(WorkerWatcherTest, SimpleSharedWorker) {
}
// This test creates one service worker with one client frame.
-//
-// TODO(pmonette): Enable this test when the WorkerWatcher starts tracking
-// service worker clients.
-TEST_F(WorkerWatcherTest, DISABLED_ServiceWorkerFrameClient) {
+TEST_F(WorkerWatcherTest, ServiceWorkerFrameClient) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kServiceWorkerRelationshipsInGraph);
+
int render_process_id = process_node_source()->CreateProcessNode();
// Create and start the service worker.
@@ -877,8 +890,6 @@ TEST_F(WorkerWatcherTest, DISABLED_ServiceWorkerFrameClient) {
EXPECT_TRUE(graph->NodeInGraph(worker_node));
EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kService);
EXPECT_EQ(worker_node->process_node(), process_node);
-
- // Now is it correctly hooked up.
EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node));
}));
@@ -927,9 +938,11 @@ TEST_F(WorkerWatcherTest, ServiceWorkerFrameClientDestroyedBeforeCommit) {
service_worker_context()->DestroyServiceWorker(service_worker_version_id);
}
-// TODO(pmonette): Enable this test when the WorkerWatcher starts tracking
-// service worker clients.
-TEST_F(WorkerWatcherTest, DISABLED_AllTypesOfServiceWorkerClients) {
+TEST_F(WorkerWatcherTest, AllTypesOfServiceWorkerClients) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kServiceWorkerRelationshipsInGraph);
+
int render_process_id = process_node_source()->CreateProcessNode();
// Create and start the service worker.
@@ -1001,11 +1014,11 @@ TEST_F(WorkerWatcherTest, DISABLED_AllTypesOfServiceWorkerClients) {
// starts after it has been assigned a client. In this case, the clients are not
// connected to the service worker until it starts. It also tests that when the
// service worker stops, its existing clients are also disconnected.
-//
-// TODO(pmonette): Enable this test when the WorkerWatcher starts tracking
-// service worker clients.
-TEST_F(WorkerWatcherTest,
- DISABLED_ServiceWorkerStartsAndStopsWithExistingClients) {
+TEST_F(WorkerWatcherTest, ServiceWorkerStartsAndStopsWithExistingClients) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kServiceWorkerRelationshipsInGraph);
+
int render_process_id = process_node_source()->CreateProcessNode();
// Create the worker.
@@ -1265,7 +1278,16 @@ TEST_F(WorkerWatcherTest, OneClientTwoSharedWorkers) {
shared_worker_service()->DestroySharedWorker(shared_worker_token_2);
}
-TEST_F(WorkerWatcherTest, FrameDestroyed) {
+void WorkerWatcherTest::TestFrameDestroyed(
+ bool enable_service_worker_relationships) {
+ base::test::ScopedFeatureList feature_list;
+ if (enable_service_worker_relationships) {
+ feature_list.InitAndEnableFeature(
+ features::kServiceWorkerRelationshipsInGraph);
+ } else {
+ feature_list.Init();
+ }
+
int render_process_id = process_node_source()->CreateProcessNode();
// Create the frame node.
@@ -1298,7 +1320,8 @@ TEST_F(WorkerWatcherTest, FrameDestroyed) {
// Check that everything is wired up correctly.
CallOnGraphAndWait(base::BindLambdaForTesting(
- [dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
+ [&enable_service_worker_relationships,
+ dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
shared_worker_node = GetSharedWorkerNode(shared_worker_token),
service_worker_node = GetServiceWorkerNode(service_worker_version_id),
client_frame_node = frame_node_source()->GetFrameNode(
@@ -1308,9 +1331,9 @@ TEST_F(WorkerWatcherTest, FrameDestroyed) {
EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
EXPECT_TRUE(IsWorkerClient(dedicated_worker_node, client_frame_node));
EXPECT_TRUE(IsWorkerClient(shared_worker_node, client_frame_node));
- // TODO(pmonette): Change this to EXPECT_TRUE() when the WorkerWatcher
- // starts tracking service worker clients.
- EXPECT_FALSE(IsWorkerClient(service_worker_node, client_frame_node));
+
+ EXPECT_EQ(enable_service_worker_relationships,
+ IsWorkerClient(service_worker_node, client_frame_node));
}));
frame_node_source()->DeleteFrameNode(render_frame_host_id);
@@ -1340,4 +1363,12 @@ TEST_F(WorkerWatcherTest, FrameDestroyed) {
dedicated_worker_service()->DestroyDedicatedWorker(dedicated_worker_token);
}
+TEST_F(WorkerWatcherTest, FrameDestroyed) {
+ TestFrameDestroyed(false);
+}
+
+TEST_F(WorkerWatcherTest, FrameDestroyedWithServiceWorkerRelationships) {
+ TestFrameDestroyed(true);
+}
+
} // namespace performance_manager
diff --git a/chromium/components/permissions/BUILD.gn b/chromium/components/permissions/BUILD.gn
index ea4ac976394..0abcfea9126 100644
--- a/chromium/components/permissions/BUILD.gn
+++ b/chromium/components/permissions/BUILD.gn
@@ -2,6 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+source_set("permissions_common") {
+ sources = [
+ "features.cc",
+ "features.h",
+ "permission_request_enums.h",
+ ]
+ deps = [ "//base" ]
+}
+
source_set("permissions") {
sources = [
"chooser_context_base.cc",
@@ -12,8 +21,6 @@ source_set("permissions") {
"contexts/geolocation_permission_context.h",
"contexts/webxr_permission_context.cc",
"contexts/webxr_permission_context.h",
- "features.cc",
- "features.h",
"notification_permission_ui_selector.cc",
"notification_permission_ui_selector.h",
"permission_context_base.cc",
@@ -52,6 +59,7 @@ source_set("permissions") {
"//components/content_settings/browser",
"//components/content_settings/core/browser",
"//components/keyed_service/content",
+ "//components/permissions/prediction_service",
"//components/strings:components_strings_grit",
"//components/ukm/content",
"//components/url_formatter",
@@ -86,6 +94,7 @@ source_set("permissions") {
} else {
sources += [ "permission_prompt_impl.cc" ]
}
+ public_deps = [ ":permissions_common" ]
}
source_set("test_support") {
diff --git a/chromium/components/permissions/android/BUILD.gn b/chromium/components/permissions/android/BUILD.gn
index 35d56e6c047..5b246167734 100644
--- a/chromium/components/permissions/android/BUILD.gn
+++ b/chromium/components/permissions/android/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/config/android/rules.gni")
import("//build/config/locales.gni")
+import("//tools/grit/grit_rule.gni")
generate_jni("jni_headers") {
sources = [
diff --git a/chromium/components/permissions/android/permission_prompt_android.cc b/chromium/components/permissions/android/permission_prompt_android.cc
index 2bacb242912..a484cb79252 100644
--- a/chromium/components/permissions/android/permission_prompt_android.cc
+++ b/chromium/components/permissions/android/permission_prompt_android.cc
@@ -131,7 +131,6 @@ static bool IsValidARCameraAccessRequestGroup(
static void CheckValidRequestGroup(
const std::vector<permissions::PermissionRequest*>& requests) {
DCHECK_EQ(static_cast<size_t>(2u), requests.size());
- DCHECK_EQ(requests[0]->GetOrigin(), requests[1]->GetOrigin());
DCHECK((IsValidMediaRequestGroup(requests)) ||
(IsValidARCameraAccessRequestGroup(requests)));
}
@@ -154,7 +153,7 @@ base::string16 PermissionPromptAndroid::GetMessageText() const {
return l10n_util::GetStringFUTF16(
IDS_STORAGE_ACCESS_INFOBAR_TEXT,
url_formatter::FormatUrlForSecurityDisplay(
- requests[0]->GetOrigin(),
+ delegate_->GetRequestingOrigin(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC),
url_formatter::FormatUrlForSecurityDisplay(
delegate_->GetEmbeddingOrigin(),
@@ -168,13 +167,13 @@ base::string16 PermissionPromptAndroid::GetMessageText() const {
return l10n_util::GetStringFUTF16(
IDS_AR_AND_MEDIA_CAPTURE_VIDEO_INFOBAR_TEXT,
url_formatter::FormatUrlForSecurityDisplay(
- requests[0]->GetOrigin(),
+ delegate_->GetRequestingOrigin(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
} else {
return l10n_util::GetStringFUTF16(
IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_INFOBAR_TEXT,
url_formatter::FormatUrlForSecurityDisplay(
- requests[0]->GetOrigin(),
+ delegate_->GetRequestingOrigin(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
}
}
diff --git a/chromium/components/permissions/android/permission_prompt_android.h b/chromium/components/permissions/android/permission_prompt_android.h
index a2069f2223e..8982a0f8f16 100644
--- a/chromium/components/permissions/android/permission_prompt_android.h
+++ b/chromium/components/permissions/android/permission_prompt_android.h
@@ -58,9 +58,9 @@ class PermissionPromptAndroid : public permissions::PermissionPrompt,
// PermissionPromptAndroid is owned by PermissionRequestManager, so it should
// be safe to hold a raw WebContents pointer here because this class is
// destroyed before the WebContents.
- content::WebContents* web_contents_;
+ content::WebContents* const web_contents_;
// |delegate_| is the PermissionRequestManager, which owns this object.
- Delegate* delegate_;
+ Delegate* const delegate_;
// The infobar used to display the permission request, if displayed in that
// format. Never assume that this pointer is currently alive.
diff --git a/chromium/components/permissions/chooser_context_base.cc b/chromium/components/permissions/chooser_context_base.cc
index 5be013f2d77..ff050c7f811 100644
--- a/chromium/components/permissions/chooser_context_base.cc
+++ b/chromium/components/permissions/chooser_context_base.cc
@@ -62,7 +62,7 @@ bool ChooserContextBase::CanRequestObjectPermission(
ContentSetting content_setting =
host_content_settings_map_->GetContentSetting(
requesting_origin.GetURL(), embedding_origin.GetURL(),
- guard_content_settings_type_, std::string());
+ guard_content_settings_type_);
DCHECK(content_setting == CONTENT_SETTING_ASK ||
content_setting == CONTENT_SETTING_BLOCK);
return content_setting == CONTENT_SETTING_ASK;
@@ -96,8 +96,8 @@ ChooserContextBase::GetGrantedObjects(const url::Origin& requesting_origin,
std::vector<std::unique_ptr<ChooserContextBase::Object>>
ChooserContextBase::GetAllGrantedObjects() {
ContentSettingsForOneType content_settings;
- host_content_settings_map_->GetSettingsForOneType(
- data_content_settings_type_, std::string(), &content_settings);
+ host_content_settings_map_->GetSettingsForOneType(data_content_settings_type_,
+ &content_settings);
std::vector<std::unique_ptr<Object>> results;
for (const ContentSettingPatternSource& content_setting : content_settings) {
@@ -223,7 +223,7 @@ base::Value ChooserContextBase::GetWebsiteSetting(
std::unique_ptr<base::Value> value =
host_content_settings_map_->GetWebsiteSetting(
requesting_origin.GetURL(), embedding_origin.GetURL(),
- data_content_settings_type_, std::string(), info);
+ data_content_settings_type_, info);
if (value)
return base::Value::FromUniquePtrValue(std::move(value));
return base::Value(base::Value::Type::DICTIONARY);
@@ -234,7 +234,7 @@ void ChooserContextBase::SetWebsiteSetting(const url::Origin& requesting_origin,
base::Value value) {
host_content_settings_map_->SetWebsiteSettingDefaultScope(
requesting_origin.GetURL(), embedding_origin.GetURL(),
- data_content_settings_type_, std::string(),
+ data_content_settings_type_,
base::Value::ToUniquePtrValue(std::move(value)));
}
diff --git a/chromium/components/permissions/chooser_context_base_unittest.cc b/chromium/components/permissions/chooser_context_base_unittest.cc
index 561bfe8b67f..5a95c827e53 100644
--- a/chromium/components/permissions/chooser_context_base_unittest.cc
+++ b/chromium/components/permissions/chooser_context_base_unittest.cc
@@ -235,9 +235,8 @@ TEST_F(ChooserContextBaseTest, GetAllGrantedObjects) {
TEST_F(ChooserContextBaseTest, GetGrantedObjectsWithGuardBlocked) {
auto* map = PermissionsClient::Get()->GetSettingsMap(browser_context());
- map->SetContentSettingDefaultScope(url1_, url1_,
- ContentSettingsType::USB_GUARD,
- std::string(), CONTENT_SETTING_BLOCK);
+ map->SetContentSettingDefaultScope(
+ url1_, url1_, ContentSettingsType::USB_GUARD, CONTENT_SETTING_BLOCK);
TestChooserContext context(browser_context());
MockPermissionObserver mock_observer;
@@ -259,9 +258,8 @@ TEST_F(ChooserContextBaseTest, GetGrantedObjectsWithGuardBlocked) {
TEST_F(ChooserContextBaseTest, GetAllGrantedObjectsWithGuardBlocked) {
auto* map = PermissionsClient::Get()->GetSettingsMap(browser_context());
- map->SetContentSettingDefaultScope(url1_, url1_,
- ContentSettingsType::USB_GUARD,
- std::string(), CONTENT_SETTING_BLOCK);
+ map->SetContentSettingDefaultScope(
+ url1_, url1_, ContentSettingsType::USB_GUARD, CONTENT_SETTING_BLOCK);
TestChooserContext context(browser_context());
MockPermissionObserver mock_observer;
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context_android.cc b/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
index b517320ac7b..ea87538ef03 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
+++ b/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
@@ -102,8 +102,8 @@ void GeolocationPermissionContextAndroid::RequestPermission(
user_gesture)) {
NotifyPermissionSet(id, requesting_frame_origin,
web_contents->GetLastCommittedURL().GetOrigin(),
- std::move(callback), false /* persist */,
- CONTENT_SETTING_BLOCK);
+ std::move(callback), /*persist=*/false,
+ CONTENT_SETTING_BLOCK, /*is_one_time=*/false);
return;
}
@@ -148,7 +148,9 @@ void GeolocationPermissionContextAndroid::NotifyPermissionSet(
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting) {
+ ContentSetting content_setting,
+ bool is_one_time) {
+ DCHECK(!is_one_time);
bool is_default_search = IsRequestingOriginDSE(requesting_origin);
if (content_setting == CONTENT_SETTING_ALLOW &&
!location_settings_->IsSystemLocationSettingEnabled()) {
@@ -350,7 +352,8 @@ void GeolocationPermissionContextAndroid::HandleUpdateAndroidPermissions(
permissions_updated ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
NotifyPermissionSet(id, requesting_frame_origin, embedding_origin,
- std::move(callback), false /* persist */, new_setting);
+ std::move(callback), false /* persist */, new_setting,
+ /*is_one_time=*/false);
}
bool GeolocationPermissionContextAndroid::CanShowLocationSettingsDialog(
@@ -415,7 +418,7 @@ void GeolocationPermissionContextAndroid::FinishNotifyPermissionSet(
ContentSetting content_setting) {
GeolocationPermissionContext::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback), persist,
- content_setting);
+ content_setting, /*is_one_time=*/false);
delegate_->FinishNotifyPermissionSet(id, requesting_origin, embedding_origin);
}
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context_android.h b/chromium/components/permissions/contexts/geolocation_permission_context_android.h
index 0ae248d6b90..5b18bfa9241 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context_android.h
+++ b/chromium/components/permissions/contexts/geolocation_permission_context_android.h
@@ -82,7 +82,8 @@ class GeolocationPermissionContextAndroid
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting) override;
+ ContentSetting content_setting,
+ bool is_one_time) override;
PermissionResult UpdatePermissionStatusWithDeviceStatus(
PermissionResult result,
const GURL& requesting_origin,
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc b/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
index cee008ebec4..cfef160254b 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
+++ b/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
@@ -14,7 +14,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/containers/id_map.h"
#include "base/gtest_prod_util.h"
@@ -23,7 +23,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/time/clock.h"
#include "build/build_config.h"
@@ -366,8 +365,7 @@ ContentSetting GeolocationPermissionContextTests::GetGeolocationContentSetting(
GURL frame_1) {
return PermissionsClient::Get()
->GetSettingsMap(browser_context())
- ->GetContentSetting(frame_0, frame_1, ContentSettingsType::GEOLOCATION,
- std::string());
+ ->GetContentSetting(frame_0, frame_1, ContentSettingsType::GEOLOCATION);
}
void GeolocationPermissionContextTests::SetGeolocationContentSetting(
@@ -376,9 +374,8 @@ void GeolocationPermissionContextTests::SetGeolocationContentSetting(
ContentSetting content_setting) {
return PermissionsClient::Get()
->GetSettingsMap(browser_context())
- ->SetContentSettingDefaultScope(frame_0, frame_1,
- ContentSettingsType::GEOLOCATION,
- std::string(), content_setting);
+ ->SetContentSettingDefaultScope(
+ frame_0, frame_1, ContentSettingsType::GEOLOCATION, content_setting);
}
bool GeolocationPermissionContextTests::HasActivePrompt() {
diff --git a/chromium/components/permissions/contexts/webxr_permission_context.cc b/chromium/components/permissions/contexts/webxr_permission_context.cc
index 82227fa9f66..83183289aa5 100644
--- a/chromium/components/permissions/contexts/webxr_permission_context.cc
+++ b/chromium/components/permissions/contexts/webxr_permission_context.cc
@@ -49,14 +49,16 @@ void WebXrPermissionContext::NotifyPermissionSet(
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting) {
+ ContentSetting content_setting,
+ bool is_one_time) {
+ DCHECK(!is_one_time);
// Only AR needs to check for additional permissions, and then only if it was
// actually allowed.
if (!(content_settings_type_ == ContentSettingsType::AR &&
content_setting == ContentSetting::CONTENT_SETTING_ALLOW)) {
PermissionContextBase::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback), persist,
- content_setting);
+ content_setting, is_one_time);
return;
}
@@ -64,7 +66,7 @@ void WebXrPermissionContext::NotifyPermissionSet(
// to save the content_setting here if we should.
if (persist) {
PermissionContextBase::UpdateContentSetting(
- requesting_origin, embedding_origin, content_setting);
+ requesting_origin, embedding_origin, content_setting, is_one_time);
}
content::WebContents* web_contents =
@@ -130,7 +132,7 @@ void WebXrPermissionContext::OnAndroidPermissionDecided(
: ContentSetting::CONTENT_SETTING_BLOCK;
PermissionContextBase::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback),
- false /*persist*/, setting);
+ false /*persist*/, setting, /*is_one_time=*/false);
}
#endif // defined(OS_ANDROID)
} // namespace permissions
diff --git a/chromium/components/permissions/contexts/webxr_permission_context.h b/chromium/components/permissions/contexts/webxr_permission_context.h
index 467a6404413..e3cb765ab40 100644
--- a/chromium/components/permissions/contexts/webxr_permission_context.h
+++ b/chromium/components/permissions/contexts/webxr_permission_context.h
@@ -38,7 +38,8 @@ class WebXrPermissionContext : public PermissionContextBase {
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting) override;
+ ContentSetting content_setting,
+ bool is_one_time) override;
void OnAndroidPermissionDecided(const PermissionRequestID& id,
const GURL& requesting_origin,
diff --git a/chromium/components/permissions/features.cc b/chromium/components/permissions/features.cc
index 8f97d358974..1544d9d638c 100644
--- a/chromium/components/permissions/features.cc
+++ b/chromium/components/permissions/features.cc
@@ -24,5 +24,31 @@ const base::Feature kBlockRepeatedNotificationPermissionPrompts{
"BlockRepeatedNotificationPermissionPrompts",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kOneTimeGeolocationPermission{
+ "OneTimeGeolocationPermission", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables an experimental permission prompt that uses a chip in the location
+// bar.
+const base::Feature kPermissionChip{"PermissionChip",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled, use the value of the `service_url` FeatureParam as the url
+// for the Web Permission Predictions Service.
+const base::Feature kPermissionPredictionServiceUseUrlOverride{
+ "kPermissionPredictionServiceUseUrlOverride",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
+namespace feature_params {
+
+const base::FeatureParam<bool> kOkButtonBehavesAsAllowAlways(
+ &permissions::features::kOneTimeGeolocationPermission,
+ "OkButtonBehavesAsAllowAlways",
+ true);
+
+const base::FeatureParam<std::string> kPermissionPredictionServiceUrlOverride{
+ &permissions::features::kPermissionPredictionServiceUseUrlOverride,
+ "service_url", ""};
+
+} // namespace feature_params
} // namespace permissions
diff --git a/chromium/components/permissions/features.h b/chromium/components/permissions/features.h
index 0109b08a219..b872fdafe54 100644
--- a/chromium/components/permissions/features.h
+++ b/chromium/components/permissions/features.h
@@ -13,8 +13,18 @@ namespace features {
extern const base::Feature kBlockPromptsIfDismissedOften;
extern const base::Feature kBlockPromptsIfIgnoredOften;
extern const base::Feature kBlockRepeatedNotificationPermissionPrompts;
+extern const base::Feature kOneTimeGeolocationPermission;
+extern const base::Feature kPermissionChip;
+extern const base::Feature kPermissionPredictionServiceUseUrlOverride;
} // namespace features
+namespace feature_params {
+
+extern const base::FeatureParam<bool> kOkButtonBehavesAsAllowAlways;
+extern const base::FeatureParam<std::string>
+ kPermissionPredictionServiceUrlOverride;
+
+} // namespace feature_params
} // namespace permissions
#endif // COMPONENTS_PERMISSIONS_FEATURES_H_
diff --git a/chromium/components/permissions/notification_permission_ui_selector.cc b/chromium/components/permissions/notification_permission_ui_selector.cc
index 52610013781..226b7e6cb4a 100644
--- a/chromium/components/permissions/notification_permission_ui_selector.cc
+++ b/chromium/components/permissions/notification_permission_ui_selector.cc
@@ -11,6 +11,7 @@ bool NotificationPermissionUiSelector::ShouldSuppressAnimation(
QuietUiReason reason) {
switch (reason) {
case QuietUiReason::kEnabledInPrefs:
+ case QuietUiReason::kPredictedVeryUnlikelyGrant:
return false;
case QuietUiReason::kTriggeredByCrowdDeny:
case QuietUiReason::kTriggeredDueToAbusiveRequests:
@@ -36,4 +37,9 @@ NotificationPermissionUiSelector::Decision::UseNormalUiAndShowNoWarning() {
return Decision(UseNormalUi(), ShowNoWarning());
}
+base::Optional<PermissionUmaUtil::PredictionGrantLikelihood>
+NotificationPermissionUiSelector::PredictedGrantLikelihoodForUKM() {
+ return base::nullopt;
+}
+
} // namespace permissions
diff --git a/chromium/components/permissions/notification_permission_ui_selector.h b/chromium/components/permissions/notification_permission_ui_selector.h
index 91e62fbb774..c2dca79fb62 100644
--- a/chromium/components/permissions/notification_permission_ui_selector.h
+++ b/chromium/components/permissions/notification_permission_ui_selector.h
@@ -8,6 +8,7 @@
#include "base/callback_forward.h"
#include "base/optional.h"
#include "components/permissions/permission_request.h"
+#include "components/permissions/permission_uma_util.h"
namespace permissions {
@@ -24,6 +25,7 @@ class NotificationPermissionUiSelector {
kTriggeredByCrowdDeny,
kTriggeredDueToAbusiveRequests,
kTriggeredDueToAbusiveContent,
+ kPredictedVeryUnlikelyGrant,
};
enum class WarningReason {
@@ -75,8 +77,15 @@ class NotificationPermissionUiSelector {
// Cancel the pending request, if any. After this, the |callback| is
// guaranteed not to be invoked anymore, and another call to SelectUiToUse()
- // can be issued.
+ // can be issued. Can be called when there is no pending request which will
+ // simply be a no-op.
virtual void Cancel() {}
+
+ // Will return the selector's discretized prediction value, if any is
+ // applicable to be recorded in UKMs. This is specific only to a selector that
+ // makes use of the Web Permission Predictions Service to make decisions.
+ virtual base::Optional<PermissionUmaUtil::PredictionGrantLikelihood>
+ PredictedGrantLikelihoodForUKM();
};
} // namespace permissions
diff --git a/chromium/components/permissions/permission_context_base.cc b/chromium/components/permissions/permission_context_base.cc
index ed1521d781a..3d05e5b592f 100644
--- a/chromium/components/permissions/permission_context_base.cc
+++ b/chromium/components/permissions/permission_context_base.cc
@@ -131,8 +131,8 @@ void PermissionContextBase::RequestPermission(
<< embedding_origin << " (" << type_name
<< " is not supported in popups)";
NotifyPermissionSet(id, requesting_origin, embedding_origin,
- std::move(callback), false /* persist */,
- CONTENT_SETTING_BLOCK);
+ std::move(callback), /*persist=*/false,
+ CONTENT_SETTING_BLOCK, /*is_one_time=*/false);
return;
}
@@ -183,8 +183,8 @@ void PermissionContextBase::RequestPermission(
// suppressed the prompt.
PermissionUmaUtil::RecordEmbargoPromptSuppressionFromSource(result.source);
NotifyPermissionSet(id, requesting_origin, embedding_origin,
- std::move(callback), false /* persist */,
- result.content_setting);
+ std::move(callback), /*persist=*/false,
+ result.content_setting, /*is_one_time=*/false);
return;
}
@@ -321,7 +321,7 @@ void PermissionContextBase::ResetPermission(const GURL& requesting_origin,
PermissionsClient::Get()
->GetSettingsMap(browser_context_)
->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
- content_settings_type_, std::string(),
+ content_settings_type_,
CONTENT_SETTING_DEFAULT);
}
@@ -340,7 +340,7 @@ ContentSetting PermissionContextBase::GetPermissionStatusInternal(
return PermissionsClient::Get()
->GetSettingsMap(browser_context_)
->GetContentSetting(requesting_origin, embedding_origin,
- content_settings_type_, std::string());
+ content_settings_type_);
}
void PermissionContextBase::DecidePermission(
@@ -401,7 +401,8 @@ void PermissionContextBase::PermissionDecided(
const GURL& requesting_origin,
const GURL& embedding_origin,
BrowserPermissionCallback callback,
- ContentSetting content_setting) {
+ ContentSetting content_setting,
+ bool is_one_time) {
DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
content_setting == CONTENT_SETTING_BLOCK ||
content_setting == CONTENT_SETTING_DEFAULT);
@@ -410,7 +411,8 @@ void PermissionContextBase::PermissionDecided(
bool persist = content_setting != CONTENT_SETTING_DEFAULT;
NotifyPermissionSet(id, requesting_origin, embedding_origin,
- std::move(callback), persist, content_setting);
+ std::move(callback), persist, content_setting,
+ is_one_time);
}
content::BrowserContext* PermissionContextBase::browser_context() const {
@@ -423,11 +425,14 @@ void PermissionContextBase::NotifyPermissionSet(
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting) {
+ ContentSetting content_setting,
+ bool is_one_time) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (persist)
- UpdateContentSetting(requesting_origin, embedding_origin, content_setting);
+ if (persist) {
+ UpdateContentSetting(requesting_origin, embedding_origin, content_setting,
+ is_one_time);
+ }
UpdateTabContext(id, requesting_origin,
content_setting == CONTENT_SETTING_ALLOW);
@@ -443,10 +448,10 @@ void PermissionContextBase::CleanUpRequest(const PermissionRequestID& id) {
DCHECK(success == 1) << "Missing request " << id.ToString();
}
-void PermissionContextBase::UpdateContentSetting(
- const GURL& requesting_origin,
- const GURL& embedding_origin,
- ContentSetting content_setting) {
+void PermissionContextBase::UpdateContentSetting(const GURL& requesting_origin,
+ const GURL& embedding_origin,
+ ContentSetting content_setting,
+ bool is_one_time) {
DCHECK_EQ(requesting_origin, requesting_origin.GetOrigin());
DCHECK_EQ(embedding_origin, embedding_origin.GetOrigin());
DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
@@ -454,11 +459,15 @@ void PermissionContextBase::UpdateContentSetting(
DCHECK(!requesting_origin.SchemeIsFile());
DCHECK(!embedding_origin.SchemeIsFile());
+ using Constraints = content_settings::ContentSettingConstraints;
PermissionsClient::Get()
->GetSettingsMap(browser_context_)
- ->SetContentSettingDefaultScope(requesting_origin, embedding_origin,
- content_settings_type_, std::string(),
- content_setting);
+ ->SetContentSettingDefaultScope(
+ requesting_origin, embedding_origin, content_settings_type_,
+ content_setting,
+ is_one_time ? Constraints{base::Time(),
+ content_settings::SessionModel::OneTime}
+ : Constraints());
}
bool PermissionContextBase::PermissionAllowedByFeaturePolicy(
diff --git a/chromium/components/permissions/permission_context_base.h b/chromium/components/permissions/permission_context_base.h
index 6e05a2b06bb..7769547d11c 100644
--- a/chromium/components/permissions/permission_context_base.h
+++ b/chromium/components/permissions/permission_context_base.h
@@ -133,7 +133,8 @@ class PermissionContextBase : public KeyedService {
const GURL& embedding_origin,
BrowserPermissionCallback callback,
bool persist,
- ContentSetting content_setting);
+ ContentSetting content_setting,
+ bool is_one_time);
// Implementors can override this method to update the icons on the
// url bar with the result of the new permission.
@@ -149,7 +150,8 @@ class PermissionContextBase : public KeyedService {
// (for example for desktop notifications).
virtual void UpdateContentSetting(const GURL& requesting_origin,
const GURL& embedding_origin,
- ContentSetting content_setting);
+ ContentSetting content_setting,
+ bool is_one_time);
// Whether the permission should be restricted to secure origins.
virtual bool IsRestrictedToSecureOrigins() const = 0;
@@ -180,7 +182,8 @@ class PermissionContextBase : public KeyedService {
const GURL& requesting_origin,
const GURL& embedding_origin,
BrowserPermissionCallback callback,
- ContentSetting content_setting);
+ ContentSetting content_setting,
+ bool is_one_time);
content::BrowserContext* browser_context_;
const ContentSettingsType content_settings_type_;
diff --git a/chromium/components/permissions/permission_context_base_unittest.cc b/chromium/components/permissions/permission_context_base_unittest.cc
index e2b9513b1d7..21db013bbfd 100644
--- a/chromium/components/permissions/permission_context_base_unittest.cc
+++ b/chromium/components/permissions/permission_context_base_unittest.cc
@@ -80,7 +80,7 @@ class TestPermissionContext : public PermissionContextBase {
const GURL& url_b) {
auto* map = PermissionsClient::Get()->GetSettingsMap(browser_context());
return map->GetContentSetting(url_a.GetOrigin(), url_b.GetOrigin(),
- content_settings_type(), std::string());
+ content_settings_type());
}
void RequestPermission(content::WebContents* web_contents,
diff --git a/chromium/components/permissions/permission_decision_auto_blocker.cc b/chromium/components/permissions/permission_decision_auto_blocker.cc
index e834e64d019..1b7aa901973 100644
--- a/chromium/components/permissions/permission_decision_auto_blocker.cc
+++ b/chromium/components/permissions/permission_decision_auto_blocker.cc
@@ -59,7 +59,7 @@ std::unique_ptr<base::DictionaryValue> GetOriginAutoBlockerData(
std::unique_ptr<base::DictionaryValue> dict =
base::DictionaryValue::From(settings->GetWebsiteSetting(
origin_url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::string(), nullptr));
+ nullptr));
if (!dict)
return std::make_unique<base::DictionaryValue>();
@@ -93,7 +93,7 @@ int RecordActionInWebsiteSettings(const GURL& url,
settings_map->SetWebsiteSettingDefaultScope(
url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::string(), std::move(dict));
+ std::move(dict));
return current_count;
}
@@ -290,8 +290,7 @@ std::set<GURL> PermissionDecisionAutoBlocker::GetEmbargoedOrigins(
DCHECK(settings_map_);
ContentSettingsForOneType embargo_settings;
settings_map_->GetSettingsForOneType(
- ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, std::string(),
- &embargo_settings);
+ ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, &embargo_settings);
std::set<GURL> origins;
for (const auto& e : embargo_settings) {
for (auto content_type : content_types) {
@@ -407,7 +406,7 @@ void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
settings_map_->SetWebsiteSettingDefaultScope(
url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::string(), std::move(dict));
+ std::move(dict));
}
void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
@@ -415,8 +414,7 @@ void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
std::unique_ptr<ContentSettingsForOneType> settings(
new ContentSettingsForOneType);
settings_map_->GetSettingsForOneType(
- ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, std::string(),
- settings.get());
+ ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA, settings.get());
for (const auto& site : *settings) {
GURL origin(site.primary_pattern.ToString());
@@ -424,7 +422,7 @@ void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
if (origin.is_valid() && filter.Run(origin)) {
settings_map_->SetWebsiteSettingDefaultScope(
origin, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::string(), nullptr);
+ nullptr);
}
}
}
@@ -453,7 +451,7 @@ void PermissionDecisionAutoBlocker::PlaceUnderEmbargo(
key, base::Value(static_cast<double>(clock_->Now().ToInternalValue())));
settings_map_->SetWebsiteSettingDefaultScope(
request_origin, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::string(), std::move(dict));
+ std::move(dict));
}
void PermissionDecisionAutoBlocker::SetClockForTesting(base::Clock* clock) {
diff --git a/chromium/components/permissions/permission_manager.cc b/chromium/components/permissions/permission_manager.cc
index d5ed9f78abb..40a9b5551fe 100644
--- a/chromium/components/permissions/permission_manager.cc
+++ b/chromium/components/permissions/permission_manager.cc
@@ -607,8 +607,7 @@ bool PermissionManager::IsPermissionKillSwitchOn(
void PermissionManager::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::vector<base::OnceClosure> callbacks;
callbacks.reserve(subscriptions_.size());
diff --git a/chromium/components/permissions/permission_manager.h b/chromium/components/permissions/permission_manager.h
index d11fb4b2c4a..47931b9b15e 100644
--- a/chromium/components/permissions/permission_manager.h
+++ b/chromium/components/permissions/permission_manager.h
@@ -170,8 +170,7 @@ class PermissionManager : public KeyedService,
// content_settings::Observer implementation.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
PermissionResult GetPermissionStatusHelper(
ContentSettingsType permission,
diff --git a/chromium/components/permissions/permission_manager_unittest.cc b/chromium/components/permissions/permission_manager_unittest.cc
index 85064839c8f..76d37a5e886 100644
--- a/chromium/components/permissions/permission_manager_unittest.cc
+++ b/chromium/components/permissions/permission_manager_unittest.cc
@@ -8,8 +8,8 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/permissions/features.h"
@@ -161,8 +161,8 @@ class PermissionManagerTest : public content::RenderViewHostTestHarness {
}
void SetPermission(ContentSettingsType type, ContentSetting value) {
- GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url_, url_, type, std::string(), value);
+ GetHostContentSettingsMap()->SetContentSettingDefaultScope(url_, url_, type,
+ value);
}
int RequestPermission(PermissionType type,
@@ -372,8 +372,7 @@ TEST_F(PermissionManagerTest, SameTypeChangeNotifies) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
@@ -390,8 +389,7 @@ TEST_F(PermissionManagerTest, DifferentTypeChangeDoesNotNotify) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), GURL(), ContentSettingsType::NOTIFICATIONS, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), GURL(), ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW);
EXPECT_FALSE(callback_called());
@@ -410,8 +408,7 @@ TEST_F(PermissionManagerTest, ChangeAfterUnsubscribeDoesNotNotify) {
subscription_id);
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
EXPECT_FALSE(callback_called());
}
@@ -424,7 +421,7 @@ TEST_F(PermissionManagerTest, DifferentPrimaryUrlDoesNotNotify) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- other_url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
+ other_url(), url(), ContentSettingsType::GEOLOCATION,
CONTENT_SETTING_ALLOW);
EXPECT_FALSE(callback_called());
@@ -441,7 +438,7 @@ TEST_F(PermissionManagerTest, DifferentSecondaryUrlDoesNotNotify) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), other_url(), ContentSettingsType::STORAGE_ACCESS, std::string(),
+ url(), other_url(), ContentSettingsType::STORAGE_ACCESS,
CONTENT_SETTING_ALLOW);
EXPECT_FALSE(callback_called());
@@ -469,8 +466,7 @@ TEST_F(PermissionManagerTest, WildCardPatternNotifies) {
TEST_F(PermissionManagerTest, ClearSettingsNotifies) {
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
int subscription_id =
GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
@@ -496,8 +492,7 @@ TEST_F(PermissionManagerTest, NewValueCorrectlyPassed) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_BLOCK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_BLOCK);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::DENIED, callback_result());
@@ -508,8 +503,7 @@ TEST_F(PermissionManagerTest, NewValueCorrectlyPassed) {
TEST_F(PermissionManagerTest, ChangeWithoutPermissionChangeDoesNotNotify) {
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
int subscription_id =
GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
@@ -518,8 +512,7 @@ TEST_F(PermissionManagerTest, ChangeWithoutPermissionChangeDoesNotNotify) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
EXPECT_FALSE(callback_called());
@@ -529,8 +522,7 @@ TEST_F(PermissionManagerTest, ChangeWithoutPermissionChangeDoesNotNotify) {
TEST_F(PermissionManagerTest, ChangesBackAndForth) {
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ASK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ASK);
int subscription_id =
GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
@@ -539,8 +531,7 @@ TEST_F(PermissionManagerTest, ChangesBackAndForth) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
@@ -548,8 +539,7 @@ TEST_F(PermissionManagerTest, ChangesBackAndForth) {
Reset();
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ASK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ASK);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::ASK, callback_result());
@@ -560,8 +550,7 @@ TEST_F(PermissionManagerTest, ChangesBackAndForth) {
TEST_F(PermissionManagerTest, ChangesBackAndForthWorker) {
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ASK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ASK);
int subscription_id =
GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
@@ -570,8 +559,7 @@ TEST_F(PermissionManagerTest, ChangesBackAndForthWorker) {
base::Unretained(this)));
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
@@ -579,8 +567,7 @@ TEST_F(PermissionManagerTest, ChangesBackAndForthWorker) {
Reset();
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ASK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ASK);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::ASK, callback_result());
@@ -598,8 +585,7 @@ TEST_F(PermissionManagerTest, SubscribeMIDIPermission) {
CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::ASK);
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::GRANTED);
EXPECT_FALSE(callback_called());
@@ -818,8 +804,7 @@ TEST_F(PermissionManagerTest, SubscribeWithPermissionDelegation) {
// Allow access for the top level origin.
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_ALLOW);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ALLOW);
// The child's permission should still be block and no callback should be run.
EXPECT_EQ(CONTENT_SETTING_BLOCK,
@@ -850,8 +835,7 @@ TEST_F(PermissionManagerTest, SubscribeWithPermissionDelegation) {
// Blocking access to the parent should trigger the callback to be run for the
// child also.
GetHostContentSettingsMap()->SetContentSettingDefaultScope(
- url(), url(), ContentSettingsType::GEOLOCATION, std::string(),
- CONTENT_SETTING_BLOCK);
+ url(), url(), ContentSettingsType::GEOLOCATION, CONTENT_SETTING_BLOCK);
EXPECT_TRUE(callback_called());
EXPECT_EQ(PermissionStatus::DENIED, callback_result());
diff --git a/chromium/components/permissions/permission_prompt.h b/chromium/components/permissions/permission_prompt.h
index cfc497f8ed8..985122b4861 100644
--- a/chromium/components/permissions/permission_prompt.h
+++ b/chromium/components/permissions/permission_prompt.h
@@ -51,11 +51,15 @@ class PermissionPrompt {
// deleted upon navigation and so on.
virtual const std::vector<PermissionRequest*>& Requests() = 0;
+ // Get the single origin for the current set of requests.
+ virtual GURL GetRequestingOrigin() const = 0;
+
// Get the top-level origin currently displayed in the address bar
// associated with the requests.
virtual GURL GetEmbeddingOrigin() const = 0;
virtual void Accept() = 0;
+ virtual void AcceptThisTime() = 0;
virtual void Deny() = 0;
virtual void Closing() = 0;
diff --git a/chromium/components/permissions/permission_request.h b/chromium/components/permissions/permission_request.h
index 64358a516f0..a6fcca9147f 100644
--- a/chromium/components/permissions/permission_request.h
+++ b/chromium/components/permissions/permission_request.h
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/permissions/permission_request_enums.h"
#include "url/gurl.h"
namespace gfx {
@@ -18,62 +19,6 @@ struct VectorIcon;
namespace permissions {
-// Used for UMA to record the types of permission prompts shown.
-// When updating, you also need to update:
-// 1) The PermissionRequestType enum in tools/metrics/histograms/enums.xml.
-// 2) The PermissionRequestTypes suffix list in
-// tools/metrics/histograms/histograms.xml.
-// 3) GetPermissionRequestString in
-// chrome/browser/permissions/permission_uma_util.cc.
-//
-// The usual rules of updating UMA values applies to this enum:
-// - don't remove values
-// - only ever add values at the end
-enum class PermissionRequestType {
- UNKNOWN = 0,
- MULTIPLE = 1,
- // UNUSED_PERMISSION = 2,
- QUOTA = 3,
- DOWNLOAD = 4,
- // MEDIA_STREAM = 5,
- REGISTER_PROTOCOL_HANDLER = 6,
- PERMISSION_GEOLOCATION = 7,
- PERMISSION_MIDI_SYSEX = 8,
- PERMISSION_NOTIFICATIONS = 9,
- PERMISSION_PROTECTED_MEDIA_IDENTIFIER = 10,
- // PERMISSION_PUSH_MESSAGING = 11,
- PERMISSION_FLASH = 12,
- PERMISSION_MEDIASTREAM_MIC = 13,
- PERMISSION_MEDIASTREAM_CAMERA = 14,
- PERMISSION_ACCESSIBILITY_EVENTS = 15,
- // PERMISSION_CLIPBOARD_READ = 16, // Replaced by
- // PERMISSION_CLIPBOARD_READ_WRITE in M81.
- PERMISSION_SECURITY_KEY_ATTESTATION = 17,
- PERMISSION_PAYMENT_HANDLER = 18,
- PERMISSION_NFC = 19,
- PERMISSION_CLIPBOARD_READ_WRITE = 20,
- PERMISSION_VR = 21,
- PERMISSION_AR = 22,
- PERMISSION_STORAGE_ACCESS = 23,
- PERMISSION_CAMERA_PAN_TILT_ZOOM = 24,
- PERMISSION_WINDOW_PLACEMENT = 25,
- PERMISSION_FONT_ACCESS = 26,
- PERMISSION_IDLE_DETECTION = 27,
- // NUM must be the last value in the enum.
- NUM
-};
-
-// Used for UMA to record whether a gesture was associated with the request. For
-// simplicity not all request types track whether a gesture is associated with
-// it or not, for these types of requests metrics are not recorded.
-enum class PermissionRequestGestureType {
- UNKNOWN,
- GESTURE,
- NO_GESTURE,
- // NUM must be the last value in the enum.
- NUM
-};
-
// Describes the interface a feature making permission requests should
// implement. A class of this type is registered with the permission request
// manager to receive updates about the result of the permissions request
@@ -128,7 +73,10 @@ class PermissionRequest {
virtual GURL GetOrigin() const = 0;
// Called when the user has granted the requested permission.
- virtual void PermissionGranted() = 0;
+ // If is_one_time is true the permission will last until all tabs of a given
+ // |origin| are closed or navigated away from. The permission will
+ // automatically expire after 1 day.
+ virtual void PermissionGranted(bool is_one_time) = 0;
// Called when the user has denied the requested permission.
virtual void PermissionDenied() = 0;
diff --git a/chromium/components/permissions/permission_request_enums.h b/chromium/components/permissions/permission_request_enums.h
new file mode 100644
index 00000000000..fb554c9f4e6
--- /dev/null
+++ b/chromium/components/permissions/permission_request_enums.h
@@ -0,0 +1,68 @@
+// Copyright 2020 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_PERMISSIONS_PERMISSION_REQUEST_ENUMS_H_
+#define COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_ENUMS_H_
+
+namespace permissions {
+
+// Used for UMA to record the types of permission prompts shown.
+// When updating, you also need to update:
+// 1) The PermissionRequestType enum in tools/metrics/histograms/enums.xml.
+// 2) The PermissionRequestTypes suffix list in
+// tools/metrics/histograms/histograms.xml.
+// 3) GetPermissionRequestString in
+// chrome/browser/permissions/permission_uma_util.cc.
+//
+// The usual rules of updating UMA values applies to this enum:
+// - don't remove values
+// - only ever add values at the end
+enum class PermissionRequestType {
+ UNKNOWN = 0,
+ MULTIPLE = 1,
+ // UNUSED_PERMISSION = 2,
+ QUOTA = 3,
+ DOWNLOAD = 4,
+ // MEDIA_STREAM = 5,
+ REGISTER_PROTOCOL_HANDLER = 6,
+ PERMISSION_GEOLOCATION = 7,
+ PERMISSION_MIDI_SYSEX = 8,
+ PERMISSION_NOTIFICATIONS = 9,
+ PERMISSION_PROTECTED_MEDIA_IDENTIFIER = 10,
+ // PERMISSION_PUSH_MESSAGING = 11,
+ PERMISSION_FLASH = 12,
+ PERMISSION_MEDIASTREAM_MIC = 13,
+ PERMISSION_MEDIASTREAM_CAMERA = 14,
+ PERMISSION_ACCESSIBILITY_EVENTS = 15,
+ // PERMISSION_CLIPBOARD_READ = 16, // Replaced by
+ // PERMISSION_CLIPBOARD_READ_WRITE in M81.
+ PERMISSION_SECURITY_KEY_ATTESTATION = 17,
+ PERMISSION_PAYMENT_HANDLER = 18,
+ PERMISSION_NFC = 19,
+ PERMISSION_CLIPBOARD_READ_WRITE = 20,
+ PERMISSION_VR = 21,
+ PERMISSION_AR = 22,
+ PERMISSION_STORAGE_ACCESS = 23,
+ PERMISSION_CAMERA_PAN_TILT_ZOOM = 24,
+ PERMISSION_WINDOW_PLACEMENT = 25,
+ PERMISSION_FONT_ACCESS = 26,
+ PERMISSION_IDLE_DETECTION = 27,
+ // NUM must be the last value in the enum.
+ NUM
+};
+
+// Used for UMA to record whether a gesture was associated with the request. For
+// simplicity not all request types track whether a gesture is associated with
+// it or not, for these types of requests metrics are not recorded.
+enum class PermissionRequestGestureType {
+ UNKNOWN,
+ GESTURE,
+ NO_GESTURE,
+ // NUM must be the last value in the enum.
+ NUM
+};
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_ENUMS_H_
diff --git a/chromium/components/permissions/permission_request_impl.cc b/chromium/components/permissions/permission_request_impl.cc
index 960a65324e8..973347269a2 100644
--- a/chromium/components/permissions/permission_request_impl.cc
+++ b/chromium/components/permissions/permission_request_impl.cc
@@ -297,16 +297,19 @@ GURL PermissionRequestImpl::GetOrigin() const {
return request_origin_;
}
-void PermissionRequestImpl::PermissionGranted() {
- std::move(permission_decided_callback_).Run(CONTENT_SETTING_ALLOW);
+void PermissionRequestImpl::PermissionGranted(bool is_one_time) {
+ std::move(permission_decided_callback_)
+ .Run(CONTENT_SETTING_ALLOW, is_one_time);
}
void PermissionRequestImpl::PermissionDenied() {
- std::move(permission_decided_callback_).Run(CONTENT_SETTING_BLOCK);
+ std::move(permission_decided_callback_)
+ .Run(CONTENT_SETTING_BLOCK, /*is_one_time=*/false);
}
void PermissionRequestImpl::Cancelled() {
- std::move(permission_decided_callback_).Run(CONTENT_SETTING_DEFAULT);
+ std::move(permission_decided_callback_)
+ .Run(CONTENT_SETTING_DEFAULT, /*is_one_time=*/false);
}
void PermissionRequestImpl::RequestFinished() {
diff --git a/chromium/components/permissions/permission_request_impl.h b/chromium/components/permissions/permission_request_impl.h
index 7ce34cc2ab0..33446901f64 100644
--- a/chromium/components/permissions/permission_request_impl.h
+++ b/chromium/components/permissions/permission_request_impl.h
@@ -23,7 +23,8 @@ namespace permissions {
// executed.
class PermissionRequestImpl : public PermissionRequest {
public:
- using PermissionDecidedCallback = base::OnceCallback<void(ContentSetting)>;
+ using PermissionDecidedCallback =
+ base::OnceCallback<void(ContentSetting, bool)>;
PermissionRequestImpl(const GURL& request_origin,
ContentSettingsType content_settings_type,
@@ -46,7 +47,7 @@ class PermissionRequestImpl : public PermissionRequest {
#endif
base::string16 GetMessageTextFragment() const override;
GURL GetOrigin() const override;
- void PermissionGranted() override;
+ void PermissionGranted(bool is_one_time) override;
void PermissionDenied() override;
void Cancelled() override;
void RequestFinished() override;
diff --git a/chromium/components/permissions/permission_request_manager.cc b/chromium/components/permissions/permission_request_manager.cc
index fd412be2fd8..c930f2f499c 100644
--- a/chromium/components/permissions/permission_request_manager.cc
+++ b/chromium/components/permissions/permission_request_manager.cc
@@ -23,7 +23,6 @@
#include "components/permissions/permission_prompt.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_request_id.h"
-#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permissions_client.h"
#include "components/permissions/switches.h"
#include "content/public/browser/back_forward_cache.h"
@@ -33,6 +32,7 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
+#include "url/gurl.h"
#include "url/origin.h"
namespace permissions {
@@ -111,7 +111,7 @@ bool ShouldGroupRequests(PermissionRequest* a, PermissionRequest* b) {
// PermissionRequestManager ----------------------------------------------------
-bool PermissionRequestManager::RequestAndSource::
+bool PermissionRequestManager::PermissionRequestSource::
IsSourceFrameInactiveAndDisallowReactivation() const {
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
@@ -173,7 +173,7 @@ void PermissionRequestManager::AddRequest(
if (auto_approval_origin) {
if (url::Origin::Create(request->GetOrigin()) ==
auto_approval_origin.value()) {
- request->PermissionGranted();
+ request->PermissionGranted(/*is_one_time=*/false);
}
request->RequestFinished();
return;
@@ -214,14 +214,27 @@ void PermissionRequestManager::AddRequest(
base::RecordAction(
base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
}
- queued_requests_.push_back({source_frame->GetProcess()->GetID(),
- source_frame->GetRoutingID(), request});
+
+ if (base::FeatureList::IsEnabled(features::kPermissionChip)) {
+ // Because the requests are shown in a different order for Chip, pending
+ // requests are returned back to queued_requests_ to process them after the
+ // new requests.
+ ResetViewStateForCurrentRequest();
+ for (auto* request : requests_)
+ queued_requests_.push_back(request);
+ requests_.clear();
+ }
+
+ queued_requests_.push_back(request);
+ request_sources_map_.emplace(
+ request, PermissionRequestSource({source_frame->GetProcess()->GetID(),
+ source_frame->GetRoutingID()}));
// If we're displaying a quiet permission request, kill it in favor of this
// permission request.
if (ShouldCurrentRequestUseQuietUI()) {
- // FinalizeBubble will call ScheduleDequeueRequest on its own.
- FinalizeBubble(PermissionAction::IGNORED);
+ // FinalizeCurrentRequests will call ScheduleDequeueRequest on its own.
+ FinalizeCurrentRequests(PermissionAction::IGNORED);
} else {
ScheduleDequeueRequestIfNeeded();
}
@@ -318,7 +331,7 @@ void PermissionRequestManager::OnVisibilityChanged(
break;
case PermissionPrompt::TabSwitchingBehavior::
kDestroyPromptAndIgnoreRequest:
- FinalizeBubble(PermissionAction::IGNORED);
+ FinalizeCurrentRequests(PermissionAction::IGNORED);
break;
case PermissionPrompt::TabSwitchingBehavior::kKeepPromptAlive:
break;
@@ -349,6 +362,16 @@ const std::vector<PermissionRequest*>& PermissionRequestManager::Requests() {
return requests_;
}
+GURL PermissionRequestManager::GetRequestingOrigin() const {
+ CHECK(!requests_.empty());
+ GURL origin = requests_.front()->GetOrigin();
+ if (DCHECK_IS_ON()) {
+ for (auto* request : requests_)
+ DCHECK_EQ(origin, request->GetOrigin());
+ }
+ return origin;
+}
+
GURL PermissionRequestManager::GetEmbeddingOrigin() const {
return web_contents()->GetLastCommittedURL().GetOrigin();
}
@@ -360,9 +383,21 @@ void PermissionRequestManager::Accept() {
std::vector<PermissionRequest*>::iterator requests_iter;
for (requests_iter = requests_.begin(); requests_iter != requests_.end();
requests_iter++) {
- PermissionGrantedIncludingDuplicates(*requests_iter);
+ PermissionGrantedIncludingDuplicates(*requests_iter, /*is_one_time=*/false);
}
- FinalizeBubble(PermissionAction::GRANTED);
+ FinalizeCurrentRequests(PermissionAction::GRANTED);
+}
+
+void PermissionRequestManager::AcceptThisTime() {
+ if (deleting_bubble_)
+ return;
+ DCHECK(view_);
+ std::vector<PermissionRequest*>::iterator requests_iter;
+ for (requests_iter = requests_.begin(); requests_iter != requests_.end();
+ requests_iter++) {
+ PermissionGrantedIncludingDuplicates(*requests_iter, /*is_one_time=*/true);
+ }
+ FinalizeCurrentRequests(PermissionAction::GRANTED_ONCE);
}
void PermissionRequestManager::Deny() {
@@ -388,7 +423,7 @@ void PermissionRequestManager::Deny() {
requests_iter++) {
PermissionDeniedIncludingDuplicates(*requests_iter);
}
- FinalizeBubble(PermissionAction::DENIED);
+ FinalizeCurrentRequests(PermissionAction::DENIED);
}
void PermissionRequestManager::Closing() {
@@ -400,7 +435,7 @@ void PermissionRequestManager::Closing() {
requests_iter++) {
CancelledIncludingDuplicates(*requests_iter);
}
- FinalizeBubble(PermissionAction::DISMISSED);
+ FinalizeCurrentRequests(PermissionAction::DISMISSED);
}
bool PermissionRequestManager::WasCurrentRequestAlreadyDisplayed() {
@@ -415,8 +450,8 @@ PermissionRequestManager::PermissionRequestManager(
tab_is_hidden_(web_contents->GetVisibility() ==
content::Visibility::HIDDEN),
auto_response_for_test_(NONE),
- notification_permission_ui_selector_(
- PermissionsClient::Get()->CreateNotificationPermissionUiSelector(
+ notification_permission_ui_selectors_(
+ PermissionsClient::Get()->CreateNotificationPermissionUiSelectors(
web_contents->GetBrowserContext())) {}
void PermissionRequestManager::ScheduleShowBubble() {
@@ -427,6 +462,13 @@ void PermissionRequestManager::ScheduleShowBubble() {
}
void PermissionRequestManager::DequeueRequestIfNeeded() {
+ // TODO(olesiamarukhno): Media requests block other media requests from
+ // pre-empting them. For example, when a camera request is pending and mic is
+ // requested, the camera request remains pending and mic request appears only
+ // after the camera request is resolved. This is caused by code in
+ // PermissionBubbleMediaAccessHandler and UserMediaClient. We probably don't
+ // need two permission queues, so resolve the duplication.
+
if (!web_contents()->IsDocumentOnLoadCompletedInMainFrame() || view_ ||
IsRequestInProgress()) {
return;
@@ -434,16 +476,15 @@ void PermissionRequestManager::DequeueRequestIfNeeded() {
// Find first valid request.
while (!queued_requests_.empty()) {
- RequestAndSource& front = queued_requests_.front();
-
- if (!front.IsSourceFrameInactiveAndDisallowReactivation()) {
- requests_.push_back(front.request);
- queued_requests_.pop_front();
+ PermissionRequest* next = PopNextQueuedRequest();
+ PermissionRequestSource& source = request_sources_map_.find(next)->second;
+ if (!source.IsSourceFrameInactiveAndDisallowReactivation()) {
+ requests_.push_back(next);
break;
}
- front.request->Cancelled();
- front.request->RequestFinished();
- queued_requests_.pop_front();
+ next->Cancelled();
+ next->RequestFinished();
+ request_sources_map_.erase(request_sources_map_.find(next));
}
if (requests_.empty()) {
@@ -451,26 +492,37 @@ void PermissionRequestManager::DequeueRequestIfNeeded() {
}
// Find additional requests that can be grouped with the first one.
- for (; !queued_requests_.empty(); queued_requests_.pop_front()) {
- RequestAndSource& front = queued_requests_.front();
- if (front.IsSourceFrameInactiveAndDisallowReactivation()) {
- front.request->Cancelled();
- front.request->RequestFinished();
- } else if (ShouldGroupRequests(requests_.front(), front.request)) {
- requests_.push_back(front.request);
+ for (; !queued_requests_.empty(); PopNextQueuedRequest()) {
+ PermissionRequest* front = PeekNextQueuedRequest();
+ PermissionRequestSource& source = request_sources_map_.find(front)->second;
+ if (source.IsSourceFrameInactiveAndDisallowReactivation()) {
+ front->Cancelled();
+ front->RequestFinished();
+ request_sources_map_.erase(request_sources_map_.find(front));
+ } else if (ShouldGroupRequests(requests_.front(), front)) {
+ requests_.push_back(front);
} else {
break;
}
}
- if (notification_permission_ui_selector_ &&
+ if (!notification_permission_ui_selectors_.empty() &&
requests_.front()->GetPermissionRequestType() ==
PermissionRequestType::PERMISSION_NOTIFICATIONS) {
- notification_permission_ui_selector_->SelectUiToUse(
- requests_.front(),
- base::BindOnce(
- &PermissionRequestManager::OnSelectedUiToUseForNotifications,
- weak_factory_.GetWeakPtr()));
+ DCHECK(!current_request_ui_to_use_.has_value());
+ // Initialize the selector decisions vector.
+ DCHECK(selector_decisions_.empty());
+ selector_decisions_.resize(notification_permission_ui_selectors_.size());
+
+ for (size_t selector_index = 0;
+ selector_index < notification_permission_ui_selectors_.size();
+ ++selector_index) {
+ notification_permission_ui_selectors_[selector_index]->SelectUiToUse(
+ requests_.front(),
+ base::BindOnce(
+ &PermissionRequestManager::OnNotificationPermissionUiSelectorDone,
+ weak_factory_.GetWeakPtr(), selector_index));
+ }
} else {
current_request_ui_to_use_ =
UiDecision(UiDecision::UseNormalUi(), UiDecision::ShowNoWarning());
@@ -491,6 +543,7 @@ void PermissionRequestManager::ShowBubble() {
if (!IsRequestInProgress())
return;
+ DCHECK(!requests_.empty());
DCHECK(!view_);
DCHECK(web_contents()->IsDocumentOnLoadCompletedInMainFrame());
DCHECK(current_request_ui_to_use_);
@@ -509,6 +562,7 @@ void PermissionRequestManager::ShowBubble() {
switch (ReasonForUsingQuietUi()) {
case QuietUiReason::kEnabledInPrefs:
case QuietUiReason::kTriggeredByCrowdDeny:
+ case QuietUiReason::kPredictedVeryUnlikelyGrant:
break;
case QuietUiReason::kTriggeredDueToAbusiveRequests:
LogWarningToConsole(kAbusiveNotificationRequestsEnforcementMessage);
@@ -520,17 +574,6 @@ void PermissionRequestManager::ShowBubble() {
base::RecordAction(base::UserMetricsAction(
"Notifications.Quiet.PermissionRequestShown"));
}
-
- if (current_request_ui_to_use_->warning_reason) {
- switch (*(current_request_ui_to_use_->warning_reason)) {
- case WarningReason::kAbusiveRequests:
- LogWarningToConsole(kAbusiveNotificationRequestsWarningMessage);
- break;
- case WarningReason::kAbusiveContent:
- LogWarningToConsole(kAbusiveNotificationContentWarningMessage);
- break;
- }
- }
}
current_request_already_displayed_ = true;
NotifyBubbleAdded();
@@ -549,13 +592,27 @@ void PermissionRequestManager::DeleteBubble() {
NotifyBubbleRemoved();
}
-void PermissionRequestManager::FinalizeBubble(
+void PermissionRequestManager::ResetViewStateForCurrentRequest() {
+ for (const auto& selector : notification_permission_ui_selectors_)
+ selector->Cancel();
+
+ current_request_already_displayed_ = false;
+ prediction_grant_likelihood_.reset();
+ current_request_ui_to_use_.reset();
+ selector_decisions_.clear();
+
+ if (view_)
+ DeleteBubble();
+}
+
+void PermissionRequestManager::FinalizeCurrentRequests(
PermissionAction permission_action) {
DCHECK(IsRequestInProgress());
-
PermissionUmaUtil::PermissionPromptResolved(
requests_, web_contents(), permission_action,
- DetermineCurrentRequestUIDispositionForUMA());
+ DetermineCurrentRequestUIDispositionForUMA(),
+ DetermineCurrentRequestUIDispositionReasonForUMA(),
+ prediction_grant_likelihood_);
content::BrowserContext* browser_context =
web_contents()->GetBrowserContext();
@@ -595,29 +652,23 @@ void PermissionRequestManager::FinalizeBubble(
}
PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
}
+ ResetViewStateForCurrentRequest();
std::vector<PermissionRequest*>::iterator requests_iter;
for (requests_iter = requests_.begin(); requests_iter != requests_.end();
requests_iter++) {
RequestFinishedIncludingDuplicates(*requests_iter);
+ request_sources_map_.erase(request_sources_map_.find(*requests_iter));
}
requests_.clear();
- if (notification_permission_ui_selector_)
- notification_permission_ui_selector_->Cancel();
-
- current_request_already_displayed_ = false;
- current_request_ui_to_use_.reset();
-
- if (view_)
- DeleteBubble();
-
ScheduleDequeueRequestIfNeeded();
}
void PermissionRequestManager::CleanUpRequests() {
- for (auto& queued_request : queued_requests_) {
- CancelledIncludingDuplicates(queued_request.request);
- RequestFinishedIncludingDuplicates(queued_request.request);
+ for (auto* queued_request : queued_requests_) {
+ CancelledIncludingDuplicates(queued_request);
+ RequestFinishedIncludingDuplicates(queued_request);
+ request_sources_map_.erase(request_sources_map_.find(queued_request));
}
queued_requests_.clear();
@@ -627,7 +678,7 @@ void PermissionRequestManager::CleanUpRequests() {
requests_iter++) {
CancelledIncludingDuplicates(*requests_iter);
}
- FinalizeBubble(PermissionAction::IGNORED);
+ FinalizeCurrentRequests(PermissionAction::IGNORED);
}
}
@@ -637,28 +688,29 @@ PermissionRequest* PermissionRequestManager::GetExistingRequest(
if (IsMessageTextEqual(existing_request, request))
return existing_request;
}
- for (RequestAndSource& request_and_source : queued_requests_) {
- if (IsMessageTextEqual(request_and_source.request, request))
- return request_and_source.request;
+ for (PermissionRequest* queued_request : queued_requests_) {
+ if (IsMessageTextEqual(queued_request, request))
+ return queued_request;
}
return nullptr;
}
void PermissionRequestManager::PermissionGrantedIncludingDuplicates(
- PermissionRequest* request) {
+ PermissionRequest* request,
+ bool is_one_time) {
DCHECK_EQ(1, base::STLCount(requests_, request) +
- CountQueuedPermissionRequests(request))
+ base::STLCount(queued_requests_, request))
<< "Only requests in [queued_[frame_]]requests_ can have duplicates";
- request->PermissionGranted();
+ request->PermissionGranted(is_one_time);
auto range = duplicate_requests_.equal_range(request);
for (auto it = range.first; it != range.second; ++it)
- it->second->PermissionGranted();
+ it->second->PermissionGranted(is_one_time);
}
void PermissionRequestManager::PermissionDeniedIncludingDuplicates(
PermissionRequest* request) {
DCHECK_EQ(1, base::STLCount(requests_, request) +
- CountQueuedPermissionRequests(request))
+ base::STLCount(queued_requests_, request))
<< "Only requests in [queued_]requests_ can have duplicates";
request->PermissionDenied();
auto range = duplicate_requests_.equal_range(request);
@@ -669,7 +721,7 @@ void PermissionRequestManager::PermissionDeniedIncludingDuplicates(
void PermissionRequestManager::CancelledIncludingDuplicates(
PermissionRequest* request) {
DCHECK_EQ(1, base::STLCount(requests_, request) +
- CountQueuedPermissionRequests(request))
+ base::STLCount(queued_requests_, request))
<< "Only requests in [queued_]requests_ can have duplicates";
request->Cancelled();
auto range = duplicate_requests_.equal_range(request);
@@ -680,7 +732,7 @@ void PermissionRequestManager::CancelledIncludingDuplicates(
void PermissionRequestManager::RequestFinishedIncludingDuplicates(
PermissionRequest* request) {
DCHECK_EQ(1, base::STLCount(requests_, request) +
- CountQueuedPermissionRequests(request))
+ base::STLCount(queued_requests_, request))
<< "Only requests in [queued_]requests_ can have duplicates";
request->RequestFinished();
// Beyond this point, |request| has probably been deleted.
@@ -704,7 +756,7 @@ bool PermissionRequestManager::ShouldCurrentRequestUseQuietUI() const {
return false;
// ContentSettingImageModel might call into this method if the user switches
- // between tabs while the |notification_permission_ui_selector_| is pending.
+ // between tabs while the |notification_permission_ui_selectors_| are pending.
return current_request_ui_to_use_ &&
current_request_ui_to_use_->quiet_ui_reason;
}
@@ -728,10 +780,55 @@ void PermissionRequestManager::NotifyBubbleRemoved() {
observer.OnBubbleRemoved();
}
-void PermissionRequestManager::OnSelectedUiToUseForNotifications(
+void PermissionRequestManager::OnNotificationPermissionUiSelectorDone(
+ size_t selector_index,
const UiDecision& decision) {
- current_request_ui_to_use_ = decision;
- ScheduleShowBubble();
+ if (decision.warning_reason) {
+ switch (*(decision.warning_reason)) {
+ case WarningReason::kAbusiveRequests:
+ LogWarningToConsole(kAbusiveNotificationRequestsWarningMessage);
+ break;
+ case WarningReason::kAbusiveContent:
+ LogWarningToConsole(kAbusiveNotificationContentWarningMessage);
+ break;
+ }
+ }
+
+ if (!prediction_grant_likelihood_.has_value()) {
+ prediction_grant_likelihood_ =
+ notification_permission_ui_selectors_[selector_index]
+ ->PredictedGrantLikelihoodForUKM();
+ }
+
+ // We have already made a decision because of a higher priority selector
+ // therefore this selector's decision can be discarded.
+ if (current_request_ui_to_use_.has_value())
+ return;
+
+ CHECK_LT(selector_index, selector_decisions_.size());
+ selector_decisions_[selector_index] = decision;
+
+ size_t decision_index = 0;
+ while (decision_index < selector_decisions_.size() &&
+ selector_decisions_[decision_index].has_value()) {
+ const UiDecision& current_decision =
+ selector_decisions_[decision_index++].value();
+
+ if (current_decision.quiet_ui_reason.has_value()) {
+ current_request_ui_to_use_ = current_decision;
+ break;
+ }
+ }
+
+ // All decisions have been considered and none was conclusive.
+ if (decision_index == selector_decisions_.size() &&
+ !current_request_ui_to_use_.has_value()) {
+ current_request_ui_to_use_ = UiDecision::UseNormalUiAndShowNoWarning();
+ }
+
+ if (current_request_ui_to_use_.has_value()) {
+ ScheduleShowBubble();
+ }
}
PermissionPromptDisposition
@@ -741,6 +838,24 @@ PermissionRequestManager::DetermineCurrentRequestUIDispositionForUMA() {
return PermissionPromptDisposition::NONE_VISIBLE;
}
+PermissionPromptDispositionReason
+PermissionRequestManager::DetermineCurrentRequestUIDispositionReasonForUMA() {
+ if (!ShouldCurrentRequestUseQuietUI()) {
+ return PermissionPromptDispositionReason::DEFAULT_FALLBACK;
+ }
+
+ switch (ReasonForUsingQuietUi()) {
+ case QuietUiReason::kEnabledInPrefs:
+ return PermissionPromptDispositionReason::USER_PREFERENCE_IN_SETTINGS;
+ case QuietUiReason::kTriggeredByCrowdDeny:
+ case QuietUiReason::kTriggeredDueToAbusiveRequests:
+ case QuietUiReason::kTriggeredDueToAbusiveContent:
+ return PermissionPromptDispositionReason::SAFE_BROWSING_VERDICT;
+ case QuietUiReason::kPredictedVeryUnlikelyGrant:
+ return PermissionPromptDispositionReason::PREDICTION_SERVICE;
+ }
+}
+
void PermissionRequestManager::LogWarningToConsole(const char* message) {
web_contents()->GetMainFrame()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kWarning, message);
@@ -762,12 +877,19 @@ void PermissionRequestManager::DoAutoResponseForTesting() {
}
}
-int PermissionRequestManager::CountQueuedPermissionRequests(
- PermissionRequest* request) {
- return std::count_if(queued_requests_.begin(), queued_requests_.end(),
- [request](const RequestAndSource& entry) {
- return request == entry.request;
- });
+PermissionRequest* PermissionRequestManager::PeekNextQueuedRequest() {
+ return base::FeatureList::IsEnabled(features::kPermissionChip)
+ ? queued_requests_.back()
+ : queued_requests_.front();
+}
+
+PermissionRequest* PermissionRequestManager::PopNextQueuedRequest() {
+ PermissionRequest* next = PeekNextQueuedRequest();
+ if (base::FeatureList::IsEnabled(features::kPermissionChip))
+ queued_requests_.pop_back();
+ else
+ queued_requests_.pop_front();
+ return next;
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(PermissionRequestManager)
diff --git a/chromium/components/permissions/permission_request_manager.h b/chromium/components/permissions/permission_request_manager.h
index 1b4a444ebe4..e0e1bddbc27 100644
--- a/chromium/components/permissions/permission_request_manager.h
+++ b/chromium/components/permissions/permission_request_manager.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_MANAGER_H_
#define COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_MANAGER_H_
+#include <algorithm>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -15,9 +16,12 @@
#include "base/observer_list.h"
#include "components/permissions/notification_permission_ui_selector.h"
#include "components/permissions/permission_prompt.h"
+#include "components/permissions/permission_uma_util.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
+class GURL;
+
namespace content {
class RenderFrameHost;
}
@@ -30,6 +34,7 @@ namespace permissions {
class PermissionRequest;
enum class PermissionAction;
enum class PermissionPromptDisposition;
+enum class PermissionPromptDispositionReason;
// The message to be printed in the Developer Tools console when the quiet
// notification permission prompt UI is shown on sites with abusive permission
@@ -130,8 +135,10 @@ class PermissionRequestManager
// PermissionPrompt::Delegate:
const std::vector<PermissionRequest*>& Requests() override;
+ GURL GetRequestingOrigin() const override;
GURL GetEmbeddingOrigin() const override;
void Accept() override;
+ void AcceptThisTime() override;
void Deny() override;
void Closing() override;
bool WasCurrentRequestAlreadyDisplayed() override;
@@ -142,10 +149,24 @@ class PermissionRequestManager
web_contents_supports_permission_requests;
}
- // For testing only, used to override the default UI selector.
+ // For testing only, used to override the default UI selectors and instead use
+ // a new one.
void set_notification_permission_ui_selector_for_testing(
std::unique_ptr<NotificationPermissionUiSelector> selector) {
- notification_permission_ui_selector_ = std::move(selector);
+ clear_notification_permission_ui_selector_for_testing();
+ add_notification_permission_ui_selector_for_testing(std::move(selector));
+ }
+
+ // For testing only, used to add a new selector without overriding the
+ // existing ones.
+ void add_notification_permission_ui_selector_for_testing(
+ std::unique_ptr<NotificationPermissionUiSelector> selector) {
+ notification_permission_ui_selectors_.emplace_back(std::move(selector));
+ }
+
+ // For testing only, clear the existing ui selectors.
+ void clear_notification_permission_ui_selector_for_testing() {
+ notification_permission_ui_selectors_.clear();
}
void set_view_factory_for_testing(PermissionPrompt::Factory view_factory) {
@@ -179,9 +200,12 @@ class PermissionRequestManager
// Delete the view object
void DeleteBubble();
+ // Finalize request.
+ void ResetViewStateForCurrentRequest();
+
// Delete the view object, finalize requests, asynchronously show a queued
// request if present.
- void FinalizeBubble(PermissionAction permission_action);
+ void FinalizeCurrentRequests(PermissionAction permission_action);
// Cancel all pending or active requests and destroy the PermissionPrompt if
// one exists. This is called if the WebContents is destroyed or navigates its
@@ -195,7 +219,8 @@ class PermissionRequestManager
PermissionRequest* GetExistingRequest(PermissionRequest* request);
// Calls PermissionGranted on a request and all its duplicates.
- void PermissionGrantedIncludingDuplicates(PermissionRequest* request);
+ void PermissionGrantedIncludingDuplicates(PermissionRequest* request,
+ bool is_one_time);
// Calls PermissionDenied on a request and all its duplicates.
void PermissionDeniedIncludingDuplicates(PermissionRequest* request);
// Calls Cancelled on a request and all its duplicates.
@@ -206,16 +231,17 @@ class PermissionRequestManager
void NotifyBubbleAdded();
void NotifyBubbleRemoved();
- void OnSelectedUiToUseForNotifications(const UiDecision& decision);
+ void OnNotificationPermissionUiSelectorDone(size_t selector_index,
+ const UiDecision& decision);
PermissionPromptDisposition DetermineCurrentRequestUIDispositionForUMA();
+ PermissionPromptDispositionReason
+ DetermineCurrentRequestUIDispositionReasonForUMA();
void LogWarningToConsole(const char* message);
void DoAutoResponseForTesting();
- int CountQueuedPermissionRequests(PermissionRequest* request);
-
// Factory to be used to create views when needed.
PermissionPrompt::Factory view_factory_;
@@ -232,20 +258,29 @@ class PermissionRequestManager
// tab is visible.
std::vector<PermissionRequest*> requests_;
- struct RequestAndSource {
+ struct PermissionRequestSource {
int render_process_id;
int render_frame_id;
- PermissionRequest* request;
bool IsSourceFrameInactiveAndDisallowReactivation() const;
};
- base::circular_deque<RequestAndSource> queued_requests_;
+ base::circular_deque<PermissionRequest*> queued_requests_;
+
+ PermissionRequest* PeekNextQueuedRequest();
+
+ PermissionRequest* PopNextQueuedRequest();
+
// Maps from the first request of a kind to subsequent requests that were
// duped against it.
std::unordered_multimap<PermissionRequest*, PermissionRequest*>
duplicate_requests_;
+ // Maps each PermissionRequest currently in |requests_| or |queued_requests_|
+ // to which RenderFrameHost it originated from. Note that no date is stored
+ // for |duplicate_requests_|.
+ std::map<PermissionRequest*, PermissionRequestSource> request_sources_map_;
+
base::ObserverList<Observer>::Unchecked observer_list_;
AutoResponseType auto_response_for_test_;
@@ -253,10 +288,17 @@ class PermissionRequestManager
// origin requesting the permission.
bool is_notification_prompt_cooldown_active_ = false;
- // Decides if the quiet prompt UI should be used to display notification
- // permission requests.
- std::unique_ptr<NotificationPermissionUiSelector>
- notification_permission_ui_selector_;
+ // A vector of selectors which decide if the quiet prompt UI should be used
+ // to display notification permission requests. Sorted from the highest
+ // priority to the lowest priority selector.
+ std::vector<std::unique_ptr<NotificationPermissionUiSelector>>
+ notification_permission_ui_selectors_;
+
+ // Holds the decisions returned by selectors. Needed in case a lower priority
+ // selector returns a decision first and we need to wait for the decisions of
+ // higher priority selectors before making use of it.
+ std::vector<base::Optional<NotificationPermissionUiSelector::Decision>>
+ selector_decisions_;
// Whether the view for the current |requests_| has been shown to the user at
// least once.
@@ -264,9 +306,14 @@ class PermissionRequestManager
// Whether to use the normal or quiet UI to display the current permission
// |requests_|, and whether to show warnings. This will be nullopt if we are
- // still waiting on the result from |notification_permission_ui_selector_|.
+ // still waiting on the result from |notification_permission_ui_selectors_|.
base::Optional<UiDecision> current_request_ui_to_use_;
+ // The likelihood value returned by the Web Permission Predictions Service,
+ // to be recoreded in UKM.
+ base::Optional<PermissionUmaUtil::PredictionGrantLikelihood>
+ prediction_grant_likelihood_;
+
// Whether the bubble is being destroyed by this class, rather than in
// response to a UI event. In this case, callbacks from the bubble itself
// should be ignored.
diff --git a/chromium/components/permissions/permission_request_manager_unittest.cc b/chromium/components/permissions/permission_request_manager_unittest.cc
index 9c2e28c5fac..3b07d8e69a8 100644
--- a/chromium/components/permissions/permission_request_manager_unittest.cc
+++ b/chromium/components/permissions/permission_request_manager_unittest.cc
@@ -3,14 +3,18 @@
// found in the LICENSE file.
#include <stddef.h>
+#include <memory>
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
+#include "components/permissions/features.h"
#include "components/permissions/notification_permission_ui_selector.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_request_manager.h"
@@ -27,7 +31,9 @@ namespace {
using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
}
-class PermissionRequestManagerTest : public content::RenderViewHostTestHarness {
+class PermissionRequestManagerTest
+ : public content::RenderViewHostTestHarness,
+ public ::testing::WithParamInterface<bool> {
public:
PermissionRequestManagerTest()
: content::RenderViewHostTestHarness(),
@@ -61,7 +67,10 @@ class PermissionRequestManagerTest : public content::RenderViewHostTestHarness {
iframe_request_mic_other_domain_(
"iframe",
PermissionRequestType::PERMISSION_MEDIASTREAM_MIC,
- GURL("http://www.youtube.com")) {}
+ GURL("http://www.youtube.com")) {
+ feature_list_.InitWithFeatureState(permissions::features::kPermissionChip,
+ GetParam());
+ }
void SetUp() override {
content::RenderViewHostTestHarness::SetUp();
@@ -132,9 +141,10 @@ class PermissionRequestManagerTest : public content::RenderViewHostTestHarness {
PermissionRequestManager* manager_;
std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
TestPermissionsClient client_;
+ base::test::ScopedFeatureList feature_list_;
};
-TEST_F(PermissionRequestManagerTest, SingleRequest) {
+TEST_P(PermissionRequestManagerTest, SingleRequest) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
@@ -145,7 +155,7 @@ TEST_F(PermissionRequestManagerTest, SingleRequest) {
EXPECT_TRUE(request1_.granted());
}
-TEST_F(PermissionRequestManagerTest, SingleRequestViewFirst) {
+TEST_P(PermissionRequestManagerTest, SingleRequestViewFirst) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
@@ -157,7 +167,11 @@ TEST_F(PermissionRequestManagerTest, SingleRequestViewFirst) {
}
// Most requests should never be grouped.
-TEST_F(PermissionRequestManagerTest, TwoRequestsUngrouped) {
+TEST_P(PermissionRequestManagerTest, TwoRequestsUngrouped) {
+ // Grouping for chip feature is tested in ThreeRequestsStackOrderChip.
+ if (GetParam())
+ return;
+
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
@@ -175,7 +189,7 @@ TEST_F(PermissionRequestManagerTest, TwoRequestsUngrouped) {
}
// Only mic/camera requests from the same origin should be grouped.
-TEST_F(PermissionRequestManagerTest, MicCameraGrouped) {
+TEST_P(PermissionRequestManagerTest, MicCameraGrouped) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
WaitForBubbleToBeShown();
@@ -198,7 +212,7 @@ TEST_F(PermissionRequestManagerTest, MicCameraGrouped) {
}
// Only camera/ptz requests from the same origin should be grouped.
-TEST_F(PermissionRequestManagerTest, CameraPtzGrouped) {
+TEST_P(PermissionRequestManagerTest, CameraPtzGrouped) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_ptz_);
WaitForBubbleToBeShown();
@@ -221,7 +235,7 @@ TEST_F(PermissionRequestManagerTest, CameraPtzGrouped) {
}
// Only mic/camera/ptz requests from the same origin should be grouped.
-TEST_F(PermissionRequestManagerTest, MicCameraPtzGrouped) {
+TEST_P(PermissionRequestManagerTest, MicCameraPtzGrouped) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_ptz_);
@@ -242,11 +256,18 @@ TEST_F(PermissionRequestManagerTest, MicCameraPtzGrouped) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_ptz_);
WaitForBubbleToBeShown();
+ // Requests should be split into two groups and each one will contain less
+ // than 3 requests (1 request + 2 request for current logic and 2 requests + 1
+ // request for chip).
EXPECT_TRUE(prompt_factory_->is_visible());
- ASSERT_EQ(prompt_factory_->request_count(), 1);
+ ASSERT_LT(prompt_factory_->request_count(), 3);
+ Accept();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ ASSERT_LT(prompt_factory_->request_count(), 3);
}
-TEST_F(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
+TEST_P(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
WaitForBubbleToBeShown();
@@ -271,7 +292,7 @@ TEST_F(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
EXPECT_TRUE(request_camera_.granted());
}
-TEST_F(PermissionRequestManagerTest, ThreeRequestsTabSwitch) {
+TEST_P(PermissionRequestManagerTest, ThreeRequestsTabSwitch) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request_ptz_);
@@ -298,12 +319,12 @@ TEST_F(PermissionRequestManagerTest, ThreeRequestsTabSwitch) {
EXPECT_TRUE(request_ptz_.granted());
}
-TEST_F(PermissionRequestManagerTest, NoRequests) {
+TEST_P(PermissionRequestManagerTest, NoRequests) {
WaitForBubbleToBeShown();
EXPECT_FALSE(prompt_factory_->is_visible());
}
-TEST_F(PermissionRequestManagerTest, PermissionRequestWhileTabSwitchedAway) {
+TEST_P(PermissionRequestManagerTest, PermissionRequestWhileTabSwitchedAway) {
MockTabSwitchAway();
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
@@ -314,19 +335,19 @@ TEST_F(PermissionRequestManagerTest, PermissionRequestWhileTabSwitchedAway) {
EXPECT_TRUE(prompt_factory_->is_visible());
}
-TEST_F(PermissionRequestManagerTest, TwoRequestsDoNotCoalesce) {
+TEST_P(PermissionRequestManagerTest, TwoRequestsDoNotCoalesce) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
- WaitForBubbleToBeShown();
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
+ WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(prompt_factory_->request_count(), 1);
}
-TEST_F(PermissionRequestManagerTest, TwoRequestsShownInTwoBubbles) {
+TEST_P(PermissionRequestManagerTest, TwoRequestsShownInTwoBubbles) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
- WaitForBubbleToBeShown();
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
+ WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(prompt_factory_->request_count(), 1);
@@ -339,7 +360,7 @@ TEST_F(PermissionRequestManagerTest, TwoRequestsShownInTwoBubbles) {
ASSERT_EQ(prompt_factory_->show_count(), 2);
}
-TEST_F(PermissionRequestManagerTest, TestAddDuplicateRequest) {
+TEST_P(PermissionRequestManagerTest, TestAddDuplicateRequest) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
@@ -348,7 +369,7 @@ TEST_F(PermissionRequestManagerTest, TestAddDuplicateRequest) {
ASSERT_EQ(prompt_factory_->request_count(), 1);
}
-TEST_F(PermissionRequestManagerTest, SequentialRequests) {
+TEST_P(PermissionRequestManagerTest, SequentialRequests) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
@@ -366,7 +387,7 @@ TEST_F(PermissionRequestManagerTest, SequentialRequests) {
EXPECT_TRUE(request2_.granted());
}
-TEST_F(PermissionRequestManagerTest, SameRequestRejected) {
+TEST_P(PermissionRequestManagerTest, SameRequestRejected) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
EXPECT_FALSE(request1_.finished());
@@ -376,7 +397,7 @@ TEST_F(PermissionRequestManagerTest, SameRequestRejected) {
ASSERT_EQ(prompt_factory_->request_count(), 1);
}
-TEST_F(PermissionRequestManagerTest, DuplicateQueuedRequest) {
+TEST_P(PermissionRequestManagerTest, DuplicateQueuedRequest) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
@@ -391,22 +412,33 @@ TEST_F(PermissionRequestManagerTest, DuplicateQueuedRequest) {
EXPECT_FALSE(dupe_request2.finished());
EXPECT_FALSE(request2_.finished());
+ WaitForBubbleToBeShown();
Accept();
- EXPECT_TRUE(dupe_request.finished());
- EXPECT_TRUE(request1_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(dupe_request2.finished());
+ EXPECT_TRUE(request2_.finished());
+ } else {
+ EXPECT_TRUE(dupe_request.finished());
+ EXPECT_TRUE(request1_.finished());
+ }
WaitForBubbleToBeShown();
Accept();
- EXPECT_TRUE(dupe_request2.finished());
- EXPECT_TRUE(request2_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(dupe_request.finished());
+ EXPECT_TRUE(request1_.finished());
+ } else {
+ EXPECT_TRUE(dupe_request2.finished());
+ EXPECT_TRUE(request2_.finished());
+ }
}
-TEST_F(PermissionRequestManagerTest, ForgetRequestsOnPageNavigation) {
+TEST_P(PermissionRequestManagerTest, ForgetRequestsOnPageNavigation) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
- WaitForBubbleToBeShown();
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
manager_->AddRequest(web_contents()->GetMainFrame(),
&iframe_request_other_domain_);
+ WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(prompt_factory_->request_count(), 1);
@@ -420,7 +452,7 @@ TEST_F(PermissionRequestManagerTest, ForgetRequestsOnPageNavigation) {
EXPECT_TRUE(iframe_request_other_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest, MainFrameNoRequestIFrameRequest) {
+TEST_P(PermissionRequestManagerTest, MainFrameNoRequestIFrameRequest) {
manager_->AddRequest(web_contents()->GetMainFrame(),
&iframe_request_same_domain_);
WaitForBubbleToBeShown();
@@ -431,7 +463,7 @@ TEST_F(PermissionRequestManagerTest, MainFrameNoRequestIFrameRequest) {
EXPECT_TRUE(iframe_request_same_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestSameDomain) {
+TEST_P(PermissionRequestManagerTest, MainFrameAndIFrameRequestSameDomain) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
manager_->AddRequest(web_contents()->GetMainFrame(),
&iframe_request_same_domain_);
@@ -441,17 +473,27 @@ TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestSameDomain) {
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(1, prompt_factory_->request_count());
Closing();
- EXPECT_TRUE(request1_.finished());
- EXPECT_FALSE(iframe_request_same_domain_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(iframe_request_same_domain_.finished());
+ EXPECT_FALSE(request1_.finished());
+ } else {
+ EXPECT_TRUE(request1_.finished());
+ EXPECT_FALSE(iframe_request_same_domain_.finished());
+ }
+
WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(1, prompt_factory_->request_count());
+
Closing();
EXPECT_FALSE(prompt_factory_->is_visible());
- EXPECT_TRUE(iframe_request_same_domain_.finished());
+ if (GetParam())
+ EXPECT_TRUE(request1_.finished());
+ else
+ EXPECT_TRUE(iframe_request_same_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestOtherDomain) {
+TEST_P(PermissionRequestManagerTest, MainFrameAndIFrameRequestOtherDomain) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
manager_->AddRequest(web_contents()->GetMainFrame(),
&iframe_request_other_domain_);
@@ -460,14 +502,24 @@ TEST_F(PermissionRequestManagerTest, MainFrameAndIFrameRequestOtherDomain) {
EXPECT_TRUE(prompt_factory_->is_visible());
Closing();
- EXPECT_TRUE(request1_.finished());
- EXPECT_FALSE(iframe_request_other_domain_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(iframe_request_other_domain_.finished());
+ EXPECT_FALSE(request1_.finished());
+ } else {
+ EXPECT_TRUE(request1_.finished());
+ EXPECT_FALSE(iframe_request_other_domain_.finished());
+ }
+
EXPECT_TRUE(prompt_factory_->is_visible());
Closing();
EXPECT_TRUE(iframe_request_other_domain_.finished());
+ if (GetParam())
+ EXPECT_TRUE(request1_.finished());
+ else
+ EXPECT_TRUE(iframe_request_other_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest, IFrameRequestWhenMainRequestVisible) {
+TEST_P(PermissionRequestManagerTest, IFrameRequestWhenMainRequestVisible) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
EXPECT_TRUE(prompt_factory_->is_visible());
@@ -477,15 +529,25 @@ TEST_F(PermissionRequestManagerTest, IFrameRequestWhenMainRequestVisible) {
WaitForFrameLoad();
ASSERT_EQ(prompt_factory_->request_count(), 1);
Closing();
- EXPECT_TRUE(request1_.finished());
- EXPECT_FALSE(iframe_request_same_domain_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(iframe_request_same_domain_.finished());
+ EXPECT_FALSE(request1_.finished());
+ } else {
+ EXPECT_TRUE(request1_.finished());
+ EXPECT_FALSE(iframe_request_same_domain_.finished());
+ }
+
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_EQ(prompt_factory_->request_count(), 1);
Closing();
EXPECT_TRUE(iframe_request_same_domain_.finished());
+ if (GetParam())
+ EXPECT_TRUE(request1_.finished());
+ else
+ EXPECT_TRUE(iframe_request_same_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest,
+TEST_P(PermissionRequestManagerTest,
IFrameRequestOtherDomainWhenMainRequestVisible) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
@@ -495,14 +557,23 @@ TEST_F(PermissionRequestManagerTest,
&iframe_request_other_domain_);
WaitForFrameLoad();
Closing();
- EXPECT_TRUE(request1_.finished());
- EXPECT_FALSE(iframe_request_other_domain_.finished());
+ if (GetParam()) {
+ EXPECT_TRUE(iframe_request_other_domain_.finished());
+ EXPECT_FALSE(request1_.finished());
+ } else {
+ EXPECT_TRUE(request1_.finished());
+ EXPECT_FALSE(iframe_request_other_domain_.finished());
+ }
+
EXPECT_TRUE(prompt_factory_->is_visible());
Closing();
- EXPECT_TRUE(iframe_request_other_domain_.finished());
+ if (GetParam())
+ EXPECT_TRUE(request1_.finished());
+ else
+ EXPECT_TRUE(iframe_request_other_domain_.finished());
}
-TEST_F(PermissionRequestManagerTest, RequestsDontNeedUserGesture) {
+TEST_P(PermissionRequestManagerTest, RequestsDontNeedUserGesture) {
WaitForFrameLoad();
WaitForBubbleToBeShown();
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
@@ -517,7 +588,7 @@ TEST_F(PermissionRequestManagerTest, RequestsDontNeedUserGesture) {
// This code path (calling Accept on a non-merged bubble, with no accepted
// permission) would never be used in actual Chrome, but its still tested for
// completeness.
-TEST_F(PermissionRequestManagerTest, UMAForSimpleDeniedBubbleAlternatePath) {
+TEST_P(PermissionRequestManagerTest, UMAForSimpleDeniedBubbleAlternatePath) {
base::HistogramTester histograms;
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
@@ -532,7 +603,7 @@ TEST_F(PermissionRequestManagerTest, UMAForSimpleDeniedBubbleAlternatePath) {
1);
}
-TEST_F(PermissionRequestManagerTest, UMAForTabSwitching) {
+TEST_P(PermissionRequestManagerTest, UMAForTabSwitching) {
base::HistogramTester histograms;
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
@@ -576,7 +647,7 @@ class MockNotificationPermissionUiSelector
static void CreateForManager(PermissionRequestManager* manager,
base::Optional<QuietUiReason> quiet_ui_reason,
bool async) {
- manager->set_notification_permission_ui_selector_for_testing(
+ manager->add_notification_permission_ui_selector_for_testing(
std::make_unique<MockNotificationPermissionUiSelector>(quiet_ui_reason,
async));
}
@@ -586,9 +657,10 @@ class MockNotificationPermissionUiSelector
bool async_;
};
-TEST_F(PermissionRequestManagerTest,
+TEST_P(PermissionRequestManagerTest,
UiSelectorNotUsedForPermissionsOtherThanNotification) {
for (auto* request : {&request_mic_, &request_camera_, &request_ptz_}) {
+ manager_->clear_notification_permission_ui_selector_for_testing();
MockNotificationPermissionUiSelector::CreateForManager(
manager_,
NotificationPermissionUiSelector::QuietUiReason::kEnabledInPrefs,
@@ -607,7 +679,7 @@ TEST_F(PermissionRequestManagerTest,
}
}
-TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
+TEST_P(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
const struct {
base::Optional<NotificationPermissionUiSelector::QuietUiReason>
quiet_ui_reason;
@@ -620,6 +692,7 @@ TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
};
for (const auto& test : kTests) {
+ manager_->clear_notification_permission_ui_selector_for_testing();
MockNotificationPermissionUiSelector::CreateForManager(
manager_, test.quiet_ui_reason, test.async);
@@ -641,9 +714,10 @@ TEST_F(PermissionRequestManagerTest, UiSelectorUsedForNotifications) {
}
}
-TEST_F(PermissionRequestManagerTest,
+TEST_P(PermissionRequestManagerTest,
UiSelectionHappensSeparatelyForEachRequest) {
using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
+ manager_->clear_notification_permission_ui_selector_for_testing();
MockNotificationPermissionUiSelector::CreateForManager(
manager_, QuietUiReason::kEnabledInPrefs, true);
MockPermissionRequest request1(
@@ -657,6 +731,7 @@ TEST_F(PermissionRequestManagerTest,
MockPermissionRequest request2(
"request2", PermissionRequestType::PERMISSION_NOTIFICATIONS,
PermissionRequestGestureType::GESTURE);
+ manager_->clear_notification_permission_ui_selector_for_testing();
MockNotificationPermissionUiSelector::CreateForManager(
manager_, NotificationPermissionUiSelector::Decision::UseNormalUi(),
true);
@@ -666,7 +741,7 @@ TEST_F(PermissionRequestManagerTest,
Accept();
}
-TEST_F(PermissionRequestManagerTest, RequestsNotSupported) {
+TEST_P(PermissionRequestManagerTest, RequestsNotSupported) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
WaitForBubbleToBeShown();
Accept();
@@ -677,4 +752,174 @@ TEST_F(PermissionRequestManagerTest, RequestsNotSupported) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
EXPECT_TRUE(request2_.cancelled());
}
+
+TEST_P(PermissionRequestManagerTest, MultipleUiSelectors) {
+ using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
+
+ const struct {
+ std::vector<base::Optional<QuietUiReason>> quiet_ui_reasons;
+ std::vector<bool> simulate_delayed_decision;
+ base::Optional<QuietUiReason> expected_reason;
+ } kTests[] = {
+ // Simple sync selectors, first one should take priority.
+ {{QuietUiReason::kTriggeredByCrowdDeny, QuietUiReason::kEnabledInPrefs},
+ {false, false},
+ QuietUiReason::kTriggeredByCrowdDeny},
+ // First selector is async but should still take priority even if it
+ // returns later.
+ {{QuietUiReason::kTriggeredByCrowdDeny, QuietUiReason::kEnabledInPrefs},
+ {true, false},
+ QuietUiReason::kTriggeredByCrowdDeny},
+ // The first selector that has a quiet ui decision should be used.
+ {{base::nullopt, base::nullopt,
+ QuietUiReason::kTriggeredDueToAbusiveContent,
+ QuietUiReason::kEnabledInPrefs},
+ {false, true, true, false},
+ QuietUiReason::kTriggeredDueToAbusiveContent},
+ // If all selectors return a normal ui, it should use a normal ui.
+ {{base::nullopt, base::nullopt}, {false, true}, base::nullopt},
+
+ // Use a bunch of selectors both async and sync.
+ {{base::nullopt, base::nullopt, base::nullopt, base::nullopt,
+ base::nullopt, QuietUiReason::kTriggeredDueToAbusiveRequests,
+ base::nullopt, QuietUiReason::kEnabledInPrefs},
+ {false, true, false, true, true, true, false, false},
+ QuietUiReason::kTriggeredDueToAbusiveRequests},
+ // Use a bunch of selectors all sync.
+ {{base::nullopt, base::nullopt, base::nullopt, base::nullopt,
+ base::nullopt, QuietUiReason::kTriggeredDueToAbusiveRequests,
+ base::nullopt, QuietUiReason::kEnabledInPrefs},
+ {false, false, false, false, false, false, false, false},
+ QuietUiReason::kTriggeredDueToAbusiveRequests},
+ // Use a bunch of selectors all async.
+ {{base::nullopt, base::nullopt, base::nullopt, base::nullopt,
+ base::nullopt, QuietUiReason::kTriggeredDueToAbusiveRequests,
+ base::nullopt, QuietUiReason::kEnabledInPrefs},
+ {true, true, true, true, true, true, true, true},
+ QuietUiReason::kTriggeredDueToAbusiveRequests},
+ };
+
+ for (const auto& test : kTests) {
+ manager_->clear_notification_permission_ui_selector_for_testing();
+ for (size_t i = 0; i < test.quiet_ui_reasons.size(); ++i) {
+ MockNotificationPermissionUiSelector::CreateForManager(
+ manager_, test.quiet_ui_reasons[i],
+ test.simulate_delayed_decision[i]);
+ }
+
+ MockPermissionRequest request(
+ "foo", PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ PermissionRequestGestureType::GESTURE);
+
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request);
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_TRUE(
+ prompt_factory_->RequestTypeSeen(request.GetPermissionRequestType()));
+ if (test.expected_reason.has_value()) {
+ EXPECT_EQ(test.expected_reason, manager_->ReasonForUsingQuietUi());
+ } else {
+ EXPECT_FALSE(manager_->ShouldCurrentRequestUseQuietUI());
+ }
+
+ Accept();
+ EXPECT_TRUE(request.granted());
+ }
+}
+
+TEST_P(PermissionRequestManagerTest, ThreeRequestsStackOrderChip) {
+ if (!GetParam())
+ return;
+
+ // Test new permissions order, requests shouldn't be grouped.
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request_mic_.granted());
+ EXPECT_FALSE(request2_.granted());
+ EXPECT_FALSE(request1_.granted());
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request2_.granted());
+ EXPECT_FALSE(request1_.granted());
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request1_.granted());
+}
+
+// Test new permissions order by adding requests one at a time.
+TEST_P(PermissionRequestManagerTest, ThreeRequestsOneByOneStackOrderChip) {
+ if (!GetParam())
+ return;
+
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
+ WaitForBubbleToBeShown();
+
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request2_);
+ WaitForBubbleToBeShown();
+
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request_mic_.granted());
+ EXPECT_FALSE(request2_.granted());
+ EXPECT_FALSE(request1_.granted());
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request2_.granted());
+ EXPECT_FALSE(request1_.granted());
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request1_.granted());
+}
+
+// Test if grouping media requests works with new requests order processing.
+TEST_P(PermissionRequestManagerTest, GroupedMediaRequestsChip) {
+ if (!GetParam())
+ return;
+
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request1_);
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
+ manager_->AddRequest(web_contents()->GetMainFrame(), &request_mic_);
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 2);
+ Accept();
+ EXPECT_TRUE(request_camera_.granted());
+ EXPECT_TRUE(request_mic_.granted());
+ EXPECT_FALSE(request1_.granted());
+ WaitForBubbleToBeShown();
+
+ EXPECT_TRUE(prompt_factory_->is_visible());
+ EXPECT_EQ(prompt_factory_->request_count(), 1);
+ Accept();
+ EXPECT_TRUE(request1_.granted());
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ PermissionRequestManagerTest,
+ ::testing::Values(false, true));
+
} // namespace permissions
diff --git a/chromium/components/permissions/permission_uma_util.cc b/chromium/components/permissions/permission_uma_util.cc
index 0cac71e89e4..600f7936650 100644
--- a/chromium/components/permissions/permission_uma_util.cc
+++ b/chromium/components/permissions/permission_uma_util.cc
@@ -110,13 +110,13 @@ void RecordEngagementMetric(const std::vector<PermissionRequest*>& requests,
type = PermissionRequestType::MULTIPLE;
DCHECK(action == "Accepted" || action == "Denied" || action == "Dismissed" ||
- action == "Ignored");
+ action == "Ignored" || action == "AcceptedOnce");
std::string name = "Permissions.Engagement." + action + '.' +
GetPermissionRequestString(type);
double engagement_score = PermissionsClient::Get()->GetSiteEngagementScore(
web_contents->GetBrowserContext(), requests[0]->GetOrigin());
- base::UmaHistogramPercentage(name, engagement_score);
+ base::UmaHistogramPercentageObsoleteDoNotUse(name, engagement_score);
}
void RecordPermissionActionUkm(
@@ -127,8 +127,11 @@ void RecordPermissionActionUkm(
int ignore_count,
PermissionSourceUI source_ui,
PermissionPromptDisposition ui_disposition,
+ base::Optional<PermissionPromptDispositionReason> ui_reason,
base::Optional<bool> has_three_consecutive_denies,
base::Optional<bool> has_previously_revoked_permission,
+ base::Optional<PermissionUmaUtil::PredictionGrantLikelihood>
+ predicted_grant_likelihood,
base::Optional<ukm::SourceId> source_id) {
// Only record the permission change if the origin is in the history.
if (!source_id.has_value())
@@ -146,6 +149,14 @@ void RecordPermissionActionUkm(
.SetSource(static_cast<int64_t>(source_ui))
.SetPromptDisposition(static_cast<int64_t>(ui_disposition));
+ if (ui_reason.has_value())
+ builder.SetPromptDispositionReason(static_cast<int64_t>(ui_reason.value()));
+
+ if (predicted_grant_likelihood.has_value()) {
+ builder.SetPredictionsApiResponse_GrantLikelihood(
+ static_cast<int64_t>(predicted_grant_likelihood.value()));
+ }
+
if (has_three_consecutive_denies.has_value()) {
int64_t satisfied_adaptive_triggers = 0;
if (has_three_consecutive_denies.value())
@@ -171,6 +182,8 @@ std::string GetPromptDispositionString(
switch (ui_disposition) {
case PermissionPromptDisposition::ANCHORED_BUBBLE:
return "AnchoredBubble";
+ case PermissionPromptDisposition::CUSTOM_MODAL_DIALOG:
+ return "CustomModalDialog";
case PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP:
return "LocationBarLeftChip";
case PermissionPromptDisposition::LOCATION_BAR_RIGHT_ANIMATED_ICON:
@@ -238,6 +251,12 @@ const char PermissionUmaUtil::kPermissionsPromptAcceptedGesture[] =
"Permissions.Prompt.Accepted.Gesture";
const char PermissionUmaUtil::kPermissionsPromptAcceptedNoGesture[] =
"Permissions.Prompt.Accepted.NoGesture";
+const char PermissionUmaUtil::kPermissionsPromptAcceptedOnce[] =
+ "Permissions.Prompt.AcceptedOnce";
+const char PermissionUmaUtil::kPermissionsPromptAcceptedOnceGesture[] =
+ "Permissions.Prompt.AcceptedOnce.Gesture";
+const char PermissionUmaUtil::kPermissionsPromptAcceptedOnceNoGesture[] =
+ "Permissions.Prompt.AcceptedOnce.NoGesture";
const char PermissionUmaUtil::kPermissionsPromptDenied[] =
"Permissions.Prompt.Denied";
const char PermissionUmaUtil::kPermissionsPromptDeniedGesture[] =
@@ -284,8 +303,9 @@ void PermissionUmaUtil::PermissionRevoked(
RecordPermissionAction(permission, PermissionAction::REVOKED, source_ui,
PermissionRequestGestureType::UNKNOWN,
PermissionPromptDisposition::NOT_APPLICABLE,
- revoked_origin,
- /*web_contents=*/nullptr, browser_context);
+ base::nullopt /* ui_reason */, revoked_origin,
+ nullptr /* web_contents */, browser_context,
+ base::nullopt /* predicted_grant_likelihood */);
}
}
@@ -349,16 +369,18 @@ void PermissionUmaUtil::PermissionPromptResolved(
const std::vector<PermissionRequest*>& requests,
content::WebContents* web_contents,
PermissionAction permission_action,
- PermissionPromptDisposition ui_disposition) {
+ PermissionPromptDisposition ui_disposition,
+ base::Optional<PermissionPromptDispositionReason> ui_reason,
+ base::Optional<PredictionGrantLikelihood> predicted_grant_likelihood) {
std::string action_string;
switch (permission_action) {
case PermissionAction::GRANTED:
- RecordPromptDecided(requests, /*accepted=*/true);
+ RecordPromptDecided(requests, /*accepted=*/true, /*is_one_time=*/false);
action_string = "Accepted";
break;
case PermissionAction::DENIED:
- RecordPromptDecided(requests, /*accepted=*/false);
+ RecordPromptDecided(requests, /*accepted=*/false, /*is_one_time*/ false);
action_string = "Denied";
break;
case PermissionAction::DISMISSED:
@@ -367,10 +389,15 @@ void PermissionUmaUtil::PermissionPromptResolved(
case PermissionAction::IGNORED:
action_string = "Ignored";
break;
+ case PermissionAction::GRANTED_ONCE:
+ RecordPromptDecided(requests, /*accepted=*/true, /*is_one_time*/ true);
+ action_string = "AcceptedOnce";
+ break;
default:
NOTREACHED();
break;
}
+
RecordEngagementMetric(requests, web_contents, action_string);
PermissionDecisionAutoBlocker* autoblocker =
@@ -388,10 +415,10 @@ void PermissionUmaUtil::PermissionPromptResolved(
PermissionRequestGestureType gesture_type = request->GetGestureType();
const GURL& requesting_origin = request->GetOrigin();
- RecordPermissionAction(permission, permission_action,
- PermissionSourceUI::PROMPT, gesture_type,
- ui_disposition, requesting_origin, web_contents,
- web_contents->GetBrowserContext());
+ RecordPermissionAction(
+ permission, permission_action, PermissionSourceUI::PROMPT, gesture_type,
+ ui_disposition, ui_reason, requesting_origin, web_contents,
+ web_contents->GetBrowserContext(), predicted_grant_likelihood);
std::string priorDismissPrefix =
"Permissions.Prompt." + action_string + ".PriorDismissCount2.";
@@ -499,11 +526,11 @@ PermissionUmaUtil::ScopedRevocationReporter::ScopedRevocationReporter(
HostContentSettingsMap* settings_map =
PermissionsClient::Get()->GetSettingsMap(browser_context_);
ContentSetting initial_content_setting = settings_map->GetContentSetting(
- primary_url_, secondary_url_, content_type_, std::string());
+ primary_url_, secondary_url_, content_type_);
is_initially_allowed_ = initial_content_setting == CONTENT_SETTING_ALLOW;
content_settings::SettingInfo setting_info;
settings_map->GetWebsiteSetting(primary_url, secondary_url, content_type_,
- std::string(), &setting_info);
+ &setting_info);
last_modified_date_ = settings_map->GetSettingLastModifiedDate(
setting_info.primary_pattern, setting_info.secondary_pattern,
content_type);
@@ -530,7 +557,7 @@ PermissionUmaUtil::ScopedRevocationReporter::~ScopedRevocationReporter() {
HostContentSettingsMap* settings_map =
PermissionsClient::Get()->GetSettingsMap(browser_context_);
ContentSetting final_content_setting = settings_map->GetContentSetting(
- primary_url_, secondary_url_, content_type_, std::string());
+ primary_url_, secondary_url_, content_type_);
if (final_content_setting != CONTENT_SETTING_ALLOW) {
// PermissionUmaUtil takes origins, even though they're typed as GURL.
GURL requesting_origin = primary_url_.GetOrigin();
@@ -552,9 +579,11 @@ void PermissionUmaUtil::RecordPermissionAction(
PermissionSourceUI source_ui,
PermissionRequestGestureType gesture_type,
PermissionPromptDisposition ui_disposition,
+ base::Optional<PermissionPromptDispositionReason> ui_reason,
const GURL& requesting_origin,
const content::WebContents* web_contents,
- content::BrowserContext* browser_context) {
+ content::BrowserContext* browser_context,
+ base::Optional<PredictionGrantLikelihood> predicted_grant_likelihood) {
PermissionDecisionAutoBlocker* autoblocker =
PermissionsClient::Get()->GetPermissionDecisionAutoBlocker(
browser_context);
@@ -566,14 +595,15 @@ void PermissionUmaUtil::RecordPermissionAction(
browser_context, web_contents, requesting_origin,
base::BindOnce(
&RecordPermissionActionUkm, action, gesture_type, permission,
- dismiss_count, ignore_count, source_ui, ui_disposition,
+ dismiss_count, ignore_count, source_ui, ui_disposition, ui_reason,
permission == ContentSettingsType::NOTIFICATIONS
? PermissionsClient::Get()
->HadThreeConsecutiveNotificationPermissionDenies(
browser_context)
: base::nullopt,
PermissionsClient::Get()->HasPreviouslyAutoRevokedPermission(
- browser_context, requesting_origin, permission)));
+ browser_context, requesting_origin, permission),
+ predicted_grant_likelihood));
switch (permission) {
case ContentSettingsType::GEOLOCATION:
@@ -656,7 +686,8 @@ void PermissionUmaUtil::RecordPermissionAction(
// static
void PermissionUmaUtil::RecordPromptDecided(
const std::vector<PermissionRequest*>& requests,
- bool accepted) {
+ bool accepted,
+ bool is_one_time) {
DCHECK(!requests.empty());
PermissionRequestType request_type = PermissionRequestType::MULTIPLE;
@@ -668,10 +699,17 @@ void PermissionUmaUtil::RecordPromptDecided(
}
if (accepted) {
- PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptAccepted, request_type);
- PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptAcceptedGesture,
- kPermissionsPromptAcceptedNoGesture,
- gesture_type, request_type);
+ if (is_one_time) {
+ PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptAcceptedOnce, request_type);
+ PERMISSION_BUBBLE_GESTURE_TYPE_UMA(
+ kPermissionsPromptAcceptedOnceGesture,
+ kPermissionsPromptAcceptedOnceNoGesture, gesture_type, request_type);
+ } else {
+ PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptAccepted, request_type);
+ PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptAcceptedGesture,
+ kPermissionsPromptAcceptedNoGesture,
+ gesture_type, request_type);
+ }
} else {
PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptDenied, request_type);
PERMISSION_BUBBLE_GESTURE_TYPE_UMA(kPermissionsPromptDeniedGesture,
diff --git a/chromium/components/permissions/permission_uma_util.h b/chromium/components/permissions/permission_uma_util.h
index 4bf397f6f72..8ae252c745f 100644
--- a/chromium/components/permissions/permission_uma_util.h
+++ b/chromium/components/permissions/permission_uma_util.h
@@ -13,6 +13,7 @@
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_result.h"
#include "components/permissions/permission_util.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
namespace content {
class BrowserContext;
@@ -104,6 +105,28 @@ enum class PermissionPromptDisposition {
// There was no UI being shown. This is usually because the user closed an
// inactive tab that had a pending permission request.
NONE_VISIBLE = 7,
+
+ // Other custom modal dialogs.
+ CUSTOM_MODAL_DIALOG = 8,
+};
+
+// The reason why the permission prompt disposition was used. Enum used in UKMs,
+// do not re-order or change values. Deprecated items should only be commented
+// out.
+enum class PermissionPromptDispositionReason {
+ // Disposition was selected in prefs.
+ USER_PREFERENCE_IN_SETTINGS = 0,
+
+ // Disposition was chosen because Safe Browsing classifies the origin
+ // as being spammy or abusive with permission requests.
+ SAFE_BROWSING_VERDICT = 1,
+
+ // Disposition was chosen based on grant likelihood predicted by the
+ // Web Permission Prediction Service.
+ PREDICTION_SERVICE = 2,
+
+ // Disposition was used as a fallback, if no selector made a decision.
+ DEFAULT_FALLBACK = 3,
};
enum class AdaptiveTriggers {
@@ -126,12 +149,18 @@ enum class PermissionAutoRevocationHistory {
// Provides a convenient way of logging UMA for permission related operations.
class PermissionUmaUtil {
public:
+ using PredictionGrantLikelihood =
+ PermissionSuggestion_Likelihood_DiscretizedLikelihood;
+
static const char kPermissionsPromptShown[];
static const char kPermissionsPromptShownGesture[];
static const char kPermissionsPromptShownNoGesture[];
static const char kPermissionsPromptAccepted[];
static const char kPermissionsPromptAcceptedGesture[];
static const char kPermissionsPromptAcceptedNoGesture[];
+ static const char kPermissionsPromptAcceptedOnce[];
+ static const char kPermissionsPromptAcceptedOnceGesture[];
+ static const char kPermissionsPromptAcceptedOnceNoGesture[];
static const char kPermissionsPromptDenied[];
static const char kPermissionsPromptDeniedGesture[];
static const char kPermissionsPromptDeniedNoGesture[];
@@ -167,7 +196,9 @@ class PermissionUmaUtil {
const std::vector<PermissionRequest*>& requests,
content::WebContents* web_contents,
PermissionAction permission_action,
- PermissionPromptDisposition ui_disposition);
+ PermissionPromptDisposition ui_disposition,
+ base::Optional<PermissionPromptDispositionReason> ui_reason,
+ base::Optional<PredictionGrantLikelihood> predicted_grant_likelihood);
static void RecordWithBatteryBucket(const std::string& histogram);
@@ -225,14 +256,17 @@ class PermissionUmaUtil {
friend class PermissionUmaUtilTest;
// web_contents may be null when for recording non-prompt actions.
- static void RecordPermissionAction(ContentSettingsType permission,
- PermissionAction action,
- PermissionSourceUI source_ui,
- PermissionRequestGestureType gesture_type,
- PermissionPromptDisposition ui_disposition,
- const GURL& requesting_origin,
- const content::WebContents* web_contents,
- content::BrowserContext* browser_context);
+ static void RecordPermissionAction(
+ ContentSettingsType permission,
+ PermissionAction action,
+ PermissionSourceUI source_ui,
+ PermissionRequestGestureType gesture_type,
+ PermissionPromptDisposition ui_disposition,
+ base::Optional<PermissionPromptDispositionReason> ui_reason,
+ const GURL& requesting_origin,
+ const content::WebContents* web_contents,
+ content::BrowserContext* browser_context,
+ base::Optional<PredictionGrantLikelihood> predicted_grant_likelihood);
// Records |count| total prior actions for a prompt of type |permission|
// for a single origin using |prefix| for the metric.
@@ -242,7 +276,8 @@ class PermissionUmaUtil {
static void RecordPromptDecided(
const std::vector<PermissionRequest*>& requests,
- bool accepted);
+ bool accepted,
+ bool is_one_time);
DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionUmaUtil);
};
diff --git a/chromium/components/permissions/permission_uma_util_unittest.cc b/chromium/components/permissions/permission_uma_util_unittest.cc
index a902bb9ef5c..1a13e706167 100644
--- a/chromium/components/permissions/permission_uma_util_unittest.cc
+++ b/chromium/components/permissions/permission_uma_util_unittest.cc
@@ -37,13 +37,11 @@ TEST_F(PermissionUmaUtilTest, ScopedRevocationReporter) {
PermissionSourceUI source_ui = PermissionSourceUI::SITE_SETTINGS;
// Allow->Block triggers a revocation.
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
- CONTENT_SETTING_ALLOW);
+ map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host, host, type, source_ui);
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
- CONTENT_SETTING_BLOCK);
+ map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_BLOCK);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
static_cast<int>(PermissionAction::REVOKED), 1);
@@ -52,8 +50,7 @@ TEST_F(PermissionUmaUtilTest, ScopedRevocationReporter) {
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host, host, type, source_ui);
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
- CONTENT_SETTING_ALLOW);
+ map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
static_cast<int>(PermissionAction::REVOKED), 1);
@@ -63,7 +60,7 @@ TEST_F(PermissionUmaUtilTest, ScopedRevocationReporter) {
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host, host, type, source_ui);
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
+ map->SetContentSettingDefaultScope(host, host, type,
CONTENT_SETTING_DEFAULT);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
@@ -74,35 +71,33 @@ TEST_F(PermissionUmaUtilTest, ScopedRevocationReporter) {
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host, host, type, source_ui);
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
+ map->SetContentSettingDefaultScope(host, host, type,
CONTENT_SETTING_DEFAULT);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
static_cast<int>(PermissionAction::REVOKED), 2);
// Allow->Block with url pattern string triggers a revocation.
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
- CONTENT_SETTING_ALLOW);
+ map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host_pattern, host_pattern, type, source_ui);
map->SetContentSettingCustomScope(host_pattern,
ContentSettingsPattern::Wildcard(), type,
- std::string(), CONTENT_SETTING_BLOCK);
+ CONTENT_SETTING_BLOCK);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
static_cast<int>(PermissionAction::REVOKED), 3);
// Allow->Block with non url pattern string does not trigger a revocation.
- map->SetContentSettingDefaultScope(host, host, type, std::string(),
- CONTENT_SETTING_ALLOW);
+ map->SetContentSettingDefaultScope(host, host, type, CONTENT_SETTING_ALLOW);
{
PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter(
&browser_context, host_containing_wildcards_pattern, host_pattern, type,
source_ui);
map->SetContentSettingCustomScope(host_containing_wildcards_pattern,
ContentSettingsPattern::Wildcard(), type,
- std::string(), CONTENT_SETTING_BLOCK);
+ CONTENT_SETTING_BLOCK);
}
histograms.ExpectBucketCount("Permissions.Action.Geolocation",
static_cast<int>(PermissionAction::REVOKED), 3);
diff --git a/chromium/components/permissions/permission_util.h b/chromium/components/permissions/permission_util.h
index 2cb93a4ba2b..73c2394a95f 100644
--- a/chromium/components/permissions/permission_util.h
+++ b/chromium/components/permissions/permission_util.h
@@ -26,6 +26,7 @@ enum class PermissionAction {
DISMISSED = 2,
IGNORED = 3,
REVOKED = 4,
+ GRANTED_ONCE = 5,
// Always keep this at the end.
NUM,
diff --git a/chromium/components/permissions/permissions_client.cc b/chromium/components/permissions/permissions_client.cc
index 96dca126088..19fa0bf7199 100644
--- a/chromium/components/permissions/permissions_client.cc
+++ b/chromium/components/permissions/permissions_client.cc
@@ -68,10 +68,10 @@ PermissionRequest::IconId PermissionsClient::GetOverrideIconId(
#endif
}
-std::unique_ptr<NotificationPermissionUiSelector>
-PermissionsClient::CreateNotificationPermissionUiSelector(
+std::vector<std::unique_ptr<NotificationPermissionUiSelector>>
+PermissionsClient::CreateNotificationPermissionUiSelectors(
content::BrowserContext* browser_context) {
- return nullptr;
+ return std::vector<std::unique_ptr<NotificationPermissionUiSelector>>();
}
void PermissionsClient::OnPromptResolved(
diff --git a/chromium/components/permissions/permissions_client.h b/chromium/components/permissions/permissions_client.h
index 406be4f7f19..c8e8c1f94a5 100644
--- a/chromium/components/permissions/permissions_client.h
+++ b/chromium/components/permissions/permissions_client.h
@@ -121,11 +121,14 @@ class PermissionsClient {
// used.
virtual PermissionRequest::IconId GetOverrideIconId(ContentSettingsType type);
- // Allows the embedder to provide a selector for chossing the UI to use for
- // notification permission requests. If the embedder returns null here, the
- // normal UI will be used.
- virtual std::unique_ptr<NotificationPermissionUiSelector>
- CreateNotificationPermissionUiSelector(
+ // Allows the embedder to provide a list of selectors for choosing the UI to
+ // use for notification permission requests. If the embedder returns an empty
+ // list, the normal UI will be used always. Then for each request, if none of
+ // the returned selectors prescribe the quiet UI, the normal UI will be used.
+ // Otherwise the quiet UI will be used. Selectors at lower indices have higher
+ // priority when determining the quiet UI flavor.
+ virtual std::vector<std::unique_ptr<NotificationPermissionUiSelector>>
+ CreateNotificationPermissionUiSelectors(
content::BrowserContext* browser_context);
using QuietUiReason = NotificationPermissionUiSelector::QuietUiReason;
diff --git a/chromium/components/permissions/prediction_service/BUILD.gn b/chromium/components/permissions/prediction_service/BUILD.gn
new file mode 100644
index 00000000000..96b42b99f5c
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2020 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("//third_party/protobuf/proto_library.gni")
+
+proto_library("prediction_service_messages_proto") {
+ sources = [ "prediction_service_messages.proto" ]
+}
+
+source_set("prediction_service") {
+ sources = [
+ "prediction_request_features.h",
+ "prediction_service.cc",
+ "prediction_service.h",
+ "prediction_service_base.h",
+ "prediction_service_common.cc",
+ "prediction_service_common.h",
+ ]
+ deps = [
+ "//components/keyed_service/content",
+ "//components/permissions:permissions_common",
+ "//services/network/public/cpp:cpp",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+ public_deps = [ ":prediction_service_messages_proto" ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [ "prediction_service_unittest.cc" ]
+ deps = [
+ ":prediction_service",
+ "//base/test:test_support",
+ "//components/permissions:permissions_common",
+ "//services/network:test_support",
+ "//services/network/public/cpp:cpp",
+ "//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
+ "//ui/gfx",
+ ]
+}
diff --git a/chromium/components/permissions/prediction_service/DEPS b/chromium/components/permissions/prediction_service/DEPS
new file mode 100644
index 00000000000..e1fbc94db6e
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+google/protobuf",
+ "+net",
+ "+services/network/public",
+ "+services/network/test",
+ "+third_party/googletest",
+]
diff --git a/chromium/components/permissions/prediction_service/prediction_request_features.h b/chromium/components/permissions/prediction_service/prediction_request_features.h
new file mode 100644
index 00000000000..ec634f8d0fd
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_request_features.h
@@ -0,0 +1,35 @@
+// Copyright 2020 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_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_REQUEST_FEATURES_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_REQUEST_FEATURES_H_
+
+#include "components/permissions/permission_request_enums.h"
+
+namespace permissions {
+
+struct PredictionRequestFeatures {
+ struct ActionCounts {
+ size_t grants = 0;
+ size_t denies = 0;
+ size_t dismissals = 0;
+ size_t ignores = 0;
+ };
+
+ // Whether a gesture is present or not.
+ PermissionRequestGestureType gesture;
+
+ // Which permissions request type this is for.
+ PermissionRequestType type;
+
+ // The permission action counts for this specific permission type.
+ ActionCounts requested_permission_counts;
+
+ // The permission action counts for all permissions type.
+ ActionCounts all_permission_counts;
+};
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_REQUEST_FEATURES_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service.cc b/chromium/components/permissions/prediction_service/prediction_service.cc
new file mode 100644
index 00000000000..d62defde0b6
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service.cc
@@ -0,0 +1,269 @@
+// Copyright 2020 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/permissions/prediction_service/prediction_service.h"
+
+#include <cmath>
+#include <memory>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
+#include "base/notreached.h"
+#include "components/permissions/features.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_common.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+
+namespace {
+
+constexpr base::TimeDelta kURLLookupTimeout = base::TimeDelta::FromSeconds(2);
+
+permissions::ClientFeatures_Gesture ConvertToProtoGesture(
+ const permissions::PermissionRequestGestureType type) {
+ switch (type) {
+ case permissions::PermissionRequestGestureType::GESTURE:
+ return permissions::ClientFeatures_Gesture_GESTURE;
+ case permissions::PermissionRequestGestureType::NO_GESTURE:
+ return permissions::ClientFeatures_Gesture_NO_GESTURE;
+ case permissions::PermissionRequestGestureType::UNKNOWN:
+ return permissions::ClientFeatures_Gesture_UNKNOWN_GESTURE;
+ case permissions::PermissionRequestGestureType::NUM:
+ break;
+ }
+
+ NOTREACHED();
+ return permissions::ClientFeatures_Gesture_UNKNOWN_GESTURE;
+}
+
+inline float GetRatioRoundedToTwoDecimals(int numerator, int denominator) {
+ if (denominator == 0)
+ return 0;
+ return roundf(100.f * numerator / denominator) / 100.f;
+}
+
+void FillInStatsFeatures(
+ const permissions::PredictionRequestFeatures::ActionCounts& counts,
+ permissions::StatsFeatures* features) {
+ int total_counts =
+ counts.denies + counts.dismissals + counts.grants + counts.ignores;
+
+ // Round to only 2 decimal places to help prevent fingerprinting.
+ features->set_avg_deny_rate(
+ GetRatioRoundedToTwoDecimals(counts.denies, total_counts));
+ features->set_avg_dismiss_rate(
+ GetRatioRoundedToTwoDecimals(counts.dismissals, total_counts));
+ features->set_avg_grant_rate(
+ GetRatioRoundedToTwoDecimals(counts.grants, total_counts));
+ features->set_avg_ignore_rate(
+ GetRatioRoundedToTwoDecimals(counts.ignores, total_counts));
+
+ // Prevent hyperspecific large counts from becoming usable to fingerprint
+ // users that see an unexpectedly large prompt count.
+ features->set_prompts_count(std::min(total_counts, 100));
+}
+
+net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() {
+ return net::DefineNetworkTrafficAnnotation("permission_predictions", R"(
+ semantics {
+ sender: "Web Permission Perdictions"
+ description:
+ "A request to the Web Permission Predictions Service. The service will "
+ "attempt to predict the likelihood that the user would grant this "
+ "permission. Based on this prediction Chrome might decide to present "
+ "the user with a different UI; a less intrusive one."
+ trigger:
+ "A permission prompt is about to be shown to the user, and the user "
+ "has opted into Safe Browsing's Enhanced Protection."
+ data:
+ "User stats helpful for attempting to predict the user's likelihood "
+ "of granting the permission: the permission type, the presence of a "
+ "user gesture, the user's OS, average deny/grant/ignore/dismiss rates "
+ "and total prompts shown, both for the specific permission type and "
+ "overall for all permission types."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This can be disabled by disabling Enhanced Protection by going to "
+ "Settings and then to the Security sub-menu."
+ chrome_policy {
+ SafeBrowsingProtectionLevel {
+ SafeBrowsingProtectionLevel: 1
+ }
+ }
+ })");
+}
+
+} // namespace
+
+namespace permissions {
+
+PredictionService::PredictionService(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+ : url_loader_factory_(url_loader_factory) {}
+PredictionService::~PredictionService() = default;
+
+void PredictionService::StartLookup(const PredictionRequestFeatures& entity,
+ LookupRequestCallback request_callback,
+ LookupResponseCallback response_callback) {
+ auto request = GetResourceRequest();
+ auto proto_request = GetPredictionRequestProto(entity);
+ std::string request_data;
+ proto_request->SerializeToString(&request_data);
+
+ SendRequestInternal(std::move(request), request_data, entity,
+ std::move(response_callback));
+
+ if (request_callback)
+ std::move(request_callback).Run(std::move(proto_request), std::string());
+}
+
+// static
+const GURL PredictionService::GetPredictionServiceUrl(
+ bool recalculate_for_testing) {
+ static base::NoDestructor<GURL> default_prediction_service_url{
+ kDefaultPredictionServiceUrl};
+ static base::NoDestructor<GURL> command_line_url_override{
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kDefaultPredictionServiceUrlSwitchKey)};
+ static base::NoDestructor<GURL> feature_param_url_override{
+ feature_params::kPermissionPredictionServiceUrlOverride.Get()};
+
+ // To facilitate tests that want to exercise various url building logic,
+ // reinitialize the static variables if this flag is set.
+ if (recalculate_for_testing) {
+ *command_line_url_override =
+ GURL(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kDefaultPredictionServiceUrlSwitchKey));
+ *feature_param_url_override =
+ GURL(feature_params::kPermissionPredictionServiceUrlOverride.Get());
+ }
+
+ if (command_line_url_override->is_valid())
+ return *command_line_url_override;
+
+ if (feature_param_url_override->is_valid())
+ return *feature_param_url_override;
+
+ return *default_prediction_service_url;
+}
+
+std::unique_ptr<network::ResourceRequest>
+PredictionService::GetResourceRequest() {
+ auto request = std::make_unique<network::ResourceRequest>();
+
+ request->url =
+ prediction_service_url_override_.is_empty()
+ ? GetPredictionServiceUrl(recalculate_service_url_every_time)
+ : prediction_service_url_override_;
+ request->load_flags = net::LOAD_DISABLE_CACHE;
+ request->method = "POST";
+ request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+
+ return request;
+}
+
+std::unique_ptr<GetSuggestionsRequest>
+PredictionService::GetPredictionRequestProto(
+ const PredictionRequestFeatures& entity) {
+ auto proto_request = std::make_unique<GetSuggestionsRequest>();
+
+ ClientFeatures* client_features = proto_request->mutable_client_features();
+ client_features->set_platform(GetCurrentPlatformProto());
+ client_features->set_gesture(ConvertToProtoGesture(entity.gesture));
+ FillInStatsFeatures(entity.all_permission_counts,
+ client_features->mutable_client_stats());
+
+ PermissionFeatures* permission_features =
+ proto_request->mutable_permission_features()->Add();
+ FillInStatsFeatures(entity.requested_permission_counts,
+ permission_features->mutable_permission_stats());
+
+ switch (entity.type) {
+ case PermissionRequestType::PERMISSION_NOTIFICATIONS:
+ permission_features->mutable_notification_permission()
+ ->InitAsDefaultInstance();
+ break;
+ default:
+ NOTREACHED() << "CPSS only supports notifications at the moment.";
+ }
+
+ return proto_request;
+}
+
+void PredictionService::SendRequestInternal(
+ std::unique_ptr<network::ResourceRequest> request,
+ const std::string& request_data,
+ const PredictionRequestFeatures& entity,
+ LookupResponseCallback response_callback) {
+ std::unique_ptr<network::SimpleURLLoader> owned_loader =
+ network::SimpleURLLoader::Create(std::move(request),
+ GetTrafficAnnotationTag());
+ owned_loader->AttachStringForUpload(request_data, "application/x-protobuf");
+
+ owned_loader->SetTimeoutDuration(kURLLookupTimeout);
+ owned_loader->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(&PredictionService::OnURLLoaderComplete,
+ weak_factory_.GetWeakPtr(), entity, owned_loader.get(),
+ base::TimeTicks::Now()),
+ network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
+
+ pending_requests_[std::move(owned_loader)] = std::move(response_callback);
+}
+
+void PredictionService::OnURLLoaderComplete(
+ const PredictionRequestFeatures& entity,
+ network::SimpleURLLoader* loader,
+ base::TimeTicks request_start_time,
+ std::unique_ptr<std::string> response_body) {
+ for (auto& request : pending_requests_) {
+ if (request.first.get() == loader) {
+ auto prediction_response =
+ CreatePredictionsResponse(loader, response_body.get());
+
+ if (request.second) {
+ std::move(request.second)
+ .Run(prediction_response != nullptr /* Lookup successful */,
+ false /* Response from cache */,
+ std::move(prediction_response));
+ }
+
+ pending_requests_.erase(request.first);
+ return;
+ }
+ }
+
+ NOTREACHED() << "Unexpected loader callback.";
+}
+
+std::unique_ptr<GetSuggestionsResponse>
+PredictionService::CreatePredictionsResponse(network::SimpleURLLoader* loader,
+ const std::string* response_body) {
+ if (!response_body || loader->NetError() != net::OK ||
+ loader->ResponseInfo()->headers->response_code() != net::HTTP_OK) {
+ return nullptr;
+ }
+
+ auto predictions_response = std::make_unique<GetSuggestionsResponse>();
+
+ if (predictions_response->ParseFromString(*response_body)) {
+ return predictions_response;
+ }
+
+ return nullptr;
+}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/prediction_service/prediction_service.h b/chromium/components/permissions/prediction_service/prediction_service.h
new file mode 100644
index 00000000000..11a3a779c60
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service.h
@@ -0,0 +1,81 @@
+// Copyright 2020 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_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/permissions/permission_request_enums.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_base.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace permissions {
+
+// TODO(crbug.com/1138595, andypaicu): Refactor this class and
+// RealTimeUrlLookupServiceBase to derive from the same base class instead of
+// doing a bunch of duplicate work. Design doc:
+// go/permissions-predictions-client-doc
+
+// Service used to makes calls to the Web Permission Suggestions Service to
+// obtaing recomandations regarding permission prompts.
+class PredictionService : public PredictionServiceBase {
+ public:
+ using PendingRequestsMap = std::map<std::unique_ptr<network::SimpleURLLoader>,
+ LookupResponseCallback>;
+ explicit PredictionService(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+ ~PredictionService() override;
+
+ void StartLookup(const PredictionRequestFeatures& entity,
+ LookupRequestCallback request_callback,
+ LookupResponseCallback response_callback) override;
+
+ void set_prediction_service_url_for_testing(const GURL& url) {
+ prediction_service_url_override_ = url;
+ }
+
+ const PendingRequestsMap& pending_requests_for_testing() {
+ return pending_requests_;
+ }
+
+ void recalculate_service_url_every_time_for_testing() {
+ recalculate_service_url_every_time = true;
+ }
+
+ private:
+ static const GURL GetPredictionServiceUrl(bool recalculate_for_testing);
+ std::unique_ptr<network::ResourceRequest> GetResourceRequest();
+ std::unique_ptr<GetSuggestionsRequest> GetPredictionRequestProto(
+ const PredictionRequestFeatures& entity);
+ void SendRequestInternal(std::unique_ptr<network::ResourceRequest> request,
+ const std::string& request_data,
+ const PredictionRequestFeatures& entity,
+ LookupResponseCallback response_callback);
+ void OnURLLoaderComplete(const PredictionRequestFeatures& entity,
+ network::SimpleURLLoader* loader,
+ base::TimeTicks request_start_time,
+ std::unique_ptr<std::string> response_body);
+ std::unique_ptr<GetSuggestionsResponse> CreatePredictionsResponse(
+ network::SimpleURLLoader* loader,
+ const std::string* response_body);
+
+ PendingRequestsMap pending_requests_;
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+ GURL prediction_service_url_override_;
+ bool recalculate_service_url_every_time = false;
+
+ base::WeakPtrFactory<PredictionService> weak_factory_{this};
+};
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service_base.h b/chromium/components/permissions/prediction_service/prediction_service_base.h
new file mode 100644
index 00000000000..dcf82fb9ca2
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service_base.h
@@ -0,0 +1,43 @@
+// Copyright 2020 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_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_BASE_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_BASE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/permissions/permission_request_enums.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+
+namespace permissions {
+
+// TODO(crbug.com/1138595, andypaicu): Refactor this class and
+// RealTimeUrlLookupServiceBase to derive from the same base class instead of
+// doing a bunch of duplicate work. Design doc:
+// https://docs.google.com/document/d/11Gd4bMpuPiVOVNhgqkixZXfckFDzv921BHoZWTBIISc/edit#heading=h.lxxeltml3hwr
+class PredictionServiceBase : public KeyedService {
+ public:
+ // TODO(crbug.com/1138595, andypaicu): once the above TODO is done, refactor
+ // to use a struct to make the call sites more readable (for both callbacks).
+ using LookupRequestCallback =
+ base::OnceCallback<void(std::unique_ptr<GetSuggestionsRequest>,
+ std::string)>; // Access token.
+
+ using LookupResponseCallback =
+ base::OnceCallback<void(bool, // Lookup successful.
+ bool, // Response from cache.
+ std::unique_ptr<GetSuggestionsResponse>)>;
+
+ virtual void StartLookup(const PredictionRequestFeatures& entity,
+ LookupRequestCallback request_callback,
+ LookupResponseCallback response_callback) = 0;
+};
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_BASE_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service_common.cc b/chromium/components/permissions/prediction_service/prediction_service_common.cc
new file mode 100644
index 00000000000..02dbf47160a
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service_common.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 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/permissions/prediction_service/prediction_service_common.h"
+
+#include "build/build_config.h"
+
+namespace permissions {
+ClientFeatures_Platform GetCurrentPlatformProto() {
+#if defined(OS_WIN)
+ return permissions::ClientFeatures_Platform_PLATFORM_WINDOWS;
+#elif defined(OS_LINUX)
+ return permissions::ClientFeatures_Platform_PLATFORM_LINUX;
+#elif defined(OS_ANDROID)
+ return permissions::ClientFeatures_Platform_PLATFORM_ANDROID;
+#elif defined(OS_MAC)
+ return permissions::ClientFeatures_Platform_PLATFORM_MAC_OS;
+#else
+ return permissions::ClientFeatures_Platform_PLATFORM_UNKNOWN;
+#endif
+}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/prediction_service/prediction_service_common.h b/chromium/components/permissions/prediction_service/prediction_service_common.h
new file mode 100644
index 00000000000..08a6ae46bce
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service_common.h
@@ -0,0 +1,25 @@
+// Copyright 2020 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_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
+
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+
+namespace permissions {
+
+// TODO(andypaicu): when available, replace with actual URL.
+constexpr char kDefaultPredictionServiceUrl[] =
+ "https://webpermissionpredictions.googleapis.com/v1:generatePredictions";
+
+// A command line switch to override the default service url.
+constexpr char kDefaultPredictionServiceUrlSwitchKey[] =
+ "permission-predictions-service-url";
+
+// Get the current platform for proto message purposes.
+ClientFeatures_Platform GetCurrentPlatformProto();
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service_messages.proto b/chromium/components/permissions/prediction_service/prediction_service_messages.proto
new file mode 100644
index 00000000000..e47d2d65b38
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service_messages.proto
@@ -0,0 +1,126 @@
+// Copyright (c) 2020 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package permissions;
+
+// Features that depend on the site that triggered the permission request.
+// Currently empty but added proactively for future versions.
+message SiteFeatures {}
+
+// Statistical features about client's interactions with permission prompts.
+// These features are computed on all permission actions that happened before
+// the current permission request.
+message StatsFeatures {
+ // Average deny rate for the client.
+ optional float avg_deny_rate = 1;
+ // Average grant rate for the client.
+ optional float avg_grant_rate = 2;
+ // Average dismiss rate for the client.
+ optional float avg_dismiss_rate = 3;
+ // Average ignore rate for the client.
+ optional float avg_ignore_rate = 4;
+ // Number of permission prompts seen by the client.
+ optional int32 prompts_count = 5;
+}
+
+// Features representing the overall (not permission-specific) client state at
+// the time the permission was requested.
+message ClientFeatures {
+ // Statistical features about client's previous interactions with permission
+ // prompts, aggregated across all permission types.
+ optional StatsFeatures client_stats = 1;
+
+ // Enum defining the client platforms.
+ enum Platform {
+ PLATFORM_UNKNOWN = 0;
+ PLATFORM_ANDROID = 1;
+ PLATFORM_WINDOWS = 2;
+ PLATFORM_LINUX = 3;
+ PLATFORM_MAC_OS = 4;
+ }
+
+ // The platform run by the client that originated the suggestion request.
+ optional Platform platform = 2;
+
+ // Enum defining gesture types.
+ enum Gesture {
+ UNKNOWN_GESTURE = 0;
+ NO_GESTURE = 1;
+ GESTURE = 2;
+ }
+ // The type of gesture performed by the user on the page before the permission
+ // prompt was shown.
+ optional Gesture gesture = 3;
+}
+
+// Features related to a specific permission type.
+message PermissionFeatures {
+ // Statistical features about client's previous interactions with permission
+ // prompts of the specific permission type.
+ optional StatsFeatures permission_stats = 1;
+
+ // Features related to the notification permission.
+ message NotificationPermission {}
+
+ // This field has two purposes:
+ // * it specifies the permission type
+ // * it contains the possible additional features for the specified type.
+ oneof permission_type { NotificationPermission notification_permission = 2; }
+}
+// Permission suggestion with the predicted likelihood that the user will grant
+// the permission prompt (more details at go/hedgehog-backend).
+message PermissionSuggestion {
+ // Additional information regarding the notification suggestion.
+ message NotificationSuggestion {}
+
+ // This field has two purposes:
+ // * it specifies the permission type for which we generated the suggestion
+ // * it contains the possible additional information for the specified type.
+ oneof suggestion_type { NotificationSuggestion notification_suggestion = 1; }
+
+ // Information about how likely a user is to perform a specific action.
+ message Likelihood {
+ // Discretized likelihood values (see go/hedgehog-provider-browser). The ML
+ // models generate predictions as floats in the range [0, 1]; the service
+ // maps these floats to the discretized likelihood values in this enum using
+ // thresholds that are defined in the implementation.
+ enum DiscretizedLikelihood {
+ UNKNOWN = 0;
+ VERY_UNLIKELY = 1;
+ UNLIKELY = 2;
+ NEUTRAL = 3;
+ LIKELY = 4;
+ VERY_LIKELY = 5;
+ }
+ // Discretized likelihood of the user performing the action.
+ optional DiscretizedLikelihood discretized_likelihood = 1;
+ }
+
+ // The ML predicts the likelihood of the user NOT granting the permission. We
+ // then convert it to how likely the user is to GRANT the permission request.
+ optional Likelihood grant_likelihood = 2;
+}
+
+// Message sent from the client to get suggestions for one or more permissions.
+message GetSuggestionsRequest {
+ // Features representing the overall (not permission-specific) client state.
+ optional ClientFeatures client_features = 1;
+ // Features that depend on the site that the client was visiting when the
+ // permission request was triggered.
+ optional SiteFeatures site_features = 2;
+ // Each PermissionFeatures message details a specific permission for which the
+ // client wants to receive a suggestion.
+ repeated PermissionFeatures permission_features = 3;
+}
+// The response message returned by the ChromePermissionsSuggestionsService to
+// the Chrome client.
+message GetSuggestionsResponse {
+ // One PermissionSuggestion is generated for each PermissionFeatures in the
+ // request. The order is kept between the input and output lists.
+ repeated PermissionSuggestion suggestion = 1;
+}
diff --git a/chromium/components/permissions/prediction_service/prediction_service_unittest.cc b/chromium/components/permissions/prediction_service/prediction_service_unittest.cc
new file mode 100644
index 00000000000..b7478bdf7d3
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_service_unittest.cc
@@ -0,0 +1,510 @@
+// Copyright 2020 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/permissions/prediction_service/prediction_service.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/permissions/features.h"
+#include "components/permissions/permission_request_enums.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_common.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+#include "google/protobuf/message_lite.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
+
+namespace {
+// Helper common requests and responses. All of these are for the NOTIFICATION
+// type.
+
+// A request that has all counts 0. With user gesture.
+const permissions::PredictionRequestFeatures kFeaturesAllCountsZero = {
+ permissions::PermissionRequestGestureType::GESTURE,
+ permissions::PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}};
+// A request that has all counts 5 expect for "grants" which are 6. Without user
+// gesture.
+const permissions::PredictionRequestFeatures kFeaturesCountsNeedingRounding = {
+ permissions::PermissionRequestGestureType::NO_GESTURE,
+ permissions::PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ {6, 5, 5, 5},
+ {6, 5, 5, 5}};
+// A request that has all counts 50. With user gesture.
+const permissions::PredictionRequestFeatures kFeaturesEvenCountsOver100 = {
+ permissions::PermissionRequestGestureType::GESTURE,
+ permissions::PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ {50, 50, 50, 50},
+ {50, 50, 50, 50}};
+// A request that has all counts 100. With user gesture.
+const permissions::PredictionRequestFeatures kFeaturesEvenCountsOver100Alt = {
+ permissions::PermissionRequestGestureType::GESTURE,
+ permissions::PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ {100, 100, 100, 100},
+ {100, 100, 100, 100}};
+// A request that has generic counts 50, and notification counts 0. Without user
+// gesture.
+const permissions::PredictionRequestFeatures kFeaturesDifferentCounts = {
+ permissions::PermissionRequestGestureType::NO_GESTURE,
+ permissions::PermissionRequestType::PERMISSION_NOTIFICATIONS,
+ {0, 0, 0, 0},
+ {50, 50, 50, 50}};
+
+// A proto request that has all ratios and total counts 0. With user gesture.
+permissions::GetSuggestionsRequest kRequestAllCountsZero;
+// A proto request that has all ratios 0.24 (~5/21) except for "grants" which
+// are 0.29 (~6/21). Without user gesture.
+permissions::GetSuggestionsRequest kRequestRoundedCounts;
+// A proto request that has all ratios .25 and total count 100. With user
+// gesture.
+permissions::GetSuggestionsRequest kRequestEqualCountsTotal100;
+// A proot request that has generic ratios .25 and total count 100 and
+// notifications ratios and counts 0. Without user gesture.
+permissions::GetSuggestionsRequest kRequestDifferentCounts;
+
+// A response that has a likelihood of DiscretizedLikelihood::LIKELY.
+permissions::GetSuggestionsResponse kResponseLikely;
+
+// A response that has a likelihood of DiscretizedLikelihood::UNLIKELY.
+permissions::GetSuggestionsResponse kResponseUnlikely;
+
+void InitializeProtoHelperObjects() {
+ kRequestAllCountsZero.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_deny_rate(0);
+ kRequestAllCountsZero.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_dismiss_rate(0);
+ kRequestAllCountsZero.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_grant_rate(0);
+ kRequestAllCountsZero.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_ignore_rate(0);
+ kRequestAllCountsZero.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_prompts_count(0);
+ kRequestAllCountsZero.mutable_client_features()->set_platform(
+ permissions::GetCurrentPlatformProto());
+ kRequestAllCountsZero.mutable_client_features()->set_gesture(
+ permissions::ClientFeatures_Gesture_GESTURE);
+ auto* permission_feature =
+ kRequestAllCountsZero.mutable_permission_features()->Add();
+ permission_feature->mutable_permission_stats()->set_avg_deny_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_grant_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0);
+ permission_feature->mutable_permission_stats()->set_prompts_count(0);
+ permission_feature->mutable_notification_permission()
+ ->InitAsDefaultInstance();
+
+ kRequestRoundedCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_deny_rate(0.24);
+ kRequestRoundedCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_dismiss_rate(0.24);
+ kRequestRoundedCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_grant_rate(0.29);
+ kRequestRoundedCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_ignore_rate(0.24);
+ kRequestRoundedCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_prompts_count(21);
+ kRequestRoundedCounts.mutable_client_features()->set_platform(
+ permissions::GetCurrentPlatformProto());
+ kRequestRoundedCounts.mutable_client_features()->set_gesture(
+ permissions::ClientFeatures_Gesture_NO_GESTURE);
+ permission_feature =
+ kRequestRoundedCounts.mutable_permission_features()->Add();
+ permission_feature->mutable_permission_stats()->set_avg_deny_rate(0.24);
+ permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0.24);
+ permission_feature->mutable_permission_stats()->set_avg_grant_rate(0.29);
+ permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0.24);
+ permission_feature->mutable_permission_stats()->set_prompts_count(21);
+ permission_feature->mutable_notification_permission()
+ ->InitAsDefaultInstance();
+
+ kRequestEqualCountsTotal100.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_deny_rate(.25);
+ kRequestEqualCountsTotal100.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_dismiss_rate(.25);
+ kRequestEqualCountsTotal100.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_grant_rate(.25);
+ kRequestEqualCountsTotal100.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_ignore_rate(.25);
+ kRequestEqualCountsTotal100.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_prompts_count(100);
+ kRequestEqualCountsTotal100.mutable_client_features()->set_platform(
+ permissions::GetCurrentPlatformProto());
+ kRequestEqualCountsTotal100.mutable_client_features()->set_gesture(
+ permissions::ClientFeatures_Gesture_GESTURE);
+ permission_feature =
+ kRequestEqualCountsTotal100.mutable_permission_features()->Add();
+ permission_feature->mutable_permission_stats()->set_avg_deny_rate(.25);
+ permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(.25);
+ permission_feature->mutable_permission_stats()->set_avg_grant_rate(.25);
+ permission_feature->mutable_permission_stats()->set_avg_ignore_rate(.25);
+ permission_feature->mutable_permission_stats()->set_prompts_count(100);
+ permission_feature->mutable_notification_permission()
+ ->InitAsDefaultInstance();
+
+ kRequestDifferentCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_deny_rate(.25);
+ kRequestDifferentCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_dismiss_rate(.25);
+ kRequestDifferentCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_grant_rate(.25);
+ kRequestDifferentCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_avg_ignore_rate(.25);
+ kRequestDifferentCounts.mutable_client_features()
+ ->mutable_client_stats()
+ ->set_prompts_count(100);
+ kRequestDifferentCounts.mutable_client_features()->set_platform(
+ permissions::GetCurrentPlatformProto());
+ kRequestDifferentCounts.mutable_client_features()->set_gesture(
+ permissions::ClientFeatures_Gesture_NO_GESTURE);
+ permission_feature =
+ kRequestDifferentCounts.mutable_permission_features()->Add();
+ permission_feature->mutable_permission_stats()->set_avg_deny_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_grant_rate(0);
+ permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0);
+ permission_feature->mutable_permission_stats()->set_prompts_count(0);
+ permission_feature->mutable_notification_permission()
+ ->InitAsDefaultInstance();
+
+ auto* prediction = kResponseLikely.mutable_suggestion()->Add();
+ prediction->mutable_grant_likelihood()->set_discretized_likelihood(
+ permissions::
+ PermissionSuggestion_Likelihood_DiscretizedLikelihood_LIKELY);
+
+ prediction = kResponseUnlikely.mutable_suggestion()->Add();
+ prediction->mutable_grant_likelihood()->set_discretized_likelihood(
+ permissions::
+ PermissionSuggestion_Likelihood_DiscretizedLikelihood_UNLIKELY);
+}
+
+} // namespace
+
+namespace permissions {
+class PredictionServiceTest : public testing::Test {
+ public:
+ PredictionServiceTest()
+ : test_shared_loader_factory_(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_)) {}
+
+ ~PredictionServiceTest() override = default;
+
+ void SetUp() override {
+ prediction_service_ =
+ std::make_unique<PredictionService>(test_shared_loader_factory_);
+
+ InitializeProtoHelperObjects();
+ }
+
+ void Respond(const GURL& url,
+ double delay_in_seconds = 0,
+ int err_code = net::OK) {
+ if (delay_in_seconds > 0) {
+ // Post a task to rerun this after |delay_in_seconds| seconds
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&PredictionServiceTest::Respond,
+ base::Unretained(this), url, 0, err_code),
+ base::TimeDelta::FromSecondsD(delay_in_seconds));
+ return;
+ }
+
+ auto head = network::mojom::URLResponseHead::New();
+ head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+ head->headers->AddHeader("Content-Type", "application/octet-stream");
+ test_url_loader_factory_.SimulateResponseForPendingRequest(
+ url, network::URLLoaderCompletionStatus(err_code), std::move(head),
+ GetResponseForUrl(url));
+ }
+
+ void StartLookup(const PredictionRequestFeatures& entity,
+ base::RunLoop* request_loop,
+ base::RunLoop* response_loop) {
+ prediction_service_->StartLookup(
+ entity,
+ base::BindOnce(&PredictionServiceTest::RequestCallback,
+ base::Unretained(this), request_loop),
+ base::BindOnce(&PredictionServiceTest::ResponseCallback,
+ base::Unretained(this), response_loop));
+ }
+
+ void RequestCallback(base::RunLoop* request_loop,
+ std::unique_ptr<GetSuggestionsRequest> request,
+ std::string access_token) {
+ received_requests_.emplace_back(std::move(request));
+ if (request_loop)
+ request_loop->Quit();
+
+ // Access token should always be the empty string.
+ EXPECT_EQ(std::string(), access_token);
+ }
+
+ void ResponseCallback(base::RunLoop* response_loop,
+ bool lookup_successful,
+ bool response_from_cache,
+ std::unique_ptr<GetSuggestionsResponse> response) {
+ received_responses_.emplace_back(std::move(response));
+ if (response_loop)
+ response_loop->Quit();
+
+ // The response is never from the cache.
+ EXPECT_FALSE(response_from_cache);
+ }
+
+ protected:
+ std::vector<std::unique_ptr<GetSuggestionsRequest>> received_requests_;
+ std::vector<std::unique_ptr<GetSuggestionsResponse>> received_responses_;
+ std::unique_ptr<PredictionService> prediction_service_;
+
+ // Different paths to simulate different server behaviours.
+ const GURL kUrl_Unlikely{"http://predictionsevice.com/unlikely"};
+ const GURL kUrl_Likely{"http://predictionsevice.com/likely"};
+ const GURL kUrl_Invalid{"http://predictionsevice.com/invalid"};
+
+ private:
+ std::string GetResponseForUrl(const GURL& url) {
+ if (url == kUrl_Unlikely) {
+ return kResponseUnlikely.SerializeAsString();
+ } else if (url == kUrl_Likely) {
+ return kResponseLikely.SerializeAsString();
+ } else if (url == GURL(permissions::kDefaultPredictionServiceUrl)) {
+ return kResponseLikely.SerializeAsString();
+ } else if (url == kUrl_Invalid) {
+ return "This is not a valid response";
+ }
+
+ return "";
+ }
+
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+};
+
+TEST_F(PredictionServiceTest, BuiltProtoRequestIsCorrect) {
+ struct {
+ PredictionRequestFeatures entity;
+ GetSuggestionsRequest expected_request;
+ } kTests[] = {
+ {kFeaturesAllCountsZero, kRequestAllCountsZero},
+ {kFeaturesCountsNeedingRounding, kRequestRoundedCounts},
+ {kFeaturesEvenCountsOver100, kRequestEqualCountsTotal100},
+ {kFeaturesEvenCountsOver100Alt, kRequestEqualCountsTotal100},
+ {kFeaturesDifferentCounts, kRequestDifferentCounts},
+ };
+
+ prediction_service_->set_prediction_service_url_for_testing(
+ GURL(kUrl_Likely));
+ for (const auto& kTest : kTests) {
+ base::RunLoop run_loop;
+ StartLookup(kTest.entity, &run_loop, nullptr /* response_loop */);
+ run_loop.Run();
+
+ EXPECT_EQ(1u, received_requests_.size());
+ EXPECT_EQ(kTest.expected_request.SerializeAsString(),
+ received_requests_[0]->SerializeAsString());
+
+ received_requests_.clear();
+ }
+}
+
+TEST_F(PredictionServiceTest, ResponsesAreCorrect) {
+ struct {
+ GURL url;
+ base::Optional<GetSuggestionsResponse> expected_response;
+ double delay_in_seconds;
+ int err_code;
+ } kTests[] = {
+ // Test different responses.
+ {kUrl_Likely, base::Optional<GetSuggestionsResponse>(kResponseLikely)},
+ {kUrl_Unlikely,
+ base::Optional<GetSuggestionsResponse>(kResponseUnlikely)},
+
+ // Test the response's timeout.
+ {kUrl_Likely, base::Optional<GetSuggestionsResponse>(kResponseLikely),
+ 0.5},
+ {kUrl_Likely, base::nullopt, 2},
+
+ // Test error code responses.
+ {kUrl_Likely, base::nullopt, 0, net::ERR_SSL_PROTOCOL_ERROR},
+ {kUrl_Likely, base::nullopt, 0, net::ERR_CONNECTION_FAILED},
+ };
+
+ for (const auto& kTest : kTests) {
+ prediction_service_->set_prediction_service_url_for_testing(kTest.url);
+ base::RunLoop response_loop;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
+ Respond(kTest.url, kTest.delay_in_seconds, kTest.err_code);
+ response_loop.Run();
+
+ EXPECT_EQ(1u, received_responses_.size());
+ if (kTest.expected_response.has_value()) {
+ EXPECT_TRUE(received_responses_[0]);
+ EXPECT_EQ(kTest.expected_response->SerializeAsString(),
+ received_responses_[0]->SerializeAsString());
+ } else {
+ EXPECT_FALSE(received_responses_[0]);
+ }
+ received_responses_.clear();
+ }
+}
+
+// Test that the Web Prediction Service url can be overridden via feature params
+// and command line, and the fallback logic in case the provided url is not
+// valid.
+TEST_F(PredictionServiceTest, FeatureParamAndCommandLineCanOverrideDefaultUrl) {
+ struct {
+ base::Optional<std::string> command_line_switch_value;
+ base::Optional<std::string> url_override_param_value;
+ GURL expected_request_url;
+ permissions::GetSuggestionsResponse expected_response;
+ } kTests[] = {
+ // Test without any overrides.
+ {base::nullopt, base::nullopt, GURL(kDefaultPredictionServiceUrl),
+ kResponseLikely},
+
+ // Test only the FeatureParam override.
+ {base::nullopt, kUrl_Unlikely.spec(), kUrl_Unlikely, kResponseUnlikely},
+ {base::nullopt, "this is not a url", GURL(kDefaultPredictionServiceUrl),
+ kResponseLikely},
+ {base::nullopt, "", GURL(kDefaultPredictionServiceUrl), kResponseLikely},
+
+ // Test only the command line override.
+ {kUrl_Unlikely.spec(), base::nullopt, kUrl_Unlikely, kResponseUnlikely},
+ {"this is not a url", base::nullopt, GURL(kDefaultPredictionServiceUrl),
+ kResponseLikely},
+ {"", base::nullopt, GURL(kDefaultPredictionServiceUrl), kResponseLikely},
+
+ // Command line takes precedence over FeatureParam, if valid.
+ {kUrl_Likely.spec(), kUrl_Unlikely.spec(), kUrl_Likely, kResponseLikely},
+ {"this is not a url", kUrl_Unlikely.spec(), kUrl_Unlikely,
+ kResponseUnlikely},
+ {"this is not a url", "this is not a url",
+ GURL(kDefaultPredictionServiceUrl), kResponseLikely},
+ };
+
+ prediction_service_->recalculate_service_url_every_time_for_testing();
+
+ for (const auto& kTest : kTests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ if (kTest.url_override_param_value.has_value()) {
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kPermissionPredictionServiceUseUrlOverride,
+ {{feature_params::kPermissionPredictionServiceUrlOverride.name,
+ kTest.url_override_param_value.value()}});
+ }
+
+ if (kTest.command_line_switch_value.has_value()) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ kDefaultPredictionServiceUrlSwitchKey,
+ kTest.command_line_switch_value.value());
+ }
+
+ base::RunLoop response_loop;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
+ Respond(kTest.expected_request_url);
+ response_loop.Run();
+ EXPECT_EQ(1u, received_responses_.size());
+ EXPECT_TRUE(received_responses_[0]);
+ EXPECT_EQ(kTest.expected_response.SerializeAsString(),
+ received_responses_[0]->SerializeAsString());
+
+ // Cleanup for next test.
+ received_responses_.clear();
+ base::CommandLine::ForCurrentProcess()->RemoveSwitch(
+ kDefaultPredictionServiceUrlSwitchKey);
+ }
+}
+
+TEST_F(PredictionServiceTest,
+ FeatureEnabledWithNoFeatureParamFallsBackOnDefault) {
+ prediction_service_->recalculate_service_url_every_time_for_testing();
+
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ features::kPermissionPredictionServiceUseUrlOverride);
+
+ base::RunLoop response_loop;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
+ Respond(GURL(kDefaultPredictionServiceUrl));
+ response_loop.Run();
+ EXPECT_EQ(1u, received_responses_.size());
+ EXPECT_TRUE(received_responses_[0]);
+ EXPECT_EQ(kResponseLikely.SerializeAsString(),
+ received_responses_[0]->SerializeAsString());
+}
+
+TEST_F(PredictionServiceTest, HandleSimultaneousRequests) {
+ prediction_service_->set_prediction_service_url_for_testing(kUrl_Likely);
+ base::RunLoop response_loop;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
+
+ prediction_service_->set_prediction_service_url_for_testing(kUrl_Unlikely);
+ base::RunLoop response_loop2;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop2);
+
+ EXPECT_EQ(2u, prediction_service_->pending_requests_for_testing().size());
+
+ Respond(kUrl_Unlikely);
+ response_loop2.Run();
+
+ EXPECT_EQ(1u, received_responses_.size());
+ EXPECT_TRUE(received_responses_[0]);
+ EXPECT_EQ(kResponseUnlikely.SerializeAsString(),
+ received_responses_[0]->SerializeAsString());
+ EXPECT_EQ(1u, prediction_service_->pending_requests_for_testing().size());
+
+ Respond(kUrl_Likely);
+ response_loop.Run();
+
+ EXPECT_EQ(2u, received_responses_.size());
+ EXPECT_TRUE(received_responses_[1].get() != nullptr);
+ EXPECT_EQ(kResponseLikely.SerializeAsString(),
+ received_responses_[1]->SerializeAsString());
+ EXPECT_EQ(0u, prediction_service_->pending_requests_for_testing().size());
+}
+
+TEST_F(PredictionServiceTest, InvalidResponse) {
+ base::RunLoop response_loop;
+ StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
+ Respond(GURL(kUrl_Invalid));
+ response_loop.Run();
+ EXPECT_FALSE(received_responses_[0]);
+}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/quota_permission_context_impl.cc b/chromium/components/permissions/quota_permission_context_impl.cc
index 2447b79f978..3c588c14904 100644
--- a/chromium/components/permissions/quota_permission_context_impl.cc
+++ b/chromium/components/permissions/quota_permission_context_impl.cc
@@ -58,7 +58,7 @@ class QuotaPermissionRequest : public PermissionRequest {
#endif
base::string16 GetMessageTextFragment() const override;
GURL GetOrigin() const override;
- void PermissionGranted() override;
+ void PermissionGranted(bool is_one_time) override;
void PermissionDenied() override;
void Cancelled() override;
void RequestFinished() override;
@@ -114,7 +114,8 @@ GURL QuotaPermissionRequest::GetOrigin() const {
return origin_url_;
}
-void QuotaPermissionRequest::PermissionGranted() {
+void QuotaPermissionRequest::PermissionGranted(bool is_one_time) {
+ DCHECK(!is_one_time);
context_->DispatchCallbackOnIOThread(
std::move(callback_),
content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW);
diff --git a/chromium/components/permissions_strings.grdp b/chromium/components/permissions_strings.grdp
index af890c0c856..946abd47da4 100644
--- a/chromium/components/permissions_strings.grdp
+++ b/chromium/components/permissions_strings.grdp
@@ -134,6 +134,15 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<message name="IDS_PERMISSION_DENY" desc="Label on button to deny a permissions request.">
Block
</message>
+ <message name="IDS_PERMISSION_ALLOW_ONCE">
+ Only this time
+ </message>
+ <message name="IDS_PERMISSION_ALLOW_ALWAYS">
+ On every visit
+ </message>
+ <message name="IDS_PERMISSIONS_BUBBLE_PROMPT_ONE_TIME" desc="The label that is used to introduce permission request details to the user in a popup.">
+ Allow <ph name="SITE_NAME">$1<ex>google.com</ex></ph> to:
+ </message>
<if expr="not is_android">
<message name="IDS_GEOLOCATION_PERMISSION_CHIP" desc="Button text representing a request for the user's physical location from a website. When clicked, shows a permission prompt bubble with more information.">
diff --git a/chromium/components/permissions_strings_grdp/IDS_PERMISSIONS_BUBBLE_PROMPT_ONE_TIME.png.sha1 b/chromium/components/permissions_strings_grdp/IDS_PERMISSIONS_BUBBLE_PROMPT_ONE_TIME.png.sha1
new file mode 100644
index 00000000000..ae4215e0e9d
--- /dev/null
+++ b/chromium/components/permissions_strings_grdp/IDS_PERMISSIONS_BUBBLE_PROMPT_ONE_TIME.png.sha1
@@ -0,0 +1 @@
+728595e3aab4e164f4f61fb135ce6e70d241060a \ No newline at end of file
diff --git a/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ALWAYS.png.sha1 b/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ALWAYS.png.sha1
new file mode 100644
index 00000000000..ae4215e0e9d
--- /dev/null
+++ b/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ALWAYS.png.sha1
@@ -0,0 +1 @@
+728595e3aab4e164f4f61fb135ce6e70d241060a \ No newline at end of file
diff --git a/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ONCE.png.sha1 b/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ONCE.png.sha1
new file mode 100644
index 00000000000..ae4215e0e9d
--- /dev/null
+++ b/chromium/components/permissions_strings_grdp/IDS_PERMISSION_ALLOW_ONCE.png.sha1
@@ -0,0 +1 @@
+728595e3aab4e164f4f61fb135ce6e70d241060a \ No newline at end of file
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
index 2a3a82ebf66..50764f48e11 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/json/string_escape.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
@@ -24,30 +24,18 @@
#include "url/origin.h"
using base::UserMetricsAction;
-using content::PluginInstanceThrottler;
using content::RenderFrame;
using content::RenderThread;
namespace plugins {
-void LoadablePluginPlaceholder::BlockForPowerSaverPoster() {
- DCHECK(!is_blocked_for_power_saver_poster_);
- is_blocked_for_power_saver_poster_ = true;
-
- DCHECK(render_frame());
- render_frame()->RegisterPeripheralPlugin(
- url::Origin::Create(GURL(GetPluginParams().url)),
- base::BindOnce(&LoadablePluginPlaceholder::MarkPluginEssential,
- weak_factory_.GetWeakPtr(),
- PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_ALLOWLIST));
-}
+void LoadablePluginPlaceholder::MaybeLoadBlockedPlugin(
+ const std::string& identifier) {
+ if (!identifier.empty() && identifier != identifier_)
+ return;
-void LoadablePluginPlaceholder::SetPremadePlugin(
- content::PluginInstanceThrottler* throttler) {
- DCHECK(throttler);
- DCHECK(!premade_throttler_);
- heuristic_run_before_ = true;
- premade_throttler_ = throttler;
+ RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI"));
+ LoadPlugin();
}
LoadablePluginPlaceholder::LoadablePluginPlaceholder(
@@ -55,37 +43,13 @@ LoadablePluginPlaceholder::LoadablePluginPlaceholder(
const blink::WebPluginParams& params,
const std::string& html_data)
: PluginPlaceholderBase(render_frame, params, html_data),
- heuristic_run_before_(false),
- is_blocked_for_tinyness_(false),
- is_blocked_for_background_tab_(false),
is_blocked_for_prerendering_(false),
- is_blocked_for_power_saver_poster_(false),
- power_saver_enabled_(false),
- premade_throttler_(nullptr),
allow_loading_(false),
finished_loading_(false) {}
LoadablePluginPlaceholder::~LoadablePluginPlaceholder() {
}
-void LoadablePluginPlaceholder::MarkPluginEssential(
- PluginInstanceThrottler::PowerSaverUnthrottleMethod method) {
- if (!power_saver_enabled_)
- return;
-
- power_saver_enabled_ = false;
-
- if (premade_throttler_)
- premade_throttler_->MarkPluginEssential(method);
- else if (method != PluginInstanceThrottler::UNTHROTTLE_METHOD_DO_NOT_RECORD)
- PluginInstanceThrottler::RecordUnthrottleMethodMetric(method);
-
- is_blocked_for_power_saver_poster_ = false;
- is_blocked_for_tinyness_ = false;
- if (!LoadingBlocked())
- LoadPlugin();
-}
-
void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
CHECK(plugin());
if (!new_plugin)
@@ -98,9 +62,7 @@ void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
}
container->SetPlugin(new_plugin);
- bool plugin_needs_initialization =
- !premade_throttler_ || new_plugin != premade_throttler_->GetWebPlugin();
- if (plugin_needs_initialization && !new_plugin->Initialize(container)) {
+ if (!new_plugin->Initialize(container)) {
if (new_plugin->Container()) {
// Since the we couldn't initialize the new plugin, but the container
// still exists, restore the placeholder and destroy the new plugin.
@@ -141,132 +103,10 @@ void LoadablePluginPlaceholder::UpdateMessage() {
blink::WebScriptSource(blink::WebString::FromUTF8(script)));
}
-void LoadablePluginPlaceholder::PluginDestroyed() {
- if (power_saver_enabled_) {
- if (premade_throttler_) {
- // Since the premade plugin has been detached from the container, it will
- // not be automatically destroyed along with the page.
- premade_throttler_->GetWebPlugin()->Destroy();
- premade_throttler_ = nullptr;
- } else if (is_blocked_for_power_saver_poster_) {
- // Record the NEVER unthrottle count only if there is no throttler.
- PluginInstanceThrottler::RecordUnthrottleMethodMetric(
- PluginInstanceThrottler::UNTHROTTLE_METHOD_NEVER);
- }
-
- // Prevent processing subsequent calls to MarkPluginEssential.
- power_saver_enabled_ = false;
- }
-
- PluginPlaceholderBase::PluginDestroyed();
-}
-
-v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject(
- v8::Isolate* isolate) const {
- // Pass through JavaScript access to the underlying throttled plugin.
- if (premade_throttler_ && premade_throttler_->GetWebPlugin()) {
- return premade_throttler_->GetWebPlugin()->V8ScriptableObject(isolate);
- }
- return v8::Local<v8::Object>();
-}
-
bool LoadablePluginPlaceholder::IsErrorPlaceholder() {
return !allow_loading_;
}
-void LoadablePluginPlaceholder::OnUnobscuredRectUpdate(
- const gfx::Rect& unobscured_rect) {
- DCHECK(content::RenderThread::Get());
- if (!render_frame())
- return;
-
- if (!plugin() || !finished_loading_)
- return;
-
- if (!is_blocked_for_tinyness_ && !is_blocked_for_power_saver_poster_)
- return;
-
- if (unobscured_rect_ == unobscured_rect)
- return;
-
- unobscured_rect_ = unobscured_rect;
-
- float zoom_factor = plugin()->Container()->PageZoomFactor();
- int width = roundf(unobscured_rect_.width() / zoom_factor);
- int height = roundf(unobscured_rect_.height() / zoom_factor);
- int x = roundf(unobscured_rect_.x() / zoom_factor);
- int y = roundf(unobscured_rect_.y() / zoom_factor);
-
- // On a size update check if we now qualify as a essential plugin.
- url::Origin main_frame_origin =
- render_frame()->GetWebFrame()->Top()->GetSecurityOrigin();
- url::Origin content_origin = url::Origin::Create(GetPluginParams().url);
- RenderFrame::PeripheralContentStatus status =
- render_frame()->GetPeripheralContentStatus(
- main_frame_origin, content_origin, gfx::Size(width, height),
- heuristic_run_before_ ? RenderFrame::DONT_RECORD_DECISION
- : RenderFrame::RECORD_DECISION);
-
- // Early exit for plugins that we've discovered to be essential.
- if (status != RenderFrame::CONTENT_STATUS_PERIPHERAL &&
- status != RenderFrame::CONTENT_STATUS_TINY) {
- MarkPluginEssential(
- heuristic_run_before_
- ? PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_SIZE_CHANGE
- : PluginInstanceThrottler::UNTHROTTLE_METHOD_DO_NOT_RECORD);
-
- if (!heuristic_run_before_ &&
- status == RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_BIG) {
- render_frame()->AllowlistContentOrigin(content_origin);
- }
-
- return;
- }
-
- if (!heuristic_run_before_) {
- OnBlockedContent(status,
- main_frame_origin.IsSameOriginWith(content_origin));
- }
-
- if (is_blocked_for_tinyness_ && status != RenderFrame::CONTENT_STATUS_TINY) {
- is_blocked_for_tinyness_ = false;
- if (!LoadingBlocked()) {
- LoadPlugin();
- }
- }
-
- if (is_blocked_for_power_saver_poster_) {
- // Adjust poster container padding and dimensions to center play button for
- // plugins and plugin posters that have their top or left portions obscured.
- std::string script = base::StringPrintf(
- "window.resizePoster('%dpx', '%dpx', '%dpx', '%dpx')", x, y, width,
- height);
- plugin()->main_frame()->ExecuteScript(
- blink::WebScriptSource(blink::WebString::FromUTF8(script)));
- }
-
- heuristic_run_before_ = true;
-}
-
-void LoadablePluginPlaceholder::WasShown() {
- if (is_blocked_for_background_tab_) {
- is_blocked_for_background_tab_ = false;
- if (!LoadingBlocked())
- LoadPlugin();
- }
-}
-
-void LoadablePluginPlaceholder::OnLoadBlockedPlugins(
- const std::string& identifier) {
- if (!identifier.empty() && identifier != identifier_)
- return;
-
- RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI"));
- MarkPluginEssential(
- PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_OMNIBOX_ICON);
- LoadPlugin();
-}
-
void LoadablePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) {
// Prerendering can only be enabled prior to a RenderView's first navigation,
// so no BlockedPlugin should see the notification that enables prerendering.
@@ -290,20 +130,13 @@ void LoadablePluginPlaceholder::LoadPlugin() {
return;
}
- if (premade_throttler_) {
- premade_throttler_->SetHiddenForPlaceholder(false /* hidden */);
- ReplacePlugin(premade_throttler_->GetWebPlugin());
- premade_throttler_ = nullptr;
- } else {
- ReplacePlugin(CreatePlugin());
- }
+ ReplacePlugin(CreatePlugin());
}
void LoadablePluginPlaceholder::LoadCallback() {
RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click"));
// If the user specifically clicks on the plugin content's placeholder,
// disable power saver throttling for this instance.
- MarkPluginEssential(PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
LoadPlugin();
}
@@ -312,11 +145,6 @@ void LoadablePluginPlaceholder::DidFinishLoadingCallback() {
if (message_.length() > 0)
UpdateMessage();
- // Wait for the placeholder to finish loading to hide the premade plugin.
- // This is necessary to prevent a flicker.
- if (premade_throttler_ && power_saver_enabled_)
- premade_throttler_->SetHiddenForPlaceholder(true /* hidden */);
-
// In case our initial geometry was reported before the placeholder finished
// loading, request another one. Needed for correct large poster unthrottling.
if (plugin()) {
@@ -344,8 +172,7 @@ const std::string& LoadablePluginPlaceholder::GetIdentifier() const {
bool LoadablePluginPlaceholder::LoadingBlocked() const {
DCHECK(allow_loading_);
- return is_blocked_for_tinyness_ || is_blocked_for_background_tab_ ||
- is_blocked_for_power_saver_poster_ || is_blocked_for_prerendering_;
+ return is_blocked_for_prerendering_;
}
} // namespace plugins
diff --git a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
index 2d69ec3c90f..5c6f3215366 100644
--- a/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
+++ b/chromium/components/plugins/renderer/loadable_plugin_placeholder.h
@@ -12,7 +12,6 @@
#include "base/timer/timer.h"
#include "components/plugins/renderer/plugin_placeholder.h"
#include "content/public/common/webplugininfo.h"
-#include "content/public/renderer/plugin_instance_throttler.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
@@ -21,42 +20,21 @@ namespace plugins {
// (blocked or disabled).
class LoadablePluginPlaceholder : public PluginPlaceholderBase {
public:
- void set_blocked_for_tinyness(bool blocked_for_tinyness) {
- is_blocked_for_tinyness_ = blocked_for_tinyness;
- }
-
- void set_blocked_for_background_tab(bool blocked_for_background_tab) {
- is_blocked_for_background_tab_ = blocked_for_background_tab;
- }
-
void set_blocked_for_prerendering(bool blocked_for_prerendering) {
is_blocked_for_prerendering_ = blocked_for_prerendering;
}
- bool power_saver_enabled() const { return power_saver_enabled_; }
-
- void set_power_saver_enabled(bool power_saver_enabled) {
- power_saver_enabled_ = power_saver_enabled;
- }
-
- // Defer loading of plugin, and instead show the Power Saver poster image.
- void BlockForPowerSaverPoster();
-
- // When we load the plugin, use this already-created plugin, not a new one.
- void SetPremadePlugin(content::PluginInstanceThrottler* throttler);
-
void AllowLoading() { allow_loading_ = true; }
+ // Load the blocked plugin if the identifier matches (or is empty).
+ void MaybeLoadBlockedPlugin(const std::string& identifier);
+
protected:
LoadablePluginPlaceholder(content::RenderFrame* render_frame,
const blink::WebPluginParams& params,
const std::string& html_data);
~LoadablePluginPlaceholder() override;
- void MarkPluginEssential(
- content::PluginInstanceThrottler::PowerSaverUnthrottleMethod method);
-
- void OnLoadBlockedPlugins(const std::string& identifier);
void OnSetIsPrerendering(bool is_prerendering);
void SetMessage(const base::string16& message);
@@ -66,8 +44,6 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
const std::string& GetIdentifier() const;
bool LoadingAllowed() const { return allow_loading_; }
- const gfx::Rect& unobscured_rect() { return unobscured_rect_; }
-
// Replace this placeholder with a different plugin (which could be
// a placeholder again).
void ReplacePlugin(blink::WebPlugin* new_plugin);
@@ -79,20 +55,10 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
void LoadCallback();
void DidFinishLoadingCallback();
- // True if the power saver heuristic has already been run on this content.
- bool heuristic_run_before_;
-
private:
// WebViewPlugin::Delegate methods:
- void PluginDestroyed() override;
- v8::Local<v8::Object> GetV8ScriptableObject(
- v8::Isolate* isolate) const override;
- void OnUnobscuredRectUpdate(const gfx::Rect& unobscured_rect) override;
bool IsErrorPlaceholder() override;
- // RenderFrameObserver methods:
- void WasShown() override;
-
void UpdateMessage();
bool LoadingBlocked() const;
@@ -109,35 +75,15 @@ class LoadablePluginPlaceholder : public PluginPlaceholderBase {
base::string16 message_;
- // True if the plugin load was deferred because this might be a tiny plugin.
- // Plugin may be automatically loaded if it receives non-tiny geometry.
- bool is_blocked_for_tinyness_;
-
- // True if the plugin load was deferred due to page being a background tab.
- // Plugin may be automatically loaded when the page is foregrounded.
- bool is_blocked_for_background_tab_;
-
// True if the plugin was blocked because the page was being prerendered.
// Plugin may be automatically be loaded when the page is displayed.
bool is_blocked_for_prerendering_;
- // True if the plugin load was deferred due to a Power Saver poster.
- bool is_blocked_for_power_saver_poster_;
-
- // True if power saver is enabled for this plugin and it has not been marked
- // essential (by a click or retroactive whitelisting).
- bool power_saver_enabled_;
-
- // When we load, uses this premade plugin instead of creating a new one.
- content::PluginInstanceThrottler* premade_throttler_;
-
bool allow_loading_;
bool finished_loading_;
std::string identifier_;
- gfx::Rect unobscured_rect_;
-
base::WeakPtrFactory<LoadablePluginPlaceholder> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(LoadablePluginPlaceholder);
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index f3959c71e48..ec58e02827a 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -10,7 +10,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
@@ -258,13 +258,17 @@ void WebViewPlugin::DidFailLoading(const WebURLError& error) {
WebViewPlugin::WebViewHelper::WebViewHelper(WebViewPlugin* plugin,
const WebPreferences& preferences)
- : plugin_(plugin) {
+ : plugin_(plugin),
+ agent_group_scheduler_(
+ blink::scheduler::WebThreadScheduler::MainThreadScheduler()
+ ->CreateAgentGroupScheduler()) {
web_view_ =
WebView::Create(/*client=*/this,
/*is_hidden=*/false,
/*is_inside_portal=*/false,
/*compositing_enabled=*/false,
- /*opener=*/nullptr, mojo::NullAssociatedReceiver());
+ /*opener=*/nullptr, mojo::NullAssociatedReceiver(),
+ *agent_group_scheduler_);
// ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
// consistent view of our preferences.
blink::WebView::ApplyWebPreferences(preferences, web_view_);
@@ -278,7 +282,8 @@ WebViewPlugin::WebViewHelper::WebViewHelper(WebViewPlugin* plugin,
blink::CrossVariantMojoAssociatedReceiver<
blink::mojom::FrameWidgetInterfaceBase>(),
blink_widget_host_receiver_.BindNewEndpointAndPassDedicatedRemote(),
- blink_widget_.BindNewEndpointAndPassDedicatedReceiver());
+ blink_widget_.BindNewEndpointAndPassDedicatedReceiver(),
+ viz::FrameSinkId());
// The WebFrame created here was already attached to the Page as its main
// frame, and the WebFrameWidget has been initialized, so we can call
diff --git a/chromium/components/plugins/renderer/webview_plugin.h b/chromium/components/plugins/renderer/webview_plugin.h
index 476074c204c..6b3f246e05a 100644
--- a/chromium/components/plugins/renderer/webview_plugin.h
+++ b/chromium/components/plugins/renderer/webview_plugin.h
@@ -15,6 +15,7 @@
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-forward.h"
#include "third_party/blink/public/mojom/page/widget.mojom.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/blink.h"
@@ -202,11 +203,23 @@ class WebViewPlugin : public blink::WebPlugin,
const gfx::Rect& focus_rect,
base::i18n::TextDirection focus_dir,
bool is_anchor_first) override {}
+ void CreateFrameSink(
+ mojo::PendingReceiver<viz::mojom::CompositorFrameSink>
+ compositor_frame_sink_receiver,
+ mojo::PendingRemote<viz::mojom::CompositorFrameSinkClient>) override {}
+ void RegisterRenderFrameMetadataObserver(
+ mojo::PendingReceiver<cc::mojom::RenderFrameMetadataObserverClient>
+ render_frame_metadata_observer_client_receiver,
+ mojo::PendingRemote<cc::mojom::RenderFrameMetadataObserver>
+ render_frame_metadata_observer) override {}
private:
WebViewPlugin* plugin_;
blink::WebNavigationControl* frame_ = nullptr;
+ std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
+ agent_group_scheduler_;
+
// Owned by us, deleted via |close()|.
blink::WebView* web_view_;
diff --git a/chromium/components/policy/BUILD.gn b/chromium/components/policy/BUILD.gn
index e5ad9ee2e37..b4c03203d44 100644
--- a/chromium/components/policy/BUILD.gn
+++ b/chromium/components/policy/BUILD.gn
@@ -5,6 +5,7 @@
import("//build/config/chrome_build.gni")
import("//build/config/features.gni")
import("//build/config/mac/base_rules.gni")
+import("//build/config/python.gni")
import("//build/toolchain/toolchain.gni")
import("//components/policy/resources/policy_templates.gni")
import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
@@ -97,7 +98,8 @@ constants_source_path = "$target_gen_dir/policy_constants.cc"
app_restrictions_path = "$target_gen_dir/app_restrictions.xml"
risk_tag_header_path = "$target_gen_dir/risk_tag.h"
-action("policy_code_generate") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("policy_code_generate") {
script = "tools/generate_policy_source.py"
chrome_version_abspath = "//chrome/VERSION"
chrome_version_path = rebase_path(chrome_version_abspath, root_build_dir)
@@ -141,7 +143,8 @@ action("policy_code_generate") {
]
}
-action("full_runtime_code_generate") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("full_runtime_code_generate") {
script = "tools/generate_policy_source.py"
chrome_version_abspath = "//chrome/VERSION"
chrome_version_path = rebase_path(chrome_version_abspath, root_build_dir)
@@ -187,7 +190,8 @@ grit("translate_policy_templates") {
}
# Generate the various templates and docs (admx, doc, json, etc.)
-action("policy_templates") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("policy_templates") {
script = "tools/template_writers/template_formatter.py"
chrome_version_abspath = "//chrome/VERSION"
chrome_version_path = rebase_path(chrome_version_abspath, root_build_dir)
diff --git a/chromium/components/policy/content/BUILD.gn b/chromium/components/policy/content/BUILD.gn
index 5c6bc224ef2..49f97398ece 100644
--- a/chromium/components/policy/content/BUILD.gn
+++ b/chromium/components/policy/content/BUILD.gn
@@ -6,6 +6,25 @@ import("//build/config/features.gni")
assert(!is_ios, "Policy Throttle should not be referenced on iOS")
+source_set("safe_sites_navigation_throttle") {
+ sources = [
+ "safe_search_service.cc",
+ "safe_search_service.h",
+ "safe_sites_navigation_throttle.cc",
+ "safe_sites_navigation_throttle.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/keyed_service/content:content",
+ "//components/policy/core/browser",
+ "//components/safe_search_api",
+ "//components/safe_search_api:safe_search_client",
+ "//content/public/browser",
+ "//net",
+ ]
+}
+
source_set("content") {
sources = [
"policy_blocklist_navigation_throttle.cc",
@@ -15,15 +34,12 @@ source_set("content") {
]
deps = [
- "//base",
+ ":safe_sites_navigation_throttle",
"//components/keyed_service/content:content",
"//components/policy/core/browser",
"//components/prefs",
- "//components/safe_search_api",
- "//components/safe_search_api:safe_search_client",
"//components/user_prefs:user_prefs",
"//content/public/browser",
- "//net",
]
}
@@ -32,6 +48,7 @@ source_set("unit_tests") {
sources = [ "policy_blocklist_navigation_throttle_unittest.cc" ]
deps = [
":content",
+ ":safe_sites_navigation_throttle",
"//base",
"//components/keyed_service/content",
"//components/policy/core/browser",
diff --git a/chromium/components/policy/core/common/BUILD.gn b/chromium/components/policy/core/common/BUILD.gn
index 43ffb518e3a..5d715b27cba 100644
--- a/chromium/components/policy/core/common/BUILD.gn
+++ b/chromium/components/policy/core/common/BUILD.gn
@@ -61,6 +61,8 @@ source_set("internal") {
"cloud/dm_token.h",
"cloud/dmserver_job_configurations.cc",
"cloud/dmserver_job_configurations.h",
+ "cloud/encrypted_reporting_job_configuration.cc",
+ "cloud/encrypted_reporting_job_configuration.h",
"cloud/enterprise_metrics.cc",
"cloud/enterprise_metrics.h",
"cloud/external_policy_data_fetcher.cc",
@@ -75,6 +77,8 @@ source_set("internal") {
"cloud/policy_value_validator.h",
"cloud/realtime_reporting_job_configuration.cc",
"cloud/realtime_reporting_job_configuration.h",
+ "cloud/reporting_job_configuration_base.cc",
+ "cloud/reporting_job_configuration_base.h",
"cloud/resource_cache.cc",
"cloud/resource_cache.h",
"cloud/signing_service.h",
@@ -159,6 +163,8 @@ source_set("internal") {
":common_constants",
"//components/policy:generated",
"//components/policy/proto",
+ "//components/policy/proto:policy_record_constants",
+ "//components/policy/proto:reporting_record_proto",
]
deps = [
@@ -357,6 +363,8 @@ static_library("test_support") {
"//components/account_id",
"//components/policy:generated",
"//components/policy/proto",
+ "//components/policy/proto:policy_record_constants",
+ "//components/policy/proto:reporting_record_proto",
"//components/strings",
"//crypto",
"//net",
@@ -463,6 +471,7 @@ source_set("unit_tests") {
"cloud/component_cloud_policy_service_unittest.cc",
"cloud/component_cloud_policy_store_unittest.cc",
"cloud/component_cloud_policy_updater_unittest.cc",
+ "cloud/encrypted_reporting_job_configuration_unittest.cc",
"cloud/external_policy_data_fetcher_unittest.cc",
"cloud/external_policy_data_updater_unittest.cc",
"cloud/realtime_reporting_job_configuration_unittest.cc",
diff --git a/chromium/components/policy/proto/BUILD.gn b/chromium/components/policy/proto/BUILD.gn
index a078d409186..c2738eaa5d8 100644
--- a/chromium/components/policy/proto/BUILD.gn
+++ b/chromium/components/policy/proto/BUILD.gn
@@ -16,9 +16,10 @@ component("proto") {
# Record constants for use with the reporting messaging library.
proto_library("policy_record_constants") {
visibility = [
- "//chrome/browser:browser",
":reporting_record_proto",
":reporting_record_proto_gen",
+ "//chrome/browser:browser",
+ "//components/policy/*",
]
sources = [ "record_constants.proto" ]
@@ -27,7 +28,11 @@ proto_library("policy_record_constants") {
# Record definitions for reporting.
proto_library("reporting_record_proto") {
- visibility = [ "//chrome/browser:browser" ]
+ visibility = [
+ "//chrome/browser:browser",
+ "//chrome/browser:test_support",
+ "//components/policy/*",
+ ]
sources = [ "record.proto" ]
deps = [ ":policy_record_constants" ]
@@ -37,10 +42,10 @@ proto_library("reporting_record_proto") {
proto_library("policy_common_definitions_compile_proto") {
visibility = [
- "//components/policy:cloud_policy_proto_generated_compile_proto",
+ ":proto_internal",
"//components/policy:chrome_settings_proto_generated_compile_proto",
+ "//components/policy:cloud_policy_proto_generated_compile_proto",
"//components/policy:generated",
- ":proto_internal",
]
sources = [ "policy_common_definitions.proto" ]
diff --git a/chromium/components/policy_strings.grdp b/chromium/components/policy_strings.grdp
index 80f52152c5a..7fd2ccf7cfd 100644
--- a/chromium/components/policy_strings.grdp
+++ b/chromium/components/policy_strings.grdp
@@ -585,8 +585,23 @@ Additional details:
<message name="IDS_POLICY_DLP_ANDROID_APPS" desc="Name shown for ARC in data leak prevention toasts.">
Android apps
</message>
- <message name="IDS_POLICY_DLP_PRINTING_BLOCKED" desc="A toast informing the user that printing is blocked.">
- Printing of this content is blocked by your administrator
+ <message name="IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE" desc="The title for notification informing the user that printing is blocked.">
+ Printing is blocked
+ </message>
+ <message name="IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE" desc="The message for notification informing the user that printing is blocked.">
+ Printing of this content is blocked by your administrator.
+ </message>
+ <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE" desc="The title for notification informing the user that screen capture is paused.">
+ Screen capture paused
+ </message>
+ <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE" desc="The message for notification informing the user that screen capture is paused.">
+ Screen capture was paused by your administrator due to content on your screen.
+ </message>
+ <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE" desc="The title for notification informing the user that screen capture is resumed.">
+ Screen capture resumed
+ </message>
+ <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE" desc="The message for notification informing the user that screen capture is resumed.">
+ Screen capture was resumed.
</message>
</grit-part>
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED.png.sha1
deleted file mode 100644
index aec5b41987a..00000000000
--- a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e36454c13cd9e034b5a9b21abffdfa0e369a8632 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE.png.sha1
new file mode 100644
index 00000000000..37f6b08ce17
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_MESSAGE.png.sha1
@@ -0,0 +1 @@
+9cc120d3ece536d600e37f93fbc265f5e5600c5d \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE.png.sha1
new file mode 100644
index 00000000000..37f6b08ce17
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE.png.sha1
@@ -0,0 +1 @@
+9cc120d3ece536d600e37f93fbc265f5e5600c5d \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1
new file mode 100644
index 00000000000..b229c3f33b3
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_MESSAGE.png.sha1
@@ -0,0 +1 @@
+ebfe478eec17a1a367f7a7caae5a30ba64f83cc3 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE.png.sha1
new file mode 100644
index 00000000000..65cb798ad82
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_PAUSED_TITLE.png.sha1
@@ -0,0 +1 @@
+9dc8bc7b71430c645dfa483ea7a0a54df9262c2c \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1
new file mode 100644
index 00000000000..e14019663fc
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_MESSAGE.png.sha1
@@ -0,0 +1 @@
+37963de8b2789e22596fb9041eaa7be6598431a3 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE.png.sha1
new file mode 100644
index 00000000000..3fa481e18f6
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_RESUMED_TITLE.png.sha1
@@ -0,0 +1 @@
+0864f0fd6954d3845e100e12e7ba7d59367dc079 \ No newline at end of file
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index 13fe6131fce..97fe935e4ff 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -10,8 +10,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
diff --git a/chromium/components/prefs/pref_change_registrar.cc b/chromium/components/prefs/pref_change_registrar.cc
index 97e591656a3..6048ef403d8 100644
--- a/chromium/components/prefs/pref_change_registrar.cc
+++ b/chromium/components/prefs/pref_change_registrar.cc
@@ -16,6 +16,10 @@ PrefChangeRegistrar::~PrefChangeRegistrar() {
// PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
// has been destroyed. This should not happen any more but be warned.
// Feel free to contact battre@chromium.org in case this happens.
+ //
+ // This can also happen for non-OTR profiles, when the
+ // DestroyProfileOnBrowserClose flag is enabled. In that case, contact
+ // nicolaso@chromium.org.
RemoveAll();
}
diff --git a/chromium/components/prefs/pref_change_registrar_unittest.cc b/chromium/components/prefs/pref_change_registrar_unittest.cc
index c41a62be4a3..848de18b56b 100644
--- a/chromium/components/prefs/pref_change_registrar_unittest.cc
+++ b/chromium/components/prefs/pref_change_registrar_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/prefs/pref_observer.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index 5da0e2bcda1..e15c2d5f723 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -157,53 +157,37 @@ void PrefService::SchedulePendingLossyWrites() {
bool PrefService::GetBoolean(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool result = false;
-
const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
- return result;
- bool rv = value->GetAsBoolean(&result);
- DCHECK(rv);
- return result;
+ if (!value || !value->is_bool())
+ return false;
+ return value->GetBool();
}
int PrefService::GetInteger(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- int result = 0;
-
const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
- return result;
- bool rv = value->GetAsInteger(&result);
- DCHECK(rv);
- return result;
+ if (!value || !value->is_int())
+ return 0;
+ return value->GetInt();
}
double PrefService::GetDouble(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- double result = 0.0;
-
const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
- return result;
- bool rv = value->GetAsDouble(&result);
- DCHECK(rv);
- return result;
+ if (!value || !value->is_double())
+ return 0.0;
+ return value->GetDouble();
}
std::string PrefService::GetString(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- std::string result;
-
const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
- return result;
- bool rv = value->GetAsString(&result);
- DCHECK(rv);
- return result;
+ if (!value || !value->is_string())
+ return std::string();
+ return value->GetString();
}
base::FilePath PrefService::GetFilePath(const std::string& path) const {
@@ -230,18 +214,19 @@ void PrefService::IteratePreferenceValues(
callback.Run(it.first, *GetPreferenceValue(it.first));
}
-std::unique_ptr<base::DictionaryValue> PrefService::GetPreferenceValues(
+base::Value PrefService::GetPreferenceValues(
IncludeDefaults include_defaults) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- std::unique_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+
+ base::Value out(base::Value::Type::DICTIONARY);
for (const auto& it : *pref_registry_) {
if (include_defaults == INCLUDE_DEFAULTS) {
- out->Set(it.first, GetPreferenceValue(it.first)->CreateDeepCopy());
+ out.SetPath(it.first, GetPreferenceValue(it.first)->Clone());
} else {
const Preference* pref = FindPreference(it.first);
if (pref->IsDefaultValue())
continue;
- out->Set(it.first, pref->GetValue()->CreateDeepCopy());
+ out.SetPath(it.first, pref->GetValue()->Clone());
}
}
return out;
@@ -309,11 +294,7 @@ bool PrefService::IsUserModifiablePreference(
const base::Value* PrefService::Get(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
- return nullptr;
- return value;
+ return GetPreferenceValueChecked(path);
}
const base::DictionaryValue* PrefService::GetDictionary(
@@ -524,15 +505,12 @@ uint64_t PrefService::GetUint64(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::Value* value = GetPreferenceValueChecked(path);
- if (!value)
+ if (!value || !value->is_string())
return 0;
- std::string result("0");
- bool rv = value->GetAsString(&result);
- DCHECK(rv);
- uint64_t val;
- base::StringToUint64(result, &val);
- return val;
+ uint64_t result;
+ base::StringToUint64(value->GetString(), &result);
+ return result;
}
void PrefService::SetTime(const std::string& path, base::Time value) {
@@ -721,19 +699,19 @@ const base::Value* PrefService::GetPreferenceValue(
CHECK(pref_value_store_);
const base::Value* default_value = nullptr;
- if (pref_registry_->defaults()->GetValue(path, &default_value)) {
- const base::Value* found_value = nullptr;
- base::Value::Type default_type = default_value->type();
- if (pref_value_store_->GetValue(path, default_type, &found_value)) {
- DCHECK(found_value->type() == default_type);
- return found_value;
- } else {
- // Every registered preference has at least a default value.
- NOTREACHED() << "no valid value found for registered pref " << path;
- }
+ if (!pref_registry_->defaults()->GetValue(path, &default_value))
+ return nullptr;
+
+ const base::Value* found_value = nullptr;
+ base::Value::Type default_type = default_value->type();
+ if (!pref_value_store_->GetValue(path, default_type, &found_value)) {
+ // Every registered preference has at least a default value.
+ NOTREACHED() << "no valid value found for registered pref " << path;
+ return nullptr;
}
- return nullptr;
+ DCHECK_EQ(found_value->type(), default_type);
+ return found_value;
}
const base::Value* PrefService::GetPreferenceValueChecked(
diff --git a/chromium/components/prefs/pref_service.h b/chromium/components/prefs/pref_service.h
index e77baccae7f..53532b0568e 100644
--- a/chromium/components/prefs/pref_service.h
+++ b/chromium/components/prefs/pref_service.h
@@ -306,8 +306,7 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// If INCLUDE_DEFAULTS is requested, preferences set to their default values
// will be included. Otherwise, these will be omitted from the returned
// dictionary.
- std::unique_ptr<base::DictionaryValue> GetPreferenceValues(
- IncludeDefaults include_defaults) const;
+ base::Value GetPreferenceValues(IncludeDefaults include_defaults) const;
bool ReadOnly() const;
diff --git a/chromium/components/prefs/pref_service_factory.cc b/chromium/components/prefs/pref_service_factory.cc
index cc8e52d887e..a60d22cffb4 100644
--- a/chromium/components/prefs/pref_service_factory.cc
+++ b/chromium/components/prefs/pref_service_factory.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/sequenced_task_runner.h"
#include "components/prefs/default_pref_store.h"
#include "components/prefs/json_pref_store.h"
diff --git a/chromium/components/prefs/pref_service_unittest.cc b/chromium/components/prefs/pref_service_unittest.cc
index 4dc3d1154ed..392cd6816c8 100644
--- a/chromium/components/prefs/pref_service_unittest.cc
+++ b/chromium/components/prefs/pref_service_unittest.cc
@@ -7,7 +7,7 @@
#include <string>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "base/values.h"
diff --git a/chromium/components/prefs/pref_test_utils.cc b/chromium/components/prefs/pref_test_utils.cc
index 8c83aaf32af..8f7bcd8ed5d 100644
--- a/chromium/components/prefs/pref_test_utils.cc
+++ b/chromium/components/prefs/pref_test_utils.cc
@@ -5,7 +5,7 @@
#include "components/prefs/pref_test_utils.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/values.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
diff --git a/chromium/components/prerender/browser/prerender_field_trial.cc b/chromium/components/prerender/browser/prerender_field_trial.cc
deleted file mode 100644
index 3d386bce56c..00000000000
--- a/chromium/components/prerender/browser/prerender_field_trial.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2012 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/prerender/browser/prerender_field_trial.h"
-
-#include <string>
-
-#include "base/metrics/field_trial.h"
-#include "components/prerender/browser/prerender_manager.h"
-
-namespace prerender {
-
-const base::Feature kNoStatePrefetchFeature{"NoStatePrefetch",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kGWSPrefetchHoldback{"GWSPrefetchHoldback",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kNavigationPredictorPrefetchHoldback{
- "NavigationPredictorPrefetchHoldback", base::FEATURE_DISABLED_BY_DEFAULT};
-
-void ConfigureNoStatePrefetch() {
- auto mode = PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH;
- if (!base::FeatureList::IsEnabled(kNoStatePrefetchFeature))
- mode = PrerenderManager::PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT;
- PrerenderManager::SetMode(mode);
-}
-
-bool IsNoStatePrefetchEnabled() {
- return PrerenderManager::GetMode() ==
- PrerenderManager::PRERENDER_MODE_NOSTATE_PREFETCH;
-}
-
-} // namespace prerender
diff --git a/chromium/components/previews/content/previews_decider_impl.cc b/chromium/components/previews/content/previews_decider_impl.cc
index defeaa5e030..8d56c58ac40 100644
--- a/chromium/components/previews/content/previews_decider_impl.cc
+++ b/chromium/components/previews/content/previews_decider_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
diff --git a/chromium/components/previews/content/previews_decider_impl_unittest.cc b/chromium/components/previews/content/previews_decider_impl_unittest.cc
index 985d9d54470..b992aef618b 100644
--- a/chromium/components/previews/content/previews_decider_impl_unittest.cc
+++ b/chromium/components/previews/content/previews_decider_impl_unittest.cc
@@ -13,8 +13,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/components/previews/core/previews_block_list_unittest.cc b/chromium/components/previews/core/previews_block_list_unittest.cc
index 85cbcb596b1..c225350eaa4 100644
--- a/chromium/components/previews/core/previews_block_list_unittest.cc
+++ b/chromium/components/previews/core/previews_block_list_unittest.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
diff --git a/chromium/components/previous_session_info/BUILD.gn b/chromium/components/previous_session_info/BUILD.gn
new file mode 100644
index 00000000000..66415edc110
--- /dev/null
+++ b/chromium/components/previous_session_info/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2020 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.
+
+source_set("previous_session_info") {
+ assert(is_ios)
+ configs += [ "//build/config/compiler:enable_arc" ]
+ sources = [
+ "previous_session_info.h",
+ "previous_session_info.mm",
+ "previous_session_info_private.h",
+ ]
+ deps = [
+ "//base",
+ "//components/version_info",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ configs += [ "//build/config/compiler:enable_arc" ]
+ testonly = true
+ sources = [ "previous_session_info_unittest.mm" ]
+ deps = [
+ ":previous_session_info",
+ "//base",
+ "//base/test:test_support",
+ "//components/version_info",
+ "//ios/web/public/test",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/previous_session_info/DEPS b/chromium/components/previous_session_info/DEPS
new file mode 100644
index 00000000000..6137f48c935
--- /dev/null
+++ b/chromium/components/previous_session_info/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/version_info/version_info.h",
+ "+ios/web/public/test/web_task_environment.h",
+]
diff --git a/chromium/components/previous_session_info/OWNERS b/chromium/components/previous_session_info/OWNERS
new file mode 100644
index 00000000000..7ff5a0dfea6
--- /dev/null
+++ b/chromium/components/previous_session_info/OWNERS
@@ -0,0 +1,5 @@
+eugenebut@chromium.org
+olivierrobin@chromium.org
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/chromium/components/previous_session_info/README b/chromium/components/previous_session_info/README
new file mode 100644
index 00000000000..ea885d60cea
--- /dev/null
+++ b/chromium/components/previous_session_info/README
@@ -0,0 +1,3 @@
+# PreviousSessionInfo
+
+PreviousSessionInfo is a component to allow using this code in other components code on iOS.
diff --git a/chromium/components/previous_session_info/previous_session_info.h b/chromium/components/previous_session_info/previous_session_info.h
new file mode 100644
index 00000000000..47a78a2f220
--- /dev/null
+++ b/chromium/components/previous_session_info/previous_session_info.h
@@ -0,0 +1,233 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_H_
+#define COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_H_
+
+#import <UIKit/UIKit.h>
+
+#include "base/callback_helpers.h"
+
+#include "url/gurl.h"
+
+namespace previous_session_info_constants {
+// - The (Integer) representing UIApplicationState.
+extern NSString* const kPreviousSessionInfoApplicationState;
+// Key in the UserDefaults for a boolean value keeping track of memory warnings.
+extern NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating;
+// Key in the UserDefaults for a double value which stores OS start time.
+extern NSString* const kOSStartTime;
+// Key in the UserDefaults for a boolean describing whether or not the session
+// restoration is in progress.
+extern NSString* const kPreviousSessionInfoRestoringSession;
+// Key in the UserDefaults for an array which contains the ids for the connected
+// scene sessions on the previous run.
+extern NSString* const kPreviousSessionInfoConnectedSceneSessionIDs;
+// Key in the UserDefaults for a dictionary with session info params.
+extern NSString* const kPreviousSessionInfoParams;
+// Key in the UserDefaults for the memory footprint of the browser process.
+extern NSString* const kPreviousSessionInfoMemoryFootprint;
+// Key in the UserDefaults for the number of open tabs.
+extern NSString* const kPreviousSessionInfoTabCount;
+// Key in the UserDefaults for the number of open "off the record" tabs.
+extern NSString* const kPreviousSessionInfoOTRTabCount;
+
+// The values of this enum are persisted (both to NSUserDefaults and logs) and
+// represent the state of the last session (which may have been running a
+// different version of the application).
+// Therefore, entries should not be renumbered and numeric values should never
+// be reused.
+enum class DeviceThermalState {
+ kUnknown = 0,
+ kNominal = 1,
+ kFair = 2,
+ kSerious = 3,
+ kCritical = 4,
+ kMaxValue = kCritical,
+};
+
+// The values of this enum are persisted (both to NSUserDefaults and logs) and
+// represent the state of the last session (which may have been running a
+// different version of the application).
+// Therefore, entries should not be renumbered and numeric values should never
+// be reused.
+enum class DeviceBatteryState {
+ kUnknown = 0,
+ kUnplugged = 1,
+ kCharging = 2,
+ // Battery is plugged into power and the battery is 100% charged.
+ kFull = 3,
+ kMaxValue = kFull,
+};
+} // namespace previous_session_info_constants
+
+// PreviousSessionInfo has two jobs:
+// - Holding information about the last session, persisted across restart.
+// These informations are accessible via the properties on the shared
+// instance.
+// - Persist information about the current session, for use in a next session.
+@interface PreviousSessionInfo : NSObject
+
+// UIApplicationState at the end of the previous session or nil if state is
+// unknown.
+@property(nonatomic, assign, readonly) UIApplicationState* applicationState;
+
+// The battery level of the device at the end of the previous session.
+@property(nonatomic, assign, readonly) float deviceBatteryLevel;
+
+// The battery state of the device at the end of the previous session.
+@property(nonatomic, assign, readonly)
+ previous_session_info_constants::DeviceBatteryState deviceBatteryState;
+
+// The storage available, in kilobytes, at the end of the previous session or -1
+// if no previous session data is available.
+@property(nonatomic, assign, readonly) NSInteger availableDeviceStorage;
+
+// The thermal state of the device at the end of the previous session.
+@property(nonatomic, assign, readonly)
+ previous_session_info_constants::DeviceThermalState deviceThermalState;
+
+// Whether the device was in low power mode at the end of the previous session.
+@property(nonatomic, assign, readonly) BOOL deviceWasInLowPowerMode;
+
+// Whether the app received a memory warning seconds before being terminated.
+@property(nonatomic, assign, readonly)
+ BOOL didSeeMemoryWarningShortlyBeforeTerminating;
+
+// Whether the app was updated between the previous and the current session.
+@property(nonatomic, assign, readonly) BOOL isFirstSessionAfterUpgrade;
+
+// Whether the language has been changed between the previous and the current
+// session.
+@property(nonatomic, assign, readonly) BOOL isFirstSessionAfterLanguageChange;
+
+// Whether or not the OS was restarted between the previous and the current
+// session.
+@property(nonatomic, assign, readonly) BOOL OSRestartedAfterPreviousSession;
+
+// Whether the previous session was on Multi Window enabled version of the
+// application. A previous session doesn't have to be from a previous run, in
+// the case of single window to multiple windows migration, after the first
+// session created/restored the flag value should be updated to |YES|.
+// TODO(crbug.com/1109280): Remove after the migration to Multi-Window sessions
+// is done.
+@property(nonatomic, assign, readonly) BOOL isMultiWindowEnabledSession;
+
+// The OS version during the previous session or nil if no previous session data
+// is available.
+@property(nonatomic, strong, readonly) NSString* OSVersion;
+
+// The date time at which recording for the previous sesion has started. Note
+// that recording usually starts soon after startup, but not exactly at the
+// startup.
+@property(nonatomic, strong, readonly) NSDate* sessionStartTime;
+
+// The time at which the previous sesion ended. Note that this is only an
+// estimate and is updated whenever another value of the receiver is updated.
+@property(nonatomic, strong, readonly) NSDate* sessionEndTime;
+
+// YES if the previous session was terminated during session restoration.
+// Reset to NO after resetSessionRestorationFlag call.
+@property(nonatomic, readonly) BOOL terminatedDuringSessionRestoration;
+
+// The list of the session IDs for all the connected scenes, used for crash
+// restoration.
+@property(nonatomic, readonly)
+ NSMutableSet<NSString*>* connectedSceneSessionsIDs;
+
+// Crash report parameters as key-value pairs.
+@property(nonatomic, readonly)
+ NSDictionary<NSString*, NSString*>* reportParameters;
+
+// Memory footprint in bytes of the browser process.
+@property(nonatomic, readonly) NSInteger memoryFootprint;
+
+// YES if ApplicationWillTerminate notification was posted for the previous
+// session.
+@property(nonatomic, readonly) BOOL applicationWillTerminateWasReceived;
+
+// Number of open tabs in the previous session.
+@property(nonatomic, readonly) NSInteger tabCount;
+
+// Number of open "off the record" tabs in the previous session.
+@property(nonatomic, readonly) NSInteger OTRTabCount;
+
+// Singleton PreviousSessionInfo. During the lifetime of the app, the returned
+// object is the same, and describes the previous session, even after a new
+// session has started (by calling beginRecordingCurrentSession).
++ (instancetype)sharedInstance;
+
+// Clears the persisted information about the previous session and starts
+// persisting information about the current session, for use in a next session.
+- (void)beginRecordingCurrentSession;
+
+// Starts memory usage data recording with given |interval|.
+- (void)startRecordingMemoryFootprintWithInterval:(base::TimeDelta)interval;
+
+// Stops memory usage data recording. No-op if
+// startRecordingMemoryFootprintWithInterval was no called.
+- (void)stopRecordingMemoryFootprint;
+
+// Updates the currently available device storage, in kilobytes.
+- (void)updateAvailableDeviceStorage:(NSInteger)availableStorage;
+
+// Updates the saved last known session time.
+- (void)updateSessionEndTime;
+
+// Updates the saved last known battery level of the device.
+- (void)updateStoredBatteryLevel;
+
+// Updates the saved last known battery state of the device.
+- (void)updateStoredBatteryState;
+
+// Updates the saved last known low power mode setting of the device.
+- (void)updateStoredLowPowerMode;
+
+// Updates the saved last known thermal state of the device.
+- (void)updateStoredThermalState;
+
+// When a session has begun, records that a memory warning was received.
+- (void)setMemoryWarningFlag;
+
+// When a session has begun, records that any memory warning flagged can be
+// ignored.
+- (void)resetMemoryWarningFlag;
+
+// Adds |sessionID| to the list of connected sessions.
+- (void)addSceneSessionID:(NSString*)sessionID;
+
+// Removes |sessionID| from the list of connected sessions.
+- (void)removeSceneSessionID:(NSString*)sessionID;
+
+// Empties the list of connected session.
+- (void)resetConnectedSceneSessionIDs;
+
+// Updates the local and the saved Multi Window support status.
+// TODO(crbug.com/1109280): Remove after the migration to Multi-Window
+// sessions is done.
+- (void)updateMultiWindowSupportStatus;
+
+// Must be called when Chrome starts session restoration. The returned closure
+// runner will clear up the flag when destroyed. Can be used on different
+// threads.
+- (base::ScopedClosureRunner)startSessionRestoration;
+
+// Must be called after reporting UTE metrics when app is started after UTE.
+// Automatically called when ScopedClosureRunner returned from -startRestoration
+// gets destructed.
+- (void)resetSessionRestorationFlag;
+
+// Records number of regular (non off the record) tabs.
+- (void)updateCurrentSessionTabCount:(NSInteger)count;
+// Records number of off the record tabs.
+- (void)updateCurrentSessionOTRTabCount:(NSInteger)count;
+
+// Records information crash report parameters.
+- (void)setReportParameterValue:(NSString*)value forKey:(NSString*)key;
+- (void)setReportParameterURL:(const GURL&)URL forKey:(NSString*)key;
+- (void)removeReportParameterForKey:(NSString*)key;
+
+@end
+
+#endif // COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_H_
diff --git a/chromium/components/previous_session_info/previous_session_info.mm b/chromium/components/previous_session_info/previous_session_info.mm
new file mode 100644
index 00000000000..6f3ef6a88c3
--- /dev/null
+++ b/chromium/components/previous_session_info/previous_session_info.mm
@@ -0,0 +1,653 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "components/previous_session_info/previous_session_info.h"
+
+#include <mach/mach.h>
+
+#import <UIKit/UIKit.h>
+
+#include "base/ios/ios_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/system/sys_info.h"
+#include "base/timer/timer.h"
+#import "components/previous_session_info/previous_session_info_private.h"
+#include "components/version_info/version_info.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using previous_session_info_constants::DeviceBatteryState;
+using previous_session_info_constants::DeviceThermalState;
+
+namespace {
+
+// Returns timestamp (in seconds since January 2001) when OS has started.
+NSTimeInterval GetOSStartTimeIntervalSinceReferenceDate() {
+ return NSDate.timeIntervalSinceReferenceDate -
+ NSProcessInfo.processInfo.systemUptime;
+}
+
+// Translates a UIDeviceBatteryState value to DeviceBatteryState value.
+DeviceBatteryState GetBatteryStateFromUIDeviceBatteryState(
+ UIDeviceBatteryState device_battery_state) {
+ switch (device_battery_state) {
+ case UIDeviceBatteryStateUnknown:
+ return DeviceBatteryState::kUnknown;
+ case UIDeviceBatteryStateUnplugged:
+ return DeviceBatteryState::kUnplugged;
+ case UIDeviceBatteryStateCharging:
+ return DeviceBatteryState::kCharging;
+ case UIDeviceBatteryStateFull:
+ return DeviceBatteryState::kFull;
+ }
+
+ return DeviceBatteryState::kUnknown;
+}
+
+// Translates a NSProcessInfoThermalState value to DeviceThermalState value.
+DeviceThermalState GetThermalStateFromNSProcessInfoThermalState(
+ NSProcessInfoThermalState process_info_thermal_state) {
+ switch (process_info_thermal_state) {
+ case NSProcessInfoThermalStateNominal:
+ return DeviceThermalState::kNominal;
+ case NSProcessInfoThermalStateFair:
+ return DeviceThermalState::kFair;
+ case NSProcessInfoThermalStateSerious:
+ return DeviceThermalState::kSerious;
+ case NSProcessInfoThermalStateCritical:
+ return DeviceThermalState::kCritical;
+ }
+
+ return DeviceThermalState::kUnknown;
+}
+
+// NSUserDefaults keys.
+// - The (string) application version.
+NSString* const kLastRanVersion = @"LastRanVersion";
+// - The (string) device language.
+NSString* const kLastRanLanguage = @"LastRanLanguage";
+// - The (integer) available device storage, in kilobytes.
+NSString* const kPreviousSessionInfoAvailableDeviceStorage =
+ @"PreviousSessionInfoAvailableDeviceStorage";
+// - The (float) battery charge level.
+NSString* const kPreviousSessionInfoBatteryLevel =
+ @"PreviousSessionInfoBatteryLevel";
+// - The (integer) underlying value of the DeviceBatteryState enum representing
+// the device battery state.
+NSString* const kPreviousSessionInfoBatteryState =
+ @"PreviousSessionInfoBatteryState";
+// - The (Date) of the recording start.
+NSString* const kPreviousSessionInfoStartTime = @"PreviousSessionInfoStartTime";
+// - The (Date) of the estimated end of the session.
+NSString* const kPreviousSessionInfoEndTime = @"PreviousSessionInfoEndTime";
+// - The (string) OS version.
+NSString* const kPreviousSessionInfoOSVersion = @"PreviousSessionInfoOSVersion";
+// - The (integer) underlying value of the DeviceThermalState enum representing
+// the device thermal state.
+NSString* const kPreviousSessionInfoThermalState =
+ @"PreviousSessionInfoThermalState";
+// - A (boolean) describing whether or not low power mode is enabled.
+NSString* const kPreviousSessionInfoLowPowerMode =
+ @"PreviousSessionInfoLowPowerMode";
+// - A (boolean) describing whether the last session was on Multi-Window enabled
+// version of the application.
+NSString* const kPreviousSessionInfoMultiWindowEnabled =
+ @"PreviousSessionInfoMultiWindowEnabled";
+// - A (boolean) describing whether the last session received
+// ApplicationWillTerminate Notification.
+NSString* const kPreviousSessionInfoAppWillTerminate =
+ @"PreviousSessionInfoAppWillTerminate";
+} // namespace
+
+namespace previous_session_info_constants {
+NSString* const kPreviousSessionInfoApplicationState =
+ @"PreviousSessionInfoApplicationState";
+NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating =
+ @"DidSeeMemoryWarning";
+NSString* const kOSStartTime = @"OSStartTime";
+NSString* const kPreviousSessionInfoRestoringSession =
+ @"PreviousSessionInfoRestoringSession";
+NSString* const kPreviousSessionInfoConnectedSceneSessionIDs =
+ @"PreviousSessionInfoConnectedSceneSessionIDs";
+NSString* const kPreviousSessionInfoParams = @"PreviousSessionInfoParams";
+NSString* const kPreviousSessionInfoMemoryFootprint =
+ @"PreviousSessionInfoMemoryFootprint";
+NSString* const kPreviousSessionInfoTabCount = @"PreviousSessionInfoTabCount";
+NSString* const kPreviousSessionInfoOTRTabCount =
+ @"PreviousSessionInfoOTRTabCount";
+} // namespace previous_session_info_constants
+
+@interface PreviousSessionInfo ()
+
+// Whether beginRecordingCurrentSession was called.
+@property(nonatomic, assign) BOOL didBeginRecordingCurrentSession;
+
+// Whether recording data is in progress.
+@property(nonatomic, assign) BOOL recordingCurrentSession;
+
+// Used for setting and resetting kPreviousSessionInfoRestoringSession flag.
+// Can be greater than one if multiple sessions are being restored in parallel.
+@property(atomic, assign) int numberOfSessionsBeingRestored;
+
+// Redefined to be read-write.
+@property(nonatomic, assign) NSInteger availableDeviceStorage;
+@property(nonatomic, assign) float deviceBatteryLevel;
+@property(nonatomic, assign) DeviceBatteryState deviceBatteryState;
+@property(nonatomic, assign) DeviceThermalState deviceThermalState;
+@property(nonatomic, assign) BOOL deviceWasInLowPowerMode;
+@property(nonatomic, assign) BOOL didSeeMemoryWarningShortlyBeforeTerminating;
+@property(nonatomic, assign) BOOL isFirstSessionAfterUpgrade;
+@property(nonatomic, assign) BOOL isFirstSessionAfterLanguageChange;
+@property(nonatomic, assign) BOOL isMultiWindowEnabledSession;
+@property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
+@property(nonatomic, strong) NSString* OSVersion;
+@property(nonatomic, strong) NSDate* sessionStartTime;
+@property(nonatomic, strong) NSDate* sessionEndTime;
+@property(nonatomic, assign) BOOL terminatedDuringSessionRestoration;
+@property(nonatomic, strong) NSMutableSet<NSString*>* connectedSceneSessionsIDs;
+@property(nonatomic, copy) NSDictionary<NSString*, NSString*>* reportParameters;
+@property(nonatomic, assign) NSInteger memoryFootprint;
+@property(nonatomic, assign) BOOL applicationWillTerminateWasReceived;
+@property(nonatomic, assign) NSInteger tabCount;
+@property(nonatomic, assign) NSInteger OTRTabCount;
+
+@end
+
+@implementation PreviousSessionInfo {
+ std::unique_ptr<UIApplicationState> _applicationState;
+ base::RepeatingTimer _memoryFootprintUpdateTimer;
+}
+
+// Singleton PreviousSessionInfo.
+static PreviousSessionInfo* gSharedInstance = nil;
+
++ (instancetype)sharedInstance {
+ if (!gSharedInstance) {
+ gSharedInstance = [[PreviousSessionInfo alloc] init];
+
+ // Load the persisted information.
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+ gSharedInstance->_applicationState.reset();
+ if ([defaults objectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]) {
+ gSharedInstance->_applicationState = std::make_unique<UIApplicationState>(
+ static_cast<UIApplicationState>([defaults
+ integerForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]));
+ }
+
+ gSharedInstance.availableDeviceStorage = -1;
+ if ([defaults objectForKey:kPreviousSessionInfoAvailableDeviceStorage]) {
+ gSharedInstance.availableDeviceStorage =
+ [defaults integerForKey:kPreviousSessionInfoAvailableDeviceStorage];
+ }
+ gSharedInstance.didSeeMemoryWarningShortlyBeforeTerminating =
+ [defaults boolForKey:previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating];
+ gSharedInstance.deviceWasInLowPowerMode =
+ [defaults boolForKey:kPreviousSessionInfoLowPowerMode];
+ gSharedInstance.deviceBatteryState = static_cast<DeviceBatteryState>(
+ [defaults integerForKey:kPreviousSessionInfoBatteryState]);
+ gSharedInstance.deviceBatteryLevel =
+ [defaults floatForKey:kPreviousSessionInfoBatteryLevel];
+ gSharedInstance.deviceThermalState = static_cast<DeviceThermalState>(
+ [defaults integerForKey:kPreviousSessionInfoThermalState]);
+ gSharedInstance.sessionStartTime =
+ [defaults objectForKey:kPreviousSessionInfoStartTime];
+ gSharedInstance.sessionEndTime =
+ [defaults objectForKey:kPreviousSessionInfoEndTime];
+
+ NSString* versionOfOSAtLastRun =
+ [defaults stringForKey:kPreviousSessionInfoOSVersion];
+ gSharedInstance.OSVersion = versionOfOSAtLastRun;
+
+ NSString* lastRanVersion = [defaults stringForKey:kLastRanVersion];
+ NSString* currentVersion =
+ base::SysUTF8ToNSString(version_info::GetVersionNumber());
+ gSharedInstance.isFirstSessionAfterUpgrade =
+ ![lastRanVersion isEqualToString:currentVersion];
+
+ // TODO(crbug.com/1109280): Remove after the migration to Multi-Window
+ // sessions is done.
+ gSharedInstance.isMultiWindowEnabledSession =
+ [defaults boolForKey:kPreviousSessionInfoMultiWindowEnabled];
+
+ gSharedInstance.connectedSceneSessionsIDs = [NSMutableSet
+ setWithArray:[defaults
+ stringArrayForKey:
+ previous_session_info_constants::
+ kPreviousSessionInfoConnectedSceneSessionIDs]];
+
+ NSTimeInterval lastSystemStartTime =
+ [defaults doubleForKey:previous_session_info_constants::kOSStartTime];
+
+ gSharedInstance.OSRestartedAfterPreviousSession =
+ // Allow 5 seconds variation to account for rounding error.
+ (abs(lastSystemStartTime - GetOSStartTimeIntervalSinceReferenceDate()) >
+ 5) &&
+ // Ensure that previous session actually exists.
+ lastSystemStartTime;
+
+ NSString* lastRanLanguage = [defaults stringForKey:kLastRanLanguage];
+ NSString* currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
+ gSharedInstance.isFirstSessionAfterLanguageChange =
+ ![lastRanLanguage isEqualToString:currentLanguage];
+
+ gSharedInstance.terminatedDuringSessionRestoration =
+ [defaults boolForKey:previous_session_info_constants::
+ kPreviousSessionInfoRestoringSession];
+
+ gSharedInstance.reportParameters =
+ [defaults dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+
+ gSharedInstance.memoryFootprint =
+ [defaults integerForKey:previous_session_info_constants::
+ kPreviousSessionInfoMemoryFootprint];
+
+ gSharedInstance.applicationWillTerminateWasReceived =
+ [defaults boolForKey:kPreviousSessionInfoAppWillTerminate];
+ gSharedInstance.tabCount =
+ [defaults integerForKey:previous_session_info_constants::
+ kPreviousSessionInfoTabCount];
+ gSharedInstance.OTRTabCount =
+ [defaults integerForKey:previous_session_info_constants::
+ kPreviousSessionInfoOTRTabCount];
+ }
+ return gSharedInstance;
+}
+
++ (void)resetSharedInstanceForTesting {
+ gSharedInstance = nil;
+}
+
+- (void)beginRecordingCurrentSession {
+ if (self.didBeginRecordingCurrentSession)
+ return;
+ self.didBeginRecordingCurrentSession = YES;
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+ // Set the current Chrome version.
+ NSString* currentVersion =
+ base::SysUTF8ToNSString(version_info::GetVersionNumber());
+ [defaults setObject:currentVersion forKey:kLastRanVersion];
+
+ // Set the current OS start time.
+ [defaults setDouble:GetOSStartTimeIntervalSinceReferenceDate()
+ forKey:previous_session_info_constants::kOSStartTime];
+
+ // Set the current OS version.
+ NSString* currentOSVersion =
+ base::SysUTF8ToNSString(base::SysInfo::OperatingSystemVersion());
+ [defaults setObject:currentOSVersion forKey:kPreviousSessionInfoOSVersion];
+
+ // Set the current language.
+ NSString* currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
+ [defaults setObject:currentLanguage forKey:kLastRanLanguage];
+
+ // Clear the memory warning flag.
+ [defaults
+ removeObjectForKey:previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating];
+
+ [[NSUserDefaults standardUserDefaults]
+ removeObjectForKey:kPreviousSessionInfoAppWillTerminate];
+
+ [defaults setObject:[NSDate date] forKey:kPreviousSessionInfoStartTime];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateApplicationState)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateApplicationState)
+ name:UIApplicationWillEnterForegroundNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(protectedDataWillBecomeUnavailable)
+ name:UIApplicationProtectedDataWillBecomeUnavailable
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(protectedDataDidBecomeAvailable)
+ name:UIApplicationProtectedDataWillBecomeUnavailable
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateApplicationState)
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateApplicationState)
+ name:UIApplicationWillResignActiveNotification
+ object:nil];
+
+ [UIDevice currentDevice].batteryMonitoringEnabled = YES;
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateStoredBatteryLevel)
+ name:UIDeviceBatteryLevelDidChangeNotification
+ object:nil];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateStoredBatteryState)
+ name:UIDeviceBatteryStateDidChangeNotification
+ object:nil];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateStoredLowPowerMode)
+ name:NSProcessInfoPowerStateDidChangeNotification
+ object:nil];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateStoredThermalState)
+ name:NSProcessInfoThermalStateDidChangeNotification
+ object:nil];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationWillTerminate)
+ name:UIApplicationWillTerminateNotification
+ object:nil];
+
+ [self resumeRecordingCurrentSession];
+}
+
+- (void)startRecordingMemoryFootprintWithInterval:(base::TimeDelta)interval {
+ _memoryFootprintUpdateTimer.Start(FROM_HERE, interval, base::BindRepeating(^{
+ [self updateMemoryFootprint];
+ }));
+}
+
+- (void)stopRecordingMemoryFootprint {
+ _memoryFootprintUpdateTimer.Stop();
+}
+- (void)resumeRecordingCurrentSession {
+ if (self.recordingCurrentSession)
+ return;
+ self.recordingCurrentSession = YES;
+ [self updateApplicationState];
+ [self updateStoredBatteryLevel];
+ [self updateStoredBatteryState];
+ [self updateStoredLowPowerMode];
+ [self updateStoredThermalState];
+ // Save critical state information for crash detection.
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (void)pauseRecordingCurrentSession {
+ self.recordingCurrentSession = NO;
+}
+
+- (void)protectedDataWillBecomeUnavailable {
+ [self pauseRecordingCurrentSession];
+}
+
+- (void)protectedDataDidBecomeAvailable {
+ [self resumeRecordingCurrentSession];
+}
+
+- (UIApplicationState*)applicationState {
+ return _applicationState.get();
+}
+
+- (void)updateAvailableDeviceStorage:(NSInteger)availableStorage {
+ if (!self.recordingCurrentSession)
+ return;
+
+ [[NSUserDefaults standardUserDefaults]
+ setInteger:availableStorage
+ forKey:kPreviousSessionInfoAvailableDeviceStorage];
+
+ [self updateSessionEndTime];
+}
+
+- (void)updateSessionEndTime {
+ if (!self.recordingCurrentSession)
+ return;
+ [[NSUserDefaults standardUserDefaults] setObject:[NSDate date]
+ forKey:kPreviousSessionInfoEndTime];
+}
+
+- (void)updateStoredBatteryLevel {
+ if (!self.recordingCurrentSession)
+ return;
+ [[NSUserDefaults standardUserDefaults]
+ setFloat:[UIDevice currentDevice].batteryLevel
+ forKey:kPreviousSessionInfoBatteryLevel];
+ [self updateSessionEndTime];
+}
+
+- (void)updateApplicationState {
+ if (!self.recordingCurrentSession)
+ return;
+ [[NSUserDefaults standardUserDefaults]
+ setInteger:UIApplication.sharedApplication.applicationState
+ forKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+
+ [self updateSessionEndTime];
+}
+
+- (void)updateStoredBatteryState {
+ if (!self.recordingCurrentSession)
+ return;
+ UIDevice* device = [UIDevice currentDevice];
+ // Translate value to an app defined enum as the system could change the
+ // underlying values of UIDeviceBatteryState between OS versions.
+ DeviceBatteryState batteryState =
+ GetBatteryStateFromUIDeviceBatteryState(device.batteryState);
+ NSInteger batteryStateValue =
+ static_cast<std::underlying_type<DeviceBatteryState>::type>(batteryState);
+
+ [[NSUserDefaults standardUserDefaults]
+ setInteger:batteryStateValue
+ forKey:kPreviousSessionInfoBatteryState];
+
+ [self updateSessionEndTime];
+}
+
+- (void)updateStoredLowPowerMode {
+ if (!self.recordingCurrentSession)
+ return;
+ BOOL isLowPoweredModeEnabled =
+ [[NSProcessInfo processInfo] isLowPowerModeEnabled];
+ [[NSUserDefaults standardUserDefaults]
+ setInteger:isLowPoweredModeEnabled
+ forKey:kPreviousSessionInfoLowPowerMode];
+
+ [self updateSessionEndTime];
+}
+
+- (void)updateStoredThermalState {
+ if (!self.recordingCurrentSession)
+ return;
+ NSProcessInfo* processInfo = [NSProcessInfo processInfo];
+ // Translate value to an app defined enum as the system could change the
+ // underlying values of NSProcessInfoThermalState between OS versions.
+ DeviceThermalState thermalState =
+ GetThermalStateFromNSProcessInfoThermalState([processInfo thermalState]);
+ NSInteger thermalStateValue =
+ static_cast<std::underlying_type<DeviceThermalState>::type>(thermalState);
+
+ [[NSUserDefaults standardUserDefaults]
+ setInteger:thermalStateValue
+ forKey:kPreviousSessionInfoThermalState];
+
+ [self updateSessionEndTime];
+}
+
+- (void)applicationWillTerminate {
+ [NSUserDefaults.standardUserDefaults
+ setBool:YES
+ forKey:kPreviousSessionInfoAppWillTerminate];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)updateMemoryFootprint {
+ if (!self.recordingCurrentSession)
+ return;
+
+ task_vm_info taskInfoData;
+ mach_msg_type_number_t count = sizeof(task_vm_info) / sizeof(natural_t);
+ kern_return_t result =
+ task_info(mach_task_self(), TASK_VM_INFO,
+ reinterpret_cast<task_info_t>(&taskInfoData), &count);
+ if (result == KERN_SUCCESS) {
+ [NSUserDefaults.standardUserDefaults
+ setInteger:taskInfoData.phys_footprint
+ forKey:previous_session_info_constants::
+ kPreviousSessionInfoMemoryFootprint];
+ [self updateSessionEndTime];
+ }
+}
+
+- (void)setMemoryWarningFlag {
+ if (!self.didBeginRecordingCurrentSession)
+ return;
+
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setBool:YES
+ forKey:previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating];
+ // Save critical state information for crash detection.
+ [defaults synchronize];
+}
+
+- (void)resetMemoryWarningFlag {
+ if (!self.didBeginRecordingCurrentSession)
+ return;
+
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults
+ removeObjectForKey:previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating];
+ // Save critical state information for crash detection.
+ [defaults synchronize];
+}
+
+- (void)synchronizeSceneSessionIDs {
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:[self.connectedSceneSessionsIDs allObjects]
+ forKey:previous_session_info_constants::
+ kPreviousSessionInfoConnectedSceneSessionIDs];
+ [defaults synchronize];
+}
+
+- (void)addSceneSessionID:(NSString*)sessionID {
+ [self.connectedSceneSessionsIDs addObject:sessionID];
+ [self synchronizeSceneSessionIDs];
+}
+
+- (void)removeSceneSessionID:(NSString*)sessionID {
+ [self.connectedSceneSessionsIDs removeObject:sessionID];
+ [self synchronizeSceneSessionIDs];
+}
+
+- (void)resetConnectedSceneSessionIDs {
+ self.connectedSceneSessionsIDs = [[NSMutableSet alloc] init];
+ [self synchronizeSceneSessionIDs];
+}
+
+- (void)updateMultiWindowSupportStatus {
+ gSharedInstance.isMultiWindowEnabledSession =
+ base::ios::IsMultiwindowSupported();
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setBool:gSharedInstance.isMultiWindowEnabledSession
+ forKey:kPreviousSessionInfoMultiWindowEnabled];
+ [defaults synchronize];
+}
+
+- (base::ScopedClosureRunner)startSessionRestoration {
+ if (self.numberOfSessionsBeingRestored == 0) {
+ [NSUserDefaults.standardUserDefaults
+ setBool:YES
+ forKey:previous_session_info_constants::
+ kPreviousSessionInfoRestoringSession];
+ // Save critical state information for crash detection.
+ [NSUserDefaults.standardUserDefaults synchronize];
+ }
+ ++self.numberOfSessionsBeingRestored;
+
+ return base::ScopedClosureRunner(base::BindOnce(^{
+ --self.numberOfSessionsBeingRestored;
+ if (self.numberOfSessionsBeingRestored == 0) {
+ [self resetSessionRestorationFlag];
+ }
+ }));
+}
+
+- (void)resetSessionRestorationFlag {
+ gSharedInstance.terminatedDuringSessionRestoration = NO;
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoRestoringSession];
+ // Save critical state information for crash detection.
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)updateCurrentSessionTabCount:(NSInteger)count {
+ [NSUserDefaults.standardUserDefaults
+ setInteger:count
+ forKey:previous_session_info_constants::kPreviousSessionInfoTabCount];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)updateCurrentSessionOTRTabCount:(NSInteger)count {
+ [NSUserDefaults.standardUserDefaults
+ setInteger:count
+ forKey:previous_session_info_constants::
+ kPreviousSessionInfoOTRTabCount];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)setReportParameterValue:(NSString*)value forKey:(NSString*)key {
+ NSMutableDictionary* params = [[NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams] mutableCopy];
+ if (!params) {
+ params = [NSMutableDictionary dictionaryWithCapacity:1];
+ }
+ params[key] = value;
+ [NSUserDefaults.standardUserDefaults
+ setObject:params
+ forKey:previous_session_info_constants::kPreviousSessionInfoParams];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)setReportParameterURL:(const GURL&)URL forKey:(NSString*)key {
+ // Store only URL origin (not whole URL spec) as requested by Privacy Team.
+ [self setReportParameterValue:base::SysUTF8ToNSString(
+ URL.GetOrigin().spec().c_str())
+ forKey:key];
+}
+
+- (void)removeReportParameterForKey:(NSString*)key {
+ NSMutableDictionary* URLs = [[NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams] mutableCopy];
+ if (URLs) {
+ URLs[key] = nil;
+ if (URLs.count == 0) {
+ URLs = nil;
+ }
+ [NSUserDefaults.standardUserDefaults
+ setObject:URLs
+ forKey:previous_session_info_constants::kPreviousSessionInfoParams];
+ [NSUserDefaults.standardUserDefaults synchronize];
+ }
+}
+
+@end
diff --git a/chromium/components/previous_session_info/previous_session_info_private.h b/chromium/components/previous_session_info/previous_session_info_private.h
new file mode 100644
index 00000000000..c8252f934b5
--- /dev/null
+++ b/chromium/components/previous_session_info/previous_session_info_private.h
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_PRIVATE_H_
+#define COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_PRIVATE_H_
+
+#import "components/previous_session_info/previous_session_info.h"
+
+@interface PreviousSessionInfo (TestingOnly)
+
+// Redefined to be read-write.
+@property(nonatomic, assign) NSInteger availableDeviceStorage;
+@property(nonatomic, assign) BOOL didSeeMemoryWarningShortlyBeforeTerminating;
+@property(nonatomic, assign) BOOL isFirstSessionAfterUpgrade;
+@property(nonatomic, assign) float deviceBatteryLevel;
+@property(nonatomic, assign)
+ previous_session_info_constants::DeviceBatteryState deviceBatteryState;
+@property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
+@property(nonatomic, copy) NSString* OSVersion;
+@property(nonatomic, strong) NSDate* sessionStartTime;
+@property(nonatomic, strong) NSDate* sessionEndTime;
+@property(nonatomic, assign) BOOL terminatedDuringSessionRestoration;
+@property(nonatomic, strong) NSMutableSet<NSString*>* connectedSceneSessionsIDs;
+@property(nonatomic, copy) NSDictionary<NSString*, NSString*>* reportParameters;
+@property(nonatomic, assign) NSInteger memoryFootprint;
+@property(nonatomic, assign) NSInteger tabCount;
+@property(nonatomic, assign) NSInteger OTRTabCount;
+
++ (void)resetSharedInstanceForTesting;
+
+- (void)pauseRecordingCurrentSession;
+- (void)resumeRecordingCurrentSession;
+- (void)updateApplicationState;
+
+@end
+
+#endif // COMPONENTS_PREVIOUS_SESSION_INFO_PREVIOUS_SESSION_INFO_PRIVATE_H_
diff --git a/chromium/components/previous_session_info/previous_session_info_unittest.mm b/chromium/components/previous_session_info/previous_session_info_unittest.mm
new file mode 100644
index 00000000000..52fbbcd4fbd
--- /dev/null
+++ b/chromium/components/previous_session_info/previous_session_info_unittest.mm
@@ -0,0 +1,721 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/previous_session_info/previous_session_info.h"
+
+#include "base/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "components/previous_session_info/previous_session_info_private.h"
+#include "components/version_info/version_info.h"
+#include "ios/web/public/test/web_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using previous_session_info_constants::kPreviousSessionInfoMemoryFootprint;
+using previous_session_info_constants::kPreviousSessionInfoRestoringSession;
+using previous_session_info_constants::
+ kPreviousSessionInfoConnectedSceneSessionIDs;
+using previous_session_info_constants::kPreviousSessionInfoTabCount;
+using previous_session_info_constants::kPreviousSessionInfoOTRTabCount;
+
+namespace {
+
+const NSInteger kTabCount = 15;
+
+// Key in the UserDefaults for a boolean value keeping track of memory warnings.
+NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating =
+ previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating;
+
+// Key in the NSUserDefaults for a string value that stores the version of the
+// last session.
+NSString* const kLastRanVersion = @"LastRanVersion";
+// Key in the NSUserDefaults for a string value that stores the language of the
+// last session.
+NSString* const kLastRanLanguage = @"LastRanLanguage";
+
+// IDs to be used for testing scene sessions.
+NSString* const kTestSession1ID = @"test_session_1";
+NSString* const kTestSession2ID = @"test_session_2";
+NSString* const kTestSession3ID = @"test_session_3";
+
+using PreviousSessionInfoTest = PlatformTest;
+
+TEST_F(PreviousSessionInfoTest, InitializationWithEmptyDefaults) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+ [defaults removeObjectForKey:kLastRanLanguage];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the default values.
+ EXPECT_FALSE([sharedInstance didSeeMemoryWarningShortlyBeforeTerminating]);
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterUpgrade]);
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterLanguageChange]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationWithSameLanguage) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kLastRanLanguage];
+
+ // Set the current language as the last ran language.
+ NSString* currentVersion = [[NSLocale preferredLanguages] objectAtIndex:0];
+ [defaults setObject:currentVersion forKey:kLastRanVersion];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterLanguageChange]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationWithDifferentLanguage) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kLastRanLanguage];
+
+ // Set the current language as the last ran language.
+ NSString* currentVersion = @"Fake Language";
+ [defaults setObject:currentVersion forKey:kLastRanVersion];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterLanguageChange]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationWithSameVersionNoMemoryWarning) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the current version as the last ran version.
+ NSString* currentVersion =
+ base::SysUTF8ToNSString(version_info::GetVersionNumber());
+ [defaults setObject:currentVersion forKey:kLastRanVersion];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_FALSE([sharedInstance didSeeMemoryWarningShortlyBeforeTerminating]);
+ EXPECT_FALSE([sharedInstance isFirstSessionAfterUpgrade]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationWithSameVersionMemoryWarning) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the current version as the last ran version.
+ NSString* currentVersion =
+ base::SysUTF8ToNSString(version_info::GetVersionNumber());
+ [defaults setObject:currentVersion forKey:kLastRanVersion];
+
+ // Set the memory warning flag as a previous session would have.
+ [defaults setBool:YES forKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_TRUE([sharedInstance didSeeMemoryWarningShortlyBeforeTerminating]);
+ EXPECT_FALSE([sharedInstance isFirstSessionAfterUpgrade]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationDifferentVersionNoMemoryWarning) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the current version as the last ran version.
+ [defaults setObject:@"Fake Version" forKey:kLastRanVersion];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_FALSE([sharedInstance didSeeMemoryWarningShortlyBeforeTerminating]);
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterUpgrade]);
+}
+
+TEST_F(PreviousSessionInfoTest, InitializationDifferentVersionMemoryWarning) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the current version as the last ran version.
+ [defaults setObject:@"Fake Version" forKey:kLastRanVersion];
+
+ // Set the memory warning flag as a previous session would have.
+ [defaults setBool:YES forKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+
+ // Instantiate the PreviousSessionInfo sharedInstance.
+ PreviousSessionInfo* sharedInstance = [PreviousSessionInfo sharedInstance];
+
+ // Checks the values.
+ EXPECT_TRUE([sharedInstance didSeeMemoryWarningShortlyBeforeTerminating]);
+ EXPECT_TRUE([sharedInstance isFirstSessionAfterUpgrade]);
+}
+
+// Creates conditions that exist on the first app run and tests
+// OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationWithoutSystemStartTime) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [[NSUserDefaults standardUserDefaults]
+ removeObjectForKey:previous_session_info_constants::kOSStartTime];
+
+ EXPECT_FALSE(
+ [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
+// Creates conditions that exist when OS was restarted after the previous app
+// run and tests OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationAfterOSRestart) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ // For the previous session OS started 60 seconds before OS has started for
+ // this session.
+ NSTimeInterval current_system_start_time =
+ NSDate.timeIntervalSinceReferenceDate -
+ NSProcessInfo.processInfo.systemUptime;
+ [[NSUserDefaults standardUserDefaults]
+ setDouble:current_system_start_time - 60
+ forKey:previous_session_info_constants::kOSStartTime];
+
+ EXPECT_TRUE(
+ [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
+// Creates conditions that exist when OS was not restarted after the previous
+// app run and tests OSRestartedAfterPreviousSession property.
+TEST_F(PreviousSessionInfoTest, InitializationForSecondSessionAfterOSRestart) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ // OS startup time is the same for this and previous session.
+ NSTimeInterval current_system_start_time =
+ NSDate.timeIntervalSinceReferenceDate -
+ NSProcessInfo.processInfo.systemUptime;
+ [[NSUserDefaults standardUserDefaults]
+ setDouble:current_system_start_time
+ forKey:previous_session_info_constants::kOSStartTime];
+
+ EXPECT_FALSE(
+ [[PreviousSessionInfo sharedInstance] OSRestartedAfterPreviousSession]);
+}
+
+TEST_F(PreviousSessionInfoTest, BeginRecordingCurrentSession) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the memory warning flag as a previous session would have.
+ [defaults setBool:YES forKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+
+ // Check that the version has been updated.
+ EXPECT_NSEQ(base::SysUTF8ToNSString(version_info::GetVersionNumber()),
+ [defaults stringForKey:kLastRanVersion]);
+
+ // Check that the memory warning flag has been reset.
+ EXPECT_FALSE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+}
+
+TEST_F(PreviousSessionInfoTest, SetMemoryWarningFlagNoOpUntilRecordingBegins) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Call the flag setter.
+ [[PreviousSessionInfo sharedInstance] setMemoryWarningFlag];
+
+ EXPECT_FALSE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+}
+
+TEST_F(PreviousSessionInfoTest,
+ ResetMemoryWarningFlagNoOpUntilRecordingBegins) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Set the memory warning flag as a previous session would have.
+ [defaults setBool:YES forKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+
+ // Call the memory warning flag resetter.
+ [[PreviousSessionInfo sharedInstance] resetMemoryWarningFlag];
+
+ EXPECT_TRUE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+}
+
+TEST_F(PreviousSessionInfoTest, MemoryWarningFlagMethodsAfterRecordingBegins) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ [defaults removeObjectForKey:kDidSeeMemoryWarningShortlyBeforeTerminating];
+ [defaults removeObjectForKey:kLastRanVersion];
+
+ // Launch the recording of the session.
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+
+ EXPECT_FALSE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+
+ // Call the memory warning flag setter.
+ [[PreviousSessionInfo sharedInstance] setMemoryWarningFlag];
+
+ EXPECT_TRUE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+
+ // Call the memory warning flag resetter.
+ [[PreviousSessionInfo sharedInstance] resetMemoryWarningFlag];
+
+ EXPECT_FALSE(
+ [defaults boolForKey:kDidSeeMemoryWarningShortlyBeforeTerminating]);
+}
+
+// Tests restoringSession is in sync with User Defaults.
+TEST_F(PreviousSessionInfoTest, NoSessionRestorationInProgress) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoRestoringSession];
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+}
+
+// Tests restoringSession is in sync with User Defaults.
+TEST_F(PreviousSessionInfoTest, SessionRestorationInProgress) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ [NSUserDefaults.standardUserDefaults
+ setBool:YES
+ forKey:kPreviousSessionInfoRestoringSession];
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+
+ EXPECT_TRUE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+}
+
+// Tests that resetSessionRestorationFlag resets User Defaults.
+TEST_F(PreviousSessionInfoTest, ResetSessionRestorationFlag) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults
+ setBool:YES
+ forKey:kPreviousSessionInfoRestoringSession];
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+
+ ASSERT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ EXPECT_TRUE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+
+ [[PreviousSessionInfo sharedInstance] resetSessionRestorationFlag];
+
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+}
+
+// Tests that AddSceneSessionID adds to User Defaults.
+TEST_F(PreviousSessionInfoTest, AddSceneSessionID) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession1ID];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession2ID];
+ NSArray<NSString*>* sessionIDs = [NSUserDefaults.standardUserDefaults
+ stringArrayForKey:kPreviousSessionInfoConnectedSceneSessionIDs];
+ EXPECT_TRUE([sessionIDs containsObject:kTestSession1ID]);
+ EXPECT_TRUE([sessionIDs containsObject:kTestSession2ID]);
+ EXPECT_EQ(2U, [sessionIDs count]);
+}
+
+// Tests that RemoveSceneSessionID removes id from User Defaults.
+TEST_F(PreviousSessionInfoTest, RemoveSceneSessionID) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession1ID];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession2ID];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession3ID];
+ NSArray<NSString*>* sessionIDs = [NSUserDefaults.standardUserDefaults
+ stringArrayForKey:kPreviousSessionInfoConnectedSceneSessionIDs];
+ ASSERT_EQ(3U, [sessionIDs count]);
+ [[PreviousSessionInfo sharedInstance] removeSceneSessionID:kTestSession3ID];
+ [[PreviousSessionInfo sharedInstance] removeSceneSessionID:kTestSession1ID];
+ sessionIDs = [NSUserDefaults.standardUserDefaults
+ stringArrayForKey:kPreviousSessionInfoConnectedSceneSessionIDs];
+ EXPECT_FALSE([sessionIDs containsObject:kTestSession3ID]);
+ EXPECT_FALSE([sessionIDs containsObject:kTestSession1ID]);
+ EXPECT_EQ(1U, [sessionIDs count]);
+}
+
+// Tests that resetConnectedSceneSessionIDs remove all session ids from User
+// Defaults.
+TEST_F(PreviousSessionInfoTest, resetConnectedSceneSessionIDs) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession1ID];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession2ID];
+ [[PreviousSessionInfo sharedInstance] addSceneSessionID:kTestSession3ID];
+ NSArray<NSString*>* sessionIDs = [NSUserDefaults.standardUserDefaults
+ stringArrayForKey:kPreviousSessionInfoConnectedSceneSessionIDs];
+ ASSERT_EQ(3U, [sessionIDs count]);
+ [[PreviousSessionInfo sharedInstance] resetConnectedSceneSessionIDs];
+ sessionIDs = [NSUserDefaults.standardUserDefaults
+ stringArrayForKey:kPreviousSessionInfoConnectedSceneSessionIDs];
+ EXPECT_EQ(0U, [sessionIDs count]);
+}
+
+// Tests that scoped object returned from startSessionRestoration correctly
+// resets User Defaults.
+TEST_F(PreviousSessionInfoTest, ParallelSessionRestorations) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoRestoringSession];
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ ASSERT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+
+ {
+ base::ScopedClosureRunner scoped_restoration =
+ [[PreviousSessionInfo sharedInstance] startSessionRestoration];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ // This should reset to NO after beginRecordingCurrentSession or
+ // resetSessionRestorationFlag
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ {
+ base::ScopedClosureRunner scoped_restoration2 =
+ [[PreviousSessionInfo sharedInstance] startSessionRestoration];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ // This should reset to NO after beginRecordingCurrentSession or
+ // resetSessionRestorationFlag
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ }
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ // This should reset to NO after beginRecordingCurrentSession or
+ // resetSessionRestorationFlag
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ }
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+}
+
+// Tests that resetSessionRestorationFlag resets the flag during session
+// restoration and that flag is kept reset after restoration is finished.
+TEST_F(PreviousSessionInfoTest,
+ ResetSessionRestorationFlagDuringParallelSessionRestorations) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoRestoringSession];
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ ASSERT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+
+ {
+ base::ScopedClosureRunner scoped_restoration =
+ [[PreviousSessionInfo sharedInstance] startSessionRestoration];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ // This should reset to NO after beginRecordingCurrentSession or
+ // resetSessionRestorationFlag
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ {
+ base::ScopedClosureRunner scoped_restoration2 =
+ [[PreviousSessionInfo sharedInstance] startSessionRestoration];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ // This should reset to NO after beginRecordingCurrentSession or
+ // resetSessionRestorationFlag
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+
+ [[PreviousSessionInfo sharedInstance] resetSessionRestorationFlag];
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ }
+ // scoped_restoration2 should not set |restoringSession| to previous state
+ // (YES), but rather leave the reset state.
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+ }
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ boolForKey:kPreviousSessionInfoRestoringSession]);
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance]
+ terminatedDuringSessionRestoration]);
+}
+
+// Tests adding and removing report parameters.
+TEST_F(PreviousSessionInfoTest, ReportParameters) {
+ // Default state.
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_FALSE([PreviousSessionInfo sharedInstance].reportParameters);
+
+ // Removing non-existing key does not crash.
+ NSString* const kKey0 = @"url0";
+ [[PreviousSessionInfo sharedInstance] removeReportParameterForKey:kKey0];
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_FALSE([PreviousSessionInfo sharedInstance].reportParameters);
+
+ // Add first URL.
+ [[PreviousSessionInfo sharedInstance]
+ setReportParameterURL:GURL("https://example.test/path")
+ forKey:kKey0];
+ NSDictionary<NSString*, NSString*>* URLs =
+ [NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+ EXPECT_NSEQ(@{kKey0 : @"https://example.test/"}, URLs); // stores only origin
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_NSEQ(URLs, [[PreviousSessionInfo sharedInstance] reportParameters]);
+
+ // Update first URL.
+ [[PreviousSessionInfo sharedInstance]
+ setReportParameterURL:GURL("https://example2.test/path")
+ forKey:kKey0];
+ URLs = [NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+ EXPECT_NSEQ(@{kKey0 : @"https://example2.test/"}, URLs);
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_NSEQ(URLs, [[PreviousSessionInfo sharedInstance] reportParameters]);
+
+ // Add second URL.
+ NSString* const kKey1 = @"url1";
+ [[PreviousSessionInfo sharedInstance]
+ setReportParameterURL:GURL("https://example3.test/path")
+ forKey:kKey1];
+ URLs = [NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+ NSDictionary<NSString*, NSString*>* expected = @{
+ kKey0 : @"https://example2.test/",
+ kKey1 : @"https://example3.test/",
+ };
+ EXPECT_NSEQ(expected, URLs);
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_NSEQ(URLs, [[PreviousSessionInfo sharedInstance] reportParameters]);
+
+ // Removing non-existing key does not crash.
+ [[PreviousSessionInfo sharedInstance] removeReportParameterForKey:@"url2"];
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_NSEQ(URLs, [[PreviousSessionInfo sharedInstance] reportParameters]);
+
+ // Remove first URL.
+ [[PreviousSessionInfo sharedInstance] removeReportParameterForKey:kKey0];
+ URLs = [NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+ EXPECT_NSEQ(@{kKey1 : @"https://example3.test/"}, URLs);
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_NSEQ(URLs, [[PreviousSessionInfo sharedInstance] reportParameters]);
+
+ // Remove second URL.
+ [[PreviousSessionInfo sharedInstance] removeReportParameterForKey:kKey1];
+ URLs = [NSUserDefaults.standardUserDefaults
+ dictionaryForKey:previous_session_info_constants::
+ kPreviousSessionInfoParams];
+ EXPECT_FALSE(URLs);
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_FALSE([[PreviousSessionInfo sharedInstance] reportParameters]);
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+}
+
+// Tests that memory footprint gets written to NSUserDefaults after
+// startRecordingMemoryFootprintWithInterval: call.
+TEST_F(PreviousSessionInfoTest, MemoryFootprintRecording) {
+ web::WebTaskEnvironment task_environment;
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoMemoryFootprint];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ [[PreviousSessionInfo sharedInstance]
+ startRecordingMemoryFootprintWithInterval:base::TimeDelta::
+ FromMilliseconds(1)];
+
+ // Memory footprint should be updated after timeout.
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ objectForKey:kPreviousSessionInfoMemoryFootprint]);
+ EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(1, ^bool {
+ base::RunLoop().RunUntilIdle();
+ return
+ [[NSUserDefaults.standardUserDefaults
+ objectForKey:kPreviousSessionInfoMemoryFootprint] integerValue] > 0;
+ }));
+}
+
+// Tests tabCount property.
+TEST_F(PreviousSessionInfoTest, TabCount) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults setInteger:kTabCount
+ forKey:kPreviousSessionInfoTabCount];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ EXPECT_EQ(kTabCount, [PreviousSessionInfo sharedInstance].tabCount);
+}
+
+// Tests tab count gets written to NSUserDefaults.
+TEST_F(PreviousSessionInfoTest, TabCountRecording) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoTabCount];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ [[PreviousSessionInfo sharedInstance] updateCurrentSessionTabCount:kTabCount];
+
+ EXPECT_NSEQ(@(kTabCount), [NSUserDefaults.standardUserDefaults
+ objectForKey:kPreviousSessionInfoTabCount]);
+}
+
+// Tests OTRTabCount property.
+TEST_F(PreviousSessionInfoTest, OtrTabCount) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults
+ setInteger:kTabCount
+ forKey:kPreviousSessionInfoOTRTabCount];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ EXPECT_EQ(kTabCount, [PreviousSessionInfo sharedInstance].OTRTabCount);
+}
+
+// Tests OTR tab count gets written to NSUserDefaults.
+TEST_F(PreviousSessionInfoTest, OtrTabCountRecording) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:kPreviousSessionInfoOTRTabCount];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ [[PreviousSessionInfo sharedInstance]
+ updateCurrentSessionOTRTabCount:kTabCount];
+
+ EXPECT_NSEQ(@(kTabCount), [NSUserDefaults.standardUserDefaults
+ objectForKey:kPreviousSessionInfoOTRTabCount]);
+}
+
+// Tests memoryFootprint property.
+TEST_F(PreviousSessionInfoTest, MemoryFootprint) {
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ NSInteger kMemoryFootprint = 1869;
+ [NSUserDefaults.standardUserDefaults
+ setInteger:kMemoryFootprint
+ forKey:kPreviousSessionInfoMemoryFootprint];
+
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ EXPECT_EQ(kMemoryFootprint,
+ [PreviousSessionInfo sharedInstance].memoryFootprint);
+}
+
+// Tests data collection pausing.
+TEST_F(PreviousSessionInfoTest, PausePreviousSessionInfoCollection) {
+ // Default state.
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Start recording. This should update the state.
+ [[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Cleanup.
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Updating state should work when recording is enabled.
+ [[PreviousSessionInfo sharedInstance] updateApplicationState];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Cleanup.
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Updating state should be noop when recording is paused.
+ [[PreviousSessionInfo sharedInstance] pauseRecordingCurrentSession];
+ [[PreviousSessionInfo sharedInstance] updateApplicationState];
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Resume recording should update the state.
+ [[PreviousSessionInfo sharedInstance] resumeRecordingCurrentSession];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Cleanup
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+ EXPECT_FALSE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Updating state should work when recording is enabled.
+ [[PreviousSessionInfo sharedInstance] updateApplicationState];
+ EXPECT_TRUE([NSUserDefaults.standardUserDefaults
+ valueForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState]);
+
+ // Cleanup.
+ [NSUserDefaults.standardUserDefaults
+ removeObjectForKey:previous_session_info_constants::
+ kPreviousSessionInfoApplicationState];
+ [PreviousSessionInfo resetSharedInstanceForTesting];
+}
+
+} // namespace
diff --git a/chromium/components/printing/browser/BUILD.gn b/chromium/components/printing/browser/BUILD.gn
index 1b3c83d06c8..c727ca42044 100644
--- a/chromium/components/printing/browser/BUILD.gn
+++ b/chromium/components/printing/browser/BUILD.gn
@@ -56,6 +56,7 @@ static_library("browser") {
"//components/printing/common:mojo_interfaces",
"//components/services/print_compositor/public/cpp",
"//components/services/print_compositor/public/mojom",
+ "//components/site_isolation",
"//components/strings:components_strings_grit",
"//printing",
"//printing/common:common",
diff --git a/chromium/components/printing/browser/DEPS b/chromium/components/printing/browser/DEPS
index 14f9e1dfcb3..1b04a6a4406 100644
--- a/chromium/components/printing/browser/DEPS
+++ b/chromium/components/printing/browser/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/crash/core/common",
"+components/discardable_memory/service",
"+components/services/print_compositor/public",
+ "+components/site_isolation",
"+components/strings/grit",
"+content/public/browser",
"+mojo/public",
diff --git a/chromium/components/printing/browser/print_composite_client.cc b/chromium/components/printing/browser/print_composite_client.cc
index 17d8a93387c..02a7786bf93 100644
--- a/chromium/components/printing/browser/print_composite_client.cc
+++ b/chromium/components/printing/browser/print_composite_client.cc
@@ -344,9 +344,10 @@ void PrintCompositeClient::RemoveCompositeRequest(int cookie) {
document_cookie_ = 0;
initiator_frame_ = nullptr;
- // Clear all stored printed and pending subframes.
+ // Reset state of the client.
pending_subframes_.clear();
printed_subframes_.clear();
+ print_render_frames_.clear();
// No longer concurrently compositing this document.
is_doc_concurrently_composited_ = false;
diff --git a/chromium/components/printing/browser/print_manager.cc b/chromium/components/printing/browser/print_manager.cc
index 63c8594c439..60a0b01969d 100644
--- a/chromium/components/printing/browser/print_manager.cc
+++ b/chromium/components/printing/browser/print_manager.cc
@@ -112,6 +112,14 @@ void PrintManager::SetAccessibilityTree(
const ui::AXTreeUpdate& accessibility_tree) {}
#endif
+void PrintManager::UpdatePrintSettings(int32_t cookie,
+ base::Value job_settings,
+ UpdatePrintSettingsCallback callback) {
+ auto params = mojom::PrintPagesParams::New();
+ params->params = mojom::PrintParams::New();
+ std::move(callback).Run(std::move(params), false);
+}
+
void PrintManager::DidShowPrintDialog() {}
void PrintManager::ShowInvalidPrinterSettingsError() {}
@@ -126,6 +134,14 @@ void PrintManager::PrintingFailed(int32_t cookie) {
#endif
}
+bool PrintManager::IsPrintRenderFrameConnected(content::RenderFrameHost* rfh) {
+ auto it = print_render_frames_.find(rfh);
+ if (it == print_render_frames_.end())
+ return false;
+
+ return it->second.is_bound() && it->second.is_connected();
+}
+
const mojo::AssociatedRemote<printing::mojom::PrintRenderFrame>&
PrintManager::GetPrintRenderFrame(content::RenderFrameHost* rfh) {
auto it = print_render_frames_.find(rfh);
diff --git a/chromium/components/printing/browser/print_manager.h b/chromium/components/printing/browser/print_manager.h
index 0eabc4339f7..51e1b88c48f 100644
--- a/chromium/components/printing/browser/print_manager.h
+++ b/chromium/components/printing/browser/print_manager.h
@@ -52,6 +52,9 @@ class PrintManager : public content::WebContentsObserver,
int32_t cookie,
const ui::AXTreeUpdate& accessibility_tree) override;
#endif
+ void UpdatePrintSettings(int32_t cookie,
+ base::Value job_settings,
+ UpdatePrintSettingsCallback callback) override;
void DidShowPrintDialog() override;
void ShowInvalidPrinterSettingsError() override;
void PrintingFailed(int32_t cookie) override;
@@ -59,6 +62,10 @@ class PrintManager : public content::WebContentsObserver,
protected:
explicit PrintManager(content::WebContents* contents);
+ // Helper method to determine if PrintRenderFrame associated remote interface
+ // is still connected.
+ bool IsPrintRenderFrameConnected(content::RenderFrameHost* rfh);
+
// Helper method to fetch the PrintRenderFrame associated remote interface
// pointer.
const mojo::AssociatedRemote<printing::mojom::PrintRenderFrame>&
diff --git a/chromium/components/printing/browser/print_manager_utils.cc b/chromium/components/printing/browser/print_manager_utils.cc
index 5df4092ebe8..1b7ca78de0d 100644
--- a/chromium/components/printing/browser/print_manager_utils.cc
+++ b/chromium/components/printing/browser/print_manager_utils.cc
@@ -7,7 +7,7 @@
#include "components/printing/browser/print_composite_client.h"
#include "components/printing/common/print.mojom.h"
#include "components/printing/common/print_messages.h"
-#include "content/public/browser/site_isolation_policy.h"
+#include "components/site_isolation/site_isolation_policy.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_settings.h"
@@ -37,7 +37,8 @@ void CreateCompositeClientIfNeeded(content::WebContents* web_contents,
// where OOPIF is used such as isolate-extensions, but should be good for
// feature testing purpose. Eventually, we will remove this check and use pdf
// compositor service by default for printing.
- if (content::SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs()) {
+ if (site_isolation::SiteIsolationPolicy::
+ ShouldPdfCompositorBeEnabledForOopifs()) {
PrintCompositeClient::CreateForWebContents(web_contents);
PrintCompositeClient::FromWebContents(web_contents)
->SetUserAgent(user_agent);
diff --git a/chromium/components/printing/browser/printer_capabilities_unittest.cc b/chromium/components/printing/browser/printer_capabilities_unittest.cc
index 507cfedd356..9a99dbfc4ad 100644
--- a/chromium/components/printing/browser/printer_capabilities_unittest.cc
+++ b/chromium/components/printing/browser/printer_capabilities_unittest.cc
@@ -123,7 +123,9 @@ TEST_F(PrinterCapabilitiesTest, ProvidedCapabilitiesUsed) {
// Set a capability and add a valid printer.
auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
caps->dpis = {{600, 600}};
- print_backend()->AddValidPrinter(printer_name, std::move(caps));
+ print_backend()->AddValidPrinter(
+ printer_name, std::move(caps),
+ std::make_unique<printing::PrinterBasicInfo>(basic_info));
base::Value settings_dictionary =
GetSettingsOnBlockingTaskRunnerAndWaitForResults(
@@ -153,7 +155,8 @@ TEST_F(PrinterCapabilitiesTest, NullCapabilitiesExcluded) {
PrinterSemanticCapsAndDefaults::Papers no_user_defined_papers;
// Return false when attempting to retrieve capabilities.
- print_backend()->AddValidPrinter(printer_name, nullptr);
+ print_backend()->AddValidPrinter(printer_name, /*caps=*/nullptr,
+ /*info=*/nullptr);
base::Value settings_dictionary =
GetSettingsOnBlockingTaskRunnerAndWaitForResults(
@@ -177,7 +180,9 @@ TEST_F(PrinterCapabilitiesTest, UserDefinedPapers) {
auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
caps->papers.push_back({"printer_foo", "printer_vendor", {100, 234}});
caps->dpis = {{600, 600}};
- print_backend()->AddValidPrinter(printer_name, std::move(caps));
+ print_backend()->AddValidPrinter(
+ printer_name, std::move(caps),
+ std::make_unique<printing::PrinterBasicInfo>(basic_info));
// Add some more paper sizes.
PrinterSemanticCapsAndDefaults::Papers user_defined_papers;
@@ -224,7 +229,9 @@ TEST_F(PrinterCapabilitiesTest, HasNotSecureProtocol) {
// Set a capability and add a valid printer.
auto caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
caps->pin_supported = true;
- print_backend()->AddValidPrinter(printer_name, std::move(caps));
+ print_backend()->AddValidPrinter(
+ printer_name, std::move(caps),
+ std::make_unique<printing::PrinterBasicInfo>(basic_info));
base::Value settings_dictionary =
GetSettingsOnBlockingTaskRunnerAndWaitForResults(
diff --git a/chromium/components/printing/common/print.mojom b/chromium/components/printing/common/print.mojom
index 4b140a2a0f4..bcd40171250 100644
--- a/chromium/components/printing/common/print.mojom
+++ b/chromium/components/printing/common/print.mojom
@@ -292,6 +292,13 @@ interface PrintManagerHost {
[Sync]
GetDefaultPrintSettings() => (PrintParams default_settings);
+ // Update the current print settings with new |job_settings|.
+ [Sync]
+ UpdatePrintSettings(
+ int32 cookie,
+ mojo_base.mojom.DictionaryValue job_settings)
+ => (PrintPagesParams current_settings, bool canceled);
+
// Tells the browser that the print dialog has been shown.
DidShowPrintDialog();
diff --git a/chromium/components/printing/common/print_messages.h b/chromium/components/printing/common/print_messages.h
index 0721f4824c7..cb8f067be18 100644
--- a/chromium/components/printing/common/print_messages.h
+++ b/chromium/components/printing/common/print_messages.h
@@ -25,7 +25,6 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/ipc/geometry/gfx_param_traits.h"
-#include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
#ifndef INTERNAL_COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
#define INTERNAL_COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
@@ -277,15 +276,6 @@ IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DidPrintDocument,
/* page content */,
bool /* completed */)
-// The renderer wants to update the current print settings with new
-// |job_settings|.
-IPC_SYNC_MESSAGE_ROUTED2_2(
- PrintHostMsg_UpdatePrintSettings,
- int /* document_cookie */,
- base::DictionaryValue /* job_settings */,
- printing::mojom::PrintPagesParams /* current_settings */,
- bool /* canceled */)
-
// It's the renderer that controls the printing process when it is generated
// by javascript. This step is about showing UI to the user to select the
// final print settings. The output parameter is the same as
diff --git a/chromium/components/printing/renderer/BUILD.gn b/chromium/components/printing/renderer/BUILD.gn
index 3db4aabccba..b17f17b9688 100644
--- a/chromium/components/printing/renderer/BUILD.gn
+++ b/chromium/components/printing/renderer/BUILD.gn
@@ -2,18 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("renderer") {
sources = [
"print_render_frame_helper.cc",
"print_render_frame_helper.h",
- "print_render_frame_helper_mac.mm",
]
deps = [
@@ -30,4 +22,8 @@ static_library("renderer") {
"//third_party/blink/public/common",
"//ui/base",
]
+
+ if (is_mac) {
+ sources += [ "print_render_frame_helper_mac.mm" ]
+ }
}
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.cc b/chromium/components/printing/renderer/print_render_frame_helper.cc
index 58e8aa32aa5..cd78b5f301b 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper.cc
@@ -44,7 +44,10 @@
#include "third_party/blink/public/common/css/page_orientation.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/mojom/frame/frame_owner_element_type.mojom.h"
+#include "third_party/blink/public/mojom/page/widget.mojom.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
+#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_double_size.h"
#include "third_party/blink/public/platform/web_size.h"
@@ -671,7 +674,7 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
/*client=*/nullptr,
/*is_hidden=*/false, /*is_inside_portal=*/false,
/*compositing_enabled=*/false, /*opener=*/nullptr,
- mojo::NullAssociatedReceiver());
+ mojo::NullAssociatedReceiver(), *source_frame.GetAgentGroupScheduler());
web_view->GetSettings()->SetJavaScriptEnabled(true);
class HeaderAndFooterClient final : public blink::WebLocalFrameClient {
@@ -696,16 +699,25 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
nullptr);
blink::WebWidgetClient web_widget_client;
+ mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget;
+ mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
+ frame_widget_receiver =
+ frame_widget.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host;
+ ignore_result(frame_widget_host.BindNewEndpointAndPassDedicatedReceiver());
+
+ mojo::AssociatedRemote<blink::mojom::Widget> widget_remote;
+ mojo::PendingAssociatedReceiver<blink::mojom::Widget> widget_receiver =
+ widget_remote.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<blink::mojom::WidgetHost> widget_host_remote;
+ ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
+
blink::WebFrameWidget::CreateForMainFrame(
- &web_widget_client, frame,
- blink::CrossVariantMojoAssociatedRemote<
- blink::mojom::FrameWidgetHostInterfaceBase>(),
- blink::CrossVariantMojoAssociatedReceiver<
- blink::mojom::FrameWidgetInterfaceBase>(),
- blink::CrossVariantMojoAssociatedRemote<
- blink::mojom::WidgetHostInterfaceBase>(),
- blink::CrossVariantMojoAssociatedReceiver<
- blink::mojom::WidgetInterfaceBase>());
+ &web_widget_client, frame, frame_widget_host.Unbind(),
+ std::move(frame_widget_receiver), widget_host_remote.Unbind(),
+ std::move(widget_receiver), viz::FrameSinkId());
web_view->DidAttachLocalMainFrame();
base::Value html(
@@ -829,6 +841,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
const bool should_print_backgrounds_;
const bool should_print_selection_only_;
bool is_printing_started_ = false;
+ blink::scheduler::WebAgentGroupScheduler& agent_group_scheduler_;
base::WeakPtrFactory<PrepareFrameAndViewForPrint> weak_ptr_factory_{this};
};
@@ -842,7 +855,8 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
original_frame_(frame),
node_to_print_(node),
should_print_backgrounds_(params.should_print_backgrounds),
- should_print_selection_only_(params.selection_only) {
+ should_print_selection_only_(params.selection_only),
+ agent_group_scheduler_(*frame->GetAgentGroupScheduler()) {
TRACE_EVENT0("print", "PrepareFrameAndViewForPrint");
mojom::PrintParamsPtr print_params = params.Clone();
@@ -937,21 +951,32 @@ void PrepareFrameAndViewForPrint::CopySelection(
/*is_hidden=*/false,
/*is_inside_portal=*/false,
/*compositing_enabled=*/false,
- /*opener=*/nullptr, mojo::NullAssociatedReceiver());
+ /*opener=*/nullptr, mojo::NullAssociatedReceiver(),
+ agent_group_scheduler_);
blink::WebView::ApplyWebPreferences(prefs, web_view);
blink::WebLocalFrame* main_frame = blink::WebLocalFrame::CreateMainFrame(
web_view, this, nullptr, base::UnguessableToken::Create(), nullptr);
frame_.Reset(main_frame);
+ blink::WebWidgetClient web_widget_client;
+ mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget;
+ mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
+ frame_widget_receiver =
+ frame_widget.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host;
+ ignore_result(frame_widget_host.BindNewEndpointAndPassDedicatedReceiver());
+
+ mojo::AssociatedRemote<blink::mojom::Widget> widget_remote;
+ mojo::PendingAssociatedReceiver<blink::mojom::Widget> widget_receiver =
+ widget_remote.BindNewEndpointAndPassDedicatedReceiver();
+
+ mojo::AssociatedRemote<blink::mojom::WidgetHost> widget_host_remote;
+ ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
+
blink::WebFrameWidget::CreateForMainFrame(
- this, main_frame,
- blink::CrossVariantMojoAssociatedRemote<
- blink::mojom::FrameWidgetHostInterfaceBase>(),
- blink::CrossVariantMojoAssociatedReceiver<
- blink::mojom::FrameWidgetInterfaceBase>(),
- blink::CrossVariantMojoAssociatedRemote<
- blink::mojom::WidgetHostInterfaceBase>(),
- blink::CrossVariantMojoAssociatedReceiver<
- blink::mojom::WidgetInterfaceBase>());
+ this, main_frame, frame_widget_host.Unbind(),
+ std::move(frame_widget_receiver), widget_host_remote.Unbind(),
+ std::move(widget_receiver), viz::FrameSinkId());
web_view->DidAttachLocalMainFrame();
node_to_print_.Reset();
@@ -2167,11 +2192,18 @@ bool PrintRenderFrameHelper::UpdatePrintSettings(
// possible.
int cookie =
print_pages_params_ ? print_pages_params_->params->document_cookie : 0;
- mojom::PrintPagesParams settings;
- settings.params = mojom::PrintParams::New();
+ mojom::PrintPagesParamsPtr settings;
bool canceled = false;
- Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie, *job_settings,
- &settings, &canceled));
+ GetPrintManagerHost()->UpdatePrintSettings(cookie, job_settings->Clone(),
+ &settings, &canceled);
+
+ // If mojom::PrintManagerHost is disconnected in the browser after calling
+ // UpdatePrintSettings(), |settings| could be null.
+ if (!settings) {
+ print_preview_context_.set_error(PREVIEW_ERROR_EMPTY_PRINTER_SETTINGS);
+ return false;
+ }
+
if (canceled) {
notify_browser_of_print_failure_ = false;
return false;
@@ -2179,7 +2211,7 @@ bool PrintRenderFrameHelper::UpdatePrintSettings(
// TODO(dhoss): Replace deprecated base::DictionaryValue::Get<Type>() calls
if (!job_settings->GetInteger(kPreviewUIID,
- &settings.params->preview_ui_id)) {
+ &settings->params->preview_ui_id)) {
NOTREACHED();
print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
return false;
@@ -2187,22 +2219,22 @@ bool PrintRenderFrameHelper::UpdatePrintSettings(
// Validate expected print preview settings.
if (!job_settings->GetInteger(kPreviewRequestID,
- &settings.params->preview_request_id) ||
+ &settings->params->preview_request_id) ||
!job_settings->GetBoolean(kIsFirstRequest,
- &settings.params->is_first_request)) {
+ &settings->params->is_first_request)) {
NOTREACHED();
print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
return false;
}
- settings.params->print_to_pdf = IsPrintToPdfRequested(*job_settings);
+ settings->params->print_to_pdf = IsPrintToPdfRequested(*job_settings);
UpdateFrameMarginsCssInfo(*job_settings);
- settings.params->print_scaling_option = GetPrintScalingOption(
- frame, node, source_is_html, *job_settings, *settings.params);
+ settings->params->print_scaling_option = GetPrintScalingOption(
+ frame, node, source_is_html, *job_settings, *settings->params);
- SetPrintPagesParams(settings);
+ SetPrintPagesParams(*settings);
- if (PrintMsg_Print_Params_IsValid(*settings.params))
+ if (PrintMsg_Print_Params_IsValid(*settings->params))
return true;
print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS);
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.h b/chromium/components/printing/renderer/print_render_frame_helper.h
index 78d76aadc20..a874a182e04 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.h
+++ b/chromium/components/printing/renderer/print_render_frame_helper.h
@@ -187,6 +187,7 @@ class PrintRenderFrameHelper
PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE_DEPRECATED = 6,
PREVIEW_ERROR_INVALID_PRINTER_SETTINGS = 7,
PREVIEW_ERROR_METAFILE_CAPTURE_FAILED_DEPRECATED = 8,
+ PREVIEW_ERROR_EMPTY_PRINTER_SETTINGS = 9,
PREVIEW_ERROR_LAST_ENUM // Always last.
};
diff --git a/chromium/components/profile_metrics/counts.cc b/chromium/components/profile_metrics/counts.cc
index fc659667056..b940e52c213 100644
--- a/chromium/components/profile_metrics/counts.cc
+++ b/chromium/components/profile_metrics/counts.cc
@@ -26,6 +26,8 @@ void LogProfileMetricsCounts(const Counts& counts) {
counts.gaia_icon);
UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfProfilesWithAuthErrors",
counts.auth_errors);
+ UMA_HISTOGRAM_ENUMERATION("Profile.ColorsUniqueness",
+ counts.colors_uniqueness);
}
}
diff --git a/chromium/components/profile_metrics/counts.h b/chromium/components/profile_metrics/counts.h
index 3fe5c565e8d..37b996d58e5 100644
--- a/chromium/components/profile_metrics/counts.h
+++ b/chromium/components/profile_metrics/counts.h
@@ -9,25 +9,27 @@
namespace profile_metrics {
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ProfileColorsUniqueness {
+ kSingleProfile = 0,
+ kUnique = 1,
+ kUniqueExceptForRepeatedDefault = 2,
+ kRepeated = 3,
+ kMaxValue = kRepeated,
+};
+
struct Counts {
- base::HistogramBase::Sample total;
- base::HistogramBase::Sample signedin;
- base::HistogramBase::Sample supervised;
- base::HistogramBase::Sample active;
- base::HistogramBase::Sample named;
- base::HistogramBase::Sample unused;
- base::HistogramBase::Sample gaia_icon;
- base::HistogramBase::Sample auth_errors;
-
- Counts()
- : total(0),
- signedin(0),
- supervised(0),
- active(0),
- named(0),
- unused(0),
- gaia_icon(0),
- auth_errors(0) {}
+ base::HistogramBase::Sample total = 0;
+ base::HistogramBase::Sample signedin = 0;
+ base::HistogramBase::Sample supervised = 0;
+ base::HistogramBase::Sample active = 0;
+ base::HistogramBase::Sample named = 0;
+ base::HistogramBase::Sample unused = 0;
+ base::HistogramBase::Sample gaia_icon = 0;
+ base::HistogramBase::Sample auth_errors = 0;
+ ProfileColorsUniqueness colors_uniqueness =
+ ProfileColorsUniqueness::kRepeated;
};
// Logs metrics related to |counts|.
diff --git a/chromium/components/query_tiles/android/tile_conversion_bridge.cc b/chromium/components/query_tiles/android/tile_conversion_bridge.cc
index 82bc2f32d18..9b31f43202d 100644
--- a/chromium/components/query_tiles/android/tile_conversion_bridge.cc
+++ b/chromium/components/query_tiles/android/tile_conversion_bridge.cc
@@ -50,4 +50,15 @@ ScopedJavaLocalRef<jobject> TileConversionBridge::CreateJavaTiles(
return jlist;
}
+ScopedJavaLocalRef<jobject> TileConversionBridge::CreateJavaTiles(
+ JNIEnv* env,
+ const std::vector<std::unique_ptr<Tile>>& tiles) {
+ ScopedJavaLocalRef<jobject> jlist = Java_TileConversionBridge_createList(env);
+
+ for (const auto& tile : tiles)
+ CreateJavaTileAndMaybeAddToList(env, jlist, *tile);
+
+ return jlist;
+}
+
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/android/tile_conversion_bridge.h b/chromium/components/query_tiles/android/tile_conversion_bridge.h
index 3aa0744de4b..6e3cc3089aa 100644
--- a/chromium/components/query_tiles/android/tile_conversion_bridge.h
+++ b/chromium/components/query_tiles/android/tile_conversion_bridge.h
@@ -20,6 +20,10 @@ class TileConversionBridge {
static ScopedJavaLocalRef<jobject> CreateJavaTiles(
JNIEnv* env,
const std::vector<Tile>& tiles);
+
+ static ScopedJavaLocalRef<jobject> CreateJavaTiles(
+ JNIEnv* env,
+ const std::vector<std::unique_ptr<Tile>>& tiles);
};
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/android/tile_provider_bridge.cc b/chromium/components/query_tiles/android/tile_provider_bridge.cc
index b8cc6c1439b..6b08892d597 100644
--- a/chromium/components/query_tiles/android/tile_provider_bridge.cc
+++ b/chromium/components/query_tiles/android/tile_provider_bridge.cc
@@ -30,6 +30,16 @@ void RunGetTilesCallback(const JavaRef<jobject>& j_callback,
j_callback, TileConversionBridge::CreateJavaTiles(env, std::move(tiles)));
}
+void RunGetTileCallback(const JavaRef<jobject>& j_callback,
+ base::Optional<Tile> tile) {
+ JNIEnv* env = AttachCurrentThread();
+ RunObjectCallbackAndroid(
+ j_callback,
+ TileConversionBridge::CreateJavaTiles(
+ env, tile.has_value() ? std::move(tile->sub_tiles)
+ : std::vector<std::unique_ptr<Tile>>()));
+}
+
} // namespace
// static
@@ -63,9 +73,19 @@ TileProviderBridge::~TileProviderBridge() {
void TileProviderBridge::GetQueryTiles(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
+ const JavaParamRef<jstring>& j_tile_id,
const JavaParamRef<jobject>& jcallback) {
- tile_service_->GetQueryTiles(base::BindOnce(
- &RunGetTilesCallback, ScopedJavaGlobalRef<jobject>(jcallback)));
+ // TODO(qinmin): refactor TileService to use a single call to handle both
+ // cases.
+ if (j_tile_id.is_null()) {
+ tile_service_->GetQueryTiles(base::BindOnce(
+ &RunGetTilesCallback, ScopedJavaGlobalRef<jobject>(jcallback)));
+ } else {
+ tile_service_->GetTile(
+ ConvertJavaStringToUTF8(env, j_tile_id),
+ base::BindOnce(&RunGetTileCallback,
+ ScopedJavaGlobalRef<jobject>(jcallback)));
+ }
}
void TileProviderBridge::OnTileClicked(JNIEnv* env,
diff --git a/chromium/components/query_tiles/android/tile_provider_bridge.h b/chromium/components/query_tiles/android/tile_provider_bridge.h
index 82b7f31054d..559acf273a7 100644
--- a/chromium/components/query_tiles/android/tile_provider_bridge.h
+++ b/chromium/components/query_tiles/android/tile_provider_bridge.h
@@ -30,6 +30,7 @@ class TileProviderBridge : public base::SupportsUserData::Data {
// Methods called from Java via JNI.
void GetQueryTiles(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
+ const JavaParamRef<jstring>& j_tile_id,
const JavaParamRef<jobject>& jcallback);
// Called when a tile is clicked.
diff --git a/chromium/components/query_tiles/internal/BUILD.gn b/chromium/components/query_tiles/internal/BUILD.gn
index c990a169946..30c5047ac85 100644
--- a/chromium/components/query_tiles/internal/BUILD.gn
+++ b/chromium/components/query_tiles/internal/BUILD.gn
@@ -47,6 +47,8 @@ source_set("internal") {
"tile_types.h",
"tile_utils.cc",
"tile_utils.h",
+ "trending_tile_handler.cc",
+ "trending_tile_handler.h",
]
public_deps = [ "//components/image_fetcher/core" ]
diff --git a/chromium/components/query_tiles/internal/image_prefetcher.cc b/chromium/components/query_tiles/internal/image_prefetcher.cc
index d9ec0f33420..70db1a41386 100644
--- a/chromium/components/query_tiles/internal/image_prefetcher.cc
+++ b/chromium/components/query_tiles/internal/image_prefetcher.cc
@@ -7,7 +7,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/query_tiles/internal/image_prefetcher_unittest.cc b/chromium/components/query_tiles/internal/image_prefetcher_unittest.cc
index 2272d6d14d2..21e449769e6 100644
--- a/chromium/components/query_tiles/internal/image_prefetcher_unittest.cc
+++ b/chromium/components/query_tiles/internal/image_prefetcher_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "components/query_tiles/internal/image_loader.h"
#include "components/query_tiles/internal/tile_group.h"
diff --git a/chromium/components/query_tiles/internal/init_aware_tile_service.cc b/chromium/components/query_tiles/internal/init_aware_tile_service.cc
index 33bc1fb2ec1..bf56b351830 100644
--- a/chromium/components/query_tiles/internal/init_aware_tile_service.cc
+++ b/chromium/components/query_tiles/internal/init_aware_tile_service.cc
@@ -5,7 +5,7 @@
#include "components/query_tiles/internal/init_aware_tile_service.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/threading/thread_task_runner_handle.h"
namespace query_tiles {
diff --git a/chromium/components/query_tiles/internal/init_aware_tile_service_unittest.cc b/chromium/components/query_tiles/internal/init_aware_tile_service_unittest.cc
index 0a049050a80..ae3327bc985 100644
--- a/chromium/components/query_tiles/internal/init_aware_tile_service_unittest.cc
+++ b/chromium/components/query_tiles/internal/init_aware_tile_service_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/test/task_environment.h"
#include "components/query_tiles/internal/tile_service_impl.h"
diff --git a/chromium/components/query_tiles/internal/stats.cc b/chromium/components/query_tiles/internal/stats.cc
index 87adf0db2cd..27fab9fe4c1 100644
--- a/chromium/components/query_tiles/internal/stats.cc
+++ b/chromium/components/query_tiles/internal/stats.cc
@@ -29,6 +29,9 @@ const char kFetcherStartHourHistogram[] = "Search.QueryTiles.Fetcher.Start";
const char kPrunedGroupReasonHistogram[] =
"Search.QueryTiles.Group.PruneReason";
+const char kTrendingTileEventHistogram[] =
+ "Search.QueryTiles.TrendingTileEvent";
+
void RecordImageLoading(ImagePreloadingEvent event) {
base::UmaHistogramEnumeration(kImagePreloadingHistogram, event);
}
@@ -61,5 +64,9 @@ void RecordGroupPruned(PrunedGroupReason reason) {
base::UmaHistogramEnumeration(kPrunedGroupReasonHistogram, reason);
}
+void RecordTrendingTileEvent(TrendingTileEvent event) {
+ base::UmaHistogramEnumeration(kTrendingTileEventHistogram, event);
+}
+
} // namespace stats
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/stats.h b/chromium/components/query_tiles/internal/stats.h
index f0467645866..fa041891d5a 100644
--- a/chromium/components/query_tiles/internal/stats.h
+++ b/chromium/components/query_tiles/internal/stats.h
@@ -26,6 +26,8 @@ extern const char kFetcherStartHourHistogram[];
extern const char kPrunedGroupReasonHistogram[];
+extern const char kTrendingTileEventHistogram[];
+
// Event to track image loading metrics.
enum class ImagePreloadingEvent {
// Start to fetch image in full browser mode.
@@ -51,6 +53,19 @@ enum class PrunedGroupReason {
kMaxValue = kInvalidLocale,
};
+// Event to track trending tile metrics.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class TrendingTileEvent {
+ // A trending tile is shown.
+ kShown = 0,
+ // A trending tile is removed.
+ kRemoved = 1,
+ // A trending tile is clicked.
+ kClicked = 2,
+ kMaxValue = kClicked,
+};
+
// Records an image preloading event.
void RecordImageLoading(ImagePreloadingEvent event);
@@ -76,6 +91,9 @@ void RecordExplodeOnFetchStarted(int explode);
// Records the reason to cause TileManager to prune the group.
void RecordGroupPruned(PrunedGroupReason reason);
+// Records the event for trending tile.
+void RecordTrendingTileEvent(TrendingTileEvent event);
+
} // namespace stats
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/stats_unittest.cc b/chromium/components/query_tiles/internal/stats_unittest.cc
index fc7550c687e..6f51ff939b3 100644
--- a/chromium/components/query_tiles/internal/stats_unittest.cc
+++ b/chromium/components/query_tiles/internal/stats_unittest.cc
@@ -60,5 +60,14 @@ TEST(QueryTilesStatsTest, RecordGroupPruned) {
tester.ExpectBucketCount(stats::kPrunedGroupReasonHistogram, 1, 1);
}
+TEST(QueryTilesStatsTest, RecordTrendingTileEvent) {
+ base::HistogramTester tester;
+ stats::RecordTrendingTileEvent(stats::TrendingTileEvent::kRemoved);
+ stats::RecordTrendingTileEvent(stats::TrendingTileEvent::kClicked);
+ tester.ExpectBucketCount(stats::kTrendingTileEventHistogram, 0, 0);
+ tester.ExpectBucketCount(stats::kTrendingTileEventHistogram, 1, 1);
+ tester.ExpectBucketCount(stats::kTrendingTileEventHistogram, 2, 1);
+}
+
} // namespace
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_config.cc b/chromium/components/query_tiles/internal/tile_config.cc
index 9fe5cc64d66..36342a4f487 100644
--- a/chromium/components/query_tiles/internal/tile_config.cc
+++ b/chromium/components/query_tiles/internal/tile_config.cc
@@ -53,6 +53,11 @@ constexpr char kTileScoreDecayLambdaKey[] = "tile_score_decay_lambda";
constexpr char kMinimumScoreForNewFrontTilesKey[] =
"min_score_for_new_front_tiles";
+constexpr char kNumTrendingTilesKey[] = "num_trending_tiles_to_display";
+
+constexpr char kMaxTrendingTileImpressionsKey[] =
+ "max_trending_tile_impressions";
+
// Default expire duration.
constexpr int kDefaultExpireDurationInSeconds = 48 * 60 * 60; // 2 days.
@@ -80,6 +85,12 @@ constexpr double kDefaultTileScoreDecayLambda = -0.099;
// clicked for 2 days.
constexpr double kDefaultMinimumTileScoreForNewFrontTiles = 0.9;
+// Default number of trending tiles to be displayed at the same time.
+constexpr int kDefaultNumTrendingTilesToDisplay = 2;
+
+// Default number of impressions a trending tile to be displayed .
+constexpr int kDefaultMaxTrendingTileImpressions = 2;
+
namespace {
// For testing. Json string for single tier experiment tag.
@@ -94,6 +105,7 @@ const GURL BuildGetQueryTileURL(const GURL& base_url, const char* path) {
replacements.SetPathStr(path);
return base_url.ReplaceComponents(replacements);
}
+
} // namespace
// static
@@ -198,4 +210,18 @@ double TileConfig::GetMinimumScoreForNewFrontTiles() {
kDefaultMinimumTileScoreForNewFrontTiles);
}
+// static
+int TileConfig::GetNumTrendingTilesToDisplay() {
+ return base::GetFieldTrialParamByFeatureAsInt(
+ features::kQueryTiles, kNumTrendingTilesKey,
+ kDefaultNumTrendingTilesToDisplay);
+}
+
+// static
+int TileConfig::GetMaxTrendingTileImpressions() {
+ return base::GetFieldTrialParamByFeatureAsInt(
+ features::kQueryTiles, kMaxTrendingTileImpressionsKey,
+ kDefaultMaxTrendingTileImpressions);
+}
+
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_config.h b/chromium/components/query_tiles/internal/tile_config.h
index 5dd1816cd12..2ed2830c49e 100644
--- a/chromium/components/query_tiles/internal/tile_config.h
+++ b/chromium/components/query_tiles/internal/tile_config.h
@@ -54,6 +54,12 @@ extern const char kTileScoreDecayLambdaKey[];
// front of others.
extern const char kMinimumScoreForNewFrontTilesKey[];
+// Finch parameter key for number of trending tiles to display.
+extern const char kNumTrendingTilesKey[];
+
+// Finch parameter key for max number of trending tile impressions.
+extern const char kMaxTrendingTileImpressionsKey[];
+
class TileConfig {
public:
// Gets the URL for the Query Tiles server.
@@ -97,6 +103,12 @@ class TileConfig {
// Get the minimum scrore for newly showing tiles that are in front of others.
static double GetMinimumScoreForNewFrontTiles();
+
+ // Get the number of trending tiles to be displayed at the same time.
+ static int GetNumTrendingTilesToDisplay();
+
+ // Get the maximum number of impressions for a trending tile to be displayed.
+ static int GetMaxTrendingTileImpressions();
};
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_fetcher_unittest.cc b/chromium/components/query_tiles/internal/tile_fetcher_unittest.cc
index 74424b055e4..f662a6fc441 100644
--- a/chromium/components/query_tiles/internal/tile_fetcher_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_fetcher_unittest.cc
@@ -4,7 +4,7 @@
#include "components/query_tiles/internal/tile_fetcher.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
diff --git a/chromium/components/query_tiles/internal/tile_group.cc b/chromium/components/query_tiles/internal/tile_group.cc
index 4cbd1536a4c..99e45da317d 100644
--- a/chromium/components/query_tiles/internal/tile_group.cc
+++ b/chromium/components/query_tiles/internal/tile_group.cc
@@ -4,9 +4,11 @@
#include "components/query_tiles/internal/tile_group.h"
+#include <set>
#include <sstream>
#include <utility>
+#include "components/query_tiles/internal/tile_iterator.h"
#include "components/query_tiles/internal/tile_utils.h"
namespace query_tiles {
@@ -27,6 +29,17 @@ void DeepCopyGroup(const TileGroup& input, TileGroup* output) {
output->tile_stats = input.tile_stats;
}
+// Removes |id| from |id_set|. Returns true if |id| is found, or false
+// otherwise.
+bool RemoveIdFromSet(std::set<std::string>* id_set, const std::string& id) {
+ const auto it = id_set->find(id);
+ if (it != id_set->end()) {
+ id_set->erase(it);
+ return true;
+ }
+ return false;
+}
+
} // namespace
TileGroup::TileGroup() = default;
@@ -76,4 +89,36 @@ std::string TileGroup::DebugString() {
return out.str();
}
+void TileGroup::RemoveTiles(const std::vector<std::string>& tile_ids) {
+ std::set<std::string> id_set(tile_ids.begin(), tile_ids.end());
+ std::queue<Tile*> tile_queue;
+ // Check if there are top level tiles to be removed.
+ for (auto iter = tiles.begin(); iter != tiles.end();) {
+ if (RemoveIdFromSet(&id_set, (*iter)->id)) {
+ iter = tiles.erase(iter);
+ if (id_set.empty())
+ return;
+ } else {
+ tile_queue.push(iter->get());
+ ++iter;
+ }
+ }
+
+ // Recursively check if there are sub tiles to be removed.
+ while (!tile_queue.empty()) {
+ Tile* tile = tile_queue.front();
+ tile_queue.pop();
+ for (auto it = tile->sub_tiles.begin(); it != tile->sub_tiles.end();) {
+ if (RemoveIdFromSet(&id_set, (*it)->id)) {
+ it = tile->sub_tiles.erase(it);
+ if (id_set.empty())
+ return;
+ } else {
+ tile_queue.push(it->get());
+ ++it;
+ }
+ }
+ }
+}
+
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_group.h b/chromium/components/query_tiles/internal/tile_group.h
index 10ce357cfef..e6b58f7e553 100644
--- a/chromium/components/query_tiles/internal/tile_group.h
+++ b/chromium/components/query_tiles/internal/tile_group.h
@@ -32,6 +32,12 @@ struct TileGroup {
// Called when a tile was clicked, need to recalculate |tile_stats|.
void OnTileClicked(const std::string& tile_id);
+ // Remove a tile from |tiles| given by its ID.
+ void RemoveTiles(const std::vector<std::string>& tile_ids);
+
+ // Find a tile with the given ID;
+ Tile* FindTile(const std::string& tile_id);
+
// Unique id for the group.
std::string id;
diff --git a/chromium/components/query_tiles/internal/tile_group_unittest.cc b/chromium/components/query_tiles/internal/tile_group_unittest.cc
index 5e0dbabc077..d1bf8b9d94f 100644
--- a/chromium/components/query_tiles/internal/tile_group_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_group_unittest.cc
@@ -81,6 +81,38 @@ TEST(TileGroupTest, OnTileClicked) {
EXPECT_EQ(group.tile_stats["guid-1-2"].score, 1.5);
}
+TEST(TileGroupTest, RemoveTiles) {
+ TileGroup group;
+ test::ResetTestGroup(&group);
+ EXPECT_EQ(group.tiles.size(), 3u);
+ EXPECT_EQ(group.tiles[2]->id, "guid-1-3");
+ EXPECT_FALSE(group.tiles[2]->sub_tiles.empty());
+
+ std::vector<std::string> tiles_to_remove;
+ tiles_to_remove.emplace_back("guid-1-1");
+ group.RemoveTiles(tiles_to_remove);
+ EXPECT_EQ(group.tiles.size(), 2u);
+ EXPECT_EQ(group.tiles[0]->id, "guid-1-2");
+ EXPECT_EQ(group.tiles[1]->id, "guid-1-3");
+
+ test::ResetTestGroup(&group);
+ tiles_to_remove.clear();
+ tiles_to_remove.emplace_back("guid-1-4");
+ group.RemoveTiles(tiles_to_remove);
+ EXPECT_EQ(group.tiles.size(), 3u);
+ EXPECT_EQ(group.tiles[2]->id, "guid-1-3");
+ EXPECT_TRUE(group.tiles[2]->sub_tiles.empty());
+
+ // Remove 2 tiles.
+ test::ResetTestGroup(&group);
+ tiles_to_remove.emplace_back("guid-1-1");
+ group.RemoveTiles(tiles_to_remove);
+ EXPECT_EQ(group.tiles.size(), 2u);
+ EXPECT_EQ(group.tiles[0]->id, "guid-1-2");
+ EXPECT_EQ(group.tiles[1]->id, "guid-1-3");
+ EXPECT_TRUE(group.tiles[1]->sub_tiles.empty());
+}
+
} // namespace
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_manager.cc b/chromium/components/query_tiles/internal/tile_manager.cc
index f5d48d188a5..cdcd8501d22 100644
--- a/chromium/components/query_tiles/internal/tile_manager.cc
+++ b/chromium/components/query_tiles/internal/tile_manager.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
@@ -20,6 +20,7 @@
#include "components/query_tiles/internal/tile_iterator.h"
#include "components/query_tiles/internal/tile_manager.h"
#include "components/query_tiles/internal/tile_utils.h"
+#include "components/query_tiles/internal/trending_tile_handler.h"
#include "components/query_tiles/switches.h"
namespace query_tiles {
@@ -67,14 +68,22 @@ class TileManagerImpl : public TileManager {
return;
}
- std::vector<Tile> tiles;
- for (const auto& tile : tile_group_->tiles)
- tiles.emplace_back(*tile.get());
+ // First remove the inactive trending tiles.
+ RemoveIdleTrendingTiles();
+ // Now build the tiles to return. Don't filter the subtiles, as they are
+ // only used for UMA purpose now.
+ // TODO(qinmin): remove all subtiles before returning the result, as they
+ // are not used.
+ std::vector<Tile> tiles =
+ trending_tile_handler_.FilterExtraTrendingTiles(tile_group_->tiles);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(tiles)));
}
void GetTile(const std::string& tile_id, TileCallback callback) override {
+ // First remove the inactive trending tiles.
+ RemoveIdleTrendingTiles();
+ // Find the tile.
const Tile* result = nullptr;
if (tile_group_) {
TileIterator it(*tile_group_, TileIterator::kAllTiles);
@@ -87,10 +96,24 @@ class TileManagerImpl : public TileManager {
}
}
}
-
auto result_tile = result ? base::make_optional(*result) : base::nullopt;
+ if (result_tile.has_value()) {
+ // Get the tiles to display, and convert the result vector.
+ // TODO(qinmin): make GetTile() return a vector of sub tiles, rather than
+ // the parent tile so we don't need the conversion below.
+ std::vector<Tile> sub_tiles =
+ trending_tile_handler_.FilterExtraTrendingTiles(
+ result_tile->sub_tiles);
+ if (!sub_tiles.empty()) {
+ std::vector<std::unique_ptr<Tile>> sub_tile_ptrs;
+ for (auto& tile : sub_tiles)
+ sub_tile_ptrs.emplace_back(std::make_unique<Tile>(std::move(tile)));
+ result_tile->sub_tiles = std::move(sub_tile_ptrs);
+ }
+ }
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), result_tile));
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(result_tile)));
}
TileGroupStatus PurgeDb() override {
@@ -168,9 +191,12 @@ class TileManagerImpl : public TileManager {
tile_stats_group_ = std::move(loaded_groups[kTileStatsGroup]);
// prevent the stats group from being deleted.
loaded_groups.erase(kTileStatsGroup);
- if (tile_group_)
- SortTiles(&tile_group_->tiles, &tile_stats_group_->tile_stats);
+ if (tile_group_) {
+ SortTilesAndClearUnusedStats(&tile_group_->tiles,
+ &tile_stats_group_->tile_stats);
+ }
}
+ trending_tile_handler_.Reset();
// Deletes other groups.
for (const auto& group_to_delete : loaded_groups)
@@ -217,8 +243,10 @@ class TileManagerImpl : public TileManager {
}
// Only swap the in memory tile group when there is no existing tile group.
- if (!tile_group_)
+ if (!tile_group_) {
tile_group_ = std::move(group);
+ trending_tile_handler_.Reset();
+ }
std::move(callback).Run(TileGroupStatus::kSuccess);
}
@@ -243,6 +271,8 @@ class TileManagerImpl : public TileManager {
// It's fine if |tile_stats_group_| is not saved, so no callback needs to
// be passed to Update().
store_->Update(kTileStatsGroup, *tile_stats_group_, base::DoNothing());
+
+ trending_tile_handler_.OnTileClicked(tile_id);
}
void OnQuerySelected(const base::Optional<std::string>& parent_tile_id,
@@ -253,7 +283,7 @@ class TileManagerImpl : public TileManager {
// Find the parent tile first. If it cannot be found, that's fine as the
// old tile score will be used.
std::vector<std::unique_ptr<Tile>>* tiles = &tile_group_->tiles;
- if (parent_tile_id.has_value()) {
+ if (parent_tile_id) {
for (const auto& tile : tile_group_->tiles) {
if (tile->id == parent_tile_id.value()) {
tiles = &tile->sub_tiles;
@@ -261,7 +291,7 @@ class TileManagerImpl : public TileManager {
}
}
}
- // Now check if a tile has the same query text.
+ // Now check if a sub tile has the same query text.
for (const auto& tile : *tiles) {
if (query_text == base::UTF8ToUTF16(tile->query_text)) {
OnTileClicked(tile->id);
@@ -270,6 +300,17 @@ class TileManagerImpl : public TileManager {
}
}
+ void RemoveIdleTrendingTiles() {
+ if (!tile_group_)
+ return;
+ std::vector<std::string> tiles_to_remove =
+ trending_tile_handler_.GetInactiveTrendingTiles();
+ if (tiles_to_remove.empty())
+ return;
+ tile_group_->RemoveTiles(tiles_to_remove);
+ store_->Update(tile_group_->id, *tile_group_, base::DoNothing());
+ }
+
// Indicates if the db is fully initialized, rejects calls if not.
bool initialized_;
@@ -291,6 +332,9 @@ class TileManagerImpl : public TileManager {
// the same language.
std::string accept_languages_;
+ // Object for managing trending tiles.
+ TrendingTileHandler trending_tile_handler_;
+
base::WeakPtrFactory<TileManagerImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/components/query_tiles/internal/tile_manager_unittest.cc b/chromium/components/query_tiles/internal/tile_manager_unittest.cc
index 51a328c9a35..1cbe6faf672 100644
--- a/chromium/components/query_tiles/internal/tile_manager_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_manager_unittest.cc
@@ -8,10 +8,12 @@
#include "base/bind.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/query_tiles/internal/tile_config.h"
#include "components/query_tiles/internal/tile_store.h"
+#include "components/query_tiles/switches.h"
#include "components/query_tiles/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -166,6 +168,15 @@ class TileManagerTest : public testing::Test {
std::move(closure).Run();
}
+ void OnTileClicked(const std::string& tile_id) {
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ manager()->OnTileClicked(tile_id);
+ }
+
protected:
TileManager* manager() { return manager_.get(); }
MockTileStore* tile_store() { return tile_store_; }
@@ -346,6 +357,236 @@ TEST_F(TileManagerTest, GetTileGroup) {
EXPECT_TRUE(test::AreTileGroupsIdentical(*actual, expected));
}
+// Check that the right number of trending tiles are returned.
+TEST_F(TileManagerTest, GetTilesWithTrendingTiles) {
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save =
+ test::GetTestTrendingTileList();
+
+ std::vector<Tile> expected;
+ expected.emplace_back(*tiles_to_save[0].get());
+ expected.emplace_back(*tiles_to_save[1].get());
+
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetTiles(std::move(expected));
+}
+
+// Check that the getTiles() will return all trending subtiles.
+TEST_F(TileManagerTest, GetTilesWithTrendingSubTiles) {
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ auto parent_tile = std::make_unique<Tile>();
+ parent_tile->id = "parent";
+ parent_tile->sub_tiles = test::GetTestTrendingTileList();
+
+ // The last subtile will be removed from the result.
+ std::vector<Tile> expected;
+ expected.emplace_back(*parent_tile.get());
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save;
+ tiles_to_save.emplace_back(std::move(parent_tile));
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetTiles(std::move(expected));
+}
+
+// Check that GetSingleTile() will filter and return the right number of
+// trending subtiles.
+TEST_F(TileManagerTest, GetSingleTileWithTrendingSubTiles) {
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ auto parent_tile = std::make_unique<Tile>();
+ parent_tile->id = "parent";
+
+ parent_tile->sub_tiles = test::GetTestTrendingTileList();
+
+ base::Optional<Tile> parent_tile2 = base::make_optional(*parent_tile.get());
+ parent_tile2->sub_tiles.pop_back();
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save;
+ tiles_to_save.emplace_back(std::move(parent_tile));
+
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetSingleTile("parent", std::move(parent_tile2));
+}
+
+// Check that trending tiles get removed after inactivity.
+TEST_F(TileManagerTest, TrendingTopTilesRemovedAfterInactivity) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kQueryTilesRemoveTrendingTilesAfterInactivity);
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save =
+ test::GetTestTrendingTileList();
+
+ std::vector<Tile> expected;
+ expected.emplace_back(*tiles_to_save[0].get());
+ expected.emplace_back(*tiles_to_save[1].get());
+ Tile trending_3 = *tiles_to_save[2].get();
+
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetTiles(expected);
+
+ // Click the 2nd tile.
+ OnTileClicked("trending_2");
+ GetTiles(expected);
+
+ // The first tile will be removed due to inactivity and the third tile
+ // will be returned.
+ expected.erase(expected.begin());
+ expected.emplace_back(std::move(trending_3));
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ GetTiles(expected);
+
+ // The 2nd tile will be removed due to inactivity.
+ expected.erase(expected.begin());
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ GetTiles(expected);
+}
+
+// Check that trending subtiles will not be removed if they are not displayed.
+TEST_F(TileManagerTest, UnshownTrendingSubTilesNotRemoved) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kQueryTilesRemoveTrendingTilesAfterInactivity);
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ auto parent_tile = std::make_unique<Tile>();
+ parent_tile->id = "parent";
+ parent_tile->sub_tiles = test::GetTestTrendingTileList();
+
+ // The last subtile will be removed from the result.
+ std::vector<Tile> expected;
+ expected.emplace_back(*parent_tile.get());
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save;
+ tiles_to_save.emplace_back(std::move(parent_tile));
+
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetTiles(expected);
+
+ // Click the parent tile and then get top level tiles.
+ OnTileClicked("parent");
+ GetTiles(expected);
+
+ // Get top level tiles again. Since sub tiles were never shown,
+ // they will not be removed.
+ OnTileClicked("parent");
+ GetTiles(expected);
+}
+
+// Check that if OnTileClicked() is followed by GetTile(), impression is
+// correctly counted.
+TEST_F(TileManagerTest, GetSingleTileAfterOnTileClicked) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kQueryTilesRemoveTrendingTilesAfterInactivity);
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
+ Init(TileGroupStatus::kNoTiles);
+
+ auto parent_tile = std::make_unique<Tile>();
+ parent_tile->id = "parent";
+ parent_tile->sub_tiles = test::GetTestTrendingTileList();
+
+ // The last subtile will be removed from the result.
+ std::vector<Tile> expected;
+ expected.emplace_back(*parent_tile.get());
+ Tile trending_3 = *(expected[0].sub_tiles[2]).get();
+
+ base::Optional<Tile> get_single_tile_expected =
+ base::make_optional(*parent_tile.get());
+ get_single_tile_expected->sub_tiles.pop_back();
+
+ std::vector<std::unique_ptr<Tile>> tiles_to_save;
+ tiles_to_save.emplace_back(std::move(parent_tile));
+
+ SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
+ GetTiles(expected);
+
+ // Click the parent tile to show the subtiles.
+ OnTileClicked("parent");
+ GetSingleTile("parent", get_single_tile_expected);
+
+ // Click the parent tile to show the subtiles.
+ OnTileClicked("parent");
+ GetSingleTile("parent", get_single_tile_expected);
+
+ // Click a trending tile to reset its impression.
+ OnTileClicked("trending_1");
+
+ // The 2nd tile will get removed.
+ expected[0].sub_tiles.erase(expected[0].sub_tiles.begin() + 1);
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ GetTiles(expected);
+
+ get_single_tile_expected->sub_tiles.pop_back();
+ get_single_tile_expected->sub_tiles.emplace_back(
+ std::make_unique<Tile>(std::move(trending_3)));
+ OnTileClicked("parent");
+ GetSingleTile("parent", get_single_tile_expected);
+
+ OnTileClicked("parent");
+ GetSingleTile("parent", get_single_tile_expected);
+
+ // Finally all tiles are removed.
+ get_single_tile_expected->sub_tiles.clear();
+ OnTileClicked("parent");
+ EXPECT_CALL(*tile_store(), Update(_, _, _))
+ .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
+ MockTileStore::UpdateCallback callback) {
+ std::move(callback).Run(true);
+ }));
+ GetSingleTile("parent", get_single_tile_expected);
+}
+
} // namespace
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_service_impl.cc b/chromium/components/query_tiles/internal/tile_service_impl.cc
index eb9310aaa63..399eb6d0fce 100644
--- a/chromium/components/query_tiles/internal/tile_service_impl.cc
+++ b/chromium/components/query_tiles/internal/tile_service_impl.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/rand_util.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/query_tiles/internal/tile_service_impl_unittest.cc b/chromium/components/query_tiles/internal/tile_service_impl_unittest.cc
index ffbcddbe11a..f467124d4aa 100644
--- a/chromium/components/query_tiles/internal/tile_service_impl_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_service_impl_unittest.cc
@@ -10,8 +10,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/test/bind_test_util.h"
+#include "base/callback_helpers.h"
+#include "base/test/bind.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/query_tiles/internal/tile_utils.cc b/chromium/components/query_tiles/internal/tile_utils.cc
index 1fcf655937a..25e122fd219 100644
--- a/chromium/components/query_tiles/internal/tile_utils.cc
+++ b/chromium/components/query_tiles/internal/tile_utils.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include <limits>
+#include "base/strings/string_util.h"
#include "components/query_tiles/internal/tile_config.h"
#include "components/query_tiles/internal/tile_utils.h"
@@ -23,10 +24,9 @@ struct TileComparator {
std::map<std::string, double> tile_score_map;
};
-} // namespace
-
void SortTiles(std::vector<std::unique_ptr<Tile>>* tiles,
- std::map<std::string, TileStats>* tile_stats) {
+ std::map<std::string, TileStats>* tile_stats,
+ std::map<std::string, double>* score_map) {
if (!tiles || tiles->empty())
return;
@@ -36,7 +36,6 @@ void SortTiles(std::vector<std::unique_ptr<Tile>>* tiles,
base::Time now_time = base::Time::Now();
TileStats last_tile_stats(now_time, last_score);
size_t new_tile_index = 0;
- std::map<std::string, double> score_map;
// Find any tiles that don't have scores, and add new entries for them.
for (size_t i = 0; i < tiles->size(); ++i) {
auto iter = tile_stats->find((*tiles)[i]->id);
@@ -66,7 +65,7 @@ void SortTiles(std::vector<std::unique_ptr<Tile>>* tiles,
}
for (size_t j = new_tile_index; j < i; ++j) {
tile_stats->emplace((*tiles)[j]->id, new_stats);
- score_map.emplace((*tiles)[j]->id, min_score);
+ score_map->emplace((*tiles)[j]->id, min_score);
}
}
// Move |new_tile_index| to the next one that might not have
@@ -74,20 +73,39 @@ void SortTiles(std::vector<std::unique_ptr<Tile>>* tiles,
new_tile_index = i + 1;
last_score = new_score;
last_tile_stats = iter->second;
- score_map.emplace((*tiles)[i]->id, last_score);
+ score_map->emplace((*tiles)[i]->id, last_score);
}
// Fill the new tiles at the end with 0 score.
if (new_tile_index < tiles->size()) {
TileStats new_stats(now_time, 0);
for (size_t j = new_tile_index; j < tiles->size(); ++j) {
tile_stats->emplace((*tiles)[j]->id, new_stats);
- score_map.emplace((*tiles)[j]->id, 0);
+ score_map->emplace((*tiles)[j]->id, 0);
}
}
// Sort the tiles in descending order.
- std::sort(tiles->begin(), tiles->end(), TileComparator(score_map));
+ std::sort(tiles->begin(), tiles->end(), TileComparator(*score_map));
for (auto& tile : *tiles)
- SortTiles(&tile->sub_tiles, tile_stats);
+ SortTiles(&tile->sub_tiles, tile_stats, score_map);
+}
+
+} // namespace
+
+void SortTilesAndClearUnusedStats(
+ std::vector<std::unique_ptr<Tile>>* tiles,
+ std::map<std::string, TileStats>* tile_stats) {
+ if (!tiles || tiles->empty())
+ return;
+ std::map<std::string, double> score_map;
+ SortTiles(tiles, tile_stats, &score_map);
+ auto iter = tile_stats->begin();
+ while (iter != tile_stats->end()) {
+ if (score_map.find(iter->first) == score_map.end()) {
+ iter = tile_stats->erase(iter);
+ } else {
+ iter++;
+ }
+ }
}
double CalculateTileScore(const TileStats& tile_stats,
@@ -99,4 +117,8 @@ double CalculateTileScore(const TileStats& tile_stats,
(current_time - tile_stats.last_clicked_time).InDaysFloored());
}
+bool IsTrendingTile(const std::string& tile_id) {
+ return base::StartsWith(tile_id, "trending_");
+}
+
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/tile_utils.h b/chromium/components/query_tiles/internal/tile_utils.h
index 35b2efb7aed..0a7a141e9dd 100644
--- a/chromium/components/query_tiles/internal/tile_utils.h
+++ b/chromium/components/query_tiles/internal/tile_utils.h
@@ -15,7 +15,8 @@ namespace query_tiles {
// Function to sort a vector of tiles based on their score in |tile_stats|. If
// a tile ID doesn't exists in |tile_stats|, a new entry will be created and
-// a score will be calculated.
+// a score will be calculated. If a tile ID in |tile_stats| doesn't show up in
+// |tiles|, it will be removed.
// To calculate scores for new tiles, ordering from the server response will
// be taken into consideration. As the server has already ordered tiles
// according to their importance.
@@ -30,13 +31,16 @@ namespace query_tiles {
// will result in (0.5, 0.5, 0.7, 0). And for new tiles at the front, they are
// guaranteed a minimum score. So that if all the other tiles haven't been
// clicked for a while, it will have a chance to be placed at the front.
-void SortTiles(std::vector<std::unique_ptr<Tile>>* tiles,
- std::map<std::string, TileStats>* tile_stats);
+void SortTilesAndClearUnusedStats(std::vector<std::unique_ptr<Tile>>* tiles,
+ std::map<std::string, TileStats>* tile_stats);
// Calculates the current tile score based on |current_time|. Tile score will
// decay over time.
double CalculateTileScore(const TileStats& tile_stats, base::Time current_time);
+// Checks whether a tile ID is for trending tile.
+bool IsTrendingTile(const std::string& tile_id);
+
} // namespace query_tiles
#endif // COMPONENTS_QUERY_TILES_INTERNAL_TILE_UTILS_H_
diff --git a/chromium/components/query_tiles/internal/tile_utils_unittest.cc b/chromium/components/query_tiles/internal/tile_utils_unittest.cc
index 000503c8b9b..55e3f932c97 100644
--- a/chromium/components/query_tiles/internal/tile_utils_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_utils_unittest.cc
@@ -12,11 +12,23 @@
namespace query_tiles {
namespace {
+// Tests that nothing happens when sorting an empty TileGroup.
+TEST(TileUtilsTest, SortEmptyTileGroup) {
+ TileGroup group;
+ std::map<std::string, TileStats> tile_stats;
+ tile_stats["guid-1-3"] = TileStats(group.last_updated_ts, 0.7);
+ tile_stats["guid-1-4"] = TileStats(group.last_updated_ts, 0.4);
+
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
+ EXPECT_EQ(tile_stats["guid-1-3"].score, 0.7);
+ EXPECT_EQ(tile_stats["guid-1-4"].score, 0.4);
+}
+
TEST(TileUtilsTest, Sort) {
TileGroup group;
test::ResetTestGroup(&group);
- SortTiles(&group.tiles, &group.tile_stats);
+ SortTilesAndClearUnusedStats(&group.tiles, &group.tile_stats);
EXPECT_EQ(group.tiles[0]->id, "guid-1-3");
EXPECT_EQ(group.tiles[1]->id, "guid-1-1");
EXPECT_EQ(group.tiles[2]->id, "guid-1-2");
@@ -32,7 +44,7 @@ TEST(TileUtilsTest, SortWithEmptytile_stats) {
std::map<std::string, TileStats> tile_stats;
- SortTiles(&group.tiles, &tile_stats);
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
EXPECT_EQ(group.tiles[0]->id, "guid-1-1");
EXPECT_EQ(group.tiles[1]->id, "guid-1-2");
EXPECT_EQ(group.tiles[2]->id, "guid-1-3");
@@ -51,7 +63,7 @@ TEST(TileUtilsTest, SortWithNewTilesAtTheFront) {
tile_stats["guid-1-4"] = TileStats(group.last_updated_ts, 0.4);
tile_stats["guid-2-2"] = TileStats(group.last_updated_ts, 0.6);
- SortTiles(&group.tiles, &tile_stats);
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
EXPECT_EQ(group.tiles[0]->id, "guid-1-1");
EXPECT_EQ(group.tiles[1]->id, "guid-1-2");
EXPECT_EQ(group.tiles[2]->id, "guid-1-3");
@@ -77,7 +89,7 @@ TEST(TileUtilsTest, SortWithNewTilesAtTheEnd) {
tile_stats["guid-1-2"] = TileStats(group.last_updated_ts, 0.2);
tile_stats["guid-2-1"] = TileStats(group.last_updated_ts, 0.3);
- SortTiles(&group.tiles, &tile_stats);
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
EXPECT_EQ(group.tiles[0]->id, "guid-1-1");
EXPECT_EQ(group.tiles[1]->id, "guid-1-2");
EXPECT_EQ(group.tiles[2]->id, "guid-1-3");
@@ -96,7 +108,7 @@ TEST(TileUtilsTest, SortWithNewTilesInTheMiddle) {
tile_stats["guid-1-1"] = TileStats(group.last_updated_ts, 0.5);
tile_stats["guid-1-3"] = TileStats(group.last_updated_ts, 0.7);
- SortTiles(&group.tiles, &tile_stats);
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
EXPECT_EQ(group.tiles[0]->id, "guid-1-3");
EXPECT_EQ(group.tiles[1]->id, "guid-1-1");
EXPECT_EQ(group.tiles[2]->id, "guid-1-2");
@@ -104,6 +116,25 @@ TEST(TileUtilsTest, SortWithNewTilesInTheMiddle) {
EXPECT_EQ(tile_stats["guid-1-2"].last_clicked_time, group.last_updated_ts);
}
+// Test the case that stats for unused tiles are cleared.
+TEST(TileUtilsTest, UnusedTilesCleared) {
+ TileGroup group;
+ test::ResetTestGroup(&group);
+ std::string unsed_tile_id = "guid-x";
+
+ std::map<std::string, TileStats> tile_stats;
+ tile_stats["guid-1-1"] = TileStats(group.last_updated_ts, 0.5);
+ tile_stats["guid-1-3"] = TileStats(group.last_updated_ts, 0.7);
+ // Stats for a tile that is no longer used.
+ tile_stats[unsed_tile_id] = TileStats(group.last_updated_ts, 0.1);
+
+ SortTilesAndClearUnusedStats(&group.tiles, &tile_stats);
+ EXPECT_EQ(group.tiles[0]->id, "guid-1-3");
+ EXPECT_EQ(group.tiles[1]->id, "guid-1-1");
+ EXPECT_EQ(group.tiles[2]->id, "guid-1-2");
+ EXPECT_TRUE(tile_stats.find(unsed_tile_id) == tile_stats.end());
+}
+
TEST(TileUtilsTest, CalculateTileScore) {
base::Time now_time = base::Time::Now();
EXPECT_EQ(CalculateTileScore(TileStats(now_time, 0.7), now_time), 0.7);
@@ -115,6 +146,13 @@ TEST(TileUtilsTest, CalculateTileScore) {
exp(-0.099));
}
+TEST(TileUtilsTest, IsTrendingTile) {
+ EXPECT_TRUE(IsTrendingTile("trending_news"));
+ EXPECT_FALSE(IsTrendingTile("Trending_news"));
+ EXPECT_FALSE(IsTrendingTile("trendingnews"));
+ EXPECT_FALSE(IsTrendingTile("news"));
+}
+
} // namespace
} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/trending_tile_handler.cc b/chromium/components/query_tiles/internal/trending_tile_handler.cc
new file mode 100644
index 00000000000..764275b963e
--- /dev/null
+++ b/chromium/components/query_tiles/internal/trending_tile_handler.cc
@@ -0,0 +1,69 @@
+// Copyright 2020 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/query_tiles/internal/trending_tile_handler.h"
+
+#include "components/query_tiles/internal/stats.h"
+#include "components/query_tiles/internal/tile_config.h"
+#include "components/query_tiles/internal/tile_utils.h"
+#include "components/query_tiles/switches.h"
+
+namespace query_tiles {
+
+TrendingTileHandler::TrendingTileHandler() = default;
+
+TrendingTileHandler::~TrendingTileHandler() = default;
+
+void TrendingTileHandler::Reset() {
+ tile_impressions_.clear();
+}
+
+std::vector<Tile> TrendingTileHandler::FilterExtraTrendingTiles(
+ const std::vector<std::unique_ptr<Tile>>& tiles) {
+ int trending_count = 0;
+ std::vector<Tile> result;
+ for (const auto& tile : tiles) {
+ if (IsTrendingTile(tile->id)) {
+ if (trending_count >= TileConfig::GetNumTrendingTilesToDisplay())
+ continue;
+ ++trending_count;
+ RecordImpression(tile->id);
+ }
+ result.emplace_back(*tile);
+ }
+ return result;
+}
+
+void TrendingTileHandler::OnTileClicked(const std::string& tile_id) {
+ tile_impressions_.erase(tile_id);
+ if (IsTrendingTile(tile_id))
+ stats::RecordTrendingTileEvent(stats::TrendingTileEvent::kClicked);
+}
+
+std::vector<std::string> TrendingTileHandler::GetInactiveTrendingTiles() {
+ std::vector<std::string> tile_ids;
+ if (!base::FeatureList::IsEnabled(
+ features::kQueryTilesRemoveTrendingTilesAfterInactivity)) {
+ return tile_ids;
+ }
+ ImpressionMap::iterator it = tile_impressions_.begin();
+ while (it != tile_impressions_.end()) {
+ if (it->second >= TileConfig::GetMaxTrendingTileImpressions()) {
+ tile_ids.emplace_back(it->first);
+ it = tile_impressions_.erase(it);
+ stats::RecordTrendingTileEvent(stats::TrendingTileEvent::kRemoved);
+ } else {
+ ++it;
+ }
+ }
+
+ return tile_ids;
+}
+
+void TrendingTileHandler::RecordImpression(const std::string& tile_id) {
+ ++tile_impressions_[tile_id];
+ stats::RecordTrendingTileEvent(stats::TrendingTileEvent::kShown);
+}
+
+} // namespace query_tiles
diff --git a/chromium/components/query_tiles/internal/trending_tile_handler.h b/chromium/components/query_tiles/internal/trending_tile_handler.h
new file mode 100644
index 00000000000..a1b335ca57b
--- /dev/null
+++ b/chromium/components/query_tiles/internal/trending_tile_handler.h
@@ -0,0 +1,57 @@
+// Copyright 2020 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_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
+#define COMPONENTS_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "components/query_tiles/internal/tile_group.h"
+#include "components/query_tiles/tile.h"
+
+namespace query_tiles {
+
+// Class for handling trending tiles. It checks whether a trending tile
+// should be displayed, hidden or removed.
+class TrendingTileHandler {
+ public:
+ // Map between tile ID and tile impression.
+ using ImpressionMap = std::map<std::string, int>;
+
+ TrendingTileHandler();
+ ~TrendingTileHandler();
+
+ TrendingTileHandler(const TrendingTileHandler& other) = delete;
+ TrendingTileHandler& operator=(const TrendingTileHandler& other) = delete;
+
+ // Resets the impression for all tiles. Must call this before calling other
+ // methods. If tile group changes, this method need to be called again.
+ void Reset();
+
+ // Given a list of tiles, remove extra trending tiles and return a list
+ // of tiles for display.
+ std::vector<Tile> FilterExtraTrendingTiles(
+ const std::vector<std::unique_ptr<Tile>>& tiles);
+
+ // Called when a tile is clicked.
+ void OnTileClicked(const std::string& tile_id);
+
+ // Returns a list of inactive trending tile Ids.
+ std::vector<std::string> GetInactiveTrendingTiles();
+
+ private:
+ // Record the impression for a tile with the give id.
+ void RecordImpression(const std::string& tile_id);
+
+ // Map to track how many times each tile is requested.
+ // A tile's impression is cleared after click.
+ // TODO(qinmin): move this to |tile_stats_group_|.
+ ImpressionMap tile_impressions_;
+};
+
+} // namespace query_tiles
+
+#endif // COMPONENTS_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
diff --git a/chromium/components/query_tiles/switches.cc b/chromium/components/query_tiles/switches.cc
index d70ac983fc9..e785a85e248 100644
--- a/chromium/components/query_tiles/switches.cc
+++ b/chromium/components/query_tiles/switches.cc
@@ -18,6 +18,9 @@ const base::Feature kQueryTilesEnableQueryEditing{
"QueryTilesEnableQueryEditing", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kQueryTilesLocalOrdering{"QueryTilesLocalOrdering",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kQueryTilesRemoveTrendingTilesAfterInactivity{
+ "QueryTilesRemoveTrendingAfterInactivity",
+ base::FEATURE_DISABLED_BY_DEFAULT};
bool IsEnabledQueryTilesInOmnibox() {
return base::FeatureList::IsEnabled(features::kQueryTilesGeoFilter) &&
diff --git a/chromium/components/query_tiles/switches.h b/chromium/components/query_tiles/switches.h
index 04c5b3db08c..9816fe8f966 100644
--- a/chromium/components/query_tiles/switches.h
+++ b/chromium/components/query_tiles/switches.h
@@ -34,6 +34,10 @@ extern const base::Feature kQueryTilesEnableQueryEditing;
// based on local user interactions.
extern const base::Feature kQueryTilesLocalOrdering;
+// Feature flag to determine whether trending tiles should disapear after
+// some time of inactivity.
+extern const base::Feature kQueryTilesRemoveTrendingTilesAfterInactivity;
+
// Helper function to determine whether query tiles should be shown on omnibox.
bool IsEnabledQueryTilesInOmnibox();
diff --git a/chromium/components/reading_list/core/reading_list_store_unittest.cc b/chromium/components/reading_list/core/reading_list_store_unittest.cc
index 8e31def92a7..3402bc240fd 100644
--- a/chromium/components/reading_list/core/reading_list_store_unittest.cc
+++ b/chromium/components/reading_list/core/reading_list_store_unittest.cc
@@ -13,8 +13,8 @@
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/reading_list/core/reading_list_model_impl.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/reading_list/features/reading_list_switches.cc b/chromium/components/reading_list/features/reading_list_switches.cc
index a7b7d890646..bbbc2a5d1fc 100644
--- a/chromium/components/reading_list/features/reading_list_switches.cc
+++ b/chromium/components/reading_list/features/reading_list_switches.cc
@@ -10,8 +10,24 @@
namespace reading_list {
namespace switches {
+
+// Allow users to save tabs for later. Enables a new button and menu for
+// accessing tabs saved for later. https://crbug.com/1109316
+const base::Feature kReadLater{"ReadLater", base::FEATURE_DISABLED_BY_DEFAULT};
+
bool IsReadingListEnabled() {
+#if defined(OS_IOS)
return BUILDFLAG(ENABLE_READING_LIST);
+#else
+ return base::FeatureList::IsEnabled(kReadLater);
+#endif
}
+
+#ifdef OS_ANDROID
+// Feature flag used for enabling read later reminder notification.
+const base::Feature kReadLaterReminderNotification{
+ "ReadLaterReminderNotification", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
} // namespace switches
} // namespace reading_list
diff --git a/chromium/components/reading_list/features/reading_list_switches.h b/chromium/components/reading_list/features/reading_list_switches.h
index 1681ddc46a9..d79c266525d 100644
--- a/chromium/components/reading_list/features/reading_list_switches.h
+++ b/chromium/components/reading_list/features/reading_list_switches.h
@@ -5,10 +5,21 @@
#ifndef COMPONENTS_READING_LIST_FEATURES_READING_LIST_SWITCHES_H_
#define COMPONENTS_READING_LIST_FEATURES_READING_LIST_SWITCHES_H_
+#include "base/feature_list.h"
+
namespace reading_list {
namespace switches {
+
+// Feature flag used for enabling Read later on desktop and Android.
+extern const base::Feature kReadLater;
// Whether Reading List is enabled on this device.
bool IsReadingListEnabled();
+
+#ifdef OS_ANDROID
+// Feature flag used for enabling read later reminder notification.
+extern const base::Feature kReadLaterReminderNotification;
+#endif
+
} // namespace switches
} // namespace reading_list
diff --git a/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm b/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
index 08a03467760..d277717b7cd 100644
--- a/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
+++ b/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
@@ -58,12 +58,30 @@ gfx::Point MovePointToWindow(const NSPoint& point,
NSHeight(content_rect) - point_in_window.y);
}
-// Returns true if |event| may have triggered dismissal of an IME and would
-// otherwise be ignored by a ui::TextInputClient when inserted.
-bool IsImeTriggerEvent(NSEvent* event) {
+// Some keys are silently consumed by -[NSView interpretKeyEvents:]
+// They should not be processed as accelerators.
+// See comments at |keyDown:| for details.
+bool ShouldIgnoreAcceleratorWithMarkedText(NSEvent* event) {
ui::KeyboardCode key = ui::KeyboardCodeFromNSEvent(event);
- return key == ui::VKEY_RETURN || key == ui::VKEY_TAB ||
- key == ui::VKEY_ESCAPE;
+ switch (key) {
+ // crbug/883952: Kanji IME completes composition and dismisses itself.
+ case ui::VKEY_RETURN:
+ // Kanji IME: select candidate words.
+ // Pinyin IME: change tone.
+ case ui::VKEY_TAB:
+ // Dismiss IME.
+ case ui::VKEY_ESCAPE:
+ // crbug/915924: Pinyin IME selects candidate.
+ case ui::VKEY_LEFT:
+ case ui::VKEY_RIGHT:
+ case ui::VKEY_UP:
+ case ui::VKEY_DOWN:
+ case ui::VKEY_PRIOR:
+ case ui::VKEY_NEXT:
+ return true;
+ default:
+ return false;
+ }
}
ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@@ -709,14 +727,14 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
[self interpretKeyEvents:@[ theEvent ]];
// When there is marked text, -[NSView interpretKeyEvents:] may handle the
- // event by dismissing the IME window in a way that neither unmarks text, nor
- // updates any composition. That is, no signal is given either to the
- // NSTextInputClient or the NSTextInputContext that the IME changed state.
- // However, we must ensure this key down is not processed as an accelerator.
- // TODO(tapted): Investigate removing the IsImeTriggerEvent() check - it's
- // probably not required, but helps tests that expect some events to always
- // get processed (i.e. TextfieldTest.TextInputClientTest).
- if (hadMarkedTextAtKeyDown && IsImeTriggerEvent(theEvent))
+ // event by updating the IME state without updating the composition text.
+ // That is, no signal is given either to the NSTextInputClient or the
+ // NSTextInputContext, leaving |hasUnhandledKeyDownEvent_| to be true.
+ // In such a case, the key down event should not processed as an accelerator.
+ // TODO(kerenzhu): Note it may be valid to always mark the key down event as
+ // handled by IME when there is marked text. For now, only certain keys are
+ // skipped.
+ if (hadMarkedTextAtKeyDown && ShouldIgnoreAcceleratorWithMarkedText(theEvent))
_hasUnhandledKeyDownEvent = NO;
// Even with marked text, some IMEs may follow with -insertNewLine:;
diff --git a/chromium/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm b/chromium/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
index 7d89bebe611..a621a83f294 100644
--- a/chromium/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
+++ b/chromium/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm
@@ -206,6 +206,8 @@ void SelectFileDialogBridge::Show(
}
}
+ const bool keep_extension_visible =
+ file_types ? file_types->keep_extension_visible : false;
if (type_ != SelectFileDialogType::kFolder &&
type_ != SelectFileDialogType::kUploadFolder &&
type_ != SelectFileDialogType::kExistingFolder) {
@@ -227,7 +229,7 @@ void SelectFileDialogBridge::Show(
// this by never hiding extensions in that case.
base::FilePath::StringType penultimate_extension =
default_path.RemoveFinalExtension().FinalExtension();
- if (!penultimate_extension.empty()) {
+ if (!penultimate_extension.empty() || keep_extension_visible) {
[dialog setExtensionHidden:NO];
} else {
[dialog setExtensionHidden:YES];
diff --git a/chromium/components/remote_cocoa/common/select_file_dialog.mojom b/chromium/components/remote_cocoa/common/select_file_dialog.mojom
index 31e91923ada..916eb21df64 100644
--- a/chromium/components/remote_cocoa/common/select_file_dialog.mojom
+++ b/chromium/components/remote_cocoa/common/select_file_dialog.mojom
@@ -28,6 +28,9 @@ struct SelectFileTypeInfo {
// Specifies whether or not there is be a filter added for all files.
bool include_all_files;
+
+ // Specifies whether the (save) file dialog should keep the extension visible.
+ bool keep_extension_visible;
};
// The interface to a file selection (Save As, Upload, etc) dialog.
diff --git a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
index 8c079b6ffde..f3d003f0b4e 100644
--- a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
+++ b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -295,7 +295,7 @@ void RenderViewContextMenuBase::RemoveAdjacentSeparators() {
}
RenderViewHost* RenderViewContextMenuBase::GetRenderViewHost() const {
- return source_web_contents_->GetRenderViewHost();
+ return source_web_contents_->GetMainFrame()->GetRenderViewHost();
}
WebContents* RenderViewContextMenuBase::GetWebContents() const {
diff --git a/chromium/components/reputation/OWNERS b/chromium/components/reputation/OWNERS
new file mode 100644
index 00000000000..de6c3759ae1
--- /dev/null
+++ b/chromium/components/reputation/OWNERS
@@ -0,0 +1,3 @@
+jdeblasio@chromium.org
+estark@chromium.org
+meacer@chromium.org
diff --git a/chromium/components/reputation/README b/chromium/components/reputation/README
new file mode 100644
index 00000000000..326019be5e7
--- /dev/null
+++ b/chromium/components/reputation/README
@@ -0,0 +1,9 @@
+This directory contains shared code related to Chrome's reputation warnings.
+
+If Chrome believes a site a user is visiting is low reputation, either due to
+failing heuristics or models in Chrome, or as determined server-side, Chrome may
+warn users about this state. This warning may either be a full-page interstitial
+warning or a pop-up while visiting the page.
+
+This warning will not trigger on sites that are not likely to be actively
+malicious, such as popular sites or sites with high engagement scores.
diff --git a/chromium/components/reputation/core/BUILD.gn b/chromium/components/reputation/core/BUILD.gn
new file mode 100644
index 00000000000..7cfc7a74c5c
--- /dev/null
+++ b/chromium/components/reputation/core/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2020 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("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+ sources = [ "safety_tips.proto" ]
+}
+
+static_library("core") {
+ sources = [
+ "safety_tip_test_utils.cc",
+ "safety_tip_test_utils.h",
+ "safety_tips_config.cc",
+ "safety_tips_config.h",
+ ]
+ deps = [
+ ":proto",
+ "//components/safe_browsing/core/db:v4_protocol_manager_util",
+ "//components/security_state/core",
+ "//third_party/re2",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [ "safety_tips_config_unittest.cc" ]
+ deps = [
+ ":core",
+ "//testing/gtest",
+ "//url",
+ ]
+ public_deps = [ "//third_party/boringssl" ]
+ all_dependent_configs = [ "//third_party/protobuf:protobuf_config" ]
+}
diff --git a/chromium/components/reputation/core/DEPS b/chromium/components/reputation/core/DEPS
new file mode 100644
index 00000000000..1f52069aaba
--- /dev/null
+++ b/chromium/components/reputation/core/DEPS
@@ -0,0 +1,11 @@
+include_rules = [
+ "+components/safe_browsing/core",
+ "+components/security_state/core",
+ "+third_party/re2",
+ "+url",
+
+ # This code is shared with ios, so content/ dependencies
+ # should not be introduced.
+ "-content",
+ "-ios/web",
+]
diff --git a/chromium/components/reputation/core/safety_tip_test_utils.cc b/chromium/components/reputation/core/safety_tip_test_utils.cc
new file mode 100644
index 00000000000..165e09c34f3
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tip_test_utils.cc
@@ -0,0 +1,79 @@
+// 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 "components/reputation/core/safety_tip_test_utils.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "components/reputation/core/safety_tips_config.h"
+
+namespace reputation {
+
+namespace {
+
+// Retrieve existing config proto if set, or create a new one otherwise.
+std::unique_ptr<SafetyTipsConfig> GetConfig() {
+ auto* old = GetSafetyTipsRemoteConfigProto();
+ if (old) {
+ return std::make_unique<SafetyTipsConfig>(*old);
+ }
+
+ auto conf = std::make_unique<SafetyTipsConfig>();
+ // Any version ID will do.
+ conf->set_version_id(4);
+ return conf;
+}
+
+} // namespace
+
+void InitializeSafetyTipConfig() {
+ SetSafetyTipsRemoteConfigProto(GetConfig());
+}
+
+void SetSafetyTipPatternsWithFlagType(std::vector<std::string> patterns,
+ FlaggedPage::FlagType type) {
+ auto config_proto = GetConfig();
+ config_proto->clear_flagged_page();
+
+ std::sort(patterns.begin(), patterns.end());
+ for (const auto& pattern : patterns) {
+ FlaggedPage* page = config_proto->add_flagged_page();
+ page->set_pattern(pattern);
+ page->set_type(type);
+ }
+
+ SetSafetyTipsRemoteConfigProto(std::move(config_proto));
+}
+
+void SetSafetyTipBadRepPatterns(std::vector<std::string> patterns) {
+ SetSafetyTipPatternsWithFlagType(patterns, FlaggedPage::BAD_REP);
+}
+
+void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns,
+ std::vector<std::string> target_patterns) {
+ auto config_proto = GetConfig();
+ config_proto->clear_allowed_pattern();
+ config_proto->clear_allowed_target_pattern();
+
+ std::sort(patterns.begin(), patterns.end());
+ std::sort(target_patterns.begin(), target_patterns.end());
+
+ for (const auto& pattern : patterns) {
+ UrlPattern* page = config_proto->add_allowed_pattern();
+ page->set_pattern(pattern);
+ }
+ for (const auto& pattern : target_patterns) {
+ HostPattern* page = config_proto->add_allowed_target_pattern();
+ page->set_regex(pattern);
+ }
+ SetSafetyTipsRemoteConfigProto(std::move(config_proto));
+}
+
+void InitializeBlankLookalikeAllowlistForTesting() {
+ SetSafetyTipAllowlistPatterns({}, {});
+}
+
+} // namespace reputation
diff --git a/chromium/components/reputation/core/safety_tip_test_utils.h b/chromium/components/reputation/core/safety_tip_test_utils.h
new file mode 100644
index 00000000000..666f97f0ecb
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tip_test_utils.h
@@ -0,0 +1,44 @@
+// 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 COMPONENTS_REPUTATION_CORE_SAFETY_TIP_TEST_UTILS_H_
+#define COMPONENTS_REPUTATION_CORE_SAFETY_TIP_TEST_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "components/reputation/core/safety_tips.pb.h"
+
+namespace reputation {
+
+// Initialize component configuration. Necessary to enable Safety Tips for
+// testing, as no heuristics trigger if the allowlist is inaccessible.
+void InitializeSafetyTipConfig();
+
+// Sets the patterns included in component with the given flag type for tests.
+// This will replace any flag patterns currently in the proto.
+void SetSafetyTipPatternsWithFlagType(std::vector<std::string> pattern,
+ FlaggedPage::FlagType type);
+
+// Sets the patterns to trigger a bad-reputation Safety Tip for tests. This just
+// calls SetSafetyTipPatternsWithFlagType with BAD_REPUTATION as the type.
+void SetSafetyTipBadRepPatterns(std::vector<std::string> pattern);
+
+// Sets allowlist patterns in the given proto for testing. This will replace any
+// allowlist patterns currently in the proto.
+// |patterns| is the list of hostnames allowed to be lookalikes.
+// |target_patterns| is the list of hostname regexes allowed to be targets of
+// lookalikes.
+void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns,
+ std::vector<std::string> target_patterns);
+
+// Ensure that the allowlist has been initialized. This is important as some
+// code (e.g. the elision policy) is fail-open (i.e. it won't elide without an
+// initialized allowlist). This is convenience wrapper around
+// SetSafetyTipAllowlistPatterns().
+void InitializeBlankLookalikeAllowlistForTesting();
+
+} // namespace reputation
+
+#endif // COMPONENTS_REPUTATION_CORE_SAFETY_TIP_TEST_UTILS_H_
diff --git a/chromium/components/reputation/core/safety_tips.proto b/chromium/components/reputation/core/safety_tips.proto
new file mode 100644
index 00000000000..b14bfaa362e
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tips.proto
@@ -0,0 +1,68 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package reputation;
+
+message FlaggedPage {
+ enum FlagType {
+ UNKNOWN = 0;
+ BAD_REP = 1;
+ YOUNG_DOMAIN = 2;
+ }
+ // |pattern| is a full URL, without scheme/username/password/port, such as
+ // example.test/test-path-for-safety-tips/test.html.
+ optional string pattern = 1;
+ optional FlagType type = 2;
+}
+
+message UrlPattern {
+ // |pattern| is a full URL, without scheme/username/password/port, such as
+ // example.test/test-path-for-safety-tips/test.html. Also see the comment for
+ // |allowed_pattern| field.
+ optional string pattern = 1;
+}
+
+message HostPattern {
+ // |regex| is a regular expression that matches allowlisted hostnames.
+ // This is different than UrlPattern.pattern which matches URLs.
+ // IMPORTANT: Don't forget to escape dots when used as label separators.
+ optional string regex = 1;
+}
+
+// Configuration for the safety tips component. A binary version of this proto
+// will be distributed to Chrome clients via component updater. The binary will
+// contain a single instance of this message.
+message SafetyTipsConfig {
+ optional uint32 version_id = 1;
+
+ // List of pages on which to show the Safety Tip UX. This must be sorted and
+ // may contain duplicate patterns (when flagged with multiple FlagTypes).
+ repeated FlaggedPage flagged_page = 2;
+
+ // List of patterns that are explicitly allowed. This must be sorted. Used to
+ // mitigate false positives in Safety Tips and Lookalike warnings.
+ // - For safety tips, the pattern can be a URL or a full suffix/prefix
+ // expression used for SafeBrowsing. See
+ // https://developers.google.com/safe-browsing/v4/urls-hashing#suffixprefix-expressions.
+ // - Lookalike warnings operate on eTLD+1, so it only makes sense for this
+ // to be eTLD+1, such as "google.com/".
+ repeated UrlPattern allowed_pattern = 3;
+
+ // Similar to allowed_pattern, but used to allowlist targets for some of the
+ // heuristics.
+ // - For edit distance, this is the matched domain. For example, consider edit
+ // distance flagging foo1.com, foo2.com, ... as a spoof of foo.com. If
+ // we are fairly sure that these are all separate and legitimate sites,
+ // allowlisting foo.com is much easier than allowlisting fooN.coms.
+ // - For target embedding, this is the embedded target. Some organizations use
+ // lookalike subdomains to proxy popular domains or customize their content
+ // for these popular domains. E.g. google-scholar-com.university.edu.
+ // In these cases it's simpler to allowlist the target instead of the
+ // embedder.
+ repeated HostPattern allowed_target_pattern = 4;
+}
diff --git a/chromium/components/reputation/core/safety_tips_config.cc b/chromium/components/reputation/core/safety_tips_config.cc
new file mode 100644
index 00000000000..e3cf98d9985
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tips_config.cc
@@ -0,0 +1,172 @@
+// 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 "components/reputation/core/safety_tips_config.h"
+
+#include "base/no_destructor.h"
+#include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
+#include "third_party/re2/src/re2/re2.h"
+#include "url/gurl.h"
+
+using safe_browsing::V4ProtocolManagerUtil;
+
+namespace reputation {
+
+namespace {
+
+class SafetyTipsConfigSingleton {
+ public:
+ void SetProto(std::unique_ptr<SafetyTipsConfig> proto) {
+ proto_ = std::move(proto);
+ }
+
+ SafetyTipsConfig* GetProto() const { return proto_.get(); }
+
+ static SafetyTipsConfigSingleton& GetInstance() {
+ static base::NoDestructor<SafetyTipsConfigSingleton> instance;
+ return *instance;
+ }
+
+ private:
+ std::unique_ptr<SafetyTipsConfig> proto_;
+};
+
+// Given a URL, generates all possible variant URLs to check the blocklist for.
+// This is conceptually almost identical to safe_browsing::UrlToFullHashes, but
+// without the hashing step.
+//
+// Note: Blocking "a.b/c/" does NOT block http://a.b/c without the trailing /.
+void UrlToSafetyTipPatterns(const GURL& url,
+ std::vector<std::string>* patterns) {
+ std::string canon_host;
+ std::string canon_path;
+ std::string canon_query;
+ V4ProtocolManagerUtil::CanonicalizeUrl(url, &canon_host, &canon_path,
+ &canon_query);
+
+ std::vector<std::string> hosts;
+ if (url.HostIsIPAddress()) {
+ hosts.push_back(url.host());
+ } else {
+ V4ProtocolManagerUtil::GenerateHostVariantsToCheck(canon_host, &hosts);
+ }
+
+ std::vector<std::string> paths;
+ V4ProtocolManagerUtil::GeneratePathVariantsToCheck(canon_path, canon_query,
+ &paths);
+
+ for (const std::string& host : hosts) {
+ for (const std::string& path : paths) {
+ DCHECK(path.length() == 0 || path[0] == '/');
+ patterns->push_back(host + path);
+ }
+ }
+}
+
+security_state::SafetyTipStatus FlagTypeToSafetyTipStatus(
+ FlaggedPage::FlagType type) {
+ switch (type) {
+ case FlaggedPage::FlagType::FlaggedPage_FlagType_UNKNOWN:
+ case FlaggedPage::FlagType::FlaggedPage_FlagType_YOUNG_DOMAIN:
+ // Reached if component includes these flags, which might happen to
+ // support newer Chrome releases.
+ return security_state::SafetyTipStatus::kNone;
+ case FlaggedPage::FlagType::FlaggedPage_FlagType_BAD_REP:
+ return security_state::SafetyTipStatus::kBadReputation;
+ }
+ NOTREACHED();
+ return security_state::SafetyTipStatus::kNone;
+}
+
+} // namespace
+
+// static
+void SetSafetyTipsRemoteConfigProto(std::unique_ptr<SafetyTipsConfig> proto) {
+ SafetyTipsConfigSingleton::GetInstance().SetProto(std::move(proto));
+}
+
+// static
+const SafetyTipsConfig* GetSafetyTipsRemoteConfigProto() {
+ return SafetyTipsConfigSingleton::GetInstance().GetProto();
+}
+
+bool IsUrlAllowlistedBySafetyTipsComponent(const SafetyTipsConfig* proto,
+ const GURL& url) {
+ DCHECK(proto);
+ DCHECK(url.is_valid());
+ std::vector<std::string> patterns;
+ UrlToSafetyTipPatterns(url, &patterns);
+ auto allowed_pages = proto->allowed_pattern();
+ for (const auto& pattern : patterns) {
+ UrlPattern search_target;
+ search_target.set_pattern(pattern);
+
+ auto lower = std::lower_bound(
+ allowed_pages.begin(), allowed_pages.end(), search_target,
+ [](const UrlPattern& a, const UrlPattern& b) -> bool {
+ return a.pattern() < b.pattern();
+ });
+
+ if (lower != allowed_pages.end() && pattern == lower->pattern()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsTargetHostAllowlistedBySafetyTipsComponent(const SafetyTipsConfig* proto,
+ const std::string& hostname) {
+ DCHECK(!hostname.empty());
+ if (proto == nullptr) {
+ return false;
+ }
+ for (const auto& host_pattern : proto->allowed_target_pattern()) {
+ if (!host_pattern.has_regex()) {
+ continue;
+ }
+ DCHECK(!host_pattern.regex().empty());
+ const re2::RE2 regex(host_pattern.regex());
+ DCHECK(regex.ok());
+ if (re2::RE2::FullMatch(hostname, regex)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+security_state::SafetyTipStatus GetSafetyTipUrlBlockType(const GURL& url) {
+ auto* proto = GetSafetyTipsRemoteConfigProto();
+ if (!proto) {
+ return security_state::SafetyTipStatus::kNone;
+ }
+
+ std::vector<std::string> patterns;
+ UrlToSafetyTipPatterns(url, &patterns);
+ auto flagged_pages = proto->flagged_page();
+ for (const auto& pattern : patterns) {
+ FlaggedPage search_target;
+ search_target.set_pattern(pattern);
+
+ auto lower = std::lower_bound(
+ flagged_pages.begin(), flagged_pages.end(), search_target,
+ [](const FlaggedPage& a, const FlaggedPage& b) -> bool {
+ return a.pattern() < b.pattern();
+ });
+
+ while (lower != flagged_pages.end() && pattern == lower->pattern()) {
+ // Skip over sites with unexpected flag types and keep looking for other
+ // matches. This allows components to include flag types not handled by
+ // this release.
+ auto type = FlagTypeToSafetyTipStatus(lower->type());
+ if (type != security_state::SafetyTipStatus::kNone) {
+ return type;
+ }
+ ++lower;
+ }
+ }
+
+ return security_state::SafetyTipStatus::kNone;
+}
+
+} // namespace reputation
diff --git a/chromium/components/reputation/core/safety_tips_config.h b/chromium/components/reputation/core/safety_tips_config.h
new file mode 100644
index 00000000000..532c0dcfd29
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tips_config.h
@@ -0,0 +1,47 @@
+// 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 COMPONENTS_REPUTATION_CORE_SAFETY_TIPS_CONFIG_H_
+#define COMPONENTS_REPUTATION_CORE_SAFETY_TIPS_CONFIG_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "components/reputation/core/safety_tips.pb.h"
+#include "components/security_state/core/security_state.h"
+
+class GURL;
+
+namespace reputation {
+
+// Sets the global configuration for Safety Tips retrieved from the component
+// updater. The configuration proto contains the list of URLs that can trigger
+// a safety tip.
+void SetSafetyTipsRemoteConfigProto(std::unique_ptr<SafetyTipsConfig> proto);
+
+// Gets the global configuration for Safety Tips as retrieved from the component
+// updater. The configuration proto contains the list of URLs that can trigger
+// a safety tip.
+const SafetyTipsConfig* GetSafetyTipsRemoteConfigProto();
+
+// Checks SafeBrowsing-style permutations of |url| against the component updater
+// allowlist and returns whether the URL is explicitly allowed.
+bool IsUrlAllowlistedBySafetyTipsComponent(const SafetyTipsConfig* proto,
+ const GURL& url);
+
+// Checks |hostname| against the component updater target allowlist and returns
+// whether it is explicitly allowed.
+bool IsTargetHostAllowlistedBySafetyTipsComponent(const SafetyTipsConfig* proto,
+ const std::string& hostname);
+
+// Checks SafeBrowsing-style permutations of |url| against the component updater
+// blocklist and returns the match type. kNone means the URL is not blocked.
+// This method assumes that the flagged pages in the safety tip config proto are
+// in sorted order.
+security_state::SafetyTipStatus GetSafetyTipUrlBlockType(const GURL& url);
+
+} // namespace reputation
+
+#endif // COMPONENTS_REPUTATION_CORE_SAFETY_TIPS_CONFIG_H_
diff --git a/chromium/components/reputation/core/safety_tips_config_unittest.cc b/chromium/components/reputation/core/safety_tips_config_unittest.cc
new file mode 100644
index 00000000000..792f54c37b8
--- /dev/null
+++ b/chromium/components/reputation/core/safety_tips_config_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 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 <vector>
+
+#include "components/reputation/core/safety_tips_config.h"
+
+#include "components/reputation/core/safety_tip_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace reputation {
+
+TEST(SafetyTipsConfigTest, TestUrlAllowlist) {
+ SetSafetyTipAllowlistPatterns({"example.com/"}, {});
+ auto* config = GetSafetyTipsRemoteConfigProto();
+ EXPECT_TRUE(IsUrlAllowlistedBySafetyTipsComponent(
+ config, GURL("http://example.com")));
+ EXPECT_FALSE(IsUrlAllowlistedBySafetyTipsComponent(
+ config, GURL("http://example.org")));
+}
+
+TEST(SafetyTipsConfigTest, TestTargetUrlAllowlist) {
+ SetSafetyTipAllowlistPatterns({}, {"exa.*\\.com"});
+ auto* config = GetSafetyTipsRemoteConfigProto();
+ EXPECT_TRUE(
+ IsTargetHostAllowlistedBySafetyTipsComponent(config, "example.com"));
+ EXPECT_FALSE(
+ IsTargetHostAllowlistedBySafetyTipsComponent(config, "example.org"));
+}
+
+} // namespace reputation
diff --git a/chromium/components/resources/BUILD.gn b/chromium/components/resources/BUILD.gn
index f424b172fd6..a36546c6978 100644
--- a/chromium/components/resources/BUILD.gn
+++ b/chromium/components/resources/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/android/config.gni")
+import("//build/config/python.gni")
import("//components/safe_browsing/buildflags.gni")
import("//printing/buildflags/buildflags.gni")
import("//tools/grit/grit_rule.gni")
@@ -37,8 +38,6 @@ grit("components_resources") {
grit_flags = [
"-E",
"about_credits_file=" + rebase_path(about_credits_file, root_build_dir),
- "-E",
- "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
]
defines = [
@@ -85,7 +84,8 @@ grit("components_scaled_resources") {
output_dir = "$root_gen_dir/components"
}
-action("about_credits") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("about_credits") {
script = "//tools/licenses.py"
depfile = "$target_gen_dir/$target_name.d"
@@ -113,6 +113,9 @@ if (is_android) {
"android/permissions_resource_id.h",
"android/sms_resource_id.h",
"android/theme_resources.h",
+ "android/webxr_resource_id.h",
]
+
+ public_deps = [ "//device/vr/buildflags" ]
}
}
diff --git a/chromium/components/resources/android/DEPS b/chromium/components/resources/android/DEPS
new file mode 100644
index 00000000000..91a82184b95
--- /dev/null
+++ b/chromium/components/resources/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+device/vr/buildflags/buildflags.h",
+]
diff --git a/chromium/components/resources/android/page_info_resource_id.h b/chromium/components/resources/android/page_info_resource_id.h
index 64f127ae2fd..dd09006da97 100644
--- a/chromium/components/resources/android/page_info_resource_id.h
+++ b/chromium/components/resources/android/page_info_resource_id.h
@@ -25,10 +25,12 @@
// PageInfoUI images, used in ConnectionInfoView
// Good:
DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD, R.drawable.pageinfo_good)
+DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD_V2, R.drawable.omnibox_https_valid)
// Warnings:
DECLARE_RESOURCE_ID(IDR_PAGEINFO_WARNING_MINOR, R.drawable.pageinfo_warning)
// Bad:
DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD, R.drawable.pageinfo_bad)
+DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD_V2, R.drawable.omnibox_not_secure_warning)
// Should never occur, use warning just in case:
// Enterprise managed: ChromeOS only.
DECLARE_RESOURCE_ID(IDR_PAGEINFO_ENTERPRISE_MANAGED,
@@ -39,3 +41,11 @@ DECLARE_RESOURCE_ID(IDR_PAGEINFO_INFO, R.drawable.pageinfo_warning)
// Major warning: Used on insecure pages, which don't show the connection info
// popup.
DECLARE_RESOURCE_ID(IDR_PAGEINFO_WARNING_MAJOR, R.drawable.pageinfo_warning)
+
+// PageInfoUI colors, used in ConnectionInfoView
+// Good:
+DECLARE_RESOURCE_ID(IDR_PAGEINFO_GOOD_COLOR, R.color.default_icon_color)
+// Warning:
+DECLARE_RESOURCE_ID(IDR_PAGEINFO_WARNING_COLOR, R.color.default_icon_color_blue)
+// Bad:
+DECLARE_RESOURCE_ID(IDR_PAGEINFO_BAD_COLOR, R.color.default_text_color_error) \ No newline at end of file
diff --git a/chromium/components/resources/android/theme_resources.h b/chromium/components/resources/android/theme_resources.h
index 58d8e2a999b..90a47974e87 100644
--- a/chromium/components/resources/android/theme_resources.h
+++ b/chromium/components/resources/android/theme_resources.h
@@ -18,6 +18,7 @@ enum {
#include "components/resources/android/page_info_resource_id.h"
#include "components/resources/android/permissions_resource_id.h"
#include "components/resources/android/sms_resource_id.h"
+#include "components/resources/android/webxr_resource_id.h"
ANDROID_COMPONENTS_RESOURCE_ID_MAX,
};
diff --git a/chromium/components/resources/android/webxr_resource_id.h b/chromium/components/resources/android/webxr_resource_id.h
new file mode 100644
index 00000000000..063c40fb99e
--- /dev/null
+++ b/chromium/components/resources/android/webxr_resource_id.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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.
+
+// This file maps permissions resource IDs to Android resource IDs.
+
+// Presence of regular include guards is checked by:
+// 1. cpplint
+// 2. a custom presubmit in src/PRESUBMIT.py
+// 3. clang (but it only checks the guard is correct if present)
+// Disable the first two with these magic comments:
+// NOLINT(build/header_guard)
+// no-include-guard-because-multiply-included
+
+#include "device/vr/buildflags/buildflags.h"
+
+// LINK_RESOURCE_ID is used for IDs that come from a .grd file.
+#ifndef LINK_RESOURCE_ID
+#error "LINK_RESOURCE_ID should be defined before including this file"
+#endif
+// DECLARE_RESOURCE_ID is used for IDs that don't have .grd entries, and
+// are only declared in this file.
+#ifndef DECLARE_RESOURCE_ID
+#error "DECLARE_RESOURCE_ID should be defined before including this file"
+#endif
+
+#if BUILDFLAG(ENABLE_ARCORE)
+DECLARE_RESOURCE_ID(IDR_ANDROID_AR_CORE_INSALL_ICON,
+ R.drawable.ic_ar_core_install)
+#endif // ENABLE_ARCORE
diff --git a/chromium/components/resources/autofill_regex_resources.grdp b/chromium/components/resources/autofill_regex_resources.grdp
new file mode 100644
index 00000000000..844aaaf24fe
--- /dev/null
+++ b/chromium/components/resources/autofill_regex_resources.grdp
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <include name="IDR_AUTOFILL_REGEX_JSON" file="../autofill/core/browser/pattern_provider/resources/regex_patterns.json" type="BINDATA" compress="brotli" />
+</grit-part>
diff --git a/chromium/components/resources/components_resources.grd b/chromium/components/resources/components_resources.grd
index 1d62db63b12..be607c11752 100644
--- a/chromium/components/resources/components_resources.grd
+++ b/chromium/components/resources/components_resources.grd
@@ -14,6 +14,7 @@ dev_ui_components_resources.grd.
<release seq="1">
<includes>
<part file="about_ui_resources.grdp" />
+ <part file="autofill_regex_resources.grdp" />
<part file="dom_distiller_resources.grdp" />
<part file="flags_ui_resources.grdp" />
<part file="management_resources.grdp" />
diff --git a/chromium/components/resources/ssl/ssl_error_assistant/BUILD.gn b/chromium/components/resources/ssl/ssl_error_assistant/BUILD.gn
index ee7e038735b..9a90fd463f2 100644
--- a/chromium/components/resources/ssl/ssl_error_assistant/BUILD.gn
+++ b/chromium/components/resources/ssl/ssl_error_assistant/BUILD.gn
@@ -2,8 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
+
# Generate the binary proto form of "ssl_error_assistant" from the ascii proto.
-action("make_ssl_error_assistant_protobuf") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("make_ssl_error_assistant_protobuf") {
script = "gen_ssl_error_assistant_proto.py"
# The output goes in $target_gen_dir since that's where
diff --git a/chromium/components/safe_browsing/content/base_blocking_page.cc b/chromium/components/safe_browsing/content/base_blocking_page.cc
index a9f9cad0af9..c19ec22ed9f 100644
--- a/chromium/components/safe_browsing/content/base_blocking_page.cc
+++ b/chromium/components/safe_browsing/content/base_blocking_page.cc
@@ -195,6 +195,8 @@ std::string BaseBlockingPage::GetExtraMetricsSuffix(
return "from_client_side_detection";
case safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE:
return "from_password_protection_service";
+ case safe_browsing::ThreatSource::REAL_TIME_CHECK:
+ return "from_real_time_check";
case safe_browsing::ThreatSource::UNKNOWN:
break;
}
diff --git a/chromium/components/safe_browsing/content/base_ui_manager.h b/chromium/components/safe_browsing/content/base_ui_manager.h
index a33c66ce224..98116d03d80 100644
--- a/chromium/components/safe_browsing/content/base_ui_manager.h
+++ b/chromium/components/safe_browsing/content/base_ui_manager.h
@@ -9,7 +9,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/security_interstitials/core/unsafe_resource.h"
diff --git a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
index 2fa3d9cc4c9..e668335c951 100644
--- a/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
+++ b/chromium/components/safe_browsing/content/browser/browser_url_loader_throttle.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
#include "base/trace_event/trace_event.h"
#include "components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h"
#include "components/safe_browsing/core/browser/url_checker_delegate.h"
@@ -251,7 +252,12 @@ void BrowserURLLoaderThrottle::WillProcessResponse(
return;
}
- if (pending_checks_ == 0)
+ bool check_completed = (pending_checks_ == 0);
+ base::UmaHistogramBoolean(
+ "SafeBrowsing.BrowserThrottle.IsCheckCompletedOnProcessResponse",
+ check_completed);
+
+ if (check_completed)
return;
DCHECK(!deferred_);
@@ -289,6 +295,8 @@ void BrowserURLLoaderThrottle::OnCompleteCheck(bool slow_check,
if (pending_checks_ == 0 && deferred_) {
deferred_ = false;
TRACE_EVENT_ASYNC_END0("safe_browsing", "Deferred", this);
+ base::UmaHistogramTimes("SafeBrowsing.BrowserThrottle.TotalDelay",
+ total_delay_);
delegate_->Resume();
}
} else {
diff --git a/chromium/components/safe_browsing/content/browser/threat_details.cc b/chromium/components/safe_browsing/content/browser/threat_details.cc
index db8abbb1b03..8ea58feb3f2 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details.cc
@@ -189,6 +189,8 @@ CSBRR::SafeBrowsingUrlApiType GetUrlApiTypeForThreatSource(
return CSBRR::PVER4_NATIVE;
case safe_browsing::ThreatSource::REMOTE:
return CSBRR::ANDROID_SAFETYNET;
+ case safe_browsing::ThreatSource::REAL_TIME_CHECK:
+ return CSBRR::REAL_TIME;
case safe_browsing::ThreatSource::UNKNOWN:
case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION:
case safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE:
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_history.cc b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
index c9976122b8c..84f88f0e272 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_history.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
@@ -9,7 +9,7 @@
#include <stddef.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/safe_browsing/content/browser/threat_details.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -24,7 +24,7 @@ ThreatDetailsRedirectsCollector::ThreatDetailsRedirectsCollector(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (history_service) {
- history_service_observer_.Add(history_service.get());
+ history_service_observation_.Observe(history_service.get());
}
}
@@ -111,7 +111,8 @@ void ThreatDetailsRedirectsCollector::AllDone() {
void ThreatDetailsRedirectsCollector::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_service_observer_.Remove(history_service);
+ DCHECK(history_service_observation_.IsObservingSource(history_service));
+ history_service_observation_.RemoveObservation();
history_service_.reset();
}
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_history.h b/chromium/components/safe_browsing/content/browser/threat_details_history.h
index efc037c15b8..4f76efebd5c 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_history.h
+++ b/chromium/components/safe_browsing/content/browser/threat_details_history.h
@@ -13,7 +13,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/history/core/browser/history_service.h"
@@ -76,8 +76,9 @@ class ThreatDetailsRedirectsCollector
std::vector<RedirectChain> redirects_urls_;
base::WeakPtr<history::HistoryService> history_service_;
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_service_observation_{this};
DISALLOW_COPY_AND_ASSIGN(ThreatDetailsRedirectsCollector);
};
diff --git a/chromium/components/safe_browsing/content/password_protection/BUILD.gn b/chromium/components/safe_browsing/content/password_protection/BUILD.gn
index 2f35e59db94..f78c297e19b 100644
--- a/chromium/components/safe_browsing/content/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/content/password_protection/BUILD.gn
@@ -14,8 +14,6 @@ source_set("password_protection") {
"password_protection_request.h",
"password_protection_service.cc",
"password_protection_service.h",
- "visual_utils.cc",
- "visual_utils.h",
]
public_deps = [ "//google_apis:google_apis" ]
@@ -75,9 +73,7 @@ source_set("password_protection_unittest") {
"password_protection_navigation_throttle_unittest.cc",
"password_protection_service_unittest.cc",
]
- if (safe_browsing_mode == 1) {
- sources += [ "visual_utils_unittest.cc" ]
- }
+
deps = [
":mock_password_protection",
":password_protection",
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_navigation_throttle_unittest.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_navigation_throttle_unittest.cc
index cdf706cabb6..509dd203788 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_navigation_throttle_unittest.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_navigation_throttle_unittest.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/safe_browsing/content/password_protection/mock_password_protection_service.h"
#include "components/safe_browsing/content/password_protection/password_protection_request.h"
#include "content/public/browser/navigation_handle.h"
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
index f0a6415f0f9..2af1a9f96df 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_request.cc
@@ -11,6 +11,7 @@
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -18,8 +19,8 @@
#include "components/safe_browsing/content/common/safe_browsing.mojom.h"
#include "components/safe_browsing/content/password_protection/metrics_util.h"
#include "components/safe_browsing/content/password_protection/password_protection_navigation_throttle.h"
-#include "components/safe_browsing/content/password_protection/visual_utils.h"
#include "components/safe_browsing/content/web_ui/safe_browsing_ui.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
#include "components/safe_browsing/core/db/allowlist_checker_client.h"
#include "components/safe_browsing/core/features.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
index 60c866b0b63..f8b4fa735f0 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service.cc
@@ -61,7 +61,7 @@ PasswordProtectionService::PasswordProtectionService(
url_loader_factory_(url_loader_factory) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (history_service)
- history_service_observer_.Add(history_service);
+ history_service_observation_.Observe(history_service);
common_spoofed_domains_ = {"login.live.com", "facebook.com", "box.com",
"google.com", "paypal.com", "apple.com",
@@ -72,17 +72,17 @@ PasswordProtectionService::PasswordProtectionService(
PasswordProtectionService::~PasswordProtectionService() {
tracker_.TryCancelAll();
CancelPendingRequests();
- history_service_observer_.RemoveAll();
+ if (history_service_observation_.IsObserving())
+ history_service_observation_.RemoveObservation();
weak_factory_.InvalidateWeakPtrs();
}
bool PasswordProtectionService::CanGetReputationOfURL(const GURL& url) {
- if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS() || net::IsLocalhost(url))
+ if (!safe_browsing::CanGetReputationOfUrl(url)) {
return false;
-
+ }
const std::string hostname = url.HostNoBrackets();
- return !net::IsHostnameNonUnique(hostname) &&
- hostname.find('.') != std::string::npos;
+ return !net::IsHostnameNonUnique(hostname);
}
#if defined(ON_FOCUS_PING_ENABLED)
@@ -404,7 +404,8 @@ void PasswordProtectionService::OnURLsDeleted(
void PasswordProtectionService::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_service_observer_.RemoveAll();
+ DCHECK(history_service_observation_.IsObservingSource(history_service));
+ history_service_observation_.RemoveObservation();
}
std::unique_ptr<PasswordProtectionNavigationThrottle>
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service.h b/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
index 75f3cd27bc9..11af62ead20 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -522,8 +522,9 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// dialog.
std::list<std::string> common_spoofed_domains_;
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_service_observation_{this};
// Weakptr can only cancel task if it is posted to the same thread. Therefore,
// we need CancelableTaskTracker to cancel tasks posted to IO thread.
diff --git a/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
index a743516b934..7f365e39ed1 100644
--- a/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
@@ -10,6 +10,7 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/null_task_runner.h"
#include "base/test/scoped_feature_list.h"
@@ -350,7 +351,7 @@ class PasswordProtectionServiceTest : public ::testing::TestWithParam<bool> {
std::unique_ptr<base::DictionaryValue> verdict_dictionary =
base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), nullptr));
+ nullptr));
if (!verdict_dictionary)
verdict_dictionary = std::make_unique<base::DictionaryValue>();
@@ -371,7 +372,7 @@ class PasswordProtectionServiceTest : public ::testing::TestWithParam<bool> {
std::move(invalid_cache_expression_entry));
content_setting_map_->SetWebsiteSettingDefaultScope(
invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), std::move(verdict_dictionary));
+ std::move(verdict_dictionary));
}
size_t GetStoredVerdictCount(LoginReputationClientRequest::TriggerType type) {
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn b/chromium/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn
index dfcfd89f593..77d460c7160 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/BUILD.gn
@@ -10,22 +10,64 @@ source_set("phishing_classifier") {
sources = [
"features.cc",
"features.h",
+ "murmurhash3_util.cc",
+ "murmurhash3_util.h",
+ "phishing_classifier.cc",
+ "phishing_classifier.h",
+ "phishing_classifier_delegate.cc",
+ "phishing_classifier_delegate.h",
+ "phishing_dom_feature_extractor.cc",
+ "phishing_dom_feature_extractor.h",
+ "phishing_term_feature_extractor.cc",
+ "phishing_term_feature_extractor.h",
+ "phishing_url_feature_extractor.cc",
+ "phishing_url_feature_extractor.h",
+ "scorer.cc",
+ "scorer.h",
]
deps = [
+ "//cc/paint",
+ "//components/paint_preview/common",
+ "//components/safe_browsing:buildflags",
+ "//components/safe_browsing/content/common:interfaces",
"//components/safe_browsing/content/renderer",
+ "//components/safe_browsing/core:client_model_proto",
+ "//components/safe_browsing/core:csd_proto",
"//components/safe_browsing/core/common",
+ "//content/public/renderer",
+ "//crypto",
+ "//skia",
+ "//third_party/blink/public:blink_headers",
+ "//third_party/smhasher:murmurhash3",
+ "//ui/base",
+ "//ui/gfx/geometry:geometry",
+ "//url",
+ "//v8",
]
}
}
source_set("unit_tests") {
testonly = true
- sources = [ "features_unittest.cc" ]
+ sources = [
+ "features_unittest.cc",
+ "murmurhash3_util_unittest.cc",
+ "phishing_term_feature_extractor_unittest.cc",
+ "phishing_url_feature_extractor_unittest.cc",
+ "scorer_unittest.cc",
+ ]
deps = [
":phishing_classifier",
"//base:base",
+ "//base/test:test_support",
"//components/safe_browsing/content/renderer/phishing_classifier:unit_tests_support",
+ "//components/safe_browsing/core:client_model_proto",
+ "//components/safe_browsing/core:csd_proto",
+ "//crypto",
+ "//skia",
+ "//testing/gmock",
"//testing/gtest",
+ "//url",
]
}
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/DEPS b/chromium/components/safe_browsing/content/renderer/phishing_classifier/DEPS
new file mode 100644
index 00000000000..a62971e35d1
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/DEPS
@@ -0,0 +1,15 @@
+include_rules = [
+ "+components/paint_preview/common",
+ "+components/safe_browsing/content/renderer",
+ "+components/safe_browsing/core/common",
+ "+components/safe_browsing/core/proto/csd.pb.h",
+ "+components/safe_browsing/core/proto/client_model.pb.h",
+ "+components/safe_browsing/core/features.h",
+ "+cc/paint",
+ "+crypto",
+ "+skia/ext",
+ "+third_party/skia/include",
+ "+third_party/smhasher",
+ "+ui/base/page_transition_types.h",
+ "+ui/gfx/geometry",
+]
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.cc
new file mode 100644
index 00000000000..16bf793bdec
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 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/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h"
+#include "third_party/smhasher/src/MurmurHash3.h"
+
+namespace safe_browsing {
+
+uint32_t MurmurHash3String(const std::string& str, uint32_t seed) {
+ uint32_t output;
+ MurmurHash3_x86_32(str.data(), str.size(), seed, &output);
+ return output;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h
new file mode 100644
index 00000000000..af47ec76f97
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 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_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_MURMURHASH3_UTIL_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_MURMURHASH3_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+
+namespace safe_browsing {
+
+// Runs the 32-bit murmurhash3 function on the given string and returns the
+// output as a uint32_t.
+uint32_t MurmurHash3String(const std::string& str, uint32_t seed);
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_MURMURHASH3_UTIL_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util_unittest.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util_unittest.cc
new file mode 100644
index 00000000000..b83c09d34e6
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util_unittest.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 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.
+//
+// Unit test to verify basic operation of murmurhash3.
+
+#include "components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h"
+
+#include <string>
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+
+TEST(MurmurHash3UtilTest, MurmurHash3String) {
+ EXPECT_EQ(893017187U, MurmurHash3String("abcd", 1234U));
+ EXPECT_EQ(3322282861U, MurmurHash3String("abcde", 56789U));
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
new file mode 100644
index 00000000000..b119085025c
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2011 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/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "cc/paint/skia_paint_canvas.h"
+#include "components/paint_preview/common/paint_preview_tracker.h"
+#include "components/safe_browsing/buildflags.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/scorer.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "crypto/sha2.h"
+#include "skia/ext/legacy_display_globals.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_document_loader.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+
+const float PhishingClassifier::kInvalidScore = -1.0;
+const float PhishingClassifier::kPhishyThreshold = 0.5;
+
+PhishingClassifier::PhishingClassifier(content::RenderFrame* render_frame)
+ : render_frame_(render_frame), scorer_(nullptr) {
+ Clear();
+}
+
+PhishingClassifier::~PhishingClassifier() {
+ // The RenderView should have called CancelPendingClassification() before
+ // we are destroyed.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!page_text_);
+}
+
+void PhishingClassifier::set_phishing_scorer(const Scorer* scorer) {
+ DCHECK(done_callback_.is_null());
+ DCHECK(!page_text_);
+ scorer_ = scorer;
+ if (scorer_) {
+ url_extractor_ = std::make_unique<PhishingUrlFeatureExtractor>();
+ dom_extractor_ = std::make_unique<PhishingDOMFeatureExtractor>();
+ term_extractor_ = std::make_unique<PhishingTermFeatureExtractor>(
+ &scorer_->page_terms(), &scorer_->page_words(),
+ scorer_->max_words_per_term(), scorer_->murmurhash3_seed(),
+ scorer_->max_shingles_per_page(), scorer_->shingle_size());
+ } else {
+ // We're disabling client-side phishing detection, so tear down all
+ // of the relevant objects.
+ url_extractor_.reset();
+ dom_extractor_.reset();
+ term_extractor_.reset();
+ }
+}
+
+bool PhishingClassifier::is_ready() const {
+ return !!scorer_;
+}
+
+void PhishingClassifier::BeginClassification(const base::string16* page_text,
+ DoneCallback done_callback) {
+ DCHECK(is_ready());
+
+ // The RenderView should have called CancelPendingClassification() before
+ // starting a new classification, so DCHECK this.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!page_text_);
+ // However, in an opt build, we will go ahead and clean up the pending
+ // classification so that we can start in a known state.
+ CancelPendingClassification();
+
+ page_text_ = page_text;
+ done_callback_ = std::move(done_callback);
+
+ // For consistency, we always want to invoke the DoneCallback
+ // asynchronously, rather than directly from this method. To ensure that
+ // this is the case, post a task to begin feature extraction on the next
+ // iteration of the message loop.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&PhishingClassifier::BeginFeatureExtraction,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PhishingClassifier::BeginFeatureExtraction() {
+ blink::WebLocalFrame* frame = render_frame_->GetWebFrame();
+
+ // Check whether the URL is one that we should classify.
+ // Currently, we only classify http/https URLs that are GET requests.
+ GURL url(frame->GetDocument().Url());
+ if (!url.SchemeIsHTTPOrHTTPS()) {
+ RunFailureCallback();
+ return;
+ }
+
+ blink::WebDocumentLoader* document_loader = frame->GetDocumentLoader();
+ if (!document_loader || document_loader->HttpMethod().Ascii() != "GET") {
+ RunFailureCallback();
+ return;
+ }
+
+ features_.reset(new FeatureMap);
+ if (!url_extractor_->ExtractFeatures(url, features_.get())) {
+ RunFailureCallback();
+ return;
+ }
+
+ // DOM feature extraction can take awhile, so it runs asynchronously
+ // in several chunks of work and invokes the callback when finished.
+ dom_extractor_->ExtractFeatures(
+ frame->GetDocument(), features_.get(),
+ base::BindOnce(&PhishingClassifier::DOMExtractionFinished,
+ base::Unretained(this)));
+}
+
+void PhishingClassifier::CancelPendingClassification() {
+ // Note that cancelling the feature extractors is simply a no-op if they
+ // were not running.
+ DCHECK(is_ready());
+ dom_extractor_->CancelPendingExtraction();
+ term_extractor_->CancelPendingExtraction();
+ weak_factory_.InvalidateWeakPtrs();
+ Clear();
+}
+
+void PhishingClassifier::DOMExtractionFinished(bool success) {
+ shingle_hashes_.reset(new std::set<uint32_t>);
+ if (success) {
+ // Term feature extraction can take awhile, so it runs asynchronously
+ // in several chunks of work and invokes the callback when finished.
+ term_extractor_->ExtractFeatures(
+ page_text_, features_.get(), shingle_hashes_.get(),
+ base::BindOnce(&PhishingClassifier::TermExtractionFinished,
+ base::Unretained(this)));
+ } else {
+ RunFailureCallback();
+ }
+}
+
+void PhishingClassifier::TermExtractionFinished(bool success) {
+ if (success) {
+#if BUILDFLAG(FULL_SAFE_BROWSING)
+ ExtractVisualFeatures();
+#else
+ VisualExtractionFinished(true);
+#endif
+ } else {
+ RunFailureCallback();
+ }
+}
+
+void PhishingClassifier::ExtractVisualFeatures() {
+ DCHECK(content::RenderThread::IsMainThread());
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ blink::WebLocalFrame* frame = render_frame_->GetWebFrame();
+ gfx::SizeF viewport_size = frame->View()->VisualViewportSize();
+ gfx::Rect bounds = ToEnclosingRect(gfx::RectF(viewport_size));
+ bitmap_ = std::make_unique<SkBitmap>();
+ // Use the Rec. 2020 color space, in case the user input is wide-gamut.
+ sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB(
+ {2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0},
+ SkNamedGamut::kRec2020);
+ SkImageInfo bitmap_info = SkImageInfo::Make(
+ bounds.width(), bounds.height(), SkColorType::kRGBA_8888_SkColorType,
+ SkAlphaType::kUnpremul_SkAlphaType, rec2020);
+ if (!bitmap_->tryAllocPixels(bitmap_info))
+ return VisualExtractionFinished(/*success=*/false);
+ SkCanvas sk_canvas(*bitmap_, skia::LegacyDisplayGlobals::GetSkSurfaceProps());
+ cc::SkiaPaintCanvas cc_canvas(&sk_canvas);
+ auto tracker = std::make_unique<paint_preview::PaintPreviewTracker>(
+ base::UnguessableToken::Create(), frame->GetEmbeddingToken(),
+ /*is_main_frame=*/true);
+ cc_canvas.SetPaintPreviewTracker(tracker.get());
+ VisualExtractionFinished(frame->CapturePaintPreview(
+ bounds, &cc_canvas, /*include_linked_destinations=*/false));
+ base::UmaHistogramTimes("SBClientPhishing.VisualFeatureTime",
+ base::TimeTicks::Now() - start_time);
+}
+
+void PhishingClassifier::VisualExtractionFinished(bool success) {
+ DCHECK(content::RenderThread::IsMainThread());
+ if (!success) {
+ RunFailureCallback();
+ return;
+ }
+
+ blink::WebLocalFrame* main_frame = render_frame_->GetWebFrame();
+
+ // Hash all of the features so that they match the model, then compute
+ // the score.
+ FeatureMap hashed_features;
+ std::unique_ptr<ClientPhishingRequest> verdict =
+ std::make_unique<ClientPhishingRequest>();
+ verdict->set_model_version(scorer_->model_version());
+ verdict->set_url(main_frame->GetDocument().Url().GetString().Utf8());
+ for (const auto& it : features_->features()) {
+ bool result = hashed_features.AddRealFeature(
+ crypto::SHA256HashString(it.first), it.second);
+ DCHECK(result);
+ ClientPhishingRequest::Feature* feature = verdict->add_feature_map();
+ feature->set_name(it.first);
+ feature->set_value(it.second);
+ }
+ for (const auto& it : *shingle_hashes_) {
+ verdict->add_shingle_hashes(it);
+ }
+ float score = static_cast<float>(scorer_->ComputeScore(hashed_features));
+ verdict->set_client_score(score);
+ verdict->set_is_phishing(score >= scorer_->threshold_probability());
+
+#if BUILDFLAG(FULL_SAFE_BROWSING)
+ visual_matching_start_ = base::TimeTicks::Now();
+ scorer_->GetMatchingVisualTargets(
+ *bitmap_, std::move(verdict),
+ base::BindOnce(&PhishingClassifier::OnVisualTargetsMatched,
+ weak_factory_.GetWeakPtr()));
+#else
+ RunCallback(*verdict);
+#endif
+}
+
+void PhishingClassifier::OnVisualTargetsMatched(
+ std::unique_ptr<ClientPhishingRequest> verdict) {
+ DCHECK(content::RenderThread::IsMainThread());
+ if (!verdict->vision_match().empty()) {
+ verdict->set_is_phishing(true);
+ }
+ base::UmaHistogramTimes("SBClientPhishing.VisualComparisonTime",
+ base::TimeTicks::Now() - visual_matching_start_);
+
+ RunCallback(*verdict);
+}
+
+void PhishingClassifier::RunCallback(const ClientPhishingRequest& verdict) {
+ std::move(done_callback_).Run(verdict);
+ Clear();
+}
+
+void PhishingClassifier::RunFailureCallback() {
+ ClientPhishingRequest verdict;
+ // In this case we're not guaranteed to have a valid URL. Just set it
+ // to the empty string to make sure we have a valid protocol buffer.
+ verdict.set_url("");
+ verdict.set_client_score(kInvalidScore);
+ verdict.set_is_phishing(false);
+ RunCallback(verdict);
+}
+
+void PhishingClassifier::Clear() {
+ page_text_ = nullptr;
+ done_callback_.Reset();
+ features_.reset(nullptr);
+ shingle_hashes_.reset(nullptr);
+ bitmap_.reset(nullptr);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
new file mode 100644
index 00000000000..ca8d43d91bb
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2012 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.
+//
+// This class handles the process of extracting all of the features from a
+// page and computing a phishyness score. The basic steps are:
+// - Run each feature extractor over the page, building up a FeatureMap of
+// feature -> value.
+// - SHA-256 hash all of the feature names in the map so that they match the
+// supplied model.
+// - Hand the hashed map off to a Scorer, which computes the probability that
+// the page is phishy.
+// - If the page is phishy, run the supplied callback.
+//
+// For more details, see phishing_*_feature_extractor.h, scorer.h, and
+// client_model.proto.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace content {
+class RenderFrame;
+}
+
+namespace safe_browsing {
+class ClientPhishingRequest;
+class FeatureMap;
+class PhishingDOMFeatureExtractor;
+class PhishingTermFeatureExtractor;
+class PhishingUrlFeatureExtractor;
+class Scorer;
+
+class PhishingClassifier {
+ public:
+ // Callback to be run when phishing classification finishes. The verdict
+ // is a ClientPhishingRequest which contains the verdict computed by the
+ // classifier as well as the extracted features. If the verdict.is_phishing()
+ // is true, the page is considered phishy by the client-side model,
+ // and the browser should ping back to get a final verdict. The
+ // verdict.client_score() is set to kInvalidScore if classification failed.
+ typedef base::OnceCallback<void(const ClientPhishingRequest& /* verdict */)>
+ DoneCallback;
+
+ static const float kInvalidScore;
+
+ // Creates a new PhishingClassifier object that will operate on
+ // |render_view|. Note that the classifier will not be 'ready' until
+ // set_phishing_scorer() is called.
+ explicit PhishingClassifier(content::RenderFrame* render_frame);
+ virtual ~PhishingClassifier();
+
+ // Sets a scorer for the classifier to use in computing the phishiness score.
+ // This must live at least as long as the PhishingClassifier. The caller is
+ // expected to cancel any pending classification before setting a phishing
+ // scorer.
+ void set_phishing_scorer(const Scorer* scorer);
+
+ // Returns true if the classifier is ready to classify pages, i.e. it
+ // has had a scorer set via set_phishing_scorer().
+ bool is_ready() const;
+
+ // Called by the RenderView when a page has finished loading. This begins
+ // the feature extraction and scoring process. |page_text| should contain
+ // the plain text of a web page, including any subframes, as returned by
+ // RenderView::CaptureText(). |page_text| is owned by the caller, and must
+ // not be destroyed until either |done_callback| is run or
+ // CancelPendingClassification() is called.
+ //
+ // To avoid blocking the render thread for too long, phishing classification
+ // may run in several chunks of work, posting a task to the current
+ // MessageLoop to continue processing. Once the scoring process is complete,
+ // |done_callback| is run on the current thread. PhishingClassifier takes
+ // ownership of the callback.
+ //
+ // It is an error to call BeginClassification if the classifier is not yet
+ // ready.
+ virtual void BeginClassification(const base::string16* page_text,
+ DoneCallback callback);
+
+ // Called by the RenderView (on the render thread) when a page is unloading
+ // or the RenderView is being destroyed. This cancels any extraction that
+ // is in progress. It is an error to call CancelPendingClassification if
+ // the classifier is not yet ready.
+ virtual void CancelPendingClassification();
+
+ private:
+ // Any score equal to or above this value is considered phishy.
+ static const float kPhishyThreshold;
+
+ // Begins the feature extraction process, by extracting URL features and
+ // beginning DOM feature extraction.
+ void BeginFeatureExtraction();
+
+ // Callback to be run when DOM feature extraction is complete.
+ // If it was successful, begins term feature extraction, otherwise
+ // runs the DoneCallback with a non-phishy verdict.
+ void DOMExtractionFinished(bool success);
+
+ // Callback to be run when term feature extraction is complete.
+ // If it was successful, begins visual feature extraction, otherwise runs the
+ // DoneCallback with a non-phishy verdict.
+ void TermExtractionFinished(bool success);
+
+ // Called to extract the visual features of the current page.
+ void ExtractVisualFeatures();
+
+ // Callback when visual feature extraction is complete.
+ // If it was successful, computes a score and runs the DoneCallback.
+ // If extraction was unsuccessful, runs the DoneCallback with a
+ // non-phishy verdict.
+ void VisualExtractionFinished(bool success);
+
+ // Callback when visual features have been scored and compared against the
+ // model.
+ void OnVisualTargetsMatched(std::unique_ptr<ClientPhishingRequest> verdict);
+
+ // Helper method to run the DoneCallback and clear the state.
+ void RunCallback(const ClientPhishingRequest& verdict);
+
+ // Helper to run the DoneCallback when feature extraction has failed.
+ // This always signals a non-phishy verdict for the page, with
+ // |kInvalidScore|.
+ void RunFailureCallback();
+
+ // Clears the current state of the PhishingClassifier.
+ void Clear();
+
+ content::RenderFrame* render_frame_; // owns us
+ const Scorer* scorer_; // owned by the caller
+ std::unique_ptr<PhishingUrlFeatureExtractor> url_extractor_;
+ std::unique_ptr<PhishingDOMFeatureExtractor> dom_extractor_;
+ std::unique_ptr<PhishingTermFeatureExtractor> term_extractor_;
+
+ // State for any in-progress extraction.
+ std::unique_ptr<FeatureMap> features_;
+ std::unique_ptr<std::set<uint32_t>> shingle_hashes_;
+ const base::string16* page_text_; // owned by the caller
+ std::unique_ptr<SkBitmap> bitmap_;
+ DoneCallback done_callback_;
+
+ // Used to record the duration of visual feature scoring.
+ base::TimeTicks visual_matching_start_;
+
+ // Used in scheduling BeginFeatureExtraction tasks.
+ // These pointers are invalidated if classification is cancelled.
+ base::WeakPtrFactory<PhishingClassifier> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(PhishingClassifier);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
new file mode 100644
index 00000000000..06c1d7d09be
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 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/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h"
+
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/debug/stack_trace.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
+#include "components/safe_browsing/content/common/safe_browsing.mojom-forward.h"
+#include "components/safe_browsing/content/common/safe_browsing.mojom-shared.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/scorer.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "content/public/renderer/document_state.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+
+using content::DocumentState;
+using content::RenderThread;
+
+namespace safe_browsing {
+
+namespace {
+
+GURL StripRef(const GURL& url) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ return url.ReplaceComponents(replacements);
+}
+
+std::set<PhishingClassifierDelegate*>& PhishingClassifierDelegates() {
+ static base::NoDestructor<std::set<PhishingClassifierDelegate*>> s;
+ return *s;
+}
+
+base::LazyInstance<std::unique_ptr<const safe_browsing::Scorer>>::
+ DestructorAtExit g_phishing_scorer = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+PhishingClassifierDelegate::PhishingClassifierDelegate(
+ content::RenderFrame* render_frame,
+ PhishingClassifier* classifier)
+ : content::RenderFrameObserver(render_frame),
+ last_main_frame_transition_(ui::PAGE_TRANSITION_LINK),
+ have_page_text_(false),
+ is_classifying_(false) {
+ PhishingClassifierDelegates().insert(this);
+ if (!classifier) {
+ classifier = new PhishingClassifier(render_frame);
+ }
+
+ classifier_.reset(classifier);
+
+ if (g_phishing_scorer.Get().get())
+ SetPhishingScorer(g_phishing_scorer.Get().get());
+
+ registry_.AddInterface(
+ base::BindRepeating(&PhishingClassifierDelegate::PhishingDetectorReceiver,
+ base::Unretained(this)));
+}
+
+PhishingClassifierDelegate::~PhishingClassifierDelegate() {
+ CancelPendingClassification(SHUTDOWN);
+ PhishingClassifierDelegates().erase(this);
+}
+
+void PhishingClassifierDelegate::SetPhishingModel(const std::string& model) {
+ safe_browsing::Scorer* scorer = nullptr;
+ // An empty model string means we should disable client-side phishing
+ // detection.
+ if (!model.empty()) {
+ scorer = safe_browsing::Scorer::Create(model);
+ if (!scorer)
+ return;
+ }
+ for (auto* delegate : PhishingClassifierDelegates())
+ delegate->SetPhishingScorer(scorer);
+ g_phishing_scorer.Get().reset(scorer);
+}
+
+// static
+PhishingClassifierDelegate* PhishingClassifierDelegate::Create(
+ content::RenderFrame* render_frame,
+ PhishingClassifier* classifier) {
+ // Private constructor and public static Create() method to facilitate
+ // stubbing out this class for binary-size reduction purposes.
+ return new PhishingClassifierDelegate(render_frame, classifier);
+}
+
+void PhishingClassifierDelegate::SetPhishingScorer(
+ const safe_browsing::Scorer* scorer) {
+ if (is_classifying_) {
+ // If there is a classification going on right now it means we're
+ // actually replacing an existing scorer with a new model. In
+ // this case we simply cancel the current classification.
+ // TODO(noelutz): if this happens too frequently we could also
+ // replace the old scorer with the new one once classification is done
+ // but this would complicate the code somewhat.
+ CancelPendingClassification(NEW_PHISHING_SCORER);
+ }
+ classifier_->set_phishing_scorer(scorer);
+}
+
+void PhishingClassifierDelegate::PhishingDetectorReceiver(
+ mojo::PendingReceiver<mojom::PhishingDetector> receiver) {
+ phishing_detector_receivers_.Add(this, std::move(receiver));
+}
+
+void PhishingClassifierDelegate::OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ registry_.TryBindInterface(interface_name, interface_pipe);
+}
+
+void PhishingClassifierDelegate::StartPhishingDetection(
+ const GURL& url,
+ StartPhishingDetectionCallback callback) {
+ RecordEvent(SBPhishingClassifierEvent::kPhishingDetectionRequested);
+
+ if (!callback_.is_null())
+ std::move(callback_).Run(mojom::PhishingDetectorResult::CANCELLED, "");
+ is_phishing_detection_running_ = true;
+ last_url_received_from_browser_ = StripRef(url);
+ callback_ = std::move(callback);
+ // Start classifying the current page if all conditions are met.
+ // See MaybeStartClassification() for details.
+ MaybeStartClassification();
+}
+
+void PhishingClassifierDelegate::DidCommitProvisionalLoad(
+ ui::PageTransition transition) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ // A new page is starting to load, so cancel classificaiton.
+ CancelPendingClassification(NAVIGATE_AWAY);
+ if (!frame->Parent())
+ last_main_frame_transition_ = transition;
+}
+
+void PhishingClassifierDelegate::DidFinishSameDocumentNavigation() {
+ // TODO(bryner): We shouldn't need to cancel classification if the navigation
+ // is within the same document. However, if we let classification continue in
+ // this case, we need to properly deal with the fact that PageCaptured will
+ // be called again for the same-document navigation. We need to be sure not
+ // to swap out the page text while the term feature extractor is still
+ // running.
+ CancelPendingClassification(NAVIGATE_WITHIN_PAGE);
+}
+
+void PhishingClassifierDelegate::PageCaptured(base::string16* page_text,
+ bool preliminary_capture) {
+ RecordEvent(SBPhishingClassifierEvent::kPageTextCaptured);
+
+ if (preliminary_capture) {
+ return;
+ }
+ // Make sure there's no classification in progress. We don't want to swap
+ // out the page text string from underneath the term feature extractor.
+ //
+ // Note: Currently, if the url hasn't changed, we won't restart
+ // classification in this case. We may want to adjust this.
+ CancelPendingClassification(PAGE_RECAPTURED);
+ last_finished_load_url_ = render_frame()->GetWebFrame()->GetDocument().Url();
+ classifier_page_text_.swap(*page_text);
+ have_page_text_ = true;
+
+ GURL stripped_last_load_url(StripRef(last_finished_load_url_));
+ // Check if toplevel URL has changed.
+ if (stripped_last_load_url == StripRef(last_url_sent_to_classifier_)) {
+ return;
+ }
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "SBClientPhishing.PageCapturedMatchesBrowserURL",
+ (last_url_received_from_browser_ == stripped_last_load_url));
+
+ MaybeStartClassification();
+}
+
+void PhishingClassifierDelegate::CancelPendingClassification(
+ CancelClassificationReason reason) {
+ if (is_classifying_) {
+ UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.CancelClassificationReason",
+ reason, CANCEL_CLASSIFICATION_MAX);
+ is_classifying_ = false;
+ }
+ if (classifier_->is_ready()) {
+ classifier_->CancelPendingClassification();
+ }
+ classifier_page_text_.clear();
+ have_page_text_ = false;
+}
+
+void PhishingClassifierDelegate::ClassificationDone(
+ const ClientPhishingRequest& verdict) {
+ is_phishing_detection_running_ = false;
+ if (callback_.is_null())
+ return;
+
+ if (verdict.client_score() != PhishingClassifier::kInvalidScore) {
+ DCHECK_EQ(last_url_sent_to_classifier_.spec(), verdict.url());
+ std::move(callback_).Run(mojom::PhishingDetectorResult::SUCCESS,
+ verdict.SerializeAsString());
+ } else {
+ std::move(callback_).Run(mojom::PhishingDetectorResult::INVALID_SCORE,
+ verdict.SerializeAsString());
+ }
+}
+
+void PhishingClassifierDelegate::MaybeStartClassification() {
+ // We can begin phishing classification when the following conditions are
+ // met:
+ // 1. A Scorer has been created
+ // 2. The browser has sent a StartPhishingDetection message for the
+ // current toplevel URL.
+ // 3. The page has finished loading and the page text has been extracted.
+ // 4. The load is a new navigation (not a session history navigation).
+ // 5. The toplevel URL has not already been classified.
+ //
+ // Note that if we determine that this particular navigation should not be
+ // classified at all (as opposed to deferring it until we get an IPC or
+ // the load completes), we discard the page text since it won't be needed.
+ if (!classifier_->is_ready()) {
+ is_phishing_detection_running_ = false;
+ // Keep classifier_page_text_, in case a Scorer is set later.
+ if (!callback_.is_null())
+ std::move(callback_).Run(
+ mojom::PhishingDetectorResult::CLASSIFIER_NOT_READY, "");
+ return;
+ }
+
+ if (last_main_frame_transition_ & ui::PAGE_TRANSITION_FORWARD_BACK) {
+ // Skip loads from session history navigation. However, update the
+ // last URL sent to the classifier, so that we'll properly detect
+ // same-document navigations.
+ last_url_sent_to_classifier_ = last_finished_load_url_;
+ classifier_page_text_.clear(); // we won't need this.
+ have_page_text_ = false;
+ is_phishing_detection_running_ = false;
+ if (!callback_.is_null())
+ std::move(callback_).Run(
+ mojom::PhishingDetectorResult::FORWARD_BACK_TRANSITION, "");
+ return;
+ }
+
+ GURL stripped_last_load_url(StripRef(last_finished_load_url_));
+ if (!have_page_text_) {
+ RecordEvent(SBPhishingClassifierEvent::kPageTextNotLoaded);
+ return;
+ }
+
+ if (last_url_received_from_browser_ != stripped_last_load_url) {
+ RecordEvent(SBPhishingClassifierEvent::kUrlShouldNotBeClassified);
+ // The browser has not yet confirmed that this URL should be classified,
+ // so defer classification for now. Note: the ref does not affect
+ // any of the browser's preclassification checks, so we don't require it
+ // to match.
+ // Keep classifier_page_text_, in case the browser notifies us later that
+ // we should classify the URL.
+ return;
+ }
+
+ last_url_sent_to_classifier_ = last_finished_load_url_;
+ is_classifying_ = true;
+ classifier_->BeginClassification(
+ &classifier_page_text_,
+ base::BindOnce(&PhishingClassifierDelegate::ClassificationDone,
+ base::Unretained(this)));
+}
+
+void PhishingClassifierDelegate::RecordEvent(SBPhishingClassifierEvent event) {
+ UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.Classifier.Event", event);
+}
+
+void PhishingClassifierDelegate::OnDestruct() {
+ if (is_phishing_detection_running_) {
+ RecordEvent(SBPhishingClassifierEvent::kDestructedBeforeClassificationDone);
+ }
+ delete this;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
new file mode 100644
index 00000000000..e361ec9191f
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2011 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.
+//
+// This class is used by the RenderView to interact with a PhishingClassifier.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_DELEGATE_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_DELEGATE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/safe_browsing/content/common/safe_browsing.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "content/public/renderer/render_thread_observer.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+class ClientPhishingRequest;
+class PhishingClassifier;
+class Scorer;
+
+enum class SBPhishingClassifierEvent {
+ kPhishingDetectionRequested = 0,
+ kPageTextCaptured = 1,
+ // Phishing detection could not start because the page text was not loaded.
+ kPageTextNotLoaded = 2,
+ // Phishing detection could not start because the url was not specified to be
+ // classified.
+ kUrlShouldNotBeClassified = 3,
+ // Phishing detection could not finish because the class was destructed.
+ kDestructedBeforeClassificationDone = 4,
+ kMaxValue = kDestructedBeforeClassificationDone,
+};
+
+class PhishingClassifierDelegate : public content::RenderFrameObserver,
+ public mojom::PhishingDetector {
+ public:
+ // The RenderFrame owns us. This object takes ownership of the classifier.
+ // Note that if classifier is null, a default instance of PhishingClassifier
+ // will be used.
+ static PhishingClassifierDelegate* Create(content::RenderFrame* render_frame,
+ PhishingClassifier* classifier);
+ ~PhishingClassifierDelegate() override;
+
+ // mojom::PhishingDetector
+ void SetPhishingModel(const std::string& model) override;
+
+ // Called by the RenderFrame once there is a phishing scorer available.
+ // The scorer is passed on to the classifier.
+ void SetPhishingScorer(const safe_browsing::Scorer* scorer);
+
+ // Called by the RenderFrame once a page has finished loading. Updates the
+ // last-loaded URL and page text, then starts classification if all other
+ // conditions are met (see MaybeStartClassification for details).
+ // We ignore preliminary captures, since these happen before the page has
+ // finished loading.
+ void PageCaptured(base::string16* page_text, bool preliminary_capture);
+
+ // RenderFrameObserver implementation, public for testing.
+
+ // Called by the RenderFrame when a page has started loading in the given
+ // WebFrame. Typically, this will cause any pending classification to be
+ // cancelled.
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
+ // Called by the RenderFrame when the same-document navigation has been
+ // committed. We continue running the current classification.
+ void DidFinishSameDocumentNavigation() override;
+
+ private:
+ friend class PhishingClassifierDelegateTest;
+
+ PhishingClassifierDelegate(content::RenderFrame* render_frame,
+ PhishingClassifier* classifier);
+
+ enum CancelClassificationReason {
+ NAVIGATE_AWAY,
+ NAVIGATE_WITHIN_PAGE,
+ PAGE_RECAPTURED,
+ SHUTDOWN,
+ NEW_PHISHING_SCORER,
+ CANCEL_CLASSIFICATION_MAX // Always add new values before this one.
+ };
+
+ void PhishingDetectorReceiver(
+ mojo::PendingReceiver<mojom::PhishingDetector> receiver);
+
+ // Cancels any pending classification and frees the page text.
+ void CancelPendingClassification(CancelClassificationReason reason);
+
+ // Records in UMA of a specific event that happens in the phishing classifier.
+ void RecordEvent(SBPhishingClassifierEvent event);
+
+ void OnDestruct() override;
+
+ void OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
+
+ // mojom::PhishingDetector
+ // Called by the RenderFrame when it receives a StartPhishingDetection IPC
+ // from the browser. This signals that it is ok to begin classification
+ // for the given toplevel URL. If the URL has been fully loaded into the
+ // RenderFrame and a Scorer has been set, this will begin classification,
+ // otherwise classification will be deferred until these conditions are met.
+ void StartPhishingDetection(const GURL& url,
+ StartPhishingDetectionCallback callback) override;
+
+ // Called when classification for the current page finishes.
+ void ClassificationDone(const ClientPhishingRequest& verdict);
+
+ // Shared code to begin classification if all conditions are met.
+ void MaybeStartClassification();
+
+ // The PhishingClassifier to use for the RenderFrame. This is created once
+ // a scorer is made available via SetPhishingScorer().
+ std::unique_ptr<PhishingClassifier> classifier_;
+
+ // The last URL that the browser instructed us to classify,
+ // with the ref stripped.
+ GURL last_url_received_from_browser_;
+
+ // The last top-level URL that has finished loading in the RenderFrame.
+ // This corresponds to the text in classifier_page_text_.
+ GURL last_finished_load_url_;
+
+ // The transition type for the last load in the main frame. We use this
+ // to exclude back/forward loads from classification. Note that this is
+ // set in DidCommitProvisionalLoad(); the transition is reset after this
+ // call in the RenderFrame, so we need to save off the value.
+ ui::PageTransition last_main_frame_transition_;
+
+ // The URL of the last load that we actually started classification on.
+ // This is used to suppress phishing classification on subframe navigation
+ // and back and forward navigations in history.
+ GURL last_url_sent_to_classifier_;
+
+ // The page text that will be analyzed by the phishing classifier. This is
+ // set by OnNavigate and cleared when the classifier finishes. Note that if
+ // there is no Scorer yet when OnNavigate is called, or the browser has not
+ // instructed us to classify the page, the page text will be cached until
+ // these conditions are met.
+ base::string16 classifier_page_text_;
+
+ // Tracks whether we have stored anything in classifier_page_text_ for the
+ // most recent load. We use this to distinguish empty text from cases where
+ // PageCaptured has not been called.
+ bool have_page_text_;
+
+ // Set to true if the classifier is currently running.
+ bool is_classifying_;
+
+ // Set to true when StartPhishingDetection method is called. It is
+ // set to false whenever phishing detection has finished.
+ bool is_phishing_detection_running_ = false;
+
+ // The callback from the most recent call to StartPhishingDetection.
+ StartPhishingDetectionCallback callback_;
+
+ mojo::ReceiverSet<mojom::PhishingDetector> phishing_detector_receivers_;
+
+ service_manager::BinderRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(PhishingClassifierDelegate);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_CLASSIFIER_DELEGATE_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.cc
new file mode 100644
index 00000000000..432c505fa53
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.cc
@@ -0,0 +1,481 @@
+// Copyright (c) 2012 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/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "content/public/renderer/render_view.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_element_collection.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
+
+namespace safe_browsing {
+
+// This time should be short enough that it doesn't noticeably disrupt the
+// user's interaction with the page.
+const int PhishingDOMFeatureExtractor::kMaxTimePerChunkMs = 10;
+
+// Experimenting shows that we get a reasonable gain in performance by
+// increasing this up to around 10, but there's not much benefit in
+// increasing it past that.
+const int PhishingDOMFeatureExtractor::kClockCheckGranularity = 10;
+
+// This should be longer than we expect feature extraction to take on any
+// actual phishing page.
+const int PhishingDOMFeatureExtractor::kMaxTotalTimeMs = 500;
+
+// Intermediate state used for computing features. See features.h for
+// descriptions of the DOM features that are computed.
+struct PhishingDOMFeatureExtractor::PageFeatureState {
+ // Link related features
+ int external_links;
+ std::unordered_set<std::string> external_domains;
+ int secure_links;
+ int total_links;
+
+ // Form related features
+ int num_forms;
+ int num_text_inputs;
+ int num_pswd_inputs;
+ int num_radio_inputs;
+ int num_check_inputs;
+ int action_other_domain;
+ int total_actions;
+ std::unordered_set<std::string> page_action_urls;
+
+ // Image related features
+ int img_other_domain;
+ int total_imgs;
+
+ // How many script tags
+ int num_script_tags;
+
+ // The time at which we started feature extraction for the current page.
+ base::TimeTicks start_time;
+
+ // The number of iterations we've done for the current extraction.
+ int num_iterations;
+
+ explicit PageFeatureState(base::TimeTicks start_time_ticks)
+ : external_links(0),
+ secure_links(0),
+ total_links(0),
+ num_forms(0),
+ num_text_inputs(0),
+ num_pswd_inputs(0),
+ num_radio_inputs(0),
+ num_check_inputs(0),
+ action_other_domain(0),
+ total_actions(0),
+ img_other_domain(0),
+ total_imgs(0),
+ num_script_tags(0),
+ start_time(start_time_ticks),
+ num_iterations(0) {}
+
+ ~PageFeatureState() {}
+};
+
+// Per-frame state
+struct PhishingDOMFeatureExtractor::FrameData {
+ // This is our reference to document.all, which is an iterator over all
+ // of the elements in the document. It keeps track of our current position.
+ blink::WebElementCollection elements;
+ // The domain of the document URL, stored here so that we don't need to
+ // recompute it every time it's needed.
+ std::string domain;
+};
+
+PhishingDOMFeatureExtractor::PhishingDOMFeatureExtractor()
+ : clock_(base::DefaultTickClock::GetInstance()) {
+ Clear();
+}
+
+PhishingDOMFeatureExtractor::~PhishingDOMFeatureExtractor() {
+ // The RenderView should have called CancelPendingExtraction() before
+ // we are destroyed.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!cur_frame_data_.get());
+ DCHECK(cur_document_.IsNull());
+}
+
+void PhishingDOMFeatureExtractor::ExtractFeatures(blink::WebDocument document,
+ FeatureMap* features,
+ DoneCallback done_callback) {
+ // The RenderView should have called CancelPendingExtraction() before
+ // starting a new extraction, so DCHECK this.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!cur_frame_data_.get());
+ DCHECK(cur_document_.IsNull());
+ // However, in an opt build, we will go ahead and clean up the pending
+ // extraction so that we can start in a known state.
+ CancelPendingExtraction();
+
+ features_ = features;
+ done_callback_ = std::move(done_callback);
+
+ page_feature_state_ = std::make_unique<PageFeatureState>(clock_->NowTicks());
+ cur_document_ = document;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PhishingDOMFeatureExtractor::ExtractFeaturesWithTimeout,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PhishingDOMFeatureExtractor::CancelPendingExtraction() {
+ // Cancel any pending callbacks, and clear our state.
+ weak_factory_.InvalidateWeakPtrs();
+ Clear();
+}
+
+void PhishingDOMFeatureExtractor::ExtractFeaturesWithTimeout() {
+ DCHECK(page_feature_state_.get());
+ ++page_feature_state_->num_iterations;
+ base::TimeTicks current_chunk_start_time = clock_->NowTicks();
+
+ if (cur_document_.IsNull()) {
+ // This will only happen if we weren't able to get the document for the
+ // main frame. We'll treat this as an extraction failure.
+ RunCallback(false);
+ return;
+ }
+
+ int num_elements = 0;
+ for (; !cur_document_.IsNull(); cur_document_ = GetNextDocument()) {
+ blink::WebElement cur_element;
+ if (cur_frame_data_.get()) {
+ // We're resuming traversal of a frame, so just advance to the next
+ // element.
+ cur_element = cur_frame_data_->elements.NextItem();
+ // When we resume the traversal, the first call to nextItem() potentially
+ // has to walk through the document again from the beginning, if it was
+ // modified between our chunks of work. Log how long this takes, so we
+ // can tell if it's too slow.
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.DOMFeatureResumeTime",
+ clock_->NowTicks() - current_chunk_start_time);
+ } else {
+ // We just moved to a new frame, so update our frame state
+ // and advance to the first element.
+ ResetFrameData();
+ cur_element = cur_frame_data_->elements.FirstItem();
+ }
+
+ for (; !cur_element.IsNull();
+ cur_element = cur_frame_data_->elements.NextItem()) {
+ if (cur_element.HasHTMLTagName("a")) {
+ HandleLink(cur_element);
+ } else if (cur_element.HasHTMLTagName("form")) {
+ HandleForm(cur_element);
+ } else if (cur_element.HasHTMLTagName("img")) {
+ HandleImage(cur_element);
+ } else if (cur_element.HasHTMLTagName("input")) {
+ HandleInput(cur_element);
+ } else if (cur_element.HasHTMLTagName("script")) {
+ HandleScript(cur_element);
+ }
+
+ if (++num_elements >= kClockCheckGranularity) {
+ num_elements = 0;
+ base::TimeTicks now = clock_->NowTicks();
+ if (now - page_feature_state_->start_time >=
+ base::TimeDelta::FromMilliseconds(kMaxTotalTimeMs)) {
+ // We expect this to happen infrequently, so record when it does.
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.DOMFeatureTimeout", 1);
+ RunCallback(false);
+ return;
+ }
+ base::TimeDelta chunk_elapsed = now - current_chunk_start_time;
+ if (chunk_elapsed >=
+ base::TimeDelta::FromMilliseconds(kMaxTimePerChunkMs)) {
+ // The time limit for the current chunk is up, so post a task to
+ // continue extraction.
+ //
+ // Record how much time we actually spent on the chunk. If this is
+ // much higher than kMaxTimePerChunkMs, we may need to adjust the
+ // clock granularity.
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.DOMFeatureChunkTime",
+ chunk_elapsed);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &PhishingDOMFeatureExtractor::ExtractFeaturesWithTimeout,
+ weak_factory_.GetWeakPtr()));
+ return;
+ }
+ // Otherwise, continue.
+ }
+ }
+
+ // We're done with this frame, recalculate the FrameData when we
+ // advance to the next frame.
+ cur_frame_data_.reset();
+ }
+
+ InsertFeatures();
+ RunCallback(true);
+}
+
+void PhishingDOMFeatureExtractor::HandleLink(const blink::WebElement& element) {
+ // Count the number of times we link to a different host.
+ if (!element.HasAttribute("href"))
+ return;
+
+ // Retrieve the link and resolve the link in case it's relative.
+ blink::WebURL full_url = CompleteURL(element, element.GetAttribute("href"));
+
+ std::string domain;
+ bool is_external = IsExternalDomain(full_url, &domain);
+ if (domain.empty())
+ return;
+
+ if (is_external) {
+ ++page_feature_state_->external_links;
+
+ // Record each unique domain that we link to.
+ page_feature_state_->external_domains.insert(domain);
+ }
+
+ // Check how many are https links.
+ if (GURL(full_url).SchemeIs("https")) {
+ ++page_feature_state_->secure_links;
+ }
+
+ ++page_feature_state_->total_links;
+}
+
+void PhishingDOMFeatureExtractor::HandleForm(const blink::WebElement& element) {
+ // Increment the number of forms on this page.
+ ++page_feature_state_->num_forms;
+
+ // Record whether the action points to a different domain.
+ if (!element.HasAttribute("action")) {
+ return;
+ }
+
+ blink::WebURL full_url = CompleteURL(element, element.GetAttribute("action"));
+
+ page_feature_state_->page_action_urls.insert(full_url.GetString().Utf8());
+
+ std::string domain;
+ bool is_external = IsExternalDomain(full_url, &domain);
+ if (domain.empty())
+ return;
+
+ if (is_external) {
+ ++page_feature_state_->action_other_domain;
+ }
+ ++page_feature_state_->total_actions;
+}
+
+void PhishingDOMFeatureExtractor::HandleImage(
+ const blink::WebElement& element) {
+ // Record whether the image points to a different domain.
+ blink::WebURL full_url = CompleteURL(element, element.GetAttribute("src"));
+ std::string domain;
+ bool is_external = IsExternalDomain(full_url, &domain);
+ if (domain.empty())
+ return;
+
+ if (is_external)
+ ++page_feature_state_->img_other_domain;
+
+ ++page_feature_state_->total_imgs;
+}
+
+void PhishingDOMFeatureExtractor::HandleInput(
+ const blink::WebElement& element) {
+ // The HTML spec says that if the type is unspecified, it defaults to text.
+ // In addition, any unrecognized type will be treated as a text input.
+ //
+ // Note that we use the attribute value rather than
+ // WebFormControlElement::formControlType() for consistency with the
+ // way the phishing classification model is created.
+ std::string type = base::ToLowerASCII(element.GetAttribute("type").Utf8());
+ if (type == "password") {
+ ++page_feature_state_->num_pswd_inputs;
+ } else if (type == "radio") {
+ ++page_feature_state_->num_radio_inputs;
+ } else if (type == "checkbox") {
+ ++page_feature_state_->num_check_inputs;
+ } else if (type != "submit" && type != "reset" && type != "file" &&
+ type != "hidden" && type != "image" && type != "button") {
+ // Note that there are a number of new input types in HTML5 that are not
+ // handled above. For now, we will consider these as text inputs since
+ // they could be used to capture user input.
+ ++page_feature_state_->num_text_inputs;
+ }
+}
+
+void PhishingDOMFeatureExtractor::HandleScript(
+ const blink::WebElement& element) {
+ ++page_feature_state_->num_script_tags;
+}
+
+void PhishingDOMFeatureExtractor::RunCallback(bool success) {
+ // Record some timing stats that we can use to evaluate feature extraction
+ // performance. These include both successful and failed extractions.
+ DCHECK(page_feature_state_.get());
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.DOMFeatureIterations",
+ page_feature_state_->num_iterations);
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.DOMFeatureTotalTime",
+ clock_->NowTicks() - page_feature_state_->start_time);
+
+ DCHECK(!done_callback_.is_null());
+ std::move(done_callback_).Run(success);
+ Clear();
+}
+
+void PhishingDOMFeatureExtractor::Clear() {
+ features_ = nullptr;
+ done_callback_.Reset();
+ cur_frame_data_.reset(nullptr);
+ cur_document_.Reset();
+}
+
+void PhishingDOMFeatureExtractor::ResetFrameData() {
+ DCHECK(!cur_document_.IsNull());
+ DCHECK(!cur_frame_data_.get());
+
+ cur_frame_data_.reset(new FrameData());
+ cur_frame_data_->elements = cur_document_.All();
+ cur_frame_data_->domain =
+ net::registry_controlled_domains::GetDomainAndRegistry(
+ cur_document_.Url(),
+ net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+}
+
+blink::WebDocument PhishingDOMFeatureExtractor::GetNextDocument() {
+ DCHECK(!cur_document_.IsNull());
+ blink::WebFrame* frame = cur_document_.GetFrame();
+ // Advance to the next frame that contains a document, with no wrapping.
+ if (frame) {
+ for (frame = frame->TraverseNext(); frame; frame = frame->TraverseNext()) {
+ // TODO(dcheng): Verify if the WebDocument::IsNull check is really needed.
+ if (frame->IsWebLocalFrame() &&
+ !frame->ToWebLocalFrame()->GetDocument().IsNull()) {
+ return frame->ToWebLocalFrame()->GetDocument();
+ }
+ }
+ } else {
+ // Keep track of how often frame traversal got "stuck" due to the
+ // current subdocument getting removed from the frame tree.
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.DOMFeatureFrameRemoved", 1);
+ }
+ return blink::WebDocument();
+}
+
+bool PhishingDOMFeatureExtractor::IsExternalDomain(const GURL& url,
+ std::string* domain) const {
+ DCHECK(domain);
+ DCHECK(cur_frame_data_.get());
+
+ if (cur_frame_data_->domain.empty()) {
+ return false;
+ }
+
+ // TODO(bryner): Ensure that the url encoding is consistent with the features
+ // in the model.
+ if (url.HostIsIPAddress()) {
+ domain->assign(url.host());
+ } else {
+ domain->assign(net::registry_controlled_domains::GetDomainAndRegistry(
+ url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
+ }
+
+ return !domain->empty() && *domain != cur_frame_data_->domain;
+}
+
+blink::WebURL PhishingDOMFeatureExtractor::CompleteURL(
+ const blink::WebElement& element,
+ const blink::WebString& partial_url) {
+ return element.GetDocument().CompleteURL(partial_url);
+}
+
+void PhishingDOMFeatureExtractor::InsertFeatures() {
+ DCHECK(page_feature_state_.get());
+
+ if (page_feature_state_->total_links > 0) {
+ // Add a feature for the fraction of times the page links to an external
+ // domain vs. an internal domain.
+ double link_freq =
+ static_cast<double>(page_feature_state_->external_links) /
+ page_feature_state_->total_links;
+ features_->AddRealFeature(features::kPageExternalLinksFreq, link_freq);
+
+ // Add a feature for each unique domain that we're linking to
+ for (const auto& domain : page_feature_state_->external_domains) {
+ features_->AddBooleanFeature(features::kPageLinkDomain + domain);
+ }
+
+ // Fraction of links that use https.
+ double secure_freq =
+ static_cast<double>(page_feature_state_->secure_links) /
+ page_feature_state_->total_links;
+ features_->AddRealFeature(features::kPageSecureLinksFreq, secure_freq);
+ }
+
+ // Record whether forms appear and whether various form elements appear.
+ if (page_feature_state_->num_forms > 0) {
+ features_->AddBooleanFeature(features::kPageHasForms);
+ }
+ if (page_feature_state_->num_text_inputs > 0) {
+ features_->AddBooleanFeature(features::kPageHasTextInputs);
+ }
+ if (page_feature_state_->num_pswd_inputs > 0) {
+ features_->AddBooleanFeature(features::kPageHasPswdInputs);
+ }
+ if (page_feature_state_->num_radio_inputs > 0) {
+ features_->AddBooleanFeature(features::kPageHasRadioInputs);
+ }
+ if (page_feature_state_->num_check_inputs > 0) {
+ features_->AddBooleanFeature(features::kPageHasCheckInputs);
+ }
+
+ // Record fraction of form actions that point to a different domain.
+ if (page_feature_state_->total_actions > 0) {
+ double action_freq =
+ static_cast<double>(page_feature_state_->action_other_domain) /
+ page_feature_state_->total_actions;
+ features_->AddRealFeature(features::kPageActionOtherDomainFreq,
+ action_freq);
+ }
+
+ // Add a feature for each unique external action url.
+ for (const auto& url : page_feature_state_->page_action_urls) {
+ features_->AddBooleanFeature(features::kPageActionURL + url);
+ }
+
+ // Record how many image src attributes point to a different domain.
+ if (page_feature_state_->total_imgs > 0) {
+ double img_freq =
+ static_cast<double>(page_feature_state_->img_other_domain) /
+ page_feature_state_->total_imgs;
+ features_->AddRealFeature(features::kPageImgOtherDomainFreq, img_freq);
+ }
+
+ // Record number of script tags (discretized for numerical stability.)
+ if (page_feature_state_->num_script_tags > 1) {
+ features_->AddBooleanFeature(features::kPageNumScriptTagsGTOne);
+ if (page_feature_state_->num_script_tags > 6) {
+ features_->AddBooleanFeature(features::kPageNumScriptTagsGTSix);
+ }
+ }
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h
new file mode 100644
index 00000000000..c7b767bff93
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_dom_feature_extractor.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2011 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.
+//
+// PhishingDOMFeatureExtractor handles computing DOM-based features for the
+// client-side phishing detection model. These include the presence of various
+// types of elements, ratios of external and secure links, and tokens for
+// external domains linked to.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_DOM_FEATURE_EXTRACTOR_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_DOM_FEATURE_EXTRACTOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/tick_clock.h"
+#include "third_party/blink/public/web/web_document.h"
+
+class GURL;
+
+namespace blink {
+class WebElement;
+}
+
+namespace safe_browsing {
+class FeatureMap;
+
+class PhishingDOMFeatureExtractor {
+ public:
+ // Callback to be run when feature extraction finishes. The callback
+ // argument is true if extraction was successful, false otherwise.
+ typedef base::OnceCallback<void(bool)> DoneCallback;
+
+ // Creates a PhishingDOMFeatureExtractor instance.
+ PhishingDOMFeatureExtractor();
+ virtual ~PhishingDOMFeatureExtractor();
+
+ // Begins extracting features into the given FeatureMap for the page.
+ // To avoid blocking the render thread for too long, the feature extractor
+ // may run in several chunks of work, posting a task to the current
+ // MessageLoop to continue processing. Once feature extraction is complete,
+ // |done_callback| is run on the current thread. PhishingDOMFeatureExtractor
+ // takes ownership of the callback.
+ void ExtractFeatures(blink::WebDocument document,
+ FeatureMap* features,
+ DoneCallback done_callback);
+
+ // Cancels any pending feature extraction. The DoneCallback will not be run.
+ // Must be called if there is a feature extraction in progress when the page
+ // is unloaded or the PhishingDOMFeatureExtractor is destroyed.
+ void CancelPendingExtraction();
+
+ void SetTickClockForTesting(const base::TickClock* clock) { clock_ = clock; }
+
+ private:
+ struct FrameData;
+ struct PageFeatureState;
+
+ // The maximum amount of wall time that we will spend on a single extraction
+ // iteration before pausing to let other MessageLoop tasks run.
+ static const int kMaxTimePerChunkMs;
+
+ // The number of elements that we will process before checking to see whether
+ // kMaxTimePerChunkMs has elapsed. Since checking the current time can be
+ // slow, we don't do this on every element processed.
+ static const int kClockCheckGranularity;
+
+ // The maximum total amount of time that the feature extractor will run
+ // before giving up on the current page.
+ static const int kMaxTotalTimeMs;
+
+ // Does the actual work of ExtractFeatures. ExtractFeaturesWithTimeout runs
+ // until a predefined maximum amount of time has elapsed, then posts a task
+ // to the current MessageLoop to continue extraction. When extraction
+ // finishes, calls RunCallback().
+ void ExtractFeaturesWithTimeout();
+
+ // Handlers for the various HTML elements that we compute features for.
+ // Since some of the features (such as ratios) cannot be computed until
+ // feature extraction is finished, these handlers do not add to the feature
+ // map directly. Instead, they update the values in the PageFeatureState.
+ void HandleLink(const blink::WebElement& element);
+ void HandleForm(const blink::WebElement& element);
+ void HandleImage(const blink::WebElement& element);
+ void HandleInput(const blink::WebElement& element);
+ void HandleScript(const blink::WebElement& element);
+
+ // Runs |done_callback_| and then clears all internal state.
+ void RunCallback(bool success);
+
+ // Clears all internal feature extraction state.
+ void Clear();
+
+ // Called after advancing |cur_document_| to update the state in
+ // |cur_frame_data_|.
+ void ResetFrameData();
+
+ // Returns the next document in frame-traversal order from cur_document_.
+ // If there are no more documents, returns a null WebDocument.
+ blink::WebDocument GetNextDocument();
+
+ // Given a URL, checks whether the domain is different from the domain of
+ // the current frame's URL. If so, stores the domain in |domain| and returns
+ // true, otherwise returns false.
+ virtual bool IsExternalDomain(const GURL& url, std::string* domain) const;
+
+ // Given a partial URL, extend it to a full url based on the current frame's
+ // URL.
+ virtual blink::WebURL CompleteURL(const blink::WebElement& element,
+ const blink::WebString& partial_url);
+
+ // Called once all frames have been processed to compute features from the
+ // PageFeatureState and add them to |features_|. See features.h for a
+ // description of which features are computed.
+ void InsertFeatures();
+
+ const base::TickClock* clock_;
+
+ // The output parameters from the most recent call to ExtractFeatures().
+ FeatureMap* features_; // The caller keeps ownership of this.
+ DoneCallback done_callback_;
+
+ // The current (sub-)document that we are processing. May be a null document
+ // (isNull()) if we are not currently extracting features.
+ blink::WebDocument cur_document_;
+
+ // Stores extra state for |cur_document_| that will be persisted until we
+ // advance to the next frame.
+ std::unique_ptr<FrameData> cur_frame_data_;
+
+ // Stores the intermediate data used to create features. This data is
+ // accumulated across all frames in the RenderView.
+ std::unique_ptr<PageFeatureState> page_feature_state_;
+
+ // Used in scheduling ExtractFeaturesWithTimeout tasks.
+ // These pointers are invalidated if extraction is cancelled.
+ base::WeakPtrFactory<PhishingDOMFeatureExtractor> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(PhishingDOMFeatureExtractor);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_DOM_FEATURE_EXTRACTOR_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.cc
new file mode 100644
index 00000000000..55cc6d8805c
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 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/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h"
+
+#include <list>
+#include <map>
+#include <memory>
+#include <unordered_set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/i18n/break_iterator.h"
+#include "base/i18n/case_conversion.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h"
+#include "crypto/sha2.h"
+
+namespace safe_browsing {
+
+// This time should be short enough that it doesn't noticeably disrupt the
+// user's interaction with the page.
+const int PhishingTermFeatureExtractor::kMaxTimePerChunkMs = 10;
+
+// Experimenting shows that we get a reasonable gain in performance by
+// increasing this up to around 10, but there's not much benefit in
+// increasing it past that.
+const int PhishingTermFeatureExtractor::kClockCheckGranularity = 5;
+
+// This should be longer than we expect feature extraction to take on any
+// actual phishing page.
+const int PhishingTermFeatureExtractor::kMaxTotalTimeMs = 500;
+
+// All of the state pertaining to the current feature extraction.
+struct PhishingTermFeatureExtractor::ExtractionState {
+ // Stores up to max_words_per_term_ previous words separated by spaces.
+ std::string previous_words;
+
+ // Stores the current shingle after a new word is processed and added in.
+ std::string current_shingle;
+
+ // Stores the sizes of the words in current_shingle. Note: the size includes
+ // the space after each word. In other words, the sum of all sizes in this
+ // list is equal to the length of current_shingle.
+ std::list<size_t> shingle_word_sizes;
+
+ // Stores the sizes of the words in previous_words. Note: the size includes
+ // the space after each word. In other words, the sum of all sizes in this
+ // list is equal to the length of previous_words.
+ std::list<size_t> previous_word_sizes;
+
+ // An iterator for word breaking.
+ std::unique_ptr<base::i18n::BreakIterator> iterator;
+
+ // The time at which we started feature extraction for the current page.
+ base::TimeTicks start_time;
+
+ // The number of iterations we've done for the current extraction.
+ int num_iterations;
+
+ ExtractionState(const base::string16& text, base::TimeTicks start_time_ticks)
+ : start_time(start_time_ticks), num_iterations(0) {
+ std::unique_ptr<base::i18n::BreakIterator> i(new base::i18n::BreakIterator(
+ text, base::i18n::BreakIterator::BREAK_WORD));
+
+ if (i->Init())
+ iterator = std::move(i);
+ }
+};
+
+PhishingTermFeatureExtractor::PhishingTermFeatureExtractor(
+ const std::unordered_set<std::string>* page_term_hashes,
+ const std::unordered_set<uint32_t>* page_word_hashes,
+ size_t max_words_per_term,
+ uint32_t murmurhash3_seed,
+ size_t max_shingles_per_page,
+ size_t shingle_size)
+ : page_term_hashes_(page_term_hashes),
+ page_word_hashes_(page_word_hashes),
+ max_words_per_term_(max_words_per_term),
+ murmurhash3_seed_(murmurhash3_seed),
+ max_shingles_per_page_(max_shingles_per_page),
+ shingle_size_(shingle_size),
+ clock_(base::DefaultTickClock::GetInstance()) {
+ Clear();
+}
+
+PhishingTermFeatureExtractor::~PhishingTermFeatureExtractor() {
+ // The RenderView should have called CancelPendingExtraction() before
+ // we are destroyed.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!state_.get());
+}
+
+void PhishingTermFeatureExtractor::ExtractFeatures(
+ const base::string16* page_text,
+ FeatureMap* features,
+ std::set<uint32_t>* shingle_hashes,
+ DoneCallback done_callback) {
+ // The RenderView should have called CancelPendingExtraction() before
+ // starting a new extraction, so DCHECK this.
+ DCHECK(done_callback_.is_null());
+ DCHECK(!state_.get());
+ // However, in an opt build, we will go ahead and clean up the pending
+ // extraction so that we can start in a known state.
+ CancelPendingExtraction();
+
+ page_text_ = page_text;
+ features_ = features;
+ shingle_hashes_ = shingle_hashes, done_callback_ = std::move(done_callback);
+
+ state_ = std::make_unique<ExtractionState>(*page_text_, clock_->NowTicks());
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout,
+ weak_factory_.GetWeakPtr()));
+}
+
+void PhishingTermFeatureExtractor::CancelPendingExtraction() {
+ // Cancel any pending callbacks, and clear our state.
+ weak_factory_.InvalidateWeakPtrs();
+ Clear();
+}
+
+void PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout() {
+ DCHECK(state_.get());
+ ++state_->num_iterations;
+ base::TimeTicks current_chunk_start_time = clock_->NowTicks();
+
+ if (!state_->iterator.get()) {
+ // We failed to initialize the break iterator, so stop now.
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.TermFeatureBreakIterError", 1);
+ RunCallback(false);
+ return;
+ }
+
+ int num_words = 0;
+ while (state_->iterator->Advance()) {
+ if (state_->iterator->IsWord()) {
+ const size_t start = state_->iterator->prev();
+ const size_t length = state_->iterator->pos() - start;
+ HandleWord(base::StringPiece16(page_text_->data() + start, length));
+ ++num_words;
+ }
+
+ if (num_words >= kClockCheckGranularity) {
+ num_words = 0;
+ base::TimeTicks now = clock_->NowTicks();
+ if (now - state_->start_time >=
+ base::TimeDelta::FromMilliseconds(kMaxTotalTimeMs)) {
+ // We expect this to happen infrequently, so record when it does.
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.TermFeatureTimeout", 1);
+ RunCallback(false);
+ return;
+ }
+ base::TimeDelta chunk_elapsed = now - current_chunk_start_time;
+ if (chunk_elapsed >=
+ base::TimeDelta::FromMilliseconds(kMaxTimePerChunkMs)) {
+ // The time limit for the current chunk is up, so post a task to
+ // continue extraction.
+ //
+ // Record how much time we actually spent on the chunk. If this is
+ // much higher than kMaxTimePerChunkMs, we may need to adjust the
+ // clock granularity.
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.TermFeatureChunkTime",
+ chunk_elapsed);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout,
+ weak_factory_.GetWeakPtr()));
+ return;
+ }
+ // Otherwise, continue.
+ }
+ }
+ RunCallback(true);
+}
+
+void PhishingTermFeatureExtractor::HandleWord(const base::StringPiece16& word) {
+ // First, extract shingle hashes.
+ const std::string& word_lower = base::UTF16ToUTF8(base::i18n::ToLower(word));
+ state_->current_shingle.append(word_lower + " ");
+ state_->shingle_word_sizes.push_back(word_lower.size() + 1);
+ if (state_->shingle_word_sizes.size() == shingle_size_) {
+ shingle_hashes_->insert(
+ MurmurHash3String(state_->current_shingle, murmurhash3_seed_));
+ state_->current_shingle.erase(0, state_->shingle_word_sizes.front());
+ state_->shingle_word_sizes.pop_front();
+ }
+ // Check if the size of shingle hashes is over the limit.
+ if (shingle_hashes_->size() > max_shingles_per_page_) {
+ // Pop the largest one.
+ auto it = shingle_hashes_->end();
+ shingle_hashes_->erase(--it);
+ }
+
+ // Next, extract page terms.
+ uint32_t word_hash = MurmurHash3String(word_lower, murmurhash3_seed_);
+
+ // Quick out if the word is not part of any term, which is the common case.
+ if (page_word_hashes_->find(word_hash) == page_word_hashes_->end()) {
+ // Word doesn't exist in our terms so we can clear the n-gram state.
+ state_->previous_words.clear();
+ state_->previous_word_sizes.clear();
+ return;
+ }
+
+ // Find all of the n-grams that we need to check and compute their SHA-256
+ // hashes.
+ std::map<std::string /* hash */, std::string /* plaintext */> hashes_to_check;
+ hashes_to_check[crypto::SHA256HashString(word_lower)] = word_lower;
+
+ // Combine the new word with the previous words to find additional n-grams.
+ // Note that we don't yet add the new word length to previous_word_sizes,
+ // since we don't want to compute the hash for the word by itself again.
+ //
+ state_->previous_words.append(word_lower);
+ std::string current_term = state_->previous_words;
+ for (auto it = state_->previous_word_sizes.begin();
+ it != state_->previous_word_sizes.end(); ++it) {
+ hashes_to_check[crypto::SHA256HashString(current_term)] = current_term;
+ current_term.erase(0, *it);
+ }
+
+ // Add features for any hashes that match page_term_hashes_.
+ for (auto it = hashes_to_check.begin(); it != hashes_to_check.end(); ++it) {
+ if (page_term_hashes_->find(it->first) != page_term_hashes_->end()) {
+ features_->AddBooleanFeature(features::kPageTerm + it->second);
+ }
+ }
+
+ // Now that we have handled the current word, we have to add a space at the
+ // end of it, and add the new word's size (including the space) to
+ // previous_word_sizes. Note: it's possible that the document language
+ // doesn't use ASCII spaces to separate words. That's fine though, we just
+ // need to be consistent with how the model is generated.
+ state_->previous_words.append(" ");
+ state_->previous_word_sizes.push_back(word_lower.size() + 1);
+
+ // Cap the number of previous words.
+ if (state_->previous_word_sizes.size() >= max_words_per_term_) {
+ state_->previous_words.erase(0, state_->previous_word_sizes.front());
+ state_->previous_word_sizes.pop_front();
+ }
+}
+
+void PhishingTermFeatureExtractor::RunCallback(bool success) {
+ // Record some timing stats that we can use to evaluate feature extraction
+ // performance. These include both successful and failed extractions.
+ DCHECK(state_.get());
+ UMA_HISTOGRAM_COUNTS_1M("SBClientPhishing.TermFeatureIterations",
+ state_->num_iterations);
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.TermFeatureTotalTime",
+ clock_->NowTicks() - state_->start_time);
+
+ DCHECK(!done_callback_.is_null());
+ std::move(done_callback_).Run(success);
+ Clear();
+}
+
+void PhishingTermFeatureExtractor::Clear() {
+ page_text_ = nullptr;
+ features_ = nullptr;
+ shingle_hashes_ = nullptr;
+ done_callback_.Reset();
+ state_.reset(nullptr);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h
new file mode 100644
index 00000000000..0193a9232ea
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2011 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.
+//
+// PhishingTermFeatureExtractor handles computing term features from the text
+// of a web page for the client-side phishing detection model. To do this, it
+// takes a list of terms that appear in the model, and scans through the page
+// text looking for them. Any terms that appear will cause a corresponding
+// features::kPageTerm feature to be added to the FeatureMap.
+//
+// To make it harder for a phisher to enumerate all of the relevant terms in
+// the model, the terms are provided as SHA-256 hashes, rather than plain text.
+//
+// There is one PhishingTermFeatureExtractor per RenderView.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_TERM_FEATURE_EXTRACTOR_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_TERM_FEATURE_EXTRACTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_set>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/time/tick_clock.h"
+
+namespace safe_browsing {
+class FeatureMap;
+
+class PhishingTermFeatureExtractor {
+ public:
+ // Callback to be run when feature extraction finishes. The callback
+ // argument is true if extraction was successful, false otherwise.
+ typedef base::OnceCallback<void(bool)> DoneCallback;
+
+ // Creates a PhishingTermFeatureExtractor which will extract features for
+ // all of the terms whose SHA-256 hashes are in |page_term_hashes|. These
+ // terms may be multi-word n-grams, with at most |max_words_per_term| words.
+ //
+ // |page_word_hashes| contains the murmur3 hashes for all of the individual
+ // words that make up the terms. Both sets of strings are UTF-8 encoded and
+ // lowercased prior to hashing. The caller owns both sets of strings, and
+ // must ensure that they are valid until the PhishingTermFeatureExtractor is
+ // destroyed.
+ //
+ // In addition to extracting page terms, we will also extract text shingling
+ // sketch, which consists of hashes of N-gram-words (referred to as shingles)
+ // in the page. |shingle_size| defines N, and |max_shingles_per_page| defines
+ // the maximum number of unique shingle hashes we extracted per page.
+ //
+ // |clock| is used for timing feature extractor operations, and may be mocked
+ // for testing. The caller keeps ownership of the clock.
+ PhishingTermFeatureExtractor(
+ const std::unordered_set<std::string>* page_term_hashes,
+ const std::unordered_set<uint32_t>* page_word_hashes,
+ size_t max_words_per_term,
+ uint32_t murmurhash3_seed,
+ size_t max_shingles_per_page,
+ size_t shingle_size);
+ ~PhishingTermFeatureExtractor();
+
+ // Begins extracting features from |page_text| into the given FeatureMap.
+ // |page_text| should contain the plain text of a web page, including any
+ // subframes, as returned by RenderView::CaptureText().
+ //
+ // To avoid blocking the render thread for too long, the feature extractor
+ // may run in several chunks of work, posting a task to the current
+ // MessageLoop to continue processing. Once feature extraction is complete,
+ // |done_callback| is run on the current thread.
+ // PhishingTermFeatureExtractor takes ownership of the callback.
+ //
+ // |page_text|, |features|, and |shingle_hashes| are owned by the caller,
+ // and must not be destroyed until either |done_callback| is run or
+ // CancelPendingExtraction() is called.
+ void ExtractFeatures(const base::string16* page_text,
+ FeatureMap* features,
+ std::set<uint32_t>* shingle_hashes,
+ DoneCallback done_callback);
+
+ // Cancels any pending feature extraction. The DoneCallback will not be run.
+ // Must be called if there is a feature extraction in progress when the page
+ // is unloaded or the PhishingTermFeatureExtractor is destroyed.
+ void CancelPendingExtraction();
+
+ void SetTickClockForTesting(const base::TickClock* clock) { clock_ = clock; }
+
+ private:
+ struct ExtractionState;
+
+ // The maximum amount of wall time that we will spend on a single extraction
+ // iteration before pausing to let other MessageLoop tasks run.
+ static const int kMaxTimePerChunkMs;
+
+ // The number of words that we will process before checking to see whether
+ // kMaxTimePerChunkMs has elapsed. Since checking the current time can be
+ // slow, we don't do this on every word processed.
+ static const int kClockCheckGranularity;
+
+ // The maximum total amount of time that the feature extractor will run
+ // before giving up on the current page.
+ static const int kMaxTotalTimeMs;
+
+ // Does the actual work of ExtractFeatures. ExtractFeaturesWithTimeout runs
+ // until a predefined maximum amount of time has elapsed, then posts a task
+ // to the current MessageLoop to continue extraction. When extraction
+ // finishes, calls RunCallback().
+ void ExtractFeaturesWithTimeout();
+
+ // Handles a single word in the page text.
+ void HandleWord(const base::StringPiece16& word);
+
+ // Runs |done_callback_| and then clears all internal state.
+ void RunCallback(bool success);
+
+ // Clears all internal feature extraction state.
+ void Clear();
+
+ // All of the term hashes that we are looking for in the page.
+ const std::unordered_set<std::string>* page_term_hashes_;
+
+ // Murmur3 hashes of all the individual words in page_term_hashes_. If
+ // page_term_hashes_ included (hashed) "one" and "one two", page_word_hashes_
+ // would contain (hashed) "one" and "two". We do this so that we can have a
+ // quick out in the common case that the current word we are processing
+ // doesn't contain any part of one of our terms.
+ const std::unordered_set<uint32_t>* page_word_hashes_;
+
+ // The maximum number of words in an n-gram.
+ const size_t max_words_per_term_;
+
+ // The seed for murmurhash3.
+ const uint32_t murmurhash3_seed_;
+
+ // The maximum number of unique shingle hashes we extract in a page.
+ const size_t max_shingles_per_page_;
+
+ // The number of words in a shingle.
+ const size_t shingle_size_;
+
+ // Non-owned pointer to our clock.
+ const base::TickClock* clock_;
+
+ // The output parameters from the most recent call to ExtractFeatures().
+ const base::string16* page_text_; // The caller keeps ownership of this.
+ FeatureMap* features_; // The caller keeps ownership of this.
+ std::set<uint32_t>* shingle_hashes_;
+ DoneCallback done_callback_;
+
+ // Stores the current state of term extraction from |page_text_|.
+ std::unique_ptr<ExtractionState> state_;
+
+ // Used in scheduling ExtractFeaturesWithTimeout tasks.
+ // These pointers are invalidated if extraction is cancelled.
+ base::WeakPtrFactory<PhishingTermFeatureExtractor> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(PhishingTermFeatureExtractor);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_TERM_FEATURE_EXTRACTOR_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc
new file mode 100644
index 00000000000..055a98117f3
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc
@@ -0,0 +1,471 @@
+// Copyright (c) 2012 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/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/murmurhash3_util.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/test_utils.h"
+#include "crypto/sha2.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ASCIIToUTF16;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+static const uint32_t kMurmurHash3Seed = 2777808611U;
+
+namespace safe_browsing {
+
+class MockTickClock : public base::TickClock {
+ public:
+ MockTickClock() = default;
+ ~MockTickClock() override = default;
+
+ MOCK_CONST_METHOD0(NowTicks, base::TimeTicks());
+};
+
+class PhishingTermFeatureExtractorTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ std::unordered_set<std::string> terms;
+ terms.insert("one");
+ terms.insert("one one");
+ terms.insert("two");
+ terms.insert("multi word test");
+ terms.insert("capitalization");
+ terms.insert("space");
+ terms.insert("separator");
+ terms.insert("punctuation");
+ // Chinese (translation of "hello")
+ terms.insert("\xe4\xbd\xa0\xe5\xa5\xbd");
+ // Chinese (translation of "goodbye")
+ terms.insert("\xe5\x86\x8d\xe8\xa7\x81");
+
+ for (auto it = terms.begin(); it != terms.end(); ++it) {
+ term_hashes_.insert(crypto::SHA256HashString(*it));
+ }
+
+ std::unordered_set<std::string> words;
+ words.insert("one");
+ words.insert("two");
+ words.insert("multi");
+ words.insert("word");
+ words.insert("test");
+ words.insert("capitalization");
+ words.insert("space");
+ words.insert("separator");
+ words.insert("punctuation");
+ words.insert("\xe4\xbd\xa0\xe5\xa5\xbd");
+ words.insert("\xe5\x86\x8d\xe8\xa7\x81");
+
+ for (auto it = words.begin(); it != words.end(); ++it) {
+ word_hashes_.insert(MurmurHash3String(*it, kMurmurHash3Seed));
+ }
+
+ ResetExtractor(3 /* max shingles per page */);
+ }
+
+ void ResetExtractor(size_t max_shingles_per_page) {
+ extractor_ = std::make_unique<PhishingTermFeatureExtractor>(
+ &term_hashes_, &word_hashes_, 3 /* max_words_per_term */,
+ kMurmurHash3Seed, max_shingles_per_page, 4 /* shingle_size */);
+ }
+
+ // Runs the TermFeatureExtractor on |page_text|, waiting for the
+ // completion callback. Returns the success boolean from the callback.
+ bool ExtractFeatures(const base::string16* page_text,
+ FeatureMap* features,
+ std::set<uint32_t>* shingle_hashes) {
+ success_ = false;
+ extractor_->ExtractFeatures(
+ page_text, features, shingle_hashes,
+ base::BindOnce(&PhishingTermFeatureExtractorTest::ExtractionDone,
+ base::Unretained(this)));
+ active_run_loop_ = std::make_unique<base::RunLoop>();
+ active_run_loop_->Run();
+ return success_;
+ }
+
+ void PartialExtractFeatures(const base::string16* page_text,
+ FeatureMap* features,
+ std::set<uint32_t>* shingle_hashes) {
+ extractor_->ExtractFeatures(
+ page_text, features, shingle_hashes,
+ base::BindOnce(&PhishingTermFeatureExtractorTest::ExtractionDone,
+ base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PhishingTermFeatureExtractorTest::QuitExtraction,
+ base::Unretained(this)));
+ active_run_loop_ = std::make_unique<base::RunLoop>();
+ active_run_loop_->RunUntilIdle();
+ }
+
+ // Completion callback for feature extraction.
+ void ExtractionDone(bool success) {
+ success_ = success;
+ active_run_loop_->QuitWhenIdle();
+ }
+
+ void QuitExtraction() {
+ extractor_->CancelPendingExtraction();
+ active_run_loop_->QuitWhenIdle();
+ }
+
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ std::unique_ptr<base::RunLoop> active_run_loop_;
+ std::unique_ptr<PhishingTermFeatureExtractor> extractor_;
+ std::unordered_set<std::string> term_hashes_;
+ std::unordered_set<uint32_t> word_hashes_;
+ bool success_; // holds the success value from ExtractFeatures
+};
+
+TEST_F(PhishingTermFeatureExtractorTest, ExtractFeatures) {
+ base::string16 page_text = ASCIIToUTF16("blah");
+ FeatureMap expected_features; // initially empty
+ std::set<uint32_t> expected_shingle_hashes;
+
+ FeatureMap features;
+ std::set<uint32_t> shingle_hashes;
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ page_text = ASCIIToUTF16("one one");
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kPageTerm + std::string("one"));
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("one one"));
+ expected_shingle_hashes.clear();
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ page_text = ASCIIToUTF16("bla bla multi word test bla");
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("multi word test"));
+ expected_shingle_hashes.clear();
+ expected_shingle_hashes.insert(
+ MurmurHash3String("bla bla multi word ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("bla multi word test ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("multi word test bla ", kMurmurHash3Seed));
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ // This text has all of the words for one of the terms, but they are
+ // not in the correct order.
+ page_text = ASCIIToUTF16("bla bla test word multi bla");
+ expected_features.Clear();
+ expected_shingle_hashes.clear();
+ expected_shingle_hashes.insert(
+ MurmurHash3String("bla bla test word ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("bla test word multi ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("test word multi bla ", kMurmurHash3Seed));
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ // Test various separators.
+ page_text = ASCIIToUTF16(
+ "Capitalization plus non-space\n"
+ "separator... punctuation!");
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("capitalization"));
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("space"));
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("separator"));
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("punctuation"));
+ expected_shingle_hashes.clear();
+ expected_shingle_hashes.insert(
+ MurmurHash3String("capitalization plus non space ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("plus non space separator ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("non space separator punctuation ", kMurmurHash3Seed));
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ // Test a page with too many words and we should only 3 minimum hashes.
+ page_text = ASCIIToUTF16("This page has way too many words.");
+ expected_features.Clear();
+ expected_shingle_hashes.clear();
+ expected_shingle_hashes.insert(
+ MurmurHash3String("this page has way ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("page has way too ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("has way too many ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("way too many words ", kMurmurHash3Seed));
+ auto it = expected_shingle_hashes.end();
+ expected_shingle_hashes.erase(--it);
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+ // Test with empty page text.
+ page_text = base::string16();
+ expected_features.Clear();
+ expected_shingle_hashes.clear();
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+
+#if !defined(OS_ANDROID)
+ // The test code is disabled due to http://crbug.com/392234
+ // The client-side detection feature is not enabled on Android yet.
+ // If we decided to enable the feature, we need to fix the bug first.
+
+ // Chinese translation of the phrase "hello goodbye hello goodbye". This tests
+ // that we can correctly separate terms in languages that don't use spaces.
+ page_text = base::UTF8ToUTF16(
+ "\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x86\x8d\xe8\xa7\x81"
+ "\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x86\x8d\xe8\xa7\x81");
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("\xe4\xbd\xa0\xe5\xa5\xbd"));
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("\xe5\x86\x8d\xe8\xa7\x81"));
+ expected_shingle_hashes.clear();
+ expected_shingle_hashes.insert(
+ MurmurHash3String("\xe4\xbd\xa0\xe5\xa5\xbd \xe5\x86\x8d\xe8\xa7\x81 "
+ "\xe4\xbd\xa0\xe5\xa5\xbd \xe5\x86\x8d\xe8\xa7\x81 ",
+ kMurmurHash3Seed));
+
+ features.Clear();
+ shingle_hashes.clear();
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+#endif
+}
+
+TEST_F(PhishingTermFeatureExtractorTest, Continuation) {
+ // For this test, we'll cause the feature extraction to run multiple
+ // iterations by incrementing the clock.
+ ResetExtractor(200 /* max shingles per page */);
+
+ // This page has a total of 30 words. For the features to be computed
+ // correctly, the extractor has to process the entire string of text.
+ base::string16 page_text(ASCIIToUTF16("one "));
+ for (int i = 0; i < 28; ++i) {
+ page_text.append(ASCIIToUTF16(base::StringPrintf("%d ", i)));
+ }
+ page_text.append(ASCIIToUTF16("two"));
+
+ // Advance the clock 3 ms every 5 words processed, 10 ms between chunks.
+ // Note that this assumes kClockCheckGranularity = 5 and
+ // kMaxTimePerChunkMs = 10.
+ base::TimeTicks now = base::TimeTicks::Now();
+ StrictMock<MockTickClock> tick_clock;
+ EXPECT_CALL(tick_clock, NowTicks())
+ // Time check at the start of extraction.
+ .WillOnce(Return(now))
+ // Time check at the start of the first chunk of work.
+ .WillOnce(Return(now))
+ // Time check after the first 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(3)))
+ // Time check after the next 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(6)))
+ // Time check after the next 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(9)))
+ // Time check after the next 5 words. This is over the chunk
+ // time limit, so a continuation task will be posted.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(12)))
+ // Time check at the start of the second chunk of work.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(22)))
+ // Time check after the next 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(25)))
+ // Time check after the next 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(28)))
+ // A final check for the histograms.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(30)));
+ extractor_->SetTickClockForTesting(&tick_clock);
+
+ FeatureMap expected_features;
+ expected_features.AddBooleanFeature(features::kPageTerm + std::string("one"));
+ expected_features.AddBooleanFeature(features::kPageTerm + std::string("two"));
+ std::set<uint32_t> expected_shingle_hashes;
+ expected_shingle_hashes.insert(
+ MurmurHash3String("one 0 1 2 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("0 1 2 3 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("1 2 3 4 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("2 3 4 5 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("3 4 5 6 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("4 5 6 7 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("5 6 7 8 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("6 7 8 9 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("7 8 9 10 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("8 9 10 11 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("9 10 11 12 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("10 11 12 13 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("11 12 13 14 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("12 13 14 15 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("13 14 15 16 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("14 15 16 17 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("15 16 17 18 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("16 17 18 19 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("17 18 19 20 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("18 19 20 21 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("19 20 21 22 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("20 21 22 23 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("21 22 23 24 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("22 23 24 25 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("23 24 25 26 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("24 25 26 27 ", kMurmurHash3Seed));
+ expected_shingle_hashes.insert(
+ MurmurHash3String("25 26 27 two ", kMurmurHash3Seed));
+
+ FeatureMap features;
+ std::set<uint32_t> shingle_hashes;
+ ASSERT_TRUE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
+ // Make sure none of the mock expectations carry over to the next test.
+ ::testing::Mock::VerifyAndClearExpectations(&tick_clock);
+
+ // Now repeat the test with the same text, but advance the clock faster so
+ // that the extraction time exceeds the maximum total time for the feature
+ // extractor. Extraction should fail. Note that this assumes
+ // kMaxTotalTimeMs = 500.
+ EXPECT_CALL(tick_clock, NowTicks())
+ // Time check at the start of extraction.
+ .WillOnce(Return(now))
+ // Time check at the start of the first chunk of work.
+ .WillOnce(Return(now))
+ // Time check after the first 5 words,
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(300)))
+ // Time check at the start of the second chunk of work.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(350)))
+ // Time check after the next 5 words. This is over the limit.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(600)))
+ // A final time check for the histograms.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(620)));
+
+ features.Clear();
+ shingle_hashes.clear();
+ EXPECT_FALSE(ExtractFeatures(&page_text, &features, &shingle_hashes));
+}
+
+TEST_F(PhishingTermFeatureExtractorTest, PartialExtractionTest) {
+ std::unique_ptr<base::string16> page_text(
+ new base::string16(ASCIIToUTF16("one ")));
+ for (int i = 0; i < 28; ++i) {
+ page_text->append(ASCIIToUTF16(base::StringPrintf("%d ", i)));
+ }
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ StrictMock<MockTickClock> tick_clock;
+ EXPECT_CALL(tick_clock, NowTicks())
+ // Time check at the start of extraction.
+ .WillOnce(Return(now))
+ // Time check at the start of the first chunk of work.
+ .WillOnce(Return(now))
+ // Time check after the first 5 words.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(7)))
+ // Time check after the next 5 words. This should be greater than
+ // kMaxTimePerChunkMs so that we stop and schedule extraction for later.
+ .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(14)));
+ extractor_->SetTickClockForTesting(&tick_clock);
+
+ FeatureMap features;
+ std::set<uint32_t> shingle_hashes;
+ // Extract first 10 words then stop.
+ PartialExtractFeatures(page_text.get(), &features, &shingle_hashes);
+
+ page_text.reset(new base::string16());
+ for (int i = 30; i < 58; ++i) {
+ page_text->append(ASCIIToUTF16(base::StringPrintf("%d ", i)));
+ }
+ page_text->append(ASCIIToUTF16("multi word test "));
+ features.Clear();
+ shingle_hashes.clear();
+
+ // This part doesn't exercise the extraction timing.
+ EXPECT_CALL(tick_clock, NowTicks())
+ .WillRepeatedly(Return(base::TimeTicks::Now()));
+
+ // Now extract normally and make sure nothing breaks.
+ EXPECT_TRUE(ExtractFeatures(page_text.get(), &features, &shingle_hashes));
+
+ FeatureMap expected_features;
+ expected_features.AddBooleanFeature(features::kPageTerm +
+ std::string("multi word test"));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.cc
new file mode 100644
index 00000000000..cbd60d19ddf
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 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/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/timer/elapsed_timer.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+
+PhishingUrlFeatureExtractor::PhishingUrlFeatureExtractor() {}
+
+PhishingUrlFeatureExtractor::~PhishingUrlFeatureExtractor() {}
+
+bool PhishingUrlFeatureExtractor::ExtractFeatures(const GURL& url,
+ FeatureMap* features) {
+ base::ElapsedTimer timer;
+ if (url.HostIsIPAddress()) {
+ if (!features->AddBooleanFeature(features::kUrlHostIsIpAddress))
+ return false;
+ } else {
+ // Remove any leading/trailing dots.
+ std::string host;
+ base::TrimString(url.host(), ".", &host);
+
+ // TODO(bryner): Ensure that the url encoding is consistent with
+ // the features in the model.
+
+ // Disallow unknown registries so that we don't classify
+ // partial hostnames (e.g. "www.subdomain").
+ size_t registry_length =
+ net::registry_controlled_domains::GetCanonicalHostRegistryLength(
+ host, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
+ net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+
+ // Check if TLD exists for host.
+ if (registry_length == 0 || registry_length == std::string::npos) {
+ return false;
+ }
+ DCHECK_LT(registry_length, host.size()) << "Non-zero registry length, but "
+ "host is only a TLD: "
+ << host;
+ size_t tld_start = host.size() - registry_length;
+ if (!features->AddBooleanFeature(features::kUrlTldToken +
+ host.substr(tld_start)))
+ return false;
+
+ // Pull off the TLD and the preceeding dot.
+ host.erase(tld_start - 1);
+ std::vector<std::string> host_tokens = base::SplitString(
+ host, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ // Check if domain exists for host.
+ if (host_tokens.empty()) {
+ return false;
+ }
+ if (!features->AddBooleanFeature(features::kUrlDomainToken +
+ host_tokens.back()))
+ return false;
+ host_tokens.pop_back();
+
+ // Now we're just left with the "other" host tokens.
+ for (auto it = host_tokens.begin(); it != host_tokens.end(); ++it) {
+ if (!features->AddBooleanFeature(features::kUrlOtherHostToken + *it))
+ return false;
+ }
+
+ if (host_tokens.size() > 1) {
+ if (!features->AddBooleanFeature(features::kUrlNumOtherHostTokensGTOne))
+ return false;
+ if (host_tokens.size() > 3) {
+ if (!features->AddBooleanFeature(
+ features::kUrlNumOtherHostTokensGTThree))
+ return false;
+ }
+ }
+ }
+
+ std::vector<std::string> long_tokens;
+ SplitStringIntoLongAlphanumTokens(url.path(), &long_tokens);
+ for (const std::string& token : long_tokens) {
+ if (!features->AddBooleanFeature(features::kUrlPathToken + token))
+ return false;
+ }
+
+ UMA_HISTOGRAM_TIMES("SBClientPhishing.URLFeatureTime", timer.Elapsed());
+ return true;
+}
+
+// static
+void PhishingUrlFeatureExtractor::SplitStringIntoLongAlphanumTokens(
+ const std::string& full,
+ std::vector<std::string>* tokens) {
+ // Split on common non-alphanumerics.
+ // TODO(bryner): Split on all(?) non-alphanumerics and handle %XX properly.
+ static const char kTokenSeparators[] = ".,\\/_-|=%:!&";
+ for (const base::StringPiece& token :
+ base::SplitStringPiece(full, kTokenSeparators, base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ // Copy over only the splits that are 3 or more chars long.
+ // TODO(bryner): Determine a meaningful min size.
+ if (token.length() >= kMinPathComponentLength)
+ tokens->push_back(token.as_string());
+ }
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h
new file mode 100644
index 00000000000..3b86c292406
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 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.
+//
+// PhishingUrlFeatureExtractor handles computing URL-based features for
+// the client-side phishing detection model. These include tokens in the
+// host and path, features pertaining to host length, and IP addresses.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_URL_FEATURE_EXTRACTOR_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_URL_FEATURE_EXTRACTOR_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+class GURL;
+
+namespace safe_browsing {
+class FeatureMap;
+
+class PhishingUrlFeatureExtractor {
+ public:
+ PhishingUrlFeatureExtractor();
+ ~PhishingUrlFeatureExtractor();
+
+ // Extracts features for |url| into the given feature map.
+ // Returns true on success.
+ bool ExtractFeatures(const GURL& url, FeatureMap* features);
+
+ private:
+ friend class PhishingUrlFeatureExtractorTest;
+
+ static const size_t kMinPathComponentLength = 3;
+
+ // Given a string, finds all substrings of consecutive alphanumeric
+ // characters of length >= kMinPathComponentLength and inserts them into
+ // tokens.
+ static void SplitStringIntoLongAlphanumTokens(
+ const std::string& full,
+ std::vector<std::string>* tokens);
+
+ DISALLOW_COPY_AND_ASSIGN(PhishingUrlFeatureExtractor);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_PHISHING_URL_FEATURE_EXTRACTOR_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor_unittest.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor_unittest.cc
new file mode 100644
index 00000000000..f5f04a341c6
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 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/safe_browsing/content/renderer/phishing_classifier/phishing_url_feature_extractor.h"
+
+#include <string>
+#include <vector>
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using ::testing::ElementsAre;
+
+namespace safe_browsing {
+
+class PhishingUrlFeatureExtractorTest : public ::testing::Test {
+ protected:
+ PhishingUrlFeatureExtractor extractor_;
+
+ void SplitStringIntoLongAlphanumTokens(const std::string& full,
+ std::vector<std::string>* tokens) {
+ PhishingUrlFeatureExtractor::SplitStringIntoLongAlphanumTokens(full,
+ tokens);
+ }
+
+ void FillFeatureMap(size_t count, FeatureMap* features) {
+ for (size_t i = 0; i < count; ++i) {
+ EXPECT_TRUE(
+ features->AddBooleanFeature(base::StringPrintf("Feature%" PRIuS, i)));
+ }
+ }
+};
+
+TEST_F(PhishingUrlFeatureExtractorTest, ExtractFeatures) {
+ std::string url = "http://123.0.0.1/mydocuments/a.file.html";
+ FeatureMap features;
+
+ // If feature map is already full, features cannot be extracted.
+ FillFeatureMap(FeatureMap::kMaxFeatureMapSize, &features);
+ ASSERT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+ features.Clear();
+
+ FeatureMap expected_features;
+ expected_features.AddBooleanFeature(features::kUrlHostIsIpAddress);
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("mydocuments"));
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("file"));
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("html"));
+
+ ASSERT_TRUE(extractor_.ExtractFeatures(GURL(url), &features));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ // If feature map is already full, features cannot be extracted.
+ features.Clear();
+ FillFeatureMap(FeatureMap::kMaxFeatureMapSize - 1, &features);
+ ASSERT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+ features.Clear();
+
+ url = "http://www.www.cnn.co.uk/sports/sports/index.html?shouldnotappear";
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kUrlTldToken +
+ std::string("co.uk"));
+ expected_features.AddBooleanFeature(features::kUrlDomainToken +
+ std::string("cnn"));
+ expected_features.AddBooleanFeature(features::kUrlOtherHostToken +
+ std::string("www"));
+ expected_features.AddBooleanFeature(features::kUrlNumOtherHostTokensGTOne);
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("sports"));
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("index"));
+ expected_features.AddBooleanFeature(features::kUrlPathToken +
+ std::string("html"));
+
+ features.Clear();
+ ASSERT_TRUE(extractor_.ExtractFeatures(GURL(url), &features));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ features.Clear();
+ // If feature map is already full, features cannot be extracted.
+ FillFeatureMap(FeatureMap::kMaxFeatureMapSize - 5, &features);
+ ASSERT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "http://justadomain.com/";
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kUrlTldToken +
+ std::string("com"));
+ expected_features.AddBooleanFeature(features::kUrlDomainToken +
+ std::string("justadomain"));
+
+ features.Clear();
+ ASSERT_TRUE(extractor_.ExtractFeatures(GURL(url), &features));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ // If feature map is already full, features cannot be extracted.
+ features.Clear();
+ FillFeatureMap(FeatureMap::kMaxFeatureMapSize - 1, &features);
+ ASSERT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "http://witharef.com/#abc";
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kUrlTldToken +
+ std::string("com"));
+ expected_features.AddBooleanFeature(features::kUrlDomainToken +
+ std::string("witharef"));
+
+ features.Clear();
+ ASSERT_TRUE(extractor_.ExtractFeatures(GURL(url), &features));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+
+ url = "http://...www..lotsodots....com./";
+ expected_features.Clear();
+ expected_features.AddBooleanFeature(features::kUrlTldToken +
+ std::string("com"));
+ expected_features.AddBooleanFeature(features::kUrlDomainToken +
+ std::string("lotsodots"));
+ expected_features.AddBooleanFeature(features::kUrlOtherHostToken +
+ std::string("www"));
+
+ features.Clear();
+ ASSERT_TRUE(extractor_.ExtractFeatures(GURL(url), &features));
+ ExpectFeatureMapsAreEqual(features, expected_features);
+ // If feature map is already full, features cannot be extracted.
+ features.Clear();
+ FillFeatureMap(FeatureMap::kMaxFeatureMapSize - 2, &features);
+ ASSERT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "http://unrecognized.tld/";
+ EXPECT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "http://com/123";
+ EXPECT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "http://.co.uk/";
+ EXPECT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "file:///nohost.txt";
+ EXPECT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+
+ url = "not:valid:at:all";
+ EXPECT_FALSE(extractor_.ExtractFeatures(GURL(url), &features));
+}
+
+TEST_F(PhishingUrlFeatureExtractorTest, SplitStringIntoLongAlphanumTokens) {
+ std::string full = "This.is/a_pretty\\unusual-!path,indeed";
+ std::vector<std::string> long_tokens;
+ SplitStringIntoLongAlphanumTokens(full, &long_tokens);
+ EXPECT_THAT(long_tokens,
+ ElementsAre("This", "pretty", "unusual", "path", "indeed"));
+
+ long_tokens.clear();
+ full = "...i-am_re/al&ly\\b,r,o|k=e:n///up%20";
+ SplitStringIntoLongAlphanumTokens(full, &long_tokens);
+ EXPECT_THAT(long_tokens, ElementsAre());
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
new file mode 100644
index 00000000000..d5c75a164f4
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2011 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/safe_browsing/content/renderer/phishing_classifier/scorer.h"
+
+#include <math.h>
+
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
+#include "components/safe_browsing/core/proto/client_model.pb.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "content/public/renderer/render_thread.h"
+#include "crypto/sha2.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace safe_browsing {
+
+namespace {
+// Enum used to keep stats about the status of the Scorer creation.
+enum ScorerCreationStatus {
+ SCORER_SUCCESS,
+ SCORER_FAIL_MODEL_OPEN_FAIL, // Not used anymore
+ SCORER_FAIL_MODEL_FILE_EMPTY, // Not used anymore
+ SCORER_FAIL_MODEL_FILE_TOO_LARGE, // Not used anymore
+ SCORER_FAIL_MODEL_PARSE_ERROR,
+ SCORER_FAIL_MODEL_MISSING_FIELDS,
+ SCORER_STATUS_MAX // Always add new values before this one.
+};
+
+void RecordScorerCreationStatus(ScorerCreationStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.ScorerCreationStatus", status,
+ SCORER_STATUS_MAX);
+}
+
+std::unique_ptr<ClientPhishingRequest> GetMatchingVisualTargetsHelper(
+ const SkBitmap& bitmap,
+ const ClientSideModel& model,
+ std::unique_ptr<ClientPhishingRequest> request) {
+ DCHECK(!content::RenderThread::IsMainThread());
+ for (const VisualTarget& target : model.vision_model().targets()) {
+ base::Optional<VisionMatchResult> result =
+ visual_utils::IsVisualMatch(bitmap, target);
+ if (result.has_value()) {
+ *request->add_vision_match() = result.value();
+ }
+ }
+
+ if (model.has_vision_model()) {
+ // Populate these fields for telementry purposes. They will be filtered in
+ // the browser process if they are not needed.
+ VisualFeatures::BlurredImage blurred_image;
+ if (visual_utils::GetBlurredImage(bitmap, &blurred_image)) {
+ std::string raw_digest = crypto::SHA256HashString(blurred_image.data());
+ request->set_screenshot_digest(
+ base::HexEncode(raw_digest.data(), raw_digest.size()));
+ request->set_screenshot_phash(
+ visual_utils::GetHashFromBlurredImage(blurred_image));
+ request->set_phash_dimension_size(48);
+ }
+ }
+
+ return request;
+}
+
+} // namespace
+
+// Helper function which converts log odds to a probability in the range
+// [0.0,1.0].
+static double LogOdds2Prob(double log_odds) {
+ // 709 = floor(1023*ln(2)). 2**1023 is the largest finite double.
+ // Small log odds aren't a problem. as the odds will be 0. It's only
+ // when we get +infinity for the odds, that odds/(odds+1) would be NaN.
+ if (log_odds >= 709) {
+ return 1.0;
+ }
+ double odds = exp(log_odds);
+ return odds / (odds + 1.0);
+}
+
+Scorer::Scorer() {}
+Scorer::~Scorer() {}
+
+/* static */
+Scorer* Scorer::Create(const base::StringPiece& model_str) {
+ std::unique_ptr<Scorer> scorer(new Scorer());
+ ClientSideModel& model = scorer->model_;
+ // Parse the phishing model.
+ if (!model.ParseFromArray(model_str.data(), model_str.size())) {
+ RecordScorerCreationStatus(SCORER_FAIL_MODEL_PARSE_ERROR);
+ return NULL;
+ } else if (!model.IsInitialized()) {
+ // The model may be missing some required fields.
+ RecordScorerCreationStatus(SCORER_FAIL_MODEL_MISSING_FIELDS);
+ return NULL;
+ }
+ RecordScorerCreationStatus(SCORER_SUCCESS);
+ for (int i = 0; i < model.page_term_size(); ++i) {
+ scorer->page_terms_.insert(model.hashes(model.page_term(i)));
+ }
+ for (int i = 0; i < model.page_word_size(); ++i) {
+ scorer->page_words_.insert(model.page_word(i));
+ }
+ return scorer.release();
+}
+
+double Scorer::ComputeScore(const FeatureMap& features) const {
+ double logodds = 0.0;
+ for (int i = 0; i < model_.rule_size(); ++i) {
+ logodds += ComputeRuleScore(model_.rule(i), features);
+ }
+ return LogOdds2Prob(logodds);
+}
+
+void Scorer::GetMatchingVisualTargets(
+ const SkBitmap& bitmap,
+ std::unique_ptr<ClientPhishingRequest> request,
+ base::OnceCallback<void(std::unique_ptr<ClientPhishingRequest>)> callback)
+ const {
+ DCHECK(content::RenderThread::IsMainThread());
+
+ // Perform scoring off the main thread to avoid blocking.
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, {base::WithBaseSyncPrimitives()},
+ base::BindOnce(&GetMatchingVisualTargetsHelper, bitmap, model_,
+ std::move(request)),
+ std::move(callback));
+}
+
+int Scorer::model_version() const {
+ return model_.version();
+}
+
+const std::unordered_set<std::string>& Scorer::page_terms() const {
+ return page_terms_;
+}
+
+const std::unordered_set<uint32_t>& Scorer::page_words() const {
+ return page_words_;
+}
+
+size_t Scorer::max_words_per_term() const {
+ return model_.max_words_per_term();
+}
+
+uint32_t Scorer::murmurhash3_seed() const {
+ return model_.murmur_hash_seed();
+}
+
+size_t Scorer::max_shingles_per_page() const {
+ return model_.max_shingles_per_page();
+}
+
+size_t Scorer::shingle_size() const {
+ return model_.shingle_size();
+}
+
+float Scorer::threshold_probability() const {
+ return model_.threshold_probability();
+}
+
+double Scorer::ComputeRuleScore(const ClientSideModel::Rule& rule,
+ const FeatureMap& features) const {
+ const std::unordered_map<std::string, double>& feature_map =
+ features.features();
+ double rule_score = 1.0;
+ for (int i = 0; i < rule.feature_size(); ++i) {
+ const auto it = feature_map.find(model_.hashes(rule.feature(i)));
+ if (it == feature_map.end() || it->second == 0.0) {
+ // If the feature of the rule does not exist in the given feature map the
+ // feature weight is considered to be zero. If the feature weight is zero
+ // we leave early since we know that the rule score will be zero.
+ return 0.0;
+ }
+ rule_score *= it->second;
+ }
+ return rule_score * rule.weight();
+}
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
new file mode 100644
index 00000000000..cbfb4f68f04
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 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.
+//
+// This class loads a client-side model and lets you compute a phishing score
+// for a set of previously extracted features. The phishing score corresponds
+// to the probability that the features are indicative of a phishing site.
+//
+// For more details on how the score is actually computed for a given model
+// and a given set of features read the comments in client_model.proto file.
+//
+// See features.h for a list of features that are currently used.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_SCORER_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_SCORER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <unordered_set>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
+#include "components/safe_browsing/core/proto/client_model.pb.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace safe_browsing {
+class FeatureMap;
+
+// Scorer methods are virtual to simplify mocking of this class.
+class Scorer {
+ public:
+ virtual ~Scorer();
+
+ // Factory method which creates a new Scorer object by parsing the given
+ // model. If parsing fails this method returns NULL.
+ static Scorer* Create(const base::StringPiece& model_str);
+
+ // This method computes the probability that the given features are indicative
+ // of phishing. It returns a score value that falls in the range [0.0,1.0]
+ // (range is inclusive on both ends).
+ virtual double ComputeScore(const FeatureMap& features) const;
+
+ // This method matches the given |bitmap| against the visual model. It
+ // modifies |request| appropriately, and returns the new request. This expects
+ // to be called on the renderer main thread, but will perform scoring
+ // asynchronously on a worker thread.
+ virtual void GetMatchingVisualTargets(
+ const SkBitmap& bitmap,
+ std::unique_ptr<ClientPhishingRequest> request,
+ base::OnceCallback<void(std::unique_ptr<ClientPhishingRequest>)> callback)
+ const;
+
+ // Returns the version number of the loaded client model.
+ int model_version() const;
+
+ // -- Accessors used by the page feature extractor ---------------------------
+
+ // Returns a set of hashed page terms that appear in the model in binary
+ // format.
+ const std::unordered_set<std::string>& page_terms() const;
+
+ // Returns a set of hashed page words that appear in the model in binary
+ // format.
+ const std::unordered_set<uint32_t>& page_words() const;
+
+ // Return the maximum number of words per term for the loaded model.
+ size_t max_words_per_term() const;
+
+ // Returns the murmurhash3 seed for the loaded model.
+ uint32_t murmurhash3_seed() const;
+
+ // Return the maximum number of unique shingle hashes per page.
+ size_t max_shingles_per_page() const;
+
+ // Return the number of words in a shingle.
+ size_t shingle_size() const;
+
+ // Returns the threshold probability above which we send a CSD ping.
+ float threshold_probability() const;
+
+ protected:
+ // Most clients should use the factory method. This constructor is public
+ // to allow for mock implementations.
+ Scorer();
+
+ private:
+ friend class PhishingScorerTest;
+
+ // Computes the score for a given rule and feature map. The score is computed
+ // by multiplying the rule weight with the product of feature weights for the
+ // given rule. The feature weights are stored in the feature map. If a
+ // particular feature does not exist in the feature map we set its weight to
+ // zero.
+ double ComputeRuleScore(const ClientSideModel::Rule& rule,
+ const FeatureMap& features) const;
+
+ ClientSideModel model_;
+ std::unordered_set<std::string> page_terms_;
+ std::unordered_set<uint32_t> page_words_;
+
+ base::WeakPtrFactory<Scorer> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(Scorer);
+};
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_RENDERER_PHISHING_CLASSIFIER_SCORER_H_
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc
new file mode 100644
index 00000000000..3b9ae0cd3c4
--- /dev/null
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer_unittest.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 2011 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/safe_browsing/content/renderer/phishing_classifier/scorer.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <unordered_set>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_discardable_memory_allocator.h"
+#include "base/threading/thread.h"
+#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
+#include "components/safe_browsing/core/proto/client_model.pb.h"
+#include "components/safe_browsing/core/proto/csd.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+
+class PhishingScorerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ base::DiscardableMemoryAllocator::SetInstance(&test_allocator_);
+
+ // Setup a simple model. Note that the scorer does not care about
+ // how features are encoded so we use readable strings here to make
+ // the test simpler to follow.
+ model_.Clear();
+ model_.add_hashes("feature1");
+ model_.add_hashes("feature2");
+ model_.add_hashes("feature3");
+ model_.add_hashes("token one");
+ model_.add_hashes("token two");
+
+ ClientSideModel::Rule* rule;
+ rule = model_.add_rule();
+ rule->set_weight(0.5);
+
+ rule = model_.add_rule();
+ rule->add_feature(0); // feature1
+ rule->set_weight(2.0);
+
+ rule = model_.add_rule();
+ rule->add_feature(0); // feature1
+ rule->add_feature(1); // feature2
+ rule->set_weight(3.0);
+
+ model_.add_page_term(3); // token one
+ model_.add_page_term(4); // token two
+
+ // These will be murmur3 hashes, but for this test it's not necessary
+ // that the hashes correspond to actual words.
+ model_.add_page_word(1000U);
+ model_.add_page_word(2000U);
+ model_.add_page_word(3000U);
+
+ model_.set_max_words_per_term(2);
+ model_.set_murmur_hash_seed(12345U);
+ model_.set_max_shingles_per_page(10);
+ model_.set_shingle_size(3);
+
+ // The first target hash is all 1-bits, except the first 8.
+ std::vector<unsigned char> target_hash;
+ target_hash.push_back('\x30');
+ for (int i = 0; i < 288; i++)
+ target_hash.push_back('\xff');
+ target_hash[1] = '\x00';
+ VisualTarget* target1 = model_.mutable_vision_model()->add_targets();
+ target1->set_digest("target1");
+ target1->set_hash(target_hash.data(), target_hash.size());
+ target1->mutable_match_config()->add_match_rule()->set_hash_distance(8.0);
+
+ // The second target hash is all 1-bits, except the second 8.
+ target_hash[1] = '\xff';
+ target_hash[2] = '\x00';
+ VisualTarget* target2 = model_.mutable_vision_model()->add_targets();
+ target2->set_digest("target2");
+ target2->set_hash(target_hash.data(), target_hash.size());
+ target2->mutable_match_config()->add_match_rule()->set_hash_distance(8.0);
+
+ // Allocate a bitmap for testing visual scoring
+ sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB(
+ {2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0},
+ SkNamedGamut::kRec2020);
+ SkImageInfo bitmap_info =
+ SkImageInfo::Make(1000, 1000, SkColorType::kRGBA_8888_SkColorType,
+ SkAlphaType::kUnpremul_SkAlphaType, rec2020);
+
+ ASSERT_TRUE(bitmap_.tryAllocPixels(bitmap_info));
+ }
+
+ void TearDown() override {
+ base::DiscardableMemoryAllocator::SetInstance(nullptr);
+ }
+
+ ClientSideModel model_;
+ SkBitmap bitmap_;
+
+ // A DiscardableMemoryAllocator is needed for certain Skia operations.
+ base::TestDiscardableMemoryAllocator test_allocator_;
+};
+
+TEST_F(PhishingScorerTest, HasValidModel) {
+ std::unique_ptr<Scorer> scorer;
+ scorer.reset(Scorer::Create(model_.SerializeAsString()));
+ EXPECT_TRUE(scorer.get() != NULL);
+
+ // Invalid model string.
+ scorer.reset(Scorer::Create("bogus string"));
+ EXPECT_FALSE(scorer.get());
+
+ // Mode is missing a required field.
+ model_.clear_max_words_per_term();
+ scorer.reset(Scorer::Create(model_.SerializePartialAsString()));
+ EXPECT_FALSE(scorer.get());
+}
+
+TEST_F(PhishingScorerTest, PageTerms) {
+ std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString()));
+ ASSERT_TRUE(scorer.get());
+
+ // Use std::vector instead of std::unordered_set for comparison.
+ // On Android, EXPECT_THAT(..., ContainerEq(...)) doesn't support
+ // std::hash_set, but std::vector works fine.
+ std::vector<std::string> expected_page_terms;
+ expected_page_terms.push_back("token one");
+ expected_page_terms.push_back("token two");
+ std::sort(expected_page_terms.begin(), expected_page_terms.end());
+
+ std::unordered_set<std::string> page_terms = scorer->page_terms();
+ std::vector<std::string> page_terms_v(page_terms.begin(), page_terms.end());
+ std::sort(page_terms_v.begin(), page_terms_v.end());
+
+ EXPECT_THAT(page_terms_v, ::testing::ContainerEq(expected_page_terms));
+}
+
+TEST_F(PhishingScorerTest, PageWords) {
+ std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString()));
+ ASSERT_TRUE(scorer.get());
+ std::vector<uint32_t> expected_page_words;
+ expected_page_words.push_back(1000U);
+ expected_page_words.push_back(2000U);
+ expected_page_words.push_back(3000U);
+ std::sort(expected_page_words.begin(), expected_page_words.end());
+
+ std::unordered_set<uint32_t> page_words = scorer->page_words();
+ std::vector<uint32_t> page_words_v(page_words.begin(), page_words.end());
+ std::sort(page_words_v.begin(), page_words_v.end());
+
+ EXPECT_THAT(page_words_v, ::testing::ContainerEq(expected_page_words));
+
+ EXPECT_EQ(2U, scorer->max_words_per_term());
+ EXPECT_EQ(12345U, scorer->murmurhash3_seed());
+ EXPECT_EQ(10U, scorer->max_shingles_per_page());
+ EXPECT_EQ(3U, scorer->shingle_size());
+}
+
+TEST_F(PhishingScorerTest, ComputeScore) {
+ std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString()));
+ ASSERT_TRUE(scorer.get());
+
+ // An empty feature map should match the empty rule.
+ FeatureMap features;
+ // The expected logodds is 0.5 (empty rule) => p = exp(0.5) / (exp(0.5) + 1)
+ // => 0.62245933120185459
+ EXPECT_DOUBLE_EQ(0.62245933120185459, scorer->ComputeScore(features));
+ // Same if the feature does not match any rule.
+ EXPECT_TRUE(features.AddBooleanFeature("not existing feature"));
+ EXPECT_DOUBLE_EQ(0.62245933120185459, scorer->ComputeScore(features));
+
+ // Feature 1 matches which means that the logodds will be:
+ // 0.5 (empty rule) + 2.0 (rule weight) * 0.15 (feature weight) = 0.8
+ // => p = 0.6899744811276125
+ EXPECT_TRUE(features.AddRealFeature("feature1", 0.15));
+ EXPECT_DOUBLE_EQ(0.6899744811276125, scorer->ComputeScore(features));
+
+ // Now, both feature 1 and feature 2 match. Expected logodds:
+ // 0.5 (empty rule) + 2.0 (rule weight) * 0.15 (feature weight) +
+ // 3.0 (rule weight) * 0.15 (feature1 weight) * 1.0 (feature2) weight = 9.8
+ // => p = 0.99999627336071584
+ EXPECT_TRUE(features.AddBooleanFeature("feature2"));
+ EXPECT_DOUBLE_EQ(0.77729986117469119, scorer->ComputeScore(features));
+}
+
+TEST_F(PhishingScorerTest, GetMatchingVisualTargetsMatchOne) {
+ std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString()));
+
+ // Make the whole image white
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = 0xffffffff;
+
+ // Make the first 164 pixels black. This will make the first 8 bits of the
+ // hash 0.
+ for (int x = 0; x < 164; x++)
+ *bitmap_.getAddr32(x, 0) = 0xff000000;
+
+ base::test::TaskEnvironment task_environment;
+ base::RunLoop run_loop;
+ std::unique_ptr<ClientPhishingRequest> request =
+ std::make_unique<ClientPhishingRequest>();
+ scorer->GetMatchingVisualTargets(
+ bitmap_, std::move(request),
+ base::BindLambdaForTesting(
+ [&](std::unique_ptr<ClientPhishingRequest> request) {
+ ASSERT_EQ(request->vision_match_size(), 1);
+ EXPECT_EQ(request->vision_match(0).matched_target_digest(),
+ "target1");
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+}
+
+TEST_F(PhishingScorerTest, GetMatchingVisualTargetsMatchBoth) {
+ std::unique_ptr<Scorer> scorer(Scorer::Create(model_.SerializeAsString()));
+
+ // Make the whole image white
+ for (int x = 0; x < 1000; x++)
+ for (int y = 0; y < 1000; y++)
+ *bitmap_.getAddr32(x, y) = 0xffffffff;
+
+ // Create an alternating black/white pattern to match both targets. The
+ // pattern is 84 black pixels, then 84 white, then 84 black, then 84 white.
+ // This causes the hash to start 0F0F, for a distance of 8 from both targets.
+ for (int x = 0; x < 84; x++)
+ *bitmap_.getAddr32(x, 0) = 0xff000000;
+
+ for (int x = 168; x < 248; x++)
+ *bitmap_.getAddr32(x, 0) = 0xff000000;
+
+ base::test::TaskEnvironment task_environment;
+ base::RunLoop run_loop;
+ std::unique_ptr<ClientPhishingRequest> request =
+ std::make_unique<ClientPhishingRequest>();
+ scorer->GetMatchingVisualTargets(
+ bitmap_, std::move(request),
+ base::BindLambdaForTesting(
+ [&](std::unique_ptr<ClientPhishingRequest> request) {
+ ASSERT_EQ(request->vision_match_size(), 2);
+ EXPECT_EQ(request->vision_match(0).matched_target_digest(),
+ "target1");
+ EXPECT_EQ(request->vision_match(1).matched_target_digest(),
+ "target2");
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
index d9fef3975a1..4d55669d995 100644
--- a/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
+++ b/chromium/components/safe_browsing/content/renderer/websocket_sb_handshake_throttle.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc b/chromium/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
index 5515555e348..d77b739bae7 100644
--- a/chromium/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
+++ b/chromium/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
@@ -6,7 +6,6 @@
#include "base/metrics/field_trial_params.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/test_simple_task_runner.h"
#include "build/build_config.h"
#include "components/prefs/testing_pref_service.h"
diff --git a/chromium/components/safe_browsing/content/web_ui/BUILD.gn b/chromium/components/safe_browsing/content/web_ui/BUILD.gn
index f176fdbc320..9750b755a59 100644
--- a/chromium/components/safe_browsing/content/web_ui/BUILD.gn
+++ b/chromium/components/safe_browsing/content/web_ui/BUILD.gn
@@ -21,12 +21,10 @@ static_library("web_ui") {
"//components/safe_browsing/core:features",
"//components/safe_browsing/core:public",
"//components/safe_browsing/core:realtimeapi_proto",
- "//components/safe_browsing/core:webprotect_proto",
"//components/safe_browsing/core/browser:network_context",
"//components/safe_browsing/core/browser:referrer_chain_provider",
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//components/safe_browsing/core/db:v4_local_database_manager",
- "//components/safe_browsing/core/realtime:policy_engine",
"//components/safe_browsing/core/web_ui:constants",
"//components/strings:components_strings_grit",
"//components/sync/protocol:protocol",
diff --git a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
index 75689ec8485..52de5bf1d31 100644
--- a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
+++ b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.html
@@ -6,6 +6,7 @@
<link rel="stylesheet" href="safe_browsing.css">
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="chrome://resources/css/tabs.css">
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/util.js"></script>
@@ -92,7 +93,6 @@
</tabpanel>
<tabpanel>
<h2>RT Lookup Pings</h2>
- <p id="rt-lookup-experiment-enabled" class="result-container"></p>
<table id="rt-lookup-ping-list" class="request-response"></table>
</tabpanel>
<tabpanel>
diff --git a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
index f5ec1b4274d..c846c671d8f 100644
--- a/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
+++ b/chromium/components/safe_browsing/content/web_ui/resources/safe_browsing.js
@@ -111,9 +111,6 @@ cr.define('safe_browsing', function() {
addRTLookupResponse(result);
});
- cr.sendWithPromise('getRTLookupExperimentEnabled', [])
- .then((enabled) => addRTLookupExperimentEnabled(enabled));
-
cr.sendWithPromise('getLogMessages', []).then((logMessages) => {
logMessages.forEach(function(message) {
addLogMessage(message);
@@ -323,12 +320,6 @@ cr.define('safe_browsing', function() {
}
}
- function addRTLookupExperimentEnabled(enabled) {
- const enabledFormatted = $('rt-lookup-template').content.cloneNode(true);
- enabledFormatted.querySelector('#experiment-bool').textContent = enabled;
- $('rt-lookup-experiment-enabled').appendChild(enabledFormatted);
- }
-
function addLogMessage(result) {
const logDiv = $('log-messages');
const eventFormatted = "[" + (new Date(result["time"])).toLocaleString() +
diff --git a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index 68db04feb80..4439f54c01b 100644
--- a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -35,9 +35,7 @@
#include "services/network/public/mojom/cookie_manager.mojom.h"
#if BUILDFLAG(FULL_SAFE_BROWSING)
#include "components/enterprise/common/proto/connectors.pb.h"
-#include "components/safe_browsing/core/proto/webprotect.pb.h"
#endif
-#include "components/safe_browsing/core/realtime/policy_engine.h"
#include "components/safe_browsing/core/web_ui/constants.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_prefs/user_prefs.h"
@@ -260,25 +258,6 @@ void WebUIInfoSingleton::ClearReportingEvents() {
#if BUILDFLAG(FULL_SAFE_BROWSING)
void WebUIInfoSingleton::AddToDeepScanRequests(
- const DeepScanningClientRequest& request) {
- if (!HasListener())
- return;
-
- // Only update the request time the first time we see a token.
- if (deep_scan_requests_.find(request.request_token()) ==
- deep_scan_requests_.end()) {
- deep_scan_requests_[request.request_token()].request_time =
- base::Time::Now();
- }
-
- deep_scan_requests_[request.request_token()].request = request;
-
- for (auto* webui_listener : webui_instances_)
- webui_listener->NotifyDeepScanJsListener(
- request.request_token(), deep_scan_requests_[request.request_token()]);
-}
-
-void WebUIInfoSingleton::AddToDeepScanRequests(
const GURL& tab_url,
const enterprise_connectors::ContentAnalysisRequest& request) {
if (!HasListener())
@@ -292,8 +271,7 @@ void WebUIInfoSingleton::AddToDeepScanRequests(
}
deep_scan_requests_[request.request_token()].tab_url = tab_url;
- deep_scan_requests_[request.request_token()].content_analysis_request =
- request;
+ deep_scan_requests_[request.request_token()].request = request;
for (auto* webui_listener : webui_instances_)
webui_listener->NotifyDeepScanJsListener(
@@ -303,28 +281,13 @@ void WebUIInfoSingleton::AddToDeepScanRequests(
void WebUIInfoSingleton::AddToDeepScanResponses(
const std::string& token,
const std::string& status,
- const DeepScanningClientResponse& response) {
- if (!HasListener())
- return;
-
- deep_scan_requests_[token].response_time = base::Time::Now();
- deep_scan_requests_[token].response_status = status;
- deep_scan_requests_[token].response = response;
-
- for (auto* webui_listener : webui_instances_)
- webui_listener->NotifyDeepScanJsListener(token, deep_scan_requests_[token]);
-}
-
-void WebUIInfoSingleton::AddToDeepScanResponses(
- const std::string& token,
- const std::string& status,
const enterprise_connectors::ContentAnalysisResponse& response) {
if (!HasListener())
return;
deep_scan_requests_[token].response_time = base::Time::Now();
deep_scan_requests_[token].response_status = status;
- deep_scan_requests_[token].content_analysis_response = response;
+ deep_scan_requests_[token].response = response;
for (auto* webui_listener : webui_instances_)
webui_listener->NotifyDeepScanJsListener(token, deep_scan_requests_[token]);
@@ -1437,64 +1400,6 @@ std::string SerializeContentAnalysisRequest(
return request_serialized;
}
-std::string SerializeDeepScanningRequest(
- const DeepScanningClientRequest& request) {
- base::DictionaryValue request_dict;
-
- request_dict.SetKey("dm_token", base::Value(request.dm_token()));
- request_dict.SetKey("fcm_notification_token",
- base::Value(request.fcm_notification_token()));
-
- if (request.has_malware_scan_request()) {
- base::DictionaryValue malware_request;
-
- switch (request.malware_scan_request().population()) {
- case MalwareDeepScanningClientRequest::POPULATION_UNKNOWN:
- malware_request.SetStringKey("population", "POPULATION_UNKNOWN");
- break;
- case MalwareDeepScanningClientRequest::POPULATION_ENTERPRISE:
- malware_request.SetStringKey("population", "POPULATION_ENTERPRISE");
- break;
- case MalwareDeepScanningClientRequest::POPULATION_TITANIUM:
- malware_request.SetStringKey("population", "POPULATION_TITANIUM");
- break;
- }
-
- request_dict.SetKey("malware_scan_request", std::move(malware_request));
- }
-
- if (request.has_dlp_scan_request()) {
- base::DictionaryValue dlp_request;
-
- switch (request.dlp_scan_request().content_source()) {
- case DlpDeepScanningClientRequest::CONTENT_SOURCE_UNKNOWN:
- dlp_request.SetStringKey("content_source", "CONTENT_SOURCE_UNKNOWN");
- break;
- case DlpDeepScanningClientRequest::FILE_DOWNLOAD:
- dlp_request.SetStringKey("content_source", "FILE_DOWNLOAD");
- break;
- case DlpDeepScanningClientRequest::FILE_UPLOAD:
- dlp_request.SetStringKey("content_source", "FILE_UPLOAD");
- break;
- case DlpDeepScanningClientRequest::WEB_CONTENT_UPLOAD:
- dlp_request.SetStringKey("content_source", "WEB_CONTENT_UPLOAD");
- break;
- }
-
- request_dict.SetKey("dlp_scan_request", std::move(dlp_request));
- }
-
- request_dict.SetKey("request_token", base::Value(request.request_token()));
- request_dict.SetKey("filename", base::Value(request.filename()));
- request_dict.SetKey("digest", base::Value(request.digest()));
-
- std::string request_serialized;
- JSONStringValueSerializer serializer(&request_serialized);
- serializer.set_pretty_print(true);
- serializer.Serialize(request_dict);
- return request_serialized;
-}
-
std::string SerializeContentAnalysisResponse(
const enterprise_connectors::ContentAnalysisResponse& response) {
base::DictionaryValue response_dict;
@@ -1553,103 +1458,6 @@ std::string SerializeContentAnalysisResponse(
return response_serialized;
}
-std::string SerializeDeepScanningResponse(
- const DeepScanningClientResponse& response) {
- base::DictionaryValue response_dict;
-
- response_dict.SetStringKey("token", response.token());
-
- if (response.has_malware_scan_verdict()) {
- base::DictionaryValue malware_verdict;
-
- switch (response.malware_scan_verdict().verdict()) {
- case MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED:
- malware_verdict.SetStringKey("verdict", "VERDICT_UNSPECIFIED");
- break;
- case MalwareDeepScanningVerdict::CLEAN:
- malware_verdict.SetStringKey("verdict", "CLEAN");
- break;
- case MalwareDeepScanningVerdict::UWS:
- malware_verdict.SetStringKey("verdict", "UWS");
- break;
- case MalwareDeepScanningVerdict::MALWARE:
- malware_verdict.SetStringKey("verdict", "MALWARE");
- break;
- case MalwareDeepScanningVerdict::SCAN_FAILURE:
- malware_verdict.SetStringKey("verdict", "SCAN_FAILURE");
- break;
- }
-
- response_dict.SetKey("malware_scan_verdict", std::move(malware_verdict));
- }
-
- if (response.has_dlp_scan_verdict()) {
- base::DictionaryValue dlp_verdict;
-
- switch (response.dlp_scan_verdict().status()) {
- case DlpDeepScanningVerdict::STATUS_UNKNOWN:
- dlp_verdict.SetStringKey("status", "STATUS_UNKNOWN");
- break;
- case DlpDeepScanningVerdict::SUCCESS:
- dlp_verdict.SetStringKey("status", "SUCCESS");
- break;
- case DlpDeepScanningVerdict::FAILURE:
- dlp_verdict.SetStringKey("status", "FAILURE");
- break;
- }
-
- base::ListValue triggered_rules;
- for (const DlpDeepScanningVerdict::TriggeredRule& rule :
- response.dlp_scan_verdict().triggered_rules()) {
- base::DictionaryValue rule_value;
-
- switch (rule.action()) {
- case DlpDeepScanningVerdict::TriggeredRule::ACTION_UNKNOWN:
- rule_value.SetStringKey("action", "ACTION_UNKNOWN");
- break;
- case DlpDeepScanningVerdict::TriggeredRule::REPORT_ONLY:
- rule_value.SetStringKey("action", "REPORT_ONLY");
- break;
- case DlpDeepScanningVerdict::TriggeredRule::WARN:
- rule_value.SetStringKey("action", "WARN");
- break;
- case DlpDeepScanningVerdict::TriggeredRule::BLOCK:
- rule_value.SetStringKey("action", "BLOCK");
- break;
- }
-
- rule_value.SetStringKey("rule_name", rule.rule_name());
- rule_value.SetDoubleKey("rule_id", rule.rule_id());
- rule_value.SetStringKey("rule_resource_name", rule.rule_resource_name());
- rule_value.SetStringKey("rule_severity", rule.rule_severity());
-
- base::ListValue matched_detectors;
- for (const DlpDeepScanningVerdict::MatchedDetector& detector :
- rule.matched_detectors()) {
- base::DictionaryValue detector_value;
- detector_value.SetStringKey("detector_id", detector.detector_id());
- detector_value.SetStringKey("display_name", detector.display_name());
- detector_value.SetStringKey("detector_type", detector.detector_type());
- matched_detectors.Append(std::move(detector_value));
- }
-
- rule_value.SetKey("matched_detectors", std::move(matched_detectors));
-
- triggered_rules.Append(std::move(rule_value));
- }
-
- dlp_verdict.SetKey("triggered_rules", std::move(triggered_rules));
-
- response_dict.SetKey("dlp_scan_verdict", std::move(dlp_verdict));
- }
-
- std::string response_serialized;
- JSONStringValueSerializer serializer(&response_serialized);
- serializer.set_pretty_print(true);
- serializer.Serialize(response_dict);
- return response_serialized;
-}
-
base::Value SerializeDeepScanDebugData(const std::string& token,
const DeepScanDebugData& data) {
base::DictionaryValue value;
@@ -1660,12 +1468,8 @@ base::Value SerializeDeepScanDebugData(const std::string& token,
}
if (data.request.has_value()) {
- value.SetStringKey("request",
- SerializeDeepScanningRequest(data.request.value()));
- } else if (data.content_analysis_request.has_value()) {
- value.SetStringKey(
- "request", SerializeContentAnalysisRequest(
- data.tab_url, data.content_analysis_request.value()));
+ value.SetStringKey("request", SerializeContentAnalysisRequest(
+ data.tab_url, data.request.value()));
}
if (!data.response_time.is_null()) {
@@ -1678,10 +1482,7 @@ base::Value SerializeDeepScanDebugData(const std::string& token,
if (data.response.has_value()) {
value.SetStringKey("response",
- SerializeDeepScanningResponse(data.response.value()));
- } else if (data.content_analysis_response.has_value()) {
- value.SetStringKey("response", SerializeContentAnalysisResponse(
- data.content_analysis_response.value()));
+ SerializeContentAnalysisResponse(data.response.value()));
}
return std::move(value);
@@ -1992,17 +1793,6 @@ void SafeBrowsingUIHandler::GetRTLookupResponses(const base::ListValue* args) {
ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
}
-void SafeBrowsingUIHandler::GetRTLookupExperimentEnabled(
- const base::ListValue* args) {
- base::ListValue value;
- value.Append(base::Value(RealTimePolicyEngine::IsUrlLookupEnabled()));
-
- AllowJavascript();
- std::string callback_id;
- args->GetString(0, &callback_id);
- ResolveJavascriptCallback(base::Value(callback_id), value);
-}
-
void SafeBrowsingUIHandler::GetReferrerChain(const base::ListValue* args) {
std::string url_string;
args->GetString(1, &url_string);
@@ -2240,10 +2030,6 @@ void SafeBrowsingUIHandler::RegisterMessages() {
base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupResponses,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
- "getRTLookupExperimentEnabled",
- base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupExperimentEnabled,
- base::Unretained(this)));
- web_ui()->RegisterMessageCallback(
"getLogMessages",
base::BindRepeating(&SafeBrowsingUIHandler::GetLogMessages,
base::Unretained(this)));
diff --git a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
index e363c8c7eb1..e35375a11f3 100644
--- a/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
+++ b/chromium/components/safe_browsing/content/web_ui/safe_browsing_ui.h
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "components/enterprise/common/proto/connectors.pb.h"
#include "components/safe_browsing/buildflags.h"
#include "components/safe_browsing/core/browser/safe_browsing_network_context.h"
#include "components/safe_browsing/core/proto/csd.pb.h"
@@ -23,7 +22,7 @@
#include "services/network/public/mojom/network_context.mojom.h"
#if BUILDFLAG(FULL_SAFE_BROWSING)
-#include "components/safe_browsing/core/proto/webprotect.pb.h"
+#include "components/enterprise/common/proto/connectors.pb.h"
#endif
namespace base {
@@ -43,16 +42,12 @@ struct DeepScanDebugData {
~DeepScanDebugData();
base::Time request_time;
- base::Optional<DeepScanningClientRequest> request;
- base::Optional<enterprise_connectors::ContentAnalysisRequest>
- content_analysis_request;
+ base::Optional<enterprise_connectors::ContentAnalysisRequest> request;
GURL tab_url;
base::Time response_time;
std::string response_status;
- base::Optional<DeepScanningClientResponse> response;
- base::Optional<enterprise_connectors::ContentAnalysisResponse>
- content_analysis_response;
+ base::Optional<enterprise_connectors::ContentAnalysisResponse> response;
};
#endif
@@ -128,10 +123,6 @@ class SafeBrowsingUIHandler : public content::WebUIMessageHandler {
// currently open chrome://safe-browsing tab was opened.
void GetRTLookupResponses(const base::ListValue* args);
- // Show whether real time lookup experiment is enabled. This is useful for
- // testing on Android, because it also takes memory threshold into account.
- void GetRTLookupExperimentEnabled(const base::ListValue* args);
-
// Get the current referrer chain for a given URL.
void GetReferrerChain(const base::ListValue* args);
@@ -335,16 +326,12 @@ class WebUIInfoSingleton {
// chrome://safe-browsing tabs. Uses |request.request_token()| as an
// identifier that can be used in |AddToDeepScanResponses| to correlate a ping
// and response.
- void AddToDeepScanRequests(const DeepScanningClientRequest& request);
void AddToDeepScanRequests(
const GURL& tab_url,
const enterprise_connectors::ContentAnalysisRequest& request);
// Add the new response to |deep_scan_requests_| and send it to all the open
// chrome://safe-browsing tabs.
- void AddToDeepScanResponses(const std::string& token,
- const std::string& status,
- const DeepScanningClientResponse& response);
void AddToDeepScanResponses(
const std::string& token,
const std::string& status,
diff --git a/chromium/components/safe_browsing/core/BUILD.gn b/chromium/components/safe_browsing/core/BUILD.gn
index 65ef314d0e7..72435c8c0ff 100644
--- a/chromium/components/safe_browsing/core/BUILD.gn
+++ b/chromium/components/safe_browsing/core/BUILD.gn
@@ -40,10 +40,6 @@ proto_library("realtimeapi_proto") {
deps = [ ":csd_proto" ]
}
-proto_library("webprotect_proto") {
- sources = [ "proto/webprotect.proto" ]
-}
-
proto_library("client_model_proto") {
proto_in_dir = "//"
sources = [ "proto/client_model.proto" ]
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
index 6c649ace3f3..9c4b1c7a2fa 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -170,7 +170,8 @@ void SafeBrowsingUrlCheckerImpl::CheckUrl(const GURL& url,
security_interstitials::UnsafeResource
SafeBrowsingUrlCheckerImpl::MakeUnsafeResource(const GURL& url,
SBThreatType threat_type,
- const ThreatMetadata& metadata) {
+ const ThreatMetadata& metadata,
+ bool is_from_real_time_check) {
security_interstitials::UnsafeResource resource;
resource.url = url;
resource.original_url = urls_[0].url;
@@ -191,7 +192,9 @@ SafeBrowsingUrlCheckerImpl::MakeUnsafeResource(const GURL& url,
base::CreateSingleThreadTaskRunner(CreateTaskTraits(ThreadID::IO));
resource.web_contents_getter = web_contents_getter_;
resource.web_state_getter = web_state_getter_;
- resource.threat_source = database_manager_->GetThreatSource();
+ resource.threat_source = is_from_real_time_check
+ ? ThreatSource::REAL_TIME_CHECK
+ : database_manager_->GetThreatSource();
return resource;
}
@@ -199,12 +202,13 @@ void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult(
const GURL& url,
SBThreatType threat_type,
const ThreatMetadata& metadata) {
- OnUrlResult(url, threat_type, metadata);
+ OnUrlResult(url, threat_type, metadata, /*is_from_real_time_check=*/false);
}
void SafeBrowsingUrlCheckerImpl::OnUrlResult(const GURL& url,
SBThreatType threat_type,
- const ThreatMetadata& metadata) {
+ const ThreatMetadata& metadata,
+ bool is_from_real_time_check) {
DCHECK_EQ(STATE_CHECKING_URL, state_);
DCHECK_LT(next_index_, urls_.size());
DCHECK_EQ(urls_[next_index_].url, url);
@@ -225,7 +229,8 @@ void SafeBrowsingUrlCheckerImpl::OnUrlResult(const GURL& url,
// happens. Create an interaction observer and continue like there wasn't
// a warning. The observer will create the interstitial when necessary.
security_interstitials::UnsafeResource unsafe_resource =
- MakeUnsafeResource(url, threat_type, metadata);
+ MakeUnsafeResource(url, threat_type, metadata,
+ is_from_real_time_check);
unsafe_resource.is_delayed_warning = true;
url_checker_delegate_
->StartObservingInteractionsForDelayedBlockingPageHelper(
@@ -271,7 +276,7 @@ void SafeBrowsingUrlCheckerImpl::OnUrlResult(const GURL& url,
UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_);
security_interstitials::UnsafeResource resource =
- MakeUnsafeResource(url, threat_type, metadata);
+ MakeUnsafeResource(url, threat_type, metadata, is_from_real_time_check);
state_ = STATE_DISPLAYING_BLOCKING_PAGE;
url_checker_delegate_->StartDisplayingBlockingPageHelper(
@@ -290,7 +295,7 @@ void SafeBrowsingUrlCheckerImpl::OnTimeout() {
weak_factory_.InvalidateWeakPtrs();
OnUrlResult(urls_[next_index_].url, safe_browsing::SB_THREAT_TYPE_SAFE,
- ThreatMetadata());
+ ThreatMetadata(), /*is_from_real_time_check=*/false);
}
void SafeBrowsingUrlCheckerImpl::CheckUrlImpl(const GURL& url,
@@ -567,7 +572,8 @@ void SafeBrowsingUrlCheckerImpl::PerformHashBasedCheck(const GURL& url) {
url, url_checker_delegate_->GetThreatTypes(), this)) {
// No match found in the local database. Safe to call |OnUrlResult| here
// directly.
- OnUrlResult(url, SB_THREAT_TYPE_SAFE, ThreatMetadata());
+ OnUrlResult(url, SB_THREAT_TYPE_SAFE, ThreatMetadata(),
+ /*is_from_real_time_check=*/false);
}
}
@@ -618,10 +624,10 @@ void SafeBrowsingUrlCheckerImpl::OnRTLookupResponse(
response->threat_info(0).threat_type());
}
if (is_cached_response && sb_threat_type == SB_THREAT_TYPE_SAFE) {
- // TODO(vakh): Add a UMA metric.
PerformHashBasedCheck(url);
} else {
- OnUrlResult(url, sb_threat_type, ThreatMetadata());
+ OnUrlResult(url, sb_threat_type, ThreatMetadata(),
+ /*is_from_real_time_check=*/true);
}
}
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
index cd6ad9ec81b..0a02615d051 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
@@ -149,7 +149,8 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
void OnUrlResult(const GURL& url,
SBThreatType threat_type,
- const ThreatMetadata& metadata);
+ const ThreatMetadata& metadata,
+ bool is_from_real_time_check);
void CheckUrlImpl(const GURL& url,
const std::string& method,
@@ -211,7 +212,8 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
security_interstitials::UnsafeResource MakeUnsafeResource(
const GURL& url,
SBThreatType threat_type,
- const ThreatMetadata& metadata);
+ const ThreatMetadata& metadata,
+ bool is_from_real_time_check);
enum State {
// Haven't started checking or checking is complete.
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
index 7838044969f..2e296884b78 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
@@ -24,6 +24,15 @@ using ::testing::_;
namespace safe_browsing {
+namespace {
+
+// A matcher for threat source in UnsafeResource.
+MATCHER_P(IsSameThreatSource, threatSource, "") {
+ return arg.threat_source == threatSource;
+}
+
+} // namespace
+
class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
public:
MockSafeBrowsingDatabaseManager() = default;
@@ -274,7 +283,8 @@ TEST_F(SafeBrowsingUrlCheckerTest, CheckUrl_DangerousUrl) {
EXPECT_CALL(callback,
Run(_, /*proceed=*/false, /*showed_interstitial=*/false));
EXPECT_CALL(*url_checker_delegate_,
- StartDisplayingBlockingPageHelper(_, _, _, _, _))
+ StartDisplayingBlockingPageHelper(
+ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _, _))
.Times(1);
safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get());
task_environment_->RunUntilIdle();
@@ -365,7 +375,8 @@ TEST_F(SafeBrowsingUrlCheckerTest, CheckUrl_RealTimeEnabledAllowlistMatch) {
// while we perform a real time URL check.
EXPECT_CALL(callback, Run(_, _, _)).Times(0);
EXPECT_CALL(*url_checker_delegate_,
- StartDisplayingBlockingPageHelper(_, _, _, _, _))
+ StartDisplayingBlockingPageHelper(
+ IsSameThreatSource(ThreatSource::UNKNOWN), _, _, _, _))
.Times(1);
safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get());
@@ -403,8 +414,10 @@ TEST_F(SafeBrowsingUrlCheckerTest,
base::MockCallback<SafeBrowsingUrlCheckerImpl::NativeCheckUrlCallback>
callback;
// Should still show blocking page because real time lookup is enabled.
- EXPECT_CALL(*url_checker_delegate_,
- StartDisplayingBlockingPageHelper(_, _, _, _, _))
+ EXPECT_CALL(
+ *url_checker_delegate_,
+ StartDisplayingBlockingPageHelper(
+ IsSameThreatSource(ThreatSource::REAL_TIME_CHECK), _, _, _, _))
.Times(1);
safe_browsing_url_checker->CheckUrl(url, "GET", callback.Get());
diff --git a/chromium/components/safe_browsing/core/common/BUILD.gn b/chromium/components/safe_browsing/core/common/BUILD.gn
index 29d87017307..4f1a5d66d08 100644
--- a/chromium/components/safe_browsing/core/common/BUILD.gn
+++ b/chromium/components/safe_browsing/core/common/BUILD.gn
@@ -45,6 +45,7 @@ source_set("unit_tests") {
"safe_browsing_policy_handler_unittest.cc",
"safe_browsing_prefs_unittest.cc",
]
+
deps = [
":safe_browsing_policy_handler",
":safe_browsing_prefs",
@@ -58,6 +59,14 @@ source_set("unit_tests") {
"//testing/gtest",
"//url:url",
]
+
+ if (safe_browsing_mode == 1) {
+ sources += [ "visual_utils_unittest.cc" ]
+ deps += [
+ ":common",
+ "//ui/gfx:color_utils",
+ ]
+ }
}
source_set("common") {
@@ -82,6 +91,18 @@ source_set("common") {
"//url/ipc:url_ipc",
]
+ if (safe_browsing_mode == 1 || safe_browsing_mode == 2) {
+ sources += [
+ "visual_utils.cc",
+ "visual_utils.h",
+ ]
+ deps += [
+ "//components/safe_browsing/core:client_model_proto",
+ "//third_party/opencv:emd",
+ "//ui/gfx:color_utils",
+ ]
+ }
+
public_deps = [ ":interfaces" ]
if (!is_ios) {
diff --git a/chromium/components/safe_browsing/core/common/DEPS b/chromium/components/safe_browsing/core/common/DEPS
index bfcfa352d35..0e74e3e375b 100644
--- a/chromium/components/safe_browsing/core/common/DEPS
+++ b/chromium/components/safe_browsing/core/common/DEPS
@@ -8,5 +8,8 @@ include_rules = [
"+content/public/test",
"+crypto/sha2.h",
"+ipc",
+ "+third_party/opencv",
+ "+third_party/skia/include",
+ "+ui/gfx",
"+url"
]
diff --git a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
index 21058a1c9b9..6ee73283658 100644
--- a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
+++ b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -96,30 +96,10 @@ const char kPasswordProtectionWarningTrigger[] =
"safebrowsing.password_protection_warning_trigger";
const char kAdvancedProtectionLastRefreshInUs[] =
"safebrowsing.advanced_protection_last_refresh";
-const char kSafeBrowsingSendFilesForMalwareCheck[] =
- "safebrowsing.send_files_for_malware_check";
-const char kUnsafeEventsReportingEnabled[] =
- "safebrowsing.unsafe_events_reporting";
-const char kBlockLargeFileTransfer[] =
- "safebrowsing.block_large_file_transfers";
-const char kDelayDeliveryUntilVerdict[] =
- "safebrowsing.delay_delivery_until_verdict";
-const char kAllowPasswordProtectedFiles[] =
- "safebrowsing.allow_password_protected_files";
-const char kCheckContentCompliance[] = "safebrowsing.check_content_compliance";
-const char kBlockUnsupportedFiletypes[] =
- "safebrowsing.block_unsupported_filetypes";
-const char kURLsToCheckComplianceOfDownloadedContent[] =
- "safebrowsing.urls_to_check_compliance_of_downloaded_content";
-const char kURLsToCheckForMalwareOfUploadedContent[] =
- "safebrowsing.urls_to_check_for_malware_of_uploaded_content";
-const char kURLsToNotCheckForMalwareOfDownloadedContent[] =
- "safebrowsing.urls_to_not_check_for_malware_of_downloaded_content";
-const char kURLsToNotCheckComplianceOfUploadedContent[] =
- "policy.urls_to_not_check_compliance_of_uploaded_content";
const char kAdvancedProtectionAllowed[] =
"safebrowsing.advanced_protection_allowed";
-
+const char kSafeBrowsingMetricsLastLogTime[] =
+ "safebrowsing.metrics_last_log_time";
} // namespace prefs
namespace safe_browsing {
@@ -229,30 +209,15 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kPasswordProtectionWarningTrigger,
PASSWORD_PROTECTION_OFF);
registry->RegisterInt64Pref(prefs::kAdvancedProtectionLastRefreshInUs, 0);
- registry->RegisterIntegerPref(prefs::kSafeBrowsingSendFilesForMalwareCheck,
- DO_NOT_SCAN);
registry->RegisterBooleanPref(prefs::kAdvancedProtectionAllowed, true);
registry->RegisterIntegerPref(
prefs::kSafeBrowsingEnterpriseRealTimeUrlCheckMode,
REAL_TIME_CHECK_DISABLED);
+ registry->RegisterInt64Pref(prefs::kSafeBrowsingMetricsLastLogTime, 0);
}
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(prefs::kSafeBrowsingTriggerEventTimestamps);
- registry->RegisterBooleanPref(prefs::kUnsafeEventsReportingEnabled, false);
- registry->RegisterIntegerPref(prefs::kBlockLargeFileTransfer, 0);
- registry->RegisterIntegerPref(prefs::kDelayDeliveryUntilVerdict, DELAY_NONE);
- registry->RegisterIntegerPref(
- prefs::kAllowPasswordProtectedFiles,
- AllowPasswordProtectedFilesValues::ALLOW_UPLOADS_AND_DOWNLOADS);
- registry->RegisterIntegerPref(prefs::kCheckContentCompliance, CHECK_NONE);
- registry->RegisterIntegerPref(prefs::kBlockUnsupportedFiletypes,
- BLOCK_UNSUPPORTED_FILETYPES_NONE);
- registry->RegisterListPref(prefs::kURLsToCheckComplianceOfDownloadedContent);
- registry->RegisterListPref(prefs::kURLsToNotCheckComplianceOfUploadedContent);
- registry->RegisterListPref(prefs::kURLsToCheckForMalwareOfUploadedContent);
- registry->RegisterListPref(
- prefs::kURLsToNotCheckForMalwareOfDownloadedContent);
}
void SetExtendedReportingPrefAndMetric(
diff --git a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
index 29672db6607..6df1d1045e8 100644
--- a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
+++ b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -92,51 +92,14 @@ extern const char kPasswordProtectionWarningTrigger[];
// microseconds);
extern const char kAdvancedProtectionLastRefreshInUs[];
-// Whether or not to send downloads to Safe Browsing for deep scanning. This
-// is configured by enterprise policy.
-extern const char kSafeBrowsingSendFilesForMalwareCheck[];
-
-// Boolean that indidicates if Chrome reports unsafe events to Google.
-extern const char kUnsafeEventsReportingEnabled[];
-
-// Integer that specifies if large files are blocked form either uploads or
-// downloads or both.
-extern const char kBlockLargeFileTransfer[];
-
-// Integer that specifies if delivery to the user of potentially unsafe data
-// is delayed until a verdict about the data is known.
-extern const char kDelayDeliveryUntilVerdict[];
-
-// Integer that specifies if password protected files can be either uploaded
-// or downloaded or both.
-extern const char kAllowPasswordProtectedFiles[];
-
-// Integer that indicates if Chrome checks data for content compliance.
-extern const char kCheckContentCompliance[];
-
-// Integer that indicates if Chrome blocks data that cannot be checked for
-// content compliance due to unsupported filetypes.
-extern const char kBlockUnsupportedFiletypes[];
-
-// List of url patterns where Chrome should check compliance of downloaded
-// files.
-extern const char kURLsToCheckComplianceOfDownloadedContent[];
-
-// List of url patterns where Chrome should check for malware of uploaded files.
-extern const char kURLsToCheckForMalwareOfUploadedContent[];
-
-// List of url patterns where Chrome should not check for malware downloaded
-// files.
-extern const char kURLsToNotCheckForMalwareOfDownloadedContent[];
-
-// List of url patterns where Chrome should not check compliance of uploaded
-// files.
-extern const char kURLsToNotCheckComplianceOfUploadedContent[];
-
// Boolean that indicates if Chrome is allowed to provide extra
// features to users enrolled in the Advanced Protection Program.
extern const char kAdvancedProtectionAllowed[];
+// Integer epoch timestamp in seconds. Indicates the last logging time of Safe
+// Browsing metrics.
+extern const char kSafeBrowsingMetricsLastLogTime[];
+
} // namespace prefs
namespace safe_browsing {
@@ -183,65 +146,9 @@ enum PasswordProtectionTrigger {
PASSWORD_PROTECTION_TRIGGER_MAX,
};
-// Enum representing possible values of the SendFilesForMalwareCheck policy.
-// This must be kept in sync with policy_templates.json.
-enum SendFilesForMalwareCheckValues {
- DO_NOT_SCAN = 0,
- SEND_DOWNLOADS = 2,
- SEND_UPLOADS = 3,
- SEND_UPLOADS_AND_DOWNLOADS = 4,
- // New options must be added before SEND_FILES_FOR_MALWARE_CHECK_MAX.
- SEND_FILES_FOR_MALWARE_CHECK_MAX = SEND_UPLOADS_AND_DOWNLOADS,
-};
-
-// Enum representing possible values of the CheckContentCompliance policy. This
-// must be kept in sync with policy_templates.json.
-enum CheckContentComplianceValues {
- CHECK_NONE = 0,
- CHECK_DOWNLOADS = 1,
- CHECK_UPLOADS = 2,
- CHECK_UPLOADS_AND_DOWNLOADS = 3,
- // New options must be added before CHECK_CONTENT_COMPLIANCE_MAX.
- CHECK_CONTENT_COMPLIANCE_MAX = CHECK_UPLOADS_AND_DOWNLOADS,
-};
-
-// Enum representing possible values of the BlockUnsupportedFiletypes policy.
-// This must be kept in sync with policy_templates.json.
-enum BlockUnsupportedFiletypesValues {
- BLOCK_UNSUPPORTED_FILETYPES_NONE = 0,
- BLOCK_UNSUPPORTED_FILETYPES_DOWNLOADS = 1,
- BLOCK_UNSUPPORTED_FILETYPES_UPLOADS = 2,
- BLOCK_UNSUPPORTED_FILETYPES_UPLOADS_AND_DOWNLOADS = 3,
-};
-
-// Enum representing possible values of the AllowPasswordProtectedFiles policy.
-// This must be kept in sync with policy_templates.json.
-enum AllowPasswordProtectedFilesValues {
- ALLOW_NONE = 0,
- ALLOW_DOWNLOADS = 1,
- ALLOW_UPLOADS = 2,
- ALLOW_UPLOADS_AND_DOWNLOADS = 3,
-};
-
-// Enum representing possible values of the BlockLargeFileTransfer policy. This
-// must be kept in sync with policy_templates.json.
-enum BlockLargeFileTransferValues {
- BLOCK_NONE = 0,
- BLOCK_LARGE_DOWNLOADS = 1,
- BLOCK_LARGE_UPLOADS = 2,
- BLOCK_LARGE_UPLOADS_AND_DOWNLOADS = 3,
-};
-
-// Enum representing possible values of the DelayDeliveryUntilVerdict policy.
-// This must be kept in sync with policy_templates.json.
-enum DelayDeliveryUntilVerdictValues {
- DELAY_NONE = 0,
- DELAY_DOWNLOADS = 1,
- DELAY_UPLOADS = 2,
- DELAY_UPLOADS_AND_DOWNLOADS = 3,
-};
-
// Enum representing possible values of the Safe Browsing state.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.safe_browsing
enum SafeBrowsingState {
@@ -251,6 +158,8 @@ enum SafeBrowsingState {
STANDARD_PROTECTION = 1,
// The user selected enhanced protection.
ENHANCED_PROTECTION = 2,
+
+ kMaxValue = ENHANCED_PROTECTION,
};
enum EnterpriseRealTimeUrlCheckMode {
diff --git a/chromium/components/safe_browsing/core/common/utils.cc b/chromium/components/safe_browsing/core/common/utils.cc
index 369c63c87bc..5131aed3ef6 100644
--- a/chromium/components/safe_browsing/core/common/utils.cc
+++ b/chromium/components/safe_browsing/core/common/utils.cc
@@ -11,6 +11,8 @@
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/prefs/pref_service.h"
#include "crypto/sha2.h"
+#include "net/base/ip_address.h"
+#include "net/base/url_util.h"
#if defined(OS_WIN)
#include "base/enterprise_util.h"
@@ -74,4 +76,30 @@ base::TimeDelta GetDelayFromPref(PrefService* prefs, const char* pref_name) {
return next_event - now;
}
+bool CanGetReputationOfUrl(const GURL& url) {
+ if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS() || net::IsLocalhost(url)) {
+ return false;
+ }
+ const std::string hostname = url.host();
+ // A valid hostname should be longer than 3 characters and have at least 1
+ // dot.
+ if (hostname.size() < 4 || base::STLCount(hostname, '.') < 1) {
+ return false;
+ }
+
+ if (net::IsLocalhost(url)) {
+ // Includes: "//localhost/", "//localhost.localdomain/", "//127.0.0.1/"
+ return false;
+ }
+
+ net::IPAddress ip_address;
+ if (url.HostIsIPAddress() && ip_address.AssignFromIPLiteral(hostname) &&
+ !ip_address.IsPubliclyRoutable()) {
+ // Includes: "//192.168.1.1/", "//172.16.2.2/", "//10.1.1.1/"
+ return false;
+ }
+
+ return true;
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/core/common/utils.h b/chromium/components/safe_browsing/core/common/utils.h
index 11da036adaf..b1a847c3ff0 100644
--- a/chromium/components/safe_browsing/core/common/utils.h
+++ b/chromium/components/safe_browsing/core/common/utils.h
@@ -41,6 +41,15 @@ void SetDelayInPref(PrefService* prefs,
const base::TimeDelta& delay);
base::TimeDelta GetDelayFromPref(PrefService* prefs, const char* pref_name);
+// Safe Browsing backend cannot get a reliable reputation of a URL if
+// (1) URL is not valid
+// (2) URL doesn't have http or https scheme
+// (3) It maps to a local host.
+// (4) Its hostname is an IP Address that is assigned from IP literal.
+// (5) Its hostname is a dotless domain.
+// (6) Its hostname is less than 4 characters.
+bool CanGetReputationOfUrl(const GURL& url);
+
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_CORE_COMMON_UTILS_H_
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils.cc b/chromium/components/safe_browsing/core/common/visual_utils.cc
index c751167b8a3..e064e1846c1 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils.cc
+++ b/chromium/components/safe_browsing/core/common/visual_utils.cc
@@ -5,7 +5,7 @@
#include <unordered_map>
#include <vector>
-#include "components/safe_browsing/content/password_protection/visual_utils.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
#include "base/check_op.h"
#include "base/numerics/checked_math.h"
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils.h b/chromium/components/safe_browsing/core/common/visual_utils.h
index 34b6764efa5..7716ca7c9c6 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils.h
+++ b/chromium/components/safe_browsing/core/common/visual_utils.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 COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
-#define COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
+#ifndef COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
+#define COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
#include <string>
@@ -52,4 +52,4 @@ base::Optional<VisionMatchResult> IsVisualMatch(const SkBitmap& image,
} // namespace visual_utils
} // namespace safe_browsing
-#endif // COMPONENTS_SAFE_BROWSING_CONTENT_PASSWORD_PROTECTION_VISUAL_UTILS_H_
+#endif // COMPONENTS_SAFE_BROWSING_CORE_COMMON_VISUAL_UTILS_H_
diff --git a/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc b/chromium/components/safe_browsing/core/common/visual_utils_unittest.cc
index 752e65dbe3e..6f6ee6e8a07 100644
--- a/chromium/components/safe_browsing/content/password_protection/visual_utils_unittest.cc
+++ b/chromium/components/safe_browsing/core/common/visual_utils_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 "components/safe_browsing/content/password_protection/visual_utils.h"
+#include "components/safe_browsing/core/common/visual_utils.h"
#include "base/test/test_discardable_memory_allocator.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/components/safe_browsing/core/db/database_manager_unittest.cc b/chromium/components/safe_browsing/core/db/database_manager_unittest.cc
index 495ffde4366..a10406e3d46 100644
--- a/chromium/components/safe_browsing/core/db/database_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/db/database_manager_unittest.cc
@@ -17,7 +17,7 @@
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/safe_browsing/core/common/test_task_environment.h"
#include "components/safe_browsing/core/db/test_database_manager.h"
diff --git a/chromium/components/safe_browsing/core/db/hit_report.h b/chromium/components/safe_browsing/core/db/hit_report.h
index 8bc0796c277..d03c3413c7c 100644
--- a/chromium/components/safe_browsing/core/db/hit_report.h
+++ b/chromium/components/safe_browsing/core/db/hit_report.h
@@ -22,6 +22,7 @@ enum class ThreatSource {
REMOTE, // From RemoteSafeBrowsingDatabaseManager
CLIENT_SIDE_DETECTION, // From ClientSideDetectionHost
PASSWORD_PROTECTION_SERVICE, // From PasswordProtectionService
+ REAL_TIME_CHECK, // From RealTimeUrlLookupService
};
// Data to report about the contents of a particular threat (malware, phishing,
diff --git a/chromium/components/safe_browsing/core/db/v4_database_unittest.cc b/chromium/components/safe_browsing/core/db/v4_database_unittest.cc
index 1b9a61a3355..2176d46ced0 100644
--- a/chromium/components/safe_browsing/core/db/v4_database_unittest.cc
+++ b/chromium/components/safe_browsing/core/db/v4_database_unittest.cc
@@ -6,7 +6,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/debug/leak_annotations.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
diff --git a/chromium/components/safe_browsing/core/db/v4_local_database_manager.cc b/chromium/components/safe_browsing/core/db/v4_local_database_manager.cc
index 31e13d56b58..b4c937636dd 100644
--- a/chromium/components/safe_browsing/core/db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing/core/db/v4_local_database_manager.cc
@@ -8,8 +8,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
diff --git a/chromium/components/safe_browsing/core/features.cc b/chromium/components/safe_browsing/core/features.cc
index 9549691b934..6bd1a1ba2f6 100644
--- a/chromium/components/safe_browsing/core/features.cc
+++ b/chromium/components/safe_browsing/core/features.cc
@@ -86,7 +86,7 @@ const base::Feature kPasswordProtectionForSignedInUsers{
};
const base::Feature kPromptAppForDeepScanning{
- "SafeBrowsingPromptAppForDeepScanning", base::FEATURE_DISABLED_BY_DEFAULT};
+ "SafeBrowsingPromptAppForDeepScanning", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kRealTimeUrlLookupEnabled{
"SafeBrowsingRealTimeUrlLookupEnabled",
@@ -103,7 +103,7 @@ const base::Feature kRealTimeUrlLookupEnabledForAllAndroidDevices{
const base::Feature kRealTimeUrlLookupEnabledForEnterprise{
"SafeBrowsingRealTimeUrlLookupEnabledForEnterprise",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kRealTimeUrlLookupEnabledForEP{
"SafeBrowsingRealTimeUrlLookupEnabledForEP",
@@ -126,9 +126,6 @@ const base::Feature kRealTimeUrlLookupNonMainframeEnabledForEP{
"SafeBrowsingRealTimeUrlLookupNonMainframeEnabledForEP",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSafeBrowsingAvailableOnIOS{
- "SafeBrowsingAvailableOnIOS", base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kSafeBrowsingSeparateNetworkContexts{
"SafeBrowsingSeparateNetworkContexts", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -138,7 +135,7 @@ const base::Feature kSafeBrowsingRemoveCookies{
constexpr base::FeatureParam<bool> kShouldFillOldPhishGuardProto{
&kPasswordProtectionForSignedInUsers, "DeprecateOldProto", false};
-const base::Feature kSafeBrowsingSecuritySectionUIAndroid{
+const base::Feature kSafeBrowsingSectionUIAndroid{
"SafeBrowsingSecuritySectionUIAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kSuspiciousSiteTriggerQuotaFeature{
@@ -183,9 +180,8 @@ constexpr struct {
{&kRealTimeUrlLookupEnabledForEPWithToken, true},
{&kRealTimeUrlLookupEnabledWithToken, true},
{&kRealTimeUrlLookupNonMainframeEnabledForEP, true},
- {&kSafeBrowsingAvailableOnIOS, true},
{&kSafeBrowsingSeparateNetworkContexts, true},
- {&kSafeBrowsingSecuritySectionUIAndroid, true},
+ {&kSafeBrowsingSectionUIAndroid, true},
{&kSuspiciousSiteTriggerQuotaFeature, true},
{&kThreatDomDetailsTagAndAttributeFeature, false},
{&kTriggerThrottlerDailyQuotaFeature, false},
diff --git a/chromium/components/safe_browsing/core/features.h b/chromium/components/safe_browsing/core/features.h
index 8098697295a..79df1359f3e 100644
--- a/chromium/components/safe_browsing/core/features.h
+++ b/chromium/components/safe_browsing/core/features.h
@@ -65,17 +65,13 @@ extern const base::Feature kPasswordProtectionForSignedInUsers;
// Controls whether Chrome prompts Advanced Protection users for deep scanning.
extern const base::Feature kPromptAppForDeepScanning;
-// Controls whether native (instead of WKWebView-provided) Safe Browsing
-// is available on iOS. When this flag is enabled, Safe Browsing is still
-// subject to an opt-out controlled by prefs::kSafeBrowsingEnabled.
-extern const base::Feature kSafeBrowsingAvailableOnIOS;
-
// Controls whether Safe Browsing uses separate NetworkContexts for each
// profile.
extern const base::Feature kSafeBrowsingSeparateNetworkContexts;
-// Controls whether the security section is shown on the settings UI on Android.
-extern const base::Feature kSafeBrowsingSecuritySectionUIAndroid;
+// Controls whether the Safe Browsing section is shown on the settings UI on
+// Android.
+extern const base::Feature kSafeBrowsingSectionUIAndroid;
// Controls whether cookies are removed from certain communications with Safe
// Browsing.
diff --git a/chromium/components/safe_browsing/core/ping_manager.cc b/chromium/components/safe_browsing/core/ping_manager.cc
index 93f3a275f68..86e9eebc0cc 100644
--- a/chromium/components/safe_browsing/core/ping_manager.cc
+++ b/chromium/components/safe_browsing/core/ping_manager.cc
@@ -186,6 +186,9 @@ GURL PingManager::SafeBrowsingHitUrl(
case safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE:
threat_source = "pps";
break;
+ case safe_browsing::ThreatSource::REAL_TIME_CHECK:
+ threat_source = "rt";
+ break;
case safe_browsing::ThreatSource::UNKNOWN:
NOTREACHED();
}
diff --git a/chromium/components/safe_browsing/core/ping_manager_unittest.cc b/chromium/components/safe_browsing/core/ping_manager_unittest.cc
index aff0c850cc3..a454d09f71b 100644
--- a/chromium/components/safe_browsing/core/ping_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/ping_manager_unittest.cc
@@ -183,6 +183,26 @@ TEST_F(PingManagerTest, TestSafeBrowsingHitUrl) {
"url.com%2F&evtb=1&src=l4&m=0&up=foo+bar",
ping_manager()->SafeBrowsingHitUrl(hp).spec());
}
+
+ // Threat source is real time check.
+ {
+ HitReport hp(base_hp);
+ hp.threat_type = SB_THREAT_TYPE_URL_PHISHING;
+ hp.threat_source = ThreatSource::REAL_TIME_CHECK;
+ hp.is_subresource = false;
+ hp.extended_reporting_level = SBER_LEVEL_SCOUT;
+ hp.is_metrics_reporting_active = true;
+ hp.is_enhanced_protection = true;
+ EXPECT_EQ(
+ "https://safebrowsing.google.com/safebrowsing/report?client=unittest&"
+ "appver=1.0&pver=4.0" +
+ key_param_ +
+ "&ext=2&enh=1&evts=phishblhit&"
+ "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
+ "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
+ "url.com%2F&evtb=0&src=rt&m=1",
+ ping_manager()->SafeBrowsingHitUrl(hp).spec());
+ }
}
TEST_F(PingManagerTest, TestThreatDetailsUrl) {
diff --git a/chromium/components/safe_browsing/core/proto/csd.proto b/chromium/components/safe_browsing/core/proto/csd.proto
index 6a84214cee2..3e9c8e5cab3 100644
--- a/chromium/components/safe_browsing/core/proto/csd.proto
+++ b/chromium/components/safe_browsing/core/proto/csd.proto
@@ -1312,6 +1312,8 @@ message ClientSafeBrowsingReportRequest {
ANDROID_SAFETYNET = 3;
// Flywheel (data compression service).
FLYWHEEL = 4;
+ // Safe Browsing real time API.
+ REAL_TIME = 5;
}
// The information propagated from the client about various environment
diff --git a/chromium/components/safe_browsing/core/proto/webprotect.proto b/chromium/components/safe_browsing/core/proto/webprotect.proto
deleted file mode 100644
index 283f6ba07e6..00000000000
--- a/chromium/components/safe_browsing/core/proto/webprotect.proto
+++ /dev/null
@@ -1,140 +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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package safe_browsing;
-
-// Malware-specific scanning information.
-message MalwareDeepScanningClientRequest {
- enum Population {
- POPULATION_UNKNOWN = 0;
- POPULATION_ENTERPRISE = 1;
- POPULATION_TITANIUM = 2;
- }
- // Identifies the type of client.
- optional Population population = 1;
-
- reserved 2;
-}
-
-// DLP-specific scanning information.
-message DlpDeepScanningClientRequest {
- // Where the content comes from, so that the proper rules can be triggered.
- enum ContentSource {
- CONTENT_SOURCE_UNKNOWN = 0;
- FILE_DOWNLOAD = 1;
- FILE_UPLOAD = 2;
- WEB_CONTENT_UPLOAD = 3;
- }
- optional ContentSource content_source = 1;
-
- // The URL containing the file download/upload or to which web content is
- // being uploaded.
- optional string url = 2;
-}
-
-// Scanning configuration sent from Chrome.
-message DeepScanningClientRequest {
- // The DM Token for Enterprise-enrolled devices
- optional string dm_token = 1;
-
- // Firebase Cloud Messaging token used to notify client of verdict.
- optional string fcm_notification_token = 2;
-
- // Malware scan specific request info.
- optional MalwareDeepScanningClientRequest malware_scan_request = 3;
-
- // DLP scan specific request info.
- optional DlpDeepScanningClientRequest dlp_scan_request = 4;
-
- // Token used to correlate requests and responses. This is different than the
- // FCM token, in that it is unique for each request.
- optional string request_token = 5;
-
- // Name of file on user system (if applicable).
- optional string filename = 6;
-
- // Sha256 digest of file.
- optional string digest = 7;
-
- // Server-side only field.
- reserved 8;
-}
-
-// Malware-specific response given back for scanned content.
-message MalwareDeepScanningVerdict {
- reserved 2;
-
- // These values are persisted to UMA logs in the
- // SafeBrowsingMalwareDeepScanningVerdict enum. Entries should not be
- // renumbered and numeric values should never be reused.
- enum Verdict {
- VERDICT_UNSPECIFIED = 0;
- CLEAN = 1;
- UWS = 2;
- MALWARE = 3;
- SCAN_FAILURE = 4;
- }
- // Verdict given to scanned content.
- optional Verdict verdict = 1;
-}
-
-message DlpDeepScanningVerdict {
- // The status of the deep scanning verdict. When status is SUCCESS and
- // triggered_rules below is empty, then the content is clean.
- enum Status {
- STATUS_UNKNOWN = 0;
- SUCCESS = 1;
- FAILURE = 2;
- }
- optional Status status = 1;
-
- // Next ID: 4
- message MatchedDetector {
- // Unique identifier for this detector.
- optional string detector_id = 1;
-
- // Display name of this detector.
- optional string display_name = 2;
-
- // Type of this detector.
- optional string detector_type = 3;
- }
-
- // Next ID: 7
- message TriggeredRule {
- enum Action {
- ACTION_UNKNOWN = 0;
- REPORT_ONLY = 1;
- WARN = 2;
- BLOCK = 3;
- }
- optional Action action = 1;
-
- optional string rule_name = 2;
-
- optional int64 rule_id = 3;
-
- optional string rule_resource_name = 4;
-
- optional string rule_severity = 5;
-
- repeated MatchedDetector matched_detectors = 6;
- }
- // Only relevant when status is SUCCESS above.
- repeated TriggeredRule triggered_rules = 2;
-}
-
-message DeepScanningClientResponse {
- // Token used to correlate requests and responses. This is different than the
- // FCM token, in that it is unique for each request.
- optional string token = 1;
-
- optional MalwareDeepScanningVerdict malware_scan_verdict = 2;
-
- optional DlpDeepScanningVerdict dlp_scan_verdict = 3;
-}
diff --git a/chromium/components/safe_browsing/core/realtime/BUILD.gn b/chromium/components/safe_browsing/core/realtime/BUILD.gn
index 62dda5c7cd8..5494e341c0f 100644
--- a/chromium/components/safe_browsing/core/realtime/BUILD.gn
+++ b/chromium/components/safe_browsing/core/realtime/BUILD.gn
@@ -64,6 +64,7 @@ static_library("url_lookup_service_base") {
"//components/safe_browsing/core:features",
"//components/safe_browsing/core:realtimeapi_proto",
"//components/safe_browsing/core:verdict_cache_manager",
+ "//components/safe_browsing/core/common:common",
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//components/safe_browsing/core/common:thread_utils",
"//components/safe_browsing/core/db:v4_protocol_manager_util",
diff --git a/chromium/components/safe_browsing/core/realtime/policy_engine.h b/chromium/components/safe_browsing/core/realtime/policy_engine.h
index e69ae303649..148bcd91df2 100644
--- a/chromium/components/safe_browsing/core/realtime/policy_engine.h
+++ b/chromium/components/safe_browsing/core/realtime/policy_engine.h
@@ -74,7 +74,6 @@ class RealTimePolicyEngine {
bool is_off_the_record);
friend class SafeBrowsingService;
- friend class SafeBrowsingUIHandler;
private:
static bool IsInExcludedCountry(const std::string& country_code);
diff --git a/chromium/components/safe_browsing/core/realtime/url_lookup_service_base.cc b/chromium/components/safe_browsing/core/realtime/url_lookup_service_base.cc
index 35a9cac6e61..b42fc530efb 100644
--- a/chromium/components/safe_browsing/core/realtime/url_lookup_service_base.cc
+++ b/chromium/components/safe_browsing/core/realtime/url_lookup_service_base.cc
@@ -15,6 +15,7 @@
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/common/thread_utils.h"
+#include "components/safe_browsing/core/common/utils.h"
#include "components/safe_browsing/core/verdict_cache_manager.h"
#include "components/sync/driver/sync_service.h"
#include "net/base/ip_address.h"
@@ -133,25 +134,10 @@ RealTimeUrlLookupServiceBase::~RealTimeUrlLookupServiceBase() = default;
// static
bool RealTimeUrlLookupServiceBase::CanCheckUrl(const GURL& url) {
- if (!url.SchemeIsHTTPOrHTTPS()) {
- return false;
+ if (VerdictCacheManager::has_artificial_unsafe_url()) {
+ return true;
}
-
- if (net::IsLocalhost(url) &&
- !VerdictCacheManager::has_artificial_unsafe_url()) {
- // Includes: "//localhost/", "//localhost.localdomain/", "//127.0.0.1/"
- return false;
- }
-
- net::IPAddress ip_address;
- if (url.HostIsIPAddress() && ip_address.AssignFromIPLiteral(url.host()) &&
- !ip_address.IsPubliclyRoutable() &&
- !VerdictCacheManager::has_artificial_unsafe_url()) {
- // Includes: "//192.168.1.1/", "//172.16.2.2/", "//10.1.1.1/"
- return false;
- }
-
- return true;
+ return CanGetReputationOfUrl(url);
}
// static
@@ -174,7 +160,10 @@ SBThreatType RealTimeUrlLookupServiceBase::GetSBThreatTypeForRTThreatType(
// static
GURL RealTimeUrlLookupServiceBase::SanitizeURL(const GURL& url) {
- return net::SimplifyUrlForRequest(url);
+ GURL::Replacements replacements;
+ replacements.ClearUsername();
+ replacements.ClearPassword();
+ return url.ReplaceComponents(replacements);
}
// static
diff --git a/chromium/components/safe_browsing/core/realtime/url_lookup_service_unittest.cc b/chromium/components/safe_browsing/core/realtime/url_lookup_service_unittest.cc
index a4f7aff2257..35d8dbe2792 100644
--- a/chromium/components/safe_browsing/core/realtime/url_lookup_service_unittest.cc
+++ b/chromium/components/safe_browsing/core/realtime/url_lookup_service_unittest.cc
@@ -202,7 +202,7 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillRequestProto) {
{"http://example.com/", "http://example.com/"},
{"http://user:pass@example.com/", "http://example.com/"},
{"http://%123:bar@example.com/", "http://example.com/"},
- {"http://example.com#123", "http://example.com/"}};
+ {"http://example.com/abc#123", "http://example.com/abc#123"}};
for (size_t i = 0; i < base::size(sanitize_url_cases); i++) {
GURL url(sanitize_url_cases[i].url);
auto result = FillRequestProto(url);
@@ -527,10 +527,11 @@ TEST_F(RealTimeUrlLookupServiceTest, TestCanCheckUrl) {
{"http://10.1.1.1/path", false},
{"http://10.1.1.1.1/path", true},
{"http://example.test/path", true},
- {"https://example.test/path", true}};
- for (size_t i = 0; i < base::size(can_check_url_cases); i++) {
- GURL url(can_check_url_cases[i].url);
- bool expected_can_check = can_check_url_cases[i].can_check;
+ {"http://nodothost/path", false},
+ {"http://x.x/shorthost", false}};
+ for (auto& can_check_url_case : can_check_url_cases) {
+ GURL url(can_check_url_case.url);
+ bool expected_can_check = can_check_url_case.can_check;
EXPECT_EQ(expected_can_check, CanCheckUrl(url));
}
}
diff --git a/chromium/components/safe_browsing/core/resources/BUILD.gn b/chromium/components/safe_browsing/core/resources/BUILD.gn
index d9c4e08d78e..5966583704f 100644
--- a/chromium/components/safe_browsing/core/resources/BUILD.gn
+++ b/chromium/components/safe_browsing/core/resources/BUILD.gn
@@ -2,10 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
+
# TODO(nparker): reduce the duplication between these two, somehow.
# Generate the binary proto form of "file_types" from the ascii proto.
-action("make_file_types_protobuf") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("make_file_types_protobuf") {
script = "gen_file_type_proto.py"
# The output goes in $target_gen_dir since that's where
@@ -63,7 +66,8 @@ action("make_file_types_protobuf") {
# Generate the binary proto for ALL platforms. This is only run manually
# when pushing the files to GCS for the component-updater to pick up.
-action("make_all_file_types_protobuf") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("make_all_file_types_protobuf") {
script = "gen_file_type_proto.py"
input_filename = "download_file_types.asciipb"
diff --git a/chromium/components/safe_browsing/core/verdict_cache_manager.cc b/chromium/components/safe_browsing/core/verdict_cache_manager.cc
index f74d1164c00..367b00eb14f 100644
--- a/chromium/components/safe_browsing/core/verdict_cache_manager.cc
+++ b/chromium/components/safe_browsing/core/verdict_cache_manager.cc
@@ -270,7 +270,7 @@ typename T::VerdictType GetMostMatchingCachedVerdictWithPathMatching(
GURL hostname = GetHostNameWithHTTPScheme(url);
std::unique_ptr<base::DictionaryValue> cache_dictionary =
base::DictionaryValue::From(content_settings->GetWebsiteSetting(
- hostname, GURL(), contents_setting_type, std::string(), nullptr));
+ hostname, GURL(), contents_setting_type, nullptr));
if (!cache_dictionary || cache_dictionary->empty())
return T::VERDICT_TYPE_UNSPECIFIED;
@@ -372,7 +372,7 @@ VerdictCacheManager::VerdictCacheManager(
stored_verdict_count_real_time_url_check_(base::nullopt),
content_settings_(content_settings) {
if (history_service)
- history_service_observer_.Add(history_service);
+ history_service_observation_.Observe(history_service);
if (!content_settings->IsOffTheRecord()) {
ScheduleNextCleanUpAfterInterval(
base::TimeDelta::FromSeconds(kCleanUpIntervalInitSecond));
@@ -382,7 +382,8 @@ VerdictCacheManager::VerdictCacheManager(
void VerdictCacheManager::Shutdown() {
CleanUpExpiredVerdicts();
- history_service_observer_.RemoveAll();
+ if (history_service_observation_.IsObserving())
+ history_service_observation_.RemoveObservation();
weak_factory_.InvalidateWeakPtrs();
}
@@ -401,8 +402,7 @@ void VerdictCacheManager::CachePhishGuardVerdict(
std::unique_ptr<base::DictionaryValue> cache_dictionary =
base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), nullptr));
+ hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr));
if (!cache_dictionary)
cache_dictionary = std::make_unique<base::DictionaryValue>();
@@ -436,7 +436,7 @@ void VerdictCacheManager::CachePhishGuardVerdict(
GetCacheExpression(verdict),
base::Value::FromUniquePtrValue(std::move(verdict_entry)));
content_settings_->SetWebsiteSettingDefaultScope(
- hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION, std::string(),
+ hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
std::move(cache_dictionary));
}
@@ -472,7 +472,7 @@ size_t VerdictCacheManager::GetStoredPhishGuardVerdictCount(
ContentSettingsForOneType settings;
content_settings_->GetSettingsForOneType(
- ContentSettingsType::PASSWORD_PROTECTION, std::string(), &settings);
+ ContentSettingsType::PASSWORD_PROTECTION, &settings);
stored_verdict_count_password_on_focus_ = 0;
stored_verdict_count_password_entry_ = 0;
for (const ContentSettingPatternSource& source : settings) {
@@ -495,8 +495,7 @@ size_t VerdictCacheManager::GetStoredRealTimeUrlCheckVerdictCount() {
ContentSettingsForOneType settings;
content_settings_->GetSettingsForOneType(
- ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, std::string(),
- &settings);
+ ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, &settings);
stored_verdict_count_real_time_url_check_ = 0;
for (const ContentSettingPatternSource& source : settings) {
for (const auto& item : source.setting_value.DictItems()) {
@@ -536,7 +535,7 @@ void VerdictCacheManager::CacheRealTimeUrlVerdict(
std::unique_ptr<base::DictionaryValue> cache_dictionary =
base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
hostname, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- std::string(), nullptr));
+ nullptr));
if (!cache_dictionary)
cache_dictionary = std::make_unique<base::DictionaryValue>();
@@ -565,7 +564,7 @@ void VerdictCacheManager::CacheRealTimeUrlVerdict(
content_settings_->SetWebsiteSettingDefaultScope(
hostname, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- std::string(), std::move(cache_dictionary));
+ std::move(cache_dictionary));
}
base::UmaHistogramCounts10000(
"SafeBrowsing.RT.CacheManager.RealTimeVerdictCount",
@@ -608,8 +607,7 @@ void VerdictCacheManager::CleanUpExpiredPhishGuardVerdicts() {
ContentSettingsForOneType password_protection_settings;
content_settings_->GetSettingsForOneType(
- ContentSettingsType::PASSWORD_PROTECTION, std::string(),
- &password_protection_settings);
+ ContentSettingsType::PASSWORD_PROTECTION, &password_protection_settings);
int removed_count = 0;
for (ContentSettingPatternSource& source : password_protection_settings) {
@@ -633,7 +631,7 @@ void VerdictCacheManager::CleanUpExpiredPhishGuardVerdicts() {
// |cache_dictionary|.
content_settings_->SetWebsiteSettingCustomScope(
source.primary_pattern, source.secondary_pattern,
- ContentSettingsType::PASSWORD_PROTECTION, std::string(),
+ ContentSettingsType::PASSWORD_PROTECTION,
cache_dictionary->DictEmpty() ? nullptr : std::move(cache_dictionary));
if ((++removed_count) == kMaxRemovedEntriesCount) {
@@ -648,7 +646,7 @@ void VerdictCacheManager::CleanUpExpiredRealTimeUrlCheckVerdicts() {
}
ContentSettingsForOneType safe_browsing_url_check_data_settings;
content_settings_->GetSettingsForOneType(
- ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, std::string(),
+ ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
&safe_browsing_url_check_data_settings);
int removed_count = 0;
@@ -668,7 +666,7 @@ void VerdictCacheManager::CleanUpExpiredRealTimeUrlCheckVerdicts() {
// |cache_dictionary|.
content_settings_->SetWebsiteSettingCustomScope(
source.primary_pattern, source.secondary_pattern,
- ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, std::string(),
+ ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
cache_dictionary->DictEmpty() ? nullptr : std::move(cache_dictionary));
if ((++removed_count) == kMaxRemovedEntriesCount) {
@@ -691,7 +689,8 @@ void VerdictCacheManager::OnURLsDeleted(
// Overridden from history::HistoryServiceObserver.
void VerdictCacheManager::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_service_observer_.Remove(history_service);
+ DCHECK(history_service_observation_.IsObservingSource(history_service));
+ history_service_observation_.RemoveObservation();
}
bool VerdictCacheManager::RemoveExpiredPhishGuardVerdicts(
@@ -791,11 +790,10 @@ void VerdictCacheManager::RemoveContentSettingsOnURLsDeleted(
GetStoredRealTimeUrlCheckVerdictCount() -
GetRealTimeUrlCheckVerdictCountForURL(url_key);
content_settings_->SetWebsiteSettingDefaultScope(
- url_key, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), nullptr);
+ url_key, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr);
content_settings_->SetWebsiteSettingDefaultScope(
url_key, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- std::string(), nullptr);
+ nullptr);
}
}
@@ -806,8 +804,7 @@ size_t VerdictCacheManager::GetPhishGuardVerdictCountForURL(
trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
std::unique_ptr<base::DictionaryValue> cache_dictionary =
base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- url, GURL(), ContentSettingsType::PASSWORD_PROTECTION, std::string(),
- nullptr));
+ url, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr));
if (!cache_dictionary || cache_dictionary->empty())
return 0;
@@ -833,7 +830,7 @@ size_t VerdictCacheManager::GetRealTimeUrlCheckVerdictCountForURL(
std::unique_ptr<base::DictionaryValue> cache_dictionary =
base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
url, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- std::string(), nullptr));
+ nullptr));
if (!cache_dictionary || cache_dictionary->empty())
return 0;
base::Value* verdict_dictionary =
diff --git a/chromium/components/safe_browsing/core/verdict_cache_manager.h b/chromium/components/safe_browsing/core/verdict_cache_manager.h
index 9bc9368cdde..c556a0fa4a3 100644
--- a/chromium/components/safe_browsing/core/verdict_cache_manager.h
+++ b/chromium/components/safe_browsing/core/verdict_cache_manager.h
@@ -8,7 +8,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
@@ -104,6 +104,7 @@ class VerdictCacheManager : public history::HistoryServiceObserver,
void StopCleanUpTimerForTesting();
private:
+ friend class SafeBrowsingBlockingPageRealTimeUrlCheckTest;
FRIEND_TEST_ALL_PREFIXES(VerdictCacheManagerTest, TestCleanUpExpiredVerdict);
FRIEND_TEST_ALL_PREFIXES(VerdictCacheManagerTest,
TestCleanUpExpiredVerdictWithInvalidEntry);
@@ -155,8 +156,9 @@ class VerdictCacheManager : public history::HistoryServiceObserver,
// Number of verdict stored for this profile for real time url check pings.
base::Optional<size_t> stored_verdict_count_real_time_url_check_;
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_service_observer_{this};
+ base::ScopedObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_service_observation_{this};
// Content settings maps associated with this instance.
scoped_refptr<HostContentSettingsMap> content_settings_;
diff --git a/chromium/components/safe_browsing/core/verdict_cache_manager_unittest.cc b/chromium/components/safe_browsing/core/verdict_cache_manager_unittest.cc
index 3fd8d784c89..03622ec86c5 100644
--- a/chromium/components/safe_browsing/core/verdict_cache_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/verdict_cache_manager_unittest.cc
@@ -201,8 +201,7 @@ TEST_F(VerdictCacheManagerTest, TestParseInvalidVerdictEntry) {
content_setting_map_->SetWebsiteSettingDefaultScope(
GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION, std::string(),
- std::move(cache_dictionary));
+ ContentSettingsType::PASSWORD_PROTECTION, std::move(cache_dictionary));
ReusedPasswordAccountType password_type;
password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
@@ -428,8 +427,7 @@ TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
content_setting_map_->SetWebsiteSettingDefaultScope(
GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION, std::string(),
- std::move(cache_dictionary));
+ ContentSettingsType::PASSWORD_PROTECTION, std::move(cache_dictionary));
ReusedPasswordAccountType password_type;
password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
@@ -439,24 +437,22 @@ TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
"www.google.com/", base::Time::Now());
// Verify we saved two entries under PasswordType PRIMARY_ACCOUNT_PASSWORD
- EXPECT_EQ(2U,
- content_setting_map_
- ->GetWebsiteSetting(GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), nullptr)
- ->FindDictKey("1")
- ->DictSize());
+ EXPECT_EQ(2U, content_setting_map_
+ ->GetWebsiteSetting(
+ GURL("http://www.google.com/"), GURL(),
+ ContentSettingsType::PASSWORD_PROTECTION, nullptr)
+ ->FindDictKey("1")
+ ->DictSize());
cache_manager_->CleanUpExpiredVerdicts();
// One should have been cleaned up
- EXPECT_EQ(1U,
- content_setting_map_
- ->GetWebsiteSetting(GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION,
- std::string(), nullptr)
- ->FindDictKey("1")
- ->DictSize());
+ EXPECT_EQ(1U, content_setting_map_
+ ->GetWebsiteSetting(
+ GURL("http://www.google.com/"), GURL(),
+ ContentSettingsType::PASSWORD_PROTECTION, nullptr)
+ ->FindDictKey("1")
+ ->DictSize());
}
TEST_F(VerdictCacheManagerTest, TestCanRetrieveCachedRealTimeUrlCheckVerdict) {
diff --git a/chromium/components/safe_browsing/ios/browser/BUILD.gn b/chromium/components/safe_browsing/ios/browser/BUILD.gn
index 87ca89f183a..4bb03bc35c1 100644
--- a/chromium/components/safe_browsing/ios/browser/BUILD.gn
+++ b/chromium/components/safe_browsing/ios/browser/BUILD.gn
@@ -10,6 +10,7 @@ source_set("allow_list") {
deps = [
"//components/safe_browsing/core/db:v4_protocol_manager_util",
+ "//components/security_interstitials/core:unsafe_resource",
"//ios/web/public",
"//url",
]
diff --git a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h
index 3253e3bdea6..b5169be8282 100644
--- a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h
+++ b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h
@@ -11,6 +11,7 @@
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
+#include "components/security_interstitials/core/unsafe_resource.h"
#import "ios/web/public/web_state_user_data.h"
#include "url/gurl.h"
@@ -50,6 +51,11 @@ class SafeBrowsingUrlAllowList
~SafeBrowsingUrlAllowList() override;
+ // Returns the URL under which allow list decisions should be stored for
+ // |resource|.
+ static GURL GetDecisionUrl(
+ const security_interstitials::UnsafeResource& resource);
+
// Adds and removes observers.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
diff --git a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm
index 763f01145e0..c0f6b9a9dcc 100644
--- a/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm
+++ b/chromium/components/safe_browsing/ios/browser/safe_browsing_url_allow_list.mm
@@ -14,6 +14,13 @@ using safe_browsing::SBThreatType;
WEB_STATE_USER_DATA_KEY_IMPL(SafeBrowsingUrlAllowList)
+// static
+GURL SafeBrowsingUrlAllowList::GetDecisionUrl(
+ const security_interstitials::UnsafeResource& resource) {
+ return resource.navigation_url.is_valid() ? resource.navigation_url
+ : resource.url;
+}
+
SafeBrowsingUrlAllowList::SafeBrowsingUrlAllowList(web::WebState* web_state)
: web_state_(web_state) {}
diff --git a/chromium/components/scheduling_metrics/thread_metrics.cc b/chromium/components/scheduling_metrics/thread_metrics.cc
index fd718388840..f84c100559d 100644
--- a/chromium/components/scheduling_metrics/thread_metrics.cc
+++ b/chromium/components/scheduling_metrics/thread_metrics.cc
@@ -34,7 +34,6 @@ ThreadMetrics::ThreadMetrics(ThreadType thread_type,
ThreadMetrics::~ThreadMetrics() {}
bool ThreadMetrics::ShouldDiscardTask(
- base::sequence_manager::TaskQueue* queue,
const base::sequence_manager::Task& task,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
// TODO(altimin): Investigate the relationship between thread time and
@@ -43,7 +42,6 @@ bool ThreadMetrics::ShouldDiscardTask(
}
void ThreadMetrics::RecordTaskMetrics(
- base::sequence_manager::TaskQueue* queue,
const base::sequence_manager::Task& task,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
DCHECK(!has_cpu_timing_for_each_task_ || task_timing.has_thread_time());
diff --git a/chromium/components/scheduling_metrics/thread_metrics.h b/chromium/components/scheduling_metrics/thread_metrics.h
index a4b2429f8fe..c5d0609dbbf 100644
--- a/chromium/components/scheduling_metrics/thread_metrics.h
+++ b/chromium/components/scheduling_metrics/thread_metrics.h
@@ -25,13 +25,11 @@ class COMPONENT_EXPORT(SCHEDULING_METRICS) ThreadMetrics {
~ThreadMetrics();
bool ShouldDiscardTask(
- base::sequence_manager::TaskQueue* queue,
const base::sequence_manager::Task& task,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing);
// Record task metrics which are shared between threads.
void RecordTaskMetrics(
- base::sequence_manager::TaskQueue* queue,
const base::sequence_manager::Task& task,
const base::sequence_manager::TaskQueue::TaskTiming& task_timing);
diff --git a/chromium/components/scheduling_metrics/thread_metrics_unittest.cc b/chromium/components/scheduling_metrics/thread_metrics_unittest.cc
index 7160af3f75b..987020fdcf9 100644
--- a/chromium/components/scheduling_metrics/thread_metrics_unittest.cc
+++ b/chromium/components/scheduling_metrics/thread_metrics_unittest.cc
@@ -40,19 +40,16 @@ TEST(MetricsHelperTest, TaskDurationPerThreadType) {
false /* has_cpu_timing_for_each_task */);
main_thread_metrics.RecordTaskMetrics(
- nullptr, FakeTask(),
- FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(0),
- ThreadSeconds(15)));
+ FakeTask(), FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(0),
+ ThreadSeconds(15)));
compositor_metrics.RecordTaskMetrics(
- nullptr, FakeTask(),
- FakeTaskTiming(Seconds(10), Seconds(80), ThreadSeconds(0),
- ThreadSeconds(5)));
+ FakeTask(), FakeTaskTiming(Seconds(10), Seconds(80), ThreadSeconds(0),
+ ThreadSeconds(5)));
compositor_metrics.RecordTaskMetrics(
- nullptr, FakeTask(), FakeTaskTiming(Seconds(100), Seconds(200)));
+ FakeTask(), FakeTaskTiming(Seconds(100), Seconds(200)));
worker_metrics.RecordTaskMetrics(
- nullptr, FakeTask(),
- FakeTaskTiming(Seconds(10), Seconds(125), ThreadSeconds(0),
- ThreadSeconds(25)));
+ FakeTask(), FakeTaskTiming(Seconds(10), Seconds(125), ThreadSeconds(0),
+ ThreadSeconds(25)));
EXPECT_THAT(
histogram_tester.GetAllSamples(
@@ -84,13 +81,11 @@ TEST(MetricsHelperTest, TrackedCPUTimeMetrics) {
true /* has_cpu_timing_for_each_task */);
main_thread_metrics.RecordTaskMetrics(
- nullptr, FakeTask(),
- FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(5),
- ThreadSeconds(15)));
+ FakeTask(), FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(5),
+ ThreadSeconds(15)));
main_thread_metrics.RecordTaskMetrics(
- nullptr, FakeTask(),
- FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(20),
- ThreadSeconds(25)));
+ FakeTask(), FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(20),
+ ThreadSeconds(25)));
EXPECT_THAT(histogram_tester.GetAllSamples(
"Scheduler.Experimental.CPUTimePerThread.Tracked"),
diff --git a/chromium/components/schema_org/BUILD.gn b/chromium/components/schema_org/BUILD.gn
index 8bf7a9142f9..9d3f9a7757b 100644
--- a/chromium/components/schema_org/BUILD.gn
+++ b/chromium/components/schema_org/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/compiled_action.gni")
+import("//build/config/python.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
source_set("unit_tests") {
@@ -52,7 +53,8 @@ compiled_action("schema_org_name_data") {
outputs = [ "$target_gen_dir/schema_org_name_data.json" ]
}
-action("generate_schema_org_code") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action("generate_schema_org_code") {
script = "//components/schema_org/generate_schema_org_code.py"
sources = [
diff --git a/chromium/components/schema_org/extractor_fuzzer.cc b/chromium/components/schema_org/extractor_fuzzer.cc
index 239fb0e0a04..fe7713b29c7 100644
--- a/chromium/components/schema_org/extractor_fuzzer.cc
+++ b/chromium/components/schema_org/extractor_fuzzer.cc
@@ -7,7 +7,7 @@
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/schema_org/common/improved_metadata.mojom.h"
#include "components/schema_org/extractor.h"
#include "components/schema_org/schema_org_entity_names.h"
diff --git a/chromium/components/schema_org/extractor_unittest.cc b/chromium/components/schema_org/extractor_unittest.cc
index f0f4013757d..1825c2e75b0 100644
--- a/chromium/components/schema_org/extractor_unittest.cc
+++ b/chromium/components/schema_org/extractor_unittest.cc
@@ -10,7 +10,7 @@
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/schema_org/common/improved_metadata.mojom.h"
#include "components/schema_org/schema_org_entity_names.h"
diff --git a/chromium/components/search/BUILD.gn b/chromium/components/search/BUILD.gn
index 0f00e236b5a..2dc5e567e57 100644
--- a/chromium/components/search/BUILD.gn
+++ b/chromium/components/search/BUILD.gn
@@ -4,14 +4,29 @@
static_library("search") {
sources = [
+ "ntp_features.cc",
+ "ntp_features.h",
+ "repeatable_queries/repeatable_queries_service.cc",
+ "repeatable_queries/repeatable_queries_service.h",
+ "repeatable_queries/repeatable_queries_service_observer.h",
"search.cc",
"search.h",
+ "search_provider_observer.cc",
+ "search_provider_observer.h",
]
deps = [
"//base",
"//components/google/core/common",
+ "//components/history/core/browser",
+ "//components/keyed_service/core",
"//components/search_engines",
+ "//components/signin/public/identity_manager",
+ "//components/variations/net",
+ "//net",
+ "//net/traffic_annotation",
+ "//services/data_decoder/public/cpp",
+ "//services/network/public/cpp",
"//url",
]
}
@@ -19,7 +34,10 @@ static_library("search") {
source_set("unit_tests") {
testonly = true
- sources = [ "search_unittest.cc" ]
+ sources = [
+ "repeatable_queries/repeatable_queries_service_unittest.cc",
+ "search_unittest.cc",
+ ]
if (is_android) {
sources += [ "search_android_unittest.cc" ]
}
@@ -27,7 +45,18 @@ source_set("unit_tests") {
deps = [
":search",
"//base",
+ "//base/test:test_support",
+ "//components/bookmarks/browser",
+ "//components/bookmarks/test",
+ "//components/history/core/test",
+ "//components/omnibox/browser:test_support",
+ "//components/search_engines:search_engines",
+ "//components/search_engines:test_support",
+ "//components/signin/public/base:test_support",
+ "//components/signin/public/identity_manager:test_support",
"//components/variations",
+ "//services/data_decoder/public/cpp:test_support",
+ "//testing/gmock",
"//testing/gtest",
]
}
diff --git a/chromium/components/search/DEPS b/chromium/components/search/DEPS
index d9bc8131244..41868402988 100644
--- a/chromium/components/search/DEPS
+++ b/chromium/components/search/DEPS
@@ -1,5 +1,14 @@
include_rules = [
+ "+components/bookmarks/browser",
+ "+components/bookmarks/test",
"+components/google/core",
+ "+components/history/core",
+ "+components/keyed_service/core",
+ "+components/omnibox/browser",
"+components/search_engines",
+ "+components/signin/public",
"+components/variations",
+ "+net",
+ "+services/data_decoder/public",
+ "+services/network/public",
]
diff --git a/chromium/components/search/ntp_features.cc b/chromium/components/search/ntp_features.cc
new file mode 100644
index 00000000000..e84bac4892a
--- /dev/null
+++ b/chromium/components/search/ntp_features.cc
@@ -0,0 +1,151 @@
+// Copyright 2018 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/search/ntp_features.h"
+
+#include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace ntp_features {
+
+// If enabled, shows a confirm dialog before removing search suggestions from
+// the New Tab page real search box ("realbox").
+const base::Feature kConfirmSuggestionRemovals{
+ "ConfirmNtpSuggestionRemovals", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, "middle slot" promos on the bottom of the NTP will show a dismiss
+// UI that allows users to close them and not see them again.
+const base::Feature kDismissPromos{"DismissNtpPromos",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, the OneGooleBar is loaded in an iframe. Otherwise, it is inlined.
+const base::Feature kIframeOneGoogleBar{"IframeOneGoogleBar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, queries that are frequently repeated by the user (and are
+// expected to be issued again) are shown as most visited tiles.
+const base::Feature kNtpRepeatableQueries{"NtpRepeatableQueries",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, the iframed OneGooleBar shows the overlays modally with a
+// backdrop.
+const base::Feature kOneGoogleBarModalOverlays{
+ "OneGoogleBarModalOverlays", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Depends on kRealbox being enabled. If enabled, the NTP "realbox" will be
+// themed like the omnibox (same background/text/selected/hover colors).
+const base::Feature kRealboxMatchOmniboxTheme{
+ "NtpRealboxMatchOmniboxTheme", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, the real search box ("realbox") on the New Tab page will show a
+// Google (g) icon instead of the typical magnifying glass (aka loupe).
+const base::Feature kRealboxUseGoogleGIcon{"NtpRealboxUseGoogleGIcon",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, shows Vasco suggestion chips in the NTP below fakebox/realbox
+// despite other config except DisableSearchSuggestChips below.
+const base::Feature kSearchSuggestChips{"SearchSuggestChips",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, hides Vasco suggestion chips in the NTP below fakebox/realbox
+// despite other config.
+const base::Feature kDisableSearchSuggestChips{
+ "DisableSearchSuggestChips", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, handles navigations from the Most Visited tiles explicitly and
+// overrides the navigation's transition type to bookmark navigation before the
+// navigation is issued.
+// TODO(crbug.com/1147589): When removing this flag, also remove the workaround
+// in ChromeContentBrowserClient::OverrideNavigationParams.
+extern const base::Feature kNtpHandleMostVisitedNavigationExplicitly{
+ "HandleMostVisitedNavigationExplicitly", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// If enabled, the WebUI new tab page will load when a new tab is created
+// instead of the local NTP.
+const base::Feature kWebUI{"NtpWebUI", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// If enabled, the Doodle will be shown on themed and dark mode NTPs.
+const base::Feature kWebUIThemeModeDoodles{"WebUIThemeModeDoodles",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// If enabled, modules will be shown.
+const base::Feature kModules{"NtpModules", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, recipe tasks module will be shown.
+const base::Feature kNtpRecipeTasksModule{"NtpRecipeTasksModule",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, shopping tasks module will be shown.
+const base::Feature kNtpShoppingTasksModule{"NtpShoppingTasksModule",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kNtpRepeatableQueriesAgeThresholdDaysParam[] =
+ "NtpRepeatableQueriesAgeThresholdDays";
+const char kNtpRepeatableQueriesRecencyHalfLifeSecondsParam[] =
+ "NtpRepeatableQueriesRecencyHalfLifeSeconds";
+const char kNtpRepeatableQueriesFrequencyExponentParam[] =
+ "NtpRepeatableQueriesFrequencyExponent";
+const char kNtpRepeatableQueriesInsertPositionParam[] =
+ "NtpRepeatableQueriesInsertPosition";
+
+const char kNtpStatefulTasksModuleDataParam[] =
+ "NtpStatefulTasksModuleDataParam";
+
+base::Time GetLocalHistoryRepeatableQueriesAgeThreshold() {
+ const base::TimeDelta kLocalHistoryRepeatableQueriesAgeThreshold =
+ base::TimeDelta::FromDays(180); // Six months.
+ std::string param_value = base::GetFieldTrialParamValueByFeature(
+ kNtpRepeatableQueries, kNtpRepeatableQueriesAgeThresholdDaysParam);
+
+ // If the field trial param is not found or cannot be parsed to an unsigned
+ // integer, return the default value.
+ unsigned int param_value_as_int = 0;
+ if (!base::StringToUint(param_value, &param_value_as_int)) {
+ return base::Time::Now() - kLocalHistoryRepeatableQueriesAgeThreshold;
+ }
+
+ return (base::Time::Now() - base::TimeDelta::FromDays(param_value_as_int));
+}
+
+int GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds() {
+ const base::TimeDelta kLocalHistoryRepeatableQueriesRecencyHalfLife =
+ base::TimeDelta::FromDays(7); // One week.
+ std::string param_value = base::GetFieldTrialParamValueByFeature(
+ kNtpRepeatableQueries, kNtpRepeatableQueriesRecencyHalfLifeSecondsParam);
+
+ // If the field trial param is not found or cannot be parsed to an unsigned
+ // integer, return the default value.
+ unsigned int param_value_as_int = 0;
+ if (!base::StringToUint(param_value, &param_value_as_int)) {
+ return kLocalHistoryRepeatableQueriesRecencyHalfLife.InSeconds();
+ }
+
+ return param_value_as_int;
+}
+
+double GetLocalHistoryRepeatableQueriesFrequencyExponent() {
+ const double kLocalHistoryRepeatableQueriesFrequencyExponent = 2.0;
+ std::string param_value = base::GetFieldTrialParamValueByFeature(
+ kNtpRepeatableQueries, kNtpRepeatableQueriesFrequencyExponentParam);
+
+ // If the field trial param is not found or cannot be parsed to an unsigned
+ // integer, return the default value.
+ double param_value_as_double = 0;
+ if (!base::StringToDouble(param_value, &param_value_as_double)) {
+ return kLocalHistoryRepeatableQueriesFrequencyExponent;
+ }
+
+ return param_value_as_double;
+}
+
+RepeatableQueriesInsertPosition GetRepeatableQueriesInsertPosition() {
+ std::string param_value = base::GetFieldTrialParamValueByFeature(
+ kNtpRepeatableQueries, kNtpRepeatableQueriesInsertPositionParam);
+ return param_value == "end" ? RepeatableQueriesInsertPosition::kEnd
+ : RepeatableQueriesInsertPosition::kStart;
+}
+
+} // namespace ntp_features
diff --git a/chromium/components/search/ntp_features.h b/chromium/components/search/ntp_features.h
new file mode 100644
index 00000000000..d2f6e1e5b9e
--- /dev/null
+++ b/chromium/components/search/ntp_features.h
@@ -0,0 +1,76 @@
+// Copyright 2018 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_SEARCH_NTP_FEATURES_H_
+#define COMPONENTS_SEARCH_NTP_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace base {
+class Time;
+} // namespace base
+
+namespace ntp_features {
+
+// The features should be documented alongside the definition of their values in
+// the .cc file.
+
+extern const base::Feature kConfirmSuggestionRemovals;
+extern const base::Feature kDismissPromos;
+extern const base::Feature kIframeOneGoogleBar;
+extern const base::Feature kNtpRepeatableQueries;
+extern const base::Feature kOneGoogleBarModalOverlays;
+extern const base::Feature kRealboxMatchOmniboxTheme;
+extern const base::Feature kRealboxUseGoogleGIcon;
+extern const base::Feature kWebUI;
+extern const base::Feature kWebUIThemeModeDoodles;
+extern const base::Feature kModules;
+extern const base::Feature kNtpRecipeTasksModule;
+extern const base::Feature kNtpShoppingTasksModule;
+
+extern const base::Feature kSearchSuggestChips;
+extern const base::Feature kDisableSearchSuggestChips;
+
+extern const base::Feature kNtpHandleMostVisitedNavigationExplicitly;
+
+// Parameter name determining the age threshold in days for local history
+// repeatable queries.
+// The value of this parameter should be parsable as an unsigned integer.
+extern const char kNtpRepeatableQueriesAgeThresholdDaysParam[];
+// Parameter name determining the number of seconds until the recency component
+// of the frecency score for local history repeatable queries decays to half.
+// The value of this parameter should be parsable as an unsigned integer.
+extern const char kNtpRepeatableQueriesRecencyHalfLifeSecondsParam[];
+// Parameter name determining the factor by which the frequency component of the
+// frecency score for local history repeatable queries is exponentiated.
+// The value of this parameter should be parsable as a double.
+extern const char kNtpRepeatableQueriesFrequencyExponentParam[];
+// Parameter name determining the position, with respect to the MV tiles, in
+// which the repeatable queries should be inserted.
+extern const char kNtpRepeatableQueriesInsertPositionParam[];
+// The available positions, with respect to the MV tiles, in which the
+// repeatable queries can be inserted.
+enum class RepeatableQueriesInsertPosition {
+ kStart = 0, // At the start of MV tiles.
+ kEnd, // At the end of MV tiles.
+};
+
+// Parameter determining the type of stateful data to request.
+extern const char kNtpStatefulTasksModuleDataParam[];
+
+// Returns the age threshold for local history repeatable queries.
+base::Time GetLocalHistoryRepeatableQueriesAgeThreshold();
+// Returns the number of seconds until the recency component of the frecency
+// score for local history repeatable queries decays to half.
+int GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
+// Returns the factor by which the frequency component of the frecency score for
+// local history repeatable queries is exponentiated.
+double GetLocalHistoryRepeatableQueriesFrequencyExponent();
+// Returns the position, with respect to the MV tiles, in which the repeatable
+// queries should be inserted.
+RepeatableQueriesInsertPosition GetRepeatableQueriesInsertPosition();
+
+} // namespace ntp_features
+
+#endif // COMPONENTS_SEARCH_NTP_FEATURES_H_
diff --git a/chromium/components/search/repeatable_queries/repeatable_queries_service.cc b/chromium/components/search/repeatable_queries/repeatable_queries_service.cc
new file mode 100644
index 00000000000..cbb4ae5f001
--- /dev/null
+++ b/chromium/components/search/repeatable_queries/repeatable_queries_service.cc
@@ -0,0 +1,487 @@
+// Copyright 2020 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/search/repeatable_queries/repeatable_queries_service.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/json/json_writer.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/scoped_observation.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history/core/browser/keyword_search_term.h"
+#include "components/history/core/browser/url_database.h"
+#include "components/search/ntp_features.h"
+#include "components/search/search_provider_observer.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/variations/net/variations_http_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace {
+const char kXSSIResponsePreamble[] = ")]}'";
+const size_t kMaxQueries = 2;
+
+bool JsonToRepeatableQueriesData(const base::Value& root_value,
+ std::vector<RepeatableQuery>* data) {
+ // 1st element is the query. 2nd element is the list of results.
+ base::string16 query;
+ const base::ListValue* root_list = nullptr;
+ const base::ListValue* results_list = nullptr;
+ if (!root_value.GetAsList(&root_list) || !root_list->GetString(0, &query) ||
+ !query.empty() || !root_list->GetList(1, &results_list))
+ return false;
+
+ // Ignore the 3rd and 4th elements. 5th element is the key-value pairs from
+ // the Suggest server containing the deletion URLs.
+ const base::DictionaryValue* extras = nullptr;
+ const base::ListValue* suggestion_details = nullptr;
+ if (!root_list->GetDictionary(4, &extras) ||
+ !extras->GetList("google:suggestdetail", &suggestion_details) ||
+ suggestion_details->GetSize() != results_list->GetSize()) {
+ return false;
+ }
+
+ base::string16 suggestion;
+ for (size_t index = 0; results_list->GetString(index, &suggestion); ++index) {
+ RepeatableQuery result;
+ result.query = base::CollapseWhitespace(suggestion, false);
+ if (result.query.empty())
+ continue;
+
+ const base::DictionaryValue* suggestion_detail = nullptr;
+ if (suggestion_details->GetDictionary(index, &suggestion_detail)) {
+ suggestion_detail->GetString("du", &result.deletion_url);
+ }
+ data->push_back(result);
+ }
+
+ return !data->empty();
+}
+} // namespace
+
+// static
+const char RepeatableQueriesService::kExtractedCountHistogram[] =
+ "NewTabPage.RepeatableQueries.ExtractedCount";
+const char RepeatableQueriesService::kExtractionDurationHistogram[] =
+ "NewTabPage.RepeatableQueries.ExtractionDuration";
+
+class RepeatableQueriesService::SigninObserver
+ : public signin::IdentityManager::Observer {
+ public:
+ SigninObserver(signin::IdentityManager* identity_manager,
+ base::RepeatingClosure callback)
+ : identity_manager_(identity_manager), callback_(std::move(callback)) {
+ if (identity_manager_) {
+ identity_manager_observation_.Observe(identity_manager_);
+ }
+ }
+ ~SigninObserver() override = default;
+
+ bool IsSignedIn() {
+ return identity_manager_ ? !identity_manager_->GetAccountsInCookieJar()
+ .signed_in_accounts.empty()
+ : false;
+ }
+
+ private:
+ // IdentityManager::Observer implementation.
+ void OnAccountsInCookieUpdated(
+ const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) override {
+ callback_.Run();
+ }
+
+ base::ScopedObservation<signin::IdentityManager,
+ signin::IdentityManager::Observer>
+ identity_manager_observation_{this};
+ // May be nullptr in tests.
+ signin::IdentityManager* const identity_manager_;
+ base::RepeatingClosure callback_;
+};
+
+RepeatableQueriesService::RepeatableQueriesService(
+ signin::IdentityManager* identity_manager,
+ history::HistoryService* history_service,
+ TemplateURLService* template_url_service,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ const GURL& request_initiator_url)
+ : history_service_(history_service),
+ template_url_service_(template_url_service),
+ url_loader_factory_(url_loader_factory),
+ request_initiator_url_(request_initiator_url),
+ signin_observer_(std::make_unique<SigninObserver>(
+ identity_manager,
+ base::BindRepeating(&RepeatableQueriesService::SigninStatusChanged,
+ base::Unretained(this)))),
+ search_provider_observer_(std::make_unique<SearchProviderObserver>(
+ template_url_service,
+ base::BindRepeating(&RepeatableQueriesService::SearchProviderChanged,
+ base::Unretained(this)))) {
+ DCHECK(history_service_);
+ DCHECK(template_url_service_);
+ DCHECK(url_loader_factory_);
+}
+
+RepeatableQueriesService::~RepeatableQueriesService() = default;
+
+void RepeatableQueriesService::Shutdown() {
+ for (auto& observer : observers_) {
+ observer.OnRepeatableQueriesServiceShuttingDown();
+ }
+}
+
+const std::vector<RepeatableQuery>&
+RepeatableQueriesService::repeatable_queries() const {
+ return repeatable_queries_;
+}
+
+void RepeatableQueriesService::Refresh() {
+ if (!search_provider_observer()->is_google()) {
+ NotifyObservers();
+ return;
+ }
+
+ if (signin_observer()->IsSignedIn()) {
+ GetRepeatableQueriesFromServer();
+ } else {
+ GetRepeatableQueriesFromURLDatabase();
+ }
+}
+
+void RepeatableQueriesService::DeleteQueryWithDestinationURL(const GURL& url) {
+ auto it = std::find_if(repeatable_queries_.begin(), repeatable_queries_.end(),
+ [&url](const auto& repeatable_query) {
+ return repeatable_query.destination_url == url;
+ });
+
+ // Return if no repeatable query with a matching destination URL exists.
+ if (it == repeatable_queries_.end()) {
+ // Still notify observers of the deletion attempt.
+ NotifyObservers();
+ return;
+ }
+
+ if (it->deletion_url.empty()) {
+ DeleteRepeatableQueryFromURLDatabase(it->query);
+ } else {
+ DeleteRepeatableQueryFromServer(it->deletion_url);
+ }
+
+ // Delete all the Google search URLs for the given query from history.
+ history_service_->DeleteMatchingURLsForKeyword(
+ template_url_service_->GetDefaultSearchProvider()->id(), it->query);
+
+ // Make sure the query is not suggested again.
+ MarkQueryAsDeleted(it->query);
+
+ // Update the repeatable queries and notify the observers.
+ repeatable_queries_.erase(it);
+ NotifyObservers();
+}
+
+void RepeatableQueriesService::AddObserver(
+ RepeatableQueriesServiceObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RepeatableQueriesService::RemoveObserver(
+ RepeatableQueriesServiceObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+RepeatableQueriesService::SigninObserver*
+RepeatableQueriesService::signin_observer() {
+ return signin_observer_.get();
+}
+
+SearchProviderObserver* RepeatableQueriesService::search_provider_observer() {
+ return search_provider_observer_.get();
+}
+
+void RepeatableQueriesService::SearchProviderChanged() {
+ // If we have cached data, clear it.
+ repeatable_queries_.clear();
+ Refresh();
+}
+
+void RepeatableQueriesService::SigninStatusChanged() {
+ // If we have cached data, clear it.
+ repeatable_queries_.clear();
+ Refresh();
+}
+
+GURL RepeatableQueriesService::GetQueryDestinationURL(
+ const base::string16& query) {
+ TemplateURLRef::SearchTermsArgs search_terms_args(query);
+ const TemplateURLRef& search_url_ref =
+ template_url_service_->GetDefaultSearchProvider()->url_ref();
+ const SearchTermsData& search_terms_data =
+ template_url_service_->search_terms_data();
+ DCHECK(search_url_ref.SupportsReplacement(search_terms_data));
+ return GURL(
+ search_url_ref.ReplaceSearchTerms(search_terms_args, search_terms_data));
+}
+
+GURL RepeatableQueriesService::GetQueryDeletionURL(
+ const std::string& deletion_url) {
+ const auto* default_provider =
+ template_url_service_->GetDefaultSearchProvider();
+ const SearchTermsData& search_terms_data =
+ template_url_service_->search_terms_data();
+ GURL request_url = default_provider->GenerateSearchURL(search_terms_data);
+ return request_url.GetOrigin().Resolve(deletion_url);
+}
+
+GURL RepeatableQueriesService::GetRequestURL() {
+ TemplateURLRef::SearchTermsArgs search_terms_args;
+ search_terms_args.request_source = TemplateURLRef::NON_SEARCHBOX_NTP;
+ const TemplateURLRef& suggestion_url_ref =
+ template_url_service_->GetDefaultSearchProvider()->suggestions_url_ref();
+ const SearchTermsData& search_terms_data =
+ template_url_service_->search_terms_data();
+ DCHECK(suggestion_url_ref.SupportsReplacement(search_terms_data));
+ return GURL(suggestion_url_ref.ReplaceSearchTerms(search_terms_args,
+ search_terms_data));
+}
+
+void RepeatableQueriesService::GetRepeatableQueriesFromServer() {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("repeatable_queries_service", R"(
+ semantics {
+ sender: "Repeatable Queries Service"
+ description:
+ "Downloads search queries to be shown on the Most Visited "
+ "section of New Tab Page to signed-in users based on their "
+ "previous search history."
+ trigger:
+ "Displaying the new tab page, if Google is the "
+ "configured search provider, and the user is signed in."
+ data: "Google credentials if user is signed in."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting:
+ "Users can control this feature by selecting a non-Google default "
+ "search engine in Chrome settings under 'Search Engine', or by "
+ "signing out of the browser on the New Tab Page. Users can opt "
+ "out of this feature by switching to custom shortcuts."
+ chrome_policy {
+ DefaultSearchProviderEnabled {
+ policy_options {mode: MANDATORY}
+ DefaultSearchProviderEnabled: false
+ }
+ BrowserSignin {
+ policy_options {mode: MANDATORY}
+ BrowserSignin: 0
+ }
+ }
+ })");
+
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ const GURL& request_url = GetRequestURL();
+ variations::AppendVariationsHeaderUnknownSignedIn(
+ request_url, variations::InIncognito::kNo, resource_request.get());
+ resource_request->url = request_url;
+ resource_request->request_initiator =
+ url::Origin::Create(request_initiator_url_);
+
+ loaders_.push_back(network::SimpleURLLoader::Create(
+ std::move(resource_request), traffic_annotation));
+ loaders_.back()->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(&RepeatableQueriesService::RepeatableQueriesResponseLoaded,
+ weak_ptr_factory_.GetWeakPtr(), loaders_.back().get()),
+ network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
+}
+
+void RepeatableQueriesService::RepeatableQueriesResponseLoaded(
+ network::SimpleURLLoader* loader,
+ std::unique_ptr<std::string> response) {
+ auto net_error = loader->NetError();
+ base::EraseIf(loaders_, [loader](const auto& loader_ptr) {
+ return loader == loader_ptr.get();
+ });
+
+ if (net_error != net::OK || !response) {
+ // In the case of network errors, keep the cached data, if any, but still
+ // notify observers of the finished load attempt.
+ NotifyObservers();
+ return;
+ }
+
+ if (base::StartsWith(*response, kXSSIResponsePreamble,
+ base::CompareCase::SENSITIVE)) {
+ *response = response->substr(strlen(kXSSIResponsePreamble));
+ }
+
+ data_decoder::DataDecoder::ParseJsonIsolated(
+ *response,
+ base::BindOnce(&RepeatableQueriesService::RepeatableQueriesParsed,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RepeatableQueriesService::RepeatableQueriesParsed(
+ data_decoder::DataDecoder::ValueOrError result) {
+ repeatable_queries_.clear();
+
+ std::vector<RepeatableQuery> queries;
+ if (result.value && JsonToRepeatableQueriesData(*result.value, &queries)) {
+ for (auto& query : queries) {
+ if (IsQueryDeleted(query.query))
+ continue;
+ query.destination_url = GetQueryDestinationURL(query.query);
+ repeatable_queries_.push_back(query);
+ if (repeatable_queries_.size() >= kMaxQueries)
+ break;
+ }
+ }
+
+ NotifyObservers();
+}
+
+void RepeatableQueriesService::GetRepeatableQueriesFromURLDatabase() {
+ repeatable_queries_.clear();
+
+ // Fail if the in-memory URL database is not available.
+ history::URLDatabase* url_db = history_service_->InMemoryDatabase();
+ if (!url_db)
+ return;
+
+ const base::TimeTicks db_query_time = base::TimeTicks::Now();
+ auto results = url_db->GetMostRecentNormalizedKeywordSearchTerms(
+ template_url_service_->GetDefaultSearchProvider()->id(),
+ ntp_features::GetLocalHistoryRepeatableQueriesAgeThreshold());
+
+ const base::Time now = base::Time::Now();
+ const int kRecencyDecayUnitSec =
+ ntp_features::GetLocalHistoryRepeatableQueriesRecencyHalfLifeSeconds();
+ const double kFrequencyExponent =
+ ntp_features::GetLocalHistoryRepeatableQueriesFrequencyExponent();
+ auto CompareByFrecency = [&](const auto& a, const auto& b) {
+ return a.GetFrecency(now, kRecencyDecayUnitSec, kFrequencyExponent) >
+ b.GetFrecency(now, kRecencyDecayUnitSec, kFrequencyExponent);
+ };
+ std::sort(results.begin(), results.end(), CompareByFrecency);
+
+ for (const auto& result : results) {
+ RepeatableQuery repeatable_query;
+ repeatable_query.query = result.normalized_term;
+ if (IsQueryDeleted(repeatable_query.query))
+ continue;
+ repeatable_query.destination_url =
+ GetQueryDestinationURL(repeatable_query.query);
+ repeatable_queries_.push_back(repeatable_query);
+ if (repeatable_queries_.size() >= kMaxQueries)
+ break;
+ }
+
+ base::UmaHistogramTimes(kExtractionDurationHistogram,
+ base::TimeTicks::Now() - db_query_time);
+ base::UmaHistogramCounts10000(kExtractedCountHistogram, results.size());
+
+ NotifyObservers();
+}
+
+void RepeatableQueriesService::DeleteRepeatableQueryFromServer(
+ const std::string& deletion_url) {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("repeatable_queries_deletion", R"(
+ semantics {
+ sender: "Repeatable Queries Service"
+ description:
+ "When users attempt to delete a server-provided repeatable search "
+ "query from the Most Visited section of New Tab Page, Chrome sends "
+ "a request to the server requesting deletion of that suggestion."
+ trigger:
+ "User attempts to delete a server-provided repeatable search "
+ "query for which the server provided a custom deletion URL from "
+ "the Most Visited section of New Tab Page, if Google is the "
+ "configured search provider, and the user is signed in."
+ data: "Google credentials if user is signed in."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting:
+ "Users can control this feature by selecting a non-Google default "
+ "search engine in Chrome settings under 'Search Engine', or by "
+ "signing out of the browser on the New Tab Page. Users can opt "
+ "out of this feature by switching to custom shortcuts."
+ chrome_policy {
+ DefaultSearchProviderEnabled {
+ policy_options {mode: MANDATORY}
+ DefaultSearchProviderEnabled: false
+ }
+ BrowserSignin {
+ policy_options {mode: MANDATORY}
+ BrowserSignin: 0
+ }
+ }
+ })");
+
+ GURL request_url = GetQueryDeletionURL(deletion_url);
+ auto deletion_request = std::make_unique<network::ResourceRequest>();
+ variations::AppendVariationsHeaderUnknownSignedIn(
+ request_url, variations::InIncognito::kNo, deletion_request.get());
+ deletion_request->url = request_url;
+ deletion_request->request_initiator =
+ url::Origin::Create(request_initiator_url_);
+
+ loaders_.push_back(network::SimpleURLLoader::Create(
+ std::move(deletion_request), traffic_annotation));
+ loaders_.back()->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(&RepeatableQueriesService::DeletionResponseLoaded,
+ weak_ptr_factory_.GetWeakPtr(), loaders_.back().get()),
+ network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
+}
+
+void RepeatableQueriesService::DeletionResponseLoaded(
+ network::SimpleURLLoader* loader,
+ std::unique_ptr<std::string> response) {
+ base::EraseIf(loaders_, [loader](const auto& loader_ptr) {
+ return loader == loader_ptr.get();
+ });
+}
+
+void RepeatableQueriesService::DeleteRepeatableQueryFromURLDatabase(
+ const base::string16& query) {
+ // Fail if the in-memory URL database is not available.
+ history::URLDatabase* url_db = history_service_->InMemoryDatabase();
+ if (!url_db)
+ return;
+
+ // Delete all the search terms matching the repeatable query suggestion from
+ // the in-memory URL database.
+ url_db->DeleteKeywordSearchTermForNormalizedTerm(
+ template_url_service_->GetDefaultSearchProvider()->id(), query);
+}
+
+void RepeatableQueriesService::NotifyObservers() {
+ for (auto& observer : observers_) {
+ observer.OnRepeatableQueriesUpdated();
+ }
+}
+
+bool RepeatableQueriesService::IsQueryDeleted(const base::string16& query) {
+ return base::Contains(deleted_repeatable_queries_, query);
+}
+
+void RepeatableQueriesService::MarkQueryAsDeleted(const base::string16& query) {
+ deleted_repeatable_queries_.insert(query);
+}
diff --git a/chromium/components/search/repeatable_queries/repeatable_queries_service.h b/chromium/components/search/repeatable_queries/repeatable_queries_service.h
new file mode 100644
index 00000000000..348e8881e20
--- /dev/null
+++ b/chromium/components/search/repeatable_queries/repeatable_queries_service.h
@@ -0,0 +1,175 @@
+// Copyright 2020 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_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
+#define COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/search/repeatable_queries/repeatable_queries_service_observer.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+#include "url/gurl.h"
+
+class SearchProviderObserver;
+class TemplateURLService;
+
+namespace history {
+class HistoryService;
+} // namespace history
+
+namespace network {
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
+} // namespace network
+
+namespace signin {
+class IdentityManager;
+} // namespace signin
+
+// Represents a repeatable query suggestion.
+class RepeatableQuery {
+ public:
+ RepeatableQuery() = default;
+ ~RepeatableQuery() = default;
+
+ bool operator==(const RepeatableQuery& other) const {
+ return query == other.query && destination_url == other.destination_url &&
+ deletion_url == other.deletion_url;
+ }
+ bool operator!=(const RepeatableQuery& other) const {
+ return !(this == &other);
+ }
+
+ // Repeatable query suggestion.
+ base::string16 query;
+
+ // The URL to navigate to when the suggestion is selected.
+ GURL destination_url;
+
+ // The relative endpoint used for deleting the query suggestion on the server.
+ // Populated for server provided queries only.
+ std::string deletion_url;
+};
+
+// Provides repeatable query suggestions to be shown in the NTP Most Visited
+// tiles when Google is the default search provider. The repeatable queries are
+// requested from the server for signed-in users and extracted from the URL
+// database for unauthenticated users.
+class RepeatableQueriesService : public KeyedService {
+ public:
+ RepeatableQueriesService(
+ signin::IdentityManager* identity_manager,
+ history::HistoryService* history_service,
+ TemplateURLService* template_url_service,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ const GURL& request_initiator_url);
+ ~RepeatableQueriesService() override;
+ RepeatableQueriesService(const RepeatableQueriesService&) = delete;
+ RepeatableQueriesService& operator=(const RepeatableQueriesService&) = delete;
+
+ // Histograms recorded by this class.
+ static const char kExtractedCountHistogram[];
+ static const char kExtractionDurationHistogram[];
+
+ // KeyedService:
+ void Shutdown() override;
+
+ // Returns the currently cached repeatable query suggestions, if any.
+ const std::vector<RepeatableQuery>& repeatable_queries() const;
+
+ // If Google is the default search provider, asynchronously requests
+ // repeatable query suggestions from the server for signed-in users and
+ // synchronously extracts them from the URL database for
+ // unauthenticated users. Regardless of success, observers are notified via
+ // RepeatableQueriesServiceObserver::OnRepeatableQueriesUpdated.
+ void Refresh();
+
+ // Deletes the records of the repeatable query suggestion with the given
+ // destination URL on the server as well as on the device, whichever is
+ // applicable. Prevents the suggestion from being offered again by
+ // blocklisting it. Updates the current set of suggestions and notifies the
+ // observers.
+ void DeleteQueryWithDestinationURL(const GURL& url);
+
+ // Add/remove observers.
+ void AddObserver(RepeatableQueriesServiceObserver* observer);
+ void RemoveObserver(RepeatableQueriesServiceObserver* observer);
+
+ protected:
+ class SigninObserver;
+
+ virtual SigninObserver* signin_observer();
+ virtual SearchProviderObserver* search_provider_observer();
+
+ // Called when the default search provider changes.
+ void SearchProviderChanged();
+
+ // Called when the signin status changes.
+ void SigninStatusChanged();
+
+ // Returns the server destination URL for |query|.
+ GURL GetQueryDestinationURL(const base::string16& query);
+
+ // Returns the resolved deletion URL for the given relative deletion URL.
+ GURL GetQueryDeletionURL(const std::string& deletion_url);
+
+ // Returns the server request URL.
+ GURL GetRequestURL();
+
+ private:
+ // Requests repeatable queries from the server. Called for signed-in users.
+ void GetRepeatableQueriesFromServer();
+ void RepeatableQueriesResponseLoaded(network::SimpleURLLoader* loader,
+ std::unique_ptr<std::string> response);
+ void RepeatableQueriesParsed(data_decoder::DataDecoder::ValueOrError result);
+
+ // Queries the in-memory URLDatabase for the repeatable queries submitted
+ // to the default search provider. Called for unauthenticated users.
+ void GetRepeatableQueriesFromURLDatabase();
+
+ // Deletes |query| from the in-memory URLDatabase.
+ void DeleteRepeatableQueryFromURLDatabase(const base::string16& query);
+
+ // Deletes the query with |deletion_url| from the server.
+ void DeleteRepeatableQueryFromServer(const std::string& deletion_url);
+ void DeletionResponseLoaded(network::SimpleURLLoader* loader,
+ std::unique_ptr<std::string> response);
+
+ void NotifyObservers();
+
+ bool IsQueryDeleted(const base::string16& query);
+ void MarkQueryAsDeleted(const base::string16& query);
+
+ history::HistoryService* history_service_;
+
+ TemplateURLService* template_url_service_;
+
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+ const GURL request_initiator_url_;
+
+ std::unique_ptr<SigninObserver> signin_observer_;
+
+ std::unique_ptr<SearchProviderObserver> search_provider_observer_;
+
+ base::ObserverList<RepeatableQueriesServiceObserver, true> observers_;
+
+ std::vector<RepeatableQuery> repeatable_queries_;
+
+ // Used to ensure the deleted repeatable queries won't be suggested again.
+ // This does not need to be persisted across sessions as the queries do get
+ // deleted on the server as well as on the device, whichever is applicable.
+ std::set<base::string16> deleted_repeatable_queries_;
+
+ std::vector<std::unique_ptr<network::SimpleURLLoader>> loaders_;
+
+ base::WeakPtrFactory<RepeatableQueriesService> weak_ptr_factory_{this};
+};
+
+#endif // COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_H_
diff --git a/chromium/components/search/repeatable_queries/repeatable_queries_service_observer.h b/chromium/components/search/repeatable_queries/repeatable_queries_service_observer.h
new file mode 100644
index 00000000000..2b17f87bf07
--- /dev/null
+++ b/chromium/components/search/repeatable_queries/repeatable_queries_service_observer.h
@@ -0,0 +1,23 @@
+// Copyright 2020 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_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
+#define COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
+
+// Observer class for the RepeatableQueriesService.
+class RepeatableQueriesServiceObserver : public base::CheckedObserver {
+ public:
+ // Called after a Refresh() call on the service, either directly or as a
+ // result of default search provider or signin status change. Note that this
+ // is called after each Refresh(), even if the network request failed, or if
+ // it didn't result in an actual change to the cached data. Observers can get
+ // the repeatable queries via RepeatableQueriesService::repeatable_queries().
+ virtual void OnRepeatableQueriesUpdated() = 0;
+
+ // Called when the service is shutting down allowing the observers to
+ // unregister themselves and clear references to the service.
+ virtual void OnRepeatableQueriesServiceShuttingDown() {}
+};
+
+#endif // COMPONENTS_SEARCH_REPEATABLE_QUERIES_REPEATABLE_QUERIES_SERVICE_OBSERVER_H_
diff --git a/chromium/components/search/repeatable_queries/repeatable_queries_service_unittest.cc b/chromium/components/search/repeatable_queries/repeatable_queries_service_unittest.cc
new file mode 100644
index 00000000000..997ff452b68
--- /dev/null
+++ b/chromium/components/search/repeatable_queries/repeatable_queries_service_unittest.cc
@@ -0,0 +1,662 @@
+// Copyright 2020 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/search/repeatable_queries/repeatable_queries_service.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/cancelable_callback.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/optional.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/url_database.h"
+#include "components/history/core/test/history_service_test_util.h"
+#include "components/omnibox/browser/in_memory_url_index.h"
+#include "components/omnibox/browser/in_memory_url_index_test_util.h"
+#include "components/search/search.h"
+#include "components/search/search_provider_observer.h"
+#include "components/search_engines/search_engines_test_util.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/signin/public/base/test_signin_client.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
+#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace {
+
+std::string GoodServerResponse() {
+ return R"()]}'
+[
+ "",
+ [
+ "server query 1",
+ "server query 2",
+ "server query 3"
+ ],
+ [],
+ [],
+ {
+ "google:suggestdetail":[
+ {
+ "du":"/delete?server+query+1"
+ },
+ {
+ "du":"/delete?server+query+2"
+ },
+ {
+ "du":"/delete?server+query+3"
+ }
+ ]
+ }
+])";
+}
+
+std::string BadServerResponse1() {
+ return R"()]}'
+[
+ "",
+ [
+ "server query 1",
+ "server query 2",
+ "server query 3"
+ ],
+ [],
+ [],
+ {
+ }
+])";
+}
+
+std::string BadServerResponse2() {
+ return R"()]}'
+[
+ "",
+ [
+ "server query 1",
+ "server query 2",
+ "server query 3"
+ ],
+ [],
+ [],
+ {
+ "google:suggestdetail":[
+ {
+ "du":"/delete?server+query+1"
+ },
+ {
+ "du":"/delete?server+query+2"
+ },
+ ]
+ }
+])";
+}
+
+// Used to populate the URLDatabase.
+struct TestURLData {
+ const TemplateURL* search_provider;
+ std::string search_terms;
+ int age_in_seconds;
+ int visit_count = 1;
+ std::string title = "";
+ int typed_count = 1;
+ bool hidden = false;
+};
+
+} // namespace
+
+class MockSearchProviderObserver : public SearchProviderObserver {
+ public:
+ MockSearchProviderObserver()
+ : SearchProviderObserver(/*template_url_service=*/nullptr,
+ base::DoNothing::Repeatedly()) {}
+ ~MockSearchProviderObserver() override = default;
+
+ MOCK_METHOD0(is_google, bool());
+};
+
+class TestRepeatableQueriesService : public RepeatableQueriesService {
+ public:
+ TestRepeatableQueriesService(
+ signin::IdentityManager* identity_manager,
+ history::HistoryService* history_service,
+ TemplateURLService* template_url_service,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ const GURL& request_initiator_url)
+ : RepeatableQueriesService(identity_manager,
+ history_service,
+ template_url_service,
+ std::move(url_loader_factory),
+ request_initiator_url) {}
+ ~TestRepeatableQueriesService() override = default;
+
+ MockSearchProviderObserver* search_provider_observer() override {
+ return &search_provider_observer_;
+ }
+
+ GURL GetQueryDestinationURL(const base::string16& query) {
+ return RepeatableQueriesService::GetQueryDestinationURL(query);
+ }
+
+ GURL GetQueryDeletionURL(const std::string& deletion_url) {
+ return RepeatableQueriesService::GetQueryDeletionURL(deletion_url);
+ }
+
+ GURL GetRequestURL() { return RepeatableQueriesService::GetRequestURL(); }
+
+ void SearchProviderChanged() {
+ RepeatableQueriesService::SearchProviderChanged();
+ }
+
+ void SigninStatusChanged() {
+ RepeatableQueriesService::SigninStatusChanged();
+ }
+
+ testing::NiceMock<MockSearchProviderObserver> search_provider_observer_;
+};
+
+class RepeatableQueriesServiceTest : public ::testing::Test,
+ public RepeatableQueriesServiceObserver {
+ public:
+ RepeatableQueriesServiceTest() = default;
+ ~RepeatableQueriesServiceTest() override = default;
+
+ void SetUp() override {
+ bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
+
+ CHECK(history_dir_.CreateUniqueTempDir());
+ history_service_ = history::CreateHistoryService(
+ history_dir_.GetPath(), /*create_history_db=*/true);
+
+ in_memory_url_index_ = std::make_unique<InMemoryURLIndex>(
+ bookmark_model_.get(), history_service_.get(), nullptr,
+ history_dir_.GetPath(), SchemeSet());
+ in_memory_url_index_->Init();
+
+ template_url_service_ = std::make_unique<TemplateURLService>(nullptr, 0);
+
+ // Add the fallback default search provider to the TemplateURLService so
+ // that it gets a valid unique identifier. Make the newly added provider the
+ // user selected default search provider.
+ TemplateURL* default_provider = template_url_service_->Add(
+ std::make_unique<TemplateURL>(default_search_provider()->data()));
+ template_url_service_->SetUserSelectedDefaultSearchProvider(
+ default_provider);
+ // Verify that Google is the default search provider.
+ EXPECT_TRUE(
+ search::DefaultSearchProviderIsGoogle(template_url_service_.get()));
+
+ identity_env_ = std::make_unique<signin::IdentityTestEnvironment>(
+ &test_url_loader_factory_);
+ identity_env_->MakePrimaryAccountAvailable("example@gmail.com");
+ identity_env_->SetAutomaticIssueOfAccessTokens(true);
+
+ service_ = std::make_unique<TestRepeatableQueriesService>(
+ identity_env_->identity_manager(), history_service_.get(),
+ template_url_service_.get(),
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_),
+ GURL());
+ EXPECT_TRUE(service_->repeatable_queries().empty());
+ service_->AddObserver(this);
+ }
+
+ void TearDown() override {
+ // RepeatableQueriesService must be explicitly shut down so that its
+ // observers can unregister.
+ service_->Shutdown();
+ // InMemoryURLIndex must be explicitly shut down or it will DCHECK() in
+ // its destructor.
+ in_memory_url_index_->Shutdown();
+ // Needed to prevent leaks due to posted history index rebuild task.
+ task_environment_.RunUntilIdle();
+ }
+
+ const TemplateURL* default_search_provider() {
+ return template_url_service_->GetDefaultSearchProvider();
+ }
+
+ network::TestURLLoaderFactory* test_url_loader_factory() {
+ return &test_url_loader_factory_;
+ }
+
+ TestRepeatableQueriesService* service() { return service_.get(); }
+
+ void set_service_is_done(bool is_done) { service_is_done_ = is_done; }
+
+ void SignIn() {
+ AccountInfo account_info =
+ identity_env_->MakeAccountAvailable("test@email.com");
+ identity_env_->SetCookieAccounts({{account_info.email, account_info.gaia}});
+ }
+
+ void SignOut() { identity_env_->SetCookieAccounts({}); }
+
+ GURL GetQueryDestinationURL(const std::string& query) {
+ return service_->GetQueryDestinationURL(base::ASCIIToUTF16(query));
+ }
+
+ void RefreshAndMaybeWaitForService() {
+ service_is_done_ = false;
+ service_->Refresh();
+ MaybeWaitForService();
+ }
+
+ void MaybeWaitForService() {
+ if (!service_is_done_) {
+ service_run_loop_ = std::make_unique<base::RunLoop>();
+ // Quits in OnRepeatableQueriesUpdated when the service is done.
+ service_run_loop_->Run();
+ }
+ }
+
+ // Fills the URLDatabase with search URLs created using the provided data.
+ void FillURLDatabase(const std::vector<TestURLData>& url_data_list) {
+ const Time now = Time::Now();
+ for (const auto& entry : url_data_list) {
+ TemplateURLRef::SearchTermsArgs search_terms_args(
+ base::UTF8ToUTF16(entry.search_terms));
+ const auto& search_terms_data =
+ template_url_service_->search_terms_data();
+ std::string search_url =
+ entry.search_provider->url_ref().ReplaceSearchTerms(
+ search_terms_args, search_terms_data);
+ history_service_->AddPageWithDetails(
+ GURL(search_url), base::UTF8ToUTF16(entry.title), entry.visit_count,
+ entry.typed_count, now - TimeDelta::FromSeconds(entry.age_in_seconds),
+ entry.hidden, history::SOURCE_BROWSED);
+ history_service_->SetKeywordSearchTermsForURL(
+ GURL(search_url), entry.search_provider->id(),
+ base::UTF8ToUTF16(entry.search_terms));
+ WaitForHistoryService();
+ }
+ }
+
+ // Waits for history::HistoryService's async operations.
+ void WaitForHistoryService() {
+ history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
+
+ // MemoryURLIndex schedules tasks to rebuild its index on the history
+ // thread. Block here to make sure they are complete.
+ BlockUntilInMemoryURLIndexIsRefreshed(in_memory_url_index_.get());
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+ std::unique_ptr<base::RunLoop> service_run_loop_;
+ std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
+ std::unique_ptr<history::HistoryService> history_service_;
+ std::unique_ptr<InMemoryURLIndex> in_memory_url_index_;
+ base::ScopedTempDir history_dir_;
+ std::unique_ptr<TemplateURLService> template_url_service_;
+ data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ std::unique_ptr<signin::IdentityTestEnvironment> identity_env_;
+ std::unique_ptr<TestRepeatableQueriesService> service_;
+ bool service_is_done_ = false;
+
+ // RepeatableQueriesServiceObserver
+ void OnRepeatableQueriesUpdated() override;
+ void OnRepeatableQueriesServiceShuttingDown() override;
+};
+
+void RepeatableQueriesServiceTest::OnRepeatableQueriesUpdated() {
+ service_is_done_ = true;
+ if (service_run_loop_) {
+ service_run_loop_->Quit();
+ }
+}
+
+void RepeatableQueriesServiceTest::OnRepeatableQueriesServiceShuttingDown() {
+ service_->RemoveObserver(this);
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn) {
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillOnce(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ // The first two server suggestions are kept as repeatable queries.
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn_BadResponse) {
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ BadServerResponse1());
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ // Cached data is cleared.
+ EXPECT_TRUE(service()->repeatable_queries().empty());
+
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ BadServerResponse2());
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ // Cached data is still empty.
+ EXPECT_TRUE(service()->repeatable_queries().empty());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn_ErrorResponse) {
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ test_url_loader_factory()->AddResponse(
+ service()->GetRequestURL(), network::mojom::URLResponseHead::New(),
+ std::string(), network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ // Cached data is kept.
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn_DefaultSearchProviderChanged) {
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillOnce(testing::Return(true))
+ .WillOnce(testing::Return(false));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ set_service_is_done(false);
+ // Simulate DSP change. Requests a refresh.
+ service()->SearchProviderChanged();
+ MaybeWaitForService();
+ // Cached data is cleared.
+ EXPECT_TRUE(service()->repeatable_queries().empty());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn_SigninStatusChanged) {
+ base::HistogramTester histogram_tester;
+
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ int original_query_age =
+ history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
+ FillURLDatabase({
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/0},
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/1},
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/original_query_age},
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/original_query_age},
+ });
+
+ set_service_is_done(false);
+ SignOut(); // Requests a refresh.
+ MaybeWaitForService();
+ // Cached data is updated to local results.
+ std::vector<RepeatableQuery> expected_local_queries{
+ {base::ASCIIToUTF16("more recent local query"),
+ GetQueryDestinationURL("more recent local query"), ""},
+ {base::ASCIIToUTF16("less recent local query"),
+ GetQueryDestinationURL("less recent local query"), ""}};
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ histogram_tester.ExpectTotalCount(
+ RepeatableQueriesService::kExtractionDurationHistogram, 1);
+ histogram_tester.ExpectTotalCount(
+ RepeatableQueriesService::kExtractedCountHistogram, 1);
+ histogram_tester.ExpectUniqueSample(
+ RepeatableQueriesService::kExtractedCountHistogram, 2, 1);
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedIn_Deletion) {
+ SignIn();
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ // Try to delete a query suggestion not provided by the service.
+ set_service_is_done(false);
+ service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
+ // No request to delete the suggestion was sent.
+ EXPECT_TRUE(test_url_loader_factory()->pending_requests()->empty());
+ MaybeWaitForService();
+ // Suggestions should not change.
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ // Delete the query suggestion provided by the service.
+ set_service_is_done(false);
+ service()->DeleteQueryWithDestinationURL(
+ GetQueryDestinationURL("server query 1"));
+ // A request to delete the suggestion was sent.
+ EXPECT_EQ(1u, test_url_loader_factory()->pending_requests()->size());
+ EXPECT_EQ(test_url_loader_factory()->GetPendingRequest(0)->request.url,
+ service()->GetQueryDeletionURL("/delete?server+query+1"));
+ MaybeWaitForService();
+ expected_server_queries = {{base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"),
+ "/delete?server+query+2"}};
+ // The deleted suggestion is not offered anymore.
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+
+ expected_server_queries = {
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"},
+ {base::ASCIIToUTF16("server query 3"),
+ GetQueryDestinationURL("server query 3"), "/delete?server+query+3"}};
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ // The deleted suggestion will not be offered again.
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedOut_DefaultSearchProviderChanged) {
+ int original_query_age =
+ history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
+ FillURLDatabase({
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/0},
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/1},
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/original_query_age},
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/original_query_age},
+ });
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillOnce(testing::Return(true))
+ .WillOnce(testing::Return(false));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_local_queries{
+ {base::ASCIIToUTF16("more recent local query"),
+ GetQueryDestinationURL("more recent local query"), ""},
+ {base::ASCIIToUTF16("less recent local query"),
+ GetQueryDestinationURL("less recent local query"), ""}};
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ set_service_is_done(false);
+ // Simulate DSP change. Requests a refresh.
+ service()->SearchProviderChanged();
+ MaybeWaitForService();
+ // Cached data is cleared.
+ EXPECT_TRUE(service()->repeatable_queries().empty());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedOut_SigninStatusChanged) {
+ int original_query_age =
+ history::kAutocompleteDuplicateVisitIntervalThreshold.InSeconds() + 3;
+ FillURLDatabase({
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/0},
+ // Issued far enough from the original query; won't be ignored:
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/1},
+ {default_search_provider(), "less recent local query",
+ /*age_in_seconds=*/original_query_age},
+ {default_search_provider(), "more recent local query",
+ /*age_in_seconds=*/original_query_age},
+ });
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_local_queries{
+ {base::ASCIIToUTF16("more recent local query"),
+ GetQueryDestinationURL("more recent local query"), ""},
+ {base::ASCIIToUTF16("less recent local query"),
+ GetQueryDestinationURL("less recent local query"), ""}};
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ test_url_loader_factory()->AddResponse(service()->GetRequestURL().spec(),
+ GoodServerResponse());
+
+ set_service_is_done(false);
+ SignIn(); // Requests a refresh.
+ MaybeWaitForService();
+ // Cached data is updated to server results.
+ std::vector<RepeatableQuery> expected_server_queries{
+ {base::ASCIIToUTF16("server query 1"),
+ GetQueryDestinationURL("server query 1"), "/delete?server+query+1"},
+ {base::ASCIIToUTF16("server query 2"),
+ GetQueryDestinationURL("server query 2"), "/delete?server+query+2"}};
+ EXPECT_EQ(expected_server_queries, service()->repeatable_queries());
+}
+
+TEST_F(RepeatableQueriesServiceTest, SignedOut_Deletion) {
+ FillURLDatabase({{default_search_provider(), "local query 1",
+ /*age_in_seconds=*/1},
+ {default_search_provider(), "local query 2",
+ /*age_in_seconds=*/2},
+ {default_search_provider(), "local query 3",
+ /*age_in_seconds=*/3}});
+
+ EXPECT_CALL(*service()->search_provider_observer(), is_google())
+ .WillRepeatedly(testing::Return(true));
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ std::vector<RepeatableQuery> expected_local_queries{
+ {base::ASCIIToUTF16("local query 1"),
+ GetQueryDestinationURL("local query 1"), ""},
+ {base::ASCIIToUTF16("local query 2"),
+ GetQueryDestinationURL("local query 2"), ""}};
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ // Try to delete a query suggestion not provided by the service.
+ set_service_is_done(false);
+ service()->DeleteQueryWithDestinationURL(GetQueryDestinationURL("blah"));
+ MaybeWaitForService();
+ // Suggestions should not change.
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ // Delete the query suggestion provided by the service.
+ set_service_is_done(false);
+ service()->DeleteQueryWithDestinationURL(
+ GetQueryDestinationURL("local query 1"));
+ MaybeWaitForService();
+ expected_local_queries = {{base::ASCIIToUTF16("local query 2"),
+ GetQueryDestinationURL("local query 2"), ""}};
+ // The deleted suggestion is not offered anymore.
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+
+ // Request a refresh.
+ RefreshAndMaybeWaitForService();
+ expected_local_queries = {{base::ASCIIToUTF16("local query 2"),
+ GetQueryDestinationURL("local query 2"), ""},
+ {base::ASCIIToUTF16("local query 3"),
+ GetQueryDestinationURL("local query 3"), ""}};
+ // The deleted suggestion will not be offered again.
+ EXPECT_EQ(expected_local_queries, service()->repeatable_queries());
+}
diff --git a/chromium/components/search/search.cc b/chromium/components/search/search.cc
index 4a0ae2f553a..8347619c680 100644
--- a/chromium/components/search/search.cc
+++ b/chromium/components/search/search.cc
@@ -5,6 +5,10 @@
#include "components/search/search.h"
#include "build/build_config.h"
+#include "components/search_engines/search_engine_type.h"
+#include "components/search_engines/search_terms_data.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_service.h"
namespace search {
@@ -16,4 +20,17 @@ bool IsInstantExtendedAPIEnabled() {
#endif
}
+bool DefaultSearchProviderIsGoogle(
+ const TemplateURLService* template_url_service) {
+ if (!template_url_service)
+ return false;
+ const TemplateURL* default_provider =
+ template_url_service->GetDefaultSearchProvider();
+ if (!default_provider)
+ return false;
+ return default_provider->GetEngineType(
+ template_url_service->search_terms_data()) ==
+ SearchEngineType::SEARCH_ENGINE_GOOGLE;
+}
+
} // namespace search
diff --git a/chromium/components/search/search.h b/chromium/components/search/search.h
index f2d04111912..56efe043340 100644
--- a/chromium/components/search/search.h
+++ b/chromium/components/search/search.h
@@ -5,12 +5,18 @@
#ifndef COMPONENTS_SEARCH_SEARCH_H_
#define COMPONENTS_SEARCH_SEARCH_H_
+class TemplateURLService;
+
namespace search {
// Returns whether the Instant Extended API is enabled. This is always true on
// desktop and false on mobile.
bool IsInstantExtendedAPIEnabled();
+// Returns whether Google is selected as the default search engine.
+bool DefaultSearchProviderIsGoogle(
+ const TemplateURLService* template_url_service);
+
} // namespace search
#endif // COMPONENTS_SEARCH_SEARCH_H_
diff --git a/chromium/components/search/search_provider_observer.cc b/chromium/components/search/search_provider_observer.cc
new file mode 100644
index 00000000000..20ecd24ba4d
--- /dev/null
+++ b/chromium/components/search/search_provider_observer.cc
@@ -0,0 +1,35 @@
+// 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 "components/search/search_provider_observer.h"
+#include "components/search/search.h"
+
+SearchProviderObserver::SearchProviderObserver(TemplateURLService* service,
+ base::RepeatingClosure callback)
+ : service_(service),
+ is_google_(search::DefaultSearchProviderIsGoogle(service_)),
+ callback_(std::move(callback)) {
+ if (service_) {
+ service_observation_.Observe(service_);
+ }
+}
+
+SearchProviderObserver::~SearchProviderObserver() = default;
+
+bool SearchProviderObserver::is_google() {
+ return is_google_;
+}
+
+void SearchProviderObserver::OnTemplateURLServiceChanged() {
+ DCHECK(service_);
+ is_google_ = search::DefaultSearchProviderIsGoogle(service_);
+ callback_.Run();
+}
+
+void SearchProviderObserver::OnTemplateURLServiceShuttingDown() {
+ DCHECK(service_);
+ DCHECK(service_observation_.IsObservingSource(service_));
+ service_observation_.RemoveObservation();
+ service_ = nullptr;
+}
diff --git a/chromium/components/search/search_provider_observer.h b/chromium/components/search/search_provider_observer.h
new file mode 100644
index 00000000000..c7c486e7e2e
--- /dev/null
+++ b/chromium/components/search/search_provider_observer.h
@@ -0,0 +1,36 @@
+// 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 COMPONENTS_SEARCH_SEARCH_PROVIDER_OBSERVER_H_
+#define COMPONENTS_SEARCH_SEARCH_PROVIDER_OBSERVER_H_
+
+#include "base/scoped_observation.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/search_engines/template_url_service_observer.h"
+
+// Keeps track of any changes in search engine provider and call
+// the provided callback if a third-party search provider (i.e. a third-party
+// NTP) is being used.
+class SearchProviderObserver : public TemplateURLServiceObserver {
+ public:
+ explicit SearchProviderObserver(TemplateURLService* service,
+ base::RepeatingClosure callback);
+ ~SearchProviderObserver() override;
+
+ virtual bool is_google();
+
+ private:
+ // TemplateURLServiceObserver:
+ void OnTemplateURLServiceChanged() override;
+ void OnTemplateURLServiceShuttingDown() override;
+
+ base::ScopedObservation<TemplateURLService, TemplateURLServiceObserver>
+ service_observation_{this};
+ // May be nullptr in tests.
+ TemplateURLService* service_;
+ bool is_google_;
+ base::RepeatingClosure callback_;
+};
+
+#endif // COMPONENTS_SEARCH_SEARCH_PROVIDER_OBSERVER_H_
diff --git a/chromium/components/search_engines/BUILD.gn b/chromium/components/search_engines/BUILD.gn
index eb66a2d9456..d95854ac609 100644
--- a/chromium/components/search_engines/BUILD.gn
+++ b/chromium/components/search_engines/BUILD.gn
@@ -152,6 +152,7 @@ source_set("unit_tests") {
"search_host_to_urls_map_unittest.cc",
"template_url_data_unittest.cc",
"template_url_prepopulate_data_unittest.cc",
+ "template_url_service_unittest.cc",
"template_url_service_util_unittest.cc",
"template_url_unittest.cc",
]
diff --git a/chromium/components/search_engines/default_search_manager.cc b/chromium/components/search_engines/default_search_manager.cc
index 61ffeff2717..82f5878b84a 100644
--- a/chromium/components/search_engines/default_search_manager.cc
+++ b/chromium/components/search_engines/default_search_manager.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/i18n/case_conversion.h"
diff --git a/chromium/components/search_engines/search_engine_utils.h b/chromium/components/search_engines/search_engine_utils.h
index 83e0dd43dac..fbba12b2639 100644
--- a/chromium/components/search_engines/search_engine_utils.h
+++ b/chromium/components/search_engines/search_engine_utils.h
@@ -11,8 +11,8 @@ class GURL;
namespace SearchEngineUtils {
-// Like the above, but takes a GURL which is expected to represent a search URL.
-// This may be called on any thread.
+// Takes a GURL and returns the matching enum if it matches the URL of a
+// well-known search engine. This may be called on any thread.
SearchEngineType GetEngineType(const GURL& url);
} // namespace SearchEngineUtils
diff --git a/chromium/components/search_engines/search_terms_data.cc b/chromium/components/search_engines/search_terms_data.cc
index 830f47f5f74..0005ed87a8d 100644
--- a/chromium/components/search_engines/search_terms_data.cc
+++ b/chromium/components/search_engines/search_terms_data.cc
@@ -46,7 +46,7 @@ std::string SearchTermsData::GetSearchClient() const {
return std::string();
}
-std::string SearchTermsData::GetSuggestClient() const {
+std::string SearchTermsData::GetSuggestClient(bool from_ntp) const {
return std::string();
}
diff --git a/chromium/components/search_engines/search_terms_data.h b/chromium/components/search_engines/search_terms_data.h
index 5f399b2ebd7..6fc30745273 100644
--- a/chromium/components/search_engines/search_terms_data.h
+++ b/chromium/components/search_engines/search_terms_data.h
@@ -40,8 +40,9 @@ class SearchTermsData {
// The suggest client parameter ("client") passed with Google suggest
// requests. See GetSuggestRequestIdentifier() for more details.
+ // |from_ntp| is true if the search is made from a non-searchbox NTP surface.
// This implementation returns the empty string.
- virtual std::string GetSuggestClient() const;
+ virtual std::string GetSuggestClient(bool from_ntp) const;
// The suggest request identifier parameter ("gs_ri") passed with Google
// suggest requests. Along with suggestclient (See GetSuggestClient()),
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index 2a4c441162f..f195c74444a 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -5,6 +5,7 @@
#include "components/search_engines/template_url.h"
#include <string>
+#include <tuple>
#include <vector>
#include "base/base64.h"
@@ -228,7 +229,8 @@ TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
bool is_exact_search,
std::string source_lang,
std::string target_lang,
- std::string fluent_languages)
+ std::string fluent_languages,
+ std::string related_searches_stamp)
: version(version),
contextual_cards_version(contextual_cards_version),
home_country(home_country),
@@ -237,7 +239,8 @@ TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
is_exact_search(is_exact_search),
source_lang(source_lang),
target_lang(target_lang),
- fluent_languages(fluent_languages) {}
+ fluent_languages(fluent_languages),
+ related_searches_stamp(related_searches_stamp) {}
TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
const ContextualSearchParams& other) = default;
@@ -1009,6 +1012,8 @@ std::string TemplateURLRef::HandleReplacements(
args.push_back("tlitetl=" + params.target_lang);
if (!params.fluent_languages.empty())
args.push_back("ctxs_fls=" + params.fluent_languages);
+ if (!params.related_searches_stamp.empty())
+ args.push_back("ctxsl_rs=" + params.related_searches_stamp);
HandleReplacement(std::string(), base::JoinString(args, "&"), *i, &url);
break;
@@ -1118,7 +1123,7 @@ std::string TemplateURLRef::HandleReplacements(
// empty string. (If we don't handle this case, we hit a
// NOTREACHED below.)
base::string16 rlz_string = search_terms_data.GetRlzParameterValue(
- search_terms_args.from_app_list);
+ search_terms_args.request_source == CROS_APP_LIST);
if (!rlz_string.empty()) {
HandleReplacement("rlz", base::UTF16ToUTF8(rlz_string), *i, &url);
}
@@ -1152,7 +1157,10 @@ std::string TemplateURLRef::HandleReplacements(
case GOOGLE_SUGGEST_CLIENT:
HandleReplacement(
- std::string(), search_terms_data.GetSuggestClient(), *i, &url);
+ std::string(),
+ search_terms_data.GetSuggestClient(
+ search_terms_args.request_source == NON_SEARCHBOX_NTP),
+ *i, &url);
break;
case GOOGLE_SUGGEST_REQUEST_ID:
@@ -1310,6 +1318,37 @@ TemplateURL::TemplateURL(const TemplateURLData& data,
TemplateURL::~TemplateURL() {
}
+bool TemplateURL::IsBetterThanEngineWithConflictingKeyword(
+ const TemplateURL* other) const {
+ DCHECK(other);
+
+ auto get_sort_key = [](const TemplateURL* engine) {
+ return std::make_tuple(
+ // Policy-created engines always win over non-policy created engines.
+ engine->created_by_policy(),
+ // The integral value of the type enum is used to sort next.
+ // This makes extension-controlled engines win.
+ engine->type(),
+ // For engines with associated extensions; more recently installed
+ // extensions win.
+ engine->extension_info_ ? engine->extension_info_->install_time
+ : base::Time(),
+ // Prefer engines that CANNOT be auto-replaced.
+ !engine->safe_for_autoreplace(),
+ // More recently modified engines win.
+ engine->last_modified(),
+ // TODO(tommycli): This should be a tie-breaker than provides a total
+ // ordering of all TemplateURLs so that distributed clients resolve
+ // conflicts identically. This sync_guid is not globally unique today,
+ // so we need to fix that before we can resolve conflicts with this.
+ engine->sync_guid());
+ };
+
+ // Although normally sort is done by operator<, in this case, we want the
+ // BETTER engine to be preceding the worse engine.
+ return get_sort_key(this) > get_sort_key(other);
+}
+
// static
base::string16 TemplateURL::GenerateKeyword(const GURL& url) {
DCHECK(url.is_valid());
diff --git a/chromium/components/search_engines/template_url.h b/chromium/components/search_engines/template_url.h
index 4a656efe31b..78a4a8fb1f0 100644
--- a/chromium/components/search_engines/template_url.h
+++ b/chromium/components/search_engines/template_url.h
@@ -68,6 +68,13 @@ class TemplateURLRef {
// the |post_data|. See http://tools.ietf.org/html/rfc2046 for the details.
typedef std::pair<std::string, std::string> PostContent;
+ // Enumeration of the known search or suggest request sources.
+ enum RequestSource {
+ SEARCHBOX, // Omnibox or the NTP realbox. The default.
+ CROS_APP_LIST, // Chrome OS app list search box.
+ NON_SEARCHBOX_NTP, // Non-searchbox NTP surfaces.
+ };
+
// This struct encapsulates arguments passed to
// TemplateURLRef::ReplaceSearchTerms methods. By default, only search_terms
// is required and is passed in the constructor.
@@ -108,6 +115,10 @@ class TemplateURLRef {
// is fluent in reading. This acts as an alternate set of languages
// to consider translating into. The languages are ordered by
// fluency, and encoded as a comma-separated list of BCP 47 languages.
+ // The |related_searches_stamp| string contains an information that
+ // indicates experiment status and server processing results so that
+ // can be logged in GWS Sawmill logs for offline analysis for the
+ // Related Searches MVP experiment.
ContextualSearchParams(int version,
int contextual_cards_version,
std::string home_country,
@@ -116,7 +127,8 @@ class TemplateURLRef {
bool is_exact_search,
std::string source_lang,
std::string target_lang,
- std::string fluent_languages);
+ std::string fluent_languages,
+ std::string related_searches_stamp);
ContextualSearchParams(const ContextualSearchParams& other);
~ContextualSearchParams();
@@ -157,6 +169,11 @@ class TemplateURLRef {
// Alternate target languages that the user is fluent in, encoded in a
// single string.
std::string fluent_languages;
+
+ // Experiment arm and processing information for the Related Searches
+ // experiment. The value is an arbitrary string that starts with a
+ // schema version number.
+ std::string related_searches_stamp;
};
// Estimates dynamic memory usage.
@@ -228,9 +245,8 @@ class TemplateURLRef {
// When searching for an image, the original size of the image.
gfx::Size image_original_size;
- // True if the search was made using the app list search box. Otherwise, the
- // search was made using the omnibox.
- bool from_app_list = false;
+ // Source of the search or suggest request.
+ RequestSource request_source = SEARCHBOX;
ContextualSearchParams contextual_search_params;
};
@@ -561,15 +577,19 @@ class TemplateURL {
using TemplateURLVector = std::vector<TemplateURL*>;
using OwnedTemplateURLVector = std::vector<std::unique_ptr<TemplateURL>>;
+ // These values are not persisted and can be freely changed.
+ // Their integer values are used for choosing the best engine during keyword
+ // conflicts, so their relative ordering should not be changed without careful
+ // thought about what happens during version skew.
enum Type {
- // Regular search engine.
- NORMAL,
+ // Installed only on this device. Should not be synced. This is not common.
+ LOCAL = 0,
+ // Regular search engine. This is the most common.
+ NORMAL = 1,
// Installed by extension through Override Settings API.
- NORMAL_CONTROLLED_BY_EXTENSION,
+ NORMAL_CONTROLLED_BY_EXTENSION = 2,
// The keyword associated with an extension that uses the Omnibox API.
- OMNIBOX_API_EXTENSION,
- // Installed only on this device. Should not be synced.
- LOCAL,
+ OMNIBOX_API_EXTENSION = 3,
};
// An AssociatedExtensionInfo represents information about the extension that
@@ -606,6 +626,25 @@ class TemplateURL {
~TemplateURL();
+ // For two engines with the same keyword, |this| and |other|,
+ // returns true if |this| is strictly better than |other|.
+ //
+ // While normal engines must all have distinct keywords, policy-created,
+ // extension-controlled and omnibox API engines may have the same keywords as
+ // each other or as normal engines. In these cases, policy-create engines
+ // override omnibox API engines, which override extension-controlled engines,
+ // which override normal engines.
+ //
+ // If there is still a conflict after this, compare by safe-for-autoreplace,
+ // then last modified date, then use the sync guid as a tiebreaker.
+ //
+ // TODO(tommycli): I'd like to use this to resolve Sync conflicts in the
+ // future, but we need a total ordering of TemplateURLs. That's not the case
+ // today, because the sync GUIDs are not actually globally unique, so there
+ // can be a genuine tie, which is not good, because then two different clients
+ // could choose to resolve the conflict in two different ways.
+ bool IsBetterThanEngineWithConflictingKeyword(const TemplateURL* other) const;
+
// Generates a suitable keyword for the specified url, which must be valid.
// This is guaranteed not to return an empty string, since TemplateURLs should
// never have an empty keyword.
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.cc b/chromium/components/search_engines/template_url_prepopulate_data.cc
index c1368c64f91..150b548b368 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data.cc
@@ -42,16 +42,16 @@ const PrepopulatedEngine* const engines_AE[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &ecosia,
};
// Albania
const PrepopulatedEngine* const engines_AL[] = {
&google,
- &yahoo,
&bing,
+ &yahoo,
&duckduckgo,
- &yandex_ru,
+ &yandex_com,
};
// Argentina
@@ -76,8 +76,8 @@ const PrepopulatedEngine* const engines_AT[] = {
const PrepopulatedEngine* const engines_AU[] = {
&google,
&bing,
- &duckduckgo,
&yahoo_au,
+ &duckduckgo,
&ecosia,
};
@@ -87,7 +87,6 @@ const PrepopulatedEngine* const engines_BA[] = {
&bing,
&yahoo,
&duckduckgo,
- &ask,
};
// Belgium
@@ -123,7 +122,7 @@ const PrepopulatedEngine* const engines_BI[] = {
&bing,
&yahoo,
&duckduckgo,
- &ask,
+ &yandex_ru,
};
// Brunei
@@ -159,7 +158,7 @@ const PrepopulatedEngine* const engines_BY[] = {
&yandex_by,
&mail_ru,
&bing,
- &yahoo,
+ &duckduckgo,
};
// Belize
@@ -185,15 +184,15 @@ const PrepopulatedEngine* const engines_CH[] = {
&google,
&bing,
&duckduckgo,
- &yahoo_ch,
&ecosia,
+ &yahoo_ch,
};
// Chile
const PrepopulatedEngine* const engines_CL[] = {
&google,
&bing,
- &yahoo_cl,
+ &yahoo_es,
&duckduckgo,
&ecosia,
};
@@ -203,15 +202,15 @@ const PrepopulatedEngine* const engines_CN[] = {
&baidu,
&sogou,
&google,
- &so_360,
&bing,
+ &so_360,
};
// Colombia
const PrepopulatedEngine* const engines_CO[] = {
&google,
&bing,
- &yahoo_co,
+ &yahoo_es,
&ecosia,
&duckduckgo,
};
@@ -238,9 +237,9 @@ const PrepopulatedEngine* const engines_CZ[] = {
const PrepopulatedEngine* const engines_DE[] = {
&google,
&bing,
- &yahoo_de,
&duckduckgo,
&ecosia,
+ &yahoo_de,
};
// Denmark
@@ -264,7 +263,7 @@ const PrepopulatedEngine* const engines_DO[] = {
// Algeria
const PrepopulatedEngine* const engines_DZ[] = {
&google,
- &yahoo,
+ &yahoo_uk,
&bing,
&yandex_ru,
&duckduckgo,
@@ -275,8 +274,8 @@ const PrepopulatedEngine* const engines_EC[] = {
&google,
&bing,
&yahoo,
- &ecosia,
&duckduckgo,
+ &ecosia,
};
// Estonia
@@ -293,7 +292,7 @@ const PrepopulatedEngine* const engines_EG[] = {
&google,
&yahoo,
&bing,
- &yandex_ru,
+ &yandex_com,
&duckduckgo,
};
@@ -348,7 +347,7 @@ const PrepopulatedEngine* const engines_GR[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &yandex_com,
};
// Guatemala
@@ -356,8 +355,8 @@ const PrepopulatedEngine* const engines_GT[] = {
&google,
&bing,
&yahoo,
- &ecosia,
&duckduckgo,
+ &ecosia,
};
// Hong Kong
@@ -365,8 +364,8 @@ const PrepopulatedEngine* const engines_HK[] = {
&google,
&yahoo_hk,
&bing,
- &yandex_com,
&baidu,
+ &duckduckgo,
};
// Honduras
@@ -374,8 +373,8 @@ const PrepopulatedEngine* const engines_HN[] = {
&google,
&bing,
&yahoo,
- &yandex_ru,
&duckduckgo,
+ &ecosia,
};
// Croatia
@@ -384,7 +383,7 @@ const PrepopulatedEngine* const engines_HR[] = {
&bing,
&yahoo,
&duckduckgo,
- &ecosia,
+ &yandex_ru,
};
// Hungary
@@ -418,26 +417,26 @@ const PrepopulatedEngine* const engines_IE[] = {
const PrepopulatedEngine* const engines_IL[] = {
&google,
&bing,
- &yahoo,
&yandex_ru,
+ &yahoo,
&duckduckgo,
};
// India
const PrepopulatedEngine* const engines_IN[] = {
&google,
- &yahoo_in,
&bing,
+ &yahoo_in,
&duckduckgo,
- &yandex_ru,
+ &ecosia,
};
// Iraq
const PrepopulatedEngine* const engines_IQ[] = {
&google,
- &yahoo,
&bing,
- &yandex_ru,
+ &yahoo_uk,
+ &yandex_com,
&duckduckgo,
};
@@ -446,16 +445,16 @@ const PrepopulatedEngine* const engines_IR[] = {
&google,
&bing,
&yahoo,
- &yandex_ru,
&ask,
+ &naver,
};
// Iceland
const PrepopulatedEngine* const engines_IS[] = {
&google,
&bing,
- &duckduckgo,
&yahoo,
+ &duckduckgo,
&ecosia,
};
@@ -474,7 +473,7 @@ const PrepopulatedEngine* const engines_JM[] = {
&bing,
&yahoo,
&duckduckgo,
- &ask,
+ &ecosia,
};
// Jordan
@@ -501,7 +500,7 @@ const PrepopulatedEngine* const engines_KE[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &ecosia,
};
// South Korea
@@ -510,7 +509,7 @@ const PrepopulatedEngine* const engines_KR[] = {
&naver,
&bing,
&daum,
- &yahoo_jp,
+ &yahoo,
};
// Kuwait
@@ -537,7 +536,7 @@ const PrepopulatedEngine* const engines_LB[] = {
&bing,
&yahoo,
&duckduckgo,
- &ecosia,
+ &yandex_ru,
};
// Liechtenstein
@@ -570,8 +569,8 @@ const PrepopulatedEngine* const engines_LU[] = {
// Latvia
const PrepopulatedEngine* const engines_LV[] = {
&google,
- &yandex_ru,
&bing,
+ &yandex_ru,
&yahoo,
&duckduckgo,
};
@@ -579,8 +578,8 @@ const PrepopulatedEngine* const engines_LV[] = {
// Libya
const PrepopulatedEngine* const engines_LY[] = {
&google,
- &yahoo,
&bing,
+ &yahoo,
&yandex_com,
&duckduckgo,
};
@@ -588,18 +587,18 @@ const PrepopulatedEngine* const engines_LY[] = {
// Morocco
const PrepopulatedEngine* const engines_MA[] = {
&google,
- &yahoo,
+ &yahoo_fr,
&bing,
- &duckduckgo,
&yandex_com,
+ &duckduckgo,
};
// Monaco
const PrepopulatedEngine* const engines_MC[] = {
&google,
&bing,
- &duckduckgo,
&yahoo,
+ &duckduckgo,
&qwant,
};
@@ -608,8 +607,8 @@ const PrepopulatedEngine* const engines_MD[] = {
&google,
&yandex_ru,
&mail_ru,
- &duckduckgo,
&bing,
+ &yahoo,
};
// Montenegro
@@ -627,7 +626,7 @@ const PrepopulatedEngine* const engines_MK[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &baidu,
};
// Mexico
@@ -635,8 +634,8 @@ const PrepopulatedEngine* const engines_MX[] = {
&google,
&bing,
&yahoo_mx,
- &ecosia,
&duckduckgo,
+ &ecosia,
};
// Malaysia
@@ -661,9 +660,9 @@ const PrepopulatedEngine* const engines_NI[] = {
const PrepopulatedEngine* const engines_NL[] = {
&google,
&bing,
- &yahoo_nl,
&duckduckgo,
- &yandex_ru,
+ &yahoo_nl,
+ &ecosia,
};
// Norway
@@ -672,15 +671,15 @@ const PrepopulatedEngine* const engines_NO[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &ecosia,
};
// New Zealand
const PrepopulatedEngine* const engines_NZ[] = {
&google,
&bing,
- &duckduckgo,
&yahoo_nz,
+ &duckduckgo,
&ecosia,
};
@@ -690,7 +689,7 @@ const PrepopulatedEngine* const engines_OM[] = {
&bing,
&yahoo,
&duckduckgo,
- &ecosia,
+ &ask,
};
// Panama
@@ -706,7 +705,7 @@ const PrepopulatedEngine* const engines_PA[] = {
const PrepopulatedEngine* const engines_PE[] = {
&google,
&bing,
- &yahoo_pe,
+ &yahoo_es,
&ecosia,
&duckduckgo,
};
@@ -714,8 +713,8 @@ const PrepopulatedEngine* const engines_PE[] = {
// Philippines
const PrepopulatedEngine* const engines_PH[] = {
&google,
- &yahoo_ph,
&bing,
+ &yahoo,
&ecosia,
&duckduckgo,
};
@@ -735,7 +734,6 @@ const PrepopulatedEngine* const engines_PL[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
};
// Puerto Rico
@@ -771,7 +769,7 @@ const PrepopulatedEngine* const engines_QA[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_com,
+ &ecosia,
};
// Romania
@@ -786,8 +784,8 @@ const PrepopulatedEngine* const engines_RO[] = {
// Serbia
const PrepopulatedEngine* const engines_RS[] = {
&google,
- &yahoo,
&bing,
+ &yahoo,
&duckduckgo,
&yandex_ru,
};
@@ -798,7 +796,7 @@ const PrepopulatedEngine* const engines_RU[] = {
&yandex_ru,
&mail_ru,
&bing,
- &yahoo,
+ &duckduckgo,
};
// Rwanda
@@ -807,7 +805,7 @@ const PrepopulatedEngine* const engines_RW[] = {
&bing,
&yahoo,
&duckduckgo,
- &mail_ru,
+ &ecosia,
};
// Saudi Arabia
@@ -832,9 +830,9 @@ const PrepopulatedEngine* const engines_SE[] = {
const PrepopulatedEngine* const engines_SG[] = {
&google,
&bing,
- &yandex_com,
- &yahoo_sg,
+ &yahoo,
&baidu,
+ &duckduckgo,
};
// Slovenia
@@ -843,7 +841,6 @@ const PrepopulatedEngine* const engines_SI[] = {
&bing,
&duckduckgo,
&yahoo,
- &yandex_ru,
};
// Slovakia
@@ -876,8 +873,8 @@ const PrepopulatedEngine* const engines_SY[] = {
// Thailand
const PrepopulatedEngine* const engines_TH[] = {
&google,
- &yahoo_th,
&bing,
+ &yahoo,
&duckduckgo,
&baidu,
};
@@ -885,10 +882,10 @@ const PrepopulatedEngine* const engines_TH[] = {
// Tunisia
const PrepopulatedEngine* const engines_TN[] = {
&google,
- &yahoo,
+ &yahoo_fr,
&bing,
- &yandex_ru,
&duckduckgo,
+ &yandex_ru,
};
// Turkey
@@ -906,7 +903,7 @@ const PrepopulatedEngine* const engines_TT[] = {
&bing,
&yahoo,
&duckduckgo,
- &ask,
+ &ecosia,
};
// Taiwan
@@ -924,7 +921,7 @@ const PrepopulatedEngine* const engines_TZ[] = {
&bing,
&yahoo,
&duckduckgo,
- &yandex_ru,
+ &ecosia,
};
// Ukraine
@@ -932,7 +929,7 @@ const PrepopulatedEngine* const engines_UA[] = {
&google,
&yandex_ua,
&bing,
- &mail_ru,
+ &duckduckgo,
&yahoo,
};
@@ -967,9 +964,9 @@ const PrepopulatedEngine* const engines_VE[] = {
const PrepopulatedEngine* const engines_VN[] = {
&google,
&coccoc,
- &yahoo,
&bing,
- &ecosia,
+ &yahoo,
+ &baidu,
};
// Yemen
@@ -987,7 +984,7 @@ const PrepopulatedEngine* const engines_ZA[] = {
&bing,
&yahoo,
&duckduckgo,
- &baidu,
+ &ecosia,
};
// Zimbabwe
@@ -995,8 +992,8 @@ const PrepopulatedEngine* const engines_ZW[] = {
&google,
&bing,
&yahoo,
- &ask,
&duckduckgo,
+ &ask,
};
// ----------------------------------------------------------------------------
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index 65cbba22618..120df608bdc 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -7,11 +7,14 @@
#include <algorithm>
#include "base/auto_reset.h"
+#include "base/base64.h"
+#include "base/base64url.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/debug/crash_logging.h"
#include "base/format_macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -47,14 +50,26 @@ const char kDeleteSyncedEngineHistogramName[] =
"Search.DeleteSyncedSearchEngine";
// Values for an enumerated histogram used to track whenever an ACTION_DELETE is
-// sent to the server for search engines.
+// sent to the server for search engines. These are persisted. Do not re-number.
enum DeleteSyncedSearchEngineEvent {
- DELETE_ENGINE_USER_ACTION,
- DELETE_ENGINE_PRE_SYNC,
- DELETE_ENGINE_EMPTY_FIELD,
+ DELETE_ENGINE_USER_ACTION = 0,
+ DELETE_ENGINE_PRE_SYNC = 1,
+ DELETE_ENGINE_EMPTY_FIELD = 2,
DELETE_ENGINE_MAX,
};
+const char kSearchTemplateURLEventsHistogramName[] =
+ "Search.TemplateURL.Events";
+
+// Values for an enumerated histogram used to track TemplateURL edge cases.
+// These are persisted. Do not re-number.
+enum SearchTemplateURLEvent {
+ SYNC_DELETE_SUCCESS = 0,
+ SYNC_DELETE_FAIL_NONEXISTENT_ENGINE = 1,
+ SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER = 2,
+ SEARCH_TEMPLATE_URL_EVENT_MAX,
+};
+
// Returns true iff the change in |change_list| at index |i| should not be sent
// up to the server based on its GUIDs presence in |sync_data| or when compared
// to changes after it in |change_list|.
@@ -146,15 +161,6 @@ size_t GetRegistryLength(const base::string16& host) {
net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
}
-// Returns the domain name (including registry) of a hostname. For example,
-// www.google.co.uk will return google.co.uk.
-base::string16 GetDomainAndRegistry(const base::string16& host) {
- return base::UTF8ToUTF16(
- net::registry_controlled_domains::GetDomainAndRegistry(
- base::UTF16ToUTF8(host),
- net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
-}
-
// For keywords that look like hostnames, returns whether KeywordProvider
// should require users to type a prefix of the hostname to match against
// them, rather than just the domain name portion. In other words, returns
@@ -383,15 +389,6 @@ void TemplateURLService::AddMatchingKeywords(
keyword_to_turl_and_length_, prefix, supports_replacement_only, matches);
}
-void TemplateURLService::AddMatchingDomainKeywords(
- const base::string16& prefix,
- bool supports_replacement_only,
- TURLsAndMeaningfulLengths* matches) {
- AddMatchingKeywordsHelper(
- keyword_domain_to_turl_and_length_, prefix, supports_replacement_only,
- matches);
-}
-
TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
const base::string16& keyword) {
return const_cast<TemplateURL*>(
@@ -401,9 +398,19 @@ TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
const TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
const base::string16& keyword) const {
- auto elem(keyword_to_turl_and_length_.find(keyword));
- if (elem != keyword_to_turl_and_length_.end())
- return elem->second.first;
+ // Finds and returns the best match for |keyword|.
+ const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
+ if (match_range.first != match_range.second) {
+ // Among the matches for |keyword| in the multimap, return the best one.
+ return std::min_element(
+ match_range.first, match_range.second,
+ [](const auto& a, const auto& b) {
+ return a.second.first
+ ->IsBetterThanEngineWithConflictingKeyword(b.second.first);
+ })
+ ->second.first;
+ }
+
return (!loaded_ && initial_default_search_provider_ &&
(initial_default_search_provider_->keyword() == keyword))
? initial_default_search_provider_.get()
@@ -1005,48 +1012,50 @@ base::Optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges(
continue;
}
- // Can't add an already-existing URL, or update/delete a non-existent one.
- if ((iter->change_type() == syncer::SyncChange::ACTION_ADD)
- ? !!existing_turl
- : !existing_turl) {
- error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
- continue;
- }
-
if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
- if (existing_turl == GetDefaultSearchProvider()) {
- // The only way Sync can attempt to delete the default search provider
- // is if we had changed the kSyncedDefaultSearchProviderGUID
- // preference, but perhaps it has not yet been received. To avoid
- // situations where this has come in erroneously, we will un-delete
- // the current default search from the Sync data. If the pref really
- // does arrive later, then default search will change to the correct
- // entry, but we'll have this extra entry sitting around. The result is
- // not ideal, but it prevents a far more severe bug where the default is
- // unexpectedly swapped to something else. The user can safely delete
- // the extra entry again later, if they choose. Most users who do not
- // look at the search engines UI will not notice this.
- // Note that we append a special character to the end of the keyword in
- // an attempt to avoid a ping-poinging situation where receiving clients
- // may try to continually delete the resurrected entry.
- base::string16 updated_keyword = UniquifyKeyword(*existing_turl, true);
- TemplateURLData data(existing_turl->data());
- data.SetKeyword(updated_keyword);
- TemplateURL new_turl(data);
- Update(existing_turl, new_turl);
-
- syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(new_turl);
- new_changes.push_back(syncer::SyncChange(FROM_HERE,
- syncer::SyncChange::ACTION_ADD,
- sync_data));
- // Ignore the delete attempt. This means we never end up resetting the
- // default search provider due to an ACTION_DELETE from sync.
- } else {
+ if (!existing_turl) {
+ // Can't DELETE a non-existent engine, although we log it.
+ UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
+ SYNC_DELETE_FAIL_NONEXISTENT_ENGINE,
+ SEARCH_TEMPLATE_URL_EVENT_MAX);
+ error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
+ continue;
+ }
+
+ // We can get an ACTION_DELETE for the default search provider if the user
+ // has changed the default search provider on a different machine, and we
+ // get the search engine update before the preference update.
+ //
+ // In this case, ignore the delete, because we never want to reset the
+ // default search provider as a result of ACTION_DELETE. If the preference
+ // update arrives later, we may be stuck with an extra search engine entry
+ // in this edge case, but it's better than most alternatives.
+ //
+ // In the past, we tried re-creating the deleted TemplateURL, but it was
+ // likely a source of duplicate search engine entries. crbug.com/1022775
+ if (existing_turl != GetDefaultSearchProvider()) {
Remove(existing_turl);
+ UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
+ SYNC_DELETE_SUCCESS,
+ SEARCH_TEMPLATE_URL_EVENT_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
+ SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER,
+ SEARCH_TEMPLATE_URL_EVENT_MAX);
}
continue;
}
+ if ((iter->change_type() == syncer::SyncChange::ACTION_ADD &&
+ existing_turl) ||
+ (iter->change_type() == syncer::SyncChange::ACTION_UPDATE &&
+ !existing_turl)) {
+ // Can't ADD an already-existing engine, and can't UPDATE a non-existent
+ // engine. Early exit here to avoid ResolvingSyncKeywordConflict().
+ error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
+ continue;
+ }
+
// Explicitly don't check for conflicts against extension keywords; in this
// case the functions which modify the keyword map know how to handle the
// conflicts.
@@ -1081,7 +1090,6 @@ base::Optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges(
MaybeUpdateDSEViaPrefs(existing_turl);
}
-
// If something went wrong, we want to prematurely exit to avoid pushing
// inconsistent data to Sync. We return the last error we received.
if (error.IsSet())
@@ -1246,6 +1254,27 @@ void TemplateURLService::ProcessTemplateURLChange(
sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
}
+std::string TemplateURLService::GetSessionToken() {
+ base::TimeTicks current_time(base::TimeTicks::Now());
+ // Renew token if it expired.
+ if (current_time > token_expiration_time_) {
+ const size_t kTokenBytes = 12;
+ std::string raw_data;
+ base::RandBytes(base::WriteInto(&raw_data, kTokenBytes + 1), kTokenBytes);
+ base::Base64UrlEncode(raw_data,
+ base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &current_token_);
+ }
+
+ // Extend expiration time another 60 seconds.
+ token_expiration_time_ = current_time + base::TimeDelta::FromSeconds(60);
+ return current_token_;
+}
+
+void TemplateURLService::ClearSessionToken() {
+ token_expiration_time_ = base::TimeTicks();
+}
+
// static
syncer::SyncData TemplateURLService::CreateSyncDataFromTemplateURL(
const TemplateURL& turl) {
@@ -1440,56 +1469,17 @@ void TemplateURLService::Init(const Initializer* initializers,
}
}
-TemplateURL* TemplateURLService::BestEngineForKeyword(TemplateURL* engine1,
- TemplateURL* engine2) {
- CHECK(engine1);
- CHECK(engine2);
- CHECK_EQ(engine1->keyword(), engine2->keyword());
-
- // We should only have overlapping keywords when at least one comes from
- // an extension.
- CHECK(IsCreatedByExtension(engine1) || IsCreatedByExtension(engine2));
-
- if (engine2->type() == engine1->type()) {
- return engine1->extension_info_->install_time >
- engine2->extension_info_->install_time
- ? engine1
- : engine2;
- }
- if (engine2->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION) {
- return engine1->type() == TemplateURL::OMNIBOX_API_EXTENSION ? engine1
- : engine2;
- }
- return engine2->type() == TemplateURL::OMNIBOX_API_EXTENSION ? engine2
- : engine1;
-}
-
void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
const base::string16& keyword = template_url->keyword();
- auto iter = keyword_to_turl_and_length_.find(keyword);
- CHECK(iter != keyword_to_turl_and_length_.end());
- // The entry at |iter| may not be |template_url| if it's an extension-created
- // entry with the same keyword.
- if (iter->second.first == template_url) {
- // We need to check whether the keyword can now be provided by another
- // TemplateURL. See the comments for BestEngineForKeyword() for more
- // information on extension keywords and how they can coexist with
- // non-extension keywords.
- TemplateURL* best_fallback = nullptr;
- for (const auto& turl : template_urls_) {
- if ((turl.get() != template_url) && (turl->keyword() == keyword)) {
- if (best_fallback)
- best_fallback = BestEngineForKeyword(best_fallback, turl.get());
- else
- best_fallback = turl.get();
- }
- }
- RemoveFromDomainMap(template_url);
- if (best_fallback) {
- AddToMap(best_fallback);
- AddToDomainMap(best_fallback);
+
+ // Remove from |keyword_to_turl_and_length_|. No need to find the best
+ // fallback. We choose the best one as-needed from the multimap.
+ const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
+ for (auto it = match_range.first; it != match_range.second;) {
+ if (it->second.first == template_url) {
+ it = keyword_to_turl_and_length_.erase(it);
} else {
- keyword_to_turl_and_length_.erase(iter);
+ ++it;
}
}
@@ -1505,25 +1495,13 @@ void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
}
void TemplateURLService::AddToMaps(TemplateURL* template_url) {
- bool template_url_is_omnibox_api =
- template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
const base::string16& keyword = template_url->keyword();
- KeywordToTURLAndMeaningfulLength::const_iterator i =
- keyword_to_turl_and_length_.find(keyword);
- if (i == keyword_to_turl_and_length_.end()) {
- AddToMap(template_url);
- AddToDomainMap(template_url);
- } else {
- TemplateURL* existing_url = i->second.first;
- CHECK_NE(existing_url, template_url);
- if (BestEngineForKeyword(existing_url, template_url) != existing_url) {
- RemoveFromDomainMap(existing_url);
- AddToMap(template_url);
- AddToDomainMap(template_url);
- }
- }
+ keyword_to_turl_and_length_.insert(std::make_pair(
+ keyword,
+ TURLAndMeaningfulLength(
+ template_url, GetMeaningfulKeywordLength(keyword, template_url))));
- if (template_url_is_omnibox_api)
+ if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
return;
if (!template_url->sync_guid().empty())
@@ -1533,40 +1511,6 @@ void TemplateURLService::AddToMaps(TemplateURL* template_url) {
provider_map_->Add(template_url, search_terms_data());
}
-void TemplateURLService::RemoveFromDomainMap(const TemplateURL* template_url) {
- const base::string16 domain = GetDomainAndRegistry(template_url->keyword());
- if (domain.empty())
- return;
-
- const auto match_range(
- keyword_domain_to_turl_and_length_.equal_range(domain));
- for (auto it(match_range.first); it != match_range.second; ) {
- if (it->second.first == template_url)
- it = keyword_domain_to_turl_and_length_.erase(it);
- else
- ++it;
- }
-}
-
-void TemplateURLService::AddToDomainMap(TemplateURL* template_url) {
- const base::string16 domain = GetDomainAndRegistry(template_url->keyword());
- // Only bother adding an entry to the domain map if its key in the domain
- // map would be different from the key in the regular map.
- if (domain != template_url->keyword()) {
- keyword_domain_to_turl_and_length_.insert(std::make_pair(
- domain,
- TURLAndMeaningfulLength(
- template_url, GetMeaningfulKeywordLength(domain, template_url))));
- }
-}
-
-void TemplateURLService::AddToMap(TemplateURL* template_url) {
- const base::string16& keyword = template_url->keyword();
- keyword_to_turl_and_length_[keyword] =
- TURLAndMeaningfulLength(
- template_url, GetMeaningfulKeywordLength(keyword, template_url));
-}
-
void TemplateURLService::SetTemplateURLs(
std::unique_ptr<OwnedTemplateURLVector> urls) {
Scoper scoper(this);
@@ -1653,29 +1597,28 @@ bool TemplateURLService::Update(TemplateURL* existing_turl,
Scoper scoper(this);
model_mutated_notification_pending_ = true;
- base::string16 old_keyword = existing_turl->keyword();
TemplateURLID previous_id = existing_turl->id();
RemoveFromMaps(existing_turl);
- // Check if new keyword conflicts with another normal engine.
+ // Check for new keyword conflicts with another normal engine.
// This is possible when autogeneration of the keyword for a Google default
// search provider at load time causes it to conflict with an existing
- // keyword. In this case we delete the existing keyword if it's replaceable,
- // or else undo the change in keyword for |existing_turl|.
- // Conflicts with extension engines are handled in AddToMaps/RemoveFromMaps
- // functions.
- // Search for conflicting keyword turl before updating values of
- // existing_turl.
- const TemplateURL* conflicting_keyword_turl =
- FindNonExtensionTemplateURLForKeyword(new_values.keyword());
-
- bool keep_old_keyword = false;
- if (conflicting_keyword_turl && conflicting_keyword_turl != existing_turl) {
- if (CanReplace(conflicting_keyword_turl))
- Remove(conflicting_keyword_turl);
- else
- keep_old_keyword = true;
+ // keyword. If the conflicting engines are replaceable, we delete them.
+ // If they're not replaceable, we leave them alone, and trust AddToMaps() to
+ // choose the best engine to assign the keyword.
+ std::vector<TemplateURL*> turls_to_remove;
+ for (const auto& turl : template_urls_) {
+ // TODO(tommycli): Investigate also replacing TemplateURL::LOCAL engines.
+ if (turl.get() != existing_turl && (turl->type() == TemplateURL::NORMAL) &&
+ (turl->keyword() == new_values.keyword()) && CanReplace(turl.get())) {
+ // Remove() invalidates iterators.
+ turls_to_remove.push_back(turl.get());
+ }
+ }
+ for (TemplateURL* turl : turls_to_remove) {
+ Remove(turl);
}
+
// Update existing turl with new values. This must happen after calling
// Remove(conflicting_keyword_turl) above, since otherwise during that
// function RemoveFromMaps() may find |existing_turl| as an alternate engine
@@ -1685,10 +1628,6 @@ bool TemplateURLService::Update(TemplateURL* existing_turl,
// calling AddToMaps() below).
existing_turl->CopyFrom(new_values);
existing_turl->data_.id = previous_id;
- if (keep_old_keyword) {
- CHECK_NE(old_keyword, new_values.keyword());
- existing_turl->data_.SetKeyword(old_keyword);
- }
AddToMaps(existing_turl);
@@ -1706,7 +1645,6 @@ bool TemplateURLService::Update(TemplateURL* existing_turl,
if (default_search_provider_source_ != DefaultSearchManager::FROM_FALLBACK)
MaybeUpdateDSEViaPrefs(existing_turl);
- CHECK(!HasDuplicateKeywords());
return true;
}
@@ -1984,7 +1922,6 @@ TemplateURL* TemplateURLService::Add(std::unique_ptr<TemplateURL> template_url,
if (template_url_ptr)
model_mutated_notification_pending_ = true;
- CHECK(!HasDuplicateKeywords());
return template_url_ptr;
}
@@ -2337,18 +2274,3 @@ TemplateURL* TemplateURLService::FindMatchingDefaultExtensionTemplateURL(
}
return nullptr;
}
-
-bool TemplateURLService::HasDuplicateKeywords() const {
- std::map<base::string16, TemplateURL*> keyword_to_template_url;
- for (const auto& template_url : template_urls_) {
- // Validate no duplicate normal engines with same keyword.
- if (!IsCreatedByExtension(template_url.get())) {
- if (keyword_to_template_url.find(template_url->keyword()) !=
- keyword_to_template_url.end()) {
- return true;
- }
- keyword_to_template_url[template_url->keyword()] = template_url.get();
- }
- }
- return false;
-}
diff --git a/chromium/components/search_engines/template_url_service.h b/chromium/components/search_engines/template_url_service.h
index e266c7a27d6..7f0210819e2 100644
--- a/chromium/components/search_engines/template_url_service.h
+++ b/chromium/components/search_engines/template_url_service.h
@@ -144,22 +144,12 @@ class TemplateURLService : public WebDataServiceConsumer,
// Adds to |matches| all TemplateURLs whose keywords begin with |prefix|,
// sorted shortest-keyword-first. If |supports_replacement_only| is true, only
- // TemplateURLs that support replacement are returned.
+ // TemplateURLs that support replacement are returned. This method must be
+ // efficient, since it's run roughly once per omnibox keystroke.
void AddMatchingKeywords(const base::string16& prefix,
bool supports_replacement_only,
TURLsAndMeaningfulLengths* matches);
- // Adds to |matches| all TemplateURLs for search engines with the domain
- // name part of the keyword starts with |prefix|, sorted
- // shortest-domain-name-first. If |supports_replacement_only| is true, only
- // TemplateURLs that support replacement are returned. Does not bother
- // searching/returning keywords that would've been found with an identical
- // call to FindMatchingKeywords(); i.e., doesn't search keywords for which
- // the domain name is the keyword.
- void AddMatchingDomainKeywords(const base::string16& prefix,
- bool supports_replacement_only,
- TURLsAndMeaningfulLengths* matches);
-
// Looks up |keyword| and returns the element it maps to. Returns NULL if
// the keyword was not found.
// The caller should not try to delete the returned pointer; the data store
@@ -400,6 +390,13 @@ class TemplateURLService : public WebDataServiceConsumer,
return *search_terms_data_;
}
+ // Obtains a session token, regenerating if necessary.
+ std::string GetSessionToken();
+
+ // Clears the session token. Should be called when the user clears browsing
+ // data.
+ void ClearSessionToken();
+
// Returns a SyncData with a sync representation of the search engine data
// from |turl|.
static syncer::SyncData CreateSyncDataFromTemplateURL(
@@ -455,6 +452,7 @@ class TemplateURLService : public WebDataServiceConsumer,
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, PreSyncDeletes);
FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, MergeInSyncTemplateURL);
FRIEND_TEST_ALL_PREFIXES(LocationBarModelTest, GoogleBaseURL);
+ FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceUnitTest, SessionToken);
friend class InstantUnitTestBase;
friend class Scoper;
@@ -464,20 +462,14 @@ class TemplateURLService : public WebDataServiceConsumer,
using GUIDToTURL = std::map<std::string, TemplateURL*>;
// A mapping from keywords to the corresponding TemplateURLs and their
- // meaningful keyword lengths. A keyword can appear only once here because
- // there can be only one active TemplateURL associated with a given keyword.
+ // meaningful keyword lengths. This is a multimap, so the system can
+ // efficiently tolerate multiple engines with the same keyword, like from
+ // extensions. The values are not sorted from best to worst for each keyword,
+ // since multimaps don't sort on value. Users that want the best value for
+ // each key must traverse through all matching items, but we expect there to
+ // be below three values per key.
using KeywordToTURLAndMeaningfulLength =
- std::map<base::string16, TURLAndMeaningfulLength>;
-
- // A mapping from domain names to corresponding TemplateURLs and their
- // meaningful keyword lengths. Specifically, for a keyword that is a
- // hostname containing more than just a domain name, e.g., 'abc.def.com',
- // the keyword is added to this map under the domain key 'def.com'. This
- // means multiple keywords from the same domain share the same key, so this
- // must be a multimap.
- using KeywordDomainToTURLAndMeaningfulLength =
std::multimap<base::string16, TURLAndMeaningfulLength>;
-
// Declaration of values to be used in an enumerated histogram to tally
// changes to the default search provider from various entry points. In
// particular, we use this to see what proportion of changes are from Sync
@@ -517,36 +509,17 @@ class TemplateURLService : public WebDataServiceConsumer,
void Init(const Initializer* initializers, int num_initializers);
- // Given two engines with the same keyword, returns which should take
- // precedence. While normal engines must all have distinct keywords,
- // extension-controlled and omnibox API engines may have the same keywords as
- // each other or as normal engines. In these cases, omnibox API engines
- // override extension-controlled engines, which override normal engines; if
- // there is still a conflict after this, the most recently-added extension
- // wins.
- TemplateURL* BestEngineForKeyword(TemplateURL* engine1, TemplateURL* engine2);
-
// Removes |template_url| from various internal maps
- // (|keyword_to_turl_and_length_|, |keyword_domain_to_turl_and_length_|,
- // |guid_to_turl_|, |provider_map_|).
+ // (|keyword_to_turl_and_length_|, |guid_to_turl_|, |provider_map_|).
void RemoveFromMaps(const TemplateURL* template_url);
// Adds |template_url| to various internal maps
- // (|keyword_to_turl_and_length_|, |keyword_domain_to_turl_and_length_|,
- // |guid_to_turl_|, |provider_map_|) if appropriate. (It might not be
- // appropriate if, for instance, |template_url|'s keyword conflicts with
- // the keyword of a custom search engine already existing in the maps that
- // is not allowed to be replaced.)
+ // (|keyword_to_turl_and_length_|, |guid_to_turl_|, |provider_map_|) if
+ // appropriate. (It might not be appropriate if, for instance,
+ // |template_url|'s keyword conflicts with the keyword of a custom search
+ // engine already existing in the maps that is not allowed to be replaced.)
void AddToMaps(TemplateURL* template_url);
- // Helper function for removing an element from
- // |keyword_domain_to_turl_and_length_|.
- void RemoveFromDomainMap(const TemplateURL* template_url);
-
- // Helper fuction for adding an element to
- // |keyword_domain_to_turl_and_length_| if appropriate.
- void AddToDomainMap(TemplateURL* template_url);
-
// Helper function for adding an element to |keyword_to_turl_and_length_|.
void AddToMap(TemplateURL* template_url);
@@ -561,7 +534,6 @@ class TemplateURLService : public WebDataServiceConsumer,
void ApplyDefaultSearchChange(const TemplateURLData* new_dse_data,
DefaultSearchManager::Source source);
-
// Applies a DSE change. May be called at startup or after transitioning to
// the loaded state. Returns true if a change actually occurred.
bool ApplyDefaultSearchChangeNoMetrics(const TemplateURLData* new_dse_data,
@@ -658,6 +630,10 @@ class TemplateURLService : public WebDataServiceConsumer,
// * |local_turl| is created by policy.
// * |prefer_local_default| is true and |local_turl| is the local default
// search provider
+ //
+ // TODO(tommycli): Consolidate into using
+ // TemplateURL::IsBetterThanEngineWithConflictingKeyword. Likely we will
+ // eliminate the |prefer_local_default| mechanism.
bool IsLocalTemplateURLBetter(const TemplateURL* local_turl,
const TemplateURL* sync_turl,
bool prefer_local_default = true) const;
@@ -723,11 +699,6 @@ class TemplateURLService : public WebDataServiceConsumer,
TemplateURL* FindMatchingDefaultExtensionTemplateURL(
const TemplateURLData& data);
- // Returns whether |template_urls_| contains more than one normal engine with
- // same keyword. Used to validate state after search engines are
- // added/updated.
- bool HasDuplicateKeywords() const;
-
// ---------- Browser state related members ---------------------------------
PrefService* prefs_ = nullptr;
@@ -748,17 +719,6 @@ class TemplateURLService : public WebDataServiceConsumer,
// Mapping from keyword to the TemplateURL.
KeywordToTURLAndMeaningfulLength keyword_to_turl_and_length_;
- // Mapping from keyword domain to the TemplateURL.
- // Entries are only allowed here if there is a corresponding entry in
- // |keyword_to_turl_and_length_|, i.e., if a template URL doesn't have an
- // entry in |keyword_to_turl_and_length_| because it's subsumed by another
- // template URL with an identical keyword, the template URL will not have an
- // entry in this map either. This map will also not bother including entries
- // for keywords in which the keyword is the domain name, with no subdomain
- // before the domain name. (The ordinary |keyword_to_turl_and_length|
- // suffices for that.)
- KeywordDomainToTURLAndMeaningfulLength keyword_domain_to_turl_and_length_;
-
// Mapping from Sync GUIDs to the TemplateURL.
GUIDToTURL guid_to_turl_;
@@ -857,6 +817,10 @@ class TemplateURLService : public WebDataServiceConsumer,
// but if no model mutation occurs, the deferred notification can be skipped.
bool model_mutated_notification_pending_ = false;
+ // Session token management.
+ std::string current_token_;
+ base::TimeTicks token_expiration_time_;
+
#if defined(OS_ANDROID)
// Manage and fetch the java object that wraps this TemplateURLService on
// android.
diff --git a/chromium/components/search_engines/template_url_service_unittest.cc b/chromium/components/search_engines/template_url_service_unittest.cc
new file mode 100644
index 00000000000..c8bfe27d6e2
--- /dev/null
+++ b/chromium/components/search_engines/template_url_service_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 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 <stddef.h>
+
+#include <memory>
+
+#include "components/search_engines/template_url_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TemplateURLServiceUnitTest : public testing::Test {
+ public:
+ TemplateURLServiceUnitTest()
+ : template_url_service_(/*initializers=*/nullptr, /*count=*/0) {}
+ TemplateURLService& template_url_service() { return template_url_service_; }
+
+ private:
+ TemplateURLService template_url_service_;
+};
+
+TEST_F(TemplateURLServiceUnitTest, SessionToken) {
+ // Subsequent calls always get the same token.
+ std::string token = template_url_service().GetSessionToken();
+ std::string token2 = template_url_service().GetSessionToken();
+ EXPECT_EQ(token, token2);
+ EXPECT_FALSE(token.empty());
+
+ // Calls do not regenerate a token.
+ template_url_service().current_token_ = "PRE-EXISTING TOKEN";
+ token = template_url_service().GetSessionToken();
+ EXPECT_EQ(token, "PRE-EXISTING TOKEN");
+
+ // ... unless the token has expired.
+ template_url_service().current_token_.clear();
+ const base::TimeDelta kSmallDelta = base::TimeDelta::FromMilliseconds(1);
+ template_url_service().token_expiration_time_ =
+ base::TimeTicks::Now() - kSmallDelta;
+ token = template_url_service().GetSessionToken();
+ EXPECT_FALSE(token.empty());
+ EXPECT_EQ(token, template_url_service().current_token_);
+
+ // ... or cleared.
+ template_url_service().current_token_.clear();
+ template_url_service().ClearSessionToken();
+ token = template_url_service().GetSessionToken();
+ EXPECT_FALSE(token.empty());
+ EXPECT_EQ(token, template_url_service().current_token_);
+
+ // The expiration time is always updated.
+ template_url_service().GetSessionToken();
+ base::TimeTicks expiration_time_1 =
+ template_url_service().token_expiration_time_;
+ base::PlatformThread::Sleep(kSmallDelta);
+ template_url_service().GetSessionToken();
+ base::TimeTicks expiration_time_2 =
+ template_url_service().token_expiration_time_;
+ EXPECT_GT(expiration_time_2, expiration_time_1);
+ EXPECT_GE(expiration_time_2, expiration_time_1 + kSmallDelta);
+}
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index 78962a03bee..ef435ac629a 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -891,7 +891,7 @@ TEST_F(TemplateURLTest, RLZFromAppList) {
EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_));
TemplateURLRef::SearchTermsArgs args(ASCIIToUTF16("x"));
- args.from_app_list = true;
+ args.request_source = TemplateURLRef::CROS_APP_LIST;
GURL result(url.url_ref().ReplaceSearchTerms(args, search_terms_data_));
ASSERT_TRUE(result.is_valid());
EXPECT_EQ("http://bar/?rlz=" + base::UTF16ToUTF8(rlz_string) + "&x",
@@ -1126,6 +1126,42 @@ TEST_F(TemplateURLTest, SearchClient) {
EXPECT_EQ("http://google.com/?foobar&client=search_client&", result_2.spec());
}
+TEST_F(TemplateURLTest, SuggestClient) {
+ const std::string base_url_str("http://google.com/?");
+ const std::string query_params_str("client={google:suggestClient}");
+ const std::string full_url_str = base_url_str + query_params_str;
+ search_terms_data_.set_google_base_url(base_url_str);
+
+ TemplateURLData data;
+ data.SetURL(full_url_str);
+ TemplateURL url(data);
+ EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_));
+ ASSERT_FALSE(url.url_ref().SupportsReplacement(search_terms_data_));
+ TemplateURLRef::SearchTermsArgs search_terms_args;
+
+ // Check that the URL is correct when a client is not present.
+ GURL result(
+ url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+ ASSERT_TRUE(result.is_valid());
+ EXPECT_EQ("http://google.com/?client=", result.spec());
+
+ // Check that the URL is correct when a client is present.
+ search_terms_data_.set_suggest_client("suggest_client");
+ GURL result_2(
+ url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+ ASSERT_TRUE(result_2.is_valid());
+ EXPECT_EQ("http://google.com/?client=suggest_client", result_2.spec());
+
+ // Check that the URL is correct when a suggest request is made from a
+ // non-searchbox NTP surface.
+ search_terms_args.request_source = TemplateURLRef::NON_SEARCHBOX_NTP;
+ GURL result_3(
+ url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_));
+ ASSERT_TRUE(result_3.is_valid());
+ EXPECT_EQ("http://google.com/?client=suggest_client_from_ntp",
+ result_3.spec());
+}
+
TEST_F(TemplateURLTest, GetURLNoSuggestionsURL) {
TemplateURLData data;
data.SetURL("http://google.com/?q={searchTerms}");
@@ -1743,7 +1779,7 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
// event.
TemplateURLRef::SearchTermsArgs::ContextualSearchParams params(
2, 1, std::string(), 0, 0, false, std::string(), std::string(),
- std::string());
+ std::string(), std::string());
search_terms_args.contextual_search_params = params;
result = url.url_ref().ReplaceSearchTerms(search_terms_args,
search_terms_data_);
@@ -1757,7 +1793,7 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
search_terms_args.contextual_search_params =
TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2, 2, "CH", 1657713458, 5, false, std::string(), std::string(),
- std::string());
+ std::string(), std::string());
result =
url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
@@ -1774,7 +1810,7 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
search_terms_args.contextual_search_params =
TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2, 1, std::string(), 0, 0, true, std::string(), std::string(),
- std::string());
+ std::string(), std::string());
result =
url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
// Find our param.
@@ -1784,7 +1820,8 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
// Test source and target languages.
search_terms_args.contextual_search_params =
TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
- 2, 1, std::string(), 0, 0, true, "es", "de", std::string());
+ 2, 1, std::string(), 0, 0, true, "es", "de", std::string(),
+ std::string());
result =
url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
// Find our params.
@@ -1797,12 +1834,23 @@ TEST_F(TemplateURLTest, ContextualSearchParameters) {
search_terms_args.contextual_search_params =
TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
2, 1, std::string(), 0, 0, true, std::string(), std::string(),
- "es,de");
+ "es,de", std::string());
result =
url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
// Find our param. These may actually be URL encoded.
size_t fluent_pos = result.find("&ctxs_fls=es,de");
EXPECT_NE(fluent_pos, std::string::npos);
+
+ // Test Related Searches.
+ search_terms_args.contextual_search_params =
+ TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
+ 2, 1, std::string(), 0, 0, true, std::string(), std::string(),
+ std::string(), "1RbCu");
+ result =
+ url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
+ // Find our param.
+ size_t ctxsl_rs_pos = result.find("&ctxsl_rs=1RbCu");
+ EXPECT_NE(ctxsl_rs_pos, std::string::npos);
}
TEST_F(TemplateURLTest, GenerateKeyword) {
diff --git a/chromium/components/search_engines/testing_search_terms_data.cc b/chromium/components/search_engines/testing_search_terms_data.cc
index ac476a04974..dea429bae2f 100644
--- a/chromium/components/search_engines/testing_search_terms_data.cc
+++ b/chromium/components/search_engines/testing_search_terms_data.cc
@@ -27,6 +27,10 @@ std::string TestingSearchTermsData::GetSearchClient() const {
return search_client_;
}
+std::string TestingSearchTermsData::GetSuggestClient(bool from_ntp) const {
+ return from_ntp ? suggest_client_ + "_from_ntp" : suggest_client_;
+}
+
std::string TestingSearchTermsData::GoogleImageSearchSource() const {
return "google_image_search_source";
}
diff --git a/chromium/components/search_engines/testing_search_terms_data.h b/chromium/components/search_engines/testing_search_terms_data.h
index 2e21f2e99e2..e7cc2be259d 100644
--- a/chromium/components/search_engines/testing_search_terms_data.h
+++ b/chromium/components/search_engines/testing_search_terms_data.h
@@ -16,6 +16,7 @@ class TestingSearchTermsData : public SearchTermsData {
std::string GoogleBaseURLValue() const override;
base::string16 GetRlzParameterValue(bool from_app_list) const override;
std::string GetSearchClient() const override;
+ std::string GetSuggestClient(bool from_ntp) const override;
std::string GoogleImageSearchSource() const override;
// Estimates dynamic memory usage.
@@ -28,10 +29,14 @@ class TestingSearchTermsData : public SearchTermsData {
void set_search_client(const std::string& search_client) {
search_client_ = search_client;
}
+ void set_suggest_client(const std::string& suggest_client) {
+ suggest_client_ = suggest_client;
+ }
private:
std::string google_base_url_;
std::string search_client_;
+ std::string suggest_client_;
DISALLOW_COPY_AND_ASSIGN(TestingSearchTermsData);
};
diff --git a/chromium/components/search_provider_logos/DEPS b/chromium/components/search_provider_logos/DEPS
index 3f147306402..6c8276f1a86 100644
--- a/chromium/components/search_provider_logos/DEPS
+++ b/chromium/components/search_provider_logos/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/google/core",
"+components/image_fetcher/core",
"+components/keyed_service/core",
"+components/search_engines",
diff --git a/chromium/components/search_provider_logos/google_logo_api.cc b/chromium/components/search_provider_logos/google_logo_api.cc
index f017e62933d..b397681c1c5 100644
--- a/chromium/components/search_provider_logos/google_logo_api.cc
+++ b/chromium/components/search_provider_logos/google_logo_api.cc
@@ -21,6 +21,7 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/values.h"
+#include "components/google/core/common/google_util.h"
#include "components/search_provider_logos/switches.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_constants.h"
@@ -32,46 +33,6 @@ namespace {
const int kDefaultIframeWidthPx = 500;
const int kDefaultIframeHeightPx = 200;
-// Appends the provided |value| to the "async" query param, according to the
-// format used by the Google doodle servers: "async=param:value,other:foo"
-// Derived from net::AppendOrReplaceQueryParameter, that can't be used because
-// it escapes ":" to "%3A", but the server requires the colon not to be escaped.
-// See: http://crbug.com/413845
-GURL AppendToAsyncQueryparam(const GURL& url, const std::string& value) {
- const std::string param_name = "async";
- bool replaced = false;
- const std::string input = url.query();
- url::Component cursor(0, input.size());
- std::string output;
- url::Component key_range, value_range;
- while (url::ExtractQueryKeyValue(input.data(), &cursor, &key_range,
- &value_range)) {
- const base::StringPiece key(input.data() + key_range.begin, key_range.len);
- std::string key_value_pair(input, key_range.begin,
- value_range.end() - key_range.begin);
- if (!replaced && key == param_name) {
- // Check |replaced| as only the first match should be replaced.
- replaced = true;
- key_value_pair += "," + value;
- }
- if (!output.empty()) {
- output += "&";
- }
-
- output += key_value_pair;
- }
- if (!replaced) {
- if (!output.empty()) {
- output += "&";
- }
-
- output += (param_name + "=" + value);
- }
- GURL::Replacements replacements;
- replacements.SetQueryStr(output);
- return url.ReplaceComponents(replacements);
-}
-
} // namespace
GURL GetGoogleDoodleURL(const GURL& google_base_url) {
@@ -98,18 +59,18 @@ GURL AppendFingerprintParamToDoodleURL(const GURL& logo_url,
return logo_url;
}
- return AppendToAsyncQueryparam(logo_url, "es_dfp:" + fingerprint);
+ return google_util::AppendToAsyncQueryParam(logo_url, "es_dfp", fingerprint);
}
GURL AppendPreliminaryParamsToDoodleURL(bool gray_background,
bool for_webui_ntp,
const GURL& logo_url) {
- std::string api_params = for_webui_ntp ? "ntp:2" : "ntp:1";
+ auto url = google_util::AppendToAsyncQueryParam(logo_url, "ntp",
+ for_webui_ntp ? "2" : "1");
if (gray_background) {
- api_params += ",graybg:1";
+ url = google_util::AppendToAsyncQueryParam(url, "graybg", "1");
}
-
- return AppendToAsyncQueryparam(logo_url, api_params);
+ return url;
}
namespace {
diff --git a/chromium/components/search_provider_logos/logo_observer.h b/chromium/components/search_provider_logos/logo_observer.h
index f71a035356e..cccd474c0e9 100644
--- a/chromium/components/search_provider_logos/logo_observer.h
+++ b/chromium/components/search_provider_logos/logo_observer.h
@@ -22,6 +22,13 @@ class LogoObserver {
// again.
virtual void OnLogoAvailable(const Logo* logo, bool from_cache) = 0;
+ // Called when it has been determined from server that the cached logo (or
+ // null) is still valid. This is independent from OnLogoAvailable and is
+ // intended for users who need to take some action that can only happen when a
+ // logo won't later change.
+ // A no-op implementation is provided for users who don't care about this.
+ virtual void OnCachedLogoRevalidated() {}
+
// Called when the LogoService will no longer send updates to this
// LogoObserver. For example: after the cached logo is validated, after
// OnFreshLogoAvailable() is called, or when the LogoService is destructed.
diff --git a/chromium/components/search_provider_logos/logo_service_impl.cc b/chromium/components/search_provider_logos/logo_service_impl.cc
index 046743545b2..fd83f4265b2 100644
--- a/chromium/components/search_provider_logos/logo_service_impl.cc
+++ b/chromium/components/search_provider_logos/logo_service_impl.cc
@@ -92,8 +92,7 @@ void ObserverOnLogoAvailable(LogoObserver* observer,
break;
case LogoCallbackReason::REVALIDATED:
- // TODO(sfiera): double-check whether we should inform the observer of the
- // fresh metadata.
+ observer->OnCachedLogoRevalidated();
break;
case LogoCallbackReason::DETERMINED:
diff --git a/chromium/components/security_interstitials/content/BUILD.gn b/chromium/components/security_interstitials/content/BUILD.gn
index 19cf18277e6..f722af214ca 100644
--- a/chromium/components/security_interstitials/content/BUILD.gn
+++ b/chromium/components/security_interstitials/content/BUILD.gn
@@ -4,13 +4,6 @@
import("//components/captive_portal/core/features.gni")
import("//third_party/protobuf/proto_library.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("security_interstitial_page") {
sources = [
"bad_clock_blocking_page.cc",
@@ -20,9 +13,6 @@ static_library("security_interstitial_page") {
"captive_portal_blocking_page.cc",
"captive_portal_blocking_page.h",
"captive_portal_helper.h",
- "captive_portal_helper_android.cc",
- "captive_portal_helper_android.h",
- "captive_portal_helper_win.cc",
"cert_report_helper.cc",
"cert_report_helper.h",
"certificate_error_report.cc",
@@ -125,7 +115,15 @@ static_library("security_interstitial_page") {
deps += [ "//components/wifi" ]
}
+ if (is_win) {
+ sources += [ "captive_portal_helper_win.cc" ]
+ }
+
if (is_android) {
+ sources += [
+ "captive_portal_helper_android.cc",
+ "captive_portal_helper_android.h",
+ ]
deps +=
[ "//components/security_interstitials/content/android:jni_headers" ]
}
diff --git a/chromium/components/security_interstitials/content/blocked_interception_blocking_page.cc b/chromium/components/security_interstitials/content/blocked_interception_blocking_page.cc
index 4e837276785..340cde9f17d 100644
--- a/chromium/components/security_interstitials/content/blocked_interception_blocking_page.cc
+++ b/chromium/components/security_interstitials/content/blocked_interception_blocking_page.cc
@@ -16,7 +16,6 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
-#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
using content::NavigationController;
using content::NavigationEntry;
diff --git a/chromium/components/security_interstitials/content/captive_portal_metrics_recorder.cc b/chromium/components/security_interstitials/content/captive_portal_metrics_recorder.cc
index b3220ff4bc0..dbfa61443d0 100644
--- a/chromium/components/security_interstitials/content/captive_portal_metrics_recorder.cc
+++ b/chromium/components/security_interstitials/content/captive_portal_metrics_recorder.cc
@@ -38,7 +38,7 @@ CaptivePortalMetricsRecorder::CaptivePortalMetricsRecorder(
captive_portal_no_response_(false),
captive_portal_detected_(false) {
captive_portal_detection_enabled_ = captive_portal_service->enabled();
- subscription_ = captive_portal_service->RegisterCallback(base::Bind(
+ subscription_ = captive_portal_service->RegisterCallback(base::BindRepeating(
&CaptivePortalMetricsRecorder::Observe, base::Unretained(this)));
}
diff --git a/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc b/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
index 4f93cf521da..7940f408e52 100644
--- a/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
+++ b/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
@@ -30,7 +30,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
-#include "base/test/scoped_feature_list.h"
#include "net/cert/cert_verify_proc_android.h"
#endif
diff --git a/chromium/components/security_interstitials/content/common_name_mismatch_handler.cc b/chromium/components/security_interstitials/content/common_name_mismatch_handler.cc
index 97a2b8b7f16..f6e7665e62a 100644
--- a/chromium/components/security_interstitials/content/common_name_mismatch_handler.cc
+++ b/chromium/components/security_interstitials/content/common_name_mismatch_handler.cc
@@ -34,9 +34,8 @@ CommonNameMismatchHandler::~CommonNameMismatchHandler() {
CommonNameMismatchHandler::TestingState
CommonNameMismatchHandler::testing_state_ = NOT_TESTING;
-void CommonNameMismatchHandler::CheckSuggestedUrl(
- const GURL& url,
- const CheckUrlCallback& callback) {
+void CommonNameMismatchHandler::CheckSuggestedUrl(const GURL& url,
+ CheckUrlCallback callback) {
// Should be used only in tests.
if (testing_state_ == IGNORE_REQUESTS_FOR_TESTING)
return;
@@ -46,7 +45,7 @@ void CommonNameMismatchHandler::CheckSuggestedUrl(
DCHECK(check_url_callback_.is_null());
check_url_ = url;
- check_url_callback_ = callback;
+ check_url_callback_ = std::move(callback);
// Create traffic annotation tag.
net::NetworkTrafficAnnotationTag traffic_annotation =
diff --git a/chromium/components/security_interstitials/content/common_name_mismatch_handler.h b/chromium/components/security_interstitials/content/common_name_mismatch_handler.h
index 6f7ea1e2191..8ab131695e7 100644
--- a/chromium/components/security_interstitials/content/common_name_mismatch_handler.h
+++ b/chromium/components/security_interstitials/content/common_name_mismatch_handler.h
@@ -46,8 +46,8 @@ class CommonNameMismatchHandler {
IGNORE_REQUESTS_FOR_TESTING
};
- typedef base::Callback<void(SuggestedUrlCheckResult result,
- const GURL& suggested_url)>
+ typedef base::OnceCallback<void(SuggestedUrlCheckResult result,
+ const GURL& suggested_url)>
CheckUrlCallback;
CommonNameMismatchHandler(
@@ -57,7 +57,7 @@ class CommonNameMismatchHandler {
// Performs a network request to suggested URL. After completion, runs the
// |callback|.
- void CheckSuggestedUrl(const GURL& url, const CheckUrlCallback& callback);
+ void CheckSuggestedUrl(const GURL& url, CheckUrlCallback callback);
// Determines if, for |request_url| serving a certificate that is valid for
// the domain names |dns_names|, there is a name that the certificate is
diff --git a/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.cc b/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.cc
index 16438e734b5..fd2b625f12f 100644
--- a/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.cc
+++ b/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.cc
@@ -5,6 +5,8 @@
#include "components/security_interstitials/content/insecure_form_navigation_throttle.h"
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
#include "components/prefs/pref_service.h"
#include "components/security_interstitials/content/insecure_form_blocking_page.h"
#include "components/security_interstitials/content/insecure_form_tab_storage.h"
@@ -13,11 +15,20 @@
#include "components/security_interstitials/core/pref_names.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
+#include "net/http/http_status_code.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "url/origin.h"
#include "url/url_constants.h"
namespace {
+
+void LogMixedFormInterstitialMetrics(
+ security_interstitials::InsecureFormNavigationThrottle::
+ InterstitialTriggeredState state) {
+ base::UmaHistogramEnumeration("Security.MixedForm.InterstitialTriggerState",
+ state);
+}
+
bool IsInsecureFormAction(const GURL& action_url) {
if (action_url.SchemeIs(url::kBlobScheme) ||
action_url.SchemeIs(url::kFileSystemScheme))
@@ -25,6 +36,7 @@ bool IsInsecureFormAction(const GURL& action_url) {
return !network::IsOriginPotentiallyTrustworthy(
url::Origin::Create(action_url));
}
+
} // namespace
namespace security_interstitials {
@@ -39,6 +51,45 @@ InsecureFormNavigationThrottle::~InsecureFormNavigationThrottle() = default;
content::NavigationThrottle::ThrottleCheckResult
InsecureFormNavigationThrottle::WillStartRequest() {
+ return GetThrottleResultForMixedForm(false /* is_redirect */);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+InsecureFormNavigationThrottle::WillRedirectRequest() {
+ return GetThrottleResultForMixedForm(true /* is_redirect */);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+InsecureFormNavigationThrottle::WillProcessResponse() {
+ // If there is an InsecureFormTabStorage associated to |web_contents_|, clear
+ // the IsProceeding flag.
+ InsecureFormTabStorage* tab_storage = InsecureFormTabStorage::FromWebContents(
+ navigation_handle()->GetWebContents());
+ if (tab_storage)
+ tab_storage->SetIsProceeding(false);
+ return content::NavigationThrottle::PROCEED;
+}
+
+const char* InsecureFormNavigationThrottle::GetNameForLogging() {
+ return "InsecureFormNavigationThrottle";
+}
+
+// static
+std::unique_ptr<InsecureFormNavigationThrottle>
+InsecureFormNavigationThrottle::MaybeCreateNavigationThrottle(
+ content::NavigationHandle* navigation_handle,
+ std::unique_ptr<SecurityBlockingPageFactory> blocking_page_factory,
+ PrefService* prefs) {
+ if (!base::FeatureList::IsEnabled(kInsecureFormSubmissionInterstitial) ||
+ (prefs && !prefs->GetBoolean(prefs::kMixedFormsWarningsEnabled)))
+ return nullptr;
+ return std::make_unique<InsecureFormNavigationThrottle>(
+ navigation_handle, std::move(blocking_page_factory));
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+InsecureFormNavigationThrottle::GetThrottleResultForMixedForm(
+ bool is_redirect) {
content::NavigationHandle* handle = navigation_handle();
if (!handle->IsFormSubmission())
return content::NavigationThrottle::PROCEED;
@@ -65,6 +116,38 @@ InsecureFormNavigationThrottle::WillStartRequest() {
if (tab_storage->IsProceeding())
return content::NavigationThrottle::PROCEED;
+ if (is_redirect) {
+ std::string feature_mode = base::GetFieldTrialParamValueByFeature(
+ kInsecureFormSubmissionInterstitial,
+ kInsecureFormSubmissionInterstitialMode);
+ // 307 and 308 redirects for POST forms are special because they can leak
+ // form data if done over HTTP.
+ if ((handle->GetResponseHeaders()->response_code() ==
+ net::HTTP_TEMPORARY_REDIRECT ||
+ handle->GetResponseHeaders()->response_code() ==
+ net::HTTP_PERMANENT_REDIRECT) &&
+ handle->IsPost()) {
+ LogMixedFormInterstitialMetrics(
+ InterstitialTriggeredState::kMixedFormRedirectWithFormData);
+ if (feature_mode !=
+ kInsecureFormSubmissionInterstitialModeIncludeRedirects &&
+ feature_mode !=
+ kInsecureFormSubmissionInterstitialModeIncludeRedirectsWithFormData) {
+ return content::NavigationThrottle::PROCEED;
+ }
+ } else {
+ LogMixedFormInterstitialMetrics(
+ InterstitialTriggeredState::kMixedFormRedirectNoFormData);
+ if (feature_mode !=
+ kInsecureFormSubmissionInterstitialModeIncludeRedirects) {
+ return content::NavigationThrottle::PROCEED;
+ }
+ }
+ } else {
+ LogMixedFormInterstitialMetrics(
+ InterstitialTriggeredState::kMixedFormDirect);
+ }
+
std::unique_ptr<InsecureFormBlockingPage> blocking_page =
blocking_page_factory_->CreateInsecureFormBlockingPage(contents,
handle->GetURL());
@@ -75,37 +158,4 @@ InsecureFormNavigationThrottle::WillStartRequest() {
CANCEL, net::ERR_BLOCKED_BY_CLIENT, interstitial_html);
}
-content::NavigationThrottle::ThrottleCheckResult
-InsecureFormNavigationThrottle::WillRedirectRequest() {
- return WillStartRequest();
-}
-
-content::NavigationThrottle::ThrottleCheckResult
-InsecureFormNavigationThrottle::WillProcessResponse() {
- // If there is an InsecureFormTabStorage associated to |web_contents_|, clear
- // the IsProceeding flag.
- InsecureFormTabStorage* tab_storage = InsecureFormTabStorage::FromWebContents(
- navigation_handle()->GetWebContents());
- if (tab_storage)
- tab_storage->SetIsProceeding(false);
- return content::NavigationThrottle::PROCEED;
-}
-
-const char* InsecureFormNavigationThrottle::GetNameForLogging() {
- return "InsecureFormNavigationThrottle";
-}
-
-// static
-std::unique_ptr<InsecureFormNavigationThrottle>
-InsecureFormNavigationThrottle::MaybeCreateNavigationThrottle(
- content::NavigationHandle* navigation_handle,
- std::unique_ptr<SecurityBlockingPageFactory> blocking_page_factory,
- PrefService* prefs) {
- if (!base::FeatureList::IsEnabled(kInsecureFormSubmissionInterstitial) ||
- (prefs && !prefs->GetBoolean(prefs::kMixedFormsWarningsEnabled)))
- return nullptr;
- return std::make_unique<InsecureFormNavigationThrottle>(
- navigation_handle, std::move(blocking_page_factory));
-}
-
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.h b/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.h
index 5cc296a6a13..73b86a6e013 100644
--- a/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.h
+++ b/chromium/components/security_interstitials/content/insecure_form_navigation_throttle.h
@@ -18,6 +18,16 @@ namespace security_interstitials {
class InsecureFormNavigationThrottle : public content::NavigationThrottle {
public:
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ // Exposed for testing.
+ enum class InterstitialTriggeredState {
+ kMixedFormDirect = 0,
+ kMixedFormRedirectWithFormData = 1,
+ kMixedFormRedirectNoFormData = 2,
+ kMaxValue = kMixedFormRedirectNoFormData,
+ };
+
InsecureFormNavigationThrottle(
content::NavigationHandle* navigation_handle,
std::unique_ptr<SecurityBlockingPageFactory> blocking_page_factory);
@@ -36,6 +46,9 @@ class InsecureFormNavigationThrottle : public content::NavigationThrottle {
PrefService* prefs);
private:
+ content::NavigationThrottle::ThrottleCheckResult
+ GetThrottleResultForMixedForm(bool is_redirect);
+
std::unique_ptr<SecurityBlockingPageFactory> blocking_page_factory_;
};
diff --git a/chromium/components/security_interstitials/content/legacy_tls_blocking_page.cc b/chromium/components/security_interstitials/content/legacy_tls_blocking_page.cc
index 93d6e0f4b6d..38ec49e3ba6 100644
--- a/chromium/components/security_interstitials/content/legacy_tls_blocking_page.cc
+++ b/chromium/components/security_interstitials/content/legacy_tls_blocking_page.cc
@@ -16,7 +16,6 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
-#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
using content::NavigationController;
using content::NavigationEntry;
diff --git a/chromium/components/security_interstitials/content/resources/connection_help.html b/chromium/components/security_interstitials/content/resources/connection_help.html
index 4494bb7fe8c..e431a7c6e2d 100644
--- a/chromium/components/security_interstitials/content/resources/connection_help.html
+++ b/chromium/components/security_interstitials/content/resources/connection_help.html
@@ -10,6 +10,7 @@
<link rel="stylesheet" href="connection_help.css">
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="strings.js"></script>
<script src="connection_help.js"></script>
diff --git a/chromium/components/security_interstitials/content/ssl_blocking_page.cc b/chromium/components/security_interstitials/content/ssl_blocking_page.cc
index a45ac94cb7b..8b3f75967de 100644
--- a/chromium/components/security_interstitials/content/ssl_blocking_page.cc
+++ b/chromium/components/security_interstitials/content/ssl_blocking_page.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
@@ -26,7 +26,6 @@
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
-#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
using base::TimeTicks;
using content::NavigationEntry;
diff --git a/chromium/components/security_interstitials/content/ssl_error_handler.cc b/chromium/components/security_interstitials/content/ssl_error_handler.cc
index e23ffe96975..f7b5cee43d4 100644
--- a/chromium/components/security_interstitials/content/ssl_error_handler.cc
+++ b/chromium/components/security_interstitials/content/ssl_error_handler.cc
@@ -377,7 +377,7 @@ class SSLErrorHandlerDelegateImpl : public SSLErrorHandler::Delegate {
GURL* suggested_url) const override;
void CheckSuggestedUrl(
const GURL& suggested_url,
- const CommonNameMismatchHandler::CheckUrlCallback& callback) override;
+ CommonNameMismatchHandler::CheckUrlCallback callback) override;
void NavigateToSuggestedURL(const GURL& suggested_url) override;
bool IsErrorOverridable() const override;
void ShowCaptivePortalInterstitial(const GURL& landing_url) override;
@@ -448,14 +448,15 @@ bool SSLErrorHandlerDelegateImpl::GetSuggestedUrl(
void SSLErrorHandlerDelegateImpl::CheckSuggestedUrl(
const GURL& suggested_url,
- const CommonNameMismatchHandler::CheckUrlCallback& callback) {
+ CommonNameMismatchHandler::CheckUrlCallback callback) {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory(
content::BrowserContext::GetDefaultStoragePartition(browser_context_)
->GetURLLoaderFactoryForBrowserProcess());
common_name_mismatch_handler_.reset(
new CommonNameMismatchHandler(request_url_, url_loader_factory));
- common_name_mismatch_handler_->CheckSuggestedUrl(suggested_url, callback);
+ common_name_mismatch_handler_->CheckSuggestedUrl(suggested_url,
+ std::move(callback));
}
void SSLErrorHandlerDelegateImpl::NavigateToSuggestedURL(
@@ -773,8 +774,8 @@ void SSLErrorHandler::StartHandlingError() {
}
delegate_->CheckSuggestedUrl(
suggested_url,
- base::Bind(&SSLErrorHandler::CommonNameMismatchHandlerCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&SSLErrorHandler::CommonNameMismatchHandlerCallback,
+ weak_ptr_factory_.GetWeakPtr()));
timer_.Start(FROM_HERE, g_config.Pointer()->interstitial_delay(), this,
&SSLErrorHandler::ShowSSLInterstitial);
@@ -790,7 +791,7 @@ void SSLErrorHandler::StartHandlingError() {
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
subscription_ = captive_portal_service_->RegisterCallback(
- base::Bind(&SSLErrorHandler::Observe, base::Unretained(this)));
+ base::BindRepeating(&SSLErrorHandler::Observe, base::Unretained(this)));
captive_portal::CaptivePortalTabHelper* captive_portal_tab_helper =
captive_portal::CaptivePortalTabHelper::FromWebContents(web_contents_);
@@ -954,8 +955,8 @@ void SSLErrorHandler::DeleteSSLErrorHandler() {
void SSLErrorHandler::HandleCertDateInvalidError() {
const base::TimeTicks now = base::TimeTicks::Now();
timer_.Start(FROM_HERE, g_config.Pointer()->interstitial_delay(),
- base::Bind(&SSLErrorHandler::HandleCertDateInvalidErrorImpl,
- base::Unretained(this), now));
+ base::BindOnce(&SSLErrorHandler::HandleCertDateInvalidErrorImpl,
+ base::Unretained(this), now));
// Try kicking off a time fetch to get an up-to-date estimate of the
// true time. This will only have an effect if network time is
// unavailable or if there is not already a query in progress.
diff --git a/chromium/components/security_interstitials/content/ssl_error_handler.h b/chromium/components/security_interstitials/content/ssl_error_handler.h
index 8eb1d994706..c24b32f51f6 100644
--- a/chromium/components/security_interstitials/content/ssl_error_handler.h
+++ b/chromium/components/security_interstitials/content/ssl_error_handler.h
@@ -69,7 +69,8 @@ extern const base::Feature kCaptivePortalCertificateList;
class SSLErrorHandler : public content::WebContentsUserData<SSLErrorHandler>,
public content::WebContentsObserver {
public:
- typedef base::Callback<void(content::WebContents*)> TimerStartedCallback;
+ typedef base::RepeatingCallback<void(content::WebContents*)>
+ TimerStartedCallback;
typedef base::OnceCallback<void(
std::unique_ptr<security_interstitials::SecurityInterstitialPage>)>
BlockingPageReadyCallback;
@@ -116,7 +117,7 @@ class SSLErrorHandler : public content::WebContentsUserData<SSLErrorHandler>,
GURL* suggested_url) const = 0;
virtual void CheckSuggestedUrl(
const GURL& suggested_url,
- const CommonNameMismatchHandler::CheckUrlCallback& callback) = 0;
+ CommonNameMismatchHandler::CheckUrlCallback callback) = 0;
virtual void NavigateToSuggestedURL(const GURL& suggested_url) = 0;
virtual bool IsErrorOverridable() const = 0;
virtual void ShowCaptivePortalInterstitial(const GURL& landing_url) = 0;
diff --git a/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc b/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
index 67043ffb89e..5473128636a 100644
--- a/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
+++ b/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
@@ -122,9 +122,10 @@ const char kCertWithoutOrganizationOrCommonName[] =
// Runs |quit_closure| on the UI thread once a URL request has been
// seen. Returns a request that hangs.
std::unique_ptr<net::test_server::HttpResponse> WaitForRequest(
- const base::Closure& quit_closure,
+ base::OnceClosure quit_closure,
const net::test_server::HttpRequest& request) {
- content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, quit_closure);
+ content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
+ std::move(quit_closure));
return std::make_unique<net::test_server::HungResponse>();
}
@@ -170,7 +171,7 @@ class TestSSLErrorHandlerDelegate : public SSLErrorHandler::Delegate {
void SendSuggestedUrlCheckResult(
const CommonNameMismatchHandler::SuggestedUrlCheckResult& result,
const GURL& suggested_url) {
- suggested_url_callback_.Run(result, suggested_url);
+ std::move(suggested_url_callback_).Run(result, suggested_url);
}
int captive_portal_checked() const { return captive_portal_checked_; }
@@ -259,10 +260,10 @@ class TestSSLErrorHandlerDelegate : public SSLErrorHandler::Delegate {
void CheckSuggestedUrl(
const GURL& suggested_url,
- const CommonNameMismatchHandler::CheckUrlCallback& callback) override {
+ CommonNameMismatchHandler::CheckUrlCallback callback) override {
DCHECK(suggested_url_callback_.is_null());
suggested_url_checked_ = true;
- suggested_url_callback_ = callback;
+ suggested_url_callback_ = std::move(callback);
}
void NavigateToSuggestedURL(const GURL& suggested_url) override {
@@ -1109,7 +1110,7 @@ TEST_F(SSLErrorHandlerDateInvalidTest, MAYBE_TimeQueryStarted) {
// Enable network time queries and handle the error. A bad clock interstitial
// should be shown.
test_server()->RegisterRequestHandler(
- base::Bind(&network_time::GoodTimeResponseHandler));
+ base::BindRepeating(&network_time::GoodTimeResponseHandler));
EXPECT_TRUE(test_server()->Start());
tracker()->SetTimeServerURLForTesting(test_server()->GetURL("/"));
field_trial_test()->SetNetworkQueriesWithVariationsService(
@@ -1173,8 +1174,8 @@ TEST_F(SSLErrorHandlerDateInvalidTest, MAYBE_TimeQueryHangs) {
// network time cannot be determined before the timer elapses, an SSL
// interstitial should be shown.
base::RunLoop wait_for_time_query_loop;
- test_server()->RegisterRequestHandler(
- base::Bind(&WaitForRequest, wait_for_time_query_loop.QuitClosure()));
+ test_server()->RegisterRequestHandler(base::BindRepeating(
+ &WaitForRequest, wait_for_time_query_loop.QuitClosure()));
EXPECT_TRUE(test_server()->Start());
tracker()->SetTimeServerURLForTesting(test_server()->GetURL("/"));
field_trial_test()->SetNetworkQueriesWithVariationsService(
diff --git a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
index bebfd91cedd..4c099add4bd 100644
--- a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
+++ b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
@@ -13,8 +13,8 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/logging.h"
@@ -236,8 +236,7 @@ void StatefulSSLHostStateDelegate::AllowCert(
GURL url = GetSecureGURLForHost(host);
std::unique_ptr<base::Value> value(
host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, std::string(),
- nullptr));
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
if (!value.get() || !value->is_dict())
value.reset(new base::DictionaryValue());
@@ -261,8 +260,7 @@ void StatefulSSLHostStateDelegate::AllowCert(
// The map takes ownership of the value, so it is released in the call to
// SetWebsiteSettingDefaultScope.
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, std::string(),
- std::move(value));
+ url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, std::move(value));
}
void StatefulSSLHostStateDelegate::Clear(
@@ -319,8 +317,7 @@ StatefulSSLHostStateDelegate::QueryPolicy(const std::string& host,
std::unique_ptr<base::Value> value(
host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, std::string(),
- nullptr));
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
if (!value.get() || !value->is_dict())
return DENIED;
@@ -386,8 +383,7 @@ void StatefulSSLHostStateDelegate::RevokeUserAllowExceptions(
GURL url = GetSecureGURLForHost(host);
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, std::string(),
- nullptr);
+ url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, nullptr);
// Decisions for non-default storage partitions are stored separately in
// memory; delete those as well.
@@ -416,8 +412,7 @@ bool StatefulSSLHostStateDelegate::HasAllowException(
std::unique_ptr<base::Value> value(
host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, std::string(),
- nullptr));
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
if (!value.get() || !value->is_dict())
return false;
diff --git a/chromium/components/security_interstitials/core/browser/resources/enhanced_protection_message.js b/chromium/components/security_interstitials/core/browser/resources/enhanced_protection_message.js
index bc2f872ca7a..35127e36021 100644
--- a/chromium/components/security_interstitials/core/browser/resources/enhanced_protection_message.js
+++ b/chromium/components/security_interstitials/core/browser/resources/enhanced_protection_message.js
@@ -21,11 +21,21 @@ function setupEnhancedProtectionMessage() {
}
if ($('enhanced-protection-link')) {
- $('enhanced-protection-link').addEventListener('click', function() {
- sendCommand(
- SecurityInterstitialCommandId.CMD_OPEN_ENHANCED_PROTECTION_SETTINGS);
- return false;
- });
+ if (mobileNav) {
+ // To make sure the touch area of the link is larger than the
+ // minimum touch area for accessibility, make the whole block tappable.
+ $('enhanced-protection-message').addEventListener('click', function() {
+ sendCommand(SecurityInterstitialCommandId
+ .CMD_OPEN_ENHANCED_PROTECTION_SETTINGS);
+ return false;
+ });
+ } else {
+ $('enhanced-protection-link').addEventListener('click', function() {
+ sendCommand(SecurityInterstitialCommandId
+ .CMD_OPEN_ENHANCED_PROTECTION_SETTINGS);
+ return false;
+ });
+ }
}
$('enhanced-protection-message').classList.remove('hidden');
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
index 04bc0440c44..07fd81ea12a 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
@@ -2,6 +2,7 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#fff">
<meta name="viewport"
content="initial-scale=1, minimum-scale=1, width=device-width">
@@ -16,6 +17,7 @@
<link rel="stylesheet" href="interstitial_lookalikeurl.css">
<link rel="stylesheet" href="interstitial_safebrowsing.css">
<link rel="stylesheet" href="interstitial_ssl.css">
+ <script src="../../../../../ui/webui/resources/js/assert.js"></script>
<script src="../../../../../ui/webui/resources/js/util.js"></script>
<script src="captive_portal.js"></script>
<script src="ssl.js"></script>
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.html b/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.html
index 4638efbd77e..74d713c406e 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.html
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.html
@@ -9,6 +9,7 @@
<title>$i18n{tabTitle}</title>
<link rel="stylesheet" href="../../common/resources/interstitial_core.css">
<link rel="stylesheet" href="interstitial_webview_quiet.css">
+ <script src="../../../../../ui/webui/resources/js/assert.js"></script>
<script src="../../../../../ui/webui/resources/js/util.js"></script>
<script src="../../common/resources/interstitial_common.js"></script>
<script src="interstitial_webview_quiet.js"></script>
diff --git a/chromium/components/security_interstitials/core/common/resources/interstitial_common.js b/chromium/components/security_interstitials/core/common/resources/interstitial_common.js
index cf0d7a06b42..006bc4d96ce 100644
--- a/chromium/components/security_interstitials/core/common/resources/interstitial_common.js
+++ b/chromium/components/security_interstitials/core/common/resources/interstitial_common.js
@@ -107,20 +107,10 @@ function sendCommand(cmd) {
window.domAutomationController.send(cmd);
// </if>
// <if expr="is_ios">
- // TODO(crbug.com/987407): Used to send commands for non-committed
- // interstitials on iOS. Should be deleted after committed interstitials are
- // fully launched.
- if (!loadTimeData.getBoolean('committed_interstitials_enabled')) {
- const iframe = document.createElement('IFRAME');
- iframe.setAttribute('src', 'js-command:' + cmd);
- document.documentElement.appendChild(iframe);
- iframe.parentNode.removeChild(iframe);
- } else {
- // Used to send commands for iOS committed interstitials.
- /** @suppress {undefinedVars|missingProperties} */ (function() {
- __gCrWeb.message.invokeOnHost({'command': 'blockingPage.' + cmd});
- })();
- }
+ // Send commands for iOS committed interstitials.
+ /** @suppress {undefinedVars|missingProperties} */ (function() {
+ __gCrWeb.message.invokeOnHost({'command': 'blockingPage.' + cmd});
+ })();
// </if>
}
@@ -147,9 +137,6 @@ function preventDefaultOnPoundLinkClicks() {
* not getting triggered.
*/
function setupIosRefresh() {
- if (!loadTimeData.getBoolean('committed_interstitials_enabled')) {
- return;
- }
const load = () => {
window.location.replace(loadTimeData.getString('url_to_reload'));
};
diff --git a/chromium/components/security_interstitials/core/features.cc b/chromium/components/security_interstitials/core/features.cc
index 40c094adfce..0cfadf776ba 100644
--- a/chromium/components/security_interstitials/core/features.cc
+++ b/chromium/components/security_interstitials/core/features.cc
@@ -9,4 +9,11 @@ namespace security_interstitials {
const base::Feature kInsecureFormSubmissionInterstitial{
"InsecureFormSubmissionInterstitial", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kInsecureFormSubmissionInterstitialMode[] = "mode";
+const char kInsecureFormSubmissionInterstitialModeIncludeRedirects[] =
+ "include-redirects";
+const char
+ kInsecureFormSubmissionInterstitialModeIncludeRedirectsWithFormData[] =
+ "include-redirects-with-form-data";
+
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/features.h b/chromium/components/security_interstitials/core/features.h
index 5fb64f46459..06f513146a6 100644
--- a/chromium/components/security_interstitials/core/features.h
+++ b/chromium/components/security_interstitials/core/features.h
@@ -12,6 +12,18 @@ namespace security_interstitials {
// Controls whether an interstitial is shown when submitting a mixed form.
extern const base::Feature kInsecureFormSubmissionInterstitial;
+// Controls if the insecure form interstitial is enabled for forms that intially
+// submit to https, but redirect to http. If not set the interstitial will only
+// be shown for forms that submit directly to http.
+extern const char kInsecureFormSubmissionInterstitialMode[];
+// If set to this mode, the interstitial will be shown for any redirect over
+// http.
+extern const char kInsecureFormSubmissionInterstitialModeIncludeRedirects[];
+// If set to this mode, the interstitial will only be shown for redirects over
+// http that expose form data (i.e. 307 or 308 redirects for POST method forms).
+extern const char
+ kInsecureFormSubmissionInterstitialModeIncludeRedirectsWithFormData[];
+
} // namespace security_interstitials
#endif // COMPONENTS_SECURITY_INTERSTITIALS_CORE_FEATURES_H_
diff --git a/chromium/components/security_state/core/features.cc b/chromium/components/security_state/core/features.cc
index 9dcd8b9dc66..529d6dc23a2 100644
--- a/chromium/components/security_state/core/features.cc
+++ b/chromium/components/security_state/core/features.cc
@@ -21,5 +21,11 @@ const base::Feature kLegacyTLSWarnings{"LegacyTLSWarnings",
const base::Feature kSafetyTipUI{"SafetyTip",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kSafetyTipUIForSimplifiedDomainDisplay{
+ "SafetyTipForSimplifiedDomainDisplay", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kSafetyTipUIOnDelayedWarning{
+ "SafetyTipUIOnDelayedWarning", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
} // namespace security_state
diff --git a/chromium/components/security_state/core/features.h b/chromium/components/security_state/core/features.h
index 59be9994918..cf1dc9085bc 100644
--- a/chromium/components/security_state/core/features.h
+++ b/chromium/components/security_state/core/features.h
@@ -44,6 +44,19 @@ extern const base::Feature kLegacyTLSWarnings;
COMPONENT_EXPORT(SECURITY_STATE_FEATURES)
extern const base::Feature kSafetyTipUI;
+// This feature enables Safety Tip warnings on some types of lookalike sites,
+// for the purposes of measuring Simplified Domain Display
+// (https://crbug.com/1090393). It has similar behavior to kSafetyTipUI, but can
+// be enabled independently in a separate experiment.
+COMPONENT_EXPORT(SECURITY_STATE_FEATURES)
+extern const base::Feature kSafetyTipUIForSimplifiedDomainDisplay;
+
+// This feature enables Safety Tip warnings on pages where there is a delayed
+// Safe Browsing warning. Has no effect unless safe_browsing::kDelayedWarnings
+// is also enabled. Can be enabled independently of kSafetyTipUI.
+COMPONENT_EXPORT(SECURITY_STATE_FEATURES)
+extern const base::Feature kSafetyTipUIOnDelayedWarning;
+
} // namespace features
} // namespace security_state
diff --git a/chromium/components/security_state/core/security_state.cc b/chromium/components/security_state/core/security_state.cc
index af0b7c5e5fd..47328ccc688 100644
--- a/chromium/components/security_state/core/security_state.cc
+++ b/chromium/components/security_state/core/security_state.cc
@@ -84,7 +84,7 @@ std::string GetHistogramSuffixForSafetyTipStatus(
// Sets |level| to the right value if status should be set.
bool ShouldSetSecurityLevelFromSafetyTip(security_state::SafetyTipStatus status,
SecurityLevel* level) {
- if (!base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) {
+ if (!IsSafetyTipUIFeatureEnabled()) {
return false;
}
@@ -328,4 +328,11 @@ bool ShouldShowDangerTriangleForWarningLevel() {
return true;
}
+bool IsSafetyTipUIFeatureEnabled() {
+ return base::FeatureList::IsEnabled(features::kSafetyTipUI) ||
+ base::FeatureList::IsEnabled(
+ features::kSafetyTipUIForSimplifiedDomainDisplay) ||
+ base::FeatureList::IsEnabled(features::kSafetyTipUIOnDelayedWarning);
+}
+
} // namespace security_state
diff --git a/chromium/components/security_state/core/security_state.h b/chromium/components/security_state/core/security_state.h
index 134d6c7a3a1..d24f20a6019 100644
--- a/chromium/components/security_state/core/security_state.h
+++ b/chromium/components/security_state/core/security_state.h
@@ -269,6 +269,10 @@ bool IsSHA1InChain(const VisibleSecurityState& visible_security_state);
// info to danger triangle as part of an experiment (crbug.com/997972).
bool ShouldShowDangerTriangleForWarningLevel();
+// Returns true if Safety Tip UI should be shown because a relevant field trial
+// is enabled.
+bool IsSafetyTipUIFeatureEnabled();
+
} // namespace security_state
#endif // COMPONENTS_SECURITY_STATE_CORE_SECURITY_STATE_H_
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
index 461d12f28b1..db2444bb701 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
@@ -368,11 +368,18 @@ void SendTabToSelfBridge::DismissEntry(const std::string& guid) {
return;
}
+ DCHECK(change_processor()->IsTrackingMetadata());
+
entry->SetNotificationDismissed(true);
std::unique_ptr<ModelTypeStore::WriteBatch> batch =
store_->CreateWriteBatch();
+ auto entity_data = CopyToEntityData(entry->AsLocalProto().specifics());
+
+ change_processor()->Put(guid, std::move(entity_data),
+ batch->GetMetadataChangeList());
+
batch->WriteData(guid, entry->AsLocalProto().SerializeAsString());
Commit(std::move(batch));
}
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
index 18535c72d66..58b4644ce2d 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/history/core/browser/history_service.h"
@@ -19,11 +18,12 @@
#include "components/send_tab_to_self/proto/send_tab_to_self.pb.h"
#include "components/send_tab_to_self/target_device_info.h"
#include "components/sync/model/entity_change.h"
+#include "components/sync/model/entity_data.h"
#include "components/sync/model/metadata_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/model_impl/in_memory_metadata_change_list.h"
#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/test_matchers.h"
#include "components/sync_device_info/device_info.h"
#include "components/sync_device_info/device_info_util.h"
@@ -50,6 +50,14 @@ const char kDeviceFormat[] = "device %d";
const char kLocalDeviceCacheGuid[] = "local_device_guid";
const char kLocalDeviceName[] = "local_device_name";
+// Action SaveArgPointeeMove<k>(pointer) saves the value pointed to by the k-th
+// (0-based) argument of the mock function by moving it to *pointer.
+ACTION_TEMPLATE(SaveArgPointeeMove,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = std::move(*testing::get<k>(args));
+}
+
sync_pb::SendTabToSelfSpecifics CreateSpecifics(
int suffix,
base::Time shared_time = base::Time::Now(),
@@ -237,8 +245,6 @@ class SendTabToSelfBridgeTest : public testing::Test {
testing::NiceMock<MockSendTabToSelfModelObserver> mock_observer_;
- base::test::ScopedFeatureList scoped_feature_list_;
-
std::unique_ptr<syncer::DeviceInfo> local_device_;
DISALLOW_COPY_AND_ASSIGN(SendTabToSelfBridgeTest);
@@ -369,6 +375,8 @@ TEST_F(SendTabToSelfBridgeTest, LocalHistoryDeletion) {
urls_to_remove.push_back(history::URLRow(GURL("http://www.example2.com/")));
EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(2)));
+ EXPECT_CALL(*processor(), Delete("guid1", _));
+ EXPECT_CALL(*processor(), Delete("guid2", _));
bridge()->OnURLsDeleted(nullptr, history::DeletionInfo::ForUrls(
urls_to_remove, std::set<GURL>()));
@@ -457,6 +465,47 @@ TEST_F(SendTabToSelfBridgeTest, ApplyDeleteNonexistent) {
EXPECT_FALSE(error);
}
+TEST_F(SendTabToSelfBridgeTest, MarkEntryOpenedInformsServer) {
+ InitializeBridge();
+
+ SendTabToSelfEntry entry("guid", GURL("http://g.com/"), "title",
+ AdvanceAndGetTime(), AdvanceAndGetTime(), "remote",
+ "remote");
+ syncer::EntityChangeList remote_data;
+ remote_data.push_back(
+ syncer::EntityChange::CreateAdd("guid", MakeEntityData(entry)));
+ bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
+ std::move(remote_data));
+ ASSERT_THAT(bridge()->GetAllGuids(), UnorderedElementsAre("guid"));
+
+ syncer::EntityData uploaded_opened_entity;
+ EXPECT_CALL(*processor(), Put("guid", _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&uploaded_opened_entity));
+ bridge()->MarkEntryOpened("guid");
+ EXPECT_TRUE(uploaded_opened_entity.specifics.send_tab_to_self().opened());
+}
+
+TEST_F(SendTabToSelfBridgeTest, DismissEntryInformsServer) {
+ InitializeBridge();
+
+ SendTabToSelfEntry entry("guid", GURL("http://g.com/"), "title",
+ AdvanceAndGetTime(), AdvanceAndGetTime(), "remote",
+ "remote");
+ syncer::EntityChangeList remote_data;
+ remote_data.push_back(
+ syncer::EntityChange::CreateAdd("guid", MakeEntityData(entry)));
+ bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(),
+ std::move(remote_data));
+ ASSERT_THAT(bridge()->GetAllGuids(), UnorderedElementsAre("guid"));
+
+ syncer::EntityData uploaded_dismissed_entity;
+ EXPECT_CALL(*processor(), Put("guid", _, _))
+ .WillOnce(SaveArgPointeeMove<1>(&uploaded_dismissed_entity));
+ bridge()->DismissEntry("guid");
+ EXPECT_TRUE(uploaded_dismissed_entity.specifics.send_tab_to_self()
+ .notification_dismissed());
+}
+
TEST_F(SendTabToSelfBridgeTest, PreserveDissmissalAfterRestartBridge) {
InitializeBridge();
@@ -468,8 +517,7 @@ TEST_F(SendTabToSelfBridgeTest, PreserveDissmissalAfterRestartBridge) {
EntityAddList({specifics}));
ASSERT_FALSE(error);
- EXPECT_CALL(*processor(), Put(_, _, _)).Times(0);
- EXPECT_CALL(*processor(), Delete(_, _)).Times(0);
+ EXPECT_CALL(*processor(), Put(_, _, _));
bridge()->DismissEntry(specifics.guid());
@@ -503,11 +551,13 @@ TEST_F(SendTabToSelfBridgeTest, ExpireEntryDuringInit) {
EntityAddList({expired_specifics, not_expired_specifics}));
ASSERT_FALSE(error);
+ ShutdownBridge();
+
AdvanceAndGetTime(kExpiryTime / 2.0);
EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(SizeIs(1)));
+ EXPECT_CALL(*processor(), Delete(_, _));
- ShutdownBridge();
InitializeBridge();
std::vector<std::string> guids = bridge()->GetAllGuids();
@@ -532,6 +582,8 @@ TEST_F(SendTabToSelfBridgeTest, AddExpiredEntry) {
const sync_pb::SendTabToSelfSpecifics not_expired_specifics =
CreateSpecifics(2, AdvanceAndGetTime(), AdvanceAndGetTime());
+ EXPECT_CALL(*processor(), Delete(_, _));
+
auto error = bridge()->ApplySyncChanges(
std::move(metadata_changes),
EntityAddList({expired_specifics, not_expired_specifics}));
@@ -549,11 +601,13 @@ TEST_F(SendTabToSelfBridgeTest, AddInvalidEntries) {
EXPECT_CALL(*mock_observer(), EntriesAddedRemotely(_)).Times(0);
// Add Entry should succeed in this case.
+ EXPECT_CALL(*processor(), Put(_, _, _));
EXPECT_NE(nullptr,
bridge()->AddEntry(GURL("http://www.example.com/"), "d",
AdvanceAndGetTime(), kLocalDeviceCacheGuid));
// Add Entry should fail on invalid URLs.
+ EXPECT_CALL(*processor(), Put(_, _, _)).Times(0);
EXPECT_EQ(nullptr, bridge()->AddEntry(GURL(), "d", AdvanceAndGetTime(),
kLocalDeviceCacheGuid));
EXPECT_EQ(nullptr,
@@ -565,6 +619,7 @@ TEST_F(SendTabToSelfBridgeTest, AddInvalidEntries) {
// Add Entry should succeed on an invalid navigation_time, since that is the
// case for sending links.
+ EXPECT_CALL(*processor(), Put(_, _, _));
EXPECT_NE(nullptr, bridge()->AddEntry(GURL("http://www.example.com/"), "d",
base::Time(), kLocalDeviceCacheGuid));
}
@@ -585,12 +640,14 @@ TEST_F(SendTabToSelfBridgeTest, AddDuplicateEntries) {
base::Time navigation_time = AdvanceAndGetTime();
// The de-duplication code does not use the title as a comparator.
// So they are intentionally different here.
+ EXPECT_CALL(*processor(), Put(_, _, _)).Times(1);
bridge()->AddEntry(GURL("http://a.com"), "a", navigation_time,
kLocalDeviceCacheGuid);
bridge()->AddEntry(GURL("http://a.com"), "b", navigation_time,
kLocalDeviceCacheGuid);
EXPECT_EQ(1ul, bridge()->GetAllGuids().size());
+ EXPECT_CALL(*processor(), Put(_, _, _)).Times(2);
bridge()->AddEntry(GURL("http://a.com"), "a", AdvanceAndGetTime(),
kLocalDeviceCacheGuid);
bridge()->AddEntry(GURL("http://b.com"), "b", AdvanceAndGetTime(),
@@ -599,8 +656,6 @@ TEST_F(SendTabToSelfBridgeTest, AddDuplicateEntries) {
}
TEST_F(SendTabToSelfBridgeTest, NotifyRemoteSendTabToSelfEntryAdded) {
- base::test::ScopedFeatureList scoped_features;
-
const std::string kRemoteGuid = "RemoteDevice";
InitializeBridge();
@@ -805,8 +860,6 @@ TEST_F(SendTabToSelfBridgeTest,
}
TEST_F(SendTabToSelfBridgeTest, NotifyRemoteSendTabToSelfEntryOpened) {
- base::test::ScopedFeatureList scoped_features;
-
InitializeBridge();
SetLocalDeviceCacheGuid("Device1");
@@ -831,8 +884,9 @@ TEST_F(SendTabToSelfBridgeTest, NotifyRemoteSendTabToSelfEntryOpened) {
std::make_unique<syncer::InMemoryMetadataChangeList>();
// an entry with "guid1" should be sent to the observers.
- EXPECT_CALL(*mock_observer(), EntriesOpenedRemotely(AllOf(
- SizeIs(1), ElementsAre(GuidIs("guid1")))));
+ EXPECT_CALL(*mock_observer(),
+ EntriesOpenedRemotely(
+ AllOf(SizeIs(1), UnorderedElementsAre(GuidIs("guid1")))));
bridge()->MergeSyncData(std::move(metadata_change_list),
std::move(remote_input));
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
index 550d6ad2919..5becab82c42 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/feature_list.h"
+#include "components/send_tab_to_self/features.h"
#include "components/sync/driver/sync_auth_util.h"
#include "components/sync/driver/sync_service.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -15,9 +16,17 @@ namespace send_tab_to_self {
SendTabToSelfModelTypeController::SendTabToSelfModelTypeController(
syncer::SyncService* sync_service,
- std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate)
- : ModelTypeController(syncer::SEND_TAB_TO_SELF, std::move(delegate)),
+ std::unique_ptr<syncer::ModelTypeControllerDelegate>
+ delegate_for_full_sync_mode,
+ std::unique_ptr<syncer::ModelTypeControllerDelegate>
+ delegate_for_transport_mode)
+ : ModelTypeController(syncer::SEND_TAB_TO_SELF,
+ std::move(delegate_for_full_sync_mode),
+ std::move(delegate_for_transport_mode)),
sync_service_(sync_service) {
+ DCHECK_EQ(base::FeatureList::IsEnabled(
+ send_tab_to_self::kSendTabToSelfWhenSignedIn),
+ ShouldRunInTransportOnlyMode());
// TODO(crbug.com/906995): Remove this observing mechanism once all sync
// datatypes are stopped by ProfileSyncService, when sync is paused.
sync_service_->AddObserver(this);
@@ -27,6 +36,25 @@ SendTabToSelfModelTypeController::~SendTabToSelfModelTypeController() {
sync_service_->RemoveObserver(this);
}
+void SendTabToSelfModelTypeController::Stop(
+ syncer::ShutdownReason shutdown_reason,
+ StopCallback callback) {
+ DCHECK(CalledOnValidThread());
+ switch (shutdown_reason) {
+ case syncer::STOP_SYNC:
+ // Special case: We want to clear all data even when Sync is stopped
+ // temporarily. This is also needed to make sure the feature stops being
+ // offered to the user, because predicates like IsUserSyncTypeActive()
+ // should return false upon stop.
+ shutdown_reason = syncer::DISABLE_SYNC;
+ break;
+ case syncer::DISABLE_SYNC:
+ case syncer::BROWSER_SHUTDOWN:
+ break;
+ }
+ ModelTypeController::Stop(shutdown_reason, std::move(callback));
+}
+
syncer::DataTypeController::PreconditionState
SendTabToSelfModelTypeController::GetPreconditionState() const {
DCHECK(CalledOnValidThread());
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.h b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.h
index b6b3cb308cf..3e75f88076b 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.h
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.h
@@ -19,14 +19,22 @@ namespace send_tab_to_self {
class SendTabToSelfModelTypeController : public syncer::ModelTypeController,
public syncer::SyncServiceObserver {
public:
- // The |delegate| and |sync_service| must not be null. Furthermore,
- // |sync_service| must outlive this object.
+ // The |delegate_for_full_sync_mode| and |sync_service| must not be null.
+ // |delegate_for_transport_mode| can be null. |sync_service| must outlive this
+ // object.
SendTabToSelfModelTypeController(
syncer::SyncService* sync_service,
- std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate);
+ std::unique_ptr<syncer::ModelTypeControllerDelegate>
+ delegate_for_full_sync_mode,
+ std::unique_ptr<syncer::ModelTypeControllerDelegate>
+ delegate_for_transport_mode);
~SendTabToSelfModelTypeController() override;
// DataTypeController overrides.
+ void Stop(syncer::ShutdownReason shutdown_reason,
+ StopCallback callback) override;
+
+ // DataTypeController overrides.
PreconditionState GetPreconditionState() const override;
// syncer::SyncServiceObserver implementation.
diff --git a/chromium/components/services/app_service/app_service_impl.cc b/chromium/components/services/app_service/app_service_impl.cc
index 2eb4a9c70d9..6395f0e739a 100644
--- a/chromium/components/services/app_service/app_service_impl.cc
+++ b/chromium/components/services/app_service/app_service_impl.cc
@@ -293,6 +293,20 @@ void AppServiceImpl::GetMenuModel(apps::mojom::AppType app_type,
std::move(callback));
}
+void AppServiceImpl::ExecuteContextMenuCommand(apps::mojom::AppType app_type,
+ const std::string& app_id,
+ int command_id,
+ const std::string& shortcut_id,
+ int64_t display_id) {
+ auto iter = publishers_.find(app_type);
+ if (iter == publishers_.end()) {
+ return;
+ }
+
+ iter->second->ExecuteContextMenuCommand(app_id, command_id, shortcut_id,
+ display_id);
+}
+
void AppServiceImpl::OpenNativeSettings(apps::mojom::AppType app_type,
const std::string& app_id) {
auto iter = publishers_.find(app_type);
diff --git a/chromium/components/services/app_service/app_service_impl.h b/chromium/components/services/app_service/app_service_impl.h
index c87c7e6f287..a75d357c2da 100644
--- a/chromium/components/services/app_service/app_service_impl.h
+++ b/chromium/components/services/app_service/app_service_impl.h
@@ -89,6 +89,11 @@ class AppServiceImpl : public apps::mojom::AppService {
apps::mojom::MenuType menu_type,
int64_t display_id,
GetMenuModelCallback callback) override;
+ void ExecuteContextMenuCommand(apps::mojom::AppType app_type,
+ const std::string& app_id,
+ int command_id,
+ const std::string& shortcut_id,
+ int64_t display_id) override;
void OpenNativeSettings(apps::mojom::AppType app_type,
const std::string& app_id) override;
void AddPreferredApp(apps::mojom::AppType app_type,
diff --git a/chromium/components/services/app_service/public/cpp/BUILD.gn b/chromium/components/services/app_service/public/cpp/BUILD.gn
index 16954843794..d9ce78f8395 100644
--- a/chromium/components/services/app_service/public/cpp/BUILD.gn
+++ b/chromium/components/services/app_service/public/cpp/BUILD.gn
@@ -47,6 +47,15 @@ component("app_update") {
]
}
+source_set("app_url_handling") {
+ sources = [
+ "url_handler_info.cc",
+ "url_handler_info.h",
+ ]
+
+ deps = [ "//url" ]
+}
+
if (is_chromeos) {
source_set("instance_update") {
sources = [
diff --git a/chromium/components/services/app_service/public/cpp/app_registry_cache.h b/chromium/components/services/app_service/public/cpp/app_registry_cache.h
index f0f3d5ea6d9..a39f7e32d9e 100644
--- a/chromium/components/services/app_service/public/cpp/app_registry_cache.h
+++ b/chromium/components/services/app_service/public/cpp/app_registry_cache.h
@@ -31,7 +31,7 @@ namespace apps {
//
// This class is not thread-safe.
//
-// See //components/services/app_service/README.md for more details.
+// See components/services/app_service/README.md for more details.
class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
public:
class COMPONENT_EXPORT(APP_UPDATE) Observer : public base::CheckedObserver {
@@ -43,7 +43,7 @@ class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
// Called when the AppRegistryCache object (the thing that this observer
// observes) will be destroyed. In response, the observer, |this|, should
// call "cache->RemoveObserver(this)", whether directly or indirectly (e.g.
- // via ScopedObserver::Remove or via Observe(nullptr)).
+ // via base::ScopedObservation::Remove or via Observe(nullptr)).
virtual void OnAppRegistryCacheWillBeDestroyed(AppRegistryCache* cache) = 0;
protected:
diff --git a/chromium/components/services/app_service/public/cpp/app_update.h b/chromium/components/services/app_service/public/cpp/app_update.h
index fcc6defc226..129a4788dd9 100644
--- a/chromium/components/services/app_service/public/cpp/app_update.h
+++ b/chromium/components/services/app_service/public/cpp/app_update.h
@@ -42,7 +42,7 @@ namespace apps {
// are const. The constructor caller must guarantee that the AppPtr references
// remain valid for the lifetime of the AppUpdate.
//
-// See //components/services/app_service/README.md for more details.
+// See components/services/app_service/README.md for more details.
class COMPONENT_EXPORT(APP_UPDATE) AppUpdate {
public:
// Modifies |state| by copying over all of |delta|'s known fields: those
diff --git a/chromium/components/services/app_service/public/cpp/icon_cache_unittest.cc b/chromium/components/services/app_service/public/cpp/icon_cache_unittest.cc
index c8f063ac337..098ab955558 100644
--- a/chromium/components/services/app_service/public/cpp/icon_cache_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/icon_cache_unittest.cc
@@ -4,8 +4,8 @@
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "components/services/app_service/public/cpp/icon_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
diff --git a/chromium/components/services/app_service/public/cpp/icon_coalescer.cc b/chromium/components/services/app_service/public/cpp/icon_coalescer.cc
index a4121c6c323..06497c44200 100644
--- a/chromium/components/services/app_service/public/cpp/icon_coalescer.cc
+++ b/chromium/components/services/app_service/public/cpp/icon_coalescer.cc
@@ -8,8 +8,8 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
namespace apps {
diff --git a/chromium/components/services/app_service/public/cpp/instance_registry.h b/chromium/components/services/app_service/public/cpp/instance_registry.h
index de60310d627..ca627904758 100644
--- a/chromium/components/services/app_service/public/cpp/instance_registry.h
+++ b/chromium/components/services/app_service/public/cpp/instance_registry.h
@@ -40,7 +40,8 @@ class InstanceRegistry {
// Called when the InstanceRegistry object (the thing that this observer
// observes) will be destroyed. In response, the observer, |this|, should
// call "instance_registry->RemoveObserver(this)", whether directly or
- // indirectly (e.g. via ScopedObserver::Remove or via Observe(nullptr)).
+ // indirectly (e.g. via base::ScopedObservation::Remove or via
+ // Observe(nullptr)).
virtual void OnInstanceRegistryWillBeDestroyed(InstanceRegistry* cache) = 0;
protected:
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter_util.cc b/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
index c8ef6124cae..f022171b067 100644
--- a/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
+++ b/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
@@ -113,6 +113,9 @@ int GetFilterMatchLevel(const apps::mojom::IntentFilterPtr& intent_filter) {
bool FiltersHaveOverlap(const apps::mojom::IntentFilterPtr& filter1,
const apps::mojom::IntentFilterPtr& filter2) {
+ if (filter1->conditions.size() != filter2->conditions.size()) {
+ return false;
+ }
if (GetFilterMatchLevel(filter1) != GetFilterMatchLevel(filter2)) {
return false;
}
diff --git a/chromium/components/services/app_service/public/cpp/publisher_base.cc b/chromium/components/services/app_service/public/cpp/publisher_base.cc
index b401bac27f0..54f85c6be0f 100644
--- a/chromium/components/services/app_service/public/cpp/publisher_base.cc
+++ b/chromium/components/services/app_service/public/cpp/publisher_base.cc
@@ -112,6 +112,13 @@ void PublisherBase::GetMenuModel(const std::string& app_id,
NOTIMPLEMENTED();
}
+void PublisherBase::ExecuteContextMenuCommand(const std::string& app_id,
+ int command_id,
+ const std::string& shortcut_id,
+ int64_t display_id) {
+ NOTIMPLEMENTED();
+}
+
void PublisherBase::OpenNativeSettings(const std::string& app_id) {
NOTIMPLEMENTED();
}
diff --git a/chromium/components/services/app_service/public/cpp/publisher_base.h b/chromium/components/services/app_service/public/cpp/publisher_base.h
index d1a292dfc89..51b3a745f31 100644
--- a/chromium/components/services/app_service/public/cpp/publisher_base.h
+++ b/chromium/components/services/app_service/public/cpp/publisher_base.h
@@ -75,6 +75,10 @@ class PublisherBase : public apps::mojom::Publisher {
apps::mojom::MenuType menu_type,
int64_t display_id,
GetMenuModelCallback callback) override;
+ void ExecuteContextMenuCommand(const std::string& app_id,
+ int command_id,
+ const std::string& shortcut_id,
+ int64_t display_id) override;
void OpenNativeSettings(const std::string& app_id) override;
void OnPreferredAppSet(
const std::string& app_id,
diff --git a/chromium/components/services/app_service/public/cpp/url_handler_info.cc b/chromium/components/services/app_service/public/cpp/url_handler_info.cc
new file mode 100644
index 00000000000..913eba8e705
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/url_handler_info.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 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/services/app_service/public/cpp/url_handler_info.h"
+
+namespace apps {
+
+UrlHandlerInfo::UrlHandlerInfo() = default;
+
+UrlHandlerInfo::UrlHandlerInfo(const UrlHandlerInfo&) = default;
+
+UrlHandlerInfo& UrlHandlerInfo::operator=(const UrlHandlerInfo&) = default;
+
+UrlHandlerInfo::UrlHandlerInfo(UrlHandlerInfo&&) = default;
+
+UrlHandlerInfo& UrlHandlerInfo::operator=(UrlHandlerInfo&&) = default;
+
+UrlHandlerInfo::~UrlHandlerInfo() = default;
+
+bool operator==(const UrlHandlerInfo& handler1,
+ const UrlHandlerInfo& handler2) {
+ return handler1.origin == handler2.origin;
+}
+
+bool operator!=(const UrlHandlerInfo& handler1,
+ const UrlHandlerInfo& handler2) {
+ return !(handler1 == handler2);
+}
+
+std::ostream& operator<<(std::ostream& out, const UrlHandlerInfo& handler) {
+ out << "origin: " << handler.origin;
+ return out;
+}
+
+} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/url_handler_info.h b/chromium/components/services/app_service/public/cpp/url_handler_info.h
new file mode 100644
index 00000000000..1d18de1da5c
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/url_handler_info.h
@@ -0,0 +1,45 @@
+// Copyright 2020 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_SERVICES_APP_SERVICE_PUBLIC_CPP_URL_HANDLER_INFO_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_URL_HANDLER_INFO_H_
+
+#include <ostream>
+#include <vector>
+
+#include "url/origin.h"
+
+namespace apps {
+
+// Contains information about a web app's URL handler information derived from
+// its web app manifest.
+struct UrlHandlerInfo {
+ UrlHandlerInfo();
+ // Copyable to support web_app::WebApp being copyable as it has a UrlHandlers
+ // member variable.
+ UrlHandlerInfo(const UrlHandlerInfo&);
+ UrlHandlerInfo& operator=(const UrlHandlerInfo&);
+ // Movable to support being contained in std::vector, which requires value
+ // types to be copyable or movable.
+ UrlHandlerInfo(UrlHandlerInfo&&);
+ UrlHandlerInfo& operator=(UrlHandlerInfo&&);
+
+ ~UrlHandlerInfo();
+
+ url::Origin origin;
+};
+
+using UrlHandlers = std::vector<UrlHandlerInfo>;
+
+bool operator==(const UrlHandlerInfo& url_handler1,
+ const UrlHandlerInfo& url_handler2);
+
+bool operator!=(const UrlHandlerInfo& url_handler1,
+ const UrlHandlerInfo& url_handler2);
+
+std::ostream& operator<<(std::ostream& out,
+ const UrlHandlerInfo& url_handler_info);
+} // namespace apps
+
+#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_URL_HANDLER_INFO_H_
diff --git a/chromium/components/services/app_service/public/mojom/app_service.mojom b/chromium/components/services/app_service/public/mojom/app_service.mojom
index 697db643f36..4e7763904c1 100644
--- a/chromium/components/services/app_service/public/mojom/app_service.mojom
+++ b/chromium/components/services/app_service/public/mojom/app_service.mojom
@@ -97,6 +97,14 @@ interface AppService {
MenuType menu_type,
int64 display_id) => (MenuItems menu_items);
+ // Executes the menu item command for an app with |app_id|.
+ ExecuteContextMenuCommand(
+ AppType app_type,
+ string app_id,
+ int32 command_id,
+ string shortcut_id,
+ int64 display_id);
+
// Opens native settings for the app with |app_id|.
OpenNativeSettings(
AppType app_type,
@@ -192,6 +200,13 @@ interface Publisher {
MenuType menu_type,
int64 display_id) => (MenuItems menu_items);
+ // Executes the menu item command for an app with |app_id|.
+ ExecuteContextMenuCommand(
+ string app_id,
+ int32 command_id,
+ string shortcut_id,
+ int64 display_id);
+
// Opens native settings for the app with |app_id|.
OpenNativeSettings(
string app_id);
diff --git a/chromium/components/services/app_service/public/mojom/types.mojom b/chromium/components/services/app_service/public/mojom/types.mojom
index f327cf93ec1..b3acba6b6e3 100644
--- a/chromium/components/services/app_service/public/mojom/types.mojom
+++ b/chromium/components/services/app_service/public/mojom/types.mojom
@@ -92,7 +92,7 @@ enum AppType {
kCrostini, // Linux (via Crostini) app.
kExtension, // Extension-backed app.
kWeb, // Web app.
- kMacNative, // Native Mac app.
+ kMacOs, // Mac OS app.
kPluginVm, // Plugin VM app, see go/pluginvm.
kLacros, // Lacros browser app, see //docs/lacros.md.
kRemote, // Remote app.
@@ -237,7 +237,7 @@ enum PermissionValueType {
// kRadio -> [command_id, string_id, radio_group_id].
// kSeparator -> [command_id].
// kSubmenu -> [command_id, string_id, submenu].
-// kArcCommand -> [command_id, shortcut_id, label, image].
+// kPublisherCommand -> [command_id, shortcut_id, label, image].
//
struct MenuItems {
array<MenuItem> items;
@@ -260,7 +260,7 @@ enum MenuItemType {
kRadio, // Can be selected/checked among a group of choices.
kSeparator, // Shows a horizontal line separator.
kSubmenu, // Presents a submenu within another menu.
- kArcCommand, // Performs an ARC shortcut action when selected.
+ kPublisherCommand, // Performs an app publisher shortcut action when selected.
};
// Which component requests context menus, the app list or shelf.
diff --git a/chromium/components/services/filesystem/directory_test_helper.cc b/chromium/components/services/filesystem/directory_test_helper.cc
index b9904f7c4e0..967a3752c44 100644
--- a/chromium/components/services/filesystem/directory_test_helper.cc
+++ b/chromium/components/services/filesystem/directory_test_helper.cc
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/services/filesystem/directory_impl.h"
#include "components/services/filesystem/lock_table.h"
#include "components/services/filesystem/public/mojom/directory.mojom.h"
@@ -52,8 +52,8 @@ DirectoryTestHelper::~DirectoryTestHelper() = default;
mojo::Remote<mojom::Directory> DirectoryTestHelper::CreateTempDir() {
mojo::Remote<mojom::Directory> remote;
- blocking_state_.Post(FROM_HERE, &BlockingState::BindNewTempDirectory,
- remote.BindNewPipeAndPassReceiver());
+ blocking_state_.AsyncCall(&BlockingState::BindNewTempDirectory)
+ .WithArgs(remote.BindNewPipeAndPassReceiver());
return remote;
}
diff --git a/chromium/components/services/font/public/mojom/font_service.mojom b/chromium/components/services/font/public/mojom/font_service.mojom
index e49aa39806a..42c9666b407 100644
--- a/chromium/components/services/font/public/mojom/font_service.mojom
+++ b/chromium/components/services/font/public/mojom/font_service.mojom
@@ -4,8 +4,8 @@
module font_service.mojom;
-import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/file_path.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
enum TypefaceSlant {
ROMAN = 0,
@@ -63,7 +63,7 @@ interface FontService {
(FontIdentity? identity, string family_name, TypefaceStyle style);
// Returns a handle to the raw font specified by |id_number|.
- OpenStream(uint32 id_number) => (mojo_base.mojom.File? font_handle);
+ OpenStream(uint32 id_number) => (mojo_base.mojom.ReadOnlyFile? font_handle);
// Returns a fallback FontIdentity and Typeface style for the given character
// and locale. If no fallback font can be found, returns a null identity.
@@ -93,5 +93,5 @@ interface FontService {
// PPAPI Specific font call to match a font family and charset.
MatchFontWithFallback(string family, bool is_bold, bool is_italic,
uint32 charset, uint32 fallback_family_type) =>
- (mojo_base.mojom.File? font_file_handle);
+ (mojo_base.mojom.ReadOnlyFile? font_file_handle);
};
diff --git a/chromium/components/services/heap_profiling/json_exporter.cc b/chromium/components/services/heap_profiling/json_exporter.cc
index 1b59bc68615..e676edd5e20 100644
--- a/chromium/components/services/heap_profiling/json_exporter.cc
+++ b/chromium/components/services/heap_profiling/json_exporter.cc
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h"
namespace heap_profiling {
namespace {
@@ -125,7 +125,7 @@ base::Value BuildAllocatorsSummary(const AllocationMap& allocations) {
base::Value BuildMemoryMaps(const ExportParams& params) {
base::trace_event::TracedValueJSON traced_value;
- memory_instrumentation::TracingObserver::MemoryMapsAsValueInto(
+ memory_instrumentation::TracingObserverTracedValue::MemoryMapsAsValueInto(
params.maps, &traced_value, params.strip_path_from_mapped_files);
return traced_value.ToBaseValue()->Clone();
}
diff --git a/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc b/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
index ff58a17dc49..d39fdb8e9a3 100644
--- a/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
@@ -14,6 +14,7 @@
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/malloc_dump_provider.h"
#include "base/trace_event/memory_dump_manager.h"
diff --git a/chromium/components/services/paint_preview_compositor/DEPS b/chromium/components/services/paint_preview_compositor/DEPS
index ce653bb5da0..3585cecf2fe 100644
--- a/chromium/components/services/paint_preview_compositor/DEPS
+++ b/chromium/components/services/paint_preview_compositor/DEPS
@@ -5,6 +5,7 @@ include_rules = [
"+content/public/child", # Windows direct write proxy access.
"+content/public/utility",
"+mojo/public/cpp",
+ "+skia/ext",
"+third_party/skia/include",
"+ui/gfx/geometry",
]
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
index 92db7fa0df6..b0796c03f24 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
@@ -25,11 +25,12 @@ PaintPreviewCompositorCollectionImpl::PaintPreviewCompositorCollectionImpl(
mojo::PendingReceiver<mojom::PaintPreviewCompositorCollection> receiver,
bool initialize_environment,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
- : io_task_runner_(std ::move(io_task_runner)) {
+ : initialize_environment_(initialize_environment),
+ io_task_runner_(std ::move(io_task_runner)) {
if (receiver)
receiver_.Bind(std::move(receiver));
- if (!initialize_environment)
+ if (!initialize_environment_)
return;
// Initialize font access for Skia.
@@ -76,7 +77,7 @@ void PaintPreviewCompositorCollectionImpl::SetDiscardableSharedMemoryManager(
discardable_memory::mojom::DiscardableSharedMemoryManager> manager) {
mojo::PendingRemote<discardable_memory::mojom::DiscardableSharedMemoryManager>
manager_remote(std::move(manager));
- discardable_shared_memory_manager_ = std::make_unique<
+ discardable_shared_memory_manager_ = base::MakeRefCounted<
discardable_memory::ClientDiscardableSharedMemoryManager>(
std::move(manager_remote), io_task_runner_);
base::DiscardableMemoryAllocator::SetInstance(
@@ -86,11 +87,12 @@ void PaintPreviewCompositorCollectionImpl::SetDiscardableSharedMemoryManager(
void PaintPreviewCompositorCollectionImpl::CreateCompositor(
mojo::PendingReceiver<mojom::PaintPreviewCompositor> receiver,
PaintPreviewCompositorCollectionImpl::CreateCompositorCallback callback) {
+ DCHECK(discardable_shared_memory_manager_ || !initialize_environment_);
base::UnguessableToken token = base::UnguessableToken::Create();
compositors_.insert(
{token,
std::make_unique<PaintPreviewCompositorImpl>(
- std::move(receiver),
+ std::move(receiver), discardable_shared_memory_manager_,
base::BindOnce(&PaintPreviewCompositorCollectionImpl::OnDisconnect,
weak_ptr_factory_.GetWeakPtr(), token))});
std::move(callback).Run(token);
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
index f35602551b8..5da7a70b249 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
@@ -66,10 +66,6 @@ class PaintPreviewCompositorCollectionImpl
mojo::Receiver<mojom::PaintPreviewCompositorCollection> receiver_{this};
- const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
- std::unique_ptr<discardable_memory::ClientDiscardableSharedMemoryManager>
- discardable_shared_memory_manager_;
-
base::flat_map<base::UnguessableToken,
std::unique_ptr<PaintPreviewCompositorImpl>>
compositors_;
@@ -78,6 +74,13 @@ class PaintPreviewCompositorCollectionImpl
sk_sp<font_service::FontLoader> font_loader_;
#endif
+ const bool initialize_environment_;
+
+ // Ensure the discardable memory manager is the last thing to get destructed.
+ const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager_;
+
base::WeakPtrFactory<PaintPreviewCompositorCollectionImpl> weak_ptr_factory_{
this};
};
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.cc b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.cc
index 9d9fc332bab..24152175ad7 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.cc
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/memory/memory_pressure_listener.h"
#include "base/optional.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
@@ -17,6 +18,7 @@
#include "components/paint_preview/common/serial_utils.h"
#include "components/paint_preview/common/serialized_recording.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageInfo.h"
@@ -81,16 +83,23 @@ base::Optional<PaintPreviewFrame> BuildFrame(
return frame;
}
-base::Optional<SkBitmap> CreateBitmap(sk_sp<SkPicture> skp,
- const gfx::Rect& clip_rect,
- float scale_factor) {
+// Holds a ref to the discardable_shared_memory_manager so it sticks around
+// until at least after skia is finished with it.
+base::Optional<SkBitmap> CreateBitmap(
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager,
+ sk_sp<SkPicture> skp,
+ const gfx::Rect& clip_rect,
+ float scale_factor) {
TRACE_EVENT0("paint_preview", "PaintPreviewCompositorImpl::CreateBitmap");
SkBitmap bitmap;
- if (!bitmap.tryAllocPixels(
- SkImageInfo::MakeN32Premul(clip_rect.width(), clip_rect.height()))) {
+ // Use N32 rather than an alpha color type as frames cannot have transparent
+ // backgrounds.
+ if (!bitmap.tryAllocPixels(SkImageInfo::MakeN32(
+ clip_rect.width(), clip_rect.height(), kOpaque_SkAlphaType))) {
return base::nullopt;
}
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, skia::LegacyDisplayGlobals::GetSkSurfaceProps());
SkMatrix matrix;
matrix.setScaleTranslate(scale_factor, scale_factor, -clip_rect.x(),
-clip_rect.y());
@@ -102,11 +111,18 @@ base::Optional<SkBitmap> CreateBitmap(sk_sp<SkPicture> skp,
PaintPreviewCompositorImpl::PaintPreviewCompositorImpl(
mojo::PendingReceiver<mojom::PaintPreviewCompositor> receiver,
- base::OnceClosure disconnect_handler) {
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager,
+ base::OnceClosure disconnect_handler)
+ : discardable_shared_memory_manager_(discardable_shared_memory_manager) {
if (receiver) {
receiver_.Bind(std::move(receiver));
receiver_.set_disconnect_handler(std::move(disconnect_handler));
}
+ listener_ = std::make_unique<base::MemoryPressureListener>(
+ FROM_HERE,
+ base::BindRepeating(&PaintPreviewCompositorImpl::OnMemoryPressure,
+ weak_ptr_factory_.GetWeakPtr()));
}
PaintPreviewCompositorImpl::~PaintPreviewCompositorImpl() {
@@ -190,9 +206,10 @@ void PaintPreviewCompositorImpl::BitmapForSeparatedFrame(
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
- {base::TaskPriority::USER_VISIBLE, base::WithBaseSyncPrimitives()},
- base::BindOnce(&CreateBitmap, frame_it->second.skp, clip_rect,
- scale_factor),
+ {base::TaskPriority::USER_VISIBLE, base::WithBaseSyncPrimitives(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(&CreateBitmap, discardable_shared_memory_manager_,
+ frame_it->second.skp, clip_rect, scale_factor),
base::BindOnce(
[](BitmapForSeparatedFrameCallback callback,
const base::Optional<SkBitmap>& maybe_bitmap) {
@@ -267,8 +284,10 @@ void PaintPreviewCompositorImpl::BitmapForMainFrame(
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
- {base::TaskPriority::USER_VISIBLE, base::WithBaseSyncPrimitives()},
- base::BindOnce(&CreateBitmap, root_frame_, clip_rect, scale_factor),
+ {base::TaskPriority::USER_VISIBLE, base::WithBaseSyncPrimitives(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(&CreateBitmap, discardable_shared_memory_manager_,
+ root_frame_, clip_rect, scale_factor),
base::BindOnce(
[](BitmapForMainFrameCallback callback,
const base::Optional<SkBitmap>& maybe_bitmap) {
@@ -289,6 +308,14 @@ void PaintPreviewCompositorImpl::SetRootFrameUrl(const GURL& url) {
url_ = url;
}
+void PaintPreviewCompositorImpl::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ if (memory_pressure_level >=
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+ receiver_.reset();
+ }
+}
+
bool PaintPreviewCompositorImpl::AddFrame(
const PaintPreviewFrameProto& frame_proto,
const base::flat_map<base::UnguessableToken, SkpResult>& skp_map,
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.h b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.h
index f339373e5c4..285fff1bc7c 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.h
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/optional.h"
+#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "components/paint_preview/common/recording_map.h"
#include "components/services/paint_preview_compositor/paint_preview_frame.h"
@@ -36,9 +37,15 @@ class PaintPreviewCompositorImpl : public mojom::PaintPreviewCompositor {
// connected to a remote) and |disconnect_handler| should be a no-op.
explicit PaintPreviewCompositorImpl(
mojo::PendingReceiver<mojom::PaintPreviewCompositor> receiver,
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager,
base::OnceClosure disconnect_handler);
~PaintPreviewCompositorImpl() override;
+ PaintPreviewCompositorImpl(const PaintPreviewCompositorImpl&) = delete;
+ PaintPreviewCompositorImpl& operator=(const PaintPreviewCompositorImpl&) =
+ delete;
+
// PaintPreviewCompositor implementation.
void BeginSeparatedFrameComposite(
mojom::PaintPreviewBeginCompositeRequestPtr request,
@@ -57,6 +64,9 @@ class PaintPreviewCompositorImpl : public mojom::PaintPreviewCompositor {
void SetRootFrameUrl(const GURL& url) override;
private:
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
// Adds |frame_proto| to |frames_| and copies required data into |response|.
// Consumes the corresponding file in |file_map|. Returns true on success.
bool AddFrame(
@@ -96,9 +106,12 @@ class PaintPreviewCompositorImpl : public mojom::PaintPreviewCompositor {
// Must be modified only by |BeginMainFrameComposite|.
sk_sp<SkPicture> root_frame_;
- PaintPreviewCompositorImpl(const PaintPreviewCompositorImpl&) = delete;
- PaintPreviewCompositorImpl& operator=(const PaintPreviewCompositorImpl&) =
- delete;
+ std::unique_ptr<base::MemoryPressureListener> listener_;
+
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ discardable_shared_memory_manager_;
+
+ base::WeakPtrFactory<PaintPreviewCompositorImpl> weak_ptr_factory_{this};
};
} // namespace paint_preview
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl_unittest.cc b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl_unittest.cc
index 2796be835c0..58837cb193f 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl_unittest.cc
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_impl_unittest.cc
@@ -9,7 +9,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/files/file.h"
@@ -301,7 +301,7 @@ class PaintPreviewCompositorBeginCompositeTest
GURL url_{"https://www.chromium.org"};
private:
- PaintPreviewCompositorImpl compositor_{mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor_{mojo::NullReceiver(), nullptr,
base::DoNothing()};
};
@@ -574,7 +574,7 @@ TEST(PaintPreviewCompositorTest, TestComposite) {
base::test::TaskEnvironment task_environment;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -599,8 +599,9 @@ TEST(PaintPreviewCompositorTest, TestComposite) {
gfx::Rect rect = gfx::ScaleToEnclosingRect(
gfx::Rect(root_frame_scroll_extent), scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
DrawDummyTestPicture(&canvas, SK_ColorDKGRAY, root_frame_scroll_extent);
compositor.BitmapForSeparatedFrame(
@@ -619,7 +620,7 @@ TEST(PaintPreviewCompositorTest, TestComposite) {
TEST(PaintPreviewCompositorTest, TestCompositeWithMemoryBuffer) {
base::test::TaskEnvironment task_environment;
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -670,8 +671,9 @@ TEST(PaintPreviewCompositorTest, TestCompositeWithMemoryBuffer) {
gfx::Rect rect = gfx::ScaleToEnclosingRect(
gfx::Rect(root_frame_scroll_extent), scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
DrawDummyTestPicture(&canvas, SK_ColorDKGRAY, root_frame_scroll_extent);
compositor.BitmapForSeparatedFrame(
@@ -692,7 +694,7 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameNoDependencies) {
base::test::TaskEnvironment task_environment;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -719,8 +721,9 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameNoDependencies) {
gfx::Rect rect = gfx::ScaleToEnclosingRect(
gfx::Rect(root_frame_scroll_extent), scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
DrawDummyTestPicture(&canvas, SK_ColorDKGRAY, root_frame_scroll_extent);
compositor.BitmapForMainFrame(
@@ -735,7 +738,7 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameOneDependency) {
base::test::TaskEnvironment task_environment;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -773,8 +776,9 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameOneDependency) {
gfx::Rect rect = gfx::ScaleToEnclosingRect(
gfx::Rect(root_frame_scroll_extent), scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
DrawDummyTestPicture(&canvas, SK_ColorDKGRAY, root_frame_scroll_extent);
// Draw the subframe where we embedded it while populating the proto.
@@ -792,7 +796,7 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameOneDependencyScrolled) {
base::test::TaskEnvironment task_environment;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -831,8 +835,9 @@ TEST(PaintPreviewCompositorTest, TestCompositeMainFrameOneDependencyScrolled) {
gfx::Rect rect = gfx::ScaleToEnclosingRect(
gfx::Rect(root_frame_scroll_extent), scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
DrawDummyTestPicture(&canvas, SK_ColorDKGRAY, root_frame_scroll_extent);
// Draw the subframe where we embedded it while populating the proto.
@@ -851,7 +856,7 @@ TEST(PaintPreviewCompositorTest,
base::test::TaskEnvironment task_environment;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- PaintPreviewCompositorImpl compositor(mojo::NullReceiver(),
+ PaintPreviewCompositorImpl compositor(mojo::NullReceiver(), nullptr,
base::BindOnce([]() {}));
GURL url("https://www.chromium.org");
const base::UnguessableToken kRootFrameID = base::UnguessableToken::Create();
@@ -892,8 +897,9 @@ TEST(PaintPreviewCompositorTest,
gfx::Rect rect =
gfx::ScaleToEnclosingRect(root_frame_clip_rect, scale_factor);
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
- SkCanvas canvas(bitmap);
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(rect.width(), rect.height(), kOpaque_SkAlphaType));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.scale(scale_factor, scale_factor);
// Offset the canvas to simulate the root frame being scrolled.
canvas.translate(-root_frame_clip_rect.x(), -root_frame_clip_rect.y());
diff --git a/chromium/components/services/patch/public/mojom/file_patcher.mojom b/chromium/components/services/patch/public/mojom/file_patcher.mojom
index ab0be5b9561..a98630563ce 100644
--- a/chromium/components/services/patch/public/mojom/file_patcher.mojom
+++ b/chromium/components/services/patch/public/mojom/file_patcher.mojom
@@ -5,21 +5,22 @@
module patch.mojom;
import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
interface FilePatcher {
// Patch |input_file| with |patch_file| using the bsdiff algorithm
// (Courgette's version) and place the output in |output_file|.
// Returns |result| bsdiff::BSDiffStatus::OK on success.
PatchFileBsdiff(
- mojo_base.mojom.File input_file,
- mojo_base.mojom.File patch_file,
+ mojo_base.mojom.ReadOnlyFile input_file,
+ mojo_base.mojom.ReadOnlyFile patch_file,
mojo_base.mojom.File output_file) => (int32 result);
// Patch |input_file| with |patch_file| using the Courgette algorithm
// and place the output in |output_file|.
// Returns |result| courgette::Status::C_OK on success.
PatchFileCourgette(
- mojo_base.mojom.File input_file,
- mojo_base.mojom.File patch_file,
+ mojo_base.mojom.ReadOnlyFile input_file,
+ mojo_base.mojom.ReadOnlyFile patch_file,
mojo_base.mojom.File output_file) => (int32 result);
};
diff --git a/chromium/components/services/print_compositor/print_compositor_impl.cc b/chromium/components/services/print_compositor/print_compositor_impl.cc
index 81db9af1f57..f8f81cc9ae1 100644
--- a/chromium/components/services/print_compositor/print_compositor_impl.cc
+++ b/chromium/components/services/print_compositor/print_compositor_impl.cc
@@ -112,7 +112,7 @@ void PrintCompositorImpl::SetDiscardableSharedMemoryManager(
// Set up discardable memory manager.
mojo::PendingRemote<discardable_memory::mojom::DiscardableSharedMemoryManager>
manager_remote(std::move(manager));
- discardable_shared_memory_manager_ = std::make_unique<
+ discardable_shared_memory_manager_ = base::MakeRefCounted<
discardable_memory::ClientDiscardableSharedMemoryManager>(
std::move(manager_remote), io_task_runner_);
base::DiscardableMemoryAllocator::SetInstance(
diff --git a/chromium/components/services/print_compositor/print_compositor_impl.h b/chromium/components/services/print_compositor/print_compositor_impl.h
index 44a3d29179c..6a97b2703b7 100644
--- a/chromium/components/services/print_compositor/print_compositor_impl.h
+++ b/chromium/components/services/print_compositor/print_compositor_impl.h
@@ -230,7 +230,7 @@ class PrintCompositorImpl : public mojom::PrintCompositor {
mojo::Receiver<mojom::PrintCompositor> receiver_{this};
const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
- std::unique_ptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
discardable_shared_memory_manager_;
// The creator of this service.
diff --git a/chromium/components/services/print_compositor/public/mojom/print_compositor.mojom b/chromium/components/services/print_compositor/public/mojom/print_compositor.mojom
index 3bcf0e4ca00..60d966717a6 100644
--- a/chromium/components/services/print_compositor/public/mojom/print_compositor.mojom
+++ b/chromium/components/services/print_compositor/public/mojom/print_compositor.mojom
@@ -48,7 +48,11 @@ interface PrintCompositor {
// Sets the accessibility tree for the overall document. This is needed
// to generate tagged (accessible) PDFs.
- [EnableIf=enable_tagged_pdf]
+ //
+ // TODO(crbug.com/1141990): AXTreeUpdate can be quite large, hence the
+ // [UnlimitedSize] tag. It may be possible to remove this if AXTreeUpdate
+ // can be reworked to avoid very large serialized values.
+ [EnableIf=enable_tagged_pdf, UnlimitedSize]
SetAccessibilityTree(ax.mojom.AXTreeUpdate accessibility_tree);
// Requests to composite a page and convert it into a PDF file.
diff --git a/chromium/components/services/quarantine/BUILD.gn b/chromium/components/services/quarantine/BUILD.gn
index fe21b0eb899..79a97348fc5 100644
--- a/chromium/components/services/quarantine/BUILD.gn
+++ b/chromium/components/services/quarantine/BUILD.gn
@@ -8,21 +8,12 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("quarantine") {
sources = [
"quarantine.cc",
"quarantine.h",
"quarantine_impl.cc",
"quarantine_impl.h",
- "quarantine_mac.mm",
- "quarantine_win.cc",
]
public_deps = [ "//components/services/quarantine/public/mojom" ]
@@ -35,10 +26,12 @@ static_library("quarantine") {
]
if (is_win) {
+ sources += [ "quarantine_win.cc" ]
deps += [ "//components/services/quarantine/public/cpp:features" ]
}
if (is_mac) {
+ sources += [ "quarantine_mac.mm" ]
frameworks = [
"Carbon.framework",
"Foundation.framework",
@@ -50,10 +43,6 @@ source_set("common") {
sources = [
"common.cc",
"common.h",
- "common_mac.h",
- "common_mac.mm",
- "common_win.cc",
- "common_win.h",
]
deps = [
@@ -61,7 +50,18 @@ source_set("common") {
"//url",
]
+ if (is_win) {
+ sources += [
+ "common_win.cc",
+ "common_win.h",
+ ]
+ }
+
if (is_mac) {
+ sources += [
+ "common_mac.h",
+ "common_mac.mm",
+ ]
frameworks = [
"Carbon.framework",
"Foundation.framework",
@@ -75,8 +75,6 @@ source_set("test_support") {
sources = [
"test_support.cc",
"test_support.h",
- "test_support_mac.mm",
- "test_support_win.cc",
]
deps = [
@@ -86,7 +84,12 @@ source_set("test_support") {
"//url",
]
+ if (is_win) {
+ sources += [ "test_support_win.cc" ]
+ }
+
if (is_mac) {
+ sources += [ "test_support_mac.mm" ]
frameworks = [
"Carbon.framework",
"Foundation.framework",
@@ -99,9 +102,7 @@ source_set("unit_tests") {
sources = [
"common_unittests.cc",
- "quarantine_mac_unittest.mm",
"quarantine_service_unittest.cc",
- "quarantine_win_unittest.cc",
]
# Chromecasts do not have extended attributes enabled; even if it were
@@ -126,10 +127,12 @@ source_set("unit_tests") {
]
if (is_win) {
+ sources += [ "quarantine_win_unittest.cc" ]
deps += [ "//components/services/quarantine/public/cpp:features" ]
}
if (is_mac) {
+ sources += [ "quarantine_mac_unittest.mm" ]
frameworks = [
"Carbon.framework",
"Foundation.framework",
diff --git a/chromium/components/services/quarantine/quarantine_win_unittest.cc b/chromium/components/services/quarantine/quarantine_win_unittest.cc
index a5eb082d1d1..adaf5937544 100644
--- a/chromium/components/services/quarantine/quarantine_win_unittest.cc
+++ b/chromium/components/services/quarantine/quarantine_win_unittest.cc
@@ -11,7 +11,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/test_file_util.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/scoped_com_initializer.h"
diff --git a/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc b/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc
index 79c88265011..0c4c3bb16e6 100644
--- a/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/dom_storage_database_unittest.cc
@@ -15,7 +15,7 @@
#include "base/strings/string_piece.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/services/storage/dom_storage/local_storage_impl.cc b/chromium/components/services/storage/dom_storage/local_storage_impl.cc
index 087978a227a..54f6cfb7c51 100644
--- a/chromium/components/services/storage/dom_storage/local_storage_impl.cc
+++ b/chromium/components/services/storage/dom_storage/local_storage_impl.cc
@@ -14,7 +14,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/metrics/histogram_functions.h"
diff --git a/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc b/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
index 928390206a1..a08f132a787 100644
--- a/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
@@ -5,7 +5,7 @@
#include "components/services/storage/dom_storage/local_storage_impl.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/span.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
@@ -14,7 +14,7 @@
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/services/storage/dom_storage/legacy_dom_storage_database.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
index ba3abadf525..7378b1d1862 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
@@ -6,15 +6,15 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
index 992ee8ecc16..f658e6d1518 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
@@ -13,7 +13,7 @@
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/services/storage/dom_storage/async_dom_storage_database.h"
#include "components/services/storage/dom_storage/dom_storage_database.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_impl.cc b/chromium/components/services/storage/dom_storage/session_storage_impl.cc
index 15b6cc5a79f..811a0717a8a 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_impl.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_impl.cc
@@ -11,7 +11,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_impl_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_impl_unittest.cc
index e8f24b42ead..c46eebfba19 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_impl_unittest.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -21,7 +21,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/services/storage/dom_storage/legacy_dom_storage_database.h"
#include "components/services/storage/dom_storage/storage_area_test_util.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_metadata_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
index 6e4502c50fa..c714338581a 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
@@ -14,7 +14,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/services/storage/dom_storage/async_dom_storage_database.h"
diff --git a/chromium/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
index 6fe3343c5c1..435a8ea767a 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
@@ -6,13 +6,13 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "components/services/storage/dom_storage/async_dom_storage_database.h"
diff --git a/chromium/components/services/storage/dom_storage/storage_area_impl.cc b/chromium/components/services/storage/dom_storage/storage_area_impl.cc
index d68d156ad61..0b90c34a9ee 100644
--- a/chromium/components/services/storage/dom_storage/storage_area_impl.cc
+++ b/chromium/components/services/storage/dom_storage/storage_area_impl.cc
@@ -5,7 +5,7 @@
#include "components/services/storage/dom_storage/storage_area_impl.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/span.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc b/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
index cb2e6997a41..6c2761aa002 100644
--- a/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
@@ -6,7 +6,6 @@
#include "base/atomic_ref_count.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/containers/span.h"
#include "base/memory/ptr_util.h"
@@ -15,7 +14,7 @@
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
diff --git a/chromium/components/services/storage/dom_storage/storage_area_test_util.cc b/chromium/components/services/storage/dom_storage/storage_area_test_util.cc
index de01b2cd713..b426a152240 100644
--- a/chromium/components/services/storage/dom_storage/storage_area_test_util.cc
+++ b/chromium/components/services/storage/dom_storage/storage_area_test_util.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
namespace storage {
namespace test {
diff --git a/chromium/components/services/storage/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc b/chromium/components/services/storage/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
index cf60a41c4fa..76371ccdd00 100644
--- a/chromium/components/services/storage/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
@@ -6,11 +6,10 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/scopes/scope_lock.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scope_unittest.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scope_unittest.cc
index 05dde0a27c9..8d8b5da7374 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scope_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scope_unittest.cc
@@ -12,7 +12,7 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/leveldb/fake_leveldb_factory.h"
#include "components/services/storage/indexed_db/scopes/disjoint_range_lock_manager.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
index 9cfaf41c644..1f6d99a8979 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
@@ -10,7 +10,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc
index 8905a11f70a..09ca4951f39 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks_unittest.cc
@@ -6,7 +6,7 @@
#include <limits>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/scopes/leveldb_scopes_coding.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
index bb1605febfe..423c877f158 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
@@ -11,7 +11,7 @@
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event_watcher.h"
#include "base/system/sys_info.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/leveldb/leveldb_factory.h"
#include "third_party/leveldatabase/env_chromium.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_unittest.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_unittest.cc
index 0a19fccf7fc..93040fe1d4e 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/scopes/disjoint_range_lock_manager.h"
#include "components/services/storage/indexed_db/scopes/leveldb_scopes.h"
diff --git a/chromium/components/services/storage/indexed_db/scopes/scopes_lock_manager_unittest.cc b/chromium/components/services/storage/indexed_db/scopes/scopes_lock_manager_unittest.cc
index 293c55e7ede..d7c30dfe6fd 100644
--- a/chromium/components/services/storage/indexed_db/scopes/scopes_lock_manager_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/scopes_lock_manager_unittest.cc
@@ -7,7 +7,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
index 161deaa6fea..4042de63d93 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
@@ -17,7 +17,7 @@
#include "base/files/file_path.h"
#include "base/no_destructor.h"
#include "base/strings/string_piece.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/services/storage/indexed_db/scopes/disjoint_range_lock_manager.h"
#include "components/services/storage/indexed_db/scopes/leveldb_scope.h"
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc
index 20a5406ab23..b24a465a1ce 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc
@@ -9,7 +9,7 @@
#include <tuple>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/components/services/storage/public/mojom/service_worker_database.mojom b/chromium/components/services/storage/public/mojom/service_worker_database.mojom
index 69fc9fa8df3..016fb80e81a 100644
--- a/chromium/components/services/storage/public/mojom/service_worker_database.mojom
+++ b/chromium/components/services/storage/public/mojom/service_worker_database.mojom
@@ -23,6 +23,9 @@ enum ServiceWorkerDatabaseStatus {
kErrorFailed = 4,
kErrorNotSupported = 5,
kErrorDisabled = 6,
+ // Mojo connection to the Storage Service is disconnected, typically due to a
+ // crash.
+ kErrorStorageDisconnected = 7,
};
// Represents a service worker registration data which is stored persistently
diff --git a/chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom b/chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom
index e37f95356df..f45a3714aa0 100644
--- a/chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom
+++ b/chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom
@@ -24,6 +24,21 @@ import "url/mojom/url.mojom";
// owned by the C++ ServiceWorkerVersion instance.
interface ServiceWorkerLiveVersionRef {};
+// Conveys information about a live service worker version. Sent from the
+// browser to the Storage Service to recover resource purging state after a
+// Storage Service restart.
+struct ServiceWorkerLiveVersionInfo {
+ // Version id.
+ int64 id;
+ // Contains resource ids which are purgeable when `reference` is disconnected.
+ // Non-empty only when the associated service worker registration has been
+ // deleted from the storage but the corresponding service worker version is
+ // still being used.
+ array<int64> purgeable_resources;
+ // A receiver which is associated with `id`.
+ pending_receiver<ServiceWorkerLiveVersionRef> reference;
+};
+
// Conveys a result of finding a registration.
// The Storage Service (components/services/storage) supplies this
// information and the //content consumes the information.
@@ -55,6 +70,9 @@ interface ServiceWorkerDataPipeStateNotifier {
};
// An interface that reads a service worker script (resource) to storage.
+// A valid use of this interface is that exactly one call to
+// ReadResponseHead(), followed by possibly multiple ReadData() calls. Each call
+// must not be overlapped.
interface ServiceWorkerResourceReader {
// Reads the response head of the resource associated with this reader.
// |status| is the number of bytes read, or a //net error.
@@ -70,6 +88,9 @@ interface ServiceWorkerResourceReader {
};
// An interface that writes a service worker script (resource) to storage.
+// A valid use of this interface is that exactly one call to
+// WriteResponseHead(), followed by at most one call to WriteData(). These calls
+// must not be overlapped.
interface ServiceWorkerResourceWriter {
// Writes the response head to storage. Returns the number of bytes written,
// or a //net error.
@@ -81,7 +102,7 @@ interface ServiceWorkerResourceWriter {
};
// An interface that writes a metadata (script cache) of a service worker script
-// to storage.
+// to storage. WriteMetadata() should be called at most once.
interface ServiceWorkerResourceMetadataWriter {
// Writes the metadata of the resource associated with this writer. Returns
// the number of bytes written, or a //net error.
@@ -110,6 +131,12 @@ interface ServiceWorkerStorageControl {
// Deletes the whole storage.
Delete() => (ServiceWorkerDatabaseStatus status);
+ // Called by the browser after a Storage Service restart. Tells the Storage
+ // Service which service worker versions are being used, which is needed to
+ // decide when it's safe to purge resources for service worker versions that
+ // have been deleted.
+ Recover(array<ServiceWorkerLiveVersionInfo> versions) => ();
+
// Returns all origins which have service worker registrations.
GetRegisteredOrigins() => (array<url.mojom.Origin> origins);
@@ -261,4 +288,18 @@ interface ServiceWorkerStorageControl {
// Applies changes to data retention policy which are relevant at shutdown.
// This is analogous to LocalStorageControl::ApplyPolicyUpdates.
ApplyPolicyUpdates(array<LocalStoragePolicyUpdate> policy_updates);
+
+ // Get resource ids which are scheduled to purge.
+ GetPurgingResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
+ array<int64> resource_ids);
+ // Gets resource ids which are purgeable.
+ GetPurgeableResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
+ array<int64> resource_ids);
+ // Gets resource ids which are uncommitted.
+ GetUncommittedResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
+ array<int64> resource_ids);
+ // Sets a callback which is executed when purging resources completes.
+ // Only a single callback can be set at a time. Overlapped calls are not
+ // allowed.
+ SetPurgingCompleteCallbackForTest() => ();
};
diff --git a/chromium/components/services/unzip/public/mojom/unzipper.mojom b/chromium/components/services/unzip/public/mojom/unzipper.mojom
index 8fd46f5a943..2822066ccc4 100644
--- a/chromium/components/services/unzip/public/mojom/unzipper.mojom
+++ b/chromium/components/services/unzip/public/mojom/unzipper.mojom
@@ -5,8 +5,8 @@
module unzip.mojom;
import "components/services/filesystem/public/mojom/directory.mojom";
-import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/file_path.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
interface UnzipFilter {
[Sync]
@@ -16,14 +16,14 @@ interface UnzipFilter {
interface Unzipper {
// Unzip |zip_file| into |output_dir|.
// Returns true on success, false otherwise.
- Unzip(mojo_base.mojom.File zip_file,
+ Unzip(mojo_base.mojom.ReadOnlyFile zip_file,
pending_remote<filesystem.mojom.Directory> output_dir)
=> (bool result);
// Same as |unzip| but only includes the files for which |filter| returns
// true. Note that this incurs one IPC for each file of the archive.
UnzipWithFilter(
- mojo_base.mojom.File zip_file,
+ mojo_base.mojom.ReadOnlyFile zip_file,
pending_remote<filesystem.mojom.Directory> output_dir,
pending_remote<UnzipFilter> filter) => (bool result);
};
diff --git a/chromium/components/session_manager/session_manager_types.h b/chromium/components/session_manager/session_manager_types.h
index 0c10be0a755..955c39c94a4 100644
--- a/chromium/components/session_manager/session_manager_types.h
+++ b/chromium/components/session_manager/session_manager_types.h
@@ -33,8 +33,8 @@ enum class SessionState {
// The session screen is locked.
LOCKED,
- // Same as SESSION_STATE_LOGIN_PRIMARY but for multi-profiles sign in i.e.
- // when there's at least one user already active in the session.
+ // Same as LOGIN_PRIMARY but for multi-profiles sign in i.e. when there's at
+ // least one user already active in the session.
LOGIN_SECONDARY,
};
diff --git a/chromium/components/sessions/BUILD.gn b/chromium/components/sessions/BUILD.gn
index dcfbf864893..904fc5b8616 100644
--- a/chromium/components/sessions/BUILD.gn
+++ b/chromium/components/sessions/BUILD.gn
@@ -8,13 +8,6 @@ if (is_android) {
import("//build/config/android/config.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
config("implementation") {
defines = [ "SESSIONS_IMPLEMENTATION" ]
}
@@ -191,17 +184,12 @@ static_library("test_support") {
}
source_set("unit_tests") {
- if (is_ios) {
- configs += [ "//build/config/compiler:enable_arc" ]
- }
testonly = true
sources = [
"core/command_storage_backend_unittest.cc",
"core/serialized_navigation_entry_unittest.cc",
"core/session_id_generator_unittest.cc",
"core/snapshotting_session_backend_unittest.cc",
- "ios/ios_serialized_navigation_builder_unittest.mm",
- "ios/ios_serialized_navigation_driver_unittest.cc",
]
if (!is_ios) {
@@ -210,6 +198,12 @@ source_set("unit_tests") {
"content/content_serialized_navigation_driver_unittest.cc",
"content/navigation_task_id_unittest.cc",
]
+ } else {
+ sources += [
+ "ios/ios_serialized_navigation_builder_unittest.mm",
+ "ios/ios_serialized_navigation_driver_unittest.cc",
+ ]
+ configs += [ "//build/config/compiler:enable_arc" ]
}
public_deps = [ ":sessions" ]
diff --git a/chromium/components/sessions/content/DEPS b/chromium/components/sessions/content/DEPS
index ce5cab76a69..06e1f2433d4 100644
--- a/chromium/components/sessions/content/DEPS
+++ b/chromium/components/sessions/content/DEPS
@@ -4,7 +4,8 @@ include_rules = [
"+content/public/test",
"+extensions/buildflags",
"+extensions/common",
- "+third_party/blink/public/platform",
+ "+third_party/blink/public/common/page_state/page_state.h",
"+third_party/blink/public/common/user_agent/user_agent_metadata.h",
+ "+third_party/blink/public/platform",
"+services/network/public/mojom/referrer_policy.mojom.h",
]
diff --git a/chromium/components/sessions/content/content_serialized_navigation_builder.cc b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
index 27b66c0145b..6c9558b67ee 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_builder.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
@@ -17,8 +17,8 @@
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/replaced_navigation_entry_data.h"
-#include "content/public/common/page_state.h"
#include "content/public/common/referrer.h"
+#include "third_party/blink/public/common/page_state/page_state.h"
namespace sessions {
namespace {
@@ -122,7 +122,7 @@ ContentSerializedNavigationBuilder::ToNavigationEntry(
// Ensure that the deserialized/restored content::NavigationEntry (and
// the content::FrameNavigationEntry underneath) has a valid PageState.
entry->SetPageState(
- content::PageState::CreateFromURL(navigation->virtual_url_));
+ blink::PageState::CreateFromURL(navigation->virtual_url_));
// The |navigation|-based referrer set below might be inconsistent with the
// referrer embedded inside the PageState set above. Nevertheless, to
@@ -141,7 +141,7 @@ ContentSerializedNavigationBuilder::ToNavigationEntry(
// Note that PageState covers some of the values inside |navigation| (e.g.
// URL, Referrer). Calling SetPageState will clobber these values in
// content::NavigationEntry (and FrameNavigationEntry(s) below).
- entry->SetPageState(content::PageState::CreateFromEncodedData(
+ entry->SetPageState(blink::PageState::CreateFromEncodedData(
navigation->encoded_page_state_));
// |navigation|-level referrer information is redundant wrt PageState, but
diff --git a/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc b/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
index a8d2d284b25..9c4e1d7c409 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_builder_unittest.cc
@@ -18,11 +18,11 @@
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
-#include "content/public/common/page_state.h"
#include "content/public/common/referrer.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/page_state/page_state.h"
namespace sessions {
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.cc b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
index 3521d41815d..017f8059e31 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
@@ -8,8 +8,8 @@
#include "base/memory/singleton.h"
#include "components/sessions/core/serialized_navigation_entry.h"
-#include "content/public/common/page_state.h"
#include "services/network/public/mojom/referrer_policy.mojom.h"
+#include "third_party/blink/public/common/page_state/page_state.h"
namespace sessions {
@@ -60,8 +60,8 @@ ContentSerializedNavigationDriver::GetSanitizedPageStateForPickle(
if (!navigation->has_post_data())
return navigation->encoded_page_state();
- content::PageState page_state = content::PageState::CreateFromEncodedData(
- navigation->encoded_page_state());
+ blink::PageState page_state =
+ blink::PageState::CreateFromEncodedData(navigation->encoded_page_state());
return page_state.RemovePasswordData().ToEncodedData();
}
@@ -71,7 +71,7 @@ void ContentSerializedNavigationDriver::Sanitize(
std::string ContentSerializedNavigationDriver::StripReferrerFromPageState(
const std::string& page_state) const {
- return content::PageState::CreateFromEncodedData(page_state)
+ return blink::PageState::CreateFromEncodedData(page_state)
.RemoveReferrer()
.ToEncodedData();
}
diff --git a/chromium/components/sessions/core/command_storage_backend_unittest.cc b/chromium/components/sessions/core/command_storage_backend_unittest.cc
index 10bf2eb5cf6..aadc28df39e 100644
--- a/chromium/components/sessions/core/command_storage_backend_unittest.cc
+++ b/chromium/components/sessions/core/command_storage_backend_unittest.cc
@@ -14,7 +14,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/sessions/core/command_storage_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/sessions/core/session_command.h b/chromium/components/sessions/core/session_command.h
index 69a4bbb1e7a..23ffc3fab89 100644
--- a/chromium/components/sessions/core/session_command.h
+++ b/chromium/components/sessions/core/session_command.h
@@ -12,6 +12,7 @@
#include <string>
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "components/sessions/core/sessions_export.h"
namespace base {
@@ -50,7 +51,9 @@ class SESSIONS_EXPORT SessionCommand {
// The contents of the command.
char* contents() { return const_cast<char*>(contents_.c_str()); }
const char* contents() const { return contents_.c_str(); }
-
+ base::StringPiece contents_as_string_piece() const {
+ return base::StringPiece(contents_);
+ }
// Identifier for the command.
id_type id() const { return id_; }
diff --git a/chromium/components/sessions/core/session_service_commands.cc b/chromium/components/sessions/core/session_service_commands.cc
index c931e3ff0f0..25eb017d0c8 100644
--- a/chromium/components/sessions/core/session_service_commands.cc
+++ b/chromium/components/sessions/core/session_service_commands.cc
@@ -65,7 +65,8 @@ static const SessionCommand::id_type kCommandLastActiveTime = 21;
static const SessionCommand::id_type kCommandSetWindowWorkspace2 = 23;
static const SessionCommand::id_type kCommandTabNavigationPathPruned = 24;
static const SessionCommand::id_type kCommandSetTabGroup = 25;
-static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26;
+// OBSOLETE Superseded by kCommandSetTabGroupMetadata2.
+// static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26;
static const SessionCommand::id_type kCommandSetTabGroupMetadata2 = 27;
static const SessionCommand::id_type kCommandSetTabGuid = 28;
static const SessionCommand::id_type kCommandSetTabUserAgentOverride2 = 29;
@@ -635,7 +636,6 @@ bool CreateTabsAndWindows(
break;
}
- case kCommandSetTabGroupMetadata:
case kCommandSetTabGroupMetadata2: {
std::unique_ptr<base::Pickle> pickle = command->PayloadAsPickle();
base::PickleIterator iter(*pickle);
@@ -652,27 +652,16 @@ bool CreateTabsAndWindows(
if (!iter.ReadString16(&title))
return true;
- if (command->id() == kCommandSetTabGroupMetadata) {
- SkColor color;
- if (!iter.ReadUInt32(&color))
- return true;
-
- // crrev.com/c/1968039 changes the color of a tab group from a SkColor
- // to a TabGroupColorId. Here we ignore the old SkColor and assign the
- // default TabGroupColorId because the fallback is acceptable while
- // the tab groups feature isn't yet launched. Once it is,
- // kCommandSetTabGroupMetadata will be deprecated in favor of
- // kCommandSetTabGroupMetadata2, which properly restores
- // TabGroupColorIds.
- group->visual_data = tab_groups::TabGroupVisualData(
- title, tab_groups::TabGroupColorId::kGrey);
- } else {
- uint32_t color_int;
- if (!iter.ReadUInt32(&color_int))
- return true;
+ uint32_t color_int;
+ if (!iter.ReadUInt32(&color_int))
+ return true;
- group->visual_data = tab_groups::TabGroupVisualData(title, color_int);
- }
+ // The |is_collapsed| boolean was added in M88 to save the collapsed
+ // state, so previous versions may not have this stored.
+ bool is_collapsed = false;
+ ignore_result(!iter.ReadBool(&is_collapsed));
+ group->visual_data =
+ tab_groups::TabGroupVisualData(title, color_int, is_collapsed);
break;
}
@@ -963,6 +952,9 @@ std::unique_ptr<SessionCommand> CreateTabGroupMetadataUpdateCommand(
WriteTokenToPickle(&pickle, group.token());
pickle.WriteString16(visual_data->title());
pickle.WriteUInt32(static_cast<int>(visual_data->color()));
+
+ // This boolean was added in M88 to save the collapsed state.
+ pickle.WriteBool(visual_data->is_collapsed());
return std::make_unique<SessionCommand>(kCommandSetTabGroupMetadata2, pickle);
}
diff --git a/chromium/components/sessions/core/snapshotting_session_backend_unittest.cc b/chromium/components/sessions/core/snapshotting_session_backend_unittest.cc
index 87c3226213a..9c500790d66 100644
--- a/chromium/components/sessions/core/snapshotting_session_backend_unittest.cc
+++ b/chromium/components/sessions/core/snapshotting_session_backend_unittest.cc
@@ -13,7 +13,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/sessions/core/session_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/sessions/core/tab_restore_service_impl.cc b/chromium/components/sessions/core/tab_restore_service_impl.cc
index e6ae900878f..7d149c1b372 100644
--- a/chromium/components/sessions/core/tab_restore_service_impl.cc
+++ b/chromium/components/sessions/core/tab_restore_service_impl.cc
@@ -1184,9 +1184,12 @@ void TabRestoreServiceImpl::PersistenceDelegate::LoadStateChanged() {
}
staging_entries_.clear();
- entries_to_write_ = 0;
tab_restore_service_helper_->PruneEntries();
+
+ // Write the loaded entries into the current session.
+ entries_to_write_ = tab_restore_service_helper_->entries().size();
+
tab_restore_service_helper_->NotifyTabsChanged();
tab_restore_service_helper_->NotifyLoaded();
diff --git a/chromium/components/shared_highlighting/OWNERS b/chromium/components/shared_highlighting/OWNERS
index e8ad847910c..eab70ff53e9 100644
--- a/chromium/components/shared_highlighting/OWNERS
+++ b/chromium/components/shared_highlighting/OWNERS
@@ -1,4 +1,5 @@
sebsg@chromium.org
+seblalancette@chromium.org
# COMPONENT: UI>Browser>SharedHighlighting
# TEAM: chrome-shared-highlighting@google.com \ No newline at end of file
diff --git a/chromium/components/shared_highlighting/core/common/BUILD.gn b/chromium/components/shared_highlighting/core/common/BUILD.gn
index 45907b4cbfd..39e5b8a3858 100644
--- a/chromium/components/shared_highlighting/core/common/BUILD.gn
+++ b/chromium/components/shared_highlighting/core/common/BUILD.gn
@@ -18,6 +18,7 @@ static_library("common") {
"//base",
"//components/search_engines:search_engine_utils",
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
]
}
@@ -31,6 +32,9 @@ source_set("unit_tests") {
deps = [
"//base/test:test_support",
"//components/shared_highlighting/core/common",
+ "//components/ukm:test_support",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//testing/gtest",
"//url",
]
diff --git a/chromium/components/shared_highlighting/core/common/DEPS b/chromium/components/shared_highlighting/core/common/DEPS
index 4b4b95c8294..f5a24182dff 100644
--- a/chromium/components/shared_highlighting/core/common/DEPS
+++ b/chromium/components/shared_highlighting/core/common/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+base/metrics/histogram_functions.h",
"+components/search_engines/search_engine_utils.h",
+ "+components/ukm/test_ukm_recorder.h",
"+net/base",
"+services/metrics/public",
"+url",
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
index 809d83f725b..b4bd12ab06f 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
@@ -7,6 +7,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "components/search_engines/search_engine_utils.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
namespace shared_highlighting {
@@ -70,4 +71,65 @@ void LogGenerateErrorTabCrash() {
void LogGenerateErrorIFrame() {
LogLinkGenerationErrorReason(LinkGenerationError::kIFrame);
}
+
+void LogGenerateSuccessLatency(base::TimeDelta latency) {
+ base::UmaHistogramTimes("SharedHighlights.LinkGenerated.TimeToGenerate",
+ latency);
+}
+
+void LogGenerateErrorLatency(base::TimeDelta latency) {
+ base::UmaHistogramTimes("SharedHighlights.LinkGenerated.Error.TimeToGenerate",
+ latency);
+}
+
+void LogLinkOpenedUkmEvent(ukm::SourceId source_id,
+ const GURL& referrer,
+ bool success) {
+ LogLinkOpenedUkmEvent(ukm::UkmRecorder::Get(), source_id, referrer, success);
+}
+
+void LogLinkOpenedUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id,
+ const GURL& referrer,
+ bool success) {
+ DCHECK(recorder);
+ if (source_id != ukm::kInvalidSourceId) {
+ ukm::builders::SharedHighlights_LinkOpened(source_id)
+ .SetSuccess(success)
+ .SetSource(static_cast<int64_t>(GetLinkSource(referrer)))
+ .Record(recorder);
+ }
+}
+
+void LogLinkGeneratedSuccessUkmEvent(ukm::SourceId source_id) {
+ LogLinkGeneratedSuccessUkmEvent(ukm::UkmRecorder::Get(), source_id);
+}
+
+void LogLinkGeneratedSuccessUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id) {
+ DCHECK(recorder);
+ if (source_id != ukm::kInvalidSourceId) {
+ ukm::builders::SharedHighlights_LinkGenerated(source_id)
+ .SetSuccess(true)
+ .Record(recorder);
+ }
+}
+
+void LogLinkGeneratedErrorUkmEvent(ukm::SourceId source_id,
+ LinkGenerationError reason) {
+ LogLinkGeneratedErrorUkmEvent(ukm::UkmRecorder::Get(), source_id, reason);
+}
+
+void LogLinkGeneratedErrorUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id,
+ LinkGenerationError reason) {
+ DCHECK(recorder);
+ if (source_id != ukm::kInvalidSourceId) {
+ ukm::builders::SharedHighlights_LinkGenerated(source_id)
+ .SetSuccess(false)
+ .SetError(static_cast<int64_t>(reason))
+ .Record(recorder);
+ }
+}
+
} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
index da1b339bf24..ea6befeaf84 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_SHARED_HIGHLIGHTING_METRICS_H_
#define COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_SHARED_HIGHLIGHTING_METRICS_H_
+#include "base/time/time.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace shared_highlighting {
@@ -12,6 +15,7 @@ namespace shared_highlighting {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// The type of errors that can happen during link generation.
+// Update corresponding |LinkGenerationError| in enums.xml.
enum class LinkGenerationError {
kIncorrectSelector = 0,
kNoRange = 1,
@@ -31,7 +35,10 @@ enum class LinkGenerationError {
// Selection happened on iframe.
kIFrame = 10,
- kMaxValue = kIFrame
+ // Timed-out waiting for a link to be generated.
+ kTimeout = 11,
+
+ kMaxValue = kTimeout
};
// These values are persisted to logs. Entries should not be renumbered and
@@ -79,6 +86,63 @@ void LogGenerateErrorTabCrash();
// iframe.
void LogGenerateErrorIFrame();
+// Records the latency for successfully generating a link.
+void LogGenerateSuccessLatency(base::TimeDelta latency);
+
+// Records the latency for failing to generate a link.
+void LogGenerateErrorLatency(base::TimeDelta latency);
+
+// Records a UKM event for opening a link with text fragments. |source_id|
+// refers to the navigation action's ID, |referrer| will be used to record the
+// source and |success| should be true only if fragments highlighting was a
+// complete success. This event can only be recorded once per navigation, and
+// this function will record using the static Recorder instance. This API can
+// only be used when calling from the browser process, otherwise no event will
+// be recorded.
+void LogLinkOpenedUkmEvent(ukm::SourceId source_id,
+ const GURL& referrer,
+ bool success);
+
+// Records a UKM event for opening a link with text fragments. |source_id|
+// refers to the navigation action's ID, |referrer| will be used to record the
+// source and |success| should be true only if fragments highlighting was a
+// complete success. This event can only be recorded once per navigation, and
+// will record using the given custom |recorder|. Prefer this API when calling
+// from a process other than the browser process.
+void LogLinkOpenedUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id,
+ const GURL& referrer,
+ bool success);
+
+// Records a UKM event for successfully generating a link with text fragments.
+// |source_id| refers to the current frame, and this function will record using
+// the static Recorder. This API can only be used when calling from the browser
+// process, otherwise no event will be recorded.
+void LogLinkGeneratedSuccessUkmEvent(ukm::SourceId source_id);
+
+// Records a UKM event for successfully generating a link with text fragments.
+// |source_id| refers to the current frame. This function will record using the
+// given custom |recorder|. Prefer this API when calling from a process other
+// than the browser process.
+void LogLinkGeneratedSuccessUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id);
+
+// Records a UKM event for failing to generate a link with text fragments.
+// |source_id| refers to the current frame and |reason| highlights the cause of
+// the failure. This function will record using the static Recorder. This API
+// can only be used when calling from the browser process, otherwise no event
+// will be recorded.
+void LogLinkGeneratedErrorUkmEvent(ukm::SourceId source_id,
+ LinkGenerationError reason);
+
+// Records a UKM event for failing to generate a link with text fragments.
+// |source_id| refers to the current frame and |reason| highlights the cause of
+// the failure. This function will record using the given custom |recorder|.
+// Prefer this API when calling from a process other than the browser process.
+void LogLinkGeneratedErrorUkmEvent(ukm::UkmRecorder* recorder,
+ ukm::SourceId source_id,
+ LinkGenerationError reason);
+
} // namespace shared_highlighting
#endif // COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_SHARED_HIGHLIGHTING_METRICS_H_
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
index 5b86125d005..122ac2d2966 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
@@ -5,6 +5,10 @@
#include "components/shared_highlighting/core/common/shared_highlighting_metrics.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -12,104 +16,280 @@ namespace shared_highlighting {
namespace {
-TEST(SharedHighlightingMetricsTest, LogTextFragmentAmbiguousMatch) {
- base::HistogramTester histogram_tester;
+const char kSearchEngineUrl[] = "https://google.com";
+const char kSourceUkmMetric[] = "Source";
+const char kSuccessUkmMetric[] = "Success";
+const char kErrorUkmMetric[] = "Error";
+
+class SharedHighlightingMetricsTest : public testing::Test {
+ protected:
+ SharedHighlightingMetricsTest() = default;
+ ~SharedHighlightingMetricsTest() override = default;
+
+ void ValidateLinkOpenedUkm(const ukm::TestAutoSetUkmRecorder& recorder,
+ ukm::SourceId source_id,
+ bool success,
+ TextFragmentLinkOpenSource source) {
+ auto entries = recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkOpened::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ const ukm::mojom::UkmEntry* entry = entries[0];
+ EXPECT_EQ(source_id, entry->source_id);
+ recorder.ExpectEntryMetric(entry, kSuccessUkmMetric, success);
+ recorder.ExpectEntryMetric(entry, kSourceUkmMetric,
+ static_cast<int64_t>(source));
+ }
+
+ base::HistogramTester histogram_tester_;
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_;
+};
+
+TEST_F(SharedHighlightingMetricsTest, LogTextFragmentAmbiguousMatch) {
LogTextFragmentAmbiguousMatch(true);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.AmbiguousMatch", 1, 1);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.AmbiguousMatch", 1,
+ 1);
LogTextFragmentAmbiguousMatch(false);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.AmbiguousMatch", 0, 1);
- histogram_tester.ExpectTotalCount("TextFragmentAnchor.AmbiguousMatch", 2);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.AmbiguousMatch", 0,
+ 1);
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.AmbiguousMatch", 2);
}
-TEST(SharedHighlightingMetricsTest, LogTextFragmentLinkOpenSource) {
- base::HistogramTester histogram_tester;
-
- GURL search_engine_url("https://google.com");
+TEST_F(SharedHighlightingMetricsTest, LogTextFragmentLinkOpenSource) {
+ GURL search_engine_url(kSearchEngineUrl);
LogTextFragmentLinkOpenSource(search_engine_url);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
- TextFragmentLinkOpenSource::kSearchEngine,
- 1);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
+ TextFragmentLinkOpenSource::kSearchEngine,
+ 1);
GURL non_search_engine_url("https://example.com");
LogTextFragmentLinkOpenSource(non_search_engine_url);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
- TextFragmentLinkOpenSource::kUnknown, 1);
- histogram_tester.ExpectTotalCount("TextFragmentAnchor.LinkOpenSource", 2);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
+ TextFragmentLinkOpenSource::kUnknown, 1);
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.LinkOpenSource", 2);
GURL empty_gurl("");
LogTextFragmentLinkOpenSource(empty_gurl);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
- TextFragmentLinkOpenSource::kUnknown, 2);
- histogram_tester.ExpectTotalCount("TextFragmentAnchor.LinkOpenSource", 3);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.LinkOpenSource",
+ TextFragmentLinkOpenSource::kUnknown, 2);
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.LinkOpenSource", 3);
}
-TEST(SharedHighlightingMetricsTest, LogTextFragmentMatchRate) {
- base::HistogramTester histogram_tester;
+TEST_F(SharedHighlightingMetricsTest, LogTextFragmentMatchRate) {
+ LogTextFragmentMatchRate(/*matches=*/2, /*text_fragments=*/2);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.MatchRate", 100, 1);
- LogTextFragmentMatchRate(/*matches=*/2, /*nb_selectors=*/2);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.MatchRate", 100, 1);
-
- LogTextFragmentMatchRate(/*matches=*/1, /*nb_selectors=*/2);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.MatchRate", 50, 1);
- histogram_tester.ExpectTotalCount("TextFragmentAnchor.MatchRate", 2);
+ LogTextFragmentMatchRate(/*matches=*/1, /*text_fragments=*/2);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.MatchRate", 50, 1);
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.MatchRate", 2);
}
-TEST(SharedHighlightingMetricsTest, LogTextFragmentSelectorCount) {
- base::HistogramTester histogram_tester;
-
+TEST_F(SharedHighlightingMetricsTest, LogTextFragmentSelectorCount) {
LogTextFragmentSelectorCount(1);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.SelectorCount", 1, 1);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.SelectorCount", 1, 1);
LogTextFragmentSelectorCount(20);
- histogram_tester.ExpectBucketCount("TextFragmentAnchor.SelectorCount", 20, 1);
- histogram_tester.ExpectTotalCount("TextFragmentAnchor.SelectorCount", 2);
+ histogram_tester_.ExpectBucketCount("TextFragmentAnchor.SelectorCount", 20,
+ 1);
+ histogram_tester_.ExpectTotalCount("TextFragmentAnchor.SelectorCount", 2);
}
-TEST(SharedHighlightingMetricsTest, LogLinkGenerationStatus) {
- base::HistogramTester histogram_tester;
-
+TEST_F(SharedHighlightingMetricsTest, LogLinkGenerationStatus) {
LogLinkGenerationStatus(true);
- histogram_tester.ExpectUniqueSample("SharedHighlights.LinkGenerated", true,
- 1);
+ histogram_tester_.ExpectUniqueSample("SharedHighlights.LinkGenerated", true,
+ 1);
LogLinkGenerationStatus(false);
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated", false,
- 1);
- histogram_tester.ExpectTotalCount("SharedHighlights.LinkGenerated", 2);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated", false,
+ 1);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 2);
}
-TEST(SharedHighlightingMetricsTest, LogLinkGenerationErrorReason) {
- base::HistogramTester histogram_tester;
-
+TEST_F(SharedHighlightingMetricsTest, LogLinkGenerationErrorReason) {
LogLinkGenerationErrorReason(LinkGenerationError::kIncorrectSelector);
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kIncorrectSelector,
- 1);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+ LinkGenerationError::kIncorrectSelector,
+ 1);
LogLinkGenerationErrorReason(LinkGenerationError::kEmptySelection);
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kEmptySelection, 1);
- histogram_tester.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 2);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+ LinkGenerationError::kEmptySelection, 1);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 2);
}
-TEST(SharedHighlightingMetricsTest, LogAndroidLinkGenerationErrorReason) {
- base::HistogramTester histogram_tester;
-
+TEST_F(SharedHighlightingMetricsTest, LogAndroidLinkGenerationErrorReason) {
LogGenerateErrorTabHidden();
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kTabHidden, 1);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+ LinkGenerationError::kTabHidden, 1);
LogGenerateErrorOmniboxNavigation();
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kOmniboxNavigation,
- 1);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+ LinkGenerationError::kOmniboxNavigation,
+ 1);
LogGenerateErrorTabCrash();
- histogram_tester.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kTabCrash, 1);
- histogram_tester.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 3);
+ histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
+ LinkGenerationError::kTabCrash, 1);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 3);
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmSuccessSearchEngine) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ bool success = true;
+
+ LogLinkOpenedUkmEvent(source_id, GURL(kSearchEngineUrl), success);
+
+ ValidateLinkOpenedUkm(ukm_recorder, source_id, success,
+ TextFragmentLinkOpenSource::kSearchEngine);
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmFailSearchEngine) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ bool success = false;
+
+ LogLinkOpenedUkmEvent(source_id, GURL(kSearchEngineUrl), success);
+
+ ValidateLinkOpenedUkm(ukm_recorder, source_id, success,
+ TextFragmentLinkOpenSource::kSearchEngine);
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmSuccessUnknownSource) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ bool success = true;
+
+ LogLinkOpenedUkmEvent(source_id, GURL(), success);
+
+ ValidateLinkOpenedUkm(ukm_recorder, source_id, success,
+ TextFragmentLinkOpenSource::kUnknown);
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmFailUnknownSource) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ bool success = false;
+
+ LogLinkOpenedUkmEvent(source_id, GURL(), success);
+
+ ValidateLinkOpenedUkm(ukm_recorder, source_id, success,
+ TextFragmentLinkOpenSource::kUnknown);
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmInvalidSourceId) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+ LogLinkOpenedUkmEvent(ukm::kInvalidSourceId, GURL(kSearchEngineUrl),
+ /*success=*/true);
+
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkOpened::kEntryName);
+ EXPECT_EQ(0u, entries.size());
+}
+
+// Tests that using the endpoints with a custom recorder won't use the static
+// UKM recorder.
+TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmCustomRecorder) {
+ ukm::TestAutoSetUkmRecorder static_ukm_recorder;
+ ukm::TestUkmRecorder custom_ukm_recorder;
+ ukm::SourceId source_id = 1;
+
+ LogLinkOpenedUkmEvent(&custom_ukm_recorder, source_id, GURL(),
+ /*success=*/true);
+
+ auto static_entries = static_ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkOpened::kEntryName);
+ EXPECT_EQ(0U, static_entries.size());
+
+ auto custom_entries = custom_ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkOpened::kEntryName);
+ EXPECT_EQ(1U, custom_entries.size());
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedUkmSuccess) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+
+ LogLinkGeneratedSuccessUkmEvent(source_id);
+
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ const ukm::mojom::UkmEntry* entry = entries[0];
+ EXPECT_EQ(source_id, entry->source_id);
+ ukm_recorder.ExpectEntryMetric(entry, kSuccessUkmMetric, true);
+ EXPECT_FALSE(ukm_recorder.GetEntryMetric(entry, kErrorUkmMetric));
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedUkmError) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ LinkGenerationError error = LinkGenerationError::kEmptySelection;
+
+ LogLinkGeneratedErrorUkmEvent(source_id, error);
+
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ const ukm::mojom::UkmEntry* entry = entries[0];
+ EXPECT_EQ(source_id, entry->source_id);
+ ukm_recorder.ExpectEntryMetric(entry, kSuccessUkmMetric, false);
+ ukm_recorder.ExpectEntryMetric(entry, kErrorUkmMetric,
+ static_cast<int64_t>(error));
+}
+
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedUkmSuccessInvalidSourceId) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+
+ LogLinkGeneratedSuccessUkmEvent(ukm::kInvalidSourceId);
+
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
+ EXPECT_EQ(0u, entries.size());
+}
+
+// Tests that using the endpoints with a custom recorder won't use the static
+// UKM recorder.
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedUkmCustomRecorder) {
+ ukm::TestAutoSetUkmRecorder static_ukm_recorder;
+ ukm::TestUkmRecorder custom_ukm_recorder;
+ ukm::SourceId source_id = 1;
+
+ LogLinkGeneratedSuccessUkmEvent(&custom_ukm_recorder, source_id);
+ LogLinkGeneratedErrorUkmEvent(&custom_ukm_recorder, source_id,
+ LinkGenerationError::kEmptySelection);
+
+ auto static_entries = static_ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
+ EXPECT_EQ(0U, static_entries.size());
+
+ auto custom_entries = custom_ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated::kEntryName);
+ EXPECT_EQ(2U, custom_entries.size());
+}
+
+// Tests that link generation success latency logs to the right histogram.
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedSuccessLatency) {
+ base::TimeDelta test_delta = base::TimeDelta::FromMilliseconds(2000);
+
+ LogGenerateSuccessLatency(test_delta);
+
+ histogram_tester_.ExpectTimeBucketCount(
+ "SharedHighlights.LinkGenerated.TimeToGenerate", test_delta, 1);
+}
+
+// Tests that link generation failure latency logs to the right histogram.
+TEST_F(SharedHighlightingMetricsTest, LinkGeneratedErrorLatency) {
+ base::TimeDelta test_delta = base::TimeDelta::FromMilliseconds(2000);
+
+ LogGenerateErrorLatency(test_delta);
+
+ histogram_tester_.ExpectTimeBucketCount(
+ "SharedHighlights.LinkGenerated.Error.TimeToGenerate", test_delta, 1);
}
} // namespace
diff --git a/chromium/components/signin/DEPS b/chromium/components/signin/DEPS
index 73fad4f9ba1..7c719c91630 100644
--- a/chromium/components/signin/DEPS
+++ b/chromium/components/signin/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+chromeos/components/account_manager",
+ "+components/account_manager_core",
"+components/content_settings",
"+components/google/core",
"+components/image_fetcher/core",
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index 33491d64f00..e949c1b65ae 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -330,8 +330,7 @@ void AboutSigninInternals::Shutdown() {
void AboutSigninInternals::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
// If this is not a change to cookie settings, just ignore.
if (content_type != ContentSettingsType::COOKIES)
return;
diff --git a/chromium/components/signin/core/browser/about_signin_internals.h b/chromium/components/signin/core/browser/about_signin_internals.h
index e9ec1605371..289afadf5ae 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.h
+++ b/chromium/components/signin/core/browser/about_signin_internals.h
@@ -224,8 +224,7 @@ class AboutSigninInternals : public KeyedService,
// content_settings::Observer implementation.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
// AccountReconcilor::Observer implementation.
void OnBlockReconcile() override;
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index a6162519895..06ac5feb054 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -128,12 +128,10 @@ bool RevokeAllSecondaryTokens(
// TODO(https://crbug.com/1122551): Move this code and
// |RevokeAllSecondaryTokens| to |DiceAccountReconcilorDelegate|.
-signin::RevokeTokenAction RevokeTokensNotInCookies(
+void RevokeTokensNotInCookies(
signin::IdentityManager* identity_manager,
const CoreAccountId& primary_account,
const std::vector<gaia::ListedAccount>& gaia_accounts) {
- bool invalidated_primary_account_token = false;
- bool revoked_token_for_secondary_account = false;
signin_metrics::SourceForRefreshTokenOperation source =
signin_metrics::SourceForRefreshTokenOperation::
kAccountReconcilor_RevokeTokensNotInCookies;
@@ -146,28 +144,11 @@ signin::RevokeTokenAction RevokeTokensNotInCookies(
auto* accounts_mutator = identity_manager->GetAccountsMutator();
if (account == primary_account) {
- invalidated_primary_account_token = true;
accounts_mutator->InvalidateRefreshTokenForPrimaryAccount(source);
} else {
- revoked_token_for_secondary_account = true;
accounts_mutator->RemoveAccount(account, source);
}
}
-
- signin::RevokeTokenAction revoke_token_action =
- signin::RevokeTokenAction::kNone;
- if (invalidated_primary_account_token &&
- revoked_token_for_secondary_account) {
- revoke_token_action =
- signin::RevokeTokenAction::kRevokeTokensForPrimaryAndSecondaryAccounts;
- } else if (invalidated_primary_account_token) {
- revoke_token_action =
- signin::RevokeTokenAction::kInvalidatePrimaryAccountToken;
- } else if (revoked_token_for_secondary_account) {
- revoke_token_action =
- signin::RevokeTokenAction::kRevokeSecondaryAccountsTokens;
- }
- return revoke_token_action;
}
// Pick the account will become first after this reconcile is finished.
@@ -365,8 +346,7 @@ void AccountReconcilor::RemoveObserver(Observer* observer) {
void AccountReconcilor::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) {
+ ContentSettingsType content_type) {
// If this is not a change to cookie settings, just ignore.
if (content_type != ContentSettingsType::COOKIES)
return;
@@ -652,9 +632,9 @@ void AccountReconcilor::OnAccountsInCookieUpdated(
// thus use sync account.
// TODO(https://crbug.com/1122551): Move to |DiceAccountReconcilorDelegate|.
DCHECK_EQ(consent_level, ConsentLevel::kSync);
- signin::RevokeTokenAction revoke_token_action = RevokeTokensNotInCookies(
- identity_manager_, primary_account, verified_gaia_accounts);
- delegate_->OnRevokeTokensNotInCookiesCompleted(revoke_token_action);
+ RevokeTokensNotInCookies(identity_manager_, primary_account,
+ verified_gaia_accounts);
+ delegate_->OnRevokeTokensNotInCookiesCompleted();
}
// Revoking tokens for secondary accounts causes the AccountTracker to
diff --git a/chromium/components/signin/core/browser/account_reconcilor.h b/chromium/components/signin/core/browser/account_reconcilor.h
index 5b5d0e84455..5a1a867cd4f 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.h
+++ b/chromium/components/signin/core/browser/account_reconcilor.h
@@ -265,8 +265,7 @@ class AccountReconcilor : public KeyedService,
// Overridden from content_settings::Observer.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier) override;
+ ContentSettingsType content_type) override;
// Overridden from signin::IdentityManager::Observer.
void OnEndBatchOfRefreshTokenStateChanges() override;
diff --git a/chromium/components/signin/core/browser/account_reconcilor_delegate.h b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
index 3b3888c2ad8..e4cd23899a5 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
@@ -19,15 +19,6 @@ class AccountReconcilor;
namespace signin {
-// Possible revoke token actions taken by the AccountReconcilor.
-enum class RevokeTokenAction {
- kNone,
- kInvalidatePrimaryAccountToken,
- kRevokeSecondaryAccountsTokens,
- kRevokeTokensForPrimaryAndSecondaryAccounts,
- kMaxValue = kRevokeTokensForPrimaryAndSecondaryAccounts
-};
-
// Base class for AccountReconcilorDelegate.
class AccountReconcilorDelegate {
public:
@@ -110,8 +101,7 @@ class AccountReconcilorDelegate {
virtual bool ShouldRevokeTokensNotInCookies() const;
// Called when |RevokeTokensNotInCookies| is finished.
- virtual void OnRevokeTokensNotInCookiesCompleted(
- RevokeTokenAction revoke_token_action) {}
+ virtual void OnRevokeTokensNotInCookiesCompleted() {}
// Returns whether tokens should be revoked when the Gaia cookie has been
// explicitly deleted by the user.
diff --git a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
index 9cbc468c454..0886d81be69 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -49,7 +49,6 @@
#include "components/signin/core/browser/active_directory_account_reconcilor_delegate.h"
#endif
-using signin::RevokeTokenAction;
using signin_metrics::AccountReconcilorState;
namespace {
@@ -398,9 +397,9 @@ void AccountReconcilorTest::SimulateLogOutFromCookieCompleted(
void AccountReconcilorTest::SimulateCookieContentSettingsChanged(
content_settings::Observer* observer,
const ContentSettingsPattern& primary_pattern) {
- observer->OnContentSettingChanged(
- primary_pattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::COOKIES, std::string());
+ observer->OnContentSettingChanged(primary_pattern,
+ ContentSettingsPattern::Wildcard(),
+ ContentSettingsType::COOKIES);
}
void AccountReconcilorTest::SetAccountConsistency(
@@ -465,7 +464,6 @@ struct ForceDiceMigrationTestTableParam {
const char* gaia_api_calls;
const char* tokens_after_reconcile;
const char* cookies_after_reconcile;
- RevokeTokenAction revoke_token_action;
};
// Pretty prints a AccountReconcilorTestTableParam. Used by gtest.
@@ -1045,8 +1043,6 @@ TEST_P(AccountReconcilorTestTable, TableRowTest) {
// nothing on the second call.
CheckReconcileIdempotent(kDiceParams, GetParam(), /*multilogin=*/false);
RunReconcile();
- histogram_tester()->ExpectTotalCount("ForceDiceMigration.RevokeTokenAction",
- 0);
}
INSTANTIATE_TEST_SUITE_P(
@@ -1072,34 +1068,34 @@ class AccountReconcilorTestForceDiceMigration
// clang-format off
const std::vector<ForceDiceMigrationTestTableParam> kForceDiceParams = {
- {"*A", "AB", "XA", "*A", "A" , RevokeTokenAction::kNone},
- {"*AxB", "AB", "XA", "*A", "A" , RevokeTokenAction::kNone},
- {"AxB", "AB", "XA", "A", "A" , RevokeTokenAction::kNone},
- {"xAxB", "AB", "X", "", "" , RevokeTokenAction::kNone},
- {"*A", "", "", "*xA", "" , RevokeTokenAction::kInvalidatePrimaryAccountToken},
- {"*A", "B", "X", "*xA", "" , RevokeTokenAction::kInvalidatePrimaryAccountToken},
- {"*AB", "B", "", "*xAB", "B" , RevokeTokenAction::kInvalidatePrimaryAccountToken},
- {"*AxB", "B", "X", "*xA", "" , RevokeTokenAction::kInvalidatePrimaryAccountToken},
- {"*ABC", "CB", "", "*xABC", "CB" , RevokeTokenAction::kInvalidatePrimaryAccountToken},
- {"*AB", "A", "", "*A", "A" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AB", "A", "", "A", "A" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AB", "", "", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "", "", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "A", "X", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "xA", "", "", "xA" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "B", "", "B", "B" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AxB", "B", "X", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AxB", "", "", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAxB", "", "", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"B", "xA", "", "", "xA" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AB", "xAB", "", "B", "xAB" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "xAC", "X", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"xAB", "AxC", "X", "", "" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"AB", "BC", "XB", "B", "B" , RevokeTokenAction::kRevokeSecondaryAccountsTokens},
- {"*AB", "", "", "*xA", "" , RevokeTokenAction::kRevokeTokensForPrimaryAndSecondaryAccounts},
- {"*xAB", "", "", "*xA", "" , RevokeTokenAction::kRevokeTokensForPrimaryAndSecondaryAccounts},
- {"*AxB", "", "", "*xA", "" , RevokeTokenAction::kRevokeTokensForPrimaryAndSecondaryAccounts},
- {"*AB", "xBxA", "", "*xA", "xBxA", RevokeTokenAction::kRevokeTokensForPrimaryAndSecondaryAccounts}
+ {"*A", "AB", "XA", "*A", "A" },
+ {"*AxB", "AB", "XA", "*A", "A" },
+ {"AxB", "AB", "XA", "A", "A" },
+ {"xAxB", "AB", "X", "", "" },
+ {"*A", "", "", "*xA", "" },
+ {"*A", "B", "X", "*xA", "" },
+ {"*AB", "B", "", "*xAB", "B" },
+ {"*AxB", "B", "X", "*xA", "" },
+ {"*ABC", "CB", "", "*xABC", "CB" },
+ {"*AB", "A", "", "*A", "A" },
+ {"AB", "A", "", "A", "A" },
+ {"AB", "", "", "", "" },
+ {"xAB", "", "", "", "" },
+ {"xAB", "A", "X", "", "" },
+ {"xAB", "xA", "", "", "xA" },
+ {"xAB", "B", "", "B", "B" },
+ {"AxB", "B", "X", "", "" },
+ {"AxB", "", "", "", "" },
+ {"xAxB", "", "", "", "" },
+ {"B", "xA", "", "", "xA" },
+ {"AB", "xAB", "", "B", "xAB" },
+ {"xAB", "xAC", "X", "", "" },
+ {"xAB", "AxC", "X", "", "" },
+ {"AB", "BC", "XB", "B", "B" },
+ {"*AB", "", "", "*xA", "" },
+ {"*xAB", "", "", "*xA", "" },
+ {"*AxB", "", "", "*xA", "" },
+ {"*AB", "xBxA", "", "*xA", "xBxA"}
};
// clang-format on
@@ -1112,8 +1108,6 @@ TEST_P(AccountReconcilorTestForceDiceMigration, TableRowTest) {
EXPECT_TRUE(test_signin_client()->is_dice_migration_completed());
EXPECT_FALSE(
GetMockReconcilor()->delegate_->ShouldRevokeTokensNotInCookies());
- histogram_tester()->ExpectUniqueSample("ForceDiceMigration.RevokeTokenAction",
- GetParam().revoke_token_action, 1);
}
// Check that the result state of the reconcile is in a final state (reconcile
@@ -2484,9 +2478,9 @@ TEST_F(AccountReconcilorMirrorTest, Lock) {
};
TestAccountReconcilorObserver observer;
- ScopedObserver<AccountReconcilor, AccountReconcilor::Observer>
- scoped_observer(&observer);
- scoped_observer.Add(reconcilor);
+ base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
+ scoped_observation(&observer);
+ scoped_observation.Observe(reconcilor);
// Lock prevents reconcile from starting, as long as one instance is alive.
std::unique_ptr<AccountReconcilor::Lock> lock_1 =
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index 4b08d8a8282..1d44ed4785c 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -22,6 +22,7 @@ android_library("java") {
"//net/android:net_java",
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:chromium_play_services_availability_java",
"//ui/android:ui_java",
]
@@ -102,6 +103,7 @@ android_library("signin_java_test_support") {
testonly = true
deps = [
":java",
+ ":signin_test_resources",
"//base:base_java",
"//base:base_java_test_support",
"//third_party/android_deps:androidx_annotation_annotation_java",
@@ -116,4 +118,12 @@ android_library("signin_java_test_support") {
"javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java",
"javatests/src/org/chromium/components/signin/test/util/FakeProfileDataSource.java",
]
+ resources_package = "org.chromium.components.signin.core.browser.javatests"
+}
+
+android_resources("signin_test_resources") {
+ testonly = true
+
+ create_srcjar = false
+ sources = [ "javatests/res/drawable/test_profile_picture.xml" ]
}
diff --git a/chromium/components/signin/core/browser/android/javatests/res/drawable/test_profile_picture.xml b/chromium/components/signin/core/browser/android/javatests/res/drawable/test_profile_picture.xml
new file mode 100644
index 00000000000..1ac46f0a979
--- /dev/null
+++ b/chromium/components/signin/core/browser/android/javatests/res/drawable/test_profile_picture.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:targetApi="21"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportWidth="192"
+ android:viewportHeight="192">
+
+ <path
+ android:fillColor="#1E8E3E"
+ android:pathData="M96,0C43.01,0,0,43.01,0,96s43.01,96,96,96s96-43.01,96-96S148.99,0,96,0z" />
+ <path
+ android:fillColor="#4C8BF5"
+ android:pathData="M96,85.09c13.28,0,24-10.72,24-24c0-13.28-10.72-24-24-24s-24,10.72-24,24
+C72,74.37,82.72,85.09,96,85.09z" />
+ <path
+ android:fillColor="#F4C20D"
+ android:pathData="M96,99.27c-29.33,0-52.36,14.18-52.36,27.27c11.09,17.06,30.51,28.36,52.36,28.36
+s41.27-11.3,52.36-28.36C148.36,113.45,125.33,99.27,96,99.27z" />
+ <path
+ android:pathData="M 0 0 H 192 V 192 H 0 V 0 Z" />
+</vector>
diff --git a/chromium/components/signin/core/browser/chrome_connected_header_helper.cc b/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
index e5c2c2f2486..d8acfa4ad2e 100644
--- a/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -32,6 +32,7 @@ const char kIsSameTabAttrName[] = "is_same_tab";
const char kIsSamlAttrName[] = "is_saml";
const char kProfileModeAttrName[] = "mode";
const char kServiceTypeAttrName[] = "action";
+const char kSupervisedAttrName[] = "supervised";
const char kSourceAttrName[] = "source";
#if defined(OS_ANDROID) || defined(OS_IOS)
const char kEligibleForConsistency[] = "eligible_for_consistency";
@@ -70,9 +71,13 @@ std::string ChromeConnectedHeaderHelper::BuildRequestCookieIfPossible(
ChromeConnectedHeaderHelper chrome_connected_helper(account_consistency);
if (!chrome_connected_helper.ShouldBuildRequestHeader(url, cookie_settings))
return "";
+
+ // Child accounts are not supported on iOS, so it is preferred to not include
+ // this information in the ChromeConnected cookie.
return chrome_connected_helper.BuildRequestHeader(
- false /* is_header_request */, url, gaia_id, profile_mode_mask,
- "" /* source */, false /* force_account_consistency */);
+ false /* is_header_request */, url, gaia_id,
+ base::nullopt /* is_child_account */, profile_mode_mask, "" /* source */,
+ false /* force_account_consistency */);
}
// static
@@ -178,6 +183,7 @@ std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
bool is_header_request,
const GURL& url,
const std::string& gaia_id,
+ const base::Optional<bool>& is_child_account,
int profile_mode_mask,
const std::string& source,
bool force_account_consistency) {
@@ -220,6 +226,11 @@ std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
account_consistency_ == AccountConsistencyMethod::kMirror;
parts.push_back(base::StringPrintf("%s=%s", kEnableAccountConsistencyAttrName,
is_mirror_enabled ? "true" : "false"));
+ if (is_child_account.has_value()) {
+ parts.push_back(
+ base::StringPrintf("%s=%s", kSupervisedAttrName,
+ is_child_account.value() ? "true" : "false"));
+ }
parts.push_back(base::StringPrintf(
"%s=%s", kConsistencyEnabledByDefaultAttrName, "false"));
diff --git a/chromium/components/signin/core/browser/chrome_connected_header_helper.h b/chromium/components/signin/core/browser/chrome_connected_header_helper.h
index 6b53aeb477b..cf37ab1ef3f 100644
--- a/chromium/components/signin/core/browser/chrome_connected_header_helper.h
+++ b/chromium/components/signin/core/browser/chrome_connected_header_helper.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/optional.h"
#include "components/signin/core/browser/signin_header_helper.h"
#include "components/signin/public/base/account_consistency_method.h"
@@ -40,6 +41,7 @@ class ChromeConnectedHeaderHelper : public SigninHeaderHelper {
std::string BuildRequestHeader(bool is_header_request,
const GURL& url,
const std::string& gaia_id,
+ const base::Optional<bool>& is_child_account,
int profile_mode_mask,
const std::string& source,
bool force_account_consistency);
diff --git a/chromium/components/signin/core/browser/cookie_reminter.cc b/chromium/components/signin/core/browser/cookie_reminter.cc
index 6627302460d..7ea025ed710 100644
--- a/chromium/components/signin/core/browser/cookie_reminter.cc
+++ b/chromium/components/signin/core/browser/cookie_reminter.cc
@@ -4,7 +4,7 @@
#include "components/signin/core/browser/cookie_reminter.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
namespace {
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
index b008cc312f7..0b55673393d 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_client.h"
@@ -75,9 +76,9 @@ DiceAccountReconcilorDelegate::GetInconsistencyReason(
std::vector<CoreAccountId> sorted_chrome_accounts(chrome_accounts);
std::sort(sorted_chrome_accounts.begin(), sorted_chrome_accounts.end());
bool missing_token =
- !base::STLIncludes(sorted_chrome_accounts, valid_gaia_accounts_ids);
+ !base::ranges::includes(sorted_chrome_accounts, valid_gaia_accounts_ids);
bool missing_cookie =
- !base::STLIncludes(valid_gaia_accounts_ids, sorted_chrome_accounts);
+ !base::ranges::includes(valid_gaia_accounts_ids, sorted_chrome_accounts);
if (missing_token && missing_cookie)
return InconsistencyReason::kCookieTokenMismatch;
@@ -305,12 +306,9 @@ bool DiceAccountReconcilorDelegate::ShouldRevokeTokensNotInCookies() const {
return !migration_completed_;
}
-void DiceAccountReconcilorDelegate::OnRevokeTokensNotInCookiesCompleted(
- RevokeTokenAction revoke_token_action) {
+void DiceAccountReconcilorDelegate::OnRevokeTokensNotInCookiesCompleted() {
migration_completed_ = true;
signin_client_->SetDiceMigrationCompleted();
- UMA_HISTOGRAM_ENUMERATION("ForceDiceMigration.RevokeTokenAction",
- revoke_token_action);
}
bool DiceAccountReconcilorDelegate::ShouldRevokeTokensOnCookieDeleted() {
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
index ad62529df16..3deee4d2746 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
@@ -41,8 +41,7 @@ class DiceAccountReconcilorDelegate : public AccountReconcilorDelegate {
// Returns true if in force migration to dice state.
bool ShouldRevokeTokensNotInCookies() const override;
// Disables force dice migration and sets dice migration as completed.
- void OnRevokeTokensNotInCookiesCompleted(
- RevokeTokenAction revoke_token_action) override;
+ void OnRevokeTokensNotInCookiesCompleted() override;
void OnReconcileFinished(const CoreAccountId& first_account) override;
bool ShouldRevokeTokensOnCookieDeleted() override;
bool ShouldRevokeTokensBeforeMultilogin(
diff --git a/chromium/components/signin/core/browser/resources/signin_index.html b/chromium/components/signin/core/browser/resources/signin_index.html
index 8700988fee1..84f9621a4ed 100644
--- a/chromium/components/signin/core/browser/resources/signin_index.html
+++ b/chromium/components/signin/core/browser/resources/signin_index.html
@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
<script src="strings.js"></script>
diff --git a/chromium/components/signin/core/browser/signin_error_controller.cc b/chromium/components/signin/core/browser/signin_error_controller.cc
index 88eb68fa75c..1725eaa1f34 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller.cc
@@ -13,7 +13,7 @@ SigninErrorController::SigninErrorController(
identity_manager_(identity_manager),
auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
DCHECK(identity_manager_);
- scoped_identity_manager_observer_.Add(identity_manager_);
+ scoped_identity_manager_observation_.Observe(identity_manager_);
Update();
}
@@ -21,7 +21,7 @@ SigninErrorController::SigninErrorController(
SigninErrorController::~SigninErrorController() = default;
void SigninErrorController::Shutdown() {
- scoped_identity_manager_observer_.RemoveAll();
+ scoped_identity_manager_observation_.RemoveObservation();
}
void SigninErrorController::Update() {
diff --git a/chromium/components/signin/core/browser/signin_error_controller.h b/chromium/components/signin/core/browser/signin_error_controller.h
index 4ada371004a..fccbb4067d3 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.h
+++ b/chromium/components/signin/core/browser/signin_error_controller.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -86,8 +86,9 @@ class SigninErrorController : public KeyedService,
const AccountMode account_mode_;
signin::IdentityManager* identity_manager_;
- ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
- scoped_identity_manager_observer_{this};
+ base::ScopedObservation<signin::IdentityManager,
+ signin::IdentityManager::Observer>
+ scoped_identity_manager_observation_{this};
// The account that generated the last auth error.
CoreAccountId error_account_id_;
diff --git a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
index ea955f29cd3..a8f0f7a2cd6 100644
--- a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -9,7 +9,7 @@
#include <functional>
#include <memory>
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/stl_util.h"
#include "base/test/task_environment.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
@@ -40,9 +40,10 @@ TEST(SigninErrorControllerTest, SingleAccount) {
SigninErrorController error_controller(
SigninErrorController::AccountMode::ANY_ACCOUNT,
identity_test_env.identity_manager());
- ScopedObserver<SigninErrorController, SigninErrorController::Observer>
- scoped_observer(&observer);
- scoped_observer.Add(&error_controller);
+ base::ScopedObservation<SigninErrorController,
+ SigninErrorController::Observer>
+ scoped_observation(&observer);
+ scoped_observation.Observe(&error_controller);
ASSERT_FALSE(error_controller.HasError());
::testing::Mock::VerifyAndClearExpectations(&observer);
diff --git a/chromium/components/signin/core/browser/signin_header_helper.cc b/chromium/components/signin/core/browser/signin_header_helper.cc
index da3b4865525..d8fabb6b2bf 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper.cc
@@ -167,6 +167,7 @@ void AppendOrRemoveMirrorRequestHeader(
RequestAdapter* request,
const GURL& redirect_url,
const std::string& gaia_id,
+ const base::Optional<bool>& is_child_account,
AccountConsistencyMethod account_consistency,
const content_settings::CookieSettings* cookie_settings,
int profile_mode_mask,
@@ -177,8 +178,8 @@ void AppendOrRemoveMirrorRequestHeader(
std::string chrome_connected_header_value;
if (chrome_connected_helper.ShouldBuildRequestHeader(url, cookie_settings)) {
chrome_connected_header_value = chrome_connected_helper.BuildRequestHeader(
- true /* is_header_request */, url, gaia_id, profile_mode_mask, source,
- force_account_consistency);
+ true /* is_header_request */, url, gaia_id, is_child_account,
+ profile_mode_mask, source, force_account_consistency);
}
chrome_connected_helper.AppendOrRemoveRequestHeader(
request, redirect_url, kChromeConnectedHeader,
diff --git a/chromium/components/signin/core/browser/signin_header_helper.h b/chromium/components/signin/core/browser/signin_header_helper.h
index 35a4c0e5c54..bf76900e121 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.h
+++ b/chromium/components/signin/core/browser/signin_header_helper.h
@@ -238,6 +238,7 @@ void AppendOrRemoveMirrorRequestHeader(
RequestAdapter* request,
const GURL& redirect_url,
const std::string& gaia_id,
+ const base::Optional<bool>& is_child_account,
AccountConsistencyMethod account_consistency,
const content_settings::CookieSettings* cookie_settings,
int profile_mode_mask,
diff --git a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
index 83f44c43e3c..d1c341de9b1 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -85,14 +85,16 @@ class SigninHeaderHelperTest : public testing::Test {
expected_request);
}
- net::HttpRequestHeaders CreateRequest(const GURL& url,
- const std::string& account_id) {
+ net::HttpRequestHeaders CreateRequest(
+ const GURL& url,
+ const std::string& account_id,
+ const base::Optional<bool>& is_child_account) {
net::HttpRequestHeaders original_headers;
RequestAdapterWrapper request_adapter(url, original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), GURL(), account_id, account_consistency_,
- cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
- force_account_consistency_);
+ request_adapter.adapter(), GURL(), account_id, is_child_account,
+ account_consistency_, cookie_settings_.get(), PROFILE_MODE_DEFAULT,
+ kTestSource, force_account_consistency_);
AppendOrRemoveDiceRequestHeader(
request_adapter.adapter(), GURL(), account_id, sync_enabled_,
account_consistency_, cookie_settings_.get(), device_id_);
@@ -114,8 +116,10 @@ class SigninHeaderHelperTest : public testing::Test {
void CheckMirrorHeaderRequest(const GURL& url,
const std::string& account_id,
+ const base::Optional<bool>& is_child_account,
const std::string& expected_request) {
- net::HttpRequestHeaders headers = CreateRequest(url, account_id);
+ net::HttpRequestHeaders headers =
+ CreateRequest(url, account_id, is_child_account);
CheckAccountConsistencyHeaderRequest(headers, kChromeConnectedHeader,
expected_request);
}
@@ -123,9 +127,11 @@ class SigninHeaderHelperTest : public testing::Test {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void CheckDiceHeaderRequest(const GURL& url,
const std::string& account_id,
+ const base::Optional<bool>& is_child_account,
const std::string& expected_mirror_request,
const std::string& expected_dice_request) {
- net::HttpRequestHeaders headers = CreateRequest(url, account_id);
+ net::HttpRequestHeaders headers =
+ CreateRequest(url, account_id, is_child_account);
CheckAccountConsistencyHeaderRequest(headers, kChromeConnectedHeader,
expected_mirror_request);
CheckAccountConsistencyHeaderRequest(headers, kDiceRequestHeader,
@@ -153,7 +159,7 @@ class SigninHeaderHelperTest : public testing::Test {
TEST_F(SigninHeaderHelperTest, TestMirrorRequestNoAccountIdChromeOS) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckMirrorHeaderRequest(
- GURL("https://docs.google.com"), "",
+ GURL("https://docs.google.com"), "", /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "",
@@ -171,6 +177,7 @@ TEST_F(SigninHeaderHelperTest, TestEligibleForConsistencyRequestGaiaOrigin) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckMirrorHeaderRequest(GURL("https://accounts.google.com"), "",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,eligible_for_consistency=true");
CheckMirrorCookieRequest(GURL("https://accounts.google.com"), "",
"eligible_for_consistency=true");
@@ -185,7 +192,8 @@ TEST_F(SigninHeaderHelperTest,
feature_list.InitAndEnableFeature(kMobileIdentityConsistency);
account_consistency_ = AccountConsistencyMethod::kMirror;
- CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "", "");
+ CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "",
+ /*is_child_account=*/base::nullopt, "");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "", "");
}
@@ -198,7 +206,7 @@ TEST_F(SigninHeaderHelperTest, TestForceAccountConsistencyMobile) {
account_consistency_ = AccountConsistencyMethod::kMirror;
force_account_consistency_ = true;
CheckMirrorHeaderRequest(
- GURL("https://docs.google.com"), "",
+ GURL("https://docs.google.com"), "", /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
}
@@ -208,7 +216,8 @@ TEST_F(SigninHeaderHelperTest, TestForceAccountConsistencyMobile) {
// account id), for non Chrome OS platforms.
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
account_consistency_ = AccountConsistencyMethod::kMirror;
- CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "", "");
+ CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "",
+ /*is_child_account=*/base::nullopt, "");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "", "");
}
#endif
@@ -218,14 +227,16 @@ TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestCookieSettingBlocked) {
account_consistency_ = AccountConsistencyMethod::kMirror;
cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
- CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "0123456789", "");
+ CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt, "");
CheckMirrorCookieRequest(GURL("https://docs.google.com"), "0123456789", "");
}
// Tests that no Mirror request is returned when the target is a non-Google URL.
TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestExternalURL) {
account_consistency_ = AccountConsistencyMethod::kMirror;
- CheckMirrorHeaderRequest(GURL("https://foo.com"), "0123456789", "");
+ CheckMirrorHeaderRequest(GURL("https://foo.com"), "0123456789",
+ /*is_child_account=*/base::nullopt, "");
CheckMirrorCookieRequest(GURL("https://foo.com"), "0123456789", "");
}
@@ -235,6 +246,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckMirrorHeaderRequest(
GURL("https://google.fr"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(GURL("https://google.de"), "0123456789",
@@ -248,6 +260,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckMirrorHeaderRequest(
GURL("https://www.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(
@@ -262,7 +275,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComNoProfileConsistency) {
RequestAdapterWrapper request_adapter(GURL("https://www.google.com"),
original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), GURL(), "0123456789", account_consistency_,
+ request_adapter.adapter(), GURL(), "0123456789",
+ /*is_child_account=*/base::nullopt, account_consistency_,
cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
false /* force_account_consistency */);
CheckAccountConsistencyHeaderRequest(request_adapter.GetFinalHeaders(),
@@ -276,7 +290,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComProfileConsistency) {
RequestAdapterWrapper request_adapter(GURL("https://www.google.com"),
original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), GURL(), "0123456789", account_consistency_,
+ request_adapter.adapter(), GURL(), "0123456789",
+ /*is_child_account=*/base::nullopt, account_consistency_,
cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
false /* force_account_consistency */);
CheckAccountConsistencyHeaderRequest(
@@ -285,6 +300,25 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComProfileConsistency) {
"consistency_enabled_by_default=false");
}
+TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComSupervised) {
+ account_consistency_ = AccountConsistencyMethod::kMirror;
+ CheckMirrorHeaderRequest(
+ GURL("https://www.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
+ "source=TestSource,mode=0,enable_account_consistency=true,"
+ "consistency_enabled_by_default=false");
+ CheckMirrorHeaderRequest(
+ GURL("https://www.google.com"), "0123456789",
+ /*is_child_account=*/base::Optional<bool>(true),
+ "source=TestSource,mode=0,enable_account_consistency=true,"
+ "supervised=true,consistency_enabled_by_default=false");
+ CheckMirrorHeaderRequest(
+ GURL("https://www.google.com"), "0123456789",
+ /*is_child_account=*/base::Optional<bool>(false),
+ "source=TestSource,mode=0,enable_account_consistency=true,"
+ "supervised=false,consistency_enabled_by_default=false");
+}
+
// Mirror is always enabled on Android and iOS, so these tests are only relevant
// on Desktop.
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -294,6 +328,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComProfileConsistency) {
TEST_F(SigninHeaderHelperTest, TestMirrorRequestGaiaURL) {
CheckMirrorHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(
@@ -308,6 +343,7 @@ TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
// ChromeConnected but no Dice for Docs URLs.
CheckDiceHeaderRequest(
GURL("https://docs.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,id=0123456789,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false",
"");
@@ -318,6 +354,7 @@ TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
ASSERT_FALSE(client_id.empty());
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false",
base::StringPrintf(
@@ -329,6 +366,7 @@ TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
sync_enabled_ = true;
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false",
base::StringPrintf("version=%s,client_id=%s,device_id=DeviceID,"
@@ -338,7 +376,8 @@ TEST_F(SigninHeaderHelperTest, TestDiceRequest) {
sync_enabled_ = false;
// No ChromeConnected and no Dice for other URLs.
- CheckDiceHeaderRequest(GURL("https://www.google.com"), "0123456789", "", "");
+ CheckDiceHeaderRequest(GURL("https://www.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt, "", "");
}
// When cookies are blocked, only the Dice header is sent.
@@ -349,7 +388,8 @@ TEST_F(SigninHeaderHelperTest, DiceCookiesBlocked) {
std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
ASSERT_FALSE(client_id.empty());
CheckDiceHeaderRequest(
- GURL("https://accounts.google.com"), "0123456789", "",
+ GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt, "",
base::StringPrintf(
"version=%s,client_id=%s,device_id=DeviceID,signin_mode=all_accounts,"
"signout_mode=show_confirmation",
@@ -361,6 +401,7 @@ TEST_F(SigninHeaderHelperTest, TestNoDiceRequestWhenDisabled) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false",
"");
@@ -375,6 +416,7 @@ TEST_F(SigninHeaderHelperTest, TestDiceEmptyDeviceID) {
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false",
base::StringPrintf("version=%s,client_id=%s,signin_mode=all_accounts,"
@@ -390,6 +432,7 @@ TEST_F(SigninHeaderHelperTest, TestSignoutConfirmation) {
CheckDiceHeaderRequest(
GURL("https://accounts.google.com"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false",
base::StringPrintf(
@@ -403,6 +446,7 @@ TEST_F(SigninHeaderHelperTest, TestSignoutConfirmation) {
TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
CheckMirrorHeaderRequest(
GURL("https://docs.google.com/document"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,id=0123456789,mode=0,enable_account_consistency=false,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(
@@ -414,6 +458,7 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
account_consistency_ = AccountConsistencyMethod::kMirror;
CheckMirrorHeaderRequest(
GURL("https://docs.google.com/document"), "0123456789",
+ /*is_child_account=*/base::nullopt,
"source=TestSource,id=0123456789,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
CheckMirrorCookieRequest(
@@ -564,7 +609,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
net::HttpRequestHeaders original_headers;
RequestAdapterWrapper request_adapter(url, original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), redirect_url, account_id, account_consistency_,
+ request_adapter.adapter(), redirect_url, account_id,
+ /*is_child_account=*/base::nullopt, account_consistency_,
cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
false /* force_account_consistency */);
EXPECT_TRUE(
@@ -582,7 +628,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
original_headers.SetHeader(kChromeConnectedHeader, "foo,bar");
RequestAdapterWrapper request_adapter(url, original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), redirect_url, account_id, account_consistency_,
+ request_adapter.adapter(), redirect_url, account_id,
+ /*is_child_account=*/base::nullopt, account_consistency_,
cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
false /* force_account_consistency */);
EXPECT_FALSE(
@@ -601,7 +648,8 @@ TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
original_headers.SetHeader(kChromeConnectedHeader, fake_header);
RequestAdapterWrapper request_adapter(url, original_headers);
AppendOrRemoveMirrorRequestHeader(
- request_adapter.adapter(), redirect_url, account_id, account_consistency_,
+ request_adapter.adapter(), redirect_url, account_id,
+ /*is_child_account=*/base::nullopt, account_consistency_,
cookie_settings_.get(), PROFILE_MODE_DEFAULT, kTestSource,
false /* force_account_consistency */);
std::string header;
diff --git a/chromium/components/signin/core/browser/signin_status_metrics_provider.cc b/chromium/components/signin/core/browser/signin_status_metrics_provider.cc
index 279eab33886..f5d509b8cbf 100644
--- a/chromium/components/signin/core/browser/signin_status_metrics_provider.cc
+++ b/chromium/components/signin/core/browser/signin_status_metrics_provider.cc
@@ -17,7 +17,6 @@ SigninStatusMetricsProvider::SigninStatusMetricsProvider(
std::unique_ptr<SigninStatusMetricsProviderDelegate> delegate,
bool is_test)
: delegate_(std::move(delegate)),
- scoped_observer_(this),
is_test_(is_test) {
DCHECK(delegate_ || is_test_);
if (is_test_)
@@ -56,7 +55,7 @@ void SigninStatusMetricsProvider::OnIdentityManagerCreated(
// Whenever a new profile is created, a new IdentityManager will be created
// for it. This ensures that all sign-in or sign-out actions of all opened
// profiles are being monitored.
- scoped_observer_.Add(identity_manager);
+ scoped_observations_.AddObservation(identity_manager);
// If the status is unknown, it means this is the first created
// IdentityManager and the corresponding profile should be the only opened
@@ -69,8 +68,8 @@ void SigninStatusMetricsProvider::OnIdentityManagerCreated(
void SigninStatusMetricsProvider::OnIdentityManagerShutdown(
signin::IdentityManager* identity_manager) {
- if (scoped_observer_.IsObserving(identity_manager))
- scoped_observer_.Remove(identity_manager);
+ if (scoped_observations_.IsObservingSource(identity_manager))
+ scoped_observations_.RemoveObservation(identity_manager);
}
void SigninStatusMetricsProvider::OnPrimaryAccountSet(
@@ -103,8 +102,8 @@ void SigninStatusMetricsProvider::Initialize() {
// Start observing all already-created IdentityManagers.
for (signin::IdentityManager* manager :
delegate_->GetIdentityManagersForAllAccounts()) {
- DCHECK(!scoped_observer_.IsObserving(manager));
- scoped_observer_.Add(manager);
+ DCHECK(!scoped_observations_.IsObservingSource(manager));
+ scoped_observations_.AddObservation(manager);
}
// It is possible that when this object is created, no IdentityManager is
diff --git a/chromium/components/signin/core/browser/signin_status_metrics_provider.h b/chromium/components/signin/core/browser/signin_status_metrics_provider.h
index f28f472ffc6..094ad210933 100644
--- a/chromium/components/signin/core/browser/signin_status_metrics_provider.h
+++ b/chromium/components/signin/core/browser/signin_status_metrics_provider.h
@@ -12,7 +12,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "build/build_config.h"
#include "components/signin/core/browser/signin_status_metrics_provider_base.h"
#include "components/signin/core/browser/signin_status_metrics_provider_delegate.h"
@@ -90,8 +90,9 @@ class SigninStatusMetricsProvider : public SigninStatusMetricsProviderBase,
// Used to track the IdentityManagers that this instance is observing so that
// this instance can be removed as an observer on its destruction.
- ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
- scoped_observer_;
+ base::ScopedMultiSourceObservation<signin::IdentityManager,
+ signin::IdentityManager::Observer>
+ scoped_observations_{this};
// Whether the instance is for testing or not.
bool is_test_;
diff --git a/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc b/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
index 0f8e86bb3d0..1ca0bb517b0 100644
--- a/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
+++ b/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
@@ -78,8 +78,9 @@ void AccountFetcherService::Initialize(
repeating_timer_ = std::make_unique<signin::PersistentRepeatingTimer>(
signin_client_->GetPrefs(), AccountFetcherService::kLastUpdatePref,
kRefreshFromTokenServiceDelay,
- base::Bind(&AccountFetcherService::RefreshAllAccountInfo,
- base::Unretained(this), /*only_fetch_if_invalid=*/false));
+ base::BindRepeating(&AccountFetcherService::RefreshAllAccountInfo,
+ base::Unretained(this),
+ /*only_fetch_if_invalid=*/false));
// Tokens may have already been loaded and we will not receive a
// notification-on-registration for |token_service_->AddObserver(this)| few
diff --git a/chromium/components/signin/internal/identity_manager/accounts_mutator_impl.cc b/chromium/components/signin/internal/identity_manager/accounts_mutator_impl.cc
index a0784df0572..271fe09e9d2 100644
--- a/chromium/components/signin/internal/identity_manager/accounts_mutator_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/accounts_mutator_impl.cc
@@ -97,7 +97,7 @@ void AccountsMutatorImpl::InvalidateRefreshTokenForPrimaryAccount(
#if defined(OS_CHROMEOS)
NOTREACHED();
#endif
- DCHECK(primary_account_manager_->IsAuthenticated());
+ DCHECK(primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync));
CoreAccountInfo primary_account_info =
primary_account_manager_->GetAuthenticatedAccountInfo();
AddOrUpdateAccount(primary_account_info.gaia, primary_account_info.email,
diff --git a/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
index 6dad64f6f3a..7a3934f1761 100644
--- a/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -11,8 +11,8 @@
#include <set>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
@@ -601,7 +601,7 @@ void GaiaCookieManagerService::ForceOnCookieChangeProcessing() {
kGaiaCookieName, std::string(), "." + google_url.host(), "/",
base::Time(), base::Time(), base::Time(), true /* secure */,
false /* httponly */, net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_DEFAULT));
+ net::COOKIE_PRIORITY_DEFAULT, false /* same_party */));
OnCookieChange(
net::CookieChangeInfo(*cookie, net::CookieAccessResult(),
net::CookieChangeCause::UNKNOWN_DELETION));
diff --git a/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 00471573a28..52d3a66b0d4 100644
--- a/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
diff --git a/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper.cc b/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper.cc
index d8f5b40eee3..299b12cd896 100644
--- a/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper.cc
+++ b/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h"
diff --git a/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper_unittest.cc b/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper_unittest.cc
index 34c5d7e522f..bffb497324d 100644
--- a/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/oauth_multilogin_helper_unittest.cc
@@ -5,8 +5,8 @@
#include "components/signin/internal/identity_manager/oauth_multilogin_helper.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h"
diff --git a/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h b/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h
index 8f5a5d62e8d..92f57fe2cb7 100644
--- a/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h
+++ b/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.h
@@ -11,8 +11,8 @@
#include <string>
#include <vector>
-#include "base/bind_helpers.h"
#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
diff --git a/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher_unittest.cc b/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher_unittest.cc
index bc8282ad5f8..2470ee5d9bf 100644
--- a/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher_unittest.cc
@@ -8,8 +8,8 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h"
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager.cc b/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
index c2ab6437c4c..8f5528f06c9 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -135,7 +135,7 @@ bool PrimaryAccountManager::IsInitialized() const {
}
CoreAccountInfo PrimaryAccountManager::GetAuthenticatedAccountInfo() const {
- if (!IsAuthenticated())
+ if (!HasPrimaryAccount(signin::ConsentLevel::kSync))
return CoreAccountInfo();
return primary_account_info();
}
@@ -149,13 +149,9 @@ CoreAccountInfo PrimaryAccountManager::GetUnconsentedPrimaryAccountInfo()
return primary_account_info();
}
-bool PrimaryAccountManager::HasUnconsentedPrimaryAccount() const {
- return !primary_account_info().account_id.empty();
-}
-
void PrimaryAccountManager::SetUnconsentedPrimaryAccountInfo(
CoreAccountInfo account_info) {
- if (IsAuthenticated()) {
+ if (HasPrimaryAccount(signin::ConsentLevel::kSync)) {
DCHECK_EQ(account_info, GetAuthenticatedAccountInfo());
return;
}
@@ -172,7 +168,7 @@ void PrimaryAccountManager::SetUnconsentedPrimaryAccountInfo(
void PrimaryAccountManager::SetAuthenticatedAccountInfo(
const CoreAccountInfo& account_info) {
DCHECK(!account_info.account_id.empty());
- DCHECK(!IsAuthenticated());
+ DCHECK(!HasPrimaryAccount(signin::ConsentLevel::kSync));
#if DCHECK_IS_ON()
{
@@ -220,11 +216,20 @@ void PrimaryAccountManager::SetPrimaryAccountInternal(
}
}
-bool PrimaryAccountManager::IsAuthenticated() const {
+bool PrimaryAccountManager::HasPrimaryAccount(
+ signin::ConsentLevel consent_level) const {
bool consented_pref =
client_->GetPrefs()->GetBoolean(prefs::kGoogleServicesConsentedToSync);
- DCHECK(!consented_pref || !primary_account_info().account_id.empty());
- return consented_pref;
+ if (primary_account_info().account_id.empty()) {
+ DCHECK(!consented_pref);
+ return false;
+ }
+ switch (consent_level) {
+ case signin::ConsentLevel::kNotRequired:
+ return true;
+ case signin::ConsentLevel::kSync:
+ return consented_pref;
+ }
}
void PrimaryAccountManager::SignIn(const std::string& username) {
@@ -233,7 +238,7 @@ void PrimaryAccountManager::SignIn(const std::string& username) {
DCHECK(!info.gaia.empty());
DCHECK(!info.email.empty());
DCHECK(!info.account_id.empty());
- if (IsAuthenticated()) {
+ if (HasPrimaryAccount(signin::ConsentLevel::kSync)) {
DCHECK_EQ(info.account_id, GetAuthenticatedAccountId())
<< "Changing the authenticated account while it is not allowed.";
return;
@@ -251,7 +256,7 @@ void PrimaryAccountManager::SignIn(const std::string& username) {
void PrimaryAccountManager::UpdateAuthenticatedAccountInfo() {
DCHECK(!primary_account_info().account_id.empty());
- DCHECK(IsAuthenticated());
+ DCHECK(HasPrimaryAccount(signin::ConsentLevel::kSync));
const CoreAccountInfo info = account_tracker_service_->GetAccountInfo(
primary_account_info().account_id);
DCHECK_EQ(info.account_id, primary_account_info().account_id);
@@ -294,7 +299,7 @@ void PrimaryAccountManager::SignOutAndKeepAllAccounts(
#if defined(OS_CHROMEOS)
void PrimaryAccountManager::RevokeSyncConsent() {
- DCHECK(IsAuthenticated());
+ DCHECK(HasPrimaryAccount(signin::ConsentLevel::kSync));
// TODO(https://crbug.com/1046746): Don't record metrics here.
StartSignOut(signin_metrics::ProfileSignout::USER_CLICKED_SIGNOUT_SETTINGS,
signin_metrics::SignoutDelete::KEEPING,
@@ -311,7 +316,7 @@ void PrimaryAccountManager::StartSignOut(
VLOG(1) << "StartSignOut: " << static_cast<int>(signout_source_metric) << ", "
<< static_cast<int>(signout_delete_metric) << ", "
<< static_cast<int>(remove_option);
- if (IsAuthenticated()) {
+ if (HasPrimaryAccount(signin::ConsentLevel::kSync)) {
client_->PreSignOut(
base::BindOnce(&PrimaryAccountManager::OnSignoutDecisionReached,
base::Unretained(this), signout_source_metric,
@@ -354,7 +359,7 @@ void PrimaryAccountManager::OnSignoutDecisionReached(
const CoreAccountInfo account_info = primary_account_info();
client_->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain);
// Revoke the sync consent.
- if (IsAuthenticated())
+ if (HasPrimaryAccount(signin::ConsentLevel::kSync))
SetPrimaryAccountInternal(account_info, /*consented_to_sync=*/false);
// Revoke all tokens before sending signed_out notification, because there
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager.h b/chromium/components/signin/internal/identity_manager/primary_account_manager.h
index 571378c757c..43ece976d1f 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager.h
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager.h
@@ -29,6 +29,7 @@
#include "components/signin/public/base/account_consistency_method.h"
#include "components/signin/public/base/signin_client.h"
#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/consent_level.h"
class AccountTrackerService;
class PrefRegistrySimple;
@@ -102,8 +103,10 @@ class PrimaryAccountManager : public ProfileOAuth2TokenServiceObserver {
// "Signed in as XXX" in the hotdog menu.
CoreAccountId GetAuthenticatedAccountId() const;
- // Returns true if there is an authenticated user.
- bool IsAuthenticated() const;
+ // Returns whether the user's primary account is available. If consent is
+ // |ConsentLevel::kSync| then true implies that the user has blessed this
+ // account for sync.
+ bool HasPrimaryAccount(signin::ConsentLevel consent_level) const;
// Signs a user in. PrimaryAccountManager assumes that |username| can be used
// to look up the corresponding account_id and gaia_id for this email.
@@ -155,9 +158,6 @@ class PrimaryAccountManager : public ProfileOAuth2TokenServiceObserver {
// account. Returns an empty info, if there is no such account.
CoreAccountInfo GetUnconsentedPrimaryAccountInfo() const;
- // Returns whether the user's unconsented primary account is available.
- bool HasUnconsentedPrimaryAccount() const;
-
// Sets the unconsented primary account. The unconsented primary account can
// only be changed if the user is not authenticated. If the user is
// authenticated, use Signout() instead.
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc b/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
index f8c37b3dbce..a5d92f83a65 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
@@ -32,6 +32,8 @@
#include "components/signin/internal/identity_manager/primary_account_policy_manager_impl.h"
#endif
+using signin::ConsentLevel;
+
class PrimaryAccountManagerTest : public testing::Test,
public PrimaryAccountManager::Observer {
public:
@@ -107,7 +109,7 @@ class PrimaryAccountManagerTest : public testing::Test,
}
void ExpectSignInWithRefreshTokenSuccess() {
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_FALSE(manager_->GetAuthenticatedAccountId().empty());
EXPECT_FALSE(manager_->GetAuthenticatedAccountInfo().email.empty());
@@ -152,14 +154,14 @@ TEST_F(PrimaryAccountManagerTest, SignOut) {
manager_->SignIn("user@gmail.com");
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_TRUE(manager_->GetAuthenticatedAccountInfo().email.empty());
EXPECT_TRUE(manager_->GetAuthenticatedAccountId().empty());
EXPECT_TRUE(manager_->GetUnconsentedPrimaryAccountInfo().IsEmpty());
// Should not be persisted anymore
ShutDownManager();
CreatePrimaryAccountManager();
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_TRUE(manager_->GetAuthenticatedAccountInfo().email.empty());
EXPECT_TRUE(manager_->GetAuthenticatedAccountId().empty());
EXPECT_TRUE(manager_->GetUnconsentedPrimaryAccountInfo().IsEmpty());
@@ -174,14 +176,14 @@ TEST_F(PrimaryAccountManagerTest, SignOutRevoke) {
token_service_.UpdateCredentials(main_account_id, "token");
token_service_.UpdateCredentials(other_account_id, "token");
manager_->SignIn("user@gmail.com");
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
// Tokens are revoked.
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_TRUE(token_service_.GetAccounts().empty());
}
@@ -197,14 +199,14 @@ TEST_F(PrimaryAccountManagerTest, SignOutDiceNoRevoke) {
token_service_.UpdateCredentials(main_account_id, "token");
token_service_.UpdateCredentials(other_account_id, "token");
manager_->SignIn("user@gmail.com");
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
// Tokens are not revoked.
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
std::vector<CoreAccountId> expected_tokens = {main_account_id,
other_account_id};
EXPECT_EQ(expected_tokens, token_service_.GetAccounts());
@@ -231,14 +233,14 @@ TEST_F(PrimaryAccountManagerTest, SignOutDiceWithError) {
ASSERT_TRUE(token_service_.RefreshTokenHasError(main_account_id));
ASSERT_TRUE(token_service_.RefreshTokenHasError(other_account_id));
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
// Only main token is revoked.
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
std::vector<CoreAccountId> expected_tokens = {other_account_id};
EXPECT_EQ(expected_tokens, token_service_.GetAccounts());
}
@@ -246,7 +248,7 @@ TEST_F(PrimaryAccountManagerTest, SignOutDiceWithError) {
TEST_F(PrimaryAccountManagerTest, SignOutWhileProhibited) {
CreatePrimaryAccountManager();
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_TRUE(manager_->GetAuthenticatedAccountInfo().email.empty());
EXPECT_TRUE(manager_->GetAuthenticatedAccountId().empty());
@@ -255,28 +257,28 @@ TEST_F(PrimaryAccountManagerTest, SignOutWhileProhibited) {
signin_client()->set_is_signout_allowed(false);
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
signin_client()->set_is_signout_allowed(true);
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
}
TEST_F(PrimaryAccountManagerTest, UnconsentedSignOutWhileProhibited) {
CreatePrimaryAccountManager();
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_TRUE(manager_->GetAuthenticatedAccountInfo().email.empty());
EXPECT_TRUE(manager_->GetAuthenticatedAccountId().empty());
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
CoreAccountInfo account_info = account_tracker()->GetAccountInfo(account_id);
manager_->SetUnconsentedPrimaryAccountInfo(account_info);
- EXPECT_TRUE(manager_->HasUnconsentedPrimaryAccount());
- EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kNotRequired));
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
signin_client()->set_is_signout_allowed(false);
manager_->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
- EXPECT_FALSE(manager_->HasUnconsentedPrimaryAccount());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kNotRequired));
}
TEST_F(PrimaryAccountManagerTest, ProhibitedAtStartup) {
@@ -505,11 +507,11 @@ TEST_F(PrimaryAccountManagerTest, RevokeSyncConsent) {
CreatePrimaryAccountManager();
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
manager_->SignIn("user@gmail.com");
- EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
manager_->RevokeSyncConsent();
- EXPECT_FALSE(manager_->IsAuthenticated());
- EXPECT_TRUE(manager_->HasUnconsentedPrimaryAccount());
+ EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
+ EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kNotRequired));
EXPECT_EQ(account_id,
manager_->GetUnconsentedPrimaryAccountInfo().account_id);
}
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc b/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
index 765335b6d00..e7d76e54ab2 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
@@ -38,7 +38,7 @@ bool PrimaryAccountMutatorImpl::SetPrimaryAccount(
if (!pref_service_->GetBoolean(prefs::kSigninAllowed))
return false;
- if (primary_account_manager_->IsAuthenticated())
+ if (primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync))
return false;
if (account_info.account_id != account_id || account_info.email.empty())
@@ -56,7 +56,8 @@ void PrimaryAccountMutatorImpl::SetUnconsentedPrimaryAccount(
#if defined(OS_CHROMEOS)
// On Chrome OS the UPA can only be set once and never removed or changed.
DCHECK(!account_id.empty());
- DCHECK(!primary_account_manager_->HasUnconsentedPrimaryAccount());
+ DCHECK(
+ !primary_account_manager_->HasPrimaryAccount(ConsentLevel::kNotRequired));
#endif
AccountInfo account_info;
if (!account_id.empty()) {
@@ -78,7 +79,7 @@ bool PrimaryAccountMutatorImpl::ClearPrimaryAccount(
ClearAccountsAction action,
signin_metrics::ProfileSignout source_metric,
signin_metrics::SignoutDelete delete_metric) {
- if (!primary_account_manager_->HasUnconsentedPrimaryAccount())
+ if (!primary_account_manager_->HasPrimaryAccount(ConsentLevel::kNotRequired))
return false;
switch (action) {
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_policy_manager_impl.cc b/chromium/components/signin/internal/identity_manager/primary_account_policy_manager_impl.cc
index bf35da6fc54..a8820ec9427 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_policy_manager_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_policy_manager_impl.cc
@@ -69,7 +69,7 @@ void PrimaryAccountPolicyManagerImpl::InitializePolicy(
void PrimaryAccountPolicyManagerImpl::OnGoogleServicesUsernamePatternChanged(
PrimaryAccountManager* primary_account_manager) {
- if (primary_account_manager->IsAuthenticated() &&
+ if (primary_account_manager->HasPrimaryAccount(signin::ConsentLevel::kSync) &&
!IsAllowedUsername(
primary_account_manager->GetAuthenticatedAccountInfo().email)) {
// Signed in user is invalid according to the current policy so sign
@@ -86,7 +86,8 @@ bool PrimaryAccountPolicyManagerImpl::IsSigninAllowed() const {
void PrimaryAccountPolicyManagerImpl::OnSigninAllowedPrefChanged(
PrimaryAccountManager* primary_account_manager) {
- if (!IsSigninAllowed() && primary_account_manager->IsAuthenticated()) {
+ if (!IsSigninAllowed() &&
+ primary_account_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
VLOG(0) << "IsSigninAllowed() set to false, signing out the user";
primary_account_manager->SignOut(
signin_metrics::SIGNOUT_PREF_CHANGED,
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
index fdda983b3a1..3d9c5037005 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
@@ -43,12 +43,11 @@ const net::BackoffEntry::Policy kBackoffPolicy = {
// |account_keys| is the set of accounts that need to be translated.
// |account_tracker_service| is an unowned pointer.
std::vector<CoreAccountId> GetOAuthAccountIdsFromAccountKeys(
- const std::set<chromeos::AccountManager::AccountKey>& account_keys,
+ const std::set<account_manager::AccountKey>& account_keys,
const AccountTrackerService* const account_tracker_service) {
std::vector<CoreAccountId> accounts;
for (auto& account_key : account_keys) {
- if (account_key.account_type !=
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
+ if (account_key.account_type != account_manager::AccountType::kGaia) {
continue;
}
@@ -120,10 +119,9 @@ ProfileOAuth2TokenServiceDelegateChromeOS::CreateAccessTokenFetcher(
}
return account_manager_->CreateAccessTokenFetcher(
- chromeos::AccountManager::AccountKey{
+ account_manager::AccountKey{
account_tracker_service_->GetAccountInfo(account_id).gaia,
- chromeos::account_manager::AccountType::
- ACCOUNT_TYPE_GAIA} /* account_key */,
+ account_manager::AccountType::kGaia} /* account_key */,
consumer);
}
@@ -257,7 +255,7 @@ ProfileOAuth2TokenServiceDelegateChromeOS::GetURLLoaderFactory() const {
}
void ProfileOAuth2TokenServiceDelegateChromeOS::OnGetAccounts(
- const std::vector<chromeos::AccountManager::Account>& accounts) {
+ const std::vector<account_manager::Account>& accounts) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This callback should only be triggered during |LoadCredentials|, which
@@ -281,23 +279,9 @@ void ProfileOAuth2TokenServiceDelegateChromeOS::OnGetAccounts(
FireRefreshTokensLoaded();
}
-void ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted(
- const chromeos::AccountManager::Account& account) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- account_keys_.insert(account.key);
-
- if (account.key.account_type !=
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
- return;
- }
-
- // All Gaia accounts in Chrome OS Account Manager must have an email
- // associated with them (https://crbug.com/933307).
- DCHECK(!account.raw_email.empty());
- CoreAccountId account_id = account_tracker_service_->SeedAccountInfo(
- account.key.id /* gaia_id */, account.raw_email);
- DCHECK(!account_id.empty());
-
+void ProfileOAuth2TokenServiceDelegateChromeOS::ContinueTokenUpsertProcessing(
+ const CoreAccountId& account_id,
+ bool has_dummy_token) {
GoogleServiceAuthError error(GoogleServiceAuthError::AuthErrorNone());
// Clear any previously cached errors for |account_id|.
// Don't call |FireAuthErrorChanged|, since we call it at the end of this
@@ -308,7 +292,7 @@ void ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted(
// However, if we know that |account_key| has a dummy token, store a
// persistent error against it, so that we can pre-emptively reject access
// token requests for it.
- if (account_manager_->HasDummyGaiaToken(account.key)) {
+ if (has_dummy_token) {
error = GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT);
@@ -323,8 +307,30 @@ void ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted(
FireAuthErrorChanged(account_id, error);
}
+void ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted(
+ const account_manager::Account& account) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ account_keys_.insert(account.key);
+
+ if (account.key.account_type != account_manager::AccountType::kGaia) {
+ return;
+ }
+
+ // All Gaia accounts in Chrome OS Account Manager must have an email
+ // associated with them (https://crbug.com/933307).
+ DCHECK(!account.raw_email.empty());
+ CoreAccountId account_id = account_tracker_service_->SeedAccountInfo(
+ account.key.id /* gaia_id */, account.raw_email);
+ DCHECK(!account_id.empty());
+
+ account_manager_->HasDummyGaiaToken(
+ account.key, base::BindOnce(&ProfileOAuth2TokenServiceDelegateChromeOS::
+ ContinueTokenUpsertProcessing,
+ weak_factory_.GetWeakPtr(), account_id));
+}
+
void ProfileOAuth2TokenServiceDelegateChromeOS::OnAccountRemoved(
- const chromeos::AccountManager::Account& account) {
+ const account_manager::Account& account) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(
signin::LoadCredentialsState::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
@@ -336,8 +342,7 @@ void ProfileOAuth2TokenServiceDelegateChromeOS::OnAccountRemoved(
}
account_keys_.erase(it);
- if (account.key.account_type !=
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA) {
+ if (account.key.account_type != account_manager::AccountType::kGaia) {
return;
}
CoreAccountId account_id =
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
index 260041b39c0..e0379dcc553 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
@@ -15,6 +15,7 @@
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "chromeos/components/account_manager/account_manager.h"
+#include "components/account_manager_core/account.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h"
#include "services/network/public/cpp/network_connection_tracker.h"
@@ -60,10 +61,8 @@ class ProfileOAuth2TokenServiceDelegateChromeOS
const net::BackoffEntry* BackoffEntry() const override;
// |chromeos::AccountManager::Observer| overrides.
- void OnTokenUpserted(
- const chromeos::AccountManager::Account& account) override;
- void OnAccountRemoved(
- const chromeos::AccountManager::Account& account) override;
+ void OnTokenUpserted(const account_manager::Account& account) override;
+ void OnAccountRemoved(const account_manager::Account& account) override;
// |NetworkConnectionTracker::NetworkConnectionObserver| overrides.
void OnConnectionChanged(network::mojom::ConnectionType type) override;
@@ -81,8 +80,11 @@ class ProfileOAuth2TokenServiceDelegateChromeOS
};
// Callback handler for |chromeos::AccountManager::GetAccounts|.
- void OnGetAccounts(
- const std::vector<chromeos::AccountManager::Account>& accounts);
+ void OnGetAccounts(const std::vector<account_manager::Account>& accounts);
+
+ // Callback handler for |chromeos::AccountManager::HasDummyGaiaToken|.
+ void ContinueTokenUpsertProcessing(const CoreAccountId& account_id,
+ bool has_dummy_token);
// Non-owning pointers.
AccountTrackerService* const account_tracker_service_;
@@ -90,7 +92,7 @@ class ProfileOAuth2TokenServiceDelegateChromeOS
chromeos::AccountManager* const account_manager_;
// A cache of AccountKeys.
- std::set<chromeos::AccountManager::AccountKey> account_keys_;
+ std::set<account_manager::AccountKey> account_keys_;
// A map from account id to the last seen error for that account.
std::map<CoreAccountId, AccountErrorStatus> errors_;
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
index f2e92878fdc..77b18daa222 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -16,7 +16,7 @@
#include "base/stl_util.h"
#include "base/test/task_environment.h"
#include "chromeos/components/account_manager/account_manager.h"
-#include "chromeos/components/account_manager/tokens.pb.h"
+#include "components/account_manager_core/account.h"
#include "components/signin/internal/identity_manager/account_tracker_service.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h"
#include "components/signin/public/base/signin_pref_names.h"
@@ -34,9 +34,6 @@ namespace signin {
namespace {
-using chromeos::account_manager::AccountType::ACCOUNT_TYPE_ACTIVE_DIRECTORY;
-using chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA;
-
constexpr char kGaiaId[] = "gaia-id";
constexpr char kGaiaToken[] = "gaia-token";
constexpr char kUserEmail[] = "user@gmail.com";
@@ -169,8 +166,10 @@ class ProfileOAuth2TokenServiceDelegateChromeOSTest : public testing::Test {
account_info_ = CreateAccountInfoTestFixture(kGaiaId, kUserEmail);
account_tracker_service_.SeedAccountInfo(account_info_);
- gaia_account_key_ = {account_info_.gaia, ACCOUNT_TYPE_GAIA};
- ad_account_key_ = {"object-guid", ACCOUNT_TYPE_ACTIVE_DIRECTORY};
+ gaia_account_key_ = {account_info_.gaia,
+ account_manager::AccountType::kGaia};
+ ad_account_key_ = {"object-guid",
+ account_manager::AccountType::kActiveDirectory};
delegate_ = std::make_unique<ProfileOAuth2TokenServiceDelegateChromeOS>(
&account_tracker_service_,
@@ -214,9 +213,8 @@ class ProfileOAuth2TokenServiceDelegateChromeOSTest : public testing::Test {
// Will result in chromeos::AccountManager calling
// |ProfileOAuth2TokenServiceDelegateChromeOS::OnTokenUpserted|.
account_manager_.UpsertAccount(
- chromeos::AccountManager::AccountKey{
- gaia_id, chromeos::account_manager::AccountType::
- ACCOUNT_TYPE_GAIA} /* account_key */,
+ account_manager::AccountKey{
+ gaia_id, account_manager::AccountType::kGaia} /* account_key */,
email /* email */, refresh_token);
}
@@ -224,8 +222,8 @@ class ProfileOAuth2TokenServiceDelegateChromeOSTest : public testing::Test {
base::ScopedTempDir tmp_dir_;
AccountInfo account_info_;
- chromeos::AccountManager::AccountKey gaia_account_key_;
- chromeos::AccountManager::AccountKey ad_account_key_;
+ account_manager::AccountKey gaia_account_key_;
+ account_manager::AccountKey ad_account_key_;
AccountTrackerService account_tracker_service_;
chromeos::AccountManager account_manager_;
std::unique_ptr<ProfileOAuth2TokenServiceDelegateChromeOS> delegate_;
@@ -365,9 +363,8 @@ TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest,
UpdateCredentials(account_info_.gaia, account_info_.email, kGaiaToken);
// Deliberately add an error.
delegate_->UpdateAuthError(account_info_.account_id, error);
- account_manager_.RemoveAccount(chromeos::AccountManager::AccountKey{
- account_info_.gaia,
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA});
+ account_manager_.RemoveAccount(account_manager::AccountKey{
+ account_info_.gaia, account_manager::AccountType::kGaia});
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
delegate_->GetAuthError(account_info_.account_id));
}
@@ -439,10 +436,12 @@ TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest,
account_tracker_service_.SeedAccountInfo(account1);
account_tracker_service_.SeedAccountInfo(account2);
account_manager_.UpsertAccount(
- chromeos::AccountManager::AccountKey{account1.gaia, ACCOUNT_TYPE_GAIA},
+ account_manager::AccountKey{account1.gaia,
+ account_manager::AccountType::kGaia},
"user1@example.com", "token1");
account_manager_.UpsertAccount(
- chromeos::AccountManager::AccountKey{account2.gaia, ACCOUNT_TYPE_GAIA},
+ account_manager::AccountKey{account2.gaia,
+ account_manager::AccountType::kGaia},
"user2@example.com", "token2");
task_environment_.RunUntilIdle();
@@ -532,8 +531,8 @@ TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest,
// accounts, 1 has a valid refresh token and 1 has a dummy token.
account_manager_.UpsertAccount(gaia_account_key_, kUserEmail, kGaiaToken);
- chromeos::AccountManager::AccountKey gaia_account_key2{"random-gaia-id",
- ACCOUNT_TYPE_GAIA};
+ account_manager::AccountKey gaia_account_key2{
+ "random-gaia-id", account_manager::AccountType::kGaia};
account_tracker_service_.SeedAccountInfo(
CreateAccountInfoTestFixture(gaia_account_key2.id, kUserEmail2));
account_manager_.UpsertAccount(gaia_account_key2, kUserEmail2,
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.h b/chromium/components/signin/ios/browser/account_consistency_service.h
index 8c2dc464600..5d8f5090aaf 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.h
+++ b/chromium/components/signin/ios/browser/account_consistency_service.h
@@ -72,11 +72,11 @@ class AccountConsistencyService : public KeyedService,
// Checks for the presence of Gaia cookies and if they have been deleted
// notifies the AccountReconcilor (the class responsible for rebuilding Gaia
- // cookies if needed).
+ // cookies if needed). Calls callback if Gaia cookies were restored.
//
// Applies a one hour time restriction in between updates to avoid too many
// |GetAllCookies| calls on the cookie manager.
- void SetGaiaCookiesIfDeleted();
+ void SetGaiaCookiesIfDeleted(base::OnceClosure cookies_restored_callback);
// Enqueues a request to set the CHROME_CONNECTED cookie for the domain of the
// |url|. The cookie is set if it is not already on the domain.
@@ -130,14 +130,13 @@ class AccountConsistencyService : public KeyedService,
// Adds CHROME_CONNECTED cookies on all the main Google domains.
void AddChromeConnectedCookies();
- // Triggers a Gaia cookie update on the Google domain.
+ // Triggers a Gaia cookie update on the Google domain. Calls
+ // |cookies_restored_callback| if the Gaia cookies were restored.
void TriggerGaiaCookieChangeIfDeleted(
+ base::OnceClosure cookies_restored_callback,
const net::CookieAccessResultList& cookie_list,
const net::CookieAccessResultList& excluded_cookies);
- // Records whether Gaia cookies were present on navigation in UMA histogram.
- static void LogIOSGaiaCookiesPresentOnNavigation(bool is_present);
-
// Clears all pending cookie requests and cached domains.
void ResetInternalState();
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.mm b/chromium/components/signin/ios/browser/account_consistency_service.mm
index d1cbf9e32cf..8e945997cae 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service.mm
@@ -67,6 +67,22 @@ static std::string GetDomainFromUrl(const GURL& url) {
url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
}
+// The Gaia cookie state on navigation for a signed-in Chrome user.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class GaiaCookieStateOnSignedInNavigation {
+ kGaiaCookiePresentOnNavigation = 0,
+ kGaiaCookieAbsentOnGoogleAssociatedDomainNavigation = 1,
+ kGaiaCookieAbsentOnAddSessionNavigation = 2,
+ kMaxValue = kGaiaCookieAbsentOnAddSessionNavigation
+};
+
+// Records the state of Gaia cookies for a navigation in UMA histogram.
+void LogIOSGaiaCookiesState(GaiaCookieStateOnSignedInNavigation state) {
+ base::UmaHistogramEnumeration("Signin.IOSGaiaCookieStateOnSignedInNavigation",
+ state);
+}
+
// Allows for manual testing by reducing the polling interval for verifying the
// existence of the GAIA cookie.
base::TimeDelta GetDelayThresholdToUpdateGaiaCookie() {
@@ -94,6 +110,7 @@ class AccountConsistencyHandler : public web::WebStatePolicyDecider,
AccountConsistencyHandler(web::WebState* web_state,
AccountConsistencyService* service,
AccountReconcilor* account_reconcilor,
+ signin::IdentityManager* identity_manager,
id<ManageAccountsDelegate> delegate);
void WebStateDestroyed(web::WebState* web_state) override;
@@ -113,10 +130,16 @@ class AccountConsistencyHandler : public web::WebStatePolicyDecider,
base::OnceCallback<void(PolicyDecision)> callback) override;
void WebStateDestroyed() override;
+ // Marks that GAIA cookies have been restored.
+ void MarkGaiaCookiesRestored();
+
bool show_consistency_promo_ = false;
+ bool gaia_cookies_restored_ = false;
AccountConsistencyService* account_consistency_service_; // Weak.
AccountReconcilor* account_reconcilor_; // Weak.
+ signin::IdentityManager* identity_manager_;
__weak id<ManageAccountsDelegate> delegate_;
+ base::WeakPtrFactory<AccountConsistencyHandler> weak_ptr_factory_;
};
} // namespace
@@ -124,11 +147,14 @@ AccountConsistencyHandler::AccountConsistencyHandler(
web::WebState* web_state,
AccountConsistencyService* service,
AccountReconcilor* account_reconcilor,
+ signin::IdentityManager* identity_manager,
id<ManageAccountsDelegate> delegate)
: web::WebStatePolicyDecider(web_state),
account_consistency_service_(service),
account_reconcilor_(account_reconcilor),
- delegate_(delegate) {
+ identity_manager_(identity_manager),
+ delegate_(delegate),
+ weak_ptr_factory_(this) {
web_state->AddObserver(this);
}
@@ -151,7 +177,26 @@ void AccountConsistencyHandler::ShouldAllowResponse(
if (signin::IsUrlEligibleForMirrorCookie(url)) {
account_consistency_service_->SetChromeConnectedCookieWithUrls(
{url, GURL(kGoogleUrl)});
- account_consistency_service_->SetGaiaCookiesIfDeleted();
+ }
+
+ // Chrome monitors GAIA cookies when navigating to Google associated domains
+ // to ensure that signed-in users remain signed-in to their Google services on
+ // the web. This includes redirects to accounts.google.com.
+ if (google_util::IsGoogleAssociatedDomainUrl(url)) {
+ // TODO(crbug.com/1131027): Disable GAIA cookie restore on Google URLs that
+ // may display cookie consent in the content area that conflict with the
+ // sign-in notification. This will be removed once we perform cookie
+ // restoration before sending a navigation request.
+ if (!(google_util::IsGoogleHomePageUrl(url) ||
+ google_util::IsGoogleSearchUrl(url))) {
+ // Reset boolean that tracks displaying the sign-in notification infobar.
+ // This ensures that only the most recent navigation will trigger an
+ // infobar.
+ gaia_cookies_restored_ = false;
+ account_consistency_service_->SetGaiaCookiesIfDeleted(
+ base::BindOnce(&AccountConsistencyHandler::MarkGaiaCookiesRestored,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
}
if (!gaia::IsGaiaSignonRealm(url.GetOrigin())) {
@@ -185,6 +230,12 @@ void AccountConsistencyHandler::ShouldAllowResponse(
}
case signin::GAIA_SERVICE_TYPE_SIGNUP:
case signin::GAIA_SERVICE_TYPE_ADDSESSION:
+ // This situation is only possible if the all cookies have been deleted by
+ // ITP restrictions and Chrome has not triggered a cookie refresh.
+ if (identity_manager_->HasPrimaryAccount()) {
+ LogIOSGaiaCookiesState(GaiaCookieStateOnSignedInNavigation::
+ kGaiaCookieAbsentOnAddSessionNavigation);
+ }
if (params.show_consistency_promo) {
show_consistency_promo_ = true;
// Allows the URL response to load before showing the consistency promo.
@@ -215,22 +266,40 @@ void AccountConsistencyHandler::ShouldAllowResponse(
std::move(callback).Run(PolicyDecision::Cancel());
}
+void AccountConsistencyHandler::MarkGaiaCookiesRestored() {
+ gaia_cookies_restored_ = true;
+}
+
void AccountConsistencyHandler::PageLoaded(
web::WebState* web_state,
web::PageLoadCompletionStatus load_completion_status) {
- if (!show_consistency_promo_ ||
- !gaia::IsGaiaSignonRealm(web_state->GetLastCommittedURL().GetOrigin()) ||
- load_completion_status == web::PageLoadCompletionStatus::FAILURE) {
+ const GURL& url = web_state->GetLastCommittedURL();
+ if (load_completion_status == web::PageLoadCompletionStatus::FAILURE ||
+ !google_util::IsGoogleDomainUrl(
+ url, google_util::ALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS)) {
return;
}
- [delegate_ onShowConsistencyPromo];
- show_consistency_promo_ = false;
- // Chrome uses the CHROME_CONNECTED cookie to determine whether the
- // eligibility promo should be shown. Once it is shown we should remove the
- // cookie, since it should otherwise not be used unless the user is signed in.
- account_consistency_service_->RemoveAllChromeConnectedCookies(
- base::OnceClosure());
+ // Displays the sign-in notification infobar if GAIA cookies have been
+ // restored. This occurs once the URL has been loaded to avoid a race
+ // condition in which the infobar is dismissed prior to the page load.
+ if (gaia_cookies_restored_) {
+ [delegate_ onRestoreGaiaCookies];
+ gaia_cookies_restored_ = false;
+ }
+
+ if (show_consistency_promo_ && gaia::IsGaiaSignonRealm(url.GetOrigin())) {
+ [delegate_ onShowConsistencyPromo];
+ show_consistency_promo_ = false;
+
+ // Chrome uses the CHROME_CONNECTED cookie to determine whether the
+ // eligibility promo should be shown. Once it is shown we should remove the
+ // cookie, since it should otherwise not be used unless the user is signed
+ // in.
+ account_consistency_service_->RemoveAllChromeConnectedCookies(
+ base::OnceClosure());
+ }
}
void AccountConsistencyHandler::WebStateDestroyed(web::WebState* web_state) {}
@@ -282,7 +351,7 @@ void AccountConsistencyService::SetWebStateHandler(
id<ManageAccountsDelegate> delegate) {
DCHECK_EQ(0u, web_state_handlers_.count(web_state));
web_state_handlers_[web_state].reset(new AccountConsistencyHandler(
- web_state, this, account_reconcilor_, delegate));
+ web_state, this, account_reconcilor_, identity_manager_, delegate));
}
void AccountConsistencyService::RemoveWebStateHandler(
@@ -293,7 +362,8 @@ void AccountConsistencyService::RemoveWebStateHandler(
web_state_handlers_.erase(web_state);
}
-void AccountConsistencyService::SetGaiaCookiesIfDeleted() {
+void AccountConsistencyService::SetGaiaCookiesIfDeleted(
+ base::OnceClosure cookies_restored_callback) {
// We currently enforce a time threshold to update the Gaia cookie
// for signed-in users to prevent calling the expensive method
// |GetAllCookies| in the cookie manager.
@@ -309,35 +379,37 @@ void AccountConsistencyService::SetGaiaCookiesIfDeleted() {
net::CookieOptions::MakeAllInclusive(),
base::BindOnce(
&AccountConsistencyService::TriggerGaiaCookieChangeIfDeleted,
- base::Unretained(this)));
+ base::Unretained(this), std::move(cookies_restored_callback)));
last_gaia_cookie_verification_time_ = base::Time::Now();
}
void AccountConsistencyService::TriggerGaiaCookieChangeIfDeleted(
+ base::OnceClosure cookies_restored_callback,
const net::CookieAccessResultList& cookie_list,
const net::CookieAccessResultList& unused_excluded_cookies) {
for (const auto& cookie : cookie_list) {
if (cookie.cookie.Name() == kGaiaCookieName) {
- LogIOSGaiaCookiesPresentOnNavigation(true);
+ LogIOSGaiaCookiesState(
+ GaiaCookieStateOnSignedInNavigation::kGaiaCookiePresentOnNavigation);
return;
}
}
// The SAPISID cookie may have been deleted previous to this update due to
// ITP restrictions marking Google domains as potential trackers.
- LogIOSGaiaCookiesPresentOnNavigation(false);
+ LogIOSGaiaCookiesState(
+ GaiaCookieStateOnSignedInNavigation::
+ kGaiaCookieAbsentOnGoogleAssociatedDomainNavigation);
if (!base::FeatureList::IsEnabled(signin::kRestoreGaiaCookiesIfDeleted)) {
return;
}
+
// Re-generate cookie to ensure that the user is properly signed in.
identity_manager_->GetAccountsCookieMutator()->ForceTriggerOnCookieChange();
-}
-
-void AccountConsistencyService::LogIOSGaiaCookiesPresentOnNavigation(
- bool is_present) {
- base::UmaHistogramBoolean("Signin.IOSGaiaCookiePresentOnNavigation",
- is_present);
+ if (!cookies_restored_callback.is_null()) {
+ std::move(cookies_restored_callback).Run();
+ }
}
void AccountConsistencyService::RemoveAllChromeConnectedCookies(
@@ -441,7 +513,7 @@ void AccountConsistencyService::SetChromeConnectedCookieWithUrl(
/*last_access_time=*/base::Time(),
/*secure=*/true,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
- net::COOKIE_PRIORITY_DEFAULT);
+ net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false);
net::CookieOptions options;
options.set_include_httponly();
options.set_same_site_cookie_context(
diff --git a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
index 6b605eef2fb..9a08bddc55f 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -9,9 +9,9 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/ios/ios_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#import "base/test/ios/wait_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -21,6 +21,7 @@
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/account_reconcilor.h"
#include "components/signin/core/browser/account_reconcilor_delegate.h"
+#include "components/signin/ios/browser/features.h"
#include "components/signin/public/base/list_accounts_test_utils.h"
#include "components/signin/public/base/test_signin_client.h"
#include "components/signin/public/identity_manager/identity_manager.h"
@@ -58,9 +59,10 @@ const char* kYoutubeDomain = "youtube.com";
// Google domain where the CHROME_CONNECTED cookie is set/removed.
const char* kCountryGoogleDomain = "google.de";
-// Name of the histogram to record whether the GAIA cookie is present.
-const char* kGAIACookiePresentHistogram =
- "Signin.IOSGaiaCookiePresentOnNavigation";
+// Name of the histogram to record the state of the GAIA cookie for the
+// navigation.
+const char* kGAIACookieOnNavigationHistogram =
+ "Signin.IOSGaiaCookieStateOnSignedInNavigation";
// Returns a cookie domain that applies for all origins on |host_domain|.
std::string GetCookieDomain(const std::string& host_domain) {
@@ -135,7 +137,7 @@ class TestWebState : public web::TestWebState {
__block web::WebStatePolicyDecider::PolicyDecision policyDecision =
web::WebStatePolicyDecider::PolicyDecision::Allow();
auto callback =
- base::Bind(^(web::WebStatePolicyDecider::PolicyDecision decision) {
+ base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) {
policyDecision = decision;
});
decider_->ShouldAllowResponse(response, for_main_frame,
@@ -301,8 +303,8 @@ class AccountConsistencyServiceTest : public PlatformTest {
// Simulates updating the Gaia cookie on the Google domain at the designated
// time interval. Returns the time at which the cookie was updated.
- void SimulateUpdateGaiaCookie() {
- account_consistency_service_->SetGaiaCookiesIfDeleted();
+ void SimulateUpdateGaiaCookie(base::OnceClosure callback) {
+ account_consistency_service_->SetGaiaCookiesIfDeleted(std::move(callback));
}
void CheckGoogleDomainHasGaiaCookie() {
@@ -686,24 +688,24 @@ TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookieAtUpdateTime) {
TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateNotUpdateTime) {
SignIn();
- SimulateUpdateGaiaCookie();
+ SimulateUpdateGaiaCookie(base::OnceClosure());
// Advance clock, but stay within the one-hour Gaia update time.
const base::Time first_update_time = base::Time::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1));
- SimulateUpdateGaiaCookie();
+ SimulateUpdateGaiaCookie(base::OnceClosure());
EXPECT_EQ(first_update_time, GetGaiaLastUpdateTime());
}
TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateAtUpdateTime) {
SignIn();
- SimulateUpdateGaiaCookie();
+ SimulateUpdateGaiaCookie(base::OnceClosure());
// Advance clock past one-hour Gaia update time.
task_environment_.FastForwardBy(base::TimeDelta::FromHours(2));
const base::Time second_update_time = base::Time::Now();
- SimulateUpdateGaiaCookie();
+ SimulateUpdateGaiaCookie(base::OnceClosure());
EXPECT_EQ(second_update_time, GetGaiaLastUpdateTime());
}
@@ -712,15 +714,50 @@ TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateAtUpdateTime) {
// |kRestoreGAIACookiesIfDeleted| experiment is disabled.
TEST_F(AccountConsistencyServiceTest, GAIACookieStatusLoggedProperly) {
base::HistogramTester histogram_tester;
+ __block bool cookie_updated = false;
+ base::OnceClosure callback = base::BindOnce(^() {
+ cookie_updated = true;
+ });
- histogram_tester.ExpectTotalCount(kGAIACookiePresentHistogram, 0);
- SimulateUpdateGaiaCookie();
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 0);
+
+ SimulateUpdateGaiaCookie(std::move(callback));
+ base::RunLoop().RunUntilIdle();
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 0);
+ ASSERT_FALSE(cookie_updated);
+
+ SignIn();
+ SimulateUpdateGaiaCookie(std::move(callback));
base::RunLoop().RunUntilIdle();
- histogram_tester.ExpectTotalCount(kGAIACookiePresentHistogram, 0);
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 1);
+ ASSERT_FALSE(cookie_updated);
+}
+
+// Ensures that in the case Gaia cookies are restored the restoration callback
+// is completed.
+TEST_F(AccountConsistencyServiceTest, GAIACookieRestoreCallbackFinished) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(
+ signin::kRestoreGaiaCookiesIfDeleted);
+
+ base::HistogramTester histogram_tester;
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 0);
+
+ __block bool cookie_updated = false;
+ SimulateUpdateGaiaCookie(base::BindOnce(^{
+ cookie_updated = true;
+ }));
+ base::RunLoop().RunUntilIdle();
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 0);
+ ASSERT_FALSE(cookie_updated);
+
SignIn();
- SimulateUpdateGaiaCookie();
+ SimulateUpdateGaiaCookie(base::BindOnce(^{
+ cookie_updated = true;
+ }));
base::RunLoop().RunUntilIdle();
- histogram_tester.ExpectTotalCount(kGAIACookiePresentHistogram, 1);
+ histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 1);
+ ASSERT_TRUE(cookie_updated);
}
// Ensures that set and remove cookie operations are handled in the order
diff --git a/chromium/components/signin/ios/browser/features.cc b/chromium/components/signin/ios/browser/features.cc
index 16789a5edfc..755d4620233 100644
--- a/chromium/components/signin/ios/browser/features.cc
+++ b/chromium/components/signin/ios/browser/features.cc
@@ -19,4 +19,8 @@ const base::Feature kRestoreGaiaCookiesIfDeleted{
const char kDelayThresholdMinutesToUpdateGaiaCookie[] =
"minutes-delay-to-restore-gaia-cookies-if-deleted";
+const base::Feature kSigninNotificationInfobarUsernameInTitle{
+ "SigninNotificationInfobarUsernameInTitle",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
} // namespace signin
diff --git a/chromium/components/signin/ios/browser/features.h b/chromium/components/signin/ios/browser/features.h
index 6fc58d0dc4b..bb2558bc6cb 100644
--- a/chromium/components/signin/ios/browser/features.h
+++ b/chromium/components/signin/ios/browser/features.h
@@ -22,6 +22,9 @@ extern const base::Feature kRestoreGaiaCookiesIfDeleted;
// for the existence of Gaia cookies for google.com.
extern const char kDelayThresholdMinutesToUpdateGaiaCookie[];
+// Feature controlling whether to use full username in sign-in notifications.
+extern const base::Feature kSigninNotificationInfobarUsernameInTitle;
+
} // namespace signin
#endif // COMPONENTS_SIGNIN_IOS_BROWSER_FEATURES_H_
diff --git a/chromium/components/signin/ios/browser/manage_accounts_delegate.h b/chromium/components/signin/ios/browser/manage_accounts_delegate.h
index 9e6f010fe60..763d93944cc 100644
--- a/chromium/components/signin/ios/browser/manage_accounts_delegate.h
+++ b/chromium/components/signin/ios/browser/manage_accounts_delegate.h
@@ -9,6 +9,10 @@ class GURL;
@protocol ManageAccountsDelegate<NSObject>
+// Called when Gaia cookies have been regenerated for a specific user sign-in.
+// This occurs when a SAPISID cookie has been deleted by the operating system.
+- (void)onRestoreGaiaCookies;
+
// Called when the user taps on a manage accounts button in a Google web
// property.
- (void)onManageAccounts;
diff --git a/chromium/components/signin/public/base/persistent_repeating_timer.cc b/chromium/components/signin/public/base/persistent_repeating_timer.cc
index cb5dada2c9b..2cff12207e2 100644
--- a/chromium/components/signin/public/base/persistent_repeating_timer.cc
+++ b/chromium/components/signin/public/base/persistent_repeating_timer.cc
@@ -30,8 +30,8 @@ void PersistentRepeatingTimer::Start() {
OnTimerFired();
} else {
timer_.Start(FROM_HERE, delay_ - time_since_update,
- base::Bind(&PersistentRepeatingTimer::OnTimerFired,
- base::Unretained(this)));
+ base::BindRepeating(&PersistentRepeatingTimer::OnTimerFired,
+ base::Unretained(this)));
}
DCHECK(timer_.IsRunning());
}
diff --git a/chromium/components/signin/public/base/persistent_repeating_timer_unittest.cc b/chromium/components/signin/public/base/persistent_repeating_timer_unittest.cc
index 29783bde3be..5f0a5779ad1 100644
--- a/chromium/components/signin/public/base/persistent_repeating_timer_unittest.cc
+++ b/chromium/components/signin/public/base/persistent_repeating_timer_unittest.cc
@@ -42,8 +42,8 @@ class PersistentRepeatingTimerTest : public ::testing::Test {
TEST_F(PersistentRepeatingTimerTest, MissingPref) {
PersistentRepeatingTimer timer(
&pref_service_, kLastUpdatedTimePref, kTestDelay,
- base::Bind(&PersistentRepeatingTimerTest::RunTask,
- base::Unretained(this)));
+ base::BindRepeating(&PersistentRepeatingTimerTest::RunTask,
+ base::Unretained(this)));
CheckCallCount(0);
// The task is run immediately on start.
@@ -62,8 +62,8 @@ TEST_F(PersistentRepeatingTimerTest, MissingPref) {
TEST_F(PersistentRepeatingTimerTest, MultipleStarts) {
PersistentRepeatingTimer timer(
&pref_service_, kLastUpdatedTimePref, kTestDelay,
- base::Bind(&PersistentRepeatingTimerTest::RunTask,
- base::Unretained(this)));
+ base::BindRepeating(&PersistentRepeatingTimerTest::RunTask,
+ base::Unretained(this)));
CheckCallCount(0);
// The task is run immediately on start.
@@ -91,8 +91,8 @@ TEST_F(PersistentRepeatingTimerTest, RecentPref) {
PersistentRepeatingTimer timer(
&pref_service_, kLastUpdatedTimePref, kTestDelay,
- base::Bind(&PersistentRepeatingTimerTest::RunTask,
- base::Unretained(this)));
+ base::BindRepeating(&PersistentRepeatingTimerTest::RunTask,
+ base::Unretained(this)));
CheckCallCount(0);
// The task is NOT run immediately on start.
@@ -118,8 +118,8 @@ TEST_F(PersistentRepeatingTimerTest, OldPref) {
PersistentRepeatingTimer timer(
&pref_service_, kLastUpdatedTimePref, kTestDelay,
- base::Bind(&PersistentRepeatingTimerTest::RunTask,
- base::Unretained(this)));
+ base::BindRepeating(&PersistentRepeatingTimerTest::RunTask,
+ base::Unretained(this)));
CheckCallCount(0);
// The task is run immediately on start.
diff --git a/chromium/components/signin/public/identity_manager/access_token_fetcher.cc b/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
index 89baf10025d..dca31a46ffb 100644
--- a/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
+++ b/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
@@ -93,7 +93,7 @@ AccessTokenFetcher::AccessTokenFetcher(
// Start observing the IdentityManager. This observer will be removed either
// when a refresh token is obtained and an access token request is started or
// when this object is destroyed.
- token_service_observer_.Add(token_service_);
+ token_service_observation_.Observe(token_service_);
}
AccessTokenFetcher::~AccessTokenFetcher() {}
@@ -109,7 +109,7 @@ void AccessTokenFetcher::StartAccessTokenRequest() {
// By the time of starting an access token request, we should no longer be
// listening for signin-related events.
- DCHECK(!token_service_observer_.IsObserving(token_service_));
+ DCHECK(!token_service_observation_.IsObservingSource(token_service_));
// Note: We might get here even in cases where we know that there's no refresh
// token. We're requesting an access token anyway, so that the token service
@@ -144,7 +144,8 @@ void AccessTokenFetcher::OnRefreshTokenAvailable(
if (!IsRefreshTokenAvailable())
return;
- token_service_observer_.Remove(token_service_);
+ DCHECK(token_service_observation_.IsObservingSource(token_service_));
+ token_service_observation_.RemoveObservation();
StartAccessTokenRequest();
}
diff --git a/chromium/components/signin/public/identity_manager/access_token_fetcher.h b/chromium/components/signin/public/identity_manager/access_token_fetcher.h
index fdfecbe4232..3e218499025 100644
--- a/chromium/components/signin/public/identity_manager/access_token_fetcher.h
+++ b/chromium/components/signin/public/identity_manager/access_token_fetcher.h
@@ -11,7 +11,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h"
#include "components/signin/public/identity_manager/scope_set.h"
@@ -245,8 +245,9 @@ class AccessTokenFetcher : public ProfileOAuth2TokenServiceObserver,
// contract.
TokenCallback callback_;
- ScopedObserver<ProfileOAuth2TokenService, ProfileOAuth2TokenServiceObserver>
- token_service_observer_{this};
+ base::ScopedObservation<ProfileOAuth2TokenService,
+ ProfileOAuth2TokenServiceObserver>
+ token_service_observation_{this};
std::unique_ptr<OAuth2AccessTokenManager::Request> access_token_request_;
diff --git a/chromium/components/signin/public/identity_manager/account_info.cc b/chromium/components/signin/public/identity_manager/account_info.cc
index a8e8c294b78..be051ee5d18 100644
--- a/chromium/components/signin/public/identity_manager/account_info.cc
+++ b/chromium/components/signin/public/identity_manager/account_info.cc
@@ -149,7 +149,7 @@ base::android::ScopedJavaLocalRef<jobject> ConvertToJavaAccountInfo(
base::android::ConvertUTF8ToJavaString(env, account_info.gaia),
avatar_image.IsEmpty()
? nullptr
- : gfx::ConvertToJavaBitmap(avatar_image.AsImageSkia().bitmap()));
+ : gfx::ConvertToJavaBitmap(*avatar_image.AsImageSkia().bitmap()));
}
base::android::ScopedJavaLocalRef<jobject> ConvertToJavaCoreAccountId(
diff --git a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
index 7dc08ffac85..216f9e5a4f3 100644
--- a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
diff --git a/chromium/components/signin/public/identity_manager/diagnostics_provider_unittest.cc b/chromium/components/signin/public/identity_manager/diagnostics_provider_unittest.cc
index b87fa74d5bc..93b64a925c4 100644
--- a/chromium/components/signin/public/identity_manager/diagnostics_provider_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/diagnostics_provider_unittest.cc
@@ -4,7 +4,7 @@
#include "components/signin/internal/identity_manager/diagnostics_provider_impl.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/test/task_environment.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
diff --git a/chromium/components/signin/public/identity_manager/identity_manager.cc b/chromium/components/signin/public/identity_manager/identity_manager.cc
index b39d993c80e..7a293d0e1d0 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager.cc
@@ -54,8 +54,8 @@ IdentityManager::IdentityManager(IdentityManager::InitParameters&& parameters)
DCHECK(account_fetcher_service_);
DCHECK(diagnostics_provider_);
- primary_account_manager_observer_.Add(primary_account_manager_.get());
- token_service_observer_.Add(token_service_.get());
+ primary_account_manager_observation_.Observe(primary_account_manager_.get());
+ token_service_observation_.Observe(token_service_.get());
token_service_->AddAccessTokenDiagnosticsObserver(this);
// IdentityManager owns the ATS, GCMS and PO2TS instances and will outlive
@@ -125,10 +125,7 @@ CoreAccountId IdentityManager::GetPrimaryAccountId(ConsentLevel consent) const {
}
bool IdentityManager::HasPrimaryAccount(ConsentLevel consent) const {
- if (consent == ConsentLevel::kNotRequired) {
- return primary_account_manager_->HasUnconsentedPrimaryAccount();
- }
- return primary_account_manager_->IsAuthenticated();
+ return primary_account_manager_->HasPrimaryAccount(consent);
}
std::unique_ptr<AccessTokenFetcher>
@@ -328,11 +325,11 @@ DeviceAccountsSynchronizer* IdentityManager::GetDeviceAccountsSynchronizer() {
}
void IdentityManager::AddDiagnosticsObserver(DiagnosticsObserver* observer) {
- diagnostics_observer_list_.AddObserver(observer);
+ diagnostics_observation_list_.AddObserver(observer);
}
void IdentityManager::RemoveDiagnosticsObserver(DiagnosticsObserver* observer) {
- diagnostics_observer_list_.RemoveObserver(observer);
+ diagnostics_observation_list_.RemoveObserver(observer);
}
void IdentityManager::OnNetworkInitialized() {
@@ -587,7 +584,7 @@ void IdentityManager::OnGaiaCookieDeletedByUserAction() {
void IdentityManager::OnAccessTokenRequested(const CoreAccountId& account_id,
const std::string& consumer_id,
const ScopeSet& scopes) {
- for (auto& observer : diagnostics_observer_list_) {
+ for (auto& observer : diagnostics_observation_list_) {
observer.OnAccessTokenRequested(account_id, consumer_id, scopes);
}
}
@@ -598,14 +595,14 @@ void IdentityManager::OnFetchAccessTokenComplete(
const ScopeSet& scopes,
GoogleServiceAuthError error,
base::Time expiration_time) {
- for (auto& observer : diagnostics_observer_list_)
+ for (auto& observer : diagnostics_observation_list_)
observer.OnAccessTokenRequestCompleted(account_id, consumer_id, scopes,
error, expiration_time);
}
void IdentityManager::OnAccessTokenRemoved(const CoreAccountId& account_id,
const ScopeSet& scopes) {
- for (auto& observer : diagnostics_observer_list_)
+ for (auto& observer : diagnostics_observation_list_)
observer.OnAccessTokenRemovedFromCache(account_id, scopes);
}
@@ -613,7 +610,7 @@ void IdentityManager::OnRefreshTokenAvailableFromSource(
const CoreAccountId& account_id,
bool is_refresh_token_valid,
const std::string& source) {
- for (auto& observer : diagnostics_observer_list_)
+ for (auto& observer : diagnostics_observation_list_)
observer.OnRefreshTokenUpdatedForAccountFromSource(
account_id, is_refresh_token_valid, source);
}
@@ -621,7 +618,7 @@ void IdentityManager::OnRefreshTokenAvailableFromSource(
void IdentityManager::OnRefreshTokenRevokedFromSource(
const CoreAccountId& account_id,
const std::string& source) {
- for (auto& observer : diagnostics_observer_list_)
+ for (auto& observer : diagnostics_observation_list_)
observer.OnRefreshTokenRemovedForAccountFromSource(account_id, source);
}
diff --git a/chromium/components/signin/public/identity_manager/identity_manager.h b/chromium/components/signin/public/identity_manager/identity_manager.h
index 6afe788e283..d2e68f4ee14 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager.h
+++ b/chromium/components/signin/public/identity_manager/identity_manager.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/internal/identity_manager/primary_account_manager.h"
@@ -682,16 +682,18 @@ class IdentityManager : public KeyedService,
std::unique_ptr<DiagnosticsProvider> diagnostics_provider_;
// Scoped observers.
- ScopedObserver<PrimaryAccountManager, PrimaryAccountManager::Observer>
- primary_account_manager_observer_{this};
- ScopedObserver<ProfileOAuth2TokenService, ProfileOAuth2TokenServiceObserver>
- token_service_observer_{this};
+ base::ScopedObservation<PrimaryAccountManager,
+ PrimaryAccountManager::Observer>
+ primary_account_manager_observation_{this};
+ base::ScopedObservation<ProfileOAuth2TokenService,
+ ProfileOAuth2TokenServiceObserver>
+ token_service_observation_{this};
// Lists of observers.
// Makes sure lists are empty on destruction.
base::ObserverList<Observer, true>::Unchecked observer_list_;
base::ObserverList<DiagnosticsObserver, true>::Unchecked
- diagnostics_observer_list_;
+ diagnostics_observation_list_;
#if defined(OS_ANDROID)
// Java-side IdentityManager object.
diff --git a/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc b/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
index ff1ec177c42..34bb3071032 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -13,9 +13,9 @@
#include "base/containers/flat_set.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/stl_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/image_fetcher/core/fake_image_decoder.h"
@@ -61,6 +61,7 @@
#if defined(OS_CHROMEOS)
#include "chromeos/components/account_manager/account_manager.h"
#include "chromeos/components/account_manager/account_manager_factory.h"
+#include "components/account_manager_core/account.h"
#include "components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.h"
#endif
@@ -307,8 +308,8 @@ class IdentityManagerTest : public testing::Test {
std::string token) {
#if defined(OS_CHROMEOS)
identity_manager()->GetChromeOSAccountManager()->UpsertAccount(
- chromeos::AccountManager::AccountKey{
- gaia_id, chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA},
+ ::account_manager::AccountKey{gaia_id,
+ account_manager::AccountType::kGaia},
email, token);
#else
token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -318,9 +319,8 @@ class IdentityManagerTest : public testing::Test {
void RevokeCredentials(const CoreAccountId& account_id, std::string gaia_id) {
#if defined(OS_CHROMEOS)
identity_manager()->GetChromeOSAccountManager()->RemoveAccount(
- chromeos::AccountManager::AccountKey{
- gaia_id,
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA});
+ ::account_manager::AccountKey{gaia_id,
+ account_manager::AccountType::kGaia});
#else
token_service()->RevokeCredentials(account_id);
#endif
@@ -2054,7 +2054,7 @@ TEST_F(IdentityManagerTest, CallbackSentOnAccountsCookieDeletedByUserAction) {
net::CanonicalCookie cookie(
"SAPISID", std::string(), ".google.com", "/", base::Time(), base::Time(),
base::Time(), /*secure=*/true, false, net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_DEFAULT);
+ net::COOKIE_PRIORITY_DEFAULT, false);
SimulateCookieDeletedByUser(identity_manager()->GetGaiaCookieManagerService(),
cookie);
run_loop.Run();
@@ -2086,7 +2086,7 @@ TEST_F(IdentityManagerTest, OnNetworkInitialized) {
net::CanonicalCookie cookie(
"SAPISID", std::string(), ".google.com", "/", base::Time(), base::Time(),
base::Time(), /*secure=*/true, false, net::CookieSameSite::NO_RESTRICTION,
- net::COOKIE_PRIORITY_DEFAULT);
+ net::COOKIE_PRIORITY_DEFAULT, false);
test_cookie_manager_ptr->DispatchCookieChange(net::CookieChangeInfo(
cookie, net::CookieAccessResult(), net::CookieChangeCause::EXPLICIT));
run_loop.Run();
diff --git a/chromium/components/signin/public/identity_manager/identity_test_utils.cc b/chromium/components/signin/public/identity_manager/identity_test_utils.cc
index 69867756b5f..e440df0a51c 100644
--- a/chromium/components/signin/public/identity_manager/identity_test_utils.cc
+++ b/chromium/components/signin/public/identity_manager/identity_test_utils.cc
@@ -23,6 +23,7 @@
#if defined(OS_CHROMEOS)
#include "chromeos/components/account_manager/account_manager.h"
+#include "components/account_manager_core/account.h"
#endif
#if defined(OS_ANDROID)
@@ -84,9 +85,8 @@ void UpdateRefreshTokenForAccount(
DCHECK(account_manager);
account_manager->UpsertAccount(
- chromeos::AccountManager::AccountKey{
- account_info.gaia,
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA},
+ account_manager::AccountKey{account_info.gaia,
+ account_manager::AccountType::kGaia},
account_info.email, new_token);
#else
token_service->UpdateCredentials(account_id, new_token);
@@ -117,7 +117,7 @@ CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
DCHECK(!identity_manager->HasPrimaryAccount());
PrimaryAccountManager* primary_account_manager =
identity_manager->GetPrimaryAccountManager();
- DCHECK(!primary_account_manager->IsAuthenticated());
+ DCHECK(!primary_account_manager->HasPrimaryAccount(ConsentLevel::kSync));
AccountInfo account_info =
EnsureAccountExists(identity_manager->GetAccountTrackerService(), email);
@@ -125,7 +125,7 @@ CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
primary_account_manager->SignIn(email);
- DCHECK(primary_account_manager->IsAuthenticated());
+ DCHECK(primary_account_manager->HasPrimaryAccount(ConsentLevel::kSync));
DCHECK(identity_manager->HasPrimaryAccount());
return identity_manager->GetPrimaryAccountInfo();
}
@@ -336,9 +336,8 @@ void RemoveRefreshTokenForAccount(IdentityManager* identity_manager,
identity_manager->GetAccountTrackerService()->GetAccountInfo(account_id);
identity_manager->GetChromeOSAccountManager()->RemoveAccount(
- chromeos::AccountManager::AccountKey{
- account_info.gaia,
- chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA});
+ account_manager::AccountKey{account_info.gaia,
+ account_manager::AccountType::kGaia});
#else
identity_manager->GetTokenService()->RevokeCredentials(account_id);
#endif
diff --git a/chromium/components/signin/public/identity_manager/identity_utils.cc b/chromium/components/signin/public/identity_manager/identity_utils.cc
index 1c414e20e5d..014d6746d95 100644
--- a/chromium/components/signin/public/identity_manager/identity_utils.cc
+++ b/chromium/components/signin/public/identity_manager/identity_utils.cc
@@ -33,7 +33,7 @@ bool IsUsernameAllowedByPattern(base::StringPiece username,
// See if the username matches the policy-provided pattern.
UErrorCode status = U_ZERO_ERROR;
- const icu::UnicodeString icu_pattern(FALSE, utf16_pattern.data(),
+ const icu::UnicodeString icu_pattern(false, utf16_pattern.data(),
utf16_pattern.length());
icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status);
if (!U_SUCCESS(status)) {
diff --git a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.cc b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.cc
index 7fe9fcb3431..fdee5db20aa 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.cc
+++ b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.cc
@@ -36,7 +36,7 @@ PrimaryAccountAccessTokenFetcher::PrimaryAccountAccessTokenFetcher(
// Start observing the IdentityManager. This observer will be removed either
// when credentials are obtained and an access token request is started or
// when this object is destroyed.
- identity_manager_observer_.Add(identity_manager_);
+ identity_manager_observation_.Observe(identity_manager_);
}
PrimaryAccountAccessTokenFetcher::~PrimaryAccountAccessTokenFetcher() = default;
@@ -56,7 +56,7 @@ void PrimaryAccountAccessTokenFetcher::StartAccessTokenRequest() {
// By the time of starting an access token request, we should no longer be
// listening for signin-related events.
- DCHECK(!identity_manager_observer_.IsObserving(identity_manager_));
+ DCHECK(!identity_manager_observation_.IsObservingSource(identity_manager_));
// Note: We might get here even in cases where we know that there's no refresh
// token. We're requesting an access token anyway, so that the token service
@@ -110,7 +110,8 @@ void PrimaryAccountAccessTokenFetcher::ProcessSigninStateChange() {
if (!AreCredentialsAvailable())
return;
- identity_manager_observer_.Remove(identity_manager_);
+ DCHECK(identity_manager_observation_.IsObservingSource(identity_manager_));
+ identity_manager_observation_.RemoveObservation();
StartAccessTokenRequest();
}
diff --git a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.h b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.h
index 66e6472fa64..36d37f916ac 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.h
+++ b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "components/signin/public/identity_manager/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h"
@@ -202,8 +202,8 @@ class PrimaryAccountAccessTokenFetcher : public IdentityManager::Observer {
// code.
AccessTokenFetcher::TokenCallback callback_;
- ScopedObserver<IdentityManager, IdentityManager::Observer>
- identity_manager_observer_{this};
+ base::ScopedObservation<IdentityManager, IdentityManager::Observer>
+ identity_manager_observation_{this};
// Internal fetcher that does the actual access token request.
std::unique_ptr<AccessTokenFetcher> access_token_fetcher_;
diff --git a/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc b/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
index 1fd559be869..11784e17738 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/containers/flat_set.h"
#include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/signin/public/base/signin_metrics.h"
@@ -63,10 +63,10 @@ class ClearPrimaryAccountTestObserver
RefreshTokenRemovedCallback on_refresh_token_removed)
: on_primary_account_cleared_(std::move(on_primary_account_cleared)),
on_refresh_token_removed_(std::move(on_refresh_token_removed)),
- scoped_observer_(this) {
+ scoped_observation_(this) {
DCHECK(on_primary_account_cleared_);
DCHECK(on_refresh_token_removed_);
- scoped_observer_.Add(identity_manager);
+ scoped_observation_.Observe(identity_manager);
}
// signin::IdentityManager::Observer implementation.
@@ -82,8 +82,9 @@ class ClearPrimaryAccountTestObserver
private:
PrimaryAccountClearedCallback on_primary_account_cleared_;
RefreshTokenRemovedCallback on_refresh_token_removed_;
- ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
- scoped_observer_;
+ base::ScopedObservation<signin::IdentityManager,
+ signin::IdentityManager::Observer>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(ClearPrimaryAccountTestObserver);
};
@@ -166,7 +167,7 @@ void RunClearPrimaryAccountTest(
},
&observed_removals);
- ClearPrimaryAccountTestObserver scoped_observer(
+ ClearPrimaryAccountTestObserver scoped_observation(
identity_manager, primary_account_cleared_callback,
refresh_token_removed_callback);
diff --git a/chromium/components/site_engagement/OWNERS b/chromium/components/site_engagement/OWNERS
new file mode 100644
index 00000000000..123948b6d3b
--- /dev/null
+++ b/chromium/components/site_engagement/OWNERS
@@ -0,0 +1,6 @@
+benwells@chromium.org
+calamity@chromium.org
+dominickn@chromium.org
+raymes@chromium.org
+
+# COMPONENT: Internals>Permissions>SiteEngagement
diff --git a/chromium/components/site_engagement/README b/chromium/components/site_engagement/README
new file mode 100644
index 00000000000..b25712c0872
--- /dev/null
+++ b/chromium/components/site_engagement/README
@@ -0,0 +1,7 @@
+This directory contains shared code for determining engaged sites.
+
+Site engagement will be a layered component (https://www.chromium.org/developers/design-documents/layered-components-design) with the following structure:
+
+- core/: shared code with no //chrome or //content dependencies
+- content/: driver for the shared code that depends on the content layer
+- ios/: driver for the shared code based on src/ios \ No newline at end of file
diff --git a/chromium/components/site_engagement/core/mojom/BUILD.gn b/chromium/components/site_engagement/core/mojom/BUILD.gn
new file mode 100644
index 00000000000..591504480f9
--- /dev/null
+++ b/chromium/components/site_engagement/core/mojom/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+ sources = [ "site_engagement_details.mojom" ]
+ public_deps = [ "//url/mojom:url_mojom_gurl" ]
+ webui_module_path = "/"
+}
diff --git a/chromium/components/site_engagement/core/mojom/OWNERS b/chromium/components/site_engagement/core/mojom/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/components/site_engagement/core/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/site_engagement/core/mojom/site_engagement_details.mojom b/chromium/components/site_engagement/core/mojom/site_engagement_details.mojom
new file mode 100644
index 00000000000..42549b019ea
--- /dev/null
+++ b/chromium/components/site_engagement/core/mojom/site_engagement_details.mojom
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mojom;
+
+import "url/mojom/url.mojom";
+
+struct SiteEngagementDetails {
+ url.mojom.Url origin;
+ double total_score;
+
+ // Details of the components which make up |score|. Note that these may
+ // sum to a value greater than |score| if it exceeds the maximum.
+ double base_score;
+ double installed_bonus;
+};
+
+interface SiteEngagementDetailsProvider {
+ GetSiteEngagementDetails() => (array<SiteEngagementDetails> info);
+ SetSiteEngagementBaseScoreForUrl(url.mojom.Url url, double score);
+};
diff --git a/chromium/components/site_isolation/BUILD.gn b/chromium/components/site_isolation/BUILD.gn
index 6e877b2c355..ee7127a3ab2 100644
--- a/chromium/components/site_isolation/BUILD.gn
+++ b/chromium/components/site_isolation/BUILD.gn
@@ -6,8 +6,10 @@ import("//build/buildflag_header.gni")
import("//build/config/chrome_build.gni")
declare_args() {
- # Normally, only official Chrome Android builds will use a Google-internal
- # list of isolated origins defined below.
+ # Normally, only Google Chrome Android and Fuchsia WebEngine builds will use
+ # a Google-internal list of isolated origins defined below.
+ # If other Fuchsia embedders are added, the associated logic may need to be
+ # updated. See crbug.com/1179087.
#
# You can set the variable 'use_internal_isolated_origins' to true to use this
# Google-internal list of isolated origins even in a developer build. Setting
@@ -15,7 +17,7 @@ declare_args() {
# internal file is missing.
use_internal_isolated_origins = false
- if (is_chrome_branded && is_android) {
+ if (is_chrome_branded && (is_android || is_fuchsia)) {
use_internal_isolated_origins = true
}
}
diff --git a/chromium/components/site_isolation/site_isolation_policy.cc b/chromium/components/site_isolation/site_isolation_policy.cc
index 9a91d3034b0..e9e300cfebd 100644
--- a/chromium/components/site_isolation/site_isolation_policy.cc
+++ b/chromium/components/site_isolation/site_isolation_policy.cc
@@ -130,4 +130,19 @@ void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(
"SiteIsolation.SavedUserTriggeredIsolatedOrigins.Size", origins.size());
}
+// static
+bool SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs() {
+ // We only create pdf compositor client and use pdf compositor service when
+ // one of the site isolation modes that forces OOPIFs is on. This includes
+ // full site isolation on desktop, password-triggered site isolation on
+ // Android for high-memory devices, and/or isolated origins specified via
+ // command line, enterprise policy, or field trials.
+ //
+ // TODO(weili, thestig): Eventually, we should remove this check and use pdf
+ // compositor service by default for printing.
+ return content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites() ||
+ IsIsolationForPasswordSitesEnabled() ||
+ content::SiteIsolationPolicy::AreIsolatedOriginsEnabled();
+}
+
} // namespace site_isolation
diff --git a/chromium/components/site_isolation/site_isolation_policy.h b/chromium/components/site_isolation/site_isolation_policy.h
index ade65a884d6..2a56331cb09 100644
--- a/chromium/components/site_isolation/site_isolation_policy.h
+++ b/chromium/components/site_isolation/site_isolation_policy.h
@@ -45,6 +45,10 @@ class SiteIsolationPolicy {
// memory threshold.
static bool ShouldDisableSiteIsolationDueToMemoryThreshold();
+ // Returns true if the PDF compositor should be enabled to allow out-of-
+ // process iframes (OOPIF's) to print properly.
+ static bool ShouldPdfCompositorBeEnabledForOopifs();
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SiteIsolationPolicy);
};
diff --git a/chromium/components/site_isolation/site_isolation_policy_unittest.cc b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
index 47d16fddefb..c77a6989461 100644
--- a/chromium/components/site_isolation/site_isolation_policy_unittest.cc
+++ b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
@@ -27,8 +27,11 @@
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
+#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -935,4 +938,119 @@ TEST_F(BuiltInIsolatedOriginsTest, NotAppliedWithFullSiteIsolation) {
}
#endif
+// Helper class for tests that use header-based opt-in origin isolation and
+// simulate a 512MB device, while turning off strict site isolation. This is
+// used for checking how opt-in origin isolation behaves with site isolation
+// memory thresholds.
+class OptInOriginIsolationPolicyTest : public BaseSiteIsolationTest {
+ public:
+ OptInOriginIsolationPolicyTest() = default;
+
+ protected:
+ void SetUp() override {
+ // Simulate a 512MB device.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableLowEndDeviceMode);
+ EXPECT_EQ(512, base::SysInfo::AmountOfPhysicalMemoryMB());
+ // Turn off strict site isolation. This simulates what would happen on
+ // Android.
+ SetEnableStrictSiteIsolation(false);
+ // Enable Origin-Agent-Cluster header.
+ feature_list_.InitAndEnableFeature(::features::kOriginIsolationHeader);
+ BaseSiteIsolationTest::SetUp();
+ }
+
+ content::BrowserContext* browser_context() { return &browser_context_; }
+
+ private:
+ content::BrowserTaskEnvironment task_environment_;
+ content::TestBrowserContext browser_context_;
+ content::RenderViewHostTestEnabler rvh_test_enabler_;
+
+ base::test::ScopedFeatureList feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(OptInOriginIsolationPolicyTest);
+};
+
+// Check that opt-in origin isolation is not applied when below the memory
+// threshold (and when full site isolation is not used).
+TEST_F(OptInOriginIsolationPolicyTest, BelowThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Define a memory threshold at 768MB. This is above the 512MB of physical
+ // memory that this test simulates, so opt-in origin isolation should be
+ // disabled.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "768"}});
+
+ EXPECT_FALSE(content::SiteIsolationPolicy::IsOptInOriginIsolationEnabled());
+
+ // Simulate a navigation to a URL that serves an Origin-Agent-Cluster header.
+ // Since we're outside of content/, it's difficult to verify that internal
+ // ChildProcessSecurityPolicy state wasn't changed by opt-in origin
+ // isolation. Instead, verify that the resulting SiteInstance doesn't
+ // require a dedicated process. This should be the end result, and it
+ // implicitly checks that ChildProcessSecurityPolicy::IsIsolatedOrigin()
+ // doesn't return true for this origin.
+ const GURL kUrl("https://www.google.com/");
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(browser_context(),
+ nullptr);
+ std::unique_ptr<content::NavigationSimulator> simulator =
+ content::NavigationSimulator::CreateBrowserInitiated(kUrl,
+ web_contents.get());
+ simulator->Start();
+ auto response_headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+ response_headers->SetHeader("Origin-Agent-Cluster", "?1");
+ simulator->SetResponseHeaders(response_headers);
+ simulator->Commit();
+
+ content::SiteInstance* site_instance =
+ simulator->GetFinalRenderFrameHost()->GetSiteInstance();
+ EXPECT_FALSE(site_instance->RequiresDedicatedProcess());
+}
+
+// Counterpart to the test above, but verifies that opt-in origin isolation is
+// enabled when above the memory threshold.
+TEST_F(OptInOriginIsolationPolicyTest, AboveThreshold) {
+ if (ShouldSkipBecauseOfConflictingCommandLineSwitches())
+ return;
+
+ // Define a memory threshold at 128MB. This is below the 512MB of physical
+ // memory that this test simulates, so opt-in origin isolation should be
+ // enabled.
+ base::test::ScopedFeatureList memory_feature;
+ memory_feature.InitAndEnableFeatureWithParameters(
+ features::kSitePerProcessOnlyForHighMemoryClients,
+ {{features::kSitePerProcessOnlyForHighMemoryClientsParamName, "128"}});
+
+ EXPECT_TRUE(content::SiteIsolationPolicy::IsOptInOriginIsolationEnabled());
+
+ // Simulate a navigation to a URL that serves an Origin-Agent-Cluster header.
+ // Verify that the resulting SiteInstance requires a dedicated process. Note
+ // that this test disables strict site isolation, so this would happen only
+ // if opt-in isolation took place.
+ const GURL kUrl("https://www.google.com/");
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(browser_context(),
+ nullptr);
+ std::unique_ptr<content::NavigationSimulator> simulator =
+ content::NavigationSimulator::CreateBrowserInitiated(kUrl,
+ web_contents.get());
+ simulator->Start();
+ auto response_headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+ response_headers->SetHeader("Origin-Agent-Cluster", "?1");
+ simulator->SetResponseHeaders(response_headers);
+ simulator->Commit();
+
+ content::SiteInstance* site_instance =
+ simulator->GetFinalRenderFrameHost()->GetSiteInstance();
+ EXPECT_TRUE(site_instance->RequiresDedicatedProcess());
+}
+
} // namespace site_isolation
diff --git a/chromium/components/speech/BUILD.gn b/chromium/components/speech/BUILD.gn
index 30148e5ce03..4ae88cb8dae 100644
--- a/chromium/components/speech/BUILD.gn
+++ b/chromium/components/speech/BUILD.gn
@@ -4,6 +4,8 @@
source_set("speech") {
sources = [
+ "chunked_byte_buffer.cc",
+ "chunked_byte_buffer.h",
"downstream_loader.cc",
"downstream_loader.h",
"downstream_loader_client.h",
@@ -20,3 +22,12 @@ source_set("speech") {
"//services/network/public/mojom",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [ "chunked_byte_buffer_unittest.cc" ]
+ deps = [
+ ":speech",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/speech/chunked_byte_buffer.cc b/chromium/components/speech/chunked_byte_buffer.cc
new file mode 100644
index 00000000000..ab65c83ed3c
--- /dev/null
+++ b/chromium/components/speech/chunked_byte_buffer.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 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/speech/chunked_byte_buffer.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/big_endian.h"
+#include "base/check_op.h"
+#include "base/lazy_instance.h"
+
+namespace {
+
+static const size_t kHeaderLength = sizeof(uint32_t);
+
+static_assert(sizeof(size_t) >= kHeaderLength,
+ "chunked byte buffer not supported on this architecture");
+
+} // namespace
+
+namespace speech {
+
+ChunkedByteBuffer::ChunkedByteBuffer()
+ : partial_chunk_(new Chunk()), total_bytes_stored_(0) {}
+
+ChunkedByteBuffer::~ChunkedByteBuffer() {
+ Clear();
+}
+
+void ChunkedByteBuffer::Append(const uint8_t* start, size_t length) {
+ size_t remaining_bytes = length;
+ const uint8_t* next_data = start;
+
+ while (remaining_bytes > 0) {
+ DCHECK(partial_chunk_ != nullptr);
+ size_t insert_length = 0;
+ bool header_completed = false;
+ bool content_completed = false;
+ std::vector<uint8_t>* insert_target;
+
+ if (partial_chunk_->header.size() < kHeaderLength) {
+ const size_t bytes_to_complete_header =
+ kHeaderLength - partial_chunk_->header.size();
+ insert_length = std::min(bytes_to_complete_header, remaining_bytes);
+ insert_target = &partial_chunk_->header;
+ header_completed = (remaining_bytes >= bytes_to_complete_header);
+ } else {
+ DCHECK_LT(partial_chunk_->content->size(),
+ partial_chunk_->ExpectedContentLength());
+ const size_t bytes_to_complete_chunk =
+ partial_chunk_->ExpectedContentLength() -
+ partial_chunk_->content->size();
+ insert_length = std::min(bytes_to_complete_chunk, remaining_bytes);
+ insert_target = partial_chunk_->content.get();
+ content_completed = (remaining_bytes >= bytes_to_complete_chunk);
+ }
+
+ DCHECK_GT(insert_length, 0U);
+ DCHECK_LE(insert_length, remaining_bytes);
+ DCHECK_LE(next_data + insert_length, start + length);
+ insert_target->insert(insert_target->end(), next_data,
+ next_data + insert_length);
+ next_data += insert_length;
+ remaining_bytes -= insert_length;
+
+ if (header_completed) {
+ DCHECK_EQ(partial_chunk_->header.size(), kHeaderLength);
+ if (partial_chunk_->ExpectedContentLength() == 0) {
+ // Handle zero-byte chunks.
+ chunks_.push_back(std::move(partial_chunk_));
+ partial_chunk_.reset(new Chunk());
+ } else {
+ partial_chunk_->content->reserve(
+ partial_chunk_->ExpectedContentLength());
+ }
+ } else if (content_completed) {
+ DCHECK_EQ(partial_chunk_->content->size(),
+ partial_chunk_->ExpectedContentLength());
+ chunks_.push_back(std::move(partial_chunk_));
+ partial_chunk_.reset(new Chunk());
+ }
+ }
+ DCHECK_EQ(next_data, start + length);
+ total_bytes_stored_ += length;
+}
+
+void ChunkedByteBuffer::Append(base::StringPiece string) {
+ Append(reinterpret_cast<const uint8_t*>(string.data()), string.size());
+}
+
+bool ChunkedByteBuffer::HasChunks() const {
+ return !chunks_.empty();
+}
+
+std::unique_ptr<std::vector<uint8_t>> ChunkedByteBuffer::PopChunk() {
+ if (chunks_.empty())
+ return nullptr;
+ std::unique_ptr<Chunk> chunk = std::move(*chunks_.begin());
+ chunks_.erase(chunks_.begin());
+ DCHECK_EQ(chunk->header.size(), kHeaderLength);
+ DCHECK_EQ(chunk->content->size(), chunk->ExpectedContentLength());
+ total_bytes_stored_ -= chunk->content->size();
+ total_bytes_stored_ -= kHeaderLength;
+ return std::move(chunk->content);
+}
+
+void ChunkedByteBuffer::Clear() {
+ chunks_.clear();
+ partial_chunk_.reset(new Chunk());
+ total_bytes_stored_ = 0;
+}
+
+ChunkedByteBuffer::Chunk::Chunk() : content(new std::vector<uint8_t>()) {}
+
+ChunkedByteBuffer::Chunk::~Chunk() {}
+
+size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
+ DCHECK_EQ(header.size(), kHeaderLength);
+ uint32_t content_length = 0;
+ base::ReadBigEndian(reinterpret_cast<const char*>(&header[0]),
+ &content_length);
+ return static_cast<size_t>(content_length);
+}
+
+} // namespace speech
diff --git a/chromium/components/speech/chunked_byte_buffer.h b/chromium/components/speech/chunked_byte_buffer.h
new file mode 100644
index 00000000000..dddc2ee26eb
--- /dev/null
+++ b/chromium/components/speech/chunked_byte_buffer.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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_SPEECH_CHUNKED_BYTE_BUFFER_H_
+#define COMPONENTS_SPEECH_CHUNKED_BYTE_BUFFER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace speech {
+
+// Models a chunk-oriented byte buffer. The term chunk is herein defined as an
+// arbitrary sequence of bytes that is preceeded by N header bytes, indicating
+// its size. Data may be appended to the buffer with no particular respect of
+// chunks boundaries. However, chunks can be extracted (FIFO) only when their
+// content (according to their header) is fully available in the buffer.
+// The current implementation support only 4 byte Big Endian headers.
+// Empty chunks (i.e. the sequence 00 00 00 00) are NOT allowed.
+//
+// E.g. 00 00 00 04 xx xx xx xx 00 00 00 02 yy yy 00 00 00 04 zz zz zz zz
+// [----- CHUNK 1 -------] [--- CHUNK 2 ---] [------ CHUNK 3 ------]
+class ChunkedByteBuffer {
+ public:
+ ChunkedByteBuffer();
+ ~ChunkedByteBuffer();
+
+ // Appends |length| bytes starting from |start| to the buffer.
+ void Append(const uint8_t* start, size_t length);
+
+ // Appends bytes contained in the |string| to the buffer.
+ void Append(base::StringPiece string);
+
+ // Checks whether one or more complete chunks are available in the buffer.
+ bool HasChunks() const;
+
+ // If enough data is available, reads and removes the first complete chunk
+ // from the buffer. Returns a NULL pointer if no complete chunk is available.
+ std::unique_ptr<std::vector<uint8_t>> PopChunk();
+
+ // Clears all the content of the buffer.
+ void Clear();
+
+ // Returns the number of raw bytes (including headers) present.
+ size_t GetTotalLength() const { return total_bytes_stored_; }
+
+ private:
+ struct Chunk {
+ Chunk();
+ ~Chunk();
+
+ std::vector<uint8_t> header;
+ std::unique_ptr<std::vector<uint8_t>> content;
+ size_t ExpectedContentLength() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Chunk);
+ };
+
+ std::vector<std::unique_ptr<Chunk>> chunks_;
+ std::unique_ptr<Chunk> partial_chunk_;
+ size_t total_bytes_stored_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChunkedByteBuffer);
+};
+
+} // namespace speech
+
+#endif // COMPONENTS_SPEECH_CHUNKED_BYTE_BUFFER_H_
diff --git a/chromium/components/speech/chunked_byte_buffer_unittest.cc b/chromium/components/speech/chunked_byte_buffer_unittest.cc
new file mode 100644
index 00000000000..ee2187ffa0b
--- /dev/null
+++ b/chromium/components/speech/chunked_byte_buffer_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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 <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "components/speech/chunked_byte_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace speech {
+
+typedef std::vector<uint8_t> ByteVector;
+
+TEST(ChunkedByteBufferTest, BasicTest) {
+ ChunkedByteBuffer buffer;
+
+ const uint8_t kChunks[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, // Chunk 1: 4 bytes
+ 0x00, 0x00, 0x00, 0x02, 0x05, 0x06, // Chunk 2: 2 bytes
+ 0x00, 0x00, 0x00, 0x01, 0x07 // Chunk 3: 1 bytes
+ };
+
+ EXPECT_EQ(0U, buffer.GetTotalLength());
+ EXPECT_FALSE(buffer.HasChunks());
+
+ // Append partially chunk 1.
+ buffer.Append(kChunks, 2);
+ EXPECT_EQ(2U, buffer.GetTotalLength());
+ EXPECT_FALSE(buffer.HasChunks());
+
+ // Complete chunk 1.
+ buffer.Append(kChunks + 2, 6);
+ EXPECT_EQ(8U, buffer.GetTotalLength());
+ EXPECT_TRUE(buffer.HasChunks());
+
+ // Append fully chunk 2.
+ buffer.Append(kChunks + 8, 6);
+ EXPECT_EQ(14U, buffer.GetTotalLength());
+ EXPECT_TRUE(buffer.HasChunks());
+
+ // Remove and check chunk 1.
+ std::unique_ptr<ByteVector> chunk;
+ chunk = buffer.PopChunk();
+ EXPECT_TRUE(chunk != nullptr);
+ EXPECT_EQ(4U, chunk->size());
+ EXPECT_EQ(0, std::char_traits<uint8_t>::compare(kChunks + 4, &(*chunk)[0],
+ chunk->size()));
+ EXPECT_EQ(6U, buffer.GetTotalLength());
+ EXPECT_TRUE(buffer.HasChunks());
+
+ // Read and check chunk 2.
+ chunk = buffer.PopChunk();
+ EXPECT_TRUE(chunk != nullptr);
+ EXPECT_EQ(2U, chunk->size());
+ EXPECT_EQ(0, std::char_traits<uint8_t>::compare(kChunks + 12, &(*chunk)[0],
+ chunk->size()));
+ EXPECT_EQ(0U, buffer.GetTotalLength());
+ EXPECT_FALSE(buffer.HasChunks());
+
+ // Append fully chunk 3.
+ buffer.Append(kChunks + 14, 5);
+ EXPECT_EQ(5U, buffer.GetTotalLength());
+
+ // Remove and check chunk 3.
+ chunk = buffer.PopChunk();
+ EXPECT_TRUE(chunk != nullptr);
+ EXPECT_EQ(1U, chunk->size());
+ EXPECT_EQ((*chunk)[0], kChunks[18]);
+ EXPECT_EQ(0U, buffer.GetTotalLength());
+ EXPECT_FALSE(buffer.HasChunks());
+}
+
+} // namespace speech
diff --git a/chromium/components/spellcheck/browser/BUILD.gn b/chromium/components/spellcheck/browser/BUILD.gn
index c66c7f6c2c5..1e00fa03944 100644
--- a/chromium/components/spellcheck/browser/BUILD.gn
+++ b/chromium/components/spellcheck/browser/BUILD.gn
@@ -8,13 +8,6 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
source_set("browser") {
sources = [
"platform_spell_checker.h",
@@ -26,10 +19,6 @@ source_set("browser") {
"spellcheck_host_metrics.cc",
"spellcheck_host_metrics.h",
"spellcheck_platform.h",
- "spellcheck_platform_android.cc",
- "spellcheck_platform_mac.mm",
- "spellchecker_session_bridge_android.cc",
- "spellchecker_session_bridge_android.h",
]
if (enable_spelling_service) {
@@ -62,22 +51,32 @@ source_set("browser") {
"//services/network/public/cpp",
]
+ if (is_mac) {
+ sources += [ "spellcheck_platform_mac.mm" ]
+ }
+
if (is_android) {
+ sources += [
+ "spellcheck_platform_android.cc",
+ "spellchecker_session_bridge_android.cc",
+ "spellchecker_session_bridge_android.h",
+ ]
deps += [ "android:jni_headers" ]
}
}
source_set("unit_tests") {
testonly = true
- sources = [
- "spellcheck_host_metrics_unittest.cc",
- "spellcheck_platform_mac_unittest.cc",
- ]
+ sources = [ "spellcheck_host_metrics_unittest.cc" ]
if (is_win) {
sources += [ "windows_spell_checker_unittest.cc" ]
}
+ if (is_mac) {
+ sources += [ "spellcheck_platform_mac_unittest.cc" ]
+ }
+
deps = [
":browser",
"//base",
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm b/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm
index 683385b75c2..f08d92a9bfb 100644
--- a/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_mac.mm
@@ -9,7 +9,7 @@
#import <Cocoa/Cocoa.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/mac/foundation_util.h"
#include "base/notreached.h"
diff --git a/chromium/components/spellcheck/browser/windows_spell_checker.cc b/chromium/components/spellcheck/browser/windows_spell_checker.cc
index ec32eb49206..41cf1ce2810 100644
--- a/chromium/components/spellcheck/browser/windows_spell_checker.cc
+++ b/chromium/components/spellcheck/browser/windows_spell_checker.cc
@@ -17,8 +17,8 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/spellcheck/common/spellcheck.mojom b/chromium/components/spellcheck/common/spellcheck.mojom
index dfaa735ced8..21bce14877c 100644
--- a/chromium/components/spellcheck/common/spellcheck.mojom
+++ b/chromium/components/spellcheck/common/spellcheck.mojom
@@ -4,7 +4,7 @@
module spellcheck.mojom;
-import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
import "mojo/public/mojom/base/string16.mojom";
// Render process interface exposed to the browser for receiving process-
@@ -25,7 +25,7 @@ interface SpellChecker {
};
struct SpellCheckBDictLanguage {
- mojo_base.mojom.File? file;
+ mojo_base.mojom.ReadOnlyFile? file;
string language;
};
diff --git a/chromium/components/spellcheck/renderer/BUILD.gn b/chromium/components/spellcheck/renderer/BUILD.gn
index 6055fd44489..cad26284323 100644
--- a/chromium/components/spellcheck/renderer/BUILD.gn
+++ b/chromium/components/spellcheck/renderer/BUILD.gn
@@ -4,13 +4,6 @@
import("//components/spellcheck/spellcheck_build_features.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
source_set("renderer") {
sources = [
"custom_dictionary_engine.cc",
@@ -73,7 +66,6 @@ source_set("unit_tests") {
"custom_dictionary_engine_unittest.cc",
"empty_local_interface_provider.cc",
"empty_local_interface_provider.h",
- "spellcheck_provider_mac_unittest.cc",
"spellcheck_provider_test.cc",
"spellcheck_provider_test.h",
"spellcheck_provider_unittest.cc",
@@ -104,7 +96,8 @@ source_set("unit_tests") {
"//third_party/icu",
]
- if (is_mac && !is_ios) {
+ if (is_mac) {
+ sources += [ "spellcheck_provider_mac_unittest.cc" ]
deps += [ "//third_party/hunspell" ]
}
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
index ec16fefbebc..3b1f0608660 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_worditerator.cc
@@ -442,7 +442,7 @@ bool SpellcheckWordIterator::Normalize(size_t input_start,
// spellchecker and we need manual normalization as well. The normalized
// text does not have to be NUL-terminated since its characters are copied to
// string16, which adds a NUL character when we need.
- icu::UnicodeString input(FALSE, &text_[input_start],
+ icu::UnicodeString input(false, &text_[input_start],
base::checked_cast<int32_t>(input_length));
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString output;
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
index 03080c18241..d7187228e93 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -16,6 +16,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "base/optional.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/platform_thread.h"
@@ -67,11 +68,11 @@ enum StartupTemperature {
// The startup type couldn't quite be classified as warm or cold, but rather
// was somewhere in between.
LUKEWARM_STARTUP_TEMPERATURE = 2,
+ // Startup temperature wasn't yet determined, or could not be determined.
+ UNDETERMINED_STARTUP_TEMPERATURE = 3,
// This must be after all meaningful values. All new values should be added
// above this one.
STARTUP_TEMPERATURE_COUNT,
- // Startup temperature wasn't yet determined.
- UNDETERMINED_STARTUP_TEMPERATURE
};
StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE;
@@ -126,17 +127,15 @@ struct SYSTEM_PROCESS_INFORMATION_EX {
typedef NTSTATUS (WINAPI *NtQuerySystemInformationPtr)(
SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
-// Gets the hard fault count of the current process through |hard_fault_count|.
-// Returns true on success.
-bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
- DCHECK(hard_fault_count);
-
+// Returns the hard fault count of the current process, or nullopt if it can't
+// be determined.
+base::Optional<uint32_t> GetHardFaultCountForCurrentProcess() {
// Get the function pointer.
static const NtQuerySystemInformationPtr query_sys_info =
reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
if (query_sys_info == nullptr)
- return false;
+ return base::nullopt;
// The output of this system call depends on the number of threads and
// processes on the entire system, and this can change between calls. Retry
@@ -145,19 +144,42 @@ bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
// and threads running on the system. The initial guess suffices for
// ~100s of processes and ~1000s of threads.
std::vector<uint8_t> buffer(32 * 1024);
- for (size_t tries = 0; tries < 3; ++tries) {
+ constexpr int kMaxNumBufferResize = 2;
+ int num_buffer_resize = 0;
+ for (;;) {
ULONG return_length = 0;
const NTSTATUS status =
query_sys_info(SystemProcessInformation, buffer.data(),
static_cast<ULONG>(buffer.size()), &return_length);
- // Insufficient space in the buffer.
+
+ // NtQuerySystemInformation succeeded.
+ if (NT_SUCCESS(status)) {
+ DCHECK_LE(return_length, buffer.size());
+ break;
+ }
+
+ // NtQuerySystemInformation failed due to insufficient buffer length.
if (return_length > buffer.size()) {
- buffer.resize(return_length);
- continue;
+ // Abort if a large size is required for the buffer. It is undesirable to
+ // fill a large buffer just to record histograms.
+ constexpr ULONG kMaxLength = 512 * 1024;
+ if (return_length >= kMaxLength)
+ return base::nullopt;
+
+ // Resize the buffer and retry, if the buffer hasn't already been resized
+ // too many times.
+ if (num_buffer_resize < kMaxNumBufferResize) {
+ ++num_buffer_resize;
+ buffer.resize(return_length);
+ continue;
+ }
}
- if (NT_SUCCESS(status) && return_length <= buffer.size())
- break;
- return false;
+
+ // Abort if NtQuerySystemInformation failed for another reason than
+ // insufficient buffer length, or if the buffer was resized too many times.
+ DCHECK(return_length <= buffer.size() ||
+ num_buffer_resize >= kMaxNumBufferResize);
+ return base::nullopt;
}
// Look for the struct housing information for the current process.
@@ -167,18 +189,16 @@ bool GetHardFaultCountForCurrentProcess(uint32_t* hard_fault_count) {
DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
SYSTEM_PROCESS_INFORMATION_EX* proc_info =
reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
- if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
- *hard_fault_count = proc_info->HardFaultCount;
- return true;
- }
+ if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id)
+ return proc_info->HardFaultCount;
// The list ends when NextEntryOffset is zero. This also prevents busy
// looping if the data is in fact invalid.
if (proc_info->NextEntryOffset <= 0)
- return false;
+ return base::nullopt;
index += proc_info->NextEntryOffset;
}
- return false;
+ return base::nullopt;
}
#endif // defined(OS_WIN)
@@ -275,28 +295,31 @@ void UmaHistogramAndTraceWithTemperatureAndMaxPressure(
// platforms.
void RecordHardFaultHistogram() {
#if defined(OS_WIN)
- uint32_t hard_fault_count = 0;
-
- // Don't record histograms if unable to get the hard fault count.
- if (!GetHardFaultCountForCurrentProcess(&hard_fault_count))
- return;
-
- // Hard fault counts are expected to be in the thousands range,
- // corresponding to faulting in ~10s of MBs of code ~10s of KBs at a time.
- // (Observed to vary from 1000 to 10000 on various test machines and
- // platforms.)
- base::UmaHistogramCustomCounts(
- "Startup.BrowserMessageLoopStartHardFaultCount", hard_fault_count, 1,
- 40000, 50);
-
- // Determine the startup type based on the number of observed hard faults.
DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature);
- if (hard_fault_count < kWarmStartHardFaultCountThreshold) {
- g_startup_temperature = WARM_STARTUP_TEMPERATURE;
- } else if (hard_fault_count >= kColdStartHardFaultCountThreshold) {
- g_startup_temperature = COLD_STARTUP_TEMPERATURE;
+
+ const base::Optional<uint32_t> hard_fault_count =
+ GetHardFaultCountForCurrentProcess();
+
+ if (hard_fault_count.has_value()) {
+ // Hard fault counts are expected to be in the thousands range,
+ // corresponding to faulting in ~10s of MBs of code ~10s of KBs at a time.
+ // (Observed to vary from 1000 to 10000 on various test machines and
+ // platforms.)
+ base::UmaHistogramCustomCounts(
+ "Startup.BrowserMessageLoopStartHardFaultCount",
+ hard_fault_count.value(), 1, 40000, 50);
+
+ // Determine the startup type based on the number of observed hard faults.
+ if (hard_fault_count < kWarmStartHardFaultCountThreshold) {
+ g_startup_temperature = WARM_STARTUP_TEMPERATURE;
+ } else if (hard_fault_count >= kColdStartHardFaultCountThreshold) {
+ g_startup_temperature = COLD_STARTUP_TEMPERATURE;
+ } else {
+ g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE;
+ }
} else {
- g_startup_temperature = LUKEWARM_STARTUP_TEMPERATURE;
+ // |g_startup_temperature| remains UNDETERMINED_STARTUP_TEMPERATURE if the
+ // number of hard faults could not be determined.
}
// Record the startup 'temperature'.
diff --git a/chromium/components/storage_monitor/BUILD.gn b/chromium/components/storage_monitor/BUILD.gn
index 80d8c7cfbba..33bcb82c603 100644
--- a/chromium/components/storage_monitor/BUILD.gn
+++ b/chromium/components/storage_monitor/BUILD.gn
@@ -4,13 +4,6 @@
import("//build/config/features.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
static_library("storage_monitor") {
sources = [
"media_storage_util.cc",
@@ -89,10 +82,12 @@ static_library("storage_monitor") {
}
if (use_udev) {
- sources += [
- "udev_util_linux.cc",
- "udev_util_linux.h",
- ]
+ if (is_linux || is_chromeos) {
+ sources += [
+ "udev_util_linux.cc",
+ "udev_util_linux.h",
+ ]
+ }
deps += [ "//device/udev_linux" ]
}
@@ -106,16 +101,8 @@ static_library("test_support") {
sources = [
"mock_removable_storage_observer.cc",
"mock_removable_storage_observer.h",
- "test_media_transfer_protocol_manager_chromeos.cc",
- "test_media_transfer_protocol_manager_chromeos.h",
- "test_portable_device_watcher_win.cc",
- "test_portable_device_watcher_win.h",
"test_storage_monitor.cc",
"test_storage_monitor.h",
- "test_storage_monitor_win.cc",
- "test_storage_monitor_win.h",
- "test_volume_mount_watcher_win.cc",
- "test_volume_mount_watcher_win.h",
]
public_deps = [
@@ -124,11 +111,25 @@ static_library("test_support") {
"//content/public/browser",
]
- if (is_chromeos && use_dbus) {
- deps = [ "//services/device/public/mojom" ]
+ if (is_chromeos) {
+ sources += [
+ "test_media_transfer_protocol_manager_chromeos.cc",
+ "test_media_transfer_protocol_manager_chromeos.h",
+ ]
+ if (use_dbus) {
+ deps = [ "//services/device/public/mojom" ]
+ }
}
if (is_win) {
+ sources += [
+ "test_portable_device_watcher_win.cc",
+ "test_portable_device_watcher_win.h",
+ "test_storage_monitor_win.cc",
+ "test_storage_monitor_win.h",
+ "test_volume_mount_watcher_win.cc",
+ "test_volume_mount_watcher_win.h",
+ ]
deps = [ "//testing/gtest" ]
}
}
@@ -136,12 +137,9 @@ static_library("test_support") {
source_set("unit_tests") {
testonly = true
sources = [
- "image_capture_device_manager_unittest.mm",
"media_storage_util_unittest.cc",
"storage_info_unittest.cc",
- "storage_monitor_mac_unittest.mm",
"storage_monitor_unittest.cc",
- "storage_monitor_win_unittest.cc",
]
deps = [
@@ -151,6 +149,17 @@ source_set("unit_tests") {
"//testing/gtest",
]
+ if (is_win) {
+ sources += [ "storage_monitor_win_unittest.cc" ]
+ }
+
+ if (is_mac) {
+ sources += [
+ "image_capture_device_manager_unittest.mm",
+ "storage_monitor_mac_unittest.mm",
+ ]
+ }
+
if (use_dbus) {
if (is_chromeos) {
deps += [
diff --git a/chromium/components/storage_monitor/media_storage_util_unittest.cc b/chromium/components/storage_monitor/media_storage_util_unittest.cc
index e46c4d01fd5..48cf058f75b 100644
--- a/chromium/components/storage_monitor/media_storage_util_unittest.cc
+++ b/chromium/components/storage_monitor/media_storage_util_unittest.cc
@@ -5,7 +5,7 @@
#include <string>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.cc b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
index 12379d7b5a2..864b22a5f51 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/sequenced_task_runner.h"
diff --git a/chromium/components/storage_monitor/storage_monitor_linux.cc b/chromium/components/storage_monitor/storage_monitor_linux.cc
index d2335217e2a..298f49b1385 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux.cc
+++ b/chromium/components/storage_monitor/storage_monitor_linux.cc
@@ -18,7 +18,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/process/kill.h"
diff --git a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
index 9a7a6175e9e..fbc566a96e2 100644
--- a/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
+++ b/chromium/components/storage_monitor/storage_monitor_mac_unittest.mm
@@ -7,7 +7,7 @@
#include <stdint.h>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/mac/foundation_util.h"
diff --git a/chromium/components/storage_monitor/volume_mount_watcher_win.cc b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
index 4f3a5c1ca82..3b2c020fa4a 100644
--- a/chromium/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
@@ -16,7 +16,7 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
diff --git a/chromium/components/strings/BUILD.gn b/chromium/components/strings/BUILD.gn
index 4f264ebc35e..776127ec454 100644
--- a/chromium/components/strings/BUILD.gn
+++ b/chromium/components/strings/BUILD.gn
@@ -3,6 +3,8 @@
# found in the LICENSE file.
import("//build/config/locales.gni")
+import("//components/feed/features.gni")
+import("//device/vr/buildflags/buildflags.gni")
import("//ppapi/buildflags/buildflags.gni")
import("//printing/buildflags/buildflags.gni")
import("//tools/grit/grit_rule.gni")
@@ -28,8 +30,11 @@ group("strings") {
grit("components_strings") {
source = "../components_strings.grd"
defines = [
+ "enable_arcore=$enable_arcore",
"enable_plugins=$enable_plugins",
"enable_print_preview=$enable_print_preview",
+ "enable_feed_v1=$enable_feed_v1",
+ "enable_vr=$enable_vr",
]
outputs = [ "grit/components_strings.h" ]
@@ -52,6 +57,11 @@ if (is_android) {
}
grit("components_chromium_strings") {
+ # TODO(crbug.com/1112471). For reasons I don't understand,
+ # IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM is not defined
+ # on desktop linux when this is run under Python3. Fix this.
+ run_under_python2 = true
+
source = "../components_chromium_strings.grd"
outputs = [ "grit/components_chromium_strings.h" ]
foreach(locale, locales_with_fake_bidi) {
diff --git a/chromium/components/strings/components_chromium_strings_is.xtb b/chromium/components/strings/components_chromium_strings_is.xtb
index e17c4abb1d6..f1041539dd8 100644
--- a/chromium/components/strings/components_chromium_strings_is.xtb
+++ b/chromium/components/strings/components_chromium_strings_is.xtb
@@ -5,7 +5,7 @@
<translation id="275588974610408078">Hrunskýrslur eru ekki í boði í Chromium.</translation>
<translation id="3064346599913645280">Þú ert að skoða örugga Chromium síðu</translation>
<translation id="3550966579244642892">Chrome OS hefur ekki lokið við frumuppsetningu</translation>
-<translation id="358997566136285270">Merki Chromium</translation>
+<translation id="358997566136285270">Chromium lógóið</translation>
<translation id="4365115785552740256">Opna kóðaverkefnið <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> og annar <ph name="BEGIN_LINK_OSS" />opinn hugbúnaður<ph name="END_LINK_OSS" /> gerir Chromium mögulegt.</translation>
<translation id="4559775032954821361">Farðu í
valmynd Chromium &gt;
diff --git a/chromium/components/strings/components_google_chrome_strings_eu.xtb b/chromium/components/strings/components_google_chrome_strings_eu.xtb
index a4738e6a577..ae3f669db8b 100644
--- a/chromium/components/strings/components_google_chrome_strings_eu.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_eu.xtb
@@ -8,7 +8,7 @@
<translation id="3140883423282498090">Aldaketek Google Chrome abiarazten duzun hurrengo aldian izango dute eragina.</translation>
<translation id="3444832043240812445">Orri honek azken hutsegiteei buruzko informazioa soilik bistaratzen du, <ph name="BEGIN_LINK" />hutsegiteen berri ematea gaitzen baduzu<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Ez eman suebakiaren edo birusen aurkako softwarearen ezarpenetan sarea atzitzeko baimena Chrome-ri.</translation>
-<translation id="4010643444566880169">Chrome OS sistemak ez du amaitu hasierako konfigurazioa.</translation>
+<translation id="4010643444566880169">Chrome OS-ek ez du amaitu hasierako konfigurazioa.</translation>
<translation id="4853578032408195113">Google Chrome-ko orri seguru bat ari zara ikusten</translation>
<translation id="6011049234605203654">Sakatu Chrome-ko menua &gt; <ph name="SETTINGS_TITLE" /> &gt; <ph name="ADVANCED_TITLE" /> &gt; <ph name="PROXIES_TITLE" /> eta ziurtatu konfigurazioa "proxyrik ez" edo "zuzena" gisa ezarrita dagoela.</translation>
<translation id="6341737370356890233">Sakatu
diff --git a/chromium/components/strings/components_google_chrome_strings_fi.xtb b/chromium/components/strings/components_google_chrome_strings_fi.xtb
index c629dc93738..f66d9d1bb92 100644
--- a/chromium/components/strings/components_google_chrome_strings_fi.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fi.xtb
@@ -1,7 +1,7 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
-<translation id="1016765312371154165">Chromea ei suljettu oikein.</translation>
+<translation id="1016765312371154165">Chrome ei sulkeutunut oikein.</translation>
<translation id="130631256467250065">Muutokset tulevat voimaan, kun käynnistät laitteen seuraavan kerran.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
<translation id="2874156562296220396">Google Chromen mahdollistivat avoimen lähdekoodin projekti <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ja muut <ph name="BEGIN_LINK_OSS" />avoimen lähdekoodin ohjelmistot<ph name="END_LINK_OSS" />.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_is.xtb b/chromium/components/strings/components_google_chrome_strings_is.xtb
index 9dc87b75d04..ce67eb62213 100644
--- a/chromium/components/strings/components_google_chrome_strings_is.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_is.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="is">
<translation id="1016765312371154165">Chrome lokaðist ekki á réttan hátt.</translation>
<translation id="130631256467250065">Breytingarnar taka gildi næst þegar þú endurræsir tækið.</translation>
-<translation id="2588322182880276190">Merki Chrome</translation>
+<translation id="2588322182880276190">Chrome lógóið</translation>
<translation id="2874156562296220396">Opna kóðaverkefnið <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> og annar <ph name="BEGIN_LINK_OSS" />opinn hugbúnaður<ph name="END_LINK_OSS" /> gerir Google Chrome mögulegt.</translation>
<translation id="3140883423282498090">Breytingarnar taka gildi næst þegar þú endurræsir Google Chrome.</translation>
<translation id="3444832043240812445">Þessi síða sýnir aðeins upplýsingar um nýleg hrun ef þú <ph name="BEGIN_LINK" />kveikir á tilkynningum um hrun<ph name="END_LINK" />.</translation>
diff --git a/chromium/components/strings/components_strings_af.xtb b/chromium/components/strings/components_strings_af.xtb
index 9b90b5cd6f6..38a96187f55 100644
--- a/chromium/components/strings/components_strings_af.xtb
+++ b/chromium/components/strings/components_strings_af.xtb
@@ -80,6 +80,14 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Jy het jou wagwoord ingevoer op 'n werf wat nie deur jou organisasie bestuur word nie. Om jou rekening te beskerm, moet jy nie jou wagwoord op ander programme en werwe hergebruik nie.</translation>
<translation id="1263231323834454256">Leeslys</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktiwiteit wat nie op hierdie toestel sal bly nie:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bladsye wat jy in hierdie venster kan bekyk
+ <ph name="LIST_ITEM" />Webkoekies en werfdata
+ <ph name="LIST_ITEM" />Rekeninginligting (<ph name="LINK_BEGIN" />meld af<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Oplaaimetode</translation>
<translation id="1281476433249504884">Stapelaar 1</translation>
<translation id="1285320974508926690">Moet nooit hierdie werf vertaal nie</translation>
@@ -283,6 +291,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="204357726431741734">Meld aan om wagwoorde te gebruik wat in jou Google-rekening gestoor is</translation>
<translation id="2053111141626950936">Bladsye in <ph name="LANGUAGE" /> sal nie vertaal word nie.</translation>
<translation id="2053553514270667976">Poskode</translation>
+<translation id="2054665754582400095">Jou teenwoordigheid</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 voorstel}other{# voorstelle}}</translation>
<translation id="2079545284768500474">Ontdoen</translation>
<translation id="20817612488360358">Stelsel se instaanbedienerinstellings word gestel om gebruik te word, maar doelbewuste instaanbedieneropstelling word ook gespesifiseer.</translation>
@@ -296,6 +305,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2102495993840063010">Android-programme</translation>
<translation id="2107021941795971877">Drukondersteuning</translation>
<translation id="2108755909498034140">Herbegin jou rekenaar</translation>
+<translation id="2111166930115883695">Druk spasie om te speel</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kaart</translation>
<translation id="2114841414352855701">Geïgnoreer, want dit is deur <ph name="POLICY_NAME" /> geïgnoreer.</translation>
@@ -307,6 +317,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="214556005048008348">Kanselleer betaling</translation>
<translation id="2147827593068025794">Agtergrondsinkronisering</translation>
<translation id="2148613324460538318">Voeg kaart by</translation>
+<translation id="2149968176347646218">Verbinding is nie veilig nie</translation>
<translation id="2154054054215849342">Sinkronisering is nie vir jou domein beskikbaar nie</translation>
<translation id="2154484045852737596">Wysig kaart</translation>
<translation id="2161656808144014275">Teks</translation>
@@ -317,7 +328,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2181821976797666341">Beleide</translation>
<translation id="2183608646556468874">Foonnommer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adresse}}</translation>
-<translation id="2187243482123994665">Gebruikerteenwoordigheid</translation>
<translation id="2187317261103489799">Bespeur (verstek)</translation>
<translation id="2188375229972301266">Veelvuldige pons onder</translation>
<translation id="2202020181578195191">Voer 'n geldige vervaljaar in</translation>
@@ -470,6 +480,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2839501879576190149">Vals werf voor</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Aanvallers probeer dalk om jou inligting (byvoorbeeld: wagwoorde, boodskappe of kredietkaartinligting) op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te steel. <ph name="BEGIN_LEARN_MORE_LINK" />Kom meer te wete<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Hierdie werf wys indringerige of misleidende advertensies.</translation>
<translation id="2878197950673342043">Plakkaatvou</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Vensterplasing</translation>
@@ -508,11 +519,11 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2996674880327704673">Voorstelle deur Google</translation>
<translation id="3002501248619246229">Gaan invoerlaaimedia na</translation>
<translation id="3005723025932146533">Wys die kopie wat gestoor is</translation>
-<translation id="3007719053326478567">Die opsie om hierdie inhoud te druk, word deur jou administrateur geblokkeer</translation>
<translation id="3008447029300691911">Voer die CVC vir <ph name="CREDIT_CARD" /> in. Nadat jy bevestig het, sal jou kaartbesonderhede met hierdie werf gedeel word.</translation>
<translation id="3010559122411665027">Lysinskrywing "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Outomaties geblokkeer</translation>
<translation id="3016780570757425217">Jou ligging ken</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, druk Tab en dan Enter om voorstel te verwyder.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Verkeerde beleidtipe</translation>
<translation id="3037605927509011580">O, mapstieks!</translation>
@@ -555,6 +566,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3207960819495026254">Geboekmerk</translation>
<translation id="3209034400446768650">Bladsy kan geld hef</translation>
<translation id="3212581601480735796">Jou aktiwiteit op <ph name="HOSTNAME" /> word gemonitor</translation>
+<translation id="3212623355668894776">Maak alle gasvensters toe sodat jou blaai-aktiwiteit op hierdie toestel uitgevee word.</translation>
<translation id="3215092763954878852">Kon nie in WebAuthn gebruik nie</translation>
<translation id="3218181027817787318">Relatief</translation>
<translation id="3225919329040284222">Die bediener het 'n sertifikaat voorgehou wat nie ooreenstem met ingeboude verwagtinge nie. Hierdie verwagtinge is vir sekere hoësekerheidwebwerwe ingesluit om jou te beskerm.</translation>
@@ -702,6 +714,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3784372983762739446">Bluetooth-toestelle</translation>
<translation id="3787705759683870569">Verval <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Grootte 16</translation>
+<translation id="3789841737615482174">Installeer</translation>
<translation id="3793574014653384240">Aantal en oorsake van die omvalle wat onlangs voorgekom het</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Lettertipe versoek</translation>
@@ -753,6 +766,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Sleutel "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Skermskoot is hervat.</translation>
<translation id="4067947977115446013">Voeg geldige adres by</translation>
<translation id="4072486802667267160">Kon nie jou betaling verwerk nie. Probeer weer.</translation>
<translation id="4075732493274867456">Die kliënt en bediener steun nie 'n gemeenskaplike SSL-protokolweergawe of kodesuite nie.</translation>
@@ -837,6 +851,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4297502707443874121">Kleinkiekie vir bladsy <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Vou uit</translation>
<translation id="4300675098767811073">Veelvuldige pons regs</translation>
+<translation id="4302514097724775343">Tik op die dinosourus om te speel</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Kon nie toegang tot jou lêer kry nie</translation>
<translation id="4305817255990598646">Skakel oor</translation>
@@ -915,6 +930,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4658638640878098064">Kram links bo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuele realiteit</translation>
+<translation id="4675657451653251260">Jy sal geen Chrome-profiel se inligting in gasmodus sien nie. Jy kan <ph name="LINK_BEGIN" />aanmeld<ph name="LINK_END" /> om toegang te kry tot jou Google-rekeninginligting, soos wagwoorde en betaalmetodes.</translation>
<translation id="467662567472608290">Hierdie bediener kon nie bewys dat dit <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaar bevat foute. Dit kan veroorsaak word deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep.</translation>
<translation id="4677585247300749148"><ph name="URL" /> wil op toeganklikheidgebeurtenisse reageer</translation>
<translation id="467809019005607715">Google Skyfies</translation>
@@ -942,6 +958,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4761104368405085019">Gebruik jou mikrofoon</translation>
<translation id="4764776831041365478">Die webbladsy by <ph name="URL" /> kan dalk tydelik af wees of dit kon permanent na 'n nuwe webadres geskuif het.</translation>
<translation id="4766713847338118463">Dubbelkram onder</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Jou aktiwiteit sal op hierdie toestel bly:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Enige lêers wat jy in hierdie venster aflaai
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">'n Onbekende fout het voorgekom.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Opspringer is geblokkeer}other{# opspringers is geblokkeer}}</translation>
<translation id="4780366598804516005">Posbus 1</translation>
@@ -1104,11 +1126,13 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5386426401304769735">Die sertifikaatketting vir hierdie werf bevat 'n sertifikaat wat met gebruik van SHA-1 onderteken is.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Randhegting regs</translation>
+<translation id="5398772614898833570">Advertensies is geblokkeer</translation>
<translation id="5400836586163650660">Grys</translation>
<translation id="540969355065856584">Hierdie bediener kon nie bewys dat dit <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat is nie op die oomblik geldig nie. Dit kan veroorsaak word deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep.</translation>
<translation id="541416427766103491">Stapelaar 4</translation>
<translation id="5421136146218899937">Vee blaaidata uit …</translation>
<translation id="5426179911063097041"><ph name="SITE" /> wil vir jou kennisgewings stuur</translation>
+<translation id="542872847390508405">Jy blaai tans as 'n gas</translation>
<translation id="5430298929874300616">Verwyder boekmerk</translation>
<translation id="5439770059721715174">Skema-stawingsfout by "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Omgekeerde volgorde, voorkant na bo</translation>
@@ -1150,12 +1174,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5571083550517324815">Kan nie by hierdie adres oplaai nie. Kies 'n ander adres.</translation>
<translation id="5580958916614886209">Gaan jou vervalmaand na en probeer weer</translation>
<translation id="5586446728396275693">Geen gestoorde adresse nie</translation>
+<translation id="5593349413089863479">Verbinding is nie heeltemal veilig nie</translation>
<translation id="5595485650161345191">Wysig adres</translation>
<translation id="5598944008576757369">Kies betaalmetode</translation>
<translation id="560412284261940334">Bestuur word nie gesteun nie</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Hierdie werf is dalk vals of bedrieglik. Chrome beveel aan dat jy dit nou verlaat.</translation>
<translation id="5610142619324316209">Die verbinding nagaan</translation>
<translation id="5610807607761827392">Jy kan kaarte en adresse in <ph name="BEGIN_LINK" />Instellings<ph name="END_LINK" /> bestuur.</translation>
<translation id="561165882404867731">Vertaal hierdie bladsy met Google Vertaal</translation>
@@ -1227,6 +1251,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5901630391730855834">Geel</translation>
<translation id="5905445707201418379">Geblokkeer ingevolge <ph name="ORIGIN" /> se oorsprongbeleid.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (gesinkroniseer)</translation>
+<translation id="5913377024445952699">Skermskoot is onderbreek</translation>
<translation id="59174027418879706">Geaktiveer</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aan</translation>
@@ -1239,6 +1264,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5963413905009737549">Afdeling</translation>
<translation id="5967592137238574583">Wysig kontakinligting</translation>
<translation id="5967867314010545767">Verwyder uit geskiedenis</translation>
+<translation id="5968793460449681917">Met elke besoek</translation>
<translation id="5975083100439434680">Zoem uit</translation>
<translation id="5979084224081478209">Gaan wagwoorde na</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6587923378399804057">Skakel wat jy gekopieer het</translation>
<translation id="6591833882275308647">Jou <ph name="DEVICE_TYPE" /> word nie bestuur nie</translation>
<translation id="6596325263575161958">Enkripsie-opsies</translation>
+<translation id="6596892391065203054">Jou administrateur blokkeer die druk van hierdie inhoud.</translation>
<translation id="6604181099783169992">Beweging- of ligsensors</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Beskermde inhoud</translation>
@@ -1453,6 +1480,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6895330447102777224">Jou kaart is bevestig</translation>
<translation id="6897140037006041989">Gebruikeragent</translation>
<translation id="6898699227549475383">Organisasie (O)</translation>
+<translation id="6907293445143367439">Laat <ph name="SITE_NAME" /> toe om:</translation>
<translation id="6910240653697687763"><ph name="URL" /> wil volle beheer van jou MIDI-toestelle oorneem</translation>
<translation id="6915804003454593391">Gebruiker:</translation>
<translation id="6934672428414710184">Hierdie naam is van jou Google-rekening af</translation>
@@ -1564,6 +1592,7 @@ Bykomende besonderhede:
<translation id="7346048084945669753">Is geaffilieer:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Bevellyn</translation>
+<translation id="7359588939039777303">Advertensies is geblokkeer.</translation>
<translation id="7372973238305370288">soekresultaat</translation>
<translation id="7374733840632556089">Hierdie probleem word veroorsaak deur 'n sertifikaat wat jy of iemand anders op jou toestel geïnstalleer het. Dit is bekend dat hierdie sertifikaat gebruik word om netwerke te monitor en te onderskep, en dit word nie deur Chrome vertrou nie. Terwyl sommige wettige gevalle vir monitering wel bestaan, soos op 'n skool- of maatskappynetwerk, wil Chrome seker maak dat jy weet dit gebeur, selfs al kan jy dit nie keer nie. Monitering kan in enige blaaier of program met toegang tot die web plaasvind.</translation>
<translation id="7375818412732305729">Lêer is aangeheg</translation>
@@ -1738,6 +1767,7 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="7976214039405368314">Te veel versoeke</translation>
<translation id="7977538094055660992">Uitvoertoestel</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Installeer ARCore om verhoogderealiteitinhoud te bekyk</translation>
<translation id="799149739215780103">Gebind</translation>
<translation id="7995512525968007366">Nie gespesifiseer nie</translation>
<translation id="800218591365569300">Probeer ander oortjies of programme toemaak om berging beskikbaar te maak.</translation>
@@ -1865,24 +1895,38 @@ Bykomende besonderhede:
<translation id="8507227106804027148">Bevellyn</translation>
<translation id="8508648098325802031">Search-ikoon</translation>
<translation id="8522552481199248698">Chrome kan jou help om jou Google-rekening te beskerm en jou wagwoord te verander.</translation>
+<translation id="8525306231823319788">Volskerm</translation>
<translation id="8530813470445476232">Vee jou blaaigeskiedenis, webkoekies, kasgeheue en meer in Chrome-instellings uit</translation>
<translation id="8533619373899488139">Besoek &lt;strong&gt;chrome://policy&lt;/strong&gt; om die lys geblokkeerde URL'e en ander beleide wat jou stelseladministrateur toepas te sien.</translation>
<translation id="8541158209346794904">Bluetooth-toestel</translation>
<translation id="8542014550340843547">Tripelkram onder</translation>
<translation id="8543181531796978784">Jy kan <ph name="BEGIN_ERROR_LINK" />'n bespeuringsprobleem aangee<ph name="END_ERROR_LINK" /> of, as jy die risikos vir jou sekuriteit verstaan, kan jy <ph name="BEGIN_LINK" />hierdie onveilige werf besoek<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Die CVC is agterop jou kaart.</translation>
+<translation id="8558485628462305855">Dateer ARCore op om verhoogderealiteitinhoud te bekyk</translation>
<translation id="8559762987265718583">'n Private verbinding aan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kan nie gevestig word nie omdat jou toestel se datum en tyd (<ph name="DATE_AND_TIME" />) verkeerd is.</translation>
<translation id="8564182942834072828">Afsonderlike dokumente/nie-ingesorteerde kopieë</translation>
<translation id="8564985650692024650">Chromium beveel aan dat jy jou <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-wagwoord terugstel as jy dit ook op ander werwe gebruik het.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktiwiteit wat nie op hierdie toestel sal bly nie:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bladsye wat jy in hierdie venster bekyk
+ <ph name="LIST_ITEM" />Webkoekies en werfdata
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Gebruik Touch ID om kaarte vinniger te bevestig</translation>
<translation id="858637041960032120">Voeg foonnommer by</translation>
<translation id="8589998999637048520">Beste gehalte</translation>
+<translation id="8600271352425265729">Net hierdie keer</translation>
<translation id="860043288473659153">Kaarthouernaam</translation>
<translation id="8606726445206553943">Gebruik jou MIDI-toestelle</translation>
+<translation id="8612761427948161954">Hallo <ph name="USERNAME" />
+ <ph name="BR" />
+ Jy blaai tans as 'n gas</translation>
<translation id="861775596732816396">Grootte 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Geen passende wagwoorde nie. Wys alle gestoorde wagwoorde.</translation>
<translation id="8625384913736129811">Stoor hierdie kaart op hierdie toestel</translation>
+<translation id="8627040765059109009">Skermskoot is hervat</translation>
<translation id="8657078576661269990">Jou administrateur het deling van <ph name="ORIGIN_NAME" /> af na <ph name="VM_NAME_1" /> en <ph name="VM_NAME_2" /> geblokkeer</translation>
<translation id="8663226718884576429">Bestellingopsomming, <ph name="TOTAL_LABEL" />, meer besonderhede</translation>
<translation id="867224526087042813">Handtekening</translation>
@@ -1945,6 +1989,7 @@ Bykomende besonderhede:
<translation id="8912362522468806198">Google-rekening</translation>
<translation id="8913778647360618320">Bestuur Betaalmetodes-knoppie; druk Enter om jou betalings- en kredietkaartinligting in Chrome-instellings te bestuur</translation>
<translation id="8918231688545606538">Hierdie bladsy is verdag</translation>
+<translation id="8922013791253848639">Laat advertensies altyd op hierdie werf toe</translation>
<translation id="892588693504540538">Pons regs bo</translation>
<translation id="8931333241327730545">Wil jy hierdie kaart in jou Google-rekening stoor?</translation>
<translation id="8932102934695377596">Jou horlosie is agter</translation>
@@ -2016,6 +2061,7 @@ Bykomende besonderhede:
<translation id="9183302530794969518">Google Dokumente</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> gebruik 'n ongesteunde protokol.</translation>
<translation id="9191834167571392248">Pons links onder</translation>
+<translation id="9199905725844810519">Druk word geblokkeer</translation>
<translation id="9205078245616868884">Jou data is met jou sinkroniseringwagfrase geënkripteer. Voer dit in om sinkronisering te begin.</translation>
<translation id="9207861905230894330">Kon nie artikel bevoeg nie.</translation>
<translation id="9213433120051936369">Pasmaak voorkoms</translation>
@@ -2026,8 +2072,10 @@ Bykomende besonderhede:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Jy kan toegang tot jou Google-rekening verloor. Chromium beveel aan dat jy jou wagwoord nou verander. Jy sal gevra word om aan te meld.</translation>
<translation id="939736085109172342">Nuwe vouer</translation>
+<translation id="945522503751344254">Stuur terugvoer</translation>
<translation id="945855313015696284">Gaan die inligting hieronder na en vee ongeldige kaarte uit</translation>
<translation id="950736567201356821">Tripelpons bo</translation>
+<translation id="951941430552851965">Jou administrateur het skermskoot onderbreek weens inhoud op jou skerm.</translation>
<translation id="961663415146723894">Gebind onder</translation>
<translation id="962484866189421427">Hierdie inhoud kan probeer om misleidende programme te installeer wat voorgee om iets anders te wees of wat data insamel wat gebruik kan word om jou na te spoor. <ph name="BEGIN_LINK" />Wys in elk geval<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Amptelike bou</translation>
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index 35bf0f84afb..346446590f3 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">የእርስዎን የይለá ቃሠበድርጅትዎ በማይተዳደር ጣቢያ ላይ አስገብተዋáˆá¢ የእርስዎን መለያ ለመጠበቅ ሲባሠየእርስዎን የይለá ቃሠበሌሎች መተáŒá‰ áˆªá‹«á‹Žá‰½ እና ጣቢያዎች ላይ አይጠቀሙበትá¢</translation>
<translation id="1263231323834454256">የንባብ á‹áˆ­á‹áˆ­</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ በዚህ መሣሪያ ላይ የማይቆይ እንቅስቃሴá¦
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />በዚህ መስኮት á‹áˆµáŒ¥ የሚመለከቷቸዠገጾች
+ <ph name="LIST_ITEM" />ኩኪዎች እና የጣቢያ á‹áˆ‚ብ
+ <ph name="LIST_ITEM" />የመለያ መረጃ (<ph name="LINK_BEGIN" />ዘáŒá‰°á‹ á‹­á‹áŒ¡<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">የመá‹áˆ°áŒƒ ስáˆá‰µ</translation>
<translation id="1281476433249504884">á‰áˆáˆ 1</translation>
<translation id="1285320974508926690">ይህን ጣቢያ በጭራሽ አትተርጉáˆ</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">በእርስዎ Google መለያ á‹áˆµáŒ¥ የተከማቹ የይለá ቃላትን ለመጠቀሠይáŒá‰¡</translation>
<translation id="2053111141626950936">በ<ph name="LANGUAGE" /> ያሉ ገጾች አይተረጎሙáˆá¢</translation>
<translation id="2053553514270667976">ዚᕠኮድ</translation>
+<translation id="2054665754582400095">የእርስዎ መገኘት</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 የአስተያየት ጥቆማ}one{# የአስተያየት ጥቆማዎች}other{# የአስተያየት ጥቆማዎች}}</translation>
<translation id="2079545284768500474">ቀáˆá‰¥áˆµ</translation>
<translation id="20817612488360358">የስርዓት ተኪ ቅንብሮች ስራ ላይ እንዲá‹áˆ‰ ተቀናብረዋሠáŒáŠ• áŒáˆáŒ½ የሆአየተኪ á‹á‰…ርሠተገáˆáŒ¿áˆá¢</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">የAndroid መተáŒá‰ áˆªá‹«á‹Žá‰½</translation>
<translation id="2107021941795971877">የህትመት ድጋáŽá‰½</translation>
<translation id="2108755909498034140">ኮáˆá’á‹á‰°áˆ­á‹ŽáŠ• ዳáŒáˆ ያስጀáˆáˆ©á‰µ</translation>
+<translation id="2111166930115883695">ለመጫወት ክáተትን ይጫኑ</translation>
<translation id="2111256659903765347">áˆá‹•áˆˆ-A</translation>
<translation id="2113977810652731515">ካርታ</translation>
<translation id="2114841414352855701">በ<ph name="POLICY_NAME" /> ስለተሻረ ችላ ተብáˆáˆá¢</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">ክáያን ሰርá‹</translation>
<translation id="2147827593068025794">የጀርባ ስáˆáˆ¨á‰µ</translation>
<translation id="2148613324460538318">ካርድ አክáˆ</translation>
+<translation id="2149968176347646218">áŒáŠ•áŠ™áŠá‰µá‹Ž ደህንáŠá‰± የተጠበቀ አይደለáˆ</translation>
<translation id="2154054054215849342">ስáˆáˆ¨á‰µ ለእርስዎ ጎራ አይገáŠáˆ</translation>
<translation id="2154484045852737596">ካርትን ያርትዑ</translation>
<translation id="2161656808144014275">ጽሑá</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">መáˆáˆªá‹«á‹Žá‰½</translation>
<translation id="2183608646556468874">ስáˆáŠ­ á‰áŒ¥áˆ­</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 አድራሻ}one{# አድራሻዎች}other{# አድራሻዎች}}</translation>
-<translation id="2187243482123994665">የተጠቃሚ ተገáŠáŠá‰µ</translation>
<translation id="2187317261103489799">አáŒáŠ (áŠá‰£áˆª)</translation>
<translation id="2188375229972301266">በርካታ ብስ áŒáˆ­áŒŒ</translation>
<translation id="2202020181578195191">ትክክለኛ የአገáˆáŒáˆŽá‰µ ማብቂያ ዓመት ያስገቡ</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">የá‹áˆ¸á‰µ ጣቢያ ከáŠá‰µ አለ</translation>
<translation id="2850739647070081192">áŒá‰¥á‹£ (የደብዳቤ á–ስታ)</translation>
<translation id="2856444702002559011">አጥቂዎች የእርስዎን መረጃ (ለáˆáˆ³áˆŒá¦ የይለá ቃላትንᣠመáˆá‹•áŠ­á‰¶á‰½áŠ•á£ ወይሠየክሬዲት ካርዶችን የመሳሰሉ) ከ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ለመስረቅ እየሞከሩ ሊሆኑ ይችላሉᢠ<ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ይህ ጣቢያ ረባሽ ወይሠአሳሳች ማስታወቂያዎችን ያሳያáˆá¢</translation>
<translation id="2878197950673342043">የá–ስተር እጥá‹á‰µ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">የመስኮት áˆá‹°á‰£</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">በGoogle የቀረቡ ጥቆማ áˆáˆ³á‰¦á‰½</translation>
<translation id="3002501248619246229">የáŒá‰¤á‰µ መሳቢያ ሚዲያን ይመáˆáŠ¨á‰±</translation>
<translation id="3005723025932146533">የተቀመጠ ቅጂ አሳይ</translation>
-<translation id="3007719053326478567">ይህን ይዘት ማተሠበአስተዳዳሪዎ ታáŒá‹·áˆ</translation>
<translation id="3008447029300691911">የ<ph name="CREDIT_CARD" /> ሲቪሲ ያስገቡᢠአንዴ ካረጋገጡ በኋላ የካርድ á‹áˆ­á‹áˆ®á‰½á‹Ž ለዚህ ጣቢያ ይጋራሉá¢</translation>
<translation id="3010559122411665027">የá‹áˆ­á‹áˆ­ áŒá‰¤á‰µ «<ph name="ENTRY_INDEX" />»ᦠ<ph name="ERROR" /></translation>
<translation id="301521992641321250">በራስ-ሰር ታáŒá‹·áˆ</translation>
<translation id="3016780570757425217">የእርስዎን መገኛ አካባቢ ይወá‰</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />ᣠየአስተያየት ጥቆማዎችን ለማስወገድ ትርን ከዚያ አስገባን ይጫኑá¢</translation>
<translation id="3023071826883856138">You4 (የደብዳቤ á–ስታ)</translation>
<translation id="3024663005179499861">የተሳሳተ የመáˆáˆªá‹« አይáŠá‰µ</translation>
<translation id="3037605927509011580">á‹á‹­á£ ተሰናከለ!</translation>
@@ -548,6 +559,7 @@
<translation id="3207960819495026254">á‹•áˆá‰£á‰µ ተደርጎበታáˆ</translation>
<translation id="3209034400446768650">ገጽ ገንዘብ ሊያስከáሠይችሠይሆናáˆ</translation>
<translation id="3212581601480735796">በ<ph name="HOSTNAME" /> ላይ የእርስዎ እንቅስቃሴ á‰áŒ¥áŒ¥áˆ­ እየተደረገበት áŠá‹</translation>
+<translation id="3212623355668894776">የአሰሳ እንቅስቃሴዎ ከዚህ መሣሪያ እንዲሰረዠáˆáˆ‰áŠ•áˆ የእንáŒá‹³ መስኮቶች á‹­á‹áŒ‰á¢</translation>
<translation id="3215092763954878852">WebAuthn ን መጠቀሠአáˆá‰°á‰»áˆˆáˆ</translation>
<translation id="3218181027817787318">አንጻራዊ</translation>
<translation id="3225919329040284222">አገáˆáŒ‹á‹© አብረዠየተሰሩ የሚጠበበማሟያዎችን የማያሟላ የእá‹á‰…ና ማረጋገጫ áŠá‹ ያቀረበá‹á¢ እáŠá‹šáˆ… የሚጠበበማሟያዎች እርስዎን ለመጠበቅ ለተረጋገጡ ከáተኛ ደህንáŠá‰µ ላላቸዠድር ጣቢያዎች ተካትተዋáˆá¢</translation>
@@ -695,6 +707,7 @@
<translation id="3784372983762739446">የብሉቱዠመሣሪያዎች</translation>
<translation id="3787705759683870569">በ<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> ላይ የአገáˆáŒáˆŽá‰µ ጊዜዠያበቃáˆ</translation>
<translation id="3789155188480882154">መጠን 16</translation>
+<translation id="3789841737615482174">ጫን </translation>
<translation id="3793574014653384240">በቅርቡ ያጋጠሙ ብáˆáˆ½á‰¶á‰½ ብዛት እና áˆáŠ­áŠ•á‹«á‰³á‰¸á‹</translation>
<translation id="3797522431967816232">Prc3 (የደብዳቤ á–ስታ)</translation>
<translation id="3799805948399000906">ቅርጸ-á‰áˆáŠ ተጠይቋáˆ</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">ቀይ ቡናማ</translation>
<translation id="4058922952496707368">á‰áˆá «<ph name="SUBKEY" />»ᦠ<ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (የደብዳቤ á–ስታ)</translation>
+<translation id="4067669230157909013">የማያ ገጽ ቀረጻ ከቆመበት ቀጥáˆáˆá¢</translation>
<translation id="4067947977115446013">የሚሰራ አድራሻ ያስገቡ</translation>
<translation id="4072486802667267160">የእርስዎን ትዕዛዠመሥራት ላይ የሆአስህተት áŠá‰ áˆ­á¢ እባክዎ እንደገና ይሞክሩá¢</translation>
<translation id="4075732493274867456">ደንበኛዠእና አገáˆáŒ‹á‹© የተለመደ የኤስኤስኤሠá•áˆ®á‰¶áŠ®áˆ ስሪት ወይሠየስአመሰá‹áˆ­ ጥቅሠአይደáŒá‰áˆá¢</translation>
@@ -827,6 +841,7 @@
<translation id="4297502707443874121">የገጽ <ph name="THUMBNAIL_PAGE" /> ድንክዬ</translation>
<translation id="42981349822642051">ዘርጋ</translation>
<translation id="4300675098767811073">በርካታ ብስ ቀáŠ</translation>
+<translation id="4302514097724775343">ለማጫወት ዲኖá‹áŠ• መታ ያድርጉ</translation>
<translation id="4302965934281694568">Chou3 (የደብዳቤ á–ስታ)</translation>
<translation id="4305666528087210886">የእርስዎ á‹á‹­áˆ ሊደርስበት አáˆá‰°á‰»áˆˆáˆ</translation>
<translation id="4305817255990598646">ቀይር</translation>
@@ -889,7 +904,7 @@
<translation id="4552089082226364758">ብáˆáŒ­á‰³</translation>
<translation id="4558551763791394412">ቅጥያዎችዎን አሰናክለዠይሞክሩá¢</translation>
<translation id="4559332380232738994">10x11</translation>
-<translation id="457875822857220463">መላኪያ</translation>
+<translation id="457875822857220463">ማድረስ</translation>
<translation id="4579056131138995126">የáŒáˆ (የደብዳቤ á–ስታ)</translation>
<translation id="4582204425268416675">ካርድ አስወáŒá‹µ</translation>
<translation id="4587425331216688090">አድራሻ ከChrome ይወገድ?</translation>
@@ -905,6 +920,7 @@
<translation id="4658638640878098064">ከላይ በቀአበኩሠስቴá•áˆˆáˆ­ áˆá‰³</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">áˆáŠ“ባዊ እá‹áŠá‰³</translation>
+<translation id="4675657451653251260">በእንáŒá‹³ áˆáŠá‰³ á‹áˆµáŒ¥ ማንኛá‹áˆ የChrome መገለጫ መረጃን አያዩáˆá¢ እንደ የይለá ቃላት እና የክáá‹« ዘዴዎች ያሉ የGoogle መለያዎን መረጃ ለመድረስ <ph name="LINK_BEGIN" />በመለያ መáŒá‰£á‰µ<ph name="LINK_END" /> ይችላሉá¢</translation>
<translation id="467662567472608290">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠስህተቶች አሉበትᢠይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="4677585247300749148"><ph name="URL" /> ለተደራሽáŠá‰µ ክስተቶች áˆáˆ‹áˆ½ መስጠት á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="467809019005607715">Google ስላይዶች</translation>
@@ -932,6 +948,12 @@
<translation id="4761104368405085019">ማይክáŽáˆ®áŠ•á‹ŽáŠ• ይጠቀማáˆ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ላይ ያለዠድረ-ገጽ ለጊዜዠየማይሰራ ወይሠእስከመጨረሻዠወደ አዲስ የድር አድራሻ ተዛá‹áˆ® ሊሆን ይችላáˆá¢</translation>
<translation id="4766713847338118463">ድርብ ከታች ስቴá•áˆˆáˆ­ áˆá‰³</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ በዚህ መሣሪያ ላይ የሚቆየዠየእርስዎ እንቅስቃሴ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />በዚህ መስኮት á‹áˆµáŒ¥ የሚያወርዷቸዠማናቸá‹áˆ á‹á‹­áˆŽá‰½
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">á‹«áˆá‰³á‹ˆá‰€ ስህተት ተከስቷáˆá¢</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ብቅ-ባይ ታáŒá‹·áˆ}one{# ብቅ-ባዮች ታáŒá‹·áˆ}other{# ብቅ-ባዮች ታáŒá‹·áˆ}}</translation>
<translation id="4780366598804516005">የመáˆá‹•áŠ­á‰µ ሳጥን 1</translation>
@@ -1094,11 +1116,13 @@
<translation id="5386426401304769735">የዚህ ጣቢያ የዕá‹á‰…ና ማረጋገጫ ሰንሰለቱ SHA-1 በመጠቀሠየተáˆáˆ¨áˆ˜ የዕá‹á‰…ና ማረጋገጫን ያካትታáˆá¢</translation>
<translation id="538659543871111977">A4-ትር</translation>
<translation id="5396631636586785122">ቀአጫáን ስá‹</translation>
+<translation id="5398772614898833570">ማስታወቂያዎች ታáŒá‹°á‹‹áˆ</translation>
<translation id="5400836586163650660">áŒáˆ«áŒ«</translation>
<translation id="540969355065856584">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠበዚህ ጊዜ ላይ የሚሰራ አይደለáˆá¢ ይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="541416427766103491">á‰áˆáˆ 4</translation>
<translation id="5421136146218899937">የአሰሳ á‹áˆ‚ብ አጽዳ…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ማሳወቂያዎችን ለእርስዎ መላክ á‹­áˆáˆáŒ‹áˆ</translation>
+<translation id="542872847390508405">እያሰሱ ያለዠእንደ እንáŒá‹³ áŠá‹</translation>
<translation id="5430298929874300616">á‹•áˆá‰£á‰µ አስወáŒá‹µ</translation>
<translation id="5439770059721715174">«<ph name="ERROR_PATH" />» ላይ የብያኔ ማረጋገጥ ስህተትᦠ<ph name="ERROR" /></translation>
<translation id="5443468954631487277">ተቃራኒ ቅደáˆ-ተከተሠáŠá‰± ወደ ላይ</translation>
@@ -1140,12 +1164,12 @@
<translation id="5571083550517324815">ከዚህ አድራሻ ላይ መá‹áˆ°á‹µ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="5580958916614886209">የእርስዎን የአገáˆáŒáˆŽá‰µ ማብቂያ ወር ይመáˆáŠ¨á‰± እና እንደገና ይሞክሩ</translation>
<translation id="5586446728396275693">áˆáŠ•áˆ የተቀመጡ አድራሻዎች የሉáˆ</translation>
+<translation id="5593349413089863479">áŒáŠ•áŠ™áŠá‰µ ሙሉ በሙሉ ደህንáŠá‰± የተጠበቀ አይደለáˆ</translation>
<translation id="5595485650161345191">አድራሻ አርትዕ</translation>
<translation id="5598944008576757369">የመክáˆá‹« ዘዴ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="560412284261940334">አስተዳደር አይደገááˆ</translation>
<translation id="5605670050355397069">ሌጀር</translation>
<translation id="5607240918979444548">ስáŠ-ሕንጻ-C</translation>
-<translation id="5608165884683734521">ይህ ጣቢያ áˆáˆ°á‰°áŠ› ወይሠአጭበርባሪ ሊሆን ይችላáˆá¢ Chrome አáˆáŠ‘ኑ ትቶ መá‹áŒ£á‰µáŠ• ይመክራáˆá¢</translation>
<translation id="5610142619324316209">áŒáŠ•áŠ™áŠá‰±áŠ• መáˆá‰°áˆ½</translation>
<translation id="5610807607761827392">ካርዶችን እና አድራሻዎችን በ<ph name="BEGIN_LINK" />ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ማቀናበር ይችላሉá¢</translation>
<translation id="561165882404867731">በGoogle ትርጉሠአማካáŠáŠá‰µ ይህን ገጽ ይተርጉሙ</translation>
@@ -1217,6 +1241,7 @@
<translation id="5901630391730855834">ቢጫ</translation>
<translation id="5905445707201418379">በ <ph name="ORIGIN" /> የደህንáŠá‰µ መመሪያ መሠረት ታáŒá‹·áˆá¢</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ሰáˆáˆ¯áˆ)</translation>
+<translation id="5913377024445952699">የማያ ገጽ ቀረጻ ባለበት ቆሟáˆ</translation>
<translation id="59174027418879706">áŠá‰…ቷáˆ</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">አብራ</translation>
@@ -1229,6 +1254,7 @@
<translation id="5963413905009737549">ክááˆ</translation>
<translation id="5967592137238574583">የዕá‹á‰‚á‹« መረጃን ያርትዑ</translation>
<translation id="5967867314010545767">ከታሪክ አስወáŒá‹µ</translation>
+<translation id="5968793460449681917">በእያንዳንዱ ጉብáŠá‰µ ላይ</translation>
<translation id="5975083100439434680">አሳንስ</translation>
<translation id="5979084224081478209">የይለá ቃላትዎን á‹­áˆá‰µáˆ¹</translation>
<translation id="5980920751713728343">መረጃ ጠቋሚ-3x5</translation>
@@ -1384,6 +1410,7 @@
<translation id="6587923378399804057">እርስዎ የቀዱት አገናáŠ</translation>
<translation id="6591833882275308647">የእርስዎ <ph name="DEVICE_TYPE" /> የሚተዳደር አይደለáˆ</translation>
<translation id="6596325263575161958">የáˆáˆµáŒ áˆ« አማራጮች</translation>
+<translation id="6596892391065203054">ይህን ይዘት ማተሠበአስተዳዳሪዎ ታáŒá‹·áˆá¢</translation>
<translation id="6604181099783169992">የእንቅስቃሴ ወይሠየብርሃን ዳሳሾች</translation>
<translation id="6609880536175561541">Prc7 (የደብዳቤ á–ስታ)</translation>
<translation id="6612358246767739896">ጥበቃ የሚደረáŒáˆˆá‰µ ይዘት</translation>
@@ -1443,6 +1470,7 @@
<translation id="6895330447102777224">የእርስዎ ካርድ ተረጋáŒáŒ§áˆ</translation>
<translation id="6897140037006041989">የተጠቀሚ ተወካይ</translation>
<translation id="6898699227549475383">ድርጅት (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> ይህን እንዲያደርጠይáቀዱá¦</translation>
<translation id="6910240653697687763"><ph name="URL" /> የእርስዎን MIDI መሳሪያዎች ሙሉ በሙሉ መቆጣጠር á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="6915804003454593391">ተጠቃሚá¦</translation>
<translation id="6934672428414710184">ይህ ስሠከእርስዎ Google መለያ የተገኘ áŠá‹</translation>
@@ -1554,6 +1582,7 @@
<translation id="7346048084945669753">ከዚህ ጋር áŒáŠ•áŠ™áŠá‰µ አለá‹á¦</translation>
<translation id="7349430561505560861">A4-ተጨማሪ</translation>
<translation id="7353601530677266744">የትእዛዠመስመር</translation>
+<translation id="7359588939039777303">ማስታወቂያዎች ታáŒá‹°á‹‹áˆá¢</translation>
<translation id="7372973238305370288">የáለጋ á‹áŒ¤á‰µ</translation>
<translation id="7374733840632556089">ይህ ችáŒáˆ­ የተáˆáŒ áˆ¨á‹ በእርስዎ ወይሠበሌላ ሰዠበእርስዎ መሣሪያ ላይ በተጫአየዕá‹á‰…ና ማረጋገጫ áˆáŠ­áŠ•á‹«á‰µ áŠá‹á¢ ይህ የዕá‹á‰…ና ማረጋገጫ አá‹á‰³áˆ¨ መረቦችን እንደሚከታተሠእና አቋርጦ እንደሚገባ የታወቀ áŠá‹ እና በChrome የታመአአይደለáˆá¢ ክትትሠለማድረጠእንደ ትáˆáˆ…ርት ቤት ወይሠየኩባንያ አá‹á‰³áˆ¨ መረብ በመሳሰሉ አንዳንድ ሕጋዊ አስáˆáˆ‹áŒŠ áˆáŠ­áŠ•á‹«á‰¶á‰½ ቢኖሩሠChrome ይህ እየተáˆáŒ áˆ¨ እንዳለ áˆáŠ•áˆ እንኳ እርስዎ ሊያስቆሙት ባይችሉሠእንዲያá‹á‰á‰µ ማድረጠይáˆáˆáŒ‹áˆá¢ ክትትሠማድረጠበማናቸá‹áˆ ድሩን በሚደርስ አሳሽ ወይሠመተáŒá‰ áˆªá‹« ላይ ሊያጋጥሠይችሠይሆናáˆá¢</translation>
<translation id="7375818412732305729">á‹á‹­áˆ ተያይዟáˆ</translation>
@@ -1728,6 +1757,7 @@
<translation id="7976214039405368314">በጣሠብዙ ጥያቄዎች</translation>
<translation id="7977538094055660992">የá‹áŒ½á‹“ት መሣሪያ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">የትክክለኛ እá‹áŠá‰³ ይዘትን ለማየት ARCore ይጫኑ</translation>
<translation id="799149739215780103">ጠርá‹</translation>
<translation id="7995512525968007366">አáˆá‰°áŒ á‰€áˆ°áˆ</translation>
<translation id="800218591365569300">የማህደረ ትá‹áˆµá‰³ ቦታን ለማስለቀቅ ሌሎች ትሮችን ወይሠá•áˆ®áŒáˆ«áˆžá‰½áŠ• ዘáŒá‰°á‹ ይሞክሩá¢</translation>
@@ -1855,25 +1885,39 @@
<translation id="8507227106804027148">የትዕዛዠመስመር</translation>
<translation id="8508648098325802031">የáለጋ አዶ</translation>
<translation id="8522552481199248698">Chrome የGoogle መለያዎን እንዲጠብበእና የይለá ቃáˆá‹ŽáŠ• እንዲቀይሩት á‹«áŒá‹˜á‹Žá‰³áˆá¢</translation>
+<translation id="8525306231823319788">ሙሉ ማያ ገጽ</translation>
<translation id="8530813470445476232">የእርስዎን የአሰሳ ታሪክᣠኩኪዎችᣠመሸጎጫዎች እና ተጨማሪ በChrome ቅንብሮች á‹áˆµáŒ¥ ያጽዱ</translation>
<translation id="8533619373899488139">የታገዱ የዩአርኤሎች á‹áˆ­á‹áˆ­ እና ሌሎች በሥርዓት አስተዳዳሪዎ አስገዳጅáŠá‰µ የተሰጣቸዠመመሪያዎችን ለማየት &lt;strong&gt;chrome://policy&lt;/strong&gt;ን ይጎብኙá¢</translation>
<translation id="8541158209346794904">የብሉቱዠመሣሪያ</translation>
<translation id="8542014550340843547">ሦስቴ ከታች በስቴá•áˆˆáˆ­ áˆá‰³</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />የáˆáˆáŒŽ ማáŒáŠ˜á‰µ ችáŒáˆ­áŠ• ሪá–ርት ማድረáŒ<ph name="END_ERROR_LINK" />ᣠወይሠደáŒáˆž በእርስዎ ደህንáŠá‰µ ላይ ሊያስከትሠየሚችለá‹áŠ• አደጋ ከተረዱ <ph name="BEGIN_LINK" />ይህን ደህንáŠá‰± á‹«áˆá‰°áŒ á‰ á‰€ ጣቢያ መጎብኘት<ph name="END_LINK" /> ይችላሉá¢</translation>
<translation id="8557066899867184262">CVC ከካርድዎ በስተጀርባ ላይ ይገኛáˆá¢</translation>
+<translation id="8558485628462305855">የትክክለኛ እá‹áŠá‰³ ይዘትን ለማየት ARCore ያዘáˆáŠ‘</translation>
<translation id="8559762987265718583">የእርስዎ መሣሪያ ቀን (<ph name="DATE_AND_TIME" />) áˆáŠ­ ስላáˆáˆ†áŠ ወደ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> የáŒáˆ áŒáŠ•áŠ™áŠá‰µ መመስረት አይቻáˆáˆá¢</translation>
<translation id="8564182942834072828">የተለዩ ሰáŠá‹¶á‰½/á‹«áˆá‰°áŒ£áˆ˜áˆ© ቅጂዎች</translation>
<translation id="8564985650692024650">Chromium የእርስዎን የ<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ይለá ቃሠበሌሎች ጣቢያዎች ላይ ዳáŒáˆ ከተጠቀሙበት እንደገና እንዲያዋቅሩት ይመክራáˆá¢</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ በዚህ መሣሪያ ላይ የማይቆይ እንቅስቃሴá¦
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />በዚህ መስኮት á‹áˆµáŒ¥ የሚመለከቷቸዠገጾች
+ <ph name="LIST_ITEM" />ኩኪዎች እና የጣቢያ á‹áˆ‚ብ
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ካርዶችን በበለጠ áጥáŠá‰µ ለማረጋገጥ የንኪ መታወቂያን ይጠቀሙ</translation>
<translation id="858637041960032120">ስáˆáŠ­ á‰áŒ¥áˆ­ ያክሉ
</translation>
<translation id="8589998999637048520">áˆáˆ­áŒ¥ ጥራት</translation>
+<translation id="8600271352425265729">አáˆáŠ• ብቻ</translation>
<translation id="860043288473659153">የካርድ á‹«á‹¢ ስáˆ</translation>
<translation id="8606726445206553943">የእርስዎን የ MIDI መሣሪያዎች ይጠቀሙ</translation>
+<translation id="8612761427948161954">ሰላሠ<ph name="USERNAME" />á£
+ <ph name="BR" />
+ እንደ እንáŒá‹³ ሆáŠá‹ እያሰሱ áŠá‹</translation>
<translation id="861775596732816396">መጠን 4</translation>
<translation id="8622948367223941507">የህáŒ-ተጨማሪ</translation>
<translation id="8623885649813806493">áˆáŠ•áˆ ተዛማጅ የይለá ቃላት የሉáˆá¢ áˆáˆ‰áŠ•áˆ የተቀመጡ የይለá ቃላትን አሳይá¢</translation>
<translation id="8625384913736129811">ይህን ካርድ ወደዚህ መሣሪያ አስቀáˆáŒ¥</translation>
+<translation id="8627040765059109009">የማያ ገጽ ቀረጻ ከቆመበት ቀጥáˆáˆ</translation>
<translation id="8657078576661269990">የእርስዎ አስተዳዳሪ ከ<ph name="ORIGIN_NAME" /> ለ<ph name="VM_NAME_1" /> እና <ph name="VM_NAME_2" /> ማጋራትን አáŒá‹°á‹‹áˆ</translation>
<translation id="8663226718884576429">የትዕዛዠማጠቃለያᣠ<ph name="TOTAL_LABEL" />ᣠተጨማሪ á‹áˆ­á‹áˆ®á‰½</translation>
<translation id="867224526087042813">áŠáˆ­áˆ›</translation>
@@ -1936,6 +1980,7 @@
<translation id="8912362522468806198">የGoogle መለያ</translation>
<translation id="8913778647360618320">የክáá‹« ዘዴዎች አá‹áˆ«áˆ­áŠ• ያቀናብሩᣠየእርስዎን ክáያዎች እና የክሬዲት ካርድ መረጃ በChrome ቅንብሮች á‹áˆµáŒ¥ ለማቀናበር አስገባን ይጫኑ</translation>
<translation id="8918231688545606538">ይህ ገጽ አጠራጣሪ áŠá‹</translation>
+<translation id="8922013791253848639">áˆáˆáŒŠá‹œ በዚህ ጣቢያ ላይ ማስታወቂያዎችን አሳይ</translation>
<translation id="892588693504540538">ከላይ ቀአበኩሠብሳ</translation>
<translation id="8931333241327730545">ይህን ካርድ በእርስዎ የGoogle መለያ ላይ ማስቀመጥ á‹­áˆáˆáŒ‹áˆ‰?</translation>
<translation id="8932102934695377596">የእርስዎ ሰዓት ወደ ኋላ ቀርቷáˆ</translation>
@@ -2007,6 +2052,7 @@
<translation id="9183302530794969518">Google ሰáŠá‹µ</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> የማይጠቀሠá•áˆ®á‰¶áŠ®áˆ ይጠቀማáˆá¢</translation>
<translation id="9191834167571392248">áŒáˆ« በኩሠከታች ብሳ</translation>
+<translation id="9199905725844810519">ማተሠታáŒá‹·áˆ</translation>
<translation id="9205078245616868884">የእርስዎ á‹áˆ‚ብ በእርስዎ የስáˆáˆ¨á‰µ የይለá ቃሠተመስጥሯáˆá¢ ስáˆáˆ¨á‰µáŠ• ለመጀመር ያስገቡትá¢</translation>
<translation id="9207861905230894330">ጽሑá ማከሠአáˆá‰°á‰»áˆˆáˆá¢</translation>
<translation id="9213433120051936369">ገጽታን ያብáŒ</translation>
@@ -2017,8 +2063,10 @@
<translation id="936474030629450166">áˆá‹•áˆˆ-B</translation>
<translation id="936602727769022409">የGoogle መለያዎን መዳረሻ ሊያጡ ይችላሉᢠChromium የይለá ቃáˆá‹ŽáŠ• አáˆáŠ‘ኑ እንዲቀይሩት ይመክራáˆá¢ በመለያ እንዲገቡ ይጠየቃሉá¢</translation>
<translation id="939736085109172342">አዲስ ዓቃáŠ</translation>
+<translation id="945522503751344254">áŒá‰¥áˆ¨áˆ˜áˆáˆµ ላክ</translation>
<translation id="945855313015696284">ከዚህ በታች ያለá‹áŠ• መረጃ á‹­áˆá‰µáˆ¹ እና ማናቸá‹áŠ•áˆ áˆáŠ­ á‹«áˆáˆ†áŠ‘ ካርዶች ይሰርዙ</translation>
<translation id="950736567201356821">ሦስቴ ከላይ ብሳ</translation>
+<translation id="951941430552851965">በማያ ገጽዎ ላይ ባለዠይዘት áˆáŠ­áŠ•á‹«á‰µ የማያ ገጽ ቀረጻ በአስተዳዳሪዎ ባለበት ቆሟáˆá¢</translation>
<translation id="961663415146723894">ከታች ጠርá‹</translation>
<translation id="962484866189421427">ይህ ይዘት የሆአሌላ áŠáŒˆáˆ­ እንደሆኑ የሚያስመስሉ አጭበርባሪ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• ወይሠእርስዎን ለመከታተሠጥቅሠላይ ሊá‹áˆ የሚችሠá‹áˆ‚ብን የሚሰበስቡ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• ለመጫን ሊሞክር ይችሠይሆናáˆá¢ <ph name="BEGIN_LINK" />የሆáŠá‹ ሆኖ አሳይ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">á‹­á‹ áŒáŠ•á‰£á‰³</translation>
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index f4e08373f65..37c4d13346a 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">لقد أدخلتَ كلمة المرور ÙÙŠ موقع إلكتروني لا تديره مؤسستك. ينصح بعدم استخدام كلمة المرور مجددًا ÙÙŠ التطبيقات ومواقع الويب الأخرى لحماية حسابك.</translation>
<translation id="1263231323834454256">قائمة القراءة</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ النشاطات التي لن يتم Ø­Ùظها على هذا الجهاز:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />الصÙحات التي تعرضها ÙÙŠ هذه الناÙذة
+ <ph name="LIST_ITEM" />ملÙات تعري٠الارتباط وبيانات الموقع الإلكتروني
+ <ph name="LIST_ITEM" />معلومات الحساب (<ph name="LINK_BEGIN" />تسجيل الخروج<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">طريقة الاستلام</translation>
<translation id="1281476433249504884">المكدّÙس 1</translation>
<translation id="1285320974508926690">عدم ترجمة هذا الموقع مطلقًا</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">â€ÙŠÙرجى تسجيل الدخول لاستخدام كلمات المرور المحÙوظة ÙÙŠ حسابك على Google.</translation>
<translation id="2053111141626950936">لن تتم ترجمة الصÙحات باللغة <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">الرمز البريدي</translation>
+<translation id="2054665754582400095">متى تستخدم جهازك</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{اقتراح واحد}zero{# اقتراح}two{اقتراحان (#)}few{# اقتراحات}many{# اقتراحًا}other{# اقتراح}}</translation>
<translation id="2079545284768500474">تراجع</translation>
<translation id="20817612488360358">تم ضبط إعدادات الخادم الوكيل ليتم استخدامها وتم أيضًا تحديد إعداد صريح للخادم الوكيل.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">â€ØªØ·Ø¨ÙŠÙ‚ات Android</translation>
<translation id="2107021941795971877">دعم الطباعة</translation>
<translation id="2108755909498034140">إعادة تشغيل جهاز الكمبيوتر</translation>
+<translation id="2111166930115883695">اضغط على Ù…Ùتاح المساÙØ© لبدء اللعب.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">البطاقة</translation>
<translation id="2114841414352855701">تم تجاهلها نظرًا لتجاوزها بواسطة <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">إلغاء الدÙع</translation>
<translation id="2147827593068025794">المزامنة ÙÙŠ الخلÙية</translation>
<translation id="2148613324460538318">إضاÙØ© بطاقة</translation>
+<translation id="2149968176347646218">الاتصال بهذا الموقع الإلكتروني غير آمن</translation>
<translation id="2154054054215849342">المزامنة غير متاحة لنطاقك</translation>
<translation id="2154484045852737596">تعديل البطاقة</translation>
<translation id="2161656808144014275">نص</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">السياسات</translation>
<translation id="2183608646556468874">رقم الهاتÙ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{عنوان واحد}zero{# عنوان}two{عنوانان (#)}few{# عناوين}many{# عنوانًا}other{# عنوان}}</translation>
-<translation id="2187243482123994665">استخدام الجهاز</translation>
<translation id="2187317261103489799">اكتشا٠(تلقائي)</translation>
<translation id="2188375229972301266">عمل عدة ثقوب ÙÙŠ الأسÙÙ„</translation>
<translation id="2202020181578195191">أدخÙÙ„ سنة تاريخ انتهاء صلاحية صحيحة</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">الموقع الذي تطلب الدخول إليه مزيّÙ</translation>
<translation id="2850739647070081192">دعوة (مغلÙ)</translation>
<translation id="2856444702002559011">قد يحاول المهاجمون سرقة معلوماتك من <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (مثل كلمات المرور أو الرسائل أو بطاقات الائتمان). <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">يعرض هذا الموقع الإلكتروني إعلانات مضلّÙلة أو غير مرغوب Ùيها.</translation>
<translation id="2878197950673342043">الطي على شكل ملصق</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">موضÙع الناÙذة</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">â€Ø§Ù‚تراحات من Google</translation>
<translation id="3002501248619246229">التحقق من دÙرج وسائل الإعلام</translation>
<translation id="3005723025932146533">عرض نسخة محÙوظة</translation>
-<translation id="3007719053326478567">حظر المشر٠إمكانية طباعة هذا المحتوى.</translation>
<translation id="3008447029300691911">â€Ø£Ø¯Ø®ÙÙ„ رمز التحقّق (CVC) لبطاقة <ph name="CREDIT_CARD" />. بعد تأكيدك، ستتم مشاركة تÙاصيل بطاقتك مع هذا الموقع.</translation>
<translation id="3010559122411665027">إدخال القائمة "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">تم الحظر تلقائيًا</translation>
<translation id="3016780570757425217">معرÙØ© موقعك</translation>
+<translation id="3017086357773116182">â€<ph name="REMOVE_SUGGESTION_SUFFIX" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم على Ù…Ùتاح Enter لإزالة هذا الاقتراح.</translation>
<translation id="3023071826883856138">â€You4 (مغلÙ)</translation>
<translation id="3024663005179499861">نوع السياسة غير صحيح</translation>
<translation id="3037605927509011580">عذرًا!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">تمت إضاÙتها إلى الإشارات المرجعية.</translation>
<translation id="3209034400446768650">إمكانية تحصيل الصÙحة للرسوم</translation>
<translation id="3212581601480735796">تتم مراقبة نشاطك على <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">عند إغلاق جميع نواÙØ° الضيÙØŒ سيتم حذ٠نشاط التصÙّح من هذا الجهاز.</translation>
<translation id="3215092763954878852">â€ØªØ¹Ø°Ù‘ر استخدام WebAuthn</translation>
<translation id="3218181027817787318">نسبي</translation>
<translation id="3225919329040284222">قدم الخادم شهادة لا تتطابق مع التوقعات المضمّنة. تم تضمين هذه التوقعات للحصول على مواقع إلكترونية موثوقة وآمنة جدًا لتوÙير الحماية لك.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">أجهزة بلوتوث</translation>
<translation id="3787705759683870569">تنتهي ÙÙŠ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">الحجم 16</translation>
+<translation id="3789841737615482174">تثبيت</translation>
<translation id="3793574014653384240">أعداد الأعطال التي حدثت مؤخرًا على الجهاز وأسبابها</translation>
<translation id="3797522431967816232">â€Prc3 (مغلÙ)</translation>
<translation id="3799805948399000906">الخط المطلوب</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">بني داكن</translation>
<translation id="4058922952496707368">المÙتاح "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">â€C1 (مغلÙ)</translation>
+<translation id="4067669230157909013">تم استئنا٠وضع "تصوير الشاشة".</translation>
<translation id="4067947977115446013">إضاÙØ© عنوان صالح</translation>
<translation id="4072486802667267160">حدث خطأ أثناء معالجة طلبك. ÙŠÙرجى إعادة المحاولة.</translation>
<translation id="4075732493274867456">لا يدعم كل من العميل والخادم مجموعة ترميز أو إصدار بروتوكول طبقة المقابس الآمنة الشائع.</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">صورة مصغّرة لصÙحة <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">توسيع</translation>
<translation id="4300675098767811073">عمل عدة ثقوب يمينًا</translation>
+<translation id="4302514097724775343">انقر على الديناصور لبدء اللعب.</translation>
<translation id="4302965934281694568">â€Chou3 (مغلÙ)</translation>
<translation id="4305666528087210886">تعذّر الوصول لملÙÙƒ</translation>
<translation id="4305817255990598646">تبديل</translation>
@@ -915,6 +930,7 @@
<translation id="4658638640878098064">وضع دبوس أعلى اليسار</translation>
<translation id="4668929960204016307">،</translation>
<translation id="4670064810192446073">الواقع الاÙتراضي</translation>
+<translation id="4675657451653251260">â€Ù„Ù† تظهر لك أي معلومات عن المل٠الشخصي ÙÙŠ Chrome ÙÙŠ "وضع الضيÙ". ويمكنك <ph name="LINK_BEGIN" />تسجيل الدخول<ph name="LINK_END" /> للوصول إلى معلومات حسابك على Google مثل كلمات المرور وطرق الدÙع.</translation>
<translation id="467662567472608290">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان تحتوي على أخطاء. وربما يكون السبب ÙÙŠ ذلك خطأ ÙÙŠ التكوين أو مهاجمًا يعترض اتصالك.</translation>
<translation id="4677585247300749148">يريد <ph name="URL" /> الاستجابة لأحداث إمكانية الوصول.</translation>
<translation id="467809019005607715">â€Ø§Ù„عروض التقديمية من Google</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">استخدام الميكروÙون</translation>
<translation id="4764776831041365478">قد تكون صÙحة الويب على العنوان <ph name="URL" /> غير متاحة مؤقتًا أو قد يكون تم نقلها نهائيًا إلى عنوان ويب جديد.</translation>
<translation id="4766713847338118463">وضع دبوسَين بالأسÙÙ„</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ نشاطك الذي سيتم Ø­Ùظه على هذا الجهاز:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />أي ملÙات تنزّÙلها ÙÙŠ هذه الناÙذة
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">حدث خطأ غير محدّد.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{تم حظر ناÙذة منبثقة}zero{تم حظر # ناÙذة منبثقة}two{تم حظر ناÙذتين منبثقتين (#)}few{تم حظر # نواÙØ° منبثقة}many{تم حظر # ناÙذةً منبثقةً}other{تم حظر # ناÙذة منبثقة}}</translation>
<translation id="4780366598804516005">صندوق البريد الإلكتروني 1</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">â€ØªØªØ¶Ù…Ù† سلسلة الشهادات لهذا الموقع شهادة موقعة باستخدام SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">خزم الحوا٠يمينًا</translation>
+<translation id="5398772614898833570">تم حظر الإعلانات</translation>
<translation id="5400836586163650660">رمادي</translation>
<translation id="540969355065856584">لم يتمكن هذا الخادم من إثبات أنه <ph name="DOMAIN" />Ø› بل إن شهادة الأمان الخاصة به غير صالحة حاليًا. وربما يكون السبب ÙÙŠ ذلك وجود خطأ ÙÙŠ التكوين أو اعترض أحد المهاجمين للاتصال.</translation>
<translation id="541416427766103491">المكدّÙس 4</translation>
<translation id="5421136146218899937">محو بيانات التصÙّح...</translation>
<translation id="5426179911063097041">يريد موقع <ph name="SITE" /> إرسال إشعارات إليك.</translation>
+<translation id="542872847390508405">أنت تتصÙØ­ كضيÙ</translation>
<translation id="5430298929874300616">إزالة إشارة مرجعية</translation>
<translation id="5439770059721715174">حدث خطأ ÙÙŠ مصادقة المخطط على "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ترتيب عكسي والوجه للأعلى</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">لا يمكن الاستلام من هذا العنوان. اختَر عنوانًا آخر.</translation>
<translation id="5580958916614886209">تحقق من شهر انتهاء الصلاحية وأعÙد المحاولة مرة أخرى</translation>
<translation id="5586446728396275693">لا توجد عناوين محÙوظة</translation>
+<translation id="5593349413089863479">الاتصال بهذا الموقع الإلكتروني غير آمن تمامًا</translation>
<translation id="5595485650161345191">تعديل العنوان</translation>
<translation id="5598944008576757369">اختيار طريقة الدÙع</translation>
<translation id="560412284261940334">الإدارة غير متوÙرة</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">â€Ù‚د يكون هذا الموقع الإلكتروني مزيÙًا أو احتياليًا. ينصح Chrome بمغادرة هذا الموقع الإلكتروني الآن.</translation>
<translation id="5610142619324316209">التحقق من الاتصال</translation>
<translation id="5610807607761827392">يمكنك إدارة البطاقات والعناوين ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">â€ØªØ±Ø¬Ù…Ø© هذه الصÙحة باستخدام "ترجمة Google"</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">أصÙر</translation>
<translation id="5905445707201418379">تم الحظر ÙˆÙقًا لسياسة المصدر <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (تمت المزامنة)</translation>
+<translation id="5913377024445952699">إيقا٠وضع "التقاط الشاشة" مؤقتًا</translation>
<translation id="59174027418879706">تم التÙعيل</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Ù…Ùعّل</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">قسم</translation>
<translation id="5967592137238574583">تعديل معلومات الاتصال</translation>
<translation id="5967867314010545767">إزالة من السجل</translation>
+<translation id="5968793460449681917">عند كل زيارة</translation>
<translation id="5975083100439434680">تصغير</translation>
<translation id="5979084224081478209">التحقق من كلمات المرور</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">الرابط الذي نسخته</translation>
<translation id="6591833882275308647">لا تتم إدارة <ph name="DEVICE_TYPE" /></translation>
<translation id="6596325263575161958">خيارات التشÙير</translation>
+<translation id="6596892391065203054">حظر المشر٠إمكانية طباعة هذا المحتوى.</translation>
<translation id="6604181099783169992">أجهزة استشعار الإضاءة والحركة</translation>
<translation id="6609880536175561541">â€Prc7 (مغلÙ)</translation>
<translation id="6612358246767739896">المحتوى المحمي</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">تم التأكد من بطاقتك</translation>
<translation id="6897140037006041989">وكيل المستخدم</translation>
<translation id="6898699227549475383">â€Ø§Ù„مؤسسة (O)</translation>
+<translation id="6907293445143367439">السماح للموقع الإلكتروني <ph name="SITE_NAME" /> بإجراء ما يلي:</translation>
<translation id="6910240653697687763">â€ÙŠØ±ÙŠØ¯ <ph name="URL" /> التحكّÙÙ… بالكامل بأجهزة MIDI الخاصة بك.</translation>
<translation id="6915804003454593391">المستخدم:</translation>
<translation id="6934672428414710184">â€Ù‡Ø°Ø§ الاسم من حسابك على Google</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">تابع إلى:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">سطر الأوامر</translation>
+<translation id="7359588939039777303">تم حظر الإعلانات.</translation>
<translation id="7372973238305370288">نتيجة البحث</translation>
<translation id="7374733840632556089">â€ØªØ­Ø¯Ø« هذه المشكلة بسبب شهادة ثبّتها أنت أو ثبّتها مستخدم آخر على جهازك. من المعرو٠أن الشهادة تÙستخدم لمراقبة الشبكات واعتراضها، ولا يثق Chrome بها. وعلى الرغم من وجود بعض الحالات المشروعة للمراقبة، كما هو الحال ÙÙŠ شبكة المدرسة أو الشركة، يريد Chrome التأكد من أنك تدرك حدوث ذلك، حتى لو لم يكن بإمكانك إيقاÙÙ‡. يمكن أن تحدث عملية المراقبة ÙÙŠ أي متصÙّح أو تطبيق يصل إلى الويب.</translation>
<translation id="7375818412732305729">تم إرÙاق ملÙ</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">عدد الطلبات كبير جدًا.</translation>
<translation id="7977538094055660992">جهاز إخراج</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">â€Ù„عرض محتوى الواقع المÙعزَّز، ÙŠÙرجى تثبيت ARCore</translation>
<translation id="799149739215780103">التجليد</translation>
<translation id="7995512525968007366">غير محدد</translation>
<translation id="800218591365569300">جرّب إغلاق علامات التبويب أو البرامج الأخرى لتÙريغ مساحة من الذاكرة.</translation>
@@ -1865,25 +1895,39 @@
<translation id="8507227106804027148">سطر الأوامر</translation>
<translation id="8508648098325802031">رمز البحث</translation>
<translation id="8522552481199248698">â€ÙŠÙ…كن أن يساعدك Chrome على حماية حسابك على Google وتغيير كلمة المرور.</translation>
+<translation id="8525306231823319788">ملء الشاشة</translation>
<translation id="8530813470445476232">â€Ù…حو سجلّ التصÙÙ‘ÙØ­ وملÙات تعري٠الارتباط وذاكرة التخزين المؤقت وغير ذلك ÙÙŠ إعدادات متصÙÙ‘ÙØ­ Chrome</translation>
<translation id="8533619373899488139">â€Ø§Ù†ØªÙ‚ÙÙ„ إلى &lt;strong&gt;chrome://policy&lt;/strong&gt; للاطّلاع على قائمة عناوين URL المحظورة والسياسات الأخرى التي ÙŠÙرضها مشر٠النظام.</translation>
<translation id="8541158209346794904">جهاز بلوتوث</translation>
<translation id="8542014550340843547">وضع ثلاثة دبابيس ÙÙŠ الأسÙÙ„</translation>
<translation id="8543181531796978784">يمكنك <ph name="BEGIN_ERROR_LINK" />الإبلاغ عن اكتشا٠مشكلة<ph name="END_ERROR_LINK" /> أو، إذا كنت تدرك المخاطر المتعلقة بالأمان، يمكنك <ph name="BEGIN_LINK" />زيارة هذا الموقع غير الآمن<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">â€Ø±Ù…ز التحقق من البطاقة (CVC) موجود خل٠بطاقتك.</translation>
+<translation id="8558485628462305855">â€Ù„عرض محتوى الواقع المÙعزَّز، ÙŠÙرجى تحديث ARCore</translation>
<translation id="8559762987265718583">تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن التاريخ والوقت للجهاز (<ph name="DATE_AND_TIME" />) غير صحيحين.</translation>
<translation id="8564182942834072828">مستندات Ù…Ùصولة/Ù†Ùسخ Ù…Ùصولة</translation>
<translation id="8564985650692024650">â€ÙŠÙوصي Chromium بإعادة تحديد كلمة المرور <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÙÙŠ حال إعادة استخدامها ÙÙŠ مواقع إلكترونية أخرى.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ النشاطات التي لن يتم Ø­Ùظها على هذا الجهاز:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />الصÙحات التي تعرضها ÙÙŠ هذه الناÙذة
+ <ph name="LIST_ITEM" />ملÙات تعري٠الارتباط وبيانات الموقع الإلكتروني
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">استخدام رقم التعري٠باللمس للتأكد من البطاقات بشكل٠أسرع</translation>
<translation id="858637041960032120">إضاÙØ© رقم هاتÙ
</translation>
<translation id="8589998999637048520">Ø£Ùضل جودة</translation>
+<translation id="8600271352425265729">هذه المرَّة Ùقط</translation>
<translation id="860043288473659153">اسم حامل البطاقة</translation>
<translation id="8606726445206553943">â€Ø§Ø³ØªØ®Ø¯Ø§Ù… أجهزة MIDI</translation>
+<translation id="8612761427948161954">مرحبًا <ph name="USERNAME" />،
+ <ph name="BR" />
+ أنت تتصÙّح ÙÙŠ "وضع الضيÙ".</translation>
<translation id="861775596732816396">الحجم 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ما Ù…ÙÙ† كلمات مرور مطابقة. يمكنك عرض جميع كلمات المرور المحÙوظة.</translation>
<translation id="8625384913736129811">Ø­Ùظ هذه البطاقة إلى هذا الجهاز</translation>
+<translation id="8627040765059109009">استئنا٠وضع "التقاط الشاشة"</translation>
<translation id="8657078576661269990">حظر المشر٠إمكانية المشاركة من <ph name="ORIGIN_NAME" /> إلى <ph name="VM_NAME_1" /> و<ph name="VM_NAME_2" />.</translation>
<translation id="8663226718884576429">ملخّص الطلب Ùˆ<ph name="TOTAL_LABEL" /> وتÙاصيل إضاÙية</translation>
<translation id="867224526087042813">التوقيع</translation>
@@ -1946,6 +1990,7 @@
<translation id="8912362522468806198">â€Ø­Ø³Ø§Ø¨ Googleâ€</translation>
<translation id="8913778647360618320">â€Ø²Ø± "إدارة Ø·Ùرق الدÙع"ØŒ اضغط على Ù…Ùتاح Enter لإدارة الدÙعات ومعلومات بطاقة الائتمان ÙÙŠ إعدادات Chrome.</translation>
<translation id="8918231688545606538">هذه الصÙحة مريبة</translation>
+<translation id="8922013791253848639">السماح دائمًا بالإعلانات على هذا الموقع</translation>
<translation id="892588693504540538">عمل ثقب أعلى اليمين</translation>
<translation id="8931333241327730545">â€Ù‡Ù„ تريد Ø­Ùظ هذه البطاقة إلى حسابك ÙÙŠ GoogleØŸ</translation>
<translation id="8932102934695377596">توقيت ساعتك متأخر عن الوقت الحالي</translation>
@@ -2017,6 +2062,7 @@
<translation id="9183302530794969518">â€Ù…ستندات Google</translation>
<translation id="9183425211371246419">يستخدم <ph name="HOST_NAME" /> بروتوكول غير مدعوم.</translation>
<translation id="9191834167571392248">عمل ثقب أسÙÙ„ اليسار</translation>
+<translation id="9199905725844810519">تم حظر الطباعة</translation>
<translation id="9205078245616868884">يتم ترميز بياناتك باستخدام عبارة مرور المزامنة. أدخلها لبدء المزامنة.</translation>
<translation id="9207861905230894330">تعذّرت إضاÙØ© مقالة.</translation>
<translation id="9213433120051936369">تخصيص المظهر</translation>
@@ -2027,8 +2073,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">â€Ù‚د لا تتمكّن من الوصول إلى حسابك على Google. لذا ينصح Chromium بتغيير كلمة مرورك الآن. وسيÙطلَب منك تسجيل الدخول.</translation>
<translation id="939736085109172342">مجلد جديد</translation>
+<translation id="945522503751344254">إرسال تعليقات</translation>
<translation id="945855313015696284">يجب التحقّÙÙ‚ من المعلومات الواردة أدناه وحذ٠أي بطاقات غير صالحة</translation>
<translation id="950736567201356821">عمل ثلاثة ثقوب من الأعلى</translation>
+<translation id="951941430552851965">لقد أوق٠المشر٠وضع "تصوير الشاشة" مؤقتًا بسبب المحتوى الذي يظهر على شاشتك.</translation>
<translation id="961663415146723894">التجليد من الأسÙÙ„</translation>
<translation id="962484866189421427">قد يحاول هذا المحتوى تثبيت تطبيقات مضللة تظهر كبرامج أخرى أو تجمع بيانات قد تÙستخدم لتتبعك. <ph name="BEGIN_LINK" />العرض على أي حال<ph name="END_LINK" /></translation>
<translation id="969892804517981540">البنية الرسمية</translation>
diff --git a/chromium/components/strings/components_strings_as.xtb b/chromium/components/strings/components_strings_as.xtb
index e6697f15722..b464e44d57b 100644
--- a/chromium/components/strings/components_strings_as.xtb
+++ b/chromium/components/strings/components_strings_as.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">আপà§à¦¨à¦¿ আপোনাৰ পà§à§°à¦¤à¦¿à¦·à§à¦ à¦¾à¦¨à§‡ পৰিচালনা নকৰা à¦à¦Ÿà¦¾ ছাইটত নিজৰ পাছৱৰà§à¦¡à¦Ÿà§‹ দিছে। আপোনাৰ à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦Ÿà§‹ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰিবলৈ আপোনাৰ পাছৱৰà§à¦¡à¦Ÿà§‹ অনà§à¦¯ à¦à¦ªà§â€Œ আৰৠছাইটত পà§à¦¨à§° বà§à¦¯à§±à¦¹à¦¾à§° নকৰিব।</translation>
<translation id="1263231323834454256">পà§à¦¾à§° সূচী</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ à¦à¦‡à¦¸à¦®à§‚হ কাৰà§à¦¯à¦•à¦²à¦¾à¦ª à¦à¦‡ ডিভাইচটোত ছেভ কৰা নহ’ব:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপà§à¦¨à¦¿ à¦à¦‡ ৱিণà§à¦¡â€™à¦¤ চোৱা পৃষà§à¦ à¦¾
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ আৰৠছাইটৰ ডেটা
+ <ph name="LIST_ITEM" />à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° তথà§à¦¯ (<ph name="LINK_BEGIN" />ছাইন আউট কৰক<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">পিকআপৰ পদà§à¦§à¦¤à¦¿</translation>
<translation id="1281476433249504884">ষà§à¦Ÿà§‡à¦•à¦¾à§° ১</translation>
<translation id="1285320974508926690">à¦à¦‡ ছাইটটো কেতিয়াও অনà§à¦¬à¦¾à¦¦ নকৰিব</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">আপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¤ ষà§à¦Ÿâ€™à§° হৈ থকা পাছৱৰà§à¦¡à¦¸à¦®à§‚হ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ ছাইন ইন কৰক</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> ভাষাৰ পৃষà§à¦ à¦¾à¦¸à¦®à§‚হ অনà§à¦¬à¦¾à¦¦ কৰা নহয়।</translation>
<translation id="2053553514270667976">পিন ক’ড</translation>
+<translation id="2054665754582400095">আপোনাৰ উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{১টা পৰামৰà§à¦¶}one{#টা পৰামৰà§à¦¶}other{#টা পৰামৰà§à¦¶}}</translation>
<translation id="2079545284768500474">আনডৠকৰক</translation>
<translation id="20817612488360358">ছিষà§à¦Ÿà§‡à¦® পà§à§°à¦•à§à¦¸à¦¿ ছেটিংসমূহ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ ছেট কৰা হৈছে কিনà§à¦¤à§ কà§à¦·à¦¤à¦¿à¦•à¦¾à§°à¦• পà§à§°à¦•à§à¦¸à¦¿ কনফিগাৰেশà§à¦¬à¦¨à§‹ নিরà§à¦¦à¦¿à¦·à§à¦Ÿ কৰা হৈছে।</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android à¦à¦ªà§â€Œ</translation>
<translation id="2107021941795971877">পà§à§°à¦¿à¦£à§à¦Ÿà§° সমৰà§à¦¥à¦¨</translation>
<translation id="2108755909498034140">আপোনাৰ কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à§°à¦Ÿà§‹ ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ কৰক</translation>
+<translation id="2111166930115883695">খেলিবলৈ সà§à¦ªà§‡â€™à¦š টিপক</translation>
<translation id="2111256659903765347">ছà§à¦ªà¦¾à§°-A</translation>
<translation id="2113977810652731515">কাৰà§à¦¡</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" />ঠইয়াক অ’ভাৰৰাইড কৰাৰ বাবে অৱজà§à¦žà¦¾ কৰা হৈছে।</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">পৰিশোধ বাতিল কৰক</translation>
<translation id="2147827593068025794">নেপথà§à¦¯à§° ছিংক</translation>
<translation id="2148613324460538318">কাৰà§à¦¡ যোগ কৰক</translation>
+<translation id="2149968176347646218">সংযোগটো সà§à§°à¦•à§à¦·à¦¿à¦¤ নহয়</translation>
<translation id="2154054054215849342">আপোনাৰ ড‘মেইনত ছিংক কৰাৰ সà§à¦¬à¦¿à¦§à¦¾ নাই</translation>
<translation id="2154484045852737596">কাৰà§à¦¡ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰক</translation>
<translation id="2161656808144014275">পাঠ</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">নীতি</translation>
<translation id="2183608646556468874">ফ’ন নমà§à¦¬à§°</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{১টা ঠিকনা}one{#টা ঠিকনা}other{#টা ঠিকনা}}</translation>
-<translation id="2187243482123994665">বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° সকà§à§°à¦¿à§Ÿà¦¤à¦¾</translation>
<translation id="2187317261103489799">চিনাকà§à¦¤à¦•à§°à¦• (ডিফ’লà§à¦Ÿ)</translation>
<translation id="2188375229972301266">তলৰ অংশত à¦à¦•à¦¾à¦§à¦¿à¦• পাঞà§à¦š কৰক</translation>
<translation id="2202020181578195191">à¦à¦Ÿà¦¾ মানà§à¦¯ মà§à¦¯à¦¾à¦¦ উকলা বছৰ দিয়ক</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">আপà§à¦¨à¦¿ চাব বিচৰা ছাইটটো ভà§à§±à¦¾</translation>
<translation id="2850739647070081192">আমনà§à¦¤à§à§°à¦£ (লেফাফা)</translation>
<translation id="2856444702002559011">আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ৰ পৰা আপোনাৰ তথà§à¦¯ চà§à§°à¦¿ কৰিবলৈ চেষà§à¦Ÿà¦¾ কৰি থাকিব পাৰে (উদাহৰণসà§à¦¬à§°à§‚পে, পাছৱরà§à¦¡, বারà§à¦¤à¦¾ বা কà§à§°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡)। <ph name="BEGIN_LEARN_MORE_LINK" />অধিক জানক<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">à¦à¦‡ ছাইটোৱে বিনা অনà§à¦®à¦¤à¦¿à¦¤ বা কোনো বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à§±à¦¾à§Ÿà¥¤</translation>
<translation id="2878197950673342043">প'ষà§à¦Ÿà¦¾à§° ফ'লà§à¦¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ৱিণà§à¦¡â€™à¦• নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ ঠাইত ৰখা</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Googleৰ পৰামৰà§à¦¶à¦¸à¦®à§‚হ</translation>
<translation id="3002501248619246229">ইনপà§à¦Ÿ টà§à§°à§‡â€™ মিডিয়া পৰীকà§à¦·à¦¾ কৰক</translation>
<translation id="3005723025932146533">ছে’ভ কৰা পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ দেখà§à§±à¦¾à¦“ক</translation>
-<translation id="3007719053326478567">à¦à¦‡ সমলখিনি পà§à§°à¦¿à¦£à§à¦Ÿ কৰাটো আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ অৱৰোধ কৰিছে</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />ৰ CVC দিয়ক। à¦à¦¬à¦¾à§° আপà§à¦¨à¦¿ নিশà§à¦šà¦¿à¦¤ কৰাৰ পিছত আপোনাৰ কাৰà§à¦¡à§° সবিশেষ à¦à¦‡ ছাইটবোৰৰ সৈতে শà§à¦¬à§‡à§Ÿà¦¾à§° কৰা হ’ব।</translation>
<translation id="3010559122411665027">তালিকাযà§à¦•à§à¦¤ অনà§à¦¤à§°à§à¦­à§à¦•à§à¦¤à¦¿ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">সà§à¦¬à¦¯à¦¼à¦‚কà§à§°à¦¿à¦¯à¦¼à¦­à¦¾à§±à§‡ অৱৰোধ কৰা হৈছে</translation>
<translation id="3016780570757425217">আপোনাৰ অৱসà§à¦¥à¦¾à¦¨ জানক</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, পৰামৰà§à¦¶ আà¦à¦¤à§°à¦¾à¦¬à¦²à§ˆ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক।</translation>
<translation id="3023071826883856138">You4 (লেফাফা)</translation>
<translation id="3024663005179499861">নীতিৰ পà§à§°à¦•à¦¾à§°à¦Ÿà§‹ ভà§à¦²</translation>
<translation id="3037605927509011580">আমি দà§à¦ƒà¦–িত!</translation>
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">বà§à¦•à¦®à¦¾à¦°à§à¦• কৰা হৈছে</translation>
<translation id="3209034400446768650">পৃষà§à¦ à¦¾à¦–নে মাচà§à¦² হিচাপে টকা ল’ব পাৰে</translation>
<translation id="3212581601480735796">আপà§à¦¨à¦¿ <ph name="HOSTNAME" />ত কৰা কারà§à¦¯à¦•à¦²à¦¾à¦ª নিৰীকà§à¦·à¦£ কৰি থকা হৈছে</translation>
+<translation id="3212623355668894776">আটাইবোৰ অতিথিৰ ৱিণà§à¦¡â€™ বনà§à¦§ কৰক যাতে à¦à¦‡ ডিভাইচটোৰ পৰা আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦‚ কাৰà§à¦¯à¦•à¦²à¦¾à¦ª মচা হয়।</translation>
<translation id="3215092763954878852">WebAuthn বà§à¦¯à§±à¦¹à¦¾à§° কৰিব পৰা নগ’ল</translation>
<translation id="3218181027817787318">আপেকà§à¦·à¦¿à¦•</translation>
<translation id="3225919329040284222">ছাৰà§à¦­à¦¾à§°à¦Ÿà§‹à§±à§‡ à¦à¦¨à§‡ à¦à¦–ন পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° দিছে যিখন বিলà§à¦Ÿ-ইন কৰি ৰখা পà§à§°à¦¤à§à¦¯à¦¾à¦¶à¦¾ সৈতে মিলা নাই। à¦à¦‡ পà§à§°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦¸à¦®à§‚হ আপোনাক সà§à§°à¦•à§à¦·à¦¿à¦¤ ৰাখিবলৈ কিছà§à¦®à¦¾à¦¨ নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ, উচà§à¦š-সà§à§°à¦•à§à¦·à¦¾ সমà§à¦ªà¦¨à§à¦¨ ৱেবছাইটত অনà§à¦¤à§°à§à¦­à§à¦•à§à¦¤ কৰা হয়।</translation>
@@ -699,6 +711,7 @@
<translation id="3784372983762739446">বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইচসমূহ</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" />ত মà§à¦¯à¦¾à¦¦ উকলিব</translation>
<translation id="3789155188480882154">আকাৰ ১৬</translation>
+<translation id="3789841737615482174">ইনষà§à¦Ÿà¦² কৰক</translation>
<translation id="3793574014653384240">শেহতীয়াকৈ হোৱা কà§à¦°à§‡à¦¶à§à¦¬à¦¸à¦®à§‚হৰ সংখà§à¦¯à¦¾ আৰৠকাৰণসমূহ</translation>
<translation id="3797522431967816232">Prc3 (লেফাফা)</translation>
<translation id="3799805948399000906">ফ’ণà§à¦Ÿà§° বাবে অনà§à§°à§‹à¦§ কৰা হৈছে</translation>
@@ -750,6 +763,7 @@
<translation id="4056223980640387499">ছেপিয়া</translation>
<translation id="4058922952496707368">চাবি "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (লেফাফা)</translation>
+<translation id="4067669230157909013">সà§à¦•à§à§°à§€à¦¨ কেপচাৰ কৰাৰ সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ পà§à¦¨à§° আৰমà§à¦­ কৰা হৈছে।</translation>
<translation id="4067947977115446013">মানà§à¦¯ ঠিকনা দিয়ক</translation>
<translation id="4075732493274867456">কà§à¦²à¦¾à§Ÿà§‡à¦£à§à¦Ÿ আৰৠছাৰà§à¦­à¦¾à§°à¦¤ à¦à¦Ÿà¦¾ উমৈহতীয়া SSL পà§à§°à¦Ÿâ€™à¦•à¦² সংসà§à¦•à§°à¦£ বা চাইফাৰ ছà§à¦Ÿ সমৰà§à¦¥à¦¨ নকৰে।</translation>
<translation id="4075941231477579656">সà§à¦ªà§°à§à¦¶ আইডি</translation>
@@ -832,6 +846,7 @@
<translation id="4297502707443874121">পৃষà§à¦ à¦¾ <ph name="THUMBNAIL_PAGE" />ৰ বাবে থামà§à¦¬à¦¨à§‡à¦‡à¦²</translation>
<translation id="42981349822642051">বিসà§à¦¤à¦¾à§° কৰক</translation>
<translation id="4300675098767811073">সোà¦à¦«à¦¾à¦²à§‡ à¦à¦•à¦¾à¦§à¦¿à¦• পাঞà§à¦š কৰক</translation>
+<translation id="4302514097724775343">খেলিবলৈ ডাইন’ছৰত টিপক</translation>
<translation id="4302965934281694568">Chou3 (লেফাফা)</translation>
<translation id="4305666528087210886">আপোনাৰ ফাইলটো à¦à¦•à§à¦¸à§‡à¦› কৰিব পৰা নগ’ল</translation>
<translation id="4305817255990598646">সলনি কৰক</translation>
@@ -910,6 +925,7 @@
<translation id="4658638640878098064">ওপৰৰ বাওà¦à¦«à¦¾à¦²à§‡ ষà§à¦Ÿà§‡'পল কৰক</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ভাৰà§à¦šà§à§±à§‡à¦² ৰিয়েলিটি</translation>
+<translation id="4675657451653251260">অতিথি ম’ডত আপà§à¦¨à¦¿ কোনো Chrome পà§à§°â€™à¦«à¦¾à¦‡à¦²à§° তথà§à¦¯ দেখা নাপায়। পাছৱৰà§à¦¡ আৰৠপৰিশোধ পদà§à¦§à¦¤à¦¿à§° দৰে নিজৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° তথà§à¦¯ à¦à¦•à§à¦¸à§‡à¦› কৰিবলৈ আপà§à¦¨à¦¿ <ph name="LINK_BEGIN" />ছাইন ইন<ph name="LINK_END" /> কৰিব পাৰে।</translation>
<translation id="467662567472608290">ছাৰà§à¦­à¦¾à§°à¦Ÿà§‹à§±à§‡ à¦à¦‡à¦Ÿà§‹ <ph name="DOMAIN" /> বà§à¦²à¦¿ পà§à§°à¦®à¦¾à¦£ কৰিব নোৱাৰিলে; ইয়াৰ সà§à§°à¦•à§à¦·à¦¾ সমà§à¦ªà§°à§à¦•à§€à¦¯à¦¼ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à¦¤ আসোà¦à§±à¦¾à¦¹ আছে। à¦à§Ÿà¦¾ কোনো ভà§à¦² কনফিগাৰেশà§à¦¬à¦¨à§° বাবে বা কোনো আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে হ’ব পাৰে।</translation>
<translation id="4677585247300749148">সাধà§à¦¯ সà§à¦¬à¦¿à¦§à¦¾à§° অনà§à¦·à§à¦ à¦¾à¦¨à¦¸à¦®à§‚à§à¦¹à¦²à§ˆ <ph name="URL" />ঠসà¦à¦¹à¦¾à§°à¦¿ জনাব খোজে</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -937,6 +953,12 @@
<translation id="4761104368405085019">আপোনাৰ মাইকà§à§°â€™à¦«â€™à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="4764776831041365478"><ph name="URL" />ৰ ৱেবপৃষà§à¦ à¦¾à¦Ÿà§‹ অসà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à§±à§‡ বà§à¦¯à§±à¦¹à¦¾à§°à¦¯à§‹à¦—à§à¦¯ হৈ নাথাকিব পাৰে বা ইয়াক কোনো নতà§à¦¨ ৱেব ঠিকনালৈ সà§à¦¥à¦¾à§Ÿà§€ ভাৱে নিয়া হ’ব পাৰে।</translation>
<translation id="4766713847338118463">তলৰ অংশত দà§à¦¬à¦¾à§° ষà§à¦Ÿà§‡'পল কৰক</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ আপোনাৰ à¦à¦‡ কাৰà§à¦¯à¦•à¦²à¦¾à¦ªà¦Ÿà§‹ à¦à¦‡ ডিভাইচটোত ছেভ কৰা হ’ব:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপà§à¦¨à¦¿ à¦à¦‡ ৱিণà§à¦¡â€™à¦¤ ডাউনল’ড কৰা যিকোনো ফাইল
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">কোনো অজà§à¦žà¦¾à¦¤ আসোà¦à§±à¦¾à¦¹ হৈছে।</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{পপ-আপ অৱৰোধ কৰা হ’ল}one{#টা পপ-আপ অৱৰোধ কৰা হৈছে}other{#টা পপ-আপ অৱৰোধ কৰা হৈছে}}</translation>
<translation id="4780366598804516005">মেইলবকà§à¦¸ ১</translation>
@@ -1099,11 +1121,13 @@
<translation id="5386426401304769735">à¦à¦‡ ছাইটটোৰ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à§° চà§à¦šà§‡à¦‡à¦¨à¦¤ SHA-1 বà§à¦¯à§±à¦¹à¦¾à§° কৰি ছাইন কৰা à¦à¦–ন পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° আছে।</translation>
<translation id="538659543871111977">A4-টেব</translation>
<translation id="5396631636586785122">সোà¦à¦«à¦¾à¦²à§‡ কাষত চিলাওক</translation>
+<translation id="5398772614898833570">বিজà§à¦žà¦¾à¦ªà¦¨ অৱৰোধ কৰা হৈছে</translation>
<translation id="5400836586163650660">ধোà¦à§±à¦¾à¦¬à§°à¦£à§€à§Ÿà¦¾</translation>
<translation id="540969355065856584">à¦à¦‡ ছারà§à¦­à¦¾à§°à¦Ÿà§‹à§±à§‡ নিজকে <ph name="DOMAIN" />; বà§à¦²à¦¿ পà§à§°à¦®à¦¾à¦£ কৰিব নোৱাৰিলে; বৰà§à¦¤à¦®à¦¾à¦¨ ইয়াৰ সà§à§°à¦•à§à¦·à¦¾ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° মানà§à¦¯ নহয়৷ à¦à§Ÿà¦¾ কোনো ভà§à¦² কনফিগাৰেশà§à¦¬à¦¨à§° বাবে বা কোনো আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে হ’ব পাৰে।</translation>
<translation id="541416427766103491">ষà§à¦Ÿà§‡à¦•à¦¾à§° ৪</translation>
<translation id="5421136146218899937">বà§à§°à¦¾à¦‰à¦œà¦¿à¦‚ ডেটা মচক...</translation>
<translation id="5426179911063097041"><ph name="SITE" />ঠআপোনালৈ জাননী পঠিয়াব বিচাৰে</translation>
+<translation id="542872847390508405">আপà§à¦¨à¦¿ অতিথি হিচাপে বà§à§°à¦¾à¦‰à¦œ কৰি আছে</translation>
<translation id="5430298929874300616">বà§à¦•à¦®à¦¾à¦°à§à¦• আà¦à¦¤à§°à¦¾à¦“ক</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />"ৰ সà§à¦•à§€à¦®à¦¾ সতà§à¦¯à¦¾à¦ªà¦¨à§° আসোà¦à§±à¦¾à¦¹ : <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ওপৰমà§à¦–ীয়াকৈ বিপৰীত কà§à§°à¦®</translation>
@@ -1145,12 +1169,12 @@
<translation id="5571083550517324815">à¦à¦‡ ঠিকনাৰ পৰা পিকআপ কৰিব নোৱাৰি। অনà§à¦¯ à¦à¦Ÿà¦¾ ঠিকনা বাছনি কৰক।</translation>
<translation id="5580958916614886209">আপোনাৰ কà§à§°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡à§° মà§à¦¯à¦¾à¦¦ উকলাৰ মাহ পৰীকà§à¦·à¦¾ কৰি আকৌ চেষà§à¦Ÿà¦¾ কৰক</translation>
<translation id="5586446728396275693">ছেভ কৰা কোনো ঠিকনা নাই</translation>
+<translation id="5593349413089863479">সংযোগটো সমà§à¦ªà§‚ৰà§à¦£à§°à§‚পে সà§à§°à¦•à§à¦·à¦¿à¦¤ নহয়</translation>
<translation id="5595485650161345191">ঠিকনা সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰক</translation>
<translation id="5598944008576757369">পৰিশোধ পদà§à¦§à¦¤à¦¿ বাছনি কৰক</translation>
<translation id="560412284261940334">পৰিচালক পà§à§°à¦¯à§‹à¦œà§à¦¯ নহয়</translation>
<translation id="5605670050355397069">লেজাৰ</translation>
<translation id="5607240918979444548">সà§à¦¥à¦¾à¦ªà¦¤à§à¦¯ বিদà§à¦¯à¦¾-C</translation>
-<translation id="5608165884683734521">à¦à¦‡ ছাইটটো ভà§à§±à¦¾ অথবা পà§à§°à¦¤à¦¾à§°à¦£à¦¾à¦®à§‚লক হ'ব পাৰে। Chromeঠà¦à¦¤à¦¿à§Ÿà¦¾à¦‡ ছাইটটো তà§à¦¯à¦¾à¦— কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
<translation id="5610142619324316209">সংযোগ পৰীকà§à¦·à¦¾ কৰক</translation>
<translation id="5610807607761827392">আপà§à¦¨à¦¿ কারà§à¦¡ আৰৠঠিকনাসমূহ <ph name="BEGIN_LINK" />ছেটিংসমূহ<ph name="END_LINK" />ত পৰিচালনা কৰিব পাৰে।</translation>
<translation id="561165882404867731">Google Translateৰ জৰিয়তে à¦à¦‡ পৃষà§à¦ à¦¾à¦–ন অনà§à¦¬à¦¾à¦¦ কৰক</translation>
@@ -1222,6 +1246,7 @@
<translation id="5901630391730855834">হালধীয়া</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />ৰ মূল নীতি অনà§à¦¯à¦¾à¦¯à¦¼à§€ অৱৰোধ কৰা হৈছে।</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ছিংক কৰা আছে)</translation>
+<translation id="5913377024445952699">সà§à¦•à§à§°à§€à¦¨ কেপচাৰ সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ পজ কৰা হ'ল</translation>
<translation id="59174027418879706">সকà§à¦·à¦® কৰা আছে</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">অন</translation>
@@ -1233,6 +1258,7 @@
<translation id="5963413905009737549">শাখা</translation>
<translation id="5967592137238574583">সমà§à¦ªà¦°à§à¦•à§° তথà§à¦¯ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰক</translation>
<translation id="5967867314010545767">ইতিহাসৰ পৰা আà¦à¦¤à§°à¦¾à¦“ক</translation>
+<translation id="5968793460449681917">পà§à§°à¦¤à¦¿à¦¬à¦¾à§° যাওà¦à¦¤à§‡</translation>
<translation id="5975083100439434680">জà§à¦® আউট কৰক</translation>
<translation id="5979084224081478209">পাছৱৰà§à¦¡à¦¬à§‹à§° পৰীকà§à¦·à¦¾ কৰক</translation>
<translation id="5980920751713728343">সূচক-৩x৫</translation>
@@ -1387,6 +1413,7 @@
<translation id="6587923378399804057">আপà§à¦¨à¦¿ পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰা লিংক</translation>
<translation id="6591833882275308647">আপোনাৰ <ph name="DEVICE_TYPE" /> পৰিচালিত নহয়</translation>
<translation id="6596325263575161958">à¦à¦¨à¦•à§à§°à¦¿à¦ªà¦¶à§à¦¬à¦¨à§° বিকলà§à¦ª</translation>
+<translation id="6596892391065203054">à¦à¦‡ সমলখিনি পà§à§°à¦¿à¦£à§à¦Ÿ কৰাটো আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ অৱৰোধ কৰিছে।</translation>
<translation id="6604181099783169992">গতি বা পোহৰ ধৰা পেলাব পৰা ছেনà§à¦¸à§°</translation>
<translation id="6609880536175561541">Prc7 (লেফাফা)</translation>
<translation id="6612358246767739896">সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল</translation>
@@ -1446,6 +1473,7 @@
<translation id="6895330447102777224">আপোনাৰ কারà§à¦¡ নিশà§à¦šà¦¿à¦¤ কৰা হৈছে</translation>
<translation id="6897140037006041989">বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° à¦à¦œà§‡à¦£à§à¦Ÿ</translation>
<translation id="6898699227549475383">পà§à§°à¦¤à¦¿à¦·à§à¦ à¦¾à¦¨ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />ক à¦à§Ÿà¦¾ কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক:</translation>
<translation id="6910240653697687763"><ph name="URL" />ঠআপোনাৰ MIDI ডিভাইচসমূহৰ সমà§à¦ªà§‚রà§à¦£ নিয়নà§à¦¤à§à§°à¦£ পাব খোজে</translation>
<translation id="6915804003454593391">বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€:</translation>
<translation id="6934672428414710184">à¦à¦‡ নামটো আপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§°</translation>
@@ -1555,6 +1583,7 @@
<translation id="7346048084945669753">অনà§à¦®à§‹à¦¦à¦¿à¦¤:</translation>
<translation id="7349430561505560861">A4-অতিৰিকà§à¦¤</translation>
<translation id="7353601530677266744">কামাণà§à¦¡ লাইন</translation>
+<translation id="7359588939039777303">বিজà§à¦žà¦¾à¦ªà¦¨ অৱৰোধ কৰা হ'ল।</translation>
<translation id="7372973238305370288">ফলাফল সনà§à¦§à¦¾à¦¨ কৰক</translation>
<translation id="7374733840632556089">আপোনাৰ ডিভাইচটোত আপà§à¦¨à¦¿ অথবা অনà§à¦¯ কোনোবাই ইনষà§à¦Ÿà¦² কৰা à¦à¦–ন পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à§° বাবে à¦à¦‡ সমসà§à¦¯à¦¾à¦Ÿà§‹ হয়। à¦à¦‡ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à¦–ন নেটৱৰà§à¦•à¦¸à¦®à§‚হ নিৰীকà§à¦·à¦£ আৰৠবাধাগà§à§°à¦¸à§à¦¤ কৰিবলৈ বà§à¦¯à§±à¦¹à¦¾à§° কৰা হয় বà§à¦²à¦¿ জনা যায় আৰৠà¦à¦‡à¦–নক Chromeঠবিশà§à¦¬à¦¾à¦¸ নকৰে। যদিও কোনো বিদà§à¦¯à¦¾à¦²à¦¯à¦¼ অথবা কোমà§à¦ªà¦¾à¦¨à§€à§° নেটৱৰà§à¦•à¦¤ নিৰীকà§à¦·à¦£ কৰাৰ দৰে কিছà§à¦®à¦¾à¦¨ বৈধ উদাহৰণ পোৱা যায়, Chromeঠআপà§à¦¨à¦¿ à¦à¦‡ বিষয়ে অৱগত হৈ থকাটো নিশà§à¦šà¦¿à¦¤ কৰিবলৈ বিচাৰে, যদিওবা আপà§à¦¨à¦¿ সেয়া বনà§à¦§ কৰিব নোৱাৰে। ৱেব à¦à¦•à§à¦¸à§‡à¦› কৰা যিকোনো বà§à§°à¦¾à¦‰à¦œà¦¾à§° অথবা à¦à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à§à¦¬à¦¨ নিৰীকà§à¦·à¦£ কৰা হ’ব পাৰে।</translation>
<translation id="7375818412732305729">ফাইল সংলগà§à¦¨ কৰিলে</translation>
@@ -1728,6 +1757,7 @@
<translation id="7976214039405368314">অতি বেছিসংখà§à¦¯à¦• অনà§à§°à§‹à¦§</translation>
<translation id="7977538094055660992">আউটপà§à¦Ÿ ডিভাইচ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾à§° সমল চাবলৈ ARCore ইনষà§à¦Ÿà¦² কৰক</translation>
<translation id="799149739215780103">সংযà§à¦•à§à¦¤ কৰক</translation>
<translation id="7995512525968007366">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ কৰা হোৱা নাই</translation>
<translation id="800218591365569300">মেম’ৰী খালী কৰিবলৈ অনà§à¦¯ টেব বা পà§à¦°â€™à¦—à§à§°à§‡à¦® বনà§à¦§ কৰি চাওক।</translation>
@@ -1855,24 +1885,38 @@
<translation id="8507227106804027148">কামাণà§à¦¡ লাইন</translation>
<translation id="8508648098325802031">সনà§à¦§à¦¾à¦¨ আইকন</translation>
<translation id="8522552481199248698">Chromeঠআপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰাত আৰৠআপোনৰ পাছৱৰà§à¦¡ সলনি কৰাত সহায় কৰিব পাৰে।</translation>
+<translation id="8525306231823319788">সমà§à¦ªà§‚রà§à¦£ সà§à¦•à§à§°à§€à¦£</translation>
<translation id="8530813470445476232">Chromeৰ ছেটিংসমূহত আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° ইতিহাস, কà§à¦•à¦¿, কেশà§à¦¬ আৰৠঅধিক বসà§à¦¤à§ মচক</translation>
<translation id="8533619373899488139">অৱৰোধ কৰা URL আৰৠআপোনাৰ ছিষà§à¦Ÿà§‡à¦®à§° পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ বলৱৎ কৰা অনà§à¦¯ নীতিসমূহৰ সূচীখন চাবলৈ &lt;strong&gt;chrome://policy&lt;/strong&gt;লৈ যাওক।</translation>
<translation id="8541158209346794904">বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইচ</translation>
<translation id="8542014550340843547">তলত তিনিবাৰ ষà§à¦Ÿà§‡'পল কৰক</translation>
<translation id="8543181531796978784">আপà§à¦¨à¦¿ <ph name="BEGIN_ERROR_LINK" />চিনাকà§à¦¤ কৰাৰ লগত জড়িত কোনো সমসà§à¦¯à¦¾à§° অভিযোগ দিব পাৰে<ph name="END_ERROR_LINK" /> বা যদি আপà§à¦¨à¦¿ নিজৰ নিৰাপতà§à¦¤à¦¾à¦œà¦¨à¦¿à¦¤ শংকাৰ বিষয়ে জানে, তেনà§à¦¤à§‡ <ph name="BEGIN_LINK" />à¦à¦‡ অসà§à§°à¦•à§à¦·à¦¿à¦¤ ছাইটটো চাব পাৰে<ph name="END_LINK" />।</translation>
<translation id="8557066899867184262">CVCটো আপোনাৰ কাৰà§à¦¡à§° পিছফালে আছে।</translation>
+<translation id="8558485628462305855">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾à§° সমল চাবলৈ ARCore আপডে’ট কৰক</translation>
<translation id="8559762987265718583">আপোনাৰ ডিভাইচৰ তাৰিখ আৰৠসময় (<ph name="DATE_AND_TIME" />) অশà§à¦¦à§à¦§ হোৱাৰ বাবে <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />লৈ কোনো বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ কৰিব নোৱাৰি।</translation>
<translation id="8564182942834072828">পৃথক নথি/নিমিলোৱা পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿à¦¸à¦®à§‚হ</translation>
<translation id="8564985650692024650">আপà§à¦¨à¦¿ যদি নিজৰ পাছৱৰà§à¦¡à¦Ÿà§‹ অনà§à¦¯ ছাইটত পà§à¦¨à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰিছিল <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />ঠআপোনাৰ পাছৱরà§à¦¡à¦Ÿà§‹ ৰিছেট কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ à¦à¦‡à¦¸à¦®à§‚হ কাৰà§à¦¯à¦•à¦²à¦¾à¦ª à¦à¦‡ ডিভাইচটোত ছেভ কৰা নহ’ব:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপà§à¦¨à¦¿ à¦à¦‡ ৱিণà§à¦¡â€™à¦¤ চোৱা পৃষà§à¦ à¦¾
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ আৰৠছাইটৰ ডেটা
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">কাৰà§à¦¡à¦¸à¦®à§‚হ খৰতকীয়াকৈ নিশà§à¦šà¦¿à¦¤ কৰিবলৈ সà§à¦ªà§°à§à¦¶ আইডি বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="858637041960032120">ফোন নমà§à¦¬à§° যোগ কৰক</translation>
<translation id="8589998999637048520">উতà§à¦¤à¦® গà§à¦£à¦—ত মান</translation>
+<translation id="8600271352425265729">কেৱল à¦à¦‡à¦¬à¦¾à§°à§° বাবে</translation>
<translation id="860043288473659153">কারà§à¦¡à§° গৰাকীৰ নাম</translation>
<translation id="8606726445206553943">আপোনাৰ MIDI ডিভাইচসমূহ বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
+<translation id="8612761427948161954">নমসà§à¦•à¦¾à§° <ph name="USERNAME" />,
+ <ph name="BR" />
+ আপà§à¦¨à¦¿ অতিথি হিচাপে বà§à§°à¦¾à¦‰à¦œ কৰি আছে</translation>
<translation id="861775596732816396">আকাৰ ৪</translation>
<translation id="8622948367223941507">লিগেল-অতিৰিকà§à¦¤</translation>
<translation id="8623885649813806493">মিলা কোনো পাছৱৰà§à¦¡ নাই। ছেভ হৈ থকা সকলো পাছৱৰà§à¦¡ দেখà§à§±à¦¾à¦“ক।</translation>
<translation id="8625384913736129811">à¦à¦‡ ডিভাইচটোত à¦à¦‡ কাৰà§à¦¡à¦–ন ছেভ কৰক</translation>
+<translation id="8627040765059109009">সà§à¦•à§à§°à§€à¦¨ কেপচাৰ কৰাৰ সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ পà§à¦¨à§° আৰমà§à¦­ কৰা হৈছে</translation>
<translation id="8657078576661269990">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ <ph name="ORIGIN_NAME" />ৰ পৰা <ph name="VM_NAME_1" /> আৰৠ<ph name="VM_NAME_2" />লৈ শà§à¦¬à§‡à¦¯à¦¼à¦¾à§° কৰাটো অৱৰোধ কৰিছে</translation>
<translation id="8663226718884576429">অৰà§à¦¡à¦¾à§°à§° সাৰাংশ, <ph name="TOTAL_LABEL" />, অধিক বিৱৰণ</translation>
<translation id="867224526087042813">চহী</translation>
@@ -1935,6 +1979,7 @@
<translation id="8912362522468806198">Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿ</translation>
<translation id="8913778647360618320">পৰিশোধৰ পদà§à¦§à¦¤à¦¿à¦¸à¦®à§‚হ পৰিচালনা কৰক বà§à¦Ÿà¦¾à¦®, Chromeৰ ছেটিংসমূহত আপোনাৰ পৰিশোধসমূহ আৰৠকà§à§°à§‡à¦¡à¦¿à¦Ÿ কাৰà§à¦¡à§° তথà§à¦¯ পৰিচালনা কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="8918231688545606538">à¦à¦‡ পৃষà§à¦ à¦¾à¦–ন সনà§à¦¦à§‡à¦¹à¦œà¦¨à¦•</translation>
+<translation id="8922013791253848639">à¦à¦‡ ছাইটটোত সদায় বিজà§à¦žà¦¾à¦ªà¦¨à§° অনà§à¦®à¦¤à¦¿ দিয়ক</translation>
<translation id="892588693504540538">সোà¦à¦«à¦¾à¦²à§‡ ওপৰৰ অংশত পাঞà§à¦š কৰক</translation>
<translation id="8931333241327730545">আপà§à¦¨à¦¿ à¦à¦‡ কারà§à¦¡ নিজৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¤ ছেভ কৰিব খোজেনে?</translation>
<translation id="8932102934695377596">আপোনাৰ ঘড়ীৰ সময় পিছপৰি আছে</translation>
@@ -2006,18 +2051,21 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" />ঠà¦à¦Ÿà¦¾ অসমরà§à¦¥à¦¿à¦¤ পà§à§°'ট'কল বà§à¦¯à§±à¦¹à¦¾à§° কৰে।</translation>
<translation id="9191834167571392248">বাওà¦à¦«à¦¾à¦²à§‡ তলৰ অংশত পাঞà§à¦š কৰক</translation>
+<translation id="9199905725844810519">পà§à§°à¦¿à¦£à§à¦Ÿ কৰাটো অৱৰোধ কৰা হৈছে</translation>
<translation id="9205078245616868884">আপোনাৰ ডেটা নিজৰ ছিংক পাছফà§à§°à§‡à¦œà§° জৰিয়তে à¦à¦¨à¦•à§à§°à¦¿à¦ªà§à¦Ÿ কৰা হৈছে। ছিংক কৰিবলৈ পাছফà§à§°à§‡à¦œ দিয়ক।</translation>
<translation id="9207861905230894330">লেখা যোগ কৰিব নোৱাৰিলে।</translation>
<translation id="9213433120051936369">ৰূপ কাষà§à¦Ÿà¦®à¦¾à¦‡à¦œ কৰক</translation>
<translation id="9215416866750762878">কোনো à¦à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à§à¦¬à¦¨à§‡ Chromeক à¦à¦‡ ছাইটৰ সৈতে সà§à§°à¦•à§à¦·à¦¿à¦¤ ভাৱে সংযà§à¦•à§à¦¤ হোৱাত বাধা পà§à§°à¦¦à¦¾à¦¨ কৰি আছে।</translation>
-<translation id="9219103736887031265">পà§à§°à¦¤à¦¿à¦šà§à¦›à¦¬à¦¿</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ফৰà§à¦®à¦–নৰ সকলো ডেটা মচক</translation>
<translation id="936474030629450166">ছà§à¦ªà¦¾à§°-B</translation>
<translation id="936602727769022409">আপà§à¦¨à¦¿ নিজৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° à¦à¦•à§à¦¸à§‡à¦› হেৰà§à§±à¦¾à¦¬ পাৰে। Chromiumঠআপোনাৰ পাছৱৰà§à¦¡à¦Ÿà§‹ à¦à¦¤à¦¿à§Ÿà¦¾à¦‡ সলনি কৰাটো চà§à¦ªà¦¾à§°à¦¿à¦› কৰিছে। আপোনাক ছাইন ইন কৰিবলৈ কোৱা হ’ব।</translation>
<translation id="939736085109172342">নতà§à¦¨ ফ'লà§à¦¡à¦¾à§°</translation>
+<translation id="945522503751344254">মতামত পঠিয়াওক</translation>
<translation id="945855313015696284">তলৰ তথà§à¦¯ পৰীকà§à¦·à¦¾ কৰক আৰৠকোনো অমানà§à¦¯ কারà§à¦¡ থাকিলে মচক</translation>
<translation id="950736567201356821">ওপৰৰ অংশত তিনিবাৰ পাঞà§à¦š কৰা</translation>
+<translation id="951941430552851965">আপোনাৰ সà§à¦•à§à§°à§€à¦¨à¦¤ থকা সমলৰ কাৰণে আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ সà§à¦•à§à§°à§€à¦¨ কেপচাৰ কৰাটো পজ কৰিছে।</translation>
<translation id="961663415146723894">তলৰ অংশত সংযà§à¦•à§à¦¤ কৰক</translation>
<translation id="962484866189421427">à¦à¦‡ সমলে বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° à¦à¦ªà§ ইনষà§à¦Ÿà¦² কৰিবলৈ চেষà§à¦Ÿà¦¾ কৰিব পাৰে যি আন ছদà§à¦®à§±à§‡à¦¶ ধাৰণ কৰিব পাৰে বা আপোনাৰ কাৰà§à¦¯à¦•à¦²à¦¾à¦ªà§° ওপৰত চকৠৰাখিবলৈ বà§à¦¯à§±à¦¹à¦¾à§° কৰা ডেটা সংগà§à§°à¦¹ কৰিব পাৰে। <ph name="BEGIN_LINK" />যিকোনো পà§à§°à¦•à¦¾à§°à§‡ দেখà§à§±à¦¾à¦“ক<ph name="END_LINK" /></translation>
<translation id="969892804517981540">আনà§à¦·à§à¦ à¦¾à¦¨à¦¿à¦• বিলà§à¦¡</translation>
diff --git a/chromium/components/strings/components_strings_az.xtb b/chromium/components/strings/components_strings_az.xtb
index 00d859dd6b7..b463c01be3b 100644
--- a/chromium/components/strings/components_strings_az.xtb
+++ b/chromium/components/strings/components_strings_az.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Təşkilatınızın idarə etmədiyi saytda parolunuzu daxil etdiniz. Hesabınızı qorumaq üçün digər tətbiq və saytlarda parolunuzdan təkrar istifadə etməyin.</translation>
<translation id="1263231323834454256">Oxu siyahısı</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Bu cihazda saxlanmayacaq fəaliyyət:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pəncərədə baxdığınız səhifələr
+ <ph name="LIST_ITEM" />Kukilər və sayt datası
+ <ph name="LIST_ITEM" />Hesab məlumatı (<ph name="LINK_BEGIN" />çıxış<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Götürmə Üsulu</translation>
<translation id="1281476433249504884">Yığıcı 1</translation>
<translation id="1285320974508926690">Bu saytı heç vaxt tərcümə etməyin</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Google Hesabınızda saxlanılan parollardan istifadə etmək üçün daxil olun</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> dilindəki səhifələr tərcümə edilməyəcək.</translation>
<translation id="2053553514270667976">Poçt indeksi</translation>
+<translation id="2054665754582400095">Mövcudluğunuz</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 təklif}other{# təklif}}</translation>
<translation id="2079545284768500474">Geri qaytarın</translation>
<translation id="20817612488360358">Sistem proksi ayarları işlənməyə ayarlanıb, lakin açıq proksi sazlanması da bəlirlənib.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android tətbiqləri</translation>
<translation id="2107021941795971877">Çap dəstəyi</translation>
<translation id="2108755909498034140">Kompüteri yenidən başladın</translation>
+<translation id="2111166930115883695">Oxutmaq üçün boşluq düyməsini basın</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kart</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> tərəfindən əvəzləndiyi üçün iqnor edin.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Ödənişi ləğv edin</translation>
<translation id="2147827593068025794">Arxafon Sinxronizasiyası</translation>
<translation id="2148613324460538318">Kart ÆlavÉ™ Edin</translation>
+<translation id="2149968176347646218">Bağlantı güvənli deyil</translation>
<translation id="2154054054215849342">Sinxronlaşma domeniniz üçün əlçatan deyil</translation>
<translation id="2154484045852737596">Kartı redaktə edin</translation>
<translation id="2161656808144014275">Mətn</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Siyasətlər</translation>
<translation id="2183608646556468874">Telefon Nömrəsi</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ünvan}other{# ünvan}}</translation>
-<translation id="2187243482123994665">İstifadəçinin evdə olması</translation>
<translation id="2187317261103489799">Aşkarlayın (defolt)</translation>
<translation id="2188375229972301266">Aşağıdan çoxsaylı deşik açın</translation>
<translation id="2202020181578195191">Düzgün bitmə ili daxil edin</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">İrəlidə saxta sayt</translation>
<translation id="2850739647070081192">Dəvət edin (Zərf)</translation>
<translation id="2856444702002559011">Hücumçular <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytından mÉ™lumat (mÉ™sÉ™lÉ™n, parol, mesaj vÉ™ ya kredit kartları) oÄŸurlamaÄŸa çalışa bilÉ™rlÉ™r. <ph name="BEGIN_LEARN_MORE_LINK" />Ætraflı mÉ™lumat<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Bu sayt inadçı və ya aldadıcı reklamlar göstərir.</translation>
<translation id="2878197950673342043">Poster formasında qatlayın</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Pəncərənin yerləşdirilməsi</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google tərəfindən təkliflər</translation>
<translation id="3002501248619246229">Daxiletmə qabı mediasını yoxlayın</translation>
<translation id="3005723025932146533">Saxlanılmış kopyanı göstərin</translation>
-<translation id="3007719053326478567">Bu məzmunun çap edilməsi administratorunuz tərəfindən bloklanıb</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> üçün CVC kodu daxil edin. Təsdiq etdikdən sonra, kart detallarınız bu sayt ilə paylaşılacaq.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />" giriş siyahısı: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Avtomatik olaraq blok edildi</translation>
<translation id="3016780570757425217">Məkanınızı bilin</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Təklifi ləğv etmək üçün Tab, sonra Enter düyməsini basın.</translation>
<translation id="3023071826883856138">You4 (Zərf)</translation>
<translation id="3024663005179499861">Yanlış siyasət növü</translation>
<translation id="3037605927509011580">Yapon xalq musiqisi dinləmisiniz?</translation>
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">ÆlfÉ™cinlÉ™nib</translation>
<translation id="3209034400446768650">Səhifədə pul çıxıla bilər</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> hostundakı fəaliyyətinizə nəzarət edilir</translation>
+<translation id="3212623355668894776">Baxış datasının bu cihazdan silinməsi üçün bütün Qonaq pəncərələrini bağlayın.</translation>
<translation id="3215092763954878852">WebAuthn istifadə edilmədi</translation>
<translation id="3218181027817787318">Nisbi</translation>
<translation id="3225919329040284222">Serverin təqdim etdiyi sertifikat daxili gözləntilərə uyğun deyil.</translation>
@@ -698,6 +710,7 @@
<translation id="3784372983762739446">Bluetooth cihazları</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> tarixindÉ™ bitir</translation>
<translation id="3789155188480882154">Ölçü 16</translation>
+<translation id="3789841737615482174">Quraşdırın</translation>
<translation id="3793574014653384240">Son vaxtlarda baş verən xətaların sayı və səbəbləri</translation>
<translation id="3797522431967816232">Prc3 (Zərf)</translation>
<translation id="3799805948399000906">Şrift üzrə sorğu göndərildi</translation>
@@ -749,6 +762,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Açar "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Zərf)</translation>
+<translation id="4067669230157909013">Ekranın çəkilməsi davam etdirilib.</translation>
<translation id="4067947977115446013">Düzgün Ãœnvan ÆlavÉ™ Edin</translation>
<translation id="4072486802667267160">Sifariş hazırlanarkən xəta baş verdi. Yenidən cəhd edin.</translation>
<translation id="4075732493274867456">Klient və server ümumi SSL protokol versiyasını və ya şifrə dəstini dəstəkləmir.</translation>
@@ -832,6 +846,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> səhifəsi üçün miniatür</translation>
<translation id="42981349822642051">Genişləndirin</translation>
<translation id="4300675098767811073">Sağdan çoxsaylı deşik açın</translation>
+<translation id="4302514097724775343">Oxutmaq üçün dinozavra toxunun</translation>
<translation id="4302965934281694568">Chou3 (Zərf)</translation>
<translation id="4305666528087210886">Faylınıza giriş mümkün olmadı</translation>
<translation id="4305817255990598646">Dəyişin</translation>
@@ -910,6 +925,7 @@
<translation id="4658638640878098064">Yuxarı soldan ştapel vurun</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reallıq</translation>
+<translation id="4675657451653251260">Qonaq rejimində Chrome profili məlumatını görməyəcəksiniz. Parollar və ödəniş metodları kimi Google hesabı məlumatlarına giriş üçün <ph name="LINK_BEGIN" />daxil ola<ph name="LINK_END" /> bilərsiniz.</translation>
<translation id="467662567472608290">Bu server <ph name="DOMAIN" /> domenini təsdiqləyə bilmir; təhlükəsizlik sertifikatında xətalar var. Buna yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantının ələ keçirilməsi səbəb ola bilər.</translation>
<translation id="4677585247300749148"><ph name="URL" /> əlçatımlılıq tədbirlərinə cavab vermək istəyir</translation>
<translation id="467809019005607715">Google Slayd</translation>
@@ -937,6 +953,12 @@
<translation id="4761104368405085019">Mikrofon işlədin</translation>
<translation id="4764776831041365478"><ph name="URL" /> ünvanındakı səhifə müvəqqəti olaraq deaktiv ola və ya həmişəlik olaraq yeni ünvana köçə bilər.</translation>
<translation id="4766713847338118463">Aşağıdan qoşa ştapel vurun</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Bu cihazda saxlanacaq fəaliyyətiniz:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pəncərədə endirdiyiniz fayllar
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Naməlum xəta baş verdi.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Popap bloklandı}other{# popap bloklandı}}</translation>
<translation id="4780366598804516005">Poçt qutusu 1</translation>
@@ -1099,11 +1121,13 @@
<translation id="5386426401304769735">Bu saytın sertifikat zənciri SHA-1 istifadə edərək imzalanmış sertifikatdan ibarətdir.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Sağdan kənarını tikin</translation>
+<translation id="5398772614898833570">Reklamlar blok edildi</translation>
<translation id="5400836586163650660">Boz</translation>
<translation id="540969355065856584">Bu server <ph name="DOMAIN" /> domenini təsdiqləyə bilmir; güvənlik sertifikatı hazırda etibarlı deyil. Buna yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantının ələ keçirilməsi səbəb ola bilər.</translation>
<translation id="541416427766103491">Yığıcı 4</translation>
<translation id="5421136146218899937">Baxış datasını silin...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> Sizə bildiriş göndərmək istəyir</translation>
+<translation id="542872847390508405">Qonaq kimi baxırsınız</translation>
<translation id="5430298929874300616">ÆlfÉ™cini silin</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" yolunda sxem doğrulama xətası: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Tərs sıra ilə üzü yuxarı</translation>
@@ -1145,12 +1169,12 @@
<translation id="5571083550517324815">Bu ünvandan götürmək mümkün deyil. Başqa ünvan seçin.</translation>
<translation id="5580958916614886209">Bitmə ayını yoxlayın və yenidən cəhd edin</translation>
<translation id="5586446728396275693">Yadda saxlanılmış ünvan yoxdur</translation>
+<translation id="5593349413089863479">Bağlantı tam güvənli deyil</translation>
<translation id="5595485650161345191">Ünvana düzəliş edin</translation>
<translation id="5598944008576757369">Ödəniş Üsulu seçin</translation>
<translation id="560412284261940334">İdarəetmə dəstəklənmir</translation>
<translation id="5605670050355397069">Qeyd Kitabçası</translation>
<translation id="5607240918979444548">Arxitektura-C</translation>
-<translation id="5608165884683734521">Bu sayt saxta və ya aldadıcı ola bilər. Chrome indi çıxmağınızı tövsiyə edir.</translation>
<translation id="5610142619324316209">Bağlantınız yoxlanılır</translation>
<translation id="5610807607761827392"><ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" /> bölməsindən kart və ünvanları idarə edə bilərsiniz.</translation>
<translation id="561165882404867731">Bu səhifəni Google Tərcümə ilə tərcümə edin</translation>
@@ -1222,6 +1246,7 @@
<translation id="5901630391730855834">Sarı</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> təhlükəsizlik siyasətinə əsasən blok edildi.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinxronlaşdırıldı)</translation>
+<translation id="5913377024445952699">Ekranın çəkilməsinə pauza verildi</translation>
<translation id="59174027418879706">Aktiv edilib</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aktiv</translation>
@@ -1234,6 +1259,7 @@
<translation id="5963413905009737549">Bölmə</translation>
<translation id="5967592137238574583">Kontakt Məlumatını Redaktə Edin</translation>
<translation id="5967867314010545767">Tarixçədən silin</translation>
+<translation id="5968793460449681917">Hər dəfə ziyarət etdikdə</translation>
<translation id="5975083100439434680">Kiçildin</translation>
<translation id="5979084224081478209">Parolları yoxlayın</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1389,6 +1415,7 @@
<translation id="6587923378399804057">Kopyalanmış link</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> idarÉ™ edilmir</translation>
<translation id="6596325263575161958">Şifrələmə variantları</translation>
+<translation id="6596892391065203054">Bu məzmunun çap edilməsi administratorunuz tərəfindən bloklanıb.</translation>
<translation id="6604181099783169992">Hərəkət və İşıq Sensorları</translation>
<translation id="6609880536175561541">Prc7 (Zərf)</translation>
<translation id="6612358246767739896">Qorunan kontent</translation>
@@ -1448,6 +1475,7 @@
<translation id="6895330447102777224">Kartınız təsdiqləndi</translation>
<translation id="6897140037006041989">İstifadəçi Agent</translation>
<translation id="6898699227549475383">Təşkilat (T)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> tətbiqinə icazə verin:</translation>
<translation id="6910240653697687763"><ph name="URL" /> MIDI cihazlarda tam nəzarət əldə etmək istəyir</translation>
<translation id="6915804003454593391">İstifadəçi:</translation>
<translation id="6934672428414710184">Bu ad Sizin Google Hesabınızdandır.</translation>
@@ -1559,6 +1587,7 @@
<translation id="7346048084945669753">QoÅŸulub:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Æmr sahÉ™si</translation>
+<translation id="7359588939039777303">Reklamlar blok edildi.</translation>
<translation id="7372973238305370288">axtarış nəticəsi</translation>
<translation id="7374733840632556089">Bu xətanın səbəbi cihazınızda siz və ya başqası tərəfindən quraşdırılmış sertifikatdır. Sertifikat şəbəkələrə nəzarət etmək və onları bloklamaq üçün istifadə olunur və Chrome ona etibar etmir. Məktəb və ya şirkət şəbəkəsi kimi bəzi hallarda qanuni nəzarətə icazə verilsə də, Chrome qarşısını ala bilməsəniz də, bunun baş verdiyini bilmənizi istəyir. Nəzarət vebə girişi olan istənilən brauzer və ya tətbiqdə baş verə bilər.</translation>
<translation id="7375818412732305729">Fayl qoÅŸulub</translation>
@@ -1733,6 +1762,7 @@
<translation id="7976214039405368314">Həddən çox sorğu var</translation>
<translation id="7977538094055660992">Çıxış cihazı</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Artırılmış virtual reallıq kontentinə baxmaq üçün ARCore quraşdırın</translation>
<translation id="799149739215780103">Uclarını qovuşdurun</translation>
<translation id="7995512525968007366">Göstərilməəyib</translation>
<translation id="800218591365569300">Yaddaşı boşaltmaq üçün digər tab və proqramları bağlayın.</translation>
@@ -1778,7 +1808,7 @@
<translation id="8175796834047840627">Daxil olduğunuza görə Chrome kartları Google Hesabında yadda saxlamağı təklif edir. Bunu ayarlarda dəyişə bilərsiniz.</translation>
<translation id="8184538546369750125">Qlobal defoltdan istifadÉ™ edin (Ä°cazÉ™ verin)</translation>
<translation id="8194797478851900357">&amp;Ləğv edin</translation>
-<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" ID ilə artırma üçün yanlış güncəlləşmə linki</translation>
+<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" identifikasiyalı artırma üçün güncəllənmə linki yanlışdır</translation>
<translation id="8202097416529803614">Sifariş xülasəsi</translation>
<translation id="8202370299023114387">Ziddiyət</translation>
<translation id="8206978196348664717">Prc4 (Zərf)</translation>
@@ -1860,24 +1890,38 @@
<translation id="8507227106804027148">Æmr sahÉ™si</translation>
<translation id="8508648098325802031">Axtarış işarəsi</translation>
<translation id="8522552481199248698">Chrome Google Hesabınızı qorumağa və parolu dəyişməyə kömək edə bilər.</translation>
+<translation id="8525306231823319788">Tam ekran</translation>
<translation id="8530813470445476232">Baxış tarixçəsi, kukilər, keş və daha çoxunu Chrome ayarlarında təmizləyin</translation>
<translation id="8533619373899488139">Bloklanmış URL-ləri və sistem admininin tətbiq etdiyi digər siyasətləri görmək üçün buraya keçin: &lt;strong&gt;chrome://policy&lt;/strong&gt;</translation>
<translation id="8541158209346794904">Bluetooth cihazı</translation>
<translation id="8542014550340843547">Aşağıdan üçlü ştapel vurun</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Aşkarlama problemini bildirə<ph name="END_ERROR_LINK" /> bilərsiniz, təhlükəsizliyiniz ilə bağlı riski başa düşürsünüzsə, <ph name="BEGIN_LINK" />bu təhlükəli sayta daxil ola bilərsiniz<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC kartın arxasında yerləşir.</translation>
+<translation id="8558485628462305855">Artırılmış virtual reallıq kontentinə baxmaq üçün ARCore'u güncəlləyin</translation>
<translation id="8559762987265718583">Cihazınızın tarixi və vaxtı (<ph name="DATE_AND_TIME" />) yanlış olduğundan, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeninə şəxsi bağlantı yaradıla bilməz.</translation>
<translation id="8564182942834072828">Ayrıca sənədlər/Sıralanmamış nüsxələr</translation>
<translation id="8564985650692024650">Parolunuzdan digər saytlarda təkrar istifadə etmisinizsə, Chromium <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parolunuzu sıfırlamağı tövsiyə edir.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Bu cihazda saxlanmayacaq fəaliyyət:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pəncərədə baxdığınız səhifələr
+ <ph name="LIST_ITEM" />Kukilər və sayt datası
+<ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Kartları daha sürətli təsdiqləmək üçün Toxunuş İD'si istifadə edin</translation>
<translation id="858637041960032120">Telefon nömrəsi əlavə edin</translation>
<translation id="8589998999637048520">Æn yüksÉ™k keyfiyyÉ™t</translation>
+<translation id="8600271352425265729">Yalnız bu dəfə</translation>
<translation id="860043288473659153">Kart sahibinin adı</translation>
<translation id="8606726445206553943">MIDI cihazlarınızı istifadə edin</translation>
+<translation id="8612761427948161954">Salam, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Qonaq kimi baxırsınız</translation>
<translation id="861775596732816396">Ölçü 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Uyğun parol yoxdur. Yadda saxlanmış bütün parolları göstərin.</translation>
<translation id="8625384913736129811">Bu Kartı Bu Cihazda yadda saxlayın</translation>
+<translation id="8627040765059109009">Ekranın çəkilməsi davam etdirildi</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> mənbəyindən <ph name="VM_NAME_1" /> və <ph name="VM_NAME_2" /> ilə paylaşma administratorunuz tərəfindən bloklanıb</translation>
<translation id="8663226718884576429">Sifarişin Yekunu, <ph name="TOTAL_LABEL" />, Daha Çox Məlumat</translation>
<translation id="867224526087042813">Ä°mza</translation>
@@ -1940,6 +1984,7 @@
<translation id="8912362522468806198">Google Hesabı</translation>
<translation id="8913778647360618320">"Ödəniş metodlarını idarə edin" düyməsi, Chrome ayarlarında ödənişlərinizi və kredit kartı məlumatlarınızı idarə etmək üçün Enter düyməsinə basın</translation>
<translation id="8918231688545606538">Bu səhifə şübhəlidir</translation>
+<translation id="8922013791253848639">Həmişə bu saytdakı reklamlara icazə verin</translation>
<translation id="892588693504540538">Yuxarı sağdan deşik açın</translation>
<translation id="8931333241327730545">Bu kartı Google Hesabınızda yadda saxlamaq istəyirsiniz?</translation>
<translation id="8932102934695377596">Saatınız geridədir</translation>
@@ -2011,6 +2056,7 @@
<translation id="9183302530794969518">Google Sənəd</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> dəstəklənməyən protokol istifadə edir.</translation>
<translation id="9191834167571392248">Aşağı soldan deşik açın</translation>
+<translation id="9199905725844810519">Çap funksiyası bloklanıb</translation>
<translation id="9205078245616868884">Datanız sinxronizasiya parol sözü ilə şifrələnib. Sinxronizasiyanı başlamaq üçün onu daxil edin.</translation>
<translation id="9207861905230894330">Məqalə əlavə etmək olmadı.</translation>
<translation id="9213433120051936369">Görünüşü fərdiləşdirin</translation>
@@ -2021,8 +2067,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google Hesabına girişi itirə bilərsiniz. Chromium parolu dəyişməyi məsləhət görür. Daxil olmağınız tələb olunacaq.</translation>
<translation id="939736085109172342">Yeni qovluq</translation>
+<translation id="945522503751344254">Geri əlaqə göndərin</translation>
<translation id="945855313015696284">Aşağıdakı məlumatı yoxlayın və yanlış kartları silin</translation>
<translation id="950736567201356821">Yuxarıdan üçlü deşik açın</translation>
+<translation id="951941430552851965">Ekranınızdakı məzmun ilə əlaqədar olaraq ekranın çəkilməsinə administratorunuz tərəfindən pauza verilib.</translation>
<translation id="961663415146723894">Aşağıdan uclarını qovuşdurun</translation>
<translation id="962484866189421427">Bu kontent başqa tətbiqə oxşayan və ya Sizi izləmək məqsədilə data əldə edən aldadıcı tətbiqləri quraşdırmağa cəhd edə bilər. <ph name="BEGIN_LINK" />İstənilən halda göstərin<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Rəsmi Quruluş</translation>
diff --git a/chromium/components/strings/components_strings_be.xtb b/chromium/components/strings/components_strings_be.xtb
index 60aea0cbda1..960a60c4f57 100644
--- a/chromium/components/strings/components_strings_be.xtb
+++ b/chromium/components/strings/components_strings_be.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ð’Ñ‹ ўвÑлі пароль на Ñайце, Ñкі не знаходзіцца пад кіраваннем арганізацыі. Каб абараніць Ñвой уліковы запіÑ, не выкарыÑтоўвайце пароль у іншых праграмах Ñ– на іншых Ñайтах.</translation>
<translation id="1263231323834454256">Ð¡Ð¿Ñ–Ñ Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ðа гÑтай прыладзе не будуць захоўвацца:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтаронкі, ÑÐºÑ–Ñ Ð²Ñ‹ праглÑдаеце Ñž гÑтым акне;
+ <ph name="LIST_ITEM" />файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ Ñайтаў;
+ <ph name="LIST_ITEM" />Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð° ўліковы Ð·Ð°Ð¿Ñ–Ñ (<ph name="LINK_BEGIN" />выйÑці<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">СпоÑаб прынÑццÑ</translation>
<translation id="1281476433249504884">Укладчык 1</translation>
<translation id="1285320974508926690">Ðіколі не перакладаць гÑÑ‚Ñ‹ Ñайт</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Каб выкарыÑтоўваць Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ð° Уліковым запіÑе Google паролі, увайдзіце Ñž Ñго</translation>
<translation id="2053111141626950936">Старонкі на мове <ph name="LANGUAGE" /> не будуць перакладацца.</translation>
<translation id="2053553514270667976">Паштовы індÑкÑ</translation>
+<translation id="2054665754582400095">Ваша прыÑутнаÑць</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 прапанова}one{# прапанова}few{# прапановы}many{# прапаноў}other{# прапановы}}</translation>
<translation id="2079545284768500474">Ðдрабіць</translation>
<translation id="20817612488360358">СіÑÑ‚ÑÐ¼Ð½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ прокÑÑ– зададзены Ð´Ð»Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹ÑтаннÑ, але ÑÑžÐ½Ð°Ñ ÐºÐ°Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð¾ÐºÑÑ– такÑама вызначана.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Праграмы Ð´Ð»Ñ Android</translation>
<translation id="2107021941795971877">Ðпоры прынтара</translation>
<translation id="2108755909498034140">ПеразапуÑціце камп'ютар.</translation>
+<translation id="2111166930115883695">Каб пачаць гульню, націÑніце прабел</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Картка</translation>
<translation id="2114841414352855701">Перавызначана палітыкай "<ph name="POLICY_NAME" />" і праігнаравана.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">СкаÑаваць плацеж</translation>
<translation id="2147827593068025794">Ð¤Ð¾Ð½Ð°Ð²Ð°Ñ ÑінхранізацыÑ</translation>
<translation id="2148613324460538318">Дадаць картку</translation>
+<translation id="2149968176347646218">ПадключÑнне не з'ÑўлÑецца бÑÑпечным</translation>
<translation id="2154054054215849342">Ð”Ð»Ñ Ð²Ð°ÑˆÐ°Ð³Ð° дамена ÑÑ–Ð½Ñ…Ñ€Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ð½ÐµÐ´Ð°ÑтупнаÑ</translation>
<translation id="2154484045852737596">РÑдагаваць картку</translation>
<translation id="2161656808144014275">ТÑкÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Палітыкі</translation>
<translation id="2183608646556468874">Ðумар Ñ‚Ñлефона</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адраÑ}one{# адраÑ}few{# адраÑÑ‹}many{# адраÑоў}other{# адраÑа}}</translation>
-<translation id="2187243482123994665">ПрыÑутнаÑць карыÑтальніка</translation>
<translation id="2187317261103489799">Ð’Ñ‹ÑўлÑць (Ñтандартна)</translation>
<translation id="2188375229972301266">Ðекалькі дзірак знізу</translation>
<translation id="2202020181578195191">УвÑдзіце Ñапраўдны год заканчÑÐ½Ð½Ñ Ñ‚Ñрміну дзеÑннÑ</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Ð’Ñ‹ збіраецеÑÑ Ð¿ÐµÑ€Ð°Ð¹Ñці на фіктыўны Ñайт</translation>
<translation id="2850739647070081192">Invite (канверт)</translation>
<translation id="2856444702002559011">ЗламыÑнікі могуць Ñпрабаваць украÑці вашы Ð´Ð°Ð½Ñ‹Ñ Ð· Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (напрыклад, паролі, паведамленні або Ð´Ð°Ð½Ñ‹Ñ ÐºÑ€Ñдытных картак). <ph name="BEGIN_LEARN_MORE_LINK" />Даведацца больш<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ГÑÑ‚Ñ‹ Ñайт паказвае назойлівую Ñ€Ñкламу або Ñ€Ñкламу, ÑÐºÐ°Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ñ†ÑŒ у зман.</translation>
<translation id="2878197950673342043">Плакатны згіб</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">РазмÑшчÑнне вокнаў</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Прапановы ад Google</translation>
<translation id="3002501248619246229">Праверыць ноÑьбіт уваходнага латка</translation>
<translation id="3005723025932146533">Паказаць захаваную копію</translation>
-<translation id="3007719053326478567">МагчымаÑць Ð´Ñ€ÑƒÐºÐ°Ð²Ð°Ð½Ð½Ñ Ð³Ñтага змеÑціва заблакіравана адмініÑтратарам</translation>
<translation id="3008447029300691911">УвÑдзіце CVC-код карткі <ph name="CREDIT_CARD" />. ПаÑÐ»Ñ Ð²Ð°ÑˆÐ°Ð³Ð° пацвÑрджÑÐ½Ð½Ñ Ð´Ð°Ð½Ñ‹Ñ Ð²Ð°ÑˆÐ°Ð¹ карткі будуць абагулены з гÑтым Ñайтам.</translation>
<translation id="3010559122411665027">Пункт ÑпіÑа "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Заблакіравана аўтаматычна</translation>
<translation id="3016780570757425217">Ведаць ваша меÑцазнаходжанне</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Каб выдаліць прапанову, націÑніце Tab, затым Enter.</translation>
<translation id="3023071826883856138">You4 (канверт)</translation>
<translation id="3024663005179499861">ÐÑправільны тып палітыкі</translation>
<translation id="3037605927509011580">Ð¯ÐºÐ°Ñ Ð½ÐµÑпадзÑванка!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">Дададзена ў закладкі</translation>
<translation id="3209034400446768650">Ðа Ñтаронцы могуць ÑпаганÑцца грошы</translation>
<translation id="3212581601480735796">Вашы дзеÑнні на <ph name="HOSTNAME" /> адÑочваюцца</translation>
+<translation id="3212623355668894776">Каб Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð° вашы дзеÑнні Ñž браўзеры была выдалена з гÑтай прылады, закрыйце ÑžÑе гаÑцÑÐ²Ñ‹Ñ Ð²Ð¾ÐºÐ½Ñ‹.</translation>
<translation id="3215092763954878852">Ðе ўдалоÑÑ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтаць WebAuthn</translation>
<translation id="3218181027817787318">ÐдноÑны</translation>
<translation id="3225919329040284222">Сервер падаў Ñертыфікат, Ñкі не адпавÑдае ўбудаваным патрабаваннÑм. ГÑÑ‚Ñ‹Ñ Ð¿Ð°Ñ‚Ñ€Ð°Ð±Ð°Ð²Ð°Ð½Ð½Ñ– ўключаны Ñž мÑтах вашай бÑÑпекі – ім адпавÑдаюць Ð½Ð°Ð´Ð·ÐµÐ¹Ð½Ñ‹Ñ Ð²Ñб-Ñайты з выÑокім узроўнем бÑÑпекі.</translation>
@@ -701,6 +713,7 @@
<translation id="3784372983762739446">Прылады Bluetooth</translation>
<translation id="3787705759683870569">ТÑрмін дзеÑннÑ: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Памер 16</translation>
+<translation id="3789841737615482174">УÑталÑваць</translation>
<translation id="3793574014653384240">КолькаÑць Ñ– прычыны нÑдаўніх збоÑÑž</translation>
<translation id="3797522431967816232">Prc3 (канверт)</translation>
<translation id="3799805948399000906">Запытаны шрыфт</translation>
@@ -752,6 +765,7 @@
<translation id="4056223980640387499">СепіÑ</translation>
<translation id="4058922952496707368">Ключ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (канверт)</translation>
+<translation id="4067669230157909013">Здыманне Ñкрана ўзноўлена.</translation>
<translation id="4067947977115446013">Дадайце Ñапраўдны адраÑ</translation>
<translation id="4072486802667267160">ÐдбылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ° апрацоўкi вашага заказу. Паўтарыце Ñпробу.</translation>
<translation id="4075732493274867456">Кліент Ñ– Ñервер не падтрымліваюць агульную верÑÑ–ÑŽ пратакола SLL або набор шыфраў.</translation>
@@ -836,6 +850,7 @@
<translation id="4297502707443874121">МініÑцюра Ñтаронкі <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Разгарнуць</translation>
<translation id="4300675098767811073">Ðекалькі дзірак Ñправа</translation>
+<translation id="4302514097724775343">Каб пачаць гульню, дакраніцеÑÑ Ð´Ð° дыназаўра</translation>
<translation id="4302965934281694568">Chou3 (канверт)</translation>
<translation id="4305666528087210886">Ðе ўдалоÑÑ Ð°Ñ‚Ñ€Ñ‹Ð¼Ð°Ñ†ÑŒ доÑтуп да файла</translation>
<translation id="4305817255990598646">Пераключыцца</translation>
@@ -914,6 +929,7 @@
<translation id="4658638640878098064">Скаба зверху злева</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Ð’Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ñ€ÑальнаÑць</translation>
+<translation id="4675657451653251260">У гаÑцÑвым Ñ€Ñжыме вы не будзеце бачыць звеÑтак профілю Chrome. Каб атрымаць доÑтуп да інфармацыі пра Ñвой Уліковы Ð·Ð°Ð¿Ñ–Ñ Google (напрыклад, да паролÑÑž Ñ– ÑпоÑабаў аплаты), <ph name="LINK_BEGIN" />увайдзіце<ph name="LINK_END" /> Ñž Ñго.</translation>
<translation id="467662567472608290">Серверу не ўдалоÑÑ Ð´Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ, што гÑта <ph name="DOMAIN" />: у Ñертыфікаце Ñ‘Ñць памылкі. Прычынай могуць быць нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ або зламыÑнік, Ñкі Ñпрабуе перахапіць падключÑнне.</translation>
<translation id="4677585247300749148"><ph name="URL" /> запытвае дазвол адказваць на падзеі функцый ÑпецыÑльных магчымаÑцей</translation>
<translation id="467809019005607715">ПрÑзентацыі Google</translation>
@@ -941,6 +957,12 @@
<translation id="4761104368405085019">ВыкарыÑтоўваць мікрафон</translation>
<translation id="4764776831041365478">Магчыма, вÑб-Ñтаронка па адраÑе <ph name="URL" /> чаÑова недаÑÑ‚ÑƒÐ¿Ð½Ð°Ñ Ð°Ð±Ð¾ была перамешчана на новы вÑб-адраÑ.</translation>
<translation id="4766713847338118463">Дзве Ñкабы знізу</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ðа гÑтай прыладзе будуць захаваны:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ð»ÑŽÐ±Ñ‹Ñ Ñ„Ð°Ð¹Ð»Ñ‹, ÑÐ¿Ð°Ð¼Ð¿Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ð°Ð¼Ñ– з выкарыÑтаннем гÑтага акна.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Узнікла невÑÐ´Ð¾Ð¼Ð°Ñ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ°.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{УÑплывальнае акно заблакіравана}one{# уÑплывальнае акно заблакіравана}few{#Â Ð²Ñ‹Ð¿Ð»Ñ‹ÑžÐ½Ñ‹Ñ Ð°ÐºÐ½Ñ‹ заблакіравана}many{# выплыўных акон заблакіравана}other{# выплыўнога акна заблакіравана}}</translation>
<translation id="4780366598804516005">ÐŸÐ°ÑˆÑ‚Ð¾Ð²Ð°Ñ Ñкрынка 1</translation>
@@ -1103,11 +1125,13 @@
<translation id="5386426401304769735">Ланцужок Ñертыфікатаў Ð´Ð»Ñ Ð³Ñтага Ñайта змÑшчае Ñертыфікат, падпіÑаны з выкарыÑтаннем алгарытму SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Сшыванне па краі Ñправа</translation>
+<translation id="5398772614898833570">РÑклама заблакіравана</translation>
<translation id="5400836586163650660">ШÑры</translation>
<translation id="540969355065856584">Серверу не ўдалоÑÑ Ð´Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ, што гÑта <ph name="DOMAIN" />; Ñертыфікат бÑÑпекі гÑтага Ñайта не раÑпазнаецца Ñк Ñапраўдны. Прычынай могуць быць нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ або зламыÑнік, Ñкі Ñпрабуе перахапіць падключÑнне.</translation>
<translation id="541416427766103491">Укладчык 4</translation>
<translation id="5421136146218899937">Выдаліць гіÑторыю праглÑдаў...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> запытвае дазвол адпраўлÑць вам апавÑшчÑнні</translation>
+<translation id="542872847390508405">Ð’Ñ‹ выкарыÑтоўваеце браўзер Ñк гоÑць</translation>
<translation id="5430298929874300616">Выдаліць закладку</translation>
<translation id="5439770059721715174">Пры праверцы Ñхемы выÑўлена памылка (<ph name="ERROR_PATH" />: <ph name="ERROR" />)</translation>
<translation id="5443468954631487277">У адваротным парадку, рабочым бокам уверх</translation>
@@ -1149,12 +1173,12 @@
<translation id="5571083550517324815">З гÑтага адраÑа забраць нельга – выберыце іншы.</translation>
<translation id="5580958916614886209">Праверце меÑÑц заканчÑÐ½Ð½Ñ Ñ‚Ñрміну дзеÑÐ½Ð½Ñ Ñ– паўтарыце Ñпробу</translation>
<translation id="5586446728396275693">ÐÑма захаваных адраÑоў</translation>
+<translation id="5593349413089863479">ПадключÑнне не цалкам бÑÑпечнае</translation>
<translation id="5595485650161345191">РÑдагаваць адраÑ</translation>
<translation id="5598944008576757369">Выбраць ÑпоÑаб аплаты</translation>
<translation id="560412284261940334">Кіраванне не падтрымліваецца</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ГÑÑ‚Ñ‹ Ñайт можа быць фальшывым ці махлÑÑ€Ñкім. Chrome Ñ€Ñкамендуе закрыць Ñго.</translation>
<translation id="5610142619324316209">Праверыць падключÑнне</translation>
<translation id="5610807607761827392">Кіраваць карткамі Ñ– адраÑамі можна Ñž <ph name="BEGIN_LINK" />Ðаладах<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">ПераклаÑці Ñтаронку з дапамогай Перакладчыка Google</translation>
@@ -1226,6 +1250,7 @@
<translation id="5901630391730855834">Жоўты</translation>
<translation id="5905445707201418379">Заблакіравана згодна з палітыкай крыніцы "<ph name="ORIGIN" />".</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñінхранізавана)</translation>
+<translation id="5913377024445952699">Здымка Ñкрана прыпынена</translation>
<translation id="59174027418879706">Уключана</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">уключана</translation>
@@ -1238,6 +1263,7 @@
<translation id="5963413905009737549">Раздзел</translation>
<translation id="5967592137238574583">РÑдагаваць ÐºÐ°Ð½Ñ‚Ð°ÐºÑ‚Ð½Ñ‹Ñ Ð·Ð²ÐµÑткі</translation>
<translation id="5967867314010545767">Выдаліць з гіÑторыі</translation>
+<translation id="5968793460449681917">Пры кожным наведванні</translation>
<translation id="5975083100439434680">Паменшыць</translation>
<translation id="5979084224081478209">Праверыць паролі</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@
<translation id="6587923378399804057">Ð¡ÐºÐ°Ð¿Ñ–Ñ€Ð°Ð²Ð°Ð½Ð°Ñ Ð²Ð°Ð¼Ñ– ÑпаÑылка</translation>
<translation id="6591833882275308647">Прылада <ph name="DEVICE_TYPE" /> не знаходзіцца пад кіраваннем</translation>
<translation id="6596325263575161958">Параметры шыфраваннÑ</translation>
+<translation id="6596892391065203054">МагчымаÑць Ð´Ñ€ÑƒÐºÐ°Ð²Ð°Ð½Ð½Ñ Ð³Ñтага змеÑціва заблакіравана адмініÑтратарам.</translation>
<translation id="6604181099783169992">Датчыкі руху або ÑвÑтла</translation>
<translation id="6609880536175561541">Prc7 (канверт)</translation>
<translation id="6612358246767739896">Ðбароненае змеÑціва</translation>
@@ -1452,6 +1479,7 @@
<translation id="6895330447102777224">Картка пацверджана</translation>
<translation id="6897140037006041989">Ðгент карыÑтальніка</translation>
<translation id="6898699227549475383">ÐÑ€Ð³Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ñ (Ð)</translation>
+<translation id="6907293445143367439">Дазволіць Ñайту <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763">Сайт <ph name="URL" /> запытвае поўны кантроль над прыладамі MIDI</translation>
<translation id="6915804003454593391">КарыÑтальнік:</translation>
<translation id="6934672428414710184">ГÑта імÑ – з вашага Уліковага запіÑу Google</translation>
@@ -1493,7 +1521,7 @@
<translation id="70705239631109039">Ваша падключÑнне не цалкам бÑÑпечнае</translation>
<translation id="7072826695771387770">Ðдбываецца небÑÑÐ¿ÐµÑ‡Ð½Ð°Ñ Ð¿Ð°Ð´Ð·ÐµÑ</translation>
<translation id="7075452647191940183">Запыт занадта вÑлікі</translation>
-<translation id="7079718277001814089">ГÑÑ‚Ñ‹ Ñайт мае шкоднае змеÑціва</translation>
+<translation id="7079718277001814089">ГÑÑ‚Ñ‹ Ñайт змÑшчае шкоднае ПЗ</translation>
<translation id="7081308185095828845">Ðа жаль, гÑта Ñ„ÑƒÐ½ÐºÑ†Ñ‹Ñ Ð½Ð° прыладзе недаÑтупнаÑ</translation>
<translation id="7083258188081898530">Латок 9</translation>
<translation id="7086090958708083563">Запампоўка запытана карыÑтальнікам</translation>
@@ -1537,7 +1565,7 @@
<translation id="7238585580608191973">Лічбавы адбітак SHA-256</translation>
<translation id="7240120331469437312">ÐльтÑрнатыўнае Ñ–Ð¼Ñ Ñуб'екта Ñертыфіката</translation>
<translation id="7243010569062352439"><ph name="PASSWORDS" />; <ph name="SIGNIN_DATA" /></translation>
-<translation id="724691107663265825">Сайт, на Ñкі вы збіраецеÑÑ Ð¿ÐµÑ€Ð°Ð¹Ñці, утрымлівае шкоднае змеÑціва</translation>
+<translation id="724691107663265825">Сайт, на Ñкі вы збіраецеÑÑ Ð¿ÐµÑ€Ð°Ð¹Ñці, змÑшчае шкоднае ПЗ</translation>
<translation id="724975217298816891">Каб абнавіць Ð´Ð°Ð½Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ–, увÑдзіце дату заканчÑÐ½Ð½Ñ Ñ‚Ñрміну дзеÑÐ½Ð½Ñ Ñ– код CVC з карткі <ph name="CREDIT_CARD" />. ПаÑÐ»Ñ Ð²Ð°ÑˆÐ°Ð³Ð° пацвÑрджÑÐ½Ð½Ñ Ð´Ð°Ð½Ñ‹Ñ Ð²Ð°ÑˆÐ°Ð¹ карткі будуць абагулены з гÑтым Ñайтам.</translation>
<translation id="7251437084390964440">ÐšÐ°Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ‹Ñ Ñеткі не адпавÑдае Ñтандарту ONC. Магчыма, Ð½ÐµÐºÐ°Ñ‚Ð¾Ñ€Ñ‹Ñ Ñ‡Ð°Ñткі канфігурацыі не былі імпартаваны.
ПадрабÑÐ·Ð½Ñ‹Ñ Ð·Ð²ÐµÑткі:
@@ -1563,6 +1591,7 @@
<translation id="7346048084945669753">КарыÑтальнік далучаны:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Камандны радок</translation>
+<translation id="7359588939039777303">РÑклама заблакіравана.</translation>
<translation id="7372973238305370288">вынік пошуку</translation>
<translation id="7374733840632556089">ГÑта праблема ўзнікае з-за Ñертыфіката, уÑталÑванага на вашай прыладзе вамі або іншым карыÑтальнікам. ÐÑць інфармацыÑ, што гÑÑ‚Ñ‹ Ñертыфікат выкарыÑтоўваецца Ð´Ð»Ñ Ð¼Ð°Ð½Ñ–Ñ‚Ð¾Ñ€Ñ‹Ð½Ð³Ñƒ Ñ– перахопу Ñетак, Ñ– таму ён не з'ÑўлÑецца давераным Ð´Ð»Ñ Chrome. Бываюць выпадкі, калі такі маніторынг не з'ÑўлÑецца незаконным (напрыклад, калі прылада знаходзіцца Ñž Ñетцы кампаніі або навучальнай уÑтановы), але Ñž любым выпадку мы хацелі б папÑÑ€Ñдзіць Ð²Ð°Ñ Ð¿Ñ€Ð° Ñ–Ñнаванне такога Ñертыфіката. Выпадкі маніторынгу могуць адбывацца Ñž любым браўзеры або Ñž любой праграме, ÑÐºÐ°Ñ Ð¼Ð°Ðµ доÑтуп да інтÑрнÑту.</translation>
<translation id="7375818412732305729">Далучаецца файл</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">Занадта шмат запытаў</translation>
<translation id="7977538094055660992">Прылада вываду</translation>
<translation id="7977894662897852582">EDP</translation>
+<translation id="79859296434321399">Каб праглÑдаць змеÑціва Ñž Ñ€Ñжыме дапоўненай Ñ€ÑальнаÑці, уÑталюйце ARCore</translation>
<translation id="799149739215780103">Пераплёт</translation>
<translation id="7995512525968007366">Ðе вызначана</translation>
<translation id="800218591365569300">Каб вызваліць памÑць, закрыйце Ñ–Ð½ÑˆÑ‹Ñ ÑžÐºÐ»Ð°Ð´ÐºÑ– або праграмы.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">Камандны радок</translation>
<translation id="8508648098325802031">Значок пошуку</translation>
<translation id="8522552481199248698">Chrome можа дапамагчы абараніць Уліковы Ð·Ð°Ð¿Ñ–Ñ Google Ñ– змÑніць ваш пароль.</translation>
+<translation id="8525306231823319788">ПоўнаÑкранны Ñ€Ñжым</translation>
<translation id="8530813470445476232">Выдаліць гіÑторыю праглÑду Ñайтаў, файлы cookie, кÑшаванае змеÑціва Ñ– іншае праз налады Chrome</translation>
<translation id="8533619373899488139">Каб прагледзець ÑÐ¿Ñ–Ñ Ð·Ð°Ð±Ð»Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ñ‹Ñ… URL-адраÑоў Ñ– Ñ–Ð½ÑˆÑ‹Ñ Ð¿Ð°Ð»Ñ–Ñ‚Ñ‹ÐºÑ–, Ñкімі кіруе ÑÑ–ÑÑ‚Ñмны адмініÑтратар, наведайце &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
<translation id="8541158209346794904">Прылада Bluetooth</translation>
<translation id="8542014550340843547">Тры Ñкабы знізу</translation>
<translation id="8543181531796978784">Ð’Ñ‹ можаце <ph name="BEGIN_ERROR_LINK" />паведаміць аб праблеме<ph name="END_ERROR_LINK" /> або, калі ÑžÑведамлÑеце рызыку Ð´Ð»Ñ Ñваёй бÑÑпекі, <ph name="BEGIN_LINK" />можаце наведаць гÑÑ‚Ñ‹ небÑÑпечны Ñайт<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC знаходзіцца на адвароце карткі.</translation>
+<translation id="8558485628462305855">Каб праглÑдаць змеÑціва Ñž Ñ€Ñжыме дапоўненай Ñ€ÑальнаÑці, абнавіце ARCore</translation>
<translation id="8559762987265718583">Памылка прыватнага падключÑÐ½Ð½Ñ Ð´Ð° дамена <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />: дата Ñ– Ñ‡Ð°Ñ Ð½Ð° вашай прыладзе (<ph name="DATE_AND_TIME" />) нÑправільныÑ.</translation>
<translation id="8564182942834072828">ÐÑÐ¾Ð±Ð½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹, Ð½ÐµÑ€Ð°Ð·Ð°Ð±Ñ€Ð°Ð½Ñ‹Ñ ÐºÐ¾Ð¿Ñ–Ñ–</translation>
<translation id="8564985650692024650">Chromium Ñ€Ñкамендуе Ñкінуць пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, калі вы карыÑталіÑÑ Ñ–Ð¼ на іншых Ñайтах.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ðа гÑтай прыладзе не будуць захоўвацца:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтаронкі, ÑÐºÑ–Ñ Ð²Ñ‹ праглÑдаеце Ñž гÑтым акне;
+ <ph name="LIST_ITEM" />файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ Ñайтаў.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ВыкарыÑтоўваць Touch ID Ð´Ð»Ñ Ñ…ÑƒÑ‚Ñ‡Ñйшага пацвÑрджÑÐ½Ð½Ñ ÐºÐ°Ñ€Ñ‚Ð°Ðº</translation>
<translation id="858637041960032120">Дадайце нумар Ñ‚Ñлефона</translation>
<translation id="8589998999637048520">ÐÐ°Ð¹Ð»ÐµÐ¿ÑˆÐ°Ñ ÑкаÑць</translation>
+<translation id="8600271352425265729">Толькі Ñž гÑÑ‚Ñ‹ раз</translation>
<translation id="860043288473659153">Ð†Ð¼Ñ ÑžÐ»Ð°Ð´Ð°Ð»ÑŒÐ½Ñ–ÐºÐ° карткі</translation>
<translation id="8606726445206553943">ВыкарыÑтоўваць прылады MIDI</translation>
+<translation id="8612761427948161954">Вітаем, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Ð’Ñ‹ выкарыÑтоўваеце браўзер Ñк гоÑць</translation>
<translation id="861775596732816396">Памер 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Пароль Ð´Ð»Ñ Ð³Ñтага Ñайта не знойдзены. Паказаць уÑе Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–.</translation>
<translation id="8625384913736129811">Захаваць гÑту картку на гÑту прыладу</translation>
+<translation id="8627040765059109009">Здымка Ñкрана ўзноўлена</translation>
<translation id="8657078576661269990">ÐдмініÑтратар заблакіраваў абагульванне змеÑціва з Ñайта <ph name="ORIGIN_NAME" /> з віртуальнымі машынамі <ph name="VM_NAME_1" /> Ñ– <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Зводка па заказе, <ph name="TOTAL_LABEL" />, Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð°Ñ Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ</translation>
<translation id="867224526087042813">ПодпіÑ</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Уліковы Ð·Ð°Ð¿Ñ–Ñ Google</translation>
<translation id="8913778647360618320">Кнопка "Ðаладзіць ÑпоÑабы аплаты". Каб кіраваць плацÑжамі Ñ– звеÑткамі крÑдытных картак праз налады Chrome, націÑніце Enter</translation>
<translation id="8918231688545606538">ГÑта Ñтаронка падазронаÑ</translation>
+<translation id="8922013791253848639">ЗаўÑёды паказваць Ñ€Ñкламу на гÑтым Ñайце</translation>
<translation id="892588693504540538">Дзірка зверху Ñправа</translation>
<translation id="8931333241327730545">Захаваць гÑту картку Ñž вашым Уліковым запіÑе Google?</translation>
<translation id="8932102934695377596">Ваш гадзіннік ÑпазнÑецца</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Дакументы Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> выкарыÑтоўвае пратакол, Ñкі не падтрымліваецца.</translation>
<translation id="9191834167571392248">Дзірка знізу злева</translation>
+<translation id="9199905725844810519">Друкаванне заблакіравана</translation>
<translation id="9205078245616868884">Вашы Ð´Ð°Ð½Ñ‹Ñ Ð·Ð°ÑˆÑ‹Ñ„Ñ€Ð°Ð²Ð°Ð½Ñ‹ з дапамогай фразы-Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ Ñінхранізацыі. УвÑдзіце Ñе, каб пачаць Ñінхранізацыю.</translation>
<translation id="9207861905230894330">Ðе ўдалоÑÑ Ð´Ð°Ð´Ð°Ñ†ÑŒ артыкул.</translation>
<translation id="9213433120051936369">Ðаладжванне выглÑду</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Ð’Ñ‹ можаце Ñтраціць доÑтуп да Ñвайго Уліковага запіÑу Google. Chromium Ñ€Ñкамендуе змÑніць пароль. Ð’Ð°Ñ Ð¿Ð°Ð¿Ñ€Ð¾ÑÑць увайÑці ва ўліковы запіÑ.</translation>
<translation id="939736085109172342">ÐÐ¾Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°</translation>
+<translation id="945522503751344254">Ðдправіць водгук</translation>
<translation id="945855313015696284">Праверце інфармацыю ніжÑй Ñ– выдаліце нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ–</translation>
<translation id="950736567201356821">Тры дзіркі зверху</translation>
+<translation id="951941430552851965">Здыманне Ñкрана была прыпынена адмініÑтратарам з-за характару змеÑціва, Ñкое знаходзілаÑÑ Ð½Ð° Ñкране.</translation>
<translation id="961663415146723894">Пераплёт знізу</translation>
<translation id="962484866189421427">Праз гÑта змеÑціва могуць уÑталÑвацца Ð¿Ð°Ð´Ð¼Ð°Ð½Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹, ÑÐºÑ–Ñ Ñпрабуюць выдаваць ÑÑбе за нешта іншае або збіраюць даныÑ, што могуць быць выкарыÑтаны Ð´Ð»Ñ ÑачÑÐ½Ð½Ñ Ð·Ð° вамі. <ph name="BEGIN_LINK" />УÑÑ‘ роўна паказаць<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ÐÑ„Ñ–Ñ†Ñ‹Ð¹Ð½Ð°Ñ Ð·Ð±Ð¾Ñ€ÐºÐ°</translation>
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index 61603b523bc..90d85152e03 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Въведохте паролата Ñи на Ñайт, който не Ñе управлÑва от организациÑта ви. За да защитите профила Ñи, не използвайте паролата Ñи повторно в други Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñайтове.</translation>
<translation id="1263231323834454256">СпиÑък за четене</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚, коÑто нÑма да бъде запазена на уÑтройÑтвото:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраниците, които преглеждате в този прозорец;
+ <ph name="LIST_ITEM" />„биÑквитките“ и данните за Ñайтовете;
+ <ph name="LIST_ITEM" />информациÑта за профила (<ph name="LINK_BEGIN" />изход<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ðачин на вземане</translation>
<translation id="1281476433249504884">Стакер 1</translation>
<translation id="1285320974508926690">Този Ñайт да не Ñе превежда никога</translation>
@@ -281,6 +289,7 @@
<translation id="204357726431741734">Влезте в профила Ñи в Google, за да използвате запазените в него пароли</translation>
<translation id="2053111141626950936">Страниците на <ph name="LANGUAGE" /> нÑма да Ñе превеждат.</translation>
<translation id="2053553514270667976">ПощенÑки код</translation>
+<translation id="2054665754582400095">ПриÑÑŠÑтвието ви</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 предложение}other{# предложениÑ}}</translation>
<translation id="2079545284768500474">ОтмÑна</translation>
<translation id="20817612488360358">За използване Ñа зададени ÑиÑтемни наÑтройки за прокÑи Ñървъра, но е поÑочена и изрична конфигурациÑ.</translation>
@@ -294,6 +303,7 @@
<translation id="2102495993840063010">ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° Android</translation>
<translation id="2107021941795971877">Опори при отпечатване</translation>
<translation id="2108755909498034140">РеÑтартирайте компютъра Ñи.</translation>
+<translation id="2111166930115883695">ÐатиÑнете интервал, за да играете</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701">Бе пренебрегнато, защото бе отменено от <ph name="POLICY_NAME" />.</translation>
@@ -305,6 +315,7 @@
<translation id="214556005048008348">Ðнулиране на плащането</translation>
<translation id="2147827593068025794">Синхронизиране на заден план</translation>
<translation id="2148613324460538318">ДобавÑне на карта</translation>
+<translation id="2149968176347646218">Връзката не е защитена</translation>
<translation id="2154054054215849342">Синхронизирането не е налице за Ð²ÑŠÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Ð²Ð°Ñ Ð´Ð¾Ð¼ÐµÐ¹Ð½</translation>
<translation id="2154484045852737596">Редактиране на картата</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -315,7 +326,6 @@
<translation id="2181821976797666341">Правила</translation>
<translation id="2183608646556468874">Телефонен номер</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑ}other{# адреÑа}}</translation>
-<translation id="2187243482123994665">ПриÑÑŠÑтвие на потребителÑ</translation>
<translation id="2187317261103489799">Откриване (по подразбиране)</translation>
<translation id="2188375229972301266">ÐÑколко перфорации в долната чаÑÑ‚</translation>
<translation id="2202020181578195191">Въведете валидна година на изтичане</translation>
@@ -466,6 +476,7 @@
<translation id="2839501879576190149">Внимание: фалшив Ñайт</translation>
<translation id="2850739647070081192">Invite (плик)</translation>
<translation id="2856444702002559011">Възможно е извършители на атака да опитват да откраднат информациÑта ви от <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например пароли, ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ номера на кредитни карти). <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ðа този Ñайт Ñе показват натрапчиви или подвеждащи реклами.</translation>
<translation id="2878197950673342043">КръÑтоÑано Ñгъване</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Разположение на прозорците</translation>
@@ -504,11 +515,11 @@
<translation id="2996674880327704673">ÐŸÑ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Google</translation>
<translation id="3002501248619246229">Проверете хартиÑта във входната тава</translation>
<translation id="3005723025932146533">Показване на запазено копие</translation>
-<translation id="3007719053326478567">Отпечатването на това Ñъдържание е блокирано от админиÑтратора ви</translation>
<translation id="3008447029300691911">Въведете кода за проверка за <ph name="CREDIT_CARD" />. След като потвърдите картата Ñи, данните за Ð½ÐµÑ Ñ‰Ðµ бъдат Ñподелени Ñ Ñ‚Ð¾Ð·Ð¸ Ñайт.</translation>
<translation id="3010559122411665027">СпиÑъчен Ð·Ð°Ð¿Ð¸Ñ â€ž<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Ðвтоматично блокирано</translation>
<translation id="3016780570757425217">ДоÑтъп до меÑтоположението ви.</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, натиÑнете Tab и Ñлед това Enter, за да премахнете предложението.</translation>
<translation id="3023071826883856138">You4 (плик)</translation>
<translation id="3024663005179499861">Грешен тип на правилото</translation>
<translation id="3037605927509011580">УжаÑ!</translation>
@@ -551,6 +562,7 @@
<translation id="3207960819495026254">С отметка</translation>
<translation id="3209034400446768650">Страницата може да ви такÑува</translation>
<translation id="3212581601480735796">ÐктивноÑтта ви в <ph name="HOSTNAME" /> Ñе Ñледи</translation>
+<translation id="3212623355668894776">Затворете вÑички прозорци в режим на гоÑÑ‚, така че активноÑтта ви при Ñърфиране да бъде изтрита от това уÑтройÑтво.</translation>
<translation id="3215092763954878852">WebAuthn не можа да Ñе използва</translation>
<translation id="3218181027817787318">ОтноÑително</translation>
<translation id="3225919329040284222">Сървърът предоÑтави Ñертификат, който не ÑъответÑтва на вградените очакваниÑ. Те Ñа включени за определени уебÑайтове Ñ Ð³Ð¾Ð»Ñма Ñтепен на ÑигурноÑÑ‚, за да ви предпазим.</translation>
@@ -698,6 +710,7 @@
<translation id="3784372983762739446">Bluetooth уÑтройÑтва</translation>
<translation id="3787705759683870569">Изтича на <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Размер 16</translation>
+<translation id="3789841737615482174">ИнÑталиране</translation>
<translation id="3793574014653384240">Брой и причини за наÑкоро възникналите Ñривове</translation>
<translation id="3797522431967816232">Prc3 (плик)</translation>
<translation id="3799805948399000906">Шрифтът е заÑвен</translation>
@@ -749,6 +762,7 @@
<translation id="4056223980640387499">СепиÑ</translation>
<translation id="4058922952496707368">Ключ „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (плик)</translation>
+<translation id="4067669230157909013">ЗаÑнемането на екрана бе възобновено.</translation>
<translation id="4067947977115446013">ДобавÑне на валиден адреÑ</translation>
<translation id="4072486802667267160">При обработването на поръчката ви възникна грешка. МолÑ, опитайте отново.</translation>
<translation id="4075732493274867456">Клиентът и Ñървърът не поддържат обща верÑÐ¸Ñ Ð¸Ð»Ð¸ пакет за шифроване за протокола SSL.</translation>
@@ -833,6 +847,7 @@
<translation id="4297502707443874121">Миниизображение на Ñтраницата <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Разгъване</translation>
<translation id="4300675098767811073">ÐÑколко перфорации отдÑÑно</translation>
+<translation id="4302514097724775343">ДокоÑнете динозавъра, за да играете</translation>
<translation id="4302965934281694568">Chou3 (плик)</translation>
<translation id="4305666528087210886">ÐÑма доÑтъп до файла</translation>
<translation id="4305817255990598646">Превключване</translation>
@@ -911,6 +926,7 @@
<translation id="4658638640878098064">Телбодиране горе влÑво</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуална реалноÑÑ‚</translation>
+<translation id="4675657451653251260">Ð’ режим на гоÑÑ‚ нÑма да виждате Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° потребителÑките профили в Chrome. Можете <ph name="LINK_BEGIN" />да влезете в профила Ñи<ph name="LINK_END" /> в Google, за да оÑъщеÑтвите доÑтъп до данните в него, като например пароли и начини на плащане.</translation>
<translation id="467662567472608290">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; Ñертификатът му за ÑигурноÑÑ‚ Ñъдържа грешки. Това може да Ñе дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="4677585247300749148"><ph name="URL" /> иÑка да реагира на ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð·Ð° доÑтъпноÑÑ‚</translation>
<translation id="467809019005607715">Google Презентации</translation>
@@ -938,6 +954,12 @@
<translation id="4761104368405085019">Използване на микрофона ви</translation>
<translation id="4764776831041365478">До уеб Ñтраницата на Ð°Ð´Ñ€ÐµÑ <ph name="URL" /> може временно да нÑма доÑтъп или да е премеÑтена за поÑтоÑнно на нов уеб адреÑ.</translation>
<translation id="4766713847338118463">Двуточково телбодиране в долната чаÑÑ‚</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚, коÑто ще бъде запазена на уÑтройÑтвото:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />файловете, които изтеглите в този прозорец.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Възникна неизвеÑтна грешка.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Блокиран е изÑкачащ прозорец}other{Блокирани Ñа # изÑкач. прозореца}}</translation>
<translation id="4780366598804516005">ПощенÑка ÐºÑƒÑ‚Ð¸Ñ 1</translation>
@@ -1100,11 +1122,13 @@
<translation id="5386426401304769735">Веригата от Ñертификати за този Ñайт Ñъдържа Ñертификат, подпиÑан Ñ SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Зашиване на деÑÐ½Ð¸Ñ Ñ€ÑŠÐ±</translation>
+<translation id="5398772614898833570">Рекламите Ñа блокирани</translation>
<translation id="5400836586163650660">Ñиво</translation>
<translation id="540969355065856584">Сървърът не можа да докаже, че е <ph name="DOMAIN" />. ПонаÑтоÑщем Ñертификатът му за ÑигурноÑÑ‚ не е валиден. Това може да Ñе дължи на неправилно конфигуриране или на прихващане на връзката ви от извършител на атака.</translation>
<translation id="541416427766103491">Стакер 4</translation>
<translation id="5421136146218899937">ИзчиÑтване на данните за Ñърфирането...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> иÑка да ви изпраща извеÑтиÑ</translation>
+<translation id="542872847390508405">Сърфирате като гоÑÑ‚</translation>
<translation id="5430298929874300616">Премахване на отметката</translation>
<translation id="5439770059721715174">При потвърждаване на Ñхемата възникна грешка в/ъв „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ð’ обратен ред Ñ Ð¾Ñ‚Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ð½Ð°Ñ‚Ð° Ñтрана нагоре</translation>
@@ -1146,12 +1170,12 @@
<translation id="5571083550517324815">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° вземане не Ñе поддържа. Изберете друг.</translation>
<translation id="5580958916614886209">Проверете меÑеца на валидноÑÑ‚ и опитайте отново</translation>
<translation id="5586446728396275693">ÐÑма запазени адреÑи</translation>
+<translation id="5593349413089863479">Връзката не е напълно защитена</translation>
<translation id="5595485650161345191">Редактиране на адреÑа</translation>
<translation id="5598944008576757369">Избиране на начин на плащане</translation>
<translation id="560412284261940334">Управлението не Ñе поддържа</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Този Ñайт може да е фалшив или измамничеÑки. Chrome препоръчва да го напуÑнете Ñега.</translation>
<translation id="5610142619324316209">Проверете връзката.</translation>
<translation id="5610807607761827392">Можете да управлÑвате картите и адреÑите от <ph name="BEGIN_LINK" />наÑтройките<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Преведете тази Ñтраница Ñ Google Преводач</translation>
@@ -1223,6 +1247,7 @@
<translation id="5901630391730855834">жълто</translation>
<translation id="5905445707201418379">Блокирано Ñпоред правилото за източник на <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинхронизирано)</translation>
+<translation id="5913377024445952699">ФункциÑта за заÑнемане на екрана е поÑтавена на пауза</translation>
<translation id="59174027418879706">Ðктивирано</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Включено</translation>
@@ -1235,6 +1260,7 @@
<translation id="5963413905009737549">СекциÑ</translation>
<translation id="5967592137238574583">Редактиране на информациÑта за връзка</translation>
<translation id="5967867314010545767">Премахване от иÑториÑта</translation>
+<translation id="5968793460449681917">При вÑÑко поÑещение</translation>
<translation id="5975083100439434680">ÐамалÑване на мащаба</translation>
<translation id="5979084224081478209">Проверка на паролите</translation>
<translation id="5980920751713728343">Index-3 x 5</translation>
@@ -1390,6 +1416,7 @@
<translation id="6587923378399804057">Копирана от Ð²Ð°Ñ Ð²Ñ€ÑŠÐ·ÐºÐ°</translation>
<translation id="6591833882275308647">УÑтройÑтвото ви <ph name="DEVICE_TYPE" /> не е управлÑвано</translation>
<translation id="6596325263575161958">Опции за шифроване</translation>
+<translation id="6596892391065203054">Отпечатването на това Ñъдържание е блокирано от админиÑтратора ви.</translation>
<translation id="6604181099783169992">Сензори за движение или Ñветлина</translation>
<translation id="6609880536175561541">Prc7 (плик)</translation>
<translation id="6612358246767739896">Защитено Ñъдържание</translation>
@@ -1449,6 +1476,7 @@
<translation id="6895330447102777224">Картата ви е потвърдена</translation>
<translation id="6897140037006041989">ПотребителÑки агент</translation>
<translation id="6898699227549475383">ÐžÑ€Ð³Ð°Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ (О)</translation>
+<translation id="6907293445143367439">Разрешаване на <ph name="SITE_NAME" /> да:</translation>
<translation id="6910240653697687763"><ph name="URL" /> иÑка да получи пълен контрол над MIDI уÑтройÑтвата ви</translation>
<translation id="6915804003454593391">Потребител:</translation>
<translation id="6934672428414710184">Това име е от профила ви в Google</translation>
@@ -1560,6 +1588,7 @@
<translation id="7346048084945669753">ПотребителÑÑ‚ е вътрешен:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Команден ред</translation>
+<translation id="7359588939039777303">Рекламите Ñа блокирани.</translation>
<translation id="7372973238305370288">резултат от Ñ‚ÑŠÑ€Ñенето</translation>
<translation id="7374733840632556089">Причината за този проблем е Ñертификат, инÑталиран на уÑтройÑтвото ви от Ð²Ð°Ñ Ð¸Ð»Ð¸ от друг потребител. Сертификатът е извеÑтен Ñ Ñ‚Ð¾Ð²Ð°, че Ñе използва за наблюдение и прехващане на мрежи и Chrome му нÑма доверие. Въпреки че ÑъщеÑтвуват нÑкои легитимни Ñлучаи за наблюдение, като например училищна или фирмена мрежа, Chrome иÑка да Ñе увери, че знаете, че това Ñе Ñлучва, дори ако не можете да го Ñпрете. Ðаблюдението може да Ñтава във вÑеки браузър или приложение, които оÑъщеÑтвÑват доÑтъп до мрежата.</translation>
<translation id="7375818412732305729">Прикачване на файл</translation>
@@ -1734,6 +1763,7 @@
<translation id="7976214039405368314">Твърде много заÑвки</translation>
<translation id="7977538094055660992">Изходно уÑтройÑтво</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">За да гледате Ñъдържание Ñ Ð¾Ð±Ð¾Ð³Ð°Ñ‚ÐµÐ½Ð° реалноÑÑ‚, инÑталирайте ARCore</translation>
<translation id="799149739215780103">Подвързване</translation>
<translation id="7995512525968007366">Ðе е поÑочено</translation>
<translation id="800218591365569300">Затворете другите раздели или програми, за да оÑвободите памет.</translation>
@@ -1861,24 +1891,38 @@
<translation id="8507227106804027148">Команден ред</translation>
<translation id="8508648098325802031">Икона за Ñ‚ÑŠÑ€Ñене</translation>
<translation id="8522552481199248698">Chrome може да ви помогне да защитите профила Ñи в Google и да промените паролата Ñи.</translation>
+<translation id="8525306231823319788">Ðа цÑл екран</translation>
<translation id="8530813470445476232">ИзчиÑтете иÑториÑта Ñи на Ñърфиране, „биÑквитките“, кеша и др. в наÑтройките на Chrome</translation>
<translation id="8533619373899488139">ПоÑетете &lt;strong&gt;chrome://policy&lt;/strong&gt;, за да видите блокираните URL адреÑи и другите правила, наложени от ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð²Ð¸ админиÑтратор.</translation>
<translation id="8541158209346794904">Bluetooth уÑтройÑтва</translation>
<translation id="8542014550340843547">Триточково телбодиране в долната чаÑÑ‚</translation>
<translation id="8543181531796978784">Можете да <ph name="BEGIN_ERROR_LINK" />подадете Ñигнал за проблем при откриването<ph name="END_ERROR_LINK" /> или, ако разбирате риÑковете за ÑигурноÑтта Ñи, да <ph name="BEGIN_LINK" />поÑетите този небезопаÑен Ñайт<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Кодът за проверка Ñе намира на гърба на картата ви.</translation>
+<translation id="8558485628462305855">За да гледате Ñъдържание Ñ Ð¾Ð±Ð¾Ð³Ð°Ñ‚ÐµÐ½Ð° реалноÑÑ‚, актуализирайте ARCore</translation>
<translation id="8559762987265718583">Ðе може да Ñе уÑтанови чаÑтна връзка Ñ/ÑŠÑ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, тъй като датата и чаÑÑŠÑ‚ на уÑтройÑтвото ви (<ph name="DATE_AND_TIME" />) Ñа неправилни.</translation>
<translation id="8564182942834072828">Отделни документи/неподредени копиÑ</translation>
<translation id="8564985650692024650">Chromium препоръчва да зададете повторно паролата Ñи за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, ако Ñте Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ð»Ð¸ и на други Ñайтове.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚, коÑто нÑма да бъде запазена на уÑтройÑтвото:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраниците, които преглеждате в този прозорец;
+ <ph name="LIST_ITEM" />„биÑквитките“ и данните за Ñайтовете.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Използвайте Touch ID, за да потвърждавате картите по-бързо</translation>
<translation id="858637041960032120">+ тел. номер</translation>
<translation id="8589998999637048520">Ðай-добро качеÑтво</translation>
+<translation id="8600271352425265729">Само този път</translation>
<translation id="860043288473659153">Име на титулÑÑ€Ñ Ð½Ð° картата</translation>
<translation id="8606726445206553943">Да използва MIDI уÑтройÑтвата ви.</translation>
+<translation id="8612761427948161954">Здравейте, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Сърфирате като гоÑÑ‚</translation>
<translation id="861775596732816396">Размер 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ÐÑма ÑъответÑтващи пароли. Показване на вÑички запазени пароли.</translation>
<translation id="8625384913736129811">Запазване на картата на това уÑтройÑтво</translation>
+<translation id="8627040765059109009">ФункциÑта за заÑнемане на екрана е възобновена</translation>
<translation id="8657078576661269990">ÐдминиÑтраторът ви е блокирал ÑподелÑнето от <ph name="ORIGIN_NAME" /> Ñ(ÑŠÑ) <ph name="VM_NAME_1" /> и <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Обобщение на поръчката, <ph name="TOTAL_LABEL" />, още подробноÑти</translation>
<translation id="867224526087042813">ПодпиÑ</translation>
@@ -1941,6 +1985,7 @@
<translation id="8912362522468806198">Профил в Google</translation>
<translation id="8913778647360618320">Бутон „Управление на начините на плащане“. ÐатиÑнете Enter, за да управлÑвате информациÑта Ñи за плащане и данните за кредитните Ñи карти в наÑтройките на Chrome</translation>
<translation id="8918231688545606538">Тази Ñтраница е подозрителна</translation>
+<translation id="8922013791253848639">Рекламите на този Ñайт да Ñа разрешени винаги</translation>
<translation id="892588693504540538">Перфориране горе вдÑÑно</translation>
<translation id="8931333241327730545">ИÑкате ли да запазите тази карта в профила Ñи в Google?</translation>
<translation id="8932102934695377596">ЧаÑовникът ви е назад</translation>
@@ -2012,6 +2057,7 @@
<translation id="9183302530794969518">Google Документи</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> използва неподдържан протокол.</translation>
<translation id="9191834167571392248">Перфориране долу влÑво</translation>
+<translation id="9199905725844810519">Отпечатването е блокирано</translation>
<translation id="9205078245616868884">Данните ви Ñа шифровани Ñ Ð¿Ñ€Ð¾Ð¿ÑƒÑка ви за Ñинхронизиране. Въведете го, за да Ñтартирате Ñинхронизирането.</translation>
<translation id="9207861905230894330">ДобавÑнето на ÑтатиÑта не бе уÑпешно.</translation>
<translation id="9213433120051936369">ПерÑонализиране на облика</translation>
@@ -2022,8 +2068,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Възможно е да загубите доÑтъп до профила Ñи в Google. Chromium препоръчва да промените паролата Ñи Ñега. Ще получите подкана за влизане в профила Ñи.</translation>
<translation id="939736085109172342">Ðова папка</translation>
+<translation id="945522503751344254">Изпращане на отзиви</translation>
<translation id="945855313015696284">Проверете информациÑта по-долу и изтрийте невалидните карти</translation>
<translation id="950736567201356821">Тройно перфориране в горната чаÑÑ‚</translation>
+<translation id="951941430552851965">ЗаÑнемането на екрана бе поÑтавено на пауза от админиÑтратора ви заради Ñъдържанието на екрана ви.</translation>
<translation id="961663415146723894">Подвързване на долната чаÑÑ‚</translation>
<translation id="962484866189421427">ВъпроÑното Ñъдържание може да Ñе опита да инÑталира измамни приложениÑ, които Ñе предÑтавÑÑ‚ за нещо друго или Ñъбират данни, които може да Ñе използват за проÑледÑването ви. <ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Официално издание</translation>
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index 0c73a2938c5..208eed8b117 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">আপনার পà§à¦°à¦¤à¦¿à¦·à§à¦ à¦¾à¦¨à§‡à¦° নয় à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ সাইটে আপনার পাসওয়ারà§à¦¡ লিখেছেন। আপনার অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° সà§à¦°à¦•à§à¦·à¦¾à¦° জনà§à¦¯ অনà§à¦¯à¦¾à¦¨à§à¦¯ অà§à¦¯à¦¾à¦ª à¦à¦¬à¦‚ সাইটগà§à¦²à¦¿à¦¤à§‡ আপনার à¦à¦‡ পাসওয়ারà§à¦¡à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করবেন না।</translation>
<translation id="1263231323834454256">পড়ার তালিকা</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ যেসব অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ à¦à¦‡ ডিভাইসে সেভ করা হবে না:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¦à¦‡ উইনà§à¦¡à§‹à¦¤à§‡ আপনি যেসব পৃষà§à¦ à¦¾ দেখেন
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ à¦à¦¬à¦‚ সাইট ডেটা
+ <ph name="LIST_ITEM" />অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° তথà§à¦¯ (<ph name="LINK_BEGIN" />সাইন-আউট করà§à¦¨<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">পিক-আপের পদà§à¦§à¦¤à¦¿</translation>
<translation id="1281476433249504884">সà§à¦Ÿà§à¦¯à¦¾à¦•à¦¾à¦° ১</translation>
<translation id="1285320974508926690">কখনই à¦à¦‡ সাইটটিকে অনà§à¦¬à¦¾à¦¦ করবেন না</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">ইতিহাসে à¦à¦¨à§à¦Ÿà§à¦°à¦¿à¦° তালিকা</translation>
<translation id="1517433312004943670">ফোন নমà§à¦¬à¦° আবশà§à¦¯à¦•</translation>
<translation id="1519264250979466059">নিরà§à¦®à¦¾à¦£à§‡à¦° তারিখ</translation>
-<translation id="1521655867290435174">Google পতà§à¦°à¦•</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">সংযোগের জনà§à¦¯ অপেকà§à¦·à¦¾ করা হচà§à¦›à§‡...</translation>
<translation id="1529521330346880926">10x15 (Envelope)</translation>
<translation id="1529789484829130889">টà§à¦°à§‡ ৮</translation>
@@ -284,6 +292,7 @@
<translation id="204357726431741734">আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ সেভ করা পাসওয়ারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে সাইন-ইন করà§à¦¨</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> ভাষার পৃষà§à¦ à¦¾ অনà§à¦¬à¦¾à¦¦ করা হবে না।</translation>
<translation id="2053553514270667976">পিন কোড</translation>
+<translation id="2054665754582400095">আপনার উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{১টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}one{#টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}other{#টি পà§à¦°à¦¸à§à¦¤à¦¾à¦¬}}</translation>
<translation id="2079545284768500474">আগের অবসà§à¦¥à¦¾à§Ÿ ফিরà§à¦¨</translation>
<translation id="20817612488360358">সিসà§à¦Ÿà§‡à¦® পà§à¦°à¦•à§à¦¸à¦¿ সেটিংস বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ সেট আছে কিনà§à¦¤à§ à¦à¦•à¦Ÿà¦¿ সà§à¦¨à¦¿à¦°à§à¦¦à¦¿à¦·à§à¦Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশনও নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা আছে৷</translation>
@@ -297,6 +306,7 @@
<translation id="2102495993840063010">Android অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿</translation>
<translation id="2107021941795971877">পà§à¦°à¦¿à¦¨à§à¦Ÿ সংকà§à¦°à¦¾à¦¨à§à¦¤ সহায়তা</translation>
<translation id="2108755909498034140">আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦° পà§à¦¨à¦°à¦¾à¦¯à¦¼ চালৠকরà§à¦¨</translation>
+<translation id="2111166930115883695">গেম খেলতে, সà§à¦ªà§‡à¦¸à¦¬à¦¾à¦° পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">কারà§à¦¡</translation>
<translation id="2114841414352855701">à¦à§œà¦¿à§Ÿà§‡ যাওয়া হয়েছে কারণ à¦à¦Ÿà¦¿ <ph name="POLICY_NAME" />-দà§à¦¬à¦¾à¦°à¦¾ ওভাররাইড করা হয়েছিল৷</translation>
@@ -308,6 +318,7 @@
<translation id="214556005048008348">পেমেনà§à¦Ÿ বাতিল করà§à¦¨</translation>
<translation id="2147827593068025794">পটভূমি সিঙà§à¦•</translation>
<translation id="2148613324460538318">কারà§à¦¡ যোগ করà§à¦¨</translation>
+<translation id="2149968176347646218">কানেকশন সà§à¦°à¦•à§à¦·à¦¿à¦¤ নয়</translation>
<translation id="2154054054215849342">আপনার ডোমেনের জনà§à¦¯ সিঙà§à¦• উপলভà§à¦¯ নেই</translation>
<translation id="2154484045852737596">কারà§à¦¡ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="2161656808144014275">পাঠà§à¦¯</translation>
@@ -318,7 +329,6 @@
<translation id="2181821976797666341">নীতিসমূহ</translation>
<translation id="2183608646556468874">ফোন নমà§à¦¬à¦°</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{১টি ঠিকানা}one{ #টি ঠিকানা}other{ #টি ঠিকানা}}</translation>
-<translation id="2187243482123994665">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° উপসà§à¦¥à¦¿à¦¤à¦¿</translation>
<translation id="2187317261103489799">শনাকà§à¦¤ করà§à¦¨ (ডিফলà§à¦Ÿ)</translation>
<translation id="2188375229972301266">নিচে মালà§à¦Ÿà¦¿à¦ªà¦² পাঞà§à¦š</translation>
<translation id="2202020181578195191">মেয়াদ শেষ হওয়ার বছরের সঠিক মান লিখà§à¦¨</translation>
@@ -471,6 +481,7 @@
<translation id="2839501879576190149">আপনি যে সাইটটি ভিজিট করতে চলেছেন সেটি ভà§à§Ÿà§‹</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ হয়ত <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> থেকে আপনার তথà§à¦¯ (যেমন পাসওয়ারà§à¦¡, মেসেজ বা কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) চà§à¦°à¦¿ করার চেষà§à¦Ÿà¦¾ করছে। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানà§à¦¨<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">à¦à¦‡ সাইট বà§à¦¯à¦¾à¦˜à¦¾à¦¤ সৃষà§à¦Ÿà¦¿à¦•à¦¾à¦°à§€ বা বিভà§à¦°à¦¾à¦¨à§à¦¤à¦¿à¦•à¦° বিজà§à¦žà¦¾à¦ªà¦¨ দেখায়।</translation>
<translation id="2878197950673342043">পোসà§à¦Ÿà¦¾à¦° ফোলà§à¦¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">উইনà§à¦¡à§‹ পà§à¦²à§‡à¦¸à¦®à§‡à¦¨à§à¦Ÿ</translation>
@@ -509,11 +520,11 @@
<translation id="2996674880327704673">Google-à¦à¦° সাজেশন</translation>
<translation id="3002501248619246229">ইনপà§à¦Ÿ টà§à¦°à§‡ মিডিয়া চেক করà§à¦¨</translation>
<translation id="3005723025932146533">সেভ করা কপি দেখà§à¦¨</translation>
-<translation id="3007719053326478567">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° à¦à¦‡ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ পà§à¦°à¦¿à¦¨à§à¦Ÿ করা বনà§à¦§ রেখেছেন</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />-à¦à¦° CVC লিখà§à¦¨à¥¤ আপনি নিশà§à¦šà¦¿à¦¤ করলে, আপনার কারà§à¦¡à§‡à¦° বিবরণ à¦à¦‡ সাইটের সাথে শেয়ার করা হবে।</translation>
<translation id="3010559122411665027">তালিকার à¦à¦¨à§à¦Ÿà§à¦°à¦¿ " <ph name="ENTRY_INDEX" /> ": <ph name="ERROR" /></translation>
<translation id="301521992641321250">সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿà¦­à¦¾à¦¬à§‡ বà§à¦²à¦• করা হয়েছে</translation>
<translation id="3016780570757425217">আপনার লোকেশন জানà§à¦¨</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, সাজেশনটি সরাতে Tab পà§à¦°à§‡à¦¸ করার পর Enter পà§à¦°à§‡à¦¸ করà§à¦¨à¥¤</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">নীতির ভà§à¦² পà§à¦°à¦•à¦¾à¦°</translation>
<translation id="3037605927509011580">ইস!</translation>
@@ -556,6 +567,7 @@
<translation id="3207960819495026254">বà§à¦•à¦®à¦¾à¦°à§à¦• করা হয়েছে</translation>
<translation id="3209034400446768650">পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° মাধà§à¦¯à¦®à§‡ টাকা চারà§à¦œ করা হতে পারে</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />-ঠআপনার অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ মনিটর করা হচà§à¦›à§‡</translation>
+<translation id="3212623355668894776">সব গেসà§à¦Ÿ উইনà§à¦¡à§‹ বনà§à¦§ করে দিন যাতে à¦à¦‡ ডিভাইস থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ মà§à¦›à§‡ যায়।</translation>
<translation id="3215092763954878852">WebAuthn বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যায়নি</translation>
<translation id="3218181027817787318">রিলেটিভ</translation>
<translation id="3225919329040284222">সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ à¦à¦®à¦¨ à¦à¦•à¦Ÿà¦¿ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ করেছে যা বিলà§à¦Ÿ-ইন পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿à¦° সাথে মেলে না৷ à¦à¦‡ পà§à¦°à¦¤à§à¦¯à¦¾à¦¶à¦¾à¦—à§à¦²à¦¿ আপনাকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ করতে কিছৠনিশà§à¦šà¦¿à¦¤, উচà§à¦š সà§à¦°à¦•à§à¦·à¦¾à¦° ওয়েবসাইটের জনà§à¦¯ অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤à§·</translation>
@@ -703,6 +715,7 @@
<translation id="3784372983762739446">বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইস</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> ঠমেয়াদ শেষ হবে</translation>
<translation id="3789155188480882154">সাইজ ১৬</translation>
+<translation id="3789841737615482174">ইনসà§à¦Ÿà¦² করà§à¦¨</translation>
<translation id="3793574014653384240">সমà§à¦ªà§à¦°à¦¤à¦¿ হওয়া কà§à¦°à§à¦¯à¦¾à¦¶à§‡à¦° সংখà§à¦¯à¦¾ à¦à¦¬à¦‚ কারণ</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">ফনà§à¦Ÿà§‡à¦° অনà§à¦°à§‹à¦§ করা হয়েছে</translation>
@@ -754,6 +767,7 @@
<translation id="4056223980640387499">সেপিয়া</translation>
<translation id="4058922952496707368">কী "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">সà§à¦•à§à¦°à¦¿à¦¨ কà§à¦¯à¦¾à¦ªà¦šà¦¾à¦°à§‡à¦° সà§à¦¬à¦¿à¦§à¦¾ আবার চালৠকরা হয়েছে।</translation>
<translation id="4067947977115446013">সঠিক ঠিকানা যোগ করà§à¦¨</translation>
<translation id="4072486802667267160">আপনার অরà§à¦¡à¦¾à¦° পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ করার সময় à¦à¦•à¦Ÿà¦¿ সমসà§à¦¯à¦¾ হয়েছে। অনà§à¦—à§à¦°à¦¹ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à¥¤</translation>
<translation id="4075732493274867456">কà§à¦²à¦¾à§Ÿà§‡à¦¨à§à¦Ÿ ও সারà§à¦­à¦¾à¦°à¦Ÿà¦¿ কোনো অভিনà§à¦¨ SSL পà§à¦°à§‹à¦Ÿà§‹à¦•à¦² সংসà§à¦•à¦°à¦£ বা সাইফার সà§à¦¯à§à¦Ÿ সমরà§à¦¥à¦¨ করে না।</translation>
@@ -838,6 +852,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> পৃষà§à¦ à¦¾à¦° থামà§à¦¬à¦¨à§‡à¦²</translation>
<translation id="42981349822642051">পà§à¦°à¦¸à¦¾à¦°à¦¿à¦¤ করà§à¦¨</translation>
<translation id="4300675098767811073">ডানদিকে মালà§à¦Ÿà¦¿à¦ªà¦² পাঞà§à¦š</translation>
+<translation id="4302514097724775343">ডাইনোসর গেম খেলতে, টà§à¦¯à¦¾à¦ª করà§à¦¨</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">আপনার ফাইল অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করা যায়নি</translation>
<translation id="4305817255990598646">পালà§à¦Ÿà¦¾à¦¨</translation>
@@ -916,9 +931,10 @@
<translation id="4658638640878098064">উপরে বাà¦à¦¦à¦¿à¦•à§‡ সà§à¦Ÿà§‡à¦ªà¦² করà§à¦¨</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ভারà§à¦šà§à¦¯à¦¼à¦¾à¦² রিয়ালিটি</translation>
+<translation id="4675657451653251260">গেসà§à¦Ÿ মোডে আপনি কোনও Chrome পà§à¦°à§‹à¦«à¦¾à¦‡à¦²à§‡à¦° তথà§à¦¯ দেখতে পাবেন না। আপনি পাসওয়ারà§à¦¡ à¦à¦¬à¦‚ পেমেনà§à¦Ÿ পদà§à¦§à¦¤à¦¿à¦° মতো নিজের Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° তথà§à¦¯ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার জনà§à¦¯ <ph name="LINK_BEGIN" />সাইন-ইন<ph name="LINK_END" /> করতে পারেন।</translation>
<translation id="467662567472608290">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿà§‡ কিছৠতà§à¦°à§à¦Ÿà¦¿ আছে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="4677585247300749148"><ph name="URL" /> অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸à¦¯à§‹à¦—à§à¦¯à¦¤à¦¾ ইভেনà§à¦Ÿà§‡ পà§à¦°à¦¤à¦¿à¦•à§à¦°à¦¿à§Ÿà¦¾ দিয়ে চায়</translation>
-<translation id="467809019005607715">Google সà§à¦²à¦¾à¦‡à¦¡à§à¦¸</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">আপনি à¦à¦‡à¦®à¦¾à¦¤à§à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦®à§‚লক সাইটে আপনার পাসওয়ারà§à¦¡ লিখেছেন। <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> à¦à¦¬à¦‚ অনà§à¦¯à¦¾à¦¨à§à¦¯ সাইটে, যেখানে যেখানে আপনি à¦à¦‡ পাসওয়ারà§à¦¡à¦Ÿà¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন, Chromium আপনাকে সেইসব জায়গায় গিয়ে আপনার সেভ করা পাসওয়ারà§à¦¡à¦—à§à¦²à¦¿ পরিবরà§à¦¤à¦¨ করতে সাজেসà§à¦Ÿ করছে।</translation>
<translation id="4690462567478992370">কোনও ভà§à¦² সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করা বনà§à¦§ করà§à¦¨</translation>
<translation id="4691835149146451662">Architecture-A (Envelope)</translation>
@@ -943,6 +959,12 @@
<translation id="4761104368405085019">আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="4764776831041365478"><ph name="URL" />-ঠওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ অসà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ ডাউন থাকতে পারে অথবা à¦à¦Ÿà¦¿ সà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ কোনো নতà§à¦¨ ওয়েব অà§à¦¯à¦¾à¦¡à§à¦°à§‡à¦¸à§‡ সরানো হয়ে থাকতে পারে৷</translation>
<translation id="4766713847338118463">নিচে ডà§à§Ÿà¦¾à¦² সà§à¦Ÿà§‡à¦ªà¦²</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ আপনার যেসব অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ à¦à¦‡ ডিভাইসেই সেভ করা হয়:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¦à¦‡ উইনà§à¦¡à§‹à¦¤à§‡ আপনি যেসব ফাইল ডাউনলোড করেন
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">à¦à¦•à¦Ÿà¦¿ অজানা তà§à¦°à§à¦Ÿà¦¿ ঘটেছে৷</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{পপ-আপ বà§à¦²à¦• করা হয়েছে}one{#টি পপ-আপ বà§à¦²à¦• করা হয়েছে}other{#টি পপ-আপ বà§à¦²à¦• করা হয়েছে}}</translation>
<translation id="4780366598804516005">মেলবকà§à¦¸ ১</translation>
@@ -1105,11 +1127,13 @@
<translation id="5386426401304769735">à¦à¦‡ সাইটের সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ শৃঙà§à¦–লে SHA-1 বà§à¦¯à¦¬à¦¹à¦¾à¦° করে সà§à¦¬à¦¾à¦•à§à¦·à¦° করা à¦à¦•à¦Ÿà¦¿ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ রয়েছে।</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">ডানদিকে ধারের দিকে সেলাই</translation>
+<translation id="5398772614898833570">বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• করা হয়েছে</translation>
<translation id="5400836586163650660">ধূসর</translation>
<translation id="540969355065856584">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ à¦à¦‡ সময়ে বৈধ নয়। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="541416427766103491">সà§à¦Ÿà§à¦¯à¦¾à¦•à¦¾à¦° ৪</translation>
<translation id="5421136146218899937">বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ডেটা সাফ করà§à¦¨...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> আপনাকে বিজà§à¦žà¦ªà§à¦¤à¦¿ পাঠাতে চায়</translation>
+<translation id="542872847390508405">আপনি অতিথি হিসাবে বà§à¦°à¦¾à¦‰à¦œ করছেন</translation>
<translation id="5430298929874300616">বà§à¦•à¦®à¦¾à¦°à§à¦• সরান</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" ঠসà§à¦•à¦¿à¦®à¦¾ বৈধতার তà§à¦°à§à¦Ÿà¦¿ হয়েছে: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">রিভারà§à¦¸ অরà§à¦¡à¦¾à¦°, সামনের দিক উপরে</translation>
@@ -1151,12 +1175,12 @@
<translation id="5571083550517324815">à¦à¦‡ ঠিকানা থেকে পিক-আপ করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
<translation id="5580958916614886209">আপনার মেয়াদ শেষের মাস পরীকà§à¦·à¦¾ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="5586446728396275693">কোনও ঠিকানা সংরকà§à¦·à¦£ করা নেই</translation>
+<translation id="5593349413089863479">কানেকশন সমà§à¦ªà§‚রà§à¦£ সà§à¦°à¦•à§à¦·à¦¿à¦¤ নয়</translation>
<translation id="5595485650161345191">ঠিকানা সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="5598944008576757369">পেমেনà§à¦Ÿà§‡à¦° পদà§à¦§à¦¤à¦¿ বেছে নিন</translation>
<translation id="560412284261940334">পরিচালনা সমরà§à¦¥à¦¿à¦¤ নয়</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">à¦à¦‡ সাইটটি জাল বা পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦®à§‚লক হতে পারে। Chrome à¦à¦–নই আপনাকে সাইটটি ছেড়ে বেরিয়ে আসতে সাজেসà§à¦Ÿ করছে।</translation>
<translation id="5610142619324316209">সংযোগ পরীকà§à¦·à¦¾ করে দেখà§à¦¨</translation>
<translation id="5610807607761827392">আপনি <ph name="BEGIN_LINK" />সেটিংস<ph name="END_LINK" /> থেকে কারà§à¦¡ à¦à¦¬à¦‚ ঠিকানাগà§à¦²à¦¿ পরিচালনা করতে পারেন।</translation>
<translation id="561165882404867731">Google Translate বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦‡ পৃষà§à¦ à¦¾ অনà§à¦¬à¦¾à¦¦ করà§à¦¨</translation>
@@ -1228,6 +1252,7 @@
<translation id="5901630391730855834">হলà§à¦¦</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> সারà§à¦­à¦¾à¦°à§‡à¦° 'অরিজিন নীতি' অনà§à¦¯à¦¾à§Ÿà§€ বà§à¦²à¦• করা হয়েছে।</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (সিঙà§à¦• হয়েছে)</translation>
+<translation id="5913377024445952699">সà§à¦•à§à¦°à¦¿à¦¨ কà§à¦¯à¦¾à¦ªà¦šà¦¾à¦° পজ করা হয়েছে</translation>
<translation id="59174027418879706">সকà§à¦·à¦®à¦¿à¦¤</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">চালৠকরা আছে</translation>
@@ -1240,6 +1265,7 @@
<translation id="5963413905009737549">বিভাগ</translation>
<translation id="5967592137238574583">পরিচিতির তথà§à¦¯ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ করà§à¦¨</translation>
<translation id="5967867314010545767">ইতিহাস থেকে সরান</translation>
+<translation id="5968793460449681917">পà§à¦°à¦¤à¦¿ ভিজিটে পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="5975083100439434680">ছোট করà§à¦¨</translation>
<translation id="5979084224081478209">পাসওয়ারà§à¦¡ চেক করà§à¦¨</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">আপনার কপি করা লিঙà§à¦•</translation>
<translation id="6591833882275308647">আপনার <ph name="DEVICE_TYPE" /> মà§à¦¯à¦¾à¦¨à§‡à¦œ করা হয়নি</translation>
<translation id="6596325263575161958">à¦à¦¨à¦•à§à¦°à¦¿à¦ªà¦¶à¦¨ বিকলà§à¦ªà¦—à§à¦²à¦¿</translation>
+<translation id="6596892391065203054">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° à¦à¦‡ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ পà§à¦°à¦¿à¦¨à§à¦Ÿ করা বনà§à¦§ রেখেছে।</translation>
<translation id="6604181099783169992">মোশন বা হালà§à¦•à¦¾ সেনà§à¦¸à¦°</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">আপনার কারà§à¦¡à¦Ÿà¦¿ নিশà§à¦šà¦¿à¦¤ করা হয়েছে</translation>
<translation id="6897140037006041989">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ à¦à¦œà§‡à¦¨à§à¦Ÿ</translation>
<translation id="6898699227549475383">সংসà§à¦¥à¦¾ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />-কে অনà§à¦®à¦¤à¦¿ দিন:</translation>
<translation id="6910240653697687763">আপনার MIDI ডিভাইসে <ph name="URL" /> পূরà§à¦£ নিয়নà§à¦¤à§à¦°à¦£ পেতে চায়</translation>
<translation id="6915804003454593391">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€:</translation>
<translation id="6934672428414710184">à¦à¦‡ নাম আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ থেকে নেওয়া</translation>
@@ -1472,7 +1500,7 @@
<translation id="6973656660372572881">সà§à¦¥à¦¿à¦° পà§à¦°à¦•à§à¦¸à¦¿ সারà§à¦­à¦¾à¦° à¦à¦¬à¦‚ .pac সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ URL-à¦à¦° উভয়ই নিরà§à¦¦à¦¿à¦·à§à¦Ÿ আছে৷</translation>
<translation id="6973932557599545801">আমি সাহাযà§à¦¯ করতে পারছি না, নিজের মতো করে à¦à¦—িয়ে যান।</translation>
<translation id="6975012522936652259">আপনি à¦à¦‡à¦®à¦¾à¦¤à§à¦° পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦®à§‚লক à¦à¦•à¦Ÿà¦¿ সাইটে আপনার পাসওয়ারà§à¦¡ লিখেছেন। <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> à¦à¦¬à¦‚ অনà§à¦¯à¦¾à¦¨à§à¦¯ সাইট যেখানে à¦à¦‡ পাসওয়ারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করেছেন সেখানে গিয়ে à¦à¦–নই পাসওয়ারà§à¦¡ পরিবরà§à¦¤à¦¨ করতে Chromium সাজেসà§à¦Ÿ করছে।</translation>
-<translation id="6979158407327259162">Google ডà§à¦°à¦¾à¦‡à¦­</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">মিউট (ডিফলà§à¦Ÿ)</translation>
<translation id="6979983982287291980">আপনার ডাউনলোড করা ফাইল Google Cloud-ঠবা থারà§à¦¡-পারà§à¦Ÿà¦¿à¦° কাছে বিশà§à¦²à§‡à¦·à¦£ করার জনà§à¦¯ পাঠানো হয়েছে। যেমন, কোনও সংবেদনশীল ডেটা বা মà§à¦¯à¦¾à¦²à¦“য়à§à¦¯à¦¾à¦° আছে কিনা জানার জনà§à¦¯ ফাইলগà§à¦²à¦¿ হয়ত সà§à¦•à§à¦¯à¦¾à¦¨ করা হতে পারে।</translation>
<translation id="6989763994942163495">উনà§à¦¨à¦¤ সেটিংস দেখান ...</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">অà§à¦¯à¦¾à¦«à¦¿à¦²à¦¿à§Ÿà§‡à¦Ÿ কিনা:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">কমà§à¦¯à¦¾à¦¨à§à¦¡ লাইন</translation>
+<translation id="7359588939039777303">বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• করা হয়েছে।</translation>
<translation id="7372973238305370288">ফলাফল খà§à¦à¦œà§à¦¨</translation>
<translation id="7374733840632556089">আপনার ডিভাইসে আপনি বা অনà§à¦¯ কেউ à¦à¦•à¦Ÿà¦¿ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ ইনসà§à¦Ÿà¦² করায় à¦à¦‡ সমসà§à¦¯à¦¾ দেখা দিচà§à¦›à§‡à¥¤ à¦à¦‡ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে নেটওয়ারà§à¦• ইনà§à¦Ÿà¦¾à¦°à¦¸à§‡à¦ªà§à¦Ÿ à¦à¦¬à¦‚ মনিটর করা হয়, তবে Chrome à¦à¦Ÿà¦¿à¦•à§‡ বিশà§à¦¬à¦¸à§à¦¤ বলে মনে করে না। কোনও সà§à¦•à§à¦²à§‡à¦° বা কোমà§à¦ªà¦¾à¦¨à¦¿ নেটওয়ারà§à¦•à§‡à¦° মতো কিছৠনেটওয়ারà§à¦• মনিটর করার পà§à¦°à§Ÿà§‡à¦¾à¦œà¦¨ হলেও, Chrome দেখে নেয় যে, আপনি যদি à¦à¦Ÿà¦¿ বনà§à¦§ করতে নাও পারেন, কী ঘটছে সেই সমà§à¦ªà¦°à§à¦•à§‡ যেন জানতে পারেন। ওয়েবে অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ আছে, à¦à¦®à¦¨ যেকোনও বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° বা অà§à¦¯à¦¾à¦ªà§‡à¦° উপর নজর রাখা হতে পারে।</translation>
<translation id="7375818412732305729">ফাইল অà§à¦¯à¦¾à¦Ÿà¦¾à¦š করা হয়েছে</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">অতà§à¦¯à¦§à¦¿à¦• অনà§à¦°à§‹à¦§</translation>
<translation id="7977538094055660992">আউটপà§à¦Ÿ ডিভাইস</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ দেখার জনà§à¦¯ ARCore ইনসà§à¦Ÿà¦² করà§à¦¨</translation>
<translation id="799149739215780103">বাà¦à¦§à¦¾à¦‡</translation>
<translation id="7995512525968007366">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করে উলà§à¦²à§‡à¦– করা নেই</translation>
<translation id="800218591365569300">মেমরি ফাà¦à¦•à¦¾ করতে অনà§à¦¯à¦¾à¦¨à§à¦¯ টà§à¦¯à¦¾à¦¬ বা পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® বনà§à¦§ করার চেষà§à¦Ÿà¦¾ করà§à¦¨à¥¤</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">কমানà§à¦¡ লাইন</translation>
<translation id="8508648098325802031">সারà§à¦š আইকন</translation>
<translation id="8522552481199248698">পাসওয়ারà§à¦¡ পরিবরà§à¦¤à¦¨ করে আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখতে Chrome সাহাযà§à¦¯ করতে পারবে।</translation>
+<translation id="8525306231823319788">পূরà§à¦£ সà§à¦•à§à¦°à§€à¦£</translation>
<translation id="8530813470445476232">Chrome সেটিংস থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস, কà§à¦•à¦¿, কà§à¦¯à¦¾à¦¶à§‡ ও আরও অনেক কিছৠমà§à¦›à§à¦¨</translation>
<translation id="8533619373899488139">বà§à¦²à¦• করা ইউআরà¦à¦²à§‡à¦° তালিকা à¦à¦¬à¦‚ আপনার সিসà§à¦Ÿà§‡à¦® অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦°à§‡à¦° পà§à¦°à§Ÿà§‹à¦— করা অনà§à¦¯à¦¾à¦¨à§à¦¯ নীতিগà§à¦²à¦¿ দেখার জনà§à¦¯ &lt;strong&gt;chrome://policy&lt;/strong&gt;-ঠযান।</translation>
<translation id="8541158209346794904">বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইস</translation>
<translation id="8542014550340843547">নিচে টà§à¦°à¦¿à¦ªà¦² সà§à¦Ÿà§‡à¦ªà¦²</translation>
<translation id="8543181531796978784">আপনি <ph name="BEGIN_ERROR_LINK" />à¦à¦•à¦Ÿà¦¿ শনাকà§à¦¤à¦•à¦°à¦£ সমসà§à¦¯à¦¾ রিপোরà§à¦Ÿ করতে পারেন<ph name="END_ERROR_LINK" /> অথবা, আপনি আপনার নিরাপতà§à¦¤à¦¾ à¦à§à¦à¦•à¦¿ বà§à¦à¦¤à§‡ পারলে, <ph name="BEGIN_LINK" />à¦à¦‡ অনিরাপদ সাইটটি ঘà§à¦°à§‡ দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="8557066899867184262">আপনার কারà§à¦¡à§‡à¦° পিছনে CVC ছবিটি আছে।</translation>
+<translation id="8558485628462305855">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ দেখার জনà§à¦¯ ARCore আপডেট করà§à¦¨</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ঠà¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করা যায়নি কারণ আপনার ডিভাইসের তারিখ à¦à¦¬à¦‚ সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়৷</translation>
<translation id="8564182942834072828">আলাদা ডকà§à¦®à§‡à¦¨à§à¦Ÿ/সংগà§à¦°à¦¹ না করা কপি</translation>
<translation id="8564985650692024650">Chromium-à¦à¦° নীতি অনà§à¦¯à¦¾à§Ÿà§€ আপনার <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> পাসওয়ারà§à¦¡ বদলে ফেলা উচিত যদি আপনি সেটি অনà§à¦¯ কোনও সাইটে বà§à¦¯à¦¬à¦¹à¦¾à¦° করে থাকেন।</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ যেসব অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ à¦à¦‡ ডিভাইসে সেভ করা হবে না:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¦à¦‡ উইনà§à¦¡à§‹à¦¤à§‡ আপনি যেসব পৃষà§à¦ à¦¾ দেখেন
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ à¦à¦¬à¦‚ সাইট ডেটা
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">কারà§à¦¡ আরও দà§à¦°à§à¦¤ কনফারà§à¦® করতে টাচ আইডি বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="858637041960032120">ফোননমà§à¦¬à¦° জà§à¦¡à¦¼à§à¦¨</translation>
<translation id="8589998999637048520">সেরা কোয়ালিটি</translation>
+<translation id="8600271352425265729">শà§à¦§à§à¦®à¦¾à¦¤à§à¦° à¦à¦‡ সময়ে</translation>
<translation id="860043288473659153">কারà§à¦¡à¦§à¦¾à¦°à¦•à§‡à¦° নাম</translation>
<translation id="8606726445206553943">আপনার MIDI ডিভাইসসমূহ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
+<translation id="8612761427948161954">হাই <ph name="USERNAME" />,
+ <ph name="BR" />
+ আপনি গেসà§à¦Ÿ হিসেবে বà§à¦°à¦¾à¦‰à¦œ করছেন</translation>
<translation id="861775596732816396">সাইজ ৪</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">পাসওয়ারà§à¦¡ মà§à¦¯à¦¾à¦š করছে না। সেভ করা সমসà§à¦¤ পাসওয়ারà§à¦¡ মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨à¥¤</translation>
<translation id="8625384913736129811">à¦à¦‡ ডিভাইসে à¦à¦‡ কারà§à¦¡à¦Ÿà¦¿ সেভ করà§à¦¨</translation>
+<translation id="8627040765059109009">সà§à¦•à§à¦°à¦¿à¦¨ কà§à¦¯à¦¾à¦ªà¦šà¦¾à¦° আবার চালৠকরা হয়েছে</translation>
<translation id="8657078576661269990">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° <ph name="ORIGIN_NAME" /> থেকে <ph name="VM_NAME_1" /> ও <ph name="VM_NAME_2" />-ঠশেয়ার করা বà§à¦²à¦• করে দিয়েছেন</translation>
<translation id="8663226718884576429">অরà§à¦¡à¦¾à¦°à§‡à¦° সারসংকà§à¦·à§‡à¦ª, <ph name="TOTAL_LABEL" />, আরও বিবরণ</translation>
<translation id="867224526087042813">সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ</translation>
<translation id="8913778647360618320">পেমেনà§à¦Ÿ পদà§à¦§à¦¤à¦¿ মà§à¦¯à¦¾à¦¨à§‡à¦œ করার বোতাম, Chrome সেটিংসে আপনার পেমেনà§à¦Ÿ ও কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡à§‡à¦° তথà§à¦¯ মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="8918231688545606538">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ সনà§à¦¦à§‡à¦¹à¦œà¦¨à¦• বলে মনে হচà§à¦›à§‡</translation>
+<translation id="8922013791253848639">à¦à¦‡ সাইটে সবসময় বিজà§à¦žà¦¾à¦ªà¦¨ দেখানোর অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="892588693504540538">উপরের ডানদিকে পাঞà§à¦š</translation>
<translation id="8931333241327730545">আপনি কি আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ à¦à¦‡ কারà§à¦¡ সেভ করতে চান?</translation>
<translation id="8932102934695377596">আপনার ঘড়ির সময় পিছিয়ে রয়েছে</translation>
@@ -2013,21 +2058,24 @@
<translation id="917450738466192189">সারà§à¦­à¦¾à¦°à§‡à¦° সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ অকারà§à¦¯à¦•à¦°à§·</translation>
<translation id="9174917557437862841">টà§à¦¯à¦¾à¦¬ সà§à¦‡à¦š বোতাম, à¦à¦‡ টà§à¦¯à¦¾à¦¬à§‡ পরিবরà§à¦¤à¦¨ করতে à¦à¦¨à§à¦Ÿà¦¾à¦° পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="9179703756951298733">Chrome সেটিংস থেকে আপনার পেমেনà§à¦Ÿ ও কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡à§‡à¦° তথà§à¦¯ মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
-<translation id="9183302530794969518">Google দসà§à¦¤à¦¾à¦¬à§‡à¦œ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> à¦à¦•à¦Ÿà¦¿ অসমরà§à¦¥à¦¿à¦¤ পà§à¦°à§‹à¦Ÿà§‹à¦•à¦² বà§à¦¯à¦¬à¦¹à¦¾à¦° করে।</translation>
<translation id="9191834167571392248">নিচে বাà¦à¦¦à¦¿à¦•à§‡ পাঞà§à¦š করà§à¦¨</translation>
+<translation id="9199905725844810519">পà§à¦°à¦¿à¦¨à§à¦Ÿà¦¿à¦‚ বà§à¦²à¦• করা আছে</translation>
<translation id="9205078245616868884">আপনার ডেটা আপনার সিঙà§à¦• পাসফà§à¦°à§‡à¦œ দিয়ে à¦à¦¨à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ করা হয়েছে। সিঙà§à¦• শà§à¦°à§ করার জনà§à¦¯ à¦à¦Ÿà¦¿ লিখà§à¦¨à¥¤</translation>
<translation id="9207861905230894330">নিবনà§à¦§ যোগ করতে বà§à¦¯à¦°à§à¦¥ হয়েছে৷</translation>
<translation id="9213433120051936369">কেমন দেখাবে তা কাসà§à¦Ÿà¦®à¦¾à¦‡à¦œ করà§à¦¨</translation>
<translation id="9215416866750762878">à¦à¦•à¦Ÿà¦¿ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¨ Chrome কে à¦à¦‡ সাইটের সাথে নিরাপদভাবে সংযà§à¦•à§à¦¤ হতে বাধা দিচà§à¦›à§‡</translation>
-<translation id="9219103736887031265">ছবিগà§à¦²à¦¿</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ফরà§à¦® সাফ করà§à¦¨</translation>
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">আপনি আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ হারাতে পারেন। Chromium-à¦à¦° পà§à¦°à¦¸à§à¦¤à¦¾à¦¬ হল যে আপনি আপনার পাসওয়ারà§à¦¡ à¦à¦–নই পরিবরà§à¦¤à¦¨ করà§à¦¨à¥¤ আপনাকে আবার সাইন-ইন করতে বলা হবে।</translation>
<translation id="939736085109172342">নতà§à¦¨ ফোলà§à¦¡à¦¾à¦°</translation>
+<translation id="945522503751344254">মতামত জানান</translation>
<translation id="945855313015696284">নিচে দেওয়া তথà§à¦¯ পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ কোনও ভà§à¦² কারà§à¦¡ থাকলে তা মà§à¦›à§‡ ফেলà§à¦¨</translation>
<translation id="950736567201356821">উপরে তিনটি পাঞà§à¦š</translation>
+<translation id="951941430552851965">আপনার সà§à¦•à§à¦°à¦¿à¦¨à§‡ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ থাকার জনà§à¦¯ অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° সà§à¦•à§à¦°à¦¿à¦¨ কà§à¦¯à¦¾à¦ªà¦šà¦¾à¦°à§‡à¦° সà§à¦¬à¦¿à¦§à¦¾ পজ করে দিয়েছেন।</translation>
<translation id="961663415146723894">নিচে বাà¦à¦§à¦¾à¦‡ করà§à¦¨</translation>
<translation id="962484866189421427">à¦à¦‡ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿà¦Ÿà¦¿ পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦®à§‚লক অà§à¦¯à¦¾à¦ª ইনসà§à¦Ÿà¦² করে দিতে পারে যেগà§à¦²à¦¿ অনà§à¦¯à¦¾à¦¨à§à¦¯ আপের থেকে আলাদা করা যায় না অথবা যেগà§à¦²à¦¿ à¦à¦®à¦¨ ডেটা সংগà§à¦°à¦¹ করে যা দিয়ে আপনার উপরে নজর রাখা যাবে। <ph name="BEGIN_LINK" />তবà§à¦“ à¦à¦Ÿà¦¿ দেখতে চাই<ph name="END_LINK" /></translation>
<translation id="969892804517981540">অফিসিয়াল বিলà§à¦¡</translation>
diff --git a/chromium/components/strings/components_strings_bs.xtb b/chromium/components/strings/components_strings_bs.xtb
index 00421b74f6b..06a18e197ea 100644
--- a/chromium/components/strings/components_strings_bs.xtb
+++ b/chromium/components/strings/components_strings_bs.xtb
@@ -80,6 +80,14 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Unijeli ste lozinku na web lokaciji kojom ne upravlja vaÅ¡a organizacija. Da zaÅ¡titite raÄun, lozinku nemojte ponovo koristiti na drugim aplikacijama i web lokacijama.</translation>
<translation id="1263231323834454256">Lista za Äitanje</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje neće ostati saÄuvane na ovom ureÄ‘aju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stranice koje pregledate u ovom prozoru
+ <ph name="LIST_ITEM" />kolaÄići i podaci o web lokaciji
+ <ph name="LIST_ITEM" />informacije o raÄunu (<ph name="LINK_BEGIN" />odjava<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">NaÄin preuzimanja</translation>
<translation id="1281476433249504884">SlagaÄ 1</translation>
<translation id="1285320974508926690">Nikada ne prevodi ovu web lokaciju</translation>
@@ -283,6 +291,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="204357726431741734">Prijavite se da koristite lozinke saÄuvane na Google raÄunu</translation>
<translation id="2053111141626950936">Stranice Äiji jezik je <ph name="LANGUAGE" />, neće se prevoditi.</translation>
<translation id="2053553514270667976">Poštanski broj</translation>
+<translation id="2054665754582400095">Vaša prisutnost</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{Jedan prijedlog}one{# prijedlog}few{# prijedloga}other{# prijedloga}}</translation>
<translation id="2079545284768500474">Vrati</translation>
<translation id="20817612488360358">Postavke sistema proksi servera su postavljene za korištenje, ali je određena i eksplicitna konfiguracija proksi servera.</translation>
@@ -296,6 +305,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2102495993840063010">Android aplikacije</translation>
<translation id="2107021941795971877">Podrška za štampanje</translation>
<translation id="2108755909498034140">Ponovo pokreni svoj raÄunar</translation>
+<translation id="2111166930115883695">Pritisnite tipku za razmak da igrate</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Zanemareno jer ga mijenja pravilo <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="214556005048008348">Otkaži plaćanje</translation>
<translation id="2147827593068025794">Sinkronizacija u pozadini</translation>
<translation id="2148613324460538318">Dodaj karticu</translation>
+<translation id="2149968176347646218">Veza nije sigurna</translation>
<translation id="2154054054215849342">Sinhronizacija nije dostupna za vašu domenu</translation>
<translation id="2154484045852737596">Uredi karticu</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -317,7 +328,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2181821976797666341">Pravila</translation>
<translation id="2183608646556468874">Broj telefona</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
-<translation id="2187243482123994665">Prisutnost korisnika</translation>
<translation id="2187317261103489799">Otkrij (zadano)</translation>
<translation id="2188375229972301266">Višestruko bušenje na donjoj strani</translation>
<translation id="2202020181578195191">Unesite važeću godinu isteka</translation>
@@ -470,6 +480,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2839501879576190149">Web lokacija koja slijedi je lažna</translation>
<translation id="2850739647070081192">Invite (koverta)</translation>
<translation id="2856444702002559011">Moguće je da napadaÄi pokuÅ¡avaju ukrasti vaÅ¡e podatke s web lokacije <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (naprimjer, lozinke, poruke ili kreditne kartice). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ova web lokacija prikazuje nametljive ili obmanjujuće oglase.</translation>
<translation id="2878197950673342043">Presavijanje postera</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Postavljanje prozora</translation>
@@ -508,11 +519,11 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2996674880327704673">Prijedlozi Googlea</translation>
<translation id="3002501248619246229">Provjerite medije na ulaznoj ladici</translation>
<translation id="3005723025932146533">Prikaži spremljenu kopiju</translation>
-<translation id="3007719053326478567">Vaš administrator je blokirao štampanje ovog sadržaja</translation>
<translation id="3008447029300691911">Unesite CVC kartice <ph name="CREDIT_CARD" />. Nakon potvrde podaci vaše kartice će se dijeliti s ovom web lokacijom.</translation>
<translation id="3010559122411665027">Unos na listi "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatski blokirano</translation>
<translation id="3016780570757425217">Poznavanje vaše lokacije</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pritisnite tipku Tab, a zatim Enter da uklonite prijedlog.</translation>
<translation id="3023071826883856138">You4 (omotnica)</translation>
<translation id="3024663005179499861">Pogrešna vrsta pravila</translation>
<translation id="3037605927509011580">Oh, ne!</translation>
@@ -555,6 +566,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3207960819495026254">OznaÄeno</translation>
<translation id="3209034400446768650">Stranica se možda naplaćuje</translation>
<translation id="3212581601480735796">Vaša aktivnost na <ph name="HOSTNAME" /> je pod nadzorom</translation>
+<translation id="3212623355668894776">Zatvorite sve prozore za goste da se vaša aktivnost pregledanja izbriše s ovog uređaja.</translation>
<translation id="3215092763954878852">Upotreba autentifikatora WebAuthn nije uspjela</translation>
<translation id="3218181027817787318">Relativno</translation>
<translation id="3225919329040284222">Poslužitelj je pokazao certifikat koji ne odgovara ugraÄ‘enim oÄekivanjima. Ta su oÄekivanja ukljuÄena za odreÄ‘ene web-lokacije s visokim stupnjem sigurnosti radi vaÅ¡e zaÅ¡tite.</translation>
@@ -702,6 +714,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3784372983762739446">Bluetooth uređaji</translation>
<translation id="3787705759683870569">IstiÄe: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">VeliÄina 16</translation>
+<translation id="3789841737615482174">Instaliraj</translation>
<translation id="3793574014653384240">Broj nedavnih padova aplikacija i uzroci</translation>
<translation id="3797522431967816232">Prc3 (Koverta)</translation>
<translation id="3799805948399000906">Font je zatražen</translation>
@@ -753,6 +766,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4056223980640387499">Sepija</translation>
<translation id="4058922952496707368">KljuÄ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (omotnica)</translation>
+<translation id="4067669230157909013">Snimanje ekrana je nastavljeno.</translation>
<translation id="4067947977115446013">Dodajte važeću adresu</translation>
<translation id="4072486802667267160">Došlo je do greške prilikom obrade vaše narudžbe. Pokušajte ponovo.</translation>
<translation id="4075732493274867456">Klijent i server ne podržavaju verziju zajedniÄkog SSL protokola ili paket za Å¡ifriranje.</translation>
@@ -837,6 +851,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4297502707443874121">SliÄica za stranicu <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Proširi</translation>
<translation id="4300675098767811073">Višestruko bušenje na desnoj strani</translation>
+<translation id="4302514097724775343">Dodirnite dinosaura da igrate</translation>
<translation id="4302965934281694568">Chou3 (koverta)</translation>
<translation id="4305666528087210886">Pristupanje vašem fajlu nije uspjelo</translation>
<translation id="4305817255990598646">Prebaci</translation>
@@ -915,6 +930,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4658638640878098064">Spajanje u gornjem lijevom uglu</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuelna realnost</translation>
+<translation id="4675657451653251260">U naÄinu rada za gosta nećete vidjeti informacije o Chrome profilu. Možete se <ph name="LINK_BEGIN" />prijaviti<ph name="LINK_END" /> da pristupite informacijama o Google raÄunu kao Å¡to su lozinke i naÄini plaćanja.</translation>
<translation id="467662567472608290">Ovaj server nije uspio dokazati da je <ph name="DOMAIN" />; njegova potvrda sigurnosti sadrži greÅ¡ke. Uzrok tome može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="4677585247300749148"><ph name="URL" /> želi odgovoriti na dogaÄ‘aje pristupaÄnosti</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4761104368405085019">Korištenje vašeg mikrofona</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje na donjoj strani</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje će ostati saÄuvane na ovom ureÄ‘aju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />svi fajlovi koje preuzmete u ovom prozoru
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Došlo je do nepoznate greške.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{SkoÄni prozor blokiran}one{# skoÄni prozor blokiran}few{# skoÄna prozora blokirana}other{# skoÄnih prozora blokirano}}</translation>
<translation id="4780366598804516005">PoÅ¡tansko sanduÄe 1</translation>
@@ -1104,11 +1126,13 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5386426401304769735">Lanac potvrda za ovu web lokaciju sadrži potvrdu koja je izdata koristeći SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Uvez desnog ruba</translation>
+<translation id="5398772614898833570">Oglasi su blokirani</translation>
<translation id="5400836586163650660">Siva</translation>
<translation id="540969355065856584">Ovaj server nije uspio dokazati da je <ph name="DOMAIN" />; njegova potvrda sigurnosti trenutno nije važeća. Uzrok tome može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="541416427766103491">SlagaÄ 4</translation>
<translation id="5421136146218899937">Obriši podatke pregledanja…</translation>
<translation id="5426179911063097041">Web lokacija <ph name="SITE" /> vam želi slati obavještenja</translation>
+<translation id="542872847390508405">Pregledavate kao gost</translation>
<translation id="5430298929874300616">Ukloni oznaku</translation>
<translation id="5439770059721715174">Greška potvrđivanja šeme na "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Obrnuti redoslijed s odštampanom stranom prema gore</translation>
@@ -1150,12 +1174,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5571083550517324815">Nije moguće preuzeti s ove adrese. Odaberite drugu adresu.</translation>
<translation id="5580958916614886209">Provjerite mjesec isteka i pokušajte ponovo.</translation>
<translation id="5586446728396275693">Nije pronađena nijedna adresa</translation>
+<translation id="5593349413089863479">Veza nije u potpunosti sigurna</translation>
<translation id="5595485650161345191">Uredite adresu</translation>
<translation id="5598944008576757369">Odaberite naÄin plaćanja</translation>
<translation id="560412284261940334">Upravljanje nije podržano</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Arhitektura-C</translation>
-<translation id="5608165884683734521">Moguće je da je ova web lokacija lažna ili obmanjujućeg sadržaja. Chrome preporuÄuje da je odmah napustite.</translation>
<translation id="5610142619324316209">Provjeriti vezu</translation>
<translation id="5610807607761827392">Karticama i adresama možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Prevedite ovu stranicu pomoću Google Prevodioca</translation>
@@ -1227,6 +1251,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5901630391730855834">Žuta</translation>
<translation id="5905445707201418379">Blokirano prema izvornim pravilima koja određuje izvor <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinhronizirano)</translation>
+<translation id="5913377024445952699">Snimanje ekrana je pauzirano</translation>
<translation id="59174027418879706">Omogućeno</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">UkljuÄeno</translation>
@@ -1239,6 +1264,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5963413905009737549">Odjeljak</translation>
<translation id="5967592137238574583">Uredite kontakt informacije</translation>
<translation id="5967867314010545767">Ukloni iz historije</translation>
+<translation id="5968793460449681917">Pri svakoj posjeti</translation>
<translation id="5975083100439434680">Smanji</translation>
<translation id="5979084224081478209">Provjeri lozinke</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6587923378399804057">Link koji ste kopirali</translation>
<translation id="6591833882275308647">Vašim uređajem <ph name="DEVICE_TYPE" /> se ne upravlja</translation>
<translation id="6596325263575161958">Opcije za Å¡ifriranje</translation>
+<translation id="6596892391065203054">Administrator je blokirao štampanje ovog sadržaja.</translation>
<translation id="6604181099783169992">Senzori za kretanje ili svjetlost</translation>
<translation id="6609880536175561541">Prc7 (koverta)</translation>
<translation id="6612358246767739896">Zaštićeni sadržaj</translation>
@@ -1453,6 +1480,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6895330447102777224">Vaša kartica je potvrđena</translation>
<translation id="6897140037006041989">KorisniÄki agent</translation>
<translation id="6898699227549475383">Organizacija (O)</translation>
+<translation id="6907293445143367439">Dozvolite web lokaciji <ph name="SITE_NAME" /> sljedeće:</translation>
<translation id="6910240653697687763">Web lokacija <ph name="URL" /> želi u potpunosti kontrolirati vaše MIDI uređaje</translation>
<translation id="6915804003454593391">Korisnik:</translation>
<translation id="6934672428414710184">Ovaj naziv je s vaÅ¡eg Google raÄuna</translation>
@@ -1564,6 +1592,7 @@ Dodatni detalji:
<translation id="7346048084945669753">Korisnik je povezan:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Komandna linija</translation>
+<translation id="7359588939039777303">Oglasi su blokirani.</translation>
<translation id="7372973238305370288">rezultat pretraživanja</translation>
<translation id="7374733840632556089">Ovaj problem nastaje zbog potvrde koju ste vi ili neko drugi instalirali na ureÄ‘aj. Poznato je da se ta potvrda koristi za nadzor i presretanje mreža te je Chrome ne smatra pouzdanom. Iako postoje opravdani sluÄajevi za nadzor, naprimjer na mrežama u Å¡kolama ili preduzećima, Chrome želi potvrditi da ste toga svjesni Äak i ako taj proces ne možete zaustaviti. Nadzor se može vrÅ¡iti u bilo kojem pregledniku ili bilo kojoj aplikaciji koja pristupa webu.</translation>
<translation id="7375818412732305729">Fajl je priložen</translation>
@@ -1738,6 +1767,7 @@ Dodatni detalji:
<translation id="7976214039405368314">Previše zahtjeva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Instalirajte ARCore da vidite sadržaj proširene realnosti</translation>
<translation id="799149739215780103">Povezivanje</translation>
<translation id="7995512525968007366">Nije navedeno</translation>
<translation id="800218591365569300">Pokušajte zatvoriti druge kartice ili programe da oslobodite memoriju.</translation>
@@ -1865,24 +1895,38 @@ Dodatni detalji:
<translation id="8507227106804027148">Komandna linija</translation>
<translation id="8508648098325802031">Ikona pretraživanja</translation>
<translation id="8522552481199248698">Chrome vam može pomoći da zaÅ¡titite svoj Google raÄun i promijenite lozinku.</translation>
+<translation id="8525306231823319788">Cijeli ekran</translation>
<translation id="8530813470445476232">IzbriÅ¡ite historiju pregledanja, kolaÄiće, keÅ¡ memoriju i drugo u postavkama Chromea</translation>
<translation id="8533619373899488139">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da vidite listu blokiranih URL-ova i druga pravila koja je nametnuo vaš administrator sistema.</translation>
<translation id="8541158209346794904">Bluetooth uređaj</translation>
<translation id="8542014550340843547">Trostruko spajanje na donjoj strani</translation>
<translation id="8543181531796978784">Možete <ph name="BEGIN_ERROR_LINK" />prijaviti problem s otkrivanjem<ph name="END_ERROR_LINK" /> ili, ako razumijete rizik po svoju sigurnost, <ph name="BEGIN_LINK" />posjetiti nesigurnu stranicu<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC se nalazi na poleđini vaše kartice.</translation>
+<translation id="8558485628462305855">Za prikaz sadržaja proširene realnosti ažurirajte ARCore</translation>
<translation id="8559762987265718583">Nije moguće uspostaviti privatnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vrijeme (<ph name="DATE_AND_TIME" />) na vaÅ¡em ureÄ‘aju nisu taÄni.</translation>
<translation id="8564182942834072828">Zasebni dokumenti/nerazvrstane kopije</translation>
<translation id="8564985650692024650">Chromium preporuÄuje da poniÅ¡tite lozinku za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je ponovo koristili na drugim web lokacijama.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje neće ostati saÄuvane na ovom ureÄ‘aju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stranice koje pregledate u ovom prozoru
+ <ph name="LIST_ITEM" />kolaÄići i podaci o web lokacijama
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Koristite Touch ID da brže potvrdite kartice</translation>
<translation id="858637041960032120">Dodajte broj telefona</translation>
<translation id="8589998999637048520">Najbolji kvalitet</translation>
+<translation id="8600271352425265729">Samo ovaj put</translation>
<translation id="860043288473659153">Ime vlasnika kartice</translation>
<translation id="8606726445206553943">Koristite MIDI uređaje</translation>
+<translation id="8612761427948161954">Zdravo <ph name="USERNAME" />,
+ <ph name="BR" />
+ Pregledate kao gost</translation>
<translation id="861775596732816396">VeliÄina 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nema lozinki koje se podudaraju. Prikaži sve saÄuvane lozinke.</translation>
<translation id="8625384913736129811">SaÄuvaj ovu karticu na ovaj ureÄ‘aj</translation>
+<translation id="8627040765059109009">Snimanje ekrana je nastavljeno</translation>
<translation id="8657078576661269990">Administrator je blokirao dijeljenje s web lokacije <ph name="ORIGIN_NAME" /> na: <ph name="VM_NAME_1" /> i <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Sažetak narudžbe, <ph name="TOTAL_LABEL" />, više detalja</translation>
<translation id="867224526087042813">Potpis</translation>
@@ -1945,6 +1989,7 @@ Dodatni detalji:
<translation id="8912362522468806198">Google raÄun</translation>
<translation id="8913778647360618320">Dugme Upravljaj naÄinima plaćanja, pritisnite Enter da upravljate plaćanjima i informacijama o kreditnim karticama u postavkama Chromea</translation>
<translation id="8918231688545606538">Ova stranica je sumnjiva</translation>
+<translation id="8922013791253848639">Uvijek omogući oglase na ovoj web lokaciji</translation>
<translation id="892588693504540538">Bušenje u gornjem desnom uglu</translation>
<translation id="8931333241327730545">Želite li saÄuvati ovu karticu na svoj Google raÄun?</translation>
<translation id="8932102934695377596">Vaš sat kasni</translation>
@@ -2016,6 +2061,7 @@ Dodatni detalji:
<translation id="9183302530794969518">Google Dokumenti</translation>
<translation id="9183425211371246419">Host raÄunar <ph name="HOST_NAME" /> koristi protokol koji nije podržan.</translation>
<translation id="9191834167571392248">Bušenje u donjem lijevom uglu</translation>
+<translation id="9199905725844810519">Å tampanje je blokirano</translation>
<translation id="9205078245616868884">VaÅ¡i podaci su Å¡ifrirani pristupnim izrazom za sinhronizaciju. Unesite ga da poÄnete sinhronizaciju.</translation>
<translation id="9207861905230894330">Dodavanje Älanka nije uspjelo.</translation>
<translation id="9213433120051936369">Prilagodite izgled</translation>
@@ -2026,8 +2072,10 @@ Dodatni detalji:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Možete izgubiti pristup svom Google raÄunu. Chromium preporuÄuje da odmah promijenite lozinku. Od vas će se tražiti da se prijavite.</translation>
<translation id="939736085109172342">Novi folder</translation>
+<translation id="945522503751344254">Pošaljite povratne informacije</translation>
<translation id="945855313015696284">Provjerite informacije u nastavku i izbrišite nevažeće kartice</translation>
<translation id="950736567201356821">Trostruko bušenje na gornjoj strani</translation>
+<translation id="951941430552851965">Administrator je pauzirao snimanje ekrana zbog sadržaja na vašem ekranu.</translation>
<translation id="961663415146723894">Povezivanje donje strane</translation>
<translation id="962484866189421427">Sadržaj može pokušati instalirati obmanjujuće aplikacije koje se pretvaraju da predstavljaju nešto drugo ili koje prikupljaju podatke koji se mogu iskoristiti za vaše praćenje. <ph name="BEGIN_LINK" />Ipak prikaži<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ZvaniÄna verzija</translation>
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index b728603d32c..ab4dd7de470 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -80,6 +80,14 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Has introduït la contrasenya en un lloc web que no està gestionat per la teva organització. Per protegir el teu compte, no facis servir la mateixa contrasenya en altres aplicacions ni llocs web.</translation>
<translation id="1263231323834454256">Llista de lectura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Activitat que no es desarà en aquest dispositiu:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pàgines que consultis en aquesta finestra
+ <ph name="LIST_ITEM" />Galetes i dades de llocs web
+ <ph name="LIST_ITEM" />Informació del compte (<ph name="LINK_BEGIN" />tanca la sessió<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Mètode de recollida</translation>
<translation id="1281476433249504884">Apiladora 1</translation>
<translation id="1285320974508926690">No tradueixis mai aquest lloc</translation>
@@ -241,7 +249,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1838374766361614909">Esborra la cerca</translation>
<translation id="1839551713262164453">S'han produït errors a la validació dels valors de la política</translation>
<translation id="1842969606798536927">Paga</translation>
-<translation id="1871208020102129563">El servidor intermediari està configurat perquè utilitzi servidors intermediaris fixos, en lloc d'un URL d'script .pac.</translation>
+<translation id="1871208020102129563">El servidor intermediari està configurat perquè utilitzi servidors intermediaris fixos, en lloc d'un URL de script .pac.</translation>
<translation id="1871284979644508959">Camp obligatori</translation>
<translation id="1875512691959384712">Formularis de Google</translation>
<translation id="187918866476621466">Obre les pàgines d'inici</translation>
@@ -279,6 +287,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="204357726431741734">Inicia la sessió per utilitzar les contrasenyes desades al teu Compte de Google</translation>
<translation id="2053111141626950936">Les pàgines en <ph name="LANGUAGE" /> no es traduiran.</translation>
<translation id="2053553514270667976">Codi postal</translation>
+<translation id="2054665754582400095">La teva presència</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggeriment}other{# suggeriments}}</translation>
<translation id="2079545284768500474">Desfés</translation>
<translation id="20817612488360358">S'ha definit la configuració del servidor intermediari del sistema perquè es pugui utilitzar, però també s'ha especificat una configuració del servidor intermediari explícita.</translation>
@@ -292,6 +301,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2102495993840063010">Aplicacions per a Android</translation>
<translation id="2107021941795971877">Suports d'impressió</translation>
<translation id="2108755909498034140">Reinicia l'ordinador</translation>
+<translation id="2111166930115883695">Prem la barra espaiadora per jugar</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Targeta</translation>
<translation id="2114841414352855701">S'ha ignorat perquè <ph name="POLICY_NAME" /> l'ha substituït.</translation>
@@ -303,6 +313,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="214556005048008348">Cancel·la el pagament</translation>
<translation id="2147827593068025794">Sincronització en segon pla</translation>
<translation id="2148613324460538318">Afegeix una targeta</translation>
+<translation id="2149968176347646218">La connexió no és segura</translation>
<translation id="2154054054215849342">La sincronització no està disponible per al teu domini</translation>
<translation id="2154484045852737596">Edita la targeta</translation>
<translation id="2161656808144014275">Text</translation>
@@ -313,7 +324,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2181821976797666341">Polítiques</translation>
<translation id="2183608646556468874">Número de telèfon</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adreça}other{# adreces}}</translation>
-<translation id="2187243482123994665">Presència de l'usuari</translation>
<translation id="2187317261103489799">Detecta (opció predeterminada)</translation>
<translation id="2188375229972301266">Encunyació múltiple a la part inferior</translation>
<translation id="2202020181578195191">Introdueix un any de caducitat vàlid</translation>
@@ -464,6 +474,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2839501879576190149">Aquest lloc web és fals</translation>
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">Pot ser que els atacants provin de robar la teva informació del lloc web <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (per exemple, contrasenyes, missatges o targetes de crèdit). <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Aquest lloc web mostra anuncis intrusius o enganyosos.</translation>
<translation id="2878197950673342043">Plegat en pòster</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Col·locació de finestres</translation>
@@ -502,11 +513,11 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2996674880327704673">Suggeriments de Google</translation>
<translation id="3002501248619246229">Comprova el suport de la safata d'entrada</translation>
<translation id="3005723025932146533">Mostra la còpia desada</translation>
-<translation id="3007719053326478567">El teu administrador ha bloquejat la impressió d'aquest contingut</translation>
<translation id="3008447029300691911">Introdueix el CVC de la targeta <ph name="CREDIT_CARD" />. Un cop confirmada, els detalls de la targeta es compartiran amb aquest lloc.</translation>
<translation id="3010559122411665027">Entrada de llista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloquejada automàticament</translation>
<translation id="3016780570757425217">Saber la vostra ubicació</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, prem la tecla de tabulació i després la d'introducció per suprimir el suggeriment.</translation>
<translation id="3023071826883856138">You4 (sobre)</translation>
<translation id="3024663005179499861">Tipus de política incorrecte</translation>
<translation id="3037605927509011580">Vaja!</translation>
@@ -549,6 +560,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3207960819495026254">S'ha afegit a les adreces d'interès.</translation>
<translation id="3209034400446768650">És possible que la pàgina faci un càrrec de diners</translation>
<translation id="3212581601480735796">La teva activitat a <ph name="HOSTNAME" /> s'està supervisant</translation>
+<translation id="3212623355668894776">Tanca totes les finestres de convidat perquè la teva activitat de navegació se suprimeixi d'aquest dispositiu.</translation>
<translation id="3215092763954878852">No s'ha pogut utilitzar WebAuthn</translation>
<translation id="3218181027817787318">Relatiu</translation>
<translation id="3225919329040284222">El servidor ha presentat un certificat que no coincideix amb les expectatives integrades. Les expectatives s'inclouen perquè determinats llocs web d'alta seguretat us protegeixin.</translation>
@@ -590,7 +602,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3395827396354264108">Mètode de recollida</translation>
<translation id="3399952811970034796">Adreça d'entrega</translation>
<translation id="3402261774528610252">La connexió utilitzada per carregar aquest lloc web ha fet servir TLS 1.0 o 1.1, estàndards que estan obsolets i es desactivaran en el futur. Un cop desactivats, els usuaris no podran carregar aquest lloc web. El servidor ha d'activar TLS 1.2 o una versió posterior.</translation>
-<translation id="3411120537985775570">El teu administrador ha bloquejat la possibilitat d'enganxar contingut de <ph name="ORIGIN_NAME" /> en aquesta ubicació</translation>
+<translation id="3411120537985775570">El teu administrador ha bloquejat l'opció d'enganxar contingut de <ph name="ORIGIN_NAME" /> en aquesta ubicació</translation>
<translation id="3414952576877147120">Mida:</translation>
<translation id="3417660076059365994">Els fitxers que penges o adjuntes s'envien a Google Cloud o a tercers perquè s'analitzin. Per exemple, pot ser que s'analitzin per detectar-hi dades sensibles o programari maliciós.</translation>
<translation id="3422248202833853650">Prova de sortir d'altres programes per alliberar memòria.</translation>
@@ -696,6 +708,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3784372983762739446">Dispositius Bluetooth</translation>
<translation id="3787705759683870569">Data de caducitat: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Mida 16</translation>
+<translation id="3789841737615482174">Instal·la</translation>
<translation id="3793574014653384240">Nombre i motius dels errors que s'han produït recentment</translation>
<translation id="3797522431967816232">Prc3 (sobre)</translation>
<translation id="3799805948399000906">Tipus de lletra sol·licitat</translation>
@@ -742,15 +755,16 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3996311196211510766">El lloc web <ph name="ORIGIN" /> ha sol·licitat que s'apliqui una política d'origen a totes les sol·licituds que rebi, però en aquest moment aquesta política no es pot aplicar.</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Document PDF que conté {COUNT} pàgina}other{Document PDF que conté {COUNT} pàgines}}</translation>
<translation id="4030383055268325496">&amp;Desfés l'addició</translation>
-<translation id="4032320456957708163"><ph name="ENROLLMENT_DOMAIN" /> gestiona el teu navegador</translation>
+<translation id="4032320456957708163">El navegador està gestionat per <ph name="ENROLLMENT_DOMAIN" /></translation>
<translation id="4056223980640387499">Sèpia</translation>
<translation id="4058922952496707368">Tecla "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (sobre)</translation>
+<translation id="4067669230157909013">La captura de pantalla s'ha reprès.</translation>
<translation id="4067947977115446013">Afegeix una adreça vàlida</translation>
<translation id="4072486802667267160">S’ha produït un error en processar la comanda. Torna-ho a provar.</translation>
<translation id="4075732493274867456">El client i el servidor no admeten cap versió de protocol SSL ni cap sistema de xifratge comuns.</translation>
<translation id="4075941231477579656">Touch ID</translation>
-<translation id="4079302484614802869">La configuració del servidor intermediari s'ha definit perquè utilitzi un URL d'script .pac, en lloc de servidors intermedis fixos.</translation>
+<translation id="4079302484614802869">La configuració del servidor intermediari s'ha definit perquè utilitzi un URL de script .pac, en lloc de servidors intermedis fixos.</translation>
<translation id="4082393374666368382">Configuració - Gestió</translation>
<translation id="4084120443451129199">Cerca el mode i prem Retorn per cercar <ph name="KEYWORD_SUFFIX" /></translation>
<translation id="4088981014127559358">Desplaçament a l'eix Y del costat 1 de la imatge</translation>
@@ -826,6 +840,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4297502707443874121">Miniatura de la pàgina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Desplega</translation>
<translation id="4300675098767811073">Encunyació múltiple a la dreta</translation>
+<translation id="4302514097724775343">Toca el dinosaure per jugar</translation>
<translation id="4302965934281694568">Chou3 (sobre)</translation>
<translation id="4305666528087210886">No s'ha pogut accedir al fitxer</translation>
<translation id="4305817255990598646">Canvia</translation>
@@ -904,6 +919,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4658638640878098064">Grapat a la part superior esquerra</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realitat virtual</translation>
+<translation id="4675657451653251260">En mode de convidat, no veuràs informació del perfil de Chrome. Pots <ph name="LINK_BEGIN" />iniciar la sessió<ph name="LINK_END" /> per accedir a la informació del teu Compte de Google, com ara les contrasenyes i les formes de pagament.</translation>
<translation id="467662567472608290">El servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat conté errors. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="4677585247300749148"><ph name="URL" /> vol respondre als esdeveniments d'accessibilitat</translation>
<translation id="467809019005607715">Presentacions de Google</translation>
@@ -931,6 +947,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4761104368405085019">Utilitzar el micròfon</translation>
<translation id="4764776831041365478">És possible que la pàgina web <ph name="URL" /> estigui temporalment fora de servei o s'hagi traslladat permanentment a una adreça web nova.</translation>
<translation id="4766713847338118463">Grapat doble a la part inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Activitat que es desarà en aquest dispositiu
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Qualsevol fitxer que baixis en aquesta finestra
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">S'ha produït un error desconegut.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Finestra emergent bloquejada}other{# finestres emergents bloquejades}}</translation>
<translation id="4780366598804516005">Bústia de correu 1</translation>
@@ -1093,11 +1115,13 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5386426401304769735">La cadena de certificats d'aquest lloc conté un certificat que s'ha signat amb SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Cosit de la vora a la dreta</translation>
+<translation id="5398772614898833570">Anuncis bloquejats</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Aquest servidor no ha pogut demostrar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat no és vàlid en aquest moment. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la connexió.</translation>
<translation id="541416427766103491">Apiladora 4</translation>
<translation id="5421136146218899937">Esborra dades de navegació...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> et vol enviar notificacions</translation>
+<translation id="542872847390508405">Esteu navegant com a convidat.</translation>
<translation id="5430298929874300616">Suprimeix l'adreça d'interès</translation>
<translation id="5439770059721715174">Error de validació de l'esquema a "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordre invers de cara amunt</translation>
@@ -1139,12 +1163,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5571083550517324815">No es pot fer la recollida en aquesta adreça. Selecciona'n una altra.</translation>
<translation id="5580958916614886209">Comprova el mes de caducitat i torna-ho a provar</translation>
<translation id="5586446728396275693">No hi ha cap adreça desada</translation>
+<translation id="5593349413089863479">La connexió no és totalment segura</translation>
<translation id="5595485650161345191">Edita l'adreça</translation>
<translation id="5598944008576757369">Selecciona una forma de pagament</translation>
<translation id="560412284261940334">Gestió no compatible</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Aquest lloc web podria ser fals o fraudulent. Chrome recomana que en surtis ara.</translation>
<translation id="5610142619324316209">Comproveu la connexió</translation>
<translation id="5610807607761827392">Pots gestionar les targetes i les adreces a <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Tradueix aquesta pàgina amb el Traductor de Google</translation>
@@ -1216,6 +1240,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5901630391730855834">Groc</translation>
<translation id="5905445707201418379">S'ha bloquejat d'acord amb la política d'origen de: <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (informació sincronitzada)</translation>
+<translation id="5913377024445952699">La captura de pantalla s'ha posat en pausa</translation>
<translation id="59174027418879706">Activat</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Activat</translation>
@@ -1228,12 +1253,13 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5963413905009737549">Secció</translation>
<translation id="5967592137238574583">Edita la informació de contacte</translation>
<translation id="5967867314010545767">Elimina de l'historial</translation>
+<translation id="5968793460449681917">En cada visita</translation>
<translation id="5975083100439434680">Redueix</translation>
<translation id="5979084224081478209">Comprova les contrasenyes</translation>
<translation id="5980920751713728343">Index-3x5</translation>
<translation id="5984570616552610254">Humitat de la sala</translation>
-<translation id="598637245381783098">No es pot obrir l'aplicació per pagar</translation>
-<translation id="5989320800837274978">No s'especifiquen servidors intermediaris ni URL d'script .pac.</translation>
+<translation id="598637245381783098">No es pot obrir l'aplicació de pagaments</translation>
+<translation id="5989320800837274978">No s'especifiquen servidors intermediaris ni URL de script .pac.</translation>
<translation id="5990559369517809815">Una extensió ha bloquejat les peticions al servidor.</translation>
<translation id="5992691462791905444">Plegat en Z per a enginyeria</translation>
<translation id="6000758707621254961"><ph name="RESULT_COUNT" /> resultats per a "<ph name="SEARCH_TEXT" />"</translation>
@@ -1383,6 +1409,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6587923378399804057">Enllaç que has copiat</translation>
<translation id="6591833882275308647">El dispositiu <ph name="DEVICE_TYPE" /> no està gestionat</translation>
<translation id="6596325263575161958">Opcions d'encriptació</translation>
+<translation id="6596892391065203054">El teu administrador ha bloquejat la impressió d'aquest contingut.</translation>
<translation id="6604181099783169992">Sensors de moviment o de llum</translation>
<translation id="6609880536175561541">Prc7 (sobre)</translation>
<translation id="6612358246767739896">Contingut protegit</translation>
@@ -1442,6 +1469,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6895330447102777224">La teva targeta s'ha confirmat</translation>
<translation id="6897140037006041989">Agent d'usuari</translation>
<translation id="6898699227549475383">Organització (O)</translation>
+<translation id="6907293445143367439">Permet a <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> vol obtenir un control total dels teus dispositius MIDI</translation>
<translation id="6915804003454593391">Usuari:</translation>
<translation id="6934672428414710184">Aquest nom prové del teu Compte de Google</translation>
@@ -1458,7 +1486,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="696703987787944103">Perceptiu</translation>
<translation id="6970216967273061347">Districte</translation>
<translation id="6972629891077993081">Dispositius d'interfície humana</translation>
-<translation id="6973656660372572881">S'especifiquen tant els servidors intermediaris fixos com un URL d'script .pac.</translation>
+<translation id="6973656660372572881">S'especifiquen tant els servidors intermediaris fixos com un URL de script .pac.</translation>
<translation id="6973932557599545801">Em sap greu, però no et puc ajudar. Continua pel teu compte.</translation>
<translation id="6975012522936652259">Acabes d'introduir la contrasenya en un lloc web enganyós. Chromium et recomana que vagis a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> i a altres llocs web en què utilitzis aquesta contrasenya i que la canviïs ara.</translation>
<translation id="6979158407327259162">Google Drive</translation>
@@ -1553,6 +1581,7 @@ Detalls addicionals:
<translation id="7346048084945669753">Està afiliat:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Línia d'ordres</translation>
+<translation id="7359588939039777303">S'han bloquejat els anuncis.</translation>
<translation id="7372973238305370288">resultat de la cerca</translation>
<translation id="7374733840632556089">Aquest problema es produeix a causa d'un certificat que tu o una altra persona heu instal·lat al dispositiu. Se sap que aquest certificat s'utilitza per supervisar i interceptar xarxes, i Chrome no hi confia. Tot i que hi ha casos en què és legítim dur a terme una supervisió, per exemple, en el cas d'una empresa o d'un centre educatiu, Chrome vol assegurar-se que estiguis al cas d'aquesta situació, encara que no la puguis evitar. La supervisió es pot produir en qualsevol navegador o aplicació que accedeixi al web.</translation>
<translation id="7375818412732305729">S'adjunta un fitxer</translation>
@@ -1727,6 +1756,7 @@ Detalls addicionals:
<translation id="7976214039405368314">Hi ha massa sol·licituds</translation>
<translation id="7977538094055660992">Dispositiu de sortida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Per veure contingut en realitat augmentada, instal·la ARCore</translation>
<translation id="799149739215780103">Enquadernació</translation>
<translation id="7995512525968007366">No especificat</translation>
<translation id="800218591365569300">Prova de tancar altres pestanyes o programes per alliberar memòria.</translation>
@@ -1854,24 +1884,38 @@ Detalls addicionals:
<translation id="8507227106804027148">Línia d'ordres</translation>
<translation id="8508648098325802031">Icona de la cerca</translation>
<translation id="8522552481199248698">Chrome et pot ajudar a protegir el Compte de Google i a canviar la contrasenya.</translation>
+<translation id="8525306231823319788">Pantalla completa</translation>
<translation id="8530813470445476232">Esborra l'historial de navegació, les galetes, la memòria cau i molt més a la configuració de Chrome</translation>
<translation id="8533619373899488139">Ves a &lt;strong&gt;chrome://policy&lt;/strong&gt; per veure la llista d'URL bloquejats i altres polítiques aplicades per l'administrador del sistema.</translation>
<translation id="8541158209346794904">Dispositiu Bluetooth</translation>
<translation id="8542014550340843547">Grapat triple a la part inferior</translation>
<translation id="8543181531796978784">Podeu <ph name="BEGIN_ERROR_LINK" />informar d'un problema de detecció<ph name="END_ERROR_LINK" /> o, si enteneu els riscos que això comporta per a la vostra seguretat, <ph name="BEGIN_LINK" />visiteu aquest lloc no segur<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">El CVC es troba a la part posterior de la targeta.</translation>
+<translation id="8558485628462305855">Per veure contingut en realitat augmentada, actualitza ARCore</translation>
<translation id="8559762987265718583">No es pot establir una connexió privada amb <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perquè la data i l'hora (<ph name="DATE_AND_TIME" />) del dispositiu són incorrectes.</translation>
<translation id="8564182942834072828">Documents independents / Còpies sense recopilar</translation>
<translation id="8564985650692024650">Chromium et recomana que restableixis la contrasenya per a <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si l'has fet servir en altres llocs web.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Activitat que no es desarà en aquest dispositiu:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pàgines que consultis en aquesta finestra
+ <ph name="LIST_ITEM" />Galetes i dades de llocs web
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Fes servir Touch ID per confirmar les targetes més ràpidament</translation>
<translation id="858637041960032120">Afegeix un número de telèfon</translation>
<translation id="8589998999637048520">Qualitat òptima</translation>
+<translation id="8600271352425265729">Només aquesta vegada</translation>
<translation id="860043288473659153">Nom del titular de la targeta</translation>
<translation id="8606726445206553943">Utilitzar els dispositius MIDI</translation>
+<translation id="8612761427948161954">Hola, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Estàs navegant com a convidat</translation>
<translation id="861775596732816396">Mida 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">No hi ha cap contrasenya que coincideixi. Mostra totes les contrasenyes desades.</translation>
<translation id="8625384913736129811">Desa aquesta targeta al dispositiu</translation>
+<translation id="8627040765059109009">Captura de pantalla represa</translation>
<translation id="8657078576661269990">El teu administrador ha bloquejat la compartició de <ph name="ORIGIN_NAME" /> a <ph name="VM_NAME_1" /> i <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Resum de la comanda, <ph name="TOTAL_LABEL" />, més detalls</translation>
<translation id="867224526087042813">Signatura</translation>
@@ -1934,6 +1978,7 @@ Detalls addicionals:
<translation id="8912362522468806198">Compte de Google</translation>
<translation id="8913778647360618320">Botó Gestiona les formes de pagament; prem Retorn per gestionar la informació dels pagaments i de les targetes de crèdit a la configuració de Chrome</translation>
<translation id="8918231688545606538">Aquesta pàgina és sospitosa</translation>
+<translation id="8922013791253848639">Permet sempre els anuncis en aquest lloc web</translation>
<translation id="892588693504540538">Encunyació a la part superior dreta</translation>
<translation id="8931333241327730545">Voleu desar aquesta targeta al vostre compte de Google?</translation>
<translation id="8932102934695377596">El rellotge està endarrerit</translation>
@@ -2005,6 +2050,7 @@ Detalls addicionals:
<translation id="9183302530794969518">Documents de Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> fa servir un protocol no admès.</translation>
<translation id="9191834167571392248">Encunyació a la part inferior esquerra</translation>
+<translation id="9199905725844810519">La impressió està bloquejada</translation>
<translation id="9205078245616868884">Les vostres dades estan encriptades amb la vostra frase de contrasenya de sincronització. Introduïu-la per començar la sincronització.</translation>
<translation id="9207861905230894330">No s'ha pogut afegir l'article.</translation>
<translation id="9213433120051936369">Personalitza l'aspecte</translation>
@@ -2015,8 +2061,10 @@ Detalls addicionals:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Podries perdre l'accés al Compte de Google. Chromium et recomana que canviïs la contrasenya ara. Se't demanarà que iniciïs la sessió.</translation>
<translation id="939736085109172342">Carpeta nova</translation>
+<translation id="945522503751344254">Envia suggeriments</translation>
<translation id="945855313015696284">Consulta la informació següent i suprimeix les targetes que no siguin vàlides</translation>
<translation id="950736567201356821">Encunyació triple a la part superior</translation>
+<translation id="951941430552851965">L'administrador ha posat en pausa la captura de pantalla a causa del contingut que s'hi mostra.</translation>
<translation id="961663415146723894">Enquadernació per la part inferior</translation>
<translation id="962484866189421427">Pot ser que aquest contingut provi d'instal·lar aplicacions enganyoses que es facin passar per d'altres o que recullin dades que podrien utilitzar-se per fer un seguiment de la teva activitat. <ph name="BEGIN_LINK" />Mostra igualment<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Muntatge oficial</translation>
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index 115001e2791..22aa84a8eab 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -80,6 +80,14 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Zadali jste své heslo na webu, který není spravován vaší organizací. Kvůli ochranÄ› úÄtu nepoužívejte jeho heslo v jiných aplikacích a na jiných webech.</translation>
<translation id="1263231323834454256">Seznam Äetby</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivita, která v zařízení nezůstane uložena:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stránky, které zobrazíte v tomto okně,
+ <ph name="LIST_ITEM" />soubory cookie a data webů,
+ <ph name="LIST_ITEM" />údaje v úÄtu (<ph name="LINK_BEGIN" />odhlásit se<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Způsob vyzvednutí</translation>
<translation id="1281476433249504884">StohovaÄ 1</translation>
<translation id="1285320974508926690">Tento web nikdy nepřekládat</translation>
@@ -279,6 +287,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="204357726431741734">Chcete-li používat hesla uložená v úÄtu Google, pÅ™ihlaste se</translation>
<translation id="2053111141626950936">Stránky v jazyce <ph name="LANGUAGE" /> se nebudou překládat.</translation>
<translation id="2053553514270667976">PSČ</translation>
+<translation id="2054665754582400095">Vaše přítomnost</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 návrh}few{# návrhy}many{# návrhu}other{# návrhů}}</translation>
<translation id="2079545284768500474">Vrátit zpět</translation>
<translation id="20817612488360358">Jako aktivní jsou nakonfigurována systémová nastavení proxy serveru, je vÅ¡ak urÄena i explicitní konfigurace proxy serveru.</translation>
@@ -292,6 +301,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2102495993840063010">Aplikace Android</translation>
<translation id="2107021941795971877">Podpora tisku</translation>
<translation id="2108755909498034140">Restartujte poÄítaÄ</translation>
+<translation id="2111166930115883695">Mezerníkem spustíte hru</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Zásada ignorována, protože bylo přepsána zásadou <ph name="POLICY_NAME" />.</translation>
@@ -303,6 +313,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="214556005048008348">Zrušit platbu</translation>
<translation id="2147827593068025794">Synchronizace na pozadí</translation>
<translation id="2148613324460538318">Přidat kartu</translation>
+<translation id="2149968176347646218">PÅ™ipojení není zabezpeÄené</translation>
<translation id="2154054054215849342">Synchronizace není pro vaši doménu k dispozici</translation>
<translation id="2154484045852737596">Úprava karty</translation>
<translation id="2161656808144014275">Text</translation>
@@ -313,7 +324,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2181821976797666341">Zásady</translation>
<translation id="2183608646556468874">Telefonní Äíslo</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adres}}</translation>
-<translation id="2187243482123994665">Aktivita uživatele</translation>
<translation id="2187317261103489799">Rozpoznat (výchozí)</translation>
<translation id="2188375229972301266">Několik děr dole</translation>
<translation id="2202020181578195191">Zadejte platný rok vypršení platnosti</translation>
@@ -464,6 +474,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2839501879576190149">Chystáte se navštívit falešný web</translation>
<translation id="2850739647070081192">Invite (obálka)</translation>
<translation id="2856444702002559011">ÚtoÄníci se mohou pokusit odcizit vaÅ¡e údaje na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (například hesla, zprávy nebo informace o platebních kartách). <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Tento web zobrazuje rušivé nebo zavádějící reklamy.</translation>
<translation id="2878197950673342043">Plakátové přeložení</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Umístění oken</translation>
@@ -502,11 +513,11 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2996674880327704673">Návrhy od Googlu</translation>
<translation id="3002501248619246229">Zkontrolujte média ve vstupní přihrádce</translation>
<translation id="3005723025932146533">Zobrazit uloženou kopii</translation>
-<translation id="3007719053326478567">Tisk tohoto obsahu administrátor zablokoval</translation>
<translation id="3008447029300691911">Zadejte kód CVC karty <ph name="CREDIT_CARD" />. Po ověření budou údaje o kartě sdíleny s tímto webem.</translation>
<translation id="3010559122411665027">Položka seznamu „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automaticky blokováno</translation>
<translation id="3016780570757425217">Přístup k údajům o vaší poloze</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, návrh odstraníte tak, že stisknete tabulátor a poté klávesu Enter.</translation>
<translation id="3023071826883856138">You4 (obálka)</translation>
<translation id="3024663005179499861">Chybný typ zásady</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
@@ -546,6 +557,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3207960819495026254">Přidáno do záložek</translation>
<translation id="3209034400446768650">Stránka může úÄtovat poplatky</translation>
<translation id="3212581601480735796">Vaše aktivita na webu <ph name="HOSTNAME" /> je sledována</translation>
+<translation id="3212623355668894776">Když zavřete všechna okna hosta, aktivita prohlížení bude ze zařízení vymazána.</translation>
<translation id="3215092763954878852">Ověření WebAuthn nebylo možné použít</translation>
<translation id="3218181027817787318">Relativní</translation>
<translation id="3225919329040284222">Server se prokázal certifikátem, který neodpovídá integrovaným oÄekáváním. Tato oÄekávaní jsou zahrnuta u urÄitých webových stránek s vysokou úrovní zabezpeÄení kvůli vaší ochranÄ›.</translation>
@@ -692,6 +704,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3784372983762739446">Zařízení Bluetooth</translation>
<translation id="3787705759683870569">Platnost do: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Velikost 16</translation>
+<translation id="3789841737615482174">Instalovat</translation>
<translation id="3793574014653384240">PoÄty a příÄiny nedávných selhání</translation>
<translation id="3797522431967816232">Prc3 (obálka)</translation>
<translation id="3799805948399000906">Požadováno písmo</translation>
@@ -742,6 +755,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4056223980640387499">Sépie</translation>
<translation id="4058922952496707368">KlÃ­Ä <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (obálka)</translation>
+<translation id="4067669230157909013">Záznam obrazovky byl obnoven.</translation>
<translation id="4067947977115446013">Přidejte platnou adresu</translation>
<translation id="4072486802667267160">Při zpracování objednávky došlo k chybě. Zkuste to prosím znovu.</translation>
<translation id="4075732493274867456">Klient a server nepodporují spoleÄnou verzi protokolu SSL nebo Å¡ifrovací sadu.</translation>
@@ -822,6 +836,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4297502707443874121">Miniatura stránky <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Rozbalit</translation>
<translation id="4300675098767811073">Několik děr vpravo</translation>
+<translation id="4302514097724775343">Klepnutím na dinosaura spustíte hru</translation>
<translation id="4302965934281694568">Chou3 (obálka)</translation>
<translation id="4305666528087210886">K souboru nelze získat přístup</translation>
<translation id="4305817255990598646">Přejít</translation>
@@ -900,6 +915,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4658638640878098064">Sponka vlevo nahoře</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuální realita</translation>
+<translation id="4675657451653251260">V režimu hosta neuvidíte žádné údaje profilu Chrome. Chcete-li získat přístup k informacím v úÄtu Google, jako jsou hesla nebo platební metody, <ph name="LINK_BEGIN" />pÅ™ihlaste se<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />, protože jeho bezpeÄnostní certifikát obsahuje chyby. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="4677585247300749148"><ph name="URL" /> chce reagovat na události přístupnosti</translation>
<translation id="467809019005607715">Prezentace Google</translation>
@@ -927,6 +943,12 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4761104368405085019">Používat mikrofon</translation>
<translation id="4764776831041365478">Webové stránky na adrese <ph name="URL" /> jsou možná doÄasnÄ› nedostupné nebo mohly být pÅ™emístÄ›ny na novou webovou adresu.</translation>
<translation id="4766713847338118463">DvÄ› sponky dole</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivita, která v zařízení zůstane uložena:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />soubory, které stáhnete v tomto okně.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Došlo k neznámé chybě.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Zablokováno vyskakovací okno}few{Zablokována # vyskakovací okna}many{Zablokováno # vyskakovacího okna}other{Zablokováno # vyskakovacích oken}}</translation>
<translation id="4780366598804516005">Schránka 1</translation>
@@ -1089,11 +1111,13 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="5386426401304769735">Řetězec certifikátů tohoto webu obsahuje certifikát podepsaný algoritmem SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Sešití na pravém okraji</translation>
+<translation id="5398772614898833570">Byly zablokovány reklamy</translation>
<translation id="5400836586163650660">Šedá</translation>
<translation id="540969355065856584">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostní certifikát v tuto chvíli není platný. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="541416427766103491">StohovaÄ 4</translation>
<translation id="5421136146218899937">Vymazat údaje o prohlížení...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vám chce zasílat oznámení</translation>
+<translation id="542872847390508405">Prohlížíte si web jako host</translation>
<translation id="5430298929874300616">Odstranit záložku</translation>
<translation id="5439770059721715174">Chyba validace schématu v místě <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Obrácené pořadí lícem nahoru</translation>
@@ -1135,12 +1159,12 @@ Kontaktujte administrátora systému.</translation>
<translation id="5571083550517324815">Vyzvednutí na této adrese není možné. Vyberte jinou adresu.</translation>
<translation id="5580958916614886209">Zkontrolujte měsíc vypršení platnosti a zkuste to znovu.</translation>
<translation id="5586446728396275693">Žádné uložené adresy</translation>
+<translation id="5593349413089863479">PÅ™ipojení není plnÄ› zabezpeÄené</translation>
<translation id="5595485650161345191">Upravit adresu</translation>
<translation id="5598944008576757369">Vybrat platební metodu</translation>
<translation id="560412284261940334">Správa není podporována</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Tento web může být faleÅ¡ný nebo podvodný. Chrome vám doporuÄuje okamžitÄ› odejít.</translation>
<translation id="5610142619324316209">Zkontrolovat připojení</translation>
<translation id="5610807607761827392">Karty a adresy můžete spravovat v <ph name="BEGIN_LINK" />Nastavení<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">PÅ™eložte tuto stránku pomocí PÅ™ekladaÄe Google</translation>
@@ -1212,6 +1236,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5901630391730855834">Žlutá</translation>
<translation id="5905445707201418379">Zablokováno na základě zásad webu <ph name="ORIGIN" /> ohledně původu.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronizováno)</translation>
+<translation id="5913377024445952699">Záznam obrazovky je pozastaven</translation>
<translation id="59174027418879706">Povoleno</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Zapnuto</translation>
@@ -1224,6 +1249,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5963413905009737549">Sekce</translation>
<translation id="5967592137238574583">Úprava kontaktních údajů</translation>
<translation id="5967867314010545767">Odstranit z historie</translation>
+<translation id="5968793460449681917">Při každé návštěvě</translation>
<translation id="5975083100439434680">Oddálit</translation>
<translation id="5979084224081478209">Zkontrolovat hesla</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1378,6 +1404,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6587923378399804057">Zkopírovaný odkaz</translation>
<translation id="6591833882275308647">Vaše zařízení <ph name="DEVICE_TYPE" /> není spravováno</translation>
<translation id="6596325263575161958">Možnosti šifrování</translation>
+<translation id="6596892391065203054">Tisk tohoto obsahu administrátor zablokoval.</translation>
<translation id="6604181099783169992">Senzory pohybu nebo světla</translation>
<translation id="6609880536175561541">Prc7 (obálka)</translation>
<translation id="6612358246767739896">Chráněný obsah</translation>
@@ -1437,6 +1464,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6895330447102777224">Vaše karta je ověřena</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">Organizace (O)</translation>
+<translation id="6907293445143367439">Povolit webu <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763">Web <ph name="URL" /> chce získat úplnou kontrolu nad zařízeními MIDI</translation>
<translation id="6915804003454593391">Uživatel:</translation>
<translation id="6934672428414710184">Toto jméno pochází z vaÅ¡eho úÄtu Google</translation>
@@ -1547,6 +1575,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7346048084945669753">Je přidružený:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Příkazový řádek</translation>
+<translation id="7359588939039777303">Byly zablokovány reklamy.</translation>
<translation id="7372973238305370288">výsledek vyhledávání</translation>
<translation id="7374733840632556089">K tomuto problému dochází kvůli certifikátu, který jste vy nebo nÄ›kdo jiný nainstalovali do zařízení. O certifikátu je známo, že se používá ke sledování a zachytávání provozu v sítích, a Chrome mu nedůvěřuje. AÄkoliv sledování v nÄ›kterých případech (například ve Å¡kolní nebo firemní síti) může být legitimní a nemůžete mu zabránit, Chrome se chce ujistit, že o nÄ›m víte. Ke sledování může docházet v kterémkoliv prohlížeÄi nebo aplikaci, které pÅ™istupují k webu.</translation>
<translation id="7375818412732305729">Připojení souboru</translation>
@@ -1721,6 +1750,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7976214039405368314">Příliš mnoho požadavků</translation>
<translation id="7977538094055660992">Výstupní zařízení</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Chcete-li zobrazit obsah pro rozšířenou realitu, nainstalujte ARCore</translation>
<translation id="799149739215780103">Vazba</translation>
<translation id="7995512525968007366">Není zadáno</translation>
<translation id="800218591365569300">Zkuste uvolnit paměť tím, že zavřete ostatní karty nebo programy.</translation>
@@ -1848,25 +1878,39 @@ Další podrobnosti:
<translation id="8507227106804027148">Příkazový řádek</translation>
<translation id="8508648098325802031">Ikona Vyhledávání</translation>
<translation id="8522552481199248698">Chrome vám může pomoci ochránit váš úÄet Google a zmÄ›nit heslo.</translation>
+<translation id="8525306231823319788">Celá obrazovka</translation>
<translation id="8530813470445476232">Vymažte historii prohlížení, soubory cookie, mezipaměť a další data v nastavení Chromu</translation>
<translation id="8533619373899488139">Na stránce &lt;strong&gt;chrome://policy&lt;/strong&gt; naleznete seznam blokovaných adres URL a další zásady vynucené vaším administrátorem systému.</translation>
<translation id="8541158209346794904">Zařízení Bluetooth</translation>
<translation id="8542014550340843547">Tři sponky dole</translation>
<translation id="8543181531796978784">Můžete <ph name="BEGIN_ERROR_LINK" />nahlásit problém se zjiÅ¡tÄ›ným webem<ph name="END_ERROR_LINK" />. Pokud bezpeÄnostní rizika chápete, můžete <ph name="BEGIN_LINK" />tento nespolehlivý web navÅ¡tívit<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Kód CVC je uveden na zadní straně karty.</translation>
+<translation id="8558485628462305855">Chcete-li zobrazit obsah pro rozšířenou realitu, aktualizujte ARCore</translation>
<translation id="8559762987265718583">Soukromé pÅ™ipojení k doménÄ› <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nelze navázat, protože máte v zařízení nastaveno chybné datum a Äas (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Oddělené dokumenty / nekompletované kopie</translation>
<translation id="8564985650692024650">Pokud jste heslo organizace <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili na jiném webu, doporuÄujeme vám ho resetovat.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivita, která v zařízení nezůstane uložena:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stránky, které zobrazíte v tomto okně,
+ <ph name="LIST_ITEM" />soubory cookie a data webů.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Potvrzovat karty rychleji pomocí technologie Touch ID</translation>
<translation id="858637041960032120">Přidat telefon
</translation>
<translation id="8589998999637048520">Nejlepší kvalita</translation>
+<translation id="8600271352425265729">Pouze tentokrát</translation>
<translation id="860043288473659153">Jméno držitele karty</translation>
<translation id="8606726445206553943">Používat vaše zařízení MIDI</translation>
+<translation id="8612761427948161954">Dobrý den, <ph name="USERNAME" />,
+ <ph name="BR" />
+ prohlížíte si web jako host</translation>
<translation id="861775596732816396">Velikost 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nebyla nalezena žádná odpovídající hesla. Zobrazit všechna uložená hesla.</translation>
<translation id="8625384913736129811">Uložit tuto kartu do zařízení</translation>
+<translation id="8627040765059109009">Záznam obrazovky byl znovu spuštěn</translation>
<translation id="8657078576661269990">Váš administrátor zablokoval sdílení ze zdroje <ph name="ORIGIN_NAME" /> s virtuálními poÄítaÄi <ph name="VM_NAME_1" /> a <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Shrnutí objednávky, <ph name="TOTAL_LABEL" />, další podrobnosti</translation>
<translation id="867224526087042813">Podpis</translation>
@@ -1929,6 +1973,7 @@ Další podrobnosti:
<translation id="8912362522468806198">ÚÄet Google</translation>
<translation id="8913778647360618320">TlaÄítko Spravovat platební metody, stisknutím klávesy Enter můžete spravovat údaje o platbách a platebních kartách v nastavení Chromu</translation>
<translation id="8918231688545606538">Tato stránka je podezřelá</translation>
+<translation id="8922013791253848639">Na tomto webu reklamy vždy povolovat</translation>
<translation id="892588693504540538">Děrování vpravo nahoře</translation>
<translation id="8931333241327730545">Chcete tuto kartu uložit do úÄtu Google?</translation>
<translation id="8932102934695377596">VaÅ¡e hodiny se zpožÄují</translation>
@@ -2000,6 +2045,7 @@ Další podrobnosti:
<translation id="9183302530794969518">Dokumenty Google</translation>
<translation id="9183425211371246419">Web <ph name="HOST_NAME" /> používá nepodporovaný protokol.</translation>
<translation id="9191834167571392248">Děrování vlevo dole</translation>
+<translation id="9199905725844810519">Tisk je blokován</translation>
<translation id="9205078245616868884">Vaše data jsou šifrována pomocí heslové fráze pro synchronizaci. Chcete-li zahájit synchronizaci, zadejte ji.</translation>
<translation id="9207861905230894330">PÅ™idání Älánku se nezdaÅ™ilo.</translation>
<translation id="9213433120051936369">Přizpůsobit vzhled</translation>
@@ -2010,8 +2056,10 @@ Další podrobnosti:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Mohli byste ztratit přístup k úÄtu Google. Chromium doporuÄuje okamžitÄ› zmÄ›nit heslo. Budete vyzváni k pÅ™ihlášení.</translation>
<translation id="939736085109172342">Nová složka</translation>
+<translation id="945522503751344254">Odeslat zpětnou vazbu</translation>
<translation id="945855313015696284">Zkontrolujte níže uvedené informace a vymažte neplatné karty</translation>
<translation id="950736567201356821">Tři díry nahoře</translation>
+<translation id="951941430552851965">Administrátor pořizování snímků obrazovky vzhledem k obsahu na obrazovce pozastavil.</translation>
<translation id="961663415146723894">Vazba dole</translation>
<translation id="962484866189421427">Tento obsah by se mohl pokusit instalovat klamavé aplikace, které se vydávají za nÄ›co jiného nebo shromažÄují data ke sledování vaší aktivity. <ph name="BEGIN_LINK" />PÅ™esto zobrazit<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Oficiální sestavení</translation>
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index 3e97c00796e..07357ba76cf 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -80,6 +80,14 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Du indtastede din adgangskode på et website, der ikke administreres af din organisation. Du kan beskytte din konto ved at undgå at bruge din adgangskode i andre apps og på andre websites.</translation>
<translation id="1263231323834454256">Læseliste</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivitet, der ikke gemmes på denne enhed:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />De sider, du besøger i dette vindue
+ <ph name="LIST_ITEM" />Cookies og websitedata
+ <ph name="LIST_ITEM" />Kontooplysninger (<ph name="LINK_BEGIN" />log ud<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Afhentningsmetode</translation>
<translation id="1281476433249504884">Stabler 1</translation>
<translation id="1285320974508926690">Oversæt aldrig dette website</translation>
@@ -283,6 +291,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="204357726431741734">Log ind for at bruge de adgangskoder, du har gemt på din Google-konto</translation>
<translation id="2053111141626950936">Sider på <ph name="LANGUAGE" /> oversættes ikke.</translation>
<translation id="2053553514270667976">Postnummer</translation>
+<translation id="2054665754582400095">Din tilstedeværelse</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 forslag}one{# forslag}other{# forslag}}</translation>
<translation id="2079545284768500474">Fortryd</translation>
<translation id="20817612488360358">Indstillingerne for systemproxy er angivet at blive brugt, men en eksplicit proxykonfiguration er også angivet.</translation>
@@ -296,6 +305,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2102495993840063010">Android-apps</translation>
<translation id="2107021941795971877">Understøttelse til udskrivning</translation>
<translation id="2108755909498034140">Genstart computeren</translation>
+<translation id="2111166930115883695">Tryk på mellemrumstasten for at spille</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignoreret, da den blev tilsidesat af <ph name="POLICY_NAME" /> .</translation>
@@ -307,6 +317,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="214556005048008348">Annuller betaling</translation>
<translation id="2147827593068025794">Synkronisering i baggrunden</translation>
<translation id="2148613324460538318">Tilføj kort</translation>
+<translation id="2149968176347646218">Forbindelsen er ikke sikker</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgængelig for dit domæne</translation>
<translation id="2154484045852737596">Rediger kort</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -317,7 +328,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2181821976797666341">Politikker</translation>
<translation id="2183608646556468874">Telefonnummer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresser}}</translation>
-<translation id="2187243482123994665">Brugertilstedeværelse</translation>
<translation id="2187317261103489799">Registrer (standardindstilling)</translation>
<translation id="2188375229972301266">Flere huller nederst</translation>
<translation id="2202020181578195191">Angiv et gyldigt udløbsår</translation>
@@ -470,6 +480,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2839501879576190149">Falsk website forude</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Brugere med ondsindede hensigter kan forsøge at stjæle dine oplysninger fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (f.eks. adgangskoder, beskeder eller kreditkort). <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Dette website viser påtrængende eller vildledende annoncer.</translation>
<translation id="2878197950673342043">Plakatfals</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Placering af vinduer</translation>
@@ -508,11 +519,11 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2996674880327704673">Forslag fra Google</translation>
<translation id="3002501248619246229">Tjek det, der er lagt i papirbakken</translation>
<translation id="3005723025932146533">Vis gemt kopi</translation>
-<translation id="3007719053326478567">Din administrator har blokeret udskrivning af dette indhold</translation>
<translation id="3008447029300691911">Angiv kontrolkoden for <ph name="CREDIT_CARD" />. Når du bekræfter, deles dine kortoplysninger med dette website.</translation>
<translation id="3010559122411665027">Angiv posten "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatisk blokering</translation>
<translation id="3016780570757425217">Kende din placering</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, tryk på Tab-tasten og derefter Enter for at fjerne forslaget.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Forkert politiktype</translation>
<translation id="3037605927509011580">Øv, surt!</translation>
@@ -555,6 +566,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3207960819495026254">Gemt som bogmærke</translation>
<translation id="3209034400446768650">Siden kan opkræve betaling</translation>
<translation id="3212581601480735796">Din aktivitet på <ph name="HOSTNAME" /> overvåges</translation>
+<translation id="3212623355668894776">Luk alle gæstevinduer for at slette din browserhistorik på denne enhed.</translation>
<translation id="3215092763954878852">WebAuthn kunne ikke anvendes</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3225919329040284222">Serveren præsenterede et certifikat, der ikke svarer til de indbyggede forventninger. Disse forventninger medtages for bestemte websites med høj sikkerhed for at beskytte dig.</translation>
@@ -702,6 +714,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3784372983762739446">Bluetooth-enheder</translation>
<translation id="3787705759683870569">Udløber <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Størrelse 16</translation>
+<translation id="3789841737615482174">Installer</translation>
<translation id="3793574014653384240">Antallene af og årsagerne til de nedbrud, der opstod for nylig</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Der blev anmodet om skrifttype</translation>
@@ -753,6 +766,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Nøgle "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Screenshot blev genoptaget.</translation>
<translation id="4067947977115446013">Tilføj gyldig adresse</translation>
<translation id="4072486802667267160">Der opstod en fejl under behandlingen af din ordre. Prøv igen.</translation>
<translation id="4075732493274867456">Klienten og serveren understøtter ikke en fælles SSL-protokolversion eller et fælles krypteringsprogram.</translation>
@@ -837,6 +851,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4297502707443874121">Miniature for siden <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Udvid</translation>
<translation id="4300675098767811073">Flere huller i højre side</translation>
+<translation id="4302514097724775343">Tryk på dinoen for at spille</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Din fil kunne ikke tilgås</translation>
<translation id="4305817255990598646">Skift</translation>
@@ -915,6 +930,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4658638640878098064">Hæftning øverst til venstre</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reality</translation>
+<translation id="4675657451653251260">Du vil ikke kunne se nogen Chrome-profiloplysninger i gæstetilstand. Du kan <ph name="LINK_BEGIN" />logge ind<ph name="LINK_END" /> for at få adgang til dine Google-kontooplysninger som f.eks. adgangskoder og betalingsmetoder.</translation>
<translation id="467662567472608290">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet indeholder fejl. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="4677585247300749148"><ph name="URL" /> anmoder om at reagere på handlinger foretaget i hjælpetilstand</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4761104368405085019">Bruge din mikrofon</translation>
<translation id="4764776831041365478">Websiden på <ph name="URL" /> kan være midlertidigt nede, eller også er den permanent flyttet til en ny webadresse.</translation>
<translation id="4766713847338118463">Dobbelthæftning nederst</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Din aktivitet, der gemmes på denne enhed:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />De filer, du downloader i dette vindue
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Der er opstået en ukendt fejl.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop op-vinduet er blokeret}one{# pop op-vindue er blokeret}other{# pop op-vinduer er blokeret}}</translation>
<translation id="4780366598804516005">Postkasse 1</translation>
@@ -1104,11 +1126,13 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5386426401304769735">Certifikatkæden for dette website indeholder et certifikat, der er signeret med SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Kanthæftning i højre side</translation>
+<translation id="5398772614898833570">Annoncer er blokeret</translation>
<translation id="5400836586163650660">Grå</translation>
<translation id="540969355065856584">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da dens sikkerhedscertifikat ikke er gyldigt i øjeblikket. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="541416427766103491">Stabler 4</translation>
<translation id="5421136146218899937">Ryd browserdata...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vil gerne sende notifikationer til dig</translation>
+<translation id="542872847390508405">Du er logget ind som gæst.</translation>
<translation id="5430298929874300616">Fjern bogmærke</translation>
<translation id="5439770059721715174">Skemavalideringsfejl på "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Omvendt rækkefølge med forside opad</translation>
@@ -1150,12 +1174,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5571083550517324815">Der kan ikke afhentes på denne adresse. Vælg en anden adresse.</translation>
<translation id="5580958916614886209">Kontrollér, om udløbsmåneden er korrekt, og prøv igen.</translation>
<translation id="5586446728396275693">Der er ikke nogen gemte adresser</translation>
+<translation id="5593349413089863479">Forbindelsen er ikke helt sikker</translation>
<translation id="5595485650161345191">Rediger adresse</translation>
<translation id="5598944008576757369">Vælg betalingsmetode</translation>
<translation id="560412284261940334">Administration er ikke understøttet</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Dette website er muligvis falsk eller ondsindet. Chrome anbefaler, at du forlader websitet med det samme.</translation>
<translation id="5610142619324316209">Tjekke din forbindelse</translation>
<translation id="5610807607761827392">Du kan administrere kort og adresser i <ph name="BEGIN_LINK" />Indstillinger<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Oversæt denne side med Google Oversæt</translation>
@@ -1227,6 +1251,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5901630391730855834">Gul</translation>
<translation id="5905445707201418379">Blokeret i overensstemmelse med oprindelsespolitikken for <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkroniseret)</translation>
+<translation id="5913377024445952699">Screenshots er sat på pause</translation>
<translation id="59174027418879706">Aktiveret</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Til</translation>
@@ -1239,6 +1264,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5963413905009737549">Afsnit</translation>
<translation id="5967592137238574583">Rediger kontaktoplysninger</translation>
<translation id="5967867314010545767">Fjern fra historik</translation>
+<translation id="5968793460449681917">Ved hvert besøg</translation>
<translation id="5975083100439434680">Zoom ud</translation>
<translation id="5979084224081478209">Tjek adgangskoder</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6587923378399804057">Link, du har kopieret</translation>
<translation id="6591833882275308647">Din <ph name="DEVICE_TYPE" /> administreres ikke</translation>
<translation id="6596325263575161958">Krypteringsmuligheder</translation>
+<translation id="6596892391065203054">Muligheden for at udskrive dette indhold er blevet blokeret af din administrator.</translation>
<translation id="6604181099783169992">Bevægelses- eller lyssensorer</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Beskyttet indhold</translation>
@@ -1453,6 +1480,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6895330447102777224">Dit kort er bekræftet</translation>
<translation id="6897140037006041989">Brugeragent</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">Giv <ph name="SITE_NAME" /> tilladelse til at:</translation>
<translation id="6910240653697687763"><ph name="URL" /> anmoder om fuld kontrol over dine MIDI-enheder</translation>
<translation id="6915804003454593391">Bruger:</translation>
<translation id="6934672428414710184">Dette navn er fra din Google-konto</translation>
@@ -1564,6 +1592,7 @@ Yderligere oplysninger:
<translation id="7346048084945669753">Er tilknyttet:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Kommandolinje</translation>
+<translation id="7359588939039777303">Annoncer er blokeret.</translation>
<translation id="7372973238305370288">søgeresultat</translation>
<translation id="7374733840632556089">Dette problem opstår på grund af et certifikat, som du eller en anden har installeret på din enhed. Certifikatet anvendes ofte til at overvåge og opfange netværk, og Chrome har ikke tillid til det. Der findes legitime årsager til at overvåge, f.eks. på skole- og virksomhedsnetværk, men Chrome vil sikre, at du er bevidst om det, når det sker, også selvom du ikke kan stoppe det. Overvågning kan finde sted i enhver browser eller app, der har adgang til nettet.</translation>
<translation id="7375818412732305729">En fil vedhæftes</translation>
@@ -1738,6 +1767,7 @@ Yderligere oplysninger:
<translation id="7976214039405368314">For mange anmodninger</translation>
<translation id="7977538094055660992">Outputenhed</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Installer ARCore for at se augmented reality-indhold</translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7995512525968007366">Ikke angivet</translation>
<translation id="800218591365569300">Prøv at lukke andre faner eller programmer for at frigøre hukommelse.</translation>
@@ -1865,25 +1895,39 @@ Yderligere oplysninger:
<translation id="8507227106804027148">Kommandolinje</translation>
<translation id="8508648098325802031">Søgeikon</translation>
<translation id="8522552481199248698">Chrome kan hjælpe dig med at beskytte din Google-konto og ændre din adgangskode.</translation>
+<translation id="8525306231823319788">Fuld skærm</translation>
<translation id="8530813470445476232">Ryd browserhistorik, cookies, cache m.m. i Chrome-indstillingerne</translation>
<translation id="8533619373899488139">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for at se listen over blokerede webadresser og andre politikker, der håndhæves af din systemadministrator.</translation>
<translation id="8541158209346794904">Bluetooth-enhed</translation>
<translation id="8542014550340843547">Trehæftning nederst</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportere et registreringsproblem<ph name="END_ERROR_LINK" /> eller, hvis du forstår den sikkerhedsrisiko, du udsætter dig for, <ph name="BEGIN_LINK" />kan du gå til dette usikre website<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Kontrolkoden findes på bagsiden af kortet.</translation>
+<translation id="8558485628462305855">Opdater ARCore for at se augmented reality-indhold</translation>
<translation id="8559762987265718583">Der kan ikke oprettes en privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, da tid og dato (<ph name="DATE_AND_TIME" />) på din enhed er forkerte.</translation>
<translation id="8564182942834072828">Individuelle dokumenter/ikke-samlede kopier</translation>
<translation id="8564985650692024650">Chromium anbefaler, at du nulstiller din adgangskode til <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, hvis du har brugt den på andre websites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivitet, der ikke gemmes på denne enhed:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />De sider, du besøger i dette vindue
+ <ph name="LIST_ITEM" />Cookies og websitedata
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Brug Touch ID for at bekræfte dine kort hurtigere</translation>
<translation id="858637041960032120">Tilføj tlf.nr.
</translation>
<translation id="8589998999637048520">Bedste kvalitet:</translation>
+<translation id="8600271352425265729">Kun denne gang</translation>
<translation id="860043288473659153">Kortholderens navn</translation>
<translation id="8606726445206553943">Brug dine MIDI-enheder</translation>
+<translation id="8612761427948161954">Hej <ph name="USERNAME" />
+ <ph name="BR" />
+ Du bruger enheden som gæst</translation>
<translation id="861775596732816396">Størrelse 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Der er ingen matchende adgangskoder. Se alle gemte adgangskoder.</translation>
<translation id="8625384913736129811">Gem dette kort på denne enhed</translation>
+<translation id="8627040765059109009">Screenshots er genoptaget</translation>
<translation id="8657078576661269990">Din administrator har blokeret deling fra <ph name="ORIGIN_NAME" /> til <ph name="VM_NAME_1" /> og <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Ordreoversigt, <ph name="TOTAL_LABEL" />, flere oplysninger</translation>
<translation id="867224526087042813">Underskrift</translation>
@@ -1946,6 +1990,7 @@ Yderligere oplysninger:
<translation id="8912362522468806198">Google-konto</translation>
<translation id="8913778647360618320">Knappen Administrer betalingsmetoder – tryk på Enter for at administrere oplysninger om dine betalinger og betalingskort i Chrome-indstillingerne</translation>
<translation id="8918231688545606538">Denne side er mistænkelig</translation>
+<translation id="8922013791253848639">Tillad altid annoncer på dette website</translation>
<translation id="892588693504540538">Hul øverst til højre</translation>
<translation id="8931333241327730545">Vil du gemme dette kort på din Google-konto?</translation>
<translation id="8932102934695377596">Dit ur er bagud</translation>
@@ -2017,6 +2062,7 @@ Yderligere oplysninger:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> anvender en ikke-understøttet protokol.</translation>
<translation id="9191834167571392248">Hul nederst til venstre</translation>
+<translation id="9199905725844810519">Udskrivning er blokeret</translation>
<translation id="9205078245616868884">Dine data er krypteret med din adgangssætning til synkronisering. Angiv den for at starte synkroniseringen.</translation>
<translation id="9207861905230894330">Artiklen kunne ikke tilføjes.</translation>
<translation id="9213433120051936369">Tilpas udseende</translation>
@@ -2027,8 +2073,10 @@ Yderligere oplysninger:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Du kan miste adgangen til din Google-konto. Chromium anbefaler, at du skifter din adgangskode nu. Du bliver bedt om at logge ind.</translation>
<translation id="939736085109172342">Ny mappe</translation>
+<translation id="945522503751344254">Send feedback</translation>
<translation id="945855313015696284">Se oplysningerne nedenfor, og slet eventuelle ugyldige kort</translation>
<translation id="950736567201356821">Tre huller øverst</translation>
+<translation id="951941430552851965">Dit screenshot blev sat på pause af din administrator på grund af indhold på din skærm.</translation>
<translation id="961663415146723894">Bind nederst</translation>
<translation id="962484866189421427">Dette indhold kan forsøge at installere vildledende apps, der foregiver at være noget andet, eller som indsamler data, der kan anvendes til at overvåge dig. <ph name="BEGIN_LINK" />Vis alligevel<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Officiel version</translation>
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index 9a6cfa04e6a..53161402313 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -80,6 +80,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Sie haben Ihr Passwort auf einer Website eingegeben, die nicht von Ihrer Organisation verwaltet wird. Zum Schutz Ihres Kontos sollten Sie das Passwort nicht für andere Apps und Websites verwenden.</translation>
<translation id="1263231323834454256">Leseliste</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivitäten, die nicht auf diesem Gerät gespeichert werden:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Seiten, die Sie in diesem Fenster besuchen
+ <ph name="LIST_ITEM" />Cookies und Websitedaten
+ <ph name="LIST_ITEM" />Kontoinformationen (<ph name="LINK_BEGIN" />Abmelden<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Abholoption</translation>
<translation id="1281476433249504884">Stapelfach 1</translation>
<translation id="1285320974508926690">Diese Website nie übersetzen</translation>
@@ -279,6 +287,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="204357726431741734">Anmelden, um die in Ihrem Google-Konto gespeicherten Passwörter zu verwenden</translation>
<translation id="2053111141626950936">Seiten auf <ph name="LANGUAGE" /> werden nicht übersetzt.</translation>
<translation id="2053553514270667976">Postleitzahl</translation>
+<translation id="2054665754582400095">Ihre Anwesenheit</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Vorschlag}other{# Vorschläge}}</translation>
<translation id="2079545284768500474">Rückgängig machen</translation>
<translation id="20817612488360358">Die System-Proxy-Einstellungen sind zur Verwendung angegeben, gleichzeitig wurde aber auch eine explizite Proxy-Konfiguration festgelegt.</translation>
@@ -292,6 +301,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2102495993840063010">Android-Apps</translation>
<translation id="2107021941795971877">Stützstrukturen für Druck</translation>
<translation id="2108755909498034140">Computer neu starten</translation>
+<translation id="2111166930115883695">Drücken Sie die Leertaste, um die Wiedergabe zu starten</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karte</translation>
<translation id="2114841414352855701">Wird ignoriert, da sie von <ph name="POLICY_NAME" /> außer Kraft gesetzt wurde.</translation>
@@ -303,6 +313,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="214556005048008348">Zahlung abbrechen</translation>
<translation id="2147827593068025794">Hintergrundsynchronisierung</translation>
<translation id="2148613324460538318">Karte hinzufügen</translation>
+<translation id="2149968176347646218">Verbindung ist nicht sicher</translation>
<translation id="2154054054215849342">Die Synchronisierung ist für Ihre Domain nicht verfügbar</translation>
<translation id="2154484045852737596">Karte bearbeiten</translation>
<translation id="2161656808144014275">Text</translation>
@@ -313,7 +324,6 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2181821976797666341">Richtlinien</translation>
<translation id="2183608646556468874">Telefonnummer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 Adresse}other{# Adressen}}</translation>
-<translation id="2187243482123994665">Anwesenheit des Nutzers</translation>
<translation id="2187317261103489799">Erkennen (Standardeinstellung)</translation>
<translation id="2188375229972301266">Mehrfache Lochung unten</translation>
<translation id="2202020181578195191">Geben Sie ein gültiges Ablaufjahr ein</translation>
@@ -464,6 +474,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2839501879576190149">Warnung: Gefälschte Website</translation>
<translation id="2850739647070081192">Invite (Umschlag)</translation>
<translation id="2856444702002559011">Hacker könnten versuchen, Ihre Daten von <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zu stehlen, zum Beispiel Passwörter, Nachrichten oder Kreditkartendaten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Diese Website zeigt aufdringliche oder irreführende Werbung an.</translation>
<translation id="2878197950673342043">Posterfaltung</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Fensterpositionierung</translation>
@@ -502,11 +513,11 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2996674880327704673">Vorschläge von Google</translation>
<translation id="3002501248619246229">Medien im Eingabefach prüfen</translation>
<translation id="3005723025932146533">Gespeicherte Kopie anzeigen</translation>
-<translation id="3007719053326478567">Ihr Administrator hat das Drucken dieses Inhalts blockiert</translation>
<translation id="3008447029300691911">Geben Sie den CVC für <ph name="CREDIT_CARD" /> ein. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="3010559122411665027">Listeneintrag "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatisch blockiert</translation>
<translation id="3016780570757425217">Ihren Standort abrufen</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um den Vorschlag zu entfernen.</translation>
<translation id="3023071826883856138">You4 (Umschlag)</translation>
<translation id="3024663005179499861">Falscher Richtlinientyp</translation>
<translation id="3037605927509011580">Oh nein!</translation>
@@ -549,6 +560,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3207960819495026254">Mit einem Lesezeichen versehen</translation>
<translation id="3209034400446768650">Auf der Seite wird möglicherweise Geld verlangt</translation>
<translation id="3212581601480735796">Ihre Aktivität auf <ph name="HOSTNAME" /> wird überwacht</translation>
+<translation id="3212623355668894776">Schließen Sie alle Gastfenster, um Ihre Browseraktivitäten von diesem Gerät zu löschen.</translation>
<translation id="3215092763954878852">WebAuthn konnte nicht verwendet werden</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3225919329040284222">Der Server hat ein Zertifikat übermittelt, das nicht mit den integrierten Erwartungen übereinstimmt. Diese Erwartungen sind zu Ihrem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten.</translation>
@@ -694,6 +706,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3784372983762739446">Bluetooth-Geräte</translation>
<translation id="3787705759683870569">Ablaufdatum: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Größe 16</translation>
+<translation id="3789841737615482174">Installieren</translation>
<translation id="3793574014653384240">Anzahl und Ursachen der kürzlich aufgetretenen Abstürze</translation>
<translation id="3797522431967816232">Prc3 (Umschlag)</translation>
<translation id="3799805948399000906">Gewünschte Schriftart</translation>
@@ -744,6 +757,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Schlüssel "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Umschlag)</translation>
+<translation id="4067669230157909013">Die Bildschirmaufnahme wurde fortgesetzt.</translation>
<translation id="4067947977115446013">Gültige Adresse hinzufügen</translation>
<translation id="4072486802667267160">Bei der Verarbeitung Ihrer Bestellung ist ein Fehler aufgetreten. Bitte versuchen Sie es noch einmal.</translation>
<translation id="4075732493274867456">Client und Server unterstützen keine gemeinsame SSL-Protokollversion oder Verschlüsselungssammlung.</translation>
@@ -824,6 +838,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4297502707443874121">Miniaturansicht für Seite <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Maximieren</translation>
<translation id="4300675098767811073">Mehrfache Lochung rechts</translation>
+<translation id="4302514097724775343">Tippen Sie auf den Dino, um die Wiedergabe zu starten</translation>
<translation id="4302965934281694568">Chou3 (Umschlag)</translation>
<translation id="4305666528087210886">Zugriff auf die Datei nicht möglich</translation>
<translation id="4305817255990598646">Wechseln</translation>
@@ -902,6 +917,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4658638640878098064">Heftklammer oben links</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual Reality</translation>
+<translation id="4675657451653251260">Im Gastmodus können Sie keine Informationen von Chrome-Profilen einsehen. Sie können <ph name="LINK_BEGIN" />sich anmelden<ph name="LINK_END" />, um auf Ihre Google-Kontoinformationen wie Passwörter und Zahlungsmethoden zuzugreifen.</translation>
<translation id="467662567472608290">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat enthält Fehler. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="4677585247300749148"><ph name="URL" /> möchte auf Bedienungshilfen reagieren</translation>
<translation id="467809019005607715">Google Präsentationen</translation>
@@ -922,13 +938,19 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="473775607612524610">Aktualisieren</translation>
<translation id="4738601419177586157">Suchvorschlag: <ph name="TEXT" /></translation>
<translation id="4742407542027196863">Passwörter verwalten…</translation>
-<translation id="4744603770635761495">Pfad zur ausführbaren Datei</translation>
+<translation id="4744603770635761495">Programmdateipfad</translation>
<translation id="4750917950439032686">Ihre Daten wie Passwörter oder Kreditkartennummern sind geschützt, wenn Sie sie an diese Website senden.</translation>
<translation id="4756388243121344051">&amp;Verlauf</translation>
<translation id="4758311279753947758">Kontaktdaten hinzufügen</translation>
<translation id="4761104368405085019">Mikrofon verwenden</translation>
<translation id="4764776831041365478">Die Webseite unter <ph name="URL" /> ist eventuell vorübergehend nicht verfügbar oder wurde dauerhaft an eine neue Webadresse verschoben.</translation>
<translation id="4766713847338118463">Zwei Heftklammern unten</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ihre Aktivitäten, die auf diesem Gerät gespeichert werden:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Alle Dateien, die Sie in diesem Fenster herunterladen
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ein unbekannter Fehler ist aufgetreten.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up blockiert}other{# Pop-ups blockiert}}</translation>
<translation id="4780366598804516005">Ablage 1</translation>
@@ -1091,11 +1113,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5386426401304769735">Die Zertifikatskette für diese Website enthält ein Zertifikat mit SHA-1-Signatur.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Mehrere Heftklammern rechts</translation>
+<translation id="5398772614898833570">Werbung blockiert</translation>
<translation id="5400836586163650660">Grau</translation>
<translation id="540969355065856584">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist zurzeit ungültig. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="541416427766103491">Stapelfach 4</translation>
<translation id="5421136146218899937">Browserdaten löschen...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> möchte Ihnen Benachrichtigungen senden</translation>
+<translation id="542872847390508405">Der Gastmodus ist aktiviert.</translation>
<translation id="5430298929874300616">Lesezeichen löschen</translation>
<translation id="5439770059721715174">Schemavalidierungsfehler in "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Umgekehrte Reihenfolge mit der Vorderseite nach oben</translation>
@@ -1137,12 +1161,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5571083550517324815">Diese Abholadresse wird nicht unterstützt. Bitte wählen Sie eine andere Adresse aus.</translation>
<translation id="5580958916614886209">Prüfen Sie Ihren Ablaufmonat und versuchen Sie es dann erneut</translation>
<translation id="5586446728396275693">Keine gespeicherten Adressen</translation>
+<translation id="5593349413089863479">Verbindung ist nicht uneingeschränkt sicher</translation>
<translation id="5595485650161345191">Adresse bearbeiten</translation>
<translation id="5598944008576757369">Zahlungsmethode auswählen</translation>
<translation id="560412284261940334">Verwaltung wird nicht unterstützt.</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Diese Website ist eventuell gefälscht oder betrügerisch. Sie sollten sie am besten verlassen.</translation>
<translation id="5610142619324316209">Verbindung prüfen</translation>
<translation id="5610807607761827392"><ph name="BEGIN_LINK" />Karten und Adressen können Sie in den Einstellungen verwalten.<ph name="END_LINK" /></translation>
<translation id="561165882404867731">Diese Seite mit Google Übersetzer übersetzen</translation>
@@ -1214,6 +1238,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5901630391730855834">Gelb</translation>
<translation id="5905445707201418379">Gemäß der Ursprungsrichtlinie von <ph name="ORIGIN" /> blockiert.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronisiert)</translation>
+<translation id="5913377024445952699">Bildschirmaufnahme pausiert</translation>
<translation id="59174027418879706">Aktiviert</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">An</translation>
@@ -1226,6 +1251,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5963413905009737549">Section-Element</translation>
<translation id="5967592137238574583">Kontaktdaten bearbeiten</translation>
<translation id="5967867314010545767">Aus Verlauf entfernen</translation>
+<translation id="5968793460449681917">Bei jedem Besuch</translation>
<translation id="5975083100439434680">Verkleinern</translation>
<translation id="5979084224081478209">Passwörter prüfen</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1381,6 +1407,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6587923378399804057">Von Ihnen kopierter Link</translation>
<translation id="6591833882275308647">Ihr <ph name="DEVICE_TYPE" /> wird nicht verwaltet</translation>
<translation id="6596325263575161958">Verschlüsselungsoptionen</translation>
+<translation id="6596892391065203054">Ihr Administrator hat das Drucken dieses Inhalts blockiert.</translation>
<translation id="6604181099783169992">Bewegungs- oder Lichtsensoren</translation>
<translation id="6609880536175561541">Prc7 (Umschlag)</translation>
<translation id="6612358246767739896">Geschützte Inhalte</translation>
@@ -1440,6 +1467,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6895330447102777224">Ihre Karte wurde bestätigt</translation>
<translation id="6897140037006041989">User-Agent</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">„<ph name="SITE_NAME" />“ Folgendes gestatten:</translation>
<translation id="6910240653697687763"><ph name="URL" /> fordert die vollständige Kontrolle über Ihre MIDI-Geräte</translation>
<translation id="6915804003454593391">Nutzer: </translation>
<translation id="6934672428414710184">Dieser Name stammt aus Ihrem Google-Konto</translation>
@@ -1551,6 +1579,7 @@ Weitere Details:
<translation id="7346048084945669753">Ist zugehörig:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Befehlszeile</translation>
+<translation id="7359588939039777303">Werbung blockiert.</translation>
<translation id="7372973238305370288">Suchergebnis</translation>
<translation id="7374733840632556089">Sie sehen diesen Fehler aufgrund eines Zertifikats, das auf Ihrem Gerät installiert ist. Chrome vertraut dem Zertifikat nicht, weil es Netzwerke unterbrechen und überwachen kann. Natürlich gibt es berechtigte Gründe für eine Überwachung, z. B. im Netzwerk von Schulen oder Unternehmen. Trotzdem soll sichergestellt werden, dass Sie über die Überwachung informiert sind, selbst wenn Sie sie nicht unterbinden können. Die Überwachung ist in jedem Browser und jeder Anwendung mit Webzugriff möglich.</translation>
<translation id="7375818412732305729">Datei angehängt</translation>
@@ -1725,6 +1754,7 @@ Weitere Details:
<translation id="7976214039405368314">Zu viele Anfragen</translation>
<translation id="7977538094055660992">Ausgabegerät</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ARCore installieren, um Augmented-Reality-Inhalte zu sehen</translation>
<translation id="799149739215780103">Binden</translation>
<translation id="7995512525968007366">Nicht angegeben</translation>
<translation id="800218591365569300">Versuchen Sie, andere Tabs oder Programme zu schließen, um Speicher freizugeben.</translation>
@@ -1852,25 +1882,39 @@ Weitere Details:
<translation id="8507227106804027148">Befehlszeile</translation>
<translation id="8508648098325802031">Symbol "Suche"</translation>
<translation id="8522552481199248698">Mithilfe von Chrome können Sie Ihr Google-Konto schützen und Ihr Passwort ändern.</translation>
+<translation id="8525306231823319788">Vollbildmodus</translation>
<translation id="8530813470445476232">In den Chrome-Einstellungen Browserverlauf, Cookies und mehr löschen sowie Cache leeren</translation>
<translation id="8533619373899488139">Unter &lt;strong&gt;chrome://policy&lt;/strong&gt; finden Sie eine Liste mit blockierten URLs und andere Richtlinien, die von Ihrem Systemadministrator festgelegt wurden.</translation>
<translation id="8541158209346794904">Bluetooth-Gerät</translation>
<translation id="8542014550340843547">Drei Heftklammern unten</translation>
<translation id="8543181531796978784">Sie können ein <ph name="BEGIN_ERROR_LINK" />Erkennungsproblem melden<ph name="END_ERROR_LINK" /> oder, wenn Sie die Sicherheitsrisiken kennen, <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Der CVC befindet sich auf der Rückseite Ihrer Karte.</translation>
+<translation id="8558485628462305855">ARCore aktualisieren, um Augmented-Reality-Inhalte zu sehen</translation>
<translation id="8559762987265718583">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit Ihres Geräts falsch sind (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Getrennte Dokumente/nicht sortierte Kopien</translation>
<translation id="8564985650692024650">Chromium empfiehlt, Ihr Passwort für <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivitäten, die nicht auf diesem Gerät gespeichert werden:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Seiten, die Sie in diesem Fenster besuchen
+ <ph name="LIST_ITEM" />Cookies und Websitedaten
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Touch ID verwenden, um Karten schneller zu bestätigen</translation>
<translation id="858637041960032120">Weitere Nummer
</translation>
<translation id="8589998999637048520">Beste Qualität</translation>
+<translation id="8600271352425265729">Nur dieses Mal</translation>
<translation id="860043288473659153">Name des Karteninhabers</translation>
<translation id="8606726445206553943">Ihre MIDI-Geräte verwenden</translation>
+<translation id="8612761427948161954">Hallo <ph name="USERNAME" />,
+ <ph name="BR" />
+ der Gastmodus ist aktiviert</translation>
<translation id="861775596732816396">Größe 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Keine übereinstimmenden Passwörter. Alle gespeicherten Passwörter anzeigen.</translation>
<translation id="8625384913736129811">Diese Karte für dieses Gerät speichern</translation>
+<translation id="8627040765059109009">Bildschirmaufnahme wurde fortgesetzt</translation>
<translation id="8657078576661269990">Ihr Administrator hat das Teilen von <ph name="ORIGIN_NAME" /> mit <ph name="VM_NAME_1" /> und <ph name="VM_NAME_2" /> blockiert</translation>
<translation id="8663226718884576429">Bestellübersicht, <ph name="TOTAL_LABEL" />, weitere Details</translation>
<translation id="867224526087042813">Signatur</translation>
@@ -1933,6 +1977,7 @@ Weitere Details:
<translation id="8912362522468806198">Google-Konto</translation>
<translation id="8913778647360618320">Schaltfläche "Zahlungsmethoden verwalten" – drücken Sie die Eingabetaste, um Zahlungen und Kreditkartendaten in den Chrome-Einstellungen zu verwalten</translation>
<translation id="8918231688545606538">Diese Seite ist verdächtig</translation>
+<translation id="8922013791253848639">Werbung auf dieser Website immer zulassen</translation>
<translation id="892588693504540538">Lochung oben rechts</translation>
<translation id="8931333241327730545">Möchten Sie diese Karte in Ihrem Google-Konto speichern?</translation>
<translation id="8932102934695377596">Ihre Uhr geht nach</translation>
@@ -2005,6 +2050,7 @@ Weitere Details:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> verwendet ein nicht unterstütztes Protokoll.</translation>
<translation id="9191834167571392248">Lochung unten links</translation>
+<translation id="9199905725844810519">Drucken ist blockiert</translation>
<translation id="9205078245616868884">Ihre Daten sind mit Ihrer Synchronisierungspassphrase verschlüsselt. Geben Sie diese ein, um die Synchronisierung zu starten.</translation>
<translation id="9207861905230894330">Der Artikel konnte nicht hinzugefügt werden.</translation>
<translation id="9213433120051936369">Layout anpassen</translation>
@@ -2015,8 +2061,10 @@ Weitere Details:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Sie könnten den Zugriff auf Ihr Google-Konto verlieren. Chromium empfiehlt Ihnen, Ihr Passwort jetzt zu ändern. Sie werden dazu aufgefordert, sich anzumelden.</translation>
<translation id="939736085109172342">Neuer Ordner</translation>
+<translation id="945522503751344254">Feedback geben</translation>
<translation id="945855313015696284">Lesen Sie sich die unten stehenden Informationen durch und löschen Sie ungültige Karten</translation>
<translation id="950736567201356821">Dreifache Lochung oben</translation>
+<translation id="951941430552851965">Die Bildschirmaufnahme wurde aufgrund von Inhalten auf Ihrem Bildschirm vom Administrator pausiert.</translation>
<translation id="961663415146723894">Bindung unten</translation>
<translation id="962484866189421427">Dieser Inhalt könnte betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten erfassen, um Sie auszuspionieren. <ph name="BEGIN_LINK" />Trotzdem zeigen<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Offizieller Build</translation>
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index 496d0d96d29..1c1d36ae1e8 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Έχετε εισαγάγει τον κωδικό Ï€Ïόσβασής σας σε έναν ιστότοπο τον οποίο δεν διαχειÏίζεται ο οÏγανισμός σας. Για να Ï€ÏοστατεÏσετε τον λογαÏιασμό σας, μην χÏησιμοποιήσετε ξανά αυτόν τον κωδικό Ï€Ïόσβασης σε άλλες εφαÏμογές και ιστοτόπους.</translation>
<translation id="1263231323834454256">Λίστα ανάγνωσης</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ΔÏαστηÏιότητα που δεν θα παÏαμένει σε αυτήν τη συσκευή:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Σελίδες που Ï€Ïοβάλετε σε αυτό το παÏάθυÏο
+ <ph name="LIST_ITEM" />Cookie και δεδομένα ιστοτόπου
+ <ph name="LIST_ITEM" />ΠληÏοφοÏίες λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï (<ph name="LINK_BEGIN" />αποσÏνδεση<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ΤÏόπος παÏαλαβής</translation>
<translation id="1281476433249504884">Μονάδα στοίβαξης 1</translation>
<translation id="1285320974508926690">Îα μην γίνεται ποτέ μετάφÏαση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… ιστότοπου</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Συνδεθείτε, για να χÏησιμοποιήσετε κωδικοÏÏ‚ Ï€Ïόσβασης που είναι αποθηκευμένοι στον ΛογαÏιασμό σας Google.</translation>
<translation id="2053111141626950936">Οι σελίδες στα <ph name="LANGUAGE" /> δεν θα μεταφÏάζονται.</translation>
<translation id="2053553514270667976">ΤαχυδÏομικός κώδικας</translation>
+<translation id="2054665754582400095">Η παÏουσία σας</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Ï€Ïόταση}other{# Ï€Ïοτάσεις}}</translation>
<translation id="2079545284768500474">ΑναίÏεση</translation>
<translation id="20817612488360358">Οι Ïυθμίσεις διακομιστή μεσολάβησης του συστήματος έχουν οÏιστεί για να χÏησιμοποιηθοÏν, αλλά καθοÏίζεται επίσης μια Ïητή διαμόÏφωση του διακομιστή μεσολάβησης.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">ΕφαÏμογές Android</translation>
<translation id="2107021941795971877">ΕκτÏπωση υποστηÏιγμάτων</translation>
<translation id="2108755909498034140">Επανεκκινήστε τον υπολογιστή σας</translation>
+<translation id="2111166930115883695">Πατήστε το πλήκτÏο διαστήματος για να παίξετε.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Παιχνίδια με κάÏτες</translation>
<translation id="2114841414352855701">Αγνοήθηκε επειδή αντικαταστάθηκε από την πολιτική <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">ΑκÏÏωση πληÏωμής</translation>
<translation id="2147827593068025794">ΣυγχÏ. παÏασκηνίου</translation>
<translation id="2148613324460538318">ΠÏοσθήκη κάÏτας</translation>
+<translation id="2149968176347646218">Η σÏνδεση δεν είναι ασφαλής.</translation>
<translation id="2154054054215849342">Ο συγχÏονισμός δεν είναι διαθέσιμος για τον τομέα σας</translation>
<translation id="2154484045852737596">ΕπεξεÏγασία κάÏτας</translation>
<translation id="2161656808144014275">Κείμενο</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Πολιτικές</translation>
<translation id="2183608646556468874">ΑÏιθμός τηλεφώνου</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 διεÏθυνση}other{# διευθÏνσεις}}</translation>
-<translation id="2187243482123994665">ΠαÏουσία χÏήστη</translation>
<translation id="2187317261103489799">Εντοπισμός (Ï€Ïοεπιλογή)</translation>
<translation id="2188375229972301266">Πολλαπλό Ï„ÏÏπημα στο κάτω μέÏος</translation>
<translation id="2202020181578195191">Εισαγάγετε ένα έγκυÏο έτος λήξης</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Ακολουθεί ψεÏτικος ιστότοπος</translation>
<translation id="2850739647070081192">Invite (Φάκελος)</translation>
<translation id="2856444702002559011">Οι εισβολείς ενδέχεται να Ï€Ïοσπαθήσουν να υποκλέψουν τα στοιχεία σας από τον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (για παÏάδειγμα, κωδικοÏÏ‚ Ï€Ïόσβασης, μηνÏματα ή πιστωτικές κάÏτες). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Αυτός ο ιστότοπος εμφανίζει παÏεμβατικές ή παÏαπλανητικές διαφημίσεις.</translation>
<translation id="2878197950673342043">Δίπλωση αφίσας</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Τοποθέτηση παÏαθÏÏου</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">ΠÏοτάσεις από Google</translation>
<translation id="3002501248619246229">Έλεγχος μέσων δίσκου εισαγωγής</translation>
<translation id="3005723025932146533">Εμφάνιση αποθηκευμένου αντιγÏάφου</translation>
-<translation id="3007719053326478567">Η εκτÏπωση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… πεÏιεχομένου έχει απαγοÏευτεί από τον διαχειÏιστή</translation>
<translation id="3008447029300691911">Εισαγάγετε τον κωδικό CVC για την πιστωτική κάÏτα <ph name="CREDIT_CARD" />. Μετά την επιβεβαίωση, θα κοινοποιηθοÏν τα στοιχεία της κάÏτας σας με αυτόν τον ιστότοπο.</translation>
<translation id="3010559122411665027">ΚαταχώÏιση λίστας "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Αποκλείστηκε αυτόματα</translation>
<translation id="3016780570757425217">ΠÏόσβαση στην τοποθεσία σας</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Πατήστε το πλήκτÏο Tab και μετά το πλήκτÏο Enter για να καταÏγήσετε την Ï€Ïόταση.</translation>
<translation id="3023071826883856138">You4 (Φάκελος)</translation>
<translation id="3024663005179499861">Λανθασμένος Ï„Ïπος πολιτικής</translation>
<translation id="3037605927509011580">Όπα! Κάτι πήγε στÏαβά!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">ΠÏοστέθηκε στους σελιδοδείκτες</translation>
<translation id="3209034400446768650">Η σελίδα ενδέχεται να σας χÏεώσει</translation>
<translation id="3212581601480735796">Η δÏαστηÏιότητά σας στο <ph name="HOSTNAME" /> παÏακολουθείται</translation>
+<translation id="3212623355668894776">Κλείστε όλα τα παÏάθυÏα πεÏιήγησης επισκέπτη, έτσι ώστε η δÏαστηÏιότητα πεÏιήγησής σας να διαγÏαφεί από αυτήν τη συσκευή.</translation>
<translation id="3215092763954878852">Δεν ήταν δυνατή η χÏήση του WebAuthn</translation>
<translation id="3218181027817787318">Σχετική</translation>
<translation id="3225919329040284222">Ο διακομιστής παÏουσίασε ένα πιστοποιητικό που δεν αντιστοιχεί στις ενσωματωμένες Ï€Ïοϋποθέσεις. Αυτές οι Ï€Ïοϋποθέσεις συμπεÏιλαμβάνονται σε συγκεκÏιμένους ιστότοπους υψηλής ασφάλειας για την Ï€Ïοστασία σας.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">Συσκευές Bluetooth</translation>
<translation id="3787705759683870569">Λήγει <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Μέγεθος 16</translation>
+<translation id="3789841737615482174">Εγκατάσταση</translation>
<translation id="3793574014653384240">ΑÏιθμοί και αιτίες των σφαλμάτων που παÏουσιάστηκαν Ï€Ïόσφατα</translation>
<translation id="3797522431967816232">Prc3 (Φάκελος)</translation>
<translation id="3799805948399000906">Ζητήθηκε γÏαμματοσειÏά</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">Σέπια</translation>
<translation id="4058922952496707368">Κλειδί "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Φάκελος)</translation>
+<translation id="4067669230157909013">H λήψη οθόνης ξεκίνησε ξανά.</translation>
<translation id="4067947977115446013">ΠÏοσθήκη έγκυÏης διεÏθυνσης</translation>
<translation id="4072486802667267160">ΠÏοέκυψε σφάλμα κατά την επεξεÏγασία της παÏαγγελίας σας. Δοκιμάστε ξανά.</translation>
<translation id="4075732493274867456">Η εφαÏμογή πελάτης και ο διακομιστής δεν υποστηÏίζουν κάποια κοινή έκδοση Ï€Ïωτοκόλλου SSL ή σουίτα κÏυπτογÏάφησης.</translation>
@@ -838,6 +852,7 @@
<translation id="4297502707443874121">ΜικÏογÏαφία για τη σελίδα <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Επέκταση</translation>
<translation id="4300675098767811073">Πολλαπλό Ï„ÏÏπημα στα δεξιά</translation>
+<translation id="4302514097724775343">Πατήστε τον δεινόσαυÏο για να παίξετε.</translation>
<translation id="4302965934281694568">Chou3 (Φάκελος)</translation>
<translation id="4305666528087210886">Δεν ήταν δυνατή η Ï€Ïόσβαση στο αÏχείο σας</translation>
<translation id="4305817255990598646">Εναλλαγή</translation>
@@ -916,6 +931,7 @@
<translation id="4658638640878098064">ΣυÏÏαφή επάνω αÏιστεÏά</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Εικονική Ï€Ïαγματικότητα</translation>
+<translation id="4675657451653251260">Δεν θα βλέπετε πληÏοφοÏίες Ï€Ïοφίλ Chrome στη λειτουÏγία επισκέπτη. ΜποÏείτε να <ph name="LINK_BEGIN" />συνδεθείτε<ph name="LINK_END" /> για να αποκτήσετε Ï€Ïόσβαση στις πληÏοφοÏίες του ΛογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ Google όπως κωδικοÏÏ‚ Ï€Ïόσβασης και Ï„Ïόπους πληÏωμής.</translation>
<translation id="467662567472608290">Ο διακομιστής δεν κατάφεÏε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του πεÏιέχει σφάλματα. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="4677585247300749148">Ο ιστότοπος <ph name="URL" /> επιθυμεί να απαντήσει σε συμβάντα Ï€Ïοσβασιμότητας</translation>
<translation id="467809019005607715">ΠαÏουσιάσεις Google</translation>
@@ -943,6 +959,12 @@
<translation id="4761104368405085019">ΧÏήση του μικÏοφώνου σας</translation>
<translation id="4764776831041365478">Η ιστοσελίδα στη διεÏθυνση <ph name="URL" /> μποÏεί να βÏίσκεται Ï€ÏοσωÏινά εκτός λειτουÏγίας ή ίσως έχει μεταφεÏθεί μόνιμα σε νέα διεÏθυνση ιστοÏ.</translation>
<translation id="4766713847338118463">Διπλή συÏÏαφή στο κάτω μέÏος</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Η δÏαστηÏιότητά σας που παÏαμένει σε αυτήν τη συσκευή:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Τυχόν αÏχεία που κατεβάζετε σε αυτό το παÏάθυÏο
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ΠαÏουσιάστηκε άγνωστο σφάλμα.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Το αναδυόμενο παÏάθυÏο αποκλ.}other{# αναδυόμενα παÏάθυÏα αποκλείστηκαν}}</translation>
<translation id="4780366598804516005">ΓÏαμματοκιβώτιο 1</translation>
@@ -1105,11 +1127,13 @@
<translation id="5386426401304769735">Η αλυσίδα Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î³Î¹Î± αυτόν τον ιστότοπο πεÏιέχει ένα πιστοποιητικό το οποίο είναι υπογεγÏαμμένο με χÏήση SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Ραφή στο δεξί άκÏο</translation>
+<translation id="5398772614898833570">Αποκλείστηκαν διαφημίσεις</translation>
<translation id="5400836586163650660">ΓκÏι</translation>
<translation id="540969355065856584">Αυτός ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν είναι έγκυÏο αυτήν τη στιγμή. Αυτό μποÏεί να οφείλεται σε εσφαλμένη ÏÏθμιση ή σε κάποιον εισβολέα που παÏεμβαίνει στη σÏνδεσή σας.</translation>
<translation id="541416427766103491">Μονάδα στοίβαξης 4</translation>
<translation id="5421136146218899937">ΔιαγÏαφή δεδομένων πεÏιήγησης...</translation>
<translation id="5426179911063097041">Η διεÏθυνση <ph name="SITE" /> θέλει να σας στείλει ειδοποιήσεις</translation>
+<translation id="542872847390508405">ΠÏαγματοποιείτε πεÏιήγηση ως Επισκέπτης</translation>
<translation id="5430298929874300616">ΚατάÏγηση σελιδοδείκτη</translation>
<translation id="5439770059721715174">Σφάλμα επαλήθευσης σχήματος σε "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ΑντίστÏοφη σειÏά με την Ï€Ïόσοψη Ï€Ïος τα επάνω</translation>
@@ -1151,12 +1175,12 @@
<translation id="5571083550517324815">Δεν είναι δυνατή η παÏαλαβή από αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
<translation id="5580958916614886209">Ελέγξτε τον μήνα λήξης σας και δοκιμάστε ξανά</translation>
<translation id="5586446728396275693">Δεν υπάÏχουν αποθηκευμένες διευθÏνσεις</translation>
+<translation id="5593349413089863479">Η σÏνδεση δεν είναι απολÏτως ασφαλής.</translation>
<translation id="5595485650161345191">ΕπεξεÏγασία διεÏθυνσης</translation>
<translation id="5598944008576757369">Επιλογή Ï„Ïόπου πληÏωμής</translation>
<translation id="560412284261940334">Η διαχείÏιση δεν υποστηÏίζεται</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Αυτός ο ιστότοπος μποÏεί να είναι ψεÏτικος ή μη νόμιμος. Το Chrome συνιστά να αποχωÏήσετε Ï„ÏŽÏα.</translation>
<translation id="5610142619324316209">Ελέγξτε τη σÏνδεση</translation>
<translation id="5610807607761827392">ΜποÏείτε να διαχειÏιστείτε τις κάÏτες και τις διευθÏνσεις στις <ph name="BEGIN_LINK" />Ρυθμίσεις<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">ΜεταφÏάστε αυτήν τη σελίδα με τη ΜετάφÏαση Google.</translation>
@@ -1228,6 +1252,7 @@
<translation id="5901630391730855834">ΚίτÏινο</translation>
<translation id="5905445707201418379">Αποκλείστηκε σÏμφωνα με την πολιτική Ï€Ïοέλευσης του <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (συγχÏονισμένο)</translation>
+<translation id="5913377024445952699">Η καταγÏαφή οθόνης τέθηκε σε παÏση</translation>
<translation id="59174027418879706">ΕνεÏγοποιημένο</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ΕνεÏγοποιημένο</translation>
@@ -1240,6 +1265,7 @@
<translation id="5963413905009737549">Ενότητα</translation>
<translation id="5967592137238574583">ΕπεξεÏγασία στοιχείων επικοινωνίας</translation>
<translation id="5967867314010545767">ΚατάÏγηση από το ιστοÏικό</translation>
+<translation id="5968793460449681917">Σε κάθε επίσκεψη</translation>
<translation id="5975083100439434680">ΣμίκÏυνση</translation>
<translation id="5979084224081478209">Έλεγχος κωδικών Ï€Ïόσβασης</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1395,6 +1421,7 @@
<translation id="6587923378399804057">ΣÏνδεσμος που αντιγÏάψατε</translation>
<translation id="6591833882275308647">Η συσκευή <ph name="DEVICE_TYPE" /> δεν είναι διαχειÏιζόμενη</translation>
<translation id="6596325263575161958">Επιλογές κÏυπτογÏάφησης</translation>
+<translation id="6596892391065203054">Η εκτÏπωση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… πεÏιεχομένου έχει αποκλειστεί από τον διαχειÏιστή.</translation>
<translation id="6604181099783169992">ΑισθητήÏες κίνησης ή φωτός</translation>
<translation id="6609880536175561541">Prc7 (Φάκελος)</translation>
<translation id="6612358246767739896">ΠÏοστατ. πεÏιεχ.</translation>
@@ -1454,6 +1481,7 @@
<translation id="6895330447102777224">Η κάÏτα σας επιβεβαιώθηκε</translation>
<translation id="6897140037006041989">ΠαÏάγοντας χÏήστη</translation>
<translation id="6898699227549475383">ΟÏγάνωση (O)</translation>
+<translation id="6907293445143367439">Îα επιτÏέπεται στον ιστότοπο <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763">Ο ιστότοπος <ph name="URL" /> επιθυμεί να αποκτήσει τον πλήÏη έλεγχο των συσκευών σας MIDI</translation>
<translation id="6915804003454593391">ΧÏήστης</translation>
<translation id="6934672428414710184">Αυτό το όνομα Ï€ÏοέÏχεται από τον ΛογαÏιασμό σας Google</translation>
@@ -1565,6 +1593,7 @@
<translation id="7346048084945669753">Είναι συνδεδεμένος:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">ΓÏαμμή εντολών</translation>
+<translation id="7359588939039777303">Αποκλείστηκαν διαφημίσεις.</translation>
<translation id="7372973238305370288">αποτέλεσμα αναζήτησης</translation>
<translation id="7374733840632556089">Αυτό το Ï€Ïόβλημα οφείλεται σε ένα πιστοποιητικό που εσείς ή κάποιος άλλος εγκατέστησε στη συσκευή σας. Το πιστοποιητικό είναι γνωστό ότι χÏησιμοποιείται για την παÏακολοÏθηση και την υποκλοπή δικτÏων και δεν θεωÏείται αξιόπιστο από το Chrome. Αν και υπάÏχουν οÏισμένες νόμιμες πεÏιπτώσεις παÏακολοÏθησης, όπως σε ένα σχολικό ή εταιÏικό δίκτυο, το Chrome θέλει να σιγουÏευτεί πως γνωÏίζετε ότι συμβαίνει, ακόμη και αν δεν μποÏείτε να τη σταματήσετε. Η παÏακολοÏθηση μποÏεί να γίνει σε οποιοδήποτε Ï€ÏόγÏαμμα πεÏιήγησης ή εφαÏμογή που έχει Ï€Ïόσβαση στον ιστό.</translation>
<translation id="7375818412732305729">Έχει επισυναφθεί αÏχείο</translation>
@@ -1739,6 +1768,7 @@
<translation id="7976214039405368314">ΠάÏα πολλά αιτήματα</translation>
<translation id="7977538094055660992">Συσκευή εξόδου</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Για να δείτε πεÏιεχόμενο επαυξημένης Ï€Ïαγματικότητας, εγκαταστήστε το ARCore</translation>
<translation id="799149739215780103">Δέσιμο</translation>
<translation id="7995512525968007366">Δεν καθοÏίστηκε</translation>
<translation id="800218591365569300">Δοκιμάστε να κλείσετε τις άλλες καÏτέλες ή τα άλλα Ï€ÏογÏάμματα για να απελευθεÏώσετε μνήμη.</translation>
@@ -1866,25 +1896,39 @@
<translation id="8507227106804027148">ΓÏαμμή εντολών</translation>
<translation id="8508648098325802031">Εικονίδιο αναζήτησης</translation>
<translation id="8522552481199248698">Το Chrome μποÏεί να σας βοηθήσει να Ï€ÏοστατεÏσετε τον ΛογαÏιασμό σας Google και να αλλάξετε τον κωδικό Ï€Ïόσβασής σας.</translation>
+<translation id="8525306231823319788">ΠλήÏης οθόνη</translation>
<translation id="8530813470445476232">ΔιαγÏάψτε το ιστοÏικό πεÏιήγησης, τα cookie, την κÏυφή μνήμη και άλλα στοιχεία στις Ïυθμίσεις του Chrome.</translation>
<translation id="8533619373899488139">Μεταβείτε στη διεÏθυνση &lt;strong&gt;chrome://policy&lt;/strong&gt; για να δείτε τη λίστα των αποκλεισμένων URL και άλλες πολιτικές που έχουν τεθεί σε εφαÏμογή από τον διαχειÏιστή του συστήματός σας.</translation>
<translation id="8541158209346794904">Συσκευή Bluetooth</translation>
<translation id="8542014550340843547">ΤÏιπλή συÏÏαφή στο κάτω μέÏος</translation>
<translation id="8543181531796978784">ΜποÏείτε να <ph name="BEGIN_ERROR_LINK" />αναφέÏετε ένα Ï€Ïόβλημα εντοπισμοÏ<ph name="END_ERROR_LINK" /> ή, εάν κατανοείτε τους κινδÏνους ασφαλείας, να <ph name="BEGIN_LINK" />επισκεφτείτε αυτόν τον μη ασφαλή ιστότοπο<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Ο κωδικός CVC βÏίσκεται στο πίσω μέÏος της κάÏτας.</translation>
+<translation id="8558485628462305855">Για να δείτε πεÏιεχόμενο επαυξημένης Ï€Ïαγματικότητας, ενημεÏώστε το ARCore</translation>
<translation id="8559762987265718583">Δεν είναι δυνατή η επίτευξη ιδιωτικής σÏνδεσης με τον τομέα <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημεÏομηνία και η ÏŽÏα (<ph name="DATE_AND_TIME" />) της συσκευής σας είναι λανθασμένες.</translation>
<translation id="8564182942834072828">ΞεχωÏιστά έγγÏαφα/ΑντίγÏαφα χωÏίς συÏÏαφή</translation>
<translation id="8564985650692024650">Το Chromium συνιστά την επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, εάν τον έχετε χÏησιμοποιήσει και σε άλλους ιστοτόπους.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ΔÏαστηÏιότητα που δεν θα παÏαμένει σε αυτήν τη συσκευή:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Σελίδες που Ï€Ïοβάλετε σε αυτό το παÏάθυÏο
+ <ph name="LIST_ITEM" />Cookie και δεδομένα ιστοτόπου
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ΧÏησιμοποιήστε το Touch ID για πιο γÏήγοÏη επιβεβαίωση καÏτών</translation>
<translation id="858637041960032120">ΠÏοσθ. τηλεφ.
</translation>
<translation id="8589998999637048520">Βέλτιστη ποιότητα</translation>
+<translation id="8600271352425265729">Μόνο αυτήν τη φοÏά</translation>
<translation id="860043288473659153">Όνομα κατόχου κάÏτας</translation>
<translation id="8606726445206553943">ΧÏήση των συσκευών σας MIDI</translation>
+<translation id="8612761427948161954">Γεια σας <ph name="USERNAME" />,
+ <ph name="BR" />
+ ΠÏαγματοποιείτε πεÏιήγηση ως Επισκέπτης</translation>
<translation id="861775596732816396">Μέγεθος 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Δεν αντιστοιχοÏν κωδικοί Ï€Ïόσβασης. Εμφάνιση όλων των αποθηκευμένων κωδικών Ï€Ïόσβασης.</translation>
<translation id="8625384913736129811">Αποθήκευση αυτής της κάÏτας στη συγκεκÏιμένη συσκευή</translation>
+<translation id="8627040765059109009">Η καταγÏαφή οθόνης συνεχίζεται</translation>
<translation id="8657078576661269990">Ο διαχειÏιστής έχει αποκλείσει την κοινοποίηση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… πεÏιεχομένου από <ph name="ORIGIN_NAME" /> σε <ph name="VM_NAME_1" /> και <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">ΣÏνοψη παÏαγγελίας, <ph name="TOTAL_LABEL" />, ΠεÏισσότεÏες λεπτομέÏειες</translation>
<translation id="867224526087042813">ΥπογÏαφή</translation>
@@ -1947,6 +1991,7 @@
<translation id="8912362522468806198">ΛογαÏιασμός Google</translation>
<translation id="8913778647360618320">Κουμπί διαχείÏισης Ï„Ïόπων πληÏωμής, πατήστε Enter για να διαχειÏιστείτε τα στοιχεία πληÏωμών και πιστωτικών καÏτών στις Ïυθμίσεις του Chrome.</translation>
<translation id="8918231688545606538">Αυτή η σελίδα είναι Ïποπτη.</translation>
+<translation id="8922013791253848639">Îα επιτÏέπονται πάντα οι διαφημίσεις σε αυτόν τον ιστότοπο</translation>
<translation id="892588693504540538">ΤÏÏπημα επάνω δεξιά</translation>
<translation id="8931333241327730545">Θέλετε να αποθηκεÏσετε αυτήν την κάÏτα στο ΛογαÏιασμό σας Google;</translation>
<translation id="8932102934695377596">Το Ïολόι σας πάει πίσω</translation>
@@ -2018,6 +2063,7 @@
<translation id="9183302530794969518">ΈγγÏαφα Google</translation>
<translation id="9183425211371246419">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> χÏησιμοποιεί μη υποστηÏιζόμενο Ï€Ïωτόκολλο.</translation>
<translation id="9191834167571392248">ΤÏÏπημα κάτω αÏιστεÏά</translation>
+<translation id="9199905725844810519">Η εκτÏπωση αποκλείστηκε</translation>
<translation id="9205078245616868884">Τα δεδομένα σας είναι κÏυπτογÏαφημένα με τη δική σας φÏάση Ï€Ïόσβασης συγχÏονισμοÏ. ΠληκτÏολογήστε την για να ξεκινήσει ο συγχÏονισμός.</translation>
<translation id="9207861905230894330">Αποτυχία Ï€Ïοσθήκης άÏθÏου.</translation>
<translation id="9213433120051936369">ΠÏοσαÏμογή της εμφάνισης</translation>
@@ -2028,8 +2074,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">ΜποÏεί να χάσετε την Ï€Ïόσβαση στον ΛογαÏιασμό σας Google. Το Chromium συνιστά να αλλάξετε τον κωδικό Ï€Ïόσβασής σας Ï„ÏŽÏα. Θα σας ζητηθεί να συνδεθείτε.</translation>
<translation id="939736085109172342">Îέος φάκελος</translation>
+<translation id="945522503751344254">Αποστολή σχολίων</translation>
<translation id="945855313015696284">Ελέγξτε τις πληÏοφοÏίες παÏακάτω και διαγÏάψτε τυχόν μη έγκυÏες κάÏτες</translation>
<translation id="950736567201356821">ΤÏιπλό Ï„ÏÏπημα στο επάνω μέÏος</translation>
+<translation id="951941430552851965">Έγινε παÏση της λήψης οθόνης από τον διαχειÏιστή σας λόγω του πεÏιεχομένου που εμφανίζεται στην οθόνη.</translation>
<translation id="961663415146723894">Δέσιμο στο κάτω μέÏος</translation>
<translation id="962484866189421427">Αυτό το πεÏιεχόμενο μποÏεί να επιχειÏήσει να εγκαταστήσει παÏαπλανητικές εφαÏμογές που Ï€ÏοσποιοÏνται ότι είναι κάτι άλλο ή συλλέγουν δεδομένα τα οποία μποÏεί να χÏησιμοποιηθοÏν για την παÏακολοÏθησή σας. <ph name="BEGIN_LINK" />Îα εμφανίζεται οÏτως ή άλλως<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Επίσημη έκδοση</translation>
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index 32118bb6344..6a31dafecf8 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -17,7 +17,7 @@
<translation id="1041998700806130099">Job sheet message</translation>
<translation id="1048785276086539861">When you edit annotations, this document will return to single-page view</translation>
<translation id="1050038467049342496">Close other apps</translation>
-<translation id="1055184225775184556">&amp;Undo Add</translation>
+<translation id="1055184225775184556">&amp;Undo add</translation>
<translation id="1056898198331236512">Warning</translation>
<translation id="1058479211578257048">Saving cards...</translation>
<translation id="10614374240317010">Never saved</translation>
@@ -29,7 +29,7 @@
<translation id="1080116354587839789">Fit to width</translation>
<translation id="1086953900555227778">Index-5x8</translation>
<translation id="1088860948719068836">Add Name on Card</translation>
-<translation id="1089439967362294234">Change Password</translation>
+<translation id="1089439967362294234">Change password</translation>
<translation id="1096545575934602868">This field should not have more than <ph name="MAX_ITEMS_LIMIT" /> entries. All further entries will be discarded.</translation>
<translation id="1101672080107056897">Error action</translation>
<translation id="1103523840287552314">Always translate <ph name="LANGUAGE" /></translation>
@@ -80,6 +80,14 @@ This will otherwise be blocked by your privacy settings. This will allow the con
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">You entered your password on a site that’s not managed by your organisation. To protect your account, don’t reuse your password on other apps and sites.</translation>
<translation id="1263231323834454256">Reading list</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Activity that won't stay on this device:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pages that you view in this window
+ <ph name="LIST_ITEM" />Cookies and site data
+ <ph name="LIST_ITEM" />Account information (<ph name="LINK_BEGIN" />sign out<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Pickup Method</translation>
<translation id="1281476433249504884">Stacker 1</translation>
<translation id="1285320974508926690">Never translate this site</translation>
@@ -88,13 +96,13 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="129553762522093515">Recently closed</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />Try clearing your cookies<ph name="END_LINK" /></translation>
<translation id="1301324364792935241">Check your secure DNS settings</translation>
-<translation id="1307966114820526988">Deprecated Features</translation>
+<translation id="1307966114820526988">Deprecated features</translation>
<translation id="131405271941274527"><ph name="URL" /> wants to send and receive info when you tap your phone on an NFC device</translation>
<translation id="1314509827145471431">Bind right</translation>
<translation id="1320233736580025032">Prc1 (Envelope)</translation>
<translation id="132301787627749051">Search for clipboard image</translation>
<translation id="1323433172918577554">Show More</translation>
-<translation id="132390688737681464">Save and Fill Addresses</translation>
+<translation id="132390688737681464">Save and fill addresses</translation>
<translation id="1330449323196174374">Left gate fold</translation>
<translation id="1333989956347591814">Your activity <ph name="BEGIN_EMPHASIS" />might still be visible<ph name="END_EMPHASIS" /> to:
<ph name="BEGIN_LIST" />
@@ -115,7 +123,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1374692235857187091">Index-4x6 (Postcard)</translation>
<translation id="1375198122581997741">About Version</translation>
<translation id="1376836354785490390">Show Less</translation>
-<translation id="1377321085342047638">Card Number</translation>
+<translation id="1377321085342047638">Card number</translation>
<translation id="1380591466760231819">Letter fold</translation>
<translation id="138218114945450791">Light blue</translation>
<translation id="1382194467192730611">USB device allowed by your administrator</translation>
@@ -234,7 +242,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1798447301915465742"><ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT" />, multiple actions are available; press 'Tab' to cycle through them</translation>
<translation id="1800473098294731951">B9</translation>
-<translation id="1803264062614276815">Cardholder Name</translation>
+<translation id="1803264062614276815">Cardholder name</translation>
<translation id="1807246157184219062">Light</translation>
<translation id="1807528111851433570">Start sheet</translation>
<translation id="1821930232296380041">Invalid request or request parameters</translation>
@@ -282,6 +290,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="204357726431741734">Sign in to use passwords saved in your Google Account</translation>
<translation id="2053111141626950936">Pages in <ph name="LANGUAGE" /> will not be translated.</translation>
<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2054665754582400095">Your presence</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}other{# suggestions}}</translation>
<translation id="2079545284768500474">Undo</translation>
<translation id="20817612488360358">System proxy settings are set to be used but an explicit proxy configuration is also specified.</translation>
@@ -295,6 +304,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2102495993840063010">Android apps</translation>
<translation id="2107021941795971877">Print supports</translation>
<translation id="2108755909498034140">Restart your computer</translation>
+<translation id="2111166930115883695">Press space to play</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Ignored because it was overridden by <ph name="POLICY_NAME" />.</translation>
@@ -302,10 +312,11 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2119867082804433120">Punch bottom right</translation>
<translation id="2129079103035905234">Motion Sensors</translation>
<translation id="2130448033692577677">The templates that you've specified may not be applied due to the DnsOverHttpsMode policy not being set.</translation>
-<translation id="213826338245044447">Mobile Bookmarks</translation>
+<translation id="213826338245044447">Mobile bookmarks</translation>
<translation id="214556005048008348">Cancel payment</translation>
<translation id="2147827593068025794">Background Sync</translation>
<translation id="2148613324460538318">Add Card</translation>
+<translation id="2149968176347646218">Connection is not secure</translation>
<translation id="2154054054215849342">Sync is not available for your domain</translation>
<translation id="2154484045852737596">Edit card</translation>
<translation id="2161656808144014275">Text</translation>
@@ -316,7 +327,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2181821976797666341">Policies</translation>
<translation id="2183608646556468874">Phone Number</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}other{# addresses}}</translation>
-<translation id="2187243482123994665">User presence</translation>
<translation id="2187317261103489799">Detect (default)</translation>
<translation id="2188375229972301266">Multiple punch bottom</translation>
<translation id="2202020181578195191">Enter a valid expiry year</translation>
@@ -378,7 +388,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2465402087343596252">Architecture-E</translation>
<translation id="2465655957518002998">Choose delivery method</translation>
<translation id="2465688316154986572">Staple</translation>
-<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Running Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Running network diagnostics<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N order</translation>
<translation id="2470767536994572628">When you edit annotations, this document will return to single-page view and its original rotation</translation>
<translation id="2479410451996844060">Invalid search URL.</translation>
@@ -390,7 +400,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2495093607237746763">If ticked, Chromium will store a copy of your card on this device for faster form filling.</translation>
<translation id="2498091847651709837">Scan new card</translation>
<translation id="2501278716633472235">Go back</translation>
-<translation id="2505268675989099013">Protect Account</translation>
+<translation id="2505268675989099013">Protect account</translation>
<translation id="2515629240566999685">Checking the signal in your area</translation>
<translation id="2521385132275182522">Staple bottom right</translation>
<translation id="2523886232349826891">Saved on this device only</translation>
@@ -469,6 +479,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2839501879576190149">Fake site ahead</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Attackers might be trying to steal your information from <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (for example, passwords, messages or credit cards). <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">This site shows intrusive or misleading ads.</translation>
<translation id="2878197950673342043">Poster fold</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Window placement</translation>
@@ -483,7 +494,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2916038427272391327">Close other programmes</translation>
<translation id="2922350208395188000">Server's certificate cannot be checked.</translation>
<translation id="2925673989565098301">Delivery Method</translation>
-<translation id="2928905813689894207">Billing Address</translation>
+<translation id="2928905813689894207">Billing address</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}}</translation>
<translation id="2930577230479659665">Trim after each copy</translation>
<translation id="2932085390869194046">Suggest password...</translation>
@@ -507,11 +518,11 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2996674880327704673">Suggestions by Google</translation>
<translation id="3002501248619246229">Check input tray media</translation>
<translation id="3005723025932146533">Show saved copy</translation>
-<translation id="3007719053326478567">Printing of this content is blocked by your administrator</translation>
<translation id="3008447029300691911">Enter the CVC for <ph name="CREDIT_CARD" />. Once you confirm, your card details will be shared with this site.</translation>
<translation id="3010559122411665027">List entry "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatically blocked</translation>
<translation id="3016780570757425217">Know your location</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, press tab then enter to remove suggestion.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Wrong policy type</translation>
<translation id="3037605927509011580">Aw, Snap!</translation>
@@ -554,6 +565,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3207960819495026254">Bookmarked</translation>
<translation id="3209034400446768650">Page may charge money</translation>
<translation id="3212581601480735796">Your activity on <ph name="HOSTNAME" /> is being monitored</translation>
+<translation id="3212623355668894776">Close all guest windows so that your browsing activity is deleted from this device.</translation>
<translation id="3215092763954878852">Couldn't use WebAuthn</translation>
<translation id="3218181027817787318">Relative</translation>
<translation id="3225919329040284222">The server presented a certificate that doesn't match built-in expectations. These expectations are included for certain, high-security websites in order to protect you.</translation>
@@ -593,7 +605,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3387261909427947069">Payment Methods</translation>
<translation id="3391030046425686457">Delivery address</translation>
<translation id="3395827396354264108">Pickup method</translation>
-<translation id="3399952811970034796">Delivery Address</translation>
+<translation id="3399952811970034796">Delivery address</translation>
<translation id="3402261774528610252">The connection used to load this site used TLS 1.0 or TLS 1.1, which are deprecated and will be disabled in the future. Once disabled, users will be prevented from loading this site. The server should enable TLS 1.2 or later.</translation>
<translation id="3411120537985775570">Pasting from <ph name="ORIGIN_NAME" /> to this location is blocked by your administrator</translation>
<translation id="3414952576877147120">Size:</translation>
@@ -654,7 +666,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="361438452008624280">List entry '<ph name="LANGUAGE_ID" />': unknown or unsupported language.</translation>
<translation id="3615877443314183785">Enter a valid expiry date</translation>
<translation id="36224234498066874">Clear Browsing Data...</translation>
-<translation id="362276910939193118">Show Full History</translation>
+<translation id="362276910939193118">Show full history</translation>
<translation id="3630155396527302611">If it is already listed as a program allowed to access the network, try
removing it from the list and adding it again.</translation>
<translation id="3630699740441428070">Administrators of this device have configured your network connection, which may allow them to see your network traffic, including which websites that you visit.</translation>
@@ -701,6 +713,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3784372983762739446">Bluetooth devices</translation>
<translation id="3787705759683870569">Expires <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Size 16</translation>
+<translation id="3789841737615482174">Install</translation>
<translation id="3793574014653384240">Numbers and causes of the crashes that occurred recently</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Font requested</translation>
@@ -752,6 +765,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Screen capture was resumed.</translation>
<translation id="4067947977115446013">Add Valid Address</translation>
<translation id="4072486802667267160">There was an error processing your order. Please try again.</translation>
<translation id="4075732493274867456">The client and server don't support a common SSL protocol version or cipher suite.</translation>
@@ -836,6 +850,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4297502707443874121">Thumbnail for page <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expand</translation>
<translation id="4300675098767811073">Multiple punch right</translation>
+<translation id="4302514097724775343">Tap the dino to play</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Your file couldn’t be accessed</translation>
<translation id="4305817255990598646">Switch</translation>
@@ -914,6 +929,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4658638640878098064">Staple top left</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reality</translation>
+<translation id="4675657451653251260">In guest mode, you won't see any Chrome profile information. You can <ph name="LINK_BEGIN" />sign in<ph name="LINK_END" /> to access your Google Account info like passwords and payment methods.</translation>
<translation id="467662567472608290">This server could not prove that it is <ph name="DOMAIN" />; its security certificate contains errors. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="4677585247300749148"><ph name="URL" /> wants to respond to accessibility events</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -941,6 +957,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4761104368405085019">Use your microphone</translation>
<translation id="4764776831041365478">The web page at <ph name="URL" /> might be temporarily down or it may have moved permanently to a new web address.</translation>
<translation id="4766713847338118463">Dual staple bottom</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Your activity that stays on this device:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Any files that you download in this window
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">An unknown error has occurred.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up blocked}other{# pop-ups blocked}}</translation>
<translation id="4780366598804516005">Mailbox 1</translation>
@@ -995,7 +1017,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4989809363548539747">This plug-in is not supported</translation>
<translation id="4995216769782533993">Confirm the security code to share your card details with this site</translation>
<translation id="5002932099480077015">If enabled, Chrome will store a copy of your card on this device for faster form filling.</translation>
-<translation id="5015510746216210676">Machine Name:</translation>
+<translation id="5015510746216210676">Machine name:</translation>
<translation id="5017554619425969104">Text that you copied</translation>
<translation id="5018422839182700155">Can't open this page</translation>
<translation id="5019198164206649151">Backing store in bad state</translation>
@@ -1091,7 +1113,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5324080437450482387">Choose contact info</translation>
<translation id="5327248766486351172">Name</translation>
<translation id="5329858041417644019">Your browser is not managed</translation>
-<translation id="5332219387342487447">Delivery Method</translation>
+<translation id="5332219387342487447">Delivery method</translation>
<translation id="5334013548165032829">Detailed system logs</translation>
<translation id="5340250774223869109">Application is blocked</translation>
<translation id="534295439873310000">NFC devices</translation>
@@ -1103,11 +1125,13 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5386426401304769735">The certificate chain for this site contains a certificate signed using SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Edge stitch right</translation>
+<translation id="5398772614898833570">Ads blocked</translation>
<translation id="5400836586163650660">Grey</translation>
<translation id="540969355065856584">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not valid at this time. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="541416427766103491">Stacker 4</translation>
<translation id="5421136146218899937">Clear browsing data...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> wants to send you notifications</translation>
+<translation id="542872847390508405">You’re browsing as a Guest</translation>
<translation id="5430298929874300616">Remove bookmark</translation>
<translation id="5439770059721715174">Schema validation error at "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Reverse order face up</translation>
@@ -1149,12 +1173,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5571083550517324815">Can’t pick up from this address. Select a different address.</translation>
<translation id="5580958916614886209">Check your expiry month and try again</translation>
<translation id="5586446728396275693">No saved addresses</translation>
+<translation id="5593349413089863479">Connection is not fully secure</translation>
<translation id="5595485650161345191">Edit address</translation>
<translation id="5598944008576757369">Choose payment method</translation>
<translation id="560412284261940334">Management not supported</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">This site could be fake or fraudulent. Chrome recommends leaving now.</translation>
<translation id="5610142619324316209">Checking the connection</translation>
<translation id="5610807607761827392">You can manage cards and addresses in <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Translate this page with Google Translate</translation>
@@ -1226,6 +1250,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5901630391730855834">Yellow</translation>
<translation id="5905445707201418379">Blocked according to <ph name="ORIGIN" />'s origin policy.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synced)</translation>
+<translation id="5913377024445952699">Screen capture paused</translation>
<translation id="59174027418879706">Enabled</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">On</translation>
@@ -1238,6 +1263,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5963413905009737549">Section</translation>
<translation id="5967592137238574583">Edit Contact Info</translation>
<translation id="5967867314010545767">Remove from history</translation>
+<translation id="5968793460449681917">On every visit</translation>
<translation id="5975083100439434680">Zoom out</translation>
<translation id="5979084224081478209">Check passwords</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6587923378399804057">Link that you copied</translation>
<translation id="6591833882275308647">Your <ph name="DEVICE_TYPE" /> is not managed</translation>
<translation id="6596325263575161958">Encryption options</translation>
+<translation id="6596892391065203054">Printing of this content is blocked by your administrator.</translation>
<translation id="6604181099783169992">Motion or light sensors</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Protected content</translation>
@@ -1450,8 +1477,9 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6888584790432772780">Chrome simplified this page to make it easier to read. Chrome retrieved the original page over an insecure connection.</translation>
<translation id="6891596781022320156">Policy level is not supported.</translation>
<translation id="6895330447102777224">Your card is confirmed</translation>
-<translation id="6897140037006041989">User Agent</translation>
+<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">Allow <ph name="SITE_NAME" /> to:</translation>
<translation id="6910240653697687763"><ph name="URL" /> wants to get full control of your MIDI devices</translation>
<translation id="6915804003454593391">User:</translation>
<translation id="6934672428414710184">This name is from your Google Account</translation>
@@ -1534,7 +1562,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="7221855153210829124">Show notifications</translation>
<translation id="7229659723041939809">You just entered your password on a deceptive site. Chrome recommends checking your saved passwords for <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> and other sites where you use this password now.</translation>
<translation id="7233592378249864828">Print confirmation sheet</translation>
-<translation id="7238585580608191973">SHA-256 Fingerprint</translation>
+<translation id="7238585580608191973">SHA-256 fingerprint</translation>
<translation id="7240120331469437312">Certificate Subject Alternative Name</translation>
<translation id="7243010569062352439"><ph name="PASSWORDS" />; <ph name="SIGNIN_DATA" /></translation>
<translation id="724691107663265825">The site ahead contains malware</translation>
@@ -1552,7 +1580,7 @@ Additional details:
<translation id="7304030187361489308">High</translation>
<translation id="7313965965371928911"><ph name="BEGIN_LINK" />Safe Browsing<ph name="END_LINK" /> warnings</translation>
<translation id="7319430975418800333">A3</translation>
-<translation id="7320336641823683070">Connection Help</translation>
+<translation id="7320336641823683070">Connection help</translation>
<translation id="7323804146520582233">Hide the '<ph name="SECTION" />' section</translation>
<translation id="733354035281974745">Device local account override</translation>
<translation id="7333654844024768166">You just entered your password on a deceptive site. Chromium recommends going to <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> and other sites where you use this password and changing it now.</translation>
@@ -1563,6 +1591,7 @@ Additional details:
<translation id="7346048084945669753">Is affiliated:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Command Line</translation>
+<translation id="7359588939039777303">Ads blocked.</translation>
<translation id="7372973238305370288">search result</translation>
<translation id="7374733840632556089">This problem happens because of a certificate that you or someone else installed on your device. The certificate is known to be used to monitor and intercept networks, and is not trusted by Chrome. While some legitimate cases for monitoring do exist, like on a school or company network, Chrome wants to make sure that you're aware it's happening, even if you can't stop it. Monitoring may happen in any browser or application that accesses the web.</translation>
<translation id="7375818412732305729">File is attached</translation>
@@ -1737,6 +1766,7 @@ Additional details:
<translation id="7976214039405368314">Too many requests</translation>
<translation id="7977538094055660992">Output device</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">To view augmented reality content, install ARCore</translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7995512525968007366">Not Specified</translation>
<translation id="800218591365569300">Try closing other tabs or programmes to free up memory.</translation>
@@ -1801,7 +1831,7 @@ Additional details:
<translation id="8249296373107784235">Abort</translation>
<translation id="8249320324621329438">Last fetched:</translation>
<translation id="8253091569723639551">Billing address required</translation>
-<translation id="825929999321470778">Show All Saved Passwords</translation>
+<translation id="825929999321470778">Show all saved passwords</translation>
<translation id="8261506727792406068">Delete</translation>
<translation id="8262952874573525464">Edge stitch bottom</translation>
<translation id="8265992338205884890">Visible data</translation>
@@ -1864,24 +1894,38 @@ Additional details:
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Search icon</translation>
<translation id="8522552481199248698">Chrome can help you protect your Google account and change your password.</translation>
+<translation id="8525306231823319788">Full screen</translation>
<translation id="8530813470445476232">Clear your browsing history, cookies, cache and more in Chrome settings</translation>
<translation id="8533619373899488139">Visit &lt;strong&gt;chrome://policy&lt;/strong&gt; to see the list of blocked URLs and other policies enforced by your system administrator.</translation>
<translation id="8541158209346794904">Bluetooth device</translation>
<translation id="8542014550340843547">Triple staple bottom</translation>
<translation id="8543181531796978784">You can <ph name="BEGIN_ERROR_LINK" />report a detection problem<ph name="END_ERROR_LINK" /> or, if you understand the risks to your security, <ph name="BEGIN_LINK" />visit this unsafe site<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">The CVC is located behind your card.</translation>
+<translation id="8558485628462305855">To view augmented reality content, update ARCore</translation>
<translation id="8559762987265718583">A private connection to <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> can't be established because your device's date and time (<ph name="DATE_AND_TIME" />) are incorrect.</translation>
<translation id="8564182942834072828">Separate documents/Uncollated copies</translation>
<translation id="8564985650692024650">Chromium recommends resetting your <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> password if you reused it on other sites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Activity that won't stay on this device:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pages that you view in this window
+ <ph name="LIST_ITEM" />Cookies and site data
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Use Touch ID to confirm cards faster</translation>
<translation id="858637041960032120">Add phone no.</translation>
<translation id="8589998999637048520">Best quality</translation>
+<translation id="8600271352425265729">Only this time</translation>
<translation id="860043288473659153">Cardholder name</translation>
<translation id="8606726445206553943">Use your MIDI devices</translation>
+<translation id="8612761427948161954">Hi <ph name="USERNAME" />,
+ <ph name="BR" />
+ You’re browsing as a guest</translation>
<translation id="861775596732816396">Size 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">No matching passwords. Show all saved passwords.</translation>
<translation id="8625384913736129811">Save This Card to This Device</translation>
+<translation id="8627040765059109009">Screen capture resumed</translation>
<translation id="8657078576661269990">Your administrator has blocked sharing from <ph name="ORIGIN_NAME" /> to <ph name="VM_NAME_1" /> and <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Order Summary, <ph name="TOTAL_LABEL" />, More Details</translation>
<translation id="867224526087042813">Signature</translation>
@@ -1944,10 +1988,11 @@ Additional details:
<translation id="8912362522468806198">Google Account</translation>
<translation id="8913778647360618320">Manage payment methods button; press enter to manage your payments and credit card info in Chrome settings</translation>
<translation id="8918231688545606538">This page is suspicious</translation>
+<translation id="8922013791253848639">Always allow ads on this site</translation>
<translation id="892588693504540538">Punch top right</translation>
<translation id="8931333241327730545">Do you want to save this card to your Google Account?</translation>
<translation id="8932102934695377596">Your clock is behind</translation>
-<translation id="893332455753468063">Add Name</translation>
+<translation id="893332455753468063">Add name</translation>
<translation id="8942355029279167844">Your administrator has allowed <ph name="APP_NAME" /> to collect diagnostics data to improve the product experience. See <ph name="BEGIN_LINK" />https://www.parallels.com/pcep<ph name="END_LINK" /> for more information.</translation>
<translation id="8943282376843390568">Lime</translation>
<translation id="8957210676456822347">Captive Portal Authorisation</translation>
@@ -2015,6 +2060,7 @@ Additional details:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> uses an unsupported protocol.</translation>
<translation id="9191834167571392248">Punch bottom left</translation>
+<translation id="9199905725844810519">Printing is blocked</translation>
<translation id="9205078245616868884">Your data is encrypted with your sync passphrase. Enter it to start sync.</translation>
<translation id="9207861905230894330">Failed to add article.</translation>
<translation id="9213433120051936369">Customise appearance</translation>
@@ -2025,8 +2071,10 @@ Additional details:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">You could lose access to your Google Account. Chromium recommends changing your password now. You'll be asked to sign in.</translation>
<translation id="939736085109172342">New folder</translation>
+<translation id="945522503751344254">Send feedback</translation>
<translation id="945855313015696284">Check the info below and delete any invalid cards</translation>
<translation id="950736567201356821">Triple punch top</translation>
+<translation id="951941430552851965">Screen capture was paused by your administrator due to content on your screen.</translation>
<translation id="961663415146723894">Bind bottom</translation>
<translation id="962484866189421427">This content might try to install deceptive apps that pretend to be something else or collect data that may be used to track you. <ph name="BEGIN_LINK" />Show anyway<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Official Build</translation>
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index 11d2e92efb0..1b4c4555ad9 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -80,6 +80,14 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ingresaste tu contraseña en un sitio que no administra tu organización. Para proteger tu cuenta, no vuelvas a usar tu contraseña en otras apps y sitios.</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ La actividad que no permanecerá en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Las páginas que ves en esta ventana
+ <ph name="LIST_ITEM" />Las cookies ni los datos del sitio
+ <ph name="LIST_ITEM" />Información de la cuenta (<ph name="LINK_BEGIN" />salir<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Método de retiro</translation>
<translation id="1281476433249504884">Apilador 1</translation>
<translation id="1285320974508926690">Nunca traducir este sitio</translation>
@@ -279,6 +287,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="204357726431741734">Accede a tu Cuenta de Google para usar las contraseñas guardadas allí</translation>
<translation id="2053111141626950936">No se traducirán las páginas en <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Código Postal</translation>
+<translation id="2054665754582400095">Tu presencia</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 sugerencia}other{# sugerencias}}</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="20817612488360358">Se ha establecido la configuración de proxy del sistema, pero también se ha especificado una configuración explícita de proxy.</translation>
@@ -292,6 +301,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2102495993840063010">Apps de Android</translation>
<translation id="2107021941795971877">Compatibilidades de la impresora</translation>
<translation id="2108755909498034140">Reinicia la computadora.</translation>
+<translation id="2111166930115883695">Presiona la barra espaciadora para jugar</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Tarjeta</translation>
<translation id="2114841414352855701">Se ignoró porque fue anulada por <ph name="POLICY_NAME" /> .</translation>
@@ -303,6 +313,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
<translation id="2148613324460538318">Agregar tarjeta</translation>
+<translation id="2149968176347646218">La conexión no es segura</translation>
<translation id="2154054054215849342">El servicio de sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
<translation id="2161656808144014275">Texto</translation>
@@ -313,7 +324,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">Número de teléfono</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 dirección}other{# direcciones}}</translation>
-<translation id="2187243482123994665">Presencia del usuario</translation>
<translation id="2187317261103489799">Detectar (predeterminado)</translation>
<translation id="2188375229972301266">Perforaciones múltiples en la parte inferior</translation>
<translation id="2202020181578195191">Ingresa un año de vencimiento válido</translation>
@@ -464,6 +474,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2839501879576190149">El sitio al que quieres acceder es falso</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Es posible que algunos atacantes intenten robar tu información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (p. ej., contraseñas, mensajes o tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Este sitio muestra anuncios intrusivos o engañosos.</translation>
<translation id="2878197950673342043">Plegado de póster</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ubicación de ventanas</translation>
@@ -502,11 +513,11 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2996674880327704673">Sugerencias de Google</translation>
<translation id="3002501248619246229">Revisar el medio en la bandeja de entrada</translation>
<translation id="3005723025932146533">Mostrar copia guardada</translation>
-<translation id="3007719053326478567">Tu administrador no permite imprimir este contenido</translation>
<translation id="3008447029300691911">Ingresa el CVC de la tarjeta <ph name="CREDIT_CARD" />. Después de confirmarla, los datos de tu tarjeta se compartirán con este sitio.</translation>
<translation id="3010559122411665027">Entrada de lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueado de forma automática</translation>
<translation id="3016780570757425217">Determinar tu ubicación</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, presiona Tab y, luego, Intro para quitar la sugerencia.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Tipo de política incorrecto</translation>
<translation id="3037605927509011580">¡Oh, no!</translation>
@@ -550,6 +561,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3207960819495026254">Agregada a favoritos</translation>
<translation id="3209034400446768650">La página puede cobrar cargos</translation>
<translation id="3212581601480735796">Se supervisa tu actividad en <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Cierra todas las ventanas de invitado para que se borre tu actividad de navegación de este dispositivo.</translation>
<translation id="3215092763954878852">No se pudo usar WebAuthn</translation>
<translation id="3218181027817787318">Relativo</translation>
<translation id="3225919329040284222">El servidor mostró un certificado que no coincide con lo esperado. Estas expectativas se incluyen en determinados sitios web con un alto nivel de seguridad para garantizar tu protección.</translation>
@@ -697,6 +709,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3784372983762739446">Dispositivos Bluetooth</translation>
<translation id="3787705759683870569">Vencimiento: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamaño 16</translation>
+<translation id="3789841737615482174">Instalar</translation>
<translation id="3793574014653384240">Cantidad de errores que se produjeron recientemente y sus causas</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Se necesita la fuente</translation>
@@ -747,6 +760,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Se reanudó la captura de pantalla.</translation>
<translation id="4067947977115446013">Agregar una dirección válida</translation>
<translation id="4072486802667267160">Se produjo un error al procesar tu pedido. Vuelve a intentarlo.</translation>
<translation id="4075732493274867456">El cliente y el servidor no admiten un conjunto de cifrado o una versión de protocolo SSL en común.</translation>
@@ -790,7 +804,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="421066178035138955">Usar datos y dispositivos de realidad virtual</translation>
<translation id="4214357935346142455">perfil de la pantalla de acceso</translation>
<translation id="4215751373031079683">7x9 (Envelope)</translation>
-<translation id="4220128509585149162">Fallos</translation>
+<translation id="4220128509585149162">Fallas</translation>
<translation id="422022731706691852">Es posible que los atacantes en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten engañarte para que instales programas que dañen tu experiencia de navegación (p. ej., al cambiar la página principal o mostrar anuncios adicionales en los sitios que visitas). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;Paso 1: Accede al portal&lt;/h4&gt;
&lt;p&gt;Para acceder a las redes Wi‑Fi de sitios como cafeterías o aeropuertos, tienes que ingresar. Para ver la página de acceso, visita una página con &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;
@@ -827,6 +841,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4297502707443874121">Miniatura para la página <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expandir</translation>
<translation id="4300675098767811073">Perforaciones múltiples a la derecha</translation>
+<translation id="4302514097724775343">Presiona el dinosaurio para jugar</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">No se pudo acceder a tu archivo</translation>
<translation id="4305817255990598646">Cambiar</translation>
@@ -905,6 +920,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4658638640878098064">Grapa en la esquina superior izquierda</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realidad virtual</translation>
+<translation id="4675657451653251260">En el modo de invitado, no verás información de perfil de Chrome. Puedes <ph name="LINK_BEGIN" />acceder<ph name="LINK_END" /> para ingresar a la información de tu Cuenta de Google, como contraseñas y formas de pago.</translation>
<translation id="467662567472608290">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad contiene errores. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="4677585247300749148"><ph name="URL" /> desea responder a los eventos de accesibilidad</translation>
<translation id="467809019005607715">Presentaciones de Google</translation>
@@ -932,6 +948,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4761104368405085019">Usar tu micrófono</translation>
<translation id="4764776831041365478">Es posible que la página web en <ph name="URL" /> no funcione temporalmente o se haya trasladado de manera permanente a una nueva dirección web.</translation>
<translation id="4766713847338118463">Grapas dobles en la parte inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ La actividad que permanecerá en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Los archivos que descargues en esta ventana
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Se bloqueó una ventana emergente}other{Se bloquearon # vent. emergentes}}</translation>
<translation id="4780366598804516005">Buzón 1</translation>
@@ -1094,11 +1116,13 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5386426401304769735">La cadena del certificado de este sitio web contiene un certificado que se firmó con SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Costura de borde a la derecha</translation>
+<translation id="5398772614898833570">Anuncios bloqueados</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Este servidor no pudo demostrar que se trata de <ph name="DOMAIN" />; el certificado de seguridad no es válido en este momento. Esto puede deberse a una configuración incorrecta o a un ataque que intercepta tu conexión.</translation>
<translation id="541416427766103491">Apilador 4</translation>
<translation id="5421136146218899937">Borrar datos de navegación...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> quiere enviarte notificaciones</translation>
+<translation id="542872847390508405">Estás navegando como invitado</translation>
<translation id="5430298929874300616">Eliminar marcador</translation>
<translation id="5439770059721715174">Error de validación de esquema en "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Orden inverso hacia arriba</translation>
@@ -1140,12 +1164,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5571083550517324815">No se puede retirar el artículo en esta dirección. Selecciona una diferente.</translation>
<translation id="5580958916614886209">Comprueba el mes de vencimiento y vuelve a intentarlo</translation>
<translation id="5586446728396275693">No hay direcciones guardadas</translation>
+<translation id="5593349413089863479">La conexión no es totalmente segura</translation>
<translation id="5595485650161345191">Editar dirección</translation>
<translation id="5598944008576757369">Seleccionar forma de pago</translation>
<translation id="560412284261940334">No se admite la administración.</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Este sitio podría ser falso o fraudulento. Chrome te recomienda que salgas de él ahora.</translation>
<translation id="5610142619324316209">Comprobar la conexión.</translation>
<translation id="5610807607761827392">Puedes administrar tarjetas y direcciones en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduce esta página con Google Traductor</translation>
@@ -1217,6 +1241,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5901630391730855834">Amarillo</translation>
<translation id="5905445707201418379">Se bloqueó conforme a la política de origen de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
+<translation id="5913377024445952699">Se pausó la captura de pantalla</translation>
<translation id="59174027418879706">Habilitado</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Sí</translation>
@@ -1229,6 +1254,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5963413905009737549">Sección</translation>
<translation id="5967592137238574583">Editar la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
+<translation id="5968793460449681917">En cada visita</translation>
<translation id="5975083100439434680">Alejar</translation>
<translation id="5979084224081478209">Revisar contraseñas</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1384,6 +1410,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6587923378399804057">Vínculo que copiaste</translation>
<translation id="6591833882275308647">Tu <ph name="DEVICE_TYPE" /> no está administrado.</translation>
<translation id="6596325263575161958">Opciones de encriptación</translation>
+<translation id="6596892391065203054">Tu administrador no permite imprimir este contenido.</translation>
<translation id="6604181099783169992">Sensores de luz o movimiento</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Contenido protegido</translation>
@@ -1441,8 +1468,9 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6888584790432772780">Chrome simplificó esta página para facilitar la lectura. Chrome recuperó la página original a través de una conexión no segura.</translation>
<translation id="6891596781022320156">No se admite el nivel de políticas.</translation>
<translation id="6895330447102777224">Tu tarjeta se confirmó</translation>
-<translation id="6897140037006041989">User agent</translation>
+<translation id="6897140037006041989">Usuario-agente</translation>
<translation id="6898699227549475383">Organización (O)</translation>
+<translation id="6907293445143367439">Permitir a <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> desea obtener el control total de tus dispositivos MIDI</translation>
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6934672428414710184">Este nombre es de tu Cuenta de Google</translation>
@@ -1554,6 +1582,7 @@ Detalles adicionales:
<translation id="7346048084945669753">Se afilió:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Línea de comandos</translation>
+<translation id="7359588939039777303">Se bloquearon anuncios.</translation>
<translation id="7372973238305370288">resultado de búsqueda</translation>
<translation id="7374733840632556089">Se produjo este problema debido a un certificado que tú o alguien más instaló en el dispositivo. El certificado se usa para interceptar y supervisar redes, y no es de confianza para Chrome. Si bien existen usos legítimos de la supervisión, como en el caso de redes de empresas o instituciones educativas, Chrome quiere asegurarse de que estás al tanto de esta situación, aunque no puedas impedirlo. La supervisión puede ocurrir en cualquier navegador o app que acceda a la Web.</translation>
<translation id="7375818412732305729">Se adjuntó un archivo</translation>
@@ -1728,13 +1757,14 @@ Detalles adicionales:
<translation id="7976214039405368314">Demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de salida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Para ver contenido de realidad aumentada, instala ARCore</translation>
<translation id="799149739215780103">Encuadernado</translation>
<translation id="7995512525968007366">Sin especificar</translation>
<translation id="800218591365569300">Prueba cerrar las demás pestañas o programas para liberar memoria.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Se guardará esta tarjeta y su dirección de facturación. Podrás usarla cuando accedas a <ph name="USER_EMAIL" />.}other{Se guardarán estas tarjetas y sus direcciones de facturación. Podrás usarlas cuando accedas a <ph name="USER_EMAIL" />.}}</translation>
<translation id="8025119109950072390">Es posible que los atacantes de este sitio te engañen para que hagas algo peligroso, como instalar software o divulgar información personal (p. ej., contraseñas, números de teléfono o tarjetas de crédito).</translation>
-<translation id="8026334261755873520">Eliminar datos de navegación</translation>
+<translation id="8026334261755873520">Borrar datos de navegación</translation>
<translation id="8028960012888758725">Cortar al finalizar el trabajo</translation>
<translation id="8034522405403831421">Esta página está en <ph name="SOURCE_LANGUAGE" />. ¿Quieres traducirla al <ph name="TARGET_LANGUAGE" />?</translation>
<translation id="8035152190676905274">Lápiz</translation>
@@ -1828,7 +1858,7 @@ Detalles adicionales:
<translation id="8371889962595521444">Certificados raíz personalizados</translation>
<translation id="8380941800586852976">Peligrosa</translation>
<translation id="8381674639488873545">Estos cargos pueden ser únicos o recurrentes, y es posible que no sean evidentes. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
-<translation id="8412145213513410671">Bloqueos (<ph name="CRASH_COUNT" />)</translation>
+<translation id="8412145213513410671">Fallas (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Debes ingresar la misma frase de contraseña dos veces.</translation>
<translation id="8416694386774425977">La configuración de red no es válida y no se pudo importar.
Detalles adicionales:
@@ -1855,25 +1885,39 @@ Detalles adicionales:
<translation id="8507227106804027148">Línea de comandos</translation>
<translation id="8508648098325802031">Ãcono de Búsqueda</translation>
<translation id="8522552481199248698">Chrome puede ayudarte a proteger tu Cuenta de Google y cambiar tu contraseña.</translation>
+<translation id="8525306231823319788">Pantalla completa</translation>
<translation id="8530813470445476232">Borra el historial de navegación, las cookies, la memoria caché y mucho más en la configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URL bloqueadas y otras políticas que estableció el administrador del sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Grapas triples en la parte inferior</translation>
<translation id="8543181531796978784">Puedes <ph name="BEGIN_ERROR_LINK" />informar un problema de detección<ph name="END_ERROR_LINK" /> o, si comprendes los riesgos de seguridad, puedes <ph name="BEGIN_LINK" />visitar el sitio no seguro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">El CVC se encuentra al dorso de tu tarjeta.</translation>
+<translation id="8558485628462305855">Para ver contenido de realidad aumentada, actualiza ARCore</translation>
<translation id="8559762987265718583">No se puede establecer una conexión privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora del dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.</translation>
<translation id="8564182942834072828">Documentos separados/copias sin intercalar</translation>
<translation id="8564985650692024650">Chromium te recomienda que restablezcas la contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la volviste a usar en otros sitios.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ La actividad que no permanecerá en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Las páginas que ves en esta ventana
+ <ph name="LIST_ITEM" />Las cookies ni los datos del sitio
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Usa Touch ID para confirmar las tarjetas más rápido</translation>
<translation id="858637041960032120">Agregar teléfono
</translation>
<translation id="8589998999637048520">Mejor calidad</translation>
+<translation id="8600271352425265729">Solo esta vez</translation>
<translation id="860043288473659153">Nombre del titular de la tarjeta</translation>
<translation id="8606726445206553943">Usar tus dispositivos MIDI</translation>
+<translation id="8612761427948161954">Hola <ph name="USERNAME" />:
+ <ph name="BR" />
+ Estás navegando como invitado</translation>
<translation id="861775596732816396">Tamaño 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">No se encontró una contraseña para este sitio. Mostrar todas las contraseñas guardadas.</translation>
<translation id="8625384913736129811">Guardar esta tarjeta para este dispositivo</translation>
+<translation id="8627040765059109009">Se reanudó la captura de pantalla</translation>
<translation id="8657078576661269990">Tu administrador no permite que <ph name="ORIGIN_NAME" /> comparta contenido con <ph name="VM_NAME_1" /> y <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Resumen del pedido, <ph name="TOTAL_LABEL" />, Más detalles</translation>
<translation id="867224526087042813">Firma</translation>
@@ -1936,6 +1980,7 @@ Detalles adicionales:
<translation id="8912362522468806198">Cuenta de Google</translation>
<translation id="8913778647360618320">Botón Administrar formas de pago: presiona Intro para administrar tus datos de pago y de tarjetas de crédito en la configuración de Chrome</translation>
<translation id="8918231688545606538">Esta página es sospechosa</translation>
+<translation id="8922013791253848639">Permite mostrar anuncios en este sitio</translation>
<translation id="892588693504540538">Perforación en la esquina superior derecha</translation>
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">El reloj está atrasado</translation>
@@ -2007,6 +2052,7 @@ Detalles adicionales:
<translation id="9183302530794969518">Documentos de Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utiliza un protocolo no compatible.</translation>
<translation id="9191834167571392248">Perforación en la esquina inferior izquierda</translation>
+<translation id="9199905725844810519">No se permite imprimir este contenido</translation>
<translation id="9205078245616868884">Tus datos están encriptados con tu frase de contraseña para sincronización. Debes ingresarla para iniciar la sincronización.</translation>
<translation id="9207861905230894330">Error al agregar artículo</translation>
<translation id="9213433120051936369">Personalizar el aspecto</translation>
@@ -2017,8 +2063,10 @@ Detalles adicionales:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Podrías perder el acceso a tu Cuenta de Google. Chromium te recomienda cambiar la contraseña ahora. Deberás acceder a la cuenta.</translation>
<translation id="939736085109172342">Nueva carpeta</translation>
+<translation id="945522503751344254">Enviar comentarios</translation>
<translation id="945855313015696284">Comprueba la información que se muestra a continuación y borra las tarjetas que no sean válidas</translation>
<translation id="950736567201356821">Perforación triple en la parte superior</translation>
+<translation id="951941430552851965">El administrador pausó la captura de pantalla debido al contenido que se muestra en ella.</translation>
<translation id="961663415146723894">Encuadernado en la parte inferior</translation>
<translation id="962484866189421427">Este contenido podría intentar instalar apps engañosas que se hagan pasar por otro tipo de contenido o que recopilen datos que se usen para rastrearte. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Build oficial</translation>
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index dbf5e0ffdeb..0ce4c6d80fe 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -8,7 +8,7 @@
<translation id="1019413721762100891">Desactivado</translation>
<translation id="1021110881106174305">Tarjetas aceptadas</translation>
<translation id="1021753677514347426">Este problema se debe a un certificado que tú u otra persona habéis instalado en el dispositivo. Chromium no confía en este certificado porque hay constancia de que se utiliza para interceptar y vigilar redes. En algunos casos, dicha vigilancia es legítima (por ejemplo, en las redes de centros educativos o empresas), pero Chrome quiere asegurarse de que estás al corriente de ello, aunque no puedas evitarlo. La vigilancia puede afectar a todos los navegadores y las aplicaciones que accedan a Internet.</translation>
-<translation id="1024111578869940408">A veces, los atacantes imitan otros sitios web haciendo cambios en la dirección web que son difíciles de ver.</translation>
+<translation id="1024111578869940408">A veces, los atacantes imitan otros sitios haciendo cambios en la dirección web que son difíciles de ver.</translation>
<translation id="1030706264415084469"><ph name="URL" /> quiere almacenar datos de gran tamaño de forma permanente en tu dispositivo</translation>
<translation id="1032854598605920125">Girar hacia la derecha</translation>
<translation id="1036348656032585052">Desactivar</translation>
@@ -48,7 +48,7 @@
<translation id="1161325031994447685">Volver a conectarte a una red Wi-Fi</translation>
<translation id="1165039591588034296">Error</translation>
<translation id="1165174597379888365">Se visita una página</translation>
-<translation id="1174723505405632867">¿Quieres permitir que <ph name="EMBEDDED_URL" /> use cookies y datos de sitios web en <ph name="TOP_LEVEL_URL" />?
+<translation id="1174723505405632867">¿Quieres permitir que <ph name="EMBEDDED_URL" /> use cookies y datos de sitios en <ph name="TOP_LEVEL_URL" />?
De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el contenido con el que interactúes funcione correctamente, pero se concederá permiso a <ph name="EMBEDDED_URL" /> para que pueda monitorizar tu actividad.</translation>
<translation id="1175364870820465910">Im&amp;primir...</translation>
@@ -56,7 +56,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Quitar</translation>
<translation id="1186201132766001848">Comprobar contraseñas</translation>
-<translation id="1195558154361252544">Las notificaciones se bloquean automáticamente en todos los sitios web, excepto en los que las permitas.</translation>
+<translation id="1195558154361252544">Las notificaciones se bloquean automáticamente en todos los sitios, excepto en los que las permitas.</translation>
<translation id="1197088940767939838">Naranja</translation>
<translation id="1201402288615127009">Siguiente</translation>
<translation id="1201895884277373915">Más entradas de este sitio</translation>
@@ -78,8 +78,16 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
&lt;li&gt;Comprueba que tu conexión a Internet funcione con normalidad.&lt;/li&gt;
&lt;li&gt;Ponte en contacto con el propietario del sitio web.&lt;/li&gt;
&lt;/ol&gt;</translation>
-<translation id="1257286744552378071">Has introducido tu contraseña en un sitio web que no está gestionado por tu organización. Para proteger tu cuenta, no vuelvas a utilizar tu contraseña en otras aplicaciones ni en otros sitios web.</translation>
+<translation id="1257286744552378071">Has introducido tu contraseña en un sitio web que no está gestionado por tu organización. Para proteger tu cuenta, no vuelvas a utilizar tu contraseña en otras aplicaciones ni en otros sitios.</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Actividad que no se guardará en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas que veas en esta ventana
+ <ph name="LIST_ITEM" />Cookies y datos de sitios
+ <ph name="LIST_ITEM" />Información de la cuenta (<ph name="LINK_BEGIN" />cerrar sesión<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Método de recogida</translation>
<translation id="1281476433249504884">Apilador 1</translation>
<translation id="1285320974508926690">No traducir nunca este sitio</translation>
@@ -153,7 +161,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1527263332363067270">Esperando conexión…</translation>
<translation id="1529521330346880926">10x15 (sobre)</translation>
<translation id="1529789484829130889">Bandeja 8</translation>
-<translation id="1530707389502320859">El sitio web al que estás intentando acceder parece falso. Los atacantes suelen imitar los sitios web haciendo pequeños cambios en la URL que son difíciles de ver.</translation>
+<translation id="1530707389502320859">El sitio web al que estás intentando acceder parece falso. Los atacantes suelen imitar los sitios haciendo pequeños cambios en la URL que son difíciles de ver.</translation>
<translation id="1531205177818805254">Exec</translation>
<translation id="1532118530259321453">Esta página dice</translation>
<translation id="153384715582417236">Eso es todo por ahora</translation>
@@ -227,7 +235,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1772163372082567643">El servidor al que te diriges (<ph name="ORIGIN" />) ha establecido un encabezado
que requiere aplicar una política de origen a todas las solicitudes que reciba. Sin embargo,
el encabezado tiene errores, lo que impide al navegador procesar
- tu solicitud de ir a <ph name="SITE" />. Los operadores de sitios web
+ tu solicitud de ir a <ph name="SITE" />. Los operadores de sitios
pueden usar las políticas de origen para configurar la seguridad y otras propiedades de un sitio web.</translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronización.</translation>
@@ -261,7 +269,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1917876262703816781">Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña ha quedado expuesta. Chrome recomienda que cambies tu contraseña de <ph name="ORIGIN" /> ahora.</translation>
<translation id="1919345977826869612">Anuncios</translation>
<translation id="1919367280705858090">Solucionar un error específico</translation>
-<translation id="192020519938775529">{COUNT,plural, =0{Ninguno}=1{1 sitio web}other{# sitios web}}</translation>
+<translation id="192020519938775529">{COUNT,plural, =0{Ninguno}=1{1 sitio web}other{# sitios}}</translation>
<translation id="1945968466830820669">Podrías perder el acceso a la cuenta de tu organización o tener problemas de suplantación de identidad. Chromium te recomienda que cambies tu contraseña ahora.</translation>
<translation id="1947454675006758438">Grapado en la parte superior derecha</translation>
<translation id="1959001866257244765">Ayuda a mejorar la seguridad de todos en la Web enviando a Google las <ph name="BEGIN_WHITEPAPER_LINK" />URL de algunas de las páginas que visites, información limitada del sistema y parte del contenido de las páginas<ph name="END_WHITEPAPER_LINK" />. <ph name="BEGIN_PRIVACY_PAGE_LINK" />Política de Privacidad<ph name="END_PRIVACY_PAGE_LINK" /></translation>
@@ -283,6 +291,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="204357726431741734">Inicia sesión para poder usar las contraseñas guardadas en tu cuenta de Google</translation>
<translation id="2053111141626950936">No se traducirán las páginas en <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Código postal</translation>
+<translation id="2054665754582400095">Tu presencia</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{Una sugerencia}other{# sugerencias}}</translation>
<translation id="2079545284768500474">Deshacer</translation>
<translation id="20817612488360358">Se ha establecido la configuración del proxy del sistema, pero también se han especificado ajustes de proxy explícitos.</translation>
@@ -296,6 +305,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2102495993840063010">Aplicaciones de Android</translation>
<translation id="2107021941795971877">Soportes de impresión</translation>
<translation id="2108755909498034140">Reinicia el ordenador</translation>
+<translation id="2111166930115883695">Pulsa la barra espaciadora para jugar</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Tarjeta</translation>
<translation id="2114841414352855701">Se ha ignorado la política porque la anula <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
<translation id="2148613324460538318">Añadir tarjeta</translation>
+<translation id="2149968176347646218">La conexión no es segura</translation>
<translation id="2154054054215849342">La sincronización no está disponible para tu dominio</translation>
<translation id="2154484045852737596">Editar tarjeta</translation>
<translation id="2161656808144014275">Texto</translation>
@@ -317,7 +328,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">N.º de teléfono</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Una dirección}other{# direcciones}}</translation>
-<translation id="2187243482123994665">Presencia del usuario</translation>
<translation id="2187317261103489799">Detectar (predeterminado)</translation>
<translation id="2188375229972301266">Perforado múltiple en la parte inferior</translation>
<translation id="2202020181578195191">Introduce un año de vencimiento válido</translation>
@@ -341,15 +351,15 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2276057643614339130">Base de impresión</translation>
<translation id="2277103315734023688">Ir hacia delante</translation>
<translation id="2283340219607151381">Guardar y autocompletar direcciones</translation>
-<translation id="2288422996159078444">Se está vigilando todo lo que escribes, las páginas que visitas y el resto de la actividad que realizas en Internet. Es posible que se modifique el contenido de los sitios web sin que lo sepas.</translation>
+<translation id="2288422996159078444">Se está vigilando todo lo que escribes, las páginas que visitas y el resto de la actividad que realizas en Internet. Es posible que se modifique el contenido de los sitios sin que lo sepas.</translation>
<translation id="2289385804009217824">Recortar</translation>
<translation id="2292556288342944218">Tu acceso a Internet está bloqueado</translation>
-<translation id="2293443924986248631">Si activas esta opción, los sitios web no podrán usar cookies para hacer un seguimiento de tu actividad en la Web. Es posible que las funciones de algunos sitios web no funcionen correctamente.</translation>
+<translation id="2293443924986248631">Si activas esta opción, los sitios no podrán usar cookies para hacer un seguimiento de tu actividad en la Web. Es posible que las funciones de algunos sitios no funcionen correctamente.</translation>
<translation id="2295290966866883927">Las URL de las páginas que visites se enviarán a Google Cloud o a terceros para que se analicen. Por ejemplo, puede que se analicen para detectar sitios web no seguros.</translation>
<translation id="2297722699537546652">B5 (sobre)</translation>
<translation id="2300306941146563769">No subido</translation>
<translation id="2310021320168182093">Chou2 (sobre)</translation>
-<translation id="2316887270356262533">Libera menos de 1 MB. Algunos sitios web pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
+<translation id="2316887270356262533">Libera menos de 1 MB. Algunos sitios pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> necesita un nombre de usuario y una contraseña.</translation>
<translation id="2330137317877982892"><ph name="CREDIT_CARD" />; fecha de caducidad: <ph name="EXPIRATION_DATE_ABBR" /></translation>
<translation id="2337852623177822836">Configuración controlada por el administrador</translation>
@@ -470,6 +480,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2839501879576190149">Sitio web falso</translation>
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">Es posible que los atacantes estén intentando robar tu información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por ejemplo, contraseñas, mensajes o tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Este sitio web muestra anuncios invasivos o engañosos.</translation>
<translation id="2878197950673342043">Plegado en cruz</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ubicación de ventanas</translation>
@@ -508,11 +519,11 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2996674880327704673">Sugerencias de Google</translation>
<translation id="3002501248619246229">Comprobar medios de bandeja de entrada</translation>
<translation id="3005723025932146533">Mostrar copia guardada</translation>
-<translation id="3007719053326478567">Tu administrador ha bloqueado la opción de imprimir este contenido</translation>
<translation id="3008447029300691911">Introduce el código CVC de la tarjeta <ph name="CREDIT_CARD" />. Cuando la confirmes, su información se compartirá con este sitio web.</translation>
<translation id="3010559122411665027">Entrada de lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueado automáticamente</translation>
<translation id="3016780570757425217">Conocer tu ubicación</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pulsa Tabulador y, a continuación, Intro para quitar la sugerencia.</translation>
<translation id="3023071826883856138">You4 (sobre)</translation>
<translation id="3024663005179499861">Tipo de política incorrecto</translation>
<translation id="3037605927509011580">¡Vaya!</translation>
@@ -555,6 +566,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3207960819495026254">Añadido a marcadores</translation>
<translation id="3209034400446768650">La página puede cobrarte dinero</translation>
<translation id="3212581601480735796">Se está vigilando tu actividad en <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Cierra todas las ventanas de invitado para que se elimine la actividad de navegación de este dispositivo.</translation>
<translation id="3215092763954878852">No se ha podido usar WebAuthn</translation>
<translation id="3218181027817787318">Relativo</translation>
<translation id="3225919329040284222">El servidor ha mostrado un certificado que no coincide con lo que se esperaba. Algunos sitios web tienen un alto nivel de seguridad para garantizar tu protección y esperan ciertas características de los certificados.</translation>
@@ -604,7 +616,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3423742043356668186">Especificado por el sistema</translation>
<translation id="3427092606871434483">Permitir (predeterminado)</translation>
<translation id="3427342743765426898">&amp;Rehacer edición</translation>
-<translation id="342781501876943858">Chromium te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios web.</translation>
+<translation id="342781501876943858">Chromium te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios.</translation>
<translation id="3428151540071562330">Una o varias URI de plantilla del servidor DnsOverHttpsTemplates no son válidas y no se utilizarán.</translation>
<translation id="3431636764301398940">Guardar esta tarjeta en el dispositivo</translation>
<translation id="3432601291244612633">Cerrar página</translation>
@@ -702,6 +714,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3784372983762739446">Dispositivos Bluetooth</translation>
<translation id="3787705759683870569">Vencimiento: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamaño 16</translation>
+<translation id="3789841737615482174">Instalar</translation>
<translation id="3793574014653384240">La cantidad y las causas de los bloqueos que han ocurrido recientemente</translation>
<translation id="3797522431967816232">Prc3 (sobre)</translation>
<translation id="3799805948399000906">Fuente solicitada</translation>
@@ -737,7 +750,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3962859241508114581">Pista anterior</translation>
<translation id="3963721102035795474">Modo de lectura</translation>
<translation id="3963837677003247395">¿Quieres continuar de forma manual?</translation>
-<translation id="3964661563329879394">{COUNT,plural, =0{Ninguno}=1{De 1 sitio web }other{De # sitios web }}</translation>
+<translation id="3964661563329879394">{COUNT,plural, =0{Ninguno}=1{De 1 sitio web }other{De # sitios }}</translation>
<translation id="397105322502079400">Calculando...</translation>
<translation id="3973234410852337861">La página <ph name="HOST_NAME" /> está bloqueada</translation>
<translation id="3987405730340719549">Chrome ha determinado que este sitio web podría ser falso o fraudulento.
@@ -753,6 +766,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (sobre)</translation>
+<translation id="4067669230157909013">Se ha reanudado la captura de pantalla.</translation>
<translation id="4067947977115446013">Añade una dirección válida</translation>
<translation id="4072486802667267160">Se ha producido un error al procesar el pedido. Vuelve a intentarlo.</translation>
<translation id="4075732493274867456">El cliente y el servidor no son compatibles con la misma versión de protocolo SSL o de cifrado.</translation>
@@ -780,7 +794,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4152318981910038897">{COUNT,plural, =1{Página 1}other{Página {COUNT}}}</translation>
<translation id="4154664944169082762">Huellas digitales</translation>
<translation id="4159784952369912983">Morado</translation>
-<translation id="4165986682804962316">Configuración de sitios web</translation>
+<translation id="4165986682804962316">Configuración de sitios</translation>
<translation id="4171400957073367226">La firma de verificación no es válida</translation>
<translation id="4171489848299289778"><ph name="RESULT_MODIFIED_DATE" /> - <ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="4172051516777682613">Mostrar siempre</translation>
@@ -795,13 +809,13 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4209166701302774460">El servidor al que te diriges (<ph name="ORIGIN" />) ha solicitado que
se aplique una política de origen a todas las solicitudes que reciba. Sin embargo, no ha
proporcionado ninguna política, lo que impide al navegador procesar tu solicitud
- de ir a <ph name="SITE" />. Los operadores de sitios web pueden usar las políticas de origen
+ de ir a <ph name="SITE" />. Los operadores de sitios pueden usar las políticas de origen
para configurar la seguridad y otras propiedades de un sitio web.</translation>
<translation id="421066178035138955">Usar dispositivos y datos de realidad virtual</translation>
<translation id="4214357935346142455">perfil de pantalla de inicio de sesión</translation>
<translation id="4215751373031079683">7x9 (sobre)</translation>
<translation id="4220128509585149162">La página no responde o se cierra</translation>
-<translation id="422022731706691852">Es posible que los atacantes que se encuentren en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten engañarte para que instales programas que empeoren tu experiencia de navegación (por ejemplo, que cambien tu página principal o muestren anuncios adicionales en los sitios web a los que accedas). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="422022731706691852">Es posible que los atacantes que se encuentren en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten engañarte para que instales programas que empeoren tu experiencia de navegación (por ejemplo, que cambien tu página principal o muestren anuncios adicionales en los sitios a los que accedas). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;Paso 1: Inicia sesión en el portal&lt;/h4&gt;
&lt;p&gt;Para acceder a las redes Wi‑Fi de sitios como cafeterías o aeropuertos, tienes que iniciar sesión. Para ver la página de inicio de sesión, accede a una página que utilice &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;
&lt;ol&gt;
@@ -837,6 +851,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4297502707443874121">Miniatura de la página <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Mostrar</translation>
<translation id="4300675098767811073">Perforado múltiple en la parte derecha</translation>
+<translation id="4302514097724775343">Toca el dinosaurio para jugar</translation>
<translation id="4302965934281694568">Chou3 (sobre)</translation>
<translation id="4305666528087210886">No se ha podido acceder al archivo</translation>
<translation id="4305817255990598646">Cambiar</translation>
@@ -851,13 +866,13 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4340982228985273705">No se ha detectado que este ordenador esté administrado por la empresa, por lo que la política solo puede instalar automáticamente extensiones alojadas en Chrome Webstore. La URL de actualización de Chrome Webstore es "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Tarjetas de crédito aceptadas</translation>
<translation id="4346833872170306413">Roc-16K</translation>
-<translation id="4349531505348777662">Acabas de introducir tu contraseña en un sitio web engañoso. Chrome te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios web en los que uses esa contraseña y que la cambies ahora.</translation>
+<translation id="4349531505348777662">Acabas de introducir tu contraseña en un sitio web engañoso. Chrome te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios en los que uses esa contraseña y que la cambies ahora.</translation>
<translation id="4356973930735388585">Es posible que los atacantes que se encuentren en este sitio web intenten instalar programas peligrosos en tu ordenador para robar o eliminar tu información (por ejemplo, fotos, contraseñas, mensajes y tarjetas de crédito).</translation>
<translation id="4358059973562876591">Es posible que las plantillas que has especificado no se apliquen debido a un error con la política DnsOverHttpsMode.</translation>
<translation id="4358461427845829800">Gestiona tus métodos de pago...</translation>
<translation id="4359160567981085931">Acabas de introducir tu contraseña en un sitio web engañoso. Chrome puede ayudarte. Para cambiar tu contraseña y notificar a Google de que tu cuenta podría estar en peligro, haz clic en Proteger cuenta.</translation>
<translation id="4367563149485757821">Number-12 (sobre)</translation>
-<translation id="4367839622597707614">{1,plural, =0{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> ha quedado expuesta. Chrome recomienda que cambies tu contraseña de <ph name="ORIGIN" /> ahora.}=1{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> y otro sitio web han quedado expuestas. Chrome te recomienda que revises ahora tus contraseñas guardadas.}other{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> y <ph name="SITES_COUNT" /> otros sitios web han quedado expuestas. Chrome te recomienda que revises ahora tus contraseñas guardadas.}}</translation>
+<translation id="4367839622597707614">{1,plural, =0{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> ha quedado expuesta. Chrome recomienda que cambies tu contraseña de <ph name="ORIGIN" /> ahora.}=1{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> y otro sitio web han quedado expuestas. Chrome te recomienda que revises ahora tus contraseñas guardadas.}other{Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña de <ph name="ORIGIN" /> y <ph name="SITES_COUNT" /> otros sitios han quedado expuestas. Chrome te recomienda que revises ahora tus contraseñas guardadas.}}</translation>
<translation id="437058704415269440">Saldo de cuenta</translation>
<translation id="4372516964750095882">Fanfold-Us</translation>
<translation id="4372948949327679948">Se esperaba un valor <ph name="VALUE_TYPE" />.</translation>
@@ -866,7 +881,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4390472908992056574">Brim</translation>
<translation id="4406896451731180161">resultados de la búsqueda</translation>
<translation id="4408413947728134509">Cookies: <ph name="NUM_COOKIES" /></translation>
-<translation id="4414290883293381923">Acabas de introducir tu contraseña en un sitio web engañoso. Chrome te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios web en los que uses esta contraseña y que la cambies ahora.</translation>
+<translation id="4414290883293381923">Acabas de introducir tu contraseña en un sitio web engañoso. Chrome te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios en los que uses esta contraseña y que la cambies ahora.</translation>
<translation id="4415426530740016218">Dirección de recogida</translation>
<translation id="4424024547088906515">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, Chrome no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="443121186588148776">Puerto serie</translation>
@@ -915,10 +930,11 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4658638640878098064">Grapado en la parte superior izquierda</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realidad virtual</translation>
+<translation id="4675657451653251260">Con el modo invitados no verás ninguna información del perfil de Chrome. Puedes <ph name="LINK_BEGIN" />iniciar sesión<ph name="LINK_END" /> para acceder a la información de tu cuenta de Google, como contraseñas o métodos de pago.</translation>
<translation id="467662567472608290">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad contiene errores. El problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="4677585247300749148"><ph name="URL" /> quiere responder a eventos de accesibilidad</translation>
<translation id="467809019005607715">Presentaciones de Google</translation>
-<translation id="4680804919228900307">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="4680804919228900307">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="4690462567478992370">Dejar de utilizar un certificado no válido</translation>
<translation id="4691835149146451662">Architecture-A (sobre)</translation>
<translation id="4701488924964507374"><ph name="SENTENCE1" /> <ph name="SENTENCE2" /></translation>
@@ -936,12 +952,18 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4738601419177586157">Sugerencia de búsqueda de <ph name="TEXT" /></translation>
<translation id="4742407542027196863">Gestionar contraseñas…</translation>
<translation id="4744603770635761495">Ruta del ejecutable</translation>
-<translation id="4750917950439032686">Tu información (por ejemplo, las contraseñas o los números de las tarjetas de crédito) es privada cuando se envía a este sitio web.</translation>
+<translation id="4750917950439032686">Tu información (por ejemplo, tus contraseñas o números de tarjeta de crédito) es privada cuando se envía a este sitio web.</translation>
<translation id="4756388243121344051">&amp;Historial</translation>
<translation id="4758311279753947758">Añadir información de contacto</translation>
<translation id="4761104368405085019">Utilizar el micrófono</translation>
<translation id="4764776831041365478">Es posible que la página web <ph name="URL" /> esté temporalmente inactiva o que se haya trasladado definitivamente a otra dirección.</translation>
<translation id="4766713847338118463">Grapado doble en la parte inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Actividad que se guardará en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Archivos que descargues en esta ventana
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Ventana emergente bloqueada}other{# ventanas emergentes bloqueadas}}</translation>
<translation id="4780366598804516005">Buzón de correo 1</translation>
@@ -1061,7 +1083,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5230815978613972521">B8</translation>
<translation id="5233045608889518621">12x19</translation>
-<translation id="5250209940322997802">"Conectarse a la red"</translation>
+<translation id="5250209940322997802">"Conéctate a la red"</translation>
<translation id="5251803541071282808">Nube</translation>
<translation id="5252000469029418751">C7 (sobre)</translation>
<translation id="5254043433801397071">Optimizar el contenido de impresión</translation>
@@ -1104,11 +1126,13 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5386426401304769735">La cadena de certificados de este sitio web contiene un certificado firmado con SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Grapado en el borde derecho</translation>
+<translation id="5398772614898833570">Anuncios bloqueados</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, ya que su certificado de seguridad no es válido en este momento. Esto puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="541416427766103491">Apilador 4</translation>
<translation id="5421136146218899937">Borrar datos de navegación...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> quiere enviarte notificaciones</translation>
+<translation id="542872847390508405">Estás navegando como invitado</translation>
<translation id="5430298929874300616">Eliminar marcador</translation>
<translation id="5439770059721715174">Error de validación de esquema en "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Orden inverso boca arriba</translation>
@@ -1150,18 +1174,18 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5571083550517324815">Los pedidos no se pueden recoger en esta dirección. Selecciona otra.</translation>
<translation id="5580958916614886209">Consulta el mes de vencimiento y vuelve a intentarlo</translation>
<translation id="5586446728396275693">Ninguna dirección guardada</translation>
+<translation id="5593349413089863479">La conexión no es completamente segura</translation>
<translation id="5595485650161345191">Editar dirección</translation>
<translation id="5598944008576757369">Seleccionar método de pago</translation>
<translation id="560412284261940334">Administración no admitida</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Este sitio web podría ser falso o fraudulento. Chrome te recomienda que salgas ahora.</translation>
<translation id="5610142619324316209">Comprobar la conexión</translation>
<translation id="5610807607761827392">Puedes gestionar las tarjetas y las direcciones en <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduce esta página con el Traductor de Google</translation>
<translation id="5612720917913232150"><ph name="URL" /> quiere utilizar la ubicación de tu ordenador</translation>
<translation id="5617949217645503996">La página <ph name="HOST_NAME" /> te ha redirigido demasiadas veces.</translation>
-<translation id="5624120631404540903">Administrar contraseñas</translation>
+<translation id="5624120631404540903">Gestionar contraseñas</translation>
<translation id="5629630648637658800">Error al cargar la configuración de la política</translation>
<translation id="5631439013527180824">Token de administración de dispositivos no válido</translation>
<translation id="5632627355679805402">Tus datos están cifrados con tu <ph name="BEGIN_LINK" />contraseña de Google<ph name="END_LINK" /> desde el <ph name="TIME" />. Introdúcela para iniciar la sincronización.</translation>
@@ -1187,7 +1211,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="571403275720188526">(arm64)</translation>
<translation id="5720705177508910913">Usuario actual</translation>
<translation id="5728056243719941842">C5 (sobre)</translation>
-<translation id="5730040223043577876">Chrome te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios web.</translation>
+<translation id="5730040223043577876">Chrome te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios.</translation>
<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Guarda la tarjeta en tu cuenta de Google}other{Guarda las tarjetas en tu cuenta de Google}}</translation>
<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Usar un número virtual para esta tarjeta}other{Seleccionar tarjetas}}</translation>
<translation id="5759751709240058861">Usar y mover tu cámara</translation>
@@ -1212,7 +1236,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="583281660410589416">Desconocido</translation>
<translation id="5838278095973806738">No deberías introducir información confidencial en este sitio web (por ejemplo, contraseñas o tarjetas de crédito) porque los atacantes podrían robarla.</translation>
<translation id="5851548754964597211">Lista de pestañas</translation>
-<translation id="5855253129151731373">El nombre de host de este sitio web se parece al de <ph name="LOOKALIKE_DOMAIN" />. Los atacantes a veces imitan a otros sitios web haciendo pequeños cambios difíciles de ver en el nombre del dominio.
+<translation id="5855253129151731373">El nombre de host de este sitio web se parece al de <ph name="LOOKALIKE_DOMAIN" />. Los atacantes a veces imitan a otros sitios haciendo pequeños cambios difíciles de ver en el nombre del dominio.
Si crees que puede tratarse de un error, ve a https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals.</translation>
<translation id="5862579898803147654">Apilador 8</translation>
@@ -1227,6 +1251,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5901630391730855834">Amarillo</translation>
<translation id="5905445707201418379">Se ha bloqueado según la política de origen de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
+<translation id="5913377024445952699">Grabación de pantalla pausada</translation>
<translation id="59174027418879706">Habilitado</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Activado</translation>
@@ -1239,6 +1264,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5963413905009737549">Etiqueta de sección</translation>
<translation id="5967592137238574583">Edita la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
+<translation id="5968793460449681917">En cada visita</translation>
<translation id="5975083100439434680">Reducir</translation>
<translation id="5979084224081478209">Comprobar contraseñas</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1334,7 +1360,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6328639280570009161">Prueba a inhabilitar la predicción de red</translation>
<translation id="6328784461820205019">"La conexión no es privada" o "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "&lt;span class="error-code"&gt;ERR_CERT_SYMANTEC_LEGACY&lt;/span&gt;" o "Error de certificado SSL"</translation>
<translation id="6328786501058569169">Este sitio web es engañoso</translation>
-<translation id="6337133576188860026">Libera menos de <ph name="SIZE" />. Algunos sitios web pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
+<translation id="6337133576188860026">Libera menos de <ph name="SIZE" />. Algunos sitios pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
<translation id="6337534724793800597">Filtrar políticas por nombre</translation>
<translation id="6353505687280762741">{COUNT,plural, =0{Ninguna}=1{1 contraseña de <ph name="DOMAIN_LIST" /> (sincronizada)}=2{2 contraseñas de <ph name="DOMAIN_LIST" /> (sincronizadas)}other{# contraseñas de <ph name="DOMAIN_LIST" /> (sincronizadas)}}</translation>
<translation id="6358450015545214790">¿Necesitas ayuda?</translation>
@@ -1345,7 +1371,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6380497234672085559">A0</translation>
<translation id="6383221683286411806">Es posible que se cobren cargos en el futuro.</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{Una sugerencia más}other{# sugerencias más}}</translation>
-<translation id="6387645831795005740">Los atacantes suelen imitar los sitios web haciendo pequeños cambios en la URL que son difíciles de ver.</translation>
+<translation id="6387645831795005740">Los atacantes suelen imitar los sitios haciendo pequeños cambios en la URL que son difíciles de ver.</translation>
<translation id="6389470377220713856">Nombre de la tarjeta</translation>
<translation id="6390200185239044127">Plegado al medio en Z</translation>
<translation id="6390662030813198813">Engineering-E</translation>
@@ -1394,6 +1420,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6587923378399804057">Enlace copiado</translation>
<translation id="6591833882275308647">Tu <ph name="DEVICE_TYPE" /> no está administrado</translation>
<translation id="6596325263575161958">Opciones de cifrado</translation>
+<translation id="6596892391065203054">Tu administrador ha bloqueado la opción de imprimir este contenido.</translation>
<translation id="6604181099783169992">Sensores de luz o movimiento</translation>
<translation id="6609880536175561541">Prc7 (sobre)</translation>
<translation id="6612358246767739896">Contenido protegido</translation>
@@ -1404,9 +1431,9 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6630809736994426279">Es posible que los atacantes que se encuentren en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten instalar programas peligrosos en tu Mac para robar o eliminar tu información (por ejemplo, fotos, contraseñas, mensajes y tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6631202559048444592">Esta política tiene más de una fuente, pero los valores son los mismos.</translation>
<translation id="663260587451432563">JIS B4</translation>
-<translation id="6643016212128521049">Eliminar</translation>
-<translation id="6645291930348198241">Acceder a cookies y datos de sitios web.</translation>
-<translation id="6646269444027925224">{COUNT,plural, =0{Ninguno}=1{De 1 sitio web (no se cerrará la sesión en tu cuenta de Google)}other{De # sitios web (no se cerrará la sesión en tu cuenta de Google)}}</translation>
+<translation id="6643016212128521049">Borrar</translation>
+<translation id="6645291930348198241">Acceder a cookies y datos de sitios.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ninguno}=1{De 1 sitio web (no se cerrará la sesión en tu cuenta de Google)}other{De # sitios (no se cerrará la sesión en tu cuenta de Google)}}</translation>
<translation id="6648459603387803038">El administrador puede cambiar la configuración del navegador de forma remota. Es posible que la actividad de este dispositivo también se administre fuera de Chrome.</translation>
<translation id="6648524591329069940">Fuente Serif</translation>
<translation id="6652101503459149953">Usar Windows Hello</translation>
@@ -1453,10 +1480,11 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6895330447102777224">Tu tarjeta se ha confirmado</translation>
<translation id="6897140037006041989">User-agent</translation>
<translation id="6898699227549475383">Organización (O)</translation>
+<translation id="6907293445143367439">Permitir a <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> quiere obtener un control absoluto de tus dispositivos MIDI</translation>
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6934672428414710184">Este nombre proviene de tu cuenta de Google</translation>
-<translation id="6944692733090228304"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> no gestiona el sitio web en el que has introducido tu contraseña. Para proteger tu cuenta, no utilices la misma contraseña en otras aplicaciones o sitios web.</translation>
+<translation id="6944692733090228304"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> no gestiona el sitio web en el que has introducido tu contraseña. Para proteger tu cuenta, no utilices la misma contraseña en otras aplicaciones o sitios.</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6948701128805548767">Selecciona una dirección para ver los métodos de recogida y los requisitos</translation>
<translation id="6949872517221025916">Cambiar contraseña</translation>
@@ -1471,7 +1499,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6972629891077993081">Dispositivos HID</translation>
<translation id="6973656660372572881">Se especifican tanto servidores proxy fijos como una URL de secuencia de comandos .pac.</translation>
<translation id="6973932557599545801">Lo siento, no puedo ayudarte. Puedes continuar por tu cuenta.</translation>
-<translation id="6975012522936652259">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios web en los que uses esa contraseña y que la cambies ahora.</translation>
+<translation id="6975012522936652259">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios en los que uses esa contraseña y que la cambies ahora.</translation>
<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">Silenciar (predeterminado)</translation>
<translation id="6979983982287291980">Los archivos que descargas se envían a Google Cloud o a terceros para que se analicen. Por ejemplo, puede que se analicen para buscar datos sensibles o software malicioso.</translation>
@@ -1522,7 +1550,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="7181261019481237103">Abrir una ventana de incógnito</translation>
<translation id="7182878459783632708">No hay políticas establecidas.</translation>
<translation id="7186367841673660872">Esta página se ha traducido del<ph name="ORIGINAL_LANGUAGE" />al<ph name="LANGUAGE_LANGUAGE" />.</translation>
-<translation id="7192203810768312527">Libera <ph name="SIZE" />. Algunos sitios web pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
+<translation id="7192203810768312527">Libera <ph name="SIZE" />. Algunos sitios pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">El administrador puede consultar lo siguiente:</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
@@ -1533,7 +1561,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="7219179957768738017">La conexión utiliza <ph name="SSL_VERSION" />.</translation>
<translation id="7220786058474068424">Procesando pago</translation>
<translation id="7221855153210829124">Mostrar notificaciones</translation>
-<translation id="7229659723041939809">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="7229659723041939809">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="7233592378249864828">Imprimir hoja de confirmación</translation>
<translation id="7238585580608191973">Huella digital SHA-256</translation>
<translation id="7240120331469437312">Nombre alternativo de la entidad receptora del certificado</translation>
@@ -1556,7 +1584,7 @@ Más información:
<translation id="7320336641823683070">Ayuda para la conexión</translation>
<translation id="7323804146520582233">Ocultar la sección "<ph name="SECTION" />"</translation>
<translation id="733354035281974745">Anulación de la cuenta local del dispositivo</translation>
-<translation id="7333654844024768166">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios web en los que uses esta contraseña y que la cambies ahora.</translation>
+<translation id="7333654844024768166">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> y otros sitios en los que uses esta contraseña y que la cambies ahora.</translation>
<translation id="7334320624316649418">&amp;Rehacer reorganización</translation>
<translation id="7337706099755338005">No está disponible en esta plataforma.</translation>
<translation id="733923710415886693">El certificado del servidor no se ha revelado a través de la Transparencia en los Certificados.</translation>
@@ -1564,6 +1592,7 @@ Más información:
<translation id="7346048084945669753">Se ha afiliado:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Línea de comandos</translation>
+<translation id="7359588939039777303">Los anuncios están bloqueados.</translation>
<translation id="7372973238305370288">resultado de búsqueda</translation>
<translation id="7374733840632556089">Este problema se debe a un certificado que tú u otra persona habéis instalado en el dispositivo. Chrome no confía en este certificado porque hay constancia de que se utiliza para interceptar y vigilar redes. En algunos casos, dicha vigilancia es legítima (por ejemplo, en las redes de centros educativos o empresas), pero Chrome quiere asegurarse de que estás al corriente de ello, aunque no puedas evitarlo. La vigilancia puede afectar a todos los navegadores y las aplicaciones que accedan a Internet.</translation>
<translation id="7375818412732305729">Se ha adjuntado un archivo</translation>
@@ -1606,7 +1635,7 @@ Más información:
<translation id="7495290002932347110">Se ha producido una quiebra de seguridad de datos en un sitio web o una aplicación y tu contraseña ha quedado expuesta. Chrome recomienda que revises las contraseñas guardadas y que cambies la de <ph name="ORIGIN" /> ahora.</translation>
<translation id="7495528107193238112">Este contenido está bloqueado. Para solucionar el problema, ponte en contacto con el propietario del sitio web.</translation>
<translation id="7498234416455752244">Seguir editando</translation>
-<translation id="7503664977220660814">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="7503664977220660814">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="7508255263130623398">El ID de dispositivo de política devuelto está vacío o no coincide con el ID de dispositivo actual</translation>
<translation id="7508870219247277067">Verde aguacate</translation>
<translation id="7511955381719512146">La red Wi-Fi que estás utilizando puede requerir que accedas a la página <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -1631,9 +1660,9 @@ Más información:
<translation id="7569952961197462199">¿Eliminar tarjeta de crédito de Chrome?</translation>
<translation id="7569983096843329377">Negro</translation>
<translation id="7575207903026901870">Botón Eliminar sugerencia, pulsa Intro para eliminar esta sugerencia</translation>
-<translation id="7578104083680115302">Paga rápidamente en aplicaciones y sitios web desde tus dispositivos utilizando las tarjetas que has guardado en Google.</translation>
+<translation id="7578104083680115302">Paga rápidamente en aplicaciones y sitios desde tus dispositivos utilizando las tarjetas que has guardado en Google.</translation>
<translation id="7581199239021537589">Cara 2 del desplazamiento de la imagen en el eje Y</translation>
-<translation id="7591636454931265313"><ph name="EMBEDDED_URL" /> quiere usar tus cookies y datos de sitios web en <ph name="TOP_LEVEL_URL" /></translation>
+<translation id="7591636454931265313"><ph name="EMBEDDED_URL" /> quiere usar tus cookies y datos de sitios en <ph name="TOP_LEVEL_URL" /></translation>
<translation id="7592362899630581445">El certificado del servidor incluye un nombre que está fuera de su cobertura.</translation>
<translation id="7598391785903975535">Menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">La página <ph name="HOST_NAME" /> no puede procesar esta solicitud ahora.</translation>
@@ -1660,7 +1689,7 @@ Más información:
<translation id="7663736086183791259">Certificado <ph name="CERTIFICATE_VALIDITY" /></translation>
<translation id="7667346355482952095">El token de política devuelto está vacío o no coincide con el token actual</translation>
<translation id="7668654391829183341">Dispositivo desconocido</translation>
-<translation id="7669271284792375604">Es posible que los atacantes que se encuentren en este sitio web intenten engañarte para que instales programas que empeoren tu experiencia de navegación (por ejemplo, que cambien tu página principal o muestren anuncios adicionales en los sitios web a los que accedas).</translation>
+<translation id="7669271284792375604">Es posible que los atacantes que se encuentren en este sitio web intenten engañarte para que instales programas que empeoren tu experiencia de navegación (por ejemplo, que cambien tu página principal o muestren anuncios adicionales en los sitios a los que accedas).</translation>
<translation id="7673278391011283842">Buzón de correo 6</translation>
<translation id="7676643023259824263">Buscar texto <ph name="TEXT" /> del portapapeles</translation>
<translation id="7682287625158474539">Dirección de envío</translation>
@@ -1711,7 +1740,7 @@ Más información:
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7862185352068345852">¿Quieres salir del sitio web?</translation>
<translation id="7865448901209910068">Mejor velocidad</translation>
-<translation id="7874263914261512992">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="7874263914261512992">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="7878562273885520351">Es posible que tu contraseña se haya vulnerado</translation>
<translation id="7882421473871500483">Marrón</translation>
<translation id="7887683347370398519">Comprueba el código CVC y vuelve a intentarlo</translation>
@@ -1738,6 +1767,7 @@ Más información:
<translation id="7976214039405368314">Demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de salida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Instala ARCore para visualizar contenido de realidad aumentada</translation>
<translation id="799149739215780103">Encuadernar</translation>
<translation id="7995512525968007366">Sin especificar</translation>
<translation id="800218591365569300">Prueba a cerrar otros programas o pestañas para liberar memoria.</translation>
@@ -1790,7 +1820,7 @@ Más información:
<translation id="8211406090763984747">La conexión es segura</translation>
<translation id="8218327578424803826">Ubicación asignada:</translation>
<translation id="8220146938470311105">C7/C6 (sobre)</translation>
-<translation id="8221250263817408492">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" /> y a otros sitios web en los que uses esa contraseña y la cambies ahora.</translation>
+<translation id="8221250263817408492">Acabas de introducir tu contraseña en un sitio web engañoso. Chromium te recomienda que accedas a <ph name="WEBSITE_1" /> y a otros sitios en los que uses esa contraseña y la cambies ahora.</translation>
<translation id="8225771182978767009">La persona que ha configurado este ordenador ha elegido bloquear este sitio web.</translation>
<translation id="8228419419708659934">Vista de dos páginas</translation>
<translation id="822964464349305906"><ph name="TYPE_1" /> o <ph name="TYPE_2" /></translation>
@@ -1850,13 +1880,13 @@ Más información:
<translation id="8438786541497918448">¿Usar cámara y micrófono?</translation>
<translation id="8446884382197647889">Más información</translation>
<translation id="8457125768502047971">Indefinido</translation>
-<translation id="8461694314515752532">Cifrar los datos sincronizados con tu propia frase de contraseña de sincronización</translation>
+<translation id="8461694314515752532">Cifrar datos sincronizados con tu propia frase de contraseña de sincronización</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{Una tarjeta de crédito}other{# tarjetas de crédito}}</translation>
<translation id="8473863474539038330">Direcciones y más</translation>
<translation id="8474910779563686872">Mostrar información para desarrolladores</translation>
<translation id="8479754468255770962">Grapado en la parte inferior izquierda</translation>
<translation id="8483780878231876732">Inicia sesión en Chrome para utilizar tarjetas de tu cuenta de Google</translation>
-<translation id="8485393050551136813">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="8485393050551136813">Acabas de escribir tu contraseña en un sitio web engañoso. Chromium te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="8488350697529856933">Aplicable a</translation>
<translation id="8490137692873530638">Apilador 10</translation>
<translation id="8498891568109133222"><ph name="HOST_NAME" /> ha tardado demasiado tiempo en responder.</translation>
@@ -1865,24 +1895,38 @@ Más información:
<translation id="8507227106804027148">Línea de comandos</translation>
<translation id="8508648098325802031">Icono de búsqueda</translation>
<translation id="8522552481199248698">Chrome puede ayudarte a proteger tu cuenta de Google y a cambiar tu contraseña.</translation>
+<translation id="8525306231823319788">Pantalla completa</translation>
<translation id="8530813470445476232">Borra el historial de navegación, las cookies, la caché y más desde la configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URL boloqueadas y otras políticas implementadas por el administrador del sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Grapado triple en la parte inferior</translation>
<translation id="8543181531796978784">Puedes <ph name="BEGIN_ERROR_LINK" />informar de un problema de detección<ph name="END_ERROR_LINK" /> o, si comprendes los riesgos que conlleva esta acción para tu seguridad, <ph name="BEGIN_LINK" />accede a este sitio web no seguro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Puedes encontrar el CVC en el reverso de la tarjeta.</translation>
+<translation id="8558485628462305855">Actualiza ARCore para visualizar contenido de realidad aumentada</translation>
<translation id="8559762987265718583">No se puede establecer una conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora de tu dispositivo (<ph name="DATE_AND_TIME" />) no son correctas.</translation>
<translation id="8564182942834072828">Separar documentos/Copias sin intercalar</translation>
-<translation id="8564985650692024650">Chromium te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios web.</translation>
+<translation id="8564985650692024650">Chromium te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Actividad que no se guardará en este dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas que veas en esta ventana
+ <ph name="LIST_ITEM" />Cookies y datos de sitios
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Usa Touch ID para confirmar tarjetas más rápido</translation>
<translation id="858637041960032120">Añade un teléfono</translation>
<translation id="8589998999637048520">Mejor calidad</translation>
+<translation id="8600271352425265729">Solo esta vez</translation>
<translation id="860043288473659153">Nombre del titular de la tarjeta</translation>
<translation id="8606726445206553943">Utilizar tus dispositivos MIDI</translation>
+<translation id="8612761427948161954">Hola, <ph name="USERNAME" />:
+ <ph name="BR" />
+ Estás navegando como invitado</translation>
<translation id="861775596732816396">Tamaño 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">No hay contraseñas que coincidan. Mostrar todas las contraseñas guardadas.</translation>
<translation id="8625384913736129811">Guardar esta tarjeta en el dispositivo</translation>
+<translation id="8627040765059109009">Grabación de pantalla reanudada</translation>
<translation id="8657078576661269990">Tu administrador ha bloqueado la opción de compartir contenido de <ph name="ORIGIN_NAME" /> en <ph name="VM_NAME_1" /> y <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Resumen del pedido: <ph name="TOTAL_LABEL" /> (más detalles)</translation>
<translation id="867224526087042813">Firma</translation>
@@ -1914,7 +1958,7 @@ Más información:
<translation id="87601671197631245">Este sitio web usa una configuración de seguridad obsoleta y puede que exponga tu información (por ejemplo, las contraseñas, los mensajes o las tarjetas de crédito) cuando se envíe a este sitio web.</translation>
<translation id="8761567432415473239">La función de Navegación segura de Google <ph name="BEGIN_LINK" />encontró programas dañinos<ph name="END_LINK" /> recientemente en el sitio <ph name="SITE" />.</translation>
<translation id="8763927697961133303">Dispositivo USB</translation>
-<translation id="8774457497170244317">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" /> y otros sitios web en los que uses esta contraseña.</translation>
+<translation id="8774457497170244317">Acabas de escribir tu contraseña en un sitio web engañoso. Chrome te recomienda que compruebes las contraseñas que has guardado en <ph name="WEBSITE_1" /> y otros sitios en los que uses esta contraseña.</translation>
<translation id="877985182522063539">A4</translation>
<translation id="8790007591277257123">&amp;Rehacer eliminación</translation>
<translation id="8792621596287649091">Podrías perder el acceso a tu cuenta de <ph name="ORG_NAME" /> o tener problemas de suplantación de identidad. Chromium te recomienda que cambies tu contraseña ahora.</translation>
@@ -1928,7 +1972,7 @@ Más información:
<translation id="884264119367021077">Dirección de envío</translation>
<translation id="884923133447025588">No se ha encontrado ningún mecanismo de revocación.</translation>
<translation id="885730110891505394">Compartir con Google</translation>
-<translation id="8858065207712248076">Chrome te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios web.</translation>
+<translation id="8858065207712248076">Chrome te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios.</translation>
<translation id="885906927438988819">Si está escrito correctamente, <ph name="BEGIN_LINK" />prueba a ejecutar el diagnóstico de red de Windows<ph name="END_LINK" />.</translation>
<translation id="8866481888320382733">Error al analizar la configuración de la política</translation>
<translation id="8866928039507595380">Plegar</translation>
@@ -1945,6 +1989,7 @@ Más información:
<translation id="8912362522468806198">cuenta de Google</translation>
<translation id="8913778647360618320">Botón Gestionar métodos de pago, pulsa Intro para gestionar la información de tus pagos y tarjetas de crédito desde la configuración de Chrome</translation>
<translation id="8918231688545606538">Esta página es sospechosa</translation>
+<translation id="8922013791253848639">Permite los anuncios siempre en este sitio web</translation>
<translation id="892588693504540538">Perforado en la parte superior derecha</translation>
<translation id="8931333241327730545">¿Quieres guardar esta tarjeta en tu cuenta de Google?</translation>
<translation id="8932102934695377596">Tu reloj está atrasado</translation>
@@ -1968,7 +2013,7 @@ Más información:
<translation id="9004367719664099443">Sesión de realidad virtual en curso</translation>
<translation id="9005998258318286617">Se ha producido un error al cargar el documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
-<translation id="9011424611726486705">Abrir ajustes de sitios web</translation>
+<translation id="9011424611726486705">Abrir ajustes de sitios</translation>
<translation id="9020200922353704812">La dirección de facturación de la tarjeta es obligatoria</translation>
<translation id="9020542370529661692">Esta página se ha traducido al <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -1995,7 +2040,7 @@ Más información:
<translation id="9114524666733003316">Confirmando tarjeta...</translation>
<translation id="9114581008513152754">Este navegador no lo administra ninguna empresa ni organización. Es posible que se administre la actividad de este dispositivo fuera de Chrome. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
<translation id="9119042192571987207">Subido</translation>
-<translation id="9128870381267983090">Conectarse a la red</translation>
+<translation id="9128870381267983090">Conéctate a la red</translation>
<translation id="9137013805542155359">Mostrar original</translation>
<translation id="9141013498910525015">Gestionar direcciones</translation>
<translation id="9148088599418889305">Seleccionar método de envío</translation>
@@ -2005,7 +2050,7 @@ Más información:
<translation id="9154194610265714752">Actualizado</translation>
<translation id="9157595877708044936">Configurando...</translation>
<translation id="9158625974267017556">C6 (sobre)</translation>
-<translation id="9168814207360376865">Permitir a los sitios web saber si tienes métodos de pago guardados</translation>
+<translation id="9168814207360376865">Permite a los sitios comprobar si tienes métodos de pago guardados</translation>
<translation id="9169664750068251925">Bloquear siempre en este sitio</translation>
<translation id="9170848237812810038">&amp;Deshacer</translation>
<translation id="9171296965991013597">¿Quieres salir de la aplicación?</translation>
@@ -2016,6 +2061,7 @@ Más información:
<translation id="9183302530794969518">Documentos de Google</translation>
<translation id="9183425211371246419">La página <ph name="HOST_NAME" /> utiliza un protocolo no admitido.</translation>
<translation id="9191834167571392248">Perforado en la parte inferior izquierda</translation>
+<translation id="9199905725844810519">La impresión está bloqueada</translation>
<translation id="9205078245616868884">Tus datos se han cifrado con tu frase de contraseña de sincronización. Introdúcela para iniciar la sincronización.</translation>
<translation id="9207861905230894330">Se ha producido un error al añadir el artículo.</translation>
<translation id="9213433120051936369">Personalizar aspecto</translation>
@@ -2026,8 +2072,10 @@ Más información:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Podrías perder el acceso a tu cuenta de Google. Chromium te recomienda que cambies la contraseña ahora. Se te pedirá que inicies sesión.</translation>
<translation id="939736085109172342">Nueva carpeta</translation>
+<translation id="945522503751344254">Enviar comentarios</translation>
<translation id="945855313015696284">Comprueba la información que aparece a continuación y elimina las tarjetas no válidas</translation>
<translation id="950736567201356821">Perforado triple en la parte superior</translation>
+<translation id="951941430552851965">Tu administrador ha pausado la captura de pantalla debido al contenido que se muestra en la pantalla.</translation>
<translation id="961663415146723894">Encuadernar por la parte inferior</translation>
<translation id="962484866189421427">Este contenido podría intentar instalar aplicaciones engañosas que se hagan pasar por otra persona o recojan datos que podrían usarse para realizar un seguimiento de tu actividad. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Build oficial</translation>
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index c663449e01b..9e97a833017 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -80,6 +80,14 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Sisestasite oma parooli saidile, mida ei halda teie organisatsioon. Oma konto kaitsmiseks ärge kasutage oma parooli muudes rakendustes ega saitidel.</translation>
<translation id="1263231323834454256">Lugemisloend</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Tegevused, mida sellesse seadmesse ei salvestata.
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Lehed, mida selles aknas vaatate.
+ <ph name="LIST_ITEM" />Küpsisefailid ja saidiandmed.
+ <ph name="LIST_ITEM" />Konto teave (<ph name="LINK_BEGIN" />väljalogimine<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Kättesaamisviis</translation>
<translation id="1281476433249504884">Virnastaja 1</translation>
<translation id="1285320974508926690">Ära kunagi seda saiti tõlgi</translation>
@@ -282,6 +290,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="204357726431741734">Logige sisse, et kasutada oma Google'i kontole salvestatud paroole</translation>
<translation id="2053111141626950936">Selles keeles lehti ei tõlgita: <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Postiindeks</translation>
+<translation id="2054665754582400095">Teie kohalolek</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 soovitus}other{# soovitust}}</translation>
<translation id="2079545284768500474">Võta tagasi</translation>
<translation id="20817612488360358">Kasutamiseks on määratud süsteemi puhverserveri seaded, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
@@ -295,6 +304,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2102495993840063010">Androidi rakendused</translation>
<translation id="2107021941795971877">Prinditeenuste toed</translation>
<translation id="2108755909498034140">Taaskäivitage oma arvuti</translation>
+<translation id="2111166930115883695">Mängimiseks vajutage tühikuklahvi</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kaart</translation>
<translation id="2114841414352855701">Seda ignoreeritakse, kuna reegel <ph name="POLICY_NAME" /> alistab selle.</translation>
@@ -306,6 +316,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="214556005048008348">Tühista makse</translation>
<translation id="2147827593068025794">Taustal sünkroonimine</translation>
<translation id="2148613324460538318">Lisa kaart</translation>
+<translation id="2149968176347646218">Ãœhendus ei ole turvaline</translation>
<translation id="2154054054215849342">Sünkroonimisteenus pole domeeni jaoks saadaval</translation>
<translation id="2154484045852737596">Kaardi muutmine</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -316,7 +327,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2181821976797666341">Reeglid</translation>
<translation id="2183608646556468874">Telefoninumber</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 aadress}other{# aadressi}}</translation>
-<translation id="2187243482123994665">Kasutaja kohalolek</translation>
<translation id="2187317261103489799">Tuvasta (vaikimisi)</translation>
<translation id="2188375229972301266">Mitu auku all</translation>
<translation id="2202020181578195191">Sisestage kehtiv aegumisaasta</translation>
@@ -469,6 +479,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2839501879576190149">Ees on võltssait</translation>
<translation id="2850739647070081192">Invite (ümbrik)</translation>
<translation id="2856444702002559011">Ründajad võivad üritada varastada teie teavet (nt paroole, sõnumeid või krediitkaarditeavet) saidilt <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Sait kuvab sekkuvaid või eksitavaid reklaame.</translation>
<translation id="2878197950673342043">Plakatikujuliselt volditud</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Akende paigutus</translation>
@@ -507,11 +518,11 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2996674880327704673">Soovitused Google'ilt</translation>
<translation id="3002501248619246229">Kontrolli sisestussalve meediat</translation>
<translation id="3005723025932146533">Kuva salvestatud koopia</translation>
-<translation id="3007719053326478567">Administraator on selle sisu printimise blokeerinud</translation>
<translation id="3008447029300691911">Sisestage krediitkaardi <ph name="CREDIT_CARD" /> CVC. Kui selle kinnitate, jagatakse teie kaardi üksikasju selle saidiga.</translation>
<translation id="3010559122411665027">Loendi kirje „<ph name="ENTRY_INDEX" />â€: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automaatselt blokeeritud</translation>
<translation id="3016780570757425217">Teada teie asukohta</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, vajutage tabulaatorit ja seejärel sisestusklahvi, et soovitus eemaldada.</translation>
<translation id="3023071826883856138">You4 (ümbrik)</translation>
<translation id="3024663005179499861">Reegli tüüp on vale</translation>
<translation id="3037605927509011580">Ups, ebaõnn!</translation>
@@ -554,6 +565,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3207960819495026254">Järjehoidjatesse lisatud</translation>
<translation id="3209034400446768650">Leht võib võtta tasu</translation>
<translation id="3212581601480735796">Teie tegevust seadmes <ph name="HOSTNAME" /> jälgitakse</translation>
+<translation id="3212623355668894776">Sulgege kõik külalise aknad, et oma sirvimistegevused sellest seadmest kustutada.</translation>
<translation id="3215092763954878852">Ãœksust WebAuthn ei saanud kasutada</translation>
<translation id="3218181027817787318">Suhteline</translation>
<translation id="3225919329040284222">Serveri esitatud sertifikaat ei vasta sisseehitatud ootustele. Ootused on teie kaitsmiseks kaasatud kindlate kõrge turvalisusega veebisaitide jaoks.</translation>
@@ -701,6 +713,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3784372983762739446">Bluetooth-seadmed</translation>
<translation id="3787705759683870569">Aegub: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Suurus 16</translation>
+<translation id="3789841737615482174">Installi</translation>
<translation id="3793574014653384240">Hiljutiste krahhide arv ja põhjused</translation>
<translation id="3797522431967816232">Prc3 (ümbrik)</translation>
<translation id="3799805948399000906">Taotleti fonti</translation>
@@ -752,6 +765,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4056223980640387499">Seepia</translation>
<translation id="4058922952496707368">Võti „<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ümbrik)</translation>
+<translation id="4067669230157909013">Ekraanikuva jäädvustamist jätkatakse.</translation>
<translation id="4067947977115446013">Sobiva aadressi lisamine</translation>
<translation id="4072486802667267160">Teie tellimuse töötlemisel ilmnes viga. Proovige uuesti.</translation>
<translation id="4075732493274867456">Klient ja server ei toeta tavapärast SSL-protokolli versiooni ega šifreerimiskomplekti.</translation>
@@ -836,6 +850,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4297502707443874121">Lehe <ph name="THUMBNAIL_PAGE" /> pisipilt</translation>
<translation id="42981349822642051">Laienda</translation>
<translation id="4300675098767811073">Mitu auku paremal</translation>
+<translation id="4302514097724775343">Mängimiseks puudutage dinosaurust</translation>
<translation id="4302965934281694568">Chou3 (ümbrik)</translation>
<translation id="4305666528087210886">Teie failile ei pääsetud juurde</translation>
<translation id="4305817255990598646">Lüliti</translation>
@@ -914,6 +929,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4658638640878098064">Kirjaklamber vasakul ülal</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuaalreaalsus</translation>
+<translation id="4675657451653251260">Te ei näe külalisrežiimis Chrome'i profiili teavet. Võite <ph name="LINK_BEGIN" />sisse logida<ph name="LINK_END" />, et pääseda juurde oma Google'i konto teabele, nagu paroolid ja makseviisid.</translation>
<translation id="467662567472608290">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat sisaldab vigu. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="4677585247300749148"><ph name="URL" /> soovib vastata juurdepääsetavuse sündmustele</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -941,6 +957,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4761104368405085019">Mikrofoni kasutamine</translation>
<translation id="4764776831041365478">Veebileht aadressil <ph name="URL" /> võib olla ajutiselt maas või jäädavalt uuele veebiaadressile teisaldatud.</translation>
<translation id="4766713847338118463">Kaks kirjaklambrit all</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Tegevused, mis jäävad sellesse seadmesse.
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Kõik selles aknas allalaaditavad failid.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Tekkis tundmatu viga.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Hüpikaken blokeeriti}other{# hüpikakent blokeeriti}}</translation>
<translation id="4780366598804516005">Postkast 1</translation>
@@ -1103,11 +1125,13 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5386426401304769735">Selle saidi sertifikaadiahel sisaldab sertifikaati, mis on allkirjastatud SHA-1-ga.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Õmblus paremas servas</translation>
+<translation id="5398772614898833570">Reklaamid on blokeeritud</translation>
<translation id="5400836586163650660">Hall</translation>
<translation id="540969355065856584">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />; selle turvasertifikaat pole praegu kehtiv. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="541416427766103491">Virnastaja 4</translation>
<translation id="5421136146218899937">Sirvimisandmete kustutamine ...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> soovib teile saata märguandeid</translation>
+<translation id="542872847390508405">Sirvite külalisena</translation>
<translation id="5430298929874300616">Järjehoidja eemaldamine</translation>
<translation id="5439770059721715174">Skeemi valideerimise viga asukohas „<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Vastupidine järjestus, esikülg ülespoole</translation>
@@ -1149,12 +1173,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5571083550517324815">Sellelt aadressilt ei saa kaupa kätte. Valige mõni teine aadress.</translation>
<translation id="5580958916614886209">Kontrollige aegumiskuud ja proovige uuesti</translation>
<translation id="5586446728396275693">Salvestatud aadresse pole</translation>
+<translation id="5593349413089863479">Ühendus pole täiesti turvaline</translation>
<translation id="5595485650161345191">Muuda aadressi</translation>
<translation id="5598944008576757369">Valige makseviis</translation>
<translation id="560412284261940334">Haldust ei toetata</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">See sait võib olla võlts või petturlik. Chrome soovitab kohe lahkuda.</translation>
<translation id="5610142619324316209">Kontrollige ühendust</translation>
<translation id="5610807607761827392">Kaarte ja aadresse saate hallata menüüs <ph name="BEGIN_LINK" />Seaded<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Tõlkige see leht rakendusega Google'i tõlge</translation>
@@ -1226,6 +1250,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5901630391730855834">Kollane</translation>
<translation id="5905445707201418379">Blokeeritud saidi <ph name="ORIGIN" /> lähtekohareegli tõttu.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sünkroonitud)</translation>
+<translation id="5913377024445952699">Ekraanikuva jäädvustamine on peatatud</translation>
<translation id="59174027418879706">Lubatud</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Sees</translation>
@@ -1238,6 +1263,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5963413905009737549">Jaotis</translation>
<translation id="5967592137238574583">Kontaktteabe muutmine</translation>
<translation id="5967867314010545767">Eemalda ajaloost</translation>
+<translation id="5968793460449681917">Igal külastusel</translation>
<translation id="5975083100439434680">Suumib välja</translation>
<translation id="5979084224081478209">Kontrolli paroole</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6587923378399804057">Teie kopeeritud link</translation>
<translation id="6591833882275308647">Teie seadet <ph name="DEVICE_TYPE" /> ei hallata</translation>
<translation id="6596325263575161958">Krüpteerimise valikud</translation>
+<translation id="6596892391065203054">Administraator on selle sisu printimise blokeerinud.</translation>
<translation id="6604181099783169992">Liikumis- või valgusandurid</translation>
<translation id="6609880536175561541">Prc7 (ümbrik)</translation>
<translation id="6612358246767739896">Kaitstud sisu</translation>
@@ -1452,6 +1479,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6895330447102777224">Teie kaart on kinnitatud</translation>
<translation id="6897140037006041989">Kasutajaagent</translation>
<translation id="6898699227549475383">Organisatsioon (O)</translation>
+<translation id="6907293445143367439">Lubage rakendusel <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> soovib teie MIDI-seadmeid täielikult juhtida</translation>
<translation id="6915804003454593391">Kasutaja:</translation>
<translation id="6934672428414710184">Nimi pärineb teie Google'i kontolt</translation>
@@ -1563,6 +1591,7 @@ Lisateave:
<translation id="7346048084945669753">On seotud:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Käsurida</translation>
+<translation id="7359588939039777303">Reklaamid on blokeeritud.</translation>
<translation id="7372973238305370288">otsingutulemus</translation>
<translation id="7374733840632556089">Selle probleemi põhjuseks on teie või kellegi teise installitud sertifikaat. Seda sertifikaati kasutatakse võrkude jälgimiseks ja ühenduste katkestamiseks ning Chrome ei usalda seda. Kuigi mõnel puhul on jälgimine seaduslik (nt kooli või ettevõtte võrgus), soovib Chrome tagada, et oleksite sellest teadlik ka juhul, kui te ei saa seda peatada. Jälgimine võib toimuda veebiühendusega brauseris või rakenduses.</translation>
<translation id="7375818412732305729">Fail on manustatud</translation>
@@ -1737,6 +1766,7 @@ Lisateave:
<translation id="7976214039405368314">Liiga palju päringuid</translation>
<translation id="7977538094055660992">Väljundseade</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Liitreaalsuse sisu vaatamiseks installige ARCore</translation>
<translation id="799149739215780103">Köide</translation>
<translation id="7995512525968007366">Ei ole määratud</translation>
<translation id="800218591365569300">Sulgege muud vahelehed või programmid, et mälu vabastada.</translation>
@@ -1864,24 +1894,38 @@ Lisateave:
<translation id="8507227106804027148">Käsurida</translation>
<translation id="8508648098325802031">Otsinguikoon</translation>
<translation id="8522552481199248698">Chrome aitab teil oma Google'i kontot kaitsta ja parooli muuta.</translation>
+<translation id="8525306231823319788">Täisekraan</translation>
<translation id="8530813470445476232">Kustutage Chrome'i seadetes oma sirvimisajalugu ja küpsisefailid ning tühjendage vahemälu</translation>
<translation id="8533619373899488139">Külastage saiti &lt;strong&gt;chrome://policy&lt;/strong&gt;, et näha blokeeritud URL-ide loendit ja teisi reegleid, mille teie süsteemiadministraator on jõustanud.</translation>
<translation id="8541158209346794904">Bluetooth-seade</translation>
<translation id="8542014550340843547">Kolm kirjaklambrit all</translation>
<translation id="8543181531796978784">Võite <ph name="BEGIN_ERROR_LINK" />teavitada tuvastusprobleemist<ph name="END_ERROR_LINK" />. Kui mõistate ohtusid oma turvalisusele, võite <ph name="BEGIN_LINK" />seda ebaturvalist saiti külastada<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC asub kaardi tagaküljel.</translation>
+<translation id="8558485628462305855">Liitreaalsuse sisu vaatamiseks värskendage ARCore'i</translation>
<translation id="8559762987265718583">Privaatset ühendust ei saa domeeniga <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> luua, kuna seadme kuupäev ja kellaaeg (<ph name="DATE_AND_TIME" />) on valed.</translation>
<translation id="8564182942834072828">Eraldi dokumendid / järjestamata koopiad</translation>
<translation id="8564985650692024650">Chromium soovitab teil organisatsiooni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parooli lähtestada, kui kasutasite seda ka muudel saitidel.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Tegevused, mida sellesse seadmesse ei salvestata.
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Lehed, mida selles aknas vaatate.
+ <ph name="LIST_ITEM" />Küpsisefailid ja saidiandmed.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Kasutage kaartide kiiremaks kinnitamiseks Touch ID-d</translation>
<translation id="858637041960032120">Lisage telefoninumber</translation>
<translation id="8589998999637048520">Parim kvaliteet</translation>
+<translation id="8600271352425265729">Ainult see kord</translation>
<translation id="860043288473659153">Kaardiomaniku nimi</translation>
<translation id="8606726445206553943">Kasutada MIDI-seadmeid</translation>
+<translation id="8612761427948161954">Tere, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Sirvite külalisena.</translation>
<translation id="861775596732816396">Suurus 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ühtivaid paroole ei ole. Vaadake kõiki salvestatud paroole.</translation>
<translation id="8625384913736129811">Salvesta kaart sellesse seadmesse</translation>
+<translation id="8627040765059109009">Ekraanikuva jäädvustamine jätkub</translation>
<translation id="8657078576661269990">Administraator blokeeris jagamise saidilt <ph name="ORIGIN_NAME" /> virtuaalmasinatesse <ph name="VM_NAME_1" /> ja <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Tellimuse kokkuvõte, <ph name="TOTAL_LABEL" />, rohkem üksikasju</translation>
<translation id="867224526087042813">Allkiri</translation>
@@ -1944,6 +1988,7 @@ Lisateave:
<translation id="8912362522468806198">Google'i konto</translation>
<translation id="8913778647360618320">Nupp Makseviiside haldamine, vajutage Chrome'i seadetes maksete ja krediitkaarditeabe haldamiseks sisestusklahvi</translation>
<translation id="8918231688545606538">See leht on kahtlane</translation>
+<translation id="8922013791253848639">Luba sellel saidil alati reklaamid</translation>
<translation id="892588693504540538">Auk ülal paremal</translation>
<translation id="8931333241327730545">Kas soovite selle kaardi salvestada oma Google'i kontole?</translation>
<translation id="8932102934695377596">Teie kell on taga</translation>
@@ -2015,6 +2060,7 @@ Lisateave:
<translation id="9183302530794969518">Google'i dokumendid</translation>
<translation id="9183425211371246419">Host <ph name="HOST_NAME" /> kasutab toetamata protokolli.</translation>
<translation id="9191834167571392248">Auk vasakul all</translation>
+<translation id="9199905725844810519">Printimine on blokeeritud</translation>
<translation id="9205078245616868884">Teie andmed on krüpteeritud teie sünkroonimisparooliga. Sisestage see sünkroonimise alustamiseks.</translation>
<translation id="9207861905230894330">Artikli lisamine ebaõnnestus.</translation>
<translation id="9213433120051936369">Ilme kohandamine</translation>
@@ -2025,8 +2071,10 @@ Lisateave:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Võite kaotada juurdepääsu oma Google'i kontole. Chromium soovitab teil kohe oma parooli muuta. Teil palutakse sisse logida.</translation>
<translation id="939736085109172342">Uus kaust</translation>
+<translation id="945522503751344254">Tagasiside saatmine</translation>
<translation id="945855313015696284">Vaadake allolevat teavet ja kustutage sobimatud kaardid</translation>
<translation id="950736567201356821">Kolm auku ülal</translation>
+<translation id="951941430552851965">Administraator on ekraanikuva jäädvustamise ekraanil kuvatud sisu tõttu ajutiselt peatanud.</translation>
<translation id="961663415146723894">Köide all</translation>
<translation id="962484866189421427">Sisu võib üritada installida petturlikke rakendusi, mis esinevad millegi muuna või koguvad andmeid, mida saab kasutada teie jälgimiseks. <ph name="BEGIN_LINK" />Kuva siiski<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Ametlik järk</translation>
diff --git a/chromium/components/strings/components_strings_eu.xtb b/chromium/components/strings/components_strings_eu.xtb
index bbe9b26fcb5..af84bf25215 100644
--- a/chromium/components/strings/components_strings_eu.xtb
+++ b/chromium/components/strings/components_strings_eu.xtb
@@ -80,6 +80,14 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Zure erakundeak kudeatzen ez duen webgune batean idatzi duzu pasahitza. Kontua babesteko, ez erabili berriro pasahitz hori beste inongo aplikazio eta webgunetan.</translation>
<translation id="1263231323834454256">Irakurketa-zerrenda</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Jarduera hauek ez dira gordeko gailuan:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />leiho honetan ikusten dituzun orriak,
+ <ph name="LIST_ITEM" />cookieak eta webguneetako datuak,
+ <ph name="LIST_ITEM" />kontuaren informazioa (<ph name="LINK_BEGIN" />amaitu saioa<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Jasotzeko modua</translation>
<translation id="1281476433249504884">1. pilatzailea</translation>
<translation id="1285320974508926690">Ez itzuli inoiz webgune hau</translation>
@@ -239,7 +247,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1826516787628120939">Egiaztatzen</translation>
<translation id="1834321415901700177">Webgune honek programa kaltegarriak ditu</translation>
<translation id="1838374766361614909">Garbitu bilaketa</translation>
-<translation id="1839551713262164453">Gidalerroen balioen balidazioak huts egin du eta erroreak ditu</translation>
+<translation id="1839551713262164453">Gidalerroetako balioen baliozkotzeak huts egin du eta erroreak ditu</translation>
<translation id="1842969606798536927">Ordaindu</translation>
<translation id="1871208020102129563">Proxy-zerbitzari finkoak erabiltzeko konfiguratu da proxya, ez .pac scripteko URLak erabiltzeko.</translation>
<translation id="1871284979644508959">Derrigorrezko eremua</translation>
@@ -279,6 +287,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="204357726431741734">Hasi saioa Google-ko kontuan gordetako pasahitzak erabiltzeko</translation>
<translation id="2053111141626950936">Ez dira itzuliko <ph name="LANGUAGE" /> darabilten orriak.</translation>
<translation id="2053553514270667976">Posta-kodea</translation>
+<translation id="2054665754582400095">Zure presentzia</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 iradokizun}other{# iradokizun}}</translation>
<translation id="2079545284768500474">Desegin</translation>
<translation id="20817612488360358">Erabiltzeko ezarri dira sistemaren proxy-ezarpenak, baina proxy-konfigurazio esplizitu bat ere zehaztu da.</translation>
@@ -292,6 +301,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2102495993840063010">Android-erako aplikazioak</translation>
<translation id="2107021941795971877">Inprimatze-euskarriak</translation>
<translation id="2108755909498034140">Berrabiarazi ordenagailua</translation>
+<translation id="2111166930115883695">Sakatu zuriune-barra jokatzeko</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Txartela</translation>
<translation id="2114841414352855701">Ez ikusi egin zaio <ph name="POLICY_NAME" /> gidalerroak gainidatzi duelako.</translation>
@@ -303,6 +313,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="214556005048008348">Utzi bertan behera ordainketa</translation>
<translation id="2147827593068025794">Atzeko planoko sinkronizazioa</translation>
<translation id="2148613324460538318">Gehitu txartela</translation>
+<translation id="2149968176347646218">Konexioa ez da segurua</translation>
<translation id="2154054054215849342">Sinkronizazioa ez dago erabilgarri zure domeinuan</translation>
<translation id="2154484045852737596">Editatu txartela</translation>
<translation id="2161656808144014275">testua</translation>
@@ -313,7 +324,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2181821976797666341">Gidalerroak</translation>
<translation id="2183608646556468874">Telefono-zenbakia</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 helbide}other{# helbide}}</translation>
-<translation id="2187243482123994665">Erabiltzailearen presentzia</translation>
<translation id="2187317261103489799">Hauteman (lehenetsia)</translation>
<translation id="2188375229972301266">Hainbat zulo behean</translation>
<translation id="2202020181578195191">Idatzi balio duen iraungitze-urte bat</translation>
@@ -464,9 +474,10 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2839501879576190149">Faltsua da webgunea</translation>
<translation id="2850739647070081192">Invite (gutun-azala)</translation>
<translation id="2856444702002559011">Baliteke erasotzaile batzuk <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webgunean duzun informazioa lapurtzen saiatzen aritzea (adibidez, pasahitzak, mezuak edo kreditu-txartelen datuak). <ph name="BEGIN_LEARN_MORE_LINK" />Lortu informazio gehiago<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Webgune honek iragarki oztopatzaile edo iruzurrezkoak erakusten ditu.</translation>
<translation id="2878197950673342043">Horma-irudi tolestura</translation>
<translation id="2878424575911748999">A1</translation>
-<translation id="2880660355386638022">Leihoaren kokalekua</translation>
+<translation id="2880660355386638022">Leihoen agerpena</translation>
<translation id="2881276955470682203">Txartela gorde nahi duzu?</translation>
<translation id="2882949212241984732">Leiho bikoitz erako tolestura</translation>
<translation id="2903493209154104877">Helbideak</translation>
@@ -502,11 +513,11 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2996674880327704673">Google-ren iradokizunak</translation>
<translation id="3002501248619246229">Egiaztatu sarrerako erretiluaren euskarria</translation>
<translation id="3005723025932146533">Erakutsi gordetako kopia</translation>
-<translation id="3007719053326478567">Administratzaileak blokeatu egin du eduki hau inprimatzeko aukera</translation>
<translation id="3008447029300691911">Idatzi <ph name="CREDIT_CARD" /> txartelaren CVC kodea. Berretsi ondoren, webgune honekin partekatuko dira txartelaren xehetasunak.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />" zerrenda-sarrera: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatikoki blokeatuta</translation>
<translation id="3016780570757425217">Ezagutu zure kokapena</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />: sakatu tabuladorea eta Sartu tekla iradokizuna kentzeko.</translation>
<translation id="3023071826883856138">You4 (gutun-azala)</translation>
<translation id="3024663005179499861">Gidalerro mota okerra</translation>
<translation id="3037605927509011580">Hutsegite bat izan da.</translation>
@@ -546,6 +557,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3207960819495026254">Laster-marka gisa gordea</translation>
<translation id="3209034400446768650">Baliteke orriak dirua kobratzea</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> webgunean egiten ari zarena gainbegiratzen ari dira</translation>
+<translation id="3212623355668894776">Itxi gonbidatu moduko leiho guztiak arakatze-jarduerak ezabatzeko gailu honetatik.</translation>
<translation id="3215092763954878852">Ezin izan da erabili WebAuthn</translation>
<translation id="3218181027817787318">Erlatiboa</translation>
<translation id="3225919329040284222">Zerbitzariak aurkeztu duen ziurtagiria ez dator bat integratutako eskakizunekin. Eskakizun horiek segurtasun handiko webgune batzuek egiten dituzte erabiltzaileak babesteko.</translation>
@@ -692,6 +704,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3784372983762739446">Bluetooth bidezko gailuak</translation>
<translation id="3787705759683870569">Iraungitze-data: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamaina: 16</translation>
+<translation id="3789841737615482174">Instalatu</translation>
<translation id="3793574014653384240">Azkenaldian gertatutako hutsegiteen kopurua eta arrazoiak</translation>
<translation id="3797522431967816232">Prc3 (gutun-azala)</translation>
<translation id="3799805948399000906">Eskatutako letra</translation>
@@ -742,6 +755,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" tekla: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (gutun-azala)</translation>
+<translation id="4067669230157909013">Pantaila-kapturari berrekin zaio.</translation>
<translation id="4067947977115446013">Gehitu balio duen helbide bat</translation>
<translation id="4072486802667267160">Errore bat gertatu da eskaera prozesatzean. Saiatu berriro.</translation>
<translation id="4075732493274867456">Bezeroak eta zerbitzariak ez dute onartzen SSL protokoloaren bertsio edo enkriptatze multzo arrunta.</translation>
@@ -822,6 +836,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> orriaren irudi txikia</translation>
<translation id="42981349822642051">Zabaldu</translation>
<translation id="4300675098767811073">Hainbat zulo eskuinean</translation>
+<translation id="4302514097724775343">Sakatu dinosauroa jokatzeko</translation>
<translation id="4302965934281694568">Chou3 (gutun-azala)</translation>
<translation id="4305666528087210886">Ezin izan da atzitu fitxategia</translation>
<translation id="4305817255990598646">Aldatu</translation>
@@ -854,7 +869,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4414290883293381923">Webgune engainagarri batean idatzi duzu pasahitza. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> eta <ph name="WEBSITE_3" /> webguneetara eta pasahitz hori erabili duzun beste webgune batzuetara joatea gomendatzen dizu Chrome-k.</translation>
<translation id="4415426530740016218">Jasotzeko helbidea</translation>
<translation id="4424024547088906515">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Chrome ez da bere segurtasun-ziurtagiriaz fidatzen. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
-<translation id="443121186588148776">Serie-ataka</translation>
+<translation id="443121186588148776">Serieko ataka</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> webguneak ez du onartu edo jaso saioa hasteko ziurtagiria.</translation>
<translation id="4432792777822557199"><ph name="SOURCE_LANGUAGE" /> darabilten orriak <ph name="TARGET_LANGUAGE" /> hizkuntzara itzuliko dira</translation>
<translation id="4434045419905280838">Leiho gainerak. / Birbideratzeak</translation>
@@ -893,13 +908,14 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4597348597567598915">Tamaina: 8</translation>
<translation id="4600854749408232102">C6/C5 (gutun-azala)</translation>
<translation id="4628948037717959914">Argazkia</translation>
-<translation id="4631649115723685955">Eskudirua itzultzeko aukerarekin</translation>
+<translation id="4631649115723685955">Dirua berreskuratzeko aukerarekin</translation>
<translation id="464342062220857295">Bilaketa-eginbideak</translation>
<translation id="4644670975240021822">Alderantzizko ordenan, ahuspez</translation>
<translation id="4646534391647090355">Eraman nazazu hara</translation>
<translation id="4658638640878098064">Grapa bat goian, ezkerretara</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Errealitate birtuala</translation>
+<translation id="4675657451653251260">Ez duzu ikusiko Chrome-ko profilari buruzko informaziorik gonbidatu moduan. Google-ko kontuko informazioa (adibidez, pasahitzak eta ordainketa-metodoak) atzitzeko, <ph name="LINK_BEGIN" />hasi saioa<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Bere segurtasun-ziurtagiriak erroreak ditu. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
<translation id="4677585247300749148"><ph name="URL" /> webguneak erabilerraztasun-gertaerei erantzun nahi die</translation>
<translation id="467809019005607715">Google Aurkezpenak</translation>
@@ -927,6 +943,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4761104368405085019">Erabili mikrofonoa</translation>
<translation id="4764776831041365478">Baliteke <ph name="URL" /> helbideko web-orria tarte batez ez funtzionatzea edo beste web-helbide batera behin betiko aldatu izatea.</translation>
<translation id="4766713847338118463">Bi grapa behean</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Jarduera hauek gailuan gordeko dira:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />leiho honetan deskargatzen dituzun fitxategiak.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Errore ezezagun bat gertatu da.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Leiho gainerakor bat blokeatu da}other{# leiho gainerakor blokeatu dira}}</translation>
<translation id="4780366598804516005">1. postontzia</translation>
@@ -941,7 +963,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Une honetan ezin zara joan <ph name="SITE" /> webgunera, Google Chrome-k prozesatu ezin dituen kredentzial nahasiak bidali baititu webguneak. Sareko erroreak eta erasoak aldi baterako izan ohi dira. Beraz, segur aski geroago funtzionatuko du orriak.</translation>
<translation id="4809079943450490359">Gailuaren administratzailearen argibideak:</translation>
-<translation id="4813512666221746211">Sarearen errorea</translation>
+<translation id="4813512666221746211">Sareko errorea</translation>
<translation id="4816492930507672669">Egokitu orrira</translation>
<translation id="4819347708020428563">Ikuspegi lehenetsian editatu nahi dituzu oharpenak?</translation>
<translation id="484462545196658690">Automatikoa</translation>
@@ -1062,7 +1084,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5285570108065881030">Erakutsi gordetako pasahitz guztiak</translation>
<translation id="5287240709317226393">Erakutsi cookieak</translation>
<translation id="5287456746628258573">Webgune honek segurtasun-konfigurazio zaharkitu bat erabiltzen du; ondorioz, baliteke zure informazioa (adibidez, pasahitzak edo kreditu-txartelen zenbakiak) agerian uztea webgune honetara bidaltzen duzunean.</translation>
-<translation id="5288108484102287882">Gidalerroen balioen balidazioak abisu batzuk sortu ditu</translation>
+<translation id="5288108484102287882">Gidalerroetako balioen baliozkotzeak abisu batzuk sortu ditu</translation>
<translation id="5289384342738547352">Dokumentu bat baino gehiago kudeatzea</translation>
<translation id="5295292838686006428">Erabiltzen duzun webgune edo aplikazio batean datuen isilpekotasuna urratu denez, zure pasahitza atzitzeko aukera izan dute. Gordetako pasahitzak seguru daudela egiaztatzea gomendatzen du Chrome-k.</translation>
<translation id="5299298092464848405">Errore bat gertatu da gidalerroak analizatzean</translation>
@@ -1089,11 +1111,13 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5386426401304769735">Webgune honen ziurtagiri-kateak SHA-1 bidez sinatutako ziurtagiri bat dauka.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Eskuineko ertza josita</translation>
+<translation id="5398772614898833570">Blokeatu egin dira iragarkiak</translation>
<translation id="5400836586163650660">Grisa</translation>
<translation id="540969355065856584">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> denik. Une honetan, bere segurtasun-ziurtagiriak ez du balio. Oker konfiguratuta dagoelako izan liteke, edo erasotzaile batek zure konexioa atzeman duelako, bestela.</translation>
<translation id="541416427766103491">4. pilatzailea</translation>
<translation id="5421136146218899937">Garbitu arakatze-datuak…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> webguneak jakinarazpenak bidali nahi dizkizu</translation>
+<translation id="542872847390508405">Gonbidatu gisa arakatzen ari zara</translation>
<translation id="5430298929874300616">Kendu laster-marka</translation>
<translation id="5439770059721715174">Eskemaren balidazio-errorea gertatu da ("<ph name="ERROR_PATH" />"): <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Alderantzizko ordenan, ahoz gora</translation>
@@ -1135,12 +1159,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5571083550517324815">Ezin da jaso helbide horretan. Hautatu beste helbide bat.</translation>
<translation id="5580958916614886209">Egiaztatu iraungitze-hilabetea eta saiatu berriro</translation>
<translation id="5586446728396275693">Ez dago helbiderik gordeta</translation>
+<translation id="5593349413089863479">Konexioa ez da guztiz segurua</translation>
<translation id="5595485650161345191">Editatu helbidea</translation>
<translation id="5598944008576757369">Aukeratu ordainketa-metodoa</translation>
<translation id="560412284261940334">Ez da onartzen kudeaketarik</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Webgune hau iruzurrezkoa izan liteke. Chrome-k orain irtetea gomendatzen du.</translation>
<translation id="5610142619324316209">Konexioa egiaztatu.</translation>
<translation id="5610807607761827392"><ph name="BEGIN_LINK" />Ezarpenak<ph name="END_LINK" /> atalean kudea ditzakezu txartelak eta helbideak.</translation>
<translation id="561165882404867731">Itzuli orria Google Translate-rekin</translation>
@@ -1212,6 +1236,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5901630391730855834">Horia</translation>
<translation id="5905445707201418379">Blokeatuta, <ph name="ORIGIN" /> webguneko jatorri-gidalerro bati jarraikiz.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinkronizatuta)</translation>
+<translation id="5913377024445952699">Pausatu da pantaila-argazkiak ateratzeko aukera</translation>
<translation id="59174027418879706">Gaituta</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aktibatuta</translation>
@@ -1224,6 +1249,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5963413905009737549">Atala</translation>
<translation id="5967592137238574583">Editatu harremanetarako informazioa</translation>
<translation id="5967867314010545767">Kendu historiatik</translation>
+<translation id="5968793460449681917">Bisita guztietan</translation>
<translation id="5975083100439434680">Txikitu</translation>
<translation id="5979084224081478209">Egiaztatu pasahitzak</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1270,7 +1296,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6107012941649240045">Nori jaulkia:</translation>
<translation id="610911394827799129">Google-ko kontuko arakatze-historiaren bestelako datu batzuk gera litezke <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> webgunean.</translation>
<translation id="6116338172782435947">Ikusi arbelean kopiatzen ditudan testuak eta irudiak</translation>
-<translation id="6120179357481664955">Gogoan al duzu UPI IDa?</translation>
+<translation id="6120179357481664955">Gogoan al duzu UPIko IDa?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6146055958333702838">Egiaztatu kableak konektatuta daudela eta berrabiarazi erabiltzen ari zaren bideratzaile, modem eta sare-gailu oro.</translation>
<translation id="614940544461990577">Konpontzeko, hauek egin ditzakezu:</translation>
@@ -1302,7 +1328,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6279516281132775660">Chrome-k <ph name="BEGIN_EMPHASIS" />ez du gordeko<ph name="END_EMPHASIS" /> informazio hau:
<ph name="BEGIN_LIST" />
<ph name="LIST_ITEM" />arakatze-historia,
- <ph name="LIST_ITEM" />cookieak eta webguneko datuak,
+ <ph name="LIST_ITEM" />cookieak eta webguneetako datuak,
<ph name="LIST_ITEM" />inprimakietan idatzitako datuak.
<ph name="END_LIST" /></translation>
<translation id="6280223929691119688">Ezin da entregatu helbide horretan. Hautatu beste helbide bat.</translation>
@@ -1378,6 +1404,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6587923378399804057">Kopiatu duzun esteka</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> gailuak ez du kudeatzailerik</translation>
<translation id="6596325263575161958">Enkriptatze aukerak</translation>
+<translation id="6596892391065203054">Administratzaileak blokeatu egin du eduki hau inprimatzeko aukera.</translation>
<translation id="6604181099783169992">Mugimenduaren eta argiaren sentsoreak</translation>
<translation id="6609880536175561541">Prc7 (gutun-azala)</translation>
<translation id="6612358246767739896">Eduki babestua</translation>
@@ -1389,7 +1416,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6631202559048444592">Gidalerroak iturburu bat baino gehiago ditu, baina balio berberekin.</translation>
<translation id="663260587451432563">JIS B4</translation>
<translation id="6643016212128521049">Garbitu</translation>
-<translation id="6645291930348198241">Cookieak eta webgunearen datuak atzitu.</translation>
+<translation id="6645291930348198241">Cookieak eta webguneko datuak atzitu.</translation>
<translation id="6646269444027925224">{COUNT,plural, =0{Bat ere ez}=1{1 gune (ez da amaituko Google-ko kontuko saioa)}other{# gune (ez da amaituko Google-ko kontuko saioa)}}</translation>
<translation id="6648459603387803038">Administratzaileak urrunetik alda dezake arakatzailearen konfigurazioa. Baliteke gailu honetako jarduerak Chrome-tik kanpo ere kudeatzea.</translation>
<translation id="6648524591329069940">Serif letra</translation>
@@ -1437,6 +1464,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6895330447102777224">Berretsi da txartela</translation>
<translation id="6897140037006041989">Erabiltzaile-agentea</translation>
<translation id="6898699227549475383">Erakundea (O)</translation>
+<translation id="6907293445143367439">Eman hau egiteko baimena <ph name="SITE_NAME" /> webguneari:</translation>
<translation id="6910240653697687763"><ph name="URL" /> webguneak MIDI gailuen kontrol osoa nahi du</translation>
<translation id="6915804003454593391">Erabiltzailea:</translation>
<translation id="6934672428414710184">Izen hori Google-ko kontukoa da</translation>
@@ -1548,6 +1576,7 @@ Xehetasun gehiago:
<translation id="7346048084945669753">Kidetuta dago:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Agindu-lerroa</translation>
+<translation id="7359588939039777303">Blokeatu egin dira iragarkiak</translation>
<translation id="7372973238305370288">bilaketa-emaitza</translation>
<translation id="7374733840632556089">Gailuan instalatu duzun edo dizuten ziurtagiri baten ondorioz gertatu da arazoa. Chrome-k ez du jotzen fidagarritzat ziurtagiria, jakina baita sareak atzeman eta kontrolatzeko erabiltzen dela. Legezko kasu batzuetan kontrolatzen bada ere (hala nola ikastetxearen edo enpresaren sareetan), egoeraz jabe zaitezen nahi du Chrome-k, nahiz eta saihestu ezin. Sarea atzitzen duen edozein arakatzaile edo aplikaziotan egiten da gainbegiratzea.</translation>
<translation id="7375818412732305729">Fitxategi bat erantsi da</translation>
@@ -1632,7 +1661,7 @@ Xehetasun gehiago:
<translation id="7633909222644580952">Errendimenduaren datuak eta hutsegite-txostenak</translation>
<translation id="7637571805876720304">Kreditu-txartela Chromium-etik kendu nahi duzu?</translation>
<translation id="7637586430889951925">{COUNT,plural, =0{Bat ere ez}=1{1 pasahitz daukazu kontuan (<ph name="DOMAIN_LIST" />)}other{# pasahitz dauzkazu kontuan (<ph name="DOMAIN_LIST" />)}}</translation>
-<translation id="7638605456503525968">Serie-atakak</translation>
+<translation id="7638605456503525968">Serieko atakak</translation>
<translation id="7639968568612851608">Gris iluna</translation>
<translation id="7647206758853451655">Inprimatze-kalitatea</translation>
<translation id="7648992873808071793">Gorde fitxategiak gailu honetan</translation>
@@ -1722,6 +1751,7 @@ Xehetasun gehiago:
<translation id="7976214039405368314">Eskaera gehiegi daude</translation>
<translation id="7977538094055660992">Irteera-gailua</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Errealitate areagotuko edukia ikusteko, instalatu ARCore</translation>
<translation id="799149739215780103">Koadernatu</translation>
<translation id="7995512525968007366">Ez da zehaztu</translation>
<translation id="800218591365569300">Saiatu beste fitxa edo programa batzuk ixten memoria gehiago uzteko erabilgarri.</translation>
@@ -1849,24 +1879,38 @@ Xehetasun gehiago:
<translation id="8507227106804027148">Agindu-lerroa</translation>
<translation id="8508648098325802031">Bilaketa-ikonoa</translation>
<translation id="8522552481199248698">Google-ko kontua babesten eta pasahitza aldatzen lagun diezazuke Chrome-k.</translation>
+<translation id="8525306231823319788">Pantaila osoa</translation>
<translation id="8530813470445476232">Garbitu arakatze-historia, cookieak, cachea eta beste Chrome-ren ezarpenetan</translation>
<translation id="8533619373899488139">Joan &lt;strong&gt;chrome://policy&lt;/strong&gt; orrira sistemaren administratzaileak blokeatutako URLen zerrenda eta aplikatutako gidalerroak ikusteko.</translation>
<translation id="8541158209346794904">Bluetooth bidezko gailua</translation>
<translation id="8542014550340843547">Hiru grapa behean</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Detekzio-arazoaren berri eman dezakezu<ph name="END_ERROR_LINK" /> edo, segurtasunari eragiten dioten arriskuak ulertzen badituzu, <ph name="BEGIN_LINK" />webgune ez-segurura joan zaitezke<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Txartelaren atzealdean agertzen da CVC kodea.</translation>
+<translation id="8558485628462305855">Errealitate areagotuko edukia ikusteko, eguneratu ARCore</translation>
<translation id="8559762987265718583">Ezin da ezarri <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeinurako konexio pribatua gailuaren data eta ordua (<ph name="DATE_AND_TIME" />) okerrak direlako.</translation>
<translation id="8564182942834072828">Dokumentu bereiziak / Elkartu gabeko kopiak</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> pasahitza beste webgune batzuetan ere erabili baduzu, hura berrezartzea gomendatzen du Chromium-ek.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Jarduera hauek ez dira gordeko gailuan:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />leiho honetan ikusten dituzun orriak,
+ <ph name="LIST_ITEM" />cookieak eta webguneetako datuak.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Erabili Touch ID txartelak bizkorrago berresteko</translation>
<translation id="858637041960032120">Gehitu telefono-zenbakia</translation>
<translation id="8589998999637048520">Kalitaterik onena</translation>
+<translation id="8600271352425265729">Oraingo honetan soilik</translation>
<translation id="860043288473659153">Txartelaren titularraren izena</translation>
<translation id="8606726445206553943">Erabili MIDI gailuak</translation>
+<translation id="8612761427948161954">Kaixo, <ph name="USERNAME" />:
+ <ph name="BR" />
+ Gonbidatu gisa arakatzen ari zara</translation>
<translation id="861775596732816396">Tamaina: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ez dago bat datorren pasahitzik. Erakutsi gordetako pasahitz guztiak.</translation>
<translation id="8625384913736129811">Gorde txartela gailu honetan</translation>
+<translation id="8627040765059109009">Berrekin zaio pantaila-argazkiak ateratzeko aukerari</translation>
<translation id="8657078576661269990">Administratzaileak blokeatu egin du <ph name="ORIGIN_NAME" /> domeinutik <ph name="VM_NAME_1" /> eta <ph name="VM_NAME_2" /> makina birtualetara edukia partekatzeko aukera</translation>
<translation id="8663226718884576429">Eskaeraren laburpena, <ph name="TOTAL_LABEL" />, xehetasun gehiago</translation>
<translation id="867224526087042813">Sinadura</translation>
@@ -1929,6 +1973,7 @@ Xehetasun gehiago:
<translation id="8912362522468806198">Google-ko kontua</translation>
<translation id="8913778647360618320">"Kudeatu ordainketa-metodoak" botoia: sakatu "Sartu" ordainketak eta kreditu-txartelaren informazioa kudeatzeko Chrome-ren ezarpenetan</translation>
<translation id="8918231688545606538">Orri hau susmagarria da</translation>
+<translation id="8922013791253848639">Eman beti iragarkiak webgune honetan erakusteko baimena</translation>
<translation id="892588693504540538">Zulo bat goian, eskuinetara</translation>
<translation id="8931333241327730545">Txartela Google-ko kontuan gorde nahi duzu?</translation>
<translation id="8932102934695377596">Erlojua atzeratuta duzu</translation>
@@ -2000,6 +2045,7 @@ Xehetasun gehiago:
<translation id="9183302530794969518">Google Dokumentuak</translation>
<translation id="9183425211371246419">Onartzen ez den protokolo bat darabil <ph name="HOST_NAME" /> webguneak.</translation>
<translation id="9191834167571392248">Zulo bat behean, ezkerretara</translation>
+<translation id="9199905725844810519">Inprimatzeko aukera blokeatuta dago</translation>
<translation id="9205078245616868884">Sinkronizatzeko pasaesaldiaren bidez daude enkriptatuta datuak. Idatz ezazu sinkronizatzen hasteko.</translation>
<translation id="9207861905230894330">Ezin izan da artikulua gehitu.</translation>
<translation id="9213433120051936369">Pertsonalizatu itxura</translation>
@@ -2010,8 +2056,10 @@ Xehetasun gehiago:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google-ko konturako sarbidea gal zenezake. Pasahitza aldatzea gomendatzen dizu Chromium-ek. Horretarako, saioa hasi beharko duzu.</translation>
<translation id="939736085109172342">Karpeta berria</translation>
+<translation id="945522503751344254">Bidali oharrak</translation>
<translation id="945855313015696284">Egiaztatu beheko informazioa eta ezabatu txartel baliogabeak</translation>
<translation id="950736567201356821">Hiru zulo goian</translation>
+<translation id="951941430552851965">Administratzaileak pausatu egin du pantaila-kaptura, pantailan agertu den edukia dela eta.</translation>
<translation id="961663415146723894">Koadernatu behetik</translation>
<translation id="962484866189421427">Eduki hau beste zerbaiten plantak egiten dituzten aplikazio iruzurtiak instalatzen saia daiteke edo datuak bil ditzake zure jarraipena egiteko. <ph name="BEGIN_LINK" />Erakutsi hala ere<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Konpilazio ofiziala</translation>
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index 469452db8d2..4d5f7980f08 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">گذرواژه‌تان را در سایتی Ú©Ù‡ توسط سازمانتان مدیریت نمی‌شود وارد کردید. برای محاÙظت از حسابتان، از گذرواژه‌تان در سایر برنامه‌ها Ùˆ سایت‌ها مجدداً استÙاده نکنید.</translation>
<translation id="1263231323834454256">Ùهرست خواندن</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ùعالیتی Ú©Ù‡ در این دستگاه نمی‌ماند:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />صÙحاتی Ú©Ù‡ در این پنجره مشاهده می‌کنید
+ <ph name="LIST_ITEM" />کوکی‌ها و داده‌های سایت
+ <ph name="LIST_ITEM" />اطلاعات حساب (<ph name="LINK_BEGIN" />خروج از سیستم<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">روش تحویل گرÙتن</translation>
<translation id="1281476433249504884">پشته‌ساز ۱</translation>
<translation id="1285320974508926690">این سایت هرگز ترجمه نشود</translation>
@@ -137,7 +145,7 @@
<translation id="1462951478840426066">از قلم‌های موجود در رایانه استÙاده کنید تا بتوانید محتوایی با شباهت زیاد به اصل ایجاد کنید</translation>
<translation id="1463543813647160932">ÛµxÛ·</translation>
<translation id="1467432559032391204">Ú†Ù¾</translation>
-<translation id="1472675084647422956">بیشتر ببینید</translation>
+<translation id="1472675084647422956">نمایش بیشتر</translation>
<translation id="1473183651233018052">JIS B10</translation>
<translation id="147358896496811705">2A0</translation>
<translation id="1476595624592550506">گذرواژه‌تان را تغییر دهید</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">â€ÙˆØ±ÙˆØ¯ به سیستم برای استÙاده از گذرواژه‌های ذخیره‌شده در «حساب Google»</translation>
<translation id="2053111141626950936">صÙحه‌های <ph name="LANGUAGE" /> ترجمه نخواهند شد.</translation>
<translation id="2053553514270667976">کد پستی</translation>
+<translation id="2054665754582400095">حضور شما</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{۱ پیشنهاد}one{# پیشنهاد}other{# پیشنهاد}}</translation>
<translation id="2079545284768500474">لغو</translation>
<translation id="20817612488360358">تنظیمات پروکسی سیستم تنظیم شده تا مورد استÙاده قرار گیرد، اما یک پیکربندی مشخص برای پروکسی نیز تعیین شده است.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">â€Ø¨Ø±Ù†Ø§Ù…ه‌های Android</translation>
<translation id="2107021941795971877">پشتیبان‌های چاپ</translation>
<translation id="2108755909498034140">رایانه را راه‌اندازی مجدد کنید</translation>
+<translation id="2111166930115883695">برای بازی کردن، کلید «Ùاصله» را Ùشار دهید</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">کارت</translation>
<translation id="2114841414352855701">نادیده گرÙته شد زیرا <ph name="POLICY_NAME" /> آن را لغو می‌کند.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">لغو پرداخت</translation>
<translation id="2147827593068025794">همگام‌سازی پس‌زمینه</translation>
<translation id="2148613324460538318">اÙزودن کارت</translation>
+<translation id="2149968176347646218">اتصال امن نیست</translation>
<translation id="2154054054215849342">همگام‌سازی برای دامنه شما در دسترس نیست</translation>
<translation id="2154484045852737596">ویرایش کارت</translation>
<translation id="2161656808144014275">نوشتار</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">خط‌ مشی‌ها</translation>
<translation id="2183608646556468874">شماره تلÙÙ†</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{۱ نشانی}one{# نشانی}other{# نشانی}}</translation>
-<translation id="2187243482123994665">حضور کاربر</translation>
<translation id="2187317261103489799">تشخیص (پیش‌Ùرض)</translation>
<translation id="2188375229972301266">چندین سوراخ در پایین</translation>
<translation id="2202020181578195191">سال انقضای معتبری وارد کنید</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">سایت پیش رو جعلی است</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">شاید مهاجم‌ها در تلاش باشند اطلاعات شما (مانند گذرواژه‌ها، پیام‌ها یا کارت‌های اعتباری) را از <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> سرقت کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">این سایتْ آگهی‌های مزاحم یا گمراه‌کننده نشان می‌دهد.</translation>
<translation id="2878197950673342043">تاخوردگی پوسترمانند</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">جای‌گذاری پنجره</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">â€Ù¾ÛŒØ´Ù†Ù‡Ø§Ø¯Ù‡Ø§ÛŒ Google</translation>
<translation id="3002501248619246229">بررسی رسانه سینی ورودی</translation>
<translation id="3005723025932146533">نمایش کپی ذخیره شده</translation>
-<translation id="3007719053326478567">سرپرست چاپ این محتوا را مسدود کرده است</translation>
<translation id="3008447029300691911">â€CVC کارت <ph name="CREDIT_CARD" /> را وارد کنید. بعد از تأیید، جزئیات کارت شما با این سایت به اشتراک گذاشته می‌شود.</translation>
<translation id="3010559122411665027">ورودی Ùهرست "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">مسدود‌شده به‌طور خودکار</translation>
<translation id="3016780570757425217">مکان‌تان را بدانید</translation>
+<translation id="3017086357773116182">â€<ph name="REMOVE_SUGGESTION_SUFFIX" />ØŒ برای «حذ٠پیشنهاد»، کلید «جهش» Ùˆ سپس Enter را Ùشار دهید.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">نوع خط‌مشی اشتباه است</translation>
<translation id="3037605927509011580">اوه، نه!</translation>
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">نشانک‌گذاری شده</translation>
<translation id="3209034400446768650">ممکن است این صÙحه از شما هزینه کسر کند</translation>
<translation id="3212581601480735796">بر Ùعالیت شما در <ph name="HOSTNAME" /> نظارت می‌شود</translation>
+<translation id="3212623355668894776">همه پنجره‌های «مهمان» را ببندید تا Ùعالیت مرورتان در این دستگاه حذ٠شود.</translation>
<translation id="3215092763954878852">â€Ø§Ø³ØªÙاده از WebAuthn ممکن نشد</translation>
<translation id="3218181027817787318">خویشاوند</translation>
<translation id="3225919329040284222">سرور گواهی را نشان می‌دهد Ú©Ù‡ با موارد پیش‌بینی‌شده داخلی مطابقت ندارد. این پیش‌بینی‌ها به‌طور حتم وب‌سایتهای دارای امنیت بالا را جهت محاÙظت از شما در بر می‌گیرند.</translation>
@@ -700,6 +712,7 @@
<translation id="3784372983762739446">دستگاه‌های بلوتوث</translation>
<translation id="3787705759683870569">تاریخ انقضا <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">اندازه ۱۶</translation>
+<translation id="3789841737615482174">نصب</translation>
<translation id="3793574014653384240">تعداد Ùˆ دلیل خرابی‌هایی Ú©Ù‡ اخیراً اتÙاق اÙتاده است</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">قلم درخواست شد</translation>
@@ -751,6 +764,7 @@
<translation id="4056223980640387499">سپیا</translation>
<translation id="4058922952496707368">کلید "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">ضبط صÙحه‌نمایش ازسر گرÙته شد.</translation>
<translation id="4067947977115446013">اÙزودن نشانی معتبر</translation>
<translation id="4072486802667267160">هنگام پردازش سÙارش شما خطایی روی داد. لطÙاً دوباره امتحان کنید.</translation>
<translation id="4075732493274867456">â€Ú©Ù„اینت Ùˆ سرور از مجموعه رمزگذاری یا نسخه پروتکل SSL مشترکی استÙاده نمی‌کنند.</translation>
@@ -835,6 +849,7 @@
<translation id="4297502707443874121">تصویر Ú©ÙˆÚ†Ú© صÙحه <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">بزرگ کردن</translation>
<translation id="4300675098767811073">چند سوراخ در راست</translation>
+<translation id="4302514097724775343">برای بازی کردن، روی دایناسور ضربه بزنید</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">دسترسی به Ùایل شما ممکن نبود</translation>
<translation id="4305817255990598646">جابه‌جایی</translation>
@@ -913,6 +928,7 @@
<translation id="4658638640878098064">منگنه در بالا سمت چپ</translation>
<translation id="4668929960204016307">،</translation>
<translation id="4670064810192446073">واقعیت مجازی</translation>
+<translation id="4675657451653251260">â€Ù†Ù…ی‌توانید اطلاعات نمایه Chrome را در «حالت مهمان» ببینید. برای دسترسی به اطلاعات «حساب Google» (مثل گذرواژه‌ها Ùˆ روش‌های پرداخت)ØŒ می‌توانید <ph name="LINK_BEGIN" />به سیستم وارد شوید<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن خطاهایی دارد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="4677585247300749148"><ph name="URL" /> می‌خواهد به رویدادهای مربوط به دسترس‌پذیری پاسخ دهد</translation>
<translation id="467809019005607715">â€Ø§Ø³Ù„ایدنگار Google</translation>
@@ -940,6 +956,12 @@
<translation id="4761104368405085019">استÙاده از میکروÙون شما</translation>
<translation id="4764776831041365478">ممکن است صÙحهٔ وب <ph name="URL" /> موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد.</translation>
<translation id="4766713847338118463">دو منگنه در پایین</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ùعالیتی Ú©Ù‡ در این دستگاه باقی می‌ماند:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ùایل‌هایی Ú©Ù‡ در این پنجره بارگیری می‌کنید
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">خطای ناشناخته‌ای رخ داد.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{پنجره بازشو مسدود شد}one{# پنجره بازشو مسدود شد}other{# پنجره بازشو مسدود شد}}</translation>
<translation id="4780366598804516005">صندوق پست ۱</translation>
@@ -1031,7 +1053,7 @@
<translation id="5125394840236832993">B-Plus</translation>
<translation id="5126510351761255129">کارتتان را تأیید کنید</translation>
<translation id="5135404736266831032">مدیریت نشانی‌ها…</translation>
-<translation id="5138227688689900538">نمایش موارد کمتر</translation>
+<translation id="5138227688689900538">نمایش کمتر</translation>
<translation id="5141240743006678641">â€Ø±Ù…زگذاری گذرواژه‌های همگام‌سازی شده با اطلاعات کاربری Google شما</translation>
<translation id="5145883236150621069">کد خطا در پاسخ خط‌مشی موجود است</translation>
<translation id="5146995429444047494">اعلان‌های مربوط به <ph name="ORIGIN" /> مسدود شده‌اند</translation>
@@ -1102,11 +1124,13 @@
<translation id="5386426401304769735">â€Ø²Ù†Ø¬ÛŒØ±Ù‡ گواهی این سایت حاوی یک گواهی با امضای SHA-1 است.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">دوختن لبه راست</translation>
+<translation id="5398772614898833570">آگهی‌ها مسدود شدند</translation>
<translation id="5400836586163650660">خاکستری</translation>
<translation id="540969355065856584">این سرور نتوانست ثابت کند که <ph name="DOMAIN" /> است؛ در حال حاضر، گواهی امنیتی آن معتبر نیست. ممکن است این مشکل به دلیل پیکربندی نادرست یا قطع اتصال شما توسط حمله‌کننده ایجاد شده باشد.</translation>
<translation id="541416427766103491">پشته‌ساز ۴</translation>
<translation id="5421136146218899937">پاک کردن داده‌های مرور...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> می‌خواهد برایتان اعلان ارسال کند</translation>
+<translation id="542872847390508405">به عنوان مهمان مرور می‌کنید</translation>
<translation id="5430298929874300616">حذ٠نشانک</translation>
<translation id="5439770059721715174">خطای تأیید طرح در «<ph name="ERROR_PATH" />»:†<ph name="ERROR" /></translation>
<translation id="5443468954631487277">روبه‌بالا به‌ترتیب معکوس</translation>
@@ -1148,12 +1172,12 @@
<translation id="5571083550517324815">تحویل گرÙتن از این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
<translation id="5580958916614886209">ماه انقضا را بررسی و دوباره امتحان کنید</translation>
<translation id="5586446728396275693">نشانی ذخیره‌شده‌ای وجود ندارد</translation>
+<translation id="5593349413089863479">اتصال کاملاً امن نیست</translation>
<translation id="5595485650161345191">ویرایش آدرس</translation>
<translation id="5598944008576757369">انتخاب روش پرداخت</translation>
<translation id="560412284261940334">مدیریت پشتیبانی نمی‌شود</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">â€Ø§ÛŒÙ† سایت می‌تواند جعلی یا کلاهبردارانه باشد. Chrome توصیه می‌کند همین‌الان خارج شوید.</translation>
<translation id="5610142619324316209">بررسی اتصال</translation>
<translation id="5610807607761827392">می‌توانید در <ph name="BEGIN_LINK" />تنظیمات<ph name="END_LINK" />، کارت‌ها و نشانی‌ها را مدیریت کنید.</translation>
<translation id="561165882404867731">â€Ø§ÛŒÙ† صÙحه را با «ترجمه Google» ترجمه کنید</translation>
@@ -1225,6 +1249,7 @@
<translation id="5901630391730855834">زرد</translation>
<translation id="5905445707201418379">مسدودشده براساس خط‌مشی اصلی <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (همگام‌سازی‌شده)</translation>
+<translation id="5913377024445952699">ضبط صÙحه‌نمایش متوق٠شد</translation>
<translation id="59174027418879706">Ùعال شد</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">روشن</translation>
@@ -1237,6 +1262,7 @@
<translation id="5963413905009737549">بخش</translation>
<translation id="5967592137238574583">ویرایش اطلاعات تماس</translation>
<translation id="5967867314010545767">حذ٠از سابقه</translation>
+<translation id="5968793460449681917">در هر بازدید</translation>
<translation id="5975083100439434680">دورنمایی کردن</translation>
<translation id="5979084224081478209">بررسی گذرواژه‌ها</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1392,6 +1418,7 @@
<translation id="6587923378399804057">پیوندی که کپی کرده‌اید</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> شما تحت مدیریت نیست</translation>
<translation id="6596325263575161958">گزینه‌های رمزگذاری</translation>
+<translation id="6596892391065203054">سرپرست چاپ این محتوا را مسدود کرده است.</translation>
<translation id="6604181099783169992">حسگرهای نوری یا حرکتی</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">محتوای محاÙظت‌شده</translation>
@@ -1451,6 +1478,7 @@
<translation id="6895330447102777224">کارتتان تأیید شد</translation>
<translation id="6897140037006041989">نماینده کاربر</translation>
<translation id="6898699227549475383">â€Ø³Ø§Ø²Ù…ان (O)</translation>
+<translation id="6907293445143367439">به <ph name="SITE_NAME" /> اجازه داده شود تا:</translation>
<translation id="6910240653697687763">â€<ph name="URL" /> می‌خواهد کنترل کامل دستگاه‌های MIDI شما را به‌دست آورد</translation>
<translation id="6915804003454593391">کاربر:</translation>
<translation id="6934672428414710184">â€Ø§ÛŒÙ† نام از حساب Google شما گرÙته شده است</translation>
@@ -1562,6 +1590,7 @@
<translation id="7346048084945669753">وابسته است:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">خط Ùرمان</translation>
+<translation id="7359588939039777303">آگهی‌ها مسدود شدند.</translation>
<translation id="7372973238305370288">نتیجه جستجو</translation>
<translation id="7374733840632556089">â€Ø¹Ù„ت این مشکل وجود یکی از گواهی‌هایی است Ú©Ù‡ شما یا Ùردی دیگر در دستگاهتان نصب کرده‌اید. از این گواهی برای نظارت بر شبکه‌ها Ùˆ رهگیری آن‌ها استÙاده می‌شود Ùˆ مورداعتماد Chrome نیست. علی‌رغم وجود برخی موارد قانونی برای نظارت، مثلاً نظارت بر شبکه‌های مدارس Ùˆ شرکت‌ها، Chrome می‌خواهد مطمئن شود Ú©Ù‡ شما از این جریان آگاهی دارید، حتی اگر نتوانید آن را متوق٠کنید. نظارت ممکن است در هر مرورگر یا برنامه‌ای Ú©Ù‡ به وب دسترسی دارد انجام شود.</translation>
<translation id="7375818412732305729">Ùایل پیوست شده است</translation>
@@ -1736,6 +1765,7 @@
<translation id="7976214039405368314">تعداد درخواست‌ها بیش از حد است</translation>
<translation id="7977538094055660992">دستگاه خروجی</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">â€Ø¨Ø±Ø§ÛŒ مشاهده محتوای واقعیت اÙزوده، ARCore را نصب کنید</translation>
<translation id="799149739215780103">به‌هم چسباندن</translation>
<translation id="7995512525968007366">تعیین نشده</translation>
<translation id="800218591365569300">سعی کنید برگه‌ها یا برنامه‌های دیگر را ببندید تا حاÙظه آزاد شود.</translation>
@@ -1863,24 +1893,38 @@
<translation id="8507227106804027148">خط Ùرمان</translation>
<translation id="8508648098325802031">نماد جستجو</translation>
<translation id="8522552481199248698">â€Chrome می‌تواند Ú©Ù…Ú© کند از حساب Google خود محاÙظت کنید Ùˆ گذرواژه‌تان را تغییر دهید.</translation>
+<translation id="8525306231823319788">تمام صÙحه</translation>
<translation id="8530813470445476232">â€Ø³Ø§Ø¨Ù‚Ù‡ مرور، کوکی، حاÙظه پنهان Ùˆ موارد دیگر را در تنظیمات Chrome پاک کنید.</translation>
<translation id="8533619373899488139">â€Ø¨Ø±Ø§ÛŒ دیدن Ùهرست نشانی‌های وب مسدودشده Ùˆ دیگر خط‌مشی‌های اعمال‌شده توسط سرپرست سیستم، از &lt;strong&gt;chrome://policy&lt;/strong&gt; بازدید کنید.</translation>
<translation id="8541158209346794904">دستگاه بلوتوث</translation>
<translation id="8542014550340843547">سه منگنه در پایین</translation>
<translation id="8543181531796978784">می‌توانید <ph name="BEGIN_ERROR_LINK" />یک مشکل شناسایی‌شده را گزارش کنید<ph name="END_ERROR_LINK" /> یا اگر از خطراتی که امنیت شما را تهدید می‌کنند مطلع شدید، <ph name="BEGIN_LINK" />از این سایت ناامن دیدن کنید<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">â€CVC در پشت کارتتان قرار گرÙته است.</translation>
+<translation id="8558485628462305855">â€Ø¨Ø±Ø§ÛŒ مشاهده محتوای واقعیت اÙزوده، ARCore را به‌روزرسانی کنید</translation>
<translation id="8559762987265718583">اتصال خصوصی به <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> انجام نمی‌شود، زیرا تاریخ و زمان دستگاه شما (<ph name="DATE_AND_TIME" />) نادرست است.</translation>
<translation id="8564182942834072828">اسناد جداگانه/کپی‌های تلÙیق‌نشده</translation>
<translation id="8564985650692024650">â€Chromium توصیه می‌کند اگر از گذرواژه <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> خود در سایت دیگری استÙاده کردید آن را بازنشانی کنید.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ùعالیتی Ú©Ù‡ در این دستگاه نمی‌ماند:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />صÙحاتی Ú©Ù‡ در این پنجره مشاهده می‌کنید
+ <ph name="LIST_ITEM" />کوکی‌ها و داده‌های سایت
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">برای به‌تأیید رساندن سریع‌تر کارت‌ها، از «شناسه لمسی» استÙاده شود</translation>
<translation id="858637041960032120">اÙزودن شماره تلÙÙ†</translation>
<translation id="8589998999637048520">بهترین Ú©ÛŒÙیت</translation>
+<translation id="8600271352425265729">Ùقط این بار</translation>
<translation id="860043288473659153">نام صاحب کارت</translation>
<translation id="8606726445206553943">â€Ø§Ø³ØªÙاده از دستگاه‌های MIDI شما</translation>
+<translation id="8612761427948161954">سلام <ph name="USERNAME" />،
+ <ph name="BR" />
+ به عنوان «مهمان» مرور می‌کنید</translation>
<translation id="861775596732816396">اندازه ۴</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">گذرواژه منطبقی وجود ندارد. نمایش همه گذرواژه‌های ذخیره‌شده.</translation>
<translation id="8625384913736129811">ذخیره کردن این کارت در این دستگاه</translation>
+<translation id="8627040765059109009">ضبط صÙحه‌نمایش ازسر گرÙته شد</translation>
<translation id="8657078576661269990">سرپرست هم‌رسانی از <ph name="ORIGIN_NAME" /> به <ph name="VM_NAME_1" /> و <ph name="VM_NAME_2" /> را مسدود کرده است</translation>
<translation id="8663226718884576429">خلاصه سÙارش، <ph name="TOTAL_LABEL" />ØŒ جزئيات بیشتر</translation>
<translation id="867224526087042813">امضا</translation>
@@ -1943,6 +1987,7 @@
<translation id="8912362522468806198">â€Ø­Ø³Ø§Ø¨ Google</translation>
<translation id="8913778647360618320">â€Ø¯Ú©Ù…Ù‡ «مدیریت روش‌های پرداخت»، برای مدیریت اطلاعات کارت اعتباری Ùˆ پرداخت‌ها در تنظیمات ChromeØŒ کلید Enter (ورود) را Ùشار دهید</translation>
<translation id="8918231688545606538">این صÙحه مشکوک است</translation>
+<translation id="8922013791253848639">آگهی‌ها همیشه در این سایت مجاز باشند</translation>
<translation id="892588693504540538">سوراخ در بالا سمت راست</translation>
<translation id="8931333241327730545">â€Ù…ی‌خواهید این کارت را در حساب Google خود ذخیره کنید؟</translation>
<translation id="8932102934695377596">ساعت شما عقب است</translation>
@@ -2014,6 +2059,7 @@
<translation id="9183302530794969518">â€Ø³Ù†Ø¯Ù†Ú¯Ø§Ø± Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> از یک پروتکل پشتیبانی‌نشده استÙاده می‌کند.</translation>
<translation id="9191834167571392248">سوراخ در پایین سمت چپ</translation>
+<translation id="9199905725844810519">چاپ کردن مسدود شده است</translation>
<translation id="9205078245616868884">داده‌های شما با عبارت عبور همگام‌سازی رمزگذاری می‌شود. برای شروع همگام‌سازی آن را وارد کنید.</translation>
<translation id="9207861905230894330">اÙزودن مقاله ناموÙÙ‚ بود.</translation>
<translation id="9213433120051936369">سÙارشی ساختن Ø´Ú©Ù„ ظاهری</translation>
@@ -2024,8 +2070,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">â€Ù…Ù…Ú©Ù† است دسترسی به حساب Google را از دست بدهید. Chromium توصیه می‌کند اکنون گذرواژه‌تان را تغییر دهید. از شما خواسته می‌شود به سیستم وارد شوید.</translation>
<translation id="939736085109172342">پوشهٔ جدید</translation>
+<translation id="945522503751344254">ارسال بازخورد</translation>
<translation id="945855313015696284">اطلاعات زیر را بررسی و کارت‌های نامعتبر را حذ٠کنید</translation>
<translation id="950736567201356821">سه سوراخ در بالا</translation>
+<translation id="951941430552851965">به‌دلیل محتوای روی صÙحه، سرپرستتان ضبط صÙحه‌نمایش را موقتاً متوق٠کرده است.</translation>
<translation id="961663415146723894">به‌هم چسباندن از پایین</translation>
<translation id="962484866189421427">این محتوا ممکن است برنامه‌های Ùریب‌دهنده‌ای نصب کند Ú©Ù‡ وانمود می‌کنند برنامه دیگری هستند یا اینکه داده‌هایی برای ردیابی شما جمع‌آوری می‌کنند. <ph name="BEGIN_LINK" />درهرصورت نشان داده شود<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ساخت رسمی</translation>
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index 996ebd1b33e..d222319b1e9 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -80,6 +80,14 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Kirjoitit salasanan sivustolle, joka ei ole organisaatiosi hallinnoima. Älä käytä samaa salasanaa muissa sovelluksissa tai muilla sivustoilla tilisi turvallisuuden vuoksi.</translation>
<translation id="1263231323834454256">Lukulista</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Tämä toiminta ei säily laitteella:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tässä ikkunassa katsomasi sivut
+ <ph name="LIST_ITEM" />Evästeet ja sivustodata
+ <ph name="LIST_ITEM" />Tilitiedot (<ph name="LINK_BEGIN" />kirjaudu ulos<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Noutotapa</translation>
<translation id="1281476433249504884">Pinoaja 1</translation>
<translation id="1285320974508926690">Älä käännä tätä sivustoa</translation>
@@ -283,6 +291,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="204357726431741734">Kirjaudu sisään käyttääksesi Google-tilillesi tallennettuja salasanoja</translation>
<translation id="2053111141626950936">Kielellä <ph name="LANGUAGE" /> kirjoitettuja sivuja ei käännetä.</translation>
<translation id="2053553514270667976">Postinumero</translation>
+<translation id="2054665754582400095">Paikallaolosi</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ehdotus}other{# ehdotusta}}</translation>
<translation id="2079545284768500474">Kumoa</translation>
<translation id="20817612488360358">Järjestelmän välityspalvelinasetukset on määritetty käytettäviksi, mutta erilliset välityspalvelimen asetukset on myös määritetty.</translation>
@@ -296,6 +305,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2102495993840063010">Android-sovellukset</translation>
<translation id="2107021941795971877">Tulostustuet</translation>
<translation id="2108755909498034140">Käynnistä tietokone uudelleen.</translation>
+<translation id="2111166930115883695">Pelaa painamalla välilyöntiä</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kortti</translation>
<translation id="2114841414352855701">Ei käytetä – käytännön <ph name="POLICY_NAME" /> ohittama.</translation>
@@ -307,6 +317,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="214556005048008348">Peruuta maksu</translation>
<translation id="2147827593068025794">Taustasynkronointi</translation>
<translation id="2148613324460538318">Lisää kortti</translation>
+<translation id="2149968176347646218">Yhteys ei ole turvallinen</translation>
<translation id="2154054054215849342">Synkronointi ei ole käytettävissä verkkotunnuksessasi.</translation>
<translation id="2154484045852737596">Muokkaa korttia</translation>
<translation id="2161656808144014275">Teksti</translation>
@@ -317,7 +328,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2181821976797666341">Käytännöt</translation>
<translation id="2183608646556468874">Puhelinnumero</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 osoite}other{# osoitetta}}</translation>
-<translation id="2187243482123994665">Käyttäjän paikallaolo</translation>
<translation id="2187317261103489799">Tunnista (oletus)</translation>
<translation id="2188375229972301266">Useita reikiä alareunassa</translation>
<translation id="2202020181578195191">Anna kelvollinen viimeinen voimassaolovuosi.</translation>
@@ -470,6 +480,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2839501879576190149">Tämä on valesivusto</translation>
<translation id="2850739647070081192">Kutsu (kirjekuori)</translation>
<translation id="2856444702002559011">Sivustolle <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää varastaa tietojasi (esimerkiksi salasanoja, viestejä tai luottokorttitietoja). <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Tällä sivustolla on häiritseviä tai harhaanjohtavia mainoksia.</translation>
<translation id="2878197950673342043">Julistetaitos</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ikkunoiden sijoittelu</translation>
@@ -508,11 +519,11 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2996674880327704673">Googlen ehdotukset</translation>
<translation id="3002501248619246229">Tarkista syöttölokeron media</translation>
<translation id="3005723025932146533">Näytä tallennettu kopio</translation>
-<translation id="3007719053326478567">Järjestelmänvalvoja on estänyt tämän sisällön tulostamisen</translation>
<translation id="3008447029300691911">Anna kortin <ph name="CREDIT_CARD" /> CVC. Vahvistamisen jälkeen korttisi tiedot jaetaan sivuston kanssa.</translation>
<translation id="3010559122411665027">Luettelokohde "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Estetty automaattisesti</translation>
<translation id="3016780570757425217">Saada sijaintisi selville.</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, poista ehdotus painamalla sarkainta ja sitten Enter</translation>
<translation id="3023071826883856138">You4 (kirjekuori)</translation>
<translation id="3024663005179499861">Väärä käytäntötyyppi</translation>
<translation id="3037605927509011580">Harmin paikka!</translation>
@@ -556,6 +567,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3207960819495026254">Kirjanmerkeissä</translation>
<translation id="3209034400446768650">Sivu voi veloittaa</translation>
<translation id="3212581601480735796">Toimintaasi (<ph name="HOSTNAME" />) tarkkaillaan</translation>
+<translation id="3212623355668894776">Sulje kaikki vierasikkunat, niin selaustoimintasi poistetaan tältä laitteelta.</translation>
<translation id="3215092763954878852">WebAuthn:n käyttö ei onnistunut</translation>
<translation id="3218181027817787318">Suhteellinen</translation>
<translation id="3225919329040284222">Palvelin esitti varmenteen, joka ei vastaa sisäänrakennettuja odotuksia. Tietyillä tehokkaasti suojatuilla sivustoilla on odotuksia, joilla suojataan käyttäjiä.</translation>
@@ -703,6 +715,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3784372983762739446">Bluetooth-laitteet</translation>
<translation id="3787705759683870569">Vanhenee <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Koko 16</translation>
+<translation id="3789841737615482174">Asenna</translation>
<translation id="3793574014653384240">Viime aikoina tapahtuneiden kaatumisten määrät ja syyt</translation>
<translation id="3797522431967816232">Prc3 (kirjekuori)</translation>
<translation id="3799805948399000906">Fonttia pyydetty</translation>
@@ -754,6 +767,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4056223980640387499">Seepia</translation>
<translation id="4058922952496707368">Avain <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (kirjekuori)</translation>
+<translation id="4067669230157909013">Näytön tallennusta on jatkettu.</translation>
<translation id="4067947977115446013">Lisää kelvollinen osoite</translation>
<translation id="4072486802667267160">Virhe tilausta käsiteltäessä. Yritä uudelleen.</translation>
<translation id="4075732493274867456">Asiakassovellus ja palvelin eivät tue samaa SSL-protokollaversiota tai salaustekniikkaa.</translation>
@@ -838,6 +852,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4297502707443874121">Sivun <ph name="THUMBNAIL_PAGE" /> pikkukuva</translation>
<translation id="42981349822642051">Laajenna</translation>
<translation id="4300675098767811073">Useita reikiä oikealla</translation>
+<translation id="4302514097724775343">Pelaa napauttamalla dinosaurusta</translation>
<translation id="4302965934281694568">Chou3 (kirjekuori)</translation>
<translation id="4305666528087210886">Tiedostoa ei voi käyttää</translation>
<translation id="4305817255990598646">Vaihda</translation>
@@ -916,6 +931,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4658638640878098064">Niitti vasemmassa yläkulmassa</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuaalitodellisuus</translation>
+<translation id="4675657451653251260">Vierastilassa et näe muiden Chrome-profiilien tietoja. <ph name="LINK_BEGIN" />Kirjautumalla sisään<ph name="LINK_END" /> pääset Google-tilisi tietoihin, kuten salasanoihin tai maksutapoihin.</translation>
<translation id="467662567472608290">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne sisältää virheitä. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="4677585247300749148"><ph name="URL" /> haluaa vastata esteettömyystapahtumiin.</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -943,6 +959,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4761104368405085019">Käyttää mikrofonia</translation>
<translation id="4764776831041365478">Osoitteessa <ph name="URL" /> oleva sivu saattaa olla väliaikaisesti pois käytöstä tai se on voitu siirtää pysyvästi uuteen osoitteeseen.</translation>
<translation id="4766713847338118463">Kaksi niittiä alareunassa</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Tämä toiminta säilyy laitteella:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tässä ikkunassa lataamasi tiedostot
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Tapahtui tuntematon virhe.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Ponnahdusikkuna estetty}other{# ponnahdusikkunaa estetty}}</translation>
<translation id="4780366598804516005">Postilaatikko 1</translation>
@@ -1105,11 +1127,13 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5386426401304769735">Tämän sivuston varmenneketju sisältää varmenteen, joka on allekirjoitettu SHA-1:llä.</translation>
<translation id="538659543871111977">A4-välilehti</translation>
<translation id="5396631636586785122">Reunasidonta oikealla</translation>
+<translation id="5398772614898833570">Mainokset estetty</translation>
<translation id="5400836586163650660">Harmaa</translation>
<translation id="540969355065856584">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />, sillä sen suojausvarmenne ei tällä hetkellä ole kelvollinen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="541416427766103491">Pinoaja 4</translation>
<translation id="5421136146218899937">Poista selaustiedot...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> haluaa lähettää sinulle ilmoituksia</translation>
+<translation id="542872847390508405">Selaat vierailijana</translation>
<translation id="5430298929874300616">Poista kirjanmerkki</translation>
<translation id="5439770059721715174">Mallin todennusvirhe kohdassa <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Käänteinen järjestys tulostuspuoli ylöspäin</translation>
@@ -1151,12 +1175,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5571083550517324815">Nouto tästä osoitteesta ei onnistu. Valitse eri osoite.</translation>
<translation id="5580958916614886209">Tarkista vanhentumiskuukausi ja yritä uudelleen.</translation>
<translation id="5586446728396275693">Ei tallennettuja osoitteita</translation>
+<translation id="5593349413089863479">Yhteys ei ole täysin suojattu</translation>
<translation id="5595485650161345191">Osoitteen muokkaus</translation>
<translation id="5598944008576757369">Valitse maksutapa</translation>
<translation id="560412284261940334">Hallintaa ei tueta</translation>
<translation id="5605670050355397069">Kierrevihko</translation>
<translation id="5607240918979444548">Arkkitehti-C</translation>
-<translation id="5608165884683734521">Tämä voi olla vilpillinen tai valesivusto. Chrome suosittelee siltä poistumista.</translation>
<translation id="5610142619324316209">Tarkista yhteys.</translation>
<translation id="5610807607761827392">Voit hallita kortteja ja osoitteita <ph name="BEGIN_LINK" />Asetuksissa<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Käännä tämä sivu Google Kääntäjällä</translation>
@@ -1228,6 +1252,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5901630391730855834">Keltainen</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> estää tämän alkuperäkäytännössään.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkronoitu)</translation>
+<translation id="5913377024445952699">Näytön tallennus keskeytetty</translation>
<translation id="59174027418879706">Käytössä</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Päällä</translation>
@@ -1240,6 +1265,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5963413905009737549">Osio</translation>
<translation id="5967592137238574583">Muokkaa yhteystietoja</translation>
<translation id="5967867314010545767">Poista historiasta</translation>
+<translation id="5968793460449681917">Joka käynnillä</translation>
<translation id="5975083100439434680">Loitonna</translation>
<translation id="5979084224081478209">Tarkista salasanat</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1395,6 +1421,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6587923378399804057">Kopioimasi linkki</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> ei ole ylläpidetty</translation>
<translation id="6596325263575161958">Salausasetukset</translation>
+<translation id="6596892391065203054">Järjestelmänvalvoja on estänyt tämän sisällön tulostamisen.</translation>
<translation id="6604181099783169992">Liike- tai valotunnistimet</translation>
<translation id="6609880536175561541">Prc7 (kirjekuori)</translation>
<translation id="6612358246767739896">Suojattu sisältö</translation>
@@ -1454,6 +1481,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6895330447102777224">Korttisi vahvistettiin.</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">Organisaatio (O)</translation>
+<translation id="6907293445143367439">Salli sivustolle (<ph name="SITE_NAME" />) nämä:</translation>
<translation id="6910240653697687763"><ph name="URL" /> haluaa MIDI-laitteidesi täyden hallintaoikeuden.</translation>
<translation id="6915804003454593391">Käyttäjä:</translation>
<translation id="6934672428414710184">Tämä nimi on peräisin Google-tililtäsi</translation>
@@ -1565,6 +1593,7 @@ Lisätietoja:
<translation id="7346048084945669753">On yhdistetty:</translation>
<translation id="7349430561505560861">A4-ekstra</translation>
<translation id="7353601530677266744">Komentorivi</translation>
+<translation id="7359588939039777303">Mainokset estetty</translation>
<translation id="7372973238305370288">hakutulos</translation>
<translation id="7374733840632556089">Tämän virheen syynä on varmenne, jonka sinä tai joku muu asensi laitteellesi. Varmennetta on aiemmin käytetty verkkojen valvontaan ja kaappaamiseen, eikä Chrome luota siihen. Valvomiselle voi olla oikea syy esimerkiksi oppilaitoksen tai yrityksen verkossa, mutta Chrome haluaa sinun tietävän valvonnasta, vaikket voi lopettaa sitä. Valvonta voi tapahtua missä tahansa selaimessa tai sovelluksessa, jolla on pääsy verkkoon.</translation>
<translation id="7375818412732305729">Tiedosto on liitetty</translation>
@@ -1739,6 +1768,7 @@ Lisätietoja:
<translation id="7976214039405368314">Liikaa pyyntöjä</translation>
<translation id="7977538094055660992">Tulostuslaite</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Asenna ARCore, niin voit nähdä AR-sisältöä.</translation>
<translation id="799149739215780103">Sidonta</translation>
<translation id="7995512525968007366">Ei määritetty</translation>
<translation id="800218591365569300">Yritä vapauttaa muistia sulkemalla muita välilehtiä tai ohjelmia.</translation>
@@ -1866,25 +1896,39 @@ Lisätietoja:
<translation id="8507227106804027148">Komentorivi</translation>
<translation id="8508648098325802031">Hakukuvake</translation>
<translation id="8522552481199248698">Chrome voi auttaa suojaamaan Google-tiliäsi ja vaihtamaan salasanasi.</translation>
+<translation id="8525306231823319788">Koko näyttö</translation>
<translation id="8530813470445476232">Tyhjennä selaushistoria, evästeet, välimuisti ja muita tietoja Chromen asetuksista</translation>
<translation id="8533619373899488139">Voit nähdä estetyt URL-osoitteet ja muut järjestelmänvalvojasi määräämät käytännöt osoitteessa &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
<translation id="8541158209346794904">Bluetooth-laite</translation>
<translation id="8542014550340843547">Kolme niittiä alareunassa</translation>
<translation id="8543181531796978784">Voit <ph name="BEGIN_ERROR_LINK" />ilmoittaa löytyneestä ongelmasta<ph name="END_ERROR_LINK" /> tai <ph name="BEGIN_LINK" />siirtyä mahdollisesti haitalliselle sivustolle<ph name="END_LINK" />, jos ymmärrät tietoturvariskit.</translation>
<translation id="8557066899867184262">CVC sijaitsee kortin takapuolella.</translation>
+<translation id="8558485628462305855">Päivitä ARCore, niin voit nähdä AR-sisältöä.</translation>
<translation id="8559762987265718583">Verkkotunnukseen <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei voi muodostaa salattua yhteyttä, koska laitteesi aika ja päivämäärä (<ph name="DATE_AND_TIME" />) ovat virheelliset.</translation>
<translation id="8564182942834072828">Erilliset dokumentit / Kokoamattomat kopiot</translation>
<translation id="8564985650692024650">Chromium suosittelee organisaation <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> salasanasi vaihtamista, jos olet käyttänyt sitä myös muilla sivustoilla.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Tämä toiminta ei säily laitteella:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tässä ikkunassa katsomasi sivut
+ <ph name="LIST_ITEM" />Evästeet ja sivustodata
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Vahvista kortteja nopeammin Touch ID:llä</translation>
<translation id="858637041960032120">Lisää puh.nro
</translation>
<translation id="8589998999637048520">Paras laatu</translation>
+<translation id="8600271352425265729">Vain tämän kerran</translation>
<translation id="860043288473659153">Kortinhaltijan nimi</translation>
<translation id="8606726445206553943">Käyttää MIDI-laitteitasi.</translation>
+<translation id="8612761427948161954">Hei <ph name="USERNAME" />
+ <ph name="BR" />
+ Selaat tällä hetkellä vierastilassa.</translation>
<translation id="861775596732816396">Koko 4</translation>
<translation id="8622948367223941507">Laki-ekstra</translation>
<translation id="8623885649813806493">Ei salasanaosumia. Näytä kaikki tallennetut salasanat.</translation>
<translation id="8625384913736129811">Tallenna kortti tälle laitteelle</translation>
+<translation id="8627040765059109009">Näytön tallennusta jatkettu</translation>
<translation id="8657078576661269990">Järjestelmänvalvoja on estänyt sivustolta <ph name="ORIGIN_NAME" /> jakamisen näille: <ph name="VM_NAME_1" /> ja <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Tilauksen yhteenveto, <ph name="TOTAL_LABEL" />, lisätietoja</translation>
<translation id="867224526087042813">Allekirjoitus</translation>
@@ -1947,6 +1991,7 @@ Lisätietoja:
<translation id="8912362522468806198">Google-tilisi avulla</translation>
<translation id="8913778647360618320">Ylläpidä maksutapoja ‑painike, paina Enter ylläpitääksesi maksu- ja credit-korttitietoja Chromen asetuksissa</translation>
<translation id="8918231688545606538">Tämä sivu on epäilyttävä</translation>
+<translation id="8922013791253848639">Salli aina mainokset tällä sivustolla.</translation>
<translation id="892588693504540538">Reikä oikeassa yläkulmassa</translation>
<translation id="8931333241327730545">Haluatko tallentaa tämän kortin Google-tilillesi?</translation>
<translation id="8932102934695377596">Kellosi jätättää</translation>
@@ -2018,6 +2063,7 @@ Lisätietoja:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> käyttää protokollaa, jota ei tueta.</translation>
<translation id="9191834167571392248">Reikä vasemmassa alakulmassa</translation>
+<translation id="9199905725844810519">Tulostus on estetty</translation>
<translation id="9205078245616868884">Tietosi on salattu synkronoinnin tunnuslauseesi avulla. Aloita synkronointi antamalla tunnuslause.</translation>
<translation id="9207861905230894330">Artikkelin lisääminen epäonnistui.</translation>
<translation id="9213433120051936369">Muokkaa ulkoasua</translation>
@@ -2028,8 +2074,10 @@ Lisätietoja:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Saatat menettää Google-tilisi käyttöoikeuden. Chromium suosittelee vaihtamaan salasanan nyt. Sinua pyydetään kirjautumaan sisään.</translation>
<translation id="939736085109172342">Uusi kansio</translation>
+<translation id="945522503751344254">Lähetä palautetta</translation>
<translation id="945855313015696284">Tarkista tiedot alta ja poista virheelliset kortit.</translation>
<translation id="950736567201356821">Kolme reikää yläreunassa</translation>
+<translation id="951941430552851965">Järjestelmänvalvoja keskeytti näytön tallennuksen näytöllä olevan sisällön vuoksi.</translation>
<translation id="961663415146723894">Alareuna sidottu</translation>
<translation id="962484866189421427">Tämä sisältö voi yrittää asentaa petollisia sovelluksia, jotka esiintyvät jonakin muuna tai keräävät tietoja, joilla sinua voidaan seurata. <ph name="BEGIN_LINK" />Näytä silti<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Virallinen koontiversio</translation>
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index 546a238d362..44a2be80ada 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -80,6 +80,14 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Inilagay mo ang iyong password sa site na hindi pinamamahalaan ng iyong organisasyon. Para protektahan ang account mo, huwag gamiting muli ang iyong password sa iba pang app at site.</translation>
<translation id="1263231323834454256">Listahan ng babasahin</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktibidad na hindi mananatili sa device na ito:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Mga page na titingnan mo sa window na ito
+ <ph name="LIST_ITEM" />Cookies at data ng site
+ <ph name="LIST_ITEM" />Impormasyon ng account (<ph name="LINK_BEGIN" />mag-sign out<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Paraan sa Pag-pick up</translation>
<translation id="1281476433249504884">Stacker 1</translation>
<translation id="1285320974508926690">Huwag isalin kailanman ang site na ito</translation>
@@ -283,6 +291,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="204357726431741734">Mag-sign in para magamit ang mga naka-save na password sa iyong Google Account</translation>
<translation id="2053111141626950936">Hindi ita-translate ang mga page na nasa <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2054665754582400095">Ang iyong presensya</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suhestyon}one{# suhestyon}other{# na suhestyon}}</translation>
<translation id="2079545284768500474">I-undo</translation>
<translation id="20817612488360358">Itinatakda ang mga setting ng proxy ng system upang magamit ngunit tinutukoy rin ang isang tahasang configuration ng proxy.</translation>
@@ -296,6 +305,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2102495993840063010">Mga Android app</translation>
<translation id="2107021941795971877">Mga suporta sa pag-print</translation>
<translation id="2108755909498034140">I-restart ang iyong computer</translation>
+<translation id="2111166930115883695">Pindutin ang space para i-play</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Binalewala dahil na-override ito ng <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="214556005048008348">Kanselahin ang pagbabayad</translation>
<translation id="2147827593068025794">Pag-sync sa Background</translation>
<translation id="2148613324460538318">Magdagdag ng Card</translation>
+<translation id="2149968176347646218">Hindi secure ang koneksyon</translation>
<translation id="2154054054215849342">Hindi available ang pag-sync para sa iyong domain</translation>
<translation id="2154484045852737596">I-edit ang card</translation>
<translation id="2161656808144014275">Text</translation>
@@ -317,7 +328,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2181821976797666341">Mga Patakaran</translation>
<translation id="2183608646556468874">Numero ng Telepono</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 address}one{# address}other{# na address}}</translation>
-<translation id="2187243482123994665">Pagiging aktibo ng user</translation>
<translation id="2187317261103489799">Tukuyin (default)</translation>
<translation id="2188375229972301266">Multiple punch bottom</translation>
<translation id="2202020181578195191">Maglagay ng wastong taon ng pag-expire</translation>
@@ -470,6 +480,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2839501879576190149">Posibleng peke ang site na ito</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Maaaring sinusubukang nakawin ng mga attacker ang iyong impormasyon mula sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (halimbawa, mga password, mensahe, o credit card). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Nagpapakita ang site na ito ng mga nakakasagabal o nakakapanlinlang na ad.</translation>
<translation id="2878197950673342043">Poster fold</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Placement ng window</translation>
@@ -508,11 +519,11 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2996674880327704673">Mga Suhestyon ng Google</translation>
<translation id="3002501248619246229">Suriin ang input tray media</translation>
<translation id="3005723025932146533">Ipakita ang naka-save na kopya</translation>
-<translation id="3007719053326478567">Na-block ng iyong administrator ang pag-print sa content na ito</translation>
<translation id="3008447029300691911">Ilagay ang CVC para sa <ph name="CREDIT_CARD" />. Kapag nagkumpirma ka na, ibabahagi ang mga detalye ng iyong card sa site na ito.</translation>
<translation id="3010559122411665027">Listahan ng entry na "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Awtomatikong na-block</translation>
<translation id="3016780570757425217">Alamin ang iyong lokasyon</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pindutin ang Tab at pagkatapos ay ang Enter para Alisin ang Suhestyon.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Maling uri ng patakaran</translation>
<translation id="3037605927509011580">Ay, Naku!</translation>
@@ -555,6 +566,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3207960819495026254">Naka-bookmark</translation>
<translation id="3209034400446768650">Puwedeng maningil ang page</translation>
<translation id="3212581601480735796">Sinusubaybayan ang iyong aktibidad sa <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Isara ang lahat ng window ng Bisita para ma-delete ang iyong aktibidad sa pag-browse sa device na ito.</translation>
<translation id="3215092763954878852">Hindi magamit ang WebAuthn</translation>
<translation id="3218181027817787318">Kaugnay</translation>
<translation id="3225919329040284222">Nagpakita ang server ng certificate na hindi tumutugma sa mga built-in na inaasahan. Ang mga inaasahang ito ay isinama para sa ilang partikular na website na may mataas na antas ng seguridad upang maprotektahan ka.</translation>
@@ -702,6 +714,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3784372983762739446">Mga device ng bluetooth</translation>
<translation id="3787705759683870569">Mag-e-expire sa <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Laki 16</translation>
+<translation id="3789841737615482174">Mag-install</translation>
<translation id="3793574014653384240">Mga bilang at sanhi ng mga pag-crash na naganap kamakailan</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Hiniling na font</translation>
@@ -753,6 +766,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Key "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Ipinagpatuloy ang screen capture.</translation>
<translation id="4067947977115446013">Magdagdag ng Wastong Address</translation>
<translation id="4072486802667267160">Nagkaroon ng error sa pagproseso ng iyong order. Pakisubukang muli.</translation>
<translation id="4075732493274867456">Hindi sinusuportahan ng client at server ang isang karaniwang bersyon o cipher suite ng SSL protocol.</translation>
@@ -837,6 +851,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4297502707443874121">Thumbnail para sa page <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Palawakin</translation>
<translation id="4300675098767811073">Multiple punch right</translation>
+<translation id="4302514097724775343">I-tap ang dino para maglaro</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Hindi ma-access ang iyong file</translation>
<translation id="4305817255990598646">Lumipat</translation>
@@ -915,6 +930,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4658638640878098064">Staple top left</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reality</translation>
+<translation id="4675657451653251260">Hindi ka makakakita ng anumang impormasyon ng profile sa Chrome sa Guest mode. Puwede kang <ph name="LINK_BEGIN" />mag-sign in<ph name="LINK_END" /> para i-access ang impormasyon ng iyong Google account tulad ng mga password at paraan ng pagbabayad.</translation>
<translation id="467662567472608290">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; naglalaman ng mga error ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="4677585247300749148">Gustong tumugon ng <ph name="URL" /> sa mga kaganapan ng pagiging accessible</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4761104368405085019">Gamitin ang iyong mikropono</translation>
<translation id="4764776831041365478">Ang webpage sa <ph name="URL" /> ay maaaring pansamantalang hindi gumagana o maaaring permanente itong inilipat sa isang bagong web address.</translation>
<translation id="4766713847338118463">Dual staple bottom</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Iyong aktibidad na mananatili sa device na ito:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Anumang file na ida-download mo sa window na ito
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Isang hindi alam na error ang nangyari.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Na-block ang pop-up}one{# pop-up ang na-block}other{# na pop-up ang na-block}}</translation>
<translation id="4780366598804516005">Mailbox 1</translation>
@@ -1104,11 +1126,13 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5386426401304769735">Naglalaman ang chain ng certificate para sa site na ito ng certificate na naka-sign gamit ang SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Edge stitch right</translation>
+<translation id="5398772614898833570">Na-block ang mga ad</translation>
<translation id="5400836586163650660">Grey</translation>
<translation id="540969355065856584">Hindi mapatunayan ng server na ito ay ang <ph name="DOMAIN" />; walang bisa ang certificate sa seguridad nito sa pagkakataong ito. Maaaring dahil ito sa isang maling pag-configure o may isang attacker na humahadlang sa iyong koneksyon.</translation>
<translation id="541416427766103491">Stacker 4</translation>
<translation id="5421136146218899937">I-clear ang data sa pag-browse...</translation>
<translation id="5426179911063097041">Gusto ng <ph name="SITE" /> na padalhan ka ng mga notification</translation>
+<translation id="542872847390508405">Nagba-browse ka bilang isang Bisita</translation>
<translation id="5430298929874300616">Alisin ang bookmark</translation>
<translation id="5439770059721715174">Error sa pagpapatunay ng schema sa "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Baligtarin ang pagkakasunod-sunod nang nakatihaya</translation>
@@ -1150,12 +1174,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5571083550517324815">Hindi maaaring mag-pick up mula sa address na ito. Pumili ng ibang address.</translation>
<translation id="5580958916614886209">Tingnan ang iyong buwan ng pag-expire at subukang muli</translation>
<translation id="5586446728396275693">Walang naka-save na address</translation>
+<translation id="5593349413089863479">Hindi ganap na secure ang koneksyon</translation>
<translation id="5595485650161345191">Mag-edit ng address</translation>
<translation id="5598944008576757369">Pumili ng Paraan ng Pagbabayad</translation>
<translation id="560412284261940334">Hindi sinusuportahan ang pamamahala</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Puwedeng maging peke o mapanloko ang site na ito. Inirerekomenda ng Chrome na umalis ngayon.</translation>
<translation id="5610142619324316209">Suriin ang koneksyon</translation>
<translation id="5610807607761827392">Maaari mong pamahalaan ang mga card at address sa <ph name="BEGIN_LINK" />Mga Setting<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Isalin ang page na ito gamit ang Google Translate</translation>
@@ -1227,6 +1251,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5901630391730855834">Dilaw</translation>
<translation id="5905445707201418379">Na-black ayon sa patakaran ng pinagmulan ng <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (naka-sync)</translation>
+<translation id="5913377024445952699">Na-pause ang screen capture</translation>
<translation id="59174027418879706">Pinagana</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Naka-on</translation>
@@ -1239,6 +1264,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5963413905009737549">Seksyon</translation>
<translation id="5967592137238574583">I-edit ang Impormasyon ng Contact</translation>
<translation id="5967867314010545767">Alisin sa history</translation>
+<translation id="5968793460449681917">Tuwing bibisita</translation>
<translation id="5975083100439434680">Mag-zoom out</translation>
<translation id="5979084224081478209">Suriin ang mga password</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6587923378399804057">Link na kinopya mo</translation>
<translation id="6591833882275308647">Hindi pinapamahalaan ang iyong <ph name="DEVICE_TYPE" /></translation>
<translation id="6596325263575161958">Mga pagpipilian sa pag-encrypt</translation>
+<translation id="6596892391065203054">Na-block ng iyong administrator ang pag-print sa content na ito.</translation>
<translation id="6604181099783169992">Mga Motion o Light Sensor</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Pinoprotektahang content</translation>
@@ -1453,6 +1480,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6895330447102777224">Nakumpirma na ang iyong card</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6898699227549475383">Samahan (O)</translation>
+<translation id="6907293445143367439">Payagan ang <ph name="SITE_NAME" /> na:</translation>
<translation id="6910240653697687763">Gusto ng <ph name="URL" /> na magkaroon ng buong kontrol sa iyong mga MIDI device</translation>
<translation id="6915804003454593391">User:</translation>
<translation id="6934672428414710184">Nagmula ang pangalang ito sa iyong Google Account</translation>
@@ -1564,6 +1592,7 @@ Mga karagdagang detalye:
<translation id="7346048084945669753">Naka-affiliate:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Command Line</translation>
+<translation id="7359588939039777303">Na-block ang mga ad.</translation>
<translation id="7372973238305370288">resulta ng paghahanap</translation>
<translation id="7374733840632556089">Nangyayari ang problemang ito dahil sa isang certificate na na-install mo o ng ibang tao sa iyong device. Kilala ang certificate sa pagsubaybay at pag-intercept ng mga network, at hindi ito pinagkakatiwalaan ng Chrome. Bagama't mayroong mga lehitimong kaso ng pagsubaybay, gaya sa network sa paaralan o kumpanya, gustong tiyakin ng Chrome na alam mong nangyayari ito, kahit na hindi mo ito mapipigilan. Posibleng mangyari ang pagsubaybay sa anumang browser o application na nag-a-access ng web.</translation>
<translation id="7375818412732305729">Nag-attach ng file</translation>
@@ -1738,6 +1767,7 @@ Mga karagdagang detalye:
<translation id="7976214039405368314">Masyadong maraming kahilingan</translation>
<translation id="7977538094055660992">Output device</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Para matingnan ang augmented reality na content, i-install ang ARCore</translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7995512525968007366">Hindi Tinukoy</translation>
<translation id="800218591365569300">Subukang isara ang iba pang tab o program upang magbakante ng memory.</translation>
@@ -1865,24 +1895,38 @@ Mga karagdagang detalye:
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Icon ng paghahanap</translation>
<translation id="8522552481199248698">Matutulungan ka ng Chrome na protektahan ang iyong Google Account at palitan ang password mo.</translation>
+<translation id="8525306231823319788">Buong screen</translation>
<translation id="8530813470445476232">I-clear ang iyong history ng pag-browse, cookies, cache, at higit pa sa mga setting ng Chrome</translation>
<translation id="8533619373899488139">Bisitahin ang &lt;strong&gt;chrome://policy&lt;/strong&gt; para makita ang listahan ng mga naka-block na URL at ang iba pang patakarang ipinapatupad ng iyong system administrator.</translation>
<translation id="8541158209346794904">Bluetooth device</translation>
<translation id="8542014550340843547">Triple staple bottom</translation>
<translation id="8543181531796978784">Maaari kang <ph name="BEGIN_ERROR_LINK" />mag-ulat ng problema sa pagtukoy<ph name="END_ERROR_LINK" /> o, kung nauunawaan mo ang mga panganib sa iyong seguridad, <ph name="BEGIN_LINK" />bisitahin ang hindi ligtas na site na ito<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Makikita ang CVC sa likod ng iyong card.</translation>
+<translation id="8558485628462305855">Para matingnan ang augmented reality na content, i-update ang ARCore</translation>
<translation id="8559762987265718583">Hindi makapagtatag ng pribadong koneksyon sa <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> dahil mali ang petsa at oras ng iyong device (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Mga hiwalay na dokumento/Mga hindi naka-collate na kopya</translation>
<translation id="8564985650692024650">Inirerekomenda ng Chromium na i-reset ang iyong password sa <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> kung ginamit mo ito sa iba pang site.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktibidad na hindi mananatili sa device na ito:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Mga page na titingnan mo sa window na ito
+ <ph name="LIST_ITEM" />Cookies at data ng site
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Gamitin ang Touch ID para kumpirmahin nang mas mabilis ang mga card</translation>
<translation id="858637041960032120">Magdagdag ng numero ng telepono</translation>
<translation id="8589998999637048520">Pinakamahusay na kalidad</translation>
+<translation id="8600271352425265729">Sa pagkakataong ito lang</translation>
<translation id="860043288473659153">Pangalan ng cardholder</translation>
<translation id="8606726445206553943">Gamitin ang iyong mga MIDI device</translation>
+<translation id="8612761427948161954">Kumusta <ph name="USERNAME" />,
+ <ph name="BR" />
+ Nagba-browse ka bilang Bisita</translation>
<translation id="861775596732816396">Laki 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Walang tumutugmang password. Ipakita ang lahat ng naka-save na password.</translation>
<translation id="8625384913736129811">I-save ang Card na Ito sa Device na Ito</translation>
+<translation id="8627040765059109009">Ipinagpatuloy ang screen capture</translation>
<translation id="8657078576661269990">Na-block ng iyong administrator ang pagbabahagi mula sa <ph name="ORIGIN_NAME" /> sa <ph name="VM_NAME_1" /> at <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Buod ng Order, <ph name="TOTAL_LABEL" />, Higit pang Detalye</translation>
<translation id="867224526087042813">Lagda</translation>
@@ -1945,6 +1989,7 @@ Mga karagdagang detalye:
<translation id="8912362522468806198">Google Account</translation>
<translation id="8913778647360618320">Button na pamahalaan ang mga paraan ng pagbabayad, pindutin ang Enter para pamahalaan ang iyong mga pagbabayad at ang impormasyon ng credit card sa mga setting ng Chrome</translation>
<translation id="8918231688545606538">Kahina-hinala ang page na ito</translation>
+<translation id="8922013791253848639">Palaging payagan ang mga ad sa site na ito</translation>
<translation id="892588693504540538">Punch top right</translation>
<translation id="8931333241327730545">Gusto mo bang i-save ang card na ito sa iyong Google Account?</translation>
<translation id="8932102934695377596">Nahuhuli ang iyong orasan</translation>
@@ -2016,6 +2061,7 @@ Mga karagdagang detalye:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419">Gumagamit ng hindi sinusuportahang protocol ang <ph name="HOST_NAME" />.</translation>
<translation id="9191834167571392248">Punch bottom left</translation>
+<translation id="9199905725844810519">Naka-block ang pag-print</translation>
<translation id="9205078245616868884">Na-encrypt ang iyong data gamit ang iyong passphrase sa pag-sync. Ilagay ito upang simulan ang pag-sync.</translation>
<translation id="9207861905230894330">Hindi naidagdag ang artikulo.</translation>
<translation id="9213433120051936369">I-customize ang hitsura</translation>
@@ -2026,8 +2072,10 @@ Mga karagdagang detalye:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Maaari kang mawalan ng access sa iyong Google Account. Inirerekomenda ng Chromium na palitan na ang iyong password. Hihilingin sa iyong mag-sign in.</translation>
<translation id="939736085109172342">Bagong folder</translation>
+<translation id="945522503751344254">Magpadala ng feedback</translation>
<translation id="945855313015696284">Tingnan ang impormasyon sa ibaba at mag-delete ng anumang invalid na card</translation>
<translation id="950736567201356821">Triple punch top</translation>
+<translation id="951941430552851965">Na-pause ng iyong administrator ang screen capture dahil sa content sa screen mo.</translation>
<translation id="961663415146723894">Bind bottom</translation>
<translation id="962484866189421427">Maaaring subukan ng content na itong mag-install ng mga mapanlinlang na app na nagpapanggap na ibang bagay o nangongolekta ng data na maaaring gamitin para subaybayan ka. <ph name="BEGIN_LINK" />Ipakita pa rin<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Official Build</translation>
diff --git a/chromium/components/strings/components_strings_fr-CA.xtb b/chromium/components/strings/components_strings_fr-CA.xtb
index 458d0da58ef..14c7345de46 100644
--- a/chromium/components/strings/components_strings_fr-CA.xtb
+++ b/chromium/components/strings/components_strings_fr-CA.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Vous avez entré votre mot de passe sur un site qui n'est pas géré par votre organisation. Pour protéger votre compte, ne réutilisez pas votre mot de passe dans d'autres applications ni sur d'autres sites.</translation>
<translation id="1263231323834454256">Liste de lecture</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Les activités qui ne seront pas enregistrées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les pages que vous voyez dans cette fenêtre
+ <ph name="LIST_ITEM" />Les témoins et les données relatives aux sites
+ <ph name="LIST_ITEM" />Les données relatives au compte (<ph name="LINK_BEGIN" />se déconnecter<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Mode de ramassage</translation>
<translation id="1281476433249504884">Empileur 1</translation>
<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">Connectez-vous pour utiliser les mots de passe enregistrés dans votre compte Google</translation>
<translation id="2053111141626950936">Les pages en <ph name="LANGUAGE" /> ne seront pas traduites.</translation>
<translation id="2053553514270667976">Code postal</translation>
+<translation id="2054665754582400095">Votre présence</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}one{# suggestion}other{# suggestions}}</translation>
<translation id="2079545284768500474">Annuler</translation>
<translation id="20817612488360358">Les paramètres de mandataire du système sont configurés pour être utilisés, mais une configuration de mandataire explicite est également spécifiée.</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Applications Android</translation>
<translation id="2107021941795971877">Supports d'impression</translation>
<translation id="2108755909498034140">Redémarrer l'ordinateur</translation>
+<translation id="2111166930115883695">Appuyez sur la barre d'espacement pour jouer</translation>
<translation id="2111256659903765347">Super A</translation>
<translation id="2113977810652731515">Carte</translation>
<translation id="2114841414352855701">Politique sans effet, car remplacée par <ph name="POLICY_NAME" />.</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">Annuler le paiement</translation>
<translation id="2147827593068025794">Synchronisation en arrière-plan</translation>
<translation id="2148613324460538318">Ajouter une carte</translation>
+<translation id="2149968176347646218">La connexion n'est pas sécurisée</translation>
<translation id="2154054054215849342">La synchronisation n'est pas offerte pour votre domaine</translation>
<translation id="2154484045852737596">Modifier la carte</translation>
<translation id="2161656808144014275">Texte</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">Règles</translation>
<translation id="2183608646556468874">Numéro de téléphone</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresses}}</translation>
-<translation id="2187243482123994665">Présence de l'utilisateur</translation>
<translation id="2187317261103489799">Détecter (par défaut)</translation>
<translation id="2188375229972301266">Perforation multiple en bas</translation>
<translation id="2202020181578195191">Entrez une année d'expiration valide</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">Cette URL mène à un site faux</translation>
<translation id="2850739647070081192">Enveloppe d'invitation</translation>
<translation id="2856444702002559011">Les cyberpirates peuvent essayer de voler vos données à partir de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (par exemple, des mots de passe, des messages ou des numéros de carte de crédit). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ce site diffuse des annonces intrusives ou trompeuses.</translation>
<translation id="2878197950673342043">Pli au format affiche</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Position des fenêtres</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Suggestions de Google</translation>
<translation id="3002501248619246229">Vérifier le support du bac d'alimentation</translation>
<translation id="3005723025932146533">Afficher une copie sauvegardée</translation>
-<translation id="3007719053326478567">Votre administrateur a bloqué l'impression de ce contenu</translation>
<translation id="3008447029300691911">Entrez le code de vérification de carte (CVC) pour <ph name="CREDIT_CARD" />. Après confirmation, les détails de votre carte seront partagés avec ce site.</translation>
<translation id="3010559122411665027">Élément de liste « <ph name="ENTRY_INDEX" /> » : <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloquée automatiquement</translation>
<translation id="3016780570757425217">Connaître votre emplacement</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour retirer la suggestion.</translation>
<translation id="3023071826883856138">Enveloppe You4</translation>
<translation id="3024663005179499861">Type de politique incorrect</translation>
<translation id="3037605927509011580">Aïe aïe aïe!</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">Favori</translation>
<translation id="3209034400446768650">Cette page peut exiger des frais</translation>
<translation id="3212581601480735796">Votre activité sur <ph name="HOSTNAME" /> est surveillée</translation>
+<translation id="3212623355668894776">Fermez toutes les fenêtres d'invité pour que votre activité de navigation soit supprimée de cet appareil.</translation>
<translation id="3215092763954878852">Impossible d'utiliser WebAuthn</translation>
<translation id="3218181027817787318">Relatif</translation>
<translation id="3225919329040284222">Le serveur dispose d'un certificat qui ne répond pas aux exigences intégrées. Celles-ci sont incluses dans certains sites Web très sécurisés afin de vous protéger.</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">Appareils Bluetooth</translation>
<translation id="3787705759683870569">Date d'expiration : <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Taille 16</translation>
+<translation id="3789841737615482174">Installer</translation>
<translation id="3793574014653384240">Nombre et causes des plantages survenus récemment</translation>
<translation id="3797522431967816232">Enveloppe Prc3</translation>
<translation id="3799805948399000906">Police demandée</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">Sépia</translation>
<translation id="4058922952496707368">Clé « <ph name="SUBKEY" /> » : <ph name="ERROR" /></translation>
<translation id="4067263367174615723">Enveloppe C1</translation>
+<translation id="4067669230157909013">La capture d'écran a repris.</translation>
<translation id="4067947977115446013">Ajouter une adresse valide</translation>
<translation id="4072486802667267160">Une erreur s'est produite lors du traitement de votre commande. Veuillez réessayer.</translation>
<translation id="4075732493274867456">Le client et le serveur ne prennent pas en charge une version habituelle du protocole SSL et de la suite de chiffrement.</translation>
@@ -826,6 +840,7 @@
<translation id="4297502707443874121">Miniature pour la page <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Développer</translation>
<translation id="4300675098767811073">Multiple perforation à droite</translation>
+<translation id="4302514097724775343">Touchez le dinosaure pour jouer</translation>
<translation id="4302965934281694568">Enveloppe Chou3</translation>
<translation id="4305666528087210886">Impossible d'accéder à votre fichier</translation>
<translation id="4305817255990598646">Changer</translation>
@@ -904,6 +919,7 @@
<translation id="4658638640878098064">Agrafe en haut à gauche</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Réalité virtuelle</translation>
+<translation id="4675657451653251260">En mode Invité, vous ne verrez aucun renseignement sur le profil dans Chrome. Vous pouvez <ph name="LINK_BEGIN" />vous connecter<ph name="LINK_END" /> pour accéder aux données de votre compte Google, comme vos mots de passe et vos modes de paiement.</translation>
<translation id="467662567472608290">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité contient des erreurs. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="4677585247300749148">L'URL <ph name="URL" /> veut répondre aux événements d'accessibilité</translation>
<translation id="467809019005607715">Google Présentations</translation>
@@ -931,6 +947,12 @@
<translation id="4761104368405085019">Utiliser votre microphone</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4766713847338118463">Double agrafe en bas</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Les activités qui seront enregistrées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les fichiers que vous téléchargez dans cette fenêtre
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Fenêtre contextuelle bloquée}one{# fenêtre contextuelle bloquée}other{# fenêtres contextuelles bloquées}}</translation>
<translation id="4780366598804516005">Boîte aux lettres 1</translation>
@@ -1093,11 +1115,13 @@
<translation id="5386426401304769735">La chaîne de certificat pour ce site contient un certificat qui a été signé avec SHA-1.</translation>
<translation id="538659543871111977">A4 à onglet</translation>
<translation id="5396631636586785122">Agrafage par le bord droit</translation>
+<translation id="5398772614898833570">Annonces bloquées</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas valide présentement. Cela peut être dû à une mauvaise configuration ou à l'interception de votre connexion par une personne malveillante.</translation>
<translation id="541416427766103491">Empileur 4</translation>
<translation id="5421136146218899937">Effacer les données de navigation...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> veut vous envoyer des notifications.</translation>
+<translation id="542872847390508405">Vous naviguez en tant qu'invité</translation>
<translation id="5430298929874300616">Supprimer le favori</translation>
<translation id="5439770059721715174">Erreur de validation du schéma à « <ph name="ERROR_PATH" /> » : <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordre inversé, face vers le haut</translation>
@@ -1139,12 +1163,12 @@
<translation id="5571083550517324815">Impossible d'effectuer un ramassage à partir de cette adresse. Sélectionnez une autre adresse.</translation>
<translation id="5580958916614886209">Vérifiez le mois d'expiration et réessayez</translation>
<translation id="5586446728396275693">Aucune adresse enregistrée</translation>
+<translation id="5593349413089863479">La connexion n'est pas entièrement sécurisée</translation>
<translation id="5595485650161345191">Modifier l'adresse</translation>
<translation id="5598944008576757369">Choisir un mode de paiement</translation>
<translation id="560412284261940334">La gestion n'est pas prise en charge</translation>
<translation id="5605670050355397069">Grand livre</translation>
<translation id="5607240918979444548">Architecture C</translation>
-<translation id="5608165884683734521">Ce site pourrait être faux ou frauduleux. Chrome vous recommande de le quitter maintenant.</translation>
<translation id="5610142619324316209">De vérifier la connexion</translation>
<translation id="5610807607761827392">Vous pouvez gérer les cartes et les adresses dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduisez cette page avec Google Traduction</translation>
@@ -1216,6 +1240,7 @@
<translation id="5901630391730855834">Jaune</translation>
<translation id="5905445707201418379">Contenu bloqué conformément à la politique relative à l'origine de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronisé)</translation>
+<translation id="5913377024445952699">Capture d'écran mise en pause</translation>
<translation id="59174027418879706">Activé</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Activé</translation>
@@ -1228,6 +1253,7 @@
<translation id="5963413905009737549">Section</translation>
<translation id="5967592137238574583">Modifier les coordonnées</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
+<translation id="5968793460449681917">À chaque visite</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
<translation id="5979084224081478209">Vérifier les mots de passe</translation>
<translation id="5980920751713728343">Fiche, 3 po x 5 po</translation>
@@ -1383,6 +1409,7 @@
<translation id="6587923378399804057">Le lien que vous avez copié</translation>
<translation id="6591833882275308647">Votre <ph name="DEVICE_TYPE" /> n'est pas géré</translation>
<translation id="6596325263575161958">Options de chiffrement</translation>
+<translation id="6596892391065203054">Votre administrateur a bloqué l'impression de ce contenu.</translation>
<translation id="6604181099783169992">Capteurs de mouvement ou de luminosité</translation>
<translation id="6609880536175561541">Enveloppe Prc7</translation>
<translation id="6612358246767739896">Contenu protégé</translation>
@@ -1442,6 +1469,7 @@
<translation id="6895330447102777224">Votre carte est confirmée</translation>
<translation id="6897140037006041989">Agent utilisateur</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">Accorder les autorisations suivantes à <ph name="SITE_NAME" /> :</translation>
<translation id="6910240653697687763">L'URL <ph name="URL" /> veut obtenir le plein contrôle de vos appareils MIDI</translation>
<translation id="6915804003454593391">Utilisateur :</translation>
<translation id="6934672428414710184">Ce nom provient de votre compte Google</translation>
@@ -1553,6 +1581,7 @@ Détails supplémentaires :
<translation id="7346048084945669753">Affilié :</translation>
<translation id="7349430561505560861">A4 Extra</translation>
<translation id="7353601530677266744">Ligne de commande</translation>
+<translation id="7359588939039777303">Annonces bloquées.</translation>
<translation id="7372973238305370288">résultat de la recherche</translation>
<translation id="7374733840632556089">Ce problème survient en raison d'un certificat installé, par vous ou quelqu'un d'autre, sur votre appareil. Le certificat n'est pas considéré comme fiable par Chrome, parce qu'on sait qu'il est utilisé pour surveiller et intercepter les réseaux. Certains cas requièrent de la surveillance, comme un réseau scolaire ou d'entreprise, mais Chrome vous le mentionne pour que vous sachiez que cette surveillance se produit, même si vous ne pouvez pas l'empêcher. La surveillance peut se produire dans tous les navigateurs et toutes les applications qui accèdent au Web.</translation>
<translation id="7375818412732305729">Un fichier est joint</translation>
@@ -1727,6 +1756,7 @@ Détails supplémentaires :
<translation id="7976214039405368314">Trop de demandes</translation>
<translation id="7977538094055660992">Appareil de sortie</translation>
<translation id="7977894662897852582">EDP</translation>
+<translation id="79859296434321399">Pour regarder du contenu de réalité augmentée, installez ARCore</translation>
<translation id="799149739215780103">Reliure</translation>
<translation id="7995512525968007366">Non spécifié</translation>
<translation id="800218591365569300">Essayez de fermer d'autres onglets ou programmes pour libérer de la mémoire.</translation>
@@ -1854,24 +1884,38 @@ Détails supplémentaires :
<translation id="8507227106804027148">Ligne de commande</translation>
<translation id="8508648098325802031">Icône de recherche</translation>
<translation id="8522552481199248698">Chrome peut vous aider à protéger votre compte Google et à changer votre mot de passe.</translation>
+<translation id="8525306231823319788">Plein écran</translation>
<translation id="8530813470445476232">Effacez votre historique de navigation, vos témoins, votre cache et plus encore dans les paramètres de Chrome</translation>
<translation id="8533619373899488139">Consultez &lt;strong&gt;chrome://policy&lt;/strong&gt; pour voir les URL bloquées et des politiques mises en œuvre par votre administrateur système.</translation>
<translation id="8541158209346794904">Appareil Bluetooth</translation>
<translation id="8542014550340843547">Triple agrafe en bas</translation>
<translation id="8543181531796978784">Vous pouvez <ph name="BEGIN_ERROR_LINK" />signaler un problème de détection<ph name="END_ERROR_LINK" /> ou, si vous comprenez les risques pour votre sécurité, <ph name="BEGIN_LINK" />consultez ce site dangereux<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Le code de vérification de carte (CVC) se trouve au dos de votre carte</translation>
+<translation id="8558485628462305855">Pour regarder du contenu de réalité augmentée, mettez à jour ARCore</translation>
<translation id="8559762987265718583">Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, car la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrectes.</translation>
<translation id="8564182942834072828">Documents séparés/Copies non assemblées</translation>
<translation id="8564985650692024650">Chromium recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Les activités qui ne seront pas enregistrées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les pages que vous voyez dans cette fenêtre
+ <ph name="LIST_ITEM" />Les témoins et les données relatives aux sites
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Utiliser Touch ID pour vérifier les cartes plus rapidement</translation>
<translation id="858637041960032120">Ajouter un numéro de téléphone</translation>
<translation id="8589998999637048520">Meilleure qualité</translation>
+<translation id="8600271352425265729">Uniquement cette fois-ci</translation>
<translation id="860043288473659153">Nom du titulaire de la carte</translation>
<translation id="8606726445206553943">Utiliser vos appareils MIDI</translation>
+<translation id="8612761427948161954">Bonjour <ph name="USERNAME" />,
+ <ph name="BR" />
+ Vous naviguez en tant qu'invité</translation>
<translation id="861775596732816396">Taille 4</translation>
<translation id="8622948367223941507">Légal extra</translation>
<translation id="8623885649813806493">Aucun mot de passe correspondant. Afficher tous les mots de passe enregistrés.</translation>
<translation id="8625384913736129811">Enregistrer cette carte sur cet appareil</translation>
+<translation id="8627040765059109009">Capture d'écran réactivée</translation>
<translation id="8657078576661269990">Votre administrateur a bloqué le partage de <ph name="ORIGIN_NAME" /> vers <ph name="VM_NAME_1" /> et vers <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Résumé de la commande, <ph name="TOTAL_LABEL" />, plus de détails</translation>
<translation id="867224526087042813">Signature</translation>
@@ -1934,6 +1978,7 @@ Détails supplémentaires :
<translation id="8912362522468806198">Compte Google</translation>
<translation id="8913778647360618320">Bouton de gestion des modes de paiement, appuyez sur la touche Entrée pour gérer vos données de paiement et vos cartes de crédit dans les paramètres de Chrome</translation>
<translation id="8918231688545606538">Cette page est suspecte</translation>
+<translation id="8922013791253848639">Toujours autoriser les annonces sur ce site</translation>
<translation id="892588693504540538">Perforation en haut à droite</translation>
<translation id="8931333241327730545">Voulez-vous enregistrer cette carte sur votre compte Google?</translation>
<translation id="8932102934695377596">Votre horloge retarde</translation>
@@ -2005,6 +2050,7 @@ Détails supplémentaires :
<translation id="9183302530794969518">Google Documents</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utilise un protocole non pris en charge.</translation>
<translation id="9191834167571392248">Perforation en bas à gauche</translation>
+<translation id="9199905725844810519">L'impression est bloquée</translation>
<translation id="9205078245616868884">Vos données sont chiffrées avec votre phrase de passe de synchronisation. Veuillez l'entrer pour commencer la synchronisation.</translation>
<translation id="9207861905230894330">Échec de l'ajout d'un article.</translation>
<translation id="9213433120051936369">Personnaliser l'apparence</translation>
@@ -2015,8 +2061,10 @@ Détails supplémentaires :
<translation id="936474030629450166">Super B</translation>
<translation id="936602727769022409">Vous risquez de perdre l'accès à votre compte Google. Chromium recommande de modifier votre mot de passe immédiatement. Vous serez invité à vous connecter.</translation>
<translation id="939736085109172342">Nouveau dossier</translation>
+<translation id="945522503751344254">Envoyer un commentaire à Google</translation>
<translation id="945855313015696284">Vérifiez les renseignements ci-dessous et supprimez les cartes incorrectes</translation>
<translation id="950736567201356821">Triple perforation en haut</translation>
+<translation id="951941430552851965">La capture d'écran a été interrompue par votre administrateur en raison du contenu affiché sur votre écran.</translation>
<translation id="961663415146723894">Reliure en bas</translation>
<translation id="962484866189421427">Ce contenu peut essayer d'installer des applications trompeuses qui prétendent être autre chose que ce qu'elles sont ou qui collectent des données pouvant être utilisées pour effectuer le suivi de votre activité. <ph name="BEGIN_LINK" />Afficher quand même<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Version officielle</translation>
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index 4fbd55bdcaf..681fe7e6204 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -80,6 +80,14 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Vous avez saisi votre mot de passe sur un site qui n'est pas géré par votre organisation. Pour protéger votre compte, ne réutilisez pas ce mot de passe dans d'autres applications ni sur d'autres sites.</translation>
<translation id="1263231323834454256">Liste de lecture</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Les données d'activité suivantes ne seront pas conservées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les pages que vous consultez dans cette fenêtre
+ <ph name="LIST_ITEM" />Les cookies et données de site
+ <ph name="LIST_ITEM" />Les informations de compte (<ph name="LINK_BEGIN" />déconnectez-vous<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Mode d'enlèvement</translation>
<translation id="1281476433249504884">Empileur 1</translation>
<translation id="1285320974508926690">Ne jamais traduire ce site</translation>
@@ -190,7 +198,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1652415888492971589">JIS B8</translation>
<translation id="1656024727720460136">Chrome a simplifié cette page pour qu'elle soit plus facile à lire. La page d'origine a été récupérée au moyen d'une connexion sécurisée.</translation>
<translation id="1656489000284462475">Enlèvement</translation>
-<translation id="1662550410081243962">Enregistrer et renseigner les modes de paiement</translation>
+<translation id="1662550410081243962">Enregistrer et saisir les modes de paiement</translation>
<translation id="1663943134801823270">Les cartes et les adresses proviennent de Chrome. Vous pouvez les gérer dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="1671391448414634642">Les pages en <ph name="SOURCE_LANGUAGE" /> seront désormais traduites en <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="1676269943528358898">Un chiffrement est normalement utilisé sur le site <ph name="SITE" /> pour protéger vos informations. Lors de la dernière tentative de connexion de Google Chrome au site <ph name="SITE" />, des identifiants inhabituels et incorrects ont été retournés. Il est possible qu'un individu malveillant tente de se faire passer pour <ph name="SITE" /> ou qu'un écran de connexion Wi-Fi ait interrompu la connexion. Vos informations restent sécurisées, car nous avons arrêté la connexion avant l'échange des données.</translation>
@@ -283,6 +291,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="204357726431741734">Connectez-vous pour utiliser les mots de passe enregistrés dans votre compte Google</translation>
<translation id="2053111141626950936">Les pages en <ph name="LANGUAGE" /> ne seront pas traduites.</translation>
<translation id="2053553514270667976">Code postal</translation>
+<translation id="2054665754582400095">Votre présence</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}one{# suggestion}other{# suggestions}}</translation>
<translation id="2079545284768500474">Annuler</translation>
<translation id="20817612488360358">Les paramètres de proxy du système sont configurés pour être utilisés, mais une configuration de proxy explicite est également spécifiée.</translation>
@@ -296,6 +305,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2102495993840063010">Applications Android</translation>
<translation id="2107021941795971877">Supports d'impression</translation>
<translation id="2108755909498034140">Redémarrez l'ordinateur</translation>
+<translation id="2111166930115883695">Appuyez sur la barre d'espace pour jouer</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Carte</translation>
<translation id="2114841414352855701">Ignorée parce que remplacée par <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="214556005048008348">Annuler le paiement</translation>
<translation id="2147827593068025794">Synchronisation en arrière-plan</translation>
<translation id="2148613324460538318">Ajouter une carte</translation>
+<translation id="2149968176347646218">La connexion n'est pas sécurisée</translation>
<translation id="2154054054215849342">La synchronisation n'est pas disponible pour votre domaine</translation>
<translation id="2154484045852737596">Modifier la carte</translation>
<translation id="2161656808144014275">Texte</translation>
@@ -317,7 +328,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2181821976797666341">Règles</translation>
<translation id="2183608646556468874">Numéro de téléphone</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}one{# adresse}other{# adresses}}</translation>
-<translation id="2187243482123994665">Présence de l'utilisateur</translation>
<translation id="2187317261103489799">Détecter (par défaut)</translation>
<translation id="2188375229972301266">Multiple perforation en bas</translation>
<translation id="2202020181578195191">Saisissez une année d'expiration valide</translation>
@@ -468,6 +478,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2839501879576190149">Attention : faux site</translation>
<translation id="2850739647070081192">Invite (enveloppe)</translation>
<translation id="2856444702002559011">Des individus malveillants tentent peut-être de subtiliser vos informations personnelles sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (mots de passe, messages ou numéros de carte de crédit, par exemple). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ce site affiche des annonces intrusives ou trompeuses.</translation>
<translation id="2878197950673342043">Pli au format affiche</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Positionnement des fenêtres</translation>
@@ -506,11 +517,11 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2996674880327704673">Suggestions de Google</translation>
<translation id="3002501248619246229">Vérifier le support du bac d'alimentation</translation>
<translation id="3005723025932146533">Afficher la copie enregistrée</translation>
-<translation id="3007719053326478567">L'administrateur a bloqué l'impression de ce contenu</translation>
<translation id="3008447029300691911">Saisissez le code CVC de la carte <ph name="CREDIT_CARD" />. Une fois la validation terminée, les informations relatives à la carte seront partagées avec ce site.</translation>
<translation id="3010559122411665027">Entrée de la liste "<ph name="ENTRY_INDEX" />" : <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloquée automatiquement</translation>
<translation id="3016780570757425217">Connaître votre position</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, appuyez sur Tabulation, puis sur Entrée pour supprimer la suggestion.</translation>
<translation id="3023071826883856138">You4 (enveloppe)</translation>
<translation id="3024663005179499861">Type de règle incorrect.</translation>
<translation id="3037605927509011580">Aïe aïe aïe</translation>
@@ -553,6 +564,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3207960819495026254">Favori</translation>
<translation id="3209034400446768650">Cette page peut vous facturer de l'argent</translation>
<translation id="3212581601480735796">Votre activité sur <ph name="HOSTNAME" /> est surveillée</translation>
+<translation id="3212623355668894776">Fermez toutes les fenêtres en mode Invité pour que votre activité de navigation soit supprimée de cet appareil.</translation>
<translation id="3215092763954878852">Impossible d'utiliser WebAuthn</translation>
<translation id="3218181027817787318">Valeur relative</translation>
<translation id="3225919329040284222">Le serveur dispose d'un certificat qui ne répond pas aux exigences intégrées. Celles-ci sont incluses dans certains sites Web très sécurisés afin de vous protéger.</translation>
@@ -700,6 +712,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3784372983762739446">Appareils Bluetooth</translation>
<translation id="3787705759683870569">Expire en <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Taille 16</translation>
+<translation id="3789841737615482174">Installer</translation>
<translation id="3793574014653384240">Nombre et causes des plantages survenus récemment</translation>
<translation id="3797522431967816232">Prc3 (enveloppe)</translation>
<translation id="3799805948399000906">Police demandée</translation>
@@ -751,6 +764,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4056223980640387499">Sépia</translation>
<translation id="4058922952496707368">Clé "<ph name="SUBKEY" />" : <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (enveloppe)</translation>
+<translation id="4067669230157909013">L'enregistrement de l'écran a repris.</translation>
<translation id="4067947977115446013">Ajouter une adresse valide</translation>
<translation id="4072486802667267160">Une erreur s'est produite lors du traitement de votre commande. Veuillez réessayer.</translation>
<translation id="4075732493274867456">Le client et le serveur ne sont pas compatibles avec une version de protocole ou une méthode de chiffrement SSL commune.</translation>
@@ -835,6 +849,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4297502707443874121">Vignette de la page <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Développer</translation>
<translation id="4300675098767811073">Multiple perforation à droite</translation>
+<translation id="4302514097724775343">Appuyez sur le dinosaure pour jouer</translation>
<translation id="4302965934281694568">Chou3 (enveloppe)</translation>
<translation id="4305666528087210886">Impossible d'accéder à votre fichier</translation>
<translation id="4305817255990598646">Changer</translation>
@@ -913,6 +928,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4658638640878098064">Agrafe en haut à gauche</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Réalité virtuelle</translation>
+<translation id="4675657451653251260">Vous ne pouvez voir aucune information de profil Chrome en mode Invité. Pour accéder à des informations liées à votre compte Google, comme vos mots de passe et modes de paiement, vous pouvez <ph name="LINK_BEGIN" />vous connecter<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité contient des erreurs. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="4677585247300749148"><ph name="URL" /> souhaite répondre aux événements d'accessibilité</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -940,6 +956,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4761104368405085019">Utiliser votre micro</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4766713847338118463">Double agrafe en bas</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Les données d'activité suivantes seront conservées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tous les fichiers que vous téléchargez dans cette fenêtre
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ fenêtre pop-up bloquée}one{# fenêtre pop-up bloquée}other{# fenêtres pop-up bloquées}}</translation>
<translation id="4780366598804516005">Boîte aux lettres 1</translation>
@@ -1102,11 +1124,13 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5386426401304769735">La chaîne de certificats de ce site contient un certificat signé avec SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Agrafage par le bord droit</translation>
+<translation id="5398772614898833570">Annonces bloquées</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Impossible de vérifier que ce serveur est bien <ph name="DOMAIN" />, car son certificat de sécurité actuel n'est pas valide. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="541416427766103491">Empileur 4</translation>
<translation id="5421136146218899937">Effacer les données de navigation...</translation>
<translation id="5426179911063097041">"<ph name="SITE" />" souhaite vous envoyer des notifications</translation>
+<translation id="542872847390508405">Vous naviguez en tant qu'invité</translation>
<translation id="5430298929874300616">Supprimer le favori</translation>
<translation id="5439770059721715174">Erreur de validation du schéma au niveau de "<ph name="ERROR_PATH" />" : <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordre inverse, face vers le haut</translation>
@@ -1148,12 +1172,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5571083550517324815">Enlèvement impossible à cette adresse. Sélectionnez-en une autre.</translation>
<translation id="5580958916614886209">Veuillez vérifier le mois d'expiration, puis réessayer</translation>
<translation id="5586446728396275693">Aucune adresse enregistrée</translation>
+<translation id="5593349413089863479">La connexion n'est pas totalement sécurisée</translation>
<translation id="5595485650161345191">Modifier l'adresse</translation>
<translation id="5598944008576757369">Sélectionner un mode de paiement</translation>
<translation id="560412284261940334">Gestion non acceptée.</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Ce site est peut-être fictif ou frauduleux. Chrome vous recommande de le quitter immédiatement.</translation>
<translation id="5610142619324316209">Vérifier la connexion</translation>
<translation id="5610807607761827392">Vous pouvez gérer les cartes et les adresses dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduisez cette page avec Google Traduction</translation>
@@ -1225,6 +1249,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5901630391730855834">Jaune</translation>
<translation id="5905445707201418379">Bloqué selon la règle relative à l'origine de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronisés)</translation>
+<translation id="5913377024445952699">Capture d'écran mise en pause</translation>
<translation id="59174027418879706">Activé</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Activé</translation>
@@ -1237,6 +1262,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5963413905009737549">Section</translation>
<translation id="5967592137238574583">Modifier les coordonnées</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
+<translation id="5968793460449681917">À chaque visite</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
<translation id="5979084224081478209">Vérifier les mots de passe</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1292,7 +1318,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6151417162996330722">La durée de validité du certificat du serveur est trop longue.</translation>
<translation id="6157877588268064908">Sélectionnez une adresse pour consulter les modes et conditions d'expédition disponibles</translation>
<translation id="6165508094623778733">En savoir plus</translation>
-<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée.</translation>
+<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée</translation>
<translation id="6180316780098470077">Intervalle entre les tentatives</translation>
<translation id="6196640612572343990">Bloquer les cookies tiers</translation>
<translation id="6203231073485539293">Vérifiez votre connexion Internet</translation>
@@ -1392,6 +1418,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6587923378399804057">Lien copié</translation>
<translation id="6591833882275308647">Votre <ph name="DEVICE_TYPE" /> n'est pas géré</translation>
<translation id="6596325263575161958">Options de chiffrement</translation>
+<translation id="6596892391065203054">L'administrateur a bloqué l'impression de ce contenu.</translation>
<translation id="6604181099783169992">Capteurs de mouvement ou de lumière</translation>
<translation id="6609880536175561541">Prc7 (enveloppe)</translation>
<translation id="6612358246767739896">Contenu protégé</translation>
@@ -1451,6 +1478,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6895330447102777224">Carte validée</translation>
<translation id="6897140037006041989">Agent utilisateur</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">Autoriser le site "<ph name="SITE_NAME" />" à :</translation>
<translation id="6910240653697687763"><ph name="URL" /> souhaite obtenir le contrôle total de vos appareils MIDI</translation>
<translation id="6915804003454593391">Utilisateur : </translation>
<translation id="6934672428414710184">Ce nom provient de votre compte Google</translation>
@@ -1515,7 +1543,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="717330890047184534">Identifiant GAIA : </translation>
<translation id="7174545416324379297">Valeurs fusionnées</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autre}one{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autre}other{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autres}}</translation>
-<translation id="7179323680825933600">Enregistrer et renseigner les modes de paiement</translation>
+<translation id="7179323680825933600">Enregistrer et saisir les modes de paiement</translation>
<translation id="7180611975245234373">Actualiser</translation>
<translation id="7181261019481237103">Ouvrir une fenêtre de navigation privée</translation>
<translation id="7182878459783632708">Aucune règle n'est définie</translation>
@@ -1562,6 +1590,7 @@ Informations supplémentaires :
<translation id="7346048084945669753">Affilié :</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Ligne de commande</translation>
+<translation id="7359588939039777303">Annonces bloquées.</translation>
<translation id="7372973238305370288">résultat de recherche</translation>
<translation id="7374733840632556089">Ce problème est dû à un certificat installé sur votre appareil par vous-même ou par quelqu'un d'autre. Ce certificat est utilisé pour surveiller et intercepter des réseaux, et n'est pas approuvé par Chrome. Bien qu'il existe des cas légitimes de surveillance (sur un réseau scolaire ou d'entreprise, par exemple), Chrome souhaite s'assurer que vous êtes au courant de cette activité, même si vous ne pouvez pas l'empêcher. La surveillance peut se produire sur n'importe quel navigateur ou application qui accède au Web.</translation>
<translation id="7375818412732305729">Fichier joint</translation>
@@ -1662,7 +1691,7 @@ Informations supplémentaires :
<translation id="7673278391011283842">Boîte aux lettres 6</translation>
<translation id="7676643023259824263">Rechercher le texte du presse-papier "<ph name="TEXT" />"</translation>
<translation id="7682287625158474539">Adresse de livraison</translation>
-<translation id="7687186412095877299">Saisit automatiquement les informations correspondant aux modes de paiement enregistrés</translation>
+<translation id="7687186412095877299">Saisir automatiquement les informations correspondant aux modes de paiement enregistrés</translation>
<translation id="7687305263118037187">Délai de nouvelle tentative</translation>
<translation id="7693583928066320343">Ordre des pages reçu</translation>
<translation id="7697066736081121494">Prc8 (enveloppe)</translation>
@@ -1736,6 +1765,7 @@ Informations supplémentaires :
<translation id="7976214039405368314">Trop de demandes</translation>
<translation id="7977538094055660992">Périphérique de sortie</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Pour afficher des contenus en réalité augmentée, installez ARCore</translation>
<translation id="799149739215780103">Reliure</translation>
<translation id="7995512525968007366">Non spécifié</translation>
<translation id="800218591365569300">Essayez de fermer les autres onglets ou programmes pour libérer de la mémoire.</translation>
@@ -1863,24 +1893,38 @@ Informations supplémentaires :
<translation id="8507227106804027148">Ligne de commande</translation>
<translation id="8508648098325802031">Icône Recherche</translation>
<translation id="8522552481199248698">Chrome peut vous aider à protéger votre compte Google et à modifier votre mot de passe.</translation>
+<translation id="8525306231823319788">Plein écran</translation>
<translation id="8530813470445476232">Effacez votre historique de navigation, supprimez les cookies, videz le cache, et plus encore dans les paramètres Chrome</translation>
<translation id="8533619373899488139">Pour consulter la liste des URL bloquées et des autres règles définies par votre administrateur système, rendez-vous sur &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
<translation id="8541158209346794904">Appareil Bluetooth</translation>
<translation id="8542014550340843547">Triple agrafe en bas</translation>
<translation id="8543181531796978784">Vous pouvez <ph name="BEGIN_ERROR_LINK" />signaler un problème de détection<ph name="END_ERROR_LINK" />. Si vous avez compris les risques auxquels vous vous exposez, vous pouvez <ph name="BEGIN_LINK" />consulter ce site dangereux<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Le code CVC figure au recto de votre carte.</translation>
+<translation id="8558485628462305855">Pour afficher des contenus en réalité augmentée, mettez à jour ARCore</translation>
<translation id="8559762987265718583">Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> : la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrectes.</translation>
<translation id="8564182942834072828">Documents séparés/Copies non assemblées</translation>
<translation id="8564985650692024650">L'équipe Chromium vous recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Les données d'activité suivantes ne seront pas conservées sur cet appareil :
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les pages que vous consultez dans cette fenêtre
+ <ph name="LIST_ITEM" />Les cookies et données de site
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Utiliser Touch ID pour confirmer les cartes plus rapidement</translation>
<translation id="858637041960032120">Saisir num tél</translation>
<translation id="8589998999637048520">Qualité optimale</translation>
+<translation id="8600271352425265729">Uniquement cette fois-ci</translation>
<translation id="860043288473659153">Nom du titulaire de la carte</translation>
<translation id="8606726445206553943">Utiliser vos appareils MIDI</translation>
+<translation id="8612761427948161954">Bonjour <ph name="USERNAME" />,
+ <ph name="BR" />
+ Vous êtes actuellement en mode Invité</translation>
<translation id="861775596732816396">Taille 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Aucun mot de passe enregistré. Afficher tous les mots de passe enregistrés.</translation>
<translation id="8625384913736129811">Enregistrer cette carte sur cet appareil</translation>
+<translation id="8627040765059109009">Capture d'écran réactivée</translation>
<translation id="8657078576661269990">L'administrateur a interdit le partage de données depuis <ph name="ORIGIN_NAME" /> vers <ph name="VM_NAME_1" /> et <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Récapitulatif de la commande, <ph name="TOTAL_LABEL" />, détails supplémentaires</translation>
<translation id="867224526087042813">Signature</translation>
@@ -1943,6 +1987,7 @@ Informations supplémentaires :
<translation id="8912362522468806198">Compte Google</translation>
<translation id="8913778647360618320">Bouton "Gérer les modes de paiement" : appuyer sur Entrée pour gérer vos paiements et les informations sur vos cartes de crédit dans les paramètres Chrome</translation>
<translation id="8918231688545606538">Cette page est suspecte</translation>
+<translation id="8922013791253848639">Toujours autoriser les annonces sur ce site</translation>
<translation id="892588693504540538">Perforation en haut à droite</translation>
<translation id="8931333241327730545">Voulez-vous enregistrer cette carte dans votre compte Google ?</translation>
<translation id="8932102934695377596">Votre horloge est en retard</translation>
@@ -1993,7 +2038,7 @@ Informations supplémentaires :
<translation id="9114524666733003316">Validation de la carte…</translation>
<translation id="9114581008513152754">Ce navigateur n'est géré par aucune entreprise ni aucune autre organisation. Il se peut que l'activité sur cet appareil soit gérée en dehors de Chrome. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
<translation id="9119042192571987207">Importation terminée</translation>
-<translation id="9128870381267983090">Se connecter au réseau</translation>
+<translation id="9128870381267983090">Connectez-vous au réseau</translation>
<translation id="9137013805542155359">Afficher l'original</translation>
<translation id="9141013498910525015">Gérer les adresses</translation>
<translation id="9148088599418889305">Sélectionner un mode de livraison</translation>
@@ -2014,6 +2059,7 @@ Informations supplémentaires :
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utilise un protocole incompatible.</translation>
<translation id="9191834167571392248">Perforation en bas à gauche</translation>
+<translation id="9199905725844810519">Impression bloquée</translation>
<translation id="9205078245616868884">Vos données sont chiffrées avec votre phrase secrète de synchronisation. Saisissez-la pour lancer la synchronisation.</translation>
<translation id="9207861905230894330">Échec de l'ajout de l'article.</translation>
<translation id="9213433120051936369">Personnaliser l'apparence</translation>
@@ -2024,8 +2070,10 @@ Informations supplémentaires :
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Vous pourriez perdre l'accès à votre compte Google. L'équipe Chromium vous recommande de modifier votre mot de passe maintenant. Vous devrez vous connecter.</translation>
<translation id="939736085109172342">Nouveau dossier</translation>
+<translation id="945522503751344254">Envoyer un commentaire</translation>
<translation id="945855313015696284">Vérifiez les informations ci-dessous et supprimez les cartes non valides</translation>
<translation id="950736567201356821">Triple perforation en haut</translation>
+<translation id="951941430552851965">Votre administrateur a suspendu l'enregistrement de l'écran en raison du contenu qui y est affiché.</translation>
<translation id="961663415146723894">Reliure en bas</translation>
<translation id="962484866189421427">Ce contenu peut essayer d'installer des applications trompeuses se faisant passer pour d'autres, ou de collecter des données afin de vous surveiller. <ph name="BEGIN_LINK" />Je souhaite y accéder malgré tout.<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Build officiel</translation>
diff --git a/chromium/components/strings/components_strings_gl.xtb b/chromium/components/strings/components_strings_gl.xtb
index 13648fa8cd5..0c139430bfc 100644
--- a/chromium/components/strings/components_strings_gl.xtb
+++ b/chromium/components/strings/components_strings_gl.xtb
@@ -80,6 +80,14 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Introduciches o teu contrasinal nun sitio que non está xestionado pola túa organización. Para protexer a túa conta, non reutilices o contrasinal noutras aplicacións ou sitios.</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Actividade que non permanecerá neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />As páxinas que vexas nesta ventá
+ <ph name="LIST_ITEM" />As cookies e os datos dos sitios
+ <ph name="LIST_ITEM" />A información da conta (<ph name="LINK_BEGIN" />pechar sesión<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Método de recollida</translation>
<translation id="1281476433249504884">Amontoador 1</translation>
<translation id="1285320974508926690">Non traducir nunca este sitio</translation>
@@ -282,6 +290,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="204357726431741734">Iniciar sesión para utilizar contrasinais gardados na túa Conta de Google</translation>
<translation id="2053111141626950936">Non se traducirán as páxinas en <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Código postal</translation>
+<translation id="2054665754582400095">A túa presenza</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suxestión}other{# suxestións}}</translation>
<translation id="2079545284768500474">Desfacer</translation>
<translation id="20817612488360358">Estableceuse a configuración do proxy do sistema que debe utilizarse, pero tamén se especificou unha configuración de proxy explícita.</translation>
@@ -295,6 +304,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2102495993840063010">Aplicacións de Android</translation>
<translation id="2107021941795971877">Soportes de impresión</translation>
<translation id="2108755909498034140">Reinicia o ordenador</translation>
+<translation id="2111166930115883695">Pulsa Espazo para xogar</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Tarxeta</translation>
<translation id="2114841414352855701">Ignorouse porque a anulou <ph name="POLICY_NAME" />.</translation>
@@ -306,6 +316,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
<translation id="2148613324460538318">Engadir tarxeta</translation>
+<translation id="2149968176347646218">A conexión non é segura</translation>
<translation id="2154054054215849342">A sincronización non está dispoñible para o teu dominio</translation>
<translation id="2154484045852737596">Editar tarxeta</translation>
<translation id="2161656808144014275">Texto</translation>
@@ -316,7 +327,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">Número de teléfono</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 enderezo}other{# enderezos}}</translation>
-<translation id="2187243482123994665">Estado de actividade do usuario</translation>
<translation id="2187317261103489799">Detectar (predeterminado)</translation>
<translation id="2188375229972301266">Varias perforacións na parte inferior</translation>
<translation id="2202020181578195191">Introduce un ano de caducidade válido</translation>
@@ -467,6 +477,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2839501879576190149">O sitio ao que te dirixes é falso</translation>
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">É posible que os piratas informáticos tenten roubar a túa información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, contrasinais, mensaxes ou tarxetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Máis información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Este sitio mostra anuncios intrusivos ou enganosos.</translation>
<translation id="2878197950673342043">Dobrez de póster</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Colocación das ventás</translation>
@@ -505,11 +516,11 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2996674880327704673">Suxestións de Google</translation>
<translation id="3002501248619246229">Comproba o soporte da bandexa de entrada</translation>
<translation id="3005723025932146533">Mostrar copia gardada</translation>
-<translation id="3007719053326478567">O teu administrador bloqueou a opción de imprimir este contido</translation>
<translation id="3008447029300691911">Introduce o código CVC da tarxeta <ph name="CREDIT_CARD" />. Unha vez que confirmes os datos, os detalles da tarxeta compartiranse con este sitio.</translation>
<translation id="3010559122411665027">Entrada da lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueado automaticamente</translation>
<translation id="3016780570757425217">Coñecer a túa localización</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Para quitar a suxestión, preme Tabulador e, a continuación, Introducir.</translation>
<translation id="3023071826883856138">You4 (sobre)</translation>
<translation id="3024663005179499861">Tipo de política incorrecta</translation>
<translation id="3037605927509011580">Vaia!</translation>
@@ -552,6 +563,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3207960819495026254">Engadida a marcadores</translation>
<translation id="3209034400446768650">Nesta páxina pódense aplicar cargos</translation>
<translation id="3212581601480735796">Estase supervisando a túa actividade en <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Pecha todas as ventás do modo de invitado para eliminar a túa actividade de navegación deste dispositivo.</translation>
<translation id="3215092763954878852">Non se puido utilizar WebAuthn</translation>
<translation id="3218181027817787318">Relativo</translation>
<translation id="3225919329040284222">O servidor presentou un certificado que non coincide coas expectativas integradas. Estas expectativas inclúense para determinados sitios web de alta seguranza co fin de protexerte.</translation>
@@ -699,6 +711,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3784372983762739446">Dispositivos Bluetooth</translation>
<translation id="3787705759683870569">Caduca o <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamaño 16</translation>
+<translation id="3789841737615482174">Instalar</translation>
<translation id="3793574014653384240">Número de fallos ocorridos recentemente e as súas causas</translation>
<translation id="3797522431967816232">Prc3 (sobre)</translation>
<translation id="3799805948399000906">Solicitouse a fonte</translation>
@@ -750,6 +763,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Clave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (sobre)</translation>
+<translation id="4067669230157909013">Retomouse o modo de captura de pantalla.</translation>
<translation id="4067947977115446013">Engade un enderezo válido</translation>
<translation id="4072486802667267160">Produciuse un erro ao procesar a túa solicitude. Téntao de novo.</translation>
<translation id="4075732493274867456">O cliente e o servidor non admiten unha versión do protocolo SSL ou o conxunto de cifrado comúns.</translation>
@@ -834,6 +848,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4297502707443874121">Miniatura da páxina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Ampliar</translation>
<translation id="4300675098767811073">Varias perforacións na parte dereita</translation>
+<translation id="4302514097724775343">Toca o dinosauro para xogar</translation>
<translation id="4302965934281694568">Chou3 (sobre)</translation>
<translation id="4305666528087210886">Non se puido acceder ao ficheiro</translation>
<translation id="4305817255990598646">Cambiar</translation>
@@ -912,6 +927,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4658638640878098064">Grampa na parte superior esquerda</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realidade virtual</translation>
+<translation id="4675657451653251260">Non verás a información de ningún perfil de Chrome no modo de invitado. Podes <ph name="LINK_BEGIN" />iniciar sesión<ph name="LINK_END" /> para acceder á información (como os contrasinais e os métodos de pago) da túa conta de Google.</translation>
<translation id="467662567472608290">Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o seu certificado de seguranza contén erros. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.</translation>
<translation id="4677585247300749148">O URL <ph name="URL" /> quere responder a eventos de accesibilidade</translation>
<translation id="467809019005607715">Presentacións de Google</translation>
@@ -939,6 +955,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4761104368405085019">Utilizar o micrófono</translation>
<translation id="4764776831041365478">É posible que a páxina web de <ph name="URL" /> estea temporalmente inactiva ou que se trasladase definitivamente a outro enderezo web.</translation>
<translation id="4766713847338118463">Dúas grampas na parte inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Actividade que permanecerá neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Calquera ficheiro que descargues nesta ventá
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Produciuse un erro descoñecido.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Bloqueouse a ventá emerxente}other{Bloqueáronse # ventás emerxentes}}</translation>
<translation id="4780366598804516005">Caixa de correo 1</translation>
@@ -1101,11 +1123,13 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5386426401304769735">A cadea de certificados deste sitio contén un certificado que se asinou con SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Grampa no bordo dereito</translation>
+<translation id="5398772614898833570">Bloqueáronse os anuncios</translation>
<translation id="5400836586163650660">Gris</translation>
<translation id="540969355065856584">Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o seu certificado de seguranza non é válido neste momento. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.</translation>
<translation id="541416427766103491">Amontoador 4</translation>
<translation id="5421136146218899937">Borrar datos de navegación...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> quere enviarche notificacións</translation>
+<translation id="542872847390508405">Estás navegando como invitado</translation>
<translation id="5430298929874300616">Eliminar marcador</translation>
<translation id="5439770059721715174">Erro de validación de esquema en "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Orde inversa cara arriba</translation>
@@ -1147,12 +1171,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5571083550517324815">Non se pode realizar a recollida neste enderezo. Selecciona un diferente.</translation>
<translation id="5580958916614886209">Comproba o mes de caducidade e téntao de novo</translation>
<translation id="5586446728396275693">Non hai enderezos gardados</translation>
+<translation id="5593349413089863479">A conexión non é totalmente segura</translation>
<translation id="5595485650161345191">Editar enderezo</translation>
<translation id="5598944008576757369">Escoller método de pago</translation>
<translation id="560412284261940334">Xestión non admitida</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Este sitio podería ser falso ou fraudulento. Chrome recomenda saír del agora.</translation>
<translation id="5610142619324316209">Comprobar a conexión</translation>
<translation id="5610807607761827392">Podes xestionar as tarxetas e os enderezos na <ph name="BEGIN_LINK" />Configuración<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduce esta páxina co Tradutor de Google</translation>
@@ -1224,6 +1248,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5901630391730855834">Amarelo</translation>
<translation id="5905445707201418379">Bloqueouse debido á política de orixe de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
+<translation id="5913377024445952699">A captura de pantalla púxose en pausa</translation>
<translation id="59174027418879706">Activado</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Activado</translation>
@@ -1236,11 +1261,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5963413905009737549">Sección</translation>
<translation id="5967592137238574583">Edita a información de contacto</translation>
<translation id="5967867314010545767">Eliminar do historial</translation>
+<translation id="5968793460449681917">Sempre que visite o sitio</translation>
<translation id="5975083100439434680">Afastar</translation>
<translation id="5979084224081478209">Comprobar contrasinais</translation>
<translation id="5980920751713728343">Index-3x5</translation>
<translation id="5984570616552610254">Humidade da cámara</translation>
-<translation id="598637245381783098">Non se pode abrir a aplicación de pago</translation>
+<translation id="598637245381783098">Non se pode abrir a aplicación para pagos</translation>
<translation id="5989320800837274978">Non se especificaron nin servidores proxy fixos nin un URL de script .pac.</translation>
<translation id="5990559369517809815">Unha extensión bloqueou as solicitudes ao servidor.</translation>
<translation id="5992691462791905444">Dobrez en Z para enxeñaría</translation>
@@ -1367,7 +1393,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6451458296329894277">Confirmar reenvío do formulario</translation>
<translation id="6457206614190510200">Costura</translation>
<translation id="6465306955648956876">Xestiona os contrasinais…</translation>
-<translation id="6468485451923838994">Letras</translation>
+<translation id="6468485451923838994">Tipos de letra</translation>
<translation id="647261751007945333">Políticas de dispositivo</translation>
<translation id="6476284679642588870">Xestionar métodos de pago</translation>
<translation id="6489534406876378309">Comezar a cargar erros</translation>
@@ -1391,6 +1417,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6587923378399804057">Ligazón que copiaches</translation>
<translation id="6591833882275308647">O teu <ph name="DEVICE_TYPE" /> non está xestionado</translation>
<translation id="6596325263575161958">Opcións de cifrado</translation>
+<translation id="6596892391065203054">O teu administrador bloqueou a opción de imprimir este contido.</translation>
<translation id="6604181099783169992">Sensores de movemento ou de luz</translation>
<translation id="6609880536175561541">Prc7 (sobre)</translation>
<translation id="6612358246767739896">Contido protexido</translation>
@@ -1439,7 +1466,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6826993739343257035">Queres permitir realidade aumentada?</translation>
<translation id="6831043979455480757">Traducir</translation>
<translation id="6839929833149231406">Ãrea</translation>
-<translation id="6846340164947227603">Usar un número de tarxeta virtual…</translation>
+<translation id="6846340164947227603">Usar un número de conta virtual…</translation>
<translation id="6852204201400771460">Queres volver cargar a aplicación?</translation>
<translation id="6865412394715372076">Esta tarxeta non puido verificarse neste momento</translation>
<translation id="6874604403660855544">&amp;Refacer adición</translation>
@@ -1450,6 +1477,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6895330447102777224">Confirmouse a túa tarxeta</translation>
<translation id="6897140037006041989">Axente de usuario</translation>
<translation id="6898699227549475383">Organización (O)</translation>
+<translation id="6907293445143367439">Permitir que <ph name="SITE_NAME" /> faga o seguinte:</translation>
<translation id="6910240653697687763">O URL <ph name="URL" /> quere obter o control total dos teus dispositivos MIDI</translation>
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6934672428414710184">Este nome procede da túa Conta de Google</translation>
@@ -1561,6 +1589,7 @@ Detalles adicionais:
<translation id="7346048084945669753">É colaborador:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Liña de comandos</translation>
+<translation id="7359588939039777303">Bloqueáronse os anuncios.</translation>
<translation id="7372973238305370288">resultado da busca</translation>
<translation id="7374733840632556089">Este problema prodúcese por causa dun certificado instalado por ti ou por outra persoa no teu dispositivo. Sábese que este certificado se utiliza para supervisar e interceptar redes, e Chrome non confía nel. Aínda que existen algunhas situacións lexítimas para a supervisión, como no caso de redes de empresas ou de centros educativos, Chrome quere asegurarse de que sexas consciente do que acontece, inda que non poidas facer nada ao respecto. A supervisión pode levarse a cabo en calquera navegador ou aplicación que acceda á Web.</translation>
<translation id="7375818412732305729">Anéxase un ficheiro</translation>
@@ -1735,6 +1764,7 @@ Detalles adicionais:
<translation id="7976214039405368314">Hai demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Para ver contido de realidade aumentada, instala ARCore</translation>
<translation id="799149739215780103">Encadernación</translation>
<translation id="7995512525968007366">Non especificado</translation>
<translation id="800218591365569300">Proba a pechar outras pestanas ou programas para liberar memoria.</translation>
@@ -1862,24 +1892,38 @@ Detalles adicionais:
<translation id="8507227106804027148">Liña de comandos</translation>
<translation id="8508648098325802031">Icona de busca</translation>
<translation id="8522552481199248698">Chrome pode axudarche a protexer a túa Conta de Google e a cambiar o teu contrasinal.</translation>
+<translation id="8525306231823319788">Pantalla completa</translation>
<translation id="8530813470445476232">Borra o historial de navegación, as cookies, a memoria caché e moito máis na configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista dos URL bloqueados e outras políticas aplicadas polo teu administrador do sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Tres grampas na parte inferior</translation>
<translation id="8543181531796978784">Podes <ph name="BEGIN_ERROR_LINK" />notificar un problema de detección<ph name="END_ERROR_LINK" /> ou, se aceptas os riscos que supón para a túa seguranza, <ph name="BEGIN_LINK" />visita este sitio non seguro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">O código CVC atópase na parte traseira da tarxeta</translation>
+<translation id="8558485628462305855">Para ver contido de realidade aumentada, actualiza ARCore</translation>
<translation id="8559762987265718583">Non se pode establecer unha conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque a data e a hora do dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.</translation>
<translation id="8564182942834072828">Documentos independentes/copias non intercaladas</translation>
<translation id="8564985650692024650">Chromium recoméndache que restablezas o contrasinal de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se o reutilizaches noutros sitios.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Actividade que non permanecerá neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />As páxinas que vexas nesta ventá
+ <ph name="LIST_ITEM" />As cookies e os datos dos sitios
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Usar Touch ID para confirmar as tarxetas máis rápido</translation>
<translation id="858637041960032120">Engadir número de teléfono</translation>
<translation id="8589998999637048520">Calidade máxima</translation>
+<translation id="8600271352425265729">Só esta vez</translation>
<translation id="860043288473659153">Nome do titular da tarxeta</translation>
<translation id="8606726445206553943">Usar os dispositivos MIDI</translation>
+<translation id="8612761427948161954">Ola, <ph name="USERNAME" />:
+ <ph name="BR" />
+ Estás navegando como invitado</translation>
<translation id="861775596732816396">Tamaño 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Non tes ningún contrasinal para este sitio. Mostrar todos os contrasinais gardados.</translation>
<translation id="8625384913736129811">Gardar esta tarxeta neste dispositivo</translation>
+<translation id="8627040765059109009">Retomouse a captura de pantalla</translation>
<translation id="8657078576661269990">O teu administrador bloqueou a función de compartir contido desde <ph name="ORIGIN_NAME" /> a <ph name="VM_NAME_1" /> e <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Resumo do pedido, <ph name="TOTAL_LABEL" />, máis detalles</translation>
<translation id="867224526087042813">Sinatura</translation>
@@ -1942,6 +1986,7 @@ Detalles adicionais:
<translation id="8912362522468806198">Conta de Google</translation>
<translation id="8913778647360618320">Botón Xestionar métodos de pago. Preme Intro para xestionar os teus métodos de pago e a información das tarxetas de crédito desde a configuración de Chrome</translation>
<translation id="8918231688545606538">Esta páxina é sospeitosa</translation>
+<translation id="8922013791253848639">Permitir sempre os anuncios neste sitio</translation>
<translation id="892588693504540538">Perforación na parte superior dereita</translation>
<translation id="8931333241327730545">Queres gardar esta tarxeta na túa conta de Google?</translation>
<translation id="8932102934695377596">O reloxo está atrasado</translation>
@@ -2013,6 +2058,7 @@ Detalles adicionais:
<translation id="9183302530794969518">Documentos de Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utiliza un protocolo non compatible.</translation>
<translation id="9191834167571392248">Perforación na parte inferior esquerda</translation>
+<translation id="9199905725844810519">A opción de impresión está bloqueada</translation>
<translation id="9205078245616868884">Os teus datos encriptáronse co teu contrasinal de sincronización. Introdúceo para comezar a sincronización.</translation>
<translation id="9207861905230894330">Non se puido engadir o artigo.</translation>
<translation id="9213433120051936369">Personalizar a aparencia</translation>
@@ -2023,8 +2069,10 @@ Detalles adicionais:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Poderías perder o acceso á túa Conta de Google. Chromium recoméndache que cambies de contrasinal agora. Deberás iniciar sesión.</translation>
<translation id="939736085109172342">Cartafol novo</translation>
+<translation id="945522503751344254">Enviar comentarios</translation>
<translation id="945855313015696284">Comproba a información que aparece a continuación e elimina as tarxetas non válidas</translation>
<translation id="950736567201356821">Tres perforacións na parte superior</translation>
+<translation id="951941430552851965">O teu administrador puxo en pausa o modo de captura de pantalla debido ao contido que se mostraba nela.</translation>
<translation id="961663415146723894">Encadernación na parte inferior</translation>
<translation id="962484866189421427">Este contido pode tentar instalar aplicacións enganosas que pretenden pasar por algo que non son ou recompilar datos que se poden utilizar para facer un seguimento das túas accións. <ph name="BEGIN_LINK" />Mostrar igualmente<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Compilación oficial</translation>
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index bb65f0eeb47..2b2d0f8d3cb 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">તમે àªàªµà«€ સાઇટ પર તમારો પાસવરà«àª¡ દાખલ કરà«àª¯à«‹ કે જે તમારી કંપની દà«àªµàª¾àª°àª¾ મેનેજ કરવામાં આવતો નથી. તમારા àªàª•àª¾àª‰àª¨à«àªŸàª¨à«‡ સà«àª°àª•à«àª·àª¿àª¤ કરવા માટે, અનà«àª¯ àªàªª અને સાઇટ પર તમારા પાસવરà«àª¡àª¨à«‹ ફરી ઉપયોગ કરશો નહિ.</translation>
<translation id="1263231323834454256">વાચન સૂચિ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ આ ડિવાઇસ પર નહીં રહે તેવી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આ છે:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />આ વિનà«àª¡à«‹àª®àª¾àª‚ તમે જોયેલા પેજ
+ <ph name="LIST_ITEM" />કà«àª•à«€ અને સાઇટનો ડેટા
+ <ph name="LIST_ITEM" />àªàª•àª¾àª‰àª¨à«àªŸ વિશેની માહિતી (<ph name="LINK_BEGIN" />સાઇન આઉટ કરો<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">પિકઅપ પદà«àª§àª¤àª¿</translation>
<translation id="1281476433249504884">સà«àªŸà«…કર 1</translation>
<translation id="1285320974508926690">આ સાઇટનà«àª‚ કà«àª¯àª¾àª°à«‡àª¯ ભાષાંતર કરશો નહીં</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">ઇતિહાસના àªàª¨à«àªŸà«àª°à«€àª¨à«€ સૂચિ</translation>
<translation id="1517433312004943670">ફોન નંબર આવશà«àª¯àª•</translation>
<translation id="1519264250979466059">નિરà«àª®àª¾àª£ તારીખ</translation>
-<translation id="1521655867290435174">Google શીટ</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">કનેકà«àª¶àª¨àª¨à«€ રાહ જોઈ રહà«àª¯àª¾àª‚ છીàª...</translation>
<translation id="1529521330346880926">10x15 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="1529789484829130889">ટà«àª°à«‡ 8</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ સà«àªŸà«‹àª° કરેલા પાસવરà«àª¡àª¨à«‹ ઉપયોગ કરવા માટે સાઇન ઇન કરો</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />માં લખાયેલાં પેજનો અનà«àªµàª¾àª¦ થશે નહીં.</translation>
<translation id="2053553514270667976">પિન કોડ</translation>
+<translation id="2054665754582400095">તમારી હાજરી</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 સૂચન}one{# સૂચન}other{# સૂચન}}</translation>
<translation id="2079545284768500474">છેલà«àª²à«‹ ફેરફાર રદ કરો</translation>
<translation id="20817612488360358">સિસà«àªŸàª® પà«àª°à«‰àª•à«àª¸à«€ સેટિંગ ઉપયોગમાં લેવા માટે સેટ છે પણ àªàª• સà«àªªàª·à«àªŸ પà«àª°à«‰àª•à«àª¸à«€ ગોઠવણીનો પણ ઉલà«àª²à«‡àª– કરાયેલો છે.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android àªàªªà«àª²àª¿àª•à«‡àª¶àª¨à«‹</translation>
<translation id="2107021941795971877">પà«àª°àª¿àª¨à«àªŸ માટેના સપોરà«àªŸ</translation>
<translation id="2108755909498034140">તમારà«àª‚ કમà«àªªà«àª¯à«àªŸàª° પà«àª¨àªƒàªªà«àª°àª¾àª°àª‚ભ કરો</translation>
+<translation id="2111166930115883695">રમવા માટે સà«àªªà«‡àª¸àª¬àª¾àª° દબાવો</translation>
<translation id="2111256659903765347">સà«àªªàª°-A</translation>
<translation id="2113977810652731515">કારà«àª¡</translation>
<translation id="2114841414352855701">અવગણà«àª¯à«àª‚ કારણ કે તે <ph name="POLICY_NAME" /> દà«àªµàª¾àª°àª¾ ઓવરરાઇડ થયà«àª‚ હતà«àª‚.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">ચà«àª•àªµàª£à«€ રદ કરો</translation>
<translation id="2147827593068025794">પૃષà«àª àª­à«‚મિ સમનà«àªµàª¯àª¨</translation>
<translation id="2148613324460538318">કારà«àª¡ ઉમેરો</translation>
+<translation id="2149968176347646218">કનેકà«àª¶àª¨ સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="2154054054215849342">સમનà«àªµàª¯àª¨ તમારા ડોમેન માટે ઉપલબà«àª§ નથી.</translation>
<translation id="2154484045852737596">કારà«àª¡àª®àª¾àª‚ ફેરફાર કરો</translation>
<translation id="2161656808144014275">ટેકà«àª¸à«àªŸ</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">નીતિઓ</translation>
<translation id="2183608646556468874">ફોન નંબર</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 સરનામà«àª‚}one{# સરનામાં}other{# સરનામાં}}</translation>
-<translation id="2187243482123994665">વપરાશકરà«àª¤àª¾àª¨à«€ હાજરી</translation>
<translation id="2187317261103489799">શોધો (ડિફૉલà«àªŸ)</translation>
<translation id="2188375229972301266">નીચેની બાજà«àª àªàª•àª¥à«€ વધૠકાણાં પાડો</translation>
<translation id="2202020181578195191">àªàª• માનà«àª¯ સમાપà«àª¤àª¿ વરà«àª· દાખલ કરો</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">આગળ નકલી સાઇટ છે</translation>
<translation id="2850739647070081192">આમંતà«àª°àª£ (àªàª¨à«àªµàª²àªª)</translation>
<translation id="2856444702002559011">હà«àª®àª²àª¾àª–ોરો કદાચ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />માંથી તમારી માહિતી (ઉદાહરણ તરીકે, પાસવરà«àª¡, સંદેશા અથવા કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡) ચોરવાનો પà«àª°àª¯àª¾àª¸ કરી રહà«àª¯àª¾àª‚ હોઈ શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">આ સાઇટ ઘૃણાસà«àªªàª¦ અથવા ભà«àª°àª¾àª®àª• જાહેરાતો બતાવે છે.</translation>
<translation id="2878197950673342043">પોસà«àªŸàª° ફોલà«àª¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">વિંડોનà«àª‚ સà«àª¥àª¾àª¨ નિયોજન</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google દà«àªµàª¾àª°àª¾ સૂચનો</translation>
<translation id="3002501248619246229">ઇનપà«àªŸ ટà«àª°à«‡ મીડિયા ચેક કરો</translation>
<translation id="3005723025932146533">સાચવેલી કૉપિ બતાવો</translation>
-<translation id="3007719053326478567">આ કનà«àªŸà«‡àª¨à«àªŸ પà«àª°àª¿àª¨à«àªŸ કરવાની સà«àªµàª¿àª§àª¾ તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ બà«àª²à«‰àª• કરવામાં આવી છે</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> માટે CVC દાખલ કરો. àªàª•àªµàª¾àª° તમે ખાતરી કરી લો, તે પછી આ સાઇટ સાથે તમારા કારà«àª¡àª¨à«€ વિગતો શેર કરવામાં આવશે.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />" àªàª¨à«àªŸà«àª°à«€àª¨à«‡ સૂચિબદà«àª§ કરો: <ph name="ERROR" /></translation>
<translation id="301521992641321250">ઑટોમૅટિક રીતે બà«àª²à«‰àª• થયà«àª‚</translation>
<translation id="3016780570757425217">તમારà«àª‚ સà«àª¥àª¾àª¨ જાણો</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ટૅબ કી દબાવો, પછી સૂચન કાઢી નાખવા માટે Enter કી દબાવો.</translation>
<translation id="3023071826883856138">You4 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="3024663005179499861">ખોટો નીતિ પà«àª°àª•àª¾àª°</translation>
<translation id="3037605927509011580">અરર કંઇક ભà«àª² થઇ!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">બà«àª•àª®àª¾àª°à«àª• કરેલ</translation>
<translation id="3209034400446768650">પેજ કદાચ નાણાં વસૂલી શકે છે</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> પરની તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿àª¨à«àª‚ નિરીકà«àª·àª£ કરવામાં આવી રહà«àª¯à«àª‚ છે</translation>
+<translation id="3212623355668894776">તમામ અતિથિ વિનà«àª¡à«‹ બંધ કરો જેથી આ ડિવાઇસમાંથી તમારી બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿ ડિલીટ કરવામાં આવે.</translation>
<translation id="3215092763954878852">WebAuthnનો ઉપયોગ કરી શકà«àª¯àª¾àª‚ નથી</translation>
<translation id="3218181027817787318">સંબંધિત</translation>
<translation id="3225919329040284222">સરà«àªµàª° àªàª• પà«àª°àª®àª¾àª£àªªàª¤à«àª° પà«àª°àª¸à«àª¤à«àª¤ કરે છે જે બિલà«àªŸ-ઇન અપેકà«àª·àª¾àª“ સાથે મેળ ખાતà«àª‚ નથી. આ અપેકà«àª·àª¾àª“માં તમને સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે અમà«àª• ચોકà«àª•àª¸, ઉચà«àªš-સà«àª°àª•à«àª·àª¾ વેબસાઇટà«àª¸àª¨à«‹ સમાવેશ થાય છે.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">બà«àª²à«‚ટૂથ ડિવાઇસ</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> માં સમાપà«àª¤ થાય છે</translation>
<translation id="3789155188480882154">કદ 16</translation>
+<translation id="3789841737615482174">ઇનà«àª¸à«àªŸà«‹àª² કરો</translation>
<translation id="3793574014653384240">તાજેતરના અકસà«àª®àª¾àª¤à«‹àª¨à«€ સંખà«àª¯àª¾ અને કારણો</translation>
<translation id="3797522431967816232">Prc3 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="3799805948399000906">ફોનà«àªŸàª¨à«€ વિનંતી કરી</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">કી "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (àªàª¨à«àªµàª²àªª)</translation>
+<translation id="4067669230157909013">સà«àª•à«àª°à«€àª¨ કૅપà«àªšàª°àª¨à«€ સà«àªµàª¿àª§àª¾ ફરી શરૂ કરવામાં આવી.</translation>
<translation id="4067947977115446013">માનà«àª¯ સરનામà«àª‚ ઉમેરો</translation>
<translation id="4072486802667267160">તમારા ઑરà«àª¡àª°àª¨à«€ પà«àª°àª•à«àª°àª¿àª¯àª¾ કરતી વખતે àªàª• ભૂલ આવી હતી. કૃપા કરીને ફરીથી પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="4075732493274867456">કà«àª²àª¾àª‡àª¨à«àªŸ અને સરà«àªµàª° સામાનà«àª¯ SSL પà«àª°à«‹àªŸà«‹àª•à«‹àª² વરà«àªàª¨ અથવા સાઇફર સà«àª¯à«‚ટની સહાય કરતા નથી.</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">પેજ <ph name="THUMBNAIL_PAGE" /> માટે થંબનેલ</translation>
<translation id="42981349822642051">વિસà«àª¤à«ƒàª¤ કરો</translation>
<translation id="4300675098767811073">જમણી બાજà«àª àªàª•àª¥à«€ વધૠકાણાં પાડો</translation>
+<translation id="4302514097724775343">રમવા માટે, ડાયનાસોર પર ટૅપ કરો</translation>
<translation id="4302965934281694568">Chou3 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="4305666528087210886">તમારી ફાઇલ àªàª•à«àª¸à«‡àª¸ કરી શકાઈ નથી</translation>
<translation id="4305817255990598646">સà«àªµàª¿àªš</translation>
@@ -899,7 +914,7 @@
<translation id="4552089082226364758">ફà«àª²à«‡àª¶</translation>
<translation id="4558551763791394412">તમારા àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨à«àª¸àª¨à«‡ અકà«àª·àª® કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="4559332380232738994">10x11</translation>
-<translation id="457875822857220463">વિતરણ</translation>
+<translation id="457875822857220463">ડિલિવરી</translation>
<translation id="4579056131138995126">વà«àª¯àª•à«àª¤àª¿àª—ત (àªàª¨à«àªµàª²àªª)</translation>
<translation id="4582204425268416675">કારà«àª¡ કાઢી નાખો</translation>
<translation id="4587425331216688090">Chrome માંથી સરનામà«àª‚ દૂર કરીàª?</translation>
@@ -915,9 +930,10 @@
<translation id="4658638640878098064">ઉપર ડાબી બાજà«àª સà«àªŸà«‡àªªàª² લગાવો</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">વરà«àªšà«àª¯à«àª…લ રિયાલિટી</translation>
+<translation id="4675657451653251260">અતિથિ મોડમાં તમને Chrome પà«àª°à«‹àª«àª¾àª‡àª²àª¨à«€ કોઈપણ માહિતી દેખાશે નહીં. તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª¨à«€ માહિતી જેમકે પાસવરà«àª¡ અને ચà«àª•àªµàª£à«€ પદà«àª§àª¤àª¿àª“ àªàª•à«àª¸à«‡àª¸ કરવા માટે, તમે <ph name="LINK_BEGIN" />સાઇન ઇન<ph name="LINK_END" /> કરી શકો છો.</translation>
<translation id="467662567472608290">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેના સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª®àª¾àª‚ ભૂલો છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="4677585247300749148"><ph name="URL" /> àªàª•à«àª¸à«‡àª¸àª¿àª¬àª¿àª²àª¿àªŸà«€ ઇવેનà«àªŸàª¨à«‹ જવાબ આપવા માગે છે</translation>
-<translation id="467809019005607715">Google સà«àª²àª¾àª‡àª¡</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">હમણાં જ કોઈ છેતરામણી સાઇટ પર તમે તમારો પાસવરà«àª¡ દાખલ કરà«àª¯à«‹. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> અને હવે તમે આ પાસવરà«àª¡àª¨à«‹ જà«àª¯àª¾àª‚ ઉપયોગ કરતા હો તે અનà«àª¯ સાઇટ પરના તમે સાચવેલા પાસવરà«àª¡ ચેક કરવાનો Chromium સà«àªàª¾àªµ આપે છે.</translation>
<translation id="4690462567478992370">અમાનà«àª¯ પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«‹ ઉપયોગ કરવાનà«àª‚ બંધ કરો</translation>
<translation id="4691835149146451662">સà«àª¥àª¾àªªàª¤à«àª¯-A (àªàª¨à«àªµàª²àªª)</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">તમારા માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«‹ ઉપયોગ કરો</translation>
<translation id="4764776831041365478"><ph name="URL" /> પરનાં વેબપેજ અસà«àª¥àª¾àª¯à«€ ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ àªàª¡à«àª°à«‡àª¸ પર ખસેડવામાં આવà«àª¯àª¾ હોઈ શકે છે.</translation>
<translation id="4766713847338118463">નીચે બે સà«àªŸà«‡àªªàª² લગાવો</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ આ ડિવાઇસ પર રહેશે તેવી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આ છે:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />આ વિનà«àª¡à«‹àª®àª¾àª‚ તમે ડાઉનલોડ કરેલી કોઈપણ ફાઇલ
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">કોઈ અજà«àªžàª¾àª¤ ભૂલ આવી.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{પૉપ-અપ બà«àª²à«‰àª• કરà«àª¯à«àª‚ં છે}one{# પૉપ-અપ બà«àª²à«‰àª• કરà«àª¯à«àª‚ં છે}other{# પૉપ-અપ બà«àª²à«‰àª• કરà«àª¯à«àª‚ં છે}}</translation>
<translation id="4780366598804516005">મેઇલબૉકà«àª¸ 1</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">આ સાઇટ માટેની પà«àª°àª®àª¾àª£àªªàª¤à«àª° શà«àª°à«ƒàª‚ખલા SHA-1 નો ઉપયોગ કરીને સહી કરેલ પà«àª°àª®àª¾àª£àªªàª¤à«àª° ધરાવે છે.</translation>
<translation id="538659543871111977">A4-ટૅબ</translation>
<translation id="5396631636586785122">જમણી બાજà«àª કિનારી જોડો</translation>
+<translation id="5398772614898833570">જાહેરાતો અવરોધિત કરી</translation>
<translation id="5400836586163650660">ગà«àª°à«‡</translation>
<translation id="540969355065856584">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° આ સમયે માનà«àª¯ નથી. આ કોઇ ખોટી ગોઠવણીને કારણે થયà«àª‚ હોય અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ હોઇ શકે છે.</translation>
<translation id="541416427766103491">સà«àªŸà«…કર 4</translation>
<translation id="5421136146218899937">બà«àª°àª¾àª‰àªàª¿àª‚ગ ડેટા સાફ કરો...</translation>
<translation id="5426179911063097041"><ph name="SITE" />તમને નોટિફિકેશનો મોકલવા માગે છે</translation>
+<translation id="542872847390508405">તમે અતિથિ તરીકે બà«àª°àª¾àª‰àª કરી રહà«àª¯àª¾àª‚ છો</translation>
<translation id="5430298929874300616">બà«àª•àª®àª¾àª°à«àª• દૂર કરો</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" પર સà«àª•à«€àª®àª¾ માનà«àª¯àª¤àª¾ ભૂલ: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ઉલટા કà«àª°àª®àª®àª¾àª‚ ઉપર તરફ</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">આ સરનામેથી પિકઅપ કરી શકતા નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="5580958916614886209">તમારો સમાપà«àª¤àª¿ મહિનો તપાસો અને ફરી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="5586446728396275693">કોઈ સાચવેલ àªàª¡à«àª°à«‡àª¸ નથી</translation>
+<translation id="5593349413089863479">કનેકà«àª¶àª¨ સંપૂરà«àª£ રીતે સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="5595485650161345191">àªàª¡à«àª°à«‡àª¸àª®àª¾àª‚ ફેરફાર કરો</translation>
<translation id="5598944008576757369">ચà«àª•àªµàª£à«€àª¨à«€ પદà«àª§àª¤àª¿ પસંદ કરો</translation>
<translation id="560412284261940334">સંચાલન સમરà«àª¥àª¿àª¤ નથી</translation>
<translation id="5605670050355397069">લેજર</translation>
<translation id="5607240918979444548">સà«àª¥àª¾àªªàª¤à«àª¯-C</translation>
-<translation id="5608165884683734521">આ સાઇટ બનાવટી અથવા કપટપૂરà«àª£ હોઈ શકે છે. Chrome ભલામણ કરે છે કે તમે અતà«àª¯àª¾àª°à«‡ જ આ સાઇટ બંધ કરી દો.</translation>
<translation id="5610142619324316209">કનેકà«àª¶àª¨ તપાસીને</translation>
<translation id="5610807607761827392">તમે <ph name="BEGIN_LINK" />સેટિંગ<ph name="END_LINK" />માં કારà«àª¡ અને સરનામાં મેનેજ કરી શકો છો.</translation>
<translation id="561165882404867731">Google Translate વડે આ પેજનો અનà«àªµàª¾àª¦ કરો</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">પીળો</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />ની ઑરિજિન પૉલિસી અનà«àª¸àª¾àª° બà«àª²à«‰àª• કરેલી છે.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (સમનà«àªµàª¯àª¿àª¤)</translation>
+<translation id="5913377024445952699">સà«àª•à«àª°à«€àª¨ કૅપà«àªšàª°àª¨à«€ સà«àªµàª¿àª§àª¾ થોભાવવામાં આવી છે</translation>
<translation id="59174027418879706">સકà«àª·àª® કરેલà«àª‚</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ચાલà«</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">સેકà«àª¶àª¨</translation>
<translation id="5967592137238574583">સંપરà«àª• માહિતીમાં ફેરફાર કરો</translation>
<translation id="5967867314010545767">ઇતિહાસમાંથી દૂર કરો</translation>
+<translation id="5968793460449681917">દરેક મà«àª²àª¾àª•àª¾àª¤ વખતે</translation>
<translation id="5975083100439434680">àªà«‚મ ઘટાડો</translation>
<translation id="5979084224081478209">પાસવરà«àª¡ ચેક કરો</translation>
<translation id="5980920751713728343">અનà«àª•à«àª°àª®àª£àª¿àª•àª¾-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">તમે કૉપિ કરેલી લિંક</translation>
<translation id="6591833882275308647">તમારà«àª‚ <ph name="DEVICE_TYPE" /> મેનેજ કરવામાં આવતà«àª‚ નથી</translation>
<translation id="6596325263575161958">àªàª¨à«àª•à«àª°àª¿àªªà«àª¶àª¨ વિકલà«àªªà«‹</translation>
+<translation id="6596892391065203054">આ કનà«àªŸà«‡àª¨à«àªŸ પà«àª°àª¿àª¨à«àªŸ કરવાની સà«àªµàª¿àª§àª¾ તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ બà«àª²à«‰àª• કરવામાં આવી છે.</translation>
<translation id="6604181099783169992">મોશન અથવા લાઇટ સેનà«àª¸àª°</translation>
<translation id="6609880536175561541">Prc7 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="6612358246767739896">સà«àª°àª•à«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">તમારા કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરવામાં આવી છે</translation>
<translation id="6897140037006041989">વપરાશકરà«àª¤àª¾ àªàªœàª¨à«àªŸ</translation>
<translation id="6898699227549475383">ઑરà«àª—ેનાઇàªà«‡àª¶àª¨ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />ને આની મંજૂરી આપો:</translation>
<translation id="6910240653697687763"><ph name="URL" /> તમારા MIDI ઉપકરણોનà«àª‚ પૂરà«àª£ નિયંતà«àª°àª£ મેળવવા માગે છે</translation>
<translation id="6915804003454593391">વપરાશકરà«àª¤àª¾: </translation>
<translation id="6934672428414710184">આ નામ તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚થી લીધà«àª‚ છે</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">સંકળાયેલા છે:</translation>
<translation id="7349430561505560861">A4-અતિરિકà«àª¤</translation>
<translation id="7353601530677266744">આદેશ પંકà«àª¤àª¿</translation>
+<translation id="7359588939039777303">જાહેરાતો અવરોધિત કરી.</translation>
<translation id="7372973238305370288">શોધ પરિણામ</translation>
<translation id="7374733840632556089">તમારા ડિવાઇસ પર તમે અથવા અનà«àª¯ કોઈ વà«àª¯àª•à«àª¤àª¿àª ઇનà«àª¸à«àªŸà«‰àª² કરેલા પà«àª°àª®àª¾àª£àªªàª¤à«àª°àª¨à«‡ કારણે આ સમસà«àª¯àª¾ થાય છે. આ પà«àª°àª®àª¾àª£àªªàª¤à«àª° નેટવરà«àª•àª¨à«‡ મોનિટર અને બંધ કરવા માટે ઉપયોગમાં લેવા માટે જાણીતà«àª‚ છે અને Chrome તેના પર વિશà«àªµàª¾àª¸ કરતà«àª‚ નથી. જો કે કેટલાક નિયમસર કિસà«àª¸àª¾àª“માં મોનિટર કરવાનà«àª‚ કારà«àª¯ થતà«àª‚ હોય છે, જેમકે શાળા અથવા કંપનીના નેટવરà«àª•àª®àª¾àª‚, પણ Chrome ખાતરી કરવા માગે છે કે તમે ભલે ઠરોકી ન શકતા હો, પણ ઠથવા વિશે તમને જાણકારી છે. વેબને àªàª•à«àª¸à«‡àª¸ કરતા કોઈપણ બà«àª°àª¾àª‰àªàª° અથવા àªàªªà«àª²àª¿àª•à«‡àª¶àª¨àª®àª¾àª‚ મોનિટર કરવાનà«àª‚ કારà«àª¯ થઈ શકે છે.</translation>
<translation id="7375818412732305729">ફાઇલ જોડવામાં આવે તà«àª¯àª¾àª°à«‡</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">ઘણી બધી વિનંતીઓ</translation>
<translation id="7977538094055660992">આઉટપà«àªŸ ડિવાઇસ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી કનà«àªŸà«‡àª¨à«àªŸ જોવા માટે, ARCore ઇનà«àª¸à«àªŸà«‰àª² કરો</translation>
<translation id="799149739215780103">જોડો</translation>
<translation id="7995512525968007366">નિરà«àª¦àª¿àª·à«àªŸ કરાયેલ નથી</translation>
<translation id="800218591365569300">મેમરી ખાલી કરવા માટે અનà«àª¯ ટૅબ અથવા પà«àª°à«‹àª—à«àª°àª¾àª®àª¨à«‡ બંધ કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">આદેશ પંકà«àª¤àª¿</translation>
<translation id="8508648098325802031">શોધ આઇકન</translation>
<translation id="8522552481199248698">Chrome તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª¨à«‡ સà«àª°àª•à«àª·àª¿àª¤ કરવામાં અને તમારો પાસવરà«àª¡ બદલવામાં તમારી સહાય કરી શકે છે.</translation>
+<translation id="8525306231823319788">પૂરà«àª£ સà«àª•à«àª°à«€àª¨</translation>
<translation id="8530813470445476232">તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ, કà«àª•à«€, કૅશ મેમરી અને બીજà«àª‚ ઘણà«àª‚ Chromeના સેટિંગમાંથી સાફ કરો</translation>
<translation id="8533619373899488139">બà«àª²à«‰àª• કરેલા URLsની સૂચિ અને તમારા સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª° દà«àªµàª¾àª°àª¾ લાગૠકરવામાં આવેલી અનà«àª¯ નીતિઓ જોવા માટે &lt;strong&gt;chrome://policy&lt;/strong&gt;ની મà«àª²àª¾àª•àª¾àª¤ લો.</translation>
<translation id="8541158209346794904">બà«àª²à«‚ટૂથ ડિવાઇસ</translation>
<translation id="8542014550340843547">નીચેની બાજà«àª તà«àª°àª£ સà«àªŸà«‡àªªàª² લગાવો</translation>
<translation id="8543181531796978784">તમે <ph name="BEGIN_ERROR_LINK" />શોધ સમસà«àª¯àª¾àª¨à«€ જાણ<ph name="END_ERROR_LINK" /> કરી શકો છો અથવા જો તમે તમારી સà«àª°àª•à«àª·àª¾ અંગેનાં જોખમોને સમજતાં હોવ, તો <ph name="BEGIN_LINK" />આ અસà«àª°àª•à«àª·àª¿àª¤ સાઇટની મà«àª²àª¾àª•àª¾àª¤<ph name="END_LINK" /> લઈ શકો છો.</translation>
<translation id="8557066899867184262">CVC તમારા કારà«àª¡àª¨à«€ પાછળ હોય છે.</translation>
+<translation id="8558485628462305855">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી કનà«àªŸà«‡àª¨à«àªŸ જોવા માટે ARCore અપડેટ કરો</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> પર ખાનગી કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરી શકાતà«àª‚ નથી કારણ કે તમારા ઉપકરણની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) અયોગà«àª¯ છે.</translation>
<translation id="8564182942834072828">અલગ દસà«àª¤àª¾àªµà«‡àªœà«‹/ગોઠવણી વિનાની કૉપિ</translation>
<translation id="8564985650692024650">જો તમે અનà«àª¯ સાઇટ પર <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> પાસવરà«àª¡àª¨à«‹ ફરી ઉપયોગ કરà«àª¯à«‹ હોય, તો Chromium તેને રીસેટ કરવાનો સà«àªàª¾àªµ આપે છે.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ આ ડિવાઇસ પર નહીં રહે તેવી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આ છે:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />આ વિનà«àª¡à«‹àª®àª¾àª‚ તમે જોયેલા પેજ
+ <ph name="LIST_ITEM" />કà«àª•à«€ અને સાઇટનો ડેટા
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">કારà«àª¡àª¨à«‡ વધૠàªàª¡àªªàª¥à«€ કનà«àª«àª°à«àª® કરવા માટે Touch IDનો ઉપયોગ કરો</translation>
<translation id="858637041960032120">ફોન નંબર ઉમેરો</translation>
<translation id="8589998999637048520">શà«àª°à«‡àª·à«àª  કà«àªµà«‰àª²àª¿àªŸà«€</translation>
+<translation id="8600271352425265729">ફકà«àª¤ આ વખતે</translation>
<translation id="860043288473659153">કારà«àª¡àª§àª¾àª°àª•àª¨à«àª‚ નામ</translation>
<translation id="8606726445206553943">તમારા MIDI ઉપકરણોનો ઉપયોગ કરો</translation>
+<translation id="8612761427948161954">નમસà«àª•àª¾àª° <ph name="USERNAME" />,
+ <ph name="BR" />
+ તમે અતિથિ તરીકે બà«àª°àª¾àª‰àª કરી રહà«àª¯àª¾àª‚ છો</translation>
<translation id="861775596732816396">કદ 4</translation>
<translation id="8622948367223941507">કાનૂની-અતિરિકà«àª¤</translation>
<translation id="8623885649813806493">કોઈ મેળ ખાતા પાસવરà«àª¡ નથી. બધા સાચવેલા પાસવરà«àª¡ બતાવો.</translation>
<translation id="8625384913736129811">આ કારà«àª¡àª¨à«‡ આ ડિવાઇસમાં સાચવો</translation>
+<translation id="8627040765059109009">સà«àª•à«àª°à«€àª¨ કૅપà«àªšàª°àª¨à«€ સà«àªµàª¿àª§àª¾ ફરી શરૂ કરી</translation>
<translation id="8657078576661269990">તમારા વà«àª¯àªµà«àª¥àª¾àªªàª•à«‡ <ph name="ORIGIN_NAME" />થી <ph name="VM_NAME_1" /> અને <ph name="VM_NAME_2" /> પર શેર કરવાનà«àª‚ બà«àª²à«‰àª• કરà«àª¯à«àª‚ છે</translation>
<translation id="8663226718884576429">ઑરà«àª¡àª°àª¨à«‹ સારાંશ, <ph name="TOTAL_LABEL" />, વધૠવિગતો</translation>
<translation id="867224526087042813">સહી</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google àªàª•àª¾àª‰àª¨à«àªŸ</translation>
<translation id="8913778647360618320">ચà«àª•àªµàª£à«€ પદà«àª§àª¤àª¿ મેનેજ કરો બટન, Chrome સેટિંગમાં તમારી ચà«àª•àªµàª£à«€àª“ અને કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡àª¨à«€ માહિતી મેનેજ કરવા માટે Enter દબાવો</translation>
<translation id="8918231688545606538">આ પેજ શંકાસà«àªªàª¦ છે</translation>
+<translation id="8922013791253848639">આ સાઇટ પર જાહેરાતો માટે હંમેશાં પરવાનગી આપે છે</translation>
<translation id="892588693504540538">ઉપર જમણી બાજà«àª કાણà«àª‚ પાડો</translation>
<translation id="8931333241327730545">શà«àª‚ તમે આ કારà«àª¡àª¨à«‡ તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ સાચવવા માગો છો?</translation>
<translation id="8932102934695377596">તમારી ઘડિયાળ પાછળ છે</translation>
@@ -2013,21 +2058,24 @@
<translation id="917450738466192189">સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° અમાનà«àª¯ છે.</translation>
<translation id="9174917557437862841">ટૅબ, સà«àªµàª¿àªš બટન, આ ટૅબ પર સà«àªµàª¿àªš કરવા માટે Enter દબાવો</translation>
<translation id="9179703756951298733">Chrome સેટિંગમાં તમારી ચà«àª•àªµàª£à«€àª“ અને કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡àª¨à«€ માહિતી મેનેજ કરો</translation>
-<translation id="9183302530794969518">Google દસà«àª¤àª¾àªµà«‡àªœ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" />, àªàª• અસમરà«àª¥àª¿àª¤ પà«àª°à«‹àªŸà«‹àª•à«‹àª²àª¨à«‹ ઉપયોગ કરે છે.</translation>
<translation id="9191834167571392248">નીચે ડાબી બાજà«àª કાણà«àª‚ પાડો</translation>
+<translation id="9199905725844810519">પà«àª°àª¿àª¨à«àªŸ કરવાની સà«àªµàª¿àª§àª¾ બà«àª²à«‰àª• કરવામાં આવી છે</translation>
<translation id="9205078245616868884">તમારો ડેટા તમારા સિંક પાસફà«àª°à«‡àª સાથે àªàª¨à«àª•à«àª°àª¿àªªà«àªŸ કરવામાં આવà«àª¯à«‹ છે. સિંક શરૂ કરવા માટે ઠદાખલ કરો.</translation>
<translation id="9207861905230894330">લેખ ઉમેરવામાં નિષà«àª«àª³ થયાં.</translation>
<translation id="9213433120051936369">દેખાવને કસà«àªŸàª®àª¾àª‡àª કરો</translation>
<translation id="9215416866750762878">કોઈ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ Chromeને આ સાઇટ સાથે સà«àª°àª•à«àª·àª¿àª¤ રીતે કનેકà«àªŸ થવાથી અટકાવી રહી છે</translation>
-<translation id="9219103736887031265">છબીઓ</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">ડાઇનરà«àª¸ કà«àª²àª¬</translation>
<translation id="935608979562296692">ફોરà«àª® સાફ કરો</translation>
<translation id="936474030629450166">સà«àªªàª°-B</translation>
<translation id="936602727769022409">તમે તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª¨à«‹ àªàª•à«àª¸à«‡àª¸ ગà«àª®àª¾àªµà«€ શકો છો. Chromium તમને હમણાં જ તમારો પાસવરà«àª¡ બદલવાનો સà«àªàª¾àªµ આપે છે. તમને સાઇન ઇન કરવા માટે કહેવામાં આવશે.</translation>
<translation id="939736085109172342">નવà«àª‚ ફોલà«àª¡àª°</translation>
+<translation id="945522503751344254">પà«àª°àª¤àª¿àª¸àª¾àª¦ મોકલો</translation>
<translation id="945855313015696284">નીચેની માહિતી જà«àª“ અને કોઈપણ અમાનà«àª¯ કારà«àª¡ ડિલીટ કરો</translation>
<translation id="950736567201356821">ઉપરની બાજà«àª તà«àª°àª£ કાણાં પાડો</translation>
+<translation id="951941430552851965">તમારી સà«àª•à«àª°à«€àª¨ પરના કનà«àªŸà«‡àª¨à«àªŸàª¨à«‡ કારણે તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•à«‡ સà«àª•à«àª°à«€àª¨ કૅપà«àªšàª°àª¨à«€ સà«àªµàª¿àª§àª¾ થોભાવી હતી.</translation>
<translation id="961663415146723894">નીચેની બાજà«àª જોડો</translation>
<translation id="962484866189421427">આ કનà«àªŸà«‡àª¨à«àªŸ કદાચ ભà«àª°àª¾àª®àª• àªàªª ઇનà«àª¸à«àªŸà«‰àª² કરવાનો પà«àª°àª¯àª¾àª¸ કરે છે કે જે પોતાની ખોટી ઓળખ આપે છે અથવા તમને ટà«àª°à«…ક કરવા માટે ઉપયોગમાં લઈ શકાય તેવો ડેટા મેળવે છે. <ph name="BEGIN_LINK" />તો પણ બતાવો<ph name="END_LINK" /></translation>
<translation id="969892804517981540">આધિકારિક બિલà«àª¡</translation>
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index 9106f858506..2a58277e95d 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">आपने अपना पासवरà¥à¤¡ à¤à¤¸à¥€ साइट पर डाला है जिसे आपका संगठन पà¥à¤°à¤¬à¤‚धित नहीं करता है. अपना खाता सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करने के लिà¤, दूसरे à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ और साइटों पर अपना पासवरà¥à¤¡ दोबारा इसà¥à¤¤à¥‡à¤®à¤¾à¤² न करें.</translation>
<translation id="1263231323834454256">पठन सूची</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ये गतिविधियां इस डिवाइस पर सेव नहीं की जाà¤à¤‚गी:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />इस विंडो पर देखे जाने वाले पेज
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ और साइट का डेटा
+ <ph name="LIST_ITEM" />खाते की जानकारी (<ph name="LINK_BEGIN" />साइन आउट करें<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">पिकअप का तरीका</translation>
<translation id="1281476433249504884">सà¥à¤Ÿà¥ˆà¤•à¤° 1</translation>
<translation id="1285320974508926690">कभी भी इस साइट का अनà¥à¤µà¤¾à¤¦ न करें</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">इतिहास à¤à¤‚टà¥à¤°à¥€ की सूची</translation>
<translation id="1517433312004943670">फ़ोन नंबर आवशà¥à¤¯à¤• है</translation>
<translation id="1519264250979466059">बिलà¥à¤¡ तारीख</translation>
-<translation id="1521655867290435174">Google पतà¥à¤°à¤•</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">कनेकà¥à¤¶à¤¨ का इंतज़ार हो रहा है</translation>
<translation id="1529521330346880926">10x15 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="1529789484829130889">टà¥à¤°à¥‡ 8</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">अपने Google खाते में सेव किठगठपासवरà¥à¤¡ इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने के लिठसाइन इन करें</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> भाषा के पेजों का अनà¥à¤µà¤¾à¤¦ नहीं किया जाà¤à¤—ा.</translation>
<translation id="2053553514270667976">ज़िप कोड</translation>
+<translation id="2054665754582400095">आपकी मौजूदगी</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 सà¥à¤à¤¾à¤µ}one{# सà¥à¤à¤¾à¤µ}other{# सà¥à¤à¤¾à¤µ}}</translation>
<translation id="2079545284768500474">पहले जैसा करें</translation>
<translation id="20817612488360358">सिसà¥â€à¤Ÿà¤® पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सेटिंग उपयोग किठजाने के लिठसेट हैं लेकिन कोई सà¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥à¥žà¤¿à¤—रेशन भी मौजूद है.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨</translation>
<translation id="2107021941795971877">पà¥à¤°à¤¿à¤‚ट सहायता</translation>
<translation id="2108755909498034140">अपना कंपà¥à¤¯à¥‚टर फिर से चालू करें</translation>
+<translation id="2111166930115883695">गेम चलाने के लिà¤, space दबाà¤à¤‚</translation>
<translation id="2111256659903765347">सà¥à¤ªà¤°-à¤</translation>
<translation id="2113977810652731515">कारà¥à¤¡</translation>
<translation id="2114841414352855701">धà¥à¤¯à¤¾à¤¨ नहीं दिया गया कà¥à¤¯à¥‹à¤‚कि यह <ph name="POLICY_NAME" /> दà¥à¤µà¤¾à¤°à¤¾ ओवरराइड की गई थी.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">भà¥à¤—तान न करें</translation>
<translation id="2147827593068025794">बैकगà¥à¤°à¤¾à¤‰à¤‚ड सिंक</translation>
<translation id="2148613324460538318">कारà¥à¤¡ जोड़ें</translation>
+<translation id="2149968176347646218">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="2154054054215849342">आपके डोमेन के लिठसिंक करने की सà¥à¤µà¤¿à¤§à¤¾ उपलबà¥â€à¤§ नहीं है</translation>
<translation id="2154484045852737596">कारà¥à¤¡ में बदलाव करें</translation>
<translation id="2161656808144014275">लेख संदेश</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">नीतियां</translation>
<translation id="2183608646556468874">फ़ोन नंबर</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 पता}one{# पते}other{# पते}}</translation>
-<translation id="2187243482123994665">उपयोगकरà¥à¤¤à¤¾ की मौजूदगी</translation>
<translation id="2187317261103489799">पता लगाà¤à¤‚ (डिफ़ॉलà¥à¤Ÿ)</translation>
<translation id="2188375229972301266">नीचे की ओर à¤à¤• से ज़à¥à¤¯à¤¾à¤¦à¤¾ पंच</translation>
<translation id="2202020181578195191">खतà¥à¤® होने का मानà¥à¤¯ वरà¥à¤· डालें</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">आप जिस साइट पर जा रहे हैं वह फ़रà¥à¤œà¤¼à¥€ है</translation>
<translation id="2850739647070081192">नà¥à¤¯à¥‹à¤¤à¤¾ (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="2856444702002559011">हो सकता है कि हमलावर <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> से आपकी जानकारी (जैसे- पासवरà¥à¤¡, मैसेज या कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ वगैरह) चà¥à¤°à¤¾à¤¨à¥‡ की कोशिश कर रहे हों. <ph name="BEGIN_LEARN_MORE_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">इस साइट में तंग करने वाले या गà¥à¤®à¤°à¤¾à¤¹ करने वाले विजà¥à¤žà¤¾à¤ªà¤¨ दिखाई देते हैं.</translation>
<translation id="2878197950673342043">पोसà¥à¤Ÿà¤° फ़ोलà¥à¤¡</translation>
<translation id="2878424575911748999">à¤1</translation>
<translation id="2880660355386638022">विंडो पà¥à¤²à¥‡à¤¸à¤®à¥‡à¤‚ट</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">Google के सà¥à¤à¤¾à¤µ</translation>
<translation id="3002501248619246229">इनपà¥à¤Ÿ टà¥à¤°à¥‡ मीडिया को चà¥à¤¨à¥‡à¤‚</translation>
<translation id="3005723025932146533">सहेजी गई कॉपी दिखाà¤à¤‚</translation>
-<translation id="3007719053326478567">इस कॉनà¥à¤Ÿà¥‡à¤‚ट को पà¥à¤°à¤¿à¤‚ट करने की सà¥à¤µà¤¿à¤§à¤¾ को आपके à¤à¤¡à¤®à¤¿à¤¨ ने बà¥à¤²à¥‰à¤• कर दिया है</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> का CVC डालें. आपकी तरफ से पà¥à¤·à¥à¤Ÿà¤¿ हो जाने पर, आपके कारà¥à¤¡ के विवरण इस साइट के साथ शेयर किठजाà¤à¤‚गे.</translation>
<translation id="3010559122411665027">सूची पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿâ€à¤¿ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ऑटोमैटिक रूप से बà¥à¤²à¥‰à¤• है</translation>
<translation id="3016780570757425217">आपका सà¥â€à¤¥à¤¾à¤¨ पता करना</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, सà¥à¤à¤¾à¤µ हटाने के लिठपहले Tab और फिर Enter दबाà¤à¤‚.</translation>
<translation id="3023071826883856138">यू4 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="3024663005179499861">गलत नीति पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="3037605927509011580">हे भगवान!</translation>
@@ -552,6 +563,7 @@
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• किया गया</translation>
<translation id="3209034400446768650">पेज पर शà¥à¤²à¥à¤• लिया जा सकता है</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> पर की जा रही आपकी गतिविधि पर नज़र रखी जा रही है</translation>
+<translation id="3212623355668894776">सभी मेहमान विंडो बंद कर दें, ताकि आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि इस डिवाइस से मिटा दी जाà¤.</translation>
<translation id="3215092763954878852">WebAuthn का इसà¥à¤¤à¥‡à¤®à¤¾à¤² नहीं किया जा सका</translation>
<translation id="3218181027817787318">मिलते-जà¥à¤²à¤¤à¥‡</translation>
<translation id="3225919329040284222">सरà¥à¤µà¤° दà¥à¤µà¤¾à¤°à¤¾ कोई पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥â€à¤¤à¥à¤¤ किया गया, जो बिलà¥â€à¤Ÿ-इन अपेकà¥à¤·à¤¾à¤“ं से मिलान नहीं करता. इन अपेकà¥à¤·à¤¾à¤“ं को आपकी सà¥à¤°à¤•à¥à¤·à¤¾ करने के लिठकà¥à¤›, उचà¥â€à¤š-सà¥à¤°à¤•à¥à¤·à¤¾ वेबसाइटों के लिठशामिल किया गया है.</translation>
@@ -699,6 +711,7 @@
<translation id="3784372983762739446">बà¥à¤²à¥‚टूथ डिवाइस</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> में खतà¥à¤® होगा</translation>
<translation id="3789155188480882154">आकार 16</translation>
+<translation id="3789841737615482174">इंसà¥â€à¤Ÿà¥‰à¤² करें</translation>
<translation id="3793574014653384240">हाल ही में बंद होने की संखà¥à¤¯à¤¾ और वजहें</translation>
<translation id="3797522431967816232">पीआरसी3 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="3799805948399000906">फ़ॉनà¥à¤Ÿ का अनà¥à¤°à¥‹à¤§ किया गया</translation>
@@ -750,6 +763,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">कà¥à¤‚जी "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">सी1 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
+<translation id="4067669230157909013">सà¥à¤•à¥à¤°à¥€à¤¨ कैपà¥à¤šà¤° करने की सà¥à¤µà¤¿à¤§à¤¾ फिर से शà¥à¤°à¥‚ की गई.</translation>
<translation id="4067947977115446013">मानà¥à¤¯ पता जोड़ें</translation>
<translation id="4072486802667267160">आपका आदेश संसाधित करते समय गड़बड़ी हà¥à¤ˆ. कृपया फिर से कोशिश करें.</translation>
<translation id="4075732493274867456">कà¥à¤²à¤¾à¤‡à¤‚ट और सरà¥à¤µà¤°, सामानà¥à¤¯ SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² वरà¥à¤¶à¤¨ या सिफ़र सà¥à¤‡à¤Ÿ का समरà¥à¤¥à¤¨ नहीं करते हैं.</translation>
@@ -834,6 +848,7 @@
<translation id="4297502707443874121">पेज <ph name="THUMBNAIL_PAGE" /> का थंबनेल</translation>
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ करें</translation>
<translation id="4300675098767811073">दाईं ओर à¤à¤• से ज़à¥à¤¯à¤¾à¤¦à¤¾ पंच</translation>
+<translation id="4302514097724775343">डायनो को चलाने के लिà¤, उस पर टैप करें</translation>
<translation id="4302965934281694568">शू3 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="4305666528087210886">आपकी फ़ाइल à¤à¤•à¥à¤¸à¥‡à¤¸ नहीं की जा सकी</translation>
<translation id="4305817255990598646">बदलें</translation>
@@ -912,9 +927,10 @@
<translation id="4658638640878098064">सबसे ऊपर बाईं ओर सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">वरà¥à¤šà¥à¤…ल रिà¤à¤²à¤¿à¤Ÿà¥€</translation>
+<translation id="4675657451653251260">मेहमान मोड में आपको Chrome की किसी भी पà¥à¤°à¥‹à¥žà¤¾à¤‡à¤² की जानकारी नहीं दिखेगी. पासवरà¥à¤¡ और पैसे चà¥à¤•à¤¾à¤¨à¥‡ के तरीकों वगैरह की जानकारी à¤à¤•à¥à¤¸à¥‡à¤¸ करने के लिà¤, आप अपने Google खाते में <ph name="LINK_BEGIN" />साइन इन<ph name="LINK_END" /> कर सकते हैं.</translation>
<translation id="467662567472608290">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° में तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ हैं. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="4677585247300749148"><ph name="URL" /> सà¥à¤²à¤­à¤¤à¤¾ इवेंट का जवाब देना चाहता है</translation>
-<translation id="467809019005607715">Google सà¥à¤²à¤¾à¤‡à¤¡</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">आपने अभी जिस साइट पर अपना पासवरà¥à¤¡ डाला है वह सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है. कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤®, <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" />, और उन साइटों पर तà¥à¤°à¤‚त जाकर, सेव किठगठपासवरà¥à¤¡ की जांच करने का सà¥à¤à¤¾à¤µ देता है जिन पर आपने इस पासवरà¥à¤¡ का इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया है.</translation>
<translation id="4690462567478992370">अमानà¥à¤¯ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° का उपयोग करना बंद करें</translation>
<translation id="4691835149146451662">आरà¥à¤•à¤¿à¤Ÿà¥‡à¤•à¥à¤šà¤°-ठ(à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
@@ -939,6 +955,12 @@
<translation id="4761104368405085019">अपना माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ उपयोग करें</translation>
<translation id="4764776831041365478"><ph name="URL" /> पर मौजूद वेबपेज संभवतः असà¥à¤¥à¤¾à¤¯à¥€ रूप से बंद है या उसे सà¥à¤¥à¤¾à¤¯à¥€ रूप से किसी नठवेब पते पर ले जाया गया है.</translation>
<translation id="4766713847338118463">नीचे की ओर डà¥à¤¯à¥à¤à¤² सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ आपकी यह गतिविधि इस डिवाइस पर सेव की जाà¤à¤—ी:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />इस विंडो पर डाउनलोड की गई कोई भी फ़ाइल
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">अजà¥à¤žà¤¾à¤¤ गड़बड़ी आई.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{पॉप-अप बà¥à¤²à¥‰à¤• किया गया}one{# पॉप-अप बà¥à¤²à¥‰à¤• किठगठहैं}other{# पॉप-अप बà¥à¤²à¥‰à¤• किठगठहैं}}</translation>
<translation id="4780366598804516005">मेलबॉकà¥à¤¸ 1</translation>
@@ -1101,11 +1123,13 @@
<translation id="5386426401304769735">इस साइट की पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शृंखला में, SHA-1 का उपयोग करके हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° किया गया पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शामिल है.</translation>
<translation id="538659543871111977">à¤4-टैब</translation>
<translation id="5396631636586785122">दाईं ओर à¤à¤œà¤¼Â à¤¸à¥à¤Ÿà¤¿à¤š</translation>
+<translation id="5398772614898833570">विजà¥à¤žà¤¾à¤ªà¤¨ बà¥à¤²à¥‰à¤• हैं</translation>
<translation id="5400836586163650660">सà¥à¤²à¥‡à¤Ÿà¥€</translation>
<translation id="540969355065856584">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° इस समय मानà¥à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥žà¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="541416427766103491">सà¥à¤Ÿà¥ˆà¤•à¤° 4</translation>
<translation id="5421136146218899937">बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग डेटा साफ़ करें...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> वेबसाइट आपको सूचनाà¤à¤‚ भेजना चाहती है</translation>
+<translation id="542872847390508405">आप à¤à¤• मेहमान के रूप में बà¥à¤°à¤¾à¤‰à¤œà¤¼ कर रहे हैं</translation>
<translation id="5430298929874300616">बà¥à¤•à¤®à¤¾à¤°à¥à¤• निकालें</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" पर सà¥à¤•à¥€à¤®à¤¾ सतà¥à¤¯à¤¾à¤ªà¤¨ गड़बड़ी: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">दूसरी तरफ़ सीधा करके रखें</translation>
@@ -1147,12 +1171,12 @@
<translation id="5571083550517324815">इस पते से पिक अप नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="5580958916614886209">अपने कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ की समय सीमा खतà¥à¤® होने का महीना जांचें और फिर से कोशिश करें</translation>
<translation id="5586446728396275693">कोई सहेजा गया पता नहीं है</translation>
+<translation id="5593349413089863479">कनेकà¥à¤¶à¤¨ पूरी तरह सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="5595485650161345191">पते में बदलाव करें</translation>
<translation id="5598944008576757369">भà¥à¤—तान का तरीका चà¥à¤¨à¥‡à¤‚</translation>
<translation id="560412284261940334">पà¥à¤°à¤¬à¤‚धन समरà¥à¤¥à¤¿à¤¤ नहीं</translation>
<translation id="5605670050355397069">लेजर</translation>
<translation id="5607240918979444548">आरà¥à¤•à¤¿à¤Ÿà¥‡à¤•à¥à¤šà¤°-सी</translation>
-<translation id="5608165884683734521">यह साइट नकली या धोखाधड़ी करने वाली हो सकती है. Chrome साइट छोड़ने का सà¥à¤à¤¾à¤µ देता है.</translation>
<translation id="5610142619324316209">कनेकà¥à¤¶à¤¨ की जाà¤à¤š करें</translation>
<translation id="5610807607761827392">आप <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में कारà¥à¤¡ और पते पà¥à¤°à¤¬à¤‚धित कर सकते हैं.</translation>
<translation id="561165882404867731">Google Translate की मदद से इस पेज का अनà¥à¤µà¤¾à¤¦ करें</translation>
@@ -1224,6 +1248,7 @@
<translation id="5901630391730855834">पीला</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> की मूल नीति के मà¥à¤¤à¤¾à¤¬à¤¿à¤• रोक लगाई गई.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (सिंक किया गया)</translation>
+<translation id="5913377024445952699">सà¥à¤•à¥à¤°à¥€à¤¨ को कैपà¥à¤šà¤° करने की सà¥à¤µà¤¿à¤§à¤¾ रोक दी गई है</translation>
<translation id="59174027418879706">चालू किया गया</translation>
<translation id="5919090499915321845">बी10</translation>
<translation id="5921185718311485855">चालू है</translation>
@@ -1236,6 +1261,7 @@
<translation id="5963413905009737549">अनà¥à¤­à¤¾à¤—</translation>
<translation id="5967592137238574583">संपरà¥à¤• जानकारी में बदलाव करें</translation>
<translation id="5967867314010545767">इतिहास से निकालें</translation>
+<translation id="5968793460449681917">वेबसाइट पर किसी के भी आने पर</translation>
<translation id="5975083100439434680">ज़ूम आउट</translation>
<translation id="5979084224081478209">पासवरà¥à¤¡ जांचें</translation>
<translation id="5980920751713728343">इंडेकà¥à¤¸-3x5</translation>
@@ -1391,6 +1417,7 @@
<translation id="6587923378399804057">आपका कॉपी किया हà¥à¤† लिंक</translation>
<translation id="6591833882275308647">आपका <ph name="DEVICE_TYPE" /> पà¥à¤°à¤¬à¤‚धित नहीं किया जाता</translation>
<translation id="6596325263575161958">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करने के तरीकों के विकलà¥à¤ª</translation>
+<translation id="6596892391065203054">इस कॉनà¥à¤Ÿà¥‡à¤‚ट को पà¥à¤°à¤¿à¤‚ट करने की सà¥à¤µà¤¿à¤§à¤¾ को आपके à¤à¤¡à¤®à¤¿à¤¨ ने बà¥à¤²à¥‰à¤• कर दिया है.</translation>
<translation id="6604181099783169992">गति या लाइट सेंसर</translation>
<translation id="6609880536175561541">पीआरसी7 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="6612358246767739896">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€</translation>
@@ -1450,6 +1477,7 @@
<translation id="6895330447102777224">आपके कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ हो गई है</translation>
<translation id="6897140037006041989">उपयोगकरà¥à¤¤à¤¾ à¤à¤œà¥‡à¤‚ट</translation>
<translation id="6898699227549475383">संगठन (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> को इनकी अनà¥à¤®à¤¤à¤¿ दें:</translation>
<translation id="6910240653697687763"><ph name="URL" /> वेबसाइट आपके MIDI डिवाइस का पूरा नियंतà¥à¤°à¤£ पाना चाहती है</translation>
<translation id="6915804003454593391">उपयोगकरà¥à¤¤à¤¾:</translation>
<translation id="6934672428414710184">यह नाम आपके Google खाते से है</translation>
@@ -1469,7 +1497,7 @@
<translation id="6973656660372572881">फ़िकà¥â€à¤¸à¥â€à¤¡ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ सरà¥à¤µà¤° और .pac सà¥â€à¤•à¥à¤°à¤¿à¤ªà¥â€à¤Ÿ URL दोनों ही बताठगठहैं.</translation>
<translation id="6973932557599545801">माफ़ करें, मैं आपकी मदद नहीं कर सकती. कृपया खà¥à¤¦ करने की कोशिश करें.</translation>
<translation id="6975012522936652259">आपने अभी-अभी जिस साइट पर अपना पासवरà¥à¤¡ डाला है वह सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है. कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤®, <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, और उन साइटों पर जाकर पासवरà¥à¤¡ बदलने का सà¥à¤à¤¾à¤µ देता है जिन पर आपने इसे इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया था.</translation>
-<translation id="6979158407327259162">Google डिसà¥à¤•</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">मà¥à¤¯à¥‚ट करें (डिफ़ॉलà¥à¤Ÿ)</translation>
<translation id="6979983982287291980">आप जो फ़ाइलें डाउनलोड करते हैं वे विशà¥à¤²à¥‡à¤·à¤£ के लिठ'Google कà¥à¤²à¤¾à¤‰à¤¡' या तीसरे पकà¥à¤·à¥‹à¤‚ को भेजी जाती हैं. उदाहरण के लिà¤, इनà¥à¤¹à¥‡à¤‚ संवेदनशील डेटा या मैलवेयर की जांच के लिठसà¥à¤•à¥ˆà¤¨ किया जा सकता है.</translation>
<translation id="6989763994942163495">अतिरिकà¥à¤¤ सेटिंग दिखाà¤à¤‚...</translation>
@@ -1561,6 +1589,7 @@
<translation id="7346048084945669753">जà¥à¤¡à¤¼à¤¾ हà¥à¤† है या नहीं:</translation>
<translation id="7349430561505560861">à¤4-à¤à¤•à¥à¤¸à¥à¤Ÿà¥à¤°à¤¾</translation>
<translation id="7353601530677266744">कमांड लाइन</translation>
+<translation id="7359588939039777303">विजà¥à¤žà¤¾à¤ªà¤¨ बà¥à¤²à¥‰à¤• हैं.</translation>
<translation id="7372973238305370288">खोज नतीजे</translation>
<translation id="7374733840632556089">यह गड़बड़ी आपके डिवाइस पर इंसà¥à¤Ÿà¥‰à¤² किठगठपà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° की वजह से हो सकती है. हो सकता है कि इसे आपने या किसी दूसरे वà¥à¤¯à¤•à¥à¤¤à¤¿ ने इंसà¥à¤Ÿà¥‰à¤² किया हो. यह पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°, नेटवरà¥à¤• पर नज़र रखने और रोकने के लिठजाना जाता है. Chrome की नज़र में यह भरोसेमंद नहीं है. हालांकि, नज़र रखने के कà¥à¤› वैध मामले भी होते हैं, जैसे कि किसी सà¥à¤•à¥‚ल या कंपनी के नेटवरà¥à¤•. Chrome यह पकà¥à¤•à¤¾ करना चाहता है कि आपको इसकी जानकारी हो. भले ही, आप इसे रोक न सकते हों. वेब को à¤à¤•à¥à¤¸à¥‡à¤¸ करने वाले किसी भी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° या à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ पर नज़र रखी जा सकती है.</translation>
<translation id="7375818412732305729">फ़ाइल अटैच की गई है</translation>
@@ -1735,6 +1764,7 @@
<translation id="7976214039405368314">बहà¥à¤¤ सारे अनà¥à¤°à¥‹à¤§</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ डिवाइस</translation>
<translation id="7977894662897852582">ईडीपी</translation>
+<translation id="79859296434321399">'बà¥à¥€ हà¥à¤ˆ वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾' की सामगà¥à¤°à¥€ देखने के लिà¤, ARCore इंसà¥à¤Ÿà¥‰à¤² करें</translation>
<translation id="799149739215780103">बाइंड</translation>
<translation id="7995512525968007366">बताया नहीं गया है</translation>
<translation id="800218591365569300">जगह खाली करने के लिठदूसरे टैब या पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करके देखें.</translation>
@@ -1862,25 +1892,39 @@
<translation id="8507227106804027148">कमांड लाइन</translation>
<translation id="8508648098325802031">सरà¥à¤š आइकॉन</translation>
<translation id="8522552481199248698">Chrome से आप अपने Google खाते की सà¥à¤°à¤•à¥à¤·à¤¾ कर सकते हैं और अपना पासवरà¥à¤¡ बदल सकते हैं.</translation>
+<translation id="8525306231823319788">फ़à¥à¤² सà¥â€à¤•à¥à¤°à¥€à¤¨</translation>
<translation id="8530813470445476232">Chrome की सेटिंग में अपना बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास, कà¥à¤•à¥€, कैश मेमोरी वगैरह मिटाà¤à¤‚</translation>
<translation id="8533619373899488139">&lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाकर, बà¥à¤²à¥‰à¤• किठगठयूआरà¤à¤² की सूची और à¤à¤¸à¥€ नीतियां देखें जिनà¥à¤¹à¥‡à¤‚ आपके à¤à¤¡à¤®à¤¿à¤¨ ने लागू किया है.</translation>
<translation id="8541158209346794904">बà¥à¤²à¥‚टूथ डिवाइस</translation>
<translation id="8542014550340843547">नीचे की ओर टà¥à¤°à¤¿à¤ªà¤² सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
<translation id="8543181531796978784">आप <ph name="BEGIN_ERROR_LINK" />पहचान संबंधी समसà¥â€à¤¯à¤¾ की रिपोरà¥à¤Ÿ<ph name="END_ERROR_LINK" /> कर सकते हैं या अगर आप अपनी सà¥à¤°à¤•à¥à¤·à¤¾ संबंधी जोखिमों को समà¤à¤¤à¥‡ हैं तो, <ph name="BEGIN_LINK" />इस असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
<translation id="8557066899867184262">कारà¥à¤¡ वेरीफ़िकेशन कोड (सीवीसी) आपके कारà¥à¤¡ के पीछे मौजूद होता है.</translation>
+<translation id="8558485628462305855">'बà¥à¥€ हà¥à¤ˆ वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾' की सामगà¥à¤°à¥€ देखने के लिà¤, ARCore अपडेट करें</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से à¤à¤• निजी कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं किया जा सकता कà¥â€à¤¯à¥‹à¤‚कि आपके डिवाइस का तारीख और समय (<ph name="DATE_AND_TIME" />) गलत है.</translation>
<translation id="8564182942834072828">अलग-अलग दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼/बिना कà¥à¤°à¤® के लगाई गई कॉपी</translation>
<translation id="8564985650692024650">अगर आपने अपने <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡ का दूसरी साइटों पर दोबारा इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया है, तो कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® आपको उसे रीसेट करने का सà¥à¤à¤¾à¤µ देता है.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ये गतिविधियां इस डिवाइस पर सेव नहीं की जाà¤à¤‚गी:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />इस विंडो पर देखे जाने वाले पेज
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ और साइट का डेटा
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Touch ID का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करके कारà¥à¤¡ की जलà¥à¤¦à¥€ पà¥à¤·à¥à¤Ÿà¤¿ करें</translation>
<translation id="858637041960032120">फ़ोन नंबर जोड़ें
</translation>
<translation id="8589998999637048520">सबसे अचà¥à¤›à¥€ कà¥à¤µà¤¾à¤²à¤¿à¤Ÿà¥€</translation>
+<translation id="8600271352425265729">सिरà¥à¤«à¤¼ इस बार अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="860043288473659153">कारà¥à¤¡à¤§à¤¾à¤°à¤• का नाम</translation>
<translation id="8606726445206553943">अपने MIDI डिवाइस का उपयोग करें</translation>
+<translation id="8612761427948161954">नमसà¥à¤¤à¥‡ <ph name="USERNAME" />,
+ <ph name="BR" />
+ आप मेहमान के तौर पर बà¥à¤°à¤¾à¤‰à¤œà¤¼ कर रहे हैं</translation>
<translation id="861775596732816396">आकार 4</translation>
<translation id="8622948367223941507">लीगल-à¤à¤•à¥à¤¸à¥à¤Ÿà¥à¤°à¤¾</translation>
<translation id="8623885649813806493">पासवरà¥à¤¡ गलत है. सेव किठगठसभी पासवरà¥à¤¡ दिखाà¤à¤‚.</translation>
<translation id="8625384913736129811">इस कारà¥à¤¡ को इस डिवाइस में सेव करें</translation>
+<translation id="8627040765059109009">सà¥à¤•à¥à¤°à¥€à¤¨ को कैपà¥à¤šà¤° करने की सà¥à¤µà¤¿à¤§à¤¾ फिर से शà¥à¤°à¥‚ कर दी गई है</translation>
<translation id="8657078576661269990">आपके à¤à¤¡à¤®à¤¿à¤¨ ने <ph name="ORIGIN_NAME" /> से <ph name="VM_NAME_1" /> और <ph name="VM_NAME_2" /> पर शेयर करने की सà¥à¤µà¤¿à¤§à¤¾ बंद कर दी है</translation>
<translation id="8663226718884576429">ऑरà¥à¤¡à¤° की खास बातें, <ph name="TOTAL_LABEL" />, ज़à¥à¤¯à¤¾à¤¦à¤¾ जानकारी</translation>
<translation id="867224526087042813">हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
@@ -1943,6 +1987,7 @@
<translation id="8912362522468806198">Google खाता</translation>
<translation id="8913778647360618320">'पैसे चà¥à¤•à¤¾à¤¨à¥‡ के तरीके पà¥à¤°à¤¬à¤‚धित करें' बटन, Chrome की सेटिंग में पैसे चà¥à¤•à¤¾à¤¨à¥‡ से जà¥à¤¡à¤¼à¥€ जानकारी और कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ की जानकारी पà¥à¤°à¤¬à¤‚धित करने के लिà¤, Enter दबाà¤à¤‚</translation>
<translation id="8918231688545606538">यह पेज संदिगà¥à¤§ है</translation>
+<translation id="8922013791253848639">इस साइट पर विजà¥à¤žà¤¾à¤ªà¤¨à¥‹à¤‚ की हमेशा अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="892588693504540538">सबसे ऊपर दाईं ओर पंच</translation>
<translation id="8931333241327730545">कà¥à¤¯à¤¾ आप इस कारà¥à¤¡ को अपने Google खाते में सेव करना चाहते हैं?</translation>
<translation id="8932102934695377596">आपकी घड़ी पीछे है</translation>
@@ -2011,21 +2056,24 @@
<translation id="917450738466192189">सरà¥à¤µà¤° का पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° अमानà¥à¤¯ है.</translation>
<translation id="9174917557437862841">टैब बदलने का बटन, इस टैब पर सà¥à¤µà¤¿à¤š करने के लिठEnter दबाà¤à¤‚</translation>
<translation id="9179703756951298733">Chrome की सेटिंग में, आप पैसे चà¥à¤•à¤¾à¤¨à¥‡ और कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ की जानकारी को पà¥à¤°à¤¬à¤‚धित कर सकते हैं</translation>
-<translation id="9183302530794969518">Google दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> à¤à¤• असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² का उपयोग करता है.</translation>
<translation id="9191834167571392248">नीचे बाईं ओर पंच</translation>
+<translation id="9199905725844810519">पà¥à¤°à¤¿à¤‚ट करने की सà¥à¤µà¤¿à¤§à¤¾ को बà¥à¤²à¥‰à¤• किया गया है</translation>
<translation id="9205078245616868884">आपका डेटा आपके सिंक पासफ़à¥à¤°à¥‡à¥› से सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ किया गया है. सिंक शà¥à¤°à¥‚ करने के लिठइसे डालें.</translation>
<translation id="9207861905230894330">लेख जोड़ने में विफल रहा.</translation>
<translation id="9213433120051936369">दिखने का तरीका अपनी पसंद के मà¥à¤¤à¤¾à¤¬à¤¿à¤• बनाà¤à¤‚</translation>
<translation id="9215416866750762878">à¤à¤• à¤à¤ªà¥â€à¤²à¤¿à¤•à¥‡à¤¶à¤¨ Chrome को इस साइट से सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ तरीके से कनेकà¥â€à¤Ÿ होने से रोक रहा है</translation>
-<translation id="9219103736887031265">इमेज</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">फ़ॉरà¥à¤® साफ़ करें</translation>
<translation id="936474030629450166">सà¥à¤ªà¤°-बी</translation>
<translation id="936602727769022409">आप अपने Google खाते का à¤à¤•à¥à¤¸à¥‡à¤¸ खो सकते हैं. कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® आपको इसी समय अपना पासवरà¥à¤¡ बदलने का सà¥à¤à¤¾à¤µ देता है. आपको साइन इन करने को कहा जाà¤à¤—ा.</translation>
<translation id="939736085109172342">नया फ़ोलà¥à¤¡à¤°</translation>
+<translation id="945522503751344254">फ़ीडबैक भेजें</translation>
<translation id="945855313015696284">नीचे दी गई जानकारी देखें और सभी गलत कारà¥à¤¡ मिटाà¤à¤‚</translation>
<translation id="950736567201356821">सबसे ऊपर टà¥à¤°à¤¿à¤ªà¤² पंच</translation>
+<translation id="951941430552851965">सà¥à¤•à¥à¤°à¥€à¤¨ पर दिख रहे कॉनà¥à¤Ÿà¥‡à¤‚ट की वजह से, आपके à¤à¤¡à¤®à¤¿à¤¨ ने सà¥à¤•à¥à¤°à¥€à¤¨ कैपà¥à¤šà¤° करने की सà¥à¤µà¤¿à¤§à¤¾ रोक दी है.</translation>
<translation id="961663415146723894">नीचे की ओर बाइंड</translation>
<translation id="962484866189421427">यह सामगà¥à¤°à¥€ à¤à¤¸à¥‡ धोखा देने वाले à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² कर सकती है जो कà¥à¤› और होने का दावा करते हैं या à¤à¤¸à¤¾ डेटा इकटà¥à¤ à¤¾ करते हैं जिसका इसà¥à¤¤à¥‡à¤®à¤¾à¤² आप पर नज़र रखने के लिठकिया जा सके. <ph name="BEGIN_LINK" />फिर भी दिखाà¤à¤‚<ph name="END_LINK" /></translation>
<translation id="969892804517981540">आधिकारिक बिलà¥à¤¡</translation>
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index 470a9ef933a..95ca99372b8 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -80,6 +80,14 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Unijeli ste zaporku na web-lokaciju kojom ne upravlja vaÅ¡a organizacija. Da biste zaÅ¡titili raÄun, nemojte upotrebljavati tu zaporku za druge aplikacije i web-lokacije.</translation>
<translation id="1263231323834454256">Popis za Äitanje</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivnost koja neće ostati na uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Stranice koje pregledavate u ovom prozoru
+ <ph name="LIST_ITEM" />Podaci o kolaÄićima i web-lokaciji
+ <ph name="LIST_ITEM" />Podaci o raÄunu (<ph name="LINK_BEGIN" />odjava<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">NaÄin preuzimanja</translation>
<translation id="1281476433249504884">Spremnik za slaganje u snopove 1</translation>
<translation id="1285320974508926690">Nikad nemoj prevoditi ovu web-lokaciju</translation>
@@ -283,6 +291,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="204357726431741734">Prijavite se kako biste upotrebljavali zaporke spremljene na Google raÄunu</translation>
<translation id="2053111141626950936">Neće se prevoditi <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">ZIP kôd</translation>
+<translation id="2054665754582400095">Vaša prisutnost</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 prijedlog}one{# prijedlog}few{# prijedloga}other{# prijedloga}}</translation>
<translation id="2079545284768500474">Poništi</translation>
<translation id="20817612488360358">Postavljena je upotreba sistemskih postavki proxy poslužitelja, ali takoÄ‘er je odreÄ‘ena izriÄita konfiguracija proxy poslužitelja.</translation>
@@ -296,6 +305,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2102495993840063010">Android aplikacije</translation>
<translation id="2107021941795971877">Podrška ispisu</translation>
<translation id="2108755909498034140">Ponovo pokrenite raÄunalo</translation>
+<translation id="2111166930115883695">Pritisnite razmaknicu za reprodukciju</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kartica</translation>
<translation id="2114841414352855701">Zanemareno jer je nadjaÄano pravilom <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="214556005048008348">Otkaži plaćanje</translation>
<translation id="2147827593068025794">Sinkronizacija u pozadini</translation>
<translation id="2148613324460538318">Dodaj karticu</translation>
+<translation id="2149968176347646218">Veza nije sigurna</translation>
<translation id="2154054054215849342">Sinkronizacija nije dostupna za vašu domenu</translation>
<translation id="2154484045852737596">Uredite karticu</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -317,7 +328,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2181821976797666341">Pravila</translation>
<translation id="2183608646556468874">Telefonski broj</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
-<translation id="2187243482123994665">Korisnikova prisutnost</translation>
<translation id="2187317261103489799">Otkrij (zadano)</translation>
<translation id="2188375229972301266">Višestruko bušenje pri dnu</translation>
<translation id="2202020181578195191">Unesite važeću godinu isteka</translation>
@@ -470,6 +480,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2839501879576190149">Pokušavate pristupiti lažnoj web-lokaciji</translation>
<translation id="2850739647070081192">Invite (omotnica)</translation>
<translation id="2856444702002559011">NapadaÄi možda pokuÅ¡avaju ukrasti vaÅ¡e podatke s web-lokacije <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primjer zaporke, poruke ili brojeve kreditnih kartica). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ova web-lokacija prikazuje ometajuće ili obmanjujuće oglase.</translation>
<translation id="2878197950673342043">Presavijanje u obliku postera</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Postavljanje prozora</translation>
@@ -508,11 +519,11 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2996674880327704673">Googleovi prijedlozi</translation>
<translation id="3002501248619246229">Provjera medija ladice za ulaganje</translation>
<translation id="3005723025932146533">Prikaži spremljenu kopiju</translation>
-<translation id="3007719053326478567">Administrator je blokirao ispis ovog sadržaja</translation>
<translation id="3008447029300691911">Unesite CVC za karticu <ph name="CREDIT_CARD" />. Nakon što ih potvrdite, podaci o kartici dijelit će se s ovom web-lokacijom.</translation>
<translation id="3010559122411665027">Unos popisa "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatski blokirano</translation>
<translation id="3016780570757425217">znati vašu lokaciju</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pritisnite Tab, a zatim Enter da biste uklonili prijedlog.</translation>
<translation id="3023071826883856138">You4 (omotnica)</translation>
<translation id="3024663005179499861">Pogrešna vrsta pravila</translation>
<translation id="3037605927509011580">O, ne!</translation>
@@ -555,6 +566,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3207960819495026254">OznaÄeno</translation>
<translation id="3209034400446768650">Stranica se možda naplaćuje</translation>
<translation id="3212581601480735796">Prati se vaša aktivnost na web-lokaciji <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Zatvorite sve prozore u naÄinu rada za goste kako bi se s ureÄ‘aja izbrisala aktivnost pregledavanja.</translation>
<translation id="3215092763954878852">Nije moguće koristiti WebAuthn</translation>
<translation id="3218181027817787318">Relativno</translation>
<translation id="3225919329040284222">Poslužitelj je pokazao certifikat koji ne odgovara ugraÄ‘enim oÄekivanjima. Ta su oÄekivanja ukljuÄena za odreÄ‘ene web-lokacije s visokim stupnjem sigurnosti radi vaÅ¡e zaÅ¡tite.</translation>
@@ -701,6 +713,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3784372983762739446">Bluetooth uređaji</translation>
<translation id="3787705759683870569">IstjeÄe <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">VeliÄina 16</translation>
+<translation id="3789841737615482174">Instaliraj</translation>
<translation id="3793574014653384240">Broj nedavnih rušenja i njihovi razlozi</translation>
<translation id="3797522431967816232">Prc3 (omotnica)</translation>
<translation id="3799805948399000906">Zatraženi font</translation>
@@ -752,6 +765,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4056223980640387499">Sepija</translation>
<translation id="4058922952496707368">Stavka "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (omotnica)</translation>
+<translation id="4067669230157909013">Snimanje zaslona je nastavljeno.</translation>
<translation id="4067947977115446013">Dodajte važeću adresu</translation>
<translation id="4072486802667267160">Došlo je do pogreške pri obradi narudžbe. Pokušajte ponovo.</translation>
<translation id="4075732493274867456">Klijent i poslužitelj ne podržavaju uobiÄajenu verziju SSL protokola ili paket Å¡ifri.</translation>
@@ -837,6 +851,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4297502707443874121">Minijatura za stranicu <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Proširi</translation>
<translation id="4300675098767811073">Višestruko bušenje s desne strane</translation>
+<translation id="4302514097724775343">Dodirnite dinosaura da biste poÄeli igrati</translation>
<translation id="4302965934281694568">Chou3 (omotnica)</translation>
<translation id="4305666528087210886">Pristup datoteci nije uspio</translation>
<translation id="4305817255990598646">Prebaci</translation>
@@ -915,6 +930,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4658638640878098064">Spajanje pri vrhu lijevo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtualna stvarnost</translation>
+<translation id="4675657451653251260">U naÄinu rada za goste ne možete vidjeti podatke drugih profila u Chromeu. Možete se <ph name="LINK_BEGIN" />prijaviti<ph name="LINK_END" /> da biste pristupili podacima o svojem Google raÄunu kao Å¡to su zaporke i naÄini plaćanja.</translation>
<translation id="467662567472608290">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat sadrži pogreške. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="4677585247300749148"><ph name="URL" /> želi odgovoriti na dogaÄ‘aje pristupaÄnosti</translation>
<translation id="467809019005607715">Google prezentacije</translation>
@@ -942,6 +958,12 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4761104368405085019">upotrijebiti vaš mikrofon</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje pri dnu</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivnost koja ostaje na uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sve datoteke koje preuzmete u ovom prozoru
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Došlo je do nepoznate pogreške.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{SkoÄni prozor blokiran}one{# skoÄni prozor blokiran}few{# skoÄna prozora blokirana}other{# skoÄnih prozora blokirano}}</translation>
<translation id="4780366598804516005">Izlazni spremnik s odjeljcima 1</translation>
@@ -1104,11 +1126,13 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5386426401304769735">Lanac certifikata za ovu web-lokaciju sadrži certifikat s SHA-1 potpisom.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Rubni Å¡av s desne strane</translation>
+<translation id="5398772614898833570">Oglasi su blokirani</translation>
<translation id="5400836586163650660">Siva</translation>
<translation id="540969355065856584">Poslužitelj nije uspio dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat trenutaÄno nije važeći. Uzrok tomu može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="541416427766103491">Spremnik za slaganje u snopove 4</translation>
<translation id="5421136146218899937">Izbriši podatke o pregledavanju...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> želi vam slati obavijesti</translation>
+<translation id="542872847390508405">Pregledavate kao gost</translation>
<translation id="5430298929874300616">Ukloni oznaku</translation>
<translation id="5439770059721715174">Pogreška provjere sheme na lokaciji "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Suprotnim redoslijedom prema gore</translation>
@@ -1150,12 +1174,12 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5571083550517324815">Preuzimanje na toj adresi nije moguće. Odaberite drugu adresu.</translation>
<translation id="5580958916614886209">Provjerite mjesec isteka, pa pokušajte ponovo</translation>
<translation id="5586446728396275693">Nema nijedne spremljene adrese</translation>
+<translation id="5593349413089863479">Veza nije potpuno sigurna</translation>
<translation id="5595485650161345191">Uređivanje adrese</translation>
<translation id="5598944008576757369">Odaberite naÄin plaćanja</translation>
<translation id="560412284261940334">Upravljanje nije podržano</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Web-lokacija je možda lažna ili joj je cilj prijevara. Chrome preporuÄuje da je odmah napustite.</translation>
<translation id="5610142619324316209">provjerite vezu</translation>
<translation id="5610807607761827392">Karticama i adresama možete upravljati u <ph name="BEGIN_LINK" />Postavkama<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Prevedite ovu stranicu pomoću Google prevoditelja</translation>
@@ -1227,6 +1251,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5901630391730855834">Žuta</translation>
<translation id="5905445707201418379">Blokirano izvornim pravilom koje određuje <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinkronizirano)</translation>
+<translation id="5913377024445952699">Snimanje zaslona je pauzirano</translation>
<translation id="59174027418879706">Omogućeno</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">UkljuÄeno</translation>
@@ -1239,6 +1264,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5963413905009737549">Odjeljak</translation>
<translation id="5967592137238574583">Uredite podatke za kontakt</translation>
<translation id="5967867314010545767">Ukloni iz povijesti</translation>
+<translation id="5968793460449681917">Pri svakom posjetu</translation>
<translation id="5975083100439434680">Smanji</translation>
<translation id="5979084224081478209">Provjeri zaporke</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6587923378399804057">Veza koju ste kopirali</translation>
<translation id="6591833882275308647">Uređaj <ph name="DEVICE_TYPE" /> nije upravljani uređaj</translation>
<translation id="6596325263575161958">Opcije Å¡ifriranja</translation>
+<translation id="6596892391065203054">Administrator je blokirao ispis ovog sadržaja.</translation>
<translation id="6604181099783169992">Senzori pokreta ili osvjetljenja</translation>
<translation id="6609880536175561541">Prc7 (omotnica)</translation>
<translation id="6612358246767739896">Zaštićeni sadržaj</translation>
@@ -1453,6 +1480,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6895330447102777224">Kartica je potvrđena</translation>
<translation id="6897140037006041989">KorisniÄki agent</translation>
<translation id="6898699227549475383">Organizacija (O)</translation>
+<translation id="6907293445143367439">Web-lokaciji <ph name="SITE_NAME" /> dopusti sljedeće:</translation>
<translation id="6910240653697687763"><ph name="URL" /> želi dobiti potpuni nadzor nad vašim MIDI uređajima</translation>
<translation id="6915804003454593391">Korisnik:</translation>
<translation id="6934672428414710184">To je ime s vaÅ¡eg Google raÄuna</translation>
@@ -1564,6 +1592,7 @@ Dodatne pojedinosti:
<translation id="7346048084945669753">Korisnik je povezan:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Naredbeni redak</translation>
+<translation id="7359588939039777303">Oglasi su blokirani.</translation>
<translation id="7372973238305370288">rezultat pretraživanja</translation>
<translation id="7374733840632556089">Do ovog problema dolazi zbog certifikata koji ste vi ili neka druga osoba instalirali na ovaj ureÄ‘aj. Certifikat se upotrebljava za nadzor i presretanje mreža i Chrome ga ne smatra pouzdanim. Iako postoje opravdani razlozi za nadziranje, kao na primjer na Å¡kolskoj mreži ili mreži tvrtke, Chrome želi da budete svjesni da se to dogaÄ‘a, Äak i ako to ne možete sprijeÄiti. Nadziranje je moguće u bilo kojem pregledniku ili aplikaciji koja pristupa webu.</translation>
<translation id="7375818412732305729">Datoteka je priložena</translation>
@@ -1738,6 +1767,7 @@ Dodatne pojedinosti:
<translation id="7976214039405368314">Previše zahtjeva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Za prikaz sadržaja proširene stvarnosti instalirajte ARCore</translation>
<translation id="799149739215780103">Uvez</translation>
<translation id="7995512525968007366">Nije navedeno</translation>
<translation id="800218591365569300">Pokušajte zatvoriti ostale kartice ili programe da biste oslobodili memoriju.</translation>
@@ -1865,25 +1895,39 @@ Dodatne pojedinosti:
<translation id="8507227106804027148">Naredbeni redak</translation>
<translation id="8508648098325802031">Ikona pretraživanja</translation>
<translation id="8522552481199248698">Chrome vam može pomoći da zaÅ¡titite svoj Google raÄun i promijenite zaporku.</translation>
+<translation id="8525306231823319788">Cijeli zaslon</translation>
<translation id="8530813470445476232">IzbriÅ¡ite povijest pregledavanja, kolaÄiće, predmemoriju i joÅ¡ mnogo toga u postavkama Chromea</translation>
<translation id="8533619373899488139">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste vidjeli popis blokiranih URL-ova i druga pravila koja je postavio vaš administrator sustava.</translation>
<translation id="8541158209346794904">Bluetooth uređaj</translation>
<translation id="8542014550340843547">Trostruko spajanje pri dnu</translation>
<translation id="8543181531796978784">Možete <ph name="BEGIN_ERROR_LINK" />prijaviti problem s otkrivanjem<ph name="END_ERROR_LINK" /> ili, ako razumijete na koje je naÄine ugrožena vaÅ¡a sigurnost, <ph name="BEGIN_LINK" />posjetite nesigurnu web-lokaciju<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC možete pronaći na poleđini kartice.</translation>
+<translation id="8558485628462305855">Za prikaz sadržaja proširene stvarnosti ažurirajte ARCore</translation>
<translation id="8559762987265718583">Sigurnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nije moguće uspostaviti jer datum i vrijeme (<ph name="DATE_AND_TIME" />) na vaÅ¡em ureÄ‘aju nisu toÄni.</translation>
<translation id="8564182942834072828">Zasebni dokumenti/nerazvrstani primjerci</translation>
<translation id="8564985650692024650">Chromium preporuÄuje poniÅ¡tavanje zaporke za organizaciju <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je upotrebljavali za druge web-lokacije.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivnost koja neće ostati na uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Stranice koje pregledavate u ovom prozoru
+ <ph name="LIST_ITEM" />Podaci o kolaÄićima i web-lokaciji
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Upotrijebite znaÄajku Touch ID za brže potvrÄ‘ivanje kartica</translation>
<translation id="858637041960032120">Dodaj tel. broj
</translation>
<translation id="8589998999637048520">Najbolja kvaliteta</translation>
+<translation id="8600271352425265729">Samo ovaj put</translation>
<translation id="860043288473659153">Ime vlasnika kartice</translation>
<translation id="8606726445206553943">upotrebljavati vaše MIDI uređaje</translation>
+<translation id="8612761427948161954">Pozdrav <ph name="USERNAME" />,
+ <ph name="BR" />
+ pregledavate kao gost</translation>
<translation id="861775596732816396">VeliÄina 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nema zaporki koje se podudaraju. Prikaži sve spremljene zaporke.</translation>
<translation id="8625384913736129811">Spremi tu karticu na ovaj uređaj</translation>
+<translation id="8627040765059109009">Snimanje zaslona je nastavljeno</translation>
<translation id="8657078576661269990">Administrator je blokirao dijeljenje s <ph name="ORIGIN_NAME" /> na <ph name="VM_NAME_1" /> i <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Sažetak narudžbe, <ph name="TOTAL_LABEL" />, više pojedinosti</translation>
<translation id="867224526087042813">Potpis</translation>
@@ -1946,6 +1990,7 @@ Dodatne pojedinosti:
<translation id="8912362522468806198">Google RaÄun</translation>
<translation id="8913778647360618320">Gumb Upravljajte naÄinima plaćanja, pritisnite Enter da biste upravljali podacima o plaćanju i kreditnoj kartici u postavkama Chromea</translation>
<translation id="8918231688545606538">Stranica je sumnjiva</translation>
+<translation id="8922013791253848639">Uvijek dopusti oglase na ovoj web-lokaciji</translation>
<translation id="892588693504540538">Bušenje pri vrhu desno</translation>
<translation id="8931333241327730545">Želite li spremiti tu karticu na Google raÄun?</translation>
<translation id="8932102934695377596">Sat kasni</translation>
@@ -2018,6 +2063,7 @@ i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predsta
<translation id="9183302530794969518">Google dokumenti</translation>
<translation id="9183425211371246419">Host <ph name="HOST_NAME" /> upotrebljava nepodržane protokole.</translation>
<translation id="9191834167571392248">Bušenje pri dnu lijevo</translation>
+<translation id="9199905725844810519">Ispis je blokiran</translation>
<translation id="9205078245616868884">Vaši su podaci šifrirani vašom šifrom za sinkronizaciju. Unesite je da biste pokrenuli sinkronizaciju.</translation>
<translation id="9207861905230894330">Dodavanje Älanka nije uspjelo.</translation>
<translation id="9213433120051936369">Prilagodi izgled</translation>
@@ -2028,8 +2074,10 @@ i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predsta
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Mogli biste izgubiti pristup svojem Google raÄunu. Chromium preporuÄuje da odmah promijenite zaporku. Morat ćete se prijaviti.</translation>
<translation id="939736085109172342">Nova mapa</translation>
+<translation id="945522503751344254">Pošaljite povratne informacije</translation>
<translation id="945855313015696284">Pregledajte informacije u nastavku i izbrišite nevažeće kartice</translation>
<translation id="950736567201356821">Trostruko bušenje pri vrhu</translation>
+<translation id="951941430552851965">Administrator je pauzirao snimanje zaslona zbog sadržaja na zaslonu.</translation>
<translation id="961663415146723894">Uvez pri dnu</translation>
<translation id="962484866189421427">Ovaj sadržaj može pokušati instalirati obmanjujuće aplikacije koje se pretvaraju da su nešto drugo ili prikupljaju podatke na temelju kojih vas je moguće pratiti. <ph name="BEGIN_LINK" />Ipak prikaži<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Službeni sastavak</translation>
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index a1f75dfb932..84ad055e3d0 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -80,6 +80,14 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Olyan webhelyen adta meg a jelszavát, amelyet nem az Ön szervezete kezel. Fiókja védelme érdekében ne használja fel újra a jelszót más alkalmazásokban és webhelyeken.</translation>
<translation id="1263231323834454256">Olvasási lista</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ami nem marad meg ezen az eszközön:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Az oldalak, melyeket ebben az ablakban nyit meg
+ <ph name="LIST_ITEM" />Sütik és webhelyadatok
+ <ph name="LIST_ITEM" />Fiókadatok (<ph name="LINK_BEGIN" />kijelentkezés<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ãtvételi mód</translation>
<translation id="1281476433249504884">1. kötegelő</translation>
<translation id="1285320974508926690">Ezt a webhelyet soha ne fordítsa le</translation>
@@ -283,6 +291,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="204357726431741734">Jelentkezzen be a Google-fiókjába mentett jelszavak használatához</translation>
<translation id="2053111141626950936">A(z) <ph name="LANGUAGE" /> nyelvű oldalak nem lesznek lefordítva.</translation>
<translation id="2053553514270667976">Irányítószám</translation>
+<translation id="2054665754582400095">Felhasználói jelenlét</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 javaslat}other{# javaslat}}</translation>
<translation id="2079545284768500474">Visszavonás</translation>
<translation id="20817612488360358">A rendszer proxybeállításai konfigurálva vannak a használathoz, de kifejezett proxykonfiguráció is meg van adva.</translation>
@@ -296,6 +305,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2102495993840063010">Android-alkalmazások</translation>
<translation id="2107021941795971877">Nyomtató támogatásai</translation>
<translation id="2108755909498034140">Indítsa újra a számítógépet</translation>
+<translation id="2111166930115883695">A játékhoz nyomja le a szóköz billentyűt</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kártya</translation>
<translation id="2114841414352855701">A rendszer figyelmen kívül hagyja, mivel a(z) <ph name="POLICY_NAME" /> felülírta.</translation>
@@ -307,6 +317,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="214556005048008348">Fizetés visszavonása</translation>
<translation id="2147827593068025794">Szinkronizálás a háttérben</translation>
<translation id="2148613324460538318">Kártya hozzáadása</translation>
+<translation id="2149968176347646218">A kapcsolat nem biztonságos</translation>
<translation id="2154054054215849342">A szinkronizálás az Ön domainjén nem áll rendelkezésre</translation>
<translation id="2154484045852737596">Kártya szerkesztése</translation>
<translation id="2161656808144014275">Szöveg</translation>
@@ -317,7 +328,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2181821976797666341">Házirendek</translation>
<translation id="2183608646556468874">Telefonszám</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 cím}other{# cím}}</translation>
-<translation id="2187243482123994665">Felhasználói jelenlét</translation>
<translation id="2187317261103489799">Észlelés (alapértelmezett)</translation>
<translation id="2188375229972301266">Több lyuk alul</translation>
<translation id="2202020181578195191">Érvényes lejárati évet kell megadnia</translation>
@@ -468,6 +478,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2839501879576190149">Hamis webhely megnyitására készül</translation>
<translation id="2850739647070081192">Invite (boríték)</translation>
<translation id="2856444702002559011">A támadók megpróbálhatják ellopni a(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő adatait (például jelszavait, üzeneteit és hitelkártyaadatait). <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2859806420264540918">Ez a webhely tolakodó vagy félrevezető hirdetéseket jelenít meg.</translation>
<translation id="2878197950673342043">Kereszthajtás</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ablakelhelyezés</translation>
@@ -506,11 +517,11 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2996674880327704673">A Google javaslatai</translation>
<translation id="3002501248619246229">Bemeneti tálca hordozójának ellenőrzése</translation>
<translation id="3005723025932146533">Mentett másolat megjelenítése</translation>
-<translation id="3007719053326478567">Ennek a tartalomnak a nyomtatását letiltotta a rendszergazda</translation>
<translation id="3008447029300691911">Adja meg a(z) <ph name="CREDIT_CARD" /> kártya CVC-kódját. Az ellenőrzést követően a böngésző megosztja kártyaadatait ezzel a webhellyel.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />." listabejegyzés: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatikusan letiltva</translation>
<translation id="3016780570757425217">Az Ön tartózkodási helyének megismerése</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, a javaslat eltávolításához nyomja le a Tab, majd az Enter gombot.</translation>
<translation id="3023071826883856138">You4 (boríték)</translation>
<translation id="3024663005179499861">Nem megfelelő irányelvtípus</translation>
<translation id="3037605927509011580">A manóba!</translation>
@@ -551,6 +562,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3207960819495026254">Könyvjelző rögzítve</translation>
<translation id="3209034400446768650">Az oldal díjat számíthat fel</translation>
<translation id="3212581601480735796">Figyelik a(z) <ph name="HOSTNAME" /> webhelyen végzett tevékenységeit</translation>
+<translation id="3212623355668894776">Zárja be mindegyik Vendég ablakot, hogy böngészési tevékenységei törlődjenek az eszközről.</translation>
<translation id="3215092763954878852">Hiba történt a WebAuthn használata során</translation>
<translation id="3218181027817787318">Relatív</translation>
<translation id="3225919329040284222">A szerver tanúsítványa nem felel meg a beépített elvárásoknak. Ezek a beépített elvárások bizonyos nagy biztonságú webhelyekre vonatkoznak az Ön védelme érdekében.</translation>
@@ -698,6 +710,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3784372983762739446">Bluetooth-eszközök</translation>
<translation id="3787705759683870569">Lejárat dátuma: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Méret: 16</translation>
+<translation id="3789841737615482174">Telepítés</translation>
<translation id="3793574014653384240">A nemrégiben előfordult összeomlások száma és kiváltó okai</translation>
<translation id="3797522431967816232">Prc3 (boríték)</translation>
<translation id="3799805948399000906">Kért betűtípus</translation>
@@ -733,7 +746,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3962859241508114581">Előző szám</translation>
<translation id="3963721102035795474">Olvasási mód</translation>
<translation id="3963837677003247395">Folytatja manuálisan?</translation>
-<translation id="3964661563329879394">{COUNT,plural, =0{Nincs}=1{ 1 webhelytől }other{# webhelytől }}</translation>
+<translation id="3964661563329879394">{COUNT,plural, =0{Nincs}=1{ 1 webhelyről }other{# webhelyről }}</translation>
<translation id="397105322502079400">Számítás…</translation>
<translation id="3973234410852337861">A(z) <ph name="HOST_NAME" /> le van tiltva</translation>
<translation id="3987405730340719549">A Chrome azt észlelte, hogy ez a webhely hamis vagy megtévesztő szándékú lehet.
@@ -749,6 +762,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4056223980640387499">Szépia</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" kulcs: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (boríték)</translation>
+<translation id="4067669230157909013">Képernyőfelvétel készítése folytatva.</translation>
<translation id="4067947977115446013">Érvényes címet adjon meg</translation>
<translation id="4072486802667267160">Hiba történt a rendelés feldolgozása közben. Kérjük, próbálja újra.</translation>
<translation id="4075732493274867456">Az ügyfél és a szerver nem támogat ugyanolyan SSL-protokollverziót vagy rejtjelezési csomagot.</translation>
@@ -833,6 +847,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4297502707443874121">A(z) <ph name="THUMBNAIL_PAGE" /> oldal indexképe</translation>
<translation id="42981349822642051">Kibontás</translation>
<translation id="4300675098767811073">Több lyuk a jobb oldalon</translation>
+<translation id="4302514097724775343">A játékhoz koppintson a dinóra</translation>
<translation id="4302965934281694568">Chou3 (boríték)</translation>
<translation id="4305666528087210886">A fájlhoz nem sikerült hozzáférni</translation>
<translation id="4305817255990598646">Váltás</translation>
@@ -911,6 +926,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4658638640878098064">Kapocs balra fent</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuális valóság</translation>
+<translation id="4675657451653251260">Vendég módban a Chrome-profilok adatai nem láthatók. <ph name="LINK_BEGIN" />Bejelentkezés<ph name="LINK_END" /> után hozzáférhet Google-fiókja adataihoz (például a jelszavakhoz és a fizetési módokhoz).</translation>
<translation id="467662567472608290">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa hibákat tartalmaz. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="4677585247300749148">A(z) <ph name="URL" /> kisegítő lehetőségekkel kapcsolatos eseményekre szeretne válaszolni</translation>
<translation id="467809019005607715">Google Diák</translation>
@@ -938,6 +954,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4761104368405085019">Mikrofon használata</translation>
<translation id="4764776831041365478">A <ph name="URL" /> weboldal ideiglenesen nem érhető el, vagy véglegesen új címre költözött.</translation>
<translation id="4766713847338118463">Kettő kapocs alul</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ami megmarad ezen az eszközön:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />A fájlok, melyeket ebben az ablakban tölt le
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ismeretlen hiba történt.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Előugró ablak letiltva}other{# előugró ablak letiltva}}</translation>
<translation id="4780366598804516005">1. postaláda</translation>
@@ -1100,11 +1122,13 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5386426401304769735">A webhely tanúsítványlánca SHA-1 titkosítással aláírt tanúsítványt tartalmaz.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Éltűzés a jobb oldalon</translation>
+<translation id="5398772614898833570">Hirdetések letiltva</translation>
<translation id="5400836586163650660">Szürke</translation>
<translation id="540969355065856584">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa jelenleg nem érvényes. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolatát.</translation>
<translation id="541416427766103491">4. kötegelő</translation>
<translation id="5421136146218899937">Böngészési adatok törlése...</translation>
<translation id="5426179911063097041">A(z) <ph name="SITE" /> értesítéseket szeretne küldeni Önnek</translation>
+<translation id="542872847390508405">Vendégként böngészik</translation>
<translation id="5430298929874300616">Könyvjelző törlése</translation>
<translation id="5439770059721715174">Sémaérvényesítési hiba a következÅ‘nél: „<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Fordított sorrend, felfelé fordítva</translation>
@@ -1146,12 +1170,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5571083550517324815">Ezen a címen nem lehetséges az átvétel. Válasszon másik címet.</translation>
<translation id="5580958916614886209">Ellenőrizze a lejárati hónapot, majd próbálja újra</translation>
<translation id="5586446728396275693">Nincsenek mentett címek</translation>
+<translation id="5593349413089863479">A kapcsolat nem teljesen biztonságos</translation>
<translation id="5595485650161345191">Cím szerkesztése</translation>
<translation id="5598944008576757369">Fizetési mód kiválasztása</translation>
<translation id="560412284261940334">A kezelés nem támogatott</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Ez a webhely hamis vagy megtévesztő szándékú lehet. A Chrome a webhely azonnali elhagyását javasolja.</translation>
<translation id="5610142619324316209">A kapcsolat ellenőrzése</translation>
<translation id="5610807607761827392">A kártyákat és a címeket a <ph name="BEGIN_LINK" />Beállítások<ph name="END_LINK" /> menüpontban kezelheti.</translation>
<translation id="561165882404867731">Oldal fordítása a Google Fordítóval</translation>
@@ -1223,6 +1247,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5901630391730855834">Sárga</translation>
<translation id="5905445707201418379">Letiltva a(z) <ph name="ORIGIN" /> eredetházirendje miatt.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (szinkronizálva)</translation>
+<translation id="5913377024445952699">Képernyőrögzítés szüneteltetve</translation>
<translation id="59174027418879706">Engedélyezve</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Be</translation>
@@ -1235,6 +1260,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5963413905009737549">Szakasz</translation>
<translation id="5967592137238574583">Kapcsolattartási adatok szerkesztése</translation>
<translation id="5967867314010545767">Eltávolítás az előzmények közül</translation>
+<translation id="5968793460449681917">Minden látogatáskor</translation>
<translation id="5975083100439434680">Kicsinyítés</translation>
<translation id="5979084224081478209">Jelszavak ellenőrzése</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1390,6 +1416,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6587923378399804057">Vágólapra másolt link</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> eszköze nem áll felügyelet alatt</translation>
<translation id="6596325263575161958">Titkosítási lehetőségek</translation>
+<translation id="6596892391065203054">Ennek a tartalomnak a nyomtatását letiltotta a rendszergazda.</translation>
<translation id="6604181099783169992">Mozgás- és fényérzékelők</translation>
<translation id="6609880536175561541">Prc7 (boríték)</translation>
<translation id="6612358246767739896">Védett tartalom</translation>
@@ -1449,6 +1476,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6895330447102777224">Kártyáját ellenőriztük</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">Szervezet (O)</translation>
+<translation id="6907293445143367439">A következő engedélyezése a(z) <ph name="SITE_NAME" /> számára:</translation>
<translation id="6910240653697687763">A(z) <ph name="URL" /> webhely teljes hozzáférést kér a MIDI-eszközökhöz</translation>
<translation id="6915804003454593391">Felhasználó:</translation>
<translation id="6934672428414710184">Ez a név a Google-fiókjából származik</translation>
@@ -1560,6 +1588,7 @@ További részletek:
<translation id="7346048084945669753">Társult felhasználó:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Parancssor</translation>
+<translation id="7359588939039777303">Hirdetések letiltva.</translation>
<translation id="7372973238305370288">keresési találat</translation>
<translation id="7374733840632556089">A probléma oka az Ön vagy valaki más által az eszközre telepített egyik tanúsítvány. Erről a tanúsítványról tudni lehet, hogy hálózati forgalom megfigyelésére és elfogására használják, és a Chrome szerint nem megbízható. Bár a megfigyelésnek létezik néhány jogszerű formája (például iskolai vagy vállalati hálózatokon), a Chrome biztosra szeretne menni abban, hogy Ön ezzel tisztában van – még akkor is, ha Ön nem tud tenni ellene. A megfigyelés az internethez hozzáférő bármely böngészőben vagy alkalmazásban megtörténhet.</translation>
<translation id="7375818412732305729">Fájlcsatolás történt</translation>
@@ -1660,7 +1689,7 @@ További részletek:
<translation id="7673278391011283842">6. postaláda</translation>
<translation id="7676643023259824263">Vágólapon lévő szöveg keresése, <ph name="TEXT" /></translation>
<translation id="7682287625158474539">Szállítási cím</translation>
-<translation id="7687186412095877299">Kitölti a fizetési űrlapokat az Ön mentett fizetési módjaival</translation>
+<translation id="7687186412095877299">Kitölti a fizetési űrlapokat az Ön mentett fizetési adataival</translation>
<translation id="7687305263118037187">Újrapróbálkozás időtúllépése</translation>
<translation id="7693583928066320343">Fogadott oldalsorrend</translation>
<translation id="7697066736081121494">Prc8 (boríték)</translation>
@@ -1734,6 +1763,7 @@ További részletek:
<translation id="7976214039405368314">Túl sok kérelem</translation>
<translation id="7977538094055660992">Kimeneti eszköz</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">A kiterjesztett valósággal kapcsolatos tartalmak megtekintéséhez telepítse az ARCore-t</translation>
<translation id="799149739215780103">Kötés</translation>
<translation id="7995512525968007366">Nincs megadva</translation>
<translation id="800218591365569300">Próbáljon meg bezárni más lapokat vagy programokat memória felszabadítása céljából.</translation>
@@ -1861,25 +1891,39 @@ További részletek:
<translation id="8507227106804027148">Parancssor</translation>
<translation id="8508648098325802031">Keresés ikon</translation>
<translation id="8522552481199248698">A Chrome segíthet a Google-fiók védelmében és a jelszó módosításában.</translation>
+<translation id="8525306231823319788">Teljes képernyő</translation>
<translation id="8530813470445476232">A böngészési előzmények, a cookie-k, a gyorsítótár és egyebek törlése a Chrome-beállítások között</translation>
<translation id="8533619373899488139">A &lt;strong&gt;chrome://policy&lt;/strong&gt; oldalon láthatja a rendszergazda által letiltott URL-ek és a beállított egyéb kötelező irányelvek listáját.</translation>
<translation id="8541158209346794904">Bluetooth-eszköz</translation>
<translation id="8542014550340843547">Három kapocs alul</translation>
<translation id="8543181531796978784">Lehetősége van arra, hogy <ph name="BEGIN_ERROR_LINK" />jelentse az észlelési problémát<ph name="END_ERROR_LINK" />, ha pedig tisztában van a biztonságát fenyegető kockázatokkal, <ph name="BEGIN_LINK" />felkeresheti a nem biztonságos webhelyet<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">A CVC-kód a kártya hátulján található.</translation>
+<translation id="8558485628462305855">A kiterjesztett valósággal kapcsolatos tartalmak megtekintéséhez frissítse az ARCore-t</translation>
<translation id="8559762987265718583">Nem hozható létre privát kapcsolat a következővel: <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, mert az eszköz dátum- és időbeállítása helytelen (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Különálló dokumentumok/Nem szétválogatott másolatok</translation>
<translation id="8564985650692024650">A Chromium azt javasolja, hogy adjon meg új <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-jelszót a régi helyett, ha azt más webhelyeken is használta.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ami nem marad meg ezen az eszközön:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Az oldalak, melyeket ebben az ablakban nyit meg
+ <ph name="LIST_ITEM" />Sütik és webhelyadatok
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">A Touch ID használata a kártyák gyorsabb ellenőrzése érdekében</translation>
<translation id="858637041960032120">Szám hozzáadása
</translation>
<translation id="8589998999637048520">Legjobb minőség</translation>
+<translation id="8600271352425265729">Csak most</translation>
<translation id="860043288473659153">Kártyatulajdonos neve</translation>
<translation id="8606726445206553943">MIDI-eszközök használata</translation>
+<translation id="8612761427948161954">Üdvözöljük, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Jelenleg vendégként használja a böngészőt.</translation>
<translation id="861775596732816396">Méret: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nincs egyező jelszó. Az összes mentett jelszó megjelenítése.</translation>
<translation id="8625384913736129811">Kártya mentése az eszközre</translation>
+<translation id="8627040765059109009">Képernyőrögzítés folytatva</translation>
<translation id="8657078576661269990">A rendszergazda letiltotta a megosztást innen: <ph name="ORIGIN_NAME" /> ide: <ph name="VM_NAME_1" /> és <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Rendelés-összefoglaló, <ph name="TOTAL_LABEL" />, További részletek</translation>
<translation id="867224526087042813">Aláírás</translation>
@@ -1942,6 +1986,7 @@ További részletek:
<translation id="8912362522468806198">Google Fiókjába</translation>
<translation id="8913778647360618320">Fizetési módok kezelése gomb, nyomja meg az Enter billentyűt a fizetési és hitelkártyaadatoknak a Chrome beállításaiban való kezeléséhez</translation>
<translation id="8918231688545606538">Ez az oldal gyanús</translation>
+<translation id="8922013791253848639">Mindig engedélyezi a hirdetéseket ezen a webhelyen</translation>
<translation id="892588693504540538">Lyuk jobbra fent</translation>
<translation id="8931333241327730545">Menti ezt a kártyát a Google-fiókjába?</translation>
<translation id="8932102934695377596">Késik az órája</translation>
@@ -2013,6 +2058,7 @@ További részletek:
<translation id="9183302530794969518">Google Dokumentumok</translation>
<translation id="9183425211371246419">A(z) <ph name="HOST_NAME" /> egy nem támogatott protokollt használ.</translation>
<translation id="9191834167571392248">Lyuk balra lent</translation>
+<translation id="9199905725844810519">A nyomtatás le van tiltva</translation>
<translation id="9205078245616868884">Adatai az összetett szinkronizálási jelszavával vannak titkosítva. Adja meg a jelszót a szinkronizálás megkezdéséhez.</translation>
<translation id="9207861905230894330">A cikk hozzáadása sikertelen.</translation>
<translation id="9213433120051936369">Megjelenés személyre szabása</translation>
@@ -2023,8 +2069,10 @@ További részletek:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Elveszítheti a hozzáférést Google-fiókjához. A Chromium azt javasolja, hogy azonnal módosítsa jelszavát. Be kell majd jelentkeznie.</translation>
<translation id="939736085109172342">Új mappa</translation>
+<translation id="945522503751344254">Visszajelzés küldése</translation>
<translation id="945855313015696284">Ellenőrizze az alábbi adatokat, és törölje az érvénytelen kártyákat</translation>
<translation id="950736567201356821">Három lyuk felül</translation>
+<translation id="951941430552851965">A képernyőfelvételt szüneteltette a rendszergazda, mert bizalmas tartalom látható a képernyőn.</translation>
<translation id="961663415146723894">Kötés alul</translation>
<translation id="962484866189421427">Ez a tartalom megtévesztő alkalmazásokat telepíthet, amelyek más alkalmazásnak tettethetik magukat, illetve az Ön nyomon követésére alkalmas adatokat gyűjthetnek. <ph name="BEGIN_LINK" />Megjelenítés mindenképpen<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Hivatalos verzió</translation>
diff --git a/chromium/components/strings/components_strings_hy.xtb b/chromium/components/strings/components_strings_hy.xtb
index f7013e72118..7e0e6c09114 100644
--- a/chromium/components/strings/components_strings_hy.xtb
+++ b/chromium/components/strings/components_strings_hy.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ô´Õ¸Ö‚Ö„ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Õ¬ Õ¥Ö„ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨ Õ´Õ« Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´, Õ¸Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¯Õ¡Õ¦Õ´Õ¡Õ¯Õ¥Ö€ÕºÕ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¸Õ²Õ´Õ«Ö: ÕÕ¥Ö€ Õ°Õ¡Õ·Õ«Õ¾Õ¨ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ¥Õ¶Ö„ Õ¿Õ¡Õ¬Õ«Õ½ Õ¹Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¡ÕµÕ¤ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨ Õ¡ÕµÕ¬ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Ö‡ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´:</translation>
<translation id="1263231323834454256">Ô¸Õ¶Õ©Õ¥Ö€ÖÕ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÖÕ¡Õ¶Õ¯</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ¹Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ«Õ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ§Õ»Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¸Ö‚Õ´,
+ <ph name="LIST_ITEM" />Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨,
+ <ph name="LIST_ITEM" />Õ°Õ¡Õ·Õ¾Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ (<ph name="LINK_BEGIN" />Õ¤Õ¸Ö‚Ö€Õ½ Õ£Õ¡Õ¬<ph name="LINK_END" />)Ö‰
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ÕÕ¿Õ¡ÖÕ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¨</translation>
<translation id="1281476433249504884">Õ‡Õ¥Õ²Õ»Õ«Õ¹ 1</translation>
<translation id="1285320974508926690">ÔµÖ€Õ¢Õ¥Ö„ Õ¹Õ©Õ¡Ö€Õ£Õ´Õ¡Õ¶Õ¥Õ¬ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¨</translation>
@@ -93,7 +101,7 @@
<translation id="1314509827145471431">Ô±Õ´Ö€Õ¡Õ¯Õ¡Ö€ Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="1320233736580025032">Prc1 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="132301787627749051">ÕÕ¥Õ²Õ´Õ¡Õ¿Õ¡Õ­Õ¿Õ¡Õ¯Õ«Õ¶ ÕºÕ¡Õ°Õ¾Õ¡Õ® ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ« Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´</translation>
-<translation id="1323433172918577554">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« Õ·Õ¡Õ¿</translation>
+<translation id="1323433172918577554">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶</translation>
<translation id="132390688737681464">ÕŠÕ¡Õ°Õ¥Õ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¤Ö€Õ¡Õ¶ÖÕ¸Õ¾ Õ«Õ¶Ö„Õ¶Õ¡Õ¬Ö€Õ¡ÖÕ¶Õ¥Õ¬ Õ±Ö‡Õ¥Ö€Õ¨</translation>
<translation id="1330449323196174374">ÕÕ¡Õ­ Ö„Õ¡Õ¼Õ¸Ö€Õ¤Õ« Õ®Õ¡Õ¬Õ¸Ö‚Õ´</translation>
<translation id="1333989956347591814">ÕÕ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ <ph name="BEGIN_EMPHASIS" />Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¯Õ¬Õ«Õ¶Õ¥Õ¶<ph name="END_EMPHASIS" />`
@@ -137,7 +145,7 @@
<translation id="1462951478840426066">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ±Õ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ« Õ¿Õ¡Õ¼Õ¡Õ¿Õ¥Õ½Õ¡Õ¯Õ¶Õ¥Ö€Õ¨, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Õ¢Õ¡Ö€Õ±Ö€ Õ³Õ·Õ£Ö€Õ¿Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬</translation>
<translation id="1463543813647160932">5 x 7</translation>
<translation id="1467432559032391204">ÕÕ¡Õ­</translation>
-<translation id="1472675084647422956">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« Õ·Õ¡Õ¿</translation>
+<translation id="1472675084647422956">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶</translation>
<translation id="1473183651233018052">JIS B10</translation>
<translation id="147358896496811705">2A0</translation>
<translation id="1476595624592550506">Õ“Õ¸Õ­Õ¥Ö„ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨</translation>
@@ -249,7 +257,7 @@
<translation id="1871284979644508959">ÕŠÕ¡Ö€Õ¿Õ¡Õ¤Õ«Ö€ Õ¤Õ¡Õ·Õ¿</translation>
<translation id="1875512691959384712">Google ÕÖ‡Õ¡Õ©Õ²Õ©Õ¥Ö€</translation>
<translation id="187918866476621466">Ô²Õ¡ÖÕ¥Õ¬ Õ´Õ¥Õ¯Õ¶Õ¡Ö€Õ¯Õ« Õ§Õ»Õ¥Ö€Õ¨</translation>
-<translation id="1883255238294161206">Ô¿Õ¸Õ®Õ¯Õ¥Õ¬ ÖÕ¡Õ¶Õ¯Õ¨</translation>
+<translation id="1883255238294161206">Ô¾Õ¡Õ¬Õ¥Õ¬ ÖÕ¡Õ¶Õ¯Õ¨</translation>
<translation id="1898423065542865115">Ô¶Õ¿Õ¸Ö‚Õ´</translation>
<translation id="1901443836186977402">{1,plural, =1{Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ¯Õ¡Ö€Õ¸Õ²Õ¡ÖÕ¡Õ¾ Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ Õ¡ÕµÕ¶ Õ«Õ½Õ¯Õ¡ÕºÕ¥Õ½ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¶Õ¸Ö‚Õ´ Õ§ <ph name="DOMAIN" /> Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©Õ¨: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¡Õ¾Õ¡Õ½Õ¿Õ¡Õ£Ö€Õ« ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨ Õ¶Õ¡Õ­Õ¸Ö€Õ¤ Ö…Ö€Õ¨ Õ¬Ö€Õ¡ÖÕ¥Õ¬ Õ§: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ«Õ¶Õ¹ÕºÕ¥Õ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨, Õ¡ÕµÕ¶ÕºÕ¥Õ½ Õ§Õ¬ Õ±Õ¥Ö€ Ö‡ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ´Õ«Õ»Ö‡ Õ¯Õ¡ÕºÕ¸Ö‚Õ²Õ¸Ö‚ Õ¾Ö€Õ¡ Õ°Õ¡Ö„Õ¥Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¸Ö‚Õ´Õ¶ Ö‡ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¬Õ½Õ¸Ö‚Õ´Õ¨: ÕÕ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ« ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¶ Õ¡ÕµÕ½ ÕºÕ¡Õ°Õ«Õ¶ ÖÕ¸Ö‚ÕµÖ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ <ph name="CURRENT_DATE" />: ÕÕ¡ Õ³Õ«ÕžÕ·Õ¿ ÕªÕ¡Õ´Õ¶ Õ§Ö‰ ÔµÕ©Õ¥ Õ¸Õ¹, Õ¸Ö‚Õ²Õ²Õ¥Ö„ Õ¡ÕµÕ¶ Ö‡ Õ©Õ¡Ö€Õ´Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ½ Õ§Õ»Õ¨:}one{Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ¯Õ¡Ö€Õ¸Õ²Õ¡ÖÕ¡Õ¾ Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ Õ¡ÕµÕ¶ Õ«Õ½Õ¯Õ¡ÕºÕ¥Õ½ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¶Õ¸Ö‚Õ´ Õ§ <ph name="DOMAIN" /> Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©Õ¨: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¡Õ¾Õ¡Õ½Õ¿Õ¡Õ£Ö€Õ« ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨ # Ö…Ö€ Õ¡Õ¼Õ¡Õ» Õ½ÕºÕ¡Õ¼Õ¾Õ¥Õ¬ Õ§: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ«Õ¶Õ¹ÕºÕ¥Õ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨, Õ¡ÕµÕ¶ÕºÕ¥Õ½ Õ§Õ¬ Õ±Õ¥Ö€ Ö‡ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ´Õ«Õ»Ö‡ Õ¯Õ¡ÕºÕ¸Ö‚Õ²Õ¸Ö‚ Õ¾Ö€Õ¡ Õ°Õ¡Ö„Õ¥Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¸Ö‚Õ´Õ¶ Ö‡ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¬Õ½Õ¸Ö‚Õ´Õ¨: ÕÕ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ« ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ Õ¡ÕµÕ½ ÕºÕ¡Õ°Õ«Õ¶ ÖÕ¸Ö‚ÕµÖ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ <ph name="CURRENT_DATE" />: ÕÕ¡ Õ³Õ«ÕžÕ·Õ¿ ÕªÕ¡Õ´Õ¶ Õ§: ÔµÕ©Õ¥ Õ¸Õ¹, Õ¸Ö‚Õ²Õ²Õ¥Ö„ Õ¡ÕµÕ¶ Ö‡ Õ©Õ¡Ö€Õ´Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ½ Õ§Õ»Õ¨:}other{Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ¯Õ¡Ö€Õ¸Õ²Õ¡ÖÕ¡Õ¾ Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ Õ¡ÕµÕ¶ Õ«Õ½Õ¯Õ¡ÕºÕ¥Õ½ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¶Õ¸Ö‚Õ´ Õ§ <ph name="DOMAIN" /> Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©Õ¨: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¡Õ¾Õ¡Õ½Õ¿Õ¡Õ£Ö€Õ« ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨ # Ö…Ö€ Õ¡Õ¼Õ¡Õ» Õ½ÕºÕ¡Õ¼Õ¾Õ¥Õ¬ Õ§: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ«Õ¶Õ¹ÕºÕ¥Õ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨, Õ¡ÕµÕ¶ÕºÕ¥Õ½ Õ§Õ¬ Õ±Õ¥Ö€ Ö‡ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ´Õ«Õ»Ö‡ Õ¯Õ¡ÕºÕ¸Ö‚Õ²Õ¸Ö‚ Õ¾Ö€Õ¡ Õ°Õ¡Ö„Õ¥Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¸Ö‚Õ´Õ¶ Ö‡ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¬Õ½Õ¸Ö‚Õ´Õ¨: ÕÕ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ« ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ Õ¡ÕµÕ½ ÕºÕ¡Õ°Õ«Õ¶ ÖÕ¸Ö‚ÕµÖ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ <ph name="CURRENT_DATE" />: ÕÕ¡ Õ³Õ«ÕžÕ·Õ¿ ÕªÕ¡Õ´Õ¶ Õ§: ÔµÕ©Õ¥ Õ¸Õ¹, Õ¸Ö‚Õ²Õ²Õ¥Ö„ Õ¡ÕµÕ¶ Ö‡ Õ©Õ¡Ö€Õ´Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ½ Õ§Õ»Õ¨:}}</translation>
<translation id="1902576642799138955">ÕŽÕ¡Õ¾Õ¥Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÕªÕ¡Õ´Õ¯Õ¥Õ¿</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Õ„Õ¸Ö‚Õ¿Ö„ Õ£Õ¸Ö€Õ®Õ¥Ö„Õ Google Õ°Õ¡Õ·Õ¾Õ¸Ö‚Õ´ ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> Õ¬Õ¥Õ¦Õ¾Õ¸Õ¾ Õ§Õ»Õ¥Ö€Õ¨ Õ¹Õ¥Õ¶ Õ©Õ¡Ö€Õ£Õ´Õ¡Õ¶Õ¾Õ«:</translation>
<translation id="2053553514270667976">Õ“Õ¸Õ½Õ¿Õ¡ÕµÕ«Õ¶ Õ¤Õ¡Õ½Õ«Õ¹</translation>
+<translation id="2054665754582400095">ÕÕ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ±Õ¥Ö€ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯}one{# suggestions}other{# Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯}}</translation>
<translation id="2079545284768500474">Õ€Õ¥Õ¿Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="20817612488360358">Õ€Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ« ÕºÖ€Õ¸Ö„Õ½Õ«-Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡ÕµÕ¾Õ¡Õ® Õ¥Õ¶, Õ¢Õ¡ÕµÖ Õ¶Õ¡Ö‡ Õ¶Õ·Õ¾Õ¡Õ® Õ§ Õ¶Ö€Õ¡ Õ¸Ö‚Õ²Õ²Õ¡Õ¯Õ« Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´:</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€</translation>
<translation id="2107021941795971877">ÕÕºÕ´Õ¡Õ¶ Õ¡Õ»Õ¡Õ¯ÖÕ¸Ö‚Õ´</translation>
<translation id="2108755909498034140">ÕŽÕ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Ö„ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ«Õ¹Õ¨</translation>
+<translation id="2111166930115883695">Õ†Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Õ¢Õ¡ÖÕ¡Õ¿Õ« Õ½Õ¿Õ¥Õ²Õ¶Õ¨</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Õ”Õ¡Ö€Õ¿</translation>
<translation id="2114841414352855701">Ô±Õ¶Õ¿Õ¥Õ½Õ¾Õ¸Ö‚Õ´ Õ§, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ£Õ¥Ö€Õ¡Õ¯Õ¡ÕµÕ¸Ö‚Õ´ Õ§ <ph name="POLICY_NAME" /> Õ¯Õ¡Õ¶Õ¸Õ¶Õ¨:</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Õ‰Õ¥Õ²Õ¡Ö€Õ¯Õ¥Õ¬ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´Õ¨</translation>
<translation id="2147827593068025794">Õ–Õ¸Õ¶Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚Õ´</translation>
<translation id="2148613324460538318">Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Ö„Õ¡Ö€Õ¿</translation>
+<translation id="2149968176347646218">Ô¿Õ¡ÕºÕ¨ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="2154054054215849342">Õ€Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚Õ´Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¹Õ§ Õ±Õ¥Ö€ Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©Õ« Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="2154484045852737596">Õ”Õ¡Ö€Õ¿Õ« ÖƒÕ¸ÖƒÕ¸Õ­Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="2161656808144014275">ÕÕ¥Ö„Õ½Õ¿</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Ô¿Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€</translation>
<translation id="2183608646556468874">Õ€Õ¥Õ¼Õ¡Õ­Õ¸Õ½Õ¡Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 Õ°Õ¡Õ½ÖÕ¥}one{# addresses}other{# Õ°Õ¡Õ½ÖÕ¥}}</translation>
-<translation id="2187243482123994665">Õ•Õ£Õ¿Õ¡Õ¿Õ«Ö€Õ¸Õ» Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="2187317261103489799">ÕˆÖ€Õ¸Õ·Õ¥Õ¬ (Õ¯Õ¡Õ¶Õ­Õ¡Õ¤Ö€Õ¾Õ¡Õ®)</translation>
<translation id="2188375229972301266">Õ„Õ« Ö„Õ¡Õ¶Õ« Õ¡Õ¶ÖÖ„ Õ¶Õ¥Ö€Ö„Ö‡Õ¸Ö‚Õ´</translation>
<translation id="2202020181578195191">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ« Õ½ÕºÕ¡Õ¼Õ´Õ¡Õ¶ Õ¾Õ¡Õ¾Õ¥Ö€ Õ¿Õ¡Ö€Õ¥Õ©Õ«Õ¾</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Ô¿Õ¡ÕµÖ„Õ¨, Õ¸Ö€Õ¨ ÕºÕ¡Õ¿Ö€Õ¡Õ½Õ¿Õ¾Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÖÕ¥Õ¬Õ¥Õ¬, Õ¯Õ¥Õ²Õ® Õ§</translation>
<translation id="2850739647070081192">Invite (Õ®Ö€Õ¡Ö€)</translation>
<translation id="2856444702002559011">Õ€Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ£Õ¸Õ²Õ¡Õ¶Õ¡Õ¬ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ (Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨, Õ¶Õ¡Õ´Õ¡Õ¯Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ¾Õ¡Ö€Õ¯Õ¡ÕµÕ«Õ¶ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¨) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Õ¯Õ¡ÕµÖ„Õ«ÖÖ‰ <ph name="BEGIN_LEARN_MORE_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¨ Õ°Õ¸Õ£Õ¶Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ Õ§ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´Ö‰</translation>
<translation id="2878197950673342043">Ô¿Ö€Õ¯Õ¶Õ¡Õ¯Õ« Õ¸Ö‚Õ²Õ²Õ¡Õ±Õ«Õ£ Õ®Õ¡Õ¬Õ¸Ö‚Õ´</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ÕŠÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€Õ« Õ¿Õ¥Õ²Õ¡Õ¯Õ¡ÕµÕ¸Ö‚Õ´</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Ô±Õ¼Õ¡Õ»Õ¡Ö€Õ¯Õ¶Õ¥Ö€ Google-Õ«Ö</translation>
<translation id="3002501248619246229">ÕÕ¿Õ¸Ö‚Õ£Õ¥Õ¬ Õ´Õ¸Ö‚Õ¿Ö„Õ¡ÕµÕ«Õ¶ Õ¤Õ¡Ö€Õ¡Õ¯Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3005723025932146533">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ ÕºÕ¡Õ°Õ¾Õ¡Õ® ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¨</translation>
-<translation id="3007719053326478567">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¹Õ« Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ¡ÕµÕ½ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¿ÕºÕ¸Ö‚Õ´Õ¨</translation>
<translation id="3008447029300691911">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ <ph name="CREDIT_CARD" /> Ö„Õ¡Ö€Õ¿Õ« CVC Õ¯Õ¸Õ¤Õ¨: Õ€Õ¥Õ¶Ö Õ¸Ö€ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¥Ö„, Õ±Õ¥Ö€ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Õ¯Õ¿Ö€Õ¡Õ´Õ¡Õ¤Ö€Õ¾Õ¥Õ¶ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ«Õ¶:</translation>
<translation id="3010559122411665027">Õ‘Õ¡Õ¶Õ¯Õ« Õ´Õ«Õ¡Õ¾Õ¸Ö€ «<ph name="ENTRY_INDEX" />Â»Õ <ph name="ERROR" /></translation>
<translation id="301521992641321250">Ô±Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§</translation>
<translation id="3016780570757425217">Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />Ö‰ Ô±Õ¼Õ¡Õ»Õ¡Ö€Õ¯Õ¨ Õ°Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="3023071826883856138">You4 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="3024663005179499861">Ô¿Õ¡Õ¶Õ¸Õ¶Õ« Õ¿Õ¥Õ½Õ¡Õ¯Õ¨ Õ½Õ­Õ¡Õ¬ Õ§</translation>
<translation id="3037605927509011580">ÕŽÕ¡Õ›Õµ</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">Ô·Õ»Õ¡Õ¶Õ·Õ¾Õ¡Õ® Õ§</translation>
<translation id="3209034400446768650">Ô±ÕµÕ½ Õ§Õ»Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ£Õ¸Ö‚Õ´Õ¡Ö€ Õ£Õ¡Õ¶Õ±Õ¥Õ¬ Õ±Õ¥Õ¦Õ¶Õ«Ö</translation>
<translation id="3212581601480735796">ÕÕ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ <ph name="HOSTNAME" /> Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¾Õ¸Ö‚Õ´ Õ¥Õ¶</translation>
+<translation id="3212623355668894776">Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ«Ö Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´ Õ¡Ö€Õ¾Õ¡Õ® Õ±Õ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ»Õ¶Õ»Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ ÖƒÕ¡Õ¯Õ¥Ö„ Õ°ÕµÕ¸Ö‚Ö€Õ« Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¢Õ¡ÖÕ¾Õ¡Õ® Õ¢Õ¸Õ¬Õ¸Ö€ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€Õ¨Ö‰</translation>
<translation id="3215092763954878852">Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ WebAuthn-Õ¨</translation>
<translation id="3218181027817787318">Õ€Õ¡Ö€Õ¡Õ¢Õ¥Ö€Õ¡Õ¯Õ¡Õ¶</translation>
<translation id="3225919329040284222">ÕÕ¥Ö€Õ¾Õ¥Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¾Õ¡Õ® Õ¾Õ¯Õ¡ÕµÕ¡Õ£Õ«Ö€Õ¨ Õ¹Õ« Õ°Õ¡Õ´Õ¡ÕºÕ¡Õ¿Õ¡Õ½Õ­Õ¡Õ¶Õ¸Ö‚Õ´ Õ¶Õ¥Ö€Õ¯Õ¡Õ¼Õ¸Ö‚ÖÕ¾Õ¡Õ® Õ°Õ¡Ö€Õ¡Õ¹Õ¡ÖƒÕ¥Ö€Õ«Õ¶: Ô±ÕµÕ½ Õ°Õ¡Ö€Õ¡Õ¹Õ¡ÖƒÕ¥Ö€Õ¨ Õ±Õ¥Õ¦ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬Õ¸Ö‚ Õ¶ÕºÕ¡Õ¿Õ¡Õ¯Õ¸Õ¾ Õ¶Õ¥Ö€Õ¡Õ¼Õ¾Õ¡Õ® Õ¥Õ¶ Õ¢Õ¡Ö€Õ±Ö€ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¸Ö€Õ¸Õ·Õ¡Õ¯Õ« Õ¾Õ¥Õ¢Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€:</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">Bluetooth Õ½Õ¡Ö€Ö„Õ¥Ö€</translation>
<translation id="3787705759683870569">ÕÕºÕ¡Õ¼Õ´Õ¡Õ¶ ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨Õ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Õ‰Õ¡Öƒ 16</translation>
+<translation id="3789841737615482174">ÕÕ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬</translation>
<translation id="3793574014653384240">ÕŽÕ¥Ö€Õ»Õ¥Ö€Õ½ Õ£Ö€Õ¡Õ¶ÖÕ¾Õ¡Õ® Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ©Õ«Õ¾Õ¶ Õ¸Ö‚ ÕºÕ¡Õ¿Õ³Õ¡Õ¼Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3797522431967816232">Prc3 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="3799805948399000906">ÕÕ¡Õ¼Õ¡Õ¿Õ¥Õ½Õ¡Õ¯Õ« Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¶ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¾Õ¥Õ¬ Õ§</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">ÕÕ¥ÕºÕ«Õ¡</translation>
<translation id="4058922952496707368">Ô²Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ «<ph name="SUBKEY" />Â»Õ <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Õ®Ö€Õ¡Ö€)</translation>
+<translation id="4067669230157909013">Ô·Õ¯Ö€Õ¡Õ¶Õ« Õ¬Õ¸Ö‚Õ½Õ¡Õ¶Õ¯Õ¡Ö€Õ´Õ¡Õ¶ Õ£Õ¸Ö€Õ®Õ¡Õ¼Õ¸Ö‚ÕµÕ©Õ¨ Õ¾Õ¥Ö€Õ¡Õ¯Õ¡Õ¶Õ£Õ¶Õ¾Õ¥ÖÖ‰</translation>
<translation id="4067947977115446013">Ô±Õ¾Õ¥Õ¬Õ¡ÖÖ€Õ¥Ö„ Õ¾Õ¡Õ¾Õ¥Ö€ Õ°Õ¡Õ½ÖÕ¥</translation>
<translation id="4072486802667267160">ÕŽÕ³Õ¡Ö€Õ¸Ö‚Õ´Õ¨ Õ´Õ·Õ¡Õ¯Õ¥Õ¬Õ¸Ö‚ Õ¨Õ¶Õ©Õ¡ÖÖ„Õ¸Ö‚Õ´ Õ½Õ­Õ¡Õ¬ Õ¡Õ¼Õ¡Õ»Õ¡ÖÕ¡Õ¾: Õ†Õ¸Ö€Õ«Ö ÖƒÕ¸Ö€Õ±Õ¥Ö„:</translation>
<translation id="4075732493274867456">ÕÕºÕ¡Õ½Õ¡Õ¼Õ¸Ö‚Õ¶ Ö‡ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ¥Õ¶ Õ¡Õ»Õ¡Õ¯ÖÕ¸Ö‚Õ´ SSL Õ°Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ¯Õ¡Ö€Õ£Õ« Õ´Õ«Ö‡Õ¶Õ¸Ö‚ÕµÕ¶ Õ¿Õ¡Ö€Õ¢Õ¥Ö€Õ¡Õ¯Õ¨ Õ¯Õ¡Õ´ Õ®Õ¡Õ®Õ¯Õ¡Õ£Ö€Õ´Õ¡Õ¶ Õ¬Ö€Õ¡Õ¯Õ¡Õ¦Õ´Õ¨:</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">Ô·Õ» <ph name="THUMBNAIL_PAGE" />-Õ« Õ´Õ¡Õ¶Ö€Õ¡ÕºÕ¡Õ¿Õ¯Õ¥Ö€</translation>
<translation id="42981349822642051">Ô¸Õ¶Õ¤Õ¡Ö€Õ±Õ¡Õ¯Õ¥Õ¬</translation>
<translation id="4300675098767811073">Õ„Õ« Ö„Õ¡Õ¶Õ« Õ¡Õ¶ÖÖ„ Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
+<translation id="4302514097724775343">Ô½Õ¡Õ²Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Õ¤Õ«Õ¶Õ¸Õ¦Õ¡Õ¾Ö€Õ« Õ¾Ö€Õ¡</translation>
<translation id="4302965934281694568">Chou3 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="4305666528087210886">Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ¢Õ¡ÖÕ¥Õ¬ Ö†Õ¡ÕµÕ¬Õ¨</translation>
<translation id="4305817255990598646">Õ“Õ¸Õ­Õ¡Ö€Õ¯Õ¥Õ¬</translation>
@@ -915,6 +930,7 @@
<translation id="4658638640878098064">Ô±Õ´Ö€Õ¡Õ¯ Õ¾Õ¥Ö€Ö‡Õ« Õ±Õ¡Õ­ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ÕŽÕ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
+<translation id="4675657451653251260">Õ€ÕµÕ¸Ö‚Ö€Õ« Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¤Õ¸Ö‚Ö„ Õ¹Õ¥Ö„ Õ¿Õ¥Õ½Õ¶Õ« Chrome-Õ« ÕºÖ€Õ¸Ö†Õ«Õ¬Õ« Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰ <ph name="LINK_BEGIN" />Õ„Õ¸Ö‚Õ¿Ö„ Õ£Õ¸Ö€Õ®Õ¥Ö„<ph name="LINK_END" />Õ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¾Õ³Õ¡Ö€Õ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¶Õ¥Ö€Õ¨ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
<translation id="467662567472608290">Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ <ph name="DOMAIN" /> Õ§: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Õ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶Õ¨ Õ½Õ­Õ¡Õ¬Õ¶Õ¥Ö€ Õ§ ÕºÕ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¸Ö‚Õ´: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö:</translation>
<translation id="4677585247300749148"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ°Õ¡Õ¿Õ¸Ö‚Õ¯ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="467809019005607715">Google ÕÕ¬Õ¡ÕµÕ¤Õ¶Õ¥Ö€</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨</translation>
<translation id="4764776831041365478">Õ€Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ§, <ph name="URL" />-Õ« Õ¾Õ¥Õ¢Õ§Õ»Õ¨ ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯Õ¡Õ¾Õ¸Ö€Õ¡ÕºÕ¥Õ½ Õ®Õ¡Õ¶Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¾Õ¡Õ® Õ§ Õ¯Õ¡Õ´ Õ´Õ·Õ¿Õ¡ÕºÕ¥Õ½ Õ¿Õ¥Õ²Õ¡ÖƒÕ¸Õ­Õ¾Õ¥Õ¬ Õ§ Õ¶Õ¸Ö€ Õ°Õ¡Õ½ÖÕ¥Õ¸Õ¾:</translation>
<translation id="4766713847338118463">ÔµÖ€Õ¯Õ¸Ö‚ Õ¡Õ´Ö€Õ¡Õ¯ Õ¶Õ¥Ö€Ö„Ö‡Õ¸Ö‚Õ´</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ¯ÕºÕ¡Õ°Õ¾Õ¥Õ¶Õ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ö†Õ¡ÕµÕ¬Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¸Ö‚Õ´Ö‰
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ô±Õ¶Õ°Õ¡ÕµÕ¿ Õ½Õ­Õ¡Õ¬ Õ§ Õ¿Õ¥Õ²Õ« Õ¸Ö‚Õ¶Õ¥ÖÕ¥Õ¬:</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ÔµÕ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§}one{# Õ¥Õ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§}other{# Õ¥Õ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§}}</translation>
<translation id="4780366598804516005">Õ“Õ¸Õ½Õ¿Õ¡Ö€Õ¯Õ² 1</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ« Õ¾Õ¯Õ¡ÕµÕ¡Õ£Ö€Õ¥Ö€Õ« Õ·Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ¡Õ¼Õ¯Õ¡ Õ§ Õ´Õ¥Õ¯ Õ¾Õ¯Õ¡ÕµÕ¡Õ£Õ«Ö€` SHA-1 Õ½Õ¿Õ¸Ö€Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢:</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Ô±Õ» Õ¥Õ¦Ö€Õ¡Õ¯Õ¡Ö€</translation>
+<translation id="5398772614898833570">Ô³Õ¸Õ¾Õ¡Õ¦Õ¤Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§</translation>
<translation id="5400836586163650660">Õ„Õ¸Õ­Ö€Õ¡Õ£Õ¸Ö‚ÕµÕ¶</translation>
<translation id="540969355065856584">Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ <ph name="DOMAIN" /> Õ§: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Õ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶Õ¶ Õ¡ÕµÕ½ Õ¡Õ¶Õ£Õ¡Õ´ Õ¾Õ¡Õ¾Õ¥Ö€ Õ¹Õ§: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö:</translation>
<translation id="541416427766103491">Õ‡Õ¥Õ²Õ»Õ«Õ¹ 4</translation>
<translation id="5421136146218899937">Մաքրել դիտարկումների տվյալները…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Õ¦ Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬</translation>
+<translation id="542872847390508405">Ô´Õ¸Ö‚Ö„ Õ´Õ¿Õ¥Õ¬ Õ¥Ö„ Õ°ÕµÕ¸Ö‚Ö€Õ« Õ¼Õ¥ÕªÕ«Õ´</translation>
<translation id="5430298929874300616">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬ Õ§Õ»Õ¡Õ¶Õ«Õ·Õ¨</translation>
<translation id="5439770059721715174">ÕÕ­Õ¥Õ´Õ¡ÕµÕ« Õ½Õ¿Õ¸Ö‚Õ£Õ´Õ¡Õ¶ Õ½Õ­Õ¡Õ¬ «<ph name="ERROR_PATH" />»-Õ¸Ö‚Õ´` <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Õ€Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ Õ°Õ¥Ö€Õ©Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢Õ Õ¥Ö€Õ¥Õ½Õ« Õ¯Õ¸Õ²Õ´Õ¸Õ¾ Õ¾Õ¥Ö€Ö‡</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">ÕÕ¾ÕµÕ¡Õ¬ Õ°Õ¡Õ½ÖÕ¥Õ«Ö Õ¡Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ¨Õ¶Õ¤Õ¸Ö‚Õ¶Õ¸Ö‚Õ´ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§: Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡ÕµÕ¬ Õ°Õ¡Õ½ÖÕ¥:</translation>
<translation id="5580958916614886209">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ½ÕºÕ¡Õ¼Õ´Õ¡Õ¶ Õ¡Õ´Õ«Õ½Õ¨ Ö‡ Õ¶Õ¸Ö€Õ«Ö ÖƒÕ¸Ö€Õ±Õ¥Ö„</translation>
<translation id="5586446728396275693">ÕŠÕ¡Õ°Õ¾Õ¡Õ® Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€ Õ¹Õ¯Õ¡Õ¶</translation>
+<translation id="5593349413089863479">Ô¿Õ¡ÕºÕ¨ Õ¬Õ«Õ¸Õ¾Õ«Õ¶ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="5595485650161345191">Õ“Õ¸Õ­Õ¥Õ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="5598944008576757369">Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¾Õ³Õ¡Ö€Õ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¨</translation>
<translation id="560412284261940334">ÕÕ¡Ö€Ö„Õ¥Ö€Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¸Ö‚Õ´Õ¨ Õ¹Õ« Õ¡Õ»Õ¡Õ¯ÖÕ¾Õ¸Ö‚Õ´</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ÕÕ¡ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¯Õ¥Õ²Õ® Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡ÕµÖ„ Õ¬Õ«Õ¶Õ¥Õ¬: Chrome-Õ¨ Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ Õ¡Õ¶Õ´Õ«Õ»Õ¡ÕºÕ¥Õ½ ÖƒÕ¡Õ¯Õ¥Õ¬ Õ¡ÕµÕ¶:</translation>
<translation id="5610142619324316209">ÕÕ¿Õ¸Ö‚Õ£Õ¥Õ¬ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´Õ¨</translation>
<translation id="5610807607761827392">Õ”Õ¡Ö€Õ¿Õ¥Ö€Õ¶ Õ¸Ö‚ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ <ph name="BEGIN_LINK" />Ô¿Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />:</translation>
<translation id="561165882404867731">Ô¹Õ¡Ö€Õ£Õ´Õ¡Õ¶Õ¥Ö„ Õ¡ÕµÕ½ Õ§Õ»Õ¨ Google Translate-Õ« Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">Ô´Õ¥Õ²Õ«Õ¶</translation>
<translation id="5905445707201418379">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Õ Õ°Õ¡Õ´Õ¡Õ±Õ¡ÕµÕ¶ <ph name="ORIGIN" />-Õ« Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¡Õ¶Õ¸Õ¶Õ«:</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Õ°Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¾Õ¡Õ®)</translation>
+<translation id="5913377024445952699">Ô·Õ¯Ö€Õ¡Õ¶Õ« Õ¿Õ¥Õ½Õ¡Õ£Ö€Õ¸Ö‚Õ´Õ¨ Õ¤Õ¡Õ¤Õ¡Ö€Õ¥ÖÕ¾Õ¡Õ® Õ§</translation>
<translation id="59174027418879706">Õ„Õ«Õ¡ÖÕ¾Õ¡Õ®</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Õ„Õ«Õ¡Ö</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">Õ€Õ¡Õ¿Õ¾Õ¡Õ®</translation>
<translation id="5967592137238574583">Õ“Õ¸ÖƒÕ¸Õ­Õ¥Ö„ Õ¯Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¡ÕµÕ«Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
<translation id="5967867314010545767">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬ ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ«Ö</translation>
+<translation id="5968793460449681917">Ô±Õ´Õ¥Õ¶ Õ¡ÕµÖÕ« ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯</translation>
<translation id="5975083100439434680">Õ“Õ¸Ö„Ö€Õ¡ÖÕ¶Õ¥Õ¬</translation>
<translation id="5979084224081478209">ÕÕ¿Õ¸Ö‚Õ£Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">ÕÕ¥Ö€ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¡Õ® Õ°Õ²Õ¸Ö‚Õ´Õ¨</translation>
<translation id="6591833882275308647">ÕÕ¥Ö€ <ph name="DEVICE_TYPE" /> Õ½Õ¡Ö€Ö„Õ¨ Õ¹Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Ö‚Õ´</translation>
<translation id="6596325263575161958">Ô³Õ¡Õ²Õ¿Õ¶Õ¡Õ£Ö€Õ´Õ¡Õ¶ Õ¨Õ¶Õ¿Ö€Õ¡Õ¶Ö„Õ¶Õ¥Ö€</translation>
+<translation id="6596892391065203054">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ§ Õ¡ÕµÕ½ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¿ÕºÕ¸Ö‚Õ´Õ¨Ö‰</translation>
<translation id="6604181099783169992">Õ‡Õ¡Ö€ÕªÕ´Õ¡Õ¶ Ö‡ Õ¬Õ¸Ö‚Õ½Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€</translation>
<translation id="6609880536175561541">Prc7 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="6612358246767739896">ÕŠÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">ÕÕ¥Ö€ Ö„Õ¡Ö€Õ¿Õ¨ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¾Õ¡Õ® Õ§</translation>
<translation id="6897140037006041989">Õ•Õ£Õ¿Õ¡Õ¿Õ«Ö€Õ¸Õ» Õ£Õ¸Ö€Õ®Õ¡Õ¯Õ¡Õ¬</translation>
<translation id="6898699227549475383">Ô¿Õ¡Õ¦Õ´Õ¡Õ¯Õ¥Ö€ÕºÕ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ (O)</translation>
+<translation id="6907293445143367439">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¿Õ¡Õ¬ <ph name="SITE_NAME" /> Õ¯Õ¡ÕµÖ„Õ«Õ¶Õ</translation>
<translation id="6910240653697687763"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ¡Õ´Õ¢Õ¸Õ²Õ»Õ¸Õ¾Õ«Õ¶ Õ¾Õ¥Ö€Õ¡Õ°Õ½Õ¯Õ¥Õ¬ Õ±Õ¥Ö€ MIDI Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¨</translation>
<translation id="6915804003454593391">Õ•Õ£Õ¿Õ¡Õ¿Õ¥Ö€`</translation>
<translation id="6934672428414710184">Ô±ÕµÕ½ Õ¡Õ¶Õ¸Ö‚Õ¶Õ¨ Õ¾Õ¥Ö€ÖÕ¾Õ¡Õ® Õ§ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ¾Õ«Ö</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">Õ“Õ¸Õ­Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¾Õ¡Õ® Õ§Õ</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Õ€Ö€Õ¡Õ´Õ¡Õ¶Õ¡Õ¿Õ¸Õ²</translation>
+<translation id="7359588939039777303">Ô³Õ¸Õ¾Õ¡Õ¦Õ¤Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Ö‰</translation>
<translation id="7372973238305370288">Õ¸Ö€Õ¸Õ¶Õ´Õ¡Õ¶ Õ¡Ö€Õ¤ÕµÕ¸Ö‚Õ¶Ö„</translation>
<translation id="7374733840632556089">Ô±ÕµÕ½ Õ­Õ¶Õ¤Õ«Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¡Õ¼Õ¡Õ»Õ¡Õ¶Õ¡Õ¬ Õ°Õ¡Õ¾Õ¡Õ½Õ¿Õ¡Õ£Ö€Õ« ÕºÕ¡Õ¿Õ³Õ¡Õ¼Õ¸Õ¾, Õ¸Ö€Õ¨ Õ¤Õ¸Ö‚Ö„ Õ¯Õ¡Õ´ Õ«Õ¶Õ¹-Õ¸Ö€ Õ´Õ¥Õ¯Õ¨ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬ Õ¥Ö„ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´Ö‰ Õ€Õ¡Õ¾Õ¡Õ½Õ¿Õ¡Õ£Õ«Ö€Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Ö‚Õ´ Õ§ ÖÕ¡Õ¶ÖÕ¥Ö€ Õ¸Ö€Õ½Õ¡Õ¬Õ¸Ö‚ Õ¸Ö‚ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬Õ¸Ö‚ Õ¶ÕºÕ¡Õ¿Õ¡Õ¯Õ¸Õ¾Ö‰ Ô±ÕµÕ¶ Õ¾Õ½Õ¿Õ¡Õ°Õ¥Õ¬Õ« Õ¹Õ§ Chrome-Õ« Õ°Õ¡Õ´Õ¡Ö€Ö‰ Ô¹Õ¥Ö‡ Õ¬Õ«Õ¶Õ¸Ö‚Õ´ Õ¥Õ¶ Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ¡Õ¶ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ´Õ¡Õ¶ Õ¤Õ¥ÕºÖ„Õ¥Ö€, Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ Õ¤ÕºÖ€Õ¸ÖÕ« Õ¯Õ¡Õ´ Õ¨Õ¶Õ¯Õ¥Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÖÕ¡Õ¶ÖÕ¸Ö‚Õ´, Chrome-Õ«Õ¶ Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ°Õ¡Õ´Õ¸Õ¦Õ¾Õ¥Õ¬, Õ¸Ö€ Õ¤Õ¸Ö‚Ö„ Õ£Õ«Õ¿Õ¥Ö„ Õ¡ÕµÕ¤ Õ´Õ¡Õ½Õ«Õ¶, Õ¶Õ¸Ö‚ÕµÕ¶Õ«Õ½Õ¯ Õ¥Õ©Õ¥ Õ¹Õ¥Ö„ Õ¯Õ¡Ö€Õ¸Õ² Õ¤Õ¡Õ¤Õ¡Ö€Õ¥ÖÕ¶Õ¥Õ¬ Õ¤Õ¡Ö‰ Õ€Õ¥Õ¿Õ¡Õ£Õ®Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¾Õ¥Õ¬ ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´ Õ¯Õ¡Õ´ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¸Ö‚Õ´, Õ¸Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ¨Ö‰</translation>
<translation id="7375818412732305729">Õ–Õ¡ÕµÕ¬Õ« Õ¯ÖÕ¸Ö‚Õ´</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">Õ‰Õ¡ÖƒÕ¡Õ¦Õ¡Õ¶Ö Õ·Õ¡Õ¿ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
<translation id="7977538094055660992">Ô±Ö€Õ¿Õ¡Õ®Õ´Õ¡Õ¶ Õ½Õ¡Ö€Ö„</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Ô¼Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¤Õ«Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Ö„ ARCore Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="799149739215780103">Ô±Õ´Ö€Õ¡Õ¯Õ¡Ö€</translation>
<translation id="7995512525968007366">Õ†Õ·Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="800218591365569300">Õ“Õ¡Õ¯Õ¥Ö„ Õ´ÕµÕ¸Ö‚Õ½ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ¨Õ Õ¿Õ¡Ö€Õ¡Õ®Ö„ Õ¡Õ¦Õ¡Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€:</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">Õ€Ö€Õ¡Õ´Õ¡Õ¶Õ¡Õ¿Õ¸Õ²</translation>
<translation id="8508648098325802031">ÕˆÖ€Õ¸Õ¶Õ´Õ¡Õ¶ ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¡Õ¯</translation>
<translation id="8522552481199248698">Chrome-Õ¨ Õ¯Ö…Õ£Õ¶Õ« ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ«Õ¾Õ¨ Ö‡ ÖƒÕ¸Õ­Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨Ö‰</translation>
+<translation id="8525306231823319788">Ô¼Õ«Õ¡Õ§Õ¯Ö€Õ¡Õ¶</translation>
<translation id="8530813470445476232">Õ‹Õ¶Õ»Õ¥Ö„ Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨, Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨, Ö„Õ¥Õ·Õ¨ Ö‡ Õ¡ÕµÕ¬ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="8533619373899488139">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® URL-Õ¶Õ¥Ö€Õ« ÖÕ¸Ö‚ÖÕ¡Õ¯Õ¨ Ö‡ Õ±Õ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ« Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¯Õ«Ö€Õ¡Õ¼Õ¾Õ¡Õ® Õ´ÕµÕ¸Ö‚Õ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€Õ¨ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¥Ö„ &lt;strong&gt;chrome://policy&lt;/strong&gt;Ö‰</translation>
<translation id="8541158209346794904">Bluetooth Õ½Õ¡Ö€Ö„</translation>
<translation id="8542014550340843547">ÔµÖ€Õ¥Ö„ Õ¡Õ´Ö€Õ¡Õ¯ Õ¶Õ¥Ö€Ö„Ö‡Õ¸Ö‚Õ´</translation>
<translation id="8543181531796978784">Ô´Õ¸Ö‚Ö„ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ <ph name="BEGIN_ERROR_LINK" />Õ¿Õ¥Õ²Õ¥Õ¯Õ¡ÖÕ¶Õ¥Õ¬ Õ°Õ¡ÕµÕ¿Õ¶Õ¡Õ¢Õ¥Ö€Õ¾Õ¡Õ® Õ­Õ¶Õ¤Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶<ph name="END_ERROR_LINK" /> Õ¯Õ¡Õ´, Õ¥Õ©Õ¥ Õ°Õ¡Õ½Õ¯Õ¡Õ¶Õ¸Ö‚Õ´ Õ¥Ö„ Õ±Õ¥Õ¦ Õ½ÕºÕ¡Õ¼Õ¶Õ¡ÖÕ¸Õ² Õ¾Õ¿Õ¡Õ¶Õ£Õ¨, Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ <ph name="BEGIN_LINK" />Õ¡ÕµÖÕ¥Õ¬Õ¥Õ¬ Õ¡ÕµÕ½ Õ¸Õ¹ Õ¡ÕºÕ¡Õ°Õ¸Õ¾ Õ¯Õ¡ÕµÖ„Õ¨<ph name="END_LINK" />:</translation>
<translation id="8557066899867184262">CVC Õ¯Õ¸Õ¤Õ¨ Õ£Ö€Õ¾Õ¡Õ® Õ§ Ö„Õ¡Ö€Õ¿Õ« Õ°Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´Ö‰</translation>
+<translation id="8558485628462305855">Ô¼Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¤Õ«Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ©Õ¡Ö€Õ´Õ¡ÖÖ€Õ¥Ö„ ARCore Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-Õ« Õ°Õ¥Õ¿ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¾Õ¥Õ¬, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ« Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨ Ö‡ ÕªÕ¡Õ´Õ¨ (<ph name="DATE_AND_TIME" />) Õ½Õ­Õ¡Õ¬ Õ§:</translation>
<translation id="8564182942834072828">Õ„Õ« Ö„Õ¡Õ¶Õ« ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©/Õ¹Õ¡Õ¼Õ¡Õ¶Õ±Õ¶Õ¡ÖÕ¾Õ¡Õ® ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¶Õ¥Ö€</translation>
<translation id="8564985650692024650">Ô½Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ¥Õ¶Ö„ Õ¿Õ¡Õ¬Õ«Õ½ Õ¾Õ¥Ö€Õ¡Õ¯Õ¡ÕµÕ¥Õ¬ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-Õ« Õ±Õ¥Ö€ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨, Õ¥Õ©Õ¥ Õ¡ÕµÕ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¥Ö„ Õ¡ÕµÕ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´:</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ¹Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ«Õ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ§Õ»Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¸Ö‚Õ´,
+ <ph name="LIST_ITEM" />Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨Ö‰
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Touch ID-Õ¶Õ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¶ Õ¡Õ¾Õ¥Õ¬Õ« Õ¡Ö€Õ¡Õ£ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="858637041960032120">Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ°Õ¥Õ¼Õ¡Õ­Õ¸Õ½Õ¡Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="8589998999637048520">Ô¼Õ¡Õ¾Õ¡Õ£Õ¸Ö‚ÕµÕ¶ Õ¸Ö€Õ¡Õ¯</translation>
+<translation id="8600271352425265729">Õ„Õ«Õ¡ÕµÕ¶ Õ¡ÕµÕ½ Õ¡Õ¶Õ£Õ¡Õ´</translation>
<translation id="860043288473659153">Õ”Õ¡Ö€Õ¿Õ¡ÕºÕ¡Õ¶Õ« Õ¡Õ¶Õ¸Ö‚Õ¶Õ¨</translation>
<translation id="8606726445206553943">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ±Õ¥Ö€ MIDI Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¨</translation>
+<translation id="8612761427948161954">ÕˆÕ²Õ»Õ¸Ö‚ÕµÕ¶, <ph name="USERNAME" />Ö‰
+ <ph name="BR" />
+ Ô´Õ¸Ö‚Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Õ°ÕµÕ¸Ö‚Ö€Õ« Õ¼Õ¥ÕªÕ«Õ´Õ¨Ö‰</translation>
<translation id="861775596732816396">Õ‰Õ¡Öƒ 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Õ€Õ¡Õ´Õ¨Õ¶Õ¯Õ¶Õ¸Õ² Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€ Õ¹Õ¯Õ¡Õ¶Ö‰ Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¢Õ¸Õ¬Õ¸Ö€ ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨Ö‰</translation>
<translation id="8625384913736129811">ÕŠÕ¡Õ°Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ¶ Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´</translation>
+<translation id="8627040765059109009">Ô·Õ¯Ö€Õ¡Õ¶Õ« Õ¿Õ¥Õ½Õ¡Õ£Ö€Õ¸Ö‚Õ´Õ¨ Õ¯Ö€Õ¯Õ«Õ¶ Õ´Õ«Õ¡ÖÕ¾Õ¡Õ® Õ§</translation>
<translation id="8657078576661269990">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¹Õ« Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÖƒÕ¸Õ­Õ¡Õ¶ÖÕ¸Ö‚Õ´Õ¨ <ph name="ORIGIN_NAME" /> Õ¯Õ¡ÕµÖ„Õ«Ö Õ¤Õ¥ÕºÕ« <ph name="VM_NAME_1" /> Ö‡ <ph name="VM_NAME_2" /> Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Õ´Õ¥Ö„Õ¥Õ¶Õ¡Õ¶Õ¥Ö€Ö‰</translation>
<translation id="8663226718884576429">ÕÕ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ ÕºÕ¡Õ¿Õ¾Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶, <ph name="TOTAL_LABEL" />, Õ´Õ¡Õ¶Ö€Õ¡Õ´Õ¡Õ½Õ¶Õ¥Ö€</translation>
<translation id="867224526087042813">ÕÕ¿Õ¸Ö€Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google Õ°Õ¡Õ·Õ«Õ¾</translation>
<translation id="8913778647360618320">«Կառավարել Õ¾Õ³Õ¡Ö€Õ´Õ¡Õ¶ եղանակները» Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ ÕÕ¥Ö€ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ¡Ö€Õ¯Õ¡ÕµÕ«Õ¶ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ EnterÖ‰</translation>
<translation id="8918231688545606538">Ô±ÕµÕ½ Õ§Õ»Õ¨ Õ¯Õ¡Õ½Õ¯Õ¡Õ®Õ¥Õ¬Õ« Õ§</translation>
+<translation id="8922013791253848639">Õ„Õ«Õ·Õ¿ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ£Õ¸Õ¾Õ¡Õ¦Õ¤Õ¶ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´</translation>
<translation id="892588693504540538">Ô±Õ¶ÖÖ„ Õ¾Õ¥Ö€Ö‡Õ« Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="8931333241327730545">ÕˆÖ‚Õ¦Õ¸ÕžÖ‚Õ´ Õ¥Ö„ ÕºÕ¡Õ°Õ¥Õ¬ Õ¡ÕµÕ½ Ö„Õ¡Ö€Õ¿Õ¨ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ¾Õ¸Ö‚Õ´:</translation>
<translation id="8932102934695377596">ÕÕ¥Ö€ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ Õ°Õ¥Õ¿ Õ§ Õ¨Õ¶Õ¯Õ¥Õ¬</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Google Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ¥Ö€</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" />-Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ§ Õ¹Õ¡Õ»Õ¡Õ¯ÖÕ¾Õ¸Õ² Õ°Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ¯Õ¡Ö€Õ£:</translation>
<translation id="9191834167571392248">Ô±Õ¶ÖÖ„ Õ¶Õ¥Ö€Ö„Ö‡Õ« Õ±Õ¡Õ­ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
+<translation id="9199905725844810519">ÕÕºÕ¸Ö‚Õ´Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§</translation>
<translation id="9205078245616868884">ÕÕ¥Ö€ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ£Ö€Õ¾Õ¥Õ¬ Õ¥Õ¶ Õ±Õ¥Ö€ Õ°Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ´Õ¡Õ¶ Õ¡Õ¶ÖÕ¡Õ¢Õ¡Õ¼Õ¸Õ¾: Õ€Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ¡Õ¶ÖÕ¡Õ¢Õ¡Õ¼Õ¨:</translation>
<translation id="9207861905230894330">Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ°Õ¸Õ¤Õ¾Õ¡Õ®Õ¨:</translation>
<translation id="9213433120051936369">Ô±Õ¶Õ°Õ¡Õ¿Õ¡Õ¯Õ¡Õ¶Õ¡ÖÖ€Õ¥Ö„ Õ¡Ö€Õ¿Õ¡Ö„Õ«Õ¶ Õ¿Õ¥Õ½Ö„Õ¨</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Õ€Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ§Õ Õ¹Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Õ´Õ¿Õ¶Õ¥Õ¬ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ«Õ¾Ö‰ Chromium-Õ¨ Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ ÖƒÕ¸Õ­Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨, Õ¸Ö€Õ«Ö Õ°Õ¥Õ¿Õ¸ Õ°Õ¡Ö€Õ¯Õ¡Õ¾Õ¸Ö€ Õ¯Õ¬Õ«Õ¶Õ« Õ¶Õ¸Ö€Õ«Ö Õ´Õ¸Ö‚Õ¿Ö„ Õ£Õ¸Ö€Õ®Õ¥Õ¬Ö‰</translation>
<translation id="939736085109172342">Õ†Õ¸Ö€ ÕºÕ¡Õ¶Õ¡Õ¯</translation>
+<translation id="945522503751344254">Ô¿Õ¡Ö€Õ®Õ«Ö„ Õ°Õ¡ÕµÕ¿Õ¶Õ¥Õ¬</translation>
<translation id="945855313015696284">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ½Õ¿Õ¸Ö€Ö‡ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Ö‡ Õ»Õ¶Õ»Õ¥Ö„ Õ¡Õ¶Õ¾Õ¡Õ¾Õ¥Ö€ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¨</translation>
<translation id="950736567201356821">ÔµÖ€Õ¥Ö„ Õ¡Õ¶ÖÖ„ Õ¾Õ¥Ö€Ö‡Õ¸Ö‚Õ´</translation>
+<translation id="951941430552851965">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¤Õ¡Õ¤Õ¡Ö€Õ¥ÖÖ€Õ¥Õ¬ Õ§ Õ§Õ¯Ö€Õ¡Õ¶Õ« Õ¬Õ¸Ö‚Õ½Õ¡Õ¶Õ¯Õ¡Ö€Õ¸Ö‚Õ´Õ¨Õ Õ§Õ¯Ö€Õ¡Õ¶Õ«Õ¶ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ¸Õ² Õ¡Õ¶ÕºÕ¡Õ¿Õ·Õ¡Õ³ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÕºÕ¡Õ¿Õ³Õ¡Õ¼Õ¸Õ¾Ö‰</translation>
<translation id="961663415146723894">Ô±Õ´Ö€Õ¡Õ¯Õ¡Ö€ Õ¶Õ¥Ö€Ö„Ö‡Õ¸Ö‚Õ´</translation>
<translation id="962484866189421427">Ô±ÕµÕ½ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ ÖƒÕ¸Ö€Õ±Õ¥Õ¬ Õ¯Õ¥Õ²Õ® Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬ Õ¯Õ¡Õ´ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ°Õ¡Õ¾Õ¡Ö„Õ¥Õ¬Õ Õ±Õ¥Õ¦ Õ°Õ¥Õ¿Ö‡Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰ <ph name="BEGIN_LINK" />Õ„Õ«Ö‡Õ¶Õ¸Ö‚ÕµÕ¶ Õ§ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ÕŠÕ¡Õ·Õ¿Õ¸Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¿Õ¡Ö€Õ¢Õ¥Ö€Õ¡Õ¯</translation>
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index 936ba83e1bf..1ace8052846 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -80,6 +80,14 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Anda memasukkan sandi di situs yang tidak dikelola oleh organisasi. Untuk melindungi akun, jangan gunakan sandi yang sama di aplikasi dan situs lain.</translation>
<translation id="1263231323834454256">Daftar bacaan</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivitas yang tidak akan tersimpan di perangkat ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Halaman yang dilihat di jendela ini
+ <ph name="LIST_ITEM" />Cookie dan data situs
+ <ph name="LIST_ITEM" />Informasi akun (<ph name="LINK_BEGIN" />logout<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Metode Pengambilan</translation>
<translation id="1281476433249504884">Tempat kertas 1</translation>
<translation id="1285320974508926690">Jangan pernah terjemahkan situs ini</translation>
@@ -279,6 +287,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="204357726431741734">Login untuk menggunakan sandi yang disimpan di Akun Google Anda</translation>
<translation id="2053111141626950936">Halaman dalam bahasa <ph name="LANGUAGE" /> tidak akan diterjemahkan.</translation>
<translation id="2053553514270667976">Kode pos</translation>
+<translation id="2054665754582400095">Kehadiran Anda</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 saran}other{# saran}}</translation>
<translation id="2079545284768500474">Urungkan</translation>
<translation id="20817612488360358">Setelan proxy sistem disetel untuk digunakan namun konfigurasi proxy eksplisit juga ditentukan.</translation>
@@ -292,6 +301,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2102495993840063010">Aplikasi Android</translation>
<translation id="2107021941795971877">Dukungan cetak</translation>
<translation id="2108755909498034140">Mulai ulang komputer</translation>
+<translation id="2111166930115883695">Tekan spasi untuk bermain</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kartu</translation>
<translation id="2114841414352855701">Diabaikan karena diganti dengan <ph name="POLICY_NAME" />.</translation>
@@ -303,6 +313,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Sinkronisasi Latar Belakang</translation>
<translation id="2148613324460538318">Tambahkan Kartu</translation>
+<translation id="2149968176347646218">Koneksi tidak aman</translation>
<translation id="2154054054215849342">Sinkronisasi tidak tersedia untuk domain Anda</translation>
<translation id="2154484045852737596">Edit kartu</translation>
<translation id="2161656808144014275">Teks</translation>
@@ -313,7 +324,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2181821976797666341">Kebijakan</translation>
<translation id="2183608646556468874">Nomor Telepon</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
-<translation id="2187243482123994665">Kehadiran pengguna</translation>
<translation id="2187317261103489799">Deteksi (default)</translation>
<translation id="2188375229972301266">Beberapa lubang di bawah</translation>
<translation id="2202020181578195191">Masukkan tahun habis masa berlaku yang valid</translation>
@@ -466,6 +476,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2839501879576190149">Situs yang akan dibuka palsu</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Penyerang mungkin berusaha mencuri informasi Anda dari <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (misalnya, sandi, pesan, atau kartu kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Situs ini menampilkan iklan yang mengganggu atau menyesatkan.</translation>
<translation id="2878197950673342043">Lipatan poster</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Penempatan jendela</translation>
@@ -504,11 +515,11 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2996674880327704673">Saran oleh Google</translation>
<translation id="3002501248619246229">Periksa media baki masukan</translation>
<translation id="3005723025932146533">Tampilkan salinan yang disimpan</translation>
-<translation id="3007719053326478567">Pencetakan konten ini diblokir oleh administrator Anda</translation>
<translation id="3008447029300691911">Masukkan CVC untuk <ph name="CREDIT_CARD" />. Setelah mengonfirmasi, detail kartu Anda akan dibagikan dengan situs ini.</translation>
<translation id="3010559122411665027">Entri daftar "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Diblokir secara otomatis</translation>
<translation id="3016780570757425217">Mengetahui lokasi Anda</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, tekan Tab, lalu Enter untuk Menghapus Saran.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Jenis kebijakan salah</translation>
<translation id="3037605927509011580">Yah!</translation>
@@ -551,6 +562,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3207960819495026254">Diberi bookmark</translation>
<translation id="3209034400446768650">Halaman mungkin dikenakan biaya</translation>
<translation id="3212581601480735796">Aktivitas Anda di <ph name="HOSTNAME" /> sedang dipantau</translation>
+<translation id="3212623355668894776">Tutup semua jendela Tamu agar aktivitas penjelajahan dihapus dari perangkat ini.</translation>
<translation id="3215092763954878852">Tidak dapat menggunakan WebAuthn</translation>
<translation id="3218181027817787318">Relatif</translation>
<translation id="3225919329040284222">Server menunjukkan sertifikat yang tidak sesuai dengan harapan terpasang. Harapan ini disertakan untuk situs web tertentu dengan keamanan tinggi guna melindungi Anda.</translation>
@@ -697,6 +709,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3784372983762739446">Perangkat bluetooth</translation>
<translation id="3787705759683870569">Masa berlaku <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Ukuran 16</translation>
+<translation id="3789841737615482174">Instal</translation>
<translation id="3793574014653384240">Jumlah dan penyebab error yang terjadi baru-baru ini</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Font diminta</translation>
@@ -747,6 +760,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Kunci "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Screenshot dilanjutkan.</translation>
<translation id="4067947977115446013">Tambahkan Alamat yang Valid</translation>
<translation id="4072486802667267160">Terjadi error saat memproses pesanan Anda. Harap coba lagi.</translation>
<translation id="4075732493274867456">Klien dan server tidak mendukung versi protokol SSL umum atau cipher suite.</translation>
@@ -827,6 +841,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4297502707443874121">Thumbnail untuk halaman <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Luaskan</translation>
<translation id="4300675098767811073">Beberapa lubang di kanan</translation>
+<translation id="4302514097724775343">Ketuk dinosaurus untuk bermain</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">File Anda tidak dapat diakses</translation>
<translation id="4305817255990598646">Alihkan</translation>
@@ -905,6 +920,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4658638640878098064">Jepretan di kiri atas</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reality</translation>
+<translation id="4675657451653251260">Anda tidak akan melihat info profil Chrome dalam mode Tamu. Anda dapat <ph name="LINK_BEGIN" />login<ph name="LINK_END" /> untuk mengakses info Akun Google Anda seperti sandi dan metode pembayaran.</translation>
<translation id="467662567472608290">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya berisi kesalahan. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ingin merespons peristiwa aksesibilitas</translation>
<translation id="467809019005607715">Google Slide</translation>
@@ -932,6 +948,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4761104368405085019">Menggunakan mikrofon Anda</translation>
<translation id="4764776831041365478">Halaman web di <ph name="URL" /> mungkin sedang tidak aktif untuk sementara atau dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="4766713847338118463">Dua jepretan di bawah</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivitas yang akan tersimpan di perangkat ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Semua file yang didownload di jendela ini
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up diblokir}other{# pop-up diblokir}}</translation>
<translation id="4780366598804516005">Kotak surat 1</translation>
@@ -1094,11 +1116,13 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5386426401304769735">Rantai sertifikat untuk situs ini berisi sertifikat yang ditandatangani menggunakan SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Jahitan tepi di kanan</translation>
+<translation id="5398772614898833570">Iklan diblokir</translation>
<translation id="5400836586163650660">Grey</translation>
<translation id="540969355065856584">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya saat ini tidak valid. Hal ini mungkin disebabkan oleh kesalahan konfigurasi atau ada penyerang yang mengganggu koneksi internet Anda.</translation>
<translation id="541416427766103491">Tempat kertas 4</translation>
<translation id="5421136146218899937">Hapus data penjelajahan...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ingin mengirimkan notifikasi kepada Anda</translation>
+<translation id="542872847390508405">Anda menjelajah sebagai Tamu</translation>
<translation id="5430298929874300616">Buang bookmark</translation>
<translation id="5439770059721715174">Kesalahan validasi skema di "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Urutan yang berkebalikan menghadap ke atas</translation>
@@ -1117,7 +1141,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
Coba hubungi administrator sistem Anda.</translation>
<translation id="549333378215107354">Ukuran 3</translation>
<translation id="5509762909502811065">B0</translation>
-<translation id="5509780412636533143">Mengelola bookmark</translation>
+<translation id="5509780412636533143">Bookmark Terkelola</translation>
<translation id="5510481203689988000">Setelan ini dikontrol di setelan Cookie.</translation>
<translation id="5510766032865166053">File mungkin telah dipindahkan atau dihapus.</translation>
<translation id="5519516356611866228">Dengan perubahan dari Anda</translation>
@@ -1140,12 +1164,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5571083550517324815">Tidak dapat mengambil dari alamat ini. Pilih alamat lain.</translation>
<translation id="5580958916614886209">Periksa bulan kedaluwarsa dan coba lagi</translation>
<translation id="5586446728396275693">Tidak ada alamat yang disimpan</translation>
+<translation id="5593349413089863479">Koneksi tidak sepenuhnya aman</translation>
<translation id="5595485650161345191">Edit alamat</translation>
<translation id="5598944008576757369">Pilih Metode Pembayaran</translation>
<translation id="560412284261940334">Pengelolaan tidak didukung</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Situs ini mungkin palsu atau penipuan. Chrome merekomendasikan untuk keluar dari situs sekarang.</translation>
<translation id="5610142619324316209">Periksa sambungan</translation>
<translation id="5610807607761827392">Anda dapat mengelola kartu dan alamat di <ph name="BEGIN_LINK" />Setelan<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Terjemahkan halaman ini dengan Google Terjemahan</translation>
@@ -1217,6 +1241,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5901630391730855834">Kuning</translation>
<translation id="5905445707201418379">Diblokir sesuai dengan kebijakan asal <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (disinkronkan)</translation>
+<translation id="5913377024445952699">Tangkapan layar dijeda</translation>
<translation id="59174027418879706">Diaktifkan</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aktif</translation>
@@ -1229,6 +1254,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5963413905009737549">Bagian</translation>
<translation id="5967592137238574583">Edit Info Kontak</translation>
<translation id="5967867314010545767">Hapus dari histori</translation>
+<translation id="5968793460449681917">Di setiap kunjungan</translation>
<translation id="5975083100439434680">Perkecil</translation>
<translation id="5979084224081478209">Periksa sandi</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1384,6 +1410,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6587923378399804057">Link yang Anda salin</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> Anda tidak dikelola</translation>
<translation id="6596325263575161958">Opsi enkripsi</translation>
+<translation id="6596892391065203054">Pencetakan konten ini diblokir oleh administrator Anda.</translation>
<translation id="6604181099783169992">Sensor Gerakan atau Cahaya</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Konten dilindungi</translation>
@@ -1443,6 +1470,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6895330447102777224">Kartu telah dikonfirmasi</translation>
<translation id="6897140037006041989">Agen Pengguna</translation>
<translation id="6898699227549475383">Organisasi (O)</translation>
+<translation id="6907293445143367439">Izinkan <ph name="SITE_NAME" /> untuk:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ingin mengontrol penuh perangkat MIDI Anda</translation>
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6934672428414710184">Nama ini dari Akun Google Anda</translation>
@@ -1533,7 +1561,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7251437084390964440">Konfigurasi jaringan tidak mematuhi standar ONC. Sebagian konfigurasi mungkin tidak diimpor. Detail tambahan: <ph name="DEBUG_INFO" /></translation>
<translation id="725866823122871198">Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat dibuat karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) komputer Anda tidak benar.</translation>
<translation id="7260504762447901703">Cabut akses</translation>
-<translation id="7275334191706090484">Bookmark yang Terkelola</translation>
+<translation id="7275334191706090484">Bookmark Terkelola</translation>
<translation id="7292031607255951991">Nama penerima</translation>
<translation id="7298195798382681320">Direkomendasikan</translation>
<translation id="7300012071106347854">Biru Kobalt</translation>
@@ -1552,6 +1580,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7346048084945669753">Berafiliasi:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Baris Perintah</translation>
+<translation id="7359588939039777303">Iklan diblokir.</translation>
<translation id="7372973238305370288">hasil penelusuran</translation>
<translation id="7374733840632556089">Masalah ini terjadi karena sertifikat yang diinstal di perangkat oleh Anda atau orang lain. Sertifikat ini diketahui sebagai sertifikat yang digunakan untuk memantau dan melakukan intersepsi jaringan dan tidak dipercaya oleh Chrome. Walau terdapat beberapa kasus pemantauan yang sah, seperti pada jaringan sekolah atau perusahaan, Chrome ingin memastikan Anda mengetahui adanya pemantauan ini, meskipun Anda tidak dapat menghentikannya. Pemantauan dapat terjadi di browser atau aplikasi yang mengakses web.</translation>
<translation id="7375818412732305729">File dilampirkan</translation>
@@ -1668,7 +1697,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="773466115871691567">Selalu terjemahkan halaman dalam bahasa <ph name="SOURCE_LANGUAGE" /></translation>
<translation id="7740996059027112821">Standar</translation>
<translation id="774634243536837715">Konten berbahaya diblokir.</translation>
-<translation id="7752995774971033316">Tidak terkelola</translation>
+<translation id="7752995774971033316">Tidak dikelola</translation>
<translation id="7757555340166475417">Dai-Pa-Kai</translation>
<translation id="7758069387465995638">Software antivirus atau firewall mungkin memblokir sambungan.</translation>
<translation id="7759163816903619567">Tampilkan domain:</translation>
@@ -1726,6 +1755,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7976214039405368314">Terlalu banyak permintaan</translation>
<translation id="7977538094055660992">Perangkat keluaran</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Untuk melihat konten augmented reality, instal ARCore</translation>
<translation id="799149739215780103">Jilid</translation>
<translation id="7995512525968007366">Tidak Ditentukan</translation>
<translation id="800218591365569300">Coba tutup tab atau program lain untuk mengosongkan memori.</translation>
@@ -1851,24 +1881,38 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Ikon penelusuran</translation>
<translation id="8522552481199248698">Chrome dapat membantu Anda melindungi Akun Google dan mengubah sandi Anda.</translation>
+<translation id="8525306231823319788">Layar penuh</translation>
<translation id="8530813470445476232">Hapus histori penjelajahan, cookie, cache, dan lainnya di setelan Chrome</translation>
<translation id="8533619373899488139">Buka &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat daftar URL yang diblokir dan kebijakan lainnya yang diterapkan oleh administrator sistem Anda.</translation>
<translation id="8541158209346794904">Perangkat Bluetooth</translation>
<translation id="8542014550340843547">Tiga jepretan di bawah</translation>
<translation id="8543181531796978784">Anda dapat <ph name="BEGIN_ERROR_LINK" />melaporkan masalah pendeteksian<ph name="END_ERROR_LINK" /> atau, jika memahami risiko bagi keamanan, Anda dapat <ph name="BEGIN_LINK" />mengunjungi situs yang tidak aman<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC terletak di bagian belakang kartu Anda.</translation>
+<translation id="8558485628462305855">Untuk melihat konten augmented reality, update ARCore</translation>
<translation id="8559762987265718583">Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat dibuat karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) perangkat tidak benar.</translation>
<translation id="8564182942834072828">Dokumen terpisah/Salinan tidak tersusun</translation>
<translation id="8564985650692024650">Chromium menyarankan untuk menyetel ulang sandi <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika Anda juga menggunakannya di situs lain.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivitas yang tidak akan tersimpan di perangkat ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Halaman yang dilihat di jendela ini
+ <ph name="LIST_ITEM" />Cookie dan data situs
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Gunakan Touch ID untuk mengonfirmasi kartu dengan lebih cepat</translation>
<translation id="858637041960032120">+ nomor telepon</translation>
<translation id="8589998999637048520">Kualitas terbaik</translation>
+<translation id="8600271352425265729">Hanya kali ini</translation>
<translation id="860043288473659153">Nama pemegang kartu</translation>
<translation id="8606726445206553943">Menggunakan perangkat MIDI Anda</translation>
+<translation id="8612761427948161954">Halo <ph name="USERNAME" />,
+ <ph name="BR" />
+ Anda menjelajah sebagai Tamu</translation>
<translation id="861775596732816396">Ukuran 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Tidak ada sandi yang cocok. Tampilkan semua sandi yang tersimpan.</translation>
<translation id="8625384913736129811">Simpan Kartu Ini ke Perangkat Ini</translation>
+<translation id="8627040765059109009">Tangkapan layar dilanjutkan</translation>
<translation id="8657078576661269990">Administrator Anda telah memblokir berbagi dari <ph name="ORIGIN_NAME" /> ke <ph name="VM_NAME_1" /> dan <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Ringkasan Pesanan, <ph name="TOTAL_LABEL" />, Detail Selengkapnya</translation>
<translation id="867224526087042813">Tanda Tangan</translation>
@@ -1931,6 +1975,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8912362522468806198">Akun Google</translation>
<translation id="8913778647360618320">Tombol Kelola metode pembayaran, tekan Enter untuk mengelola info pembayaran dan kartu kredit di setelan Chrome</translation>
<translation id="8918231688545606538">Halaman ini mencurigakan</translation>
+<translation id="8922013791253848639">Selalu izinkan iklan di situs ini</translation>
<translation id="892588693504540538">Lubang di kanan atas</translation>
<translation id="8931333241327730545">Ingin menyimpan kartu ini ke Akun Google Anda?</translation>
<translation id="8932102934695377596">Setelan waktu Anda terlalu lambat</translation>
@@ -2002,6 +2047,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="9183302530794969518">Google Dokumen</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> menggunakan protokol yang tidak didukung.</translation>
<translation id="9191834167571392248">Lubang di kiri bawah</translation>
+<translation id="9199905725844810519">Pencetakan diblokir</translation>
<translation id="9205078245616868884">Data Anda dienkripsi dengan frasa sandi sinkronisasi. Masukkan frasa sandi untuk memulai sinkronisasi.</translation>
<translation id="9207861905230894330">Gagal menambahkan artikel.</translation>
<translation id="9213433120051936369">Sesuaikan tampilan</translation>
@@ -2012,11 +2058,13 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Anda dapat kehilangan akses ke Akun Google Anda. Chromium merekomendasikan untuk mengubah sandi Anda sekarang. Anda akan diminta untuk login.</translation>
<translation id="939736085109172342">Folder baru</translation>
+<translation id="945522503751344254">Kirim masukan</translation>
<translation id="945855313015696284">Periksa info di bawah dan hapus kartu apa pun yang tidak valid</translation>
<translation id="950736567201356821">Tiga lubang di atas</translation>
+<translation id="951941430552851965">Screenshot dijeda oleh administrator Anda karena konten di layar.</translation>
<translation id="961663415146723894">Jilid bawah</translation>
<translation id="962484866189421427">Konten ini mungkin mencoba menginstal aplikasi penipuan dengan berpura-pura menjadi sesuatu yang lain atau mengumpulkan data yang dapat digunakan untuk melacak Anda. <ph name="BEGIN_LINK" />Tampilkan saja<ph name="END_LINK" /></translation>
-<translation id="969892804517981540">Pembuatan Resmi</translation>
+<translation id="969892804517981540">Build Resmi</translation>
<translation id="973773823069644502">Tambahkan Alamat Pengiriman</translation>
<translation id="975560348586398090">{COUNT,plural, =0{Tidak ada}=1{1 item}other{# item}}</translation>
<translation id="981121421437150478">Offline</translation>
diff --git a/chromium/components/strings/components_strings_is.xtb b/chromium/components/strings/components_strings_is.xtb
index 0d56156b4ec..66da852078e 100644
--- a/chromium/components/strings/components_strings_is.xtb
+++ b/chromium/components/strings/components_strings_is.xtb
@@ -80,6 +80,14 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Þú slóst inn aðgangsorðið þitt á síðu sem þitt fyrirtæki hefur ekki umsjón með. Til að vernda reikninginn þinn skaltu ekki nota sama aðgangsorð í öðrum forritum og á öðrum síðum.</translation>
<translation id="1263231323834454256">Leslisti</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Eftirfarandi virkni er ekki vistuð í þessu tæki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Síður sem þú skoðar í þessum glugga
+ <ph name="LIST_ITEM" />Fótspor og gögn vefsvæða
+ <ph name="LIST_ITEM" />Reikningsupplýsingar (<ph name="LINK_BEGIN" />útskráning<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Afhendingarmáti</translation>
<translation id="1281476433249504884">Staflari 1</translation>
<translation id="1285320974508926690">Aldrei þýða þetta vefsvæði</translation>
@@ -284,6 +292,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="204357726431741734">Skráðu þig inn til að nota aðgangsorð sem eru vistuð á Google reikningnum þínum</translation>
<translation id="2053111141626950936">Síður á þessu tungumáli verða ekki þýddar: <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Póstnúmer</translation>
+<translation id="2054665754582400095">Viðvera þín</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{Ein tillaga}one{# tillaga}other{# tillögur}}</translation>
<translation id="2079545284768500474">Afturkalla</translation>
<translation id="20817612488360358">Valið er að nota proxy-stillingar kerfis en skýr proxy-stilling er einnig tilgreind.</translation>
@@ -297,6 +306,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="2102495993840063010">Android forrit</translation>
<translation id="2107021941795971877">Prentstuðningur</translation>
<translation id="2108755909498034140">Endurræstu tölvuna</translation>
+<translation id="2111166930115883695">Ãttu á bilslána til að spila</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Hunsuð vegna þess að <ph name="POLICY_NAME" /> hnekkti henni.</translation>
@@ -308,6 +318,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="214556005048008348">Hætta við greiðslu</translation>
<translation id="2147827593068025794">Samstilling í bakgrunni</translation>
<translation id="2148613324460538318">Bæta við korti</translation>
+<translation id="2149968176347646218">Tengingin er ekki örugg</translation>
<translation id="2154054054215849342">Samstilling er ekki í boði fyrir lénið þitt</translation>
<translation id="2154484045852737596">Breyta korti</translation>
<translation id="2161656808144014275">Texti</translation>
@@ -318,7 +329,6 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="2181821976797666341">Reglur</translation>
<translation id="2183608646556468874">Símanúmer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Eitt heimilisfang}one{# heimilisfang}other{# heimilisföng}}</translation>
-<translation id="2187243482123994665">Viðvera notanda</translation>
<translation id="2187317261103489799">Greina (sjálfgefið)</translation>
<translation id="2188375229972301266">Mörg göt neðst</translation>
<translation id="2202020181578195191">Færðu inn gilt lokaár</translation>
@@ -471,6 +481,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="2839501879576190149">Falskt vefsvæði</translation>
<translation id="2850739647070081192">Invite (umslag)</translation>
<translation id="2856444702002559011">Tölvuþrjótar gætu verið að reyna að stela upplýsingum þínum frá <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (til dæmis aðgangsorðum, skilaboðum eða kreditkortum). <ph name="BEGIN_LEARN_MORE_LINK" />Frekari upplýsingar<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Þetta vefsvæði sýnir ágengar eða villandi auglýsingar.</translation>
<translation id="2878197950673342043">Veggspjaldabrot</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Gluggastaðsetning</translation>
@@ -509,11 +520,11 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="2996674880327704673">Tillögur frá Google</translation>
<translation id="3002501248619246229">Athuga miðil í innbakka</translation>
<translation id="3005723025932146533">Sýna vistað afrit</translation>
-<translation id="3007719053326478567">Kerfisstjóri hefur lokað á að þetta efni sé prentað</translation>
<translation id="3008447029300691911">Sláðu inn CVC-númerið fyrir <ph name="CREDIT_CARD" />. Greiðslukortaupplýsingum verður deilt með þessu vefsvæði eftir að þú hefur staðfest.</translation>
<translation id="3010559122411665027">Listafærsla „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Sjálfkrafa lokað á</translation>
<translation id="3016780570757425217">Komast að staðsetningunni þinni</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ýttu á dálkalykilinn og svo færslulykilinn (Enter) til að fjarlægja tillögu.</translation>
<translation id="3023071826883856138">You4 (umslag)</translation>
<translation id="3024663005179499861">Röng gerð stefnu</translation>
<translation id="3037605927509011580">Rækallinn!</translation>
@@ -556,6 +567,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="3207960819495026254">à bókamerkjum</translation>
<translation id="3209034400446768650">Síðan kann að rukka gjald</translation>
<translation id="3212581601480735796">Fylgst er með virkni þinni á <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">Lokaðu öllum gestagluggum svo að vafranotkun þinni verði eytt úr þessu tæki.</translation>
<translation id="3215092763954878852">Ekki var hægt að nota WebAuthn</translation>
<translation id="3218181027817787318">Háð</translation>
<translation id="3225919329040284222">Þjónninn framvísaði vottorði sem samsvarar ekki innbyggðum væntingum. Þessar væntingar eru hafðar með fyrir tiltekin mjög örugg vefsvæði í því skyni að vernda þig.</translation>
@@ -703,6 +715,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="3784372983762739446">Bluetooth-tæki</translation>
<translation id="3787705759683870569">Rennur út <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Stærð 16</translation>
+<translation id="3789841737615482174">Setja upp</translation>
<translation id="3793574014653384240">Fjöldi nýlegra hruntilvika og orsakir þeirra</translation>
<translation id="3797522431967816232">Prc3 (umslag)</translation>
<translation id="3799805948399000906">Beðið um leturgerð</translation>
@@ -754,6 +767,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="4056223980640387499">Brúnn blær</translation>
<translation id="4058922952496707368">Lykill „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (umslag)</translation>
+<translation id="4067669230157909013">Skjáupptöku var haldið áfram.</translation>
<translation id="4067947977115446013">Bæta gildu heimilisfangi við</translation>
<translation id="4072486802667267160">Villa kom upp þegar verið var að vinna úr pöntuninni þinni. Reyndu aftur.</translation>
<translation id="4075732493274867456">Biðlarinn og þjónninn styðja ekki sameiginlega útgáfu SSL-samskiptareglna eða dulkóðunarsafns.</translation>
@@ -838,6 +852,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="4297502707443874121">Smámynd síðu <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Stækka</translation>
<translation id="4300675098767811073">Mörg göt hægra megin</translation>
+<translation id="4302514097724775343">Ãttu á risaeðluna til að spila</translation>
<translation id="4302965934281694568">Chou3 (umslag)</translation>
<translation id="4305666528087210886">Ekki var hægt að opna skrána þína</translation>
<translation id="4305817255990598646">Skipta</translation>
@@ -916,6 +931,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="4658638640878098064">Hefti efst til vinstri</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Sýndarveruleiki</translation>
+<translation id="4675657451653251260">Þú munt ekki sjá neinar prófílupplýsingar í Chrome í gestastillingu. Þú getur <ph name="LINK_BEGIN" />skráð þig inn<ph name="LINK_END" /> til að fá aðgang að Google reikningsupplýsingum á borð við aðgangsorð og greiðslumáta.</translation>
<translation id="467662567472608290">Þessi þjónn gat ekki sannað að hann sé <ph name="DOMAIN" />; öryggisvottorð hans inniheldur villur. Þetta kann að orsakast af vanstillingu eða tölvuþrjóti sem komist hefur inn í tenginguna.</translation>
<translation id="4677585247300749148"><ph name="URL" /> vill svara aðgengisatburðum</translation>
<translation id="467809019005607715">Google skyggnur</translation>
@@ -943,6 +959,12 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="4761104368405085019">Nota hljóðnemann</translation>
<translation id="4764776831041365478">Vefsíðan á <ph name="URL" /> gæti legið niðri tímabundið eða gæti hafa verið flutt varanlega á annað veffang.</translation>
<translation id="4766713847338118463">Tvö hefti neðst</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Eftirfarandi virkni er vistuð í þessu tæki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Allar skrár sem þú sækir í þessum glugga
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Óþekkt villa kom upp.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Lokað á sprettiglugga}one{Lokað á # sprettiglugga}other{Lokað á # sprettiglugga}}</translation>
<translation id="4780366598804516005">Pósthólf 1</translation>
@@ -1105,11 +1127,13 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="5386426401304769735">Vottorðskeðja þessa vefsvæðis inniheldur vottorð sem var undirritað með SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Saumur hægra megin</translation>
+<translation id="5398772614898833570">Lokað á auglýsingar</translation>
<translation id="5400836586163650660">Grár</translation>
<translation id="540969355065856584">Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans er ekki gilt eins og er. Þetta kann að orsakast af vanstillingu eða þá að tölvuþrjótur er að reyna að komast inn í tenginguna þína.</translation>
<translation id="541416427766103491">Staflari 4</translation>
<translation id="5421136146218899937">Hreinsa vafragögn...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vill senda þér tilkynningar</translation>
+<translation id="542872847390508405">Þú ert að vafra sem gestur</translation>
<translation id="5430298929874300616">Fjarlægja bókamerki</translation>
<translation id="5439770059721715174">Villa við staðfestingu skema á „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Öfug röð, snýr upp</translation>
@@ -1151,12 +1175,12 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="5571083550517324815">Ekki er hægt að sækja frá þessu heimilisfangi. Veldu annað heimilisfang.</translation>
<translation id="5580958916614886209">Athugaðu mánuð gildistímans og reyndu aftur</translation>
<translation id="5586446728396275693">Engin vistuð vistföng</translation>
+<translation id="5593349413089863479">Tengingin er ekki alveg örugg</translation>
<translation id="5595485650161345191">Breyta heimilisfangi</translation>
<translation id="5598944008576757369">Velja greiðslumáta</translation>
<translation id="560412284261940334">Stjórnun er ekki studd</translation>
<translation id="5605670050355397069">Kladdi</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Þetta vefsvæði gæti verið falskt eða sviksamlegt. Chrome mælir með að þú yfirgefir það núna.</translation>
<translation id="5610142619324316209">Athuga tenginguna</translation>
<translation id="5610807607761827392">Þú getur haft umsjón með kortum og heimilisföngum í <ph name="BEGIN_LINK" />stillingunum<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Þýða þessa síðu með Google Translate</translation>
@@ -1228,6 +1252,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="5901630391730855834">Gulur</translation>
<translation id="5905445707201418379">Lokað á samkvæmt upprunareglu <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (samstillt)</translation>
+<translation id="5913377024445952699">Hlé gert á skjámyndatöku</translation>
<translation id="59174027418879706">Virkt</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Kveikt</translation>
@@ -1240,6 +1265,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="5963413905009737549">Hluti</translation>
<translation id="5967592137238574583">Breyta samskiptaupplýsingum</translation>
<translation id="5967867314010545767">Fjarlægja úr ferli</translation>
+<translation id="5968793460449681917">Við hverja heimsókn</translation>
<translation id="5975083100439434680">Minnka aðdrátt</translation>
<translation id="5979084224081478209">Yfirfara aðgangsorð</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1303,7 +1329,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="622039917539443112">Brotið tvisvar til helminga</translation>
<translation id="6221345481584921695">Örugg vefnotkun Google <ph name="BEGIN_LINK" />greindi nýlega spilliforrit<ph name="END_LINK" /> á <ph name="SITE" />. Vefsvæði sem allajafna eru örugg smitast stundum af spilliforritum. Skaðlega efnið er upprunnið frá <ph name="SUBRESOURCE_HOST" />, þekktum dreifingaraðila spilliforrita.</translation>
<translation id="6234122620015464377">Klippa eftir hvert skjal</translation>
-<translation id="6240447795304464094">Google Pay merki</translation>
+<translation id="6240447795304464094">Google Pay lógóið</translation>
<translation id="6241121617266208201">Fela tillögur</translation>
<translation id="624499991300733384">Prentsamsetningarþjónusta</translation>
<translation id="6254436959401408446">Ekki nóg minni til að birta þessa síðu</translation>
@@ -1395,6 +1421,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="6587923378399804057">Tengill sem þú afritaðir</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> er ekki stjórnað</translation>
<translation id="6596325263575161958">Dulkóðunarvalkostir</translation>
+<translation id="6596892391065203054">Stjórnandinn hefur lokað á prentun þessa efnis</translation>
<translation id="6604181099783169992">Hreyfi- eða birtuskynjarar</translation>
<translation id="6609880536175561541">Prc7 (umslag)</translation>
<translation id="6612358246767739896">Varið efni</translation>
@@ -1454,6 +1481,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="6895330447102777224">Kortið er staðfest</translation>
<translation id="6897140037006041989">Vafraupplýsingar</translation>
<translation id="6898699227549475383">Notendaskipan (O)</translation>
+<translation id="6907293445143367439">Leyfa <ph name="SITE_NAME" /> að:</translation>
<translation id="6910240653697687763"><ph name="URL" /> vill fá fulla stjórn á MIDI-tækjunum þínum</translation>
<translation id="6915804003454593391">Notandi:</translation>
<translation id="6934672428414710184">Þetta nafn kemur af Google reikningnum þínum</translation>
@@ -1565,6 +1593,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="7346048084945669753">Tengist:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Skipanalína</translation>
+<translation id="7359588939039777303">Lokað á auglýsingar.</translation>
<translation id="7372973238305370288">leitarniðurstaða</translation>
<translation id="7374733840632556089">Þetta vandamál tengist vottorði sem þú eða einhver annar setti upp í tækinu þínu. Vitað er að þetta vottorð er notað til að fylgjast með og grípa inn í netkerfi og Chrome treystir því ekki. Þrátt fyrir að notkun þess geti í einhverjum tilvikum átt rétt á sér, svo sem á skóla- eða fyrirtækjaneti, vill Chrome tryggja að þú vitir af því, þó að þú getir ekki komið í veg fyrir notkun þess. Eftirlit getur átt sér stað í öllum vöfrum eða forritum sem nota vefinn.</translation>
<translation id="7375818412732305729">Skrá er hengd við</translation>
@@ -1739,6 +1768,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="7976214039405368314">Of margar beiðnir</translation>
<translation id="7977538094055660992">Úttakstæki</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Til að skoða efni aukins veruleika skaltu setja upp ARCore</translation>
<translation id="799149739215780103">Binda</translation>
<translation id="7995512525968007366">Ekki tilgreint</translation>
<translation id="800218591365569300">Prófaðu að loka öðrum forritum til að losa um minni.</translation>
@@ -1866,24 +1896,38 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="8507227106804027148">Skipanalína</translation>
<translation id="8508648098325802031">Leitartákn</translation>
<translation id="8522552481199248698">Chrome getur hjálpað þér að vernda Google reikninginn þinn og breyta aðgangsorðinu.</translation>
+<translation id="8525306231823319788">Allur skjárinn</translation>
<translation id="8530813470445476232">Hreinsaðu vafraferilinn þinn, fótspor, skyndiminni og fleira í stillingum Chrome</translation>
<translation id="8533619373899488139">Opnaðu &lt;strong&gt;chrome://policy&lt;/strong&gt; til að sjá vefslóðir á bannlista og aðrar reglur sem kerfisstjórinn þinn setur.</translation>
<translation id="8541158209346794904">Bluetooth-tæki</translation>
<translation id="8542014550340843547">Þrjú hefti neðst</translation>
<translation id="8543181531796978784">Þú getur <ph name="BEGIN_ERROR_LINK" />tilkynnt vandamál við greiningu<ph name="END_ERROR_LINK" /> eða, ef þú skilur hvaða hættu þetta hefur í för með sér fyrir öryggi þitt, <ph name="BEGIN_LINK" />opnað þetta ótrausta vefsvæði<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC-númer er aftan á kortinu.</translation>
+<translation id="8558485628462305855">Til að skoða efni aukins veruleika skaltu uppfæra ARCore</translation>
<translation id="8559762987265718583">Ekki er hægt að koma á lokaðri tengingu við <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vegna þess að dag- og tímasetning tækisins (<ph name="DATE_AND_TIME" />) er röng.</translation>
<translation id="8564182942834072828">Aðskilin skjöl / ekki samröðuð eintök</translation>
<translation id="8564985650692024650">Chromium mælir með því að þú endurstillir aðgangsorðið fyrir <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ef þú notaðir það einnig á öðrum síðum.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Eftirfarandi virkni er ekki vistuð í þessu tæki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Síður sem þú skoðar í þessum glugga
+ <ph name="LIST_ITEM" />Fótspor og gögn vefsvæða
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Notaðu Touch ID til að staðfesta kort hraðar</translation>
<translation id="858637041960032120">Bæta við símanúmeri</translation>
<translation id="8589998999637048520">Mest gæði</translation>
+<translation id="8600271352425265729">Aðeins í þetta skipti</translation>
<translation id="860043288473659153">Nafn korthafa</translation>
<translation id="8606726445206553943">Nota MIDI-tækin þín</translation>
+<translation id="8612761427948161954">Hæ, <ph name="USERNAME" />.
+ <ph name="BR" />
+ Þú ert að vafra sem gestur</translation>
<translation id="861775596732816396">Stærð 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Engin samsvarandi aðgangsorð. Sýna öll vistuð aðgangsorð.</translation>
<translation id="8625384913736129811">Vista þetta kort í þessu tæki</translation>
+<translation id="8627040765059109009">Skjámyndatöku haldið áfram</translation>
<translation id="8657078576661269990">Kerfisstjórinn lokaði á deilingar frá <ph name="ORIGIN_NAME" /> til <ph name="VM_NAME_1" /> og <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Yfirlit pöntunar, <ph name="TOTAL_LABEL" />, frekari upplýsingar</translation>
<translation id="867224526087042813">Undirskrift</translation>
@@ -1946,6 +1990,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="8912362522468806198">Google reikningur</translation>
<translation id="8913778647360618320">Hnappurinn Stjórna greiðslumátum, ýttu á Enter til að stjórna greiðslu- og kreditkortaupplýsingum í stillingum Chrome</translation>
<translation id="8918231688545606538">Þessi síða er grunsamleg</translation>
+<translation id="8922013791253848639">Leyfa alltaf auglýsingar á þessu vefsvæði</translation>
<translation id="892588693504540538">Gatað efst til hægri</translation>
<translation id="8931333241327730545">Viltu vista þetta kort á Google reikningnum þínum?</translation>
<translation id="8932102934695377596">Klukkan er á eftir</translation>
@@ -2017,6 +2062,7 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="9183302530794969518">Google skjöl</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> notast við óstuddar samskiptareglur.</translation>
<translation id="9191834167571392248">Gat neðst til vinstri</translation>
+<translation id="9199905725844810519">Lokað er fyrir prentun</translation>
<translation id="9205078245616868884">Gögnin þín eru dulkóðuð með aðgangsorði samstillingar. Sláðu það inn til að hefja samstillingu.</translation>
<translation id="9207861905230894330">Ekki tókst að bæta greininni við.</translation>
<translation id="9213433120051936369">Sérsníða útlit</translation>
@@ -2027,8 +2073,10 @@ og röng skilríki til baka. Þetta getur gerst þegar tölvuþrjótur reynir aÃ
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Þú gætir glatað aðganginum að Google reikningnum þínum. Chromium mælir með því að þú skiptir um aðgangsorð núna. Þú verður beðin(n) um að skrá þig inn.</translation>
<translation id="939736085109172342">Ný mappa</translation>
+<translation id="945522503751344254">Senda ábendingu</translation>
<translation id="945855313015696284">Kannaðu upplýsingarnar hér að neðan og eyddu öllum ógildum kortum</translation>
<translation id="950736567201356821">Þrjú göt efst</translation>
+<translation id="951941430552851965">Stjórnandi gerði hlé á skjáupptöku vegna efnis á skjánum þínum.</translation>
<translation id="961663415146723894">Bundið neðst</translation>
<translation id="962484866189421427">Þetta efni gæti verið að reyna að setja upp villandi forrit sem virðast vera eitthvað annað en þau eru eða safna gögnum sem má nota til að fylgjast með þér. <ph name="BEGIN_LINK" />Sýna samt<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Opinber smíði</translation>
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index 2eef8b8f1db..ac2ec200197 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -80,10 +80,18 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Hai inserito la password su un sito non gestito dalla tua organizzazione. Per proteggere il tuo account, non riutilizzare la password su altri siti e app.</translation>
<translation id="1263231323834454256">Elenco di lettura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Attività che non verranno salvate sul dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pagine visualizzate in questa finestra
+ <ph name="LIST_ITEM" />Cookie e dati relativi al sito
+ <ph name="LIST_ITEM" />Dati dell'account (<ph name="LINK_BEGIN" />esci<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Metodo di ritiro</translation>
<translation id="1281476433249504884">Fascicolatore 1</translation>
<translation id="1285320974508926690">Non tradurre mai questo sito</translation>
-<translation id="1292701964462482250">"Il software installato sul computer sta impedendo a Chrome di connettersi in sicurezza a Internet" (solo su computer Windows)</translation>
+<translation id="1292701964462482250">"Il software installato sul computer sta impedendo a Chrome di connettersi in sicurezza al Web" (solo su computer Windows)</translation>
<translation id="1294154142200295408">Variazioni nella riga di comando</translation>
<translation id="129553762522093515">Chiuse di recente</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />Prova a cancellare i cookie<ph name="END_LINK" /></translation>
@@ -176,7 +184,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1592005682883173041">Accesso ai dati locali</translation>
<translation id="1594030484168838125">Scegli</translation>
<translation id="161042844686301425">Ciano</translation>
-<translation id="1620510694547887537">Videocamera</translation>
+<translation id="1620510694547887537">Fotocamera</translation>
<translation id="1623104350909869708">Impedisci la creazione di altre finestre di dialogo in questa pagina</translation>
<translation id="16338877384480380">Architecture-B</translation>
<translation id="1634828734222219955">Totale</translation>
@@ -283,6 +291,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="204357726431741734">Accedi per usare le password salvate nel tuo Account Google</translation>
<translation id="2053111141626950936">Le pagine in <ph name="LANGUAGE" /> non verranno tradotte.</translation>
<translation id="2053553514270667976">ZIP</translation>
+<translation id="2054665754582400095">La tua presenza</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggerimento}other{# suggerimenti}}</translation>
<translation id="2079545284768500474">Annulla</translation>
<translation id="20817612488360358">Devono essere utilizzate le impostazioni del proxy di sistema ma è stata specificata anche una configurazione proxy esplicita.</translation>
@@ -296,6 +305,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2102495993840063010">App Android</translation>
<translation id="2107021941795971877">Supporti di stampa</translation>
<translation id="2108755909498034140">Riavvia il computer</translation>
+<translation id="2111166930115883695">Premi la barra spaziatrice per giocare</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Carta</translation>
<translation id="2114841414352855701">Ignorata perché è stata sostituita da <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="214556005048008348">Annulla pagamento</translation>
<translation id="2147827593068025794">Sincronizzazione in background</translation>
<translation id="2148613324460538318">Aggiungi carta</translation>
+<translation id="2149968176347646218">La connessione non è sicura</translation>
<translation id="2154054054215849342">Il servizio di sincronizzazione non è disponibile per il tuo dominio</translation>
<translation id="2154484045852737596">Modifica la carta</translation>
<translation id="2161656808144014275">Testo</translation>
@@ -317,7 +328,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2181821976797666341">Criteri</translation>
<translation id="2183608646556468874">Numero di telefono</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}other{# indirizzi}}</translation>
-<translation id="2187243482123994665">Presenza dell'utente</translation>
<translation id="2187317261103489799">Rileva (predefinita)</translation>
<translation id="2188375229972301266">Perforatura multipla in basso</translation>
<translation id="2202020181578195191">Inserisci un anno di scadenza valido</translation>
@@ -470,6 +480,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2839501879576190149">Sito falso</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Gli utenti malintenzionati potrebbero provare a carpire le tue informazioni da <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ad esempio, password, messaggi o carte di credito). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Questo sito mostra annunci invasivi o fuorvianti.</translation>
<translation id="2878197950673342043">Piegatura a mappa</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Posizionamento delle finestre</translation>
@@ -508,11 +519,11 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2996674880327704673">Suggerimenti di Google</translation>
<translation id="3002501248619246229">Controlla contenuti multimediali cassetto di input</translation>
<translation id="3005723025932146533">Mostra copia salvata</translation>
-<translation id="3007719053326478567">La stampa di questi contenuti è stata bloccata dall'amministratore</translation>
<translation id="3008447029300691911">Inserisci il codice CVC della carta <ph name="CREDIT_CARD" />. Dopo essere stati confermati, i dettagli della carta saranno condivisi con questo sito.</translation>
<translation id="3010559122411665027">Voce "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloccata automaticamente</translation>
<translation id="3016780570757425217">Conoscere la tua posizione</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, premi Tab e poi Invio per rimuovere il suggerimento.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Tipo di criterio errato</translation>
<translation id="3037605927509011580">Uffa!</translation>
@@ -552,6 +563,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3207960819495026254">Aggiunto ai preferiti</translation>
<translation id="3209034400446768650">La pagina potrebbe addebitare denaro</translation>
<translation id="3212581601480735796">La tua attività su <ph name="HOSTNAME" /> è monitorata</translation>
+<translation id="3212623355668894776">Chiudi tutte le finestre Ospite per eliminare la tua attività di navigazione dal dispositivo.</translation>
<translation id="3215092763954878852">Impossibile usare WebAuthn</translation>
<translation id="3218181027817787318">Relativo</translation>
<translation id="3225919329040284222">Il server ha presentato un certificato che non corrisponde alle previsioni integrate. Queste previsioni sono incluse per determinati siti web con protezione elevata allo scopo di proteggerti.</translation>
@@ -699,6 +711,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3784372983762739446">Dispositivi Bluetooth</translation>
<translation id="3787705759683870569">Data di scadenza: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Dimensione 16</translation>
+<translation id="3789841737615482174">Installa</translation>
<translation id="3793574014653384240">Numero e cause degli arresti anomali che si sono verificati di recente</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Nome carattere richiesto</translation>
@@ -750,6 +763,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4056223980640387499">Seppia</translation>
<translation id="4058922952496707368">Chiave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">L'acquisizione della schermata è stata ripresa.</translation>
<translation id="4067947977115446013">Aggiungi un indirizzo valido</translation>
<translation id="4072486802667267160">Si è verificato un errore durante l'elaborazione dell'ordine. Riprova.</translation>
<translation id="4075732493274867456">Il client e il server non supportano un pacchetto di crittografia o una versione del protocollo SSL comuni.</translation>
@@ -770,7 +784,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4123572138124678573">Tripla perforatura in basso</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 altro}other{# altri}}</translation>
<translation id="4130226655945681476">Controllare i cavi di rete, il modem e il router</translation>
-<translation id="413544239732274901">Ulteriori informazioni</translation>
+<translation id="413544239732274901">Scopri di più</translation>
<translation id="4142935452406587478">Vassoio 10</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizza impostazioni predefinite globali (Rileva)</translation>
@@ -834,6 +848,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4297502707443874121">Miniatura della pagina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Espandi</translation>
<translation id="4300675098767811073">Perforatura multipla a destra</translation>
+<translation id="4302514097724775343">Tocca il dinosauro per giocare</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Impossibile accedere al file</translation>
<translation id="4305817255990598646">Cambia</translation>
@@ -912,6 +927,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4658638640878098064">Pinzatura in alto a sinistra</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realtà virtuale</translation>
+<translation id="4675657451653251260">In modalità ospite, non vedrai alcuna informazione del profilo Chrome. Puoi <ph name="LINK_BEGIN" />accedere<ph name="LINK_END" /> per visualizzare le informazioni del tuo Account Google, quali password e metodi di pagamento.</translation>
<translation id="467662567472608290">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza contiene errori. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="4677585247300749148"><ph name="URL" /> vuole rispondere agli eventi di accessibilità</translation>
<translation id="467809019005607715">Presentazioni Google</translation>
@@ -939,6 +955,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4761104368405085019">Utilizzare il microfono</translation>
<translation id="4764776831041365478">La pagina web all'indirizzo <ph name="URL" /> potrebbe essere temporaneamente non disponibile oppure è stata permanentemente spostata a un nuovo indirizzo web.</translation>
<translation id="4766713847338118463">Doppia pinzatura in basso</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Attività che verranno salvate sul dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Qualsiasi file scaricato in questa finestra
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Si è verificato un errore sconosciuto.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Popup bloccato}other{# popup bloccati}}</translation>
<translation id="4780366598804516005">Mailbox 1</translation>
@@ -1101,11 +1123,13 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5386426401304769735">Il certificato di questo sito contiene un certificato che è stato firmato utilizzando SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Impuntura a destra</translation>
+<translation id="5398772614898833570">Annunci bloccati</translation>
<translation id="5400836586163650660">Grigio</translation>
<translation id="540969355065856584">Questo server non è riuscito a verificare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato valido in questa fase. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che ha intercettato la connessione.</translation>
<translation id="541416427766103491">Fascicolatore 4</translation>
<translation id="5421136146218899937">Cancella dati di navigazione...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vuole inviarti notifiche</translation>
+<translation id="542872847390508405">Stai navigando come ospite</translation>
<translation id="5430298929874300616">Rimuovi preferito</translation>
<translation id="5439770059721715174">Errore di convalida dello schema in "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordine inverso a faccia in su</translation>
@@ -1147,12 +1171,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5571083550517324815">Impossibile ritirare dall'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
<translation id="5580958916614886209">Controlla il mese di scadenza e riprova</translation>
<translation id="5586446728396275693">Nessun indirizzo salvato</translation>
+<translation id="5593349413089863479">La connessione non è completamente sicura</translation>
<translation id="5595485650161345191">Modifica indirizzo</translation>
<translation id="5598944008576757369">Scegli il metodo di pagamento</translation>
<translation id="560412284261940334">Gestione non supportata</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Il sito potrebbe essere falso o fraudolento. Chrome ti consiglia di uscire immediatamente.</translation>
<translation id="5610142619324316209">Verificare la connessione</translation>
<translation id="5610807607761827392">Puoi gestire carte e indirizzi nelle <ph name="BEGIN_LINK" />Impostazioni<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduci la pagina con Google Traduttore</translation>
@@ -1224,6 +1248,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5901630391730855834">Giallo</translation>
<translation id="5905445707201418379">Bloccato secondo la norma di partenza di <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizzati)</translation>
+<translation id="5913377024445952699">Acquisizione schermo in pausa</translation>
<translation id="59174027418879706">Attivato</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">On</translation>
@@ -1236,6 +1261,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5963413905009737549">Sezione</translation>
<translation id="5967592137238574583">Modifica informazioni di contatto</translation>
<translation id="5967867314010545767">Rimuovi da cronologia</translation>
+<translation id="5968793460449681917">A ogni visita</translation>
<translation id="5975083100439434680">Diminuisci lo zoom</translation>
<translation id="5979084224081478209">Controlla password</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1290,7 +1316,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6151417162996330722">Il certificato del server ha un periodo di validità troppo lungo.</translation>
<translation id="6157877588268064908">Seleziona un indirizzo per conoscere i requisiti e i metodi di spedizione</translation>
<translation id="6165508094623778733">Ulteriori informazioni</translation>
-<translation id="6177128806592000436">La tua connessione a questo sito non è protetta</translation>
+<translation id="6177128806592000436">La tua connessione a questo sito non è sicura</translation>
<translation id="6180316780098470077">Intervallo tra tentativi</translation>
<translation id="6196640612572343990">Blocca cookie di terze parti</translation>
<translation id="6203231073485539293">Controlla la connessione a Internet</translation>
@@ -1390,6 +1416,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6587923378399804057">Link copiato</translation>
<translation id="6591833882275308647">Il tuo dispositivo <ph name="DEVICE_TYPE" /> non è gestito</translation>
<translation id="6596325263575161958">Opzioni di crittografia</translation>
+<translation id="6596892391065203054">La stampa di questi contenuti è stata bloccata dall'amministratore.</translation>
<translation id="6604181099783169992">Sensori di movimento o della luce</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Contenuti protetti</translation>
@@ -1429,7 +1456,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Lilla</translation>
<translation id="6786747875388722282">Estensioni</translation>
-<translation id="6790428901817661496">Play</translation>
+<translation id="6790428901817661496">Riproduci</translation>
<translation id="679355240208270552">Ignorato perché la ricerca predefinita non è attiva secondo la norma.</translation>
<translation id="6794951432696553238">Verifica più velocemente le tue carte usando Windows Hello d'ora in poi</translation>
<translation id="681021252041861472">Campo obbligatorio</translation>
@@ -1449,6 +1476,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6895330447102777224">La carta è stata confermata</translation>
<translation id="6897140037006041989">User-agent</translation>
<translation id="6898699227549475383">Organizzazione (O)</translation>
+<translation id="6907293445143367439">Consenti al sito <ph name="SITE_NAME" /> di:</translation>
<translation id="6910240653697687763"><ph name="URL" /> vuole avere il controllo totale dei tuoi dispositivi MIDI</translation>
<translation id="6915804003454593391">Utente:</translation>
<translation id="6934672428414710184">Questo nome proviene dal tuo Account Google</translation>
@@ -1560,6 +1588,7 @@ Ulteriori dettagli:
<translation id="7346048084945669753">Con affiliazione:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Riga di comando</translation>
+<translation id="7359588939039777303">Annunci bloccati.</translation>
<translation id="7372973238305370288">risultato della ricerca</translation>
<translation id="7374733840632556089">Questo problema si verifica a causa di un certificato installato sul dispositivo da te o da un'altra persona. È noto che il certificato viene usato per monitorare e intercettare le reti e non è considerato attendibile da Chrome. Esistono alcuni casi leciti per il monitoraggio, ad esempio su una rete scolastica o aziendale, ma Chrome vuole assicurarsi che tu sappia che viene effettuato, anche se non puoi interromperlo. Il monitoraggio potrebbe essere effettuato in qualsiasi browser o applicazione che accede al Web.</translation>
<translation id="7375818412732305729">Viene allegato un file</translation>
@@ -1734,6 +1763,7 @@ Ulteriori dettagli:
<translation id="7976214039405368314">Numero eccessivo di richieste</translation>
<translation id="7977538094055660992">Dispositivo di uscita</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Per visualizzare i contenuti di realtà aumentata, installa ARCore</translation>
<translation id="799149739215780103">Rilegatura</translation>
<translation id="7995512525968007366">Non specificato</translation>
<translation id="800218591365569300">Prova a chiudere altri programmi o schede per liberare spazio in memoria.</translation>
@@ -1783,7 +1813,7 @@ Ulteriori dettagli:
<translation id="8202097416529803614">Riepilogo dell’ordine</translation>
<translation id="8202370299023114387">Conflitto</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
-<translation id="8211406090763984747">La connessione è protetta</translation>
+<translation id="8211406090763984747">La connessione è sicura</translation>
<translation id="8218327578424803826">Posizione assegnata:</translation>
<translation id="8220146938470311105">C7/C6 (Busta)</translation>
<translation id="8221250263817408492">Hai appena inserito la tua password su un sito ingannevole. Chromium ti consiglia di visitare il sito <ph name="WEBSITE_1" /> e altri siti in cui utilizzi questa password e di cambiarla subito.</translation>
@@ -1861,24 +1891,38 @@ Ulteriori dettagli:
<translation id="8507227106804027148">Riga di comando</translation>
<translation id="8508648098325802031">Icona Ricerca</translation>
<translation id="8522552481199248698">Chrome può aiutarti a proteggere il tuo Account Google e a modificare la password.</translation>
+<translation id="8525306231823319788">Schermo intero</translation>
<translation id="8530813470445476232">Cancella la cronologia di navigazione e i cookie, svuota la cache e altro ancora nelle impostazioni di Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; per visualizzare l'elenco di URL bloccati e altre norme applicate dall'amministratore di sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Tripla pinzatura in basso</translation>
<translation id="8543181531796978784">Puoi <ph name="BEGIN_ERROR_LINK" />segnalare un problema di rilevamento<ph name="END_ERROR_LINK" /> oppure, se sei consapevole dei rischi per la tua sicurezza, <ph name="BEGIN_LINK" />visita questo sito non sicuro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Il codice CVC si trova sul lato posteriore della carta.</translation>
+<translation id="8558485628462305855">Per visualizzare i contenuti di realtà aumentata, aggiorna ARCore</translation>
<translation id="8559762987265718583">Impossibile stabilire una connessione privata con il sito <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perché data e ora del dispositivo (<ph name="DATE_AND_TIME" />) sono sbagliate.</translation>
<translation id="8564182942834072828">Documenti separati/Copie non fascicolate</translation>
<translation id="8564985650692024650">Chromium ti consiglia di reimpostare la password di <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, se l'hai utilizzata su altri siti.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Attività che non verranno salvate sul dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pagine visualizzate in questa finestra
+ <ph name="LIST_ITEM" />Cookie e dati relativi al sito
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Usa Touch ID per verificare più velocemente le carte</translation>
<translation id="858637041960032120">Aggiungi telefono</translation>
<translation id="8589998999637048520">Migliore qualità</translation>
+<translation id="8600271352425265729">Solo questa volta</translation>
<translation id="860043288473659153">Nome del titolare della carta</translation>
<translation id="8606726445206553943">Utilizzare i tuoi dispositivi MIDI</translation>
+<translation id="8612761427948161954">Ciao <ph name="USERNAME" />,
+ <ph name="BR" />
+ Stai navigando come ospite</translation>
<translation id="861775596732816396">Dimensione 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nessuna password corrispondente. Mostra tutte le password salvate.</translation>
<translation id="8625384913736129811">Salva la carta su questo dispositivo</translation>
+<translation id="8627040765059109009">Acquisizione schermo ripresa</translation>
<translation id="8657078576661269990">L'amministratore ha bloccato la condivisione da <ph name="ORIGIN_NAME" /> a <ph name="VM_NAME_1" /> e <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Riepilogo ordine, <ph name="TOTAL_LABEL" />, altri dettagli</translation>
<translation id="867224526087042813">Firma</translation>
@@ -1941,6 +1985,7 @@ Ulteriori dettagli:
<translation id="8912362522468806198">Google Account</translation>
<translation id="8913778647360618320">Pulsante Gestisci metodi di pagamento, premi Invio per gestire i tuoi pagamenti e i dati delle carte di credito nelle impostazioni di Chrome</translation>
<translation id="8918231688545606538">Questa pagina è sospetta</translation>
+<translation id="8922013791253848639">Consenti sempre gli annunci su questo sito</translation>
<translation id="892588693504540538">Perforatura in alto a destra</translation>
<translation id="8931333241327730545">Vuoi salvare la scheda nel tuo Account Google?</translation>
<translation id="8932102934695377596">L'orologio è indietro</translation>
@@ -2012,6 +2057,7 @@ Ulteriori dettagli:
<translation id="9183302530794969518">Documenti Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utilizza un protocollo non supportato.</translation>
<translation id="9191834167571392248">Perforatura in basso a sinistra</translation>
+<translation id="9199905725844810519">La stampa è bloccata</translation>
<translation id="9205078245616868884">I tuoi dati vengono criptati con la tua passphrase di sincronizzazione. Inseriscila per avviare la sincronizzazione.</translation>
<translation id="9207861905230894330">Impossibile aggiungere l'articolo.</translation>
<translation id="9213433120051936369">Personalizza aspetto</translation>
@@ -2022,8 +2068,10 @@ Ulteriori dettagli:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Potresti non riuscire più ad accedere al tuo Account Google. Chromium consiglia di cambiare subito la password. Ti verrà chiesto di eseguire l'accesso.</translation>
<translation id="939736085109172342">Nuova cartella</translation>
+<translation id="945522503751344254">Invia feedback</translation>
<translation id="945855313015696284">Controlla le informazioni riportate di seguito ed elimina le schede non valide</translation>
<translation id="950736567201356821">Tripla perforatura in alto</translation>
+<translation id="951941430552851965">L'acquisizione della schermata è stata messa in pausa dall'amministratore a causa dei contenuti visualizzati.</translation>
<translation id="961663415146723894">Rilegatura in basso</translation>
<translation id="962484866189421427">Questi contenuti potrebbero installare app ingannevoli che si spacciano per qualcos'altro o raccolgono dati che potrebbero essere usati per monitorare la tua attività. <ph name="BEGIN_LINK" />Mostra comunque<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Build ufficiale</translation>
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index 88ef584a536..00ee23546db 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">הזנת ×ת הסיסמה ב×תר ש×ינו מנוהל על-ידי ×”×רגון שלך. כדי להגן על החשבון, ×ין לעשות שימוש חוזר בסיסמה ב×פליקציות וב××ª×¨×™× ×חרי×.</translation>
<translation id="1263231323834454256">רשימת קרי××”</translation>
+<translation id="1267173982554786072">â€<ph name="BEGIN_BOLD" />
+ פעילות ×©×œ× ×ª×™×©×ž×¨ במכשיר ×”×–×”
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />×”×“×¤×™× ×©×ž×•×¦×’×™× ×‘×—×œ×•×Ÿ ×”×–×”
+ <ph name="LIST_ITEM" />קובצי cookie ונתוני ×תר
+ <ph name="LIST_ITEM" />פרטי חשבון (<ph name="LINK_BEGIN" />יצי××”<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">שיטת ×יסוף</translation>
<translation id="1281476433249504884">×ž×¢×¨×™× 1</translation>
<translation id="1285320974508926690">××™× ×™ רוצה לקבל ×ª×¨×’×•× ×©×œ ×תר ×–×”</translation>
@@ -231,7 +239,7 @@
כדי להגדיר מ×פייני ×בטחה ומ××¤×™×™× ×™× ××—×¨×™× ×¢×‘×•×¨ ×תר מסוי×.</translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1783075131180517613">יש לעדכן ×ת ביטוי הסיסמה של הסנכרון.</translation>
-<translation id="1787142507584202372">×›×ן מופיעות הכרטיסיות ש×תה פותח</translation>
+<translation id="1787142507584202372">×›×ן מופיעות הכרטיסיות שפתחת</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1798447301915465742">â€<ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT" />, ניתן לבצע כמה פעולות, יש להקיש על Tab כדי לעבור ביניהן</translation>
<translation id="1800473098294731951">B9</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">â€×›×“×™ להשתמש בסיסמ×ות השמורות בחשבון Google, עליך להיכנס שוב לחשבון</translation>
<translation id="2053111141626950936">×“×¤×™× ×‘<ph name="LANGUAGE" /> ×œ× ×™×ª×•×¨×’×ž×•.</translation>
<translation id="2053553514270667976">מיקוד</translation>
+<translation id="2054665754582400095">הנוכחות שלך ×ונליין</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{הצעה ×חת}two{שתי הצעות}many{# הצעות}other{# הצעות}}</translation>
<translation id="2079545284768500474">ביטול הפעולה</translation>
<translation id="20817612488360358">â€× ×§×‘×¢ שימוש בהגדרות שרת Proxy של מערכת ×ך בנוסף מצוינת ×’× ×ª×¦×•×¨×” מפורשת של שרת Proxy.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">â€×פליקציות Android</translation>
<translation id="2107021941795971877">תמיכות להדפסה</translation>
<translation id="2108755909498034140">×תחול המחשב</translation>
+<translation id="2111166930115883695">יש להקיש על המקש 'רווח' כדי לשחק</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">כרטיס</translation>
<translation id="2114841414352855701">המערכת התעלמה ×ž×©×•× ×©×”×ž×“×™× ×™×•×ª בוטלה על ידי <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">ביטול תשלו×</translation>
<translation id="2147827593068025794">סנכרון ברקע</translation>
<translation id="2148613324460538318">הוספת כרטיס</translation>
+<translation id="2149968176347646218">החיבור ×ינו מ×ובטח</translation>
<translation id="2154054054215849342">סנכרון ×ינו זמין בדומיין שלך</translation>
<translation id="2154484045852737596">עריכת כרטיס</translation>
<translation id="2161656808144014275">טקסט</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">מדיניות</translation>
<translation id="2183608646556468874">מספר טלפון</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{כתובת ×חת}two{שתי כתובות}many{# כתובות}other{# כתובות}}</translation>
-<translation id="2187243482123994665">נוכחות משתמש</translation>
<translation id="2187317261103489799">זהה (ברירת מחדל)</translation>
<translation id="2188375229972301266">× ×™×§×•×‘×™× ×ž×¨×•×‘×™× ×‘×—×œ×§ התחתון</translation>
<translation id="2202020181578195191">עליך להזין שנת תפוגה חוקית</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">×”×תר המבוקש נר××” מזויף</translation>
<translation id="2850739647070081192">Invite (Envelope)‎</translation>
<translation id="2856444702002559011">ייתכן ×©×ª×•×§×¤×™× ×ž× ×¡×™× ×œ×’× ×•×‘ ×ת ×”×¤×¨×˜×™× ×©×œ×š מה×תר <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (לדוגמה, סיסמ×ות, הודעות ×ו כרטיסי ×שר××™). <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ב×תר ×”×–×” מוצגות מודעות מפריעות ×ו מטעות.</translation>
<translation id="2878197950673342043">קיפול כרזה</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">×ž×™×§×•× ×—×œ×•× ×•×ª</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">â€×”צעות מ×ת Google</translation>
<translation id="3002501248619246229">בדיקת מדיה במגש קלט</translation>
<translation id="3005723025932146533">הצגת עותק שמור</translation>
-<translation id="3007719053326478567">מנהל המערכת ×—×¡× ×ת ×”×פשרות להדפיס ×ת התוכן ×”×–×”</translation>
<translation id="3008447029300691911">יש להזין ×ת קוד ×”×ימות של הכרטיס <ph name="CREDIT_CARD" />. ל×חר ×”×ישור, פרטי הכרטיס שלך ישותפו ×¢× ×”×תר ×”×–×”.</translation>
<translation id="3010559122411665027">רשומה ברשימה "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">נחסמה ×וטומטית</translation>
<translation id="3016780570757425217">לדעת מה ×”×ž×™×§×•× ×©×œ×š</translation>
+<translation id="3017086357773116182">â€<ph name="REMOVE_SUGGESTION_SUFFIX" />, יש להקיש על Tab ו××– על Enter כדי להסיר ×ת ההצעה.</translation>
<translation id="3023071826883856138">You4 (Envelope)‎</translation>
<translation id="3024663005179499861">סוג המדיניות שגוי</translation>
<translation id="3037605927509011580">×וי, ל×!</translation>
@@ -539,7 +550,7 @@
<translation id="3150653042067488994">שגי×ת שרת זמנית</translation>
<translation id="3154506275960390542">דף ×–×” כולל טופס שעשוי להישלח ב×ופן ×œ× ×ž×ובטח. ×”× ×ª×•× ×™× ×©×©×•×œ×—×™× ×™×”×™×• ×’×œ×•×™×™× ×‘×ž×”×œ×š ההעברה, וקיימת סכנה שמישהו ישנה ×ת ×”×¤×¨×˜×™× ×©×”×©×¨×ª יקבל.</translation>
<translation id="3157931365184549694">שחזור</translation>
-<translation id="3162559335345991374">â€×™×™×ª×›×Ÿ שתידרש להיכנס לדף ההתחברות של רשת ×”-Wi-Fi שבה ×תה משתמש.</translation>
+<translation id="3162559335345991374">â€×™×™×ª×›×Ÿ שרשת ×”-Wi-Fi דורשת כניסה לדף ההתחברות שלה.</translation>
<translation id="3167968892399408617">â€×“×¤×™× ×©×”×¦×’×ª בכרטיסיות מצב ×נונימי ×œ× ×™×™×©×ž×¨×• בהיסטוריית הדפדפן, ב×חסון קובצי ×”-Cookie ×ו בהיסטוריית ×”×—×™×¤×•×©×™× ×œ×חר שכל כרטיסיות המצב ×”×נונימי ייסגרו. ×§×‘×¦×™× ×©×”×•×¨×“×ª ×ו סימניות שיצרת יישמרו.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">××™</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">מסומן בסימנייה</translation>
<translation id="3209034400446768650">כניסה לדף עשויה להיות כרוכה בתשלו×</translation>
<translation id="3212581601480735796">הפעילות שלך ב-<ph name="HOSTNAME" /> מנוטרת</translation>
+<translation id="3212623355668894776">כד××™ לסגור ×ת כל חלונות ×”××•×¨×—×™× ×›×“×™ שפעילות הגלישה תימחק מהמכשיר ×”×–×”.</translation>
<translation id="3215092763954878852">â€×œ× ניתן להשתמש ב-WebAuthn</translation>
<translation id="3218181027817787318">יחסי</translation>
<translation id="3225919329040284222">השרת הציג ×ישור ש×ינו תו×× ×ת הציפיות המובנות. ציפיות ×לה נכללות עבור ×תרי ×ינטרנט ×ž×¡×•×™×ž×™× ×‘×¢×œ×™ ×בטחה גבוהה כדי להגן עליך.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">â€×ž×›×©×™×¨×™ Bluetooth</translation>
<translation id="3787705759683870569">ת×ריך תפוגה: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">גודל 16</translation>
+<translation id="3789841737615482174">התקנה</translation>
<translation id="3793574014653384240">כמות הקריסות ש×ירעו ל×חרונה והסיבות שהובילו לקריסות ×”×לה</translation>
<translation id="3797522431967816232">Prc3 (Envelope)‎</translation>
<translation id="3799805948399000906">גופן שהתבקש</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">חו×-ספיה</translation>
<translation id="4058922952496707368">מפתח "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)‎</translation>
+<translation id="4067669230157909013">×פשרות ×¦×™×œ×•× ×”×ž×¡×š הופעלה מחדש.</translation>
<translation id="4067947977115446013">הוספה של כתובת חוקית</translation>
<translation id="4072486802667267160">התרחשה שגי××” במהלך עיבוד ×”×ª×©×œ×•× ×©×œ×š. יש לנסות שוב.</translation>
<translation id="4075732493274867456">â€×”לקוח והשרת ××™× × ×ª×•×ž×›×™× ×‘×’×¨×¡×” נפוצה של פרוטוקול SSL ×ו בחבילת הצפנה.</translation>
@@ -835,6 +849,7 @@
<translation id="4297502707443874121">תמונה ממוזערת של הדף <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">הרחבה</translation>
<translation id="4300675098767811073">× ×™×§×•×‘×™× ×ž×¨×•×‘×™× ×‘×¦×“ ימין</translation>
+<translation id="4302514097724775343">יש להקיש על הדינוז×ור כדי לשחק</translation>
<translation id="4302965934281694568">Chou3 (Envelope)‎</translation>
<translation id="4305666528087210886">×œ× × ×™×ª×Ÿ לגשת לקובץ</translation>
<translation id="4305817255990598646">מעבר</translation>
@@ -913,6 +928,7 @@
<translation id="4658638640878098064">סיכת הידוק בפינה השמ×לית העליונה</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">מצי×ות מדומה</translation>
+<translation id="4675657451653251260">â€×‘מצב ×ורח ×œ× × ×™×ª×Ÿ לר×ות ×¤×¨×˜×™× ×©×œ פרופיל Chrome. עליך <ph name="LINK_BEGIN" />להיכנס<ph name="LINK_END" /> כדי לגשת למידע של חשבון Google שלך, כמו סיסמ×ות ו×מצעי תשלו×.</translation>
<translation id="467662567472608290">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו מכיל שגי×ות. ייתכן שהסיבה לכך ×”×™× ×”×’×“×¨×” שגויה ×ו תוקף המיירט ×ת החיבור שלך.</translation>
<translation id="4677585247300749148"><ph name="URL" /> רוצה להגיב ל×ירועי נגישות</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -940,6 +956,12 @@
<translation id="4761104368405085019">להשתמש במיקרופון</translation>
<translation id="4764776831041365478">ייתכן שדף ×”×ינטרנט בכתובת <ph name="URL" /> ×ינו פעיל זמנית, ×ו שהועבר לכתובת ×ינטרנט חדשה לצמיתות.</translation>
<translation id="4766713847338118463">שתי סיכות הידוק בחלק התחתון</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ הפעילות שלך שנשמרת במכשיר:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />כל ×”×§×‘×¦×™× ×©×”×•×¨×“×ª בחלון ×”×–×”
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">â€×ירעה שגי××” ×œ× ×ž×•×›×¨×ª.
@@ -1106,11 +1128,13 @@ Del</translation>
<translation id="5386426401304769735">â€×©×¨×©×¨×ª ×”××™×©×•×¨×™× ×©×œ ×”×תר ×”×–×” כוללת ×ישור ×©× ×—×ª× ×‘×מצעות SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">הידוק קצוות בצד ימין</translation>
+<translation id="5398772614898833570">מודעות חסומות</translation>
<translation id="5400836586163650660">×פור</translation>
<translation id="540969355065856584">שרת ×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />; ×ישור ×”×בטחה שלו ×ינו תקף כעת. הסיבה לכך עשויה להיות תצורה שגויה ×ו שתוקף מיירט ×ת החיבור שלך.</translation>
<translation id="541416427766103491">×ž×¢×¨×™× 4</translation>
<translation id="5421136146218899937">ניקוי נתוני גלישה...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> רוצה לשלוח לך הודעות</translation>
+<translation id="542872847390508405">גלישה ×›×ורח</translation>
<translation id="5430298929874300616">הסרת סימנייה</translation>
<translation id="5439770059721715174">שגי×ת ×ימות סכימה ב-"<ph name="ERROR_PATH" />"â€: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">בסדר הפוך ×¢× ×”×¤× ×™× ×›×œ×¤×™ מעלה</translation>
@@ -1153,12 +1177,12 @@ Del</translation>
<translation id="5571083550517324815">×œ× × ×™×ª×Ÿ לבצע ×יסוף מהכתובת הזו. עליך לבחור כתובת ×חרת.</translation>
<translation id="5580958916614886209">יש לבדוק ×ת חודש התפוגה ולנסות שוב</translation>
<translation id="5586446728396275693">×œ× × ×©×ž×¨×• כתובות</translation>
+<translation id="5593349413089863479">החיבור ×œ× ×œ×’×ž×¨×™ מ×ובטח</translation>
<translation id="5595485650161345191">עריכת כתובת</translation>
<translation id="5598944008576757369">בחירת ×מצעי תשלו×</translation>
<translation id="560412284261940334">ניהול ×ינו נתמך</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">â€×”×תר ×”×–×” עשוי להיות מזויף ×ו לשמש להונ××”. ההמלצה של Chrome ×”×™× ×œ×¦×ת ממנו עכשיו.</translation>
<translation id="5610142619324316209">לבדוק ×ת החיבור</translation>
<translation id="5610807607761827392">×פשר לנהל ×ת ×”×›×¨×˜×™×¡×™× ×•×”×›×ª×•×‘×•×ª דרך ×”<ph name="BEGIN_LINK" />הגדרות<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">â€× ×™×ª×Ÿ ×œ×ª×¨×’× ×ת הדף ×”×–×” ב×מצעות Google Translate</translation>
@@ -1230,6 +1254,7 @@ Del</translation>
<translation id="5901630391730855834">צהוב</translation>
<translation id="5905445707201418379">× ×—×¡× ×‘×”×ª×× ×œ×ž×“×™× ×™×•×ª המקור של <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (מסונכרני×)</translation>
+<translation id="5913377024445952699">×פשרות ×¦×™×œ×•× ×”×ž×¡×š מושהית</translation>
<translation id="59174027418879706">מופעל</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">מופעל</translation>
@@ -1242,6 +1267,7 @@ Del</translation>
<translation id="5963413905009737549">קטע</translation>
<translation id="5967592137238574583">עריכת ×”×¤×¨×˜×™× ×œ×™×¦×™×¨×ª קשר</translation>
<translation id="5967867314010545767">הסרה מההיסטוריה</translation>
+<translation id="5968793460449681917">בכל ביקור</translation>
<translation id="5975083100439434680">התרחקות</translation>
<translation id="5979084224081478209">בדיקת הסיסמ×ות</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1397,6 +1423,7 @@ Del</translation>
<translation id="6587923378399804057">קישור שהעתקת</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> ×–×” ×ינו מנוהל</translation>
<translation id="6596325263575161958">×פשרויות הצפנה</translation>
+<translation id="6596892391065203054">מנהל המערכת ×—×¡× ×ת ×”×פשרות להדפיס ×ת התוכן ×”×–×”.</translation>
<translation id="6604181099783169992">חיישני תנועה ×ו ×ור</translation>
<translation id="6609880536175561541">Prc7 (Envelope)‎</translation>
<translation id="6612358246767739896">תוכן מוגן</translation>
@@ -1456,6 +1483,7 @@ Del</translation>
<translation id="6895330447102777224">הכרטיס שלך מ×ושר</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">â€×רגון (O)</translation>
+<translation id="6907293445143367439">×”×תר <ph name="SITE_NAME" /> יוכל:</translation>
<translation id="6910240653697687763">â€<ph name="URL" /> רוצה לקבל שליטה מל××” על מכשירי ×”-MIDI שלך</translation>
<translation id="6915804003454593391">משתמש:</translation>
<translation id="6934672428414710184">â€×”×©× ×”×–×” ×”×•× ×ž×—×©×‘×•×Ÿ Google שלך</translation>
@@ -1567,6 +1595,7 @@ Del</translation>
<translation id="7346048084945669753">משויך:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">שורת פקודה </translation>
+<translation id="7359588939039777303">מודעות חסומות.</translation>
<translation id="7372973238305370288">תוצ×ת חיפוש</translation>
<translation id="7374733840632556089">â€×”בעיה הזו מתרחשת בגלל ×ישור שהותקן במכשיר על ידך ×ו על ידי מישהו ×חר. ×”×ישור ×”×–×” מוכר ×›×ישור שמשמש לצורך מעקב ×חרי רשתות ויירוט × ×ª×•× ×™× ×ž×¨×©×ª×•×ª, ×•×”×•× ×œ× × ×—×©×‘ כמהימן על ידי Chrome. ×‘×ž×§×¨×™× ×ž×¡×•×™×ž×™× ×ž×ª×‘×¦×¢ מעקב מסיבות לגיטימיות, כמו במוסדות חינוך ×ו ברשתות של חברות, ×ך Chrome רוצה ×œ×•×•×“× ×©×”×ž×¢×§×‘ מתבצע בידיעתך ×’× ×× ×ין לך ×פשרות לעצור ×ותו. המעקב עשוי להתבצע בכל דפדפן ×ו ×פליקציה ×©× ×™×’×©×™× ×œ×ינטרנט.</translation>
<translation id="7375818412732305729">מצורף קובץ</translation>
@@ -1707,7 +1736,7 @@ Del</translation>
<translation id="7813600968533626083">â€×”×× ×œ×”×¡×™×¨ מ-Chrome הצעות בשביל טפסי×?</translation>
<translation id="781440967107097262">לשתף ×ת הלוח?</translation>
<translation id="7815407501681723534">נמצ×ו <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ×‘× ×•×©× '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782886543891417279">â€×™×™×ª×›×Ÿ שתידרש להיכנס לדף ההתחברות של רשת ×”-Wi-Fi שבה ×תה משתמש (<ph name="WIFI_NAME" />).</translation>
+<translation id="782886543891417279">â€×™×™×ª×›×Ÿ שרשת ×”-Wi-Fi דורשת כניסה לדף ההתחברות שלה. (<ph name="WIFI_NAME" />).</translation>
<translation id="7836231406687464395">Postfix (Envelope)‎</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{לל×}=1{×פליקציה ×חת (<ph name="EXAMPLE_APP_1" />)}=2{2 ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}many{# ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
<translation id="785549533363645510">×¢× ×–×ת, עדיין ×פשר לר×ות ×ותך. המעבר למצב גלישה בסתר ×œ× ×ž×¡×ª×™×¨ ×ת הגלישה שלך מהמעסיק, מספק ×”×ינטרנט ×ו מה××ª×¨×™× ×©××œ×™×”× × ×›× ×¡×ª.</translation>
@@ -1741,6 +1770,7 @@ Del</translation>
<translation id="7976214039405368314">יותר מדי בקשות</translation>
<translation id="7977538094055660992">מכשיר פלט</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">â€×›×“×™ להציג תוכן של מצי×ות רבודה, צריך להתקין ×ת ARCore</translation>
<translation id="799149739215780103">כריכה</translation>
<translation id="7995512525968007366">×œ× ×¦×•×™×Ÿ</translation>
<translation id="800218591365569300">מומלץ לסגור כרטיסיות ×ו תוכניות ×חרות וכך לפנות ×ž×§×•× ×‘×–×™×›×¨×•×Ÿ.</translation>
@@ -1868,24 +1898,38 @@ Del</translation>
<translation id="8507227106804027148">שורת פקודה</translation>
<translation id="8508648098325802031">סמל החיפוש</translation>
<translation id="8522552481199248698">â€×‘עזרת Chrome ×פשר להגן על חשבון Google ולשנות ×ת הסיסמה.</translation>
+<translation id="8525306231823319788">מסך מל×</translation>
<translation id="8530813470445476232">â€×‘הגדרות Chrome, ניתן לנקות ×ת היסטוריית הגלישה, ×ת קובצי ×”-cookie, ×ת המטמון ועוד</translation>
<translation id="8533619373899488139">â€×‘כתובת &lt;strong&gt;chrome://policy&lt;/strong&gt; מוצגת רשימה של כתובות ××ª×¨×™× ×©× ×—×¡×ž×• ×•×ª×§× ×•× ×™× ××—×¨×™× ×©× ××›×¤×™× ×¢×œ ידי מנהל המערכת.</translation>
<translation id="8541158209346794904">â€×ž×›×©×™×¨ Bluetooth</translation>
<translation id="8542014550340843547">3 סיכות הידוק בחלק התחתון</translation>
<translation id="8543181531796978784">ב×פשרותך <ph name="BEGIN_ERROR_LINK" />לדווח על בעיית זיהוי<ph name="END_ERROR_LINK" /> ×ו, ×× ×¡×™×›×•× ×™ ×”×בטחה ×ž×•×‘× ×™× ×œ×š, <ph name="BEGIN_LINK" />להיכנס ל×תר ×”×–×”, ש×ינו מ×ובטח<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">קוד ×”×ימות × ×ž×¦× ×‘×’×‘ הכרטיס.</translation>
+<translation id="8558485628462305855">â€×›×“×™ להציג תוכן של מצי×ות רבודה, צריך לעדכן ×ת ARCore</translation>
<translation id="8559762987265718583">×œ× × ×™×ª×Ÿ ליצור חיבור פרטי ×ל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> מפני שהת×ריך והשעה (<ph name="DATE_AND_TIME" />) במכשיר שלך שגויי×.</translation>
<translation id="8564182942834072828">×ž×¡×ž×›×™× × ×¤×¨×“×™×/×¢×•×ª×§×™× ×œ× ×ž×¡×•×“×¨×™×</translation>
<translation id="8564985650692024650">â€×× ×”×–× ×ª ×ת הסיסמה של <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ב××ª×¨×™× ×חרי×, ההמלצה של Chromium ×”×™× ×œ×פס ×ותה.</translation>
+<translation id="856887218454489335">â€<ph name="BEGIN_BOLD" />
+ פעילות ×©×œ× ×ª×™×©×ž×¨ במכשיר ×”×–×”:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />×”×“×¤×™× ×©×ž×•×¦×’×™× ×‘×—×œ×•×Ÿ ×”×–×”
+ <ph name="LIST_ITEM" />קובצי cookie ונתוני ×תר
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">â€×©×™×ž×•×© ב-Touch ID כדי ל×שר ×›×¨×˜×™×¡×™× ×ž×”×¨ יותר</translation>
<translation id="858637041960032120">הוספת מספר טלפון</translation>
<translation id="8589998999637048520">×”×יכות הטובה ביותר</translation>
+<translation id="8600271352425265729">רק הפע×</translation>
<translation id="860043288473659153">×©× ×‘×¢×œ הכרטיס</translation>
<translation id="8606726445206553943">â€×œ×”שתמש במכשירי ×”-MIDI שלך</translation>
+<translation id="8612761427948161954">×”×™×™ <ph name="USERNAME" />,
+ <ph name="BR" />
+ הגלישה מתבצעת כרגע במצב ×ורח</translation>
<translation id="861775596732816396">גודל 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">×ין סיסמ×ות תו×מות. יש להציג ×ת כל הסיסמ×ות השמורות.</translation>
<translation id="8625384913736129811">שמירת כרטיס זה במכשיר הנוכחי</translation>
+<translation id="8627040765059109009">×פשרות ×¦×™×œ×•× ×”×ž×¡×š ממשיכה לפעול</translation>
<translation id="8657078576661269990">×”×פשרות לשיתוף מ-<ph name="ORIGIN_NAME" /> ×ל <ph name="VM_NAME_1" /> ו×ל <ph name="VM_NAME_2" /> נחסמה על ידי מנהל המערכת</translation>
<translation id="8663226718884576429">×¡×™×›×•× ×”×–×ž× ×”, <ph name="TOTAL_LABEL" />, ×¤×¨×˜×™× × ×•×¡×¤×™×</translation>
<translation id="867224526087042813">חתימה</translation>
@@ -1948,6 +1992,7 @@ Del</translation>
<translation id="8912362522468806198">â€×—שבון Google</translation>
<translation id="8913778647360618320">â€×”לחצן 'ניהול ×מצעי תשלו×', יש להקיש על Enter כדי לנהל ×ת ×”×ª×©×œ×•×ž×™× ×•×ת פרטי כרטיס ×”×שר××™ שלך בהגדרות Chrome</translation>
<translation id="8918231688545606538">הדף הזה חשוד</translation>
+<translation id="8922013791253848639">תמיד ל×פשר מודעות ב×תר ×”×–×”</translation>
<translation id="892588693504540538">ניקוב בפינה הימנית העליונה</translation>
<translation id="8931333241327730545">â€×”×× ×‘×¨×¦×•× ×š לשמור ×ת הכרטיס ×”×–×” בחשבון Google שלך?</translation>
<translation id="8932102934695377596">השעון שלך מ×חר</translation>
@@ -2019,6 +2064,7 @@ Del</translation>
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> משתמש בפרוטוקול ש×ינו נתמך.</translation>
<translation id="9191834167571392248">ניקוב בפינה השמ×לית התחתונה</translation>
+<translation id="9199905725844810519">ההדפסה חסומה</translation>
<translation id="9205078245616868884">×”× ×ª×•× ×™× ×©×œ×š ×ž×•×¦×¤× ×™× ×‘×מצעות ביטוי הסיסמה לסנכרון. יש להזין ×ותו כדי להתחיל בסנכרון.</translation>
<translation id="9207861905230894330">הוספת הפריט נכשלה.</translation>
<translation id="9213433120051936369">הת×מה ×ישית של המר××”</translation>
@@ -2029,8 +2075,10 @@ Del</translation>
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">â€×™×™×ª×›×Ÿ שמישהו ×חר ישלול ×ת הגישה שלך לחשבון Google. לגלישה בטוחה ב-Chromium, מומלץ לשנות ×ת הסיסמה עכשיו.</translation>
<translation id="939736085109172342">תיקייה חדשה</translation>
+<translation id="945522503751344254"> שליחת משוב</translation>
<translation id="945855313015696284">יש לבדוק ×ת המידע שבהמשך ולמחוק ×›×¨×˜×™×¡×™× ×¢× ×©×’×™×ות</translation>
<translation id="950736567201356821">3 × ×™×§×•×‘×™× ×‘×—×œ×§ העליון</translation>
+<translation id="951941430552851965">×¦×™×œ×•× ×”×ž×¡×š הושהה על ידי מנהל המערכת שלך עקב תוכן שהופיע במסך שלך.</translation>
<translation id="961663415146723894">כריכה בקצה התחתון</translation>
<translation id="962484866189421427">ייתכן שבתוכן ×”×–×” יש קוד להתקנת ×פליקציות מטעות שמתחזות למשהו ×חר ×ו ש×וספות × ×ª×•× ×™× ×”×ž××¤×©×¨×™× ×œ×¢×§×•×‘ ×חריך. <ph name="BEGIN_LINK" />×× ×™ רוצה לר×ות בכל ×–×ת<ph name="END_LINK" /></translation>
<translation id="969892804517981540">גרסה רשמית</translation>
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index b2bf8830c6d..708898f1859 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">組織ãŒç®¡ç†ã—ã¦ã„ãªã„サイトã§ãƒ‘スワードを入力ã—ã¾ã—ãŸã€‚アカウントをä¿è­·ã™ã‚‹ã«ã¯ã€ä»–ã®ã‚¢ãƒ—リやサイトã§ãƒ‘スワードをå†ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„。</translation>
<translation id="1263231323834454256">リーディング リスト</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«ä¿å­˜ã•ã‚Œãªã„アクティビティ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§è¡¨ç¤ºã•ã‚ŒãŸãƒšãƒ¼ã‚¸
+ <ph name="LIST_ITEM" />Cookie ã¨ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿
+ <ph name="LIST_ITEM" />アカウント情報(<ph name="LINK_BEGIN" />ログアウト<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">å—ã‘å–り方法</translation>
<translation id="1281476433249504884">スタッカー 1</translation>
<translation id="1285320974508926690">ã“ã®ã‚µã‚¤ãƒˆã¯ç¿»è¨³ã—ãªã„</translation>
@@ -224,7 +232,7 @@
<translation id="1757773103848038814">Monospace フォント</translation>
<translation id="1763864636252898013">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ã€ã”使用ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ãƒ„ールを実行ã—ã¦ã¿ã¦ãã ã•ã„<ph name="END_LINK" />。</translation>
-<translation id="1772163372082567643">アクセスã—ã¦ã„るサーãƒãƒ¼ <ph name="ORIGIN" /> ã§ã¯ã€ã‚µãƒ¼ãƒãƒ¼ã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã‚’é©ç”¨ã™ã‚‹ã“ã¨ã‚’求ã‚るヘッダーãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã™ãŒã€ãƒ˜ãƒƒãƒ€ãƒ¼ã®å½¢å¼ãŒæ­£ã—ããªã„ãŸã‚ã€ãƒ–ラウザ㯠<ph name="SITE" /> ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。オリジン ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µã‚¤ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚„ãã®ä»–ã®ãƒ—ロパティを設定ã™ã‚‹ç›®çš„ã§ã‚µã‚¤ãƒˆé‹å–¶è€…ãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚</translation>
+<translation id="1772163372082567643">アクセスã—ã¦ã„るサーãƒãƒ¼ <ph name="ORIGIN" /> ã§ã¯ã€ã‚µãƒ¼ãƒãƒ¼ã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã‚’é©ç”¨ã™ã‚‹ã“ã¨ã‚’求ã‚るヘッダーãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã™ãŒã€ãƒ˜ãƒƒãƒ€ãƒ¼ã®å½¢å¼ãŒæ­£ã—ããªã„ãŸã‚ã€ãƒ–ラウザ㯠<ph name="SITE" /> ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。オリジン ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µã‚¤ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚„ãã®ä»–ã®ãƒ—ロパティを設定ã™ã‚‹ç›®çš„ã§ãƒ‘ブリッシャーãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚</translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1783075131180517613">åŒæœŸãƒ‘スフレーズを更新ã—ã¦ãã ã•ã„。</translation>
<translation id="1787142507584202372">最近開ã„ãŸã‚¿ãƒ–ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">Google アカウントã«ä¿å­˜ã—ãŸãƒ‘スワードを使用ã™ã‚‹ã«ã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />ã®ãƒšãƒ¼ã‚¸ã¯ç¿»è¨³ã•ã‚Œã¾ã›ã‚“。</translation>
<translation id="2053553514270667976">郵便番å·</translation>
+<translation id="2054665754582400095">ユーザーã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 件ã®å€™è£œ}other{# 件ã®å€™è£œ}}</translation>
<translation id="2079545284768500474">å…ƒã«æˆ»ã™</translation>
<translation id="20817612488360358">システム プロキシ設定を使用ã™ã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ãŒã€æ˜Žç¤ºçš„ãªãƒ—ロキシã®è¨­å®šã‚‚指定ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android アプリ</translation>
<translation id="2107021941795971877">å°åˆ·ã‚µãƒãƒ¼ãƒˆ</translation>
<translation id="2108755909498034140">パソコンをå†èµ·å‹•ã™ã‚‹</translation>
+<translation id="2111166930115883695">プレイã™ã‚‹ã«ã¯ Space キーを押ã—ã¦ãã ã•ã„</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">カード</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ã«ã‚ˆã£ã¦ä¸Šæ›¸ãã•ã‚Œã‚‹ãŸã‚無視ã•ã‚Œã¾ã™ã€‚</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">支払ã„をキャンセル</translation>
<translation id="2147827593068025794">ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰åŒæœŸ</translation>
<translation id="2148613324460538318">カードを追加</translation>
+<translation id="2149968176347646218">接続ã¯å®‰å…¨ã§ã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="2154054054215849342">ãŠä½¿ã„ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã§ã¯åŒæœŸæ©Ÿèƒ½ã‚’ã”利用ã„ãŸã ã‘ã¾ã›ã‚“</translation>
<translation id="2154484045852737596">カードを編集</translation>
<translation id="2161656808144014275">テキスト</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">ãƒãƒªã‚·ãƒ¼</translation>
<translation id="2183608646556468874">電話番å·</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 件ã®ã‚¢ãƒ‰ãƒ¬ã‚¹}other{# 件ã®ã‚¢ãƒ‰ãƒ¬ã‚¹}}</translation>
-<translation id="2187243482123994665">ユーザーã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態</translation>
<translation id="2187317261103489799">検出(デフォルト)</translation>
<translation id="2188375229972301266">多穴パンãƒï¼ˆä¸‹ï¼‰</translation>
<translation id="2202020181578195191">有効期é™ï¼ˆå¹´ï¼‰ã‚’æ­£ã—ã„å½¢å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">å½ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã—よã†ã¨ã—ã¦ã„ã¾ã™</translation>
<translation id="2850739647070081192">Invite(å°ç­’)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã§ã¯ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦ã€ãƒ‘スワードã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カードãªã©ã®æƒ…å ±ãŒç›—ã¾ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ã“ã®ã‚µã‚¤ãƒˆã§ã¯ç…©ã‚ã—ã„広告ã¾ãŸã¯èª¤è§£ã‚’æ‹›ã広告ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
<translation id="2878197950673342043">ãƒã‚¹ã‚¿ãƒ¼æŠ˜ã‚Š</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ウィンドウã®é…ç½®</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google ã«ã‚ˆã‚‹ãŠã™ã™ã‚</translation>
<translation id="3002501248619246229">給紙トレイã®ãƒ¡ãƒ‡ã‚£ã‚¢ã‚’確èªã—ã¦ãã ã•ã„</translation>
<translation id="3005723025932146533">ä¿å­˜æ¸ˆã¿ã®ã‚³ãƒ”ーを表示</translation>
-<translation id="3007719053326478567">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å°åˆ·ã¯ç®¡ç†è€…ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ã® CVC を入力ã—ã¾ã™ã€‚確èªã‚’è¡Œã†ã¨ã€ã‚«ãƒ¼ãƒ‰ã®è©³ç´°ãŒã“ã®ã‚µã‚¤ãƒˆã¨å…±æœ‰ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="3010559122411665027">リスト エントリ「<ph name="ENTRY_INDEX" />ã€: <ph name="ERROR" /></translation>
<translation id="301521992641321250">自動ブロックã•ã‚Œã¾ã—ãŸ</translation>
<translation id="3016780570757425217">ユーザーã®ç¾åœ¨åœ°ã®èªè­˜</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€å€™è£œã‚’削除ã—ã¾ã™ã€‚</translation>
<translation id="3023071826883856138">æ´‹4(å°ç­’)</translation>
<translation id="3024663005179499861">ãƒãƒªã‚·ãƒ¼ タイプãŒé–“é•ã£ã¦ã„ã¾ã™</translation>
<translation id="3037605927509011580">エラー</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">ブックマークã—ã¾ã—ãŸ</translation>
<translation id="3209034400446768650">ã“ã®ãƒšãƒ¼ã‚¸ã§ã¯æ–™é‡‘ãŒè«‹æ±‚ã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ã§ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã¯ç›£è¦–ã•ã‚Œã¦ã„ã¾ã™</translation>
+<translation id="3212623355668894776">ゲスト ウィンドウをã™ã¹ã¦é–‰ã˜ã‚Œã°ã€ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã‹ã‚‰é–²è¦§ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="3215092763954878852">WebAuthn を使用ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="3218181027817787318">相対的</translation>
<translation id="3225919329040284222">サーãƒãƒ¼ã®æ示ã—ãŸè¨¼æ˜Žæ›¸ãŒã€çµ„ã¿è¾¼ã¾ã‚Œã¦ã„る想定ã®è¨¼æ˜Žæ›¸ã¨ä¸€è‡´ã—ã¾ã›ã‚“。ã“れらã®æƒ³å®šã®è¨¼æ˜Žæ›¸ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ä¿è­·ã®ãŸã‚ã€ç‰¹å®šã®å®‰å…¨æ€§ã®é«˜ã„ウェブサイトã«ã¤ã„ã¦ç”¨æ„ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">Bluetoothデãƒã‚¤ã‚¹</translation>
<translation id="3787705759683870569">有効期é™: <ph name="EXPIRATION_MONTH" /> / <ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">サイズ 16</translation>
+<translation id="3789841737615482174">インストール</translation>
<translation id="3793574014653384240">最近発生ã—ãŸå•é¡Œã®ä»¶æ•°ã¨åŽŸå› </translation>
<translation id="3797522431967816232">Prc3(å°ç­’)</translation>
<translation id="3799805948399000906">リクエストã•ã‚ŒãŸãƒ•ã‚©ãƒ³ãƒˆ</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">セピア</translation>
<translation id="4058922952496707368">キー「<ph name="SUBKEY" />ã€: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1(å°ç­’)</translation>
+<translation id="4067669230157909013">スクリーン キャプãƒãƒ£ãŒå†é–‹ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="4067947977115446013">有効ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã®è¿½åŠ </translation>
<translation id="4072486802667267160">ã”注文ã®å‡¦ç†ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。</translation>
<translation id="4075732493274867456">クライアントã¨ã‚µãƒ¼ãƒãƒ¼ã§ã€å…±é€šã® SSL プロトコル ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¾ãŸã¯æš—å·ã‚¹ã‚¤ãƒ¼ãƒˆãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
@@ -785,7 +799,7 @@
<translation id="4196861286325780578">移動ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ファイアウォールã¨ã‚¦ã‚¤ãƒ«ã‚¹å¯¾ç­–ã®è¨­å®šã‚’確èªã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="4209092469652827314">大</translation>
-<translation id="4209166701302774460">アクセスã—ã¦ã„るサーãƒãƒ¼ <ph name="ORIGIN" /> ã§ã¯ã€ã‚µãƒ¼ãƒãƒ¼ã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã‚’é©ç”¨ã™ã‚‹ã“ã¨ãŒæ±‚ã‚られã¦ã„ã¾ã™ãŒã€ãƒãƒªã‚·ãƒ¼ãŒã‚µãƒ¼ãƒãƒ¼ã‹ã‚‰é€ä¿¡ã•ã‚Œãªã‹ã£ãŸãŸã‚ã€ãƒ–ラウザ㯠<ph name="SITE" /> ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。オリジン ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µã‚¤ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚„ãã®ä»–ã®ãƒ—ロパティを設定ã™ã‚‹ç›®çš„ã§ã‚µã‚¤ãƒˆé‹å–¶è€…ãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚</translation>
+<translation id="4209166701302774460">アクセスã—ã¦ã„るサーãƒãƒ¼ <ph name="ORIGIN" /> ã§ã¯ã€ã‚µãƒ¼ãƒãƒ¼ã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã‚’é©ç”¨ã™ã‚‹ã“ã¨ãŒæ±‚ã‚られã¦ã„ã¾ã™ãŒã€ãƒãƒªã‚·ãƒ¼ãŒã‚µãƒ¼ãƒãƒ¼ã‹ã‚‰é€ä¿¡ã•ã‚Œãªã‹ã£ãŸãŸã‚ã€ãƒ–ラウザ㯠<ph name="SITE" /> ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。オリジン ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µã‚¤ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚„ãã®ä»–ã®ãƒ—ロパティを設定ã™ã‚‹ç›®çš„ã§ãƒ‘ブリッシャーãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚</translation>
<translation id="421066178035138955">ãƒãƒ¼ãƒãƒ£ãƒ« リアリティ デãƒã‚¤ã‚¹ã¨ãƒ‡ãƒ¼ã‚¿ã®ä½¿ç”¨</translation>
<translation id="4214357935346142455">ログイン画é¢ã®ãƒ—ロファイル</translation>
<translation id="4215751373031079683">7x9(å°ç­’)</translation>
@@ -826,6 +840,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> ページã®ã‚µãƒ ãƒã‚¤ãƒ«</translation>
<translation id="42981349822642051">展開</translation>
<translation id="4300675098767811073">多穴パンãƒï¼ˆå³ï¼‰</translation>
+<translation id="4302514097724775343">プレイã™ã‚‹ã«ã¯æ竜をタップã—ã¦ãã ã•ã„</translation>
<translation id="4302965934281694568">é•·3(å°ç­’)</translation>
<translation id="4305666528087210886">ファイルã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="4305817255990598646">切り替ãˆ</translation>
@@ -904,6 +919,7 @@
<translation id="4658638640878098064">ステープル(左上)</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ãƒãƒ¼ãƒãƒ£ãƒ« リアリティ(VR)</translation>
+<translation id="4675657451653251260">ゲストモードã§ã¯ Chrome プロファイルã®æƒ…å ±ãŒè¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。<ph name="LINK_BEGIN" />ログイン<ph name="LINK_END" />ã™ã‚‹ã¨ã€ãƒ‘スワードやãŠæ”¯æ‰•ã„方法ãªã©ã® Google アカウント情報ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚</translation>
<translation id="467662567472608290">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã«ã¯ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™ã€‚原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="4677585247300749148"><ph name="URL" /> ã‹ã‚‰ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼è£œåŠ©æ©Ÿèƒ½ã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¿œç­”ã™ã‚‹è¨±å¯ã‚’求ã‚られã¦ã„ã¾ã™</translation>
<translation id="467809019005607715">Google スライド</translation>
@@ -931,6 +947,12 @@
<translation id="4761104368405085019">マイクを使用ã™ã‚‹</translation>
<translation id="4764776831041365478"><ph name="URL" /> ã®ã‚¦ã‚§ãƒ–ページã¯ä¸€æ™‚çš„ã«åœæ­¢ã—ã¦ã„ã‚‹ã‹ã€æ–°ã—ã„ウェブアドレスã«ç§»å‹•ã—ãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="4766713847338118463">2 ã‹æ‰€ã®ã‚¹ãƒ†ãƒ¼ãƒ—ル(下)</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«ä¿å­˜ã•ã‚Œã‚‹ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ä¸æ˜Žãªã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ãƒãƒƒãƒ—アップãŒãƒ–ロックã•ã‚Œã¾ã—ãŸ}other{# 件ã®ãƒãƒƒãƒ—アップãŒãƒ–ロックã•ã‚Œã¾ã—ãŸ}}</translation>
<translation id="4780366598804516005">用紙å—ã‘ 1</translation>
@@ -1093,11 +1115,13 @@
<translation id="5386426401304769735">ã“ã®ã‚µã‚¤ãƒˆã®è¨¼æ˜Žæ›¸ãƒã‚§ãƒ¼ãƒ³ã«ã¯ SHA-1 を使ã£ã¦ç½²åã•ã‚ŒãŸè¨¼æ˜Žæ›¸ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">端綴ã˜ï¼ˆå³ï¼‰</translation>
+<translation id="5398772614898833570">広告ãŒãƒ–ロックã•ã‚Œã¾ã—ãŸ</translation>
<translation id="5400836586163650660">グレー</translation>
<translation id="540969355065856584">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ç¾åœ¨æœ‰åŠ¹ã§ã¯ã‚ã‚Šã¾ã›ã‚“。設定ãŒä¸é©åˆ‡ã‹ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦æŽ¥ç¶šãŒå¦¨å®³ã•ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="541416427766103491">スタッカー 4</translation>
<translation id="5421136146218899937">閲覧履歴データを削除...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ãŒé€šçŸ¥ã‚’é€ä¿¡ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚</translation>
+<translation id="542872847390508405">ゲスト モードã§ãƒ–ラウジング中</translation>
<translation id="5430298929874300616">ブックマークを削除</translation>
<translation id="5439770059721715174">「<ph name="ERROR_PATH" />ã€ã§ã‚¹ã‚­ãƒ¼ãƒžç¢ºèªã‚¨ãƒ©ãƒ¼: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">逆ã®é †åºï¼ˆä¸Šå‘ã)</translation>
@@ -1139,12 +1163,12 @@
<translation id="5571083550517324815">ã“ã®ä½æ‰€ã§ã®å—ã‘å–ã‚Šã¯ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="5580958916614886209">有効期é™ã®ã€Œæœˆã€ã‚’確èªã—ã¦ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„</translation>
<translation id="5586446728396275693">ä¿å­˜ã•ã‚Œã¦ã„ã‚‹ä½æ‰€ãŒã‚ã‚Šã¾ã›ã‚“</translation>
+<translation id="5593349413089863479">接続ã¯å®Œå…¨ã«ã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="5595485650161345191">ä½æ‰€ã®ç·¨é›†</translation>
<translation id="5598944008576757369">ãŠæ”¯æ‰•ã„方法をé¸æŠž</translation>
<translation id="560412284261940334">管ç†ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">å½ã®ã‚µã‚¤ãƒˆã¾ãŸã¯ä¸æ­£ãªã‚µã‚¤ãƒˆã®å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚ã“ã®ã‚µã‚¤ãƒˆã‹ã‚‰é›¢ã‚Œã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚</translation>
<translation id="5610142619324316209">接続を確èªã™ã‚‹</translation>
<translation id="5610807607761827392">カードã¨ä½æ‰€ã¯ [<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] ã§ç®¡ç†ã§ãã¾ã™ã€‚</translation>
<translation id="561165882404867731">Google 翻訳ã§ã“ã®ãƒšãƒ¼ã‚¸ã‚’翻訳ã™ã‚‹</translation>
@@ -1216,6 +1240,7 @@
<translation id="5901630391730855834">黄</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> ã®ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã«æ²¿ã£ã¦ãƒ–ロックã—ã¾ã—ãŸã€‚</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(åŒæœŸæ¸ˆã¿ï¼‰</translation>
+<translation id="5913377024445952699">ç”»é¢ã‚­ãƒ£ãƒ—ãƒãƒ£ãŒä¸€æ™‚åœæ­¢ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="59174027418879706">有効</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">オン</translation>
@@ -1228,6 +1253,7 @@
<translation id="5963413905009737549">セクション</translation>
<translation id="5967592137238574583">連絡先情報ã®ç·¨é›†</translation>
<translation id="5967867314010545767">履歴ã‹ã‚‰å‰Šé™¤</translation>
+<translation id="5968793460449681917">アクセスã™ã‚‹ãŸã³ã«ç¢ºèª</translation>
<translation id="5975083100439434680">縮å°ã™ã‚‹</translation>
<translation id="5979084224081478209">パスワードを確èª</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1383,6 +1409,7 @@
<translation id="6587923378399804057">コピーã—ãŸãƒªãƒ³ã‚¯</translation>
<translation id="6591833882275308647">ã”使用㮠<ph name="DEVICE_TYPE" /> ã¯ç®¡ç†ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="6596325263575161958">æš—å·åŒ–オプション</translation>
+<translation id="6596892391065203054">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å°åˆ·ã¯ç®¡ç†è€…ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="6604181099783169992">モーション センサーã¾ãŸã¯å…‰ã‚»ãƒ³ã‚µãƒ¼</translation>
<translation id="6609880536175561541">Prc7(å°ç­’)</translation>
<translation id="6612358246767739896">ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„</translation>
@@ -1442,6 +1469,7 @@
<translation id="6895330447102777224">カードを確èªã—ã¾ã—ãŸ</translation>
<translation id="6897140037006041989">ユーザー エージェント</translation>
<translation id="6898699227549475383">組織(O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> ã«æ¬¡ã®æ¨©é™ã‚’許å¯:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ã‹ã‚‰ã€MIDI デãƒã‚¤ã‚¹ã‚’フル コントロールã™ã‚‹è¨±å¯ã‚’求ã‚られã¦ã„ã¾ã™</translation>
<translation id="6915804003454593391">ユーザー:</translation>
<translation id="6934672428414710184">Google アカウントã§è¨­å®šã•ã‚Œã¦ã„ã‚‹åå‰ã§ã™</translation>
@@ -1553,6 +1581,7 @@
<translation id="7346048084945669753">外部ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‹ã©ã†ã‹:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">コマンドライン</translation>
+<translation id="7359588939039777303">広告ãŒãƒ–ロックã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="7372973238305370288">検索çµæžœ</translation>
<translation id="7374733840632556089">ã“ã®å•é¡Œã¯ã€ã‚ãªãŸã¾ãŸã¯ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒãƒ‡ãƒã‚¤ã‚¹ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸè¨¼æ˜Žæ›¸ãŒåŽŸå› ã§ç™ºç”Ÿã—ã¾ã™ã€‚該当ã®è¨¼æ˜Žæ›¸ã¯ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ç›£è¦–ã¨å‚å—ã«ä½¿ã‚れるã“ã¨ãŒç¢ºèªã•ã‚Œã¦ãŠã‚Šã€Chrome ã§ã¯ä¿¡é ¼ã•ã‚Œã¦ã„ã¾ã›ã‚“。学校や会社ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãªã©ã§åˆæ³•çš„ã«ç›£è¦–ã•ã‚Œã¦ã„るケースもã‚ã‚Šã¾ã™ãŒã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒç›£è¦–ã‚’æ­¢ã‚られãªã„ã¨ã—ã¦ã‚‚監視ã®äº‹å®Ÿã‚’把æ¡ã§ãるよã†ã«ã€Chrome ã§ã¯ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’表示ã—ã¦ã„ã¾ã™ã€‚監視ã®å¯¾è±¡ã¯ã€ãƒ–ラウザã€ã¾ãŸã¯ã‚¦ã‚§ãƒ–ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã‚¢ãƒ—リケーションã§ã™ã€‚</translation>
<translation id="7375818412732305729">ファイルãŒæ·»ä»˜ã•ã‚ŒãŸ</translation>
@@ -1727,6 +1756,7 @@
<translation id="7976214039405368314">リクエストãŒå¤šã™ãŽã¾ã™</translation>
<translation id="7977538094055660992">出力デãƒã‚¤ã‚¹</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">æ‹¡å¼µç¾å®Ÿï¼ˆAR)コンテンツを表示ã™ã‚‹ã«ã¯ ARCore をインストールã—ã¦ãã ã•ã„</translation>
<translation id="799149739215780103">製本</translation>
<translation id="7995512525968007366">指定ãªã—</translation>
<translation id="800218591365569300">メモリを解放ã™ã‚‹ãŸã‚ã«ã€ä»–ã®ã‚¿ãƒ–やプログラムを閉ã˜ã¦ã¿ã¦ãã ã•ã„。</translation>
@@ -1854,25 +1884,39 @@
<translation id="8507227106804027148">コマンドライン</translation>
<translation id="8508648098325802031">検索アイコン</translation>
<translation id="8522552481199248698">Chrome ã«ã¯ Google アカウントã®ä¿è­·ã¨ãƒ‘スワードã®å¤‰æ›´ã‚’サãƒãƒ¼ãƒˆã™ã‚‹æ©Ÿèƒ½ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+<translation id="8525306231823319788">全画é¢è¡¨ç¤º</translation>
<translation id="8530813470445476232">Chrome ã®è¨­å®šã§é–²è¦§å±¥æ­´ã€Cookieã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ãªã©ã‚’消去ã™ã‚‹</translation>
<translation id="8533619373899488139">&lt;strong&gt;chrome://policy&lt;/strong&gt; ã§ã€ãƒ–ロックã•ã‚ŒãŸ URL ã®ãƒªã‚¹ãƒˆã¨ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ãŒè¨­å®šã—ãŸä»–ã®ãƒãƒªã‚·ãƒ¼ã‚’確èªã§ãã¾ã™ã€‚</translation>
<translation id="8541158209346794904">Bluetooth デãƒã‚¤ã‚¹</translation>
<translation id="8542014550340843547">3 ã‹æ‰€ã®ã‚¹ãƒ†ãƒ¼ãƒ—ル(下)</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />検出ã®å•é¡Œã‚’ã”報告<ph name="END_ERROR_LINK" />ãã ã•ã„。<ph name="BEGIN_LINK" />安全ã§ãªã„ã“ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹<ph name="END_LINK" />ã™ã‚‹å ´åˆã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ä¸Šã®ãƒªã‚¹ã‚¯ãŒã‚ã‚‹ã“ã¨ã‚’ã”承知ãŠããã ã•ã„。</translation>
<translation id="8557066899867184262">CVC ã¯ã‚«ãƒ¼ãƒ‰ã®è£é¢ã«è¨˜è¼‰ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
+<translation id="8558485628462305855">æ‹¡å¼µç¾å®Ÿï¼ˆAR)コンテンツを表示ã™ã‚‹ã«ã¯ ARCore ã‚’æ›´æ–°ã—ã¦ãã ã•ã„</translation>
<translation id="8559762987265718583">デãƒã‚¤ã‚¹ã®æ—¥æ™‚(<ph name="DATE_AND_TIME" />)ãŒæ­£ã—ããªã„ãŸã‚ã€<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ã¸ã®ãƒ—ライベート接続を確立ã§ãã¾ã›ã‚“。</translation>
<translation id="8564182942834072828">個別ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆä¸åˆã„ãªã—)</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> パスワードを他ã®ã‚µã‚¤ãƒˆã§å†ä½¿ç”¨ã—ãŸå ´åˆã€Chromium ã§ã¯ãƒ‘スワードã®å†è¨­å®šã‚’促ã™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«ä¿å­˜ã•ã‚Œãªã„アクティビティ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§è¡¨ç¤ºã•ã‚ŒãŸãƒšãƒ¼ã‚¸
+ <ph name="LIST_ITEM" />Cookie ã¨ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Touch ID を使用ã—ã¦ã‚«ãƒ¼ãƒ‰ã‚’ã™ã°ã‚„ã確èªã™ã‚‹</translation>
<translation id="858637041960032120">電話番å·ã‚’追加
</translation>
<translation id="8589998999637048520">最高画質</translation>
+<translation id="8600271352425265729">今回ã®ã¿</translation>
<translation id="860043288473659153">カードå義人</translation>
<translation id="8606726445206553943">MIDI デãƒã‚¤ã‚¹ã®ä½¿ç”¨</translation>
+<translation id="8612761427948161954"><ph name="USERNAME" />様
+ <ph name="BR" />
+ ゲストモードã§ãƒ–ラウジング中ã§ã™</translation>
<translation id="861775596732816396">サイズ 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">一致ã™ã‚‹ãƒ‘スワードãŒã‚ã‚Šã¾ã›ã‚“。ä¿å­˜ã—ãŸãƒ‘スワードをã™ã¹ã¦è¡¨ç¤ºã—ã¾ã™ã€‚</translation>
<translation id="8625384913736129811">ã“ã®ã‚«ãƒ¼ãƒ‰æƒ…報をã“ã®ãƒ‡ãƒã‚¤ã‚¹ã«ä¿å­˜ã™ã‚‹</translation>
+<translation id="8627040765059109009">ç”»é¢ã‚­ãƒ£ãƒ—ãƒãƒ£ãŒå†é–‹ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> ã‹ã‚‰ <ph name="VM_NAME_1" /> ãŠã‚ˆã³ <ph name="VM_NAME_2" /> ã¸ã®å…±æœ‰ã¯ã€ç®¡ç†è€…ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="8663226718884576429">ã”注文ã®æ¦‚è¦ã€<ph name="TOTAL_LABEL" />ã€ãã®ä»–ã®è©³ç´°</translation>
<translation id="867224526087042813">ç½²å</translation>
@@ -1935,6 +1979,7 @@
<translation id="8912362522468806198">Google アカウントを使用</translation>
<translation id="8913778647360618320">ãŠæ”¯æ‰•ã„方法を管ç†ã™ã‚‹ãƒœã‚¿ãƒ³ã§ã™ã€‚Enter キーを押ã™ã¨ã€Chrome ã®è¨­å®šã§ãŠæ”¯æ‰•ã„ã¨ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カードã®æƒ…報を管ç†ã—ã¾ã™</translation>
<translation id="8918231688545606538">ä¸å¯©ãªãƒšãƒ¼ã‚¸ã§ã™</translation>
+<translation id="8922013791253848639">ã“ã®ã‚µã‚¤ãƒˆã§å¸¸ã«åºƒå‘Šã‚’許å¯ã—ã¾ã™</translation>
<translation id="892588693504540538">パンãƒï¼ˆå³ä¸Šï¼‰</translation>
<translation id="8931333241327730545">ã“ã®ã‚«ãƒ¼ãƒ‰ã‚’ Google アカウントã«ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="8932102934695377596">時計ãŒé…ã‚Œã¦ã„ã¾ã™</translation>
@@ -2006,6 +2051,7 @@
<translation id="9183302530794969518">Google ドキュメント</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ã§ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„プロトコルãŒä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="9191834167571392248">パンãƒï¼ˆå·¦ä¸‹ï¼‰</translation>
+<translation id="9199905725844810519">å°åˆ·ã¯ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="9205078245616868884">データã¯åŒæœŸãƒ‘スフレーズã§æš—å·åŒ–ã•ã‚Œã¾ã™ã€‚åŒæœŸã‚’開始ã™ã‚‹ã«ã¯ã€åŒæœŸãƒ‘スフレーズを入力ã—ã¦ãã ã•ã„。</translation>
<translation id="9207861905230894330">記事を追加ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="9213433120051936369">デザインをカスタマイズã™ã‚‹</translation>
@@ -2016,8 +2062,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google アカウントã«ã‚¢ã‚¯ã‚»ã‚¹ã§ããªããªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚Chromium ã§ä»Šã™ãパスワードを変更ã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚変更ã®éš›ã«ã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã‚ˆã†æ±‚ã‚られã¾ã™ã€‚</translation>
<translation id="939736085109172342">æ–°ã—ã„フォルダ</translation>
+<translation id="945522503751344254">フィードãƒãƒƒã‚¯ã‚’é€ä¿¡</translation>
<translation id="945855313015696284">下記ã®æƒ…報を確èªã—ã€ç„¡åŠ¹ãªã‚«ãƒ¼ãƒ‰ãŒã‚ã‚Œã°å‰Šé™¤ã—ã¦ãã ã•ã„</translation>
<translation id="950736567201356821">3 穴パンãƒï¼ˆä¸Šï¼‰</translation>
+<translation id="951941430552851965">ç”»é¢ä¸Šã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã«å•é¡ŒãŒã‚ã‚‹ãŸã‚ã€ç®¡ç†è€…ã«ã‚ˆã£ã¦ã‚¹ã‚¯ãƒªãƒ¼ãƒ³ キャプãƒãƒ£ãŒä¸€æ™‚åœæ­¢ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="961663415146723894">製本(下綴ã˜ï¼‰</translation>
<translation id="962484866189421427">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を表示ã™ã‚‹ã¨ã€è©æ¬ºçš„ãªã‚¢ãƒ—リ(他ã®ã‚‚ã®ã«æˆã‚Šã™ã¾ã—ãŸã‚Šã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è¿½è·¡ãªã©ã«ä½¿ç”¨å¯èƒ½ãªãƒ‡ãƒ¼ã‚¿ã‚’åŽé›†ã—ãŸã‚Šã™ã‚‹ã‚¢ãƒ—リ)ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ãŒè©¦è¡Œã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LINK" />å±é™ºæ€§ã‚’ç†è§£ã—ãŸã†ãˆã§è¡¨ç¤ºã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Official Build</translation>
diff --git a/chromium/components/strings/components_strings_ka.xtb b/chromium/components/strings/components_strings_ka.xtb
index e2aa232d1fe..d84f0e885b4 100644
--- a/chromium/components/strings/components_strings_ka.xtb
+++ b/chromium/components/strings/components_strings_ka.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">თქვენ შეიყვáƒáƒœáƒ”თ პáƒáƒ áƒáƒšáƒ˜ სáƒáƒ˜áƒ¢áƒ–ე, რáƒáƒ›áƒ”ლსáƒáƒª áƒáƒ  მáƒáƒ áƒ—áƒáƒ•áƒ¡ თქვენი áƒáƒ áƒ’áƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ. თქვენი áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ დáƒáƒ¡áƒáƒªáƒáƒ•áƒáƒ“ áƒáƒ  გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნáƒáƒ— იგივე პáƒáƒ áƒáƒšáƒ˜ სხვრáƒáƒžáƒ”ბსრდრსáƒáƒ˜áƒ¢áƒ”ბზე.</translation>
<translation id="1263231323834454256">სáƒáƒ™áƒ˜áƒ—ხáƒáƒ•áƒ˜ სიáƒ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒ, რáƒáƒ›áƒ”ლიც áƒáƒ  დáƒáƒ áƒ©áƒ”ბრáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />áƒáƒ› ფáƒáƒœáƒ¯áƒáƒ áƒáƒ¨áƒ˜ ნáƒáƒœáƒáƒ®áƒ˜ გვერდები
+ <ph name="LIST_ITEM" />ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის მáƒáƒœáƒáƒªáƒ”მები
+ <ph name="LIST_ITEM" />áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ (<ph name="LINK_BEGIN" />გáƒáƒ¡áƒ•áƒšáƒ<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">წáƒáƒ¦áƒ”ბის მეთáƒáƒ“ი</translation>
<translation id="1281476433249504884">სტეკერი 1</translation>
<translation id="1285320974508926690">áƒáƒ áƒáƒ¡áƒ“რáƒáƒ¡ გáƒáƒ“áƒáƒ—áƒáƒ áƒ’მნრეს სáƒáƒ˜áƒ¢áƒ˜</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">თქვენს Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ შენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ”ბის გáƒáƒ›áƒáƒ¡áƒáƒ§áƒ”ნებლáƒáƒ“ შედით სისტემáƒáƒ¨áƒ˜</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> გვერდები áƒáƒ  ითáƒáƒ áƒ’მნებáƒ.</translation>
<translation id="2053553514270667976">ZIP კáƒáƒ“ი</translation>
+<translation id="2054665754582400095">თქვენი დáƒáƒ¡áƒ¬áƒ áƒ”ბáƒ</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 შეთáƒáƒ•áƒáƒ–ებáƒ}other{# შეთáƒáƒ•áƒáƒ–ებáƒ}}</translation>
<translation id="2079545284768500474">მáƒáƒ¥áƒ›áƒ”დების გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
<translation id="20817612488360358">დáƒáƒ§áƒ”ნებულირსისტემის პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრების გáƒáƒ›áƒáƒ§áƒ”ნებáƒ, მáƒáƒ’რáƒáƒ› áƒáƒ¡áƒ”ვე მითითებულირპრáƒáƒ¥áƒ¡áƒ˜áƒ¡ áƒáƒ¨áƒ™áƒáƒ áƒ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ.</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android-ის áƒáƒžáƒ”ბი</translation>
<translation id="2107021941795971877">ბეჭდვის დáƒáƒ›áƒ®áƒ›áƒáƒ áƒ” სáƒáƒ¨áƒ£áƒáƒšáƒ”ბები</translation>
<translation id="2108755909498034140">თქვენი კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რის გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
+<translation id="2111166930115883695">დáƒáƒ¡áƒáƒ™áƒ áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ შáƒáƒ áƒ˜áƒ¡áƒ¡</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">ბიზნეს ბáƒáƒ áƒáƒ—ი დიზáƒáƒ˜áƒœáƒ˜</translation>
<translation id="2114841414352855701">იგნáƒáƒ áƒ˜áƒ áƒ”ბულიáƒ, რáƒáƒ“გáƒáƒœ იგი ჩáƒáƒœáƒáƒªáƒ•áƒšáƒ”ბულირ<ph name="POLICY_NAME" />-ის მიერ.</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">გáƒáƒ“áƒáƒ®áƒ“ის გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
<translation id="2147827593068025794">ფáƒáƒœáƒ£áƒ áƒ˜ სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ</translation>
<translation id="2148613324460538318">ბáƒáƒ áƒáƒ—ის დáƒáƒ›áƒáƒ¢áƒ”ბáƒ</translation>
+<translation id="2149968176347646218">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ დáƒáƒ£áƒªáƒ•áƒ”ლიáƒ</translation>
<translation id="2154054054215849342">სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ მიუწვდáƒáƒ›áƒ”ლირთქვენი დáƒáƒ›áƒ”ნისთვის</translation>
<translation id="2154484045852737596">ბáƒáƒ áƒáƒ—ის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="2161656808144014275">ტექსტი</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">წესები</translation>
<translation id="2183608646556468874">ტელეფáƒáƒœáƒ˜áƒ¡ ნáƒáƒ›áƒ”რი</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 მისáƒáƒ›áƒáƒ áƒ—ი}other{# მისáƒáƒ›áƒáƒ áƒ—ი}}</translation>
-<translation id="2187243482123994665">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის დáƒáƒ¡áƒ¬áƒ áƒ”ბáƒ</translation>
<translation id="2187317261103489799">áƒáƒ›áƒáƒªáƒœáƒáƒ‘რ(ნáƒáƒ’ულისხმევი)</translation>
<translation id="2188375229972301266">მრáƒáƒ•áƒáƒšáƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრქვემáƒáƒ—</translation>
<translation id="2202020181578195191">შეიყვáƒáƒœáƒ”თ მáƒáƒ¥áƒ›áƒ”დების ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ სწáƒáƒ áƒ˜ წელი</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">მáƒáƒ”რიდეთ ყáƒáƒšáƒ‘ სáƒáƒ˜áƒ¢áƒ¡</translation>
<translation id="2850739647070081192">Invite (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="2856444702002559011">თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლები შეიძლებრცáƒáƒ“áƒáƒœ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-დáƒáƒœ თქვენი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მáƒáƒžáƒáƒ áƒ•áƒ (მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, პáƒáƒ áƒáƒšáƒ”ბის, შეტყáƒáƒ‘ინებების áƒáƒœ სáƒáƒ™áƒ áƒ”დიტრბáƒáƒ áƒáƒ—ების მáƒáƒœáƒáƒªáƒ”მების). <ph name="BEGIN_LEARN_MORE_LINK" />შეიტყვეთ მეტი<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">áƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე ნáƒáƒ©áƒ•áƒ”ნებირმáƒáƒ›áƒáƒ‘ეზრებელი áƒáƒœ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœáƒ˜ რეკლáƒáƒ›áƒ.</translation>
<translation id="2878197950673342043">დáƒáƒ™áƒ”ცვრპáƒáƒ¡áƒ¢áƒ”რის ფáƒáƒ áƒ›áƒ˜áƒ—</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ გáƒáƒœáƒšáƒáƒ’ებáƒ</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">შემáƒáƒ—áƒáƒ•áƒáƒ–ებები Google-ისგáƒáƒœ</translation>
<translation id="3002501248619246229">შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ შეყვáƒáƒœáƒ˜áƒ¡ ლáƒáƒœáƒ’რის მედიáƒ</translation>
<translation id="3005723025932146533">შენáƒáƒ®áƒ£áƒšáƒ˜ áƒáƒ¡áƒšáƒ˜áƒ¡ ჩვენებáƒ</translation>
-<translation id="3007719053326478567">áƒáƒ› კáƒáƒœáƒ¢áƒ”ნტის ბეჭდვრდáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ</translation>
<translation id="3008447029300691911">შეიყვáƒáƒœáƒ”თ <ph name="CREDIT_CARD" />-ის CVC. დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბის შემდეგ, თქვენი ბáƒáƒ áƒáƒ—ის დეტáƒáƒšáƒ”ბი áƒáƒ› სáƒáƒ˜áƒ¢áƒ—áƒáƒœ გáƒáƒ–იáƒáƒ áƒ“ებáƒ.</translation>
<translation id="3010559122411665027">სიის ჩáƒáƒœáƒáƒ¬áƒ”რი „<ph name="ENTRY_INDEX" />“ <ph name="ERROR" /></translation>
<translation id="301521992641321250">დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒáƒ“</translation>
<translation id="3016780570757425217">თქვენი მდებáƒáƒ áƒ”áƒáƒ‘ის ცáƒáƒ“ნáƒ</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, შემáƒáƒ—áƒáƒ•áƒáƒ–ების áƒáƒ›áƒáƒ¡áƒáƒ¨áƒšáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ ჯერ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, ხáƒáƒšáƒ შემდეგ Enter-ს.</translation>
<translation id="3023071826883856138">You4 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="3024663005179499861">áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ პáƒáƒšáƒ˜áƒ¢áƒ˜áƒ™áƒ˜áƒ¡ ტიპი</translation>
<translation id="3037605927509011580">უი, ხáƒáƒ áƒ•áƒ”ზი!</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">ჩáƒáƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ˜áƒ</translation>
<translation id="3209034400446768650">გვერდმრშეიძლებრდáƒáƒ’áƒáƒ™áƒ˜áƒ¡áƒ áƒáƒ— თáƒáƒœáƒ®áƒ˜áƒ¡ გáƒáƒ“áƒáƒ®áƒ“áƒ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />-ზე თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რმáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ის ქვეშáƒáƒ</translation>
+<translation id="3212623355668894776">áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘იდáƒáƒœ თქვენი დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘ის წáƒáƒ¡áƒáƒ¨áƒšáƒ”ლáƒáƒ“ დáƒáƒ®áƒ£áƒ áƒ”თ სტუმრის ყველრფáƒáƒœáƒ¯áƒáƒ áƒ.</translation>
<translation id="3215092763954878852">WebAuthn-ის გáƒáƒ›áƒáƒ§áƒ”ნებრვერ ხერხდებáƒ</translation>
<translation id="3218181027817787318">ფáƒáƒ áƒ“áƒáƒ‘ითი</translation>
<translation id="3225919329040284222">სერვერმრწáƒáƒ áƒ›áƒáƒáƒ“გინრსერტიფიკáƒáƒ¢áƒ˜, რáƒáƒ›áƒ”ლიც áƒáƒ  შეესáƒáƒ‘áƒáƒ›áƒ”ბრჩáƒáƒ¨áƒ”ნებულ მáƒáƒ—ხáƒáƒ•áƒœáƒ”ბს. ეს მáƒáƒ—ხáƒáƒ•áƒœáƒ”ბი ჩáƒáƒ áƒ—ულირუსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის მáƒáƒ¦áƒáƒšáƒ˜ დáƒáƒœáƒ˜áƒ¡ მქáƒáƒœáƒ” გáƒáƒ áƒ™áƒ•áƒ”ული ვებსáƒáƒ˜áƒ¢áƒ”ბისთვის, თქვენი დáƒáƒªáƒ•áƒ˜áƒ¡ მიზნით.</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">Bluetooth მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ები</translation>
<translation id="3787705759683870569">ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ თáƒáƒ áƒ˜áƒ¦áƒ˜: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ზáƒáƒ›áƒ 16</translation>
+<translation id="3789841737615482174">ინსტáƒáƒšáƒáƒªáƒ˜áƒ</translation>
<translation id="3793574014653384240">áƒáƒ®áƒšáƒáƒ®áƒáƒœ დáƒáƒ¤áƒ˜áƒ¥áƒ¡áƒ˜áƒ áƒ”ბული áƒáƒ•áƒáƒ áƒ˜áƒ£áƒšáƒ˜ გáƒáƒ—იშვების ნáƒáƒ›áƒ áƒ”ბი დრგáƒáƒ›áƒáƒ›áƒ¬áƒ•áƒ”ვი მიზეზები</translation>
<translation id="3797522431967816232">Prc3 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="3799805948399000906">შრიფტი მáƒáƒ—ხáƒáƒ•áƒœáƒ˜áƒšáƒ˜áƒ</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">სეპიáƒ</translation>
<translation id="4058922952496707368">გáƒáƒ¡áƒáƒ¦áƒ”ბი „<ph name="SUBKEY" />“ <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (კáƒáƒœáƒ•áƒ”რტი)</translation>
+<translation id="4067669230157909013">ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ¦áƒ‘ეჭდვრგáƒáƒ’რძელდáƒ.</translation>
<translation id="4067947977115446013">მიუთითეთ სწáƒáƒ áƒ˜ მისáƒáƒ›áƒáƒ áƒ—ი</translation>
<translation id="4072486802667267160">თქვენი შეკვეთის დáƒáƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბრვერ მáƒáƒ®áƒ”რხდáƒ. გთხáƒáƒ•áƒ—, ცáƒáƒ“áƒáƒ— ხელáƒáƒ®áƒšáƒ.</translation>
<translation id="4075732493274867456">კლიენტისრდრსერვერის მიერ áƒáƒ  áƒáƒ áƒ˜áƒ¡ მხáƒáƒ áƒ“áƒáƒ­áƒ”რილი SSL პრáƒáƒ¢áƒáƒ™áƒáƒšáƒ˜áƒ¡ სáƒáƒ”რთრვერსირáƒáƒœ შიფრáƒáƒ¢áƒáƒ áƒ”ბის ნáƒáƒ™áƒ áƒ”ბი.</translation>
@@ -826,6 +840,7 @@
<translation id="4297502707443874121">ესკიზი გვერდისთვის <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">გáƒáƒ¨áƒšáƒ</translation>
<translation id="4300675098767811073">მრáƒáƒ•áƒšáƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრმáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ•</translation>
+<translation id="4302514097724775343">სáƒáƒ—áƒáƒ›áƒáƒ¨áƒáƒ“ შეეხეთ დინáƒáƒ–áƒáƒ•áƒ áƒ¡</translation>
<translation id="4302965934281694568">Chou3 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="4305666528087210886">თქვენს ფáƒáƒ˜áƒšáƒ–ე წვდáƒáƒ›áƒ ვერ მáƒáƒ®áƒ”რხდáƒ</translation>
<translation id="4305817255990598646">გáƒáƒ“áƒáƒ áƒ—ვáƒ</translation>
@@ -904,6 +919,7 @@
<translation id="4658638640878098064">ზედრმáƒáƒ áƒªáƒ®áƒ”ნრნáƒáƒ¬áƒ˜áƒšáƒ˜áƒ¡ დáƒáƒ¡áƒ¢áƒ”პლერებáƒ</translation>
<translation id="4668929960204016307">.</translation>
<translation id="4670064810192446073">ვირტუáƒáƒšáƒ£áƒ áƒ˜ რეáƒáƒšáƒáƒ‘áƒ</translation>
+<translation id="4675657451653251260">სტუმრის რეჟიმში Chrome პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ¡ ვერ დáƒáƒ˜áƒœáƒáƒ®áƒáƒ•áƒ—. Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ–ე (მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, პáƒáƒ áƒáƒšáƒ”ბზე áƒáƒœ გáƒáƒ“áƒáƒ®áƒ“ის მეთáƒáƒ“ებზე) წვდáƒáƒ›áƒ˜áƒ¡áƒ—ვის შეგიძლიáƒáƒ— <ph name="LINK_BEGIN" />შეხვიდეთ სისტემáƒáƒ¨áƒ˜<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">ეს სერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერტიფიკáƒáƒ¢áƒ˜ შეიცáƒáƒ•áƒ¡ შეცდáƒáƒ›áƒáƒ¡. ეს შეიძლებრგáƒáƒ›áƒáƒ¬áƒ•áƒ”ული იყáƒáƒ¡ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ გáƒáƒ“áƒáƒ­áƒ áƒ˜áƒ—.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ითხáƒáƒ•áƒ¡ მáƒáƒ áƒ¢áƒ˜áƒ• წვდáƒáƒ›áƒáƒ¡áƒ—áƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბულ მáƒáƒ•áƒšáƒ”ნებზე რეáƒáƒ’ირების ნებáƒáƒ áƒ—ვáƒ</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -931,6 +947,12 @@
<translation id="4761104368405085019">გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ თქვენი მიკრáƒáƒ¤áƒáƒœáƒ˜</translation>
<translation id="4764776831041365478">ვებგვერდი <ph name="URL" />-ზე შეიძლებრდრáƒáƒ”ბით იყáƒáƒ¡ მწყáƒáƒ‘რიდáƒáƒœ გáƒáƒ›áƒáƒ¡áƒ£áƒšáƒ˜ áƒáƒœ შეიძლებრის სáƒáƒ›áƒ£áƒ“áƒáƒ›áƒáƒ“ გáƒáƒ“áƒáƒ•áƒ˜áƒ“რáƒáƒ®áƒáƒš ვებ მისáƒáƒ›áƒáƒ áƒ—ზე.</translation>
<translation id="4766713847338118463">áƒáƒ áƒ›áƒáƒ’áƒáƒ“ დáƒáƒ¡áƒ¢áƒ”პლერებრქვემáƒáƒ—</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒ, რáƒáƒ›áƒ”ლიც დáƒáƒ áƒ©áƒ”ბრáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />áƒáƒ› ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ მეშვეáƒáƒ‘ით ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული ფáƒáƒ˜áƒšáƒ”ბი
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">დáƒáƒ¤áƒ˜áƒ¥áƒ¡áƒ˜áƒ áƒ“რუცნáƒáƒ‘ი შეცდáƒáƒ›áƒ.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{áƒáƒ›áƒáƒ›áƒ®áƒ¢áƒáƒ áƒ˜ ფáƒáƒœáƒ¯áƒáƒ áƒ დáƒáƒ˜áƒ‘ლáƒáƒ™áƒ}other{# áƒáƒ›áƒáƒ›áƒ®áƒ¢áƒáƒ áƒ˜ ფáƒáƒœáƒ¯áƒáƒ áƒ დáƒáƒ˜áƒ‘ლáƒáƒ™áƒ}}</translation>
<translation id="4780366598804516005">სáƒáƒ¤áƒáƒ¡áƒ¢áƒ ყუთი 1</translation>
@@ -1093,11 +1115,13 @@
<translation id="5386426401304769735">áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ სერტიფიკáƒáƒ¢áƒ—რჯáƒáƒ­áƒ•áƒ˜ SHA-1-ის მეშვეáƒáƒ‘ით ხელმáƒáƒ¬áƒ”რილ სერტიფიკáƒáƒ¢áƒ¡ შეიცáƒáƒ•áƒ¡.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">კიდეების მიკერებრმáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ•</translation>
+<translation id="5398772614898833570">რეკლáƒáƒ›áƒ დáƒáƒ˜áƒ‘ლáƒáƒ™áƒ</translation>
<translation id="5400836586163650660">ნáƒáƒªáƒ áƒ˜áƒ¡áƒ¤áƒ”რი</translation>
<translation id="540969355065856584">ეს სერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს, რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერთიფიკáƒáƒ¢áƒ˜ áƒáƒ›áƒŸáƒáƒ›áƒáƒ“ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ. ეს შეიძლებრიყáƒáƒ¡ გáƒáƒ›áƒáƒ¬áƒ•áƒ”ული áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ ხელში ჩáƒáƒ’დებით.</translation>
<translation id="541416427766103491">სტეკერი 4</translation>
<translation id="5421136146218899937">დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების მáƒáƒœáƒáƒªáƒ”მების გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”ბáƒâ€¦</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ითხáƒáƒ•áƒ¡ თქვენთვის შეტყáƒáƒ‘ინებების გáƒáƒ›áƒáƒ’ზáƒáƒ•áƒœáƒáƒ¡</translation>
+<translation id="542872847390508405">თქვენ áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებთ სáƒáƒ˜áƒ¢áƒ¡ სტუმრის სტáƒáƒ¢áƒ£áƒ¡áƒ˜áƒ—</translation>
<translation id="5430298929874300616">სáƒáƒœáƒ˜áƒ¨áƒœáƒ˜áƒ¡ áƒáƒ›áƒáƒ¨áƒšáƒ</translation>
<translation id="5439770059721715174">ქსემის გáƒáƒ“áƒáƒ›áƒáƒ¬áƒ›áƒ”ვის შეცდáƒáƒ›áƒ „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">უკუმიმდევრáƒáƒ‘რნáƒáƒ‘ეჭდი მხáƒáƒ áƒ˜áƒ— áƒáƒ¦áƒ›áƒ</translation>
@@ -1139,12 +1163,12 @@
<translation id="5571083550517324815">áƒáƒ› მისáƒáƒ›áƒáƒ áƒ—იდáƒáƒœ წáƒáƒ›áƒáƒ¦áƒ”ბრვერ მáƒáƒ®áƒ”რხდებáƒ. áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ სხვრმისáƒáƒ›áƒáƒ áƒ—ი.</translation>
<translation id="5580958916614886209">შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ თვე დრხელáƒáƒ®áƒšáƒ ცáƒáƒ“ეთ</translation>
<translation id="5586446728396275693">შენáƒáƒ®áƒ£áƒšáƒ˜ მისáƒáƒ›áƒáƒ áƒ—ები áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
+<translation id="5593349413089863479">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ სრულáƒáƒ“ დáƒáƒªáƒ£áƒšáƒ˜ áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
<translation id="5595485650161345191">მისáƒáƒ›áƒáƒ áƒ—ის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="5598944008576757369">გáƒáƒ“áƒáƒ®áƒ“ის მეთáƒáƒ“ის áƒáƒ áƒ©áƒ”ვáƒ</translation>
<translation id="560412284261940334">მáƒáƒ áƒ—ვრáƒáƒ  áƒáƒ áƒ˜áƒ¡ მხáƒáƒ áƒ“áƒáƒ­áƒ”რილი</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ეს სáƒáƒ˜áƒ¢áƒ˜ შეიძლებრიყáƒáƒ¡ ყáƒáƒšáƒ‘ი áƒáƒœ თáƒáƒ¦áƒšáƒ˜áƒ—ური. Chrome გირჩევთ გáƒáƒ¡áƒ•áƒšáƒáƒ¡.</translation>
<translation id="5610142619324316209">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ შემáƒáƒ¬áƒ›áƒ”ბáƒ</translation>
<translation id="5610807607761827392">ბáƒáƒ áƒáƒ—ებისრდრმისáƒáƒ›áƒáƒ áƒ—ების მáƒáƒ áƒ—ვრ<ph name="BEGIN_LINK" />პáƒáƒ áƒáƒ›áƒ”ტრებში<ph name="END_LINK" /> შეგიძლიáƒáƒ—.</translation>
<translation id="561165882404867731">თáƒáƒ áƒ’მნეთ ეს გვერდი Google Translate-ის მეშვეáƒáƒ‘ით</translation>
@@ -1216,6 +1240,7 @@
<translation id="5901630391730855834">ყვითელი</translation>
<translation id="5905445707201418379">დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ <ph name="ORIGIN" />-ის წყáƒáƒ áƒáƒ¡ წესების შესáƒáƒ‘áƒáƒ›áƒ˜áƒ¡áƒáƒ“.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (სინქრáƒáƒœáƒ˜áƒ–ებული)</translation>
+<translation id="5913377024445952699">ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ¦áƒ‘ეჭდვრდáƒáƒžáƒáƒ£áƒ–დáƒ</translation>
<translation id="59174027418879706">ჩáƒáƒ áƒ—ული</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ჩáƒáƒ áƒ—ული</translation>
@@ -1228,6 +1253,7 @@
<translation id="5963413905009737549">სექციáƒ</translation>
<translation id="5967592137238574583">სáƒáƒ™áƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="5967867314010545767">áƒáƒ›áƒáƒ¨áƒáƒšáƒ”თ ისტáƒáƒ áƒ˜áƒ˜áƒ“áƒáƒœ</translation>
+<translation id="5968793460449681917">ყáƒáƒ•áƒ”ლ ვიზიტზე</translation>
<translation id="5975083100439434680">დáƒáƒ¨áƒáƒ áƒ”ბáƒ</translation>
<translation id="5979084224081478209">პáƒáƒ áƒáƒšáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბáƒ</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1383,6 +1409,7 @@
<translation id="6587923378399804057">თქვენ მიერ კáƒáƒžáƒ˜áƒ áƒ”ბული ბმული</translation>
<translation id="6591833882275308647">თქვენი <ph name="DEVICE_TYPE" /> áƒáƒ  áƒáƒ áƒ˜áƒ¡ მáƒáƒ áƒ—ული</translation>
<translation id="6596325263575161958">დáƒáƒ¨áƒ˜áƒ¤áƒ•áƒ áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრები</translation>
+<translation id="6596892391065203054">áƒáƒ› კáƒáƒœáƒ¢áƒ”ნტის ბეჭდვრდáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ.</translation>
<translation id="6604181099783169992">მáƒáƒ«áƒ áƒáƒáƒ‘ის áƒáƒœ გáƒáƒœáƒáƒ—ების სენსáƒáƒ áƒ”ბი</translation>
<translation id="6609880536175561541">Prc7 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="6612358246767739896">დáƒáƒªáƒ£áƒšáƒ˜ შიგთáƒáƒ•áƒ¡áƒ˜</translation>
@@ -1442,6 +1469,7 @@
<translation id="6895330447102777224">თქვენი ბáƒáƒ áƒáƒ—ი დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ“áƒ</translation>
<translation id="6897140037006041989">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის áƒáƒ’ენტი</translation>
<translation id="6898699227549475383">áƒáƒ áƒ’áƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />-ისთვის დáƒáƒ¨áƒ•áƒ”ბული იყáƒáƒ¡:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ითხáƒáƒ•áƒ¡ თქვენი MIDI მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ების სრულáƒáƒ“ გáƒáƒ™áƒáƒœáƒ¢áƒ áƒáƒšáƒ”ბის ნებáƒáƒ áƒ—ვáƒáƒ¡</translation>
<translation id="6915804003454593391">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბელი:</translation>
<translation id="6934672428414710184">ეს სáƒáƒ®áƒ”ლი მáƒáƒ›áƒ“ინáƒáƒ áƒ”áƒáƒ‘ს თქვენი Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ“áƒáƒœ</translation>
@@ -1553,6 +1581,7 @@
<translation id="7346048084945669753">áƒáƒ¤áƒ˜áƒšáƒ˜áƒ áƒ”ბულáƒáƒ‘áƒ:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">ბრძáƒáƒœáƒ”ბის სტრიქáƒáƒœáƒ˜</translation>
+<translation id="7359588939039777303">რეკლáƒáƒ›áƒ დáƒáƒ˜áƒ‘ლáƒáƒ™áƒ.</translation>
<translation id="7372973238305370288">ძიების შედეგი</translation>
<translation id="7374733840632556089">áƒáƒ› პრáƒáƒ‘ლემის გáƒáƒ›áƒáƒ›áƒ¬áƒ•áƒ”ვი მიზეზირთქვენ áƒáƒœ სხვის მიერ თქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე დáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”ბული სერტიფიკáƒáƒ¢áƒ˜. ცნáƒáƒ‘ილიáƒ, რáƒáƒ› ეს სერტიფიკáƒáƒ¢áƒ˜ გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნებრქსელების მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ისთვის დრხელში ჩáƒáƒ¡áƒáƒ’დებáƒáƒ“, áƒáƒ›áƒ˜áƒ¢áƒáƒ› Chrome მáƒáƒ¡ áƒáƒ  ენდáƒáƒ‘áƒ. მáƒáƒ áƒ—áƒáƒšáƒ˜áƒ, áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ის კáƒáƒœáƒáƒœáƒ˜áƒ”რი მიზეზები (მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, სáƒáƒ¡áƒ¬áƒáƒ•áƒšáƒ”ბლების áƒáƒœ კáƒáƒ›áƒžáƒáƒœáƒ˜áƒ”ბის ქსელებში), Chrome-ს მáƒáƒ˜áƒœáƒª სურს, რáƒáƒ› იცáƒáƒ“ეთ, რრხდებრიმ შემთხვევáƒáƒ¨áƒ˜áƒª კი, თუ áƒáƒ¦áƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ¡ ვერ áƒáƒ¦áƒ™áƒ•áƒ”თთ. მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ი შეიძლებრმიმდინáƒáƒ áƒ”áƒáƒ‘დეს ვებზე წვდáƒáƒ›áƒ˜áƒ¡ მქáƒáƒœáƒ” ნებისმიერ ბრáƒáƒ£áƒ–ერში თუ áƒáƒžáƒšáƒ˜áƒ™áƒáƒªáƒ˜áƒáƒ¨áƒ˜.</translation>
<translation id="7375818412732305729">ფáƒáƒ˜áƒšáƒ˜áƒ¡ დáƒáƒ áƒ—ვáƒ</translation>
@@ -1727,6 +1756,7 @@
<translation id="7976214039405368314">ზედმეტáƒáƒ“ ბევრი მáƒáƒ—ხáƒáƒ•áƒœáƒáƒ</translation>
<translation id="7977538094055660992">გáƒáƒ›áƒáƒ¢áƒáƒœáƒ˜áƒ¡ მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘ის კáƒáƒœáƒ¢áƒ”ნტის სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ დáƒáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”თ ARCore</translation>
<translation id="799149739215780103">áƒáƒ™áƒ˜áƒœáƒ«áƒ•áƒ</translation>
<translation id="7995512525968007366">áƒáƒ  áƒáƒ áƒ˜áƒ¡ მითითებული</translation>
<translation id="800218591365569300">მეხსიერების გáƒáƒ›áƒáƒ¡áƒáƒ—áƒáƒ•áƒ˜áƒ¡áƒ£áƒ¤áƒšáƒ”ბლáƒáƒ“ ცáƒáƒ“ეთ სხვრჩáƒáƒœáƒáƒ áƒ—ების áƒáƒœ პრáƒáƒ’რáƒáƒ›áƒ”ბის დáƒáƒ®áƒ£áƒ áƒ•áƒ.</translation>
@@ -1854,24 +1884,38 @@
<translation id="8507227106804027148">ბრძáƒáƒœáƒ”ბáƒáƒ—რსტრიქáƒáƒœáƒ˜</translation>
<translation id="8508648098325802031">ძიების ხáƒáƒ¢áƒ£áƒšáƒ</translation>
<translation id="8522552481199248698">Chrome-ს შეუძლირდáƒáƒ’ეხმáƒáƒ áƒáƒ— თქვენი Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ დáƒáƒªáƒ•áƒáƒ¨áƒ˜ დრპáƒáƒ áƒáƒšáƒ˜áƒ¡ შეცვლáƒáƒ¨áƒ˜.</translation>
+<translation id="8525306231823319788">მთელ ეკრáƒáƒœáƒ–ე</translation>
<translation id="8530813470445476232">გáƒáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”თ დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების ისტáƒáƒ áƒ˜áƒ, ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები, ქეში დრსხვრკáƒáƒœáƒ¢áƒ”ნტი Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
<translation id="8533619373899488139">ეწვიეთ გვერდს &lt;strong&gt;chrome://policy&lt;/strong&gt; დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜ URL-ების სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ დრáƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ გáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”ბული სხვრწესების დáƒáƒ¡áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებლáƒáƒ“.</translation>
<translation id="8541158209346794904">Bluetooth მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒ</translation>
<translation id="8542014550340843547">სáƒáƒ›áƒ›áƒáƒ’áƒáƒ“ დáƒáƒ¡áƒ¢áƒ”პლერებრქვემáƒáƒ—</translation>
<translation id="8543181531796978784">შეგიძლიáƒáƒ— <ph name="BEGIN_ERROR_LINK" />მáƒáƒ’ვáƒáƒ®áƒ¡áƒ”ნáƒáƒ— გáƒáƒ›áƒáƒ•áƒšáƒ”ნáƒáƒ¡áƒ—áƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული პრáƒáƒ‘ლემáƒ<ph name="END_ERROR_LINK" /> áƒáƒœ თუ áƒáƒªáƒœáƒáƒ‘იერებთ უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბáƒáƒ¡áƒ—áƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბულ რისკებს, <ph name="BEGIN_LINK" />გáƒáƒ“áƒáƒ®áƒ•áƒ˜áƒ“ეთ áƒáƒ› áƒáƒ áƒáƒ¡áƒáƒ˜áƒ›áƒ”დრსáƒáƒ˜áƒ¢áƒ–ე<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC მითითებულირთქვენი ბáƒáƒ áƒáƒ—ის უკáƒáƒœáƒ ნáƒáƒ¬áƒ˜áƒšáƒ–ე.</translation>
+<translation id="8558485628462305855">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘ის კáƒáƒœáƒ¢áƒ”ნტის სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ გáƒáƒœáƒáƒáƒ®áƒšáƒ”თ ARCore</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-თáƒáƒœ პირáƒáƒ“ი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ დáƒáƒ›áƒ§áƒáƒ áƒ”ბრშეუძლებელიáƒ, რáƒáƒ“გáƒáƒœ თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის თáƒáƒ áƒ˜áƒ¦áƒ˜ დრდრáƒÂ (<ph name="DATE_AND_TIME" />) áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ.</translation>
<translation id="8564182942834072828">სხვáƒáƒ“áƒáƒ¡áƒ®áƒ•áƒ დáƒáƒ™áƒ£áƒ›áƒ”ნტი/შეურჩეველი áƒáƒ¡áƒšáƒ”ბი</translation>
<translation id="8564985650692024650">Chromium გირჩევთ, გáƒáƒ“áƒáƒáƒ§áƒ”ნáƒáƒ— <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-ის პáƒáƒ áƒáƒšáƒ˜, თუ მáƒáƒ¡ სხვრსáƒáƒ˜áƒ¢áƒ”ბზეც იყენებთ.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒ, რáƒáƒ›áƒ”ლიც áƒáƒ  დáƒáƒ áƒ©áƒ”ბრáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />áƒáƒ› ფáƒáƒœáƒ¯áƒáƒ áƒáƒ¨áƒ˜ ნáƒáƒœáƒáƒ®áƒ˜ გვერდები
+ <ph name="LIST_ITEM" />ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის მáƒáƒœáƒáƒªáƒ”მები
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Touch ID-ს გáƒáƒ›áƒáƒ§áƒ”ნებრბáƒáƒ áƒáƒ—ების უფრრსწრáƒáƒ¤áƒáƒ“ დáƒáƒ¡áƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბლáƒáƒ“</translation>
<translation id="858637041960032120">დáƒáƒáƒ›áƒáƒ¢áƒ”თ ტელეფáƒáƒœáƒ˜áƒ¡ ნáƒáƒ›áƒ”რი</translation>
<translation id="8589998999637048520">სáƒáƒ£áƒ™áƒ”თესრხáƒáƒ áƒ˜áƒ¡áƒ®áƒ˜</translation>
+<translation id="8600271352425265729">მხáƒáƒšáƒáƒ“ áƒáƒ›áƒ¯áƒ”რáƒáƒ“</translation>
<translation id="860043288473659153">ბáƒáƒ áƒáƒ—ის მფლáƒáƒ‘ელის სáƒáƒ®áƒ”ლი</translation>
<translation id="8606726445206553943">თქვენი MIDI მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ების გáƒáƒ›áƒáƒ§áƒ”ნებáƒ</translation>
+<translation id="8612761427948161954">გáƒáƒ›áƒáƒ áƒ¯áƒáƒ‘áƒ, <ph name="USERNAME" />,
+ <ph name="BR" />
+ ვებს სტუმრის სტáƒáƒ¢áƒ£áƒ¡áƒ˜áƒ— áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებთ</translation>
<translation id="861775596732816396">ზáƒáƒ›áƒ 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">შესáƒáƒ¢áƒ§áƒ•áƒ˜áƒ¡áƒ˜ პáƒáƒ áƒáƒšáƒ”ბი áƒáƒ  áƒáƒ áƒ˜áƒ¡. ყველრშენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ˜áƒ¡ ჩვენებáƒ.</translation>
<translation id="8625384913736129811">ბáƒáƒ áƒáƒ—ის შენáƒáƒ®áƒ•áƒ áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე</translation>
+<translation id="8627040765059109009">ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ¦áƒ‘ეჭდვრგáƒáƒ’რძელდáƒ</translation>
<translation id="8657078576661269990">თქვენმრáƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ›áƒ დáƒáƒ‘ლáƒáƒ™áƒ <ph name="ORIGIN_NAME" />-დáƒáƒœ <ph name="VM_NAME_1" />-სრდრ<ph name="VM_NAME_2" />-ზე გáƒáƒ–იáƒáƒ áƒ”ბáƒ</translation>
<translation id="8663226718884576429">შეკვეთის რეზიუმე, <ph name="TOTAL_LABEL" />, დáƒáƒ›áƒáƒ¢áƒ”ბითი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="867224526087042813">ხელმáƒáƒ¬áƒ”რáƒ</translation>
@@ -1934,6 +1978,7 @@
<translation id="8912362522468806198">Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜</translation>
<translation id="8913778647360618320">გáƒáƒ“áƒáƒ®áƒ“ის მეთáƒáƒ“ების მáƒáƒ áƒ—ვის ღილáƒáƒ™áƒ˜, Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ სáƒáƒ’áƒáƒ“áƒáƒ®áƒ“რდრსáƒáƒ™áƒ áƒ”დიტრბáƒáƒ áƒáƒ—ების ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter-ს</translation>
<translation id="8918231688545606538">ეს გვერდი სáƒáƒ”ჭვáƒáƒ</translation>
+<translation id="8922013791253848639">áƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე რეკლáƒáƒ›áƒ˜áƒ¡ ყáƒáƒ•áƒ”ლთვის დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="892588693504540538">ზედრმáƒáƒ áƒ¯áƒ•áƒ”ნრნáƒáƒ¬áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ•áƒ áƒ”ტáƒ</translation>
<translation id="8931333241327730545">გსურთ áƒáƒ› ბáƒáƒ áƒáƒ—ის თქვენს Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ შენáƒáƒ®áƒ•áƒ?</translation>
<translation id="8932102934695377596">თქვენი სáƒáƒáƒ—ი უკáƒáƒœáƒáƒ</translation>
@@ -2005,6 +2050,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> მხáƒáƒ áƒ“áƒáƒ£áƒ­áƒ”რელ პრáƒáƒ¢áƒáƒ™áƒáƒšáƒ¡ იყენებს.</translation>
<translation id="9191834167571392248">ქვედრმáƒáƒ áƒªáƒ®áƒ”ნრნáƒáƒ¬áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ•áƒ áƒ”ტáƒ</translation>
+<translation id="9199905725844810519">ბეჭდვრდáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ</translation>
<translation id="9205078245616868884">თქვენი მáƒáƒœáƒáƒªáƒ”მები დáƒáƒ¨áƒ˜áƒ¤áƒ áƒ£áƒšáƒ˜áƒ სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ˜áƒ“უმლრფრáƒáƒ–ის მეშვეáƒáƒ‘ით. სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ¡áƒáƒ¬áƒ§áƒ”ბáƒáƒ“, შეიყვáƒáƒœáƒ”თ სáƒáƒ˜áƒ“უმლრფრáƒáƒ–áƒ.</translation>
<translation id="9207861905230894330">ვერ მáƒáƒ®áƒ”რხდრსტáƒáƒ¢áƒ˜áƒ˜áƒ¡ დáƒáƒ›áƒáƒ¢áƒ”ბáƒ.</translation>
<translation id="9213433120051936369">მáƒáƒ˜áƒ áƒ’ეთ იერსáƒáƒ®áƒ”</translation>
@@ -2015,8 +2061,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">თქვენ შეიძლებრდáƒáƒ™áƒáƒ áƒ’áƒáƒ— წვდáƒáƒ›áƒ თქვენს Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ–ე. Chromium გირჩევთ, áƒáƒ®áƒšáƒáƒ•áƒ” შეცვáƒáƒšáƒáƒ— პáƒáƒ áƒáƒšáƒ˜. თქვენ მáƒáƒ’იწევთ სისტემáƒáƒ¨áƒ˜ შესვლáƒ.</translation>
<translation id="939736085109172342">áƒáƒ®áƒáƒšáƒ˜ სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ე</translation>
+<translation id="945522503751344254">შეფáƒáƒ¡áƒ”ბის გáƒáƒ’ზáƒáƒ•áƒœáƒ</translation>
<translation id="945855313015696284">გáƒáƒ”ცáƒáƒœáƒ˜áƒ— ქვემáƒáƒ— მáƒáƒªáƒ”მულ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ¡ დრწáƒáƒ¨áƒáƒšáƒ”თ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ბáƒáƒ áƒáƒ—ები</translation>
<translation id="950736567201356821">სáƒáƒ›áƒ›áƒáƒ’áƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრზემáƒáƒ—</translation>
+<translation id="951941430552851965">ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ¦áƒ‘ეჭდვრდáƒáƒžáƒáƒ£áƒ–დრთქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ, რáƒáƒ“გáƒáƒœ ეკრáƒáƒœáƒ–ე გáƒáƒ áƒ™áƒ•áƒ”ული ტიპის კáƒáƒœáƒ¢áƒ”ნტი გáƒáƒ¥áƒ•áƒ—.</translation>
<translation id="961663415146723894">áƒáƒ™áƒ˜áƒœáƒ«áƒ•áƒ ქვემáƒáƒ—</translation>
<translation id="962484866189421427">áƒáƒ› კáƒáƒœáƒ¢áƒ”ნტის მეშვეáƒáƒ‘ით შეიძლებრდáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ“ეს შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœáƒ˜ áƒáƒžáƒ”ბი, რáƒáƒ›áƒšáƒ”ბსáƒáƒª შეუძლირთáƒáƒ•áƒ˜áƒ¡ გáƒáƒ¡áƒáƒ¦áƒ”ბრსხვრáƒáƒžáƒ”ბáƒáƒ“ áƒáƒœ ისეთი მáƒáƒœáƒáƒªáƒ”მების შეგრáƒáƒ•áƒ”ბáƒ, რáƒáƒ›áƒ”ლთრმეშვეáƒáƒ‘ითáƒáƒª შესáƒáƒ«áƒšáƒ”ბელი იქნებრთქვენთვის თვáƒáƒšáƒ˜áƒ¡ მიდევნებáƒ. <ph name="BEGIN_LINK" />მáƒáƒ˜áƒœáƒª ჩვენებáƒ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">áƒáƒ¤áƒ˜áƒªáƒ˜áƒáƒšáƒ£áƒ áƒ˜ კáƒáƒœáƒ¡áƒ¢áƒ áƒ£áƒ¥áƒªáƒ˜áƒ</translation>
diff --git a/chromium/components/strings/components_strings_kk.xtb b/chromium/components/strings/components_strings_kk.xtb
index e0587fa736f..463706a94f8 100644
--- a/chromium/components/strings/components_strings_kk.xtb
+++ b/chromium/components/strings/components_strings_kk.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ÒšÒ±Ð¿Ð¸Ñ Ñөзіңізді ұйымыңыз баÑқармайтын Ñайтта енгіздіңіз. ЕÑептік жазбаны қорғау үшін Ò›Ò±Ð¿Ð¸Ñ Ñөзді баÑқа қолданбалар мен Ñайттарда қолданбаңыз.</translation>
<translation id="1263231323834454256">Оқу тізімі</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Құрылғыда келеÑÑ– ақпарат Ñақталмайды:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />оÑÑ‹ терезеде көретін беттер;
+ <ph name="LIST_ITEM" />cookie файлдары және Ñайт деректері;
+ <ph name="LIST_ITEM" />еÑептік жазба туралы ақпарат (<ph name="LINK_BEGIN" />шығу<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Таңдау әдіÑÑ–</translation>
<translation id="1281476433249504884">1-жинаÑтырушы</translation>
<translation id="1285320974508926690">Бұл Ñайтты ешқашан аудармау</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Google еÑептік жазбаңызда Ñақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздерді пайдалану үшін кіру</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> тіліндегі беттер аударылмайды.</translation>
<translation id="2053553514270667976">Пошта индекÑÑ–</translation>
+<translation id="2054665754582400095">Бар болу деректері</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Ò±ÑыныÑ}other{# Ò±ÑыныÑ}}</translation>
<translation id="2079545284768500474">Қайтару</translation>
<translation id="20817612488360358">Жүйелік прокÑи параметрлері пайдалану үшін орнатылған, бірақ анық прокÑи конфигурациÑÑÑ‹ да көрÑетілген.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android қолданбалары</translation>
<translation id="2107021941795971877">БаÑпаны қолдау</translation>
<translation id="2108755909498034140">Компьютерді қайта Ñ–Ñке қоÑу</translation>
+<translation id="2111166930115883695">Ойнау үшін Ð±Ð¾Ñ Ð¾Ñ€Ñ‹Ð½ пернеÑін баÑыңыз.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701">Еленбейді, Ñебебі оны <ph name="POLICY_NAME" /> қайта анықтаған.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Төлемнен Ð±Ð°Ñ Ñ‚Ð°Ñ€Ñ‚Ñƒ</translation>
<translation id="2147827593068025794">Фондық Ñинхрондау</translation>
<translation id="2148613324460538318">Картаны енгізу</translation>
+<translation id="2149968176347646218">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ò›Ð°ÑƒÑ–Ð¿Ñіз емеÑ</translation>
<translation id="2154054054215849342">Синхрондау функциÑÑÑ‹ доменіңіз үшін қолжетімді емеÑ</translation>
<translation id="2154484045852737596">Карта мәліметін өңдеу</translation>
<translation id="2161656808144014275">Мәтін</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">СаÑÑаттар</translation>
<translation id="2183608646556468874">Телефон нөмірі</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 мекенжай}other{# мекенжай}}</translation>
-<translation id="2187243482123994665">Пайдаланушының бар-жоғы</translation>
<translation id="2187317261103489799">Ðнықтау (әдепкі)</translation>
<translation id="2188375229972301266">Төменгі жағын бірнеше рет теÑу</translation>
<translation id="2202020181578195191">Ð”Ò±Ñ€Ñ‹Ñ Ð¶Ð°Ñ€Ð°Ð¼Ð´Ñ‹Ð»Ñ‹Ò› мерзімі аÑқталатын жылды енгізіңіз</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Ðазар аударыңыз: жалған Ñайт</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ñайтындағы шабуылдаушылар ақпаратыңызды (мыÑалы, Ò›Ò±Ð¿Ð¸Ñ Ñөздер, хабарлар немеÑе неÑиелік карталар) ұрлауға әрекет етуі мүмкін.<ph name="BEGIN_LEARN_MORE_LINK" />Толығырақ<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Бұл Ñайтта мазалайтын немеÑе жалған ақпаратты жарнамалар көрÑетіледі.</translation>
<translation id="2878197950673342043">ПоÑтер тәрізді бүктеу</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Терезені орналаÑтыру</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google Ò±Ñынатындар</translation>
<translation id="3002501248619246229">ÐšÑ–Ñ€Ñ–Ñ Ð½Ð°ÑƒÐ°Ñының деректерін текÑеру</translation>
<translation id="3005723025932146533">Сақталған көшірмені көрÑету</translation>
-<translation id="3007719053326478567">Бұл мазмұнды баÑып шығаруға әкімші тыйым Ñалған.</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> картаÑының CVC кодын енгізіңіз. Карта мәліметтері раÑталғаннан кейін Ñайтқа беріледі.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />" тізім жазбаÑÑ‹: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Ðвтоматты түрде бөгелген</translation>
<translation id="3016780570757425217">ОрналаÑқан жеріңізді білу</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Ò±ÑыныÑÑ‚Ñ‹ өшіру үшін Tab пернеÑін, Ñодан кейін Enter пернеÑін баÑыңыз.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Қате ÑаÑÑат түрі</translation>
<translation id="3037605927509011580">Қап!</translation>
@@ -554,6 +565,7 @@
<translation id="3207960819495026254">Бетбелгі қойылған</translation>
<translation id="3209034400446768650">Бұл бет ақылы болуы мүмкін</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> хоÑтында әрекетіңіз бақыланады</translation>
+<translation id="3212623355668894776">Браузерді қолдану мәліметі бұл құрылғыдан жойылуы үшін, қонақ режиміндегі барлық терезені жабыңыз.</translation>
<translation id="3215092763954878852">WebAuthn қолдану мүмкін болмады</translation>
<translation id="3218181027817787318">Ò°Ò›ÑаÑ</translation>
<translation id="3225919329040284222">Сервер ендірілген параметрлерге ÑÓ™Ð¹ÐºÐµÑ ÐºÐµÐ»Ð¼ÐµÐ¹Ñ‚Ñ–Ð½ Ñертификатты Ò±Ñынды. Бұл параметрлер Ñізді қорғау үшін аÑа қауіпÑіз белгілі бір веб-Ñайттар үшін қамтылған.</translation>
@@ -701,6 +713,7 @@
<translation id="3784372983762739446">Bluetooth құрылғылары</translation>
<translation id="3787705759683870569">Жарамдылық мерзімі: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Өлшемі: 16</translation>
+<translation id="3789841737615482174">Орнату</translation>
<translation id="3793574014653384240">Жақында болған бұзылудың Ñандары мен Ñебептері</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Қаріп Ñұралды</translation>
@@ -752,6 +765,7 @@
<translation id="4056223980640387499">СепиÑ</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" кілті: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Экранды Ñуретке Ñ‚Ò¯Ñіру жалғаÑÑ‚Ñ‹.</translation>
<translation id="4067947977115446013">Жарамды мекенжайды енгізу</translation>
<translation id="4072486802667267160">Төлем жаÑау кезінде қате кетті. Әрекетті қайталаңыз.</translation>
<translation id="4075732493274867456">Клиент пен Ñервер ортақ SSL протоколының нұÑқаÑын немеÑе шифрлар жиынтығын қолдамайды.</translation>
@@ -836,6 +850,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> бетіне арналған нобай</translation>
<translation id="42981349822642051">Жаю</translation>
<translation id="4300675098767811073">Оң жақтан бірнеше рет теÑу</translation>
+<translation id="4302514097724775343">Ойнау үшін динозаврды баÑыңыз.</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Файлға кіру мүмкін болмады</translation>
<translation id="4305817255990598646">ÐуыÑу</translation>
@@ -914,6 +929,7 @@
<translation id="4658638640878098064">Жоғарғы Ñол жағын қапÑыру</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуалды шындық</translation>
+<translation id="4675657451653251260">Қонақ режимінде Chrome профилі туралы ешқандай ақпарат көрÑетілмейді. ÒšÒ±Ð¿Ð¸Ñ Ñөздер және төлеу әдіÑÑ– ÑиÑқты деректерді пайдалану үшін Google еÑептік жазбаÑына <ph name="LINK_BEGIN" />кіріңіз<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Бұл Ñервер өзінің <ph name="DOMAIN" /> екенін дәлелдей алмады; оның қауіпÑіздік Ñертификатында қателер бар. Бұл Ð´Ò±Ñ€Ñ‹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñланбағаннан немеÑе зиÑнды бағдарламаның байланыÑқа кедергі келтіргенінен болуы мүмкін.</translation>
<translation id="4677585247300749148"><ph name="URL" /> арнайы мүмкіндіктер оқиғаларына жауап бергіÑÑ– келеді</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -941,6 +957,12 @@
<translation id="4761104368405085019">Микрофоныңызды пайдалану</translation>
<translation id="4764776831041365478"><ph name="URL" /> мекенжайындағы веб-бет уақытша Ñ–Ñтен шыққан немеÑе тұрақты түрде баÑқа мекенжайға көшкен болуы мүмкін.</translation>
<translation id="4766713847338118463">Төменгі жағын екі рет қапÑыру</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Құрылғыда келеÑілер Ñақталады:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />оÑÑ‹ терезеде жүктеп алған кез келген файлдар.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">БелгіÑіз қате орын алды.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Қалқымалы терезе бөгелді}other{# қалқымалы терезе бөгелді}}</translation>
<translation id="4780366598804516005">1-ші пошта жәшігі</translation>
@@ -1103,11 +1125,13 @@
<translation id="5386426401304769735">ОÑÑ‹ Ñайтқа арналған Ñертификат тізбегінде SHA-1 көмегімен қолтаңба қойылған Ñертификат бар.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Оң жақ жиегін тігу</translation>
+<translation id="5398772614898833570">Жарнамалар бөгелді</translation>
<translation id="5400836586163650660">Сұр</translation>
<translation id="540969355065856584">Бұл Ñервер өзінің <ph name="DOMAIN" /> екенін дәлелдей алмады; оның қауіпÑіздік Ñертификаты әзірше жарамайды. Бұл Ð´Ò±Ñ€Ñ‹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñланбағаннан немеÑе зиÑнды бағдарламаның байланыÑқа кедергі келтіргенінен болуы мүмкін.</translation>
<translation id="541416427766103491">4-жинаÑтырушы</translation>
<translation id="5421136146218899937">Шолу деректерін өшіру…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> хабарландыру жіберуге Ñ€Ò±Ò›Ñат Ñұрады</translation>
+<translation id="542872847390508405">Қонақ ретінде шолудаÑыз</translation>
<translation id="5430298929874300616">Бетбелгіні жою</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" жолындағы Ñхеманы раÑтау қатеÑÑ–: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Кері ретпен беткі жағында</translation>
@@ -1149,12 +1173,12 @@
<translation id="5571083550517324815">Бұл мекенжайдан таңдалмайды. БаÑқа мекенжайды таңдаңыз.</translation>
<translation id="5580958916614886209">Жарамдылық мерзімі бітетін айды текÑеріп, әрекетті қайталаңыз</translation>
<translation id="5586446728396275693">Сақталған мекенжайлар жоқ</translation>
+<translation id="5593349413089863479">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ñ‚Ð¾Ð»Ñ‹Ò› қауіпÑіз емеÑ</translation>
<translation id="5595485650161345191">Мекенжайды өзгерту</translation>
<translation id="5598944008576757369">Төлем әдіÑін таңдау</translation>
<translation id="560412284261940334">БаÑқаруға қолдау көрÑетілмеген</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Бұл – жалған немеÑе алаÑÒ› Ñайт болуы мүмкін. Chrome одан шығып кетуді Ò±Ñынады.</translation>
<translation id="5610142619324316209">БайланыÑÑ‚Ñ‹ текÑеру</translation>
<translation id="5610807607761827392">Карталарды және мекенжайларды <ph name="BEGIN_LINK" />Параметрлер<ph name="END_LINK" /> бөлімінде реттей алаÑыз.</translation>
<translation id="561165882404867731">ОÑÑ‹ бетті Google Translate арқылы аударыңыз.</translation>
@@ -1226,6 +1250,7 @@
<translation id="5901630391730855834">Сары</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> баÑтапқы ÑаÑÑатына ÑÓ™Ð¹ÐºÐµÑ Ð±Ó©Ð³ÐµÐ»Ð´Ñ–.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинхрондалған)</translation>
+<translation id="5913377024445952699">Экранды Ñ‚Ò¯Ñіру кідіртілді</translation>
<translation id="59174027418879706">ҚоÑылған</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ҚоÑулы</translation>
@@ -1238,6 +1263,7 @@
<translation id="5963413905009737549">Бөлім</translation>
<translation id="5967592137238574583">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð°Ò›Ð¿Ð°Ñ€Ð°Ñ‚Ñ‹Ð½ өңдеу</translation>
<translation id="5967867314010545767">Тарихтан алып таÑтау</translation>
+<translation id="5968793460449681917">Кірген Ñайын</translation>
<translation id="5975083100439434680">Кішірейту</translation>
<translation id="5979084224081478209">ÒšÒ±Ð¿Ð¸Ñ Ñөздерді текÑеру</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@
<translation id="6587923378399804057">Көшірілген Ñілтеме</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> құрылғыңыз баÑқарылмайды.</translation>
<translation id="6596325263575161958">Шифрлау опциÑлары</translation>
+<translation id="6596892391065203054">Бұл мазмұнды баÑып шығаруға әкімші тыйым Ñалған.</translation>
<translation id="6604181099783169992">ÒšÐ¾Ð·Ò“Ð°Ð»Ñ‹Ñ Ð½Ðµ жарық датчиктері</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Қорғалған мазмұн</translation>
@@ -1452,6 +1479,7 @@
<translation id="6895330447102777224">Картаңыз раÑталды</translation>
<translation id="6897140037006041989">Пайдаланушы агенті</translation>
<translation id="6898699227549475383">Ұйым (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> Ñайтына мына әрекеттерді орындауға Ñ€Ò±Ò›Ñат етіңіз:</translation>
<translation id="6910240653697687763"><ph name="URL" /> беті MIDI құрылғыларыңызды толық бақылағыÑÑ‹ келеді</translation>
<translation id="6915804003454593391">Пайдаланушы:</translation>
<translation id="6934672428414710184">Бұл атау Google еÑептік жазбаңызда бар.</translation>
@@ -1563,6 +1591,7 @@
<translation id="7346048084945669753">үлеÑÑ‚ÐµÑ Ð¿Ð°Ð¹Ð´Ð°Ð»Ð°Ð½ÑƒÑˆÑ‹:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Пәрмен жолы</translation>
+<translation id="7359588939039777303">Жарнамалар бөгелді.</translation>
<translation id="7372973238305370288">іздеу нәтижеÑÑ–</translation>
<translation id="7374733840632556089">Құрылғыңызға Ñіз немеÑе әлдекім орнатқан Ñертификатқа байланыÑÑ‚Ñ‹ оÑÑ‹ қате шығып тұрған болуы мүмкін. Бұл Ñертификат Ñенімді болып Ñаналмайды, әдетте ол желідегі деректерді қадағалауға және Ò±Ñтап қалуға пайдаланылады. Мұндай әрекеттерге құрылғы оқу орнында немеÑе жұмыÑта болған кезде Ñ€Ò±Ò›Ñат етіледі. Қалай болғанда да Chrome мұндай Ñертификаттың болатынын еÑкертеді. Әрекетті қадағалау интернетке кіретін кез келген браузерде немеÑе қолданбада жүреді.</translation>
<translation id="7375818412732305729">Файл тіркелді</translation>
@@ -1737,6 +1766,7 @@
<translation id="7976214039405368314">Сұраулар Ñаны өте көп.</translation>
<translation id="7977538094055660992">Шығару құрылғыÑÑ‹</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Толықтырылған шындық мазмұнын көру үшін ARCore платформаÑын орнатыңыз</translation>
<translation id="799149739215780103">Байлау</translation>
<translation id="7995512525968007366">КөрÑетілмеген</translation>
<translation id="800218591365569300">Жадты боÑату үшін баÑқа қойындылары не бағдарламаларды жауып көріңіз</translation>
@@ -1864,24 +1894,38 @@
<translation id="8507227106804027148">Пәрмен жолы</translation>
<translation id="8508648098325802031">Іздеу белгішеÑÑ–</translation>
<translation id="8522552481199248698">Chrome браузері Google еÑептік жазбаңызды қорғауға және Ò›Ò±Ð¿Ð¸Ñ Ñөзіңізді өзгертуге көмектеÑеді.</translation>
+<translation id="8525306231823319788">Толық Ñкран</translation>
<translation id="8530813470445476232">Chrome параметрлерінен браузерді қолдану тарихын, cookie файлдарын, кÑшті және Ñ‚.б. деректерді өшіріңіз.</translation>
<translation id="8533619373899488139">Тыйым Ñалынған URL мекенжайларын және жүйе әкімшіÑÑ– енгізген баÑқа ÑаÑÑаттар тізімін қарау үшін &lt;strong&gt;chrome://policy&lt;/strong&gt; бетіне кіріңіз.</translation>
<translation id="8541158209346794904">Bluetooth құрылғыÑÑ‹</translation>
<translation id="8542014550340843547">Төменгі жағын үш рет қапÑыру</translation>
<translation id="8543181531796978784">Сіз <ph name="BEGIN_ERROR_LINK" />анықтау мәÑелеÑÑ– туралы хабарлай<ph name="END_ERROR_LINK" /> алаÑыз, қауіпÑіздігіңізге төнетін қатерді Ñ‚Ò¯Ñінетін болÑаңыз, <ph name="BEGIN_LINK" />қауіпті Ñайтқа кіріңіз<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC коды картаңыздың артқы жағында орналаÑқан.</translation>
+<translation id="8558485628462305855">Толықтырылған шындық мазмұнын көру үшін ARCore платформаÑын жаңартыңыз</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> доменімен жеке Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð¾Ñ€Ð½Ð°Ñ‚Ñƒ мүмкін емеÑ, Ñебебі құрылғыңыздың күні мен уақыты (<ph name="DATE_AND_TIME" />) Ð´Ò±Ñ€Ñ‹Ñ ÐµÐ¼ÐµÑ.</translation>
<translation id="8564182942834072828">Бөлек құжаттар/реттелмеген көшірмелер</translation>
<translation id="8564985650692024650">Chromium баÑқа Ñайттарда пайдаланылған <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> Ò›Ò±Ð¿Ð¸Ñ Ñөзін қайта орнатуды Ò±Ñынады.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Құрылғыда келеÑÑ– ақпарат Ñақталмайды:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />оÑÑ‹ терезеде көрілетін беттер;
+ <ph name="LIST_ITEM" />cookie файлдары және Ñайт деректері.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Карталарыңызды жылдам раÑтау үшін Touch ID пайдаланыңыз.</translation>
<translation id="858637041960032120">Телефон нөмірін қоÑу</translation>
<translation id="8589998999637048520">Ең жақÑÑ‹ Ñапа</translation>
+<translation id="8600271352425265729">Тек оÑÑ‹ жолы</translation>
<translation id="860043288473659153">Карта иеÑінің аты-жөні</translation>
<translation id="8606726445206553943">MIDI құрылғыларыңызды пайдалану</translation>
+<translation id="8612761427948161954">СәлеметÑіз бе, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Сіз қонақ режимін пайдаланып жатырÑыз.</translation>
<translation id="861775596732816396">Өлшемі: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ð¡Ó™Ð¹ÐºÐµÑ Ò›Ò±Ð¿Ð¸Ñ Ñөздер жоқ. Барлық Ñақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздерді көрÑету.</translation>
<translation id="8625384913736129811">Картаны оÑÑ‹ құрылғыға Ñақтау</translation>
+<translation id="8627040765059109009">Экранды Ñ‚Ò¯Ñіру қайта қоÑылды</translation>
<translation id="8657078576661269990">Әкімші <ph name="ORIGIN_NAME" /> Ñайтындағы мазмұнды <ph name="VM_NAME_1" /> және <ph name="VM_NAME_2" /> жүйелерімен бөліÑуге тыйым Ñалды.</translation>
<translation id="8663226718884576429">ТапÑÑ‹Ñ€Ñ‹Ñ Ò›Ð¾Ñ€Ñ‹Ñ‚Ñ‹Ð½Ð´Ñ‹ÑÑ‹, <ph name="TOTAL_LABEL" />, толығырақ деректер</translation>
<translation id="867224526087042813">Қолтаңба</translation>
@@ -1944,6 +1988,7 @@
<translation id="8912362522468806198">Google еÑептік жазбаÑÑ‹</translation>
<translation id="8913778647360618320">"Төлеу әдіÑтерін баÑқару" түймеÑÑ–. Chrome параметрлерінде төлемдеріңіз және неÑиелік картаңыз туралы ақпаратты баÑқару үшін Enter пернеÑін баÑыңыз.</translation>
<translation id="8918231688545606538">Бұл бет күдікті.</translation>
+<translation id="8922013791253848639">ОÑÑ‹ Ñайтта жарнамаларға әрқашан Ñ€Ò±Ò›Ñат ету</translation>
<translation id="892588693504540538">Жоғарғы оң жағын теÑу</translation>
<translation id="8931333241327730545">Бұл картаны Google еÑептік жазбаÑына Ñақтағыңыз келе ме?</translation>
<translation id="8932102934695377596">Сағатыңыз артта қалған</translation>
@@ -2015,6 +2060,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> қолданылмайтын протоколды пайдаланады.</translation>
<translation id="9191834167571392248">Төменгі Ñол жақты теÑу</translation>
+<translation id="9199905725844810519">БаÑып шығаруға тыйым Ñалынған</translation>
<translation id="9205078245616868884">Деректер Ñинхрондаудың Ò›Ò±Ð¿Ð¸Ñ Ñ„Ñ€Ð°Ð·Ð°Ñымен шифрланған. Синхрондауды баÑтау үшін оны енгізіңіз.</translation>
<translation id="9207861905230894330">Мақала қоÑу мүмкін болмады.</translation>
<translation id="9213433120051936369">КөрініÑÑ‚Ñ– реттеу</translation>
@@ -2025,8 +2071,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google еÑептік жазбаңызға кіре алмай қалуыңыз мүмкін. Chromium Ò›Ò±Ð¿Ð¸Ñ Ñөзді қазір өзгертуге ÐºÐµÒ£ÐµÑ Ð±ÐµÑ€ÐµÐ´Ñ–. Сонан Ñоң еÑептік жазбаға кіру Ñұралады.</translation>
<translation id="939736085109172342">Жаңа қалта</translation>
+<translation id="945522503751344254">Пікір жіберу</translation>
<translation id="945855313015696284">Төмендегі ақпаратты текÑеріп, жарамÑыз карталарды жойыңыз</translation>
<translation id="950736567201356821">Жоғарғы жағын үш рет теÑу</translation>
+<translation id="951941430552851965">Экраныңыздағы мазмұнға байланыÑÑ‚Ñ‹ әкімші Ñкранды Ñуретке Ñ‚Ò¯Ñіру процеÑін уақытша тоқтатты.</translation>
<translation id="961663415146723894">Төменгі жағын байлау</translation>
<translation id="962484866189421427">Бұл мазмұн жалған қолданбалар орнатуы мүмкін, олар баÑқа біреудің атын жамылуы немеÑе Ñізді бақылау үшін пайдаланылатын деректерді жинауы мүмкін. <ph name="BEGIN_LINK" />Бәрібір көрÑету<ph name="END_LINK" /></translation>
<translation id="969892804517981540">РеÑми жинақ</translation>
diff --git a/chromium/components/strings/components_strings_km.xtb b/chromium/components/strings/components_strings_km.xtb
index 330de5cafab..be5a6aa0654 100644
--- a/chromium/components/strings/components_strings_km.xtb
+++ b/chromium/components/strings/components_strings_km.xtb
@@ -81,6 +81,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">អ្នក​បានបញ្ចូល​ពាក្យសម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​នៅលើ​ទំពáŸážšážŠáŸ‚ល​មិនបាន​គ្រប់គ្រង​ដោយស្ážáž¶áž”áŸáž“​របស់អ្នក។ ដើម្បី​ការពារ​គណនី​របស់អ្នក សូមកុំ​ប្រើពាក្យ​សម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​ម្ážáž„ទៀážâ€‹áž“ៅលើ​កម្មវិធី និង​ទំពáŸážšáž•áŸ’សáŸáž„​។</translation>
<translation id="1263231323834454256">បញ្ជី​អាន</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ សកម្មភាពដែលនឹងមិនស្ážáž·ážáž“ៅក្នុងឧបករណáŸáž“áŸáŸ‡áŸ–
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ទំពáŸážšážŠáŸ‚លអ្នកមើលនៅក្នុងវិនដូនáŸáŸ‡
+ <ph name="LIST_ITEM" />ទិន្ននáŸáž™áž‚áŸáž áž‘ំពáŸážš áž“áž·áž„ážáž¼áž‚ី
+ <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“គណនី (<ph name="LINK_BEGIN" />áž…áŸáž‰<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">មធ្យោបាយ​ទៅយក</translation>
<translation id="1281476433249504884">ទម្រគំនរ​ទី 1</translation>
<translation id="1285320974508926690">មិនបកប្រែគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡áž‘ៀážáž¡áž¾áž™</translation>
@@ -285,6 +293,7 @@
<translation id="204357726431741734">ចូលគណនី ដើម្បីប្រើ​ពាក្យសម្ងាážáŸ‹â€‹ážŠáŸ‚លរក្សាទុក​នៅក្នុងគណនី Google របស់អ្នក</translation>
<translation id="2053111141626950936">ទំពáŸážšáž‡áž¶ <ph name="LANGUAGE" /> នឹងមិនážáŸ’រូវ​បានបកប្រែទáŸáŸ”</translation>
<translation id="2053553514270667976">áž›áŸážáž€áž¼ážŠážáŸ†áž”ន់</translation>
+<translation id="2054665754582400095">​វážáŸ’ážáž˜áž¶áž“របស់អ្នក</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{ការផ្ážáž›áŸ‹áž™áŸ„បល់ 1}other{ការផ្ážáž›áŸ‹áž™áŸ„បល់ #}}</translation>
<translation id="2079545284768500474">ážáŸ’រឡប់វិញ</translation>
<translation id="20817612488360358">ការកំណážáŸ‹áž”្រូកស៊ីប្រពáŸáž“្ធážáŸ’រូវបានកំណážáŸ‹ážŠáž¾áž˜áŸ’បីប្រើ ប៉ុន្ážáŸ‚ការកំណážáŸ‹áž”្រូកស៊ីជាក់លាក់កáŸážáŸ’រូវបានបញ្ជាក់ផងដែរ។</translation>
@@ -298,6 +307,7 @@
<translation id="2102495993840063010">កម្មវិធី Android</translation>
<translation id="2107021941795971877">ជំនួយក្នុង​ការបោះពុម្ព</translation>
<translation id="2108755909498034140">ចាប់ផ្ážáž¾áž»áž˜áž€áž»áŸ†áž–្យូទáŸážšážšáž”ស់អ្នកឡើងវិញ</translation>
+<translation id="2111166930115883695">ចុច "space" ដើម្បីលáŸáž„</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">កាáž</translation>
<translation id="2114841414352855701">មិនបានអើពើ ពីព្រោះវាážáŸ’រូវបានបដិសáŸáž’ដោយ <ph name="POLICY_NAME" />។</translation>
@@ -309,6 +319,7 @@
<translation id="214556005048008348">បោះបង់​ការបង់ប្រាក់</translation>
<translation id="2147827593068025794">សមកាលកម្មផ្ទៃážáž¶áž„ក្រោយ</translation>
<translation id="2148613324460538318">បញ្ចូល​បណ្ណ</translation>
+<translation id="2149968176347646218">ការážáž—្ជាប់នáŸáŸ‡â€‹áž‚្មានសុវážáŸ’ážáž·áž—ាពទáŸ</translation>
<translation id="2154054054215849342">ដែនរបស់អ្នកមិនអាចប្រើសមកាលកម្មបានទáŸ</translation>
<translation id="2154484045852737596">កែសម្រួលកាáž</translation>
<translation id="2161656808144014275">អážáŸ’ážáž”áž‘</translation>
@@ -319,7 +330,6 @@
<translation id="2181821976797666341">គោលការណáŸ</translation>
<translation id="2183608646556468874">áž›áŸážâ€‹áž‘ូរសព្ទ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{អាសយដ្ឋាន 1}other{អាសយដ្ឋាន #}}</translation>
-<translation id="2187243482123994665">ážœážáŸ’ážáž˜áž¶áž“របស់​អ្នកប្រើប្រាស់</translation>
<translation id="2187317261103489799">ស្វែងរក (លំនាំដើម)</translation>
<translation id="2188375229972301266">ចោះ​ច្រើនរន្ធ​ážáž¶áž„ក្រោម</translation>
<translation id="2202020181578195191">បញ្ចូលឆ្នាំផុážáž€áŸ†ážŽážáŸ‹áž²áŸ’យបានážáŸ’រឹមážáŸ’រូវ</translation>
@@ -473,6 +483,7 @@
<translation id="2839501879576190149">áž‚áŸáž áž‘ំពáŸážšâ€‹áž€áŸ’លែងក្លាយ​នៅážáž¶áž„មុáž</translation>
<translation id="2850739647070081192">Invite (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="2856444702002559011">អ្នក​វាយ​ប្រហារ​ប្រហែល​ជាកំពុង​លួចយក​ពáŸážáŸŒáž˜áž¶áž“​របស់អ្នក​ពី <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ឧទាហរណáŸáŸ– ពាក្យសម្ងាážáŸ‹ សារ ឬបណ្ណឥណទាន)។ <ph name="BEGIN_LEARN_MORE_LINK" />ស្វែងយល់បន្ážáŸ‚ម<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">áž‚áŸáž áž‘ំពáŸážšâ€‹áž“áŸáŸ‡áž”ង្ហាញ​ការផ្សាយពាណិជ្ជកម្ម​ដែលនាំឱ្យយល់ច្រឡំ ឬរំážáž¶áž“។</translation>
<translation id="2878197950673342043">áž”ážáŸ‹â€‹áž•áŸ’ទាំងរូបភាព</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ការដាក់​វិនដូ</translation>
@@ -511,11 +522,11 @@
<translation id="2996674880327704673">ការណែនាំ​ពី Google</translation>
<translation id="3002501248619246229">áž–áž·áž“áž·ážáŸ’យមើល​មáŸážŒáŸ€áž“ៃទម្រ​ធាážáž»áž”ញ្ចូល</translation>
<translation id="3005723025932146533">បង្ហាញច្បាប់ចម្លងដែលបានរក្សាទុក</translation>
-<translation id="3007719053326478567">អ្នកគ្រប់គ្រងរបស់អ្នកបានទប់ស្កាážáŸ‹áž€áž¶ážšáž”ោះពុម្ពážáŸ’លឹមសារនáŸáŸ‡</translation>
<translation id="3008447029300691911">បញ្ចូល CVC សម្រាប់ <ph name="CREDIT_CARD" /> ។ បន្ទាប់ពីអ្នកបញ្ជាក់ហើយ áž–áŸážáŸŒáž˜áž¶áž“លម្អិážáž–ីកាážáŸ‹ážšáž”ស់អ្នកនឹងážáŸ’រូវបានចែករំលែកជាមួយគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡áŸ”</translation>
<translation id="3010559122411665027">ធាážáž»áž”ញ្ជី "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">បាន​ទប់ស្កាážáŸ‹ážŠáŸ„យ​ស្វáŸáž™â€‹áž”្រវážáŸ’ážáž·</translation>
<translation id="3016780570757425217">ដឹងពីទីážáž¶áŸ†áž„របស់អ្នក</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ចុច "Tab" រួចចុច "Enter" ដើម្បី​លុបការណែនាំ។</translation>
<translation id="3023071826883856138">You4 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="3024663005179499861">ប្រភáŸáž‘គោលការណáŸážáž»ážŸ</translation>
<translation id="3037605927509011580">អូយ ទក់!</translation>
@@ -558,6 +569,7 @@
<translation id="3207960819495026254">បានចំណាំ</translation>
<translation id="3209034400446768650">ទំពáŸážšáž¢áž¶áž…​នឹង​គិážáž”្រាក់</translation>
<translation id="3212581601480735796">សកម្មភាព​របស់អ្នក​នៅលើ <ph name="HOSTNAME" /> កំពុងážáŸ’រូវ​បានឃ្លាំមើល</translation>
+<translation id="3212623355668894776">បិទវិនដូភ្ញៀវទាំងអស់ ដើម្បីលុបសកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážážšáž”ស់អ្នកចáŸáž‰áž–ីឧបករណáŸáž“áŸáŸ‡áŸ”</translation>
<translation id="3215092763954878852">មិនអាចប្រើ WebAuthn បានទáŸ</translation>
<translation id="3218181027817787318">ពាក់ពáŸáž“្ធ</translation>
<translation id="3225919329040284222">ម៉ាស៊ីនមáŸáž“áŸáŸ‡áž”ានបង្ហាញទិន្ននáŸáž™ážŠáŸ‚លមិនážáŸ’រូវគ្នាជាមួយការរំពឺងដែលភ្ជាប់ជាមួយ។ ការរំពឹងទុកទាំងនáŸáŸ‡ážšáž¶áž”់បញ្ចូលទាំងគáŸáž áž‘ំពáŸážšážŸáž»ážœážáŸ’ážáž·áž—ាពážáŸ’ពស់ជាក់លាក់ដើម្បីការពារអ្នក។</translation>
@@ -705,6 +717,7 @@
<translation id="3784372983762739446">ឧបករណáŸâ€‹áž”៊្លូធូស</translation>
<translation id="3787705759683870569">áž•áž»ážáž€áŸ†ážŽážáŸ‹ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ទំហំ 16</translation>
+<translation id="3789841737615482174">ážáŸ†áž¡áž¾áž„</translation>
<translation id="3793574014653384240">មូលហáŸážáž» និងចំនួននៃការគាំង ដែលបានកើážáž¡áž¾áž„កាលពីពáŸáž›ážáŸ’មីៗនáŸáŸ‡</translation>
<translation id="3797522431967816232">Prc3 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="3799805948399000906">បានស្នើសុំ​ពុម្ពអក្សរ</translation>
@@ -756,6 +769,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">សោ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ស្រោម​សំបុážáŸ’ážš)</translation>
+<translation id="4067669230157909013">ការážážáž¢áŸáž€áŸ’រង់​ážáŸ’រូវបានបន្ážáŸ”</translation>
<translation id="4067947977115446013">បញ្ចូល​អាសយដ្ឋានដែល​ážáŸ’រឹមážáŸ’រូវ</translation>
<translation id="4072486802667267160">មាន​បញ្ហា​ក្នុងការដំណើរការ​ការ​បញ្ជា​ទិញ​របស់​អ្នក។ សូម​ព្យាយាម​ម្ដង​ទៀážáŸ”</translation>
<translation id="4075732493274867456">ម៉ាស៊ីនកូន និងម៉ាស៊ីនមáŸáž˜áž·áž“គាំទ្រកំណែប្រូážáž¼áž€áž¼áž› SSL ទូទៅ ឬសៃភáŸážšážŸáŸŠáž¼áž (cipher suite) áž‘áŸáŸ”</translation>
@@ -840,6 +854,7 @@
<translation id="4297502707443874121">រូបភាព​ážáž¼áž…ៗសម្រាប់ទំពáŸážš <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">ពង្រីក</translation>
<translation id="4300675098767811073">ចោះ​ច្រើនរន្ធ​ážáž¶áž„ស្ដាំ</translation>
+<translation id="4302514097724775343">ចុច "ដាយណូសáŸážš" ដើម្បីលáŸáž„</translation>
<translation id="4302965934281694568">Chou3 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="4305666528087210886">មិនអាចចូលប្រើ​ឯកសារ​របស់អ្នកបានទáŸ</translation>
<translation id="4305817255990598646">ប្ដូរ​</translation>
@@ -919,6 +934,7 @@
<translation id="4658638640878098064">កិប​ážáž¶áž„លើ​ផ្នែកážáž¶áž„ឆ្វáŸáž„</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">VR</translation>
+<translation id="4675657451653251260">អ្នកនឹងមិនឃើញពáŸážáŸŒáž˜áž¶áž“របស់កម្រងពáŸážáŸŒáž˜áž¶áž“ Chrome នៅក្នុងមុážáž„ារ​ភ្ញៀវទáŸáŸ” អ្នកអាច<ph name="LINK_BEGIN" />ចូល<ph name="LINK_END" /> ដើម្បីចូលប្រើពáŸážáŸŒáž˜áž¶áž“គណនី Google របស់អ្នកដូចជា ពាក្យសម្ងាážáŸ‹ និងវិធីបង់ប្រាក់ជាដើម។</translation>
<translation id="467662567472608290">ម៉ាស៊ីនមáŸáž“áŸáŸ‡áž˜áž·áž“អាចបង្ហាញážáž¶ážœáž¶áž‡áž¶ <ph name="DOMAIN" /> ទ០វិញ្ញាបនបáŸážáŸ’រសុវážáŸ’ážáž·áž—ាពរបស់វាផ្ទុកកំហុសឆ្គង។ áž“áŸáŸ‡áž¢áž¶áž…បណ្ážáž¶áž›áž˜áž€áž–ីការកំណážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ ឬមានការស្ទាក់ការភ្ជាប់របស់អ្នកពីអ្នកវាយប្រហារ។</translation>
<translation id="4677585247300749148"><ph name="URL" /> ចង់ឆ្លើយážáž”​នឹងព្រឹážáŸ’ážáž·áž€áž¶ážšážŽáŸâ€‹áž—ាពងាយស្រួល</translation>
<translation id="467809019005607715">Google បទបង្ហាញ</translation>
@@ -946,6 +962,12 @@
<translation id="4761104368405085019">ប្រើម៉ៃក្រូហ្វូនរបស់អ្នក</translation>
<translation id="4764776831041365478">áž‚áŸáž áž‘ំពáŸážšáž“ៅ <ph name="URL" /> អាចមិនដំណើរការបណ្ážáŸ„ះអាសន្ន ឬវាអាចážáŸ’រូវបានផ្លាស់ទីទៅអាសយដ្ឋានគáŸáž áž‘ំពáŸážšážáŸ’មី។</translation>
<translation id="4766713847338118463">កិប​ពីរគ្រាប់​ážáž¶áž„ក្រោម</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ សកម្មភាពរបស់អ្នកដែលស្ážáž·ážáž“ៅក្នុងឧបករណáŸáž“áŸáŸ‡áŸ–
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ឯកសារទាំងឡាយដែលអ្នកទាញយកនៅក្នុងវិនដូនáŸáŸ‡
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">កំហុសឆ្គងមិនស្គាល់បានកើážáž¡áž¾áž„។</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{​ផ្ទាំងផុសážáŸ’រូវ​បាន​ទប់ស្កាážáŸ‹}other{​ផ្ទាំងផុស # ážáŸ’រូវ​បាន​ទប់ស្កាážáŸ‹}}</translation>
<translation id="4780366598804516005">ប្រអប់​សំបុážáŸ’រទី 1</translation>
@@ -1108,11 +1130,13 @@
<translation id="5386426401304769735">ážáŸ’សែ​វិញ្ញាបនបážáŸ’រ​សម្រាប់​ទំពáŸážšâ€‹áž“áŸáŸ‡â€‹áž•áŸ’ទុក​វិញ្ញាបនបážáŸ’រ​មួយ​ដែល​ចុះហážáŸ’ážáž›áŸážáž¶â€‹ážŠáŸ„យប្រើ SHA-1 ។</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">ដáŸážšáž‚ែម​ážáž¶áž„ស្ដាំ</translation>
+<translation id="5398772614898833570">បាន​ទប់ស្កាážáŸ‹â€‹áž€áž¶ážšáž•áŸ’សាយពាណិជ្ជកម្ម</translation>
<translation id="5400836586163650660">ប្រផáŸáŸ‡</translation>
<translation id="540969355065856584">ម៉ាស៊ីនមáŸáž“áŸáŸ‡áž˜áž·áž“អាចបង្ហាញážáž¶ážœáž¶áž‡áž¶ <ph name="DOMAIN" /> នោះទ០វិញ្ញាបនបážáŸ’រសុវážáŸ’ážáž·áž—ាពរបស់វាមិនមានសុពលភាពទáŸáž“ៅពáŸáž›áž“áŸáŸ‡áŸ” វាអាចបណ្ážáž¶áž›áž˜áž€áž–ីការកំណážáŸ‹ážšáž…នាសម្ពáŸáž“្ធមិនážáŸ’រឹមážáŸ’រូវ ឬមានអ្នកវាយប្រហារកំពុងរារាំងការážáž—្ជាប់របស់អ្នក។</translation>
<translation id="541416427766103491">ទម្រគំនរ​ទី 4</translation>
<translation id="5421136146218899937">ជម្រះទិន្ននáŸáž™ážšáž»áž€ážšáž€...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ចង់​ផ្ញើ​ការជូន​ដំណឹងទៅអ្នក</translation>
+<translation id="542872847390508405">អ្នកកំពុងរុករកជារបៀបភ្ញៀវ</translation>
<translation id="5430298929874300616">ដកចំណាំចáŸáž‰</translation>
<translation id="5439770059721715174">កំហុសឆ្គងសុពលភាពសញ្ញាážáŸ†ážŽáž¶áž„នៅ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ផ្ងារឡើងážáž¶áž˜áž›áŸ†ážŠáž¶áž”់លំដោយ​បញ្ច្រាស</translation>
@@ -1154,12 +1178,12 @@
<translation id="5571083550517324815">មិនអាចទៅយកពីអាសយដ្ឋាននáŸáŸ‡áž”ានទáŸáŸ” សូមជ្រើសរើសអាសយដ្ឋានផ្សáŸáž„។</translation>
<translation id="5580958916614886209">áž–áž·áž“áž·ážáŸ’យមើល​ážáŸ‚​ផុážâ€‹áž€áŸ†ážŽážáŸ‹â€‹ážšáž”ស់អ្នក​ រួច​ព្យាយាម​ម្ážáž„​ទៀážâ€‹</translation>
<translation id="5586446728396275693">គ្មានអាសយដ្ឋានដែលបានរក្សាទុកទáŸ</translation>
+<translation id="5593349413089863479">ការ​ážáž—្ជាប់នáŸáŸ‡áž˜áž·áž“មានសុវážáŸ’ážáž·áž—ាពទាំងស្រុងទáŸ</translation>
<translation id="5595485650161345191">កែសម្រួលអាសយដ្ឋាន</translation>
<translation id="5598944008576757369">ជ្រើសរើស​វិធី​បង់ប្រាក់</translation>
<translation id="560412284261940334">ការគ្រប់គ្រងមិនážáŸ’រូវបានគាំទ្រទáŸ</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">áž‚áŸáž áž‘ំពáŸážšâ€‹áž“áŸáŸ‡â€‹áž¢áž¶áž…ក្លែងក្លាយ ឬ​បោកប្រាស់។ Chrome សូមណែនាំឱ្យ​ចាកចáŸáž‰â€‹áž¥áž¡áž¼ážœáž“áŸáŸ‡áŸ”</translation>
<translation id="5610142619324316209">áž–áž·áž“áž·ážáŸ’យការážáž—្ជាប់</translation>
<translation id="5610807607761827392">អ្នក​អាច​គ្រប់គ្រង​កាážâ€‹ និង​អាសយដ្ឋាន​នៅក្នុង​ <ph name="BEGIN_LINK" />ការកំណážáŸ‹â€‹<ph name="END_LINK" />។</translation>
<translation id="561165882404867731">បកប្រែទំពáŸážšáž“áŸáŸ‡ážŠáŸ„យប្រើ Google បកប្រែ</translation>
@@ -1231,6 +1255,7 @@
<translation id="5901630391730855834">លឿង</translation>
<translation id="5905445707201418379">បានទប់ស្កាážáŸ‹â€‹ážŠáŸ„យ​ផ្អែកលើ​គោលការណáŸâ€‹ážŠáž¾áž˜â€‹ážšáž”ស់ <ph name="ORIGIN" /> ។</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (បានធ្វើសមកាលកម្ម)</translation>
+<translation id="5913377024445952699">បានផ្អាក​ការážážâ€‹áž¢áŸáž€áŸ’រង់</translation>
<translation id="59174027418879706">បានបើកដំណើរការ</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">បើក</translation>
@@ -1243,6 +1268,7 @@
<translation id="5963413905009737549">ផ្នែក</translation>
<translation id="5967592137238574583">កែសម្រួល​ពáŸážáŸŒáž˜áž¶áž“​ទំនាក់ទំនង</translation>
<translation id="5967867314010545767">ដកចáŸáž‰áž–ីប្រវážáŸ’ážáž·</translation>
+<translation id="5968793460449681917">រាល់ពáŸáž›â€‹áž…ូលមើល</translation>
<translation id="5975083100439434680">បង្រួម</translation>
<translation id="5979084224081478209">áž–áž·áž“áž·ážáŸ’យពាក្យសម្ងាážáŸ‹</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1398,6 +1424,7 @@
<translation id="6587923378399804057">ážáŸ†ážŽážŠáŸ‚លអ្នក​បានចម្លង</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> មិនážáŸ’រូវបាន​គ្រប់គ្រងទáŸ</translation>
<translation id="6596325263575161958">ជម្រើសការអ៊ីនគ្រីប</translation>
+<translation id="6596892391065203054">អ្នកគ្រប់គ្រងរបស់អ្នកបានទប់ស្កាážáŸ‹áž€áž¶ážšáž”ោះពុម្ពážáŸ’លឹមសារនáŸáŸ‡áŸ”</translation>
<translation id="6604181099783169992">ឧបករណáŸâ€‹áž…ាប់​សញ្ញាពន្លឺ ឬចលនា</translation>
<translation id="6609880536175561541">Prc7 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="6612358246767739896">មាážáž·áž€áž¶ážŠáŸ‚លបានការពារ</translation>
@@ -1457,6 +1484,7 @@
<translation id="6895330447102777224">កាážážšáž”ស់អ្នកបានបញ្ជាក់រួចហើយ</translation>
<translation id="6897140037006041989">ភ្នាក់ងារអ្នកប្រើ</translation>
<translation id="6898699227549475383">អង្គភាព (O)</translation>
+<translation id="6907293445143367439">អនុញ្ញាážáž±áŸ’áž™ <ph name="SITE_NAME" />៖</translation>
<translation id="6910240653697687763"><ph name="URL" /> ចង់​គ្រប់គ្រង​ឧបករណ០MIDI របស់អ្នក​ទាំងស្រុង</translation>
<translation id="6915804003454593391">អ្នកប្រើ៖</translation>
<translation id="6934672428414710184">ឈ្មោះ​នáŸáŸ‡â€‹áž”ាន​មកពី​គណនី Google របស់អ្នក</translation>
@@ -1568,6 +1596,7 @@
<translation id="7346048084945669753">បានភ្ជាប់៖</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">អážáŸ’ážáž”ទបញ្ជា</translation>
+<translation id="7359588939039777303">បាន​ទប់ស្កាážáŸ‹â€‹áž€áž¶ážšáž•áŸ’សាយ​ពាណិជ្ជកម្ម។</translation>
<translation id="7372973238305370288">លទ្ធផលស្វែងរក</translation>
<translation id="7374733840632556089">បញ្ហា​នáŸáŸ‡â€‹áž€áž¾ážáž¡áž¾áž„​ដោយសារ​វិញ្ញាបនបážáŸ’រ​ដែល​អ្នក ឬ​អ្នកផ្សáŸáž„​ទៀážâ€‹áž”ានដំឡើង​នៅលើ​ឧបករណáŸâ€‹ážšáž”ស់អ្នក​។ វិញ្ញាបនបážáŸ’រ​នáŸáŸ‡â€‹ážáŸ’រូវបាន​ប្រើ​ ដើម្បី​ឃ្លាំមើល និង​បង្អាក់​បណ្ដាញ ហើយ Chrome មិន​ទុកចិážáŸ’ážâ€‹áž›áž¾â€‹ážœáž·áž‰áŸ’ញាបនបážáŸ’រ​នáŸáŸ‡áž‘áŸâ€‹áŸ” ទោះបីជា​មាន​ករណី​ស្របច្បាប់​មួយចំនួន ដែលអនុញ្ញាážáž±áŸ’យមានការ​ឃ្លាំមើល​ ដូចជា​នៅលើ​បណ្ដាញ​របស់​ក្រុមហ៊ុន ឬ​សាលារៀន​កáŸážŠáŸ„áž™ ក០Chrome ចង់​បញ្ជាក់ឱ្យអ្នក​ដឹង​ច្បាស់ážáž¶ អ្នកអាចកំពុងážáŸ’រូវបានឃ្លាំមើល​ ទោះបីជា​អ្នក​មិនអាច​បញ្ឈប់​សកម្មភាពនáŸáŸ‡â€‹áž”ានកáŸážŠáŸ„យ​។ ការឃ្លាំមើល​អាច​កើážáž¡áž¾áž„​នៅក្នុង​កម្មវិធី​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិហឬ​កម្មវិធី​ទាំងឡាយ​ដែល​ចូលប្រើ​បណ្ដាញ​។</translation>
<translation id="7375818412732305729">ឯកសារ​ážáŸ’រូវបាន​ភ្ជាប់</translation>
@@ -1743,6 +1772,7 @@
<translation id="7976214039405368314">សំណើច្រើនពáŸáž€</translation>
<translation id="7977538094055660992">ឧបករណáŸáž“ៃធាážáž»áž”ញ្ចáŸáž‰</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ដើម្បី​មើលážáŸ’លឹមសារ AR សូមដំឡើង ARCore</translation>
<translation id="799149739215780103">ភ្ជាប់</translation>
<translation id="7995512525968007366">មិនបានបញ្ជាក់</translation>
<translation id="800218591365569300">សាកល្បងបិទផ្ទាំង ឬកម្មវិធីផ្សáŸáž„ទៀហដើម្បីបង្កើនទំហំអង្គចងចាំ។</translation>
@@ -1870,24 +1900,38 @@
<translation id="8507227106804027148">ជួរពាក្យបញ្ជា</translation>
<translation id="8508648098325802031">រូប​ស្វែងរក</translation>
<translation id="8522552481199248698">Chrome អាច​ជួយ​អ្នក​ក្នុងការការពារ​គណនី Google និង​ផ្លាស់ប្ដូរ​ពាក្យសម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​។</translation>
+<translation id="8525306231823319788">áž–áŸáž‰áž¢áŸáž€áŸ’រង់</translation>
<translation id="8530813470445476232">សម្អាážáž”្រវážáŸ’ážáž·â€‹ážšáž»áž€ážšáž€â€‹ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិហážáž¼áž‚ី ឃ្លាំងផ្ទុកទិន្ននáŸáž™ážšáž”ស់អ្នក និងអ្វីៗជាច្រើនទៀážâ€‹áž“ៅក្នុង​ការកំណážáŸ‹ Chrome</translation>
<translation id="8533619373899488139">សូមចូលទៅកាន់ &lt;strong&gt;chrome://policy&lt;/strong&gt; ដើម្បីមើល​បញ្ជី URL ដែលបាន​ទប់ស្កាážáŸ‹ និងគោលការណáŸâ€‹áž•áŸ’សáŸáž„ទៀហដែលបានអនុវážáŸ’ážâ€‹ážŠáŸ„យអ្នកគ្រប់គ្រងប្រពáŸáž“្ធ​របស់អ្នក។</translation>
<translation id="8541158209346794904">ឧបករណáŸâ€‹áž”៊្លូធូស</translation>
<translation id="8542014550340843547">កិប​បីគ្រាប់​ážáž¶áž„ក្រោម</translation>
<translation id="8543181531796978784">អ្នកអាច<ph name="BEGIN_ERROR_LINK" />រាយការណáŸáž¢áŸ†áž–ីបញ្ហាដែលបានរកឃើញ<ph name="END_ERROR_LINK" /> ឬប្រសិនបើអ្នកយល់ពីហានិភáŸáž™áž…ំពោះសុវážáŸ’ážáž·áž—ាពរបស់អ្នកហើយ <ph name="BEGIN_LINK" />សូមចូលទៅកាន់គáŸáž áž‘ំពáŸážšáž‚្មានសុវážáŸ’ážáž·áž—ាពនáŸáŸ‡<ph name="END_LINK" />។</translation>
<translation id="8557066899867184262">CVC ស្ážáž·ážâ€‹áž“ៅក្រោយ​បណ្ណ​របស់អ្នក។</translation>
+<translation id="8558485628462305855">ដើម្បី​មើលážáŸ’លឹមសារ AR សូមដំឡើងជំនាន់ ARCore</translation>
<translation id="8559762987265718583">ការភ្ជាប់ឯកជនទៅ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> មិនអាចធ្វើឡើងទ០ពីព្រោះកាលបរិច្ឆáŸáž‘ និងម៉ោងឧបករណáŸážšáž”ស់អ្នក (<ph name="DATE_AND_TIME" />)មិនážáŸ’រឹមážáŸ’រូវ។</translation>
<translation id="8564182942834072828">ឯកសារ​ដាច់ដោយឡែក/ច្បាប់ចម្លង​ដាច់ដោយឡែក</translation>
<translation id="8564985650692024650">Chromium ណែនាំឱ្យ​កំណážáŸ‹â€‹áž–ាក្យសម្ងាážáŸ‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> របស់អ្នក​ឡើងវិញ ប្រសិនបើ​អ្នកបាន​ប្រើ​វាម្ážáž„ទៀážâ€‹áž“ៅលើ​ទំពáŸážšáž•áŸ’សáŸáž„។</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ សកម្មភាពដែលនឹងមិនស្ážáž·ážáž“ៅលើឧបករណáŸáž“áŸáŸ‡áŸ–
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ទំពáŸážšážŠáŸ‚លអ្នកមើលនៅក្នុងវិនដូនáŸáŸ‡
+ <ph name="LIST_ITEM" />ទិន្ននáŸáž™áž‚áŸáž áž‘ំពáŸážš áž“áž·áž„ážáž¼áž‚ី
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ប្រើ Touch ID ដើម្បី​បញ្ជាក់​បណ្ណឱ្យ​បាន​រហáŸážŸâ€‹áž‡áž¶áž„មុន</translation>
<translation id="858637041960032120">បន្ážáŸ‚មលáŸážáž‘ូរសáŸáž–្ទ</translation>
<translation id="8589998999637048520">គុណភាព​ល្អបំផុáž</translation>
+<translation id="8600271352425265729">ážáŸ‚áž–áŸáž›áž“áŸáŸ‡â€‹áž”៉ុណ្ណោះ</translation>
<translation id="860043288473659153">ឈ្មោះ​ម្ចាស់​កាáž</translation>
<translation id="8606726445206553943">ប្រើឧបករណ០MIDI របស់អ្នក</translation>
+<translation id="8612761427948161954">សួស្ដី <ph name="USERNAME" />
+ <ph name="BR" />
+ អ្នកកំពុងរុករកក្នុងនាមជាភ្ញៀវ</translation>
<translation id="861775596732816396">ទំហំ 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">គ្មាន​ពាក្យសម្ងាážáŸ‹â€‹ážŠáŸ‚áž›ážáŸ’រូវគ្នាទáŸáŸ” បង្ហាញ​ពាក្យសម្ងាážáŸ‹â€‹ážŠáŸ‚លបានរក្សាទុក​ទាំងអស់។</translation>
<translation id="8625384913736129811">រក្សាទុកបណ្ណនáŸáŸ‡áž‘ៅក្នុងឧបករណáŸáž“áŸáŸ‡</translation>
+<translation id="8627040765059109009">បានបន្ážâ€‹áž€áž¶ážšážážâ€‹áž¢áŸáž€áŸ’រង់</translation>
<translation id="8657078576661269990">អ្នកគ្រប់គ្រង​របស់អ្នកបានទប់ស្កាážáŸ‹â€‹áž€áž¶ážšáž…ែករំលែក​ពី <ph name="ORIGIN_NAME" /> ទៅ <ph name="VM_NAME_1" /> áž“áž·áž„ <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">ការ​សង្ážáŸáž”​អំពី​ការបញ្ជាទិញ, <ph name="TOTAL_LABEL" />, áž–áŸážáŸŒáž˜áž¶áž“​លម្អិážâ€‹áž”ន្ážáŸ‚ម</translation>
<translation id="867224526087042813">áž ážáŸ’ážáž›áŸážáž¶</translation>
@@ -1950,6 +1994,7 @@
<translation id="8912362522468806198">គណនី Google</translation>
<translation id="8913778647360618320">ប៊ូážáž»áž„ "គ្រប់គ្រងវិធីបង់ប្រាក់" ចុច "Enter" ដើម្បីគ្រប់គ្រងការបង់ប្រាក់ áž“áž·áž„áž–áŸážáŸŒáž˜áž¶áž“បណ្ណឥណទានរបស់អ្នក​នៅក្នុងការកំណážáŸ‹ Chrome</translation>
<translation id="8918231688545606538">ទំពáŸážšáž“áŸáŸ‡áž‚ួរឱ្យសង្សáŸáž™</translation>
+<translation id="8922013791253848639">អនុញ្ញាážâ€‹áž€áž¶ážšáž•áŸ’សាយ​ពាណិជ្ជកម្ម​នៅលើ​ទំពáŸážšáž“áŸáŸ‡â€‹áž‡áž¶áž“ិច្ច</translation>
<translation id="892588693504540538">ចោះ​ážáž¶áž„លើ​ផ្នែក​ážáž¶áž„ស្ដាំ</translation>
<translation id="8931333241327730545">ážáž¾áž¢áŸ’នកចង់រក្សាទុកកាážáž“áŸáŸ‡áž‘ៅគណនី Google របស់អ្នកដែរឬទáŸ?</translation>
<translation id="8932102934695377596">ម៉ោងរបស់អ្នកដើរយឺáž</translation>
@@ -2021,6 +2066,7 @@
<translation id="9183302530794969518">Google ឯកសារ</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ប្រើប្រូážáž¼áž€áž¼áž›ážŠáŸ‚លមិនážáŸ’រូវបានគាំទ្រ</translation>
<translation id="9191834167571392248">ចោះ​ážáž¶áž„ក្រោម​ផ្នែកážáž¶áž„ឆ្វáŸáž„</translation>
+<translation id="9199905725844810519">ការបោះពុម្ពážáŸ’រូវបានទប់ស្កាážáŸ‹áŸ”</translation>
<translation id="9205078245616868884">ទិន្ននáŸáž™ážšáž”ស់អ្នកážáŸ’រូវបានអ៊ិនគ្រីបដោយប្រើឃ្លាសម្ងាážáŸ‹ážŸáž˜áž€áž¶áž›áž€áž˜áŸ’មរបស់អ្នក។ សូមបញ្ចូលវាដើម្បីចាប់ផ្ážáž¾áž˜áž’្វើសមកាលកម្ម។</translation>
<translation id="9207861905230894330">បានបរាជáŸáž™áž€áŸ’នុងបន្ážáŸ‚មអážáŸ’ážáž”ទ។</translation>
<translation id="9213433120051936369">ប្ដូររូបរាងážáž¶áž˜áž”ំណង</translation>
@@ -2031,8 +2077,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">អ្នកអាច​បាážáŸ‹áž”ង់​សិទ្ធិចូល​ប្រើ​គណនី Google របស់អ្នក។ Chromium ណែនាំ​ឱ្យប្ដូរ​ពាក្យសម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​ឥឡូវនáŸáŸ‡áŸ” អ្នកនឹងážáŸ’រូវបាន​ស្នើ​ឱ្យ​ចូល​គណនី។</translation>
<translation id="939736085109172342">ážážáž¯áž€ážŸáž¶ážšážáŸ’មី</translation>
+<translation id="945522503751344254">ផ្ញើមážáž·</translation>
<translation id="945855313015696284">សូមពិនិážáŸ’យ​មើលពáŸážáŸŒáž˜áž¶áž“​ážáž¶áž„ក្រោម រួចលុប​កាážážŠáŸ‚ល​មិនážáŸ’រឹមážáŸ’រូវ</translation>
<translation id="950736567201356821">ចោះ​បីរន្ធ​ážáž¶áž„លើ</translation>
+<translation id="951941430552851965">ការážážâ€‹áž¢áŸáž€áŸ’រង់​ážáŸ’រូវបានផ្អាក​ដោយ​អ្នកគ្រប់គ្រង​របស់អ្នក ដោយសារ​ážáŸ’លឹមសារ​នៅលើ​អáŸáž€áŸ’រង់​របស់អ្នក។</translation>
<translation id="961663415146723894">ភ្ជាប់​ážáž¶áž„ក្រោម</translation>
<translation id="962484866189421427">ážáŸ’លឹមសារនáŸáŸ‡áž¢áž¶áž…ព្យាយាមដំឡើងកម្មវិធីបោកប្រាស់ ដែល​ក្លែង​ធ្វើជាអ្វីម្យ៉ាង ឬ​ប្រមូល​ទិន្ននáŸáž™â€‹ážŠáŸ‚ល​អាច​ប្រើ​ដើម្បីážáž¶áž˜â€‹ážŠáž¶áž“អ្នក។ <ph name="BEGIN_LINK" />បង្ហាញចុះមិន​អី​ទáŸâ€‹<ph name="END_LINK" /></translation>
<translation id="969892804517981540">áž›áŸážáž€áŸ†ážŽáŸ‚ផ្លូវការ</translation>
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index 37285b07edf..37803035967 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ನೀವೠನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಿಮà³à²® ಸಂಸà³à²¥à³†à²¯à³ ನಿರà³à²µà²¹à²£à³† ಮಾಡದ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ನಮೂದಿಸಿದà³à²¦à³€à²°à²¿. ನಿಮà³à²® ಖಾತೆಯನà³à²¨à³ ರಕà³à²·à²¿à²¸à²²à³, ಇತರ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳಲà³à²²à²¿ ಮತà³à²¤à³ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œ ಅನà³à²¨à³ ಮರà³à²¬à²³à²•à³† ಮಾಡಬೇಡಿ.</translation>
<translation id="1263231323834454256">ಓದà³à²µ ಪಟà³à²Ÿà²¿</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ಈ ಸಾಧನದಲà³à²²à²¿ ಉಳಿಯದ ಚಟà³à²µà²Ÿà²¿à²•à³†:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಈ ವಿಂಡೋದಲà³à²²à²¿ ನೀವೠವೀಕà³à²·à²¿à²¸à³à²µ ಪà³à²Ÿà²—ಳà³
+ <ph name="LIST_ITEM" />ಕà³à²•à³€à²—ಳೠಮತà³à²¤à³ ಸೈಟೠಡೇಟಾ
+ <ph name="LIST_ITEM" />ಖಾತೆಯ ಮಾಹಿತಿ (<ph name="LINK_BEGIN" />ಸೈನೠಔಟà³<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ಪಿಕಪೠವಿಧಾನ</translation>
<translation id="1281476433249504884">ಸà³à²Ÿà³à²¯à²¾à²•à²°à³ 1</translation>
<translation id="1285320974508926690">ಈ ಸೈಟೠಅನà³à²¨à³ ಎಂದಿಗೂ ಭಾಷಾಂತರಿಸದಿರಿ</translation>
@@ -148,7 +156,7 @@
<translation id="1513706915089223971">ಇತಿಹಾಸ ನಮೂದà³à²—ಳ ಪಟà³à²Ÿà²¿</translation>
<translation id="1517433312004943670">ಫೋನೠಸಂಖà³à²¯à³† ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="1519264250979466059">ಬಿಲà³à²¡à³ ಡೇಟಾ</translation>
-<translation id="1521655867290435174">Google ಶೀಟà³â€Œà²—ಳà³</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">ಸಂಪರà³à²•à²•à³à²•à³† ಕಾಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="1529521330346880926">10x15 (Envelope)</translation>
<translation id="1529789484829130889">ಟà³à²°à³‡ 8</translation>
@@ -281,6 +289,7 @@
<translation id="204357726431741734">ನಿಮà³à²® Google ಖಾತೆಯಲà³à²²à²¿ ಉಳಿಸಲಾದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲೠಸೈನೠಇನೠಮಾಡಿ</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />ಭಾಷೆಯಲà³à²²à²¿à²°à³à²µ ಪà³à²Ÿà²—ಳೠಅನà³à²µà²¾à²¦à²•à³à²•à³Šà²³à²ªà²¡à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="2053553514270667976">ಪಿನೠಕೋಡà³</translation>
+<translation id="2054665754582400095">ನಿಮà³à²® ಉಪಸà³à²¥à²¿à²¤à²¿</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ಸಲಹೆ}one{# ಸಲಹೆಗಳà³}other{# ಸಲಹೆಗಳà³}}</translation>
<translation id="2079545284768500474">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="20817612488360358">ಸಿಸà³à²Ÿà²‚ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಬಳಸಲೠಹೊಂದಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗವಾದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ಸಹ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
@@ -294,6 +303,7 @@
<translation id="2102495993840063010">Android ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳà³</translation>
<translation id="2107021941795971877">ಪà³à²°à²¿à²‚ಟೠಬೆಂಬಲಗಳà³</translation>
<translation id="2108755909498034140">ನಿಮà³à²® ಕಂಪà³à²¯à³‚ಟರೠಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಿ</translation>
+<translation id="2111166930115883695">ಆಡಲà³, ಸà³à²ªà³‡à²¸à³ ಒತà³à²¤à²¿</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">ಕಾರà³à²¡à³</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ರಿಂದ ಅತಿಕà³à²°à²®à²¿à²¸à²²à²¾à²—ಿರà³à²µ ಕಾರಣ ಇದನà³à²¨à³ ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
@@ -305,6 +315,7 @@
<translation id="214556005048008348">ಪಾವತಿಯನà³à²¨à³ ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="2147827593068025794">ಹಿನà³à²¨à³†à²²à³† ಸಿಂಕà³</translation>
<translation id="2148613324460538318">ಕಾರà³à²¡à³ ಸೇರಿಸಿ</translation>
+<translation id="2149968176347646218">ಕನೆಕà³à²·à²¨à³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಲà³à²²</translation>
<translation id="2154054054215849342">ಸಿಂಕೠಸೇವೆಯೠನಿಮà³à²® ಡೊಮೇನà³â€Œà²—ೆ ಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="2154484045852737596">ಕಾರà³à²¡à³ ಎಡಿಟೠಮಾಡಿ</translation>
<translation id="2161656808144014275">ಪಠà³à²¯</translation>
@@ -315,7 +326,6 @@
<translation id="2181821976797666341">ನಿಯಮಗಳà³</translation>
<translation id="2183608646556468874">ಫೋನೠಸಂಖà³à²¯à³†</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ವಿಳಾಸ}one{# ವಿಳಾಸಗಳà³}other{# ವಿಳಾಸಗಳà³}}</translation>
-<translation id="2187243482123994665">ಬಳಕೆದಾರರ ಉಪಸà³à²¥à²¿à²¤à²¿</translation>
<translation id="2187317261103489799">ಪತà³à²¤à³† ಮಾಡಿ (ಡಿಫಾಲà³à²Ÿà³)</translation>
<translation id="2188375229972301266">ಕೆಳಭಾಗದಲà³à²²à²¿ ಅನೇಕ ತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
<translation id="2202020181578195191">ಮಾನà³à²¯à²µà²¾à²¦ ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ ವರà³à²·à²µà²¨à³à²¨à³ ನಮೂದಿಸಿ</translation>
@@ -466,6 +476,7 @@
<translation id="2839501879576190149">ನಕಲಿ ಸೈಟೠಮà³à²‚ದಿದೆ</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">ದಾಳಿಕೋರರೠ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಿಂದ ನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಕದಿಯಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಸಂದೇಶಗಳೠಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³). <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ಅತಿಕà³à²°à²®à²£à²•à²¾à²°à²¿à²¯à²¾à²—ಿರà³à²µ ಅಥವಾ ತಪà³à²ªà³à²¦à²¾à²°à²¿à²—ೆಳೆಯà³à²µ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ಈ ಸೈಟೠತೋರಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2878197950673342043">ಪೋಸà³à²Ÿà²°à³ ಮಾದರಿಯಲà³à²²à²¿ ಮಡಿಸಿ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ವಿಂಡೋ ಪà³à²²à³‡à²¸à³â€Œà²®à³†à²‚ಟà³</translation>
@@ -504,11 +515,11 @@
<translation id="2996674880327704673">Google ನಿಂದ ಸಲಹೆಗಳà³</translation>
<translation id="3002501248619246229">ಇನà³â€Œà²ªà³à²Ÿà³ ಟà³à²°à³‡ ಮೀಡಿಯಾವನà³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="3005723025932146533">ಉಳಿಸಲಾದ ನಕಲನà³à²¨à³ ತೋರಿಸà³</translation>
-<translation id="3007719053326478567">ಈ ವಿಷಯವನà³à²¨à³ ಮà³à²¦à³à²°à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿದà³à²¦à²¾à²°à³†</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ಗೆ CVC ಅನà³à²¨à³ ನಮೂದಿಸಿ. ನೀವೠಒಮà³à²®à³† ಖಚಿತಪಡಿಸಿದರೆ, ನಿಮà³à²® ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ಈ ಸೈಟೠಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3010559122411665027">ಪಟà³à²Ÿà²¿ ನಮೂದೠ"<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="3016780570757425217">ನಿಮà³à²® ಸà³à²¥à²³à²µà²¨à³à²¨à³ ತಿಳಿದà³à²•à³Šà²³à³à²³à²¿</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ಸಲಹೆಯನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à²²à³ ಟà³à²¯à²¾à²¬à³ ಒತà³à²¤à²¿, ನಂತರ ಎಂಟರೠಒತà³à²¤à²¿.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">ತಪà³à²ªà²¾à²¦ ನೀತಿಯ ಪà³à²°à²•à²¾à²°</translation>
<translation id="3037605927509011580">ಓಹà³, ಹೋಯà³à²¤à³!</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="3209034400446768650">ಈ ಪà³à²Ÿà²µà³, ಶà³à²²à³à²• ವಿಧಿಸಬಹà³à²¦à³</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ನಲà³à²²à²¿ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯ ಮೇಲೆ ನಿಗಾ ಇಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
+<translation id="3212623355668894776">ಎಲà³à²²à²¾ ಅತಿಥಿ ವಿಂಡೋಗಳನà³à²¨à³ ಮà³à²šà³à²šà²¿, ಇದರಿಂದಾಗಿ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ಈ ಸಾಧನದಿಂದ ಅಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3215092763954878852">WebAuthn ಅನà³à²¨à³ ಬಳಸಲೠಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²</translation>
<translation id="3218181027817787318">ಸಂಬಂಧಿತ</translation>
<translation id="3225919329040284222">ಆಂತರಿಕ ಮಾನದಂಡಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಸರà³à²µà²°à³ ಹಾಜರಿಪಡಿಸಿದೆ. ನಿಮà³à²® ಸà³à²°à²•à³à²·à²¤à³†à²¯ ಸಲà³à²µà²¾à²—ಿ ಕೆಲವೠಹೆಚà³à²šà³ ಸà³à²°à²•à³à²·à²¿à²¤ ವೆಬೠಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಈ ಮಾನದಂಡಗಳನà³à²¨à³ ಸೇರà³à²ªà²¡à³†à²—ೊಳಿಸಲಾಗಿದೆ.</translation>
@@ -695,6 +707,7 @@
<translation id="3784372983762739446">ಬà³à²²à³‚ಟೂತà³â€Œâ€Œ ಸಾಧನಗಳà³</translation>
<translation id="3787705759683870569">ಅವಧಿ-ಮà³à²•à³à²¤à²¾à²¯ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ಗಾತà³à²° 16</translation>
+<translation id="3789841737615482174">ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³</translation>
<translation id="3793574014653384240">ಇತà³à²¤à³€à²šà³†à²—ೆ ಸಂಭವಿಸಿದ ಕà³à²°à³à²¯à²¾à²¶à³â€Œà²—ಳ ಸಂಖà³à²¯à³† ಮತà³à²¤à³ ಕಾರಣಗಳà³</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">ವಿನಂತಿಸಲಾದ ಫಾಂಟà³</translation>
@@ -745,6 +758,7 @@
<translation id="4056223980640387499">ಸೆಪಿಯಾ</translation>
<translation id="4058922952496707368">ಕೀ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">ಸà³à²•à³à²°à³€à²¨à³ ಕà³à²¯à²¾à²ªà³à²šà²°à³ ಅನà³à²¨à³ ಪà³à²¨à²°à²¾à²°à²‚ಭಿಸಲಾಗಿದೆ.</translation>
<translation id="4067947977115446013">ಮಾನà³à²¯à²µà²¾à²¦ ವಿಳಾಸ ಸೇರಿಸಿ</translation>
<translation id="4072486802667267160">ನಿಮà³à²® ಆರà³à²¡â€Œà²°à³ ಅನà³à²¨à³ ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—ೊಳಿಸà³à²µà²²à³à²²à²¿ ದೋಷ ಕಂಡà³à²¬à²‚ದಿದೆ. ದಯವಿಟà³à²Ÿà³ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="4075732493274867456">ಸಾಮಾನà³à²¯ SSL ಪà³à²°à³Šà²Ÿà³‹à²•à²¾à²²à³ ಆವೃತà³à²¤à²¿ ಅಥವಾ ಸೈಫರೠಸà³à²¯à³‚ಟೠಅನà³à²¨à³ ಕà³à²²à³ˆà²‚ಟೠಮತà³à²¤à³ ಸರà³à²µà²°à³ ಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²².</translation>
@@ -825,6 +839,7 @@
<translation id="4297502707443874121">ಪà³à²Ÿ <ph name="THUMBNAIL_PAGE" /> ರ ಥಂಬà³â€Œà²¨à³‡à²²à³</translation>
<translation id="42981349822642051">ವಿಸà³à²¤à²°à²¿à²¸à²¿</translation>
<translation id="4300675098767811073">ಬಲಭಾಗದಲà³à²²à²¿ ಅನೇಕ ತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
+<translation id="4302514097724775343">ಆಡಲà³, ಡೈನೋ ಅನà³à²¨à³ ಟà³à²¯à²¾à²ªà³ ಮಾಡಿ</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">ನಿಮà³à²® ಫೈಲೠಅನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²</translation>
<translation id="4305817255990598646">ಬದಲಿಸಿ</translation>
@@ -887,7 +902,7 @@
<translation id="4552089082226364758">ಫà³à²²à³à²¯à²¾à²¶à³â€Œ</translation>
<translation id="4558551763791394412">ನಿಮà³à²® ವಿಸà³à²¤à²°à²£à³†à²—ಳನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="4559332380232738994">10x11</translation>
-<translation id="457875822857220463">ವಿತರಣೆ</translation>
+<translation id="457875822857220463">ಡೆಲಿವರಿ</translation>
<translation id="4579056131138995126">Personal (Envelope)</translation>
<translation id="4582204425268416675">ಕಾರà³à²¡à³ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="4587425331216688090">Chrome ನಿಂದ ವಿಳಾಸವನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
@@ -903,9 +918,10 @@
<translation id="4658638640878098064">ಮೇಲಿನ ಎಡಭಾಗದಲà³à²²à²¿ ಸà³à²Ÿà³‡à²ªà²²à³ ಹಾಕಿ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ವರà³à²šà³à²µà²²à³ ರಿಯಾಲಿಟಿ</translation>
+<translation id="4675657451653251260">ಅತಿಥಿ ಮೋಡà³â€Œà²¨à²²à³à²²à²¿ ನಿಮಗೆ ಯಾವà³à²¦à³‡ Chrome ಪà³à²°à³Šà²«à³ˆà²²à³â€Œà²¨ ಮಾಹಿತಿ ಗೋಚರಿಸà³à²µà³à²¦à²¿à²²à³à²². ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ಪಾವತಿ ವಿಧಾನಗಳಂತಹ ನಿಮà³à²® Google ಖಾತೆಯ ಮಾಹಿತಿಯನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನೀವೠ<ph name="LINK_BEGIN" />ಸೈನೠಇನà³<ph name="LINK_END" /> ಮಾಡಬಹà³à²¦à³.</translation>
<translation id="467662567472608290">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦à²²à³à²²à²¿ ಸಾಕಷà³à²Ÿà³ ದೋಷಗಳಿವೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="4677585247300749148">ಪà³à²°à²µà³†à³•à²¶à²¿à²¸à³à²µà²¿à²•à³† ಈವೆಂಟà³â€Œà²—ಳಿಗೆ <ph name="URL" /> ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à²¿à²¸à²²à³ ಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
-<translation id="467809019005607715">Google ಸà³à²²à³ˆà²¡à³â€Œà²—ಳà³</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">ವಂಚನೆ ಮಾಡà³à²µ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿, ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ಈಗಷà³à²Ÿà³‡ ನೀವೠನಮೂದಿಸಿದà³à²¦à³€à²°à²¿. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> ಮತà³à²¤à³ ಈ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಬಳಸà³à²µ ಇತರ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಉಳಿಸಿದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಈಗಲೇ ಪರಿಶೀಲಿಸà³à²µà²‚ತೆ Chromium ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="4690462567478992370">ಅಮಾನà³à²¯ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಬಳಸಿಕೊಂಡೠನಿಲà³à²²à²¿à²¸à²¿</translation>
<translation id="4691835149146451662">Architecture-A (Envelope)</translation>
@@ -930,6 +946,12 @@
<translation id="4761104368405085019">ನಿಮà³à²® ಮೈಕà³à²°à³Šà²«à³‹à²¨à³ ಅನà³à²¨à³ ಬಳಸಿ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ನಲà³à²²à²¿à²°à³à²µ ವೆಬà³â€Œà²ªà³à²Ÿà²µà³ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¦à³‡ ಇರಬಹà³à²¦à³ ಅಥವಾ ಅದನà³à²¨à³ ಶಾಶà³à²µà²¤à²µà²¾à²—ಿ ಹೊಸ ವೆಬೠವಿಳಾಸಕà³à²•à³† ಸರಿಸಲಾಗಿರಬಹà³à²¦à³.</translation>
<translation id="4766713847338118463">ಕೆಳಭಾಗದಲà³à²²à²¿ ಎರಡೠಸà³à²Ÿà³‡à²ªà²²à³ ಹಾಕಿ</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ಈ ಸಾಧನದಲà³à²²à²¿ ಉಳಿಯà³à²µ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಈ ವಿಂಡೋದಲà³à²²à²¿ ನೀವೠಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡà³à²µ ಯಾವà³à²¦à³‡ ಫೈಲà³â€Œà²—ಳà³
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ಅಪರಿಚಿತ ದೋಷವೊಂದೠಎದà³à²°à²¾à²—ಿದೆ.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ಪಾಪà³-ಅಪೠಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ}one{# ಪಾಪà³-ಅಪà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ}other{# ಪಾಪà³-ಅಪà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ}}</translation>
<translation id="4780366598804516005">ಮೇಲà³â€Œà²¬à²¾à²•à³à²¸à³ 1</translation>
@@ -1092,11 +1114,13 @@
<translation id="5386426401304769735">ಈ ಸೈಟà³â€Œà²—ೆ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಸರಣಿಯೠSHA-1 ಬಳಸಿಕೊಂಡೠಸಹಿ ಮಾಡಲಾದ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಒಳಗೊಂಡಿರà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">ಬಲಭಾಗದ ಅಂಚನà³à²¨à³ ಹೊಲಿಯಿರಿ</translation>
+<translation id="5398772614898833570">ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="5400836586163650660">ಬೂದà³</translation>
<translation id="540969355065856584">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಈ ಸಮಯದಲà³à²²à²¿ ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಮಾನà³à²¯à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="541416427766103491">ಸà³à²Ÿà³à²¯à²¾à²•à²°à³ 4</translation>
<translation id="5421136146218899937">ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಡೇಟಾವನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ...</translation>
<translation id="5426179911063097041">ನಿಮಗೆ ಅಧಿಸೂಚನೆಗಳನà³à²¨à³ ಕಳà³à²¹à²¿à²¸à²²à³ <ph name="SITE" /> ಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
+<translation id="542872847390508405">ನೀವೠಒಬà³à²¬ ಅತಿಥಿಯಂತೆ ಬà³à²°à³Œà²¸à³ ಮಾಡà³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿</translation>
<translation id="5430298929874300616">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" ನಲà³à²²à²¿ ಸà³à²•à³€à²®à²¾ ಮೌಲà³à²µà³€à²•à²°à²£ ದೋಷ: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ಹಿಮà³à²®à³à²– ಆರà³à²¡à²°à³ ಮà³à²– ಮೇಲಕà³à²•à³†</translation>
@@ -1138,12 +1162,12 @@
<translation id="5571083550517324815">ಈ ವಿಳಾಸದಿಂದ ಪಿಕಪೠಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
<translation id="5580958916614886209">ನಿಮà³à²® ಮà³à²•à³à²¤à²¾à²¯ ತಿಂಗಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತà³à²¤à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="5586446728396275693">ಯಾವà³à²¦à³‡ ಉಳಿಸಲಾದ ವಿಳಾಸಗಳಿಲà³à²²</translation>
+<translation id="5593349413089863479">ಕನೆಕà³à²·à²¨à³ ಸಂಪೂರà³à²£à²µà²¾à²—ಿ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಲà³à²²</translation>
<translation id="5595485650161345191">ವಿಳಾಸ ಎಡಿಟೠಮಾಡಿ</translation>
<translation id="5598944008576757369">ಪಾವತಿ ವಿಧಾನವನà³à²¨à³ ಆರಿಸಿ</translation>
<translation id="560412284261940334">ನಿರà³à²µà²¾à²¹à²• ಬೆಂಬಲಿಸà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ಇದೠನಕಲಿ ಅಥವಾ ವಂಚನೆಯ ಸೈಟೠಆಗಿರಬಹà³à²¦à³. ಇದೀಗ ಈ ಸೈಟà³â€Œà²¨à²¿à²‚ದ ಹೊರಹೋಗಲೠChrome ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5610142619324316209">ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="5610807607761827392">ನೀವೠಕಾರà³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ವಿಳಾಸಗಳನà³à²¨à³ <ph name="BEGIN_LINK" />ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="561165882404867731">Google Translate ಮೂಲಕ ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ ಅನà³à²µà²¾à²¦à²¿à²¸à²¿</translation>
@@ -1215,6 +1239,7 @@
<translation id="5901630391730855834">ಹಳದಿ</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> ನ ಮೂಲ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²—ೆ ಅನà³à²—à³à²£à²µà²¾à²—ಿ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ಸಿಂಕà³â€Œ ಮಾಡಲಾಗಿದೆ)</translation>
+<translation id="5913377024445952699">ಸà³à²•à³à²°à²¿à³•à²¨à³ ಕà³à²¯à²¾à²ªà³à²šà²°à³ ಅನà³à²¨à³ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="59174027418879706">ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ಆನà³</translation>
@@ -1227,6 +1252,7 @@
<translation id="5963413905009737549">ವಿಭಾಗ</translation>
<translation id="5967592137238574583">ಸಂಪರà³à²• ಮಾಹಿತಿಯನà³à²¨à³ ಎಡಿಟೠಮಾಡಿ</translation>
<translation id="5967867314010545767">ಇತಿಹಾಸದಿಂದ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
+<translation id="5968793460449681917">ಪà³à²°à²¤à²¿ ಭೇಟಿಯಲà³à²²à²¿</translation>
<translation id="5975083100439434680">à²à³‚ಮೠಔಟà³</translation>
<translation id="5979084224081478209">ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1381,6 +1407,7 @@
<translation id="6587923378399804057">ನೀವೠನಕಲಿಸಿದ ಲಿಂಕà³</translation>
<translation id="6591833882275308647">ನಿಮà³à²® <ph name="DEVICE_TYPE" /> ಸಾಧನವನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¿à²²à³à²²</translation>
<translation id="6596325263575161958">ಎನà³â€Œà²•à³à²°à²¿à²«à³à²¶à²¨à³ ಆಯà³à²•à³†à²—ಳà³</translation>
+<translation id="6596892391065203054">ಈ ವಿಷಯ ಪà³à²°à²¿à²‚ಟೠಮಾಡà³à²µà³à²¦à²¨à³à²¨à³ ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿದà³à²¦à²¾à²°à³†.</translation>
<translation id="6604181099783169992">ಚಲನೆ ಅಥವಾ ಬೆಳಕಿನ ಸೆನà³à²¸à²°à³â€Œà²—ಳà³</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">ಸಂರಕà³à²·à²¿à²¸à²¿à²¦ ವಿಷಯ</translation>
@@ -1440,6 +1467,7 @@
<translation id="6895330447102777224">ನಿಮà³à²® ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸಲಾಗಿದೆ</translation>
<translation id="6897140037006041989">ಬಳಕೆದಾರರ à²à²œà³†à²‚ಟà³</translation>
<translation id="6898699227549475383">ಸಂಸà³à²¥à³† (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> ಅವರಿಗೆ ಇದಕà³à²•à²¾à²—ಿ ಅನà³à²®à²¤à²¿ ನೀಡಿ:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ನಿಮà³à²® MIDI ಸಾಧನಗಳ ಸಂಪೂರà³à²£ ನಿಯಂತà³à²°à²£ ಪಡೆಯಲೠಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="6915804003454593391">ಬಳಕೆದಾರ:</translation>
<translation id="6934672428414710184">ಈ ಹೆಸರೠನಿಮà³à²® Google ಖಾತೆಯಿಂದ ಬಂದಿದೆ</translation>
@@ -1459,7 +1487,7 @@
<translation id="6973656660372572881">ಹೊಂದಿಸಿದ ಪà³à²°à²¾à²•à³à²¸à²¿ ಸರà³à²µà²°à³â€Œà²—ಳೠಮತà³à²¤à³ .pac ಸà³à²•à³à²°à²¿à²ªà³à²Ÿà³ URL ಎರಡನà³à²¨à³‚ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="6973932557599545801">ಕà³à²·à²®à²¿à²¸à²¿, ನನà³à²¨à²¿à²‚ದ ಸಹಾಯ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¿à²²à³à²², ನಿಮà³à²® ವಿವೇಚನೆಗೆ ತಕà³à²•à²‚ತೆ ಮà³à²‚ದà³à²µà²°à²¿à²¸à²¿.</translation>
<translation id="6975012522936652259">ನೀವೠಈಗಷà³à²Ÿà³‡ ವಂಚನೆ ಮಾಡà³à²µ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಮೂದಿಸಿದà³à²¦à³€à²°à²¿. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> ಹಾಗೂ ಈ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಬಳಸà³à²µ ಇತರ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಈಗಲೇ ಬದಲಾಯಿಸಲೠChromium ನಿಮಗೆ ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
-<translation id="6979158407327259162">Google ಡà³à²°à³ˆà²µà³â€Œâ€Œ</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">ಮà³à²¯à³‚ಟೠ(ಡಿಫಾಲà³à²Ÿà³)</translation>
<translation id="6979983982287291980">ನೀವೠಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಿದ ಫೈಲà³â€Œà²—ಳನà³à²¨à³ ವಿಶà³à²²à³‡à²·à²£à³† ಮಾಡಲà³, ಅವà³à²—ಳನà³à²¨à³ Google ಕà³à²²à³Œà²¡à³ ಅಥವಾ ಥರà³à²¡à³ ಪಾರà³à²Ÿà²¿à²—ಳಿಗೆ ಕಳà³à²¹à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¦à³†. ಉದಾಹರಣೆಗೆ, ಸೂಕà³à²·à³à²®à²µà²¾à²¦ ವೈಯಕà³à²¤à²¿à²• ಡೇಟಾ ಅಥವಾ ಮಾಲà³â€Œà²µà³‡à²°à³ ಅನà³à²¨à³ ಪತà³à²¤à³†à²¹à²šà³à²šà²²à³ ಅವà³à²—ಳನà³à²¨à³ ಸà³à²•à³à²¯à²¾à²¨à³ ಮಾಡಬಹà³à²¦à³.</translation>
<translation id="6989763994942163495">ಸà³à²§à²¾à²°à²¿à²¤ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸà³...</translation>
@@ -1551,6 +1579,7 @@
<translation id="7346048084945669753">ಸಂಯೋಜಿತವಾಗಿದà³à²¦à²¾à²°à³†:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">ಕಮಾಂಡೠಸಾಲà³</translation>
+<translation id="7359588939039777303">ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ.</translation>
<translation id="7372973238305370288">ಹà³à²¡à³à²•à²¾à²Ÿ ಫಲಿತಾಂಶ</translation>
<translation id="7374733840632556089">ನಿಮà³à²® ಸಾಧನದಲà³à²²à²¿ ನೀವೠಅಥವಾ ಬೇರೊಬà³à²¬à²°à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿರà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦à²¿à²‚ದಾಗಿ ಈ ಸಮಸà³à²¯à³† ಉಂಟಾಗà³à²¤à³à²¤à²¦à³†. ನೆಟà³â€Œà²µà²°à³à²•à³â€Œà²—ಳನà³à²¨à³ ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ಮಾಡಲೠಮತà³à²¤à³ ಪà³à²°à²¤à²¿à²¬à²‚ಧಿಸಲೠಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಬಳಸಲಾಗà³à²¤à³à²¤à²¦à³† ಎಂದೠತಿಳಿದà³à²¬à²‚ದಿದೆ ಮತà³à²¤à³ ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಕà³à²°à²¿à²¤à³ Chrome ಗೆ ವಿಶà³à²µà²¾à²¸à²µà²¿à²²à³à²². ಕೆಲವೠಕಾನೂನà³à²¬à²¦à³à²§ ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ಪà³à²°à²•à²°à²£à²—ಳೠಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿à²¦à³à²¦à²°à³‚, ಉದಾಹರಣೆಗೆ ಶಾಲೆ ಅಥವಾ ಕಂಪನಿಯ ನೆಟà³â€Œà²µà²°à³à²•à³â€Œ, ಅದನà³à²¨à³ ತಡೆಯಲೠಸಾಧà³à²¯à²µà²¾à²—ದಿದà³à²¦à²°à³‚ ಸಹ, ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ನಡೆಯà³à²¤à³à²¤à²¿à²¦à³† ಎಂಬà³à²¦à³ ನಿಮಗೆ ತಿಳಿದಿದೆ ಎಂದೠಖಚಿತಪಡಿಸಿಕೊಳà³à²³à²²à³ Chrome ಬಯಸà³à²¤à³à²¤à²¦à³†. ವೆಬೠಅನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µ ಯಾವà³à²¦à³‡ ಬà³à²°à³Œà²¸à²°à³ ಅಥವಾ ಆà³à²¯à²ªà³â€Œà²¨à²²à³à²²à²¿ ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ನಡೆಯಬಹà³à²¦à³.</translation>
<translation id="7375818412732305729">ಫೈಲೠಲಗತà³à²¤à²¿à²¸à²¿à²¦à²¾à²—</translation>
@@ -1724,6 +1753,7 @@
<translation id="7976214039405368314">ಅತೀ ಹೆಚà³à²šà³ ವಿನಂತಿಗಳà³</translation>
<translation id="7977538094055660992">ಔಟà³â€Œà²ªà³à²Ÿà³ ಸಾಧನ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ವರà³à²§à²¿à²¤ ನೈಜತೆಯ ವಿಷಯವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³, ARCore ಅನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿ</translation>
<translation id="799149739215780103">ಬೈಂಡೠಮಾಡಿ</translation>
<translation id="7995512525968007366">ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿಲà³à²²</translation>
<translation id="800218591365569300">ಮೆಮೊರಿ ಮà³à²•à³à²¤à²—ೊಳಿಸಲೠಇತರ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಅಥವಾ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಮà³à²šà³à²šà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
@@ -1851,25 +1881,39 @@
<translation id="8507227106804027148">ಕಮಾಂಡೠಸಾಲà³</translation>
<translation id="8508648098325802031">ಹà³à²¡à³à²•à²¾à²Ÿà²¦ à²à²•à²¾à²¨à³</translation>
<translation id="8522552481199248698">ನಿಮà³à²® Google ಖಾತೆಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²²à³ ಮತà³à²¤à³ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ಬದಲಾಯಿಸಲೠChrome ಸಹಾಯ ಮಾಡಬಲà³à²²à²¦à³.</translation>
+<translation id="8525306231823319788">ಪೂರà³à²£ ಪರದೆ</translation>
<translation id="8530813470445476232">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ, ಕà³à²•à³€à²—ಳà³, ಕà³à²¯à²¾à²·à³ ಮತà³à²¤à³ ಇನà³à²¨à²·à³à²Ÿà²µà³à²—ಳನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ</translation>
<translation id="8533619373899488139">ನಿಮà³à²® ಸಿಸà³à²Ÿà²®à³ ನಿರà³à²µà²¾à²¹à²•à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿರà³à²µ URLಗಳ ಪಟà³à²Ÿà²¿ ಮತà³à²¤à³ ಜಾರಿಗೊಳಿಸಿರà³à²µ ಇತರ ನೀತಿಗಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ &lt;strong&gt;chrome://policy&lt;/strong&gt; ಗೆ ಭೇಟಿ ನೀಡಿ.</translation>
<translation id="8541158209346794904">ಬà³à²²à³‚ಟೂತೠಸಾಧನ</translation>
<translation id="8542014550340843547">ಕೆಳಭಾಗದಲà³à²²à²¿ ಮೂರೠಸà³à²Ÿà³‡à²ªà²²à³ ಹಾಕಿ</translation>
<translation id="8543181531796978784">ನೀವೠ<ph name="BEGIN_ERROR_LINK" />ಪತà³à²¤à³† ಹಚà³à²šà³à²µà²¿à²•à³† ಸಮಸà³à²¯à³†à²¯à²¨à³à²¨à³ ವರದಿ ಮಾಡಬಹà³à²¦à³<ph name="END_ERROR_LINK" /> ಅಥವಾ ನಿಮà³à²® ಭದà³à²°à²¤à³†à²¯ ಅಪಾಯಗಳ ಕà³à²°à²¿à²¤à³ ನಿಮಗೆ ಅರà³à²¥à²µà²¾à²—ಿದà³à²¦à²°à³†, <ph name="BEGIN_LINK" />ಈ ಅಸà³à²°à²•à³à²·à²¿à²¤ ಸೈಟà³â€Œà²—ೆ ಭೇಟಿ ನೀಡಿ<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">ನಿಮà³à²® ಕಾರà³à²¡à³ ಹಿಂಬದಿಯಲà³à²²à²¿ CVC ಇರà³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="8558485628462305855">ವರà³à²§à²¿à²¤ ನೈಜತೆಯ ವಿಷಯವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³, ARCore ಅನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಿ</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಗೆ ಖಾಸಗಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²² à²à²•à³†à²‚ದರೆ ನಿಮà³à²® ಸಾಧನದ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪà³à²ªà²¾à²—ಿದೆ.</translation>
<translation id="8564182942834072828">ಪà³à²°à²¤à³à²¯à³‡à²• ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œà²—ಳà³/ಸಂಯೋಜಿಸದ ಪà³à²°à²¤à²¿à²—ಳà³</translation>
<translation id="8564985650692024650">ನೀವೠಇತರ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œ ಅನà³à²¨à³ ಮರà³à²¬à²³à²•à³† ಮಾಡಿದà³à²¦à²²à³à²²à²¿ ನಿಮà³à²® <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ಪಾಸವರà³à²¡à³ ಅನà³à²¨à³ ಮರà³à²¹à³Šà²‚ದಿಸಲೠChromium ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ಈ ಸಾಧನದಲà³à²²à²¿ ಉಳಿಯದ ಚಟà³à²µà²Ÿà²¿à²•à³†:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಈ ವಿಂಡೋದಲà³à²²à²¿ ನೀವೠವೀಕà³à²·à²¿à²¸à³à²µ ಪà³à²Ÿà²—ಳà³
+ <ph name="LIST_ITEM" />ಕà³à²•à³€à²—ಳೠಮತà³à²¤à³ ಸೈಟೠಡೇಟಾ
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ವೇಗವಾಗಿ ದೃಢೀಕರಿಸಲೠಟಚೠID ಬಳಸಿ</translation>
<translation id="858637041960032120">ಫೋನೠಸಂ. ಸೇರಿಸಿ
</translation>
<translation id="8589998999637048520">ಅತà³à²¯à³à²¤à³à²¤à²® ಗà³à²£à²®à²Ÿà³à²Ÿ</translation>
+<translation id="8600271352425265729">ಈ ಬಾರಿ ಮಾತà³à²°</translation>
<translation id="860043288473659153">ಕಾರà³à²¡à³â€Œà²¹à³‹à²²à³à²¡à²°à³ ಹೆಸರà³</translation>
<translation id="8606726445206553943">ನಿಮà³à²® MIDI ಸಾಧನಗಳನà³à²¨à³ ಬಳಸಿ</translation>
+<translation id="8612761427948161954">ಹಾಯೠ<ph name="USERNAME" />,
+ <ph name="BR" />
+ ನೀವೠಒಬà³à²¬ ಅತಿಥಿಯಂತೆ ಬà³à²°à³Œà²¸à³ ಮಾಡà³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿</translation>
<translation id="861775596732816396">ಗಾತà³à²° 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ಯಾವà³à²¦à³‡ ಹೊಂದಾಣಿಕೆಯಾಗà³à²µà²‚ತಹ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳಿಲà³à²². ಉಳಿಸಿದ ಎಲà³à²²à²¾ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸಿ.</translation>
<translation id="8625384913736129811">ಈ ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಈ ಸಾಧನದಲà³à²²à²¿ ಉಳಿಸಿ</translation>
+<translation id="8627040765059109009">ಸà³à²•à³à²°à²¿à³•à²¨à³ ಕà³à²¯à²¾à²ªà³à²šà²°à³ ಅನà³à²¨à³ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಲಾಗಿದೆ</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> ನಿಂದ <ph name="VM_NAME_1" /> ಮತà³à²¤à³ <ph name="VM_NAME_2" /> ಗೆ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à²¨à³à²¨à³ ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿದà³à²¦à²¾à²°à³†</translation>
<translation id="8663226718884576429">ಆರà³à²¡à²°à³ ಸಾರಾಂಶ, <ph name="TOTAL_LABEL" />, ಹೆಚà³à²šà²¿à²¨ ವಿವರಗಳà³</translation>
<translation id="867224526087042813">ಸಹಿ</translation>
@@ -1932,6 +1976,7 @@
<translation id="8912362522468806198">Google ಖಾತೆ</translation>
<translation id="8913778647360618320">'ಪಾವತಿ ವಿಧಾನಗಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿' ಬಟನà³, Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಪಾವತಿಗಳೠಮತà³à²¤à³ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಮಾಹಿತಿಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ ಎಂಟರೠಒತà³à²¤à²¿</translation>
<translation id="8918231688545606538">ಈ ಪà³à²Ÿà²µà³ ಅನà³à²®à²¾à²¨à²¾à²¸à³à²ªà²¦à²µà²¾à²—ಿದೆ</translation>
+<translation id="8922013791253848639">ಈ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ಯಾವಾಗಲೂ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²¿</translation>
<translation id="892588693504540538">ಮೇಲಿನ ಬಲಭಾಗದಲà³à²²à²¿ ತೂತೠಮಾಡಿ</translation>
<translation id="8931333241327730545">ಈ ಕಾರà³à²¡à²¨à³à²¨à³ ನಿಮà³à²® Google ಖಾತೆನಲà³à²²à²¿ ಉಳಿಸಲೠಬಯಸà³à²µà²¿à²°à²¾?</translation>
<translation id="8932102934695377596">ನಿಮà³à²® ಗಡಿಯಾರ ಹಿಂದೆ ಇದೆ</translation>
@@ -2000,21 +2045,24 @@
<translation id="917450738466192189">ಸರà³à²µà²°à³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ಅಮಾನà³à²¯à²µà²¾à²—ಿದೆ.</translation>
<translation id="9174917557437862841">ಟà³à²¯à²¾à²¬à³ ಬದಲಿಸà³à²µ ಬಟನà³, ಈ ಟà³à²¯à²¾à²¬à³â€Œà²—ೆ ಬದಲಾಯಿಸಲೠEnter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="9179703756951298733">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಪಾವತಿಗಳೠಮತà³à²¤à³ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಮಾಹಿತಿಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
-<translation id="9183302530794969518">Google ಡಾಕà³à²¸à³â€Œ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ಬೆಂಬಲಿತವಲà³à²²à²¦ ಪà³à²°à³‹à²Ÿà³‹à²•à²¾à²²à³ ಬಳಸà³à²¤à³à²¤à²¿à²¦à³†.</translation>
<translation id="9191834167571392248">ಕೆಳಗಿನ ಎಡಭಾಗದಲà³à²²à²¿ ತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
+<translation id="9199905725844810519">ಪà³à²°à²¿à²‚ಟಿಂಗೠಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="9205078245616868884">ನಿಮà³à²® ಡೇಟಾವನà³à²¨à³ ನಿಮà³à²® ಸಿಂಕೠಪಾಸà³â€Œà²«à³à²°à³‡à²¸à³â€Œà²¨à³†à³‚ಂದಿಗೆ ಎನà³â€Œà²•à³à²°à²¿à²ªà³à²Ÿà³ ಮಾಡಲಾಗಿದೆ. ಸಿಂಕೠಪà³à²°à²¾à²°à²‚ಭಿಸಲೠಅದನà³à²¨à³ ನಮೂದಿಸಿ.</translation>
<translation id="9207861905230894330">ಲೇಖನವನà³à²¨à³ ಸೇರಿಸಲೠವಿಫಲವಾಗಿದೆ.</translation>
<translation id="9213433120051936369">ಗೋಚರತೆಯನà³à²¨à³ ಕಸà³à²Ÿà²®à³ˆà²¸à³ ಮಾಡಿ</translation>
<translation id="9215416866750762878">ಈ ಸೈಟà³â€Œà²—ೆ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿ ಸಂಪರà³à²•à²¿à²¸à³à²µ Chromeನ ಕಾರà³à²¯à²µà²¨à³à²¨à³ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œ ಸà³à²¥à²—ಿತಗೊಳಿಸಿದೆ</translation>
-<translation id="9219103736887031265">ಚಿತà³à²°à²—ಳà³</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ಫಾರà³à²®à³ ತೆರವà³à²—ೊಳಿಸಿ</translation>
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">ನಿಮà³à²® Google ಖಾತೆಗೆ ನೀವೠಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ಕಳೆದà³à²•à³Šà²³à³à²³à²¬à²¹à³à²¦à³. ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œ ಅನà³à²¨à³ ಈಗಲೇ ಬದಲಾಯಿಸà³à²µà²‚ತೆ Chromium ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†. ಸೈನೠಇನೠಮಾಡಲೠನಿಮà³à²®à²¨à³à²¨à³ ಕೇಳಲಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="939736085109172342">ಹೊಸ ಫೋಲà³à²¡à²°à³</translation>
+<translation id="945522503751344254">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²¨à³à²¨à³ ಕಳà³à²¹à²¿à²¸à²¿</translation>
<translation id="945855313015696284">ಕೆಳಗಿನ ಮಾಹಿತಿಯನà³à²¨à³ ಪರಿಶೀಲಿಸಿ ಮತà³à²¤à³ ಯಾವà³à²¦à³‡ ಅಮಾನà³à²¯ ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ಅಳಿಸಿ</translation>
<translation id="950736567201356821">ಮೇಲà³à²­à²¾à²—ದಲà³à²²à²¿ ಮೂರೠತೂತೠಮಾಡಿ</translation>
+<translation id="951941430552851965">ನಿಮà³à²® ಸà³à²•à³à²°à³€à²¨à³â€Œà²¨à²²à³à²²à²¿ ಗೌಪà³à²¯ ವಿಷಯ ಇರà³à²µ ಕಾರಣ, ನಿರà³à²µà²¾à²¹à²•à²°à³ ಸà³à²•à³à²°à³€à²¨à³ ಕà³à²¯à²¾à²ªà³à²šà²°à³ ಅನà³à²¨à³ ವಿರಾಮಗೊಳಿಸಿದà³à²¦à²¾à²°à³†.</translation>
<translation id="961663415146723894">ಕೆಳಭಾಗದಲà³à²²à²¿ ಬೈಂಡೠಮಾಡಿ</translation>
<translation id="962484866189421427">ಈ ವಿಷಯವೠವಂಚಕ ಆà³à²¯à²ªà³â€Œà²—ಳನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¬à²¹à³à²¦à³. ಈ ಆà³à²¯à²ªà³â€Œà²—ಳೠಬೇರೆ ಯಾವà³à²¦à²°à²‚ತೆಯೋ ಸೋಗೠಹಾಕà³à²µ ಅಥವಾ ನಿಮà³à²®à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡಲೠಬಳಸಬಹà³à²¦à²¾à²¦ ಡೇಟಾವನà³à²¨à³ ಸಂಗà³à²°à²¹à²¿à²¸à³à²µ ಸಾಧà³à²¯à²¤à³†à²¯à²¿à²¦à³†. <ph name="BEGIN_LINK" />ಹೇಗಿದà³à²¦à²°à³‚ ತೋರಿಸಿ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ಅಧಿಕೃತವಾಗಿ ನಿರà³à²®à²¿à²¸à²¿</translation>
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index 7d88404b607..b5c1afd3132 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ì¡°ì§ì—ì„œ 관리하지 않는 사ì´íŠ¸ì— ë‚´ 비밀번호를 입력했습니다. ê³„ì •ì„ ì•ˆì „í•˜ê²Œ 보호하려면 다른 앱과 사ì´íŠ¸ì—ì„œ ë™ì¼í•œ 비밀번호를 재사용하지 마세요.</translation>
<translation id="1263231323834454256">ì½ê¸° 목ë¡</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ê¸°ê¸°ì— ì €ìž¥ë˜ì§€ 않는 í™œë™ ë‚´ì—­:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ì´ ì°½ì—ì„œ ì ‘ì†í•˜ëŠ” 페ì´ì§€
+ <ph name="LIST_ITEM" />쿠키 ë° ì‚¬ì´íŠ¸ ë°ì´í„°
+ <ph name="LIST_ITEM" />계정 정보(<ph name="LINK_BEGIN" />로그아웃<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">픽업 방법</translation>
<translation id="1281476433249504884">스태커 1</translation>
<translation id="1285320974508926690">ì´ ì‚¬ì´íŠ¸ 번역 안함</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">방문 ê¸°ë¡ í•­ëª© 목ë¡</translation>
<translation id="1517433312004943670">전화번호 필요</translation>
<translation id="1519264250979466059">ìƒì„± 날짜</translation>
-<translation id="1521655867290435174">Google 스프레드시트</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">연결 대기 중...</translation>
<translation id="1529521330346880926">10x15(봉투)</translation>
<translation id="1529789484829130889">íŠ¸ë ˆì´ 8</translation>
@@ -243,7 +251,7 @@
<translation id="1842969606798536927">결제</translation>
<translation id="1871208020102129563">프ë¡ì‹œê°€ .pac 스í¬ë¦½íŠ¸ URLì´ ì•„ë‹Œ ê³ ì • 프ë¡ì‹œ 서버를 사용하ë„ë¡ ì„¤ì •ë©ë‹ˆë‹¤.</translation>
<translation id="1871284979644508959">필수 입력란</translation>
-<translation id="1875512691959384712">Google 설문지</translation>
+<translation id="1875512691959384712">Google Forms</translation>
<translation id="187918866476621466">시작 페ì´ì§€ 열기</translation>
<translation id="1883255238294161206">접기 목ë¡</translation>
<translation id="1898423065542865115">í•„í„°ë§</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">Google ê³„ì •ì— ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ 사용하여 로그ì¸</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />ë¡œ ëœ íŽ˜ì´ì§€ë¥¼ 번역하지 않습니다.</translation>
<translation id="2053553514270667976">우편번호</translation>
+<translation id="2054665754582400095">활ë™</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{제안 1개}other{제안 #개}}</translation>
<translation id="2079545284768500474">실행취소</translation>
<translation id="20817612488360358">시스템 프ë¡ì‹œ ì„¤ì •ì´ ì‚¬ìš©í•˜ë„ë¡ ì„¤ì •ë˜ì—ˆì§€ë§Œ ëª…ì‹œì  í”„ë¡ì‹œ ì„¤ì •ë„ ì§€ì •ë˜ì–´ 있습니다.</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android 앱</translation>
<translation id="2107021941795971877">ì¸ì‡„ 지지대</translation>
<translation id="2108755909498034140">컴퓨터 다시 시작</translation>
+<translation id="2111166930115883695">플레ì´í•˜ë ¤ë©´ 스페ì´ìŠ¤ë°”를 누르세요.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">카드</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" />ì´(ê°€) ìš°ì„  ì ìš©ë˜ì—ˆê¸° ë•Œë¬¸ì— ë¬´ì‹œë©ë‹ˆë‹¤.</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">결제 취소</translation>
<translation id="2147827593068025794">백그ë¼ìš´ë“œ ë™ê¸°í™”</translation>
<translation id="2148613324460538318">카드 추가</translation>
+<translation id="2149968176347646218">ì—°ê²°ì´ ì•ˆì „í•˜ì§€ ì•ŠìŒ</translation>
<translation id="2154054054215849342">ë„ë©”ì¸ì— 대해 ë™ê¸°í™”를 사용할 수 없습니다.</translation>
<translation id="2154484045852737596">카드 수정</translation>
<translation id="2161656808144014275">í…스트</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">ì •ì±…</translation>
<translation id="2183608646556468874">전화번호</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{주소 1개}other{주소 #개}}</translation>
-<translation id="2187243482123994665">ì‚¬ìš©ìž ì ‘ì† ìƒíƒœ</translation>
<translation id="2187317261103489799">ê°ì§€(기본값)</translation>
<translation id="2188375229972301266">하단 다공 펀칭</translation>
<translation id="2202020181578195191">올바른 만료 ì—°ë„를 입력하세요.</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">가짜 사ì´íŠ¸ 주ì˜</translation>
<translation id="2850739647070081192">Invite(봉투)</translation>
<translation id="2856444702002559011">공격ìžê°€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ì—ì„œ ì •ë³´(예: 비밀번호, 메시지, ì‹ ìš©ì¹´ë“œ 등)를 ë„용하려고 ì‹œë„ ì¤‘ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ì´ ì‚¬ì´íŠ¸ì—서는 ë°©í•´ê°€ ë˜ê±°ë‚˜ 사용ìžë¥¼ 현혹하는 광고를 표시합니다.</translation>
<translation id="2878197950673342043">í¬ìŠ¤í„° í´ë“œ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">창 배치</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google 추천</translation>
<translation id="3002501248619246229">ìž…ë ¥ íŠ¸ë ˆì´ ë¯¸ë””ì–´ 확ì¸</translation>
<translation id="3005723025932146533">ì €ìž¥ëœ ì‚¬ë³¸ 표시</translation>
-<translation id="3007719053326478567">관리ìžê°€ ì´ ì½˜í…ì¸ ì˜ ì¸ì‡„를 차단했습니다.</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ì¹´ë“œì˜ CVC를 입력하세요. 카드를 확ì¸í•˜ë©´ ì¹´ë“œ 세부정보가 ì´ ì‚¬ì´íŠ¸ì™€ 공유ë©ë‹ˆë‹¤.</translation>
<translation id="3010559122411665027">ëª©ë¡ í•­ëª© '<ph name="ENTRY_INDEX" />': <ph name="ERROR" /></translation>
<translation id="301521992641321250">ìžë™ìœ¼ë¡œ 차단ë¨</translation>
<translation id="3016780570757425217">ë‚´ 위치 확ì¸</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ì¶”ì²œì„ ì‚­ì œí•˜ë ¤ë©´ Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter 누르기</translation>
<translation id="3023071826883856138">You4(봉투)</translation>
<translation id="3024663005179499861">ìž˜ëª»ëœ ì •ì±… 유형</translation>
<translation id="3037605927509011580">ì•—, ì´ëŸ°!</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">ë¶ë§ˆí¬ì— 추가ë¨</translation>
<translation id="3209034400446768650">페ì´ì§€ì—ì„œ ìš”ê¸ˆì„ ì²­êµ¬í•  수 있ìŒ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />ì—ì„œì˜ í™œë™ì´ 모니터ë§ë˜ê³  있ìŒ</translation>
+<translation id="3212623355668894776">게스트 ì°½ì„ ëª¨ë‘ ë‹«ìœ¼ë©´ 기기ì—ì„œ íƒìƒ‰ 활ë™ì´ ì‚­ì œë©ë‹ˆë‹¤.</translation>
<translation id="3215092763954878852">WebAuthnì„ ì‚¬ìš©í•  수 ì—†ìŒ</translation>
<translation id="3218181027817787318">ìƒëŒ€</translation>
<translation id="3225919329040284222">서버가 ë‚´ìž¥ëœ ê¸°ëŒ€ì¹˜ì™€ ì¼ì¹˜í•˜ì§€ 않는 ì¸ì¦ì„œë¥¼ 전달했습니다. ì´ëŸ¬í•œ 기대치는 사용ìžë¥¼ 보호하기 위해 ë³´ì•ˆì´ ì—„ê²©í•œ 특정 웹사ì´íŠ¸ì— í¬í•¨ë©ë‹ˆë‹¤.</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">블루투스 장치</translation>
<translation id="3787705759683870569">만료: <ph name="EXPIRATION_YEAR" />년 <ph name="EXPIRATION_MONTH" />월</translation>
<translation id="3789155188480882154">í¬ê¸° 16</translation>
+<translation id="3789841737615482174">설치</translation>
<translation id="3793574014653384240">최근 ë°œìƒí•œ ë¹„ì •ìƒ ì¢…ë£Œì˜ íšŸìˆ˜ ë° ì›ì¸</translation>
<translation id="3797522431967816232">Prc3(봉투)</translation>
<translation id="3799805948399000906">글꼴 요청ë¨</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">세피아</translation>
<translation id="4058922952496707368">'<ph name="SUBKEY" />' 키: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1(봉투)</translation>
+<translation id="4067669230157909013">화면 캡처가 다시 시작ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="4067947977115446013">유효한 주소 추가</translation>
<translation id="4072486802667267160">ì£¼ë¬¸ì„ ì²˜ë¦¬í•˜ëŠ” ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„하세요.</translation>
<translation id="4075732493274867456">í´ë¼ì´ì–¸íŠ¸ì™€ 서버가 ì¼ë°˜ì ì¸ SSL 프로토콜 버전 ë˜ëŠ” 암호화 ì œí’ˆêµ°ì„ ì§€ì›í•˜ì§€ 않습니다.</translation>
@@ -826,6 +840,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> 페ì´ì§€ 미리보기 ì´ë¯¸ì§€</translation>
<translation id="42981349822642051">펼치기</translation>
<translation id="4300675098767811073">오른쪽 다공 펀칭</translation>
+<translation id="4302514097724775343">플레ì´í•˜ë ¤ë©´ ê³µë£¡ì„ íƒ­í•˜ì„¸ìš”.</translation>
<translation id="4302965934281694568">Chou3(봉투)</translation>
<translation id="4305666528087210886">파ì¼ì— 액세스할 수 ì—†ìŒ</translation>
<translation id="4305817255990598646">전환</translation>
@@ -904,9 +919,10 @@
<translation id="4658638640878098064">왼쪽 ìƒë‹¨ 스테ì´í”Œ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ê°€ìƒ í˜„ì‹¤</translation>
+<translation id="4675657451653251260">게스트 모드ì—서는 Chrome 프로필 정보를 ë³¼ 수 없습니다. 비밀번호 ë° ê²°ì œ 수단과 ê°™ì€ Google 계정 정보를 보려면 <ph name="LINK_BEGIN" />로그ì¸<ph name="LINK_END" />하세요.</translation>
<translation id="467662567472608290">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없으며 ì„œë²„ì˜ ë³´ì•ˆ ì¸ì¦ì„œì— 오류가 있습니다. 서버를 잘못 설정했거나 불법 사용ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="4677585247300749148"><ph name="URL" />ì—ì„œ 접근성 ì´ë²¤íŠ¸ì— ì‘답하려고 합니다</translation>
-<translation id="467809019005607715">Google 프레젠테ì´ì…˜</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">사기성 사ì´íŠ¸ì— 비밀번호를 입력했습니다. 지금 바로 <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> 등 ë™ì¼í•œ 비밀번호를 사용한 사ì´íŠ¸ì— ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ 확ì¸í•˜ëŠ” ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤.</translation>
<translation id="4690462567478992370">유효하지 ì•Šì€ ì¸ì¦ì„œ 사용 중단</translation>
<translation id="4691835149146451662">Architecture-A(봉투)</translation>
@@ -931,6 +947,12 @@
<translation id="4761104368405085019">마ì´í¬ 사용</translation>
<translation id="4764776831041365478"><ph name="URL" />ì˜ ì›¹íŽ˜ì´ì§€ê°€ ì¼ì‹œì ìœ¼ë¡œ 다운ë˜ì—ˆê±°ë‚˜ 새 웹 주소로 완전히 ì´ë™í–ˆì„ 수 있습니다.</translation>
<translation id="4766713847338118463">하단 듀얼 스테ì´í”Œ</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ê¸°ê¸°ì— ì €ìž¥ë˜ëŠ” í™œë™ ë‚´ì—­:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ì´ ì°½ì—ì„œ 다운로드하는 모든 파ì¼
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{íŒì—… 1ê°œ 차단ë¨}other{íŒì—… #ê°œ 차단ë¨}}</translation>
<translation id="4780366598804516005">ë©”ì¼ë°•ìŠ¤ 1</translation>
@@ -1093,11 +1115,13 @@
<translation id="5386426401304769735">ì´ ì‚¬ì´íŠ¸ì˜ ì¸ì¦ì„œ ì²´ì¸ì€ SHA-1ì„ ì‚¬ìš©í•˜ì—¬ ì„œëª…ëœ ì¸ì¦ì„œë¥¼ í¬í•¨í•©ë‹ˆë‹¤.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">오른쪽 ì—지 스티치</translation>
+<translation id="5398772614898833570">ê´‘ê³  차단ë¨</translation>
<translation id="5400836586163650660">그레ì´</translation>
<translation id="540969355065856584">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없습니다. ì„œë²„ì˜ ë³´ì•ˆ ì¸ì¦ì„œê°€ 현재 유효하지 않습니다. 서버를 잘못 설정했거나 공격ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="541416427766103491">스태커 4</translation>
<translation id="5421136146218899937">ì¸í„°ë„· 사용 ê¸°ë¡ ì‚­ì œ...</translation>
<translation id="5426179911063097041"><ph name="SITE" />ì—ì„œ ì•Œë¦¼ì„ ë³´ë‚´ë ¤ê³  합니다.</translation>
+<translation id="542872847390508405">게스트로 ë¡œê·¸ì¸ ì¤‘</translation>
<translation id="5430298929874300616">ë¶ë§ˆí¬ ì‚­ì œ</translation>
<translation id="5439770059721715174">'<ph name="ERROR_PATH" />'ì—ì„œ 스키마 유효성 검사 오류: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">역순으로 ì¸ì‡„ë©´ì´ ìœ„ë¥¼ 향하게</translation>
@@ -1139,12 +1163,12 @@
<translation id="5571083550517324815">ì´ ì£¼ì†Œì—ì„œ 수령할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="5580958916614886209">유효기간 ì›”ì„ í™•ì¸í•œ 후 다시 ì‹œë„í•´ 주세요.</translation>
<translation id="5586446728396275693">ì €ìž¥ëœ ì£¼ì†Œ ì—†ìŒ</translation>
+<translation id="5593349413089863479">ì—°ê²° ë³´ì•ˆì´ ì™„ë²½í•˜ì§€ ì•ŠìŒ</translation>
<translation id="5595485650161345191">주소 수정</translation>
<translation id="5598944008576757369">ê²°ì œ 수단 ì„ íƒ</translation>
<translation id="560412284261940334">관리가 지ì›ë˜ì§€ ì•ŠìŒ</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">허위 ë˜ëŠ” 사기성 사ì´íŠ¸ì¼ 수 있습니다. Chromeì—서는 사ì´íŠ¸ì—ì„œ 지금 바로 나갈 ê²ƒì„ ê¶Œìž¥í•©ë‹ˆë‹¤.</translation>
<translation id="5610142619324316209">ì—°ê²° 확ì¸</translation>
<translation id="5610807607761827392"><ph name="BEGIN_LINK" />설정<ph name="END_LINK" />ì—ì„œ 카드와 주소를 관리할 수 있습니다.</translation>
<translation id="561165882404867731">Google 번역으로 ì´ íŽ˜ì´ì§€ë¥¼ 번역하세요.</translation>
@@ -1216,6 +1240,7 @@
<translation id="5901630391730855834">노란색</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />ì˜ ê¸°ì¡´ ì •ì±…ì— ë”°ë¼ ì°¨ë‹¨ë¨</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(ë™ê¸°í™”ë¨)</translation>
+<translation id="5913377024445952699">화면 캡처가 ì¼ì‹œì¤‘지ë¨</translation>
<translation id="59174027418879706">사용 가능</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">사용</translation>
@@ -1228,6 +1253,7 @@
<translation id="5963413905009737549">섹션</translation>
<translation id="5967592137238574583">ì—°ë½ì²˜ ì •ë³´ 수정</translation>
<translation id="5967867314010545767">기ë¡ì—ì„œ ì‚­ì œ</translation>
+<translation id="5968793460449681917">방문할 때마다</translation>
<translation id="5975083100439434680">축소</translation>
<translation id="5979084224081478209">비밀번호 확ì¸</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1383,6 +1409,7 @@
<translation id="6587923378399804057">복사한 ë§í¬</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> 기기는 관리 ëŒ€ìƒ ê¸°ê¸°ê°€ 아닙니다.</translation>
<translation id="6596325263575161958">암호화 옵션</translation>
+<translation id="6596892391065203054">관리ìžê°€ ì´ ì½˜í…ì¸ ì˜ ì¸ì‡„를 차단했습니다.</translation>
<translation id="6604181099783169992">모션 ë˜ëŠ” ì¡°ë„ ì„¼ì„œ</translation>
<translation id="6609880536175561541">Prc7(봉투)</translation>
<translation id="6612358246767739896">ë³´í˜¸ëœ ì½˜í…츠</translation>
@@ -1442,6 +1469,7 @@
<translation id="6895330447102777224">카드가 확ì¸ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="6897140037006041989">ì‚¬ìš©ìž ì—ì´ì „트</translation>
<translation id="6898699227549475383">ì¡°ì§(O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />ì˜ ë‹¤ìŒ ìž‘ì—… 허용:</translation>
<translation id="6910240653697687763"><ph name="URL" />ì—ì„œ MIDI 기기를 완전히 제어하려고 합니다.</translation>
<translation id="6915804003454593391">사용ìž:</translation>
<translation id="6934672428414710184">Google ê³„ì •ì— ë“±ë¡ëœ ì´ë¦„입니다.</translation>
@@ -1461,7 +1489,7 @@
<translation id="6973656660372572881">ê³ ì • 프ë¡ì‹œ 서버와 .pac 스í¬ë¦½íŠ¸ URLì´ ëª¨ë‘ ì§€ì •ë˜ì–´ 있습니다.</translation>
<translation id="6973932557599545801">죄송합니다. ë” ì´ìƒ ë„와드릴 수 없습니다. ì§ì ‘ 계ì†í•´ 주세요.</translation>
<translation id="6975012522936652259">사기성 사ì´íŠ¸ì— 비밀번호를 입력했습니다. 지금 바로 <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> 등 ë™ì¼í•œ 비밀번호를 사용한 사ì´íŠ¸ë¡œ ì´ë™í•˜ì—¬ 비밀번호를 변경하시기 ë°”ëžë‹ˆë‹¤.</translation>
-<translation id="6979158407327259162">Google ë“œë¼ì´ë¸Œ</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">ìŒì†Œê±°(기본값)</translation>
<translation id="6979983982287291980">다운로드한 파ì¼ì€ 분ì„ì„ ìœ„í•´ Google Cloud ë˜ëŠ” 타사로 전송ë©ë‹ˆë‹¤. 예를 들어, 민ê°í•œ ì •ë³´ ë˜ëŠ” 멀웨어를 찾기 위해 파ì¼ì„ 스캔할 수 있습니다.</translation>
<translation id="6989763994942163495">고급 설정 표시</translation>
@@ -1553,6 +1581,7 @@
<translation id="7346048084945669753">ì—°ê²°ë¨:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">명령줄</translation>
+<translation id="7359588939039777303">ê´‘ê³ ê°€ 차단ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="7372973238305370288">검색결과</translation>
<translation id="7374733840632556089">나 ë˜ëŠ” 다른 사용ìžê°€ ê¸°ê¸°ì— ì„¤ì¹˜í•œ ì¸ì¦ì„œë¡œ ì¸í•´ ì´ ë¬¸ì œê°€ ë°œìƒí•  수 있습니다. ì´ ì¸ì¦ì„œëŠ” 네트워í¬ë¥¼ 모니터ë§í•˜ê³  가로막는 ë° ì‚¬ìš©ë˜ëŠ” 것으로 알려져 있으며, Chromeì—ì„œ 신뢰하지 않습니다. í•™êµë‚˜ 회사 네트워í¬ì—ì„œ ë°œìƒí•˜ëŠ” 합법ì ì¸ 모니터ë§ë„ 존재합니다. 사용ìžê°€ 멈출 수는 ì—†ë”ë¼ë„ 모니터ë§ì´ ì´ë¤„지고 있다는 ì‚¬ì‹¤ì„ Chromeì—서는 알립니다. 모니터ë§ì€ ì›¹ì— ì•¡ì„¸ìŠ¤í•˜ëŠ” 모든 브ë¼ìš°ì € ë˜ëŠ” 애플리케ì´ì…˜ì—ì„œ ì´ë¤„집니다.</translation>
<translation id="7375818412732305729">íŒŒì¼ ì²¨ë¶€ë¨</translation>
@@ -1726,6 +1755,7 @@
<translation id="7976214039405368314">요청 횟수가 너무 많ìŒ</translation>
<translation id="7977538094055660992">출력 기기</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ì¦ê°• 현실 콘í…츠를 보려면 ARCore를 설치하세요.</translation>
<translation id="799149739215780103">ë°”ì¸ë“œ</translation>
<translation id="7995512525968007366">지정ë˜ì§€ ì•ŠìŒ</translation>
<translation id="800218591365569300">다른 탭ì´ë‚˜ í”„ë¡œê·¸ëž¨ì„ ì¢…ë£Œí•˜ì—¬ 메모리를 확보하세요.</translation>
@@ -1853,24 +1883,38 @@
<translation id="8507227106804027148">명령줄</translation>
<translation id="8508648098325802031">검색 ì•„ì´ì½˜</translation>
<translation id="8522552481199248698">Chromeì„ í†µí•´ Google ê³„ì •ì„ ë³´í˜¸í•˜ê³  비밀번호를 변경할 수 있습니다.</translation>
+<translation id="8525306231823319788">전체화면</translation>
<translation id="8530813470445476232">Chrome 설정ì—ì„œ 방문 기ë¡, 쿠키, ìºì‹œ ë“±ì„ ì‚­ì œí•˜ì„¸ìš”.</translation>
<translation id="8533619373899488139">ì°¨ë‹¨ëœ URL ë° ì‹œìŠ¤í…œ 관리ìžê°€ 설정한 기타 ì •ì±… 목ë¡ì„ 확ì¸í•˜ë ¤ë©´ &lt;strong&gt;chrome://policy&lt;/strong&gt;를 방문하세요.</translation>
<translation id="8541158209346794904">블루투스 기기</translation>
<translation id="8542014550340843547">하단 트리플 스테ì´í”Œ</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />ê°ì§€ 문제를 ì‹ ê³ <ph name="END_ERROR_LINK" />í•  수 있으며, ë³´ì•ˆì— ë¯¸ì¹˜ëŠ” ìœ„í—˜ì„ ê°ìˆ˜í•œë‹¤ë©´ <ph name="BEGIN_LINK" />ì´ ì•ˆì „í•˜ì§€ ì•Šì€ ì‚¬ì´íŠ¸ë¥¼ 방문<ph name="END_LINK" />í•  수 있습니다.</translation>
<translation id="8557066899867184262">CVC는 ì¹´ë“œ ë’·ë©´ì— ìžˆìŠµë‹ˆë‹¤.</translation>
+<translation id="8558485628462305855">ì¦ê°• 현실 콘í…츠를 보려면 ARCore를 ì—…ë°ì´íŠ¸í•˜ì„¸ìš”.</translation>
<translation id="8559762987265718583">ê¸°ê¸°ì˜ ë‚ ì§œì™€ 시간(<ph name="DATE_AND_TIME" />)ì´ ìž˜ëª»ë˜ì–´ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />ì— ëŒ€í•œ 비공개 ì—°ê²°ì„ ì„¤ì •í•  수 없습니다.</translation>
<translation id="8564182942834072828">ë³„ë„ ë¬¸ì„œ/모으지 ì•Šì€ ì‚¬ë³¸</translation>
<translation id="8564985650692024650">다른 사ì´íŠ¸ì—ì„œ 비밀번호를 재사용했다면 <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 비밀번호를 재설정하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ê¸°ê¸°ì— ì €ìž¥ë˜ì§€ 않는 í™œë™ ë‚´ì—­:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ì´ ì°½ì—ì„œ ì ‘ì†í•˜ëŠ” 페ì´ì§€
+ <ph name="LIST_ITEM" />쿠키 ë° ì‚¬ì´íŠ¸ ë°ì´í„°
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Touch ID를 사용하여 빠르게 ì¹´ë“œ 확ì¸</translation>
<translation id="858637041960032120">번호 추가</translation>
<translation id="8589998999637048520">고품질 순</translation>
+<translation id="8600271352425265729">ì´ë²ˆë§Œ 허용</translation>
<translation id="860043288473659153">ì¹´ë“œ 명ì˜ìž ì´ë¦„</translation>
<translation id="8606726445206553943">MIDI 기기를 사용합니다.</translation>
+<translation id="8612761427948161954"><ph name="USERNAME" />님, 안녕하세요
+ <ph name="BR" />
+ 게스트로 íƒìƒ‰ 중입니다</translation>
<translation id="861775596732816396">í¬ê¸° 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ì¼ì¹˜í•˜ëŠ” 비밀번호가 없습니다. ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ ëª¨ë‘ í‘œì‹œí•©ë‹ˆë‹¤.</translation>
<translation id="8625384913736129811">ì´ ê¸°ê¸°ì— ì¹´ë“œ 저장</translation>
+<translation id="8627040765059109009">화면 캡처가 다시 시작ë¨</translation>
<translation id="8657078576661269990">관리ìžê°€ <ph name="ORIGIN_NAME" />ì—ì„œ <ph name="VM_NAME_1" /> ë° <ph name="VM_NAME_2" /> ê°€ìƒ ë¨¸ì‹ ìœ¼ë¡œ 공유하는 ìž‘ì—…ì„ ì°¨ë‹¨í–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="8663226718884576429">주문 요약, <ph name="TOTAL_LABEL" />, 세부정보 ë”보기</translation>
<translation id="867224526087042813">서명</translation>
@@ -1933,6 +1977,7 @@
<translation id="8912362522468806198">Google 계정</translation>
<translation id="8913778647360618320">ê²°ì œ 수단 관리 버튼, Chrome 설정ì—ì„œ ê²°ì œ ë° ì‹ ìš©ì¹´ë“œ 정보를 관리하려면 Enter 누르기</translation>
<translation id="8918231688545606538">ì˜ì‹¬ìŠ¤ëŸ¬ìš´ 페ì´ì§€</translation>
+<translation id="8922013791253848639">ì´ ì‚¬ì´íŠ¸ì˜ ê´‘ê³  í•­ìƒ í—ˆìš©</translation>
<translation id="892588693504540538">오른쪽 ìƒë‹¨ 펀칭</translation>
<translation id="8931333241327730545">ì´ ì¹´ë“œë¥¼ Google ê³„ì •ì— ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="8932102934695377596">ì‹œê°„ì´ ë„ˆë¬´ 먼 과거로 설정ë˜ì–´ 있습니다.</translation>
@@ -2001,9 +2046,10 @@
<translation id="917450738466192189">ì„œë²„ì˜ ì¸ì¦ì„œê°€ 유효하지 않습니다.</translation>
<translation id="9174917557437862841">탭 전환 버튼, ì´ íƒ­ìœ¼ë¡œ 전환하려면 Enter를 누르세요</translation>
<translation id="9179703756951298733">Chrome 설정ì—ì„œ ê²°ì œ ë° ì‹ ìš©ì¹´ë“œ 정보를 관리하세요.</translation>
-<translation id="9183302530794969518">Google 문서</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" />ì—ì„œ 지ì›ë˜ì§€ 않는 í”„ë¡œí† ì½œì„ ì‚¬ìš©í•©ë‹ˆë‹¤.</translation>
<translation id="9191834167571392248">왼쪽 하단 펀칭</translation>
+<translation id="9199905725844810519">ì¸ì‡„ê°€ 차단ë¨</translation>
<translation id="9205078245616868884">ë™ê¸°í™” 암호로 ë°ì´í„°ê°€ 암호화ë˜ì–´ 있습니다. ë™ê¸°í™”를 시작하려면 입력하세요.</translation>
<translation id="9207861905230894330">ê¸€ì„ ì¶”ê°€í•˜ì§€ 못했습니다.</translation>
<translation id="9213433120051936369">ë””ìžì¸ 사용ìžì„¤ì •</translation>
@@ -2014,8 +2060,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google ê³„ì •ì— ì•¡ì„¸ìŠ¤í•˜ì§€ 못할 수 있습니다. ë”°ë¼ì„œ 지금 비밀번호를 변경하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤. 로그ì¸í•˜ë¼ëŠ” 메시지가 표시ë©ë‹ˆë‹¤.</translation>
<translation id="939736085109172342">새 í´ë”</translation>
+<translation id="945522503751344254">ì˜ê²¬ 보내기</translation>
<translation id="945855313015696284">아래 정보를 확ì¸í•˜ê³  ìž˜ëª»ëœ ì¹´ë“œë¥¼ 삭제하세요.</translation>
<translation id="950736567201356821">ìƒë‹¨ 3ê³µ 펀칭</translation>
+<translation id="951941430552851965">í™”ë©´ì˜ ì½˜í…츠 ë•Œë¬¸ì— ê´€ë¦¬ìžê°€ 화면 캡처를 ì¼ì‹œì¤‘지했습니다.</translation>
<translation id="961663415146723894">하단 ë°”ì¸ë“œ</translation>
<translation id="962484866189421427">ì´ ì½˜í…츠ì—ì„œ 다른 ì•±ì¸ ê²ƒì²˜ëŸ¼ 가장하거나 사용ìžë¥¼ 추ì í•˜ëŠ” ë° ì‚¬ìš©ë  ìˆ˜ 있는 ë°ì´í„°ë¥¼ 수집하는 사기성 ì•±ì„ ì„¤ì¹˜í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. <ph name="BEGIN_LINK" />ê·¸ëž˜ë„ í‘œì‹œí•˜ê¸°<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ê³µì‹ ë¹Œë“œ</translation>
diff --git a/chromium/components/strings/components_strings_ky.xtb b/chromium/components/strings/components_strings_ky.xtb
index 0a964172da0..4a91a59e529 100644
--- a/chromium/components/strings/components_strings_ky.xtb
+++ b/chromium/components/strings/components_strings_ky.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">СырÑөзүңүздү уюмуңуз тарабынан башкарылбаган Ñайтка киргиздиңиз. Ðккаунтуңузду коргоо үчүн ÑÑ‹Ñ€Ñөзүңүздү башка колдонмолор менен Ñайттарда колдонбоңуз.</translation>
<translation id="1263231323834454256">Окуу тизмеÑи</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Бул түзмөктө Ñакталбай турган аракеттер:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Бул терезеде каралган баракчалар
+ <ph name="LIST_ITEM" />Cookie файлдары жана Ñайттын маалыматы
+ <ph name="LIST_ITEM" />Ðккаунттун маалыматы (<ph name="LINK_BEGIN" />чыгуу<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ðлып кетүү ыкмаÑÑ‹</translation>
<translation id="1281476433249504884">6-төшөгүч</translation>
<translation id="1285320974508926690">Бул Ñайт Ñч качан которулбаÑын</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Google аккаунтуңузда Ñакталган ÑÑ‹Ñ€Ñөздөрдү колдонуу үчүн аккаунтуңузга кириңиз</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> тилиндеги барактар которулбайт.</translation>
<translation id="2053553514270667976">Почта индекÑи</translation>
+<translation id="2054665754582400095">Сайтта же Ñайтта ÑмеÑтигиңиз</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Ñунуш}other{# Ñунуш}}</translation>
<translation id="2079545284768500474">Кайтаруу</translation>
<translation id="20817612488360358">Тутумдун прокÑи жөндөөлөрү коюлду жана ошону менен катар, айкын прокÑи конфигурайиÑÑÑ‹ да белгиленди.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android Колдонмолору</translation>
<translation id="2107021941795971877">БаÑып чыгарууну колдоо</translation>
<translation id="2108755909498034140">Компьютериңизди өчүрүп-күйгүзүңүз</translation>
+<translation id="2111166930115883695">Ойноп баштоо үчүн боштук баÑкычын баÑыңыз</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> кайра аныктагандыктан Ñтибарга алынган жок.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Төлөмдү жокко чыгаруу</translation>
<translation id="2147827593068025794">Фондо шайкештирүү</translation>
<translation id="2148613324460538318">Картаны кошуу</translation>
+<translation id="2149968176347646218">Туташуу кооптуу</translation>
<translation id="2154054054215849342">Домениңизде шайкештирүү функциÑÑÑ‹ жок</translation>
<translation id="2154484045852737596">Карточканы түзөтүү</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">СаÑÑаттар</translation>
<translation id="2183608646556468874">Телефон номери</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 дарек}other{# дарек}}</translation>
-<translation id="2187243482123994665">Колдонуучунун Ñайтта же Ñайтта ÑмеÑтиги</translation>
<translation id="2187317261103489799">Ðныктоо (демейки)</translation>
<translation id="2188375229972301266">Төмөнкү жагын бир нече жолу тешүү</translation>
<translation id="2202020181578195191">Мөөнөтү аÑктоочу жылды туура киргизиңиз</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Жалган Ñайтка өткөнү жатаÑыз</translation>
<translation id="2850739647070081192">Invite (Конверт)</translation>
<translation id="2856444702002559011">Чабуулчулар <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> дарегинен маалыматыңызды (миÑалы, ÑÑ‹Ñ€Ñөздөр, билдирүүлөр же наÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð°Ð»Ð°Ñ€Ñ‹) уурдоого аракет кылып жатышы мүмкүн. <ph name="BEGIN_LEARN_MORE_LINK" />Кеңири маалымат<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Бул Ñайт тажатма же адаштыруучу жарнамаларды көрÑөтүп жатат.</translation>
<translation id="2878197950673342043">ПоÑтер формаÑында бүктөө</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Терезени жайгаштыруу</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google Ñунуштайт</translation>
<translation id="3002501248619246229">Киргизүү түпкүчүнүн медиаÑын текшерүү</translation>
<translation id="3005723025932146533">Сакталган көчүрмөнү көрÑÓ©Ñ‚Ò¯Ò¯</translation>
-<translation id="3007719053326478567">Бул мазмунду баÑып чыгаруу аракети админиÑтраторуңуз тарабынан бөгөттөлгөн</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> карточкаңыздын CVC кодун киргизиңиз. Текшерилгенден кийин карточкаңыздын маалыматы бул Ñайтта көрүнөт.</translation>
<translation id="3010559122411665027">Тизмедеги жазуу "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Ðвтоматтык түрдө бөгөттөлдү</translation>
<translation id="3016780570757425217">Жайгашкан жериңизди билүү</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Сунушту өчүрүү үчүн Tab, андан кийин Enter баÑкычын баÑыңыз.</translation>
<translation id="3023071826883856138">You4 (Конверт)</translation>
<translation id="3024663005179499861">Туура ÑÐ¼ÐµÑ ÑаÑÑат түрү</translation>
<translation id="3037605927509011580">Ðтаңдын көрү!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">КыÑтармаланды</translation>
<translation id="3209034400446768650">Барак төлөм өндүрүшү мүмкүн</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> Ñайтындагы аракеттериңиз көзөмөлдөнүүдө</translation>
+<translation id="3212623355668894776">Көрүлгөн вебÑайттарды бул түзмөктөн өчүрүү үчүн Конок режиминдеги бардык терезелерди жабыңыз.</translation>
<translation id="3215092763954878852">WebAuthn'ди колдонуу мүмкүн ÑмеÑ</translation>
<translation id="3218181027817787318">Окшош</translation>
<translation id="3225919329040284222">Сервер кыналган күтүүлөргө дал келбеген таÑтыктама тапшырды. Бул күтүүлөр Ñиздин коопÑуздугуңузду камÑыз кылган ишенимдүү вебÑайттарда камтылган.</translation>
@@ -701,6 +713,7 @@
<translation id="3784372983762739446">Bluetooth түзмөктөрү</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> мөөнөтү аÑктайт</translation>
<translation id="3789155188480882154">Өлчөмү: 16</translation>
+<translation id="3789841737615482174">Орнотуу</translation>
<translation id="3793574014653384240">Ðкыркы убакта орун алган бузулуулардын Ñаны жана Ñебептери</translation>
<translation id="3797522431967816232">Prc3 (Конверт)</translation>
<translation id="3799805948399000906">Ðрип Ñуралды</translation>
@@ -752,6 +765,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Ðчкыч "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Конверт)</translation>
+<translation id="4067669230157909013">Экранды тартуу улантылды.</translation>
<translation id="4067947977115446013">Дарегин туура көрÑөтүңүз</translation>
<translation id="4072486802667267160">Буйрутмаңызды иштетүү учурунда ката кетти. Кайталап көрүңүз.</translation>
<translation id="4075732493274867456">Кардар менен Ñерверде ар кандай SSL протоколунун верÑиÑлары же шифрлер топтому колдоого алынат.</translation>
@@ -836,6 +850,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> барагынын ÑÑкизи</translation>
<translation id="42981349822642051">Жайып көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="4300675098767811073">Оң жагын бир нече жолу тешүү</translation>
+<translation id="4302514097724775343">Ойноп баштоо үчүн динозаврды таптап коюңуз</translation>
<translation id="4302965934281694568">Chou3 (Конверт)</translation>
<translation id="4305666528087210886">Файл ачылбай койду</translation>
<translation id="4305817255990598646">Которулуу</translation>
@@ -914,6 +929,7 @@
<translation id="4658638640878098064">Жогорку Ñол жагын илмек менен бекитүү</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуалдык дүйнө</translation>
+<translation id="4675657451653251260">Конок режиминде Chrome'догу профилдин маалыматы көрүнбөйт. СырÑөздөр жана төлөм ыкмалары ÑÑ‹Ñктуу Google аккаунтуңуздагы маалыматты көрүү үчүн аккаунтуңузга <ph name="LINK_BEGIN" />кириңиз<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Бул Ñервер <ph name="DOMAIN" /> Ñкендигин далилдей алган жок; Ñебеби анын коопÑуздук таÑтыктамаÑында каталар бар. Мындай көйгөй туура ÑÐ¼ÐµÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¼ÐµÐ½ÐµÐ½ шартталышы мүмкүн же туташууңузга чабуулчу кийлигишип жатат.</translation>
<translation id="4677585247300749148"><ph name="URL" /> атайын мүмкүнчүлүктөрдү иштетүүгө урукÑат Ñуроодо</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -941,6 +957,12 @@
<translation id="4761104368405085019">Микрофонуңузду колдонуңуз</translation>
<translation id="4764776831041365478"><ph name="URL" /> дарегиндеги веб-баракча убактылуу иштебейт же жаңы веб дарекке биротоло көчүрүлгөн окшойт.</translation>
<translation id="4766713847338118463">Төмөн жагын Ñки жолу илмек менен бекитүү</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Бул түзмөктө Ñактала турган колдонмолор:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Бул терезеден жүктөлүп алынган файлдар
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">БелгиÑиз ката кетти.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Калкыма терезе бөгөттөлгөн}other{# калкыма терезе бөгөттөлгөн}}</translation>
<translation id="4780366598804516005">1-Ñлектрондук каттар кутуÑу</translation>
@@ -1103,11 +1125,13 @@
<translation id="5386426401304769735">Бул Ñайттын таÑтыктамалар чынжырында SHA-1 алгоритми менен кол коюлган таÑтыктама камтылган.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Оң четин жамоо</translation>
+<translation id="5398772614898833570">Жарнамалар бөгөттөлдү</translation>
<translation id="5400836586163650660">Боз</translation>
<translation id="540969355065856584">Бул Ñервер <ph name="DOMAIN" /> Ñкендигин далилдей алган жок; азыркы учурда анын коопÑуздук таÑтыктамаÑÑ‹ жарактуу ÑмеÑ. Бул туура ÑÐ¼ÐµÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñлоодон болушу мүмкүн же чабуулчу туташууңузга тоÑкоол болууда.</translation>
<translation id="541416427766103491">4-төшөгүч</translation>
<translation id="5421136146218899937">Серептөө дайындарын тазалап Ñалуу…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> Ñизге билдирмелерди жөнөткөнү жатат</translation>
+<translation id="542872847390508405">Конок катары Ñерептеп жатаÑыз</translation>
<translation id="5430298929874300616">КыÑтарманы алып Ñалуу</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />": <ph name="ERROR" /> Ñхемалык текшерүү катаÑÑ‹</translation>
<translation id="5443468954631487277">ТеÑкери иретте алдыңкы бетин өйдө каратып</translation>
@@ -1149,12 +1173,12 @@
<translation id="5571083550517324815">Бул даректен алып кетүү мүмкүн ÑмеÑ. Башка дарек тандаңыз.</translation>
<translation id="5580958916614886209">Мөөнөтү аÑктоочу айды текшерип, кайталап көрүңүз</translation>
<translation id="5586446728396275693">Сакталган даректер жок</translation>
+<translation id="5593349413089863479">Туташуу кооптуураак</translation>
<translation id="5595485650161345191">Даректи түзөтүү</translation>
<translation id="5598944008576757369">Төлөм ыкмаÑын тандоо</translation>
<translation id="560412284261940334">Башкаруу колдоого алынбайт</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Бул жалган Ñайт болушу мүмкүн. Chrome бул Ñайттан дароо чыгууну Ñунуштайт.</translation>
<translation id="5610142619324316209">Туташууну текшерип көрүңүз</translation>
<translation id="5610807607761827392">Карточкаларды жана даректерди <ph name="BEGIN_LINK" />Жөндөөлөрдөн<ph name="END_LINK" /> башкарÑаңыз болот.</translation>
<translation id="561165882404867731">Бул баракты Google Котормочуда которуңуз</translation>
@@ -1226,6 +1250,7 @@
<translation id="5901630391730855834">Сары</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> баштапкы ÑаÑÑатына ылайык бөгөттөлдү.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (шайкештирилген)</translation>
+<translation id="5913377024445952699">Экранды тартуу тындырылды</translation>
<translation id="59174027418879706">Иштетилген</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Күйүк</translation>
@@ -1238,6 +1263,7 @@
<translation id="5963413905009737549">Бөлүм</translation>
<translation id="5967592137238574583">Байланыш маалыматын түзөтүү</translation>
<translation id="5967867314010545767">Таржымалдан алып Ñалуу</translation>
+<translation id="5968793460449681917">Баш баккан Ñайын</translation>
<translation id="5975083100439434680">Кичирейтүү</translation>
<translation id="5979084224081478209">СырÑөздөрдү текшерүү</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@
<translation id="6587923378399804057">Сиз көчүргөн шилтеме</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> түзмөгүңүз башкарылган жок</translation>
<translation id="6596325263575161958">Шифрлөө параметрлери</translation>
+<translation id="6596892391065203054">Бул мазмунду баÑып чыгаруу аракети админиÑтраторуңуз тарабынан бөгөттөлгөн.</translation>
<translation id="6604181099783169992">Кыймыл же жарык ÑенÑорлору</translation>
<translation id="6609880536175561541">Prc7 (Конверт)</translation>
<translation id="6612358246767739896">Корголгон мазмун</translation>
@@ -1452,6 +1479,7 @@
<translation id="6895330447102777224">Карточкаңыз текшерилди</translation>
<translation id="6897140037006041989">Колдонуучунун агенти</translation>
<translation id="6898699227549475383">Уюм (У)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> үчүн төмөнкү урукÑаттар керек:</translation>
<translation id="6910240653697687763"><ph name="URL" /> MIDI түзмөктөрүңүздү толугу менен көзөмөлдөгөнү жатат</translation>
<translation id="6915804003454593391">Колдонуучу:</translation>
<translation id="6934672428414710184">Бул Ñ‹Ñым Google аккаунтуңуздан алынды</translation>
@@ -1563,6 +1591,7 @@
<translation id="7346048084945669753">Байланыштырылган:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Буйрук Ñабы</translation>
+<translation id="7359588939039777303">Жарнамалар бөгөттөлдү.</translation>
<translation id="7372973238305370288">издөө натыйжаÑÑ‹</translation>
<translation id="7374733840632556089">Бул маÑеле түзмөгүңүзгө орнотулган таÑтыктамадан улам келип чыгышы мүмкүн. Ðл таÑтыктама тармактарга көз Ñалып, ортодон кармап калууÑу менен белгилүү. Ðны Chrome ишенимдүү таÑтыктама катары көрбөйт. Мындай таÑтыктамаларды мектептин же уюмдун тармактарында көзөмөлдөөнүн мыйзамдуу жолдору бар. Сиз Ñч нерÑе кыла албаганыңыз менен, Chrome бул маÑеле тууралуу кабарыңыздын болушун туура көрдү. Көзөмөлдөө Интернетке туташкан бардык Ñерепчилерде жана колдонмолордо жүргүзүлөт.</translation>
<translation id="7375818412732305729">Файл тиркелди</translation>
@@ -1737,6 +1766,7 @@
<translation id="7976214039405368314">Өтүнүчтөр өтө көп жөнөтүлдү</translation>
<translation id="7977538094055660992">Чыгаруу түзмөгү</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Кошумчаланган чындыкты көрүү үчүн ARCore кызматын орнотуңуз</translation>
<translation id="799149739215780103">Байлоо</translation>
<translation id="7995512525968007366">Белгиленген ÑмеÑ</translation>
<translation id="800218591365569300">ЭÑтутумду бошотуу үчүн башка өтмөктөрдү же программаларды жаап көрүңүз.</translation>
@@ -1864,24 +1894,38 @@
<translation id="8507227106804027148">Буйрук Ñабы</translation>
<translation id="8508648098325802031">Издөө ÑүрөтчөÑÒ¯</translation>
<translation id="8522552481199248698">Chrome Google аккаунтуңуздун коопÑуздугун коргоп, ÑÑ‹Ñ€Ñөзүңүздү өзгөртүүгө жардам берет.</translation>
+<translation id="8525306231823319788">Толук Ñкран</translation>
<translation id="8530813470445476232">Chrome'дун жөндөөлөрүнө өтүп, Ñерептөө таржымалын, cookie файлдарын, кÑштерди жана башкаларды өчүрүңүз</translation>
<translation id="8533619373899488139">Бөгөттөлгөн URL'дерди жана тутум админиÑтраторуңуз ишке киргизген ÑаÑÑаттарды көрүү үчүн, &lt;strong&gt;chrome://policy&lt;/strong&gt; дарегине кириңиз.</translation>
<translation id="8541158209346794904">Bluetooth түзмөгү</translation>
<translation id="8542014550340843547">Төмөнкү жагын үч жолу тешүү</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Ðныкталган көйгөйдү кабарлаÑаңыз<ph name="END_ERROR_LINK" /> болот, же жеке дайын-даректериңиз зыÑнга учурап калат деп коркпоÑоңуз, <ph name="BEGIN_LINK" />бул кооптуу Ñайтка кире<ph name="END_LINK" /> бериңиз.</translation>
<translation id="8557066899867184262">CVC карточкаңыздын артында жайгашкан.</translation>
+<translation id="8558485628462305855">Кошумчаланган чындыкты көрүү үчүн ARCore кызматын жаңыртыңыз</translation>
<translation id="8559762987265718583">Түзмөгүңүздүн күнү жана убакыты (<ph name="DATE_AND_TIME" />) туура ÑÐ¼ÐµÑ Ð±Ð¾Ð»Ð³Ð¾Ð½Ð´ÑƒÐºÑ‚Ð°Ð½, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> менен ÐºÑƒÐ¿ÑƒÑ Ñ‚ÑƒÑ‚Ð°ÑˆÑƒÑƒ мүмкүн болбой жатат.</translation>
<translation id="8564182942834072828">Өзүнчө документ/Иреттелбеген көчүрмөлөр</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÑÑ‹Ñ€Ñөзүңүздү башка Ñайттарда колдонгон болÑоңуз, Chromium аны өзгөртүүнү Ñунуштайт.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Бул түзмөктө Ñакталбай турган аракеттер:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Бул терезеде каралган баракчалар
+ <ph name="LIST_ITEM" />Cookie файлдары жана Ñайттын маалыматы
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Карталарды тезирÑÑк ыраÑтоо үчүн Touch ID функциÑÑын колдонуу</translation>
<translation id="858637041960032120">Телефон номерин кошуу</translation>
<translation id="8589998999637048520">Мыкты Ñапат</translation>
+<translation id="8600271352425265729">Ушул жолу гана</translation>
<translation id="860043288473659153">Карта ÑÑÑинин аты</translation>
<translation id="8606726445206553943">MIDI түзмөктөрүңүздү колдонуңуз</translation>
+<translation id="8612761427948161954">Салам, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Конок катары Ñерептеп жатаÑыз</translation>
<translation id="861775596732816396">Өлчөмү: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Дал келген ÑÑ‹Ñ€Ñөздөр жок. Бардык Ñакталган ÑÑ‹Ñ€Ñөздөрдү көрÑÓ©Ñ‚Ò¯Ò¯.</translation>
<translation id="8625384913736129811">Бул карточка ушул түзмөктө ÑакталÑын</translation>
+<translation id="8627040765059109009">Экранды тартуу улантылды</translation>
<translation id="8657078576661269990">ÐдминиÑтраторуңуз <ph name="ORIGIN_NAME" /> Ñайтын <ph name="VM_NAME_1" /> жана <ph name="VM_NAME_2" /> менен бөлүшүүгө тыюу Ñалып койгон</translation>
<translation id="8663226718884576429">Буйрутма тууралуу маалымат, <ph name="TOTAL_LABEL" />, Толук маалымат</translation>
<translation id="867224526087042813">Колтамга</translation>
@@ -1944,6 +1988,7 @@
<translation id="8912362522468806198">Google аккаунту</translation>
<translation id="8913778647360618320">Төлөм ыкмаларын башкаруу баÑкычы. Chrome'дун жөндөөлөрүнө өтүп, төлөмдөрүңүздү жана наÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð¾Ñ‡ÐºÐ°Ñынын маалыматын башкаруу үчүн, Enter баÑкычын баÑыңыз</translation>
<translation id="8918231688545606538">Бул шектүү баракча</translation>
+<translation id="8922013791253848639">Бул Ñайттагы жарнамалар дайыма көрÑөтүлÑүн</translation>
<translation id="892588693504540538">Жогорку оң жагын тешүү</translation>
<translation id="8931333241327730545">Бул карточканы Google аккаунтуңузга Ñактап коеÑузбу?</translation>
<translation id="8932102934695377596">Саатыңыз артта</translation>
@@ -2015,6 +2060,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> колдоого алынбаган протоколду колдонуп жатат.</translation>
<translation id="9191834167571392248">Төмөнкү Ñол жагын тешүү</translation>
+<translation id="9199905725844810519">БаÑып чыгаруу бөгөттөлгөн</translation>
<translation id="9205078245616868884">Дайын-даректериңиз ÐºÑƒÐ¿ÑƒÑ Ñөз айкашы менен шифрленген. Шайкештирип баштоо үчүн аны киргизиңиз.</translation>
<translation id="9207861905230894330">Макала кошулбай койду.</translation>
<translation id="9213433120051936369">Көрүнүшүн ыңгайлаштыруу</translation>
@@ -2025,8 +2071,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Кимдир бирөө Google аккаунтуңузга кирип алган окшойт. Chromium ÑÑ‹Ñ€Ñөзүңүздү азыр өзгөртүүнү Ñунуштайт. Ðккаунтуңузга кайра киришиңиз керек болот.</translation>
<translation id="939736085109172342">Жаңы папка</translation>
+<translation id="945522503751344254">Пикириңизди билдириңиз</translation>
<translation id="945855313015696284">Төмөнкү маалыматты текшерип, жаракÑыз карталарды өчүрүңүз</translation>
<translation id="950736567201356821">Жогорку жагын үч жолу тешүү</translation>
+<translation id="951941430552851965">Экранда көрүнүп турган мазмунга байланыштуу андан видео жаздырып алууну админиÑтраторуңуз токтотуп койду.</translation>
<translation id="961663415146723894">Төмөн жагын байлоо</translation>
<translation id="962484866189421427">Бул мазмун башка колдонмолорго окшош жаÑалма колдонмолорду орнотуп коюшу же Ñизге көз Ñалуу үчүн дайындарды чогултуп алышы мүмкүн. <ph name="BEGIN_LINK" />Баары бир көрÑөтүлÑүн<ph name="END_LINK" /></translation>
<translation id="969892804517981540">РаÑмий курама</translation>
diff --git a/chromium/components/strings/components_strings_lo.xtb b/chromium/components/strings/components_strings_lo.xtb
index 03859bca491..78bd02fadbb 100644
--- a/chromium/components/strings/components_strings_lo.xtb
+++ b/chromium/components/strings/components_strings_lo.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ທ່ານໄດ້ປ້ອນລະຫັດຜ່ານຂອງທ່ານໃນເວັບໄຊທີ່ບà»à»ˆàº–ືàºàºˆàº±àº”àºàº²àº™à»‚ດàºàº­àº»àº‡àºàº²àº™àºˆàº±àº”ຕັ້ງຂອງທ່ານ. ເພື່ອປົàºàº›à»‰àº­àº‡àºšàº±àº™àºŠàºµàº‚ອງທ່ານ, àºàº°àº¥àº¸àº™àº²àº¢à»ˆàº²àº™àº³àº¥àº°àº«àº±àº”ຜ່ານຂອງທ່ານມາໃຊ້ໃà»à»ˆàº¢àº¹à»ˆà»ƒàº™à»àº­àº±àºš à»àº¥àº° ເວັບໄຊອື່ນ.</translation>
<translation id="1263231323834454256">ລາàºàºàº²àº™àº—ີ່ຈະອ່ານ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ àºàº²àº™à»€àº„ື່ອນໄຫວທີ່ຈະບà»à»ˆàº„ົງຢູ່ໃນອຸປະàºàº­àº™àº™àºµà»‰:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ໜ້າທີ່ທ່ານເບິ່ງໃນໜ້າຈà»àº™àºµà»‰
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº„ຸàºàºàºµà»‰ à»àº¥àº° ເວັບໄຊ
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àºšàº±àº™àºŠàºµ (<ph name="LINK_BEGIN" />ອອàºàºˆàº²àºàº¥àº°àºšàº»àºš<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ວິທີàºàº²àº™àº®àº±àºšà»€àº„ື່ອງ</translation>
<translation id="1281476433249504884">ສະà»àº•àº±àºà»€àºàºµà»‰ 1</translation>
<translation id="1285320974508926690">ຢ່າà»àº›à»€àº§àº±àºšâ€‹à»„ຊ​ທ໌ນີ້</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">ເຂົ້າສູ່ລະບົບເພື່ອໃຊ້ລະຫັດຜ່ານທີ່ບັນທຶàºà»„ວ້ໃນບັນຊີ Google ຂອງທ່ານ</translation>
<translation id="2053111141626950936">ລະບົບຈະບà»à»ˆà»àº›à»œà»‰àº²à»€àº›àº±àº™ <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">ລະ​ຫັດ​ຊິບ</translation>
+<translation id="2054665754582400095">àºàº²àº™àº™àº³à»ƒàºŠà»‰àº‚ອງທ່ານ</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ຄຳ​à»àº™àº°àº™àº³}other{# ຄຳ​à»àº™àº°àº™àº³}}</translation>
<translation id="2079545284768500474">ບà»à»ˆà»€àº®àº±àº”</translation>
<translation id="20817612488360358">àºàº²àº™àº•àº±à»‰àº‡àº„່າພຣັອàºàºŠàºµàº¥àº°àºšàº»àºšàº–ືàºàº•àº±à»‰àº‡à»ƒàº«à»‰àº–ືàºàº™à»àº²à»ƒàºŠà»‰ à»àº•à»ˆàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າພຣັອàºàºŠàºµàº—ີ່ຈະà»àºˆà»‰àº‡à»„ດ້ຖືàºàº¥àº°àºšàº¸â€‹à»àºˆà»‰àº‡àº™à»àº²àº­àºµàº.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">à»àº­àº±àºš Android</translation>
<translation id="2107021941795971877">àºàº²àº™àº®àº­àº‡àº®àº±àºšàºàº²àº™àºžàº´àº¡</translation>
<translation id="2108755909498034140">ປິດເປີດຄອມພິວເຕີຂອງທ່ານຄືນໃà»à»ˆ</translation>
+<translation id="2111166930115883695">àºàº»àº”àºàº°àº«àº§à»ˆàº²àº‡à»€àºžàº·à»ˆàº­àº«àº¼àº´à»‰àº™</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">ບັດ</translation>
<translation id="2114841414352855701">ຖືàºàº¥àº°à»€àº¥àºµàº ເພາະວ່າມັນຖືàºàº¥àº»àºšàº¥à»‰àº²àº‡à»‚ດຠ<ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">àºàº»àºà»€àº¥àºµàºàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™</translation>
<translation id="2147827593068025794">àºàº²àº™àºŠàº´à»‰àº‡àº‚à»à»‰àº¡àº¹àº™à»ƒàº™àºžàº·à»‰àº™àº«àº¼àº±àº‡</translation>
<translation id="2148613324460538318">ເພີ່ມບັດ</translation>
+<translation id="2149968176347646218">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàºšà»à»ˆàº›àº­àº”ໄພ</translation>
<translation id="2154054054215849342">àºàº²àº™àºŠàº´à»‰àº‡àº‚à»à»‰àº¡àº¹àº™àºšà»à»ˆàº¡àºµà»ƒàº«à»‰àº™àº³à»ƒàºŠà»‰àºªàº³àº¥àº±àºšà»‚ດເມນຂອງທ່ານ</translation>
<translation id="2154484045852737596">à»àºà»‰à»„ຂບັດ</translation>
<translation id="2161656808144014275">ຂà»à»‰àº„ວາມ</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">ນະ​ໂàºâ€‹àºšàº²àº</translation>
<translation id="2183608646556468874">ເບີໂທລະສັບ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ທີ່ຢູ່}other{# ທີ່ຢູ່}}</translation>
-<translation id="2187243482123994665">àºàº²àº™à»€àº„ື່ອນໄຫວນຳໃຊ້ຂອງຜູ້ໃຊ້</translation>
<translation id="2187317261103489799">àºàº§àº”ຫາ (ຄ່າເລີ່ມຕົ້ນ)</translation>
<translation id="2188375229972301266">ເຈາະຮູຢູ່ລຸ່ມສຸດຫຼາàºàº®àº¹</translation>
<translation id="2202020181578195191">ປ້ອນປີà»àº»àº”ອາàºàº¸àº—ີ່ຖືàºàº•à»‰àº­àº‡</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">ລະວັງເວັບໄຊປອມ</translation>
<translation id="2850739647070081192">Invite (ຊອງຈົດà»àº²àº)</translation>
<translation id="2856444702002559011">ຜູ້ໂຈມຕີອາດຈະàºàº³àº¥àº±àº‡àºžàº°àºàº²àºàº²àº¡àº¥àº±àºà»€àº­àº»àº²àº‚à»à»‰àº¡àº¹àº™àº‚ອງທ່ານຈາຠ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ຕົວຢ່າງ: ລະຫັດຜ່ານ, ຂà»à»‰àº„ວາມ ຫຼື ບັດເຄຣດິດ). <ph name="BEGIN_LEARN_MORE_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ເວັບໄຊນີ້ສະà»àº”ງໂຄສະນາທີ່ລົບàºàº§àº™ ຫຼື ຫຼອàºàº¥àº§àº‡.</translation>
<translation id="2878197950673342043">ພັບà»àºšàºšà»‚ປສເຕີ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ຕຳà»à»œà»ˆàº‡à»œà»‰àº²àºˆà»</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">àºàº²àº™à»àº™àº°àº™àº³à»‚ດຠGoogle</translation>
<translation id="3002501248619246229">àºàº§àº”ສອບສື່ຂອງຖາດເຈ້àºà»€àº‚ົ້າ</translation>
<translation id="3005723025932146533">ສະà»àº”ງສà»àº²à»€àº™àº»àº²àº—ີ່ບັນທຶàºà»„ວ້</translation>
-<translation id="3007719053326478567">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານບລັອàºàºàº²àº™àºžàº´àº¡à»€àº™àº·à»‰àº­àº«àº²àº™àºµà»‰</translation>
<translation id="3008447029300691911">ປ້ອນ CVC ສຳລັບ <ph name="CREDIT_CARD" />. ເມື່ອທ່ານຢືນຢັນ, ລາàºàº¥àº°àº­àº½àº”ບັດຂອງທ່ານຈະຖືàºà»àºšà»ˆàº‡àº›àº±àº™àºàº±àºšà»€àº§àº±àºšà»„ຊນີ້.</translation>
<translation id="3010559122411665027">àºàº²àº™àº›à»‰àº­àº™à»€àº‚ົ້າລາàºàºŠàº·à»ˆ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ບລັອàºàº­àº±àº”ຕະໂນມັດà»àº¥à»‰àº§</translation>
<translation id="3016780570757425217">ຮູ້​ຈັàºâ€‹àºªàº°â€‹àº–ານ​ທີ່​ຂອງ​ທ່ານ</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™ Enter ເພື່ອລຶບàºàº²àº™à»àº™àº°àº™àº³àº­àº­àº.</translation>
<translation id="3023071826883856138">You4 (ຊອງຈົດà»àº²àº)</translation>
<translation id="3024663005179499861">ປະເພດນະໂàºàºšàº²àºàºœàº´àº”ພາດ</translation>
<translation id="3037605927509011580">ອ່າ, ຖ່າàºàº®àº¹àºš!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">ໃສ່ບຸàºâ€‹àº¡àº²àºâ€‹à»Œâ€‹à»àº¥à»‰àº§</translation>
<translation id="3209034400446768650">ໜ້າອາດຈະຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™</translation>
<translation id="3212581601480735796">àºàº³àº¥àº±àº‡àº¡àºµàºàº²àº™àº•àº´àº”ຕາມເບິ່ງàºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານໃນ <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">ປິດໜ້າຈà»à»àº‚àºàº—ັງà»àº»àº”ເພື່ອໃຫ້àºàº²àº™à»€àº„ື່ອນໄຫວທ່ອງເວັບຂອງທ່ານຖືàºàº¥àº¶àºšàº­àº­àºàºˆàº²àºàº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰.</translation>
<translation id="3215092763954878852">ບà»à»ˆàºªàº²àº¡àº²àº”ໃຊ້ WebAuthn ໄດ້</translation>
<translation id="3218181027817787318">àºàº²àº”ພີ່ນ້ອງ</translation>
<translation id="3225919329040284222">ເຊີບເວີໄດ້ນà»àº²àºªàº°à»€à»œàºµà»ƒàºšàº¢àº±à»‰àº‡àº¢àº·àº™àº—ີ່ບà»à»ˆàºàº»àº‡àºàº±àºšàºªàº´à»ˆàº‡àº„າດຫວັງທີ່àºàº±àº‡à»„ວ້ຢູ່ໃນ. ສິ່ງຄາດຫວັງເຫຼົ່ານີ້ຖືàºà»€àº­àº»àº²àº¥àº§àº¡à»„ວ້ໃຫ້àºàº±àºšà»€àº§àº±àºšà»„ຊທ໌ຄວາມປອດໄພສູງ, ສະເພາະ ເພື່ອປົàºàº›à»‰àº­àº‡àº—່ານ.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">ອຸປະàºàº­àº™ Bluetooth</translation>
<translation id="3787705759683870569">à»àº»àº”ອາàºàº¸ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ຂະໜາດ 16</translation>
+<translation id="3789841737615482174">​ຕິດ​ຕັ້ງ</translation>
<translation id="3793574014653384240">ຈຳນວນ à»àº¥àº° ສາເຫດຂອງàºàº²àº™àº‚ັດຂ້ອງທີ່ເàºàºµàº”ຂຶ້ນເມື່ອບà»à»ˆàº”ົນມານີ້</translation>
<translation id="3797522431967816232">Prc3 (ຊອງຈົດà»àº²àº)</translation>
<translation id="3799805948399000906">ຂà»àºŸàº­àº™à»àº¥à»‰àº§</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">ສີນà»à»‰àº²àº•àº²àº™àº”à»àº²</translation>
<translation id="4058922952496707368">ປຸ່ມ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ຊອງຈົດà»àº²àº)</translation>
+<translation id="4067669230157909013">ສືບຕà»à»ˆàºàº²àº™àº–່າàºàº®àº¹àºšà»œà»‰àº²àºˆà»à»àº¥à»‰àº§.</translation>
<translation id="4067947977115446013">ເພີ່ມທີ່ຢູ່ທີ່ຖືàºàº•à»‰àº­àº‡</translation>
<translation id="4072486802667267160">ມີຄວາມຜິດພາດໃນàºàº²àº™àº”ຳເນີນຄຳສັ່ງຊື້ຂອງທ່ານ, àºàº°àº¥àº¸àº™àº²àº¥àº­àº‡àº­àºµàºàº„ັ້ງ.</translation>
<translation id="4075732493274867456">ລູàºàº‚່າຠà»àº¥àº° ເຊີບເວີບà»à»ˆàº®àº­àº‡àº®àº±àºšà»€àº§àºµàºŠàº±àº™à»‚ປຣໂຕຄ໠ຫຼື ຊຸດລະຫັດລັບ SSL ທົ່ວໄປ.</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">ຮູບຕົວຢ່າງສຳລັບໜ້າ <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">ຂະ​ຫàºàº²àº</translation>
<translation id="4300675098767811073">ເຈາະຮູເບື້ອງຂວາຫຼາàºàº®àº¹</translation>
+<translation id="4302514097724775343">à»àº•àº° dino ເພື່ອຫຼິ້ນ</translation>
<translation id="4302965934281694568">Chou3 (ຊອງຈົດà»àº²àº)</translation>
<translation id="4305666528087210886">ບà»à»ˆàºªàº²àº¡àº²àº”ເຂົ້າເຖິງໄຟລ໌ຂອງທ່ານໄດ້</translation>
<translation id="4305817255990598646">ປ່ຽນ</translation>
@@ -915,6 +930,7 @@
<translation id="4658638640878098064">ໜີບàºàº°àº«àº¼àº±àºšà»€àºŸàºµàº¢àº¹à»ˆà»€àº—ິງສຸດເບື້ອງຊ້າàº</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ເວີຊົວ ຣິອາຣິທີ</translation>
+<translation id="4675657451653251260">ທ່ານຈະບà»à»ˆà»€àº«àº±àº™àº‚à»à»‰àº¡àº¹àº™à»‚ປຣໄຟລ໌ Chrome ໃດໆໃນໂà»àº”à»àº‚àº. ທ່ານສາມາດ <ph name="LINK_BEGIN" />ເຂົ້າສູ່ລະບົບ<ph name="LINK_END" /> ເພື່ອເຂົ້າເຖິງຂà»à»‰àº¡àº¹àº™àºšàº±àº™àºŠàºµ Google ຂອງທ່ານ ເຊັ່ນ: ລະຫັດຜ່ານ à»àº¥àº° ວິທີàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™à»„ດ້.</translation>
<translation id="467662567472608290">ເຊີບເວີນີ້ບà»à»ˆàºªàº²àº¡àº²àº”ພິສູດໄດ້ວ່າ ມັນà»àº¡à»ˆàº™ <ph name="DOMAIN" />; ໃບຢັ້ງຢືນຄວາມປອດໄພຂອງມັນມີຄວາມຜິດພາດ. ອັນນີ້ອາດຈະເຮັດໃຫ້ເàºàºµàº”ມີàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າຜິດ ຫຼືຜູ້ໂຈມຕີອາດຈະດັàºà»€àº­àº»àº²àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານ.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ຕ້ອງàºàº²àº™àº•àº­àºšàºªàº°à»œàº­àº‡àºàº±àºšà»€àº«àº”àºàº²àº™àºŠà»ˆàº§àºà»€àº‚ົ້າເຖິງ</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">ໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ</translation>
<translation id="4764776831041365478">ໜ້າເວັບຢູ່ທີ່ <ph name="URL" /> ອາດຈະໃຊ້ບà»à»ˆà»„ດ້ຊົ່ວຄາວ ຫຼືມັນອາດຈະໄດ້àºà»‰àº²àºàº­àº­àºà»„ປໃສ່ທີ່ຢູ່ເວັບໃà»à»ˆàº–າວອນà»àº¥à»‰àº§.</translation>
<translation id="4766713847338118463">ໜີບàºàº°àº«àº¼àº±àºšà»€àºŸàºµàº¢àº¹à»ˆàº¥àº¸à»ˆàº¡àºªàº¸àº”ສອງເທື່ອ</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ àºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານທີ່ຈະàºàº±àº‡àº„ົງຢູ່ໃນອຸປະàºàº­àº™àº™àºµà»‰:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ໄຟລ໌ຕ່າງໆທີ່ທ່ານດາວໂຫຼດໃນໜ້າຈà»àº™àºµà»‰
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ເàºàºµàº”ຄວາມຜິດພາດທີ່ບà»à»ˆàº®àº¹à»‰àºˆàº±àº.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ບລັອàºàº›àº±àº­àºšàº­àº±àºšà»àº¥à»‰àº§}other{ບລັອຠ# ປັອບອັບà»àº¥à»‰àº§}}</translation>
<translation id="4780366598804516005">àºà»ˆàº­àº‡àºˆàº»àº”à»àº²àº 1</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">ຕ່ອງໂສ້ໃບຮັບຮອງສຳລັບເວັບໄຊນີ້ປະàºàº­àºšàº¡àºµà»ƒàºšàº®àº±àºšàº®àº­àº‡àº—ີ່ເຊັນຊື່ໂດàºà»ƒàºŠà»‰ SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">ຫàºàº´àºšàº‚ອບເບື້ອງຂວາ</translation>
+<translation id="5398772614898833570">ບລັອàºà»‚ຄສະນາໄວ້à»àº¥à»‰àº§</translation>
<translation id="5400836586163650660">ສີເທົາ</translation>
<translation id="540969355065856584">ເຊີບເວີນີ້ບà»à»ˆàºªàº²àº¡àº²àº”ພິສູດໄດ້ວ່າ ມັນà»àº¡à»ˆàº™ <ph name="DOMAIN" />; ໃບຢັ້ງຢືນຄວາມປອດໄພຂອງມັນໃຊ້​ບà»à»ˆâ€‹à»„ດ້​ໃນ​ເວ​ລາ​ນີ້. ອັນນີ້ອາດຈະເຮັດໃຫ້ເàºàºµàº”ມີàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າຜິດ ຫຼືຜູ້ໂຈມຕີອາດຈະດັàºà»€àº­àº»àº²àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານ.</translation>
<translation id="541416427766103491">ສະà»àº•àº±àºà»€àºàºµà»‰ 4</translation>
<translation id="5421136146218899937">ລຶບຂà»à»‰àº¡àº¹àº™àºàº²àº™àº—່ອງເນັດ...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ຕ້ອງàºàº²àº™àºªàº»à»ˆàº‡àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™à»ƒàº«à»‰àº—່ານ</translation>
+<translation id="542872847390508405">ທ່ານàºà»àº²àº¥àº±àº‡àº—່ອງເວັບໃນຖານະເປັນà»àº‚àº</translation>
<translation id="5430298929874300616">ເອົາບຸàºàº¡àº²àºàº„໌ອອàºà»„ປ</translation>
<translation id="5439770059721715174">àºàº²àº™àº®àº±àºšàº®àº­àº‡àº®àº¹àºšà»àºšàºšàºœàº´àº”ພາດຢູ່ທີ່ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ລຳດັບàºà»‰àº­àº™àºàº±àºšàº›àºµà»‰àº™à»œà»‰àº²àº‚ຶ້ນ</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">ບà»à»ˆàºªàº²àº¡àº²àº”ຮັບເອົາເຄື່ອງຈາàºàº—ີ່ຢູ່ນີ້ໄດ້. ເລືອàºàº—ີ່ຢູ່ອື່ນ.</translation>
<translation id="5580958916614886209">àºàº§àº”ເບິ່ງເດືອນà»àº»àº”ອາàºàº¸àº‚ອງທ່ານ à»àº¥àº° ລອງອີàºàº„ັ້ງ</translation>
<translation id="5586446728396275693">ບà»à»ˆàº¡àºµàº—ີ່ຢູ່ທີ່ບັນທຶàºà»„ວ້</translation>
+<translation id="5593349413089863479">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàºšà»à»ˆàº›àº­àº”ໄພສົມບູນ</translation>
<translation id="5595485650161345191">à»àºà»‰à»„ຂທີ່ຢູ່</translation>
<translation id="5598944008576757369">ເລືອàºàº§àº´àº—ີàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™</translation>
<translation id="560412284261940334">àºàº²àº™àºˆàº±àº”àºàº²àº™àºšà»à»ˆà»„ດ້ຮັບàºàº²àº™àº®àº­àº‡àº®àº±àºš</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ເວັບໄຊນີ້ອາດເປັນເວັບໄຊປອມ ຫຼື ສà»à»‰à»‚àºàº‡. Chrome à»àº™àº°àº™àº³à»ƒàº«à»‰àº­àº­àºàº”ຽວນີ້.</translation>
<translation id="5610142619324316209">àºàº³àº¥àº±àº‡àºàº§àº”ເບິ່ງàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆ</translation>
<translation id="5610807607761827392">ທ່ານສາມາດຈັດàºàº²àº™àºšàº±àº” à»àº¥àº° ທີ່ຢູ່ໄດ້ໃນ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">à»àº›à»œà»‰àº²àº™àºµà»‰àº”້ວຠGoogle à»àº›àºžàº²àºªàº²</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">ສີ​ເຫຼືອງ</translation>
<translation id="5905445707201418379">ບລັອàºà»„ວ້ຕາມນະໂàºàºšàº²àºàº•àº»à»‰àº™àº—າງຂອງ <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ຊິ້ງຂà»à»‰àº¡àº¹àº™à»àº¥à»‰àº§)</translation>
+<translation id="5913377024445952699">ຢຸດàºàº²àº™àº–່າàºàº®àº¹àºšà»œà»‰àº²àºˆà»à»„ວ້ຊົ່ວຄາວà»àº¥à»‰àº§</translation>
<translation id="59174027418879706">ເປີດໃຊ້ງານà»àº¥à»‰àº§</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ເປີດ</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">ຕອນ</translation>
<translation id="5967592137238574583">à»àºà»‰à»„ຂຂà»à»‰àº¡àº¹àº™àº•àº´àº”ຕà»à»ˆ</translation>
<translation id="5967867314010545767">ເອົາ​ອອàºàºˆàº²àºâ€‹àº›àº°â€‹àº«àº§àº±àº”</translation>
+<translation id="5968793460449681917">ໃນà»àº•à»ˆàº¥àº°àº„ັ້ງທີ່ເຂົ້າເບິ່ງ</translation>
<translation id="5975083100439434680">ຊູມອອàº</translation>
<translation id="5979084224081478209">àºàº§àº”ເບິ່ງລະຫັດຜ່ານ</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">ລິ້ງທີ່ທ່ານສຳເນົາ</translation>
<translation id="6591833882275308647">ບà»à»ˆàº¡àºµàºàº²àº™àºˆàº±àº”àºàº²àº™ <ph name="DEVICE_TYPE" /> ຂອງທ່ານ</translation>
<translation id="6596325263575161958">ທາງເລືອàºàºàº²àº™à»ƒàºªà»ˆàº¥àº°àº«àº±àº”</translation>
+<translation id="6596892391065203054">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານບລັອàºàºàº²àº™àºžàº´àº¡à»€àº™àº·à»‰àº­àº«àº²àº™àºµà»‰.</translation>
<translation id="6604181099783169992">ເຊັນເຊີàºàº§àº”ຈັບàºàº²àº™à»€àº„ື່ອນໄຫວ ຫຼື à»àºªàº‡</translation>
<translation id="6609880536175561541">Prc7 (ຊອງຈົດà»àº²àº)</translation>
<translation id="6612358246767739896">ເນື້ອ​ໃນ​ທີ່ຖືàºâ€‹àº›àº»àºâ€‹àº›à»‰àº­àº‡</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">ຢືນຢັນບັດຂອງທ່ານà»àº¥à»‰àº§</translation>
<translation id="6897140037006041989">ຕົວà»àº—ນຜູ້ໃຊ້</translation>
<translation id="6898699227549475383">ອົງàºàº²àº™àºˆàº±àº”ຕັ້ງ (O)</translation>
+<translation id="6907293445143367439">ອະນຸàºàº²àº”ໃຫ້ <ph name="SITE_NAME" /> ສາມາດ:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ຕ້ອງàºàº²àº™à»„ດ້ຮັບàºàº²àº™àº„ວບຄຸມເຕັມຕà»à»ˆàºàº±àºšàº­àº¸àº›àº°àºàº­àº™ MIDI ຂອງທ່ານ</translation>
<translation id="6915804003454593391">ຜູ້​ໃຊ້​:</translation>
<translation id="6934672428414710184">ຊື່ນີ້ມາຈາàºàºšàº±àº™àºŠàºµ Google ຂອງທ່ານ</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">ເຊື່ອມໂàºàº‡:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">à»àº–ວຄà»àº²àºªàº±à»ˆàº‡</translation>
+<translation id="7359588939039777303">ບລັອàºà»‚ຄສະນາໄວ້à»àº¥à»‰àº§.</translation>
<translation id="7372973238305370288">ຜົນ​àºàº²àº™àº„ົ້ນ​ຫາ</translation>
<translation id="7374733840632556089">ບັນຫານີ້ເàºàºµàº”ຂຶ້ນເນື່ອງຈາàºà»ƒàºšàº®àº±àºšàº®àº­àº‡àº—ີ່ທ່ານ ຫຼື ຄົນອື່ນຕິດຕັ້ງໃນອຸປະàºàº­àº™àº‚ອງທ່ານ. ເປັນທີ່ຮູ້àºàº±àº™àº§à»ˆàº²à»ƒàºšàº®àº±àºšàº®àº­àº‡àº™àºµà»‰àº–ືàºà»ƒàºŠà»‰à»€àºžàº·à»ˆàº­àº•àº´àº”ຕາມ à»àº¥àº° ສະàºàº±àº”àºàº±à»‰àº™à»€àº„ືອຂ່າຠà»àº¥àº° Chrome ບà»à»ˆà»€àºŠàº·à»ˆàº­àº–ືໃບຮັບຮອງນີ້. ເຖິງà»àº¡à»ˆàº™àº§à»ˆàº²àºˆàº°àº¡àºµàºšàº²àº‡àºà»àº¥àº°àº™àºµàº—ີ່àºàº²àº™àº•àº´àº”ຕາມອາດຈະຖືàºàºàº»àº”à»àº²àº ເຊັ່ນ: ໃນເຄືອຂ່າàºàº‚ອງໂຮງຮຽນ ຫຼື ບà»àº¥àº´àºªàº±àº”, à»àº•à»ˆ Chrome àºà»àºàº±àº‡àº•à»‰àº­àº‡àºàº²àº™à»ƒàº«à»‰à»àº™à»ˆà»ƒàºˆàº§à»ˆàº²àº—່ານຮັບຮູ້ວ່າມີàºàº²àº™àº•àº´àº”ຕາມເບິ່ງ ເຖິງà»àº¡à»ˆàº™àº§à»ˆàº²àº—່ານບà»à»ˆàºªàº²àº¡àº²àº”ຢຸດມັນໄດ້àºà»àº•àº²àº¡. àºàº²àº™àº•àº´àº”ຕາມອາດຈະເàºàºµàº”ຂຶ້ນໃນໂປຣà»àºàº£àº¡àº—່ອງເວັບ ຫຼື à»àº­àº±àºšàºžàº¥àº´à»€àº„ຊັນໃດໆàºà»àº•àº²àº¡àº—ີ່ເຂົ້າເຖິງເວັບໄຊໄດ້.</translation>
<translation id="7375818412732305729">à»àº™àºšà»„ຟລ໌à»àº¥à»‰àº§</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">ມີàºàº²àº™àº®à»‰àº­àº‡àº‚à»àº«àº¼àº²àºà»€àºàºµàº™à»„ປ</translation>
<translation id="7977538094055660992">ອຸປະàºàº­àº™à»€àºˆà»‰àºàº­àº­àº</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ເພື່ອເບິ່ງເນື້ອຫາອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ, àºàº°àº¥àº¸àº™àº²àº•àº´àº”ຕັ້ງ ARCore àºà»ˆàº­àº™</translation>
<translation id="799149739215780103">ຫບິບເຫຼັ້ມ</translation>
<translation id="7995512525968007366">ບà»à»ˆâ€‹à»„ດ້ລະ​ບຸ</translation>
<translation id="800218591365569300">ລອງປິດà»àº–ບ ຫຼື ໂປຣà»àºàº£àº¡àº­àº·à»ˆàº™à»€àºžàº·à»ˆàº­àº‚ະຫàºàº²àºàº„ວາມຈຳ.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">à»àº–ວຄà»àº²àºªàº±à»ˆàº‡</translation>
<translation id="8508648098325802031">ໄອຄອນຊອàºàº«àº²</translation>
<translation id="8522552481199248698">Chrome ສາມາດຊ່ວàºàº—່ານປົàºàº›à»‰àº­àº‡àºšàº±àº™àºŠàºµ Google ຂອງທ່ານ à»àº¥àº° ປ່ຽນລະຫັດຜ່ານຂອງທ່ານໄດ້.</translation>
+<translation id="8525306231823319788">ເຕັມຫນ້າ​ຈà»â€‹</translation>
<translation id="8530813470445476232">ລຶບລ້າງປະຫວັດàºàº²àº™àº—່ອງເວັບ, ຄຸàºàºàºµà»‰, à»àº„ສ à»àº¥àº° ອື່ນໆອີàºà»ƒàº™àºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="8533619373899488139">ເຂົ້າຫາ &lt;strong&gt;chrome://policy&lt;/strong&gt; ເພື່ອເບິ່ງລາàºàºŠàº·à»ˆàº‚ອງ URL ທີ່ຖືàºàºšàº¥àº±àº­àºà»„ວ້ à»àº¥àº° ນະໂàºàºšàº²àºàº­àº·à»ˆàº™àº—ີ່ຜູ້ຄວບຄຸມລະບົບຂອງທ່ານບັງຄັບໃຊ້.</translation>
<translation id="8541158209346794904">ອຸປະàºàº­àº™ Bluetooth</translation>
<translation id="8542014550340843547">ໜີບàºàº°àº«àº¼àº±àºšà»€àºŸàºµàº¢àº¹à»ˆàº¥àº¸à»ˆàº¡àºªàº¸àº”ສາມເທື່ອ</translation>
<translation id="8543181531796978784">ທ່ານ​ສາ​ມາດ​ <ph name="BEGIN_ERROR_LINK" />ລາàºâ€‹àº‡àº²àº™â€‹àºšàº±àº™â€‹àº«àº²â€‹àº—ີ່àºàº§àº”​ພົບ​ໄດ້<ph name="END_ERROR_LINK" /> ຫຼື, ຖ້າທ່ານເຂົ້າໃຈຄວາມສ່ຽງຕà»à»ˆàº„ວາມປອດໄພຂອງທ່ານ, <ph name="BEGIN_LINK" />ເຂົ້າ​ເບິ່ງ​ເວັບ​ໄຊ​ທ໌​ທີ່​ບà»à»ˆâ€‹àº›àº­àº”​ໄພ​ນີ້<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">ມີ CVC ຢູ່ຫຼັງບັດຂອງທ່ານ.</translation>
+<translation id="8558485628462305855">ເພື່ອເບິ່ງເນື້ອຫາອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ, àºàº°àº¥àº¸àº™àº²àº­àº±àºšà»€àº”ດ ARCore</translation>
<translation id="8559762987265718583">ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”​ຕັ້ງ​àºàº²àº™â€‹à»€àºŠàº·à»ˆàº­àº¡â€‹àº•à»à»ˆâ€‹àºªà»ˆàº§àº™â€‹àº•àº»àº§â€‹àºàº±àºš <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ໄດ້ ເພາະ​ວ່າ​ວັນ​ທີ à»àº¥àº°â€‹à»€àº§â€‹àº¥àº²â€‹àº­àº¸â€‹àº›àº°â€‹àºàº­àº™â€‹àº‚ອງ​ທ່ານ (<ph name="DATE_AND_TIME" />) ບà»à»ˆâ€‹àº–ືàºâ€‹àº•à»‰àº­àº‡.</translation>
<translation id="8564182942834072828">ເອàºàº°àºªàº²àº™à»àºàºàºàº±àº™/ບà»à»ˆà»„ດ້ຈັດຊຸດສຳເນົາ</translation>
<translation id="8564985650692024650">Chromium à»àº™àº°àº™àº³à»ƒàº«à»‰àº£àºµà»€àºŠàº±àº”ລະຫັດຜ່ານ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ຂອງທ່ານ ຖ້າທ່ານນຳມັນມາໃຊ້ໃà»à»ˆà»ƒàº™à»€àº§àº±àºšà»„ຊອື່ນ.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ àºàº²àº™à»€àº„ື່ອນໄຫວທີ່ຈະບà»à»ˆàº„ົງຢູ່ໃນອຸປະàºàº­àº™àº™àºµà»‰:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ໜ້າທີ່ທ່ານເບິ່ງໃນໜ້າຈà»àº™àºµà»‰
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº„ຸàºàºàºµà»‰ à»àº¥àº° ເວັບໄຊ
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ໃຊ້ Touch ID ເພື່ອຢືນຢັນບັດໄດ້ໄວຂຶ້ນ</translation>
<translation id="858637041960032120">ເພີ່ມ​ເບີໂທລະ​ສັບ</translation>
<translation id="8589998999637048520">ຄຸນນະພາບດີສຸດ</translation>
+<translation id="8600271352425265729">ອະນຸàºàº²àº”ສະເພາະເທື່ອນີ້</translation>
<translation id="860043288473659153">ຊື່ຜູ້ຖືບັດ</translation>
<translation id="8606726445206553943">ໃຊ້​ອຸ​ປະ​àºàº­àº™â€‹ MIDI ຂອງ​ທ່ານ</translation>
+<translation id="8612761427948161954">ສະບາàºàº”ີ <ph name="USERNAME" />,
+ <ph name="BR" />
+ ທ່ານàºàº³àº¥àº±àº‡àº—່ອງເວັບເປັນà»àº‚àºàº¢àº¹à»ˆ</translation>
<translation id="861775596732816396">ຂະໜາດ 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ບà»à»ˆàº¡àºµàº¥àº°àº«àº±àº”ຜ່ານທີ່àºàº»àº‡àºàº±àº™. ສະà»àº”ງລະຫັດຜ່ານທີ່ບັນທຶàºà»„ວ້ທັງà»àº»àº”.</translation>
<translation id="8625384913736129811">ບັນທຶàºàºšàº±àº”ນີ້ໃສ່ອຸປະàºàº­àº™àº™àºµà»‰</translation>
+<translation id="8627040765059109009">ສືບຕà»à»ˆàºàº²àº™àº–່າàºàº®àº¹àºšà»œà»‰àº²àºˆà»à»àº¥à»‰àº§</translation>
<translation id="8657078576661269990">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານໄດ້ບລັອàºàºàº²àº™à»àºšà»ˆàº‡àº›àº±àº™àºˆàº²àº <ph name="ORIGIN_NAME" /> ຫາ <ph name="VM_NAME_1" /> à»àº¥àº° <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">ສັງຮວມຄຳສັ່ງຊື້, <ph name="TOTAL_LABEL" />, ລາàºàº¥àº°àº­àº½àº”ເພີ່ມເຕີມ</translation>
<translation id="867224526087042813">ລາàºà»€àºŠàº±àº™</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">ບັນຊີ Google</translation>
<translation id="8913778647360618320">ປຸ່ມຈັດàºàº²àº™àº§àº´àº—ີàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™, àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™àºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™àºšàº±àº”ເຄຣດິດໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="8918231688545606538">ໜ້ານີ້ໜ້າສົງໄສ</translation>
+<translation id="8922013791253848639">ອະນຸàºàº²àº”ໂຄສະນາໃນເວັບໄຊນີ້ທຸàºà»€àº—ື່ອ</translation>
<translation id="892588693504540538">ເຈາະຮູເທິງສຸດເບື້ອງຊ້າàº</translation>
<translation id="8931333241327730545">ທ່ານຕ້ອງàºàº²àº™àºšàº±àº™àº—ຶàºàºšàº±àº”ນີ້ໃສ່ບັນຊີ Google ຂອງທ່ານບà»?</translation>
<translation id="8932102934695377596">ໂມງ​ຂອງ​ທ່ານ​ຊ້າ</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ໃຊ້ໂປຣໂຕຄà»àº—ີ່ບà»à»ˆàº–ືàºàº®àº­àº‡àº®àº±àºš.</translation>
<translation id="9191834167571392248">ເຈາະຮູຢູ່ລຸ່ມສຸດເບື້ອງຊ້າàº</translation>
+<translation id="9199905725844810519">ມີàºàº²àº™àºšàº¥àº±àº­àºàºàº²àº™àºžàº´àº¡à»„ວ້</translation>
<translation id="9205078245616868884">ຂà»à»‰àº¡àº¹àº™àº‚ອງທ່ານຖືàºà»€àº‚ົ້າລະຫັດໄວ້ດ້ວàºàº§àº°àº¥àºµàºœà»ˆàº²àº™àºàº²àº™àºŠàº´à»‰àº‡àº‚ອງທ່ານ. ໃຫ້ປ້ອນມັນເພື່ອເລີ່ມàºàº²àº™àºŠàº´à»‰àº‡àº‚à»à»‰àº¡àº¹àº™.</translation>
<translation id="9207861905230894330">ເພີ່ມບົດຄວາມບà»à»ˆàºªà»àº²à»€àº¥àº±àº”.</translation>
<translation id="9213433120051936369">ປັບà»àº•à»ˆàº‡àº®àº¹àºšàº®à»ˆàº²àº‡àº¥àº±àºàºªàº°àº™àº°</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">ທ່ານອາດສູນເສàºàºªàº´àº”ເຂົ້າເຖິງບັນຊີ Google ຂອງທ່ານໄດ້. Chromium à»àº™àº°àº™àº³à»ƒàº«à»‰àº›à»ˆàº½àº™àº¥àº°àº«àº±àº”ຜ່ານຕອນນີ້ເລີàº. ທ່ານຈະຖືàºàº®à»‰àº­àº‡àº‚à»à»ƒàº«à»‰à»€àº‚ົ້າສູ່ລະບົບ.</translation>
<translation id="939736085109172342">ໂຟລເດີ​ໃຫມ່</translation>
+<translation id="945522503751344254">ສົ່ງ​ຄà»àº²â€‹àº„ິດ​​ເຫັນ</translation>
<translation id="945855313015696284">àºàº§àº”ເບິ່ງຂà»à»‰àº¡àº¹àº™àº‚້າງລຸ່ມ à»àº¥àº° ລຶບບັດທີ່ໃຊ້ບà»à»ˆà»„ດ້ຕ່າງໆ</translation>
<translation id="950736567201356821">ເຈາະຮູຢູ່ເທິງສຸດສາມຮູ</translation>
+<translation id="951941430552851965">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານໄດ້ຢຸດàºàº²àº™àº–່າàºàº®àº¹àºšà»œà»‰àº²àºˆà»à»„ວ້ຊົ່ວຄາວເນື່ອງຈາàºà»€àº™àº·à»‰àº­àº«àº²à»ƒàº™à»œà»‰àº²àºˆà»àº‚ອງທ່ານ.</translation>
<translation id="961663415146723894">ຫàºàº´àºšà»€àº«àº¼àº±à»‰àº¡àº¥àº¸à»ˆàº¡àºªàº¸àº”</translation>
<translation id="962484866189421427">ເນື້ອຫານີ້ອາດຈະພະàºàº²àºàº²àº¡àº•àº´àº”ຕັ້ງà»àº­àº±àºšàº«àº¼àº­àºàº¥àº§àº‡àº—ີ່ປອມເປັນສິ່ງອື່ນ ຫຼື ເàºàº±àºšàºàº³àº‚à»à»‰àº¡àº¹àº™àº—ີ່ອາດຈະຖືàºà»ƒàºŠà»‰à»€àºžàº·à»ˆàº­àº•àº´àº”ຕາມທ່ານ. <ph name="BEGIN_LINK" />ຢືນຢັນàºàº²àº™àºªàº°à»àº”ງ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ສ້າງເປັນທາງàºàº²àº™</translation>
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index 8e958281736..8843e611c17 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -80,6 +80,14 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Įvedėte slaptažodį svetainėje, kurios netvarko jūsų organizacija. Kad apsaugotumėte paskyrą, nenaudokite to paties slaptažodžio kitose programose ir svetainėse.</translation>
<translation id="1263231323834454256">Skaitymo sąrašas</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Šiame įrenginyje neišsaugoma veikla:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />šiame lange peržiūrimi puslapiai;
+ <ph name="LIST_ITEM" />slapukai ir svetainÄ—s duomenys;
+ <ph name="LIST_ITEM" />paskyros informacija (<ph name="LINK_BEGIN" />atsijungti<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">PaÄ—mimo metodas</translation>
<translation id="1281476433249504884">1 dÄ—tuvÄ—</translation>
<translation id="1285320974508926690">Niekada neversti Å¡ios svetainÄ—s</translation>
@@ -283,6 +291,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="204357726431741734">Prisijunkite, kad galėtumėte naudoti „Google“ paskyroje išsaugotus slaptažodžius</translation>
<translation id="2053111141626950936">Puslapiai, paraÅ¡yti <ph name="LANGUAGE" />, verÄiami nebus.</translation>
<translation id="2053553514270667976">Pašto kodas</translation>
+<translation id="2054665754582400095">Jūsų veiklos duomenys</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 pasiūlymas}one{# pasiūlymas}few{# pasiūlymai}many{# pasiūlymo}other{# pasiūlymų}}</translation>
<translation id="2079545284768500474">Anuliuoti</translation>
<translation id="20817612488360358">Sistemos įgaliotojo serverio nustatymai nustatyti kaip naudotini, bet taip pat nurodyta tiksli įgaliotojo serverio konfigūracija.</translation>
@@ -296,6 +305,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2102495993840063010">„Android“ programos</translation>
<translation id="2107021941795971877">Spausdinimo atraminės struktūros</translation>
<translation id="2108755909498034140">Iš naujo paleiskite kompiuterį</translation>
+<translation id="2111166930115883695">Paleiskite paspaudę tarpo klavišą</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">KortelÄ—</translation>
<translation id="2114841414352855701">Nepaisoma, nes buvo pakeista taikant „<ph name="POLICY_NAME" />“.</translation>
@@ -307,6 +317,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="214556005048008348">Atšaukti mokėjimą</translation>
<translation id="2147827593068025794">Fono sinchronizavimas</translation>
<translation id="2148613324460538318">PridÄ—ti kortelÄ™</translation>
+<translation id="2149968176347646218">Ryšys nėra saugus</translation>
<translation id="2154054054215849342">Sinchronizavimo paslauga nepasiekiama jūsų domenui</translation>
<translation id="2154484045852737596">KortelÄ—s informacijos redagavimas</translation>
<translation id="2161656808144014275">Tekstas</translation>
@@ -317,7 +328,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2181821976797666341">Politika</translation>
<translation id="2183608646556468874">Telefono numeris</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresas}one{# adresas}few{# adresai}many{# adreso}other{# adresų}}</translation>
-<translation id="2187243482123994665">Naudotojo buvimas</translation>
<translation id="2187317261103489799">Aptikti (numatytoji parinktis)</translation>
<translation id="2188375229972301266">Kelios skylÄ—s apaÄioje</translation>
<translation id="2202020181578195191">Įveskite tinkamus galiojimo laiko pabaigos metus</translation>
@@ -470,6 +480,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2839501879576190149">Ketinate apsilankyti netikroje svetainÄ—je</translation>
<translation id="2850739647070081192">„Invite“ (vokas)</translation>
<translation id="2856444702002559011">Užpuolikai gali bandyti pavogti jūsų informaciją iš <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (pvz., slaptažodžius, pranešimus ar kredito kortelių duomenis). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Å ioje svetainÄ—je rodomi nepageidaujami arba klaidinantys skelbimai.</translation>
<translation id="2878197950673342043">Perlenkimas į keturias dalis</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Lango padÄ—ties nustatymas</translation>
@@ -508,11 +519,11 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2996674880327704673">„Google“ pasiūlymai</translation>
<translation id="3002501248619246229">Patikrinkite įvesties dėklo mediją</translation>
<translation id="3005723025932146533">Rodyti išsaugotą kopiją</translation>
-<translation id="3007719053326478567">Administratorius užblokavo galimybę spausdinti šį turinį</translation>
<translation id="3008447029300691911">Įveskite „<ph name="CREDIT_CARD" />“ kortelės saugos kodą (CVC). Kai patvirtinsite, išsami kortelės informacija bus bendrinama su šia svetaine.</translation>
<translation id="3010559122411665027">Sąrašo įrašas „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatiškai užblokuota</translation>
<translation id="3016780570757425217">Žinoti jūsų vietovę</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, paspauskite tabuliavimo klavišą, tada „Enter“, kad pašalintumėte pasiūlymą.</translation>
<translation id="3023071826883856138">„You4“ (vokas)</translation>
<translation id="3024663005179499861">Netinkamas politikos tipas</translation>
<translation id="3037605927509011580">Oi!</translation>
@@ -556,6 +567,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3207960819495026254">Pažymėta</translation>
<translation id="3209034400446768650">Puslapyje galite būti apmokestinti</translation>
<translation id="3212581601480735796">Jūsų veikla <ph name="HOSTNAME" /> stebima</translation>
+<translation id="3212623355668894776">Uždarykite visus sveÄio langus, kad narÅ¡ymo veikla bÅ«tų iÅ¡trinta iÅ¡ Å¡io įrenginio.</translation>
<translation id="3215092763954878852">Nepavyko naudoti „WebAuthn“</translation>
<translation id="3218181027817787318">Santykinis</translation>
<translation id="3225919329040284222">Serveris pateikė sertifikatą, kuris neatitinka numatytų reikalavimų. Šie reikalavimai taikomi tam tikrose itin saugiose svetainėse, kad jūs būtumėte saugūs.</translation>
@@ -703,6 +715,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3784372983762739446">„Bluetooth“ įrenginiai</translation>
<translation id="3787705759683870569">Galiojimo laikas baigiasi <ph name="EXPIRATION_MONTH" /> / <ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Dydis: 16</translation>
+<translation id="3789841737615482174">Įdiegti</translation>
<translation id="3793574014653384240">Neseniai įvykusių strigÄių skaiÄiai ir priežastys</translation>
<translation id="3797522431967816232">„Prc3“ (vokas)</translation>
<translation id="3799805948399000906">Užklausa dėl šrifto</translation>
@@ -754,6 +767,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4056223980640387499">Sepija</translation>
<translation id="4058922952496707368">Raktas „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (vokas)</translation>
+<translation id="4067669230157909013">Ekrano fiksavimas atnaujintas.</translation>
<translation id="4067947977115446013">Tinkamo adreso pridÄ—jimas</translation>
<translation id="4072486802667267160">Apdorojant jūsų užsakymą įvyko klaida. Bandykite dar kartą.</translation>
<translation id="4075732493274867456">Kliento programa ir serveris nepalaiko įprasto SSL protokolo versijos ar šifruotojo programų komplekto.</translation>
@@ -838,6 +852,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> puslapio miniatiūra</translation>
<translation id="42981349822642051">IÅ¡skleisti</translation>
<translation id="4300675098767811073">Kelios skylės dešinėje</translation>
+<translation id="4302514097724775343">Palieskite dinozaurÄ…, kad paleistumÄ—te</translation>
<translation id="4302965934281694568">„Chou3“ (vokas)</translation>
<translation id="4305666528087210886">Nepavyko pasiekti failo</translation>
<translation id="4305817255990598646">Perjungti</translation>
@@ -916,6 +931,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4658638640878098064">Sankabėlė viršuje kairėje</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtualioji realybÄ—</translation>
+<translation id="4675657451653251260">SveÄio režimu „Chrome“ profilio informacijos nematysite. Galite <ph name="LINK_BEGIN" />prisijungti<ph name="LINK_END" />, kad pasiektumÄ—te „Google“ paskyros informacijÄ…, pvz., slaptažodžius ir mokÄ—jimo metodus.</translation>
<translation id="467662567472608290">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikate yra klaidų. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="4677585247300749148"><ph name="URL" /> nori reaguoti į pritaikymo neįgaliesiems įvykius</translation>
<translation id="467809019005607715">„Google“ skaidrės</translation>
@@ -943,6 +959,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4761104368405085019">Naudoti mikrofonÄ…</translation>
<translation id="4764776831041365478">Tinklalapis šiuo adresu <ph name="URL" /> gali laikinai neveikti arba visam laikui būti perkeltas kitu žiniatinklio adresu.</translation>
<translation id="4766713847338118463">Dvi sankabÄ—lÄ—s apaÄioje</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Šiame įrenginyje išsaugoma veikla:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />bet kokie šiame lange atsisiųsti failai.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Įvyko nežinoma klaida.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{IÅ¡Å¡okantysis langas užblokuotas}one{# iÅ¡Å¡okantysis langas užblokuotas}few{# iÅ¡Å¡okantieji langai užblokuoti}many{# iÅ¡Å¡okanÄiojo lango užblokuota}other{# iÅ¡Å¡okanÄiųjų langų užblokuota}}</translation>
<translation id="4780366598804516005">1 pašto dėžutė</translation>
@@ -1105,11 +1127,13 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5386426401304769735">Šios svetainės sertifikatų grandinėje yra sertifikatas, pasirašytas naudojant SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Kraštų sukabinimas dešinėje</translation>
+<translation id="5398772614898833570">Skelbimai užblokuoti</translation>
<translation id="5400836586163650660">Pilka spalva</translation>
<translation id="540969355065856584">Šiam serveriui nepavyko patvirtinti, kad jis yra <ph name="DOMAIN" />; šiuo metu jo saugos sertifikatas negalioja. Tai gali būti dėl netinkamos konfigūracijos arba dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="541416427766103491">4 dÄ—tuvÄ—</translation>
<translation id="5421136146218899937">Išvalyti naršymo duomenis...</translation>
<translation id="5426179911063097041">Svetainė <ph name="SITE" /> nori siųsti jums pranešimus</translation>
+<translation id="542872847390508405">NarÅ¡ote kaip sveÄias</translation>
<translation id="5430298929874300616">Pašalinti žymę</translation>
<translation id="5439770059721715174">Schemos patvirtinimo klaida „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Atvirkštine tvarka, gerąja puse į viršų</translation>
@@ -1151,12 +1175,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5571083550517324815">Negalima paimti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="5580958916614886209">Patikrinkite galiojimo pabaigos mėnesį ir bandykite dar kartą</translation>
<translation id="5586446728396275693">Nėra išsaugotų adresų</translation>
+<translation id="5593349413089863479">Ryšys nevisiškai saugus</translation>
<translation id="5595485650161345191">Adreso redagavimas</translation>
<translation id="5598944008576757369">Pasirinkti mokÄ—jimo metodÄ…</translation>
<translation id="560412284261940334">Tvarkymas nepalaikomas</translation>
<translation id="5605670050355397069">Buhalterinis</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Svetainė gali būti suklastota ar apgavikiška. „Chrome“ rekomenduoja dabar iš jos išeiti.</translation>
<translation id="5610142619324316209">Patikrinti ryšį</translation>
<translation id="5610807607761827392">Korteles ir adresus galite tvarkyti skiltyje <ph name="BEGIN_LINK" />Nustatymai<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Verskite šį puslapį naudodami „Google“ vertėją</translation>
@@ -1228,6 +1252,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5901630391730855834">Geltona</translation>
<translation id="5905445707201418379">Užblokuota vadovaujantis „<ph name="ORIGIN" />“ pradine politika.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinchronizuota)</translation>
+<translation id="5913377024445952699">Ekrano fiksavimas pristabdytas</translation>
<translation id="59174027418879706">Įjungta</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Įjungta</translation>
@@ -1240,6 +1265,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5963413905009737549">Skiltis</translation>
<translation id="5967592137238574583">KontaktinÄ—s informacijos redagavimas</translation>
<translation id="5967867314010545767">Pašalinti iš istorijos</translation>
+<translation id="5968793460449681917">Per kiekvienÄ… apsilankymÄ…</translation>
<translation id="5975083100439434680">Tolinti</translation>
<translation id="5979084224081478209">Patikrinti slaptažodžius</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1395,6 +1421,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6587923378399804057">Nukopijuota nuoroda</translation>
<translation id="6591833882275308647">Jūsų „<ph name="DEVICE_TYPE" />“ netvarkomas</translation>
<translation id="6596325263575161958">Å ifravimo parinktys</translation>
+<translation id="6596892391065203054">Administratorius užblokavo galimybę spausdinti šį turinį.</translation>
<translation id="6604181099783169992">Judesio arba Å¡viesos jutikliai</translation>
<translation id="6609880536175561541">„Prc7“ (vokas)</translation>
<translation id="6612358246767739896">Apsaugotas turinys</translation>
@@ -1454,6 +1481,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6895330447102777224">KortelÄ— patvirtinta</translation>
<translation id="6897140037006041989">Naudotojo atstovas</translation>
<translation id="6898699227549475383">Organizacija (O)</translation>
+<translation id="6907293445143367439">Leisti <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> nori visiškai valdyti MIDI įrenginius</translation>
<translation id="6915804003454593391">Naudotojas:</translation>
<translation id="6934672428414710184">Šis vardas yra iš jūsų „Google“ paskyros</translation>
@@ -1565,6 +1593,7 @@ Papildoma išsami informacija:
<translation id="7346048084945669753">Susietas:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Komandos eilutÄ—</translation>
+<translation id="7359588939039777303">Skelbimai užblokuoti.</translation>
<translation id="7372973238305370288">paieškos rezultatas</translation>
<translation id="7374733840632556089">Ši problema kyla dėl sertifikato, kurį jūs ar kitas asmuo įdiegėte įrenginyje. Žinoma, kad sertifikatas naudojamas tinklams stebėti ir nuskaityti ir nėra patikimas sistemoje „Chrome“. Kai kurie stebėjimo atvejai yra teisėti, pvz., mokyklos ar įmonės tinkle, bet „Chrome“ nori būti tikra, kad apie stebėjimą būsite informuoti, net jei jo nutraukti negalite. Stebėjimas galimas bet kurioje naršyklėje ar programoje, iš kurių pasiekiamas žiniatinklis.</translation>
<translation id="7375818412732305729">PridÄ—tas failas</translation>
@@ -1739,6 +1768,7 @@ Papildoma išsami informacija:
<translation id="7976214039405368314">Per daug užklausų</translation>
<translation id="7977538094055660992">Išvesties įrenginys</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Norėdami peržiūrėti išplėstosios realybės turinį įdiekite „ARCore“</translation>
<translation id="799149739215780103">Įrišimas</translation>
<translation id="7995512525968007366">Nenurodytas</translation>
<translation id="800218591365569300">Pabandykite uždaryti skirtukus arba kitas programas, kad atlaisvintumėte atminties.</translation>
@@ -1866,25 +1896,39 @@ Papildoma išsami informacija:
<translation id="8507227106804027148">Komandos eilutÄ—</translation>
<translation id="8508648098325802031">Paieškos piktograma</translation>
<translation id="8522552481199248698">„Chrome“ gali padėti apsaugoti „Google“ paskyrą ir pakeisti slaptažodį.</translation>
+<translation id="8525306231823319788">Viso ekrano režimas</translation>
<translation id="8530813470445476232">Išvalykite naršymo istoriją, slapukus, talpyklą ir kita „Chrome“ nustatymuose</translation>
<translation id="8533619373899488139">Apsilankykite adresu &lt;strong&gt;chrome://policy&lt;/strong&gt;, kad peržiūrėtumėte užblokuotų URL sąrašą ir kitą politiką, kurią taiko sistemos administratoriaus.</translation>
<translation id="8541158209346794904">„Bluetooth“ įrenginys</translation>
<translation id="8542014550340843547">Trys sankabÄ—lÄ—s apaÄioje</translation>
<translation id="8543181531796978784">Galite <ph name="BEGIN_ERROR_LINK" />pranešti apie aptikimo problemą<ph name="END_ERROR_LINK" /> arba, jei suprantate saugos riziką, galite <ph name="BEGIN_LINK" />apsilankyti šioje nesaugioje svetainėje<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">KortelÄ—s saugos kodas (CVC) nurodytas kitoje kortelÄ—s pusÄ—je.</translation>
+<translation id="8558485628462305855">Norėdami peržiūrėti išplėstosios realybės turinį atnaujinkite „ARCore“</translation>
<translation id="8559762987265718583">Nepavyksta užmegzti privataus ryšio su <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, nes įrenginio data ir laikas (<ph name="DATE_AND_TIME" />) yra netinkami.</translation>
<translation id="8564182942834072828">Atskiras dokumentas / nesugretintos kopijos</translation>
<translation id="8564985650692024650">„Chromium“ rekomenduoja iš naujo nustatyti <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> slaptažodį, jei naudojate jį kitose svetainėse.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Šiame įrenginyje neišsaugoma veikla:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />šiame lange peržiūrimi puslapiai;
+ <ph name="LIST_ITEM" />slapukai ir svetainÄ—s duomenys.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Patvirtinkite korteles greiÄiau su „Touch ID“</translation>
<translation id="858637041960032120">PridÄ—ti tel. nr.
</translation>
<translation id="8589998999637048520">Geriausia kokybÄ—</translation>
+<translation id="8600271352425265729">Tik šį kartą</translation>
<translation id="860043288473659153">KortelÄ—s savininko vardas</translation>
<translation id="8606726445206553943">Naudoti MIDI įrenginius</translation>
+<translation id="8612761427948161954">Sveiki, <ph name="USERNAME" />,
+ <ph name="BR" />
+ narÅ¡ote kaip sveÄias</translation>
<translation id="861775596732816396">Dydis: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">NÄ—ra jokių atitinkanÄių slaptažodžių. Rodyti visus iÅ¡saugotus slaptažodžius.</translation>
<translation id="8625384913736129811">Išsaugoti šią kortelę šiame įrenginyje</translation>
+<translation id="8627040765059109009">Ekrano fiksavimas atnaujintas</translation>
<translation id="8657078576661269990">Administratorius užblokavo bendrinimą iš <ph name="ORIGIN_NAME" /> su „<ph name="VM_NAME_1" />“ ir „<ph name="VM_NAME_2" />“</translation>
<translation id="8663226718884576429">Užsakymo suvestinė, <ph name="TOTAL_LABEL" />, daugiau informacijos</translation>
<translation id="867224526087042813">Parašas</translation>
@@ -1947,6 +1991,7 @@ Papildoma išsami informacija:
<translation id="8912362522468806198">„Google“ paskyra</translation>
<translation id="8913778647360618320">Mygtukas „Tvarkyti mokėjimo metodus“, paspauskite „Enter“, jei norite tvarkyti mokėjimus ir kredito kortelę „Chrome“ nustatymuose</translation>
<translation id="8918231688545606538">Šis puslapis įtartinas</translation>
+<translation id="8922013791253848639">Visada leisti skelbimus Å¡ioje svetainÄ—je</translation>
<translation id="892588693504540538">Skylė viršuje dešinėje</translation>
<translation id="8931333241327730545">Ar norite išsaugoti šios kortelės informaciją „Google“ paskyroje?</translation>
<translation id="8932102934695377596">Jūsų laikrodis atsilieka</translation>
@@ -2018,6 +2063,7 @@ Papildoma išsami informacija:
<translation id="9183302530794969518">„Google“ dokumentai</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> naudojamas nepalaikomas protokolas.</translation>
<translation id="9191834167571392248">SkylÄ— apaÄioje kairÄ—je</translation>
+<translation id="9199905725844810519">Spausdinimas užblokuotas</translation>
<translation id="9205078245616868884">Duomenys užšifruoti naudojant sinchronizavimo slaptafrazę. Įveskite ją, kad pradėtumėte sinchronizuoti.</translation>
<translation id="9207861905230894330">Nepavyko pridÄ—ti straipsnio.</translation>
<translation id="9213433120051936369">IÅ¡vaizdos tinkinimas</translation>
@@ -2028,8 +2074,10 @@ Papildoma išsami informacija:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Galite prarasti prieigą prie „Google“ paskyros. „Chromium“ rekomenduoja pakeisti slaptažodį dabar. Bus prašoma prisijungti.</translation>
<translation id="939736085109172342">Naujas aplankas</translation>
+<translation id="945522503751344254">Siųsti atsiliepimą</translation>
<translation id="945855313015696284">Patikrinkite toliau pateiktą informaciją ir ištrinkite visas netinkamas korteles</translation>
<translation id="950736567201356821">Trys skylės viršuje</translation>
+<translation id="951941430552851965">Administratorius pristabdė ekrano fiksavimą dėl jūsų ekrane rodomo turinio.</translation>
<translation id="961663415146723894">Ä®riÅ¡imas apaÄioje</translation>
<translation id="962484866189421427">Å is turinys gali bandyti įdiegti klaidinanÄių programų, kurios apsimeta kitomis programomis, arba rinkti duomenis, naudojamus jums stebÄ—ti. <ph name="BEGIN_LINK" />Rodyti vis tiek<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Oficialiai pagaminta</translation>
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index f56af483949..f1d87882f60 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -80,6 +80,14 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">JÅ«s ievadÄ«jÄt paroli vietnÄ“, kuru nepÄrvalda jÅ«su organizÄcija. Lai aizsargÄtu savu kontu, neizmantojiet Å¡o paroli citÄs lietotnÄ“s un vietnÄ“s.</translation>
<translation id="1263231323834454256">Lasīšanas saraksts</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ TÄlÄk norÄdÄ«tÄs darbÄ«bas Å¡ajÄ ierÄ«cÄ“ netiks saglabÄtas:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Å¡ajÄ logÄ skatÄ«tÄs lapas;
+ <ph name="LIST_ITEM" />sīkfaili un vietņu dati;
+ <ph name="LIST_ITEM" />konta informÄcija (<ph name="LINK_BEGIN" />izrakstÄ«ties<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Saņemšanas veids</translation>
<translation id="1281476433249504884">1. izvades vieta</translation>
<translation id="1285320974508926690">Nekad netulkot Å¡o vietni</translation>
@@ -283,6 +291,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="204357726431741734">Pierakstieties, lai izmantotu savÄ Google kontÄ saglabÄtÄs paroles.</translation>
<translation id="2053111141626950936">Lapas netiks tulkotas no Å¡Ä«s valodas: <ph name="LANGUAGE" /></translation>
<translation id="2053553514270667976">Pasta indekss</translation>
+<translation id="2054665754582400095">JÅ«su klÄtbÅ«tne</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ieteikums}zero{# ieteikumi}one{# ieteikums}other{# ieteikumi}}</translation>
<translation id="2079545284768500474">Atsaukt</translation>
<translation id="20817612488360358">Ir iestatÄ«ta datora starpniekserveru iestatÄ«jumu lietoÅ¡ana, bet ir norÄdÄ«ta arÄ« atklÄta starpniekservera konfigurÄcija.</translation>
@@ -296,6 +305,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2102495993840063010">Android lietotnes</translation>
<translation id="2107021941795971877">Balsta struktÅ«ras drukÄÅ¡ana</translation>
<translation id="2108755909498034140">Restartējiet datoru</translation>
+<translation id="2111166930115883695">Lai spēlētu, nospiediet atstarpes taustiņu</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karte</translation>
<translation id="2114841414352855701">Ignorēta, jo to atcēla politika <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="214556005048008348">Atcelt maksÄjumu</translation>
<translation id="2147827593068025794">SinhronizÄcija fonÄ</translation>
<translation id="2148613324460538318">Pievienot karti</translation>
+<translation id="2149968176347646218">Savienojums nav drošs</translation>
<translation id="2154054054215849342">SinhronizÄcija jÅ«su domÄ“nam nav pieejama.</translation>
<translation id="2154484045852737596">Kartes informÄcijas rediģēšana</translation>
<translation id="2161656808144014275">Teksts</translation>
@@ -317,7 +328,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2181821976797666341">Politikas</translation>
<translation id="2183608646556468874">TÄlruņa numurs</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adrese}zero{# adreses}one{# adrese}other{# adreses}}</translation>
-<translation id="2187243482123994665">LietotÄja aktivitÄte</translation>
<translation id="2187317261103489799">Noteikt (pēc noklusējuma)</translation>
<translation id="2188375229972301266">VairÄki caurumi apakÅ¡daļÄ</translation>
<translation id="2202020181578195191">Ievadiet derīgu gadu</translation>
@@ -468,6 +478,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2839501879576190149">JÅ«s grasÄties atvÄ“rt viltotu vietni</translation>
<translation id="2850739647070081192">Invite (aploksne)</translation>
<translation id="2856444702002559011">IespÄ“jams, uzbrucÄ“ji mÄ“Ä£ina nozagt jÅ«su informÄciju no vietnes <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (piemÄ“ram, paroles, ziņojumus vai kredÄ«tkarÅ¡u datus). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2859806420264540918">Å ajÄ vietnÄ“ tiek rÄdÄ«tas traucÄ“joÅ¡as vai maldinoÅ¡as reklÄmas.</translation>
<translation id="2878197950673342043">PlakÄta locÄ«jums</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Logu izvietošana</translation>
@@ -506,11 +517,11 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2996674880327704673">Google ieteikumi</translation>
<translation id="3002501248619246229">Ievades paliktņa materiÄla pÄrbaude</translation>
<translation id="3005723025932146533">RÄdÄ«t saglabÄto versiju</translation>
-<translation id="3007719053326478567">JÅ«su administrators bloÄ·Ä“ja Å¡Ä« satura drukÄÅ¡anu</translation>
<translation id="3008447029300691911">Ievadiet kredÄ«tkartes <ph name="CREDIT_CARD" /> CVC. PÄ“c apstiprinÄÅ¡anas kartes informÄcija tiks kopÄ«gota ar Å¡o vietni.</translation>
<translation id="3010559122411665027">Saraksta ieraksts “<ph name="ENTRY_INDEX" />â€: <ph name="ERROR" /></translation>
<translation id="301521992641321250">AutomÄtiski bloÄ·Ä“ta</translation>
<translation id="3016780570757425217">uzzinÄt jÅ«su atraÅ¡anÄs vietu</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, lai noņemtu ieteikumu, nospiediet tabulēšanas taustiņu un pēc tam — taustiņu Enter.</translation>
<translation id="3023071826883856138">You4 (aploksne)</translation>
<translation id="3024663005179499861">Politikas tips nav pareizs.</translation>
<translation id="3037605927509011580">Cilnes avÄrija.</translation>
@@ -553,6 +564,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3207960819495026254">AtzÄ«mÄ“ts kÄ grÄmatzÄ«me</translation>
<translation id="3209034400446768650">LapÄ var tikt iekasÄ“ta nauda</translation>
<translation id="3212581601480735796">JÅ«su veiktÄs darbÄ«bas pakalpojumÄ <ph name="HOSTNAME" /> tiek uzraudzÄ«tas</translation>
+<translation id="3212623355668894776">Aizveriet visus viesa režīma logus, lai jÅ«su pÄrlÅ«koÅ¡anas darbÄ«bas tiktu izdzÄ“stas no Å¡Ä«s ierÄ«ces.</translation>
<translation id="3215092763954878852">NeizdevÄs izmantot WebAuthn</translation>
<translation id="3218181027817787318">Relatīva</translation>
<translation id="3225919329040284222">Serveris uzrÄdÄ«ja sertifikÄtu, kas neatbilst iebÅ«vÄ“tajÄm cerÄ«bÄm. Å Ä«s cerÄ«bas ir ietvertas konkrÄ“tÄm, augstas droÅ¡Ä«bas vietnÄ“m, lai aizsargÄtu jÅ«s.</translation>
@@ -699,6 +711,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3784372983762739446">Bluetooth ierīces</translation>
<translation id="3787705759683870569">Derīguma termiņš: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">16. izmērs</translation>
+<translation id="3789841737615482174">Instalēt</translation>
<translation id="3793574014653384240">Nesen notikuÅ¡o avÄriju skaits un cÄ“loņi</translation>
<translation id="3797522431967816232">Prc3 (aploksne)</translation>
<translation id="3799805948399000906">Tika pieprasīts fonts</translation>
@@ -750,6 +763,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4056223980640387499">SÄ“pija</translation>
<translation id="4058922952496707368">Atslēga <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (aploksne)</translation>
+<translation id="4067669230157909013">EkrÄna tverÅ¡ana ir atsÄkta.</translation>
<translation id="4067947977115446013">Derīgas adreses pievienošana</translation>
<translation id="4072486802667267160">ApstrÄdÄjot pasÅ«tÄ«jumu, radÄs kļūda. LÅ«dzu, mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="4075732493274867456">Klients un serveris neatbalsta bieži lietoto SSL protokola versiju vai šifra komplektu.</translation>
@@ -834,6 +848,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4297502707443874121">Lappuses numur <ph name="THUMBNAIL_PAGE" /> sīktēls</translation>
<translation id="42981349822642051">Izvērst</translation>
<translation id="4300675098767811073">VairÄki caurumi labajÄ pusÄ“</translation>
+<translation id="4302514097724775343">Lai spēlētu, pieskarieties dinozauram</translation>
<translation id="4302965934281694568">Chou3 (aploksne)</translation>
<translation id="4305666528087210886">Jūsu failam nevarēja piekļūt</translation>
<translation id="4305817255990598646">PÄriet</translation>
@@ -912,6 +927,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4658638640878098064">Skavojums augÅ¡Ä“jÄ kreisajÄ malÄ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">VirtuÄlÄ realitÄte</translation>
+<translation id="4675657451653251260">Viesa režīmÄ netiks rÄdÄ«ta neviena Chrome profila informÄcija. Lai piekļūtu Google kontÄ saglabÄtajai informÄcijai, piemÄ“ram, parolÄ“m un maksÄjumu veidiem, varat <ph name="LINK_BEGIN" />pierakstÄ«ties<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄtÄ ir kļūdas. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="4677585247300749148">Vietnē <ph name="URL" /> tiek pieprasīta atļauja reaģēt uz piekļūstamības notikumiem.</translation>
<translation id="467809019005607715">Google prezentÄcijas</translation>
@@ -939,6 +955,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4761104368405085019">Izmantot jūsu mikrofonu</translation>
<translation id="4764776831041365478">TÄ«mekļa lapa vietnÄ“ <ph name="URL" /> var Ä«slaicÄ«gi nebÅ«t pieejama, vai tÄ var bÅ«t pÄrvietota uz jaunu tÄ«mekļa adresi.</translation>
<translation id="4766713847338118463">Dubults skavojums apakÅ¡daļÄ</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Å ajÄ ierÄ«cÄ“ tiks saglabÄtas Å¡Ädas darbÄ«bas:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />visi Å¡ajÄ logÄ lejupielÄdÄ“tie faili.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">RadÄs nezinÄma kļūda.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Uznirstošais logs ir bloķēts}zero{# uznirstošie logi ir bloķēti}one{# uznirstošais logs ir bloķēts}other{# uznirstošie logi ir bloķēti}}</translation>
<translation id="4780366598804516005">1. pastkaste</translation>
@@ -1101,11 +1123,13 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5386426401304769735">Å Ä«s vietnes sertifikÄtu Ä·Ä“dÄ“ ir iekļauts sertifikÄts, kas ir parakstÄ«ts, izmantojot SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Malu saÅ¡uvums labajÄ pusÄ“</translation>
+<translation id="5398772614898833570">ReklÄmu rÄdÄ«Å¡ana bloÄ·Ä“ta</translation>
<translation id="5400836586163650660">Pelēka</translation>
<translation id="540969355065856584">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄ droÅ¡Ä«bas sertifikÄts Å¡obrÄ«d nav derÄ«gs. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ļaunprÄtÄ«gi izmanto jÅ«su savienojumu.</translation>
<translation id="541416427766103491">4. izvades vieta</translation>
<translation id="5421136146218899937">NotÄ«rÄ«t pÄrlÅ«koÅ¡anas datus</translation>
<translation id="5426179911063097041">No vietnes <ph name="SITE" /> tiek mÄ“Ä£inÄts nosÅ«tÄ«t paziņojumus.</translation>
+<translation id="542872847390508405">JÅ«s veicat pÄrlÅ«koÅ¡anu viesa režīmÄ</translation>
<translation id="5430298929874300616">Noņemt grÄmatzÄ«mi</translation>
<translation id="5439770059721715174">Å eit tika atklÄta shÄ“mas validÄ“Å¡anas kļūda: <ph name="ERROR_PATH" />. Kļūdas ziņojums: <ph name="ERROR" />.</translation>
<translation id="5443468954631487277">Pretēja secība, virspuse uz augšu</translation>
@@ -1147,12 +1171,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5571083550517324815">Nevar saņemt sÅ«tÄ«jumu Å¡ajÄ adresÄ“. Atlasiet citu adresi.</translation>
<translation id="5580958916614886209">PÄrbaudiet derÄ«guma termiņa mÄ“nesi un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="5586446728396275693">Nav saglabÄtu adreÅ¡u.</translation>
+<translation id="5593349413089863479">Savienojums nav pilnīgi drošs</translation>
<translation id="5595485650161345191">Rediģēt adresi</translation>
<translation id="5598944008576757369">IzvÄ“lÄ“ties maksÄjuma veidu</translation>
<translation id="560412284261940334">PÄrvaldÄ«Å¡ana netiek atbalstÄ«ta.</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Å Ä« vietne varÄ“tu bÅ«t viltota vai krÄpnieciska. Chrome iesaka pamest vietni tÅ«lÄ«t.</translation>
<translation id="5610142619324316209">PÄrbaudiet savienojumu.</translation>
<translation id="5610807607761827392">Varat pÄrvaldÄ«t karÅ¡u un adreÅ¡u informÄciju sadaÄ¼Ä <ph name="BEGIN_LINK" />IestatÄ«jumi<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Tulkojiet Å¡Ä«s lapas saturu, izmantojot Google tulkotÄju.</translation>
@@ -1224,6 +1248,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5901630391730855834">Dzeltena</translation>
<translation id="5905445707201418379">BloÄ·Ä“ts, pamatojoties uz <ph name="ORIGIN" /> izcelsmes politiku.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (veikta sinhronizÄcija)</translation>
+<translation id="5913377024445952699">EkrÄnuzņēmumu izveide ir pÄrtraukta</translation>
<translation id="59174027418879706">Iespējots</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Iesl.</translation>
@@ -1236,6 +1261,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5963413905009737549">Sadaļa</translation>
<translation id="5967592137238574583">KontaktinformÄcijas rediģēšana</translation>
<translation id="5967867314010545767">Noņemt no vēstures</translation>
+<translation id="5968793460449681917">KatrÄ apmeklÄ“juma reizÄ“</translation>
<translation id="5975083100439434680">TÄlinÄt</translation>
<translation id="5979084224081478209">PÄrbaudÄ«t paroles</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1391,6 +1417,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6587923378399804057">JÅ«su kopÄ“tÄ saite</translation>
<translation id="6591833882275308647">JÅ«su <ph name="DEVICE_TYPE" /> ierÄ«ce netiek pÄrvaldÄ«ta</translation>
<translation id="6596325263575161958">Šifrēšanas opcijas</translation>
+<translation id="6596892391065203054">JÅ«su administrators bloÄ·Ä“ja Å¡Ä« satura drukÄÅ¡anu.</translation>
<translation id="6604181099783169992">Kustību un gaismas sensori</translation>
<translation id="6609880536175561541">Prc7 (aploksne)</translation>
<translation id="6612358246767739896">AizsargÄts saturs</translation>
@@ -1450,6 +1477,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6895330447102777224">Karte ir apstiprinÄta</translation>
<translation id="6897140037006041989">LietotÄja aÄ£ents</translation>
<translation id="6898699227549475383">OrganizÄcija (O)</translation>
+<translation id="6907293445143367439">Vai atļaujat vietnei <ph name="SITE_NAME" /> veikt tÄlÄk norÄdÄ«tÄs darbÄ«bas?</translation>
<translation id="6910240653697687763">VietnÄ“ <ph name="URL" /> tiek pieprasÄ«ta atļauja pilnÄ«bÄ pÄrvaldÄ«t jÅ«su MIDI ierÄ«ces.</translation>
<translation id="6915804003454593391">LietotÄjs:</translation>
<translation id="6934672428414710184">Å is vÄrds ir no jÅ«su Google konta</translation>
@@ -1561,6 +1589,7 @@ Papildu informÄcija:
<translation id="7346048084945669753">Ir saistīts:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Komandrinda</translation>
+<translation id="7359588939039777303">ReklÄmu rÄdÄ«Å¡ana ir bloÄ·Ä“ta.</translation>
<translation id="7372973238305370288">meklÄ“Å¡anas rezultÄts</translation>
<translation id="7374733840632556089">Å Ä«s problÄ“mas iemesls ir sertifikÄts, kuru jÅ«s vai kÄds cits ir instalÄ“jis jÅ«su ierÄ«cÄ“. Ir zinÄms, ka Å¡is sertifikÄts tiek izmantots tÄ«klu pÄrraudzÄ«bai un pÄrtverÅ¡anai, un pÄrlÅ«ks Chrome tam neuzticas. Lai gan pastÄv daži likumÄ«gi pÄrraudzÄ«bas gadÄ«jumi, piemÄ“ram, skolas vai uzņēmuma tÄ«klÄ, pÄrlÅ«ks Chrome vÄ“las pÄrliecinÄties, ka esat par to informÄ“ts, pat ja nevarat to apturÄ“t. PÄrraudzÄ«ba var notikt jebkurÄ pÄrlÅ«kÄ vai lietojumprogrammÄ ar piekļuvi tÄ«meklim.</translation>
<translation id="7375818412732305729">Tiek pievienots fails</translation>
@@ -1735,6 +1764,7 @@ Papildu informÄcija:
<translation id="7976214039405368314">PÄrÄk daudz pieprasÄ«jumu</translation>
<translation id="7977538094055660992">Izvades ierīce</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Lai skatÄ«tu papildinÄtÄs realitÄtes saturu, instalÄ“jiet ARCore</translation>
<translation id="799149739215780103">Iesējums</translation>
<translation id="7995512525968007366">Nav norÄdÄ«ts</translation>
<translation id="800218591365569300">Aizveriet citas cilnes vai programmas, lai atbrÄ«votu vietu atmiņÄ.</translation>
@@ -1862,25 +1892,39 @@ Papildu informÄcija:
<translation id="8507227106804027148">Komandrinda</translation>
<translation id="8508648098325802031">Meklēšanas ikona</translation>
<translation id="8522552481199248698">Chrome var palÄ«dzÄ“t jums aizsargÄt jÅ«su Google kontu un nomainÄ«t paroli.</translation>
+<translation id="8525306231823319788">PilnekrÄna režīms</translation>
<translation id="8530813470445476232">NotÄ«riet savu pÄrlÅ«koÅ¡anas vÄ“sturi, sÄ«kfailus, keÅ¡atmiņu un citus datus Chrome iestatÄ«jumos.</translation>
<translation id="8533619373899488139">ApmeklÄ“jiet vietni &lt;strong&gt;chrome://policy&lt;/strong&gt;, lai skatÄ«tu bloÄ·Ä“to URL sarakstu, kÄ arÄ« citas politikas, ko noteicis sistÄ“mas administrators.</translation>
<translation id="8541158209346794904">Bluetooth ierīce</translation>
<translation id="8542014550340843547">TrÄ«skÄrÅ¡s skavojums apakÅ¡daļÄ</translation>
<translation id="8543181531796978784">JÅ«s varat <ph name="BEGIN_ERROR_LINK" />ziņot par noteikÅ¡anas problÄ“mu<ph name="END_ERROR_LINK" /> vai, ja apzinÄties droÅ¡Ä«bas riskus, <ph name="BEGIN_LINK" />apmeklÄ“t Å¡o nedroÅ¡o vietni<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC kods ir norÄdÄ«ts jÅ«su kartes aizmugurÄ“.</translation>
+<translation id="8558485628462305855">Lai skatÄ«tu papildinÄtÄs realitÄtes saturu, atjauniniet ARCore</translation>
<translation id="8559762987265718583">Nevar izveidot privÄtu savienojumu ar <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, jo jÅ«su ierÄ«ces datums un laiks (<ph name="DATE_AND_TIME" />) nav pareizs.</translation>
<translation id="8564182942834072828">AtseviÅ¡Ä·i dokumenti/nesakÄrtotu lapu kopijas</translation>
<translation id="8564985650692024650">Chromium iesaka atiestatÄ«t jÅ«su <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> paroli, ja izmantojÄt to citÄs vietnÄ“s.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ TÄlÄk norÄdÄ«tÄs darbÄ«bas Å¡ajÄ ierÄ«cÄ“ netiks saglabÄtas:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Å¡ajÄ logÄ skatÄ«tÄs lapas;
+ <ph name="LIST_ITEM" />sīkfaili un vietņu dati.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Izmantot Touch ID, lai apstiprinÄtu kartes ÄtrÄk</translation>
<translation id="858637041960032120">Piev. tÄlr. nr.
</translation>
<translation id="8589998999637048520">OptimÄlÄ kvalitÄte</translation>
+<translation id="8600271352425265729">Tikai Å¡oreiz</translation>
<translation id="860043288473659153">Bankas kartes Ä«paÅ¡nieka vÄrds</translation>
<translation id="8606726445206553943">izmantot jūsu MIDI ierīces</translation>
+<translation id="8612761427948161954">Labdien, <ph name="USERNAME" />!
+ <ph name="BR" />
+ JÅ«s veicat pÄrlÅ«koÅ¡anu viesa režīmÄ.</translation>
<translation id="861775596732816396">4. izmērs</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nav atbilstoÅ¡u paroļu. RÄdÄ«t visas saglabÄtÄs paroles.</translation>
<translation id="8625384913736129811">SaglabÄt Å¡o karti Å¡ajÄ ierÄ«cÄ“</translation>
+<translation id="8627040765059109009">EkrÄnuzņēmumu izveide atsÄkta</translation>
<translation id="8657078576661269990">Jūsu administrators bloķēja <ph name="ORIGIN_NAME" /> satura kopīgošanu ar <ph name="VM_NAME_1" /> un <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Pasūtījuma kopsavilkums, <ph name="TOTAL_LABEL" />, citi dati</translation>
<translation id="867224526087042813">Iespiedloksne</translation>
@@ -1943,6 +1987,7 @@ Papildu informÄcija:
<translation id="8912362522468806198">Google konts</translation>
<translation id="8913778647360618320">Poga “PÄrvaldÄ«t maksÄjumu veidusâ€. Lai pÄrvaldÄ«tu savus maksÄjumus un kredÄ«tkarÅ¡u informÄciju Chrome iestatÄ«jumos, nospiediet ievadÄ«Å¡anas taustiņu.</translation>
<translation id="8918231688545606538">Šī lapa ir aizdomīga</translation>
+<translation id="8922013791253848639">VienmÄ“r atļaut reklÄmu rÄdÄ«Å¡anu Å¡ajÄ vietnÄ“</translation>
<translation id="892588693504540538">Caurums augÅ¡Ä“jÄ labajÄ malÄ</translation>
<translation id="8931333241327730545">Vai vÄ“laties saglabÄt Å¡o karti savÄ Google kontÄ?</translation>
<translation id="8932102934695377596">NorÄdÄ«tais laiks ir pÄrÄk tÄlu pagÄtnÄ“</translation>
@@ -2014,6 +2059,7 @@ Papildu informÄcija:
<translation id="9183302530794969518">Google dokumenti</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> izmanto neatbalstītu protokolu.</translation>
<translation id="9191834167571392248">Caurums apakÅ¡Ä“jÄ kreisajÄ malÄ</translation>
+<translation id="9199905725844810519">DrukÄÅ¡ana ir bloÄ·Ä“ta</translation>
<translation id="9205078245616868884">JÅ«su dati ir Å¡ifrÄ“ti, izmantojot jÅ«su sinhronizÄcijas ieejas frÄzi. Lai sÄktu sinhronizÄciju, ievadiet ieejas frÄzi.</translation>
<translation id="9207861905230894330">Rakstu neizdevÄs pievienot.</translation>
<translation id="9213433120051936369">Izskata pielÄgoÅ¡ana</translation>
@@ -2024,8 +2070,10 @@ Papildu informÄcija:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Varat zaudēt piekļuvi savam Google kontam. Chromium iesaka nekavējoties nomainīt paroli. Jums tiks lūgts pierakstīties.</translation>
<translation id="939736085109172342">Jauna mape</translation>
+<translation id="945522503751344254">Sūtīt atsauksmes</translation>
<translation id="945855313015696284">PÄrbaudiet tÄlÄk sniegto informÄciju un dzÄ“siet visas nederÄ«gÄs kartÄ«tes.</translation>
<translation id="950736567201356821">TrÄ«s caurumi augÅ¡daļÄ</translation>
+<translation id="951941430552851965">JÅ«su administrators pÄrtrauca ekrÄna tverÅ¡anu jÅ«su ekrÄnÄ redzamÄ satura dēļ.</translation>
<translation id="961663415146723894">IesÄ“jums apakÅ¡daļÄ</translation>
<translation id="962484866189421427">Å is saturs jÅ«su ierÄ«cÄ“ var mÄ“Ä£inÄt instalÄ“t maldinoÅ¡as lietotnes, kas tiek uzdodas par cita veida saturu, vai vÄkt datus, kas var tikt izmantoti jÅ«su izsekoÅ¡anai. <ph name="BEGIN_LINK" />TÄpat rÄdÄ«t<ph name="END_LINK" />.</translation>
<translation id="969892804517981540">OficiÄlÄ UzbÅ«ve</translation>
diff --git a/chromium/components/strings/components_strings_mk.xtb b/chromium/components/strings/components_strings_mk.xtb
index dfbf75b9a5e..3ae28b91ce2 100644
--- a/chromium/components/strings/components_strings_mk.xtb
+++ b/chromium/components/strings/components_strings_mk.xtb
@@ -40,7 +40,7 @@
<translation id="112840717907525620">Кешот на политиката е во ред</translation>
<translation id="1130564665089811311">Копче „Преведи ја Ñтраницата“, притиÑнете Enter за да ја преведете Ñтраницава Ñо „Преведи на Google“</translation>
<translation id="1131264053432022307">Сликата што ја копиравте</translation>
-<translation id="1150979032973867961">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; oперативниот ÑиÑтем на компјутерот не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="1150979032973867961">Серверот не може да докаже дека е <ph name="DOMAIN" />; oперативниот ÑиÑтем на компјутерот не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="1151972924205500581">Потребна е лозинка</translation>
<translation id="1156303062776767266">Прегледувате локална или Ñподелена датотека</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> неочекувано ја затвори врÑката.</translation>
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ја внеÑовте лозинката на Ñајт што не е управуван од организацијата. За да ја заштитите Ñметката, не кориÑтете ја лозинката повторно на други апликации и Ñајтови.</translation>
<translation id="1263231323834454256">СпиÑок за читање</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚ што нема да оÑтане на уредов:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраниците што ги прегледувате во овој прозорец
+ <ph name="LIST_ITEM" />колачињата и податоците за Ñајтот
+ <ph name="LIST_ITEM" />податоците на Ñметката (<ph name="LINK_BEGIN" />одјавете Ñе<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ðачин на подигнување</translation>
<translation id="1281476433249504884">Фиока за Ñкладирање 1</translation>
<translation id="1285320974508926690">Ðикогаш не преведувај ја оваа локација</translation>
@@ -195,11 +203,11 @@
<translation id="1671391448414634642">ОтÑега, Ñтраниците на <ph name="SOURCE_LANGUAGE" /> ќе Ñе преведуваат на <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="1676269943528358898"><ph name="SITE" /> обично кориÑти шифрирање за да ги заштити вашите информации. Кога Google Chrome овој пат Ñе обиде да Ñе поврзе на <ph name="SITE" />, веб-Ñајтот врати невообичаени и неточни акредитиви. Ова може да Ñе Ñлучи кога напаѓач Ñе преправа дека е <ph name="SITE" /> или кога екран за најавување на Wi-Fi го прекинува поврзувањето. Вашите информации ÑÑ ÑƒÑˆÑ‚Ðµ Ñе безбедни, затоа што Google Chrome го запре поврзувањето пред да Ñе разменат податоци.</translation>
<translation id="1682696192498422849">Прво краткиот раб</translation>
-<translation id="168693727862418163">ВредноÑта на правилото не можеше да Ñе потврди Ñпоред неговата шема и ќе биде игнорирана.</translation>
+<translation id="168693727862418163">ВредноÑта на правилото не може да Ñе потврди Ñпоред неговата шема и ќе биде игнорирана.</translation>
<translation id="168841957122794586">Сертификатот на Ñерверот Ñодржи Ñлаб криптографÑки клуч.</translation>
<translation id="1697532407822776718">Подготвени Ñте.</translation>
<translation id="1703835215927279855">Letter</translation>
-<translation id="1706954506755087368">{1,plural, =1{Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е утрешен. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}one{Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е поÑле # ден во иднината. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}other{Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е поÑле # дена во иднината. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}}</translation>
+<translation id="1706954506755087368">{1,plural, =1{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е утрешен. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}one{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е поÑле # ден во иднината. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}other{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат наводно е поÑле # дена во иднината. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка.}}</translation>
<translation id="1710259589646384581">ОС</translation>
<translation id="1712552549805331520"><ph name="URL" /> Ñака трајно да Ñкладира податоци на вашиот локален компјутер</translation>
<translation id="1713628304598226412">Фиока 2</translation>
@@ -222,7 +230,7 @@
<translation id="1752021286346845558">ПоштенÑко Ñандаче 8</translation>
<translation id="1753706481035618306">Број на Ñтраница</translation>
<translation id="1757773103848038814">Фонт Monospace</translation>
-<translation id="1763864636252898013">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; oперативниот ÑиÑтем на уредот не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="1763864636252898013">Серверот не може да докаже дека е <ph name="DOMAIN" />; oперативниот ÑиÑтем на уредот не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Обидете Ñе да извршите дијагноÑтика на мрежата на Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Серверот каде што Ñте упатени, <ph name="ORIGIN" />, поÑтавил наÑлов
Ñо кој Ñе бара примена на правило за потекло за Ñите барања до него. Ðо,
@@ -251,7 +259,7 @@
<translation id="187918866476621466">Отвори ги Ñтраниците на Ñтартување</translation>
<translation id="1883255238294161206">Собери ÑпиÑок</translation>
<translation id="1898423065542865115">Филтрирање</translation>
-<translation id="1901443836186977402">{1,plural, =1{Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат иÑтече претходниот ден. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали е тоа во ред? Доколку не, намеÑтете го чаÑовникот на ÑиÑтемот, па оÑвежете ја Ñтраницата.}one{Серверот не може да докаже дека е <ph name="DOMAIN" /> бидејќи неговиот безбедноÑен Ñертификат иÑтече пред # ден. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач којшто го преÑретнува поврзувањето. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали тоа е во ред? Доколку не е, треба да го поправите чаÑовникот на ÑиÑтемот, а потоа да ја оÑвежите Ñтраницата.}other{Серверот не може да докаже дека е <ph name="DOMAIN" /> бидејќи неговиот безбедноÑен Ñертификат иÑтече пред # дена. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач којшто го преÑретнува поврзувањето. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали тоа е во ред? Доколку не е, треба да го поправите чаÑовникот на ÑиÑтемот, а потоа да ја оÑвежите Ñтраницата.}}</translation>
+<translation id="1901443836186977402">{1,plural, =1{Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат иÑтече претходниот ден. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач што ја преÑретнува вашата врÑка. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали е тоа во ред? Доколку не, намеÑтете го чаÑовникот на ÑиÑтемот, па оÑвежете ја Ñтраницата.}one{Серверот не може да докаже дека е <ph name="DOMAIN" /> бидејќи неговиот безбедноÑен Ñертификат иÑтече пред # ден. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач којшто го преÑретнува поврзувањето. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали тоа е во ред? Доколку не е, треба да го поправите чаÑовникот на ÑиÑтемот, а потоа да ја оÑвежите Ñтраницата.}other{Серверот не може да докаже дека е <ph name="DOMAIN" /> бидејќи неговиот безбедноÑен Ñертификат иÑтече пред # дена. Тоа можеби Ñе должи на погрешна конфигурација или на напаѓач којшто го преÑретнува поврзувањето. ЧаÑовникот на компјутерот моментално е поÑтавен на <ph name="CURRENT_DATE" />. Дали тоа е во ред? Доколку не е, треба да го поправите чаÑовникот на ÑиÑтемот, а потоа да ја оÑвежите Ñтраницата.}}</translation>
<translation id="1902576642799138955">Период на важноÑÑ‚</translation>
<translation id="1908217026282415406">КориÑтење и движење на камерата</translation>
<translation id="191374271204266022">Копирај како JSON</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Ðајавете Ñе за да кориÑтите лозинки зачувани во вашата Ñметка на Google</translation>
<translation id="2053111141626950936">Страниците на <ph name="LANGUAGE" /> нема да Ñе преведуваат.</translation>
<translation id="2053553514270667976">ПоштенÑки број</translation>
+<translation id="2054665754582400095">Вашето приÑуÑтво</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 предлог}one{# предлог}other{# предлози}}</translation>
<translation id="2079545284768500474">Врати</translation>
<translation id="20817612488360358">ПоÑтавките на прокÑи на ÑиÑтемот Ñе поÑтавени да Ñе кориÑтат, но назначена е и јаÑна конфигурација на прокÑи.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Ðпликации за Android</translation>
<translation id="2107021941795971877">Поддршка на печатењето</translation>
<translation id="2108755909498034140">РеÑтартирајте го компјутерот</translation>
+<translation id="2111166930115883695">ПритиÑнете го копчето за празно меÑто за да пуштите</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Картичка</translation>
<translation id="2114841414352855701">Игнорирано бидејќи е отфрлено од <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Откажи го плаќањето</translation>
<translation id="2147827593068025794">Синхронизација во заднина</translation>
<translation id="2148613324460538318">Додајте картичка</translation>
+<translation id="2149968176347646218">Ð’Ñ€Ñката не е безбедна</translation>
<translation id="2154054054215849342">Ðе е доÑтапна Ñинхронизација за вашиот домен</translation>
<translation id="2154484045852737596">Уредете ја картичката</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Политики</translation>
<translation id="2183608646556468874">ТелефонÑки број</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑа}one{# адреÑа}other{# адреÑи}}</translation>
-<translation id="2187243482123994665">ПриÑуÑтво на кориÑник</translation>
<translation id="2187317261103489799">Откриј (Ñтандардно)</translation>
<translation id="2188375229972301266">Повеќе дупки долу</translation>
<translation id="2202020181578195191">ВнеÑете важечка година на иÑтекување</translation>
@@ -371,7 +381,7 @@
<translation id="239429038616798445">Овој метод на иÑпорака не е доÑтапен. Изберете друг.</translation>
<translation id="2396249848217231973">&amp;Врати бришење</translation>
<translation id="2410754574180102685">Government-Legal</translation>
-<translation id="2413528052993050574">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; можеби неговиот безбедноÑен Ñертификат е повлечен. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="2413528052993050574">Серверот не може да докаже дека е <ph name="DOMAIN" />; можеби неговиот безбедноÑен Ñертификат е повлечен. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="2414886740292270097">Темна</translation>
<translation id="2438874542388153331">Четири дупки деÑно</translation>
<translation id="245044156129055925">Тукушто ја внеÑовте лозинката на Ñајт што може да ве измами. Chromium ви препорачува да ја промените лозинката веднаш.</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Пред Ð²Ð°Ñ Ðµ лажен Ñајт</translation>
<translation id="2850739647070081192">Invite (плик)</translation>
<translation id="2856444702002559011">Ðапаѓачите можеби Ñе обидуваат да ги украдат вашите информации од <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (на пример, лозинки, пораки или кредитни картички). <ph name="BEGIN_LEARN_MORE_LINK" />Дознајте повеќе<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Сајтов прикажува нападни или лажни реклами.</translation>
<translation id="2878197950673342043">Превиткување поÑтер</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ПоÑтавување прозорец</translation>
@@ -489,7 +500,7 @@
<translation id="2930577230479659665">Кратење по Ñекој примерок</translation>
<translation id="2932085390869194046">Предложете лозинка…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
-<translation id="2941952326391522266">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот Ñертификат е од <ph name="DOMAIN2" />. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="2941952326391522266">Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот Ñертификат е од <ph name="DOMAIN2" />. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="2943895734390379394">Време на прикачување:</translation>
<translation id="2948083400971632585">Може да ги оневозможите прокÑијата конфигурирани за врÑка од Ñтраницата поÑтавки.</translation>
<translation id="2951588413176968965">Моето поштенÑко Ñандаче</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Предлози од Google</translation>
<translation id="3002501248619246229">Провери ги Ñодржините во влезната фиока</translation>
<translation id="3005723025932146533">Прикажи зачувана копија</translation>
-<translation id="3007719053326478567">ÐдминиÑтраторот го блокирал печатењето на Ñодржинава</translation>
<translation id="3008447029300691911">ВнеÑете го CVC за <ph name="CREDIT_CARD" />. Откако ќе потврдите, деталите за вашата картичка ќе Ñе Ñподелат Ñо Ñајтот.</translation>
<translation id="3010559122411665027">Ð—Ð°Ð¿Ð¸Ñ Ð²Ð¾ ÑпиÑок „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">ÐвтоматÑки блокирана</translation>
<translation id="3016780570757425217">Знајте ја Ñвојата локација</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, притиÑнете го копчето Tab, а потоа копчето Enter за да го отÑтраните предлогот.</translation>
<translation id="3023071826883856138">You4 (плик)</translation>
<translation id="3024663005179499861">Погрешен тип правило</translation>
<translation id="3037605927509011580">По ѓаволите!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">Обележано</translation>
<translation id="3209034400446768650">Страницата може да наплаќа</translation>
<translation id="3212581601480735796">Вашата активноÑÑ‚ на <ph name="HOSTNAME" /> Ñе набљудува</translation>
+<translation id="3212623355668894776">Затворете ги Ñите гоÑтинÑки прозорци за да може активноÑта од прелиÑтувањето да Ñе избрише од уредов.</translation>
<translation id="3215092763954878852">Ðе може да Ñе кориÑти WebAuthn</translation>
<translation id="3218181027817787318">Релативна</translation>
<translation id="3225919329040284222">Серверот претÑтави Ñертификат што не Ñе Ñовпаѓа Ñо вградените очекувања. Овие очекувања Ñе вклучени за Ñигурни веб-локации Ñо голема ÑигурноÑÑ‚ за да бидете заштитени.</translation>
@@ -668,7 +680,7 @@
<translation id="3658742229777143148">Ревизија</translation>
<translation id="3676592649209844519">ID на уред:</translation>
<translation id="3677008721441257057">Дали миÑлевте на &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN" />&lt;/a&gt;?</translation>
-<translation id="3678029195006412963">Барањето не можеше да Ñе потпише</translation>
+<translation id="3678029195006412963">Барањето не може да Ñе потпише</translation>
<translation id="3678529606614285348">Отворете ја Ñтраницата во нов инкогнито прозорец (Ctrl-Shift-N)</translation>
<translation id="3681007416295224113">Информации за Ñертификат</translation>
<translation id="3701427423622901115">РеÑетирањето е потврдено.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">Уреди Ñо Bluetooth</translation>
<translation id="3787705759683870569">ИÑтекува на <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Големина 16</translation>
+<translation id="3789841737615482174">ИнÑталирај</translation>
<translation id="3793574014653384240">Број на падови и причини за падовите што Ñе Ñлучиле неодамна</translation>
<translation id="3797522431967816232">Prc3 (плик)</translation>
<translation id="3799805948399000906">Побаран е фонт</translation>
@@ -729,7 +742,7 @@
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
<translation id="3939773374150895049">Да Ñе кориÑти WebAuthn намеÑто CVC?</translation>
<translation id="3946209740501886391">Секогаш прашувај на овој Ñајт</translation>
-<translation id="3949571496842715403">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат не наведува алтернативни имиња на предметот. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="3949571496842715403">Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат не наведува алтернативни имиња на предметот. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="3949601375789751990">ИÑторијата на прелиÑтување Ñе појавува тука</translation>
<translation id="3949870428812919180">Ðема зачувани начини на плаќање</translation>
<translation id="3950820424414687140">Ðајави Ñе</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Клуч „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (плик)</translation>
+<translation id="4067669230157909013">Снимањето на екранот продолжи.</translation>
<translation id="4067947977115446013">Додајте важечка адреÑа</translation>
<translation id="4072486802667267160">ÐаÑтана грешка при обработката на вашата нарачка. Обидете Ñе повторно.</translation>
<translation id="4075732493274867456">Клиентот и Ñерверот не ја поддржуваат верзијата на заедничкиот SSL-протокол или пакетот за шифрирање.</translation>
@@ -837,8 +851,9 @@
<translation id="4297502707443874121">Сликичка за Ñтраницата <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Прошири</translation>
<translation id="4300675098767811073">Повеќе дупки деÑно</translation>
+<translation id="4302514097724775343">Допрете го диноÑауруÑот за да играте</translation>
<translation id="4302965934281694568">Chou3 (плик)</translation>
-<translation id="4305666528087210886">Ðе можеше да Ñе приÑтапи до вашата датотека</translation>
+<translation id="4305666528087210886">Ðе може да Ñе приÑтапи до вашата датотека</translation>
<translation id="4305817255990598646">Префрли</translation>
<translation id="4312613361423056926">B2</translation>
<translation id="4312866146174492540">Блокирај (Ñтандардно)</translation>
@@ -868,7 +883,7 @@
<translation id="4408413947728134509">Колачиња <ph name="NUM_COOKIES" /></translation>
<translation id="4414290883293381923">Тукушто ја внеÑовте Ñвојата лозинка на измамнички Ñајт. Chrome препорачува да одите на <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> и на други Ñајтови каде што ја кориÑтите лозинкава и да ја промените веднаш.</translation>
<translation id="4415426530740016218">ÐдреÑа за подигнување</translation>
-<translation id="4424024547088906515">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; Chrome не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="4424024547088906515">Серверот не може да докаже дека е <ph name="DOMAIN" />; Chrome не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="443121186588148776">СериÑка порта</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> не го прифати вашиот Ñертификат за најавување или можеби таков Ñертификат не е обезбеден.</translation>
<translation id="4432792777822557199">ОтÑега-натаму, Ñтраниците на <ph name="SOURCE_LANGUAGE" /> ќе Ñе преведуваат на <ph name="TARGET_LANGUAGE" /></translation>
@@ -915,7 +930,8 @@
<translation id="4658638640878098064">Спојување горе лево</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуелна реалноÑÑ‚</translation>
-<translation id="467662567472608290">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат Ñодржи грешки. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="4675657451653251260">Во режим на гоÑтин нема да гледате податоци за профили на Chrome. Може да Ñе <ph name="LINK_BEGIN" />најавите<ph name="LINK_END" /> за да приÑтапите до податоците на Ñметката на Google, како лозинките и начините на плаќање.</translation>
+<translation id="467662567472608290">Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат Ñодржи грешки. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="4677585247300749148"><ph name="URL" /> Ñака да одговара на наÑтани за приÑтапноÑÑ‚</translation>
<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">Тукушто ја внеÑовте Ñвојата лозинка на измамнички Ñајт. Chromium препорачува веднаш да ги проверите зачуваните лозинки за <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> и другите Ñајтови каде што ја кориÑтите лозинкава.</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">КориÑтете го микрофонот</translation>
<translation id="4764776831041365478">Веб-локацијата на <ph name="URL" /> можеби привремено не работи или можеби е трајно премеÑтена на нова веб-адреÑа.</translation>
<translation id="4766713847338118463">Двојно Ñпојување долу</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚ што ќе оÑтане на уредов:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñите датотеки што ги преземате во овој прозорец
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Се појави непозната грешка.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Скокачкиот прозорец е блокиран}one{# Ñкокачки прозорец е блокиран}other{# Ñкокачки прозорци Ñе блокирани}}</translation>
<translation id="4780366598804516005">ПоштенÑко Ñандаче 1</translation>
@@ -1022,7 +1044,7 @@
<translation id="5088142053160410913">Порака до операторот</translation>
<translation id="5089810972385038852">Држава</translation>
<translation id="5093232627742069661">Z-превиткување</translation>
-<translation id="5094747076828555589">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; Chromium не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="5094747076828555589">Серверот не може да докаже дека е <ph name="DOMAIN" />; Chromium не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="5095208057601539847">Провинција</translation>
<translation id="5097099694988056070">СтатиÑтички податоци за уредот, како на пример, кориÑтење CPU/RAM</translation>
<translation id="5097501891273180634">A2</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">Синџирот Ñо Ñертификати за Ñајтов Ñодржи Ñертификат потпишан Ñо SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Шиење на работ деÑно</translation>
+<translation id="5398772614898833570">Рекламите Ñе блокирани</translation>
<translation id="5400836586163650660">Сива</translation>
-<translation id="540969355065856584">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат не е важечки во моментов. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="540969355065856584">Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот безбедноÑен Ñертификат не е важечки во моментов. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="541416427766103491">Фиока за Ñкладирање 4</translation>
<translation id="5421136146218899937">ИÑчиÑти податоци од прелиÑтување…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> Ñака да ви иÑпраќа извеÑтувања</translation>
+<translation id="542872847390508405">Пребарувате како ГоÑтин</translation>
<translation id="5430298929874300616">ОтÑтрани обележувач</translation>
<translation id="5439770059721715174">Грешка при потврдување шема на „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Обратен редоÑлед Ñо лицето нагоре</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">Ðе може да Ñе подигне од оваа адреÑа. Изберете друга.</translation>
<translation id="5580958916614886209">Проверете го меÑецот на иÑтекување и обидете Ñе повторно</translation>
<translation id="5586446728396275693">Ðема зачувани адреÑи</translation>
+<translation id="5593349413089863479">Ð’Ñ€Ñката не е потполно безбедна</translation>
<translation id="5595485650161345191">Измени адреÑа</translation>
<translation id="5598944008576757369">Изберете начин на плаќање</translation>
<translation id="560412284261940334">Управувањето не е поддржано</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Сајтов може да е лажен или измамнички. Chrome препорачува да го напуштите веднаш.</translation>
<translation id="5610142619324316209">Да ја проверите врÑката</translation>
<translation id="5610807607761827392">Може да управувате Ñо картичките и адреÑите во <ph name="BEGIN_LINK" />„ПоÑтавки“<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Преведете ја Ñтраницава Ñо „Преведи на Google“</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">Жолта боја</translation>
<translation id="5905445707201418379">Блокирано ÑоглаÑно правилото за потекло на <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинхронизирани)</translation>
+<translation id="5913377024445952699">Снимањето на екранот е паузирано</translation>
<translation id="59174027418879706">Овозможено</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Вклучено</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">Секција</translation>
<translation id="5967592137238574583">Изменете ги информациите за контакт</translation>
<translation id="5967867314010545767">ОтÑтрани од иÑторијата</translation>
+<translation id="5968793460449681917">При Ñекоја поÑета</translation>
<translation id="5975083100439434680">Одзумирај</translation>
<translation id="5979084224081478209">Провери ги лозинките</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">Линкот што го копиравте</translation>
<translation id="6591833882275308647">Вашиот <ph name="DEVICE_TYPE" /> не е управуван</translation>
<translation id="6596325263575161958">Опции за шифрирање</translation>
+<translation id="6596892391065203054">ÐдминиÑтраторот го блокирал печатењето на Ñодржинава.</translation>
<translation id="6604181099783169992">Сензори за движење или Ñветлина</translation>
<translation id="6609880536175561541">Prc7 (плик)</translation>
<translation id="6612358246767739896">Заштитена Ñодржина</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">Вашата картичка е потврдена</translation>
<translation id="6897140037006041989">КориÑнички агент</translation>
<translation id="6898699227549475383">Организација (O)</translation>
+<translation id="6907293445143367439">Дозволете <ph name="SITE_NAME" /> да:</translation>
<translation id="6910240653697687763"><ph name="URL" /> Ñака да добие целоÑна контрола над вашите MIDI-уреди</translation>
<translation id="6915804003454593391">КориÑник:</translation>
<translation id="6934672428414710184">Ова име е од вашата Ñметка на Google</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">Е поврзан:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Командна линија</translation>
+<translation id="7359588939039777303">Рекламите Ñе блокирани.</translation>
<translation id="7372973238305370288">резултат од пребарувањето</translation>
<translation id="7374733840632556089">Грешкава Ñе Ñлучува поради Ñертификат што вие или некој друг Ñте го инÑталирале на уредот. Познато е дека Ñертификатов Ñе кориÑти за надзор и преÑретнување мрежи и Chrome нема доверба во него. Иако поÑтојат и легитимни Ñлучаи за надзор, како на пр., во училишна или компаниÑка мрежа, Chrome Ñака да Ñе увери дека знаете дека поÑтои надзор, дури и ако не може да го Ñопрете. Ðадзорот може да Ñе Ñлучи во кој било прелиÑтувач или апликација што приÑтапува на интернет.</translation>
<translation id="7375818412732305729">Приложена е датотека</translation>
@@ -1627,7 +1656,7 @@
<translation id="7552846755917812628">ИÑпробајте ги Ñледните Ñовети:</translation>
<translation id="7554791636758816595">Ðова картичка</translation>
<translation id="7564049878696755256">Може да го изгубите приÑтапот до вашата Ñметка на <ph name="ORG_NAME" /> или да ви го украдат идентитетот. Chrome препорачува да ја Ñмените лозинката веднаш.</translation>
-<translation id="7567204685887185387">Серверот не можеше да докаже дека е <ph name="DOMAIN" />; можеби неговиот безбедноÑен Ñертификат е издаден лажно. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
+<translation id="7567204685887185387">Серверот не може да докаже дека е <ph name="DOMAIN" />; можеби неговиот безбедноÑен Ñертификат е издаден лажно. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="7569952961197462199">ОтÑтрани ја кредитната картичка од Chrome?</translation>
<translation id="7569983096843329377">Црна</translation>
<translation id="7575207903026901870">Копче за отÑтранување предлог, притиÑнете Enter за да го отÑтраните предлогов</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">Премногу барања</translation>
<translation id="7977538094055660992">Излезен уред</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">За да прегледувате Ñодржини во проширена реалноÑÑ‚, инÑталирајте го ARCore</translation>
<translation id="799149739215780103">Врзување</translation>
<translation id="7995512525968007366">Ðе е наведено</translation>
<translation id="800218591365569300">Обидете Ñе да ги затворите другите картички или програми за да оÑлободите меморија.</translation>
@@ -1840,7 +1870,7 @@
<translation id="8381674639488873545">Овие трошоци може да бидат еднократни или повторливи и може нема да бидат очигледни. <ph name="BEGIN_LINK" />Сепак прикажи<ph name="END_LINK" /></translation>
<translation id="8412145213513410671">Падови (<ph name="CRASH_COUNT" />)</translation>
<translation id="8412392972487953978">Мора да ја внеÑете иÑтата лозинка двапати.</translation>
-<translation id="8416694386774425977">Конфигурацијата на мрежата е неважечка и не можеше да Ñе увезе.
+<translation id="8416694386774425977">Конфигурацијата на мрежата е неважечка и не може да Ñе увезе.
Дополнителни детали:
<ph name="DEBUG_INFO" /></translation>
<translation id="8424582179843326029"><ph name="FIRST_LABEL" /> <ph name="SECOND_LABEL" /> <ph name="THIRD_LABEL" /></translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">Командна линија</translation>
<translation id="8508648098325802031">Икона за пребарување</translation>
<translation id="8522552481199248698">Chrome може да ви помогне да ја заштитите Ñметката на Google и да ја промените лозинката.</translation>
+<translation id="8525306231823319788">Цел екран</translation>
<translation id="8530813470445476232">Избришете ја иÑторијата на прелиÑтување, колачињата, кешот и друго во поÑтавките за Chrome</translation>
<translation id="8533619373899488139">Одете на &lt;strong&gt;chrome://policy&lt;/strong&gt; за да го видите ÑпиÑокот Ñо блокирани URL-адреÑи, како и други правила што ги наметнал ÑиÑтемÑкиот админиÑтратор.</translation>
<translation id="8541158209346794904">Уред Ñо Bluetooth</translation>
<translation id="8542014550340843547">Тројно Ñпојување долу</translation>
<translation id="8543181531796978784">Може да <ph name="BEGIN_ERROR_LINK" />пријавите проблем Ñо откривањето<ph name="END_ERROR_LINK" /> или, доколку ги разбирате ризиците по безбедноÑта, <ph name="BEGIN_LINK" />поÑетете ја оваа небезбедна Ñтраница<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC-бројот Ñе наоѓа на задната Ñтрана на картичката.</translation>
+<translation id="8558485628462305855">За да прегледувате Ñодржини во проширена реалноÑÑ‚, ажурирајте го ARCore</translation>
<translation id="8559762987265718583">Ðе може да Ñе воÑпоÑтави приватна врÑка до <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> бидејќи датумот и времето на вашиот уред (<ph name="DATE_AND_TIME" />) Ñе погрешни.</translation>
<translation id="8564182942834072828">Одделни документи/неподредени примероци</translation>
<translation id="8564985650692024650">Chromium препорачува реÑетирање на лозинката за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако повторно Ñте ја употребиле на други Ñајтови.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ÐктивноÑÑ‚ што нема да оÑтане на уредов:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраниците што ги прегледувате во овој прозорец
+ <ph name="LIST_ITEM" />колачињата и податоците за Ñајтот
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">КориÑтете Touch ID за побрзо потврдување на картичките</translation>
<translation id="858637041960032120">Додај телефонÑки број</translation>
<translation id="8589998999637048520">Ðајдобар квалитет</translation>
+<translation id="8600271352425265729">Само овој пат</translation>
<translation id="860043288473659153">Име на ÑопÑтвеникот на картичката</translation>
<translation id="8606726445206553943">КориÑтете ги MIDI уредите</translation>
+<translation id="8612761427948161954">Здраво <ph name="USERNAME" />,
+ <ph name="BR" />
+ ПрелиÑтувате како гоÑтин</translation>
<translation id="861775596732816396">Големина 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ðема лозинки што Ñе Ñовпаѓаат. Прикажи ги Ñите зачувани лозинки.</translation>
<translation id="8625384913736129811">Зачувај ја картичкава на уредов</translation>
+<translation id="8627040765059109009">Снимањето на екранот продолжи</translation>
<translation id="8657078576661269990">ÐдминиÑтраторот го блокирал Ñподелувањето од <ph name="ORIGIN_NAME" /> на <ph name="VM_NAME_1" /> и <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Краток преглед на нарачка, <ph name="TOTAL_LABEL" />, повеќе детали</translation>
<translation id="867224526087042813">ПотпиÑ</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Сметка на Google</translation>
<translation id="8913778647360618320">Копче „Управувајте Ñо начините на плаќање“, притиÑнете Enter за да управувате Ñо податоците за плаќањата и кредитната картичка во поÑтавките за Chrome</translation>
<translation id="8918231688545606538">Страницава е Ñомнителна</translation>
+<translation id="8922013791253848639">Секогаш дозволувај реклами на Ñајтов</translation>
<translation id="892588693504540538">Дупка горе деÑно</translation>
<translation id="8931333241327730545">Дали Ñакате да ја зачувате картичкава на Ñметката на Google?</translation>
<translation id="8932102934695377596">Вашиот чаÑовник доцни</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Документи на Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> кориÑти неподдржан протокол.</translation>
<translation id="9191834167571392248">Дупка долу лево</translation>
+<translation id="9199905725844810519">Печатењето е блокирано</translation>
<translation id="9205078245616868884">Вашите податоци Ñе шифрирани Ñо лозинката за Ñинхронизирање. ВнеÑете ја за да го започнете Ñинхронизирањето.</translation>
<translation id="9207861905230894330">Ðе уÑпеа да Ñе додаде напиÑ.</translation>
<translation id="9213433120051936369">ПриÑпоÑобете го изгледот</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Може да го изгубите приÑтапот до Ñметката на Google. Chromium препорачува да ја промените лозинката Ñега. Ќе Ñе побара од Ð²Ð°Ñ Ð´Ð° Ñе најавите.</translation>
<translation id="939736085109172342">Ðова папка</translation>
+<translation id="945522503751344254">ИÑпратете повратни информации</translation>
<translation id="945855313015696284">Проверете ги информациите подолу и избришете ги Ñите неважечки картички</translation>
<translation id="950736567201356821">Три дупки горе</translation>
+<translation id="951941430552851965">ÐдминиÑтраторот го паузираше Ñнимањето на екранот поради Ñодржините на екранот.</translation>
<translation id="961663415146723894">Врзување долу</translation>
<translation id="962484866189421427">Содржиниве може да Ñе обидат да инÑталираат лажни апликации што Ñе преправаат дека Ñе нешто друго или да Ñобираат податоци што може да ги кориÑтат за да ве Ñледат. <ph name="BEGIN_LINK" />Сепак прикажи<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Официјална верзија</translation>
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index 10ec2240fdd..39b884d3b48 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´¥à´¾à´ªà´¨à´¤àµà´¤à´¿à´¨àµ നിയനàµà´¤àµà´°à´£à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ സൈറàµà´±à´¿à´²à´¾à´£àµ പാസàµâ€Œà´µàµ‡à´¡àµ നൽകിയിരികàµà´•àµà´¨àµà´¨à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† à´…à´•àµà´•àµ—à´£àµà´Ÿàµ പരിരകàµà´·à´¿à´•àµà´•à´¾àµ», മറàµà´±àµ ആപàµà´ªàµà´•à´³à´¿à´²àµà´‚ സൈറàµà´±àµà´•à´³à´¿à´²àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† പാസàµâ€Œà´µàµ‡à´¡àµ à´ªàµà´¨à´°àµà´ªà´¯àµ‹à´—à´¿à´•àµà´•à´°àµà´¤àµ.</translation>
<translation id="1263231323834454256">വായനാ ലിസàµà´±àµà´±àµ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ സംരകàµà´·à´¿à´•àµà´•à´¾à´¤àµà´¤ ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´ˆ വിൻഡോയിൽ നിങàµà´™àµ¾ കാണàµà´¨àµà´¨ പേജàµà´•àµ¾
+ <ph name="LIST_ITEM" />à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚
+ <ph name="LIST_ITEM" />à´…à´•àµà´•àµ—à´£àµà´Ÿàµ വിവരങàµà´™àµ¾ (<ph name="LINK_BEGIN" />സൈൻ ഔടàµà´Ÿàµ ചെയàµà´¯àµà´•<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">പികàµà´•à´ªàµà´ªàµ രീതി</translation>
<translation id="1281476433249504884">à´¸àµà´±àµà´±à´¾à´•àµà´•àµ¼ 1</translation>
<translation id="1285320974508926690">à´ˆ സൈറàµà´±àµ à´’à´°à´¿à´•àµà´•à´²àµà´‚ വിവരàµâ€â€Œà´¤àµà´¤à´¨à´‚ ചെയàµà´¯à´°àµà´¤àµ</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">à´šà´°à´¿à´¤àµà´° എൻടàµà´°à´¿à´•à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµ</translation>
<translation id="1517433312004943670">ഫോൺ നമàµà´ªàµ¼ ആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="1519264250979466059">ബിൽഡൠതീയതി</translation>
-<translation id="1521655867290435174">Google ഷീറàµà´±àµ</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">കണകàµà´·à´¨àµà´µàµ‡à´£àµà´Ÿà´¿ കാകàµà´•àµà´¨àµà´¨àµâ€¦</translation>
<translation id="1529521330346880926">10x15 (എൻവലപàµà´ªàµ)</translation>
<translation id="1529789484829130889">à´Ÿàµà´°àµ‡ 8</translation>
@@ -282,6 +290,7 @@
<translation id="204357726431741734">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ സംരകàµà´·à´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´³àµà´³ പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ ഉപയോഗികàµà´•à´¾àµ» സൈൻ ഇൻ ചെയàµà´¯àµà´•</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> ഭാഷയിലàµà´³àµà´³ പേജàµà´•àµ¾ വിവർതàµà´¤à´¨à´‚ ചെയàµà´¯à´¿à´²àµà´².</translation>
<translation id="2053553514270667976">തപാൽ കോഡàµ</translation>
+<translation id="2054665754582400095">നിങàµà´™à´³àµà´Ÿàµ† സാനàµà´¨à´¿à´§àµà´¯à´‚</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{ഒരൠനിർദàµà´¦àµ‡à´¶à´‚}other{# നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾}}</translation>
<translation id="2079545284768500474">പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="20817612488360358">സിസàµà´±àµà´±à´‚ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ à´•àµà´°à´®àµ€à´•à´°à´£à´‚ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ സജàµà´œà´®à´¾à´•àµà´•à´¿, പകàµà´·àµ† ഒരൠസàµâ€Œà´ªà´·àµâ€Œà´Ÿà´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷനàµà´‚ അതോടൊപàµà´ªà´‚ നിർദàµà´¦àµ‡à´¶à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
@@ -295,6 +304,7 @@
<translation id="2102495993840063010">Android ആപàµâ€Œà´¸àµ</translation>
<translation id="2107021941795971877">à´ªàµà´°à´¿à´¨àµà´±àµ സപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµà´•àµ¾</translation>
<translation id="2108755909498034140">നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ റീസàµâ€Œà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´•</translation>
+<translation id="2111166930115883695">കളികàµà´•à´¾àµ» 'Space' അമർതàµà´¤àµà´•</translation>
<translation id="2111256659903765347">സൂപàµà´ªàµ¼-A</translation>
<translation id="2113977810652731515">കാർഡàµ</translation>
<translation id="2114841414352855701"> <ph name="POLICY_NAME" /> à´Žà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ മറികടനàµà´¨à´¤à´¿à´¨à´¾àµ½ ഇതൠഅവഗണിചàµà´šàµ.</translation>
@@ -306,6 +316,7 @@
<translation id="214556005048008348">പേയàµâ€Œà´®àµ†à´¨àµâ€à´±àµ റദàµà´¦à´¾à´•àµà´•àµà´•</translation>
<translation id="2147827593068025794">പശàµà´šà´¾à´¤àµà´¤à´²à´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½</translation>
<translation id="2148613324460538318">കാർഡൠചേർകàµà´•àµà´•</translation>
+<translation id="2149968176347646218">കണകàµà´·àµ» à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="2154054054215849342">നിങàµà´™à´³àµà´Ÿàµ† ഡൊമെയàµâ€Œà´¨à´¿à´¨àµ വേണàµà´Ÿà´¿ സമനàµà´µà´¯à´‚ ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="2154484045852737596">കാർഡൠഎഡിറàµà´±àµ ചെയàµà´¯àµà´•</translation>
<translation id="2161656808144014275">വാചകം</translation>
@@ -316,7 +327,6 @@
<translation id="2181821976797666341">നയങàµà´™àµ¾</translation>
<translation id="2183608646556468874">ഫോണàµâ€ നമàµà´ªà´°àµâ€</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{ഒരൠവിലാസം}other{# വിലാസങàµà´™àµ¾}}</translation>
-<translation id="2187243482123994665">ഉപയോകàµà´¤àµƒ സാനàµà´¨à´¿à´§àµà´¯à´‚</translation>
<translation id="2187317261103489799">à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´• (ഡിഫോൾടàµà´Ÿàµ)</translation>
<translation id="2188375229972301266">താഴെ à´’à´¨àµà´¨à´¿à´²à´§à´¿à´•à´‚ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
<translation id="2202020181578195191">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ ശരിയായ വർഷം നലàµâ€à´•àµà´•</translation>
@@ -467,6 +477,7 @@
<translation id="2839501879576190149">à´µàµà´¯à´¾à´œ സൈറàµà´±àµ ഉണàµà´Ÿàµ</translation>
<translation id="2850739647070081192">à´•àµà´·à´£à´‚ (എൻവലപàµà´ªàµ)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ നിങàµà´™à´³àµà´Ÿàµ† വിവരം മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» à´…à´•àµà´°à´®à´¿à´•àµ¾ à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨àµà´£àµà´Ÿà´¾à´µà´¾à´‚ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, സനàµà´¦àµ‡à´¶à´™àµà´™àµ¾, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾). <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">à´ˆ സൈറàµà´±àµ, അനാവശàµà´¯à´®àµ‹ തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ‹ ആയ പരസàµà´¯à´™àµà´™àµ¾ കാണികàµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="2878197950673342043">പോസàµâ€Œà´±àµà´±àµ¼ മടകàµà´•àµ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">വിൻഡോ à´ªàµà´²àµ†à´¯àµâ€Œà´¸àµâ€Œà´®àµ†à´¨àµà´±àµ</translation>
@@ -505,11 +516,11 @@
<translation id="2996674880327704673">Google-ൽ നിനàµà´¨àµà´³àµà´³ നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾</translation>
<translation id="3002501248619246229">ഇൻപàµà´Ÿàµà´Ÿàµ à´Ÿàµà´°àµ‡ മീഡിയ പരിശോധികàµà´•àµà´•</translation>
<translation id="3005723025932146533">സംരകàµà´·à´¿à´šàµà´š പകർപàµà´ªàµ കാണികàµà´•àµà´•</translation>
-<translation id="3007719053326478567">à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµà´®à´¿àµ» à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤àµ</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />-à´¨àµà´±àµ† CVC നൽകàµà´•. à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´šàµà´šàµ à´•à´´à´¿à´žàµà´žà´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠവിശദാംശങàµà´™àµ¾ à´ˆ സൈറàµà´±àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´‚.</translation>
<translation id="3010559122411665027">ലിസàµà´±àµà´±àµ എൻടàµà´°à´¿ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">à´¸àµà´µà´¯à´®àµ‡à´µ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="3016780570757425217">നിങàµà´™à´³àµà´Ÿàµ† ലൊകàµà´•àµ‡à´·àµ» അറിയàµà´•</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, നിർദàµà´¦àµ‡à´¶à´‚ നീകàµà´•à´‚ ചെയàµà´¯à´¾àµ» Tab' അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ 'Enter' അമർതàµà´¤àµà´•.</translation>
<translation id="3023071826883856138">You4 (എൻവലപàµà´ªàµ)</translation>
<translation id="3024663005179499861">തെറàµà´±à´¾à´¯ നയ തരം</translation>
<translation id="3037605927509011580">à´•à´·àµà´Ÿà´‚!</translation>
@@ -551,6 +562,7 @@
<translation id="3207960819495026254">à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="3209034400446768650">പേജൠപണം ഈടാകàµà´•à´¿à´¯àµ‡à´•àµà´•à´¾à´‚</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ നിരീകàµà´·à´£à´¤àµà´¤à´¿à´²à´¾à´£àµ</translation>
+<translation id="3212623355668894776">à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµ നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¾àµ» à´Žà´²àµà´²à´¾ അതിഥി വിൻഡോകളàµà´‚ à´…à´Ÿà´¯àµà´•àµà´•àµà´•.</translation>
<translation id="3215092763954878852">WebAuthn ഉപയോഗികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="3218181027817787318">റിലേറàµà´±àµ€à´µàµ</translation>
<translation id="3225919329040284222">ബിൽടàµà´Ÿàµ-ഇൻ à´ªàµà´°à´¤àµ€à´•àµà´·à´•à´³àµâ€à´•àµà´•àµ പൊരàµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿà´¾à´¤àµà´¤ സരàµâ€à´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¾à´£àµ സെരàµâ€à´µà´°àµâ€ അവതരിപàµà´ªà´¿à´šàµà´šà´¤àµ. നിങàµà´™à´³àµ† സംരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•à´¾à´¯àµà´³àµà´³ നിശàµà´šà´¿à´¤, ഉനàµà´¨à´¤-à´¸àµà´°à´•àµà´·à´¾ വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾à´•àµà´•à´¾à´¯à´¾à´£àµ à´ˆ à´ªàµà´°à´¤àµ€à´•àµà´·à´•àµ¾ ഉൾപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ.</translation>
@@ -698,6 +710,7 @@
<translation id="3784372983762739446">Bluetooth ഉപകരണങàµà´™àµ¾</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" />-ൽ അവസാനികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3789155188480882154">വലàµà´ªàµà´ªà´‚ 16</translation>
+<translation id="3789841737615482174">ഇനàµâ€à´¸àµà´±àµà´±à´¾àµ¾ ചെയàµà´¯àµà´•</translation>
<translation id="3793574014653384240">à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ†à´¯àµà´£àµà´Ÿà´¾à´¯ à´•àµà´°à´¾à´·àµà´•à´³àµà´Ÿàµ† à´Žà´£àµà´£à´µàµà´‚ കാരണങàµà´™à´³àµà´‚</translation>
<translation id="3797522431967816232">Prc3 (എൻവലപàµà´ªàµ)</translation>
<translation id="3799805948399000906">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¿à´šàµà´š ഫോണàµà´Ÿàµ</translation>
@@ -749,6 +762,7 @@
<translation id="4056223980640387499">സിപിയ</translation>
<translation id="4058922952496707368">കീ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (എൻവലപàµà´ªàµ)</translation>
+<translation id="4067669230157909013">à´¸àµà´•àµà´°àµ€àµ» à´•àµà´¯à´¾à´ªàµâ€Œà´šàµ¼ à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´šàµà´šàµ.</translation>
<translation id="4067947977115446013">ശരിയായ വിലാസം ചേർകàµà´•àµà´•</translation>
<translation id="4072486802667267160">നിങàµà´™à´³àµà´Ÿàµ† ഓർഡർ à´ªàµà´°àµ‡à´¾à´¸à´¸àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ ഒരൠപിശകàµà´£àµà´Ÿà´¾à´¯à´¿. വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´šàµà´šàµà´¨àµ‹à´•àµà´•àµ‚.</translation>
<translation id="4075732493274867456">ഒരൠസാധാരണ SSL à´ªàµà´°àµ‹à´Ÿàµà´Ÿàµ‹à´•àµà´•àµ‹àµ¾ പതിപàµà´ªà´¿à´¨àµ†à´¯àµ‹ സൈഫർ à´¸àµà´¯àµ‚à´Ÿàµà´Ÿà´¿à´¨àµ†à´¯àµ‹ à´•àµà´²à´¯à´¨àµà´±àµà´‚ സെർവറàµà´‚ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•à´¿à´²àµà´².</translation>
@@ -831,6 +845,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" />-ാം പേജിനàµà´³àµà´³ ലഘàµà´šà´¿à´¤àµà´°à´‚</translation>
<translation id="42981349822642051">വികസിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="4300675098767811073">വലതàµà´µà´¶à´¤àµà´¤àµ à´’à´¨àµà´¨à´¿à´²à´§à´¿à´•à´‚ പഞàµà´šàµà´•àµ¾ ചെയàµà´¯àµà´•</translation>
+<translation id="4302514097724775343">കളികàµà´•à´¾àµ» ദിനോസറിൽ ടാപàµà´ªàµ ചെയàµà´¯àµà´•</translation>
<translation id="4302965934281694568">Chou3 (എൻവലപàµà´ªàµ)</translation>
<translation id="4305666528087210886">നിങàµà´™à´³àµà´Ÿàµ† ഫയൽ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾à´¨à´¾à´¯à´¿à´²àµà´²</translation>
<translation id="4305817255990598646">à´¸àµà´µà´¿à´šàµà´šàµ ചെയàµà´¯àµà´•</translation>
@@ -909,9 +924,10 @@
<translation id="4658638640878098064">à´®àµà´•à´³à´¿àµ½ ഇടതàµà´µà´¶à´¤àµà´¤àµ à´¸àµâ€Œà´±àµà´±àµ‡à´ªàµà´ªà´¿àµ¾ ചെയàµà´¯àµà´•</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">വെർചàµà´µàµ½ റിയാലിറàµà´±à´¿</translation>
+<translation id="4675657451653251260">അതിഥി മോഡിലായിരികàµà´•àµà´®àµà´ªàµ‹àµ¾ നിങàµà´™àµ¾à´•àµà´•àµ Chrome à´ªàµà´°àµŠà´«àµˆà´²àµà´•à´³àµà´Ÿàµ†à´¯àµŠà´¨àµà´¨àµà´‚ വിവരങàµà´™àµ¾ കാണാനാകിലàµà´². പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµà´‚ പേയàµà´®àµ†à´¨àµà´±àµ രീതികളàµà´‚ പോലàµà´³àµà´³ Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ വിവരങàµà´™àµ¾ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» നിങàµà´™àµ¾à´•àµà´•àµ <ph name="LINK_BEGIN" />സൈൻ ഇൻ<ph name="LINK_END" /> ചെയàµà´¯à´¾à´‚.</translation>
<translation id="467662567472608290">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿àµ½ പിശകàµà´•àµ¾ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ കൊണàµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ.</translation>
<translation id="4677585247300749148">à´ªàµà´°à´µàµ‡à´¶à´¨à´•àµà´·à´®à´¤à´¾ ഇവനàµà´±àµà´•à´³àµ‹à´Ÿàµ à´ªàµà´°à´¤à´¿à´•à´°à´¿à´•àµà´•à´¾àµ» <ph name="URL" /> ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
-<translation id="467809019005607715">Google à´¸àµà´²àµˆà´¡àµ</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">വഞàµà´šà´¨à´¾à´ªà´°à´®à´¾à´¯ സൈറàµà´±à´¿àµ½ നിങàµà´™àµ¾ ഇപàµà´ªàµ‹àµ¾ പാസàµâ€à´µàµ‡à´¡àµ നൽകി. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" />, കൂടാതെ നിങàµà´™àµ¾ ഇപàµà´ªàµ‹àµ¾ à´ˆ പാസàµâ€Œà´µàµ‡à´¡àµ ഉപയോഗികàµà´•àµà´¨àµà´¨ മറàµà´±àµ സൈറàµà´±àµà´•àµ¾ à´Žà´¨àµà´¨à´¿à´µà´¯àµâ€Œà´•àµà´•à´¾à´¯à´¿ നിങàµà´™à´³àµà´Ÿàµ† സംരകàµà´·à´¿à´šàµà´š പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ പരിശോധികàµà´•à´¾àµ» Chromium നിർദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="4690462567478992370">അസാധàµà´µà´¾à´¯ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ നിർതàµà´¤àµà´•</translation>
<translation id="4691835149146451662">ആരàµâ€à´•àµà´•à´¿à´Ÿàµ†à´•àµà´šàµà´šà´°àµâ€-A (എൻവലപàµà´ªàµ)</translation>
@@ -936,6 +952,12 @@
<translation id="4761104368405085019">നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ഉപയോഗികàµà´•àµà´•</translation>
<translation id="4764776831041365478"><ph name="URL" /> ലെ വെബàµâ€Œà´ªàµ‡à´œàµ താലàµâ€â€Œà´•àµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ à´ªàµà´°à´µà´°àµâ€â€Œà´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚, à´…à´²àµà´²àµ†à´™àµà´•à´¿à´²àµâ€â€Œ ഒരൠപàµà´¤à´¿à´¯ വെബൠവിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ ശാശàµà´µà´¤à´®à´¾à´¯à´¿ നീകàµà´•à´‚ചെയàµà´¯à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="4766713847338118463">താഴെ ഇരടàµà´Ÿ à´¸àµâ€Œà´±àµà´±àµ‡à´ªàµà´ªà´¿àµ¾ ചെയàµà´¯àµà´•</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ സംരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨ നിങàµà´™à´³àµà´Ÿàµ† ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´ˆ വിൻഡോയിൽ നിങàµà´™àµ¾ ഡൗൺലോഡൠചെയàµà´¯àµà´¨àµà´¨ ഫയലàµà´•à´³àµ†à´²àµà´²à´¾à´‚
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ഒരൠഅജàµà´žà´¾à´¤ പിശകൠസംഭവിചàµà´šàµ.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{പോപàµà´ªàµ-à´…à´ªàµà´ªàµ തടഞàµà´žàµ}other{# പോപàµà´ªàµ-à´…à´ªàµà´ªàµà´•àµ¾ തടഞàµà´žàµ}}</translation>
<translation id="4780366598804516005">മെയിൽബോകàµà´¸àµ 1</translation>
@@ -1098,11 +1120,13 @@
<translation id="5386426401304769735">à´ˆ സൈറàµà´±à´¿à´¨àµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ ചെയിനിൽ SHA-1 ഉപയോഗിചàµà´šàµ സൈൻ ചെയàµâ€Œà´¤ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="538659543871111977">A4-ടാബàµ</translation>
<translation id="5396631636586785122">വലതàµà´µà´¶à´¤àµà´¤àµ അരികൠകൂടàµà´Ÿà´¿à´šàµà´šàµ‡àµ¼à´•àµà´•àµ½</translation>
+<translation id="5398772614898833570">പരസàµà´¯à´™àµà´™àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="5400836586163650660">ചാരനിറം</translation>
<translation id="540969355065856584">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ ഇപàµà´ªàµ‹àµ¾ സാധàµà´¤à´¯àµà´³àµà´³à´¤à´²àµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠആകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ കൊണàµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ.</translation>
<translation id="541416427766103491">à´¸àµà´±àµà´±à´¾à´•àµà´•àµ¼ 4</translation>
<translation id="5421136146218899937">à´¬àµà´°àµ—സിംഗൠഡാറàµà´± മായàµâ€Œà´•àµà´•àµà´•...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> നിങàµà´™àµ¾à´•àµà´•àµ അറിയിപàµà´ªàµà´•àµ¾ അയയàµâ€Œà´•àµà´•à´¾àµ» ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="542872847390508405">നിങàµà´™àµ¾ ഒരൠഅതിഥിയായി à´¬àµà´°àµ—à´¸àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨àµ</translation>
<translation id="5430298929874300616">à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµ നീകàµà´•à´‚ചെയàµà´¯àµà´•</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" à´Žà´¨àµà´¨à´¤à´¿àµ½ à´¸àµâ€Œà´•àµ€à´® മൂലàµà´²àµà´¯à´¨à´¿àµ¼à´£àµà´£à´¯ പിശകàµ: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">വിപരീത à´•àµà´°à´®à´¤àµà´¤à´¿àµ½ ഫേസൠഅപàµà´ªàµ</translation>
@@ -1144,12 +1168,12 @@
<translation id="5571083550517324815">à´ˆ വിലാസതàµà´¤à´¿àµ½ നിനàµà´¨àµ പികàµà´•àµà´…à´ªàµà´ªàµ ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="5580958916614886209">കാലാവധി തീരàµà´¨àµà´¨ മാസം പരിശോധിചàµà´šàµ വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
<translation id="5586446728396275693">സംരകàµà´·à´¿à´šàµà´š വിലാസങàµà´™à´³àµŠà´¨àµà´¨àµà´®à´¿à´²àµà´²</translation>
+<translation id="5593349413089863479">കണകàµà´·àµ» പൂർണàµà´£à´®à´¾à´¯àµà´‚ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="5595485650161345191">വിലാസം à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯àµà´•</translation>
<translation id="5598944008576757369">പേയàµâ€Œà´®àµ†à´¨àµâ€à´±àµ രീതി തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="560412284261940334">മാനേജàµà´®àµ†à´¨àµà´±àµ പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="5605670050355397069">ലെഡàµâ€Œà´œàµ¼</translation>
<translation id="5607240918979444548">ആരàµâ€à´•àµà´•à´¿à´Ÿàµ†à´•àµà´šàµà´šà´°àµâ€-C</translation>
-<translation id="5608165884683734521">à´ˆ സൈറàµà´±àµ à´µàµà´¯à´¾à´œà´®àµ‹ വഞàµà´šà´¨à´¾à´ªà´°à´®àµ‹ ആകാം. à´ˆ സൈറàµà´±àµ ഇപàµà´ªàµ‹àµ¾ വിടാൻ Chrome à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ.</translation>
<translation id="5610142619324316209">കണകàµà´·àµ» പരിശോധികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="5610807607761827392">നിങàµà´™àµ¾à´•àµà´•àµ <ph name="BEGIN_LINK" />à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> കാർഡàµà´•à´³àµà´‚ വിലാസങàµà´™à´³àµà´‚ മാനേജൠചെയàµà´¯à´¾à´‚.</translation>
<translation id="561165882404867731">Google Translate ഉപയോഗിചàµà´šàµ à´ˆ പേജൠവിവർതàµà´¤à´¨à´‚ ചെയàµà´¯àµà´•</translation>
@@ -1221,6 +1245,7 @@
<translation id="5901630391730855834">മഞàµà´ž</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† ഉറവിട നയതàµà´¤à´¿à´¨àµ à´…à´¨àµà´¸àµƒà´¤à´®à´¾à´¯à´¿ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤àµ.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´šàµà´šà´¤àµ)</translation>
+<translation id="5913377024445952699">à´¸àµâ€Œà´•àµà´°àµ€àµ» à´•àµà´¯à´¾à´ªàµâ€Œà´šàµ¼ താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ നിർതàµà´¤à´¿</translation>
<translation id="59174027418879706">à´ªàµà´°à´¾à´ªàµà´¤à´®à´¾à´•àµà´•à´¿</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ഓണാണàµ</translation>
@@ -1233,6 +1258,7 @@
<translation id="5963413905009737549">വിഭാഗം</translation>
<translation id="5967592137238574583">കോൺടാകàµâ€Œà´±àµà´±àµ വിവരം à´Žà´¡à´¿à´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="5967867314010545767">à´šà´°à´¿à´¤àµà´°à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµà´‚ നീകàµà´•à´‚ചെയàµà´¯àµà´•</translation>
+<translation id="5968793460449681917">ഓരോ തവണ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´®àµà´ªàµ‹à´´àµà´‚</translation>
<translation id="5975083100439434680">സൂം ഔടàµà´Ÿàµ ചെയàµà´¯àµà´•</translation>
<translation id="5979084224081478209">പാസàµâ€Œà´µàµ‡à´¡àµ പരിശോധികàµà´•àµ‚</translation>
<translation id="5980920751713728343">സൂചിക-3x5</translation>
@@ -1388,6 +1414,7 @@
<translation id="6587923378399804057">നിങàµà´™àµ¾ പകർതàµà´¤à´¿à´¯ ലിങàµà´•àµ</translation>
<translation id="6591833882275308647">നിങàµà´™à´³àµà´Ÿàµ† <ph name="DEVICE_TYPE" /> മാനേജൠചെയàµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="6596325263575161958">എൻകàµà´°à´¿à´ªàµâ€Œà´·àµ» à´“à´ªàµâ€Œà´·à´¨àµà´•àµ¾</translation>
+<translation id="6596892391065203054">à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµà´®à´¿àµ» à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="6604181099783169992">ചലന à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ വെളിചàµà´š സെൻസറàµà´•àµ¾</translation>
<translation id="6609880536175561541">Prc7 (എൻവലപàµà´ªàµ)</translation>
<translation id="6612358246767739896">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚</translation>
@@ -1447,6 +1474,7 @@
<translation id="6895330447102777224">നിങàµà´™à´³àµà´Ÿàµ† കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´šàµà´šàµ</translation>
<translation id="6897140037006041989">ഉപയോകàµà´¤àµƒ à´à´œà´¨àµâ€à´±àµ</translation>
<translation id="6898699227549475383">à´“à´°àµâ€â€Œà´—നൈസേഷനàµâ€â€Œ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> -നെ ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨à´¤àµ ചെയàµà´¯à´¾àµ» à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•:</translation>
<translation id="6910240653697687763">നിങàµà´™à´³àµà´Ÿàµ† MIDI ഉപകരണങàµà´™à´³àµà´Ÿàµ† പൂർണàµà´£à´®à´¾à´¯ നിയനàµà´¤àµà´°à´£à´‚ à´à´±àµà´±àµ†à´Ÿàµà´•àµà´•à´¾àµ» <ph name="URL" /> ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="6915804003454593391">ഉപയോകàµà´¤à´¾à´µàµ:</translation>
<translation id="6934672428414710184">à´ˆ പേരൠനിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ</translation>
@@ -1466,7 +1494,7 @@
<translation id="6973656660372572881">à´¸àµà´¥à´¿à´°à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ സെർവറàµà´•à´³àµà´‚ ഒരൠസàµâ€Œà´•àµà´°à´¿à´ªàµà´±àµà´±àµ URL-ഉം à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="6973932557599545801">à´•àµà´·à´®à´¿à´•àµà´•à´£à´‚, എനികàµà´•àµ സഹായികàµà´•à´¾àµ» കഴിയിലàµà´², à´¸àµà´µà´¯à´‚ പൂരിപàµà´ªà´¿à´•àµà´•àµà´•.</translation>
<translation id="6975012522936652259">വഞàµà´šà´¨à´¾à´ªà´°à´®à´¾à´¯ സൈറàµà´±à´¿àµ½ നിങàµà´™àµ¾ ഇപàµà´ªàµ‹àµ¾ പാസàµâ€à´µàµ‡à´¡àµ നൽകി. നിങàµà´™àµ¾ à´ˆ പാസàµâ€Œà´µàµ‡à´¡àµ ഉപയോഗികàµà´•àµà´¨àµà´¨ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, മറàµà´±àµ സൈറàµà´±àµà´•àµ¾ à´Žà´¨àµà´¨à´¿à´µà´¯à´¿à´²àµ‡à´•àµà´•àµ പോയി, ഇപàµà´ªàµ‹àµ¾ തനàµà´¨àµ† അതൠമാറàµà´±à´¾àµ» Chromium à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ.</translation>
-<translation id="6979158407327259162">Google à´¡àµà´°àµˆà´µàµ</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">à´®àµà´¯àµ‚à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´• (ഡിഫോൾടàµà´Ÿàµ)</translation>
<translation id="6979983982287291980">നിങàµà´™àµ¾ ഡൗൺലോഡൠചെയàµà´¯àµà´¨àµà´¨ ഫയലàµà´•àµ¾ വിശകലനം ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ Google à´•àµà´²àµ—ഡിലേകàµà´•àµ‹ മൂനàµà´¨à´¾à´‚ à´•à´•àµà´·à´¿à´•àµ¾à´•àµà´•àµ‹ അയയàµà´•àµà´•àµà´¨àµà´¨àµ. ഉദാഹരണതàµà´¤à´¿à´¨àµ, സെൻസിറàµà´±àµ€à´µà´¾à´¯à´¿à´Ÿàµà´Ÿàµà´³àµà´³ à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´¯ ഡാറàµà´±à´¯àµ‹ മാൽവേറോ ഉണàµà´Ÿàµ‹à´¯àµ†à´¨àµà´¨à´±à´¿à´¯à´¾àµ» à´…à´µ à´¸àµâ€Œà´•à´¾àµ» ചെയàµâ€Œà´¤àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="6989763994942163495">വിപàµà´²à´®à´¾à´¯ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ കാണികàµà´•àµà´•...</translation>
@@ -1558,6 +1586,7 @@
<translation id="7346048084945669753">അംഗമായി ഉളàµâ€à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ‹:</translation>
<translation id="7349430561505560861">A4-അധികം</translation>
<translation id="7353601530677266744">കമാനàµâ€à´¡àµ ലൈനàµâ€â€Œ</translation>
+<translation id="7359588939039777303">പരസàµà´¯à´™àµà´™àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ.</translation>
<translation id="7372973238305370288">തിരയൽ ഫലം</translation>
<translation id="7374733840632556089">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµ‹ മറàµà´±à´¾à´°àµ†à´™àµà´•à´¿à´²àµà´®àµ‹ ഇൻസàµà´±àµà´±à´¾àµ¾ ചെ‌യàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഒരൠസർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ കാരണമാണൠഈ à´ªàµà´°à´¶àµâ€Œà´¨à´‚ സംഭവികàµà´•àµà´¨àµà´¨à´¤àµ. നെറàµà´±àµâ€à´µàµ¼à´•àµà´•àµà´•àµ¾ നിരീകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµà´‚ തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´¨àµà´‚ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤à´¾à´¯à´¿ അറിയപàµà´ªàµ†à´Ÿàµà´¨àµà´¨à´¤à´¾à´£àµ à´ˆ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ, Chrome-നൠഇതിനെ വിശàµà´µà´¾à´¸à´®à´¿à´²àµà´². à´¸àµâ€à´•àµ‚ളിലോ à´•à´®àµà´ªà´¨à´¿ നെറàµà´±àµâ€à´µàµ¼à´•àµà´•à´¿à´²àµ‹ ഉളàµà´³à´¤àµà´ªàµ‹à´²àµ†, നിരീകàµà´·à´£à´µàµà´®à´¾à´¯à´¿ ബനàµà´§à´ªàµà´ªàµ†à´Ÿàµà´Ÿ സതàµà´¯à´¨àµà´§à´®à´¾à´¯ à´šà´¿à´² സംഗതികൾ നിലവിലàµà´£àµà´Ÿàµ, നിങàµà´™àµ¾à´•àµà´•à´¿à´¤àµ അവസാനിപàµà´ªà´¿à´•àµà´•à´¾àµ» കഴിയിലàµà´²àµ†à´™àµà´•à´¿à´²àµà´‚ ഇതൠനടകàµà´•àµà´¨àµà´¨àµà´£àµà´Ÿàµ†à´¨àµà´¨àµ നിങàµà´™à´³àµ† അറിയികàµà´•à´¾àµ» Chrome താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. വെബൠആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯àµà´¨àµà´¨ à´à´¤àµ†à´¾à´°àµ à´¬àµà´°àµ—സറിലോ ആപàµà´ªà´¿à´²àµ‹ നിരീകàµà´·à´£à´‚ നടനàµà´¨àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="7375818412732305729">ഫയൽ à´…à´±àµà´±à´¾à´šàµà´šàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾</translation>
@@ -1730,6 +1759,7 @@
<translation id="7976214039405368314">നിരവധി à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•àµ¾</translation>
<translation id="7977538094055660992">ഔടàµà´Ÿàµà´ªàµà´Ÿàµà´Ÿàµ ഉപകരണം</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">à´…à´¨àµà´¬à´¨àµà´§ യാഥാർതàµà´¥àµà´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാണാൻ, ARCore ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¯àµ‚</translation>
<translation id="799149739215780103">ബൈൻഡൠചെയàµà´¯àµà´•</translation>
<translation id="7995512525968007366">à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
<translation id="800218591365569300">ഇടം സൃഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» മറàµà´±àµ ടാബàµà´•à´³àµ‹ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•à´³àµ‹ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤àµ പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
@@ -1857,24 +1887,38 @@
<translation id="8507227106804027148">കമാനàµâ€à´¡àµ ലൈനàµâ€â€Œ</translation>
<translation id="8508648098325802031">തിരയൽ à´à´•àµà´•àµº</translation>
<translation id="8522552481199248698">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ പരിരകàµà´·à´¿à´•àµà´•à´¾à´¨àµà´‚ പാസàµâ€Œà´µàµ‡à´¡àµ മാറàµà´±à´¾à´¨àµà´‚ Chrome സഹായികàµà´•àµà´‚.</translation>
+<translation id="8525306231823319788">പൂരàµâ€à´£àµà´£ à´¸àµà´•àµà´°àµ€à´¨àµâ€</translation>
<translation id="8530813470445476232">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´µàµà´‚ à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ കാഷെയàµà´‚ മറàµà´±àµà´‚ മായàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="8533619373899488139">à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¤ URL-à´•à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿àµ» നടപàµà´ªà´¿à´²à´¾à´•àµà´•à´¿à´¯ മറàµà´±àµ നയങàµà´™à´³àµà´‚ കാണàµà´¨àµà´¨à´¤à´¿à´¨àµ &lt;strong&gt;chrome://policy&lt;/strong&gt; സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
<translation id="8541158209346794904">Bluetooth ഉപകരണം</translation>
<translation id="8542014550340843547">താഴെ മൂനàµà´¨àµ തവണ à´¸àµâ€Œà´±àµà´±àµ‡à´ªàµà´ªà´¿àµ¾ ചെയàµà´¯àµà´•</translation>
<translation id="8543181531796978784">നിങàµà´™àµ¾à´•àµà´•àµ <ph name="BEGIN_ERROR_LINK" />à´¸àµà´°à´•àµà´·à´¾à´ªàµà´°à´¶àµâ€Œà´¨à´‚ റിപàµà´ªàµ‹àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯à´¾à´‚<ph name="END_ERROR_LINK" /> à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½, à´¸àµà´°à´•àµà´·à´¯àµ† ബാധിചàµà´šàµ‡à´•àµà´•à´¾à´µàµà´¨àµà´¨ അപകട സാധàµà´¯à´¤à´•à´³àµ†à´•àµà´•àµà´±à´¿à´šàµà´šàµ ബോധàµà´¯à´®àµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½ <ph name="BEGIN_LINK" />à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ à´ˆ സൈറàµà´±àµ<ph name="END_LINK" />സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
<translation id="8557066899867184262">കാർഡിനൠപിനàµà´¨à´¿à´²à´¾à´£àµ CVC രേഖപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ.</translation>
+<translation id="8558485628462305855">à´…à´¨àµà´¬à´¨àµà´§ യാഥാർതàµà´¥àµà´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാണാൻ, ARCore à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯àµ‚</translation>
<translation id="8559762987265718583">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† തീയതിയàµà´‚ സമയവàµà´‚ (<ph name="DATE_AND_TIME" />) തെറàµà´±à´¾à´¯à´¤à´¿à´¨à´¾àµ½ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ à´¸àµà´µà´•à´¾à´°àµà´¯ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
<translation id="8564182942834072828">വെവàµà´µàµ‡à´±àµ† ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµà´•àµ¾/à´•àµà´°à´®à´¤àµà´¤à´¿à´²à´²àµà´²à´¾à´¤àµà´¤ പകർപàµà´ªàµà´•àµ¾</translation>
<translation id="8564985650692024650">മറàµà´±àµ സൈറàµà´±àµà´•à´³à´¿àµ½ നിങàµà´™àµ¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> പാസàµâ€Œà´µàµ‡à´¡àµ à´ªàµà´¨à´°àµà´ªà´¯àµ‹à´—à´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½, അതൠറീസെറàµà´±àµ ചെയàµà´¯à´¾àµ» Chromium à´¶àµà´ªà´¾àµ¼â€Œà´¶ ചെയàµà´¯àµà´¨àµà´¨àµ.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ സംരകàµà´·à´¿à´•àµà´•à´¾à´¤àµà´¤ ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´ˆ വിൻഡോയിൽ നിങàµà´™àµ¾ കാണàµà´¨àµà´¨ പേജàµà´•àµ¾
+ <ph name="LIST_ITEM" />à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">കാർഡàµà´•àµ¾ വേഗതàµà´¤à´¿àµ½ à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•à´¾àµ» à´Ÿà´šàµà´šàµ à´à´¡à´¿ ഉപയോഗികàµà´•àµà´•</translation>
<translation id="858637041960032120">ഫോണàµâ€ നമàµà´ªà´°àµâ€ ചേരàµâ€à´•àµà´•àµà´•</translation>
<translation id="8589998999637048520">à´à´±àµà´±à´µàµà´‚ മികചàµà´š നിലവാരം</translation>
+<translation id="8600271352425265729">ഇപàµà´ªàµ‹à´´à´¤àµà´¤àµ‡à´•àµà´•àµ മാതàµà´°à´‚</translation>
<translation id="860043288473659153">കാർഡിനàµà´±àµ† ഉടമയàµà´Ÿàµ† പേരàµ</translation>
<translation id="8606726445206553943">നിങàµà´™à´³àµà´Ÿàµ† MIDI ഉപകരണങàµà´™àµ¾ ഉപയോഗികàµà´•àµà´•</translation>
+<translation id="8612761427948161954">ഹായൠ<ph name="USERNAME" />,
+ <ph name="BR" />
+ നിങàµà´™àµ¾ ഒരൠഅതിഥിയായി à´¬àµà´°àµ—സൠചെയàµà´¯àµà´¨àµà´¨àµ</translation>
<translation id="861775596732816396">വലàµà´ªàµà´ªà´‚ 4</translation>
<translation id="8622948367223941507">നിയമപരം-അധികം</translation>
<translation id="8623885649813806493">പൊരàµà´¤àµà´¤à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨ പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµŠà´¨àµà´¨àµà´®à´¿à´²àµà´². സംരകàµà´·à´¿à´šàµà´š à´Žà´²àµà´²à´¾ പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµà´‚ കാണികàµà´•àµà´•.</translation>
<translation id="8625384913736129811">à´ˆ ഉപകരണതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ à´ˆ കാർഡൠസംരകàµà´·à´¿à´•àµà´•àµà´•</translation>
+<translation id="8627040765059109009">à´¸àµâ€Œà´•àµà´°àµ€àµ» à´•àµà´¯à´¾à´ªàµâ€Œà´šàµ¼ à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´šàµà´šàµ</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ <ph name="VM_NAME_1" />, <ph name="VM_NAME_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯à´¿à´²àµ‡à´•àµà´•àµ പങàµà´•à´¿à´Ÿàµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµà´®à´¿àµ» à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤àµ</translation>
<translation id="8663226718884576429">ഓർഡർ സംഗàµà´°à´¹à´‚, <ph name="TOTAL_LABEL" />, കൂടàµà´¤àµ½ വിശദാംശങàµà´™àµ¾</translation>
<translation id="867224526087042813">à´’à´ªàµà´ªàµ</translation>
@@ -1937,6 +1981,7 @@
<translation id="8912362522468806198">Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ</translation>
<translation id="8913778647360618320">'പേയàµâ€Œà´®àµ†à´¨àµà´±àµ രീതികൾ മാനേജൠചെയàµà´¯àµà´•' ബടàµà´Ÿàµº, Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† പേയàµâ€Œà´®àµ†à´¨àµà´±àµà´•à´³àµà´‚ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠവിവരങàµà´™à´³àµà´‚ മാനേജൠചെയàµà´¯à´¾àµ» 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="8918231688545606538">à´ˆ പേജൠസംശയാസàµà´ªà´¦à´®à´¾à´£àµ</translation>
+<translation id="8922013791253848639">à´ˆ സൈറàµà´±à´¿àµ½ à´Žà´²àµà´²à´¾à´¯àµâ€Œà´ªàµà´ªàµ‹à´´àµà´‚ പരസàµà´¯à´™àµà´™àµ¾ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="892588693504540538">à´®àµà´•à´³à´¿àµ½ വലതàµà´µà´¶à´¤àµà´¤àµ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
<translation id="8931333241327730545">à´ˆ കാർഡൠനിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ സംരകàµà´·à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="8932102934695377596">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ വളരെ പിനàµà´¨à´¿à´²à´¾à´£àµ</translation>
@@ -2005,21 +2050,24 @@
<translation id="917450738466192189">സെർവറിനàµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ അസാധàµà´µà´¾à´£àµ.</translation>
<translation id="9174917557437862841">ടാബൠമാറാനàµà´³àµà´³ ബടàµà´Ÿàµº, à´ˆ ടാബിലേകàµà´•àµ മാറാൻ എൻàµà´±àµ¼ അമർതàµà´¤àµà´•</translation>
<translation id="9179703756951298733">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† പേയàµâ€Œà´®àµ†à´¨àµà´±àµà´•à´³àµà´‚ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠവിവരങàµà´™à´³àµà´‚ മാനേജൠചെയàµà´¯àµà´•</translation>
-<translation id="9183302530794969518">Google ഡോകàµâ€Œà´¸àµ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•à´¾à´¤àµà´¤ ഒരൠപàµà´°àµ‹à´Ÿàµà´Ÿàµ‹à´•àµà´•àµ‹à´³à´¾à´£àµ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ.</translation>
<translation id="9191834167571392248">താഴെ ഇടതàµà´µà´¶à´¤àµà´¤àµ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
+<translation id="9199905725844810519">à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµ½ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="9205078245616868884">നിങàµà´™à´³àµà´Ÿàµ† സമനàµà´µà´¯ പാസàµâ€Œà´«àµà´°àµ†à´¯àµâ€Œà´¸àµ ഉപയോഗിചàµà´šàµ ഡാറàµà´± എൻകàµà´°à´¿à´ªàµâ€Œà´±àµà´±àµ ചെയàµâ€Œà´¤àµ. സമനàµà´µà´¯à´‚ ആരംഭികàµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ ഇതൠനൽകàµà´•.</translation>
<translation id="9207861905230894330">ലേഖനം ചേർകàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="9213433120051936369">ദൃശàµà´¯à´®à´¾à´•àµà´¨àµà´¨ രീതി ഇഷàµà´Ÿà´¾à´¨àµà´¸àµƒà´¤à´®à´¾à´•àµà´•àµà´•</translation>
<translation id="9215416866750762878">à´ˆ സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯à´¿ കണകàµà´±àµà´±àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ Chrome-നെ ഒരൠആപàµà´ªàµ തടയàµà´¨àµà´¨àµ</translation>
-<translation id="9219103736887031265">à´šà´¿à´¤àµà´°à´™àµà´™àµ¾â€Œ</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ഫോം മായàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="936474030629450166">സൂപàµà´ªàµ¼-B</translation>
<translation id="936602727769022409">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµâ€Œà´¸à´¸àµ നഷàµâ€Œà´Ÿà´ªàµà´ªàµ†à´Ÿà´¾à´¨à´¿à´Ÿà´¯àµà´£àµà´Ÿàµ. ഇപàµà´ªàµ‹àµ¾ തനàµà´¨àµ† പാസàµâ€Œà´µàµ‡à´¡àµ മാറàµà´±à´¾àµ» Chromium à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ. സൈൻ ഇൻ ചെയàµà´¯à´¾àµ» നിങàµà´™à´³àµ‹à´Ÿàµ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿàµà´‚.</translation>
<translation id="939736085109172342">à´ªàµà´¤à´¿à´¯ ഫോളàµâ€à´¡à´°àµâ€</translation>
+<translation id="945522503751344254">ഫീഡàµâ€Œà´¬à´¾à´•àµà´•àµ അയയàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="945855313015696284">à´šàµà´µà´Ÿàµ†à´¯àµà´³àµà´³ വിവരം പരിശോധിചàµà´šàµ, അസാധàµà´µà´¾à´¯ കാരàµâ€à´¡àµà´•à´³àµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½ à´…à´µ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´•</translation>
<translation id="950736567201356821">à´®àµà´•à´³à´¿àµ½ മൂനàµà´¨àµ തവണ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
+<translation id="951941430552851965">à´¸àµâ€Œà´•àµà´°àµ€à´¨à´¿à´²àµ† ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാരണം à´¸àµà´•àµà´°àµ€àµ» à´•àµà´¯à´¾à´ªàµâ€Œà´šàµ¼ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ നിർതàµà´¤à´¿.</translation>
<translation id="961663415146723894">താഴെ ബൈൻഡൠചെയàµà´¯àµà´•</translation>
<translation id="962484866189421427">മറàµà´±àµ†à´¨àµà´¤àµ†à´™àµà´•à´¿à´²àµà´‚ ആണെനàµà´¨àµ അവകാശപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ നിങàµà´™à´³àµ† à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯à´¾àµ» ഉപയോഗിചàµà´šàµ‡à´•àµà´•à´¾à´µàµà´¨àµà´¨ ഡാറàµà´± ശേഖരികàµà´•àµà´¨àµà´¨, തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨ ആപàµà´ªàµà´•àµ¾ ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´¶àµà´°à´®à´¿à´šàµà´šàµ‡à´•àµà´•à´¾à´‚. <ph name="BEGIN_LINK" />à´Žà´¨àµà´¤à´¾à´¯à´¾à´²àµà´‚ കാണികàµà´•àµà´•<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ഔദàµà´¯àµ‹à´—à´¿à´• ബിലàµâ€à´¡àµ</translation>
diff --git a/chromium/components/strings/components_strings_mn.xtb b/chromium/components/strings/components_strings_mn.xtb
index 79a4fe522f1..ebe46fa8f79 100644
--- a/chromium/components/strings/components_strings_mn.xtb
+++ b/chromium/components/strings/components_strings_mn.xtb
@@ -80,10 +80,18 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Та нууц үгÑÑ Ñ‚Ð°Ð½Ð°Ð¹ байгууллагын удирддаггүй Ñайтад оруулÑан байна. БүртгÑлÑÑ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ñ…Ñ‹Ð½ тулд буÑад апп болон Ñайтад нууц үгÑÑ Ð´Ð°Ñ…Ð¸Ð½ бүү ашиглана уу.</translation>
<translation id="1263231323834454256">Унших жагÑаалт</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ үлдÑхгүй үйл ажиллагаа:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Таны ÑÐ½Ñ Ñ†Ð¾Ð½Ñ…Ð¾Ð½Ð´ үзÑÑн хуудаÑнууд
+ <ph name="LIST_ITEM" />Күүки болон Ñайтын өгөгдөл
+ <ph name="LIST_ITEM" />БүртгÑлийн мÑдÑÑлÑл (<ph name="LINK_BEGIN" />гарах<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ðвах төрөл</translation>
<translation id="1281476433249504884">Гарах цааÑыг зÑÑ€ÑгцүүлÑÑ… тавцан 1</translation>
<translation id="1285320974508926690">Ð­Ð½Ñ Ñайтыг Ñ…ÑзÑÑ Ñ‡ бүү хөрвүүл</translation>
-<translation id="1292701964462482250">"Таны компьютер дÑÑрх программ хангамж Chrome-г вÑбÑд аюулгүй холбогдохыг зогÑоож байна" (зөвхөн Windows компьютерт боломжтой)</translation>
+<translation id="1292701964462482250">"Таны компьютер дÑÑрх программ хангамж Chrome-г вебÑд аюулгүй холбогдохыг зогÑоож байна" (зөвхөн Windows компьютерт боломжтой)</translation>
<translation id="1294154142200295408">Тушаалын мөрийн хувилбар</translation>
<translation id="129553762522093515">СаÑхан хаагдÑан</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />КүүкигÑÑ ÑƒÑтгана уу<ph name="END_LINK" /></translation>
@@ -231,7 +239,7 @@
Ñайтад зориулж аюулгүй байдал болон буÑад шинж чанарыг тохируулахад Ñайтын оператор ашиглаж болно.</translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1783075131180517613">Та өөрийн тохиргоо хийдÑг нууц үгийг шинÑчлÑÐ½Ñ Ò¯Ò¯.</translation>
-<translation id="1787142507584202372">Таны нÑÑлттÑй чихтÑй Ñ…ÑƒÑƒÐ´Ð°Ñ Ñнд харагдана</translation>
+<translation id="1787142507584202372">Таны нÑÑлттÑй таб Ñнд харагдана</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1798447301915465742"><ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT" />, олон үйлдÑл хийх боломжтой, үйлдÑл хооронд шилжихийн тулд Таб дÑÑÑ€ дарна уу</translation>
<translation id="1800473098294731951">B9</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Google БүртгÑлдÑÑ Ñ…Ð°Ð´Ð³Ð°Ð»Ñан нууц үгÑийг ашиглахын тулд нÑвтрÑÑ…</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> Ñ…Ñл дÑÑрх хуудÑыг орчуулахгүй.</translation>
<translation id="2053553514270667976">Зип Код</translation>
+<translation id="2054665754582400095">Таны байгаа ÑÑÑÑ…</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 зөвлөмж}other{# зөвлөмж}}</translation>
<translation id="2079545284768500474">Буцаах</translation>
<translation id="20817612488360358">СиÑтемийн прокÑи-гийн тохиргоонуудыг ашиглахаар ÑуулгаÑан Ñ…Ñдий ч прокÑи-гийн нарийн тохиргоог зааж өгÑөн байна.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Ðндройд апп</translation>
<translation id="2107021941795971877">Ð¥ÑвлÑлийн дÑмжлÑг</translation>
<translation id="2108755909498034140">Компьютероо дахин ÑхлүүлÑÑ…</translation>
+<translation id="2111166930115883695">Тоглохын тулд space дÑÑÑ€ дарна уу</translation>
<translation id="2111256659903765347">Супер-A</translation>
<translation id="2113977810652731515">Карт</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> нь өөрчилÑөн учир ÑÐ½Ñ Ð¶ÑƒÑ€Ð°Ð¼ хүчингүй.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Төлбөрийг цуцлах</translation>
<translation id="2147827593068025794">Цаана Ñинк хийх</translation>
<translation id="2148613324460538318">Карт нÑмÑÑ…</translation>
+<translation id="2149968176347646218">Холболт аюултай байна</translation>
<translation id="2154054054215849342">Таны домайнд Ñинк хийх боломжгүй байна</translation>
<translation id="2154484045852737596">Картыг заÑах</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Тохиргоонууд</translation>
<translation id="2183608646556468874">УтаÑны дугаар</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 хаÑг}other{# хаÑг}}</translation>
-<translation id="2187243482123994665">Ð¥ÑÑ€ÑглÑгч байгаа ÑÑÑÑ…</translation>
<translation id="2187317261103489799">ИлрүүлÑÑ… (өгөгдмөл)</translation>
<translation id="2188375229972301266">Доод буланд олон нүх цоолох</translation>
<translation id="2202020181578195191">ДууÑах оныг зөв оруулна уу</translation>
@@ -424,7 +434,7 @@
<translation id="2660779039299703961">Үйл Ñвдал</translation>
<translation id="2664887757054927933">{COUNT,plural, =0{Байхгүй}=1{(<ph name="DOMAIN_LIST" />-н) 1 нууц үг}=2{(<ph name="DOMAIN_LIST" />-н) 2 нууц үг}other{(<ph name="DOMAIN_LIST" />-н) # нууц үг}}</translation>
<translation id="2666092431469916601">ДÑÑд</translation>
-<translation id="2666117266261740852">БуÑад чихтÑй хуудаÑ, аппыг хаах</translation>
+<translation id="2666117266261740852">БуÑад таб, аппыг хаах</translation>
<translation id="2672201172023654893">Таны хөтчийг удирдаагүй байна.</translation>
<translation id="2674170444375937751">Та өөрийн түүхÑÑÑ ÑдгÑÑÑ€ хуудÑыг уÑтгахдаа итгÑлтÑй байна уу?</translation>
<translation id="2674804415323431591">Зөвлөмжүүдийг нуух</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Хуурамч Ñайт байна</translation>
<translation id="2850739647070081192">Урилга (Дугтуй)</translation>
<translation id="2856444702002559011">Халдагчид <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-Ñ Ñ‚Ð°Ð½Ñ‹ нууц үг, меÑÑеж, кредит карт зÑÑ€Ñг мÑдÑÑллийг хулгайлахаар оролдож байж болзошгүй. <ph name="BEGIN_LEARN_MORE_LINK" />ДÑлгÑÑ€Ñнгүй үзÑÑ…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ð­Ð½Ñ Ñайт төвөгтÑй ÑÑвÑл хуурамч зар харуулдаг.</translation>
<translation id="2878197950673342043">ПоÑтерын нугалаа</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Цонх байршуулалт</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google-н зөвлөмж</translation>
<translation id="3002501248619246229">Оролтын цааÑны медиаг Ñ…Ñнах</translation>
<translation id="3005723025932146533">ХадгалагдÑан хуулбарыг харуулах</translation>
-<translation id="3007719053326478567">Таны админиÑтратор ÑÐ½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚Ñ‹Ð³ Ñ…ÑвлÑхийг блоклоÑон</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />-н карт баталгаажуулалтын кодыг оруулна уу. БаталгаажуулÑны дараагаар таны картын дÑлгÑÑ€Ñнгүйг ÑÐ½Ñ Ñайтад хуваалцах болно.</translation>
<translation id="3010559122411665027">Оруулалтын жагÑаалт "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Ðвтоматаар блок хийÑÑн</translation>
<translation id="3016780570757425217">Байршлаа мÑдÑж аваарай</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Зөвлөмжийг хаÑахын тулд Tab дÑÑÑ€ дараа нь Enter дÑÑÑ€ дарна уу.</translation>
<translation id="3023071826883856138">You4 (Дугтуй)</translation>
<translation id="3024663005179499861">Буруу журмын төрөл</translation>
<translation id="3037605927509011580">Aw, Snap!</translation>
@@ -540,7 +551,7 @@
<translation id="3154506275960390542">Ð­Ð½Ñ Ñ…ÑƒÑƒÐ´Ð°Ñ Ð½ÑŒ илгÑÑÑ…Ñд аюултай байж болзошгүй маÑгтыг агуулдаг. Таны илгÑÑÑ… өгөгдлийг шилжүүлÑÑ… зуур буÑад Ñ…Ò¯Ð¼Ò¯Ò¯Ñ Ñ…Ð°Ñ€Ð°Ñ…, халдагч ÑтгÑÑд Ñерверийн хүлÑÑн авах зүйлийг өөрчлөх боломжтой.</translation>
<translation id="3157931365184549694">Дахин ÑÑргÑÑÑ…</translation>
<translation id="3162559335345991374">Таны ашиглаж буй Wi-Fi ÑүлжÑÑ Ñ‚Ð°Ð½Ñ‹Ð³ нÑвтрÑÑ… хуудаÑÑ‚ орохыг шаардах магадлалтай.</translation>
-<translation id="3167968892399408617">Ðууцлалын чихтÑй хуудÑанд хардаг чихтÑй хуудÑыг хааÑан үед таны хөтчийн түүх, күүки дÑлгүүр, хайлтын түүхÑнд харагдахгүй. Таны татÑан файл болон Ò¯Ò¯ÑгÑÑÑн хавчуургыг хадгалах болно.</translation>
+<translation id="3167968892399408617">Ðууцлалын табад хардаг чихтÑй хуудÑыг хааÑан үед таны хөтчийн түүх, күүки дÑлгүүр, хайлтын түүхÑнд харагдахгүй. Таны татÑан файл болон Ò¯Ò¯ÑгÑÑÑн хавчуургыг хадгалах болно.</translation>
<translation id="3169472444629675720">Олох</translation>
<translation id="3174168572213147020">Ðрал</translation>
<translation id="3176929007561373547">ПрокÑи тохиргоогоо шалгана уу. ЭÑвÑл ÑүлжÑÑний админтайгаа холбогдож 
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">Хавчуурга хадгалагдÑан</translation>
<translation id="3209034400446768650">Ð¥ÑƒÑƒÐ´Ð°Ñ Ñ‚Ó©Ð»Ð±Ó©Ñ€ нÑÑ…Ñмжилж болзошгүй</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> дÑÑрх таны үйл ажиллагааг Ñ…Ñнаж байна</translation>
+<translation id="3212623355668894776">Бүх Зочин цонхыг хааÑнаар таны хөтчийн үйл ажиллагаа ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ÑÑÑ ÑƒÑтана.</translation>
<translation id="3215092763954878852">WebAuthn-г ашиглаж чадÑангүй</translation>
<translation id="3218181027817787318">Харьцангуй</translation>
<translation id="3225919329040284222">Ð¡ÐµÑ€Ð²ÐµÑ€Ó©Ó©Ñ Ó©Ð³Ñөн гÑрчилгÑÑ Ð½ÑŒ өгөгдÑөн хүлÑÑлттÑй таарахгүй байна. ЭдгÑÑÑ€ хүлÑÑлтүүдийг таныг хамгаалахын тулд тодорхой, аюулгүйн өндөр зÑÑ€ÑглÑлийн
@@ -703,6 +715,7 @@
<translation id="3784372983762739446">Bluetooth төхөөрөмжүүд</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" />-д дууÑна</translation>
<translation id="3789155188480882154">Ð¥ÑмжÑÑ 16</translation>
+<translation id="3789841737615482174">Суулгах</translation>
<translation id="3793574014653384240">Сүүлийн үед гарÑан гÑмтлийн тоо болон шалтгаан</translation>
<translation id="3797522431967816232">Prc3 (Дугтуй)</translation>
<translation id="3799805948399000906">Фонтын нÑрийг шаардÑан</translation>
@@ -744,7 +757,7 @@
<translation id="3987405730340719549">Ð­Ð½Ñ Ñайт нь хуурамч ÑÑвÑл залилангийн шинжтÑй байж болно гÑж Chrome тодорхойлÑон.
Ð¥ÑÑ€Ñв та үүнийг харуулÑан нь алдаа гÑж үзÑж байвал https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals-Ñ€ зочлоорой.</translation>
-<translation id="3987940399970879459">1 Ð¼ÐµÐ³Ð°Ð±Ð°Ð¹Ñ‚Ð°Ð°Ñ Ð±Ð°Ð³Ð°</translation>
+<translation id="3987940399970879459">1 МБ-Ð°Ð°Ñ Ð±Ð°Ð³Ð°</translation>
<translation id="3990250421422698716">ШилжүүлÑн байрлуулах оффÑет</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> Ñайт үндÑÑн удирдамжийг
бүх Ñ…Ò¯ÑÑлтдÑÑ Ñ…ÑÑ€ÑгжүүлÑÑ… Ñ…Ò¯ÑÑлт тавьÑан Ñ…Ñдий ч ÑÐ½Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¼Ð¶Ð¸Ð¹Ð³ одоогоор Ñ…ÑÑ€ÑгжүүлÑÑ… боломжгүй байна.</translation>
@@ -754,6 +767,7 @@
<translation id="4056223980640387499">Сепиа</translation>
<translation id="4058922952496707368">Түлхүүр "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Дугтуй)</translation>
+<translation id="4067669230157909013">ДÑлгÑцийн зураг авахыг үргÑлжлүүлÑÑн.</translation>
<translation id="4067947977115446013">ХүчинтÑй хаÑг нÑмÑÑ…</translation>
<translation id="4072486802667267160">Таны захиалгыг боловÑруулахад алдаа гарлаa. Дахин оролдоно уу.</translation>
<translation id="4075732493274867456">ҮйлчлүүлÑгч болон Ñервер нь SSL протоколын нийтлÑг хувилбар, ÑÑвÑл шифрийн бүрдлийг дÑмждÑггүй.</translation>
@@ -838,6 +852,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> хуудаÑны өнгөц зураг</translation>
<translation id="42981349822642051">Өргөтгөх</translation>
<translation id="4300675098767811073">Баруун ирмÑг дагуу олон нүх цоолох</translation>
+<translation id="4302514097724775343">Тоглохын тулд диног товшино уу</translation>
<translation id="4302965934281694568">Chou3 (Дугтуй)</translation>
<translation id="4305666528087210886">Таны файлд хандаж чадÑангүй</translation>
<translation id="4305817255990598646">СÑлгÑÑ…</translation>
@@ -916,9 +931,10 @@
<translation id="4658638640878098064">Зүүн дÑÑд буланд үдÑÑ…</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуал бодит байдал</translation>
+<translation id="4675657451653251260">Та Зочны горимд Chrome профайлын Ñмар ч мÑдÑÑлÑл харахгүй. Та нууц үг, төлбөрийн Ñ…ÑÑ€ÑгÑÑл зÑÑ€Ñг Google БүртгÑлийнхÑÑ Ð¼ÑдÑÑлÑлд хандахын тулд <ph name="LINK_BEGIN" />нÑвтрÑÑ…<ph name="LINK_END" /> боломжтой.</translation>
<translation id="467662567472608290">Ð­Ð½Ñ Ñервер нь <ph name="DOMAIN" />-аа баталж чадÑангүй; мөн Ñерверийн хамгаалалтын Ñертификат нь алдаа агуулж байна. Ð­Ð½Ñ Ð½ÑŒ тохиргоо буруу хийгдÑÑнÑÑÑ ÑÑвÑл халдагч таны холболтонд Ñаад болж байж болох юм.</translation>
<translation id="4677585247300749148"><ph name="URL" /> хүртÑÑмжийн үйл ажиллагаанд хариу өгөх Ñ…Ò¯ÑÑлтÑй байна</translation>
-<translation id="467809019005607715">Google ҮзүүлÑн</translation>
+<translation id="467809019005607715">Google Слайд</translation>
<translation id="4680804919228900307">Та дөнгөж ÑÐ°Ñ ÑÑжигтÑй Ñайтад нууц үгÑÑ Ð¾Ñ€ÑƒÑƒÐ»Ð»Ð°Ð°. Таны ÑÐ½Ñ Ð½ÑƒÑƒÑ† үгийг ашигладаг <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> болон буÑад Ñайтын хувьд хадгалÑан нууц үгÑÑÑ Ð¾Ð´Ð¾Ð¾ шалгахыг Chromium зөвлөж байна.</translation>
<translation id="4690462567478992370">Хүчингүй Ñертификат ашиглахыг зогÑоох</translation>
<translation id="4691835149146451662">Ðрхитектур-A (Дугтуй)</translation>
@@ -943,11 +959,17 @@
<translation id="4761104368405085019">Микрофоноо ашигла</translation>
<translation id="4764776831041365478"><ph name="URL" /> Ñ…Ð¾Ð»Ð±Ð¾Ð¾Ñ Ð±Ò¯Ñ…Ð¸Ð¹ веб Ñ…ÑƒÑƒÐ´Ð°Ñ Ð½ÑŒ түр хугацаагаар ажиллахгүй ÑÑвÑл ÑˆÐ¸Ð½Ñ Ð²ÐµÐ± хаÑгтай болÑон байна.</translation>
<translation id="4766713847338118463">Доод буланд хоёр удаа үдÑÑ…</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ үлдÑÑ… таны үйл ажиллагаа:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Таны ÑÐ½Ñ Ñ†Ð¾Ð½Ñ…Ð¾Ð½Ð´ татÑан аливаа файл
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Үл мÑдÑгдÑÑ… алдаа гарлаа.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ҮзÑгдÑÑ… зүйлийг блоклоÑон}other{# үзÑгдÑÑ… зүйлийг блоклоÑон}}</translation>
<translation id="4780366598804516005">Шуудангийн хайрцаг 1</translation>
<translation id="4780900888022378816">Таны төхөөрөмжийг <ph name="ENROLLMENT_DOMAIN" />-Ñ, харин таны бүртгÑлийг <ph name="ACCOUNT_DOMAIN" />-Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¶ байна.</translation>
-<translation id="4785689107224900852">Ð­Ð½Ñ Ñ‡Ð¸Ñ…Ñ‚Ñй Ñ…ÑƒÑƒÐ´Ð°Ñ Ñ€ÑƒÑƒ ÑÑлгÑÑ…</translation>
+<translation id="4785689107224900852">Ð­Ð½Ñ Ñ‚Ð°Ð± руу ÑÑлгÑÑ…</translation>
<translation id="4791134497475588553">Linux-н апп ÑуулгагдÑан болон Ñ…ÑзÑÑ Ñ…Ð°Ð¼Ð³Ð¸Ð¹Ð½ Ñүүлд түүнийг ашиглаÑан</translation>
<translation id="4792686369684665359">Таны илгÑÑÑ… гÑж буй мÑдÑÑлÑл аюултай байна</translation>
<translation id="4796594887379589189">Ðжилтай холбоотой бүртгÑлийн ID</translation>
@@ -1105,11 +1127,13 @@
<translation id="5386426401304769735">Ð­Ð½Ñ Ñайтын Ñертификатын Ñ…ÑлхÑÑ Ð½ÑŒ SHA-1-г ашиглан баталгаажуулÑан байна.</translation>
<translation id="538659543871111977">A4-Таб</translation>
<translation id="5396631636586785122">Баруун ирмÑгийг нь нийлүүлж үдÑÑ…</translation>
+<translation id="5398772614898833570">Зарыг блоклоÑон</translation>
<translation id="5400836586163650660">Саарал</translation>
<translation id="540969355065856584">Ð­Ð½Ñ Ñервер нь <ph name="DOMAIN" /> гÑдгÑÑ Ð±Ð°Ñ‚Ð°Ð»Ð¶ чадÑангүй. Учир нь Ñерверийн аюулгүй байдлын гÑрчилгÑÑ Ð½ÑŒ одоогоор хүчин төгөлдөр Ð±ÑƒÑ Ð±Ð°Ð¹Ð½Ð°. Ð­Ð½Ñ Ð°Ð»Ð´Ð°Ð° нь тохиргоо буруу хийгдÑÑнÑÑÑ, ÑÑвÑл халдагч таны холболтонд Ñаад учруулж Ð±Ð°Ð¹Ð³Ð°Ð°Ð³Ð°Ð°Ñ ÑˆÐ°Ð»Ñ‚Ð³Ð°Ð°Ð»Ð¶ болзошгүй.</translation>
<translation id="541416427766103491">Гарах цааÑыг зÑÑ€ÑгцүүлÑÑ… тавцан 4</translation>
<translation id="5421136146218899937">Хайлт хийÑÑн тухай мÑдÑÑллийг арилгах...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> танд мÑдÑгдÑл илгÑÑÑ… Ñ…Ò¯ÑÑлтÑй байна</translation>
+<translation id="542872847390508405">Та зочны хувиар хайлт хийж байна.</translation>
<translation id="5430298929874300616">Хавчуургыг уÑтга</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />":<ph name="ERROR" /> дÑÑ… Ñхемийн баталгаажуулахад гарÑан алдаа</translation>
<translation id="5443468954631487277">ÐүүрÑÑÑ€ нь дÑÑш харуулж, хуудаÑны урвуу дарааллаар</translation>
@@ -1151,12 +1175,12 @@
<translation id="5571083550517324815">Ð­Ð½Ñ Ñ…Ð°ÑÐ³Ð°Ð°Ñ Ð°Ð²Ð°Ñ… боломжгүй тул Ó©Ó©Ñ€ хаÑг Ñонгоно уу.</translation>
<translation id="5580958916614886209">Хүчингүй болох Ñарыг шалгаад дахин оролдоно уу</translation>
<translation id="5586446728396275693">ХадгалÑан хаÑг байхгүй</translation>
+<translation id="5593349413089863479">Холболт бүрÑн аюулгүй биш байна</translation>
<translation id="5595485650161345191">ХаÑгийг заÑах</translation>
<translation id="5598944008576757369">Төлбөрийн Ñ…ÑÑ€ÑгÑÑл Ñонгох</translation>
<translation id="560412284261940334">Удирдлагын зүгÑÑÑ Ð·Ó©Ð²ÑˆÓ©Ó©Ñ€Ó©Ð» олгоогүй байна</translation>
<translation id="5605670050355397069">Тайлан</translation>
<translation id="5607240918979444548">Ðрхитектур-C</translation>
-<translation id="5608165884683734521">Ð­Ð½Ñ Ñайт хуурамч ÑÑвÑл залилангийн шинжтÑй байж болно. Chrome одоо орхихыг Ñанал болгож байна.</translation>
<translation id="5610142619324316209">Холболтыг шалгаж байна</translation>
<translation id="5610807607761827392">Та карт, хаÑгийг <ph name="BEGIN_LINK" />Тохиргоо<ph name="END_LINK" /> Ñ…ÑÑÑгт удирдах боломжтой.</translation>
<translation id="561165882404867731">Ð­Ð½Ñ Ñ…ÑƒÑƒÐ´Ñыг Google Орчуулагчаар орчуулах</translation>
@@ -1228,6 +1252,7 @@
<translation id="5901630391730855834">Шар</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />-н үндÑÑн удирдамжийн дагуу хориглоÑон.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинк хийÑÑн)</translation>
+<translation id="5913377024445952699">ДÑлгÑцийн зураг авахыг түр зогÑооÑон</translation>
<translation id="59174027418879706">ИдÑвхжÑÑн</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ÐÑаалттай</translation>
@@ -1240,6 +1265,7 @@
<translation id="5963413905009737549">Ð¥ÑÑÑг</translation>
<translation id="5967592137238574583">Харилцагчийн мÑдÑÑллийг заÑах</translation>
<translation id="5967867314010545767">ТүүхÑн Ñ…ÑÑгÑÑÑ ÑƒÑтгах</translation>
+<translation id="5968793460449681917">Зочлох бүрд</translation>
<translation id="5975083100439434680">БагаÑгаж харах</translation>
<translation id="5979084224081478209">Ðууц үгийг шалгах</translation>
<translation id="5980920751713728343">ИндекÑ-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">Таны хуулÑан холбооÑ</translation>
<translation id="6591833882275308647">Таны <ph name="DEVICE_TYPE" />-г удирдаагүй байна</translation>
<translation id="6596325263575161958">ШифрлÑлтийн Ñонголтууд</translation>
+<translation id="6596892391065203054">Таны админиÑтратор ÑÐ½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚Ñ‹Ð³ Ñ…ÑвлÑхийг блоклоÑон.</translation>
<translation id="6604181099783169992">Хөдөлгөөн ÑÑвÑл гÑÑ€Ñл мÑдрÑгч</translation>
<translation id="6609880536175561541">Prc7 (Дугтуй)</translation>
<translation id="6612358246767739896">ХамгаалагдÑан агуулга</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">Таны картыг баталгаажуулÑан байна</translation>
<translation id="6897140037006041989">Ð¥ÑÑ€ÑглÑгчийн төлөөлөгч</translation>
<translation id="6898699227549475383">Байгууллага (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />-д дараахыг зөвшөөрөх:</translation>
<translation id="6910240653697687763"><ph name="URL" /> таны MIDI төхөөрөмжүүдийг бүрÑн Ñ…Ñнах Ñ…Ò¯ÑÑлтÑй байна</translation>
<translation id="6915804003454593391">Ð¥ÑÑ€ÑглÑгч:</translation>
<translation id="6934672428414710184">Ð­Ð½Ñ Ð½Ñрийг таны Google БүртгÑлÑÑÑ Ð³Ð°Ñ€Ð³Ð°Ñан байна</translation>
@@ -1504,7 +1532,7 @@
<translation id="7108819624672055576">Өргөтгөл зөвшөөрÑөн</translation>
<translation id="7111012039238467737">(ХүчинтÑй)</translation>
<translation id="7118618213916969306">Түр Ñанах ойн URL болох <ph name="SHORT_URL" />-г хайх</translation>
-<translation id="7119414471315195487">БуÑад чихтÑй хуудаÑ, ÑÑвÑл программыг хаах</translation>
+<translation id="7119414471315195487">БуÑад таб, ÑÑвÑл программыг хаах</translation>
<translation id="7129409597930077180">Ð­Ð½Ñ Ñ…Ð°Ñг руу хүргÑÑ… боломжгүй тул Ó©Ó©Ñ€ хаÑг Ñонгоно уу.</translation>
<translation id="7135130955892390533">Төлөвийг харуулах</translation>
<translation id="7138472120740807366">ХүргÑлтийн арга</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">Холбоотой:</translation>
<translation id="7349430561505560861">A4-ÐÑмÑлт</translation>
<translation id="7353601530677266744">Тушаалын мөр</translation>
+<translation id="7359588939039777303">Зарыг блоклоÑон.</translation>
<translation id="7372973238305370288">хайлтын үр дүн</translation>
<translation id="7374733840632556089">Та ÑÑвÑл Ó©Ó©Ñ€ Ñ…Ñн нÑгÑн таны төхөөрөмж дÑÑÑ€ ÑуулгаÑан Ñертификатын ÑƒÐ»Ð¼Ð°Ð°Ñ Ð¸Ð¹Ð¼ аÑуудал гардаг. Сертификатыг ÑүлжÑÑнд Ñ…Ñналт хийх болон Ð´ÑƒÐ½Ð´Ð°Ð°Ñ Ð½ÑŒ өгөгдөл цуглуулахад ашигладаг гÑж мÑдÑгдÑÑн бөгөөд Chrome түүнд итгÑхгүй байна. Сургууль ÑÑвÑл компанийн ÑүлжÑÑнд Ñ…Ñналт хийх зÑÑ€Ñг хууль Ñ‘Ñны зарим тохиолдол байдаг бөгөөд Chrome нь та Ñ…Ñналтыг зогÑоож чадахгүй байÑан ч Ñ…Ñналт хийгдÑж байгаа тухай таныг мÑдÑж байгаа ÑÑÑхийг шалгах Ñ…Ò¯ÑÑлтÑй байна. Ð’ÑбÑд ханддаг аливаа хөтөч ÑÑвÑл аппликÑйшн дÑÑÑ€ Ñ…Ñналт хийж болзошгүй.</translation>
<translation id="7375818412732305729">Файлыг хавÑаргадаг</translation>
@@ -1577,7 +1606,7 @@
<translation id="7400418766976504921">URL</translation>
<translation id="7403591733719184120">Таны <ph name="DEVICE_NAME" />-г удирдаж байна</translation>
<translation id="7407424307057130981">&lt;p&gt;Таны Windows компьютерт Superfish программ хангамж байгаа тохиолдолд та Ñ‚ÑƒÑ Ð°Ð»Ð´Ð°Ð°Ð³ харах болно.&lt;/p&gt;
- &lt;p&gt;Ð¢ÑƒÑ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼ хангамжийг түр хугацаанд идÑвхгүй болгохын тулд ÑдгÑÑÑ€ алхмыг дагаÑнаар та вÑбÑд хандах боломжтой болно. Танд админы Ñрх шаардлагатай.&lt;/p&gt;
+ &lt;p&gt;Ð¢ÑƒÑ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼ хангамжийг түр хугацаанд идÑвхгүй болгохын тулд ÑдгÑÑÑ€ алхмыг дагаÑнаар та вебÑд хандах боломжтой болно. Танд админы Ñрх шаардлагатай.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ЭхлүүлÑÑ…&lt;/strong&gt; гÑÑнийг дараад дараа нь &lt;strong&gt;"Дотоод үйлчилгÑÑг харах"&lt;/strong&gt; гÑÑнийг олоод Ñонгоно уу
&lt;li&gt;&lt;strong&gt;VisualDiscovery&lt;/strong&gt;-г Ñонгоно уу
@@ -1738,9 +1767,10 @@
<translation id="7976214039405368314">Ð¥ÑÑ‚ олон Ñ…Ò¯ÑÑлт</translation>
<translation id="7977538094055660992">Гаралтын төхөөрөмж</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ӨргөтгөÑөн бодит орчны (ÐR) агуулга харахын тулд ARCore-г Ñуулгана уу</translation>
<translation id="799149739215780103">ҮдÑж хавтаÑлах</translation>
<translation id="7995512525968007366">Зааж өгөөгүй</translation>
-<translation id="800218591365569300">Санах ойн багтаамжийг нÑмÑгдүүлÑхийн тулд буÑад чихтÑй хуудаÑ, ÑÑвÑл программыг хаана уу.</translation>
+<translation id="800218591365569300">Санах ойн багтаамжийг нÑмÑгдүүлÑхийн тулд буÑад таб, ÑÑвÑл программыг хаана уу.</translation>
<translation id="8004582292198964060">Хөтөч</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ð­Ð½Ñ ÐºÐ°Ñ€Ñ‚ болон үүний тооцооны хаÑгийг хадгална. Та үүнийг <ph name="USER_EMAIL" />-д нÑвтÑÑ€ÑÑн үедÑÑ Ð°ÑˆÐ¸Ð³Ð»Ð°Ñ… боломжтой болно.}other{ЭдгÑÑÑ€ карт болон ÑдгÑÑрийн тооцооны хаÑгийг хадгална. Та ÑдгÑÑрийг <ph name="USER_EMAIL" />-д нÑвтÑÑ€ÑÑн үедÑÑ Ð°ÑˆÐ¸Ð³Ð»Ð°Ñ… боломжтой болно.}}</translation>
<translation id="8025119109950072390">Ð­Ð½Ñ Ñайтад байгаа халдагчид таныг программ хангамж Ñуулгах, ÑÑвÑл хувийн мÑдÑÑллÑÑ Ñ…Ð°Ñ€ÑƒÑƒÐ»Ð°Ñ… (жишÑÑ Ð½ÑŒ: нууц үг, утаÑны дугаар, ÑÑвÑл кредит карт) зÑÑ€Ñг аюултай үйлдÑл хийлгÑÑ…ÑÑÑ€ оролдож болзошгүй.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">Тушаалын мөр</translation>
<translation id="8508648098325802031">Хайлтын Ð´Ò¯Ñ€Ñ Ñ‚ÑмдÑг</translation>
<translation id="8522552481199248698">Chrome танд Google БүртгÑлÑÑ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ñ… болон нууц үгÑÑ Ñолиход туÑлах боломжтой.</translation>
+<translation id="8525306231823319788">БүтÑн дÑлгÑц</translation>
<translation id="8530813470445476232">Chrome Ñ‚Ð¾Ñ…Ð¸Ñ€Ð³Ð¾Ð¾Ð½Ð¾Ð¾Ñ Ñ…Ó©Ñ‚Ñ‡Ð¸Ð¹Ð½ түүх, күүки, завÑрын Ñанах ой болон буÑад зүйлийг уÑтгах</translation>
<translation id="8533619373899488139">СиÑтемийн админиÑтраторынхаа Ñ…ÑÑ€ÑгжүүлдÑг блоклоÑон URL-үүдийн болон буÑад удирдамжийн жагÑаалтыг харахын тулд &lt;strong&gt; chrome://policy&lt;/strong&gt;-д зочилно уу.</translation>
<translation id="8541158209346794904">Bluetooth төхөөрөмж</translation>
<translation id="8542014550340843547">Доод буланд гурван удаа үдÑÑ…</translation>
<translation id="8543181531796978784">Та <ph name="BEGIN_ERROR_LINK" />илрүүлÑÑн аÑуудлаа мÑдÑÑлж болно<ph name="END_ERROR_LINK" /> ÑÑвÑл учирч болох ÑÑ€Ñдлийг ойлгож байгаа бол <ph name="BEGIN_LINK" />ÑнÑÑ…Ò¯Ò¯ хамгаалалтгүй Ñайтад зочлоорой<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Карт баталгаажуулалтын код таны картын ард байрладаг.</translation>
+<translation id="8558485628462305855">ӨргөтгөÑөн бодит орчны (AR) агуулга харахын тулд ARCore-г шинÑÑ‡Ð¸Ð»Ð½Ñ Ò¯Ò¯</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> руу таны төхөөрөмжийн он Ñар өдөр, цаг <ph name="DATE_AND_TIME" /> ) буруу байгаа ÑƒÑ‡Ñ€Ð°Ð°Ñ Ñ…ÑƒÐ²Ð¸Ð¹Ð½ холболт Ò¯Ò¯ÑгÑж болохгүй байна.</translation>
<translation id="8564182942834072828">ТуÑдаа документ/ЗÑÑ€ÑгцүүлÑÑгүй хувь</translation>
<translation id="8564985650692024650">Ð¥ÑÑ€Ñв та <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-н нууц үгийг буÑад Ñайтад дахин ашиглаÑан бол Chromium-Ñ Ò¯Ò¯Ð½Ð¸Ð¹Ð³ шинÑчлÑхийг зөвлөж байна.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ үлдÑхгүй үйл ажиллагаа:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Таны ÑÐ½Ñ Ñ†Ð¾Ð½Ñ…Ð¾Ð½Ð´ үзÑÑн хуудÑууд
+ <ph name="LIST_ITEM" />Күүки болон Ñайтын өгөгдөл
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Картуудыг илүү хурдан баталгаажуулахын тулд Touch ID-г ашиглах</translation>
<translation id="858637041960032120">УтаÑны дугаар нÑмÑÑ…</translation>
<translation id="8589998999637048520">Хамгийн оновтой чанар</translation>
+<translation id="8600271352425265729">Зөвхөн ÑÐ½Ñ ÑƒÐ´Ð°Ð°</translation>
<translation id="860043288473659153">Карт ÑзÑмшигчийн нÑÑ€</translation>
<translation id="8606726445206553943">MIDI төхөөрөмжүүдÑÑ Ð°ÑˆÐ¸Ð³Ð»Ð°</translation>
+<translation id="8612761427948161954">Сайн байна уу <ph name="USERNAME" />,
+ <ph name="BR" />
+ Та Зочноор үзÑж байна</translation>
<translation id="861775596732816396">Ð¥ÑмжÑÑ 4</translation>
<translation id="8622948367223941507">Хууль Ñ‘Ñны-ÐÑмÑлт</translation>
<translation id="8623885649813806493">Таарах нууц үг алга. Бүх хадгалÑан нууц үгийг харуулна уу.</translation>
<translation id="8625384913736129811">Ð­Ð½Ñ ÐºÐ°Ñ€Ñ‚Ñ‹Ð³ ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ð¸Ð´ хадгалах</translation>
+<translation id="8627040765059109009">ДÑлгÑцийн зураг авахыг үргÑлжлүүлÑÑн</translation>
<translation id="8657078576661269990">Таны админиÑтратор <ph name="ORIGIN_NAME" />-Ñ <ph name="VM_NAME_1" /> болон <ph name="VM_NAME_2" />-тай хуваалцахыг блоклоÑон</translation>
<translation id="8663226718884576429">Захиалгын дүн, <ph name="TOTAL_LABEL" />, ДÑлгÑÑ€Ñнгүй</translation>
<translation id="867224526087042813">Гарын Ò¯ÑÑг</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google БүртгÑл</translation>
<translation id="8913778647360618320">Төлбөрийн Ñ…ÑÑ€ÑгÑлүүдийг удирдах товч, Chrome-н тохиргоон дÑÑÑ€ төлбөр болон кредит картынхаа мÑдÑÑллийг удирдахын тулд Enter дарна уу</translation>
<translation id="8918231688545606538">Ð­Ð½Ñ Ñ…ÑƒÑƒÐ´Ð°Ñ ÑÑжигтÑй байна</translation>
+<translation id="8922013791253848639">Ð­Ð½Ñ Ñайтад зарыг үргÑлж зөвшөөрөх</translation>
<translation id="892588693504540538">Баруун дÑÑд буланд нÑг нүх цоолох</translation>
<translation id="8931333241327730545">Та картаа өөрийн Google БүртгÑлд хадгалах уу?</translation>
<translation id="8932102934695377596">Таны цаг хоцорч байна</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Google ДокÑ</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> нь дÑмжигдÑÑгүй протоколыг ашигладаг.</translation>
<translation id="9191834167571392248">Зүүн доод буланд нÑг нүх цоолох</translation>
+<translation id="9199905725844810519">Ð¥ÑвлÑхийг блоклоÑон байна</translation>
<translation id="9205078245616868884">Таны өгөгдлийг таны Ñинк хийх нÑвтрÑÑ… үгтÑй шифрлÑÑÑн. Синкийг ÑхлүүлÑхийн тулд үүнийг оруулна уу.</translation>
<translation id="9207861905230894330">Өгүүллийг нÑмÑÑ… Ñвц амжилтгүй боллоо.</translation>
<translation id="9213433120051936369">Харагдах байдлыг өөрчлөх</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Супер-B</translation>
<translation id="936602727769022409">Та Google БүртгÑлийнхÑÑ Ñ…Ð°Ð½Ð´Ð°Ð»Ñ‚Ñ‹Ð³ алдаж болзошгүй. Chromium таныг нууц үгÑÑ Ð¾Ð´Ð¾Ð¾ Ñолихыг зөвлөж байна. Ð¢Ð°Ð½Ð°Ð°Ñ Ð½ÑвтрÑхийг шаардана.</translation>
<translation id="939736085109172342">Ð¨Ð¸Ð½Ñ Ñ…Ð°Ð²Ñ‚Ð°Ñ</translation>
+<translation id="945522503751344254">Санал Ñ…Ò¯ÑÑлт илгÑÑÑ…</translation>
<translation id="945855313015696284">Доорх мÑдÑÑллийг шалгаад хүчингүй бүх картыг уÑтгана уу</translation>
<translation id="950736567201356821">Баруун дÑÑд буланд гурван нүх цоолох</translation>
+<translation id="951941430552851965">Таны дÑлгÑцийн контентын ÑƒÐ»Ð¼Ð°Ð°Ñ Ñ‚Ð°Ð½Ñ‹ админиÑтратор дÑлгÑцийн зураг авахыг түр зогÑооÑон байна.</translation>
<translation id="961663415146723894">Доод булан дагуу үдÑж хавтаÑлах</translation>
<translation id="962484866189421427">Ð­Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚ Ñмар нÑг дүр ÑÑгÑÑÑн ÑÑвÑл таныг Ñ…Ñнахын тулд өгөгдөл цуглуулах зорилготой хуурамч апп Ñуулгахыг оролдож болзошгүй. <ph name="BEGIN_LINK" />Ямартай ч харуулах<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Ðлбан Ñ‘Ñоор бий болгох</translation>
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index adbbca00ef2..d68334bb4d7 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">तà¥à¤®à¤šà¥à¤¯à¤¾ संसà¥à¤¥à¥‡à¤¦à¥à¤µà¤¾à¤°à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलà¥à¤¯à¤¾ न जाणाऱà¥à¤¯à¤¾ साइटवर तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ à¤à¤‚टर केला आहे. तà¥à¤®à¤šà¥‡ खाते संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ इतर अâ€à¥…पà¥à¤¸ आणि साइटवर तà¥à¤®à¤šà¥à¤¯à¤¾ पासवरà¥à¤¡à¤šà¤¾ पà¥à¤¨à¥à¤¹à¤¾ वापर करू नका.</translation>
<translation id="1263231323834454256">वाचन सूची</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° न राहणाऱà¥à¤¯à¤¾ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तà¥à¤®à¥à¤¹à¥€ या विंडोमधà¥à¤¯à¥‡ पाहिलेली पेज
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ आणि साइट डेटा
+ <ph name="LIST_ITEM" />खाते माहिती (<ph name="LINK_BEGIN" />साइन आउट करा<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">घेणà¥à¤¯à¤¾à¤šà¥€ पदà¥à¤§à¤¤</translation>
<translation id="1281476433249504884">सà¥à¤Ÿà¥…कर १</translation>
<translation id="1285320974508926690">या साइटचा कधीही भाषांतर करॠनका</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">इतिहास नोंदींची सूची</translation>
<translation id="1517433312004943670">फोन नंबर आवशà¥à¤¯à¤• आहे</translation>
<translation id="1519264250979466059">बिलà¥à¤¡ तारीख</translation>
-<translation id="1521655867290435174">Google पतà¥à¤°à¤•</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">कनेकà¥à¤¶à¤¨à¤šà¥€ वाट पाहत आहे...</translation>
<translation id="1529521330346880926">10x15 (Envelope)10x15 (Envelope)</translation>
<translation id="1529789484829130889">टà¥à¤°à¥‡ ८</translation>
@@ -248,7 +256,7 @@
<translation id="1871208020102129563">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ निशà¥à¤šà¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आले आहे, .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL नवà¥à¤¹à¥‡.</translation>
<translation id="1871284979644508959">या जागा भरणे आवशà¥à¤¯à¤•</translation>
<translation id="1875512691959384712">Google Forms</translation>
-<translation id="187918866476621466">पà¥à¤°à¤¾à¤°à¤‚भ पृषà¥à¤  उघडा</translation>
+<translation id="187918866476621466">सà¥à¤°à¥‚ पृषà¥à¤  उघडा</translation>
<translation id="1883255238294161206">सूची कोलॅपà¥à¤¸</translation>
<translation id="1898423065542865115">फिलà¥à¤Ÿà¤° करणे</translation>
<translation id="1901443836186977402">{1,plural, =1{या सरà¥à¤µà¥à¤¹à¤°à¤²à¤¾ तो <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करता आले नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शेवटचà¥à¤¯à¤¾ तारखेला à¤à¤•à¥à¤¸à¥à¤ªà¤¾à¤¯à¤° à¤à¤¾à¤²à¥‡ आहे. हे कदाचित चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ काà¤à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोरांनी तà¥à¤®à¤šà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ आणलेलà¥à¤¯à¤¾ अडथळà¥à¤¯à¤¾à¤‚मà¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ आहे. तà¥à¤®à¤šà¥à¤¯à¤¾ काà¤à¤ªà¥à¤¯à¥à¤Ÿà¤°à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट केले आहे. हे योगà¥à¤¯ आहे का? ते योगà¥à¤¯ नसलà¥à¤¯à¤¾à¤¸, तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ सिसà¥à¤Ÿà¤®à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ पà¥à¤¨à¥à¤¹à¤¾ सेट करा आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पेज रिफà¥à¤°à¥‡à¤¶ करा.}other{या सरà¥à¤µà¥à¤¹à¤°à¤²à¤¾ तो <ph name="DOMAIN" />असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करता आले नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° # दिवसांपूरà¥à¤µà¥€ à¤à¤•à¥à¤¸à¥à¤ªà¤¾à¤¯à¤° à¤à¤¾à¤²à¥‡ आहे. हे कदाचित चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ काà¤à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोरांनी तà¥à¤®à¤šà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ आणलेलà¥à¤¯à¤¾ अडथळà¥à¤¯à¤¾à¤‚मà¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ आहे. तà¥à¤®à¤šà¥à¤¯à¤¾ काà¤à¤ªà¥à¤¯à¥à¤Ÿà¤°à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ सधà¥à¤¯à¤¾ <ph name="CURRENT_DATE" /> वर सेट केले आहे. हे योगà¥à¤¯ आहे का? ते योगà¥à¤¯ नसलà¥à¤¯à¤¾à¤¸, तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ सिसà¥à¤Ÿà¤®à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ पà¥à¤¨à¥à¤¹à¤¾ सेट करा आणि तà¥à¤¯à¤¾à¤¨à¤‚तर हे पेज रिफà¥à¤°à¥‡à¤¶ करा.}}</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">तà¥à¤®à¤šà¥à¤¯à¤¾ Google खाते मधà¥à¤¯à¥‡ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ वापरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ साइन इन करा</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />मधील पेज भाषांतरीत केले जाणार नाहीत.</translation>
<translation id="2053553514270667976">पिनकोड</translation>
+<translation id="2054665754582400095">तà¥à¤®à¤šà¥€ उपसà¥à¤¥à¤¿à¤¤à¥€</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 सूचना}other{# सूचना}}</translation>
<translation id="2079545284768500474">पहिलà¥à¤¯à¤¾à¤¸à¤¾à¤°à¤–े करा</translation>
<translation id="20817612488360358">सिसà¥à¤Ÿà¤® पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंगà¥à¤œ वापरणà¥â€à¤¯à¤¾à¤¸ सेट करणà¥â€à¤¯à¤¾à¤¤ आलà¥à¤¯à¤¾ परंतॠà¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉंफिगरेशन देखील निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android अâ€à¥…पà¥à¤¸</translation>
<translation id="2107021941795971877">पà¥à¤°à¤¿à¤‚ट सपोरà¥à¤Ÿ</translation>
<translation id="2108755909498034140">तà¥à¤®à¤šà¤¾ कॉंपà¥à¤¯à¥à¤Ÿà¤° रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
+<translation id="2111166930115883695">खेळणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ सà¥à¤ªà¥‡à¤¸ दाबा</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">कारà¥à¤¡</translation>
<translation id="2114841414352855701">दà¥à¤°à¥à¤²à¤•à¥à¤· केले कारण ते <ph name="POLICY_NAME" /> कडून अधिलिखित à¤à¤¾à¤²à¥‡ होते.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">पेमेंट रदà¥à¤¦ करा</translation>
<translation id="2147827593068025794">पारà¥à¤¶à¥à¤µà¤­à¥‚मी सिंक</translation>
<translation id="2148613324460538318">कारà¥à¤¡ जोडा</translation>
+<translation id="2149968176347646218">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="2154054054215849342">आपलà¥à¤¯à¤¾ डोमेनसाठी सिंक उपलबà¥à¤§ नाही</translation>
<translation id="2154484045852737596">कारà¥à¤¡ संपादित करा</translation>
<translation id="2161656808144014275">मजकूर</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">धोरणे</translation>
<translation id="2183608646556468874">फोन नंबर</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 पतà¥à¤¤à¤¾}other{# पतà¥à¤¤à¥‡}}</translation>
-<translation id="2187243482123994665">वापरकरà¥à¤¤à¥à¤¯à¤¾à¤šà¥€ ॲकà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€</translation>
<translation id="2187317261103489799">शोधा (डीफॉलà¥à¤Ÿ)</translation>
<translation id="2188375229972301266">मलà¥à¤Ÿà¤¿à¤ªà¤² पंच बॉटम</translation>
<translation id="2202020181578195191">वैध समापà¥à¤¤à¥€ वरà¥à¤· à¤à¤‚टर करा</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">पà¥à¤¢à¥‡ बनावट साइट आहे</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">हलà¥à¤²à¥‡à¤–ोर कदाचित तà¥à¤®à¤šà¥€ माहिती (उदाहरणारà¥à¤¥ पासवरà¥à¤¡, संदेश किंवा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> मधून चोरणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करत असतील. <ph name="BEGIN_LEARN_MORE_LINK" />आणखी जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ही साइट अनाहूत किंवा दिशाभूल करणाऱà¥à¤¯à¤¾ जाहिराती दाखवते.</translation>
<translation id="2878197950673342043">पोसà¥à¤Ÿà¤° फोलà¥à¤¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">विंडो सà¥à¤¥à¤¾à¤¨ नियोजन</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google चà¥à¤¯à¤¾ सूचना</translation>
<translation id="3002501248619246229">इनपà¥à¤Ÿ टà¥à¤°à¥‡ मीडिया तपासा</translation>
<translation id="3005723025932146533">सेवà¥à¤¹ केलेली पà¥à¤°à¤¤ दरà¥à¤¶à¤µà¤¾</translation>
-<translation id="3007719053326478567">तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ या आशयास पà¥à¤°à¤¿à¤‚ट करणे बà¥à¤²à¥‰à¤• केले आहे</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> साठी CVC पà¥à¤°à¤µà¤¿à¤·à¥â€à¤Ÿ करा. तà¥à¤®à¥à¤¹à¥€ पà¥à¤·à¥à¤Ÿà¥€ केलà¥à¤¯à¤¾à¤µà¤°, तà¥à¤®à¤šà¥‡ कारà¥à¤¡ तपशील या साइटसह शेअर केले जातील.</translation>
<translation id="3010559122411665027">सूची पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¥€ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">आपोआप बà¥à¤²à¥‰à¤• केलेले</translation>
<translation id="3016780570757425217">तà¥à¤®à¤šà¥‡ सà¥à¤¥à¤¾à¤¨ जाणून घà¥à¤¯à¤¾</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, सूचना काढून टाकणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">चà¥à¤•à¥€à¤šà¤¾ धोरण पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="3037605927509011580">चà¥à¤šà¤•!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• केलेली</translation>
<translation id="3209034400446768650">पेज कदाचित शà¥à¤²à¥à¤• आकारू शकते</translation>
<translation id="3212581601480735796">तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="HOSTNAME" /> वरील अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€à¤šà¥‡ परीकà¥à¤·à¤£ केले जात आहे</translation>
+<translation id="3212623355668894776">सरà¥à¤µ अतिथी विंडो बंद करा जेणेकरून, तà¥à¤®à¤šà¥€ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥‚न हटवली जाईल.</translation>
<translation id="3215092763954878852">WebAuthn वापरता आले नाही</translation>
<translation id="3218181027817787318">संबंधित</translation>
<translation id="3225919329040284222">सरà¥à¤µà¥à¤¹à¤°à¤¨à¥‡ असे सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ सादर केले आहे जे अंगभूत अपेकà¥à¤·à¤¾à¤‚शी जà¥à¤³à¤¤ नाही. या अपेकà¥à¤·à¤¾ तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ संरकà¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ विशिषà¥à¤Ÿ, उचà¥à¤š सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤šà¥à¤¯à¤¾ वेबसाइटसाठी समाविषà¥à¤Ÿ केलà¥à¤¯à¤¾ आहेत.</translation>
@@ -701,6 +713,7 @@
<translation id="3784372983762739446">बà¥à¤²à¥‚टूथ डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="3787705759683870569">समापà¥à¤¤ होते: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">आकार १६</translation>
+<translation id="3789841737615482174">सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ करा</translation>
<translation id="3793574014653384240">अलीकडे à¤à¤¾à¤²à¥‡à¤²à¥à¤¯à¤¾ कà¥à¤°à¥…शची संखà¥à¤¯à¤¾ आणि कारणे</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">फॉनà¥à¤Ÿà¤šà¥€ विनंती केली</translation>
@@ -752,6 +765,7 @@
<translation id="4056223980640387499">सेपिया</translation>
<translation id="4058922952496707368">की "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">सà¥â€à¤•à¥à¤°à¥€à¤¨ कॅपà¥â€à¤šà¤° पà¥à¤¨à¥â€à¤¹à¤¾ सà¥à¤°à¥‚ केले आहे.</translation>
<translation id="4067947977115446013">वैध पतà¥à¤¤à¤¾ जोडा</translation>
<translation id="4072486802667267160">तà¥à¤®à¤šà¥à¤¯à¤¾ मागणीवर पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करताना à¤à¤°à¤° आली, कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.</translation>
<translation id="4075732493274867456">कà¥à¤²à¤¾à¤¯à¤‚ट आणि सरà¥à¤µà¥à¤¹à¤° à¤à¤• सामानà¥à¤¯ SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² आवृतà¥à¤¤à¥€ किंवा सायफर संचाला सपोरà¥à¤Ÿ करीत नाही.</translation>
@@ -836,6 +850,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> पेजची थंबनेल</translation>
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ करा</translation>
<translation id="4300675098767811073">मलà¥à¤Ÿà¤¿à¤ªà¤² पंच राइट</translation>
+<translation id="4302514097724775343">खेळणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ डायनासोरवर टॅप करा</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">तà¥à¤®à¤šà¥€ फाइल अâ€à¥…कà¥à¤¸à¥‡à¤¸ करता आली नाही</translation>
<translation id="4305817255990598646">सà¥à¤µà¤¿à¤š</translation>
@@ -914,9 +929,10 @@
<translation id="4658638640878098064">सà¥à¤Ÿà¥‡à¤ªà¤² टॉप लेफà¥à¤Ÿ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">आभासी वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾</translation>
+<translation id="4675657451653251260">तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ अतिथी मोडमधà¥à¤¯à¥‡ Chrome पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤²à¤šà¥€ कोणतीही माहिती दिसणार नाही. पासवरà¥à¤¡ आणि पेमेंट पदà¥à¤§à¤¤à¥€ यांसारखी तà¥à¤®à¤šà¥€ Google खाते माहिती अâ€à¥…कà¥à¤¸à¥‡à¤¸ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤®à¥à¤¹à¥€ <ph name="LINK_BEGIN" />साइन इन<ph name="LINK_END" /> करू शकता.</translation>
<translation id="467662567472608290">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿà¤®à¤§à¥à¤¯à¥‡ à¤à¤°à¤° आहेत. हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉंफिगरेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोराने तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ इंटरसेपà¥à¤Ÿ केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ला ॲकà¥à¤¸à¥‡à¤¸à¤¿à¤¬à¤¿à¤²à¤¿à¤Ÿà¥€ इवà¥â€à¤¹à¥‡à¤‚टना पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ दà¥à¤¯à¤¾à¤¯à¤šà¤¾ आहे</translation>
-<translation id="467809019005607715">Google सà¥à¤²à¤¾à¤‡à¤¡</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">तà¥à¤®à¥à¤¹à¥€ आताच à¤à¤•à¤¾ फसवà¥à¤¯à¤¾ साइटवर तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ à¤à¤‚टर केला. तà¥à¤®à¥à¤¹à¥€ हा पासवरà¥à¤¡ आता जेथे वापरता अशा <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> आणि इतर साइटसाठी तà¥à¤®à¤šà¥‡ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ तपासणà¥à¤¯à¤¾à¤šà¥€ Chromium शिफारस करते.</translation>
<translation id="4690462567478992370">चà¥à¤•à¥€à¤šà¥‡ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ वापरणे थांबवा</translation>
<translation id="4691835149146451662">Architecture-A (Envelope)</translation>
@@ -941,6 +957,12 @@
<translation id="4761104368405085019">तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ वापरा</translation>
<translation id="4764776831041365478"><ph name="URL" /> येथील वेबपेज कदाचित तातà¥à¤ªà¥à¤°à¤¤à¥‡ बंद आहे किंवा ते कदाचित कायमचे नवीन वेब पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° हलवले आहे.</translation>
<translation id="4766713847338118463">डà¥à¤¯à¥à¤…ल सà¥à¤Ÿà¥‡à¤ªà¤² बॉटम</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° राहणारी अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तà¥à¤®à¥à¤¹à¥€ या विंडोमधून डाउनलोड केलेलà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾à¤¹à¥€ फाइल
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">à¤à¤• अजà¥à¤žà¤¾à¤¤ à¤à¤°à¤° आली आहे.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{पॉप-अप बà¥à¤²à¥‰à¤• केला}other{# पॉप-अप बà¥à¤²à¥‰à¤• केले}}</translation>
<translation id="4780366598804516005">मेलबॉकà¥à¤¸ १</translation>
@@ -1103,11 +1125,13 @@
<translation id="5386426401304769735">या साइटसाठी असलेलà¥à¤¯à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ शà¥à¤°à¥ƒà¤‚खलेत SHA-1 वापरून सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€ केलेले सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ असते.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">à¤à¤œ सà¥à¤Ÿà¤¿à¤š राइट</translation>
+<translation id="5398772614898833570">जाहिराती बà¥à¤²à¥‰à¤• केलà¥à¤¯à¤¾</translation>
<translation id="5400836586163650660">राखाडी</translation>
<translation id="540969355065856584">हा सरà¥à¤µà¥à¤¹à¤° <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ यावेळी वैध नाही. हे कदाचित चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉंफिगरेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोर तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ इंटरसेपà¥à¤Ÿ करत असलà¥â€à¤¯à¤¾à¤®à¥à¤³à¥‡ होऊ शकते.</translation>
<translation id="541416427766103491">सà¥à¤Ÿà¥…कर ४</translation>
<translation id="5421136146218899937">बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग डेटा साफ करा...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ला तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ सूचना पाठवायची आहे</translation>
+<translation id="542872847390508405">तà¥à¤®à¥à¤¹à¥€ अतिथी मà¥à¤¹à¤£à¥‚न बà¥à¤°à¤¾à¤‰à¤ करत आहात</translation>
<translation id="5430298929874300616">बà¥à¤•à¤®à¤¾à¤°à¥à¤• काढून टाका</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" वर सà¥à¤•à¥€à¤®à¤¾ ऑथेंटिकेशन à¤à¤°à¤°: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">उलटà¥à¤¯à¤¾ कà¥à¤°à¤®à¤¾à¤¨à¥‡ फेस अप</translation>
@@ -1149,12 +1173,12 @@
<translation id="5571083550517324815">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤°à¥‚न पिक अप करू शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="5580958916614886209">तà¥à¤®à¤šà¤¾ कालबाहà¥à¤¯à¤¤à¤¾ महिना तपासा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
<translation id="5586446728396275693">कोणतेही सेवà¥à¤¹ केलेले ॲडà¥à¤°à¥‡à¤¸ नाही</translation>
+<translation id="5593349413089863479">कनेकà¥à¤¶à¤¨ पूरà¥à¤£à¤ªà¤£à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="5595485650161345191">पतà¥à¤¤à¤¾ संपादित करा</translation>
<translation id="5598944008576757369">पेमेंट पदà¥à¤§à¤¤ निवडा</translation>
<translation id="560412284261940334">वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ समरà¥à¤¥à¤¿à¤¤ नाही</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ही साइट बनावट किंवा कपटपूरà¥à¤£ असू शकते. आता सोडून देणà¥à¤¯à¤¾à¤šà¥€ Chrome शिफारस करते.</translation>
<translation id="5610142619324316209">कनेकà¥à¤¶à¤¨ तपासणे</translation>
<translation id="5610807607761827392">तà¥à¤®à¥à¤¹à¥€ कारà¥à¤¡ आणि पतà¥à¤¤à¥‡ <ph name="BEGIN_LINK" />सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू शकता.</translation>
<translation id="561165882404867731">या पेजचे Google Translate यासह भाषांतर करा</translation>
@@ -1226,6 +1250,7 @@
<translation id="5901630391730855834">पिवळा</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> चà¥à¤¯à¤¾ मूळ धोरणानà¥à¤¸à¤¾à¤° बà¥à¤²à¥‰à¤• केले आहे.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (सिंक केलेले)</translation>
+<translation id="5913377024445952699">सà¥â€à¤•à¥à¤°à¥€à¤¨ कॅपà¥â€à¤šà¤° थांबवले आहे</translation>
<translation id="59174027418879706">सकà¥à¤·à¤®</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">सà¥à¤°à¥‚ करा</translation>
@@ -1238,6 +1263,7 @@
<translation id="5963413905009737549">विभाग</translation>
<translation id="5967592137238574583">संपरà¥à¤• माहिती संपादित करा</translation>
<translation id="5967867314010545767">इतिहासातून काढून टाका</translation>
+<translation id="5968793460449681917">पà¥à¤°à¤¤à¥à¤¯à¥‡à¤• भेटीला</translation>
<translation id="5975083100439434680">à¤à¥‚म कमी करा</translation>
<translation id="5979084224081478209">पासवरà¥à¤¡ तपासा</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1370,10 +1396,10 @@
<translation id="6451458296329894277">फॉरà¥à¤® रीसबमिशनची पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="6457206614190510200">साडल सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="6465306955648956876">पासवरà¥à¤¡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा...</translation>
-<translation id="6468485451923838994">फॉनà¥à¤Ÿ</translation>
+<translation id="6468485451923838994">फॉंट</translation>
<translation id="647261751007945333">डिवà¥à¤¹à¤¾à¤‡à¤¸ धोरणे</translation>
<translation id="6476284679642588870">पेमेंट पदà¥à¤§à¤¤à¥€ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
-<translation id="6489534406876378309">कà¥à¤°à¥…श अपलोड करणे पà¥à¤°à¤¾à¤°à¤‚भ करा</translation>
+<translation id="6489534406876378309">कà¥à¤°à¥…श अपलोड करणे सà¥à¤°à¥‚ करा</translation>
<translation id="6499038740797743453">पासवरà¥à¤¡ रीसेट करायचा?</translation>
<translation id="6502991525169604759">तà¥à¤®à¤šà¥à¤¯à¤¾ बदलांशिवाय</translation>
<translation id="6508722015517270189">Chrome रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">तà¥à¤®à¥à¤¹à¥€ कॉपी केलेली लिंक</translation>
<translation id="6591833882275308647">तà¥à¤®à¤šà¥‡ <ph name="DEVICE_TYPE" /> वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलेले नाही</translation>
<translation id="6596325263575161958">à¤à¤‚कà¥à¤°à¤¿à¤ªà¥à¤¶à¤¨ परà¥à¤¯à¤¾à¤¯</translation>
+<translation id="6596892391065203054">तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ या आशयाचे पà¥à¤°à¤¿à¤‚टिंग बà¥à¤²à¥‰à¤• केले आहे.</translation>
<translation id="6604181099783169992">गती किंवा पà¥à¤°à¤•à¤¾à¤¶ सेनà¥à¤¸à¤°</translation>
<translation id="6609880536175561541">Prc7 (Envelope)Prc7 (Envelope)</translation>
<translation id="6612358246767739896">संरकà¥à¤·à¤¿à¤¤ आशय</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">आपलà¥à¤¯à¤¾ कारà¥à¤¡à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ केली</translation>
<translation id="6897140037006041989">वापरकरà¥à¤¤à¤¾ à¤à¤œà¤‚ट</translation>
<translation id="6898699227549475383">संसà¥à¤¥à¤¾à¤¤à¥à¤®à¤• (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> ला याची अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ला तà¥à¤®à¤šà¥à¤¯à¤¾ MIDI डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥‡ पूरà¥à¤£ नियंतà¥à¤°à¤£ मिळवायचे आहे</translation>
<translation id="6915804003454593391">वापरकरà¥à¤¤à¤¾:</translation>
<translation id="6934672428414710184">हे नाव तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤µà¤°à¥‚न आहे</translation>
@@ -1472,7 +1500,7 @@
<translation id="6973656660372572881">निशà¥à¤šà¤¿à¤¤ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सरà¥à¤µà¥à¤¹à¤° आणि .pac सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ URL निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहेत.</translation>
<translation id="6973932557599545801">सॉरी मला मदत करता आली नाही कृपया तà¥à¤®à¥à¤¹à¥€ सà¥à¤µà¤¤à¤ƒà¤š सà¥à¤°à¥‚ ठेवा.</translation>
<translation id="6975012522936652259">तà¥à¤®à¥à¤¹à¥€ आताच à¤à¤•à¤¾ फसवà¥à¤¯à¤¾ साइटवर तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ à¤à¤‚टर केला. तà¥à¤®à¥à¤¹à¥€ हा पासवरà¥à¤¡ जेथे वापरता अशा <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> आणि इतर साइटवर जाणà¥à¤¯à¤¾à¤šà¥€ आणि तो आता बदलणà¥à¤¯à¤¾à¤šà¥€ Chromium शिफारस करते.</translation>
-<translation id="6979158407327259162">Google डà¥à¤°à¤¾à¤‡à¤µà¥à¤¹</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">निःशबà¥à¤¦ करा (डीफॉलà¥à¤Ÿ)</translation>
<translation id="6979983982287291980">तà¥à¤®à¥à¤¹à¥€ डाउनलोड केलेलà¥à¤¯à¤¾ फाइल विशà¥à¤²à¥‡à¤·à¤£à¤¾à¤¸à¤¾à¤ à¥€ Google Cloud किंवा तृतीय पकà¥à¤·à¤¾à¤‚कडे पाठवलà¥à¤¯à¤¾ जातात. उदाहरणारà¥à¤¥, तà¥à¤¯à¤¾ संवेदनशील डेटा किंवा मालवेअरसाठी सà¥à¤•à¥…न केलà¥à¤¯à¤¾ जाऊ शकतात.</translation>
<translation id="6989763994942163495">पà¥à¤°à¤—त सेटिंगà¥à¤œ दरà¥à¤¶à¤µà¤¾...</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">याचà¥à¤¯à¤¾à¤¶à¥€ संबंधित आहे:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">कमांड लाइन</translation>
+<translation id="7359588939039777303">जाहिराती बà¥à¤²à¥‰à¤• केलà¥à¤¯à¤¾.</translation>
<translation id="7372973238305370288">शोध परिणाम</translation>
<translation id="7374733840632556089">तà¥à¤®à¥à¤¹à¥€ किंवा इतर कोणीतरी तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° इंसà¥à¤Ÿà¥‰à¤² केलेलà¥à¤¯à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿà¤®à¥à¤³à¥‡ ही समसà¥à¤¯à¤¾ येते. हे सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ नेटवरà¥à¤•à¤šà¥‡ नियंतà¥à¤°à¤£ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आणि वà¥à¤¯à¤¤à¥à¤¯à¤¯ आणणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरले जाते आणि Chrome ला यावर विशà¥à¤µà¤¾à¤¸ नाही. दरमà¥à¤¯à¤¾à¤¨ नियंतà¥à¤°à¤£ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ काही कायदेशीर पà¥à¤°à¤•à¤°à¤£à¥‡ असà¥à¤¤à¤¿à¤¤à¥à¤¤à¥à¤µà¤¾à¤¤ आहेत, जसे की शाळा किंवा कंपनीचà¥à¤¯à¤¾ नेटवरà¥à¤•à¤µà¤°, तà¥à¤®à¥à¤¹à¥€ हे थांबवू शकत नसलात तरीही तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ याची जाणीव आहे याची Chrome ला खातà¥à¤°à¥€ करायची आहे. वेबचा ॲकà¥à¤¸à¥‡à¤¸ असणाऱà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾à¤¹à¥€ बà¥à¤°à¤¾à¤‰à¤à¤° किंवा ॲपà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨à¤šà¥‡ नियंतà¥à¤°à¤£ केले जाऊ शकते.</translation>
<translation id="7375818412732305729">फाइल अटॅच केली आहे</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">खूप जासà¥à¤¤ विनंतà¥à¤¯à¤¾</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ऑगमेंटेड रीअâ€à¥…लिटी आशय पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, ARCore इंसà¥à¤Ÿà¥‰à¤² करा</translation>
<translation id="799149739215780103">बाइंड</translation>
<translation id="7995512525968007366">नमूद केलेले नाही</translation>
<translation id="800218591365569300">मेमरी मोकळी करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अनà¥à¤¯ टॅब किंवा पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करून पहा.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">कमांड लाइन</translation>
<translation id="8508648098325802031">शोध आयकन</translation>
<translation id="8522552481199248698">तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤šà¥‡ संरकà¥à¤·à¤£ करणà¥à¤¯à¤¾à¤¤ आणि तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ बदलणà¥à¤¯à¤¾à¤¤ Chrome तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ मदत करू शकते.</translation>
+<translation id="8525306231823319788">फà¥à¤² सà¥à¤•à¥à¤°à¥€à¤¨</translation>
<translation id="8530813470445476232">Chrome सेटिंगà¥à¤œà¤®à¤§à¥€à¤² तà¥à¤®à¤šà¤¾ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास, कà¥à¤•à¥€, कॅशे आणि बरेच काही साफ करा</translation>
<translation id="8533619373899488139">तà¥à¤®à¤šà¥à¤¯à¤¾ सिसà¥à¤Ÿà¤® अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¦à¥à¤µà¤¾à¤°à¥‡ बà¥à¤²à¥‰à¤• केलेलà¥à¤¯à¤¾ URL आणि लागू केलेली इतर धोरणे पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ &lt;strong&gt;chrome://policy&lt;/strong&gt; ला भेट दà¥à¤¯à¤¾.</translation>
<translation id="8541158209346794904">बà¥à¤²à¥‚टूथ डिवà¥â€à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="8542014550340843547">टà¥à¤°à¤¿à¤ªà¤² सà¥à¤Ÿà¥‡à¤ªà¤² बॉटम</translation>
<translation id="8543181531796978784">तà¥à¤®à¥à¤¹à¥€ <ph name="BEGIN_ERROR_LINK" />ओळखणà¥â€à¤¯à¤¾à¤šà¥à¤¯à¤¾ समसà¥â€à¤¯à¥‡à¤šà¤¾ अहवाल<ph name="END_ERROR_LINK" /> देऊ शकता किंवा तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¥‡à¤¸ असणारà¥â€à¤¯à¤¾ जोखीम तà¥à¤®à¥à¤¹à¥€ समजत असलà¥â€à¤¯à¤¾à¤¸, <ph name="BEGIN_LINK" />या असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइटला भेट दà¥à¤¯à¤¾<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVV तà¥à¤®à¤šà¥à¤¯à¤¾ कारà¥à¤¡à¤¾à¤šà¥à¤¯à¤¾ मागील बाजूस दिलेला असतो.</translation>
+<translation id="8558485628462305855">ऑगमेंटेड रीअâ€à¥…लिटी आशय पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, ARCore अपडेट करा</translation>
<translation id="8559762987265718583">आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) चà¥à¤•à¥€à¤šà¥€ असलà¥à¤¯à¤¾à¤¨à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² केले जाऊ शकले नाही.</translation>
<translation id="8564182942834072828">वेगळे केलेले दसà¥à¤¤à¤à¤µà¤œ/संकलित न केलेलà¥à¤¯à¤¾ पà¥à¤°à¤¤à¥€</translation>
<translation id="8564985650692024650">जर तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡à¤šà¤¾ इतर साइटवर पà¥à¤¨à¥à¤¹à¤¾ वापर केला असेल तर Chromium तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ तो रीसेट करणà¥à¤¯à¤¾à¤šà¥€ शिफारस करतो.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° न राहणाऱà¥à¤¯à¤¾ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तà¥à¤®à¥à¤¹à¥€ या विंडोमधà¥à¤¯à¥‡ पाहिलेली पेज
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ आणि साइट डेटा
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">कारà¥à¤¡à¤¾à¤‚ची जलद खातà¥à¤°à¥€ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टच आयडी वापरा</translation>
<translation id="858637041960032120">फोन नंबर जोडा</translation>
<translation id="8589998999637048520">सरà¥à¤µà¥‹à¤¤à¥à¤¤à¤® गà¥à¤£à¤µà¤¤à¥à¤¤à¤¾</translation>
+<translation id="8600271352425265729">फकà¥à¤¤ या वेळी</translation>
<translation id="860043288473659153">कारà¥à¤¡à¤§à¤¾à¤°à¤•à¤¾à¤šà¥‡ नाव</translation>
<translation id="8606726445206553943">तà¥à¤®à¤šà¥‡ MIDI डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸ वापरा</translation>
+<translation id="8612761427948161954">हाय <ph name="USERNAME" />,
+ <ph name="BR" />
+ तà¥à¤®à¥à¤¹à¥€ अतिथी मà¥à¤¹à¤£à¥‚न बà¥à¤°à¤¾à¤‰à¤ करत आहात</translation>
<translation id="861775596732816396">आकार ४</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">जà¥à¤³à¤£à¤¾à¤°à¥‡ कोणतेही पासवरà¥à¤¡ नाहीत. सेवà¥à¤¹ केलेले सरà¥à¤µ पासवरà¥à¤¡ दाखवा.</translation>
<translation id="8625384913736129811">या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° हे कारà¥à¤¡ सेवà¥â€à¤¹ करा</translation>
+<translation id="8627040765059109009">सà¥â€à¤•à¥à¤°à¥€à¤¨ कॅपà¥â€à¤šà¤° पà¥à¤¨à¥à¤¹à¤¾ सà¥à¤°à¥‚ केले आहे</translation>
<translation id="8657078576661269990">तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ <ph name="ORIGIN_NAME" /> वरून <ph name="VM_NAME_1" /> आणि <ph name="VM_NAME_2" /> वर शेअर करणे बà¥à¤²à¥‰à¤• केले</translation>
<translation id="8663226718884576429">ऑरà¥à¤¡à¤° सारांश, <ph name="TOTAL_LABEL" />, आणखी तपशील</translation>
<translation id="867224526087042813">सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google खाते</translation>
<translation id="8913778647360618320">पेमेंट पदà¥à¤§à¤¤à¥€ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा बटण, Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥€ पेमेंट आणि कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ माहिती वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤‚टर दाबा</translation>
<translation id="8918231688545606538">हे पेज संशयासà¥à¤ªà¤¦ आहे</translation>
+<translation id="8922013791253848639">या साइटवर कायम जाहिरातींना परवानगी दà¥à¤¯à¤¾</translation>
<translation id="892588693504540538">पंच टॉप राइट</translation>
<translation id="8931333241327730545">तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤¤ हे कारà¥à¤¡ सेवà¥à¤¹ करू इचà¥à¤›à¤¿à¤¤à¤¾?</translation>
<translation id="8932102934695377596">तà¥à¤®à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ मागे आहे</translation>
@@ -2013,21 +2058,24 @@
<translation id="917450738466192189">सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ चà¥à¤•à¥€à¤šà¥‡ आहे.</translation>
<translation id="9174917557437862841">टॅब सà¥à¤µà¤¿à¤š बटण, या टॅबवर जाणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤‚टर दाबा</translation>
<translation id="9179703756951298733">Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥€ पेमेंट आणि कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ यांची माहिती वà¥â€à¤¯à¤µà¤¸à¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
-<translation id="9183302530794969518">Google दसà¥à¤¤à¤à¤µà¤œ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¥‰à¤² वापरतो.</translation>
<translation id="9191834167571392248">पंच बॉटम लेफà¥à¤Ÿ</translation>
+<translation id="9199905725844810519">पà¥à¤°à¤¿à¤‚ट करणे बà¥à¤²à¥‰à¤• केले</translation>
<translation id="9205078245616868884">तà¥à¤®à¤šà¤¾ डेटा तà¥à¤®à¤šà¥à¤¯à¤¾ सिंक सांकेतिक पासफà¥à¤°à¥‡à¤à¤¾à¤¸à¤¹ à¤à¤‚कà¥à¤°à¤¿à¤ªà¥à¤Ÿ केलेला केला जातो. सिंक सà¥à¤°à¥‚ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तो à¤à¤‚टर करा.</translation>
<translation id="9207861905230894330">लेख जोडणà¥à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€.</translation>
<translation id="9213433120051936369">सà¥à¤µà¤°à¥‚प कसà¥à¤Ÿà¤®à¤¾à¤‡à¤ करा</translation>
<translation id="9215416866750762878">à¤à¤• ॲपà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ Chrome ला या साइटशी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤ªà¤£à¥‡ कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न थांबवत आहे</translation>
-<translation id="9219103736887031265">इमेज</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">फॉरà¥à¤® साफ करा</translation>
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤šà¤¾ ॲकà¥à¤¸à¥‡à¤¸ कदाचित गमवाल. Chromium आता तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ बदलणà¥à¤¯à¤¾à¤šà¥€ शिफारस करते. तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ साइन इन करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ सांगितले जाऊ शकते.</translation>
<translation id="939736085109172342">नवीन फोलà¥â€à¤¡à¤°</translation>
+<translation id="945522503751344254">अभिपà¥à¤°à¤¾à¤¯ पाठवा</translation>
<translation id="945855313015696284">खालील माहिती तपासा आणि कोणतीही चà¥à¤•à¥€à¤šà¥€ कारà¥à¤¡à¥‡ हटवा</translation>
<translation id="950736567201356821">टà¥à¤°à¤¿à¤ªà¤² पंच टॉप</translation>
+<translation id="951941430552851965">तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤•à¥à¤°à¥€à¤¨à¤µà¤°à¥€à¤² आशयामà¥à¤³à¥‡ तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ सà¥à¤•à¥à¤°à¥€à¤¨ कॅपà¥à¤šà¤° थांबवले आहे.</translation>
<translation id="961663415146723894">बाइंड बॉटम</translation>
<translation id="962484866189421427">हा आशय काहीतरी दà¥à¤¸à¤°à¥‡ असणà¥à¤¯à¤¾à¤šà¥€ बतावणी करणारी फसवी ॲपà¥à¤¸ इंसà¥à¤Ÿà¥‰à¤² करणà¥à¤¯à¤¾à¤šà¤¾ किंवा तà¥à¤®à¤šà¤¾ माग ठेवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरला जाऊ शकणारा डेटा गोळा करणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करू शकतो. <ph name="BEGIN_LINK" />तरीही दाखवा<ph name="END_LINK" /></translation>
<translation id="969892804517981540">अधिकृत बिलà¥à¤¡</translation>
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index ce2e5938ff2..50f2a10fd73 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -80,6 +80,14 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Anda memasukkan kata laluan pada tapak yang tidak diurus oleh organisasi anda. Untuk melindungi akaun anda, jangan gunakan semula kata laluan anda pada apl dan tapak lain.</translation>
<translation id="1263231323834454256">Senarai bacaan</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktiviti yang tidak akan dikekalkan pada peranti ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Halaman yang anda lihat dalam tetingkap ini
+ <ph name="LIST_ITEM" />Kuki dan data laman
+ <ph name="LIST_ITEM" />Maklumat akaun (<ph name="LINK_BEGIN" />log keluar<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Kaedah Pengambilan</translation>
<translation id="1281476433249504884">Petak 1</translation>
<translation id="1285320974508926690">Jangan sekali-kali menterjemahkan tapak ini</translation>
@@ -283,6 +291,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="204357726431741734">Log masuk untuk menggunakan kata laluan yang disimpan dalam Akaun Google anda</translation>
<translation id="2053111141626950936">Halaman dalam <ph name="LANGUAGE" /> tidak akan diterjemah.</translation>
<translation id="2053553514270667976">Poskod</translation>
+<translation id="2054665754582400095">Kehadiran anda</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 cadangan}other{# cadangan}}</translation>
<translation id="2079545284768500474">Buat asal</translation>
<translation id="20817612488360358">Tetapan proksi sistem telah sedia untuk digunakan tetapi konfigurasi proksi jelas juga telah ditentukan.</translation>
@@ -296,6 +305,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2102495993840063010">Apl Android</translation>
<translation id="2107021941795971877">Sokongan cetakan</translation>
<translation id="2108755909498034140">Mulakan semula komputer anda</translation>
+<translation id="2111166930115883695">Tekan kekunci Ruang untuk bermain</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kad</translation>
<translation id="2114841414352855701">Diabaikan kerana ia telah diatasi oleh <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Penyegerakan Latar Belakang</translation>
<translation id="2148613324460538318">Tambahkan Kad</translation>
+<translation id="2149968176347646218">Sambungan tidak selamat</translation>
<translation id="2154054054215849342">Penyegerakan tidak tersedia untuk domain anda</translation>
<translation id="2154484045852737596">Edit kad</translation>
<translation id="2161656808144014275">Teks</translation>
@@ -317,7 +328,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2181821976797666341">Dasar</translation>
<translation id="2183608646556468874">Nombor Telefon</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 alamat}other{# alamat}}</translation>
-<translation id="2187243482123994665">Kehadiran pengguna</translation>
<translation id="2187317261103489799">Kesan (lalai)</translation>
<translation id="2188375229972301266">Berbilang tebukan bawah</translation>
<translation id="2202020181578195191">Masukkan tahun tamat tempoh yang sah</translation>
@@ -470,6 +480,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2839501879576190149">Tapak palsu di hadapan</translation>
<translation id="2850739647070081192">Jemputan (Sampul Surat)</translation>
<translation id="2856444702002559011">Penyerang mungkin akan cuba mencuri maklumat anda daripada <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (contohnya, kata laluan, mesej atau kad kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Tapak ini menyiarkan iklan yang mengganggu atau mengelirukan.</translation>
<translation id="2878197950673342043">Lipatan poster</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Peletakan tetingkap</translation>
@@ -508,11 +519,11 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2996674880327704673">Cadangan oleh Google</translation>
<translation id="3002501248619246229">Semak media dulang input</translation>
<translation id="3005723025932146533">Paparkan salinan disimpan</translation>
-<translation id="3007719053326478567">Pencetakan kandungan ini disekat oleh pentadbir anda</translation>
<translation id="3008447029300691911">Masukkan CVC untuk <ph name="CREDIT_CARD" />. Setelah anda mengesahkan, butiran kad anda akan dikongsi dengan tapak ini.</translation>
<translation id="3010559122411665027">Masukan senarai "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Disekat secara automatik</translation>
<translation id="3016780570757425217">Ketahui lokasi anda</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, tekan kekunci Tab kemudian Enter untuk Mengalih Keluar Cadangan.</translation>
<translation id="3023071826883856138">You4 (Sampul Surat)</translation>
<translation id="3024663005179499861">Jenis dasar salah</translation>
<translation id="3037605927509011580">Oh, Tidak!</translation>
@@ -555,6 +566,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3207960819495026254">Ditandai halaman</translation>
<translation id="3209034400446768650">Halaman mungkin mengenakan bayaran berbentuk wang</translation>
<translation id="3212581601480735796">Aktiviti anda pada <ph name="HOSTNAME" /> sedang dipantau</translation>
+<translation id="3212623355668894776">Tutup semua tetingkap Tetamu supaya aktiviti penyemakan imbas anda dipadamkan daripada peranti ini.</translation>
<translation id="3215092763954878852">Tidak dapat menggunakan WebAuthn</translation>
<translation id="3218181027817787318">Relatif</translation>
<translation id="3225919329040284222">Pelayan memberikan sijil yang tidak sepadan dengan jangkaan terbina dalam. Jangkaan ini disertakan untuk tapak web dengan keselamatan tinggi tertentu untuk melindungi anda.</translation>
@@ -703,6 +715,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3784372983762739446">Peranti Bluetooth</translation>
<translation id="3787705759683870569">Tamat tempoh pada <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Saiz 16</translation>
+<translation id="3789841737615482174">Pasang</translation>
<translation id="3793574014653384240">Bilangan dan punca ranap sistem yang berlaku baru-baru ini</translation>
<translation id="3797522431967816232">Prc3 (Sampul Surat)</translation>
<translation id="3799805948399000906">Fon diminta</translation>
@@ -754,6 +767,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Kekunci "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Sampul Surat)</translation>
+<translation id="4067669230157909013">Tangkapan skrin telah disambung semula.</translation>
<translation id="4067947977115446013">Tambahkan Alamat yang Sah</translation>
<translation id="4072486802667267160">Ralat berlaku semasa memproses pesanan anda. Sila cuba lagi.</translation>
<translation id="4075732493274867456">Pelanggan dan pelayan tidak menyokong versi protokol SSL atau set sifer biasa.</translation>
@@ -838,6 +852,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4297502707443874121">Lakaran kecil untuk halaman <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Kembangkan</translation>
<translation id="4300675098767811073">Berbilang tebukan kanan</translation>
+<translation id="4302514097724775343">Ketik dinosaur itu untuk bermain</translation>
<translation id="4302965934281694568">Chou3 (Sampul Surat)</translation>
<translation id="4305666528087210886">Fail anda tidak dapat diakses</translation>
<translation id="4305817255990598646">Tukar</translation>
@@ -916,6 +931,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4658638640878098064">Kokot atas sebelah kiri</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realiti maya</translation>
+<translation id="4675657451653251260">Anda tidak akan melihat sebarang maklumat profil Chrome dalam mod Tetamu. Anda boleh <ph name="LINK_BEGIN" />log masuk<ph name="LINK_END" /> untuk mengakses maklumat akaun Google anda seperti kata laluan dan kaedah pembayaran.</translation>
<translation id="467662567472608290">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mengandungi ralat. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintas sambungan anda.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ingin menjawab acara kebolehaksesan</translation>
<translation id="467809019005607715">Slaid Google</translation>
@@ -943,6 +959,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4761104368405085019">Gunakan mikrofon anda</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin tergendala buat sementara waktu atau ia mungkin dpindahkan secara kekal ke alamat web baharu.</translation>
<translation id="4766713847338118463">Dua kokot bawah</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktiviti anda yang dikekalkan pada peranti ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sebarang fail yang anda muat turun dalam tetingkap ini
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ralat tidak diketahui telah berlaku.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Tetingkap timbul disekat}other{# tetingkap timbul disekat}}</translation>
<translation id="4780366598804516005">Peti mel 1</translation>
@@ -1105,11 +1127,13 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5386426401304769735">Rantaian sijil untuk tapak ini mengandungi sijil yang ditandatangani menggunakan SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Jahitan tepi kanan</translation>
+<translation id="5398772614898833570">Iklan disekat</translation>
<translation id="5400836586163650660">Kelabu</translation>
<translation id="540969355065856584">Pelayan ini tidak dapat membuktikan bahawa pelayan adalah <ph name="DOMAIN" />; sijil keselamatan pelayan tidak sah pada masa ini. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang memintas sambungan anda.</translation>
<translation id="541416427766103491">Petak 4</translation>
<translation id="5421136146218899937">Kosongkan data semakan imbas...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> mahu menghantar pemberitahuan kepada anda</translation>
+<translation id="542872847390508405">Anda menyemak imbas sebagai Tetamu</translation>
<translation id="5430298929874300616">Alih keluar penanda halaman</translation>
<translation id="5439770059721715174">Ralat pengesahan skema di "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Susunan terbalik menghadap ke atas</translation>
@@ -1151,12 +1175,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5571083550517324815">Tidak boleh mengambil dari alamat ini. Pilih alamat lain.</translation>
<translation id="5580958916614886209">Semak bulan tamat tempoh anda dan cuba lagi</translation>
<translation id="5586446728396275693">Tiada alamat yang disimpan</translation>
+<translation id="5593349413089863479">Sambungan tidak selamat sepenuhnya</translation>
<translation id="5595485650161345191">Edit alamat</translation>
<translation id="5598944008576757369">Pilih Kaedah Pembayaran</translation>
<translation id="560412284261940334">Pengurusan tidak disokong</translation>
<translation id="5605670050355397069">Lejar</translation>
<translation id="5607240918979444548">Seni Bina-C</translation>
-<translation id="5608165884683734521">Tapak ini mungkin palsu atau penipuan. Chrome mengesyorkan agar anda meninggalkan tapak sekarang.</translation>
<translation id="5610142619324316209">Menyemak sambungan</translation>
<translation id="5610807607761827392">Anda boleh mengurus kad dan alamat dalam <ph name="BEGIN_LINK" />Tetapan<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Terjemahkan halaman ini dengan Google Terjemah</translation>
@@ -1228,6 +1252,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5901630391730855834">Kuning</translation>
<translation id="5905445707201418379">Disekat menurut dasar asal <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (disegerakkan)</translation>
+<translation id="5913377024445952699">Tangkapan skrin dijeda</translation>
<translation id="59174027418879706">Didayakan</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Hidup</translation>
@@ -1240,6 +1265,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5963413905009737549">Bahagian</translation>
<translation id="5967592137238574583">Edit Maklumat Hubungan</translation>
<translation id="5967867314010545767">Buang daripada sejarah</translation>
+<translation id="5968793460449681917">Pada setiap lawatan</translation>
<translation id="5975083100439434680">Zum keluar</translation>
<translation id="5979084224081478209">Semak kata laluan</translation>
<translation id="5980920751713728343">Indeks-3x5</translation>
@@ -1395,6 +1421,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6587923378399804057">Pautan yang anda salin</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> anda tidak diurus</translation>
<translation id="6596325263575161958">Pilihan penyulitan</translation>
+<translation id="6596892391065203054">Pencetakan kandungan ini disekat oleh pentadbir anda.</translation>
<translation id="6604181099783169992">Penderia Gerakan atau Cahaya</translation>
<translation id="6609880536175561541">Prc7 (Sampul Surat)</translation>
<translation id="6612358246767739896">Kandungan yang dilindungi</translation>
@@ -1454,6 +1481,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6895330447102777224">Kad anda telah disahkan</translation>
<translation id="6897140037006041989">Ejen Pengguna</translation>
<translation id="6898699227549475383">Organisasi (O)</translation>
+<translation id="6907293445143367439">Benarkan <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> mahu mendapatkan kawalan penuh terhadap peranti MIDI anda</translation>
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6934672428414710184">Nama ini daripada Akaun Google anda</translation>
@@ -1565,6 +1593,7 @@ Butiran tambahan:
<translation id="7346048084945669753">Ialah ahli gabungan:</translation>
<translation id="7349430561505560861">A4-Ekstra</translation>
<translation id="7353601530677266744">Baris Perintah</translation>
+<translation id="7359588939039777303">Iklan disekat.</translation>
<translation id="7372973238305370288">hasil carian</translation>
<translation id="7374733840632556089">Masalah ini berlaku disebabkan oleh sijil yang anda pasang atau dipasang oleh orang lain pada peranti anda. Sijil itu diketahui digunakan untuk memantau dan memintas rangkaian, dan tidak dipercayai oleh Chrome. Walaupun terdapat sebab yang munasabah untuk melakukan pemantauan, seperti pada rangkaian institusi pengajian atau syarikat, Chrome ingin memastikan anda menyedari pemantauan berlaku, walaupun anda tidak dapat menghentikan pemantauan itu. Pemantauan boleh berlaku pada mana-mana penyemak imbas atau aplikasi yang mengakses web.</translation>
<translation id="7375818412732305729">Fail dilampirkan</translation>
@@ -1739,6 +1768,7 @@ Butiran tambahan:
<translation id="7976214039405368314">Terlalu banyak permintaan</translation>
<translation id="7977538094055660992">Peranti output</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Untuk melihat kandungan realiti tambahan, pasang ARCore</translation>
<translation id="799149739215780103">Ikatan</translation>
<translation id="7995512525968007366">Tidak Ditentukan</translation>
<translation id="800218591365569300">Cuba tutup tab atau atur cara lain untuk mengosongkan memori.</translation>
@@ -1866,25 +1896,39 @@ Butiran tambahan:
<translation id="8507227106804027148">Baris perintah</translation>
<translation id="8508648098325802031">Ikon Carian</translation>
<translation id="8522552481199248698">Chrome boleh membantu anda melindungi Akaun Google anda dan menukar kata laluan anda.</translation>
+<translation id="8525306231823319788">Skrin penuh</translation>
<translation id="8530813470445476232">Kosongkan sejarah penyemakan imbas, kuki, cache dan pelbagai lagi dalam tetapan Chrome</translation>
<translation id="8533619373899488139">Lawati &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat senarai URL yang disekat dan dasar lain yang dikuatkuasakan oleh pentadbir sistem anda.</translation>
<translation id="8541158209346794904">Peranti Bluetooth</translation>
<translation id="8542014550340843547">Tiga kokot bawah</translation>
<translation id="8543181531796978784">Anda boleh <ph name="BEGIN_ERROR_LINK" />laporkan masalah pengesanan<ph name="END_ERROR_LINK" /> atau jika anda memahami risikonya kepada keselamatan anda, <ph name="BEGIN_LINK" />lawati tapak yang tidak selamat ini<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC terletak di belakang kad anda.</translation>
+<translation id="8558485628462305855">Untuk melihat kandungan realiti tambahan, kemas kini ARCore</translation>
<translation id="8559762987265718583">Sambungan peribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak boleh diwujudkan kerana tarikh dan masa peranti anda (<ph name="DATE_AND_TIME" />) tidak betul.</translation>
<translation id="8564182942834072828">Dokumen berasingan/Salinan berasingan</translation>
<translation id="8564985650692024650">Chromium mengesyorkan penetapan semula kata laluan <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika anda menggunakan semula kata laluan itu di tapak lain.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktiviti yang tidak akan dikekalkan pada peranti ini:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Halaman yang anda lihat dalam tetingkap ini
+ <ph name="LIST_ITEM" />Kuki dan data laman
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Gunakan Touch ID untuk mengesahkan kad dengan lebih cepat</translation>
<translation id="858637041960032120">Tambah no. tel.
</translation>
<translation id="8589998999637048520">Kualiti terbaik</translation>
+<translation id="8600271352425265729">Kali ini sahaja</translation>
<translation id="860043288473659153">Nama pemegang kad</translation>
<translation id="8606726445206553943">Gunakan peranti MIDI anda</translation>
+<translation id="8612761427948161954">Hai <ph name="USERNAME" />,
+ <ph name="BR" />
+ Anda sedang menyemak imbas sebagai Tetamu</translation>
<translation id="861775596732816396">Saiz 4</translation>
<translation id="8622948367223941507">Perundangan-Ekstra</translation>
<translation id="8623885649813806493">Tiada kata laluan yang sepadan. Tunjukkan semua kata laluan yang disimpan.</translation>
<translation id="8625384913736129811">Simpan Kad Ini pada Peranti Ini</translation>
+<translation id="8627040765059109009">Tangkapan skrin disambung semula</translation>
<translation id="8657078576661269990">Pentadbir anda telah menyekat tindakan mengongsikan data daripada <ph name="ORIGIN_NAME" /> ke <ph name="VM_NAME_1" /> dan <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Ringkasan Pesanan, <ph name="TOTAL_LABEL" />, Butiran Lanjut</translation>
<translation id="867224526087042813">Tandatangan</translation>
@@ -1947,6 +1991,7 @@ Butiran tambahan:
<translation id="8912362522468806198">Akaun Google</translation>
<translation id="8913778647360618320">Butang uruskan kaedah pembayaran, tekan Enter untuk menguruskan maklumat kad kredit dan pembayaran anda dalam tetapan Chrome</translation>
<translation id="8918231688545606538">Halaman ini mencurigakan</translation>
+<translation id="8922013791253848639">Sentiasa benarkan iklan di tapak ini</translation>
<translation id="892588693504540538">Tebukan atas sebelah kanan</translation>
<translation id="8931333241327730545">Adakah anda mahu menyimpan kad ini ke Akaun Google anda?</translation>
<translation id="8932102934695377596">Jam anda di belakang</translation>
@@ -2018,6 +2063,7 @@ Butiran tambahan:
<translation id="9183302530794969518">Dokumen Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> menggunakan protokol yang tidak disokong.</translation>
<translation id="9191834167571392248">Tebukan bawah sebelah kiri</translation>
+<translation id="9199905725844810519">Pencetakan disekat</translation>
<translation id="9205078245616868884">Data anda disulitkan dengan ungkapan laluan segerak anda. Masukkannya untuk memulakan penyegerakan.</translation>
<translation id="9207861905230894330">Gagal menambahkan artikel.</translation>
<translation id="9213433120051936369">Sesuaikan rupa</translation>
@@ -2028,8 +2074,10 @@ Butiran tambahan:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Anda mungkin akan kehilangan akses kepada Akaun Google anda. Chromium mengesyorkan supaya anda menukar kata laluan sekarang. Anda akan diminta untuk log masuk.</translation>
<translation id="939736085109172342">Folder baharu</translation>
+<translation id="945522503751344254">Hantar maklum balas</translation>
<translation id="945855313015696284">Semak maklumat di bawah dan padamkan sebarang kad yang tidak sah</translation>
<translation id="950736567201356821">Tiga tebukan atas</translation>
+<translation id="951941430552851965">Tangkapan skrin telah dijeda oleh pentadbir anda disebabkan oleh kandungan pada skrin anda.</translation>
<translation id="961663415146723894">Ikatan bawah</translation>
<translation id="962484866189421427">Kandungan ini mungkin cuba memasang apl mengelirukan yang berpura-pura menjadi sesuatu yang lain atau mengumpulkan data yang mungkin digunakan untuk menjejak anda. <ph name="BEGIN_LINK" />Tunjukkan juga <ph name="END_LINK" /></translation>
<translation id="969892804517981540">Binaan Rasmi</translation>
diff --git a/chromium/components/strings/components_strings_my.xtb b/chromium/components/strings/components_strings_my.xtb
index 723a280fb7f..e53562f183c 100644
--- a/chromium/components/strings/components_strings_my.xtb
+++ b/chromium/components/strings/components_strings_my.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">သင့်အဖွဲ့အစည်းက စီမံá€á€”့်á€á€½á€²á€á€¼á€„်းမရှိသည့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€½á€„် သင်á စကားá€á€¾á€€á€ºá€€á€­á€¯ ထည့်ထားပါသည်ዠသင့်အကောင့်ကို ကာကွယ်ရန် အá€á€¼á€¬á€¸á€¡á€€á€ºá€•á€ºá€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် သင့်စကားá€á€¾á€€á€ºá€€á€­á€¯ ပြန်မသုံးပါနှင့်á‹</translation>
<translation id="1263231323834454256">ဖá€á€ºá€›á€”် စာရင်း</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ဤစက်á€á€½á€„် သိမ်းမည်မဟုá€á€ºá€žá€±á€¬ လုပ်ဆောင်á€á€»á€€á€º-
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ဤá€á€„်းဒိုးá€á€½á€„် သင်ကြည့်ရှုသောစာမျက်နှာများ
+ <ph name="LIST_ITEM" />ကွá€á€ºá€€á€®á€¸á€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬á€™á€»á€¬á€¸
+ <ph name="LIST_ITEM" />အကောင့်အá€á€»á€€á€ºá€¡á€œá€€á€º (<ph name="LINK_BEGIN" />ထွက်ရန်<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">လာယူနည်း</translation>
<translation id="1281476433249504884">စီထည့်သည့်ပုံး á</translation>
<translation id="1285320974508926690">ဒီဆိုက်ကို ဘယ်á€á€±á€¬á€·á€™á€¾ ဘာသာမပြန်ပါနှင့်</translation>
@@ -145,7 +153,7 @@
<translation id="1492194039220927094">မူá€á€«á€’များ ထည့်သွင်းရန်-</translation>
<translation id="1501859676467574491">သင့် Google အကောင့်မှ ကá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပြရန်</translation>
<translation id="1507202001669085618">&lt;p&gt;အွန်လိုင်း မရရှိမီ လက်မှá€á€ºá€‘ိုးá€á€„်ရသည့် Wi-Fi ပေါ်á€á€šá€ºá€€á€­á€¯ အသုံးပြုသည့်အá€á€« ဤအမှားကို á€á€½á€±á€·á€›á€•á€«á€™á€Šá€ºá‹&lt;/p&gt;
- &lt;p&gt;ထိုအမှားအယွင်းကို ဖြေရှင်းရန် သင်ဖွင့်ရန် ကြိုးစားနေသည့် စာမျက်နှာá€á€½á€„် &lt;strong&gt;á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”်&lt;/strong&gt; ကို ကလစ်နှိပ်ပါá‹&lt;/p&gt;</translation>
+ &lt;p&gt;ထိုအမှားအယွင်းကို ဖြေရှင်းရန် သင်ဖွင့်ရန် ကြိုးစားနေသည့် စာမျက်နှာá€á€½á€„် &lt;strong&gt;á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”်&lt;/strong&gt; ကို နှိပ်ပါá‹&lt;/p&gt;</translation>
<translation id="1513706915089223971">မှá€á€ºá€á€™á€ºá€¸ ထည့်သွင်းမှုများ စာရင်း</translation>
<translation id="1517433312004943670">ဖုန်းနံပါá€á€ºá€œá€­á€¯á€¡á€•á€ºá€•á€«á€žá€Šá€º</translation>
<translation id="1519264250979466059">á€á€Šá€ºá€†á€±á€¬á€€á€ºá€žá€Šá€·á€º ရက်စွဲ</translation>
@@ -285,6 +293,7 @@
<translation id="204357726431741734">သင့် Google Account á€á€½á€„် သိမ်းထားသောစကားá€á€¾á€€á€ºá€™á€»á€¬á€¸ အသုံးပြုရန် လက်မှá€á€ºá€‘ိုးá€á€„်ပါ</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> ဘာသာဖြင့် စာမျက်နှာများကို ဘာသာပြန်မည် မဟုá€á€ºá€•á€«á‹</translation>
<translation id="2053553514270667976">ဇစ်ကုဒ်</translation>
+<translation id="2054665754582400095">သင်ရှိနေမှု</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{အကြံပြုá€á€»á€€á€º á á€á€¯}other{အကြံပြုá€á€»á€€á€º # á€á€¯}}</translation>
<translation id="2079545284768500474">á€á€…်ဆင့်နောက်ပြန်ရန်</translation>
<translation id="20817612488360358">စနစ် ပရောက်စီ ဆက်á€á€„်များကို အသုံးပြုရန် သá€á€ºá€™á€¾á€á€º ပေးထားသော်လည်း အထူး ဖေါ်ပြပေးထားသည့် ပရောက်စီ စီစဉ်ဖွဲ့စည်းမှု á€á€…်á€á€¯á€€á€­á€¯á€•á€« ဖေါ်ပြပေးထားသည်á‹</translation>
@@ -298,6 +307,7 @@
<translation id="2102495993840063010">Android အက်ပ်များ</translation>
<translation id="2107021941795971877">ပုံနှိပ်မှုဆိုင်ရာ အကူအညီများ</translation>
<translation id="2108755909498034140">သင်áကွန်ပျူá€á€¬á€€á€­á€¯ ပိá€á€ºá€•á€¼á€®á€¸á€•á€¼á€”်ဖွင့်ပါ</translation>
+<translation id="2111166930115883695">ဖွင့်ရန် နေရာá€á€¼á€¬á€¸á€á€œá€¯á€á€º နှိပ်ပါ</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">ကá€á€º</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> မှလွမ်းမိုးá€á€²á€·á€žá€±á€¬á€€á€¼á€±á€¬á€„့် လစ်လျူရှုá€á€²á€·á€žá€Šá€ºá‹</translation>
@@ -309,6 +319,7 @@
<translation id="214556005048008348">ငွေပေးá€á€»á€±á€™á€¾á€¯á€€á€­á€¯ ပယ်ဖျက်ရန်</translation>
<translation id="2147827593068025794">နောက်á€á€¶á€á€½á€„်စင့်á€á€ºá€œá€¯á€•á€ºá€á€¼á€„်း</translation>
<translation id="2148613324460538318">ကá€á€ºá€‘ည့်ရန်…</translation>
+<translation id="2149968176347646218">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€žá€Šá€º မလုံá€á€¼á€¯á€¶á€•á€«</translation>
<translation id="2154054054215849342">သင့်ဒိုမိန်း အá€á€½á€€á€º စင့်á€á€ºá€œá€¯á€•á€ºá€á€¼á€„်း မရနိုင်ပါ</translation>
<translation id="2154484045852737596">ကá€á€ºá€€á€­á€¯ á€á€Šá€ºá€¸á€–ြá€á€ºá€•á€«</translation>
<translation id="2161656808144014275">စာသား</translation>
@@ -319,7 +330,6 @@
<translation id="2181821976797666341">ပေါ်လစီများ</translation>
<translation id="2183608646556468874">ဖုန်းနံပါá€á€º</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{လိပ်စာ á á€á€¯}other{လိပ်စာ # á€á€¯}}</translation>
-<translation id="2187243482123994665">အသုံးပြုသူ ရှိနေမှု</translation>
<translation id="2187317261103489799">ရှာကြည့်ရန် (မူရင်း)</translation>
<translation id="2188375229972301266">အောက်á€á€¼á€±á€á€½á€„် အများအပြားဖောက်ရန်</translation>
<translation id="2202020181578195191">မှန်ကန်သည့် ကုန်ဆုံးမည့်á€á€¯á€”ှစ်ကို ထည့်ပါ</translation>
@@ -472,6 +482,7 @@
<translation id="2839501879576190149">ရှေ့á€á€½á€„် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€á€¯á€›á€¾á€­á€žá€Šá€º</translation>
<translation id="2850739647070081192">ဖိá€á€ºá€…ာ (စာအိá€á€º)</translation>
<translation id="2856444702002559011">á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€žá€°á€™á€»á€¬á€¸á€€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ရှိ သင်áအá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€­á€¯á€¸á€šá€°á€›á€”် ကြိုးပမ်းနိုင်ပါသည် (ဥပမာ- စကားá€á€¾á€€á€ºáŠ မက်ဆေ့ဂျ်နှင့် á€á€›á€€á€ºá€’စ်ကá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸)á‹ <ph name="BEGIN_LEARN_MORE_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ စိá€á€ºá€¡á€”ှောင့်အယှက်ဖြစ်စေသော (သို့) အထင်အမြင်မှားစေသော ကြော်ငြာများကို ပြသည်á‹</translation>
<translation id="2878197950673342043">ပိုစá€á€¬á€•á€¯á€¶ á€á€±á€«á€€á€ºá€›á€”်</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">á€á€„်းဒိုး နေရာá€á€»á€‘ားမှု</translation>
@@ -512,11 +523,11 @@
<translation id="2996674880327704673">Google á အကြံပြုá€á€»á€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="3002501248619246229">ထည့်သွင်းသည့်ဗန်းရှိ မီဒီယာကို စစ်ဆေးပါ</translation>
<translation id="3005723025932146533">သိမ်းထားသည့် မိá€á€¹á€á€°á€€á€­á€¯á€•á€¼á€•á€«</translation>
-<translation id="3007719053326478567">ဤအကြောင်းအရာ ပုံနှိပ်ထုá€á€ºá€á€¼á€„်းကို သင်áစီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပိá€á€ºá€‘ားသည်</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> အá€á€½á€€á€º CVC ကိုထည့်ပါዠအá€á€Šá€ºá€•á€¼á€¯á€•á€¼á€®á€¸á€žá€Šá€ºá€”ှင့် သင့်ကဒ်áအသေးစိá€á€ºá€¡á€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ဤဆိုက်အား မျှá€á€±á€žá€½á€¬á€¸á€•á€«á€™á€Šá€ºá‹</translation>
<translation id="3010559122411665027">အကြောင်းအရာ စာရင်း "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">အလိုအလျောက် ပိá€á€ºá€‘ားသည်</translation>
<translation id="3016780570757425217">သင့်á€á€Šá€ºá€”ေရာအား သိလိုá</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />አ'á€á€˜á€º' နှိပ်ပါአထို့နောက် 'အကြံပြုá€á€»á€€á€ºá€–ယ်ရှားရန်' Enter နှိပ်ပါá‹</translation>
<translation id="3023071826883856138">You4 (စာအိá€á€º)</translation>
<translation id="3024663005179499861">မူá€á€«á€’ ပုံစံ မှားနေ</translation>
<translation id="3037605927509011580">အောአလက်ဖျောက်!</translation>
@@ -556,6 +567,7 @@
<translation id="3207960819495026254">ဘွá€á€ºá€™á€€á€ºá€œá€¯á€•á€ºá€•á€¼á€®á€¸á</translation>
<translation id="3209034400446768650">စာမျက်နှာသည် ငွေကုန်ကျမှုများ ဖြစ်စေနိုင်သည်</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ရှိ သင့်လုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ စောင့်ကြည့်နေသည်</translation>
+<translation id="3212623355668894776">'ဧည့်သည်' á€á€„်းဒိုးအားလုံးကို ပိá€á€ºá€œá€­á€¯á€€á€ºá€•á€«á€€ သင်áကြည့်ရှုá€á€¼á€„်းများကို ဤစက်မှ ဖျက်လိုက်ပါမည်á‹</translation>
<translation id="3215092763954878852">WebAuthn ကို အသုံးပြုá မရပါ</translation>
<translation id="3218181027817787318">အလိုက်သင့်</translation>
<translation id="3225919329040284222">ဆာဗာက ပြသá€á€²á€·á€žá€Šá€ºá€· လက်မှá€á€ºá€™á€¾á€¬ á€á€•á€ºá€†á€„်ထားသည့် မျှော်လင့်á€á€»á€€á€ºá€™á€»á€¬á€¸á€”ှင့် မá€á€­á€¯á€€á€ºá€†á€­á€¯á€„်ပါዠယင်း မျှော်လင့်á€á€»á€€á€ºá€™á€»á€¬á€¸á€™á€¾á€¬ သင့်ကို ကာကွယ်ပေးရန် အá€á€½á€€á€º အဆင့်မြင့် လုံá€á€¼á€¯á€¶á€™á€¾á€¯ ရှိကြသည့် á€á€€á€ºá€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ရည်ရွယ် ထည့်သွင်းထားပါသည်á‹</translation>
@@ -701,6 +713,7 @@
<translation id="3784372983762739446">ဘလူးá€á€°á€¸á€žá€ºá€…က်ပစ္စည်းများ</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> á€á€½á€„် ကုန်ဆုံးမည်</translation>
<translation id="3789155188480882154">အရွယ်အစား áá†</translation>
+<translation id="3789841737615482174">á€á€•á€ºá€†á€„်ရန်</translation>
<translation id="3793574014653384240">မကြာသေးမီက ဖြစ်ပွားá€á€²á€·á€žá€Šá€ºá€· ရပ်á€á€”့်သွားá€á€¼á€„်း အရေအá€á€½á€€á€ºá€™á€»á€¬á€¸á€”ှင့် အကြောင်းရင်းများ</translation>
<translation id="3797522431967816232">Prc3 (စာအိá€á€º)</translation>
<translation id="3799805948399000906">ဖောင့်á€á€±á€¬á€„်းဆိုထားသည်</translation>
@@ -752,6 +765,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">သော့ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (စာအိá€á€º)</translation>
+<translation id="4067669230157909013">ဖန်သားပြင်ပုံဖမ်းá€á€¼á€„်းကို ဆက်လုပ်ထားသည်á‹</translation>
<translation id="4067947977115446013">မှန်ကန်သည့် လိပ်စာကို ထည့်ပါ</translation>
<translation id="4072486802667267160">သင်á မှာယူမှုကို ဆောင်ရွက်နေစဉ် မှားယွင်းမှုá€á€…်á€á€¯ ရှိနေပါသည်ዠထပ်လုပ်ကြည့်ပါá‹</translation>
<translation id="4075732493274867456">အသုံးပြုသူနှင့် ဆာဗာသည် ယေဘုယျ SSL ပရိုá€á€­á€¯á€€á€±á€¬á€—ားရှင်း သို့မဟုá€á€º စာá€á€¾á€€á€ºá€–ော်နည်းများကို မထောက်ပံ့ပါá‹</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">စာမျက်နှာ <ph name="THUMBNAIL_PAGE" /> အá€á€½á€€á€º ပုံသေး</translation>
<translation id="42981349822642051">á€á€­á€¯á€¸á€á€»á€²á€·</translation>
<translation id="4300675098767811073">ညာဘက်á€á€½á€„် အများအပြားဖောက်ရန်</translation>
+<translation id="4302514097724775343">ကစားရန် ဒိုင်နိုကိုá€á€­á€¯á€·á€•á€«</translation>
<translation id="4302965934281694568">Chou3 (စာအိá€á€º)</translation>
<translation id="4305666528087210886">သင့်ဖိုင်ကို သုံးáမရနိုင်ပါ</translation>
<translation id="4305817255990598646">á€á€œá€¯á€á€º</translation>
@@ -915,6 +930,7 @@
<translation id="4658638640878098064">ညာဘက်ထိပ်á€á€½á€„် á€á€»á€¯á€•á€ºá€…က်ဖြင့် á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ပကá€á€­á€¡á€žá€½á€„်</translation>
+<translation id="4675657451653251260">'ဧည့်သည်မုဒ်' á€á€½á€„် Chrome ပရိုဖိုင်á အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ မြင်ရမည်မဟုá€á€ºá€•á€«á‹ စကားá€á€¾á€€á€ºá€”ှင့် ငွေပေးá€á€»á€±á€”ည်းလမ်းများကဲ့သို့ သင်á Google အကောင့်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ á€á€„်ကြည့်ရန် <ph name="LINK_BEGIN" />လက်မှá€á€ºá€‘ိုးá€á€„်<ph name="LINK_END" /> နိုင်သည်á‹</translation>
<translation id="467662567472608290">ဒီဆာဗာက <ph name="DOMAIN" /> ဖြစ်á€á€¬á€€á€­á€¯ သက်သေထူ မပြနိုင်á€á€²á€·á€•á€«áŠ áŽá€„်းá လုံá€á€¼á€¯á€¶á€›á€±á€¸ လက်မှá€á€ºá€‘ဲမှာ အမှားများ ပါá€á€„်နေသည်ዠဖွဲ့စည်းစီစဉ်မှု အမှားကြောင့် သို့မဟုá€á€º á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€œá€­á€¯á€žá€°á€€ သင်á á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ကြားဖြá€á€ºá€šá€°á€”ေá ထိုသို့ ဖြစ်လာနိုင်á€á€²á€·á€•á€«á€žá€Šá€ºá‹</translation>
<translation id="4677585247300749148"><ph name="URL" /> သည် အများသုံးစွဲနိုင်မှု ဖြစ်ရပ်များကို á€á€¯á€¶á€·á€•á€¼á€”်လိုပါသည်</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">သင့်မိုက်á€á€›á€­á€¯á€–ုန်းကို အသုံးပြုရန်</translation>
<translation id="4764776831041365478"><ph name="URL" /> ပေါ်က á€á€˜á€ºá€…ာမျက်နှာမှ ယာယီ ဒေါင်းနေá€á€¬ ဖြစ်နိုင်သည် သို့မဟုá€á€º áŽá€„်းသည် á€á€˜á€º လိပ်စာ သစ်ဆီသို့ ထာá€á€› ရွှေ့ပြောင်းသွားá€á€¬ ဖြစ်နိုင်သည်á‹</translation>
<translation id="4766713847338118463">အောက်á€á€¼á€±á€á€½á€„် á€á€»á€¯á€•á€ºá€…က်ဖြင့် နှစ်á€á€»á€€á€ºá€á€»á€¯á€•á€ºá€›á€”်</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ဤစက်á€á€½á€„် သိမ်းမည့်လုပ်ဆောင်á€á€»á€€á€º-
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ဤá€á€„်းဒိုးá€á€½á€„် ဒေါင်းလုဒ်လုပ်သောဖိုင်များ
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">မသိရသည့် မှားယွင်းမှုá€á€…်á€á€¯ ဖြစ်á€á€²á€·á€žá€Šá€ºá‹</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ပေါ့ပ်အပ်ကို ပိá€á€ºá€‘ားသည်}other{ပေါ့ပ်အပ်ကို # á€á€¯á€€á€­á€¯ ပိá€á€ºá€‘ားသည်}}</translation>
<translation id="4780366598804516005">စာá€á€­á€¯á€€á€ºá€•á€¯á€¶á€¸ á</translation>
@@ -1104,17 +1126,19 @@
<translation id="5386426401304769735">ဤဆိုက်အá€á€½á€€á€º အသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€€á€½á€„်းဆက်á€á€½á€„် SHA-1 ကို အသုံးပြုá လက်မှá€á€ºá€‘ိုးထားသည့် အသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€á€…်စောင် ပါá€á€„်ပါသည်á‹</translation>
<translation id="538659543871111977">A4-á€á€˜á€º</translation>
<translation id="5396631636586785122">ညာဘက်အစွန်းá€á€½á€„် အပ်á€á€»á€Šá€ºá€–ြင့်á€á€»á€¯á€•á€ºá€›á€”်</translation>
+<translation id="5398772614898833570">ကြော်ငြာများကို ပိá€á€ºá€œá€­á€¯á€€á€ºá€•á€«á€•á€¼á€®</translation>
<translation id="5400836586163650660">မီးá€á€­á€¯á€¸</translation>
<translation id="540969355065856584">ဤဆာဗာသည် <ph name="DOMAIN" /> ဖြစ်ကြောင်း သက်သေမပြနိုင်ပါ; áŽá€„်းáလုံá€á€¼á€¯á€¶á€›á€±á€¸ အသိမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€žá€Šá€º ယá€á€¯á€¡á€á€»á€­á€”်á€á€½á€„် á€á€›á€¬á€¸á€™á€á€„်ပါዠဖွဲ့စည်းမှု အမှားကြောင့် သို့မဟုá€á€º á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€œá€­á€¯á€žá€°á€€ သင်áá€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ကြားဖြá€á€ºá€šá€°á€”ေá ထိုသို့ဖြစ်လာနိုင်á€á€²á€·á€•á€«á€žá€Šá€ºá‹</translation>
<translation id="541416427766103491">စီထည့်သည့်ပုံး á„</translation>
<translation id="5421136146218899937">ဘရောင်ဇာ ဒေá€á€¬á€€á€­á€¯ ရှင်းရန်...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> သည် သင့်ထံသို့ အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸ ပို့လိုသည်</translation>
+<translation id="542872847390508405">သင်သည် ဧည့်သည် အဖြစ် á€á€„်ကြည့်နေသည်</translation>
<translation id="5430298929874300616">စာညှပ် ဖယ်ရှားရန်</translation>
<translation id="5439770059721715174">Schema မှန်ကန်ကြောင်းအá€á€Šá€ºá€•á€¼á€¯á€™á€¾á€¯ မှားယွင်းá€á€¼á€„်း "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ပြောင်းပြန်အစဉ်ဖြင့် အပေါ်လှန်ထားရန်</translation>
<translation id="5447765697759493033">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€€á€­á€¯ ဘာသာပြန်မည် မဟုá€á€ºá€•á€«</translation>
<translation id="5452270690849572955">ဤ <ph name="HOST_NAME" /> စာမျက်နှာကို မá€á€½á€±á€·á€•á€«</translation>
-<translation id="5455374756549232013">မူá€á€«á€’ အá€á€»á€­á€”်ထုမှု ညံ့ဖျင်း</translation>
+<translation id="5455374756549232013">ညံ့ဖျင်းသည့် မူá€á€«á€’ အá€á€»á€­á€”်ဖော်ပြá€á€»á€€á€º</translation>
<translation id="5457113250005438886">မမှန်ပါ</translation>
<translation id="5458150163479425638">{CONTACT,plural, =0{<ph name="CONTACT_PREVIEW" />}=1{<ph name="CONTACT_PREVIEW" /> နှင့် နောက်ထပ် <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}other{<ph name="CONTACT_PREVIEW" /> နှင့် နောက်ထပ် <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}}</translation>
<translation id="5470861586879999274">&amp;á€á€Šá€ºá€¸á€–ြá€á€ºá€™á€¾á€¯ ပြန်လုပ်ရန်</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">ဤလိပ်စာမှ ပစ္စည်းထုá€á€ºá€šá€°áမရပါዠအá€á€¼á€¬á€¸á€œá€­á€•á€ºá€…ာá€á€…်á€á€¯á€€á€­á€¯ ရွေးပါá‹</translation>
<translation id="5580958916614886209">သင့်ကုန်ဆုံးမည့်လကို ကြည့်ပြီး ပြန်စမ်းကြည့်ပါ</translation>
<translation id="5586446728396275693">သိမ်းဆည်းထားသည့် လိပ်စာများ မရှိပါ</translation>
+<translation id="5593349413089863479">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€žá€Šá€º အပြည့်အá€á€™á€œá€¯á€¶á€á€¼á€¯á€¶á€•á€«</translation>
<translation id="5595485650161345191">လိပ်စာ á€á€Šá€ºá€¸á€–ြá€á€ºá€›á€”်</translation>
<translation id="5598944008576757369">ငွေပေးá€á€»á€±á€”ည်းလမ်း ရွေးရန်</translation>
<translation id="560412284261940334">စီမံရေးရာမှ အကူအညီမရနိုင်ပါá‹</translation>
<translation id="5605670050355397069">လယ်ဂျာ</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€žá€Šá€º အá€á€¯ သို့မဟုá€á€º လှည့်ဖြားမှု ဖြစ်နိုင်သည်ዠယá€á€¯á€‘ွက်ရန် Chrome က အကြံပြုပါသည်á‹</translation>
<translation id="5610142619324316209">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ စစ်ဆေးနေသည်</translation>
<translation id="5610807607761827392">ကá€á€ºá€”ှင့် လိပ်စာများကို <ph name="BEGIN_LINK" />ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„် စီမံနိုင်သည်á‹</translation>
<translation id="561165882404867731">ဤစာမျက်နှာကို Google Translate သုံးá ဘာသာပြန်ပါ</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">အáါရောင်</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> á ရင်းမြစ် မူá€á€«á€’အရ ပိá€á€ºá€‘ားသည်á‹</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (စင့်á€á€ºá€œá€¯á€•á€ºá€‘ားသည်)</translation>
+<translation id="5913377024445952699">ဖန်သားပြင်ရိုက်ယူမှုကို á€á€á€›á€•á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
<translation id="59174027418879706">ဖွင့်ထားသည်</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ဖွင့်ထားသည်</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">အပိုင်း</translation>
<translation id="5967592137238574583">အဆက်အသွယ် အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ á€á€Šá€ºá€¸á€–ြá€á€ºá€á€¼á€„်း</translation>
<translation id="5967867314010545767">သမိုင်းမှ ဖယ်ရှားရန်</translation>
+<translation id="5968793460449681917">á€á€„်ကြည့်á€á€­á€¯á€„်း</translation>
<translation id="5975083100439434680">ဇူးမ်ဖြုá€á€ºá€›á€”်</translation>
<translation id="5979084224081478209">စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸ စစ်ဆေးရန်</translation>
<translation id="5980920751713728343">အညွှန်း-áƒxá…</translation>
@@ -1393,6 +1419,7 @@
<translation id="6587923378399804057">သင် မိá€á€¹á€á€°á€€á€°á€¸á€‘ားသော လင့်á€á€º</translation>
<translation id="6591833882275308647">သင်á <ph name="DEVICE_TYPE" /> ကို စီမံá€á€”့်á€á€½á€²á€™á€‘ားပါ</translation>
<translation id="6596325263575161958">လုံá€á€¼á€¯á€¶á€¡á€±á€¬á€„်ပြုလုပ်á€á€¼á€„်း ရွေးá€á€»á€šá€ºá€™á€¾á€¯á€™á€»á€¬á€¸</translation>
+<translation id="6596892391065203054">ဤအကြောင်းအရာ ပုံနှိပ်ထုá€á€ºá€šá€°á€á€¼á€„်းကို သင်áစီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပိá€á€ºá€‘ားသည်á‹</translation>
<translation id="6604181099783169992">လှုပ်ရှားမှု သို့မဟုá€á€º အလင်းအာရုံá€á€¶á€€á€­á€›á€­á€šá€¬á€™á€»á€¬á€¸</translation>
<translation id="6609880536175561541">Prc7 (စာအိá€á€º)</translation>
<translation id="6612358246767739896">ကာကွယ်ထားသည့် အကြောင်းအရာ</translation>
@@ -1452,6 +1479,7 @@
<translation id="6895330447102777224">သင့်ကဒ်ကို အá€á€Šá€ºá€•á€¼á€¯á€•á€¼á€®á€¸á€•á€«á€•á€¼á€®</translation>
<translation id="6897140037006041989">အသုံးပြုသူ ကိုယ်စားလှယ်</translation>
<translation id="6898699227549475383">အဖွဲ့အစည်း (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> အား အောက်ပါကိုá€á€½á€„့်ပြုပါ−</translation>
<translation id="6910240653697687763"><ph name="URL" /> သည် သင်á MIDI စက်များကို အပြည့်အဠထိန်းá€á€»á€¯á€•á€ºá€œá€­á€¯á€žá€Šá€º</translation>
<translation id="6915804003454593391">အသုံးပြုသူ:</translation>
<translation id="6934672428414710184">ဤအမည်သည် သင်á Google အကောင့်မှဖြစ်သည်á‹</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">အောက်ပါနှင့် ပေါင်းစည်းထားသည်−</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">ညွှန်ကြားá€á€»á€€á€º လိုင်း</translation>
+<translation id="7359588939039777303">ကြော်ငြာများကို ပိá€á€ºá€œá€­á€¯á€€á€ºá€•á€«á€•á€¼á€®á‹</translation>
<translation id="7372973238305370288">ရှာဖွေá€á€¼á€„်းရလာဒ်</translation>
<translation id="7374733840632556089">သင် သို့မဟုá€á€º á€á€…်စုံá€á€…်ယောက်က သင့်စက်ပေါ်á€á€½á€„် ထည့်သွင်းထားသည့် အသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€á€…်á€á€¯á€€á€¼á€±á€¬á€„့် ဤပြဿနာ ဖြစ်ပေါ်ရá€á€¼á€„်းဖြစ်သည်ዠကွန်ရက်များကို စောင့်ကြည့်ရန်နှင့် ကြားဖြá€á€ºá€›á€”်အá€á€½á€€á€º အသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€€á€­á€¯ အသုံးပြုကြောင်း သိရှိထားပြီး Chrome က ယုံကြည်စိá€á€ºá€á€»á€á€¼á€„်း မရှိပါዠကျောင်း သို့မဟုá€á€º ကုမ္ပá€á€®á€€á€½á€”်ရက်များá€á€½á€„် á€á€›á€¬á€¸á€á€„်စောင့်ကြည့်သည့် ကိစ္စရပ်အá€á€»á€­á€¯á€·á€›á€¾á€­á€”ေပြီး áŽá€„်းကို သင်က ပိá€á€ºáမရနိုင်သော်လည်း ထိုသို့စောင့်ကြည့်နေကြောင်း Chrome က သင့်အား သá€á€­á€‘ားစေလိုပါသည်ዠá€á€˜á€ºá€€á€­á€¯ အသုံးပြုသည့် ဘရောင်ဇာ သို့မဟုá€á€º အပလီကေးရှင်းá€á€­á€¯á€„်းá€á€½á€„် စောင့်ကြည့်á€á€¼á€„်းများ ရှိနိုင်သည်á‹</translation>
<translation id="7375818412732305729">ဖိုင်ကို á€á€½á€²á€á€»á€­á€á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">á€á€±á€¬á€„်းဆိုမှုများ များလွန်းနေသည်</translation>
<translation id="7977538094055660992">ထုá€á€ºá€šá€°á€™á€Šá€·á€ºá€…က်</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">လွန်ကဲပကá€á€­á€¡á€žá€½á€„်ကို ကြည့်ရန် ARCore ကို ထည့်ပါ</translation>
<translation id="799149739215780103">á€á€½á€²á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="7995512525968007366">သá€á€ºá€™á€¾á€á€ºá€™á€‘ားပါ</translation>
<translation id="800218591365569300">မှá€á€ºá€‰á€¬á€á€ºá€”ေရာလွá€á€ºá€›á€›á€¾á€­á€…ေရန် á€á€˜á€º သို့မဟုá€á€º ပရိုဂရမ်များကို ပိá€á€ºá€€á€¼á€Šá€·á€ºá€•á€«á‹</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">ညွှန်ကြားá€á€»á€€á€º လိုင်း</translation>
<translation id="8508648098325802031">ရှာဖွေမှု သင်္ကေá€</translation>
<translation id="8522552481199248698">Chrome က သင်á Google အကောင့်ကို ကာကွယ်ရန်နှင့် စကားá€á€¾á€€á€ºá€•á€¼á€±á€¬á€„်းရန် ကူညီနိုင်ပါသည်á‹</translation>
+<translation id="8525306231823319788">မျက်နှာပြင် အပြည့်</translation>
<translation id="8530813470445476232">Chrome ဆက်á€á€„်များá€á€½á€„် ကြည့်ရှုá€á€¼á€„်းမှá€á€ºá€á€™á€ºá€¸áŠ ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸áŠ ကက်ရှ်နှင့် အá€á€¼á€¬á€¸á€¡á€›á€¬á€™á€»á€¬á€¸á€€á€­á€¯ ရှင်းပါ</translation>
<translation id="8533619373899488139">သင်á စနစ်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပြဋ္ဌာန်းထားသည့် အá€á€¼á€¬á€¸ မူá€á€«á€’များနှင့် ပိá€á€ºá€‘ားသော URL များစာရင်းကို ကြည့်ရန် &lt;strong&gt;chrome://policy&lt;/strong&gt; သို့ á€á€„်ကြည့်ပါá‹</translation>
<translation id="8541158209346794904">ဘလူးá€á€¯á€žá€º စက်ပစ္စည်း</translation>
<translation id="8542014550340843547">အောက်á€á€¼á€±á€á€½á€„် á€á€»á€¯á€•á€ºá€…က်ဖြင့် သုံးá€á€»á€€á€ºá€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="8543181531796978784">သင်သည် <ph name="BEGIN_ERROR_LINK" /> ထောက်လှမ်းá€á€¶á€›á€žá€Šá€·á€º ပြဿနာကို သá€á€„်းပို့နိုင် <ph name="END_ERROR_LINK" /> သို့မဟုá€á€ºáŠ သင်က သင်á လုံá€á€¼á€¯á€¶á€›á€±á€¸á€†á€­á€¯á€„်ရာ အန္á€á€›á€¬á€šá€ºá€™á€»á€¬á€¸á€€á€­á€¯ နားလည်လျှင်አ<ph name="BEGIN_LINK" /> မလုံá€á€¼á€¯á€¶á€žá€Šá€·á€º ဤဆိုက်<ph name="END_LINK" /> á€á€„်ကြည့်နိုင်သည်á‹</translation>
<translation id="8557066899867184262">CVC သည် သင့်ကဒ်အနောက်ဘက်á€á€¼á€™á€ºá€¸á€á€½á€„် ရှိသည်á‹</translation>
+<translation id="8558485628462305855">လွန်ကဲပကá€á€­á€¡á€žá€½á€„်ကို ကြည့်ရန် ARCore ကို အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€•á€«</translation>
<translation id="8559762987265718583">သင့်ကိရိယာá ရက်စွဲ နှင့် အá€á€»á€­á€”် (<ph name="DATE_AND_TIME" />)မှာ မမှန်á <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ထံသို့ ကိုယ်ရေး á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ထူထောင်မရနိုင်ပါá‹</translation>
<translation id="8564182942834072828">သီးá€á€¼á€¬á€¸ စာရွက်စာá€á€™á€ºá€¸á€™á€»á€¬á€¸/စုစည်းစီစဉ်မထားသော မိá€á€¹á€á€°á€™á€»á€¬á€¸</translation>
<translation id="8564985650692024650">အá€á€¼á€¬á€¸á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် သင်á <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> စကားá€á€¾á€€á€ºá€€á€­á€¯ ပြန်သုံးထားပါက áŽá€„်းကို ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€›á€”် Chromium က အကြံပြုပါသည်á‹</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ဤစက်á€á€½á€„် သိမ်းမည်မဟုá€á€ºá€žá€±á€¬ လုပ်ဆောင်á€á€»á€€á€º-
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ဤá€á€„်းဒိုးá€á€½á€„် သင်ကြည့်ရှုသောစာမျက်နှာများ
+ <ph name="LIST_ITEM" />ကွá€á€ºá€€á€®á€¸á€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬á€™á€»á€¬á€¸
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ကá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိုမိုမြန်ဆန်စွာ အá€á€Šá€ºá€•á€¼á€¯á€›á€”် Touch ID ကို အသုံးပြုပါ</translation>
<translation id="858637041960032120">ဖုန်းနံပါá€á€º ပေါင်းထည့်ရန်</translation>
<translation id="8589998999637048520">အကောင်းဆုံး အရည်အသွေး</translation>
+<translation id="8600271352425265729">ဤအကြိမ်သာ</translation>
<translation id="860043288473659153">ကá€á€ºá€€á€­á€¯á€„်ဆောင်သူအမည်</translation>
<translation id="8606726445206553943">သင်á MIDI စက်ကိရိယာများအား သုံးပါ</translation>
+<translation id="8612761427948161954">မင်္ဂလာပါ <ph name="USERNAME" />
+ <ph name="BR" />
+ သင်သည် 'ဧည့်သည်' အဖြစ် á€á€„်ကြည့်နေသည်</translation>
<translation id="861775596732816396">အရွယ်အစား á„</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸ မá€á€°á€Šá€®á€•á€«á‹ သိမ်းထားသော စကားá€á€¾á€€á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸á€€á€­á€¯ ပြပါá‹</translation>
<translation id="8625384913736129811">ဤကဒ်ကို ဤစက်ပစ္စည်းá€á€½á€„် သိမ်းရန်</translation>
+<translation id="8627040765059109009">ဖန်သားပြင်ရိုက်ယူမှုကို ဆက်လုပ်သည်</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> မှ <ph name="VM_NAME_1" /> နှင့် <ph name="VM_NAME_2" /> သို့ မျှá€á€±á€á€¼á€„်းကို သင်áစီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပိá€á€ºá€‘ားသည်</translation>
<translation id="8663226718884576429">မှာယူမှု အနှစ်á€á€»á€¯á€•á€ºáŠ <ph name="TOTAL_LABEL" />አနောက်ထပ် အသေးစိá€á€ºá€¡á€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="867224526087042813">လက်မှá€á€º</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google အကောင့်</translation>
<translation id="8913778647360618320">ငွေပေးá€á€»á€±á€”ည်းလမ်း စီမံရန်á€á€œá€¯á€á€ºáŠ Chrome ဆက်á€á€„်များá€á€½á€„် ငွေပေးá€á€»á€±á€™á€¾á€¯á€™á€»á€¬á€¸á€”ှင့် á€á€›á€€á€ºá€’စ်ကá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ စီမံရန် Enter နှိပ်ပါ</translation>
<translation id="8918231688545606538">ဤစာမျက်နှာသည် သံသယဖြစ်ဖွယ် ရှိသည်</translation>
+<translation id="8922013791253848639">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€½á€„် ကြော်ငြာများကို အမြဲá€á€™á€ºá€¸ á€á€½á€„့်ပြုရန်</translation>
<translation id="892588693504540538">ညာဘက်ထိပ်á€á€½á€„် ဖောက်ရန်</translation>
<translation id="8931333241327730545">သင့် Google အကောင့်သို့ ဤကဒ်ကိုသိမ်းလိုပါသလားá‹</translation>
<translation id="8932102934695377596">သင်á နာရီ နောက်ကျနေ</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> သည်ထောက်ပံ့မှုမရှိသည့် ပရိုá€á€­á€¯á€€á€±á€¬á€€á€­á€¯ အသုံးပြုထားသည်á‹</translation>
<translation id="9191834167571392248">ဘယ်ဘက်အောက်á€á€¼á€±á€á€½á€„် ဖောက်ရန်</translation>
+<translation id="9199905725844810519">ပုံနှိပ်ထုá€á€ºá€šá€°á€á€¼á€„်းကို ပိá€á€ºá€‘ားသည်</translation>
<translation id="9205078245616868884">သင့်ဒေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ သင်စင့်á€á€ºá€•á€¼á€¯á€œá€¯á€•á€ºá€‘ားသည့် စကားá€á€¾á€€á€ºá€–ြင့် အသွင်á€á€¾á€€á€ºá€‘ားပါသည်ዠစင့်á€á€ºá€•á€¼á€¯á€œá€¯á€•á€ºá€á€¼á€„်းစá€á€„်ရန် áŽá€„်းကိုထည့်ပါá‹</translation>
<translation id="9207861905230894330">ဆောင်းပါး ပေါင်းထည့်á€á€¼á€„်း မအောင်မြင်ပါá‹</translation>
<translation id="9213433120051936369">အသွင်အပြင် စိá€á€ºá€€á€¼á€­á€¯á€€á€ºá€•á€¼á€¯á€œá€¯á€•á€ºá€á€¼á€„်း</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">သင်á Google အကောင့်ကို အသုံးပြုá€á€½á€„့် ဆုံးရှုံးနိုင်သည်ዠသင့်စကားá€á€¾á€€á€ºá€€á€­á€¯ ယá€á€¯á€•á€„်ပြောင်းရန် Chromium က အကြံပြုပါသည်ዠသင့်အား လက်မှá€á€ºá€‘ိုးá€á€„်á€á€­á€¯á€„်းပါမည်á‹</translation>
<translation id="939736085109172342">ဖိုင်á€á€½á€²á€¡á€žá€…်</translation>
+<translation id="945522503751344254">အကြံပြုá€á€»á€€á€º ပေးပို့မည်</translation>
<translation id="945855313015696284">အောက်ပါအá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ စစ်ဆေးပြီး မမှန်ကန်သည့် ကá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ဖျက်ပါ</translation>
<translation id="950736567201356821">ထိပ်á€á€½á€„် သုံးá€á€»á€€á€ºá€–ောက်ရန်</translation>
+<translation id="951941430552851965">သင်áဖန်သားပြင်ပေါ်ရှိ အကြောင်းအရာကြောင့် ဖန်သားပြင်ပုံဖမ်းá€á€¼á€„်းကို စီမံá€á€”့်á€á€½á€²á€žá€°á€€ ရပ်ထားသည်á‹</translation>
<translation id="961663415146723894">အောက်á€á€¼á€±á€á€½á€„် á€á€½á€²á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="962484866189421427">ဤအကြောင်းအရာသည် အယောင်ဆောင်သော သို့မဟုá€á€º သင့်ကိုá€á€¼á€±á€›á€¬á€á€¶á€›á€¬á€á€½á€„် အသုံးပြုနိုင်သော ဒေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ စုစည်းသော လိမ်လည်လှည့်ဖျားသည့် အက်ပ်များကို ထည့်သွင်းနိုင်သည်ዠ<ph name="BEGIN_LINK" />မည်သို့ဖြစ်စေ ပြပါ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">á€á€›á€¬á€¸á€á€„် á€á€Šá€ºá€†á€±á€¬á€€á€ºá€™á€¾á€¯</translation>
diff --git a/chromium/components/strings/components_strings_ne.xtb b/chromium/components/strings/components_strings_ne.xtb
index 27e9823fade..5019cbdf4a3 100644
--- a/chromium/components/strings/components_strings_ne.xtb
+++ b/chromium/components/strings/components_strings_ne.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">तपाईंले आफà¥à¤¨à¥‹ संगठनले वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ नगरेको कà¥à¤¨à¥ˆ साइटमा आफà¥à¤¨à¥‹ पासवरà¥à¤¡ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ गरà¥à¤¨à¥à¤­à¤¯à¥‹à¥¤ आफà¥à¤¨à¥‹ खाता सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨, अनà¥à¤¯ à¤à¤ª र साइटहरूमा तपाईंको पासवरà¥à¤¡ पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¥‹à¤— नगरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="1263231323834454256">पाठà¥à¤¯ सूची</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ निमà¥à¤¨ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो यनà¥à¤¤à¥à¤°à¤®à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिने छैन:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंले यो विनà¥à¤¡à¥‹à¤®à¤¾ हेरà¥à¤¨à¥‡ पेजहरू
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ तथा साइटको डेटा
+ <ph name="LIST_ITEM" />खातासमà¥à¤¬à¤¨à¥à¤§à¥€ जानकारी (<ph name="LINK_BEGIN" />साइन आउट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">पिकअपको विधि</translation>
<translation id="1281476433249504884">सà¥à¤Ÿà¥à¤¯à¤¾à¤•à¤° १</translation>
<translation id="1285320974508926690">यो साइट कहिले पनि अनà¥à¤µà¤¾à¤¦ नगरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">आफà¥à¤¨à¥‹ Google खातामा सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिà¤à¤•à¤¾ पासवरà¥à¤¡à¤¹à¤°à¥‚ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ साइन इन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> भाषाका पृषà¥à¤ à¤¹à¤°à¥‚ अनà¥à¤µà¤¾à¤¦ गरिने छैननà¥à¥¤</translation>
<translation id="2053553514270667976">जिप कोड</translation>
+<translation id="2054665754582400095">तपाईंको उपसà¥à¤¥à¤¿à¤¤à¤¿</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{१ सà¥à¤à¤¾à¤µ}other{# सà¥à¤à¤¾à¤µà¤¹à¤°à¥‚}}</translation>
<translation id="2079545284768500474">अनà¥à¤¡à¥‚ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="20817612488360358">पà¥à¤°à¤£à¤¾à¤²à¥€ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ सेटिङहरू पà¥à¤°à¤¯à¥‹à¤—का लागि सेट छनॠतर à¤à¤‰à¤Ÿà¤¾ सà¥à¤ªà¤·à¥à¤Ÿ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ कनà¥à¤«à¤¿à¤—रेसन पनि निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ गरिà¤à¤•à¥‹ छ।</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android à¤à¤ªà¤¹à¤°à¥‚</translation>
<translation id="2107021941795971877">मà¥à¤¦à¥à¤°à¤£à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ सहायता पà¥à¤°à¤¦à¤¾à¤¨ गरà¥à¤¨à¥‡ सेवा</translation>
<translation id="2108755909498034140">आफà¥à¤¨à¥‹ कमà¥à¤ªà¥à¤¯à¥à¤Ÿà¤° पà¥à¤¨à¤ƒ सà¥à¤°à¥ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2111166930115883695">पà¥à¤²à¥‡ गरà¥à¤¨ space थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">कारà¥à¤¡</translation>
<translation id="2114841414352855701">यसलाई <ph name="POLICY_NAME" /> दà¥à¤µà¤¾à¤°à¤¾ ओभरराइड गरिà¤à¤•à¥‹ हà¥à¤¨à¤¾à¤²à¥‡ उपेकà¥à¤·à¤¾ गरियो।</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ रदà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2147827593068025794">पृषà¥à¤ à¤­à¥‚मिमा सिंक गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾</translation>
<translation id="2148613324460538318">कारà¥à¤¡ थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2149968176347646218">इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छैन</translation>
<translation id="2154054054215849342">तपाईंको डोमेनको लागि सिंंक उपलबà¥à¤§ छैन</translation>
<translation id="2154484045852737596">कारà¥à¤¡ समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2161656808144014275">पाठ</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">नीतिहरू</translation>
<translation id="2183608646556468874">फोन नमà¥à¤¬à¤°</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{१ ठेगाना}other{# ठेगानाहरू}}</translation>
-<translation id="2187243482123994665">पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾à¤•à¥‹ उपसà¥à¤¥à¤¿à¤¤à¤¿</translation>
<translation id="2187317261103489799">पतà¥à¤¤à¤¾ लगाउनà¥à¤¹à¥‹à¤¸à¥ (पूरà¥à¤µà¤¨à¤¿à¤°à¥à¤§à¤¾à¤°à¤¿à¤¤ मान)</translation>
<translation id="2188375229972301266">फेदमा à¤à¤•à¤­à¤¨à¥à¤¦à¤¾ बढी पà¥à¤µà¤¾à¤²</translation>
<translation id="2202020181578195191">मà¥à¤¯à¤¾à¤¦ सकिने मानà¥à¤¯ वरà¥à¤· पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">तपाईं जान लागà¥à¤¨à¥à¤­à¤à¤•à¥‹ साइट नकà¥à¤•à¤²à¥€ साइट हो</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤¹à¤°à¥‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> बाट तपाईंको जानकारी (उदाहरणका लागि, पासवरà¥à¤¡, सनà¥à¤¦à¥‡à¤¶ वा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡à¤¹à¤°à¥‚) चोरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¤¾à¤¸ गरिरहेका हà¥à¤¨à¤¸à¤•à¥à¤›à¤¨à¥à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">यो साइटले हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¤¾à¤°à¥€ वा भà¥à¤°à¤¾à¤®à¤• विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ देखाउà¤à¤›à¥¤</translation>
<translation id="2878197950673342043">पोसà¥à¤Ÿà¤° फोलà¥à¤¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">विनà¥à¤¡à¥‹ रहने सà¥à¤¥à¤¾à¤¨</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google बाट पà¥à¤°à¤¾à¤ªà¥à¤¤ सà¥à¤à¤¾à¤µà¤¹à¤°à¥‚</translation>
<translation id="3002501248619246229">इनपà¥à¤Ÿ टà¥à¤°à¥‡à¤•à¥‹ मिडिया जाà¤à¤šà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3005723025932146533">बचत गरिà¤à¤•à¥‹ पà¥à¤°à¤¤à¤¿ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="3007719053326478567">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ यो सामगà¥à¤°à¥€ पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾ बà¥à¤²à¤• गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छ</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> को CVC पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤ तपाईंले पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥‡ बितà¥à¤¤à¤¿à¤•à¥ˆ, तपाईंको कारà¥à¤¡à¤•à¤¾ विवरणहरू यस साइटमा साà¤à¥‡à¤¦à¤¾à¤°à¥€ गरिने छनà¥à¥¤</translation>
<translation id="3010559122411665027">सूची पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">सà¥à¤µà¤¤à¤ƒ रोक लगाइयो</translation>
<translation id="3016780570757425217">तपाईà¤à¤•à¥‹ सà¥à¤¥à¤¾à¤¨ जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, सà¥à¤à¤¾à¤µ हटाउन Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">गलत नीति पà¥à¤°à¤•à¤¾à¤°</translation>
<translation id="3037605927509011580">हरे, सà¥à¤¨à¥à¤¯à¤¾à¤ª!</translation>
@@ -552,6 +563,7 @@
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• लगाइयो</translation>
<translation id="3209034400446768650">यो पृषà¥à¤ à¤²à¥‡ शà¥à¤²à¥à¤• लिन सकà¥à¤›</translation>
<translation id="3212581601480735796">तपाईंले <ph name="HOSTNAME" /> मा गरà¥à¤¨à¥‡ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ªà¤®à¤¾à¤¥à¤¿ निगरानी गरिà¤à¤¦à¥ˆ छ</translation>
+<translation id="3212623355668894776">तपाईंले बà¥à¤°à¤¾à¤‰à¤œà¤° पà¥à¤°à¤¯à¥‹à¤— गरी गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो यनà¥à¤¤à¥à¤°à¤¬à¤¾à¤Ÿ मेटाइयोसॠभनà¥à¤¨à¤¾à¤•à¤¾ खातिर सबै गेसà¥à¤Ÿ विनà¥à¤¡à¥‹à¤¹à¤°à¥‚ बनà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="3215092763954878852">WebAuthn पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकिà¤à¤¨</translation>
<translation id="3218181027817787318">सापेकà¥à¤·</translation>
<translation id="3225919329040284222">सरà¥à¤­à¤°à¤²à¥‡ अनà¥à¤¤à¤°à¥à¤¨à¤¿à¤°à¥à¤®à¤¿à¤¤ अपेकà¥à¤·à¤¾à¤¹à¤°à¥‚सà¤à¤— नमिलà¥à¤¨à¥‡ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ गरà¥â€à¤¯à¥‹à¥¤ यी अपेकà¥à¤·à¤¾à¤¹à¤°à¥‚ विशेष, उचà¥à¤š-सà¥à¤°à¤•à¥à¤·à¤¾ वेबसाटइहरूको लागि तपाइà¤à¤²à¤¾à¤ˆ सà¥à¤°à¤•à¥à¤·à¤¾ गरà¥à¤¨ समावेश गरिà¤à¤•à¤¾ छनà¥à¥¤</translation>
@@ -699,6 +711,7 @@
<translation id="3784372983762739446">बà¥à¤²à¥à¤Ÿà¥à¤¥ उपकरणहरू</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> मा मà¥à¤¯à¤¾à¤¦ सकिनà¥à¤›</translation>
<translation id="3789155188480882154">आकार १६</translation>
+<translation id="3789841737615482174">सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3793574014653384240">हालसालै भà¤à¤•à¤¾ कà¥à¤°à¥à¤¯à¤¾à¤¸à¤¹à¤°à¥‚को सङà¥à¤–à¥à¤¯à¤¾ र तिनको कारण</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">मागिà¤à¤•à¥‹ फनà¥à¤Ÿ</translation>
@@ -750,6 +763,7 @@
<translation id="4056223980640387499">सेपिया</translation>
<translation id="4058922952496707368">कà¥à¤žà¥à¤œà¥€ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">सà¥à¤•à¥à¤°à¤¿à¤¨ कà¥à¤¯à¤¾à¤ªà¥à¤šà¤° गरà¥à¤¨à¥‡ कारà¥à¤¯ सà¥à¤šà¤¾à¤°à¥ भà¤à¤•à¥‹ छ।</translation>
<translation id="4067947977115446013">मानà¥à¤¯ ठेगाना थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4072486802667267160">तपाईंको भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€à¤•à¥‹ पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾à¤²à¤¾à¤ˆ अघि बढाउà¤à¤¦à¤¾ कà¥à¤¨à¥ˆ तà¥à¤°à¥à¤Ÿà¤¿ भयो, कृपया फेरि पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="4075732493274867456">गà¥à¤°à¤¾à¤¹à¤• र सरà¥à¤­à¤°à¤²à¥‡ à¤à¤‰à¤Ÿà¤¾ साधारण SSL पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¤² संसà¥à¤•à¤°à¤£ वा साइफर सà¥à¤‡à¤Ÿà¤²à¤¾à¤ˆ समरà¥à¤¥à¤¨ गरà¥à¤¦à¥ˆà¤¨à¤¨à¥à¥¤</translation>
@@ -833,6 +847,7 @@
<translation id="4297502707443874121">पृषà¥à¤  <ph name="THUMBNAIL_PAGE" /> को थमà¥à¤¬à¤¨à¥‡à¤²</translation>
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4300675098767811073">दायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ à¤à¤•à¤­à¤¨à¥à¤¦à¤¾ बढी पà¥à¤µà¤¾à¤²</translation>
+<translation id="4302514097724775343">पà¥à¤²à¥‡ गरà¥à¤¨ dino मा टà¥à¤¯à¤¾à¤ª गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">तपाईंको फाइल हेरà¥à¤¨ र पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकिà¤à¤¨</translation>
<translation id="4305817255990598646">सà¥à¤µà¤¿à¤š</translation>
@@ -911,6 +926,7 @@
<translation id="4658638640878098064">सिरानको बायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">भरà¥à¤šà¥à¤…ल रियालिटी</translation>
+<translation id="4675657451653251260">तपाईं गेसà¥à¤Ÿ मोडमा Chrome पà¥à¤°à¥‹à¤«à¤¾à¤‡à¤²à¤•à¥‹ कà¥à¤¨à¥ˆ पनि जानकारी देखà¥à¤¨à¥ हà¥à¤¨à¥‡ छैन। तपाईं पासवरà¥à¤¡ तथा भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ विधि जसà¥à¤¤à¤¾ Google खातामा भà¤à¤•à¤¾ आफà¥à¤¨à¤¾ जानकारी पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ <ph name="LINK_BEGIN" />साइन इन<ph name="LINK_END" /> गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤</translation>
<translation id="467662567472608290">यो सरà¥à¤­à¤°à¤²à¥‡ यो <ph name="DOMAIN" /> को भनि पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ गरà¥à¤¨ सकेन; यसको सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤®à¤¾ तà¥à¤°à¥à¤Ÿà¤¿à¤¹à¤°à¥‚ छनà¥à¥¤ यो कà¥à¤¨à¥ˆ à¤à¤‰à¤Ÿà¤¾ मिसकनà¥à¤«à¤¿à¤—रेसन वा कà¥à¤¨à¥ˆ आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤²à¥‡ तपाईंको जडानमा गरेको हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¥‹ कारणले गरà¥à¤¦à¤¾ भà¤à¤•à¥‹ हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="4677585247300749148"><ph name="URL" /> पहà¥à¤à¤šà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ कारà¥à¤¯à¤•à¥à¤°à¤®à¤¹à¤°à¥‚मा पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾ दिन चाहनà¥à¤›</translation>
<translation id="467809019005607715">Google सà¥à¤²à¤¾à¤‡à¤¡</translation>
@@ -938,6 +954,12 @@
<translation id="4761104368405085019">आफà¥à¤¨à¥‹ माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4764776831041365478"><ph name="URL" /> को वेबपेज असà¥à¤¥à¤¾à¤¯à¥€ रूपमा बनà¥à¤¦ भà¤à¤•à¥‹ हà¥à¤¨ सकà¥à¤› वा तà¥à¤¯à¥‹ सà¥à¤¥à¤¾à¤¯à¥€ रूपमा à¤à¤‰à¤Ÿà¤¾ नयाठवेब ठेगानामा सरेको हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="4766713847338118463">फेदमा दà¥à¤ˆ सà¥à¤Ÿà¤¿à¤š</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ तपाईंले गरà¥à¤¨à¥‡ निमà¥à¤¨ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो यनà¥à¤¤à¥à¤°à¤®à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिनà¥à¤›:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंले यो विनà¥à¤¡à¥‹à¤®à¤¾ डाउनलोड गरà¥à¤¨à¥‡ सबै फाइलहरू
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">à¤à¤‰à¤Ÿà¤¾ अजà¥à¤žà¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¤¿ देखापरà¥à¤¯à¥‹ ।</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{पप-अपमाथि रोक लगाइयो}other{# पप-अपहरूमाथि रोक लगाइयो}}</translation>
<translation id="4780366598804516005">मेलबकà¥à¤¸ १</translation>
@@ -1100,11 +1122,13 @@
<translation id="5386426401304769735">यस साइटको पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° शà¥à¤°à¥ƒà¤‚खलामा SHA-१ पà¥à¤°à¤¯à¥‹à¤— गरी हसà¥à¤¤à¤¾à¤•à¥à¤·à¤° गरिà¤à¤•à¥‹ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° समावेश छ।</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">दायाठकिनारमा सà¥à¤Ÿà¤¿à¤š</translation>
+<translation id="5398772614898833570">विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚माथि रोक लगाइयो</translation>
<translation id="5400836586163650660">खरानी रङà¥à¤—</translation>
<translation id="540969355065856584">यो सरà¥à¤­à¤°à¤²à¥‡ <ph name="DOMAIN" /> हो भने साबित गरà¥à¤¨ सकेन; यस समयमा यसको सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° मानà¥à¤¯ छैन। यो कनà¥à¤«à¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨ गलत भà¤à¤° वा à¤à¤‰à¤Ÿà¤¾ आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤²à¥‡ तपाईà¤à¤•à¥‹ जडान रोकेर भà¤à¤•à¥‹ हà¥à¤¨à¥ सकà¥à¤›à¥¤</translation>
<translation id="541416427766103491">सà¥à¤Ÿà¥à¤¯à¤¾à¤•à¤° ४</translation>
<translation id="5421136146218899937">बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ डाटा खाली गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> तपाईंलाई सूचनाहरू पठाउन चाहनà¥à¤›</translation>
+<translation id="542872847390508405">तपाइठपाहà¥à¤¨à¤¾à¤•à¥‹ रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›</translation>
<translation id="5430298929874300616">पà¥à¤¸à¥à¤¤à¤•à¤šà¤¿à¤¨à¥‹ हटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />":<ph name="ERROR" /> मा सà¥à¤•à¤¿à¤®à¤¾ रà¥à¤œà¥‚ तà¥à¤°à¥à¤Ÿà¤¿</translation>
<translation id="5443468954631487277">विपरीत कà¥à¤°à¤® तर माथितिर फरà¥à¤•à¤¾à¤à¤°</translation>
@@ -1146,12 +1170,12 @@
<translation id="5571083550517324815">यो ठेगानाबाट पिकअप गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤ कà¥à¤¨à¥ˆ अरà¥à¤•à¥‹ ठेगाना चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="5580958916614886209">आफà¥à¤¨à¥‹ मà¥à¤¯à¤¾à¤¦ सकिने महिनाको जाà¤à¤š गरी फेरि पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5586446728396275693">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिà¤à¤•à¥‹ कà¥à¤¨à¥ˆ ठेगाना छैन</translation>
+<translation id="5593349413089863479">इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ पूरà¥à¤£ रूपमा सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छैन</translation>
<translation id="5595485650161345191">ठेगाना समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5598944008576757369">भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ विधि छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="560412284261940334">वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ समरà¥à¤¥à¤¿à¤¤ छैन</translation>
<translation id="5605670050355397069">लेजर</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">यो साइट à¤à¥à¤Ÿà¥‹ वा ठगीपूरà¥à¤£ हà¥à¤¨ सकà¥à¤›à¥¤ Chrome ले अब यो साइट छोडà¥à¤¨ सिफारिस गरà¥à¤›à¥¤</translation>
<translation id="5610142619324316209">जडानलाई जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5610807607761827392">तपाईं <ph name="BEGIN_LINK" />सेटिङहरू<ph name="END_LINK" /> मा गई कारà¥à¤¡ र ठेगानाहरूको वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤</translation>
<translation id="561165882404867731">Google अनà¥à¤µà¤¾à¤¦à¤•à¤•à¤¾ सहायताले यो पृषà¥à¤  अनà¥à¤µà¤¾à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1223,6 +1247,7 @@
<translation id="5901630391730855834">पहेà¤à¤²à¥‹</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> को मूल नीतिका आधारमा रोक लगाइयो।</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (सिंक गरिà¤à¤•à¥‹)</translation>
+<translation id="5913377024445952699">सà¥à¤•à¥à¤°à¤¿à¤¨ कà¥à¤¯à¤¾à¤ªà¥à¤šà¤° गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾ पज गरियो</translation>
<translation id="59174027418879706">सकà¥à¤·à¤® गरिà¤à¤•à¥‹</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">सकà¥à¤°à¤¿à¤¯ छ</translation>
@@ -1235,6 +1260,7 @@
<translation id="5963413905009737549">खणà¥à¤¡</translation>
<translation id="5967592137238574583">समà¥à¤ªà¤°à¥à¤•à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ जानकारी समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5967867314010545767">इतिहासबाट हटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="5968793460449681917">साइट खोलà¥à¤¦à¥ˆà¤ªà¤¿à¤šà¥à¤›à¥‡</translation>
<translation id="5975083100439434680">जà¥à¤® आउट</translation>
<translation id="5979084224081478209">पासवरà¥à¤¡à¤¹à¤°à¥‚को जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1390,6 +1416,7 @@
<translation id="6587923378399804057">तपाईंले पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ लिंक</translation>
<translation id="6591833882275308647">तपाईंको <ph name="DEVICE_TYPE" /> वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ छैन</translation>
<translation id="6596325263575161958">गà¥à¤ªà¥à¤¤à¥€à¤•à¤°à¤£ विकलà¥à¤ªà¤¹à¤°à¥‚</translation>
+<translation id="6596892391065203054">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ यो सामगà¥à¤°à¥€ पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾ बà¥à¤²à¤• गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छ।</translation>
<translation id="6604181099783169992">चाल वा पà¥à¤°à¤•à¤¾à¤¶à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ सेनà¥à¤¸à¤°à¤¹à¤°à¥‚</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€</translation>
@@ -1449,6 +1476,7 @@
<translation id="6895330447102777224">तपाईंको कारà¥à¤¡à¤•à¥‹ पà¥à¤·à¥à¤Ÿà¤¿ भयो</translation>
<translation id="6897140037006041989">पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ à¤à¤œà¥‡à¤¨à¥à¤Ÿ</translation>
<translation id="6898699227549475383">संगठन (सं)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> लाई निमà¥à¤¨ कारà¥à¤¯à¤¹à¤°à¥‚ गरà¥à¤¨Â à¤¦à¤¿à¤¨à¥à¤¹à¥‹à¤¸à¥:</translation>
<translation id="6910240653697687763"><ph name="URL" /> तपाईंका MIDI यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚माथि पूरà¥à¤£ नियनà¥à¤¤à¥à¤°à¤£ पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨ चाहनà¥à¤›</translation>
<translation id="6915804003454593391">पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾:</translation>
<translation id="6934672428414710184">यो नाम तपाईंको Google खाताबाट लिइà¤à¤•à¥‹ हो</translation>
@@ -1560,6 +1588,7 @@
<translation id="7346048084945669753">समà¥à¤¬à¤¦à¥à¤§ पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ हो कि होइन:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">आदेश रेखा</translation>
+<translation id="7359588939039777303">विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚माथि रोक लगाइयो।</translation>
<translation id="7372973238305370288">खोजको परिणाम</translation>
<translation id="7374733840632556089">तपाईं वा अरू कसैले तपाईंको यनà¥à¤¤à¥à¤°à¤®à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरेका कारण यसà¥à¤¤à¥‹ समसà¥à¤¯à¤¾ आउà¤à¤›à¥¤ उकà¥à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° नेटवरà¥à¤•à¤¹à¤°à¥‚को निगरानी गरà¥à¤¨ र तिनमा अवरोध गरà¥à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरिने भनी चिनिनà¥à¤› र Chrome ले यसलाई विशà¥à¤µà¤¾à¤¸ गरà¥à¤¦à¥ˆà¤¨à¥¤ विदà¥à¤¯à¤¾à¤²à¤¯ वा कमà¥à¤ªà¤¨à¥€à¤•à¥‹ नेटवरà¥à¤• जसà¥à¤¤à¤¾ केही सà¥à¤¥à¤¾à¤¨à¤•à¤¾ हकमा निगरानी गरिने कारà¥à¤¯ वैध नै मानिनà¥à¤› र तपाईंले तà¥à¤¯à¤¸à¥à¤¤à¤¾ निगरानीलाई रोकà¥à¤¨ नसकà¥à¤¨à¥‡ भठतापनि Chrome तपाईं तà¥à¤¯à¤¸à¤¬à¤¾à¤°à¥‡ जानकार रहनà¥à¤¹à¥‹à¤¸à¥ भनà¥à¤¨à¥‡ चाहनà¥à¤›à¥¤ वेबमाथि पहà¥à¤à¤š गरà¥à¤¨ सकà¥à¤¨à¥‡ जà¥à¤¨à¤¸à¥à¤•à¥ˆ बà¥à¤°à¤¾à¤‰à¤œà¤° वा à¤à¤ªà¤®à¤¾à¤¥à¤¿ निगरानी हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="7375818412732305729">फाइल à¤à¤Ÿà¥à¤¯à¤¾à¤š गरिà¤à¤¦à¤¾</translation>
@@ -1619,7 +1648,7 @@
<translation id="7542995811387359312">सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ भरणलाई अकà¥à¤·à¤® बनाइà¤à¤•à¥‹ छ किनभने यो फारामले सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ जडान पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¦à¥ˆà¤¨à¥¤</translation>
<translation id="7548892272833184391">जडानसमà¥à¤¬à¤¨à¥à¤§à¥€ तà¥à¤°à¥à¤Ÿà¤¿à¤¹à¤°à¥‚ ठिक गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7549584377607005141">यो वेबपृषà¥à¤  ठीकसà¤à¤— पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ हà¥à¤¨à¤•à¥‹ लागि यस वेबपृषà¥à¤ à¤²à¤¾à¤ˆ तपाइà¤à¤²à¥‡ पहिले पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ लगत आवशà¥à¤¯à¤• छ। तपाइà¤à¤²à¥‡ यो लगत फेरि पठाउन सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›, तर यसो गरà¥à¤¨à¤¾à¤²à¥‡ यस पृषà¥à¤ à¤²à¥‡ पहिले पà¥à¤°à¤¦à¤¦à¤°à¥à¤¶à¤¨ गरेको कà¥à¤¨à¥ˆ पनि कारà¥à¤¯ तपाइà¤à¤²à¥‡ फेरि गरà¥à¤¨à¥à¤¹à¥à¤¨à¥‡à¤›à¥¤</translation>
-<translation id="7550637293666041147">तपाईंको यनà¥à¤¤à¥à¤°à¤•à¥‹ पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾à¤•à¥‹ नाम र Chrome को पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾à¤•à¥‹ नाम</translation>
+<translation id="7550637293666041147">तपाईंको यनà¥à¤¤à¥à¤°à¤•à¥‹ यà¥à¤œà¤°à¤¨à¥‡à¤® र Chrome को यà¥à¤œà¤°à¤¨à¥‡à¤®</translation>
<translation id="7552846755917812628">निमà¥à¤¨ सà¥à¤à¤¾à¤µà¤¹à¤°à¥‚को पालना गरी हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥:</translation>
<translation id="7554791636758816595">नयाठटà¥à¤¯à¤¾à¤¬</translation>
<translation id="7564049878696755256">तपाईंले आफà¥à¤¨à¥‹ <ph name="ORG_NAME" /> खातामाथिको पहà¥à¤à¤š गà¥à¤®à¤¾à¤‰à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› वा तपाईंको पहिचान चोरी हà¥à¤¨ सकà¥à¤›à¥¤ Chrome तपाईंलाई आफà¥à¤¨à¥‹ पासवरà¥à¤¡ अहिले नै परिवरà¥à¤¤à¤¨ गरà¥à¤¨ सिफारिस गरà¥à¤›à¥¤</translation>
@@ -1734,6 +1763,7 @@
<translation id="7976214039405368314">अतà¥à¤¯à¤¨à¥à¤¤ धेरै पटक अनà¥à¤°à¥‹à¤§ गरियो</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ यनà¥à¤¤à¥à¤°</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटी सामगà¥à¤°à¥€ हेरà¥à¤¨ ARCore सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="799149739215780103">बाइनà¥à¤¡</translation>
<translation id="7995512525968007366">निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ नभà¤à¤•à¥‹</translation>
<translation id="800218591365569300">मेमोरी खाली गरà¥à¤¨ अनà¥à¤¯ टà¥à¤¯à¤¾à¤¬ वा पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤®à¤¹à¤°à¥‚ बनà¥à¤¦ गरी हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
@@ -1861,24 +1891,38 @@
<translation id="8507227106804027148">कमानà¥à¤¡ लाइन</translation>
<translation id="8508648098325802031">खोज आइकन</translation>
<translation id="8522552481199248698">Chrome ले तपाईंलाई आफà¥à¤¨à¥‹ Google खाता सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨ र आफà¥à¤¨à¥‹ पासवरà¥à¤¡ बदलà¥à¤¨ मदà¥à¤¦à¤¤ गरà¥à¤¨ सकà¥à¤›à¥¤</translation>
+<translation id="8525306231823319788">पूरà¥à¤£ सà¥à¤•à¥à¤°à¥€à¤¨</translation>
<translation id="8530813470445476232">Chrome का सेटिङमा गई आफà¥à¤¨à¥‹ बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ इतिहास, कà¥à¤•à¥€, कà¥à¤¯à¤¾à¤¸ र अनà¥à¤¯ डेटा मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8533619373899488139">बà¥à¤²à¤• गरिà¤à¤•à¤¾ URL र तपाईंको पà¥à¤°à¤£à¤¾à¤²à¥€à¤•à¤¾ à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ लागू गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ अनà¥à¤¯ नीतिहरूको सूची हेरà¥à¤¨ &lt;strong&gt;chrome://policy&lt;/strong&gt; मा जानà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="8541158209346794904">बà¥à¤²à¥à¤Ÿà¥à¤¥ यनà¥à¤¤à¥à¤°</translation>
<translation id="8542014550340843547">फेदमा तीन सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="8543181531796978784">तपाईं <ph name="BEGIN_ERROR_LINK" />à¤à¤• पतà¥à¤¤à¤¾ लगाउने समसà¥à¤¯à¤¾ रिपोरà¥à¤Ÿ गरà¥à¤¨<ph name="END_ERROR_LINK" /> सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›, यदि तपाईं आफà¥à¤¨à¥‹ सà¥à¤°à¤•à¥à¤·à¤¾à¤•à¥‹ जोखिम बà¥à¤à¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› भने, <ph name="BEGIN_LINK" />असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइटको भà¥à¤°à¤®à¤£ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" />।</translation>
<translation id="8557066899867184262">उकà¥à¤¤ CVC तपाईंको कारà¥à¤¡à¤•à¥‹ पछाडितिर छ।</translation>
+<translation id="8558485628462305855">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटी सामगà¥à¤°à¥€ हेरà¥à¤¨ ARCore अपडेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />मा à¤à¤‰à¤Ÿà¤¾ निजी जडान सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨ किनकि तपाईà¤à¤•à¥‹ यनà¥à¤¤à¥à¤°à¤•à¥‹ मिति र समय <ph name="DATE_AND_TIME" /> गलत छनà¥à¥¤</translation>
<translation id="8564182942834072828">छà¥à¤Ÿà¥à¤Ÿà¤¾ छà¥à¤Ÿà¥à¤Ÿà¥ˆ कागजातहरू/कà¥à¤°à¤®à¤¬à¤¦à¥à¤§ नगरिà¤à¤•à¤¾ पà¥à¤°à¤¤à¤¿à¤¹à¤°à¥‚</translation>
<translation id="8564985650692024650">तपाईंले आफà¥à¤¨à¥‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> को पासवरà¥à¤¡ अनà¥à¤¯ साइटहरूमा पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ खणà¥à¤¡à¤®à¤¾ Chromium ले तपाईंलाई उकà¥à¤¤ पासवरà¥à¤¡ रिसेट गरà¥à¤¨ सिफारिस गरà¥à¤¦à¤›à¥¤</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ निमà¥à¤¨ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो यनà¥à¤¤à¥à¤°à¤®à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिने छैन:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंले यो विनà¥à¤¡à¥‹à¤®à¤¾ हेरà¥à¤¨à¥‡ पेजहरू
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ तथा साइटको डेटा
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">कारà¥à¤¡à¤¹à¤°à¥‚ अठछिटो पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨ Touch ID पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="858637041960032120">फोन नमà¥à¤¬à¤° थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8589998999637048520">उतà¥à¤•à¥ƒà¤·à¥à¤Ÿ गà¥à¤£à¤¸à¥à¤¤à¤°</translation>
+<translation id="8600271352425265729">यो बेला मातà¥à¤°</translation>
<translation id="860043288473659153">कारà¥à¤¡à¤µà¤¾à¤²à¤¾à¤•à¥‹ नाम</translation>
<translation id="8606726445206553943">तपाईà¤à¤•à¤¾ MIDI यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="8612761427948161954">नमसà¥à¤¤à¥‡ <ph name="USERNAME" />,
+ <ph name="BR" />
+ तपाईं अतिथिका रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›</translation>
<translation id="861775596732816396">आकार ४</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">मिलà¥à¤¦à¥‹ पासवरà¥à¤¡ फेला परेन। सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिà¤à¤•à¤¾ सबै पासवरà¥à¤¡à¤¹à¤°à¥‚ देखाउनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="8625384913736129811">यो कारà¥à¤¡à¤²à¤¾à¤ˆ यस यनà¥à¤¤à¥à¤°à¤®à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="8627040765059109009">सà¥à¤•à¥à¤°à¤¿à¤¨à¤¸à¤Ÿ खिचà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾ सà¥à¤šà¤¾à¤°à¥ गरिà¤à¤•à¥‹ छ</translation>
<translation id="8657078576661269990">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ <ph name="ORIGIN_NAME" /> बाट <ph name="VM_NAME_1" /> र <ph name="VM_NAME_2" /> मा सेयर गरà¥à¤¨à¥‡ रोक लगाउनà¥à¤­à¤à¤•à¥‹ छ</translation>
<translation id="8663226718884576429">अरà¥à¤¡à¤°à¤•à¥‹ सारांश, <ph name="TOTAL_LABEL" />, थप विवरण</translation>
<translation id="867224526087042813">हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
@@ -1941,6 +1985,7 @@
<translation id="8912362522468806198">Google खाता</translation>
<translation id="8913778647360618320">'भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ विधिहरू वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥' नामक बटन, Chrome का सेटिङमा गई आफà¥à¤¨à¤¾ भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ तथा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ जानकारी वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨ Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8918231688545606538">यो पृषà¥à¤  शङà¥à¤•à¤¾à¤¸à¥à¤ªà¤¦ छ</translation>
+<translation id="8922013791253848639">यो साइटमा सधैठविजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ राखà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="892588693504540538">सिरानको दायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ पà¥à¤µà¤¾à¤²</translation>
<translation id="8931333241327730545">तपाईं आफà¥à¤¨à¥‹ Google खातामा यो कारà¥à¤¡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤›?</translation>
<translation id="8932102934695377596">तपाईंको घडी ढिला छ</translation>
@@ -2012,6 +2057,7 @@
<translation id="9183302530794969518">Google कागजात</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ले असमरà¥à¤¥à¤¿à¤¤ पà¥à¤°à¥‹à¤Ÿà¥‹à¤•à¤² पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¦à¤›à¥¤</translation>
<translation id="9191834167571392248">फेदको बायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ पà¥à¤µà¤¾à¤²</translation>
+<translation id="9199905725844810519">पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾ बà¥à¤²à¤• गरिà¤à¤•à¥‹ छ</translation>
<translation id="9205078245616868884">तपाईà¤à¤•à¥‹ डेटालाई तपाईà¤à¤•à¥‹ सिंक पासफà¥à¤°à¥‡à¤œà¤®à¤¾à¤°à¥à¤«à¤¤ इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ गरिà¤à¤•à¥‹ छ। सिंक सà¥à¤°à¥ गरà¥à¤¨ तà¥à¤¯à¥‹ पासफà¥à¤°à¥‡à¤œ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="9207861905230894330">लेख थपà¥à¤¨ असफल भयो।</translation>
<translation id="9213433120051936369">आफूले चाहेअनà¥à¤¸à¤¾à¤°à¤•à¥‹ रूप बनाउनà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -2022,8 +2068,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">तपाईं आफà¥à¤¨à¥‹ Google खातामाथिको पहà¥à¤à¤š गà¥à¤®à¤¾à¤‰à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ Chromium तपाईंलाई आफà¥à¤¨à¥‹ पासवरà¥à¤¡ अहिले नै परिवरà¥à¤¤à¤¨ गरà¥à¤¨ सिफारिस गरà¥à¤›à¥¤ तपाईंलाई साइन इन गरà¥à¤¨ लगाइने छ।</translation>
<translation id="939736085109172342">नयाठफोलà¥à¤¡à¤°</translation>
+<translation id="945522503751344254">पृषà¥à¤ à¤ªà¥‹à¤·à¤£ पठाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="945855313015696284">तल दिइà¤à¤•à¥‹ जानकारीको जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ र सबै अमानà¥à¤¯ कारà¥à¤¡ मेटà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="950736567201356821">सिरानमा तीन पà¥à¤µà¤¾à¤²</translation>
+<translation id="951941430552851965">तपाईंको सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ गोपà¥à¤¯ सामगà¥à¤°à¥€ भà¤à¤•à¤¾ कारण तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ सà¥à¤•à¥à¤°à¤¿à¤¨ कà¥à¤¯à¤¾à¤ªà¥à¤šà¤° गरà¥à¤¨à¥‡ कारà¥à¤¯ असà¥à¤¥à¤¾à¤¯à¥€ रूपमा रोकà¥à¤•à¤¾ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छ।</translation>
<translation id="961663415146723894">फेदको बाइनà¥à¤¡</translation>
<translation id="962484866189421427">यो सामगà¥à¤°à¥€à¤²à¥‡ आफूलाई अरà¥à¤•à¥ˆ रूपमा पà¥à¤°à¤¸à¥à¤¤à¥à¤¤ गरà¥à¤¨à¥‡ भà¥à¤°à¤¾à¤®à¤• अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—हरूको सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨ वा तपाईंलाई टà¥à¤°à¥à¤¯à¤¾à¤• गरà¥à¤¨à¥‡ कारà¥à¤¯à¤®à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकिने डेटाको सङà¥à¤•à¤²à¤¨ गरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨ सकà¥à¤›à¥¤ <ph name="BEGIN_LINK" />जे भठपनि देखाउनà¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="969892804517981540">आधिकारिक निरà¥à¤®à¤¾à¤£</translation>
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index 03735b05d74..0c1bbbd9fb4 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -80,6 +80,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Je hebt je wachtwoord ingevoerd op een site die niet door je organisatie wordt beheerd. Hergebruik je wachtwoord niet voor andere apps en sites om je account te beschermen.</translation>
<translation id="1263231323834454256">Leeslijst</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />Activiteit die niet op dit apparaat blijft staan:<ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pagina's die je bekijkt in dit venster
+ <ph name="LIST_ITEM" />Cookies en sitegegevens
+ <ph name="LIST_ITEM" />Accountgegevens (<ph name="LINK_BEGIN" />uitloggen<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ophaalmethode</translation>
<translation id="1281476433249504884">Stapeleenheid 1</translation>
<translation id="1285320974508926690">Deze site nooit vertalen</translation>
@@ -280,6 +286,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="204357726431741734">Inloggen om wachtwoorden te gebruiken die zijn opgeslagen in je Google-account</translation>
<translation id="2053111141626950936">Pagina's in het <ph name="LANGUAGE" /> worden niet vertaald.</translation>
<translation id="2053553514270667976">Postcode</translation>
+<translation id="2054665754582400095">Je aanwezigheid</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestie}other{# suggesties}}</translation>
<translation id="2079545284768500474">Ongedaan maken</translation>
<translation id="20817612488360358">De proxyinstellingen van het systeem moeten worden gebruikt, maar er is ook een expliciete proxyconfiguratie opgegeven.</translation>
@@ -293,6 +300,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2102495993840063010">Android-apps</translation>
<translation id="2107021941795971877">Afdruksteunen</translation>
<translation id="2108755909498034140">Je computer opnieuw opstarten</translation>
+<translation id="2111166930115883695">Druk op de spatiebalk om te spelen</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Pas</translation>
<translation id="2114841414352855701">Genegeerd omdat het werd overschreven door <ph name="POLICY_NAME" />.</translation>
@@ -304,6 +312,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="214556005048008348">Betaling annuleren</translation>
<translation id="2147827593068025794">Synchronisatie op de achtergrond</translation>
<translation id="2148613324460538318">Pas toevoegen</translation>
+<translation id="2149968176347646218">Verbinding is niet beveiligd</translation>
<translation id="2154054054215849342">De synchronisatieservice is niet beschikbaar voor je domein</translation>
<translation id="2154484045852737596">Pas bewerken</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -314,7 +323,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2181821976797666341">Beleid</translation>
<translation id="2183608646556468874">Telefoonnummer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adressen}}</translation>
-<translation id="2187243482123994665">Aanwezigheid van gebruiker</translation>
<translation id="2187317261103489799">Detecteren (standaard)</translation>
<translation id="2188375229972301266">Meerdere perforaties onder</translation>
<translation id="2202020181578195191">Geef een geldig vervaljaar op</translation>
@@ -443,7 +451,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="272451190272506600">Raak de sensor aan om te betalen</translation>
<translation id="2728127805433021124">Het certificaat van de server is ondertekend met een zwak ondertekeningsalgoritme.</translation>
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Verbindingsdiagnose uitvoeren<ph name="END_LINK" /></translation>
-<translation id="2734544361860335147">Als je deze functies inschakelt, kun je browsergegevens kwijtraken of je veiligheid of privacy in gevaar brengen. Ingeschakelde functies zijn van toepassing op alle gebruikers van deze browser.</translation>
+<translation id="2734544361860335147">Als je deze functies inschakelt, kun je browsegegevens kwijtraken of je veiligheid of privacy in gevaar brengen. Ingeschakelde functies zijn van toepassing op alle gebruikers van deze browser.</translation>
<translation id="2735043616039983645">Er zijn meerdere bronnen met conflicterende waarden aanwezig voor dit beleid.</translation>
<translation id="2738330467931008676">Ophaaladres kiezen</translation>
<translation id="2740531572673183784">OK</translation>
@@ -465,6 +473,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2839501879576190149">Nepsite gedetecteerd</translation>
<translation id="2850739647070081192">Invite (envelop)</translation>
<translation id="2856444702002559011">Cybercriminelen proberen mogelijk je gegevens van <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te stelen (bijvoorbeeld wachtwoorden, berichten of creditcardgegevens). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Site geeft opdringerige of misleidende advertenties weer.</translation>
<translation id="2878197950673342043">Kruisvouw</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Vensterplaatsing</translation>
@@ -503,14 +512,14 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2996674880327704673">Suggesties van Google</translation>
<translation id="3002501248619246229">Materiaal in de invoerlade controleren</translation>
<translation id="3005723025932146533">Opgeslagen kopie weergeven</translation>
-<translation id="3007719053326478567">Het afdrukken van deze content is geblokkeerd door je beheerder</translation>
<translation id="3008447029300691911">Geef de CVC-code voor <ph name="CREDIT_CARD" /> op. Zodra je bevestigt, worden je creditcardgegevens gedeeld met deze site.</translation>
<translation id="3010559122411665027">Lijstitem '<ph name="ENTRY_INDEX" />': <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatisch geblokkeerd</translation>
<translation id="3016780570757425217">Je locatie weten</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, druk op Tab en daarna op Enter om de suggestie te verwijderen.</translation>
<translation id="3023071826883856138">You4 (envelop)</translation>
<translation id="3024663005179499861">Onjuist beleidstype</translation>
-<translation id="3037605927509011580">Helaas.</translation>
+<translation id="3037605927509011580">Asjemenou!</translation>
<translation id="3041612393474885105">Certificaatgegevens</translation>
<translation id="3060227939791841287">C9 (envelop)</translation>
<translation id="3061707000357573562">Patchservice</translation>
@@ -547,6 +556,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3207960819495026254">Toegevoegd aan 'Bookmarks'</translation>
<translation id="3209034400446768650">Pagina kan geld in rekening brengen</translation>
<translation id="3212581601480735796">Je activiteit op <ph name="HOSTNAME" /> wordt gecontroleerd</translation>
+<translation id="3212623355668894776">Sluit alle gastvensters zodat je browse-activiteit wordt verwijderd van dit apparaat.</translation>
<translation id="3215092763954878852">Kan WebAuthn niet gebruiken</translation>
<translation id="3218181027817787318">Relatief</translation>
<translation id="3225919329040284222">De server heeft een certificaat gepresenteerd dat niet overeenkomt met de ingebouwde verwachtingen. Deze verwachtingen zijn opgenomen voor bepaalde websites om je te beschermen.</translation>
@@ -692,6 +702,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3784372983762739446">Bluetooth-apparaten</translation>
<translation id="3787705759683870569">Verloopt: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Grootte 16</translation>
+<translation id="3789841737615482174">Installeren</translation>
<translation id="3793574014653384240">Aantallen en oorzaken van de crashes die onlangs hebben plaatsgevonden</translation>
<translation id="3797522431967816232">Prc3 (envelop)</translation>
<translation id="3799805948399000906">Lettertype aangevraagd</translation>
@@ -743,6 +754,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Sleutel '<ph name="SUBKEY" />': <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (envelop)</translation>
+<translation id="4067669230157909013">De schermopname is hervat.</translation>
<translation id="4067947977115446013">Geldig adres toevoegen</translation>
<translation id="4072486802667267160">Er is een fout opgetreden bij het verwerken van je bestelling. Probeer het opnieuw.</translation>
<translation id="4075732493274867456">De client en server ondersteunen geen algemene SSL-protocolversie of coderingssuite.</translation>
@@ -807,7 +819,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
&lt;p&gt;Deze foutmelding wordt weergegeven wanneer je antivirussoftware gebruikt met HTTPS-bescherming of HTTPS-scannen. Deze software verhindert dat Chrome beveiliging biedt.&lt;/p&gt;
&lt;p&gt;Schakel je antivirussoftware uit om het probleem op te lossen. Als de pagina werkt nadat je de software hebt uitgeschakeld, kun je de software uitschakelen wanneer je beveiligde sites bezoekt.&lt;/p&gt;
&lt;p&gt;Vergeet niet je antivirussoftware weer in te schakelen zodra je klaar bent.&lt;/p&gt;
- &lt;h4&gt;Stap 5: Vraag extra ondersteuning&lt;/h4&gt;
+ &lt;h4&gt;Stap 5: Vraag extra support&lt;/h4&gt;
&lt;p&gt;Als de fout nog steeds wordt weergegeven, neem je contact op met de eigenaar van de website.&lt;/p&gt;</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Voer Netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="4234495348042597185"><ph name="BEGIN_LINK" />Doorgaan naar <ph name="SITE" /><ph name="END_LINK" /></translation>
@@ -827,6 +839,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4297502707443874121">Miniatuur voor pagina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Uitvouwen</translation>
<translation id="4300675098767811073">Meerdere perforaties rechts</translation>
+<translation id="4302514097724775343">Tik op de dino om te spelen</translation>
<translation id="4302965934281694568">Chou3 (envelop)</translation>
<translation id="4305666528087210886">Je bestand kan niet worden geopend</translation>
<translation id="4305817255990598646">Overschakelen</translation>
@@ -905,6 +918,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4658638640878098064">Nietje linksboven</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reality</translation>
+<translation id="4675657451653251260">Je ziet geen Chrome-profielgegevens in de gastmodus. Je kunt <ph name="LINK_BEGIN" />inloggen<ph name="LINK_END" /> voor toegang tot je Google-accountgegevens zoals wachtwoorden en betaalmethoden.</translation>
<translation id="467662567472608290">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server bevat fouten. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="4677585247300749148"><ph name="URL" /> wil reageren op toegankelijkheidsfunctionaliteit</translation>
<translation id="467809019005607715">Google Presentaties</translation>
@@ -932,6 +946,10 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4761104368405085019">Je microfoon gebruiken</translation>
<translation id="4764776831041365478"><ph name="URL" /> werkt even niet, of de pagina kan verhuisd zijn naar een nieuw webadres.</translation>
<translation id="4766713847338118463">Twee nietjes onder</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />Je activiteit die op dit apparaat blijft staan:<ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bestanden die je downloadt in dit venster
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Er is een onbekende fout opgetreden.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up geblokkeerd}other{# pop-ups geblokkeerd}}</translation>
<translation id="4780366598804516005">Mailbox 1</translation>
@@ -1094,11 +1112,13 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5386426401304769735">De certificaatketen voor deze site bevat een certificaat dat is ondertekend met SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Inbinden met nietjes rechts</translation>
+<translation id="5398772614898833570">Advertenties geblokkeerd</translation>
<translation id="5400836586163650660">Grijs</translation>
<translation id="540969355065856584">Deze server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat is momenteel niet geldig. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="541416427766103491">Stapeleenheid 4</translation>
<translation id="5421136146218899937">Browsegegevens wissen</translation>
<translation id="5426179911063097041"><ph name="SITE" /> wil meldingen sturen</translation>
+<translation id="542872847390508405">Je browst momenteel als gast</translation>
<translation id="5430298929874300616">Bookmark verwijderen</translation>
<translation id="5439770059721715174">Schemavalidatiefout op '<ph name="ERROR_PATH" />': <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Omgekeerde volgorde met de bedrukte zijde omhoog</translation>
@@ -1140,12 +1160,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5571083550517324815">Kan niet ophalen van dit adres. Selecteer een ander adres.</translation>
<translation id="5580958916614886209">Controleer de vervalmaand en probeer het opnieuw</translation>
<translation id="5586446728396275693">Geen opgeslagen adressen</translation>
+<translation id="5593349413089863479">Verbinding is niet volledig beveiligd</translation>
<translation id="5595485650161345191">Adres bewerken</translation>
<translation id="5598944008576757369">Betaalmethode kiezen</translation>
<translation id="560412284261940334">Beheer wordt niet ondersteund</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Deze site is mogelijk nep of bedrieglijk. Chrome raadt je aan de site direct te verlaten.</translation>
<translation id="5610142619324316209">Controleer de verbinding</translation>
<translation id="5610807607761827392">Je kunt passen en adressen beheren in <ph name="BEGIN_LINK" />Instellingen<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Deze pagina vertalen met Google Translate</translation>
@@ -1217,6 +1237,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5901630391730855834">Geel</translation>
<translation id="5905445707201418379">Geblokkeerd op basis van het herkomstbeleid van <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (gesynchroniseerd)</translation>
+<translation id="5913377024445952699">Schermopname onderbroken</translation>
<translation id="59174027418879706">Ingeschakeld</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aan</translation>
@@ -1229,6 +1250,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5963413905009737549">Sectie</translation>
<translation id="5967592137238574583">Contactgegevens bewerken</translation>
<translation id="5967867314010545767">Verwijderen uit geschiedenis</translation>
+<translation id="5968793460449681917">Bij elk bezoek</translation>
<translation id="5975083100439434680">Uitzoomen</translation>
<translation id="5979084224081478209">Wachtwoorden controleren</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1285,7 +1307,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6165508094623778733">Meer informatie</translation>
<translation id="6177128806592000436">Je verbinding met deze site is niet beveiligd</translation>
<translation id="6180316780098470077">Interval voor nieuwe poging</translation>
-<translation id="6196640612572343990">Indirecte cookies blokkeren</translation>
+<translation id="6196640612572343990">Cookies van derden blokkeren</translation>
<translation id="6203231073485539293">Controleer je internetverbinding</translation>
<translation id="6218753634732582820">Adres verwijderen uit Chromium?</translation>
<translation id="622039917539443112">Parallelvouw</translation>
@@ -1383,6 +1405,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6587923378399804057">Link die je hebt gekopieerd</translation>
<translation id="6591833882275308647">Je <ph name="DEVICE_TYPE" /> wordt niet beheerd</translation>
<translation id="6596325263575161958">Opties voor encryptie</translation>
+<translation id="6596892391065203054">Het afdrukken van deze content is geblokkeerd door je beheerder.</translation>
<translation id="6604181099783169992">Bewegings- of lichtsensoren</translation>
<translation id="6609880536175561541">Prc7 (envelop)</translation>
<translation id="6612358246767739896">Beschermde content</translation>
@@ -1442,6 +1465,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6895330447102777224">Je creditcard is bevestigd</translation>
<translation id="6897140037006041989">User-agent</translation>
<translation id="6898699227549475383">Organisatie (O)</translation>
+<translation id="6907293445143367439">Toestaan dat <ph name="SITE_NAME" /> het volgende doet:</translation>
<translation id="6910240653697687763"><ph name="URL" /> wil volledig beheer van je MIDI-apparaten hebben</translation>
<translation id="6915804003454593391">Gebruiker:</translation>
<translation id="6934672428414710184">Dit is de naam die in je Google-account staat</translation>
@@ -1553,6 +1577,7 @@ Aanvullende informatie:
<translation id="7346048084945669753">Is gelieerd:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Opdrachtregel</translation>
+<translation id="7359588939039777303">Advertenties geblokkeerd.</translation>
<translation id="7372973238305370288">zoekresultaat</translation>
<translation id="7374733840632556089">Dit probleem doet zich voor als gevolg van een certificaat dat jij of iemand anders heeft geïnstalleerd op je apparaat. Het certificaat staat erom bekend dat het wordt gebruikt voor netwerkmonitoring en -onderschepping en wordt niet vertrouwd door Chrome. Hoewel er ook legitieme certificaten bestaan, bijvoorbeeld op een school- of zakelijk netwerk, wil Chrome zeker weten dat je begrijpt wat er gebeurt, ook als je het niet kunt tegenhouden. Monitoring kan plaatsvinden in elke browser of app met toegang tot internet.</translation>
<translation id="7375818412732305729">Bestand wordt bijgevoegd</translation>
@@ -1727,6 +1752,7 @@ Aanvullende informatie:
<translation id="7976214039405368314">Te veel verzoeken</translation>
<translation id="7977538094055660992">Uitvoerapparaat</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Installeer ARCore om augmented reality-content te bekijken</translation>
<translation id="799149739215780103">Inbinden</translation>
<translation id="7995512525968007366">Niet opgegeven</translation>
<translation id="800218591365569300">Probeer andere tabbladen en programma's te sluiten om geheugen vrij te maken.</translation>
@@ -1854,24 +1880,36 @@ Aanvullende informatie:
<translation id="8507227106804027148">Opdrachtregel</translation>
<translation id="8508648098325802031">Zoekpictogram</translation>
<translation id="8522552481199248698">Chrome kan je helpen je Google-account te beschermen en je wachtwoord te wijzigen.</translation>
+<translation id="8525306231823319788">Volledig scherm</translation>
<translation id="8530813470445476232">Je browsegeschiedenis, cookies, cache en meer wissen in de Chrome-instellingen</translation>
<translation id="8533619373899488139">Ga naar &lt;strong&gt;chrome://policy&lt;/strong&gt; om de lijst met geblokkeerde URL's en andere beleidsregels te bekijken die worden afgedwongen door je systeembeheerder.</translation>
<translation id="8541158209346794904">Bluetooth-apparaat</translation>
<translation id="8542014550340843547">Drie nietjes onder</translation>
<translation id="8543181531796978784">Je kunt <ph name="BEGIN_ERROR_LINK" />een detectieprobleem melden<ph name="END_ERROR_LINK" />. Als je de veiligheidsrisico's begrijpt, kun je ook <ph name="BEGIN_LINK" />deze onveilige site bezoeken<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">De CVC-code staat op de achterkant van je pas.</translation>
+<translation id="8558485628462305855">Update ARCore om augmented reality-content te bekijken</translation>
<translation id="8559762987265718583">Er kan geen privéverbinding met <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tot stand worden gebracht, omdat de datum en tijd van je apparaat (<ph name="DATE_AND_TIME" />) onjuist zijn.</translation>
<translation id="8564182942834072828">Afzonderlijke documenten/ongesorteerde exemplaren</translation>
<translation id="8564985650692024650">Chromium raadt je aan het wachtwoord voor <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> opnieuw in te stellen als je het voor andere sites hebt hergebruikt.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />Activiteit die niet op dit apparaat blijft staan:<ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Pagina's die je bekijkt in dit venster
+ <ph name="LIST_ITEM" />Cookies en sitegegevens
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Gebruik Touch ID om kaarten sneller te bevestigen</translation>
<translation id="858637041960032120">Telnr. toevoegen</translation>
<translation id="8589998999637048520">Beste kwaliteit</translation>
+<translation id="8600271352425265729">Alleen deze keer</translation>
<translation id="860043288473659153">Naam kaarthouder</translation>
<translation id="8606726445206553943">Je MIDI-apparaten gebruiken</translation>
+<translation id="8612761427948161954">Hallo <ph name="USERNAME" />,
+ <ph name="BR" />
+ Je browst momenteel als gast</translation>
<translation id="861775596732816396">Grootte 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Geen overeenkomende wachtwoorden. Alle opgeslagen wachtwoorden weergeven.</translation>
<translation id="8625384913736129811">Deze pas opslaan op dit apparaat</translation>
+<translation id="8627040765059109009">Schermopname hervat</translation>
<translation id="8657078576661269990">Je beheerder heeft delen door <ph name="ORIGIN_NAME" /> met <ph name="VM_NAME_1" /> en <ph name="VM_NAME_2" /> geblokkeerd</translation>
<translation id="8663226718884576429">Besteloverzicht, <ph name="TOTAL_LABEL" />, meer informatie</translation>
<translation id="867224526087042813">Handtekening</translation>
@@ -1934,6 +1972,7 @@ Aanvullende informatie:
<translation id="8912362522468806198">Google-account</translation>
<translation id="8913778647360618320">Knop 'Betaalmethoden beheren'. Druk op Enter om je betalingen en creditcardgegevens te beheren in de Chrome-instellingen.</translation>
<translation id="8918231688545606538">Deze pagina is verdacht</translation>
+<translation id="8922013791253848639">Altijd advertenties op deze site toestaan</translation>
<translation id="892588693504540538">Perforatie rechtsboven</translation>
<translation id="8931333241327730545">Wil je deze pas opslaan in je Google-account?</translation>
<translation id="8932102934695377596">Je klok loopt achter</translation>
@@ -2005,6 +2044,7 @@ Aanvullende informatie:
<translation id="9183302530794969518">Google Documenten</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> gebruikt een niet-ondersteund protocol.</translation>
<translation id="9191834167571392248">Perforatie linksonder</translation>
+<translation id="9199905725844810519">Afdrukken is geblokkeerd</translation>
<translation id="9205078245616868884">Je gegevens zijn versleuteld met je wachtwoordzin voor synchronisatie. Geef deze op om de synchronisatie te starten.</translation>
<translation id="9207861905230894330">Kan artikel niet toevoegen.</translation>
<translation id="9213433120051936369">Weergave aanpassen</translation>
@@ -2015,8 +2055,10 @@ Aanvullende informatie:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Je kunt de toegang tot je Google-account kwijtraken. Chromium raadt je aan je wachtwoord nu te wijzigen. Je wordt gevraagd in te loggen op je account.</translation>
<translation id="939736085109172342">Nieuwe map</translation>
+<translation id="945522503751344254">Feedback sturen</translation>
<translation id="945855313015696284">Controleer de informatie hieronder en verwijder alle ongeldige passen</translation>
<translation id="950736567201356821">Drie perforaties boven</translation>
+<translation id="951941430552851965">Je beheerder heeft de schermopname onderbroken vanwege de content op je scherm.</translation>
<translation id="961663415146723894">Onder inbinden</translation>
<translation id="962484866189421427">Deze content kan mogelijk proberen misleidende apps te installeren die zich voordoen als iets anders of gegevens verzamelen die kunnen worden gebruikt om je te volgen. <ph name="BEGIN_LINK" />Toch weergeven<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Officiële build</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index ee2ad590fba..afa57f70a86 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -80,6 +80,14 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Du har skrevet inn passordet ditt på et nettsted som ikke administreres av organisasjonen din. For å beskytte kontoen din må du ikke bruke det samme passordet i andre apper eller på andre nettsteder.</translation>
<translation id="1263231323834454256">Leseliste</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivitet som ikke blir værende på denne enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />sider du åpner i dette vinduet
+ <ph name="LIST_ITEM" />informasjonskapsler og nettstedsdata
+ <ph name="LIST_ITEM" />kontoinformasjon (<ph name="LINK_BEGIN" />logg av<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Hentemåte</translation>
<translation id="1281476433249504884">Hylle 1</translation>
<translation id="1285320974508926690">Oversett aldri dette nettstedet</translation>
@@ -283,6 +291,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="204357726431741734">Logg på for å bruke passord som er lagret i Google-kontoen din</translation>
<translation id="2053111141626950936">Sider på <ph name="LANGUAGE" /> oversettes ikke.</translation>
<translation id="2053553514270667976">Postnummer</translation>
+<translation id="2054665754582400095">Tilstedeværelsen din</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 forslag}other{# forslag}}</translation>
<translation id="2079545284768500474">Angre</translation>
<translation id="20817612488360358">Innstillinger for systemmellomtjener er stilt inn på å brukes, men en uttrykkelig mellomtjenerkonfigurasjon er også angitt.</translation>
@@ -296,6 +305,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2102495993840063010">Android-apper</translation>
<translation id="2107021941795971877">Utskriftsstøtter</translation>
<translation id="2108755909498034140">Start datamaskinen på nytt.</translation>
+<translation id="2111166930115883695">Trykk på mellomrom for å spille</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignorert fordi det ble overstyrt av <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="214556005048008348">Avbryt betalingen</translation>
<translation id="2147827593068025794">Bakgrunnssynkronisering</translation>
<translation id="2148613324460538318">Legg til et kort</translation>
+<translation id="2149968176347646218">Tilkoblingen er ikke sikker</translation>
<translation id="2154054054215849342">Synkronisering er ikke tilgjengelig for domenet ditt</translation>
<translation id="2154484045852737596">Endre kortet</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -317,7 +328,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2181821976797666341">Retningslinjer</translation>
<translation id="2183608646556468874">Telefonnummer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresse}other{# adresser}}</translation>
-<translation id="2187243482123994665">Brukertilstedeværelse</translation>
<translation id="2187317261103489799">Oppdag (standard)</translation>
<translation id="2188375229972301266">Flere hull bunn</translation>
<translation id="2202020181578195191">Angi et gyldig utløpsår</translation>
@@ -470,6 +480,7 @@ brukere av denne nettleseren.</translation>
<translation id="2839501879576190149">Falskt nettsted i sikte</translation>
<translation id="2850739647070081192">Invite (konvolutt)</translation>
<translation id="2856444702002559011">Det kan hende at angripere prøver å stjele informasjonen din fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (for eksempel passord, meldinger og kredittkortinformasjon). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Dette nettstedet viser forstyrrende eller villedende annonser.</translation>
<translation id="2878197950673342043">Kryssfals</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Vindusplassering</translation>
@@ -508,11 +519,11 @@ brukere av denne nettleseren.</translation>
<translation id="2996674880327704673">Forslag fra Google</translation>
<translation id="3002501248619246229">Sjekk inndataskuffmedier</translation>
<translation id="3005723025932146533">Vis lagret kopi</translation>
-<translation id="3007719053326478567">Administratoren din har blokkert utskrift av dette innholdet</translation>
<translation id="3008447029300691911">Skriv inn verifiseringskoden for <ph name="CREDIT_CARD" />. NÃ¥r du bekrefter, deles kortinformasjonen din med dette nettstedet.</translation>
<translation id="3010559122411665027">Listeoppføring «<ph name="ENTRY_INDEX" />»: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatisk blokkert</translation>
<translation id="3016780570757425217">vite hvor du er</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> – trykk på Tab og deretter på Enter for å fjerne forslaget.</translation>
<translation id="3023071826883856138">You4 (konvolutt)</translation>
<translation id="3024663005179499861">Feil type enhetsinnstillinger</translation>
<translation id="3037605927509011580">Æsj!</translation>
@@ -555,6 +566,7 @@ brukere av denne nettleseren.</translation>
<translation id="3207960819495026254">Bokmerket</translation>
<translation id="3209034400446768650">Siden kan belaste deg for penger</translation>
<translation id="3212581601480735796">Aktiviteten din på <ph name="HOSTNAME" /> overvåkes</translation>
+<translation id="3212623355668894776">Lukk alle gjestevinduer, slik at nettleseraktiviteten din slettes fra denne enheten.</translation>
<translation id="3215092763954878852">Kunne ikke bruke WebAuthn</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3225919329040284222">Tjeneren oppga et sertifikat som ikke samsvarte med innebygde forventninger. Disse forventningene benyttes for visse nettsteder med høy sikkerhet, og brukes for å beskytte deg.</translation>
@@ -702,6 +714,7 @@ brukere av denne nettleseren.</translation>
<translation id="3784372983762739446">Bluetooth-enheter</translation>
<translation id="3787705759683870569">Utløper <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Størrelse 16</translation>
+<translation id="3789841737615482174">Installer</translation>
<translation id="3793574014653384240">Tall for og årsaker til krasjene som har forekommet nylig</translation>
<translation id="3797522431967816232">Prc3 (konvolutt)</translation>
<translation id="3799805948399000906">Forespurt skrifttype</translation>
@@ -753,6 +766,7 @@ brukere av denne nettleseren.</translation>
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Nøkkel – «<ph name="SUBKEY" />»: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (konvolutt)</translation>
+<translation id="4067669230157909013">Skjermopptaket er gjenopptatt.</translation>
<translation id="4067947977115446013">Du må angi en gyldig adresse</translation>
<translation id="4072486802667267160">Det oppsto en feil under behandlingen av bestillingen din. Prøv på nytt.</translation>
<translation id="4075732493274867456">Klienten og tjeneren støtter ingen felles SSL-protokollversjon eller -chifferserie.</translation>
@@ -837,6 +851,7 @@ brukere av denne nettleseren.</translation>
<translation id="4297502707443874121">Miniatyrbilde for side <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Vis</translation>
<translation id="4300675098767811073">Flere hull høyre</translation>
+<translation id="4302514097724775343">Trykk på dinosauren for å spille</translation>
<translation id="4302965934281694568">Chou3 (konvolutt)</translation>
<translation id="4305666528087210886">Kunne ikke åpne filen</translation>
<translation id="4305817255990598646">Bytt</translation>
@@ -915,6 +930,7 @@ brukere av denne nettleseren.</translation>
<translation id="4658638640878098064">Stift oppe til venstre</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuell virkelighet</translation>
+<translation id="4675657451653251260">Du ser ikke informasjon om andre Chrome-profiler i gjestemodus. Du kan <ph name="LINK_BEGIN" />logge på<ph name="LINK_END" /> for å få tilgang til informasjon i Google-kontoen din, som passord og betalingsmåter.</translation>
<translation id="467662567472608290">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren inneholder feil. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="4677585247300749148"><ph name="URL" /> ber om å svare på tilgjengelighetshendelser</translation>
<translation id="467809019005607715">Google Presentasjoner</translation>
@@ -942,6 +958,12 @@ brukere av denne nettleseren.</translation>
<translation id="4761104368405085019">bruke mikrofonen din</translation>
<translation id="4764776831041365478">Det kan hende at nettsiden på <ph name="URL" /> er midlertidig nede eller flyttet permanent til en ny nettadresse.</translation>
<translation id="4766713847338118463">To stifter bunn</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivitet som blir værende på denne enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />eventuelle filer du laster ned i dette vinduet
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Det har oppstått en ukjent feil.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Et forgrunnsvindu er blokkert}other{# forgrunnsvinduer er blokkert}}</translation>
<translation id="4780366598804516005">Postkasse 1</translation>
@@ -1104,11 +1126,13 @@ brukere av denne nettleseren.</translation>
<translation id="5386426401304769735">Sertifikatkjeden for dette nettstedet inneholder et sertifikat som er signert med SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Kantstifting høyre</translation>
+<translation id="5398772614898833570">Annonser er blokkert</translation>
<translation id="5400836586163650660">Grå</translation>
<translation id="540969355065856584">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke gyldig for øyeblikket. Dette kan være forårsaket av en feilkonfigurasjon eller en angriper som lytter på tilkoblingen din.</translation>
<translation id="541416427766103491">Hylle 4</translation>
<translation id="5421136146218899937">Slett nettleserdata</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vil sende deg varsler</translation>
+<translation id="542872847390508405">Du surfer som gjest</translation>
<translation id="5430298929874300616">Fjern bokmerke</translation>
<translation id="5439770059721715174">Skjemavalideringsfeil i «<ph name="ERROR_PATH" />»: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Motsatt rekkefølge – forsiden opp</translation>
@@ -1150,12 +1174,12 @@ brukere av denne nettleseren.</translation>
<translation id="5571083550517324815">Kan ikke hente på denne adressen. Velg en annen adresse.</translation>
<translation id="5580958916614886209">Kontrollér utløpsmåneden, og prøv igjen</translation>
<translation id="5586446728396275693">Ingen adresser er lagret</translation>
+<translation id="5593349413089863479">Tilkoblingen er ikke helt sikker</translation>
<translation id="5595485650161345191">Rediger adresse</translation>
<translation id="5598944008576757369">Velg betalingsmåte</translation>
<translation id="560412284261940334">Administrering støttes ikke</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Dette nettstedet kan være falskt eller prøve å svindle deg. Chrome anbefaler at du forlater det nå.</translation>
<translation id="5610142619324316209">Sjekk tilkoblingen</translation>
<translation id="5610807607761827392">Du kan administrere kort og adresser i <ph name="BEGIN_LINK" />Innstillinger<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Oversett denne siden med Google Oversetter</translation>
@@ -1227,6 +1251,7 @@ brukere av denne nettleseren.</translation>
<translation id="5901630391730855834">Gul</translation>
<translation id="5905445707201418379">Blokkert i samsvar med opphavsregelen for <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkronisert)</translation>
+<translation id="5913377024445952699">Skjermopptaket er satt på pause</translation>
<translation id="59174027418879706">Aktivert</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">PÃ¥</translation>
@@ -1239,6 +1264,7 @@ brukere av denne nettleseren.</translation>
<translation id="5963413905009737549">Del</translation>
<translation id="5967592137238574583">Endre kontaktinformasjonen</translation>
<translation id="5967867314010545767">Fjern fra loggen</translation>
+<translation id="5968793460449681917">Hver gang jeg besøker nettstedet</translation>
<translation id="5975083100439434680">Zoom ut</translation>
<translation id="5979084224081478209">Kontrollér passordene</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ brukere av denne nettleseren.</translation>
<translation id="6587923378399804057">Linken du kopierte</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> administreres ikke</translation>
<translation id="6596325263575161958">Krypteringsalternativer</translation>
+<translation id="6596892391065203054">Administratoren din har blokkert utskrift av dette innholdet.</translation>
<translation id="6604181099783169992">Bevegelses- eller lyssensorer</translation>
<translation id="6609880536175561541">Prc7 (konvolutt)</translation>
<translation id="6612358246767739896">Beskyttet innhold</translation>
@@ -1453,6 +1480,7 @@ brukere av denne nettleseren.</translation>
<translation id="6895330447102777224">Kortet ditt er bekreftet</translation>
<translation id="6897140037006041989">Brukeragent</translation>
<translation id="6898699227549475383">Organisasjon (O)</translation>
+<translation id="6907293445143367439">La <ph name="SITE_NAME" /></translation>
<translation id="6910240653697687763"><ph name="URL" /> ber om full kontroll over MIDI-enhetene dine</translation>
<translation id="6915804003454593391">Bruker:</translation>
<translation id="6934672428414710184">Dette navnet er fra Google-kontoen din</translation>
@@ -1563,6 +1591,7 @@ brukere av denne nettleseren.</translation>
<translation id="7346048084945669753">Er tilknyttet:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Kommandolinje </translation>
+<translation id="7359588939039777303">Annonser er blokkert.</translation>
<translation id="7372973238305370288">søkeresultat</translation>
<translation id="7374733840632556089">Dette problemet oppstår på grunn av et sertifikat du eller noen andre har installert på enheten. Det er kjent at sertifikatet brukes til nettverksavlytting og -overvåking, og Chrome stoler ikke på det. Selv om det finnes legitime bruksområder for overvåking, f.eks. på skole- eller bedriftsnettverk, vil Chrome sørge for at du er klar over at det foregår, selv om du ikke kan stoppe det. Overvåking kan skje i alle nettlesere og applikasjoner som bruker nettet.</translation>
<translation id="7375818412732305729">Filer legges ved</translation>
@@ -1737,6 +1766,7 @@ brukere av denne nettleseren.</translation>
<translation id="7976214039405368314">For mange forespørsler</translation>
<translation id="7977538094055660992">Utskriftsenhet</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Du må installere ARCore for å se innhold med utvidet virkelighet</translation>
<translation id="799149739215780103">Innbinding</translation>
<translation id="7995512525968007366">Ikke spesifisert</translation>
<translation id="800218591365569300">Prøv å lukke andre faner eller programmer for å frigjøre minne.</translation>
@@ -1864,24 +1894,38 @@ Mer informasjon:
<translation id="8507227106804027148">Kommandolinje</translation>
<translation id="8508648098325802031">Søkeikon</translation>
<translation id="8522552481199248698">Chrome kan hjelpe deg med å beskytte Google-kontoen din og endre passordet ditt.</translation>
+<translation id="8525306231823319788">Full skjerm</translation>
<translation id="8530813470445476232">Tøm nettleserloggen, slett informasjonskapsler, tøm bufferen med mer i Chrome-innstillingene</translation>
<translation id="8533619373899488139">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for å se listen over blokkerte nettadresser og andre regler systemadministratoren din har fastsatt.</translation>
<translation id="8541158209346794904">Bluetooth-enhet</translation>
<translation id="8542014550340843547">Tre stifter bunn</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportere et påvisningsproblem<ph name="END_ERROR_LINK" /> eller, hvis du forstår sikkerhetsrisikoen, <ph name="BEGIN_LINK" />gå til dette usikre nettstedet<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC-koden finner du på baksiden av kortet.</translation>
+<translation id="8558485628462305855">Du må oppdatere ARCore for å se innhold med utvidet virkelighet</translation>
<translation id="8559762987265718583">En privat tilkobling til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kunne ikke etableres fordi datoen og klokkeslettet (<ph name="DATE_AND_TIME" />) er feil på enheten.</translation>
<translation id="8564182942834072828">Separate dokumenter / ukollaterte eksemplarer</translation>
<translation id="8564985650692024650">Chromium anbefaler at du tilbakestiller passordet ditt for <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> hvis du også har brukt det på andre nettsteder.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivitet som ikke blir værende på denne enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />sider du åpner i dette vinduet
+ <ph name="LIST_ITEM" />informasjonskapsler og nettstedsdata
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Bruk Touch ID til å bekrefte kort raskere</translation>
<translation id="858637041960032120">Legg til telefonnummer</translation>
<translation id="8589998999637048520">Beste kvalitet</translation>
+<translation id="8600271352425265729">Bare denne gangen</translation>
<translation id="860043288473659153">Kortinnehavers navn</translation>
<translation id="8606726445206553943">bruke MIDI-enhetene dine</translation>
+<translation id="8612761427948161954">Hei, <ph name="USERNAME" />
+ <ph name="BR" />
+ Du surfer som gjest</translation>
<translation id="861775596732816396">Størrelse 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ingen samsvarende passord. Vis alle lagrede passord.</translation>
<translation id="8625384913736129811">Lagre dette kortet på denne enheten</translation>
+<translation id="8627040765059109009">Skjermopptaket er gjenopptatt</translation>
<translation id="8657078576661269990">Administratoren din har blokkert deling fra <ph name="ORIGIN_NAME" /> til <ph name="VM_NAME_1" /> og <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Bestillingssammendrag, <ph name="TOTAL_LABEL" />, mer informasjon</translation>
<translation id="867224526087042813">Signatur</translation>
@@ -1944,6 +1988,7 @@ Mer informasjon:
<translation id="8912362522468806198">Google-konto</translation>
<translation id="8913778647360618320">Knappen «Administrer betalingsmåter» – trykk på Enter for å administrere betalingene og kredittkortopplysningene dine i Chrome-innstillingene</translation>
<translation id="8918231688545606538">Denne siden er mistenkelig</translation>
+<translation id="8922013791253848639">Tillat alltid annonser på dette nettstedet</translation>
<translation id="892588693504540538">Hull oppe til høyre</translation>
<translation id="8931333241327730545">Vil du lagre dette kortet i Google-kontoen din?</translation>
<translation id="8932102934695377596">Klokken går for sent</translation>
@@ -2015,6 +2060,7 @@ Mer informasjon:
<translation id="9183302530794969518">Google Dokumenter</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> bruker en protokoll som ikke støttes.</translation>
<translation id="9191834167571392248">Hull nede til venstre</translation>
+<translation id="9199905725844810519">Utskrift er blokkert</translation>
<translation id="9205078245616868884">Dataene dine er kryptert med passordfrasen din for synkronisering. Skriv den inn for å starte synkroniseringen.</translation>
<translation id="9207861905230894330">Kunne ikke legge til artikkelen.</translation>
<translation id="9213433120051936369">Tilpass utseendet</translation>
@@ -2025,8 +2071,10 @@ Mer informasjon:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Du kan miste tilgangen til Google-kontoen din. Chromium anbefaler at du endrer passordet ditt nå. Du blir bedt om å logge på.</translation>
<translation id="939736085109172342">Ny mappe</translation>
+<translation id="945522503751344254">Send tilbakemelding</translation>
<translation id="945855313015696284">GÃ¥ gjennom informasjonen nedenfor, og slett eventuelle ugyldige kort</translation>
<translation id="950736567201356821">Tre hull topp</translation>
+<translation id="951941430552851965">Administratoren din har satt skjermopptaket på pause på grunn av innholdet på skjermen.</translation>
<translation id="961663415146723894">Innbinding bunn</translation>
<translation id="962484866189421427">Dette innholdet kan prøve å installere villedende apper som gir seg ut for å være noe annet, eller samle inn data som kan brukes til å spore deg. <ph name="BEGIN_LINK" />Vis det likevel<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Offisiell delversjon</translation>
diff --git a/chromium/components/strings/components_strings_or.xtb b/chromium/components/strings/components_strings_or.xtb
index 9f53a483f26..dd371deda38 100644
--- a/chromium/components/strings/components_strings_or.xtb
+++ b/chromium/components/strings/components_strings_or.xtb
@@ -54,7 +54,7 @@
<translation id="1175364870820465910">&amp;ମà­à¬¦à­à¬°à¬£...</translation>
<translation id="1175875016430184367">ଡାହାଣ ପଟରେ ତିନୋଟି ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
<translation id="1178581264944972037">ବିରତି</translation>
-<translation id="1181037720776840403">ଅପସାରଣ</translation>
+<translation id="1181037720776840403">କାଢ଼ି ଦିଅନà­à¬¤à­</translation>
<translation id="1186201132766001848">ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଯାଞà­à¬š କରନà­à¬¤à­</translation>
<translation id="1195558154361252544">ଆପଣ ଅନà­à¬®à¬¤à¬¿ ଦେଇଥିବା ସାଇଟà­â€à¬—à­à­œà¬¿à¬• ବà­à­Ÿà¬¤à­€à¬¤ ସମସà­à¬¤ ସାଇଟà­â€Œà¬°à­‡ ବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à­œà¬¿à¬•à­ ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="1197088940767939838">କମଳା</translation>
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ଆପଣ ଆପଣଙà­à¬•à¬° ପାସà­â€à­±à¬°à­à¬¡ à¬à¬ªà¬°à¬¿ à¬à¬• ସାଇଟà­â€Œà¬°à­‡ ଲେଖିଛନà­à¬¤à¬¿ ଯାହା ଆପଣଙà­à¬• ସଂସà­à¬¥à¬¾ ଦà­à¬µà¬¾à¬°à¬¾ ପରିଚାଳିତ ନà­à¬¹à­‡à¬à¥¤ ଆପଣଙà­à¬• ଆକାଉଣà­à¬Ÿà¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରଖିବା ପାଇà¬, ଅନà­à­Ÿ ଆପୠଓ ସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à¬°à­‡ ଆପଣଙà­à¬•à¬° ପାସà­â€à­±à¬°à­à¬¡ ପà­à¬¨à¬ƒà¬¬à­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­ ନାହିà¬à¥¤</translation>
<translation id="1263231323834454256">ପà­à¬¿à¬¬à¬¾ ତାଲିକା</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª ଯାହା à¬à¬¹à¬¿ ଡିଭାଇସରେ ରହିବ ନାହିà¬:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ଆପଣ à¬à¬¹à¬¿ ୱିଣà­à¬¡à­‹à¬°à­‡ ଦେଖିଥିବା ପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬•
+ <ph name="LIST_ITEM" />କà­à¬•à­€ ଓ ସାଇଟୠଡାଟା
+ <ph name="LIST_ITEM" />ଆକାଉଣà­à¬Ÿ ସୂଚନା (<ph name="LINK_BEGIN" />ସାଇନୠଆଉଟୠକରନà­à¬¤à­<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ଉଠାଇବା ପଦà­à¬§à¬¤à¬¿</translation>
<translation id="1281476433249504884">ଷà­à¬Ÿà¬¾à¬•à¬°à­ 1</translation>
<translation id="1285320974508926690">à¬à¬¹à¬¿ ସାଇଟà­â€à¬•à­ କଦାପି ଅନà­à¬¬à¬¾à¬¦ କରନà­à¬¤à­ ନାହିà¬</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">à¬à¬£à­à¬Ÿà­à¬°à¬¿ କରାଯାଉଥିବା ଇତିହାସର ତାଲିକା</translation>
<translation id="1517433312004943670">ଫୋନୠନମà­à¬¬à¬° ଆବଶà­à­Ÿà¬• ଅଟେ</translation>
<translation id="1519264250979466059">ବିଲà­à¬¡ ତାରିଖ</translation>
-<translation id="1521655867290435174">Google ସିଟà­â€Œà¬¸</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">ସଂଯୋଗ ପାଇଠଅପେକà­à¬·à¬¾à¬°à¬¤â€¦</translation>
<translation id="1529521330346880926">10x15 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="1529789484829130889">ଟà­à¬°à­‡ 8</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">ଆପଣଙà­à¬• Google ଆକାଉଣà­à¬Ÿà¬°à­‡ ସେଭୠକରାଯାଇଥିବା ପାସୱାରà­à¬¡à¬—à­à­œà¬¿à¬• ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସାଇନୠଇନୠକରନà­à¬¤à­</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />ରେ ଥିବା ପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬• ଅନà­à¬¬à¬¾à¬¦ କରାଯିବ ନାହିà¬à¥¤</translation>
<translation id="2053553514270667976">ZIP କୋଡà­</translation>
+<translation id="2054665754582400095">ଆପଣଙà­à¬• ଉପସà­à¬¥à¬¿à¬¤à¬¿</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1ଟି ପରାମରà­à¬¶}other{#ଟି ପରାମରà­à¬¶}}</translation>
<translation id="2079545284768500474">ପୂରà­à¬¬à¬¬à¬¤à­</translation>
<translation id="20817612488360358">ସିଷà­à¬Ÿà¬®à­ ପà­à¬°à¬•à­à¬¸à¬¿ ସେଟିଂସୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ପାଇଠପà­à¬°à¬¸à­à¬¤à­à¬¤ ଅଛି କିନà­à¬¤à­ à¬à¬• ସà­à¬¨à¬¿à¬°à­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ପà­à¬°à¬•à­à¬¸à¬¿ କନà­â€Œà¬«à¬¿à¬—à­â€Œà¬°à­‡à¬¸à¬¨à­ ମଧà­à­Ÿ ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ କରାଯାଇଛି।</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android ଆପଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="2107021941795971877">ପà­à¬°à¬¿à¬£à­à¬Ÿ ସପୋରà­à¬Ÿ</translation>
<translation id="2108755909498034140">ଆପଣଙà­à¬•à¬° କମà­à¬ªà­à­Ÿà­à¬Ÿà¬°à­ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ କରନà­à¬¤à­</translation>
+<translation id="2111166930115883695">ଗେମୠଖେଳିବା ପାଇଠSpace ଦବାନà­à¬¤à­</translation>
<translation id="2111256659903765347">ସà­à¬ªà¬°à­-A</translation>
<translation id="2113977810652731515">କାରà­à¬¡</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ଦà­à­±à¬¾à¬°à¬¾ ଓଭରà­â€à¬°à¬¾à¬‡à¬¡à­ ହୋଇଥିବାରୠà¬à¬¹à¬¾à¬•à­ ଅଣଦେଖା କରାଯାଇଛି।</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">ପେମେଣà­à¬Ÿ ବାତିଲୠକରନà­à¬¤à­</translation>
<translation id="2147827593068025794">ପୃଷà­à¬ à¬­à­‚ମି ସିଙà­à¬•à­</translation>
<translation id="2148613324460538318">କାରà­à¬¡ ଯୋଗ କରନà­à¬¤à­</translation>
+<translation id="2149968176347646218">ସଂଯୋଗଟି ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ନà­à¬¹à­‡à¬</translation>
<translation id="2154054054215849342">ଆପଣଙà­à¬• ଡୋମେନୠପାଇଠସିଙà­à¬•à­ ଉପଲବà­à¬§ ନାହିà¬</translation>
<translation id="2154484045852737596">କାରà­à¬¡à¬•à­ à¬à¬¡à¬¿à¬Ÿà­ କରନà­à¬¤à­</translation>
<translation id="2161656808144014275">ଟେକà­à¬¸à¬Ÿà­</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">ନୀତି</translation>
<translation id="2183608646556468874">ଫୋନୠନମà­à¬¬à¬°</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1ଟି ଠିକଣା}other{#ଟି ଠିକଣା}}</translation>
-<translation id="2187243482123994665">ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾à¬™à­à¬• ସକà­à¬°à¬¿à­Ÿà¬¤à¬¾</translation>
<translation id="2187317261103489799">ଚିହà­à¬¨à¬Ÿ କରନà­à¬¤à­ (ଡିଫଲà­à¬Ÿ)</translation>
<translation id="2188375229972301266">ତଳ ପଟରେ à¬à¬•à¬¾à¬§à¬¿à¬• ପଞà­à¬šà­</translation>
<translation id="2202020181578195191">ସମୟସୀମା ଶେଷ ହେଉଥିବା à¬à¬• ବୈଧ ବରà­à¬· ଲେଖନà­à¬¤à­</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">ନକଲି ସାଇଟୠଆଗରେ ଅଛି</translation>
<translation id="2850739647070081192">ନିମନà­à¬¤à­à¬°à¬£ କରନà­à¬¤à­ (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="2856444702002559011">ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ହà­à¬à¬¤ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ରୠଆପଣଙà­à¬•à¬° ସୂଚନା ଚୋରାଇବାକୠଚେଷà­à¬Ÿà¬¾ କରିପାରନà­à¬¤à¬¿ (ଉଦାହରଣ ସà­à­±à¬°à­‚ପ, ପାସà­â€à­±à¬°à­à¬¡, ମେସେଜୠକିମà­à¬¬à¬¾ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­â€ କାରà­à¬¡)। <ph name="BEGIN_LEARN_MORE_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">à¬à¬¹à¬¿ ସାଇଟୠଅନଧିକାର ପà­à¬°à¬¬à­‡à¬¶ କରିଥିବା କିମà­à¬¬à¬¾ ବିଭà­à¬°à¬¾à¬¨à­à¬¤à¬¿à¬•à¬° ବିଜà­à¬žà¬¾à¬ªà¬¨ ପà­à¬°à¬¦à¬°à­à¬¶à¬¨ କରà­à¬›à¬¿à¥¤</translation>
<translation id="2878197950673342043">ପୋଷà­à¬Ÿà¬°à­ ଫୋଲà­à¬¡</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ୱିଣà­à¬¡à­‹ ପà­à¬²à­‡à¬¸à¬®à­‡à¬£à­à¬Ÿ</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google ଠାରୠପà­à¬°à¬¾à¬ªà­à¬¤ ପà­à¬°à¬¸à­à¬¤à¬¾à¬¬à¬—à­à­œà¬¿à¬•</translation>
<translation id="3002501248619246229">ଇନପà­à¬Ÿà­ ଟà­à¬°à­‡ ମିଡିଆ ଯାଞà­à¬š କରନà­à¬¤à­</translation>
<translation id="3005723025932146533">ସେଭୠହୋଇଥିବା କପି ଦେଖାନà­à¬¤à­</translation>
-<translation id="3007719053326478567">à¬à¬¹à¬¿ ବିଷୟବସà­à¬¤à­à¬•à­ ପà­à¬°à¬¿à¬£à­à¬Ÿ କରିବା ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" />ର CVC ଲେଖନà­à¬¤à­à¥¤ ଆପଣ ଥରେ ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରିବା ପରେ, ଆପଣଙà­à¬•à¬° କାରà­à¬¡à¬° ବିବରଣୀ à¬à¬¹à¬¿ ସାଇଟà­â€Œ ସହିତ ସେୟାରà­â€Œ କରାଯିବ।</translation>
<translation id="3010559122411665027">ତାଲିକା à¬à¬£à­à¬Ÿà­à¬°à¬¿ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ସà­à­±à¬šà¬¾à¬³à¬¿à¬¤ ଭାବେ ବà­à¬²à¬•à­ କରାଗଲା</translation>
<translation id="3016780570757425217">ଆପଣଙà­à¬•à¬° ଲୋକେସନà­â€Œ ଜାଣନà­à¬¤à­</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, ପରାମରà­à¬¶à¬•à­ କାà­à¬¿à¬¬à¬¾ ପାଇଠTab କରି Enter ଦବାନà­à¬¤à­à¥¤</translation>
<translation id="3023071826883856138">You4 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="3024663005179499861">ଭà­à¬² ନୀତି ପà­à¬°à¬•à¬¾à¬°</translation>
<translation id="3037605927509011580">ଇସ!</translation>
@@ -547,6 +558,7 @@
<translation id="3207960819495026254">ବà­à¬•à­â€à¬®à¬¾à¬°à­à¬• କରାଯାଇଛି</translation>
<translation id="3209034400446768650">ପୃଷà­à¬ à¬¾ ଶà­à¬³à­à¬• ଲାଗୠହୋଇପାରେ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />ରେ ଆପଣଙà­à¬•à¬° କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ ନିରୀକà­à¬·à¬£ କରାଯାଉଛି</translation>
+<translation id="3212623355668894776">à¬à¬¹à¬¿ ଡିଭାଇସରୠଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ ଡିଲିଟୠକରିବା ପାଇଠସମସà­à¬¤ ଅତିଥି ୱିଣà­à¬¡à­‹ ବନà­à¬¦ କରନà­à¬¤à­à¥¤</translation>
<translation id="3215092763954878852">WebAuthn ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇପାରିଲା ନାହିà¬</translation>
<translation id="3218181027817787318">ରିଲେଟିଭà­</translation>
<translation id="3225919329040284222">ସରà­à¬­à¬°à­ à¬à¬• ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€Œà¬•à­ ଉପସà­à¬¥à¬¾à¬ªà¬¨ କରà­à¬›à¬¿, ଯାହା ବିଲà­à¬Ÿ-ଇନୠପà­à¬°à¬¤à­à­Ÿà¬¾à¬¶à¬¾ ସହ ମେଳ ଖାଉନାହିà¬à¥¤ à¬à¬¹à¬¿ ପà­à¬°à¬¤à­à­Ÿà¬¾à¬¶à¬¾à¬—à­à­œà¬¿à¬• ଆପଣଙà­à¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରଖିବାକୠକିଛି ଉଚà­à¬š ସà­à¬°à¬•à­à¬·à¬¾ ଥିବା ୱେବà­â€à¬¸à¬¾à¬‡à¬Ÿà­â€à¬—à­à­œà¬¿à¬• ପାଇଠଅନà­à¬¤à¬°à­à¬­à­à¬•à­à¬¤ କରାଯାଇଛି।</translation>
@@ -693,6 +705,7 @@
<translation id="3784372983762739446">ବà­à¬²à­à¬Ÿà­à¬¥à­ ଡିଭାଇସଗà­à­œà¬¿à¬•</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" />ରେ ମିଆଦ ସମାପà­à¬¤ ହେବ</translation>
<translation id="3789155188480882154">ଆକାର 16</translation>
+<translation id="3789841737615482174">ସଂସà­à¬¥à¬¾à¬ªà¬¨</translation>
<translation id="3793574014653384240">ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ଘଟିଥିବା କà­à¬°à¬¾à¬¸à¬—à­à¬¡à¬¼à¬¿à¬•à¬° ସଂଖà­à­Ÿà¬¾ à¬à¬¬à¬‚ କାରଣଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="3797522431967816232">Prc3 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="3799805948399000906">ଅନà­à¬°à­‹à¬§ କରାଯାଇଥିବା ଫଣà­à¬Ÿ</translation>
@@ -743,6 +756,7 @@
<translation id="4056223980640387499">ସେପିଆ</translation>
<translation id="4058922952496707368">କୀ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
+<translation id="4067669230157909013">ସà­à¬•à­à¬°à¬¿à¬¨à­ କà­à­Ÿà¬¾à¬ªà¬šà¬°à¬•à­ ପà­à¬£à¬¿ ଆରମà­à¬­ କରାଯାଇଛି।</translation>
<translation id="4067947977115446013">ବୈଧ ଠିକଣା ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="4072486802667267160">ଆପଣଙà­à¬•à¬° ଅରà­à¬¡à¬°à­ ପà­à¬°à¬•à­à¬°à¬¿à­Ÿà¬¾à¬•à¬°à¬£ କରିବା ସମୟରେ à¬à¬• ତà­à¬°à­à¬Ÿà¬¿ ହୋଇଛି। ଦୟାକରି ପà­à¬£à¬¿à¬¥à¬°à­‡ ଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­à¥¤</translation>
<translation id="4075732493274867456">କà­à¬²à¬¾à¬à¬£à­à¬Ÿ ଓ ସରà­à¬­à¬°à­ à¬à¬• ସାଧାରଣ SSL ପà­à¬°à­‹à¬Ÿà­‹à¬•à¬²à­ ସଂସà­à¬•à¬°à¬£ କିମà­à¬¬à¬¾ ସାଇଫରୠସà­à¬Ÿà­â€à¬° ସମରà­à¬¥à¬¨ କରନà­à¬¤à¬¿ ନାହିà¬à¥¤</translation>
@@ -823,6 +837,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> ପୃଷà­à¬ à¬¾ ପାଇଠଥମà­à¬¬à¬¨à­‡à¬²à­</translation>
<translation id="42981349822642051">ପà­à¬°à¬¸à¬¾à¬°à¬£ କରନà­à¬¤à­</translation>
<translation id="4300675098767811073">ଡାହାଣ ପଟରେ à¬à¬•à¬¾à¬§à¬¿à¬• ପଞà­à¬šà­</translation>
+<translation id="4302514097724775343">ଖେଳିବା ପାଇଠଡାଇନୋସରରେ ଟାପୠକରନà­à¬¤à­</translation>
<translation id="4302965934281694568">Chou3 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="4305666528087210886">ଆପଣଙà­à¬• ଫାଇଲକୠଆକà­à¬¸à­‡à¬¸à­ କରାଯାଇପାରିଲା ନାହିà¬</translation>
<translation id="4305817255990598646">ସà­à­±à¬¿à¬šà­ କରନà­à¬¤à­</translation>
@@ -901,9 +916,10 @@
<translation id="4658638640878098064">ଉପର ବାମ ପଟରେ ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ଭରà­à¬šà­à¬†à¬²à­ ରିଆଲିଟୀ</translation>
+<translation id="4675657451653251260">ଆପଣ ଅତିଥି ମୋଡରେ କୌଣସି Chrome ପà­à¬°à­‹à¬«à¬¾à¬‡à¬²à­ ସୂଚନା ଦେଖିବେ ନାହିà¬à¥¤ ଆପଣ ପାସୱାରà­à¬¡ à¬à¬¬à¬‚ ପେମେଣà­à¬Ÿ ପଦà­à¬§à¬¤à¬¿à¬—à­à­œà¬¿à¬• ପରି ଆପଣଙà­à¬• Google ଆକାଉଣà­à¬Ÿ ସୂଚନାକୠଆକà­à¬¸à­‡à¬¸à­ କରିବା ପାଇଠ<ph name="LINK_BEGIN" />ସାଇନୠଇନà­<ph name="LINK_END" /> କରିପାରିବେ।</translation>
<translation id="467662567472608290">à¬à¬¹à¬¿ ସରà­à¬­à¬°à­ ପà­à¬°à¬®à¬¾à¬£ କରିପାରିଲା ନାହିଠଯେ, à¬à¬¹à¬¾ à¬à¬• <ph name="DOMAIN" /> ଅଟେ; à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€Œà¬°à­‡ ତà­à¬°à­à¬Ÿà¬¿ ଅଛି। à¬à¬¹à¬¾ ହà­à¬à¬¤, à¬à¬• ଭà­à¬²à­ କନଫିଗà­â€â€à¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ କାରଣରୠହୋଇପାରେ।</translation>
<translation id="4677585247300749148"><ph name="URL" /> ଆକà­à¬¸à­‡à¬¸à¬¿à¬¬à¬¿à¬²à¬¿à¬Ÿà­€ ଇଭେଣà­à¬Ÿà¬•à­ ପà­à¬°à¬¤à¬¿à¬•à­à¬°à¬¿à­Ÿà¬¾ ଦେବାକୠଚାହà­à¬à¬›à¬¿</translation>
-<translation id="467809019005607715">Google ସà­à¬²à¬¾à¬‡à¬¡à­â€</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">ଆପଣ à¬à¬¬à­‡ à¬à¬• ପà­à¬°à¬¤à¬¾à¬°à¬£à¬¾à¬®à­‚ଳକ ସାଇଟରେ ଆପଣଙà­à¬• ପାସୱାରà­à¬¡ ଲେଖିଛନà­à¬¤à¬¿à¥¤ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> <ph name="WEBSITE_3" /> à¬à¬¬à¬‚ ଆପଣ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ à¬à¬¹à¬¿ ପାସୱାରà­à¬¡ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିଥିବା ଅନà­à­Ÿ ସାଇଟଗà­à¬¡à¬¼à¬¿à¬• ପାଇଠChromium ଆପଣଙà­à¬•à¬° ସେଭୠକରାଯାଇଥିବା ପାସୱାରà­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଯାଞà­à¬š କରିବାକୠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରେ।</translation>
<translation id="4690462567478992370">à¬à¬• ଅବୈଧ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ବନà­à¬¦ କରନà­à¬¤à­</translation>
<translation id="4691835149146451662">ଆରà­à¬•à¬¿à¬Ÿà­‡à¬•à­â€Œà¬šà¬°à­-A (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
@@ -928,6 +944,12 @@
<translation id="4761104368405085019">ଆପଣଙà­à¬•à¬° ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="4764776831041365478"><ph name="URL" />ରେ ଥିବା ୱେବà­â€Œà¬ªà­ƒà¬·à­à¬ à¬¾à¬Ÿà¬¿ ଅସà­à¬¥à¬¾à­Ÿà­€à¬°à­‚ପେ ଡାଉନà­â€Œ ଥାଇପାରେ କିମà­à¬¬à¬¾ ସà­à¬¥à¬¾à­Ÿà­€à¬­à¬¾à¬¬à­‡ à¬à¬• ନୂତନ ୱେବୠଠିକଣାକୠସà­à¬¥à¬¾à¬¨à¬¾à¬¨à­à¬¤à¬° ହୋଇପାରେ।</translation>
<translation id="4766713847338118463">ତଳ ପଟରେ ଦà­à¬‡à¬Ÿà¬¿ ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ଆପଣଙà­à¬• କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª ଯାହା à¬à¬¹à¬¿ ଡିଭାଇସରେ ରହେ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¬à¬¹à¬¿ ୱିଣà­à¬¡à­‹à¬°à­‡ ଆପଣ ଡାଉନଲୋଡୠକରିଥିବା ଯେ କୌଣସି ଫାଇଲà­
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">à¬à¬• ଅଜà­à¬žà¬¾à¬¤ ତୃଟି ସଂଘଟିତ ହୋଇଅଛି ।</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ପପà­â€-ଅପୠବà­à¬²à¬•à­ କରାଯାଇଛି}other{#ଟି ପପà­â€-ଅପୠବà­à¬²à¬•à­ କରାଯାଇଛି}}</translation>
<translation id="4780366598804516005">ମେଲବକà­à¬¸ 1</translation>
@@ -1090,11 +1112,13 @@
<translation id="5386426401304769735">à¬à¬¹à¬¿ ସାଇଟà­â€Œ ପାଇଠଥିବା ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€Œ ଶୃଙà­à¬–ଳାରେ SHA-1ର ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରି ଦସà­à¬¤à¬–ତ କରାଯାଇଥିବା ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€Œ ଅଛି।</translation>
<translation id="538659543871111977">A4-ଟାବà­</translation>
<translation id="5396631636586785122">ଡାହାଣ ପଟରେ à¬à¬œà­ ଷà­à¬Ÿà¬¿à¬šà­</translation>
+<translation id="5398772614898833570">ବିଜà­à¬žà¬¾à¬ªà¬¨à¬—à­à­œà¬¿à¬• ଅବରୋଧ ହୋâ€à¬‡à¬›à¬¿</translation>
<translation id="5400836586163650660">ଧୂସର</translation>
<translation id="540969355065856584">à¬à¬¹à¬¿ ସରà­à¬­à¬°à­, à¬à¬¹à¬¾ <ph name="DOMAIN" /> ବୋଲି ପà­à¬°à¬®à¬¾à¬£à¬¿à¬¤ କରିପାରିଲା ନାହିà¬; à¬à¬¹à¬¿ ସମୟରେ à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ବୈଧ ନà­à¬¹à­‡à¬à¥¤ à¬à¬¹à¬¾ ହà­à¬à¬¤ à¬à¬• ଭà­à¬²à­ କନଫିଗà­â€â€à¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ କାରଣରୠହୋଇପାରେ।</translation>
<translation id="541416427766103491">ଷà­à¬Ÿà¬¾à¬•à¬°à­ 4</translation>
<translation id="5421136146218899937">ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଡାଟା ଖାଲି କରନà­à¬¤à­...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ଆପଣଙà­à¬•à­ ବିଜà­à¬žà¬ªà­à¬¤à¬¿ ପଠାଇବାକୠଚାହà­à¬à¬›à¬¿</translation>
+<translation id="542872847390508405">ଆପଣ à¬à¬• ଅତିଥି ଭାବରେ ବà­à¬°à¬¾à¬‰à¬œà­ କରà­à¬›à¬¨à­à¬¤à¬¿</translation>
<translation id="5430298929874300616">ବà­à¬•à¬®à¬¾à¬°à­à¬•à­ କାà­à¬¿à¬¦à¬¿à¬…ନà­à¬¤à­</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />"ରେ ସà­à¬•à¬¿à¬®à¬¾ ବୈଧିକରଣ ତà­à¬°à­à¬Ÿà¬¿: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ଓଲଟା ଅରà­à¬¡à¬°à¬°à­‡ ଫେସୠଅପà­</translation>
@@ -1136,12 +1160,12 @@
<translation id="5571083550517324815">à¬à¬¹à¬¿ ଠିକଣାରୠପିକୠଅପୠକରିହେବ ନାହିà¬à¥¤ à¬à¬• ଭିନà­à¬¨ ଠିକଣା ଚୟନ କରନà­à¬¤à­à¥¤</translation>
<translation id="5580958916614886209">ଆପଣଙà­à¬•à¬° ମିଆଦ ଶେଷ ହେଉଥିବା ମାସ ଯାଞà­à¬š କରନà­à¬¤à­ à¬à¬¬à¬‚ ପà­à¬£à¬¿ ଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­</translation>
<translation id="5586446728396275693">କୌଣସି ସେଭୠହୋଇଥିବା ଠିକଣାଗà­à­œà¬¿à¬• ନାହିà¬</translation>
+<translation id="5593349413089863479">ସଂଯୋଗଟି ସମà­à¬ªà­‚ରà­à¬£à­à¬£ ଭାବେ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ନà­à¬¹à­‡à¬</translation>
<translation id="5595485650161345191">ଠିକଣା à¬à¬¡à¬¿à¬Ÿà­ କରନà­à¬¤à­</translation>
<translation id="5598944008576757369">ପେମେଣà­à¬Ÿ ମେଥଡୠବାଛନà­à¬¤à­</translation>
<translation id="560412284261940334">ପରିଚାଳନା ସମରà­à¬¥à¬¿à¬¤ ନà­à¬¹à­‡à¬</translation>
<translation id="5605670050355397069">ଲେଜରà­</translation>
<translation id="5607240918979444548">ଆରà­à¬•à¬¿à¬Ÿà­‡à¬•à­â€Œà¬šà¬°à­-C</translation>
-<translation id="5608165884683734521">à¬à¬¹à¬¿ ସାଇଟୠନକଲ ବା ପà­à¬°à¬¤à¬¾à¬°à¬£à¬¾à¬®à­‚ଳକ ହୋଇପାରିବ ନାହିଠChrome ଅନà­à¬®à­‹à¬¦à¬¨à¬—à­à­œà¬¿à¬• ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ଛାଡ଼à­à¬›à¬¿à¥¤</translation>
<translation id="5610142619324316209">ସଂଯୋଗ ଯାଞà­à¬š ହେଉଛି</translation>
<translation id="5610807607761827392">ଆପଣ <ph name="BEGIN_LINK" />ସେଟିଂସà­â€Œ<ph name="END_LINK" />ରେ କାରà­à¬¡ ଓ ଠିକଣା ପରିଚାଳନ କରିପାରିବେ।</translation>
<translation id="561165882404867731">Google Translate ସାହାଯà­à­Ÿà¬°à­‡ à¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾à¬•à­ ଅନà­à¬¬à¬¾à¬¦ କରନà­à¬¤à­</translation>
@@ -1213,6 +1237,7 @@
<translation id="5901630391730855834">ହଳଦିଆ</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />ର ମୂଳ ନୀତି ଅନà­à¬¯à¬¾à­Ÿà­€ ବà­à¬²à¬•à­ କରାଯାଇଛି।</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> ( ସିଙà­à¬•à­â€ କରାଯାଇଛି)</translation>
+<translation id="5913377024445952699">ସà­à¬•à­à¬°à¬¿à¬¨à­ କà­à­Ÿà¬¾à¬ªà¬šà¬°à­ ବିରତ କରାଯାଇଛି</translation>
<translation id="59174027418879706">ସାମରà­à¬¥à­à­Ÿ ହୋଇଛି</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ଚାଲୠଅଛି</translation>
@@ -1225,6 +1250,7 @@
<translation id="5963413905009737549">ବିଭାଗ</translation>
<translation id="5967592137238574583">ଯୋଗାଯୋଗ ସୂଚନା à¬à¬¡à¬¿à¬Ÿà­ କରନà­à¬¤à­</translation>
<translation id="5967867314010545767">ଇତିବୃତà­à¬¤à¬¿à¬°à­ କାà­à¬¿ ଦିଅନà­à¬¤à­</translation>
+<translation id="5968793460449681917">ପà­à¬°à¬¤à­à­Ÿà­‡à¬• ଭିଜିଟୠସମୟରେ</translation>
<translation id="5975083100439434680">ଜà­à¬®à­ କମାନà­à¬¤à­</translation>
<translation id="5979084224081478209">ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଯାଞà­à¬š କରନà­à¬¤à­</translation>
<translation id="5980920751713728343">ସୂଚୀ-3x5</translation>
@@ -1379,6 +1405,7 @@
<translation id="6587923378399804057">ଆପଣ କପି କରିଥିବା ଲିଙà­à¬•à­</translation>
<translation id="6591833882275308647">ଆପଣଙà­à¬•à¬° <ph name="DEVICE_TYPE" /> ପରିଚାଳିତ ହେଉ ନାହିà¬</translation>
<translation id="6596325263575161958">à¬à¬¨à­â€Œà¬•à­à¬°à¬¿à¬ªà­à¬¸à¬¨à­ ବିକଳà­à¬ª</translation>
+<translation id="6596892391065203054">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ à¬à¬¹à¬¿ ବିଷୟବସà­à¬¤à­à¬•à­ ପà­à¬°à¬¿à¬£à­à¬Ÿ କରିବାକୠବà­à¬²à¬•à­ କରାଯାଇଛି।</translation>
<translation id="6604181099783169992">ମୋସନୠକିମà­à¬¬à¬¾ ଲାଇଟà­â€Œ ସେନà­à¬¸à¬°à­</translation>
<translation id="6609880536175561541">Prc7 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="6612358246767739896">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­</translation>
@@ -1438,6 +1465,7 @@
<translation id="6895330447102777224">ଆପଣଙà­à¬• କାରà­à¬¡ ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରାଯାଇଛି</translation>
<translation id="6897140037006041989">ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾ à¬à¬œà­‡à¬£à­à¬Ÿ</translation>
<translation id="6898699227549475383">ସଂସà­à¬¥à¬¾ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" />କୠà¬à¬¹à¬¾ କରିବାକୠଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ଆପଣଙà­à¬•à¬° MIDI ଡିଭାଇସà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬° ପୂରà­à¬£à­à¬£ ନିୟନà­à¬¤à­à¬°à¬£ ପà­à¬°à¬¾à¬ªà­à¬¤ କରିବାକୠଚାହେà¬</translation>
<translation id="6915804003454593391">ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾:</translation>
<translation id="6934672428414710184">à¬à¬¹à¬¿ ନାମ ଆପଣଙà­à¬•à¬° Google ଆକାଉଣà­à¬Ÿà¬°à­ ଅଟେ</translation>
@@ -1549,6 +1577,7 @@
<translation id="7346048084945669753">ସà­à¬¬à­€à¬•à­ƒà¬¤à¬¿ ପà­à¬°à¬¾à¬ªà­à¬¤ କି ନà­à¬¹à­‡à¬:</translation>
<translation id="7349430561505560861">A4-ଅତିରିକà­à¬¤</translation>
<translation id="7353601530677266744">କମାଣà­à¬¡ ଲାଇନà­â€Œ</translation>
+<translation id="7359588939039777303">ବିଜà­à¬žà¬¾à¬ªà¬¨à¬—à­à­œà¬¿à¬• ବà­à¬²à¬•à­ କରାଯାଇଛି।</translation>
<translation id="7372973238305370288">ସନà­à¬§à¬¾à¬¨ ଫଳାଫଳ</translation>
<translation id="7374733840632556089">ଆପଣ କିମà­à¬¬à¬¾ ଅନà­à­Ÿ କେହି ଜଣେ ଆପଣଙà­à¬• ଡିଭାଇସà­â€Œà¬°à­‡ ଇନଷà­à¬Ÿà¬²à­ କରିଥିବା à¬à¬• ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ଯୋଗà­à¬ à¬à¬¹à¬¿ ସମସà­à­Ÿà¬¾à¬Ÿà¬¿ ହୋଇଥାà¬à¥¤ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€à¬Ÿà¬¿ ନେଟà­â€à­±à¬¾à¬°à­à¬•à¬—à­à­œà¬¿à¬•à¬° ନିରୀକà­à¬·à¬£ à¬à¬¬à¬‚ ଗତିରୋଧ ନିମନà­à¬¤à­‡ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇଥାଠବୋଲି ଜଣାଯାଠà¬à¬¬à¬‚ Chrome à¬à¬¹à¬¾à¬•à­ ବିଶà­à­±à¬¾à¬¸ କରେ ନାହିà¬à¥¤ ଯଦିଓ କୌଣସି ସà­à¬•à­à¬²à­ କିମà­à¬¬à¬¾ କମà­à¬ªà¬¾à¬¨à­€ ନେଟà­â€à­±à¬¾à¬°à­à¬• ପରି ନିରୀକà­à¬·à¬£ ପାଇଠକିଛି ବୈଧ ଉଦାହରଣ ବିଦà­à­Ÿà¬®à¬¾à¬¨ ଅଛି, Chrome à¬à¬¹à¬¾ ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରିବାକୠଚାହେଠଯେ, ଆପଣ à¬à¬¹à¬¾à¬•à­ ବନà­à¬¦ ନକରିପାରିଲେ ମଧà­à­Ÿ ଆପଣ à¬à¬¹à¬¾ ହେଉଥିବା ବିଷୟରେ ଅବଗତ ରà­à¬¹à¬¨à­à¬¤à­à¥¤ ୱେବୠଆକà­à¬¸à­‡à¬¸à­ କରିପାରà­à¬¥à¬¿à¬¬à¬¾ ଯେ କୌଣସି ବà­à¬°à¬¾à¬‰à¬œà¬°à­ କିମà­à¬¬à¬¾ ଆପà­à¬²à¬¿à¬•à­‡à¬¸à¬¨à­â€â€à¬°à­‡ ନିରୀକà­à¬·à¬£ ହୋଇପାରେ।</translation>
<translation id="7375818412732305729">ଫାଇଲୠଆଟାଚୠକରାଯାଇଛି</translation>
@@ -1723,6 +1752,7 @@
<translation id="7976214039405368314">ଅନେକଗà­à­œà¬¿à¬ ଅନà­à¬°à­‹à¬§</translation>
<translation id="7977538094055660992">ଆଉଟପà­à¬Ÿà­ ଡିଭାଇସà­</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ବୃଦà­à¬§à¬¿ ହେଉଥିବା ବାସà­à¬¤à¬¬à¬¤à¬¾ ବିଷୟବସà­à¬¤à­ ଦେଖିବାକୠARCore ଇନà­â€Œà¬·à­à¬Ÿà¬²à­ କରନà­à¬¤à­</translation>
<translation id="799149739215780103">ବାଇଣà­à¬¡</translation>
<translation id="7995512525968007366">ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ହୋଇନାହିà¬</translation>
<translation id="800218591365569300">ମେମୋରୀ ଖାଲି କରିବା ପାଇଠଅନà­à­Ÿà¬¾à¬¨à­à­Ÿ ଟାବୠବା ପà­à¬°à­‹à¬—à­à¬°à¬¾à¬®à­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à­ ବନà­à¬¦ କରିବାକୠଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­à¥¤</translation>
@@ -1850,24 +1880,38 @@
<translation id="8507227106804027148">କମାଣà­à¬¡ ଲାଇନà­</translation>
<translation id="8508648098325802031">ଆଇକନà­â€Œ ଖୋଜନà­à¬¤à­</translation>
<translation id="8522552481199248698">Chrome ଆପଣଙà­à¬•à­ ଆପଣଙà­à¬•à¬° Google ଆକାଉଣà­à¬Ÿà¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରଖିବା à¬à¬¬à¬‚ ଆପଣଙà­à¬•à¬° ପାସà­â€à­±à¬¾à¬°à­à¬¡ ବଦଳାଇବାରେ ସାହାଯà­à­Ÿ କରିପାରିବ।</translation>
+<translation id="8525306231823319788">ପୂରà­à¬£à­à¬£ ସà­à¬•à­à¬°à¬¿à¬¨à­â€Œ</translation>
<translation id="8530813470445476232">Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଇତିହାସ, କà­à¬•à­€, କà­à­Ÿà¬¾à¬¶à­ à¬à¬¬à¬‚ ଆହà­à¬°à¬¿ ଅନେକ କିଛି ଖାଲି କରନà­à¬¤à­</translation>
<translation id="8533619373899488139">ବà­à¬²à¬•à­ କରାଯାଇଥିବା URLଗà­à­œà¬¿à¬•à¬° ତାଲିକା à¬à¬¬à¬‚ ଆପଣଙà­à¬• ସିଷà­à¬Ÿà¬®à­ ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à¬µà¬¾à¬°à¬¾ ଲାଗୠକରାଯାଇଥିବା ଅନà­à­Ÿ ନୀତିଗà­à­œà¬¿à¬•à­ ଦେଖିବା ପାଇଠ&lt;strong&gt;chrome://policy&lt;/strong&gt; କୠଭିଜିଟୠକରନà­à¬¤à­à¥¤</translation>
<translation id="8541158209346794904">ବà­à¬²à­à¬Ÿà­à¬¥à­ ଡିଭାଇସà­</translation>
<translation id="8542014550340843547">ତଳ ପଟରେ ତିନୋଟି ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
<translation id="8543181531796978784">ଆପଣ <ph name="BEGIN_ERROR_LINK" />à¬à¬• ଚିହà­à¬¨à¬Ÿ ସମସà­à­Ÿà¬¾à¬° ରିପୋରà­à¬Ÿ<ph name="END_ERROR_LINK" /> କରିପାରିବେ କିମà­à¬¬à¬¾ ଯଦି ଆପଣ ନିଜର ସà­à¬°à¬•à­à¬·à¬¾ ପାଇଠବିପଦଗà­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬à¬¿à¬ªà¬¾à¬°à­à¬›à¬¨à­à¬¤à¬¿, ତେବେ <ph name="BEGIN_LINK" />à¬à¬¹à¬¿ ଅସà­à¬°à¬•à­à¬·à¬¿à¬¤ ସାଇଟà­â€Œà¬•à­ ଯାଇପାରିବେ<ph name="END_LINK" />।</translation>
<translation id="8557066899867184262">CVC ଆପଣଙà­à¬• କାରà­à¬¡à¬° ପଛପଟେ ଅଛି।</translation>
+<translation id="8558485628462305855">ବୃଦà­à¬§à¬¿ ହେଉଥିବା ବାସà­à¬¤à¬¬à¬¤à¬¾ ସମà­à¬¬à¬¨à­à¬§à¬¿à¬¤ ବିଷୟବସà­à¬¤à­ ଦେଖିବା ପାଇà¬, ARCore ଅପଡେଟୠକରନà­à¬¤à­</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />କୠà¬à¬• ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ସଂଯୋଗ ସà­à¬¥à¬¾à¬ªà¬¨ କରାଯାଇପାରିବ ନାହିଠକାରଣ, ଆପଣଙà­à¬• ଡିଭାଇସà­â€Œà¬° ତାରିଖ à¬à¬¬à¬‚ ସମୟ (<ph name="DATE_AND_TIME" />) ଭà­à¬² ଅଛି।</translation>
<translation id="8564182942834072828">ଅଲଗା ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿà¬—à­à¬¡à¬¼à¬¿à¬•/ସଂଗà­à¬°à¬¹ କରାଯାଇନଥିବା କପିଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="8564985650692024650">ଆପଣ ଯଦି ଆପଣଙà­à¬•à¬° <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬•à­ ଅନà­à­Ÿ ସାଇଟà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ପà­à¬¨à¬ƒ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିଛନà­à¬¤à¬¿, ତେବେ Chromium ଆପଣଙà­à¬•à­ à¬à¬¹à¬¿ ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬•à­ ରିସେଟୠକରିବା ପାଇଠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରà­à¬›à¬¿à¥¤</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª ଯାହା à¬à¬¹à¬¿ ଡିଭାଇସରେ ରହିବ ନାହିà¬:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ଆପଣ à¬à¬¹à¬¿ ୱିଣà­à¬¡à­‹à¬°à­‡ ଦେଖିଥିବା ପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬•
+ <ph name="LIST_ITEM" />କà­à¬•à­€ à¬à¬¬à¬‚ ସାଇଟୠଡାଟା
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">କାରà­à¬¡à¬—à­à­œà¬¿à¬•à­ ଅତି ଶୀଘà­à¬° ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରିବା ପାଇଠTouch ID ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="858637041960032120">ଫୋନà­â€Œ ନମà­à¬¬à¬°à­â€ ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="8589998999637048520">ଉତà­à¬¤à¬® ଗà­à¬£à¬¬à¬¤à­à¬¤à¬¾</translation>
+<translation id="8600271352425265729">କେବଳ à¬à¬¹à¬¿ ସମୟ ପାଇà¬</translation>
<translation id="860043288473659153">କାରà­à¬¡à¬¹à­‹à¬²à­à¬¡à¬°à­â€Œà¬° ନାମ</translation>
<translation id="8606726445206553943">ଆପଣଙà­à¬•à¬° MIDI ଡିଭାଇସୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
+<translation id="8612761427948161954">ନମସà­à¬•à¬¾à¬° <ph name="USERNAME" />,
+ <ph name="BR" />
+ ଆପଣ à¬à¬• ଅତିଥି ଭାବରେ ବà­à¬°à¬¾à¬‰à¬œà­ କରà­à¬›à¬¨à­à¬¤à¬¿</translation>
<translation id="861775596732816396">ଆକାର 4</translation>
<translation id="8622948367223941507">ଲିଗାଲà­-ଅତିରିକà­à¬¤</translation>
<translation id="8623885649813806493">କୌଣସି ମେଳ ହେଉଥିବା ପାସୱାରà­à¬¡ ନାହିà¬à¥¤ ସେଭୠକରାଯାଇଥିବା ସମସà­à¬¤ ପାସୱାରà­à¬¡ ଦେଖାନà­à¬¤à­à¥¤</translation>
<translation id="8625384913736129811">à¬à¬¹à¬¿ ଡିଭାଇସà­â€Œà¬°à­‡ କାରà­à¬¡à¬Ÿà¬¿à¬•à­ ସେଭୠକରନà­à¬¤à­</translation>
+<translation id="8627040765059109009">ସà­à¬•à­à¬°à¬¿à¬¨à­ କà­à­Ÿà¬¾à¬ªà¬šà¬°à­ ପà­à¬£à¬¿ ଆରମà­à¬­ ହୋଇଛି</translation>
<translation id="8657078576661269990">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à­ <ph name="ORIGIN_NAME" />ରୠ<ph name="VM_NAME_1" /> à¬à¬¬à¬‚ <ph name="VM_NAME_2" />କୠସେୟାରିଂ ବà­à¬²à¬•à­ କରିଛନà­à¬¤à¬¿</translation>
<translation id="8663226718884576429">ଅରà­à¬¡à¬° ସାରାଂଶ, <ph name="TOTAL_LABEL" />, ଅଧିକ ବିବରଣୀ</translation>
<translation id="867224526087042813">ଦସà­à¬¤à¬–ତ</translation>
@@ -1930,6 +1974,7 @@
<translation id="8912362522468806198">Google ଆକାଉଣà­à¬Ÿ</translation>
<translation id="8913778647360618320">"ପେମେଣà­à¬Ÿ ପଦà­à¬§à¬¤à¬¿ ପରିଚାଳନା କରନà­à¬¤à­" ବଟନà­, Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ପେମେଣà­à¬Ÿ à¬à¬¬à¬‚ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­ କାରà­à¬¡ ସୂଚନା ପରିଚାଳନା କରିବାକୠEnter ଦବାନà­à¬¤à­</translation>
<translation id="8918231688545606538">à¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾à¬Ÿà¬¿ ସନà­à¬¦à­‡à¬¹à¬œà¬¨à¬• ଅଟେ</translation>
+<translation id="8922013791253848639">à¬à¬¹à¬¿ ସାଇଟà­â€Œà¬°à­‡ ସରà­à¬¬à¬¦à¬¾ ବିଜà­à¬žà¬¾à¬ªà¬¨à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="892588693504540538">ଉପର ଡାହାଣ ପଟରେ ପଞà­à¬šà­</translation>
<translation id="8931333241327730545">ଆପଣ ନିଜର Google ଆକାଉଣà­à¬Ÿà¬°à­‡ à¬à¬¹à¬¿ କାରà­à¬¡à¬•à­ ସେଭୠକରିବାକୠଚାହà­à¬à¬›à¬¨à­à¬¤à¬¿ କି?</translation>
<translation id="8932102934695377596">ଆପଣଙà­à¬•à¬° ଘଣà­à¬Ÿà¬¾à¬° ସମୟ ପଛରେ ଅଛି</translation>
@@ -1998,21 +2043,24 @@
<translation id="917450738466192189">ସରà­à¬­à¬°à­â€à¬° ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ଅବୈଧ ଅଟେ।</translation>
<translation id="9174917557437862841">ଟାବୠସà­à­±à¬¿à¬šà­ କରିବାର ବଟନà­, à¬à¬¹à¬¿ ଟାବà­â€à¬•à­ ସà­à­±à¬¿à¬šà­ କରିବା ପାଇଠà¬à¬£à­à¬Ÿà¬°à­ ଦବାନà­à¬¤à­</translation>
<translation id="9179703756951298733">Chrome ସେଟିଂସରେ ଆପଣଙà­à¬•à¬° ପେମେଣà­à¬Ÿ à¬à¬¬à¬‚ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­ କାରà­à¬¡ ସୂଚନା ପରିଚାଳନା କରନà­à¬¤à­</translation>
-<translation id="9183302530794969518">Google ଡକସà­</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ଗୋଟିଠଅସମରà­à¬¥à¬¿à¬¤ ପà­à¬°à­‹à¬Ÿà­‹à¬•à¬²à­â€Œ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬›à¬¨à­à¬¤à¬¿à¥¤</translation>
<translation id="9191834167571392248">ତଳ ବାମ ପଟରେ ପଞà­à¬šà­</translation>
+<translation id="9199905725844810519">ପà­à¬°à¬¿à¬£à­à¬Ÿà¬¿à¬‚କୠବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="9205078245616868884">ଆପଣଙà­à¬•à¬° ଡାଟା ଆପଣଙà­à¬• ପାସà­â€Œà¬«à­à¬°à­‡à¬œà­ ମାଧà­à­Ÿà¬®à¬°à­‡ à¬à¬¨à­â€Œà¬•à­à¬°à¬¿à¬ªà­à¬Ÿ କରାଯାଇଛି। ସିଙà­à¬•à­ ଆରମà­à¬­ କରିବାକୠà¬à¬¹à¬¾ ଲେଖନà­à¬¤à­à¥¤</translation>
<translation id="9207861905230894330">ନିବନà­à¬§ ଯୋଗ କରିହେଲା ନାହିà¬à¥¤</translation>
<translation id="9213433120051936369">à¬à¬ªà¬¿à¬à¬°à­‡à¬¨à­à¬¸ କଷà­à¬Ÿà¬®à¬¾à¬‡à¬œà­ କରନà­à¬¤à­</translation>
<translation id="9215416866750762878">à¬à¬• ଆପà­à¬²à¬¿à¬•à­‡à¬¸à¬¨à­ Chromeକୠà¬à¬¹à¬¿ ସାଇଟୠସହିତ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରୂପେ ସଂଯୋଗ କରିବାକୠବାଧା ଦେଉଛି</translation>
-<translation id="9219103736887031265">ଛବିଗà­à¬¡à¬¼à¬¿à¬•</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ଫରà­à¬® ଖାଲି କରନà­à¬¤à­</translation>
<translation id="936474030629450166">ସà­à¬ªà¬°à­-B</translation>
<translation id="936602727769022409">ଆପଣ, ଆପଣଙà­à¬•à¬° Google ଆକାଉଣà­à¬Ÿà¬•à­ ଆକà­à¬¸à­‡à¬¸à­â€Œ ହରାଇପାରନà­à¬¤à¬¿à¥¤ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ Chromium ଆପଣଙà­à¬•à­ ପାସà­â€Œà­±à¬°à­à¬¡ ପରିବରà­à¬¤à­à¬¤à¬¨ କରିବା ପାଇଠସà­à¬ªà¬¾à¬°à¬¿à¬¸à­â€Œ କରà­à¬›à¬¿à¥¤ ଆପଣଙà­à¬•à­ ସାଇନà­â€Œ ଇନà­â€Œ ପାଇଠକà­à¬¹à¬¾à¬¯à¬¿à¬¬à¥¤</translation>
<translation id="939736085109172342">ନୂତନ ଫୋଲà­à¬¡à¬°</translation>
+<translation id="945522503751344254">ମତାମତ ପଠାନà­à¬¤à­</translation>
<translation id="945855313015696284">ନିମà­à¬¨à¬°à­‡ ଦିଆଯାଇଥିବା ସୂଚନାକୠଯାଞà­à¬š କରନà­à¬¤à­ à¬à¬¬à¬‚ କୌଣସି ଅବୈଧ କାରà­à¬¡à¬•à­ ଡିଲିଟୠକରନà­à¬¤à­</translation>
<translation id="950736567201356821">ଉପର ପଟରେ ତିନୋଟି ପଞà­à¬šà­</translation>
+<translation id="951941430552851965">ଆପଣଙà­à¬• ସà­à¬•à­à¬°à¬¿à¬¨à¬°à­‡ ଥିବା ବିଷୟବସà­à¬¤à­ ଯୋଗà­à¬ ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ ସà­à¬•à­à¬°à¬¿à¬¨à­ କà­à­Ÿà¬¾à¬ªà¬šà¬°à¬•à­ ବିରତ କରାଯାଇଛି।</translation>
<translation id="961663415146723894">ତଳ ପଟରେ ବାଇଣà­à¬¡</translation>
<translation id="962484866189421427">à¬à¬¹à¬¿ ବିଷୟବସà­à¬¤à­ ପà­à¬°à¬¤à¬¾à¬°à¬£à¬¾à¬¤à­à¬®à¬• ଆପà­à¬¸ ଇନà­â€à¬·à­à¬Ÿà¬²à­â€ କରିପାରେ ଯାହା ଅନà­à­Ÿ କିଛି ହେବାର ଛଳନା କରନà­à¬¤à¬¿ କିମà­à¬¬à¬¾ à¬à¬ªà¬°à¬¿ ଡାଟା ସଂଗà­à¬°à¬¹ କରିପାରନà­à¬¤à¬¿ ଯାହା ଆପଣଙà­à¬•à­ ଟà­à¬°à¬¾à¬•à­â€ କରିବା ପାଇଠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇପାରେ। <ph name="BEGIN_LINK" />ଯେକୌଣସି ଉପାୟରେ ଦେଖାନà­à¬¤à­<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ଅଫିସିଆଲୠବିଲà­à¬¡</translation>
diff --git a/chromium/components/strings/components_strings_pa.xtb b/chromium/components/strings/components_strings_pa.xtb
index 96ff4a597ec..3034e311e9f 100644
--- a/chromium/components/strings/components_strings_pa.xtb
+++ b/chromium/components/strings/components_strings_pa.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ਤà©à¨¸à©€à¨‚ ਉਸ ਸਾਈਟ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਹੈ ਜੋ ਤà©à¨¹à¨¾à¨¡à©€ ਸੰਸਥਾ ਵੱਲੋਂ ਪà©à¨°à¨¬à©°à¨§à¨¿à¨¤ ਨਹੀਂ ਹੈ। ਆਪਣੇ ਖਾਤੇ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਰੱਖਣ ਲਈ, ਹੋਰਾਂ à¨à¨ªà¨¾à¨‚ ਅਤੇ ਸਾਈਟਾਂ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਮà©à©œ ਨਾ ਵਰਤੋ।</translation>
<translation id="1263231323834454256">ਪੜà©à¨¹à¨¤ ਸੂਚੀ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ਉਹ ਸਰਗਰਮੀਆਂ ਜੋ ਇਸ ਡੀਵਾਈਸ 'ਤੇ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਇਸ ਵਿੰਡੋ ਵਿੱਚ ਦੇਖੇ ਜਾਣ ਵਾਲੇ ਪੰਨੇ
+ <ph name="LIST_ITEM" />ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ
+ <ph name="LIST_ITEM" />ਖਾਤਾ ਜਾਣਕਾਰੀ (<ph name="LINK_BEGIN" />ਸਾਈਨ-ਆਊਟ ਕਰੋ<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">ਪਿਕਅੱਪ ਵਿਧੀ</translation>
<translation id="1281476433249504884">ਸਟੈਕਰ 1</translation>
<translation id="1285320974508926690">ਕਦੇ ਵੀ ਇਸ ਸਾਈਟ ਦਾ ਅਨà©à¨µà¨¾à¨¦ ਨਾ ਕਰੋ</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">ਇਤਿਹਾਸ ਇੰਦਰਾਜਾਂ ਦੀ ਸੂਚੀ</translation>
<translation id="1517433312004943670">ਫ਼ੋਨ ਨੰਬਰ ਲੋੜੀਂਦਾ ਹੈ</translation>
<translation id="1519264250979466059">ਬਿਲਡ ਤਾਰੀਖ</translation>
-<translation id="1521655867290435174">Google ਸ਼ੀਟਾਂ</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">ਕਨੈਕਸ਼ਨ ਦੀ ਉਡੀਕ ਹੋ ਰਹੀ ਹੈ...</translation>
<translation id="1529521330346880926">10x15 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="1529789484829130889">ਟà©à¨°à©‡à¨… 8</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ ਵਰਤਣ ਲਈ ਸਾਈਨ-ਇਨ ਕਰੋ</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> ਭਾਸ਼ਾ ਵਾਲੇ ਪੰਨਿਆਂ ਦਾ ਅਨà©à¨µà¨¾à¨¦ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ।</translation>
<translation id="2053553514270667976">ਜ਼ਿਪ ਕੋਡ</translation>
+<translation id="2054665754582400095">ਤà©à¨¹à¨¾à¨¡à©€ ਮੌਜੂਦਗੀ</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ਸà©à¨à¨¾à¨…}one{# ਸà©à¨à¨¾à¨…}other{ # ਸà©à¨à¨¾à¨…}}</translation>
<translation id="2079545284768500474">ਅਣਕੀਤਾ ਕਰੋ</translation>
<translation id="20817612488360358">ਸਿਸਟਮ ਪà©à¨°à©Œà¨•à¨¸à©€ ਸੈਟਿੰਗਾਂ ਵਰਤੇ ਜਾਣ ਲਈ ਸੈੱਟ ਕੀਤੀਆਂ ਗਈਆਂ ਹਨ ਪਰ ਇੱਕ ਸਪਸ਼ਟ ਪà©à¨°à©Œà¨•à¨¸à©€ ਸੰਰੂਪਿਤ ਵੀ ਨਿਸ਼ਚਿਤ ਹੈ।</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android à¨à¨ªà¨¾à¨‚</translation>
<translation id="2107021941795971877">ਪà©à¨°à¨¿à©°à¨Ÿ ਸੰਬੰਧੀ ਸਹਾਇਤਾਵਾਂ</translation>
<translation id="2108755909498034140">ਆਪਣੇ ਕੰਪਿਊਟਰ ਨੂੰ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਕਰੋ</translation>
+<translation id="2111166930115883695">ਖੇਡਣ ਲਈ space ਦਬਾਓ</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">ਕਾਰਡ</translation>
<translation id="2114841414352855701">ਅਣਡਿੱਠ ਕੀਤਾ ਕਿਉਂਕਿ ਇਹ <ph name="POLICY_NAME" /> ਵੱਲੋਂ ਓਵਰਰਾਈਡ ਕੀਤਾ ਸੀ।</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">ਭà©à¨—ਤਾਨ ਰੱਦ ਕਰੋ</translation>
<translation id="2147827593068025794">ਬੈਕਗà©à¨°à¨¾à¨Šà¨‚ਡ ਸਮਕਾਲੀਕਰਨ</translation>
<translation id="2148613324460538318">ਕਾਰਡ ਸ਼ਾਮਲ ਕਰੋ</translation>
+<translation id="2149968176347646218">ਕਨੈਕਸ਼ਨ ਸà©à¨°à©±à¨–ਿਅਤ ਨਹੀਂ ਹੈ</translation>
<translation id="2154054054215849342">ਸਮਕਾਲੀਕਰਨ ਤà©à¨¹à¨¾à¨¡à©€ ਡੋਮੇਨ ਲਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ</translation>
<translation id="2154484045852737596">ਕਾਰਡ ਦਾ ਸੰਪਾਦਨ ਕਰੋ</translation>
<translation id="2161656808144014275">ਲਿਖਤ</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">ਨੀਤੀਆਂ</translation>
<translation id="2183608646556468874">ਫ਼ੋਨ ਨੰਬਰ</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ਪਤਾ}one{# ਪਤੇ}other{# ਪਤੇ}}</translation>
-<translation id="2187243482123994665">ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ</translation>
<translation id="2187317261103489799">ਪਤਾ ਲਗਾਓ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)</translation>
<translation id="2188375229972301266">ਹੇਠਾਂ ਇੱਕ ਤੋਂ ਵੱਧ ਮੋਰੀਆਂ</translation>
<translation id="2202020181578195191">ਇੱਕ ਵੈਧ ਮਿਆਦ ਸਮਾਪਤੀ ਸਾਲ ਦਾਖਲ ਕਰੋ</translation>
@@ -465,6 +475,7 @@
<translation id="2839501879576190149">ਅੱਗੇ ਨਕਲੀ ਸਾਈਟ ਹੈ</translation>
<translation id="2850739647070081192">ਸੱਦਾ (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="2856444702002559011">ਹਮਲਾਵਰ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ਤੋਂ ਤà©à¨¹à¨¾à¨¡à©€ ਜਾਣਕਾਰੀ ਨੂੰ ਚੋਰੀ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹਨ (ਉਦਾਹਰਨ ਲਈ, ਪਾਸਵਰਡ, ਸà©à¨¨à©‡à¨¹à©‡, ਜਾਂ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ)। <ph name="BEGIN_LEARN_MORE_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ਇਹ ਸਾਈਟ ਦਖਲਅੰਦਾਜ਼ੀ ਜਾਂ ਗà©à¨®à¨°à¨¾à¨¹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀ ਹੈ।</translation>
<translation id="2878197950673342043">ਪੋਸਟਰ ਰੂਪੀ ਤਹਿ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ਵਿੰਡੋ ਪਲੇਸਮੈਂਟ</translation>
@@ -503,11 +514,11 @@
<translation id="2996674880327704673">Google ਵੱਲੋਂ ਸà©à¨à¨¾à¨…</translation>
<translation id="3002501248619246229">ਇਨਪà©à©±à¨Ÿ ਟà©à¨°à©‡à¨… ਮੀਡੀਆ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
<translation id="3005723025932146533">ਰੱਖਿਅਤ ਕੀਤੀ ਕਾਪੀ ਦਿਖਾਓ</translation>
-<translation id="3007719053326478567">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਵੱਲੋਂ ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਪà©à¨°à¨¿à©°à¨Ÿ ਕਰਨ ਦੀ ਸà©à¨µà¨¿à¨§à¨¾ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> ਦਾ CVC ਦਾਖਲ ਕਰੋ। ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਪà©à¨¸à¨¼à¨Ÿà©€ ਕੀਤੇ ਜਾਣ 'ਤੇ, ਤà©à¨¹à¨¾à¨¡à©‡ ਕਾਰਡ ਵੇਰਵੇ ਇਸ ਸਾਈਟ ਨਾਲ ਸਾਂà¨à©‡ ਕੀਤੇ ਜਾਣਗੇ।</translation>
<translation id="3010559122411665027">ਸੂਚੀ à¨à¨‚ਟਰੀ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਬਲੌਕ ਕੀਤੀ ਗਈ</translation>
<translation id="3016780570757425217">ਆਪਣੇ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਬਾਰੇ ਜਾਣੋ</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Tab ਦਬਾਓ ਫਿਰ ਸà©à¨à¨¾à¨… ਨੂੰ ਹਟਾਉਣ ਲਈ Enter ਦਬਾਓ।</translation>
<translation id="3023071826883856138">You4 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="3024663005179499861">ਨੀਤੀ ਦੀ ਗਲਤ ਕਿਸਮ</translation>
<translation id="3037605927509011580">ਆਹ, ਸਨੈਪ!</translation>
@@ -548,6 +559,7 @@
<translation id="3207960819495026254">ਬà©à©±à¨•à¨®à¨¾à¨°à¨• ਕੀਤੇ</translation>
<translation id="3209034400446768650">ਸ਼ਾਇਦ ਪੰਨੇ ਵੱਲੋਂ ਖਰਚੇ ਲਠਜਾਣ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> 'ਤੇ ਤà©à¨¹à¨¾à¨¡à©€ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ</translation>
+<translation id="3212623355668894776">ਸਾਰੀਆਂ ਮਹਿਮਾਨ ਵਿੰਡੋਆਂ ਨੂੰ ਬੰਦ ਕਰੋ ਤਾਂ ਜੋ ਤà©à¨¹à¨¾à¨¡à©€ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਮਿਟਾਇਆ ਜਾ ਸਕੇ।</translation>
<translation id="3215092763954878852">WebAuthn ਨੂੰ ਨਹੀਂ ਵਰਤ ਸਕਦੇ</translation>
<translation id="3218181027817787318">ਸੰਬੰਧਿਤ</translation>
<translation id="3225919329040284222">ਸਰਵਰ ਨੇ ਇੱਕ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਪੇਸ਼ ਕੀਤਾ ਸੀ ਜੋ ਪਹਿਲਾਂ ਤੋਂ ਮੌਜੂਦ ਅਨà©à¨®à¨¾à¨¨à¨¾à¨‚ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ। ਇਹ ਅਨà©à¨®à¨¾à¨¨à¨¾à¨‚ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ ਤਾਂ ਕਿ ਉੱਚ-ਸà©à¨°à©±à¨–ਿਆ ਵਾਲੀਆਂ ਵੈੱਬਸਾਈਟਾਂ ਦੀ ਰੱਖਿਆ ਕੀਤੀ ਜਾਵੇ।</translation>
@@ -694,6 +706,7 @@
<translation id="3784372983762739446">ਬਲੂਟà©à©±à¨¥ ਡੀਵਾਈਸਾਂ</translation>
<translation id="3787705759683870569">ਮਿਆਦ ਸਮਾਪਤੀ ਦੀ ਮਿਤੀ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ਆਕਾਰ 16</translation>
+<translation id="3789841737615482174">ਸਥਾਪਤ ਕਰੋ</translation>
<translation id="3793574014653384240">ਹਾਲ ਹੀ ਵਿੱਚ ਵਾਪਰੇ ਕà©à¨°à©ˆà¨¶à¨¾à¨‚ ਦੀ ਗਿਣਤੀ ਅਤੇ ਕਾਰਨ</translation>
<translation id="3797522431967816232">Prc3 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="3799805948399000906">ਫ਼ੌਂਟ ਲਈ ਬੇਨਤੀ ਕੀਤੀ</translation>
@@ -744,6 +757,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">ਕà©à©°à¨œà©€ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
+<translation id="4067669230157909013">ਸਕà©à¨°à©€à¨¨ ਕੈਪਚਰ ਨੂੰ ਮà©à©œ-ਚਾਲੂ ਕੀਤਾ ਗਿਆ।</translation>
<translation id="4067947977115446013">ਵੈਧ ਪਤਾ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="4072486802667267160">ਤà©à¨¹à¨¾à¨¡à©‡ ਆਰਡਰ 'ਤੇ ਪà©à¨°à¨•à¨¿à¨°à¨¿à¨† ਕਰਨ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ। ਕਿਰਪਾ ਕਰਕੇ ਦà©à¨¬à¨¾à¨°à¨¾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
<translation id="4075732493274867456">ਗਾਹਕ ਅਤੇ ਸਰਵਰ ਇੱਕ ਆਮ SSL ਪà©à¨°à©‹à¨Ÿà©‹à¨•à©‹à¨² ਵਰਜਨ ਜਾਂ ਸਿਫ਼ਰ ਸà©à¨ˆà¨Ÿ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੇ ਹਨ।</translation>
@@ -824,6 +838,7 @@
<translation id="4297502707443874121">ਪੰਨਾ <ph name="THUMBNAIL_PAGE" /> ਲਈ ਲਘੂ-ਚਿੱਤਰ</translation>
<translation id="42981349822642051">ਵਿਸਤਾਰ ਕਰੋ</translation>
<translation id="4300675098767811073">ਸੱਜੇ ਪਾਸੇ ਇੱਕ ਤੋਂ ਵੱਧ ਮੋਰੀਆਂ</translation>
+<translation id="4302514097724775343">ਖੇਡਣ ਲਈ ਡਾਇਨਾਸੌਰ 'ਤੇ ਟੈਪ ਕਰੋ</translation>
<translation id="4302965934281694568">Chou3 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="4305666528087210886">ਤà©à¨¹à¨¾à¨¡à©€ ਫ਼ਾਈਲ 'ਤੇ ਪਹà©à©°à¨š ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ</translation>
<translation id="4305817255990598646">ਸਵਿੱਚ ਕਰੋ</translation>
@@ -902,9 +917,10 @@
<translation id="4658638640878098064">ਉੱਪਰ ਖੱਬੇ ਪਾਸੇ ਪਿੰਨ</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">ਆਭਾਸੀ ਵਾਸਤਵਿਕਤਾ</translation>
+<translation id="4675657451653251260">ਤà©à¨¹à¨¾à¨¨à©‚à©° ਮਹਿਮਾਨ ਮੋਡ ਵਿੱਚ Chrome ਪà©à¨°à©‹à¨«à¨¾à¨ˆà¨² ਦੀ ਕੋਈ ਜਾਣਕਾਰੀ ਨਹੀਂ ਦਿਸੇਗੀ। ਤà©à¨¸à©€à¨‚ ਪਾਸਵਰਡਾਂ ਅਤੇ ਭà©à¨—ਤਾਨ ਵਿਧੀਆਂ ਵਰਗੀ ਆਪਣੀ Google ਖਾਤੇ ਦੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਲਈ <ph name="LINK_BEGIN" />ਸਾਈਨ-ਇਨ<ph name="LINK_END" /> ਕਰ ਸਕਦੇ ਹੋ।</translation>
<translation id="467662567472608290">ਇਹ ਸਰਵਰ ਇਹ ਸਾਬਤ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦੇ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਵਿੱਚ ਗੜਬੜੀਆਂ ਹਨ। ਇਹ ਇੱਕ ਗਲਤ ਸੰਰੂਪਣ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="4677585247300749148"><ph name="URL" /> ਦੀ ਪਹà©à©°à¨šà¨¯à©‹à¨—ਤਾ ਇਵੈਂਟਾਂ 'ਤੇ ਪà©à¨°à¨¤à¨¿à¨•à¨¿à¨°à¨¿à¨† ਕਰਨ ਦੀ ਇੱਛਾ ਹੈ</translation>
-<translation id="467809019005607715">Google ਸਲਾਈਡਾਂ</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">ਤà©à¨¸à©€à¨‚ ਹà©à¨£à©‡-ਹà©à¨£à©‡ ਕਿਸੇ ਭਰਮਪੂਰਨ ਸਾਈਟ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਹੈ। Chromium ਵੱਲੋਂ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> ਅਤੇ ਉਹਨਾਂ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਆਪਣੇ ਰੱਖਿਅਤ ਪਾਸਵਰਡਾਂ ਨੂੰ ਜਾਂਚਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਜਿੱਥੇ ਹà©à¨£ ਤà©à¨¸à©€à¨‚ ਇਹ ਪਾਸਵਰਡ ਵਰਤਦੇ ਹੋ।</translation>
<translation id="4690462567478992370">ਅਵੈਧ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਵਰਤਣਾ ਬੰਦ ਕਰੋ</translation>
<translation id="4691835149146451662">Architecture-A (ਲਿਫ਼ਾਫ਼ਾ)</translation>
@@ -929,6 +945,12 @@
<translation id="4761104368405085019">ਆਪਣਾ ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨ ਵਰਤੋ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ਤੇ ਵੈਬਪੇਜ ਅਸਥਾਈ ਤੌਰ ਤੇ ਹੌਲੀ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਇਹ ਸਥਾਈ ਤੌਰ ਤੇ ਕਿਸੇ ਨਵੇਂ ਵੈਬ ਪਤੇ ਤੇ ਮੂਵ ਹੋ ਗਿਆ ਹੋ ਸਕਦਾ ਹੈ।</translation>
<translation id="4766713847338118463">ਹੇਠਾਂ ਦੋ ਪਿੰਨਾਂ</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ਤà©à¨¹à¨¾à¨¡à©€ ਉਹ ਸਰਗਰਮੀ ਜੋ ਇਸ ਡੀਵਾਈਸ 'ਤੇ ਰੱਖਿਅਤ ਕੀਤੀ ਜਾਵੇਗੀ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਇਸ ਵਿੰਡੋ ਵਿੱਚ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਡਾਊਨਲੋਡ ਕੀਤੀ ਕੋਈ ਵੀ ਫ਼ਾਈਲ
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ਇੱਕ ਅਗਿਆਤ ਗੜਬੜ ਹੋਈ ਹੈ।</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{[=1]ਪੌਪ-ਅੱਪ ਬਲਾਕ ਕੀਤਾ ਗਿਆ}one{# ਪੌਪ-ਅੱਪ ਬਲਾਕ ਕੀਤਾ ਗਿਆ}other{# ਪੌਪ-ਅੱਪ ਬਲਾਕ ਕੀਤੇ ਗà¨}}</translation>
<translation id="4780366598804516005">ਮੇਲਬਾਕਸ 1</translation>
@@ -1091,11 +1113,13 @@
<translation id="5386426401304769735">ਇਸ ਸਾਈਟ ਲਈ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਲੜੀ ਵਿੱਚ SHA-1 ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਹਸਤਾਖਰ ਕੀਤਾ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਸ਼ਾਮਲ ਹੈ।</translation>
<translation id="538659543871111977">A4-ਟੈਬ</translation>
<translation id="5396631636586785122">ਸੱਜੇ ਕਿਨਾਰੇ ਤੋਂ ਸਿਲਾਈ</translation>
+<translation id="5398772614898833570">ਵਿਗਿਆਪਨ ਬਲੌਕ ਕੀਤੇ ਗà¨</translation>
<translation id="5400836586163650660">ਸਲੇਟੀ</translation>
<translation id="540969355065856584">ਇਹ ਸਰਵਰ ਇਹ ਸਾਬਤ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਇਸ ਸਮੇਂ ਵੈਧ ਨਹੀਂ ਹੈ। ਇਹ ਇੱਕ ਗਲਤ ਸੰਰੂਪਣ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="541416427766103491">ਸਟੈਕਰ 4</translation>
<translation id="5421136146218899937">ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਡਾਟਾ ਹਟਾਓ</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ਤà©à¨¹à¨¾à¨¨à©‚à©° ਸੂਚਨਾਵਾਂ ਭੇਜਣਾ ਚਾਹà©à©°à¨¦à©€ ਹੈ।</translation>
+<translation id="542872847390508405">ਤà©à¨¸à©€à¨‚ ਇੱਕ ਮਹਿਮਾਨ ਦੇ ਤੌਰ ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰ ਰਹੇ ਹੋ</translation>
<translation id="5430298929874300616">ਬà©à©±à¨•à¨®à¨¾à¨°à¨• ਹਟਾਓ</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" ਤੇ Schema ਪà©à¨°à¨®à¨¾à¨£à©€à¨•à¨°à¨¨ ਗੜਬੜ : <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ਉਲਟੇ ਕà©à¨°à¨® ਵਿੱਚ ਪਾਸਾ ਉੱਪਰ ਕੀਤੇ ਹੋà¨</translation>
@@ -1137,12 +1161,12 @@
<translation id="5571083550517324815">ਇਸ ਪਤੇ ਤੋਂ ਪਿੱਕਅੱਪ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਕਿਸੇ ਵੱਖਰੇ ਪਤੇ ਨੂੰ ਚà©à¨£à©‹à¥¤</translation>
<translation id="5580958916614886209">ਆਪਣੀ ਮਿਆਦ ਸਮਾਪਤੀ ਦੇ ਮਹੀਨੇ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਦà©à¨¬à¨¾à¨°à¨¾ ਕੋਸ਼ਿਸ਼ ਕਰੋ</translation>
<translation id="5586446728396275693">ਕੋਈ ਰੱਖਿਅਤ ਪਤੇ ਨਹੀਂ ਹਨ</translation>
+<translation id="5593349413089863479">ਕਨੈਕਸ਼ਨ ਪੂਰੀ ਤਰà©à¨¹à¨¾à¨‚ ਸà©à¨°à©±à¨–ਿਅਤ ਨਹੀਂ ਹੈ</translation>
<translation id="5595485650161345191">ਪਤਾ ਸੰਪਾਦਿਤ ਕਰੋ</translation>
<translation id="5598944008576757369">ਭà©à¨—ਤਾਨ ਵਿਧੀ ਚà©à¨£à©‹</translation>
<translation id="560412284261940334">ਪà©à¨°à¨¬à©°à¨§à¨¨ ਸਮਰਥਿਤ ਨਹੀਂ</translation>
<translation id="5605670050355397069">ਵਹੀ-ਖਾਤਾ</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">ਸਾਈਟ ਨਕਲੀ ਜਾਂ ਧੋਖਾਧੜੀ ਵਾਲੀ ਹੋ ਸਕਦੀ ਹੈ। Chrome ਹà©à¨£à©‡ ਇਸਨੂੰ ਛੱਡਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।</translation>
<translation id="5610142619324316209">ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
<translation id="5610807607761827392">ਤà©à¨¸à©€à¨‚ <ph name="BEGIN_LINK" />ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਕਾਰਡਾਂ ਅਤੇ ਪਤਿਆਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰ ਸਕਦੇ ਹੋ।</translation>
<translation id="561165882404867731">ਇਸ ਪੰਨੇ ਦਾ Google Translate ਨਾਲ ਅਨà©à¨µà¨¾à¨¦ ਕਰੋ</translation>
@@ -1214,6 +1238,7 @@
<translation id="5901630391730855834">ਪੀਲਾ</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> ਦੀ ਮੂਲ ਸੰਬੰਧੀ ਨੀਤੀ ਮà©à¨¤à¨¾à¨¬à¨• ਬਲਾਕ ਕੀਤਾ ਗਿਆ।</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ਸਮਕਾਲੀਕਿਰਤ ਕੀਤੇ ਗà¨)</translation>
+<translation id="5913377024445952699">ਸਕà©à¨°à©€à¨¨ ਕੈਪਚਰ ਕਰਨਾ ਰੋਕਿਆ ਗਿਆ</translation>
<translation id="59174027418879706">ਸਮਰਥਿਤ</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ਚਾਲੂ</translation>
@@ -1226,6 +1251,7 @@
<translation id="5963413905009737549">ਭਾਗ</translation>
<translation id="5967592137238574583">ਸੰਪਰਕ ਜਾਣਕਾਰੀ ਦਾ ਸੰਪਾਦਨ ਕਰੋ</translation>
<translation id="5967867314010545767">ਇਤਿਹਾਸ ਵਿੱਚੋਂ ਹਟਾਓ</translation>
+<translation id="5968793460449681917">ਹਰੇਕ ਫੇਰੀ 'ਤੇ</translation>
<translation id="5975083100439434680">ਜ਼ੂਮ ਘਟਾਓ</translation>
<translation id="5979084224081478209">ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1380,6 +1406,7 @@
<translation id="6587923378399804057">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਕਾਪੀ ਕੀਤਾ ਲਿੰਕ</translation>
<translation id="6591833882275308647">ਤà©à¨¹à¨¾à¨¡à¨¾ <ph name="DEVICE_TYPE" /> ਪà©à¨°à¨¬à©°à¨§à¨¿à¨¤ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ</translation>
<translation id="6596325263575161958">à¨à¨¨à¨•à©à¨°à¨¿à¨ªà¨¶à¨¨ ਚੋਣਾਂ</translation>
+<translation id="6596892391065203054">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਵੱਲੋਂ ਇਸ ਸਮੱਗਰੀ ਨੂੰ ਪà©à¨°à¨¿à©°à¨Ÿ ਕਰਨ ਦੀ ਸà©à¨µà¨¿à¨§à¨¾ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ।</translation>
<translation id="6604181099783169992">ਮੋਸ਼ਨ ਜਾਂ ਲਾਈਟ ਸੈਂਸਰ</translation>
<translation id="6609880536175561541">Prc7 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="6612358246767739896">ਸà©à¨°à©±à¨–ਿਅਤ ਸਮੱਗਰੀ</translation>
@@ -1439,6 +1466,7 @@
<translation id="6895330447102777224">ਤà©à¨¹à¨¾à¨¡à©‡ ਕਾਰਡ ਦੀ ਪà©à¨¸à¨¼à¨Ÿà©€ ਹੋ ਗਈ ਹੈ</translation>
<translation id="6897140037006041989">ਵਰਤੋਂਕਾਰ à¨à¨œà©°à¨Ÿ</translation>
<translation id="6898699227549475383">ਕੰਪਨੀ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> ਨੂੰ ਇਹ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ:</translation>
<translation id="6910240653697687763"><ph name="URL" /> ਦੀ ਤà©à¨¹à¨¾à¨¡à©‡ MIDI ਡੀਵਾਈਸਾਂ 'ਤੇ ਪੂਰਾ ਕੰਟਰੋਲ ਕਰਨ ਦੀ ਇੱਛਾ ਹੈ</translation>
<translation id="6915804003454593391">ਵਰਤੋਂਕਾਰ:</translation>
<translation id="6934672428414710184">ਇਹ ਨਾਮ ਤà©à¨¹à¨¾à¨¡à©‡ Google ਖਾਤੇ ਤੋਂ ਲਿਆ ਗਿਆ ਹੈ</translation>
@@ -1458,7 +1486,7 @@
<translation id="6973656660372572881">ਦੋਵੇਂ ਸਥਿਰ ਪà©à¨°à©Œà¨•à¨¸à©€ ਸਰਵਰ ਅਤੇ ਇੱਕ .pac ਸਕà©à¨°à¨¿à¨ªà¨Ÿ URL ਨਿਰਦਿਸ਼ਟ ਹਨ।</translation>
<translation id="6973932557599545801">ਮਾਫ਼ ਕਰਨਾ ਮੇਰੇ ਵੱਲੋਂ ਮਦਦ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ, ਕਿਰਪਾ ਕਰਕੇ ਖà©à¨¦ ਜਾਰੀ ਰੱਖੋ।</translation>
<translation id="6975012522936652259">ਤà©à¨¸à©€à¨‚ ਹà©à¨£à©‡-ਹà©à¨£à©‡ ਕਿਸੇ ਭਰਮਪੂਰਨ ਸਾਈਟ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਹੈ। Chromium ਵੱਲੋਂ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> ਅਤੇ ਉਹਨਾਂ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਜਾ ਕੇ ਹà©à¨£à©‡ ਆਪਣਾ ਪਾਸਵਰਡ ਬਦਲਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਜਿੱਥੇ ਤà©à¨¸à©€à¨‚ ਆਪਣਾ ਪਾਸਵਰਡ ਵਰਤਿਆ ਹੈ।</translation>
-<translation id="6979158407327259162">Google ਡਰਾਈਵ</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">ਮਿਊਟ ਕਰੋ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)</translation>
<translation id="6979983982287291980">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਵਿਸ਼ਲੇਸ਼ਣ ਲਈ Google ਕਲਾਊਡ ਜਾਂ ਤੀਜੀਆਂ ਧਿਰਾਂ ਨੂੰ ਭੇਜਿਆ ਜਾਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਉਹਨਾਂ ਨੂੰ ਸੰਵੇਦਨਸ਼ੀਲ ਡਾਟੇ ਜਾਂ ਮਾਲਵੇਅਰ ਲਈ ਸਕੈਨ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।</translation>
<translation id="6989763994942163495">ਉੱਨਤ ਸੈਟਿੰਗਾਂ ਦਿਖਾਓ...</translation>
@@ -1550,6 +1578,7 @@
<translation id="7346048084945669753">ਸੰਬੰਧਿਤ ਹੈ:</translation>
<translation id="7349430561505560861">A4-ਵਾਧੂ</translation>
<translation id="7353601530677266744">ਕਮਾਂਡ ਲਾਈਨ</translation>
+<translation id="7359588939039777303">ਵਿਗਿਆਪਨ ਬਲੌਕ ਕੀਤੇ ਗà¨à¥¤</translation>
<translation id="7372973238305370288">ਖੋਜ ਨਤੀਜਾ</translation>
<translation id="7374733840632556089">ਇਹ ਸਮੱਸਿਆ ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ 'ਤੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਜਾਂ ਕਿਸੇ ਹੋਰ ਵੱਲੋਂ ਸਥਾਪਤ ਕੀਤੇ ਕਿਸੇ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਕਰਕੇ ਆਈ। ਇਹ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਨੈੱਟਵਰਕਾਂ 'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖਣ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਰੋਕਣ ਲਈ ਜਾਣਿਆ ਜਾਂਦਾ ਹੈ, ਅਤੇ Chrome ਵੱਲੋਂ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਹੈ। ਹਾਲਾਂਕਿ ਕà©à¨ ਵੈਧ ਮਾਮਲਿਆਂ ਵਿੱਚ ਵੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਜਿਵੇਂ ਕਿ ਸਕੂਲ ਜਾਂ ਕੰਪਨੀ ਦੇ ਨੈੱਟਵਰਕ 'ਤੇ, Chrome ਇਹ ਪੱਕਾ ਕਰਨਾ ਚਾਹà©à©°à¨¦à¨¾ ਹੈ ਕਿ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਇਸ ਗੱਲ ਦੀ ਜਾਣਕਾਰੀ ਹੈ ਕਿ ਇਸ ਤਰà©à¨¹à¨¾à¨‚ ਹੋ ਰਿਹਾ ਹੈ, ਭਾਵੇਂ ਤà©à¨¸à©€à¨‚ ਇਸਨੂੰ ਰੋਕ ਨਹੀਂ ਸਕਦੇ। ਵੈੱਬ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਵਾਲੇ ਕਿਸੇ ਵੀ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨° ਜਾਂ à¨à¨ªà¨²à©€à¨•à©‡à¨¶à¨¨ 'ਤੇ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।</translation>
<translation id="7375818412732305729">ਫ਼ਾਈਲ ਨੱਥੀ ਕੀਤੀ ਗਈ ਹੈ</translation>
@@ -1724,6 +1753,7 @@
<translation id="7976214039405368314">ਬਹà©à¨¤ ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ</translation>
<translation id="7977538094055660992">ਆਊਟਪà©à©±à¨Ÿ ਡੀਵਾਈਸ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ਸੰਵਰਧਿਤ ਵਾਸਤਵਿਕਤਾ ਵਾਲੀ ਸਮੱਗਰੀ ਦੇਖਣ ਲਈ, ARCore ਸਥਾਪਤ ਕਰੋ</translation>
<translation id="799149739215780103">ਜਿਲਦਬੰਦ</translation>
<translation id="7995512525968007366">ਨਿਰਦਿਸ਼ਟ ਨਹੀਂ ਕੀਤਾ</translation>
<translation id="800218591365569300">ਮੈਮੋਰੀ ਖਾਲੀ ਕਰਨ ਲਈ ਦੂਜੀਆਂ ਟੈਬਾਂ ਜਾਂ ਪà©à¨°à©‹à¨—ਰਾਮਾਂ ਨੂੰ ਬੰਦ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
@@ -1851,24 +1881,38 @@
<translation id="8507227106804027148">ਕਮਾਂਡ ਲਾਈਨ</translation>
<translation id="8508648098325802031">ਖੋਜ ਪà©à¨°à¨¤à©€à¨•</translation>
<translation id="8522552481199248698">Chrome ਤà©à¨¹à¨¾à¨¡à©‡ Google ਖਾਤੇ ਦੀ ਸà©à¨°à©±à¨–ਿਆ ਕਰਨ ਅਤੇ ਪਾਸਵਰਡ ਬਦਲਣ ਵਿੱਚ ਤà©à¨¹à¨¾à¨¡à©€ ਮਦਦ ਕਰ ਸਕਦਾ ਹੈ।</translation>
+<translation id="8525306231823319788">ਪੂਰੀ ਸਕà©à¨°à©€à¨¨</translation>
<translation id="8530813470445476232">ਆਪਣੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਇਤਿਹਾਸ, ਕà©à¨•à©€à¨œà¨¼, ਕੈਸ਼ੇ ਅਤੇ ਹੋਰ ਚੀਜ਼ਾਂ ਨੂੰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਕਲੀਅਰ ਕਰੋ</translation>
<translation id="8533619373899488139">ਬਲਾਕ ਕੀਤੇ URL ਅਤੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਸਿਸਟਮ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਵੱਲੋਂ ਲਾਗੂ ਕੀਤੀਆਂ ਹੋਰ ਨੀਤੀਆਂ ਦੀ ਸੂਚੀ ਦੇਖਣ ਲਈ &lt;strong&gt;chrome://policy&lt;/strong&gt; 'ਤੇ ਜਾਓ।</translation>
<translation id="8541158209346794904">ਬਲੂਟà©à©±à¨¥ ਡੀਵਾਈਸ</translation>
<translation id="8542014550340843547">ਹੇਠਾਂ ਤਿੰਨ ਪਿੰਨਾਂ</translation>
<translation id="8543181531796978784">ਤà©à¨¸à©€à¨‚ <ph name="BEGIN_ERROR_LINK" />ਇੱਕ ਖੋਜ ਸਮੱਸਿਆ ਦੀ ਰਿਪੋਰਟ ਕਰ ਸਕਦੇ ਹੋ<ph name="END_ERROR_LINK" /> ਜਾਂ ਜੇਕਰ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਲੱਗਦਾ ਹੈ ਕਿ ਤà©à¨¹à¨¾à¨¡à©€ ਸà©à¨°à©±à¨–ਿਆ ਨੂੰ ਖਤਰਾ ਹੈ, ਤਾਂ ਤà©à¨¸à©€à¨‚ <ph name="BEGIN_LINK" />ਇਸ ਅਸà©à¨°à©±à¨–ਿਅਤ ਸਾਈਟ 'ਤੇ ਜਾ<ph name="END_LINK" />ਸਕਦੇ ਹੋ।</translation>
<translation id="8557066899867184262">CVC ਤà©à¨¹à¨¾à¨¡à©‡ ਕਾਰਡ ਦੇ ਪਿੱਛੇ ਮੌਜੂਦ ਹੈ।</translation>
+<translation id="8558485628462305855">ਸੰਵਰਧਿਤ ਵਾਸਤਵਿਕਤਾ ਵਾਲੀ ਸਮੱਗਰੀ ਦੇਖਣ ਲਈ, ARCore ਅੱਪਡੇਟ ਕਰੋ</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ਨਾਲ ਇੱਕ ਨਿੱਜੀ ਕਨੈਕਸ਼ਨ ਨੂੰ ਸਥਾਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਦੀ ਤਾਰੀਖ ਅਤੇ ਸਮਾਂ (<ph name="DATE_AND_TIME" />) ਗ਼ਲਤ ਹੈ।</translation>
<translation id="8564182942834072828">ਵੱਖਰੇ ਦਸਤਾਵੇਜ਼/ਅਣਇਕੱਤਰ ਕਾਪੀਆਂ</translation>
<translation id="8564985650692024650">ਜੇਕਰ ਤà©à¨¸à©€à¨‚ ਆਪਣੇ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ਪਾਸਵਰਡ ਨੂੰ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਮà©à©œ ਵਰਤਿਆ ਹੈ, ਤਾਂ Chromium ਵੱਲੋਂ ਇਸਨੂੰ ਰੀਸੈੱਟ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ਉਹ ਸਰਗਰਮੀਆਂ ਜੋ ਇਸ ਡੀਵਾਈਸ 'ਤੇ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਇਸ ਵਿੰਡੋ ਵਿੱਚ ਦੇਖੇ ਜਾਣ ਵਾਲੇ ਪੰਨੇ
+ <ph name="LIST_ITEM" />ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ਕਾਰਡਾਂ ਦੀ ਤੇਜ਼ੀ ਨਾਲ ਤਸਦੀਕ ਕਰਨ ਲਈ ਸਪਰਸ਼ ਆਈਡੀ ਵਰਤੋ</translation>
<translation id="858637041960032120">ਫ਼ੋਨ ਨੰਬਰ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="8589998999637048520">ਬਿਹਤਰੀਨ ਕà©à¨†à¨²à¨¿à¨Ÿà©€</translation>
+<translation id="8600271352425265729">ਸਿਰਫ਼ ਇਸ ਵਾਰ</translation>
<translation id="860043288473659153">ਕਾਰਡਧਾਰਕ ਦਾ ਨਾਮ</translation>
<translation id="8606726445206553943">ਆਪਣੀਆਂ MIDI ਡਿਵਾਈਸਾਂ ਵਰਤੋ</translation>
+<translation id="8612761427948161954">ਸਤਿ ਸà©à¨°à©€ ਅਕਾਲ <ph name="USERNAME" />,
+ <ph name="BR" />
+ ਤà©à¨¸à©€à¨‚ ਮਹਿਮਾਨ ਵਜੋਂ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰ ਰਹੇ ਹੋ</translation>
<translation id="861775596732816396">ਆਕਾਰ 4</translation>
<translation id="8622948367223941507">ਕਨੂੰਨੀ-ਵਾਧੂ</translation>
<translation id="8623885649813806493">ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਪਾਸਵਰਡ ਨਹੀਂ। ਸਾਰੇ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ ਦਿਖਾਓ।</translation>
<translation id="8625384913736129811">ਇਸ ਕਾਰਡ ਨੂੰ ਇਸ ਡੀਵਾਈਸ 'ਤੇ ਰੱਖਿਅਤ ਕਰੋ</translation>
+<translation id="8627040765059109009">ਸਕà©à¨°à©€à¨¨ ਕੈਪਚਰ ਮà©à©œ-ਚਾਲੂ ਕੀਤਾ ਗਿਆ</translation>
<translation id="8657078576661269990">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਨੇ <ph name="ORIGIN_NAME" /> ਤੋਂ <ph name="VM_NAME_1" /> ਅਤੇ <ph name="VM_NAME_2" /> ਨਾਲ ਸਾਂà¨à¨¾ ਕਰਨ ਦੀ ਸà©à¨µà¨¿à¨§à¨¾ ਨੂੰ ਬਲਾਕ ਕਰ ਦਿੱਤਾ ਹੈ</translation>
<translation id="8663226718884576429">ਆਰਡਰ ਸਾਰਾਂਸ਼, <ph name="TOTAL_LABEL" />, ਹੋਰ ਵੇਰਵੇ</translation>
<translation id="867224526087042813">ਹਸਤਾਖਰ</translation>
@@ -1931,6 +1975,7 @@
<translation id="8912362522468806198">Google ਖਾਤਾ</translation>
<translation id="8913778647360618320">'ਭà©à¨—ਤਾਨ ਵਿਧੀਆਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ' ਬਟਨ, Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੇ ਭà©à¨—ਤਾਨਾਂ ਅਤੇ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ ਜਾਣਕਾਰੀ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="8918231688545606538">ਇਹ ਪੰਨਾ ਸ਼ੱਕੀ ਹੈ</translation>
+<translation id="8922013791253848639">ਇਸ ਸਾਈਟ 'ਤੇ ਹਮੇਸ਼ਾ ਵਿਗਿਆਪਨਾਂ ਨੂੰ ਇਜਾਜ਼ਤ ਦਿਓ</translation>
<translation id="892588693504540538">ਉੱਪਰ ਸੱਜੇ ਪਾਸੇ ਮੋਰੀ</translation>
<translation id="8931333241327730545">ਕੀ ਤà©à¨¸à©€à¨‚ ਇਸ ਕਾਰਡ ਨੂੰ ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਚਾਹà©à©°à¨¦à©‡ ਹੋ?</translation>
<translation id="8932102934695377596">ਤà©à¨¹à¨¾à¨¡à©€ ਘੜੀ ਪਿੱਛੇ ਹੈ</translation>
@@ -1999,9 +2044,10 @@
<translation id="917450738466192189">ਸਰਵਰ ਦਾ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਅਵੈਧ ਹੈ।</translation>
<translation id="9174917557437862841">ਟੈਬ ਬਦਲਣ ਦਾ ਬਟਨ, ਇਸ ਟੈਬ 'ਤੇ ਜਾਣ ਲਈ à¨à¨‚ਟਰ ਦਬਾਓ</translation>
<translation id="9179703756951298733">Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੇ ਭà©à¨—ਤਾਨਾਂ ਅਤੇ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
-<translation id="9183302530794969518">Google ਡੌਕਸ</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ਇੱਕ ਅਸਮਰਥਿਤ ਪà©à¨°à©‹à¨Ÿà©‹à¨•à©‹à¨² ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ।</translation>
<translation id="9191834167571392248">ਹੇਠਾਂ ਖੱਬੇ ਪਾਸੇ ਮੋਰੀ</translation>
+<translation id="9199905725844810519">ਪà©à¨°à¨¿à©°à¨Ÿ ਕਰਨਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ</translation>
<translation id="9205078245616868884">ਤà©à¨¹à¨¾à¨¡à¨¾ ਡਾਟਾ ਤà©à¨¹à¨¾à¨¡à©‡ ਸਮਕਾਲੀਕਰਨ ਪਾਸਫਰੇਜ਼ ਨਾਲ ਇਨਕà©à¨°à¨¿à¨ªà¨Ÿ ਕੀਤਾ ਗਿਆ ਹੈ। ਸਮਕਾਲੀਕਰਨ ਸ਼à©à¨°à©‚ ਕਰਨ ਲਈ ਇਸਨੂੰ ਦਾਖਲ ਕਰੋ।</translation>
<translation id="9207861905230894330">ਲੇਖ ਜੋੜਨ ਵਿੱਚ ਅਸਫਲ।</translation>
<translation id="9213433120051936369">ਦਿੱਖ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ</translation>
@@ -2012,8 +2058,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">ਤà©à¨¸à©€à¨‚ ਆਪਣੇ Google ਖਾਤੇ ਤੱਕ ਪਹà©à©°à¨š ਗà©à¨† ਸਕਦੇ ਹੋ। Chromium ਵੱਲੋਂ ਹà©à¨£à©‡ ਤà©à¨¹à¨¾à¨¡à¨¾ ਪਾਸਵਰਡ ਬਦਲਣ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਤà©à¨¹à¨¾à¨¨à©‚à©° ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।</translation>
<translation id="939736085109172342">ਨਵਾਂ ਫੋਲਡਰ</translation>
+<translation id="945522503751344254">ਪà©à¨°à¨¤à©€à¨•à¨°à¨® ਭੇਜੋ</translation>
<translation id="945855313015696284">ਹੇਠਾਂ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਦੀ ਜਾਂਚ ਕਰਕੇ ਕੋਈ ਵੀ ਅਵੈਧ ਕਾਰਡ ਮਿਟਾਓ</translation>
<translation id="950736567201356821">ਉੱਪਰ ਤਿੰਨ ਮੋਰੀਆਂ</translation>
+<translation id="951941430552851965">ਤà©à¨¹à¨¾à¨¡à©€ ਸਕà©à¨°à©€à¨¨ 'ਤੇ ਸਮੱਗਰੀ ਹੋਣ ਕਾਰਨ ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਵੱਲੋਂ ਸਕà©à¨°à©€à¨¨ ਕੈਪਚਰ ਨੂੰ ਰੋਕਿਆ ਗਿਆ।</translation>
<translation id="961663415146723894">ਹੇਠਾਂ ਜਿਲਦਬੰਦ</translation>
<translation id="962484866189421427">ਇਹ ਸਮੱਗਰੀ ਭਰਮਪੂਰਨ à¨à¨ªà¨¾à¨‚ ਨੂੰ ਸਥਾਪਤ ਕਰ ਸਕਦੀ ਹੈ, ਜੋ ਕà©à¨ ਹੋਰ ਹੋਣ ਦਾ ਦਾਅਵਾ ਕਰਦੀਆਂ ਹਨ ਜਾਂ ਅਜਿਹਾ ਡਾਟਾ ਇਕੱਠਾ ਕਰਦੀਆਂ ਹਨ ਜਿਸਦੀ ਵਰਤੋਂ ਨਾਲ ਤà©à¨¹à¨¾à¨¡à©‡ 'ਤੇ ਨਜ਼ਰ ਰੱਖੀ ਜਾ ਸਕਦੀ ਹੈ। <ph name="BEGIN_LINK" />ਫਿਰ ਵੀ ਦਿਖਾਓ<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ਅਧਿਕਾਰਿਤ ਬਿਲਡ</translation>
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index 3ceb0dd2691..5655f9c0b81 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -80,6 +80,14 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Wpisałeś swoje hasło na stronie, którą nie zarządza Twoja organizacja. Aby chronić konto, nie używaj swojego hasła w innych aplikacjach ani na innych stronach.</translation>
<translation id="1263231323834454256">Do przeczytania</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Działania, które nie zostaną zapisane na tym urządzeniu:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />strony wyświetlane w tym oknie,
+ <ph name="LIST_ITEM" />pliki cookie i dane witryn,
+ <ph name="LIST_ITEM" />informacje o koncie (<ph name="LINK_BEGIN" />wyloguj się<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Metoda odbioru</translation>
<translation id="1281476433249504884">Układarka 1</translation>
<translation id="1285320974508926690">Nigdy nie tłumacz tej witryny</translation>
@@ -176,7 +184,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1592005682883173041">Lokalny dostęp do danych</translation>
<translation id="1594030484168838125">Wybierz</translation>
<translation id="161042844686301425">Cyjan</translation>
-<translation id="1620510694547887537">Kamera</translation>
+<translation id="1620510694547887537">Aparat</translation>
<translation id="1623104350909869708">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie</translation>
<translation id="16338877384480380">Architecture-B</translation>
<translation id="1634828734222219955">Suma</translation>
@@ -279,6 +287,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="204357726431741734">Zaloguj się, by używać haseł zapisanych na Twoim koncie Google</translation>
<translation id="2053111141626950936">Strony w tym języku (<ph name="LANGUAGE" />) nie będą tłumaczone.</translation>
<translation id="2053553514270667976">Kod pocztowy</translation>
+<translation id="2054665754582400095">Twoja obecność</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 podpowiedź}few{# podpowiedzi}many{# podpowiedzi}other{# podpowiedzi}}</translation>
<translation id="2079545284768500474">Cofnij</translation>
<translation id="20817612488360358">Skonfigurowano używanie systemowych ustawień proxy, ale podano też jawną konfigurację proxy.</translation>
@@ -292,6 +301,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2102495993840063010">Aplikacje na Androida</translation>
<translation id="2107021941795971877">Elementy pomocnicze drukowania</translation>
<translation id="2108755909498034140">Uruchom ponownie komputer</translation>
+<translation id="2111166930115883695">Naciśnij spację, by zacząć grać</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Ignorowana, ponieważ jest zastąpiona przez <ph name="POLICY_NAME" />.</translation>
@@ -303,6 +313,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="214556005048008348">Anuluj płatność</translation>
<translation id="2147827593068025794">Synchronizacja w tle</translation>
<translation id="2148613324460538318">Dodaj kartÄ™</translation>
+<translation id="2149968176347646218">Połączenie nie jest bezpieczne</translation>
<translation id="2154054054215849342">Synchronizacja nie jest dostępna w Twojej domenie.</translation>
<translation id="2154484045852737596">Edytowanie karty</translation>
<translation id="2161656808144014275">Tekstowe</translation>
@@ -313,7 +324,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2181821976797666341">Zasady</translation>
<translation id="2183608646556468874">Numer telefonu</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}few{# adresy}many{# adresów}other{# adresu}}</translation>
-<translation id="2187243482123994665">Obecność użytkownika</translation>
<translation id="2187317261103489799">Wykrywaj (domyślnie)</translation>
<translation id="2188375229972301266">Wiele otworów na dole</translation>
<translation id="2202020181578195191">Wpisz rok w prawidłowym formacie</translation>
@@ -466,6 +476,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2839501879576190149">Wchodzisz na fałszywą stronę</translation>
<translation id="2850739647070081192">Invite (koperta)</translation>
<translation id="2856444702002559011">Osoby atakujące mogą próbować wykraść Twoje informacje ze strony <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na przykład hasła, wiadomości lub dane kart kredytowych). <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Na tej stronie wyświetlają się uciążliwe lub wprowadzające w błąd reklamy.</translation>
<translation id="2878197950673342043">Składanie krzyżowe</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Rozmieszczenie okien</translation>
@@ -504,11 +515,11 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2996674880327704673">Sugestie Google</translation>
<translation id="3002501248619246229">Sprawdź nośnik na tacy wejściowej</translation>
<translation id="3005723025932146533">Pokaż zapisaną kopię</translation>
-<translation id="3007719053326478567">Administrator zablokował drukowanie tej zawartości</translation>
<translation id="3008447029300691911">Wpisz kod CVC karty <ph name="CREDIT_CARD" />. Po potwierdzeniu szczegółowe dane karty zostaną udostępnione tej stronie.</translation>
<translation id="3010559122411665027">Pozycja listy „<ph name="ENTRY_INDEX" />â€: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatycznie zablokowane</translation>
<translation id="3016780570757425217">Sprawdzanie Twojej lokalizacji</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Aby usunąć sugestię, naciśnij Tab, a potem Enter.</translation>
<translation id="3023071826883856138">You4 (koperta)</translation>
<translation id="3024663005179499861">Nieprawidłowy typ zasady</translation>
<translation id="3037605927509011580">Kurza twarz!</translation>
@@ -551,6 +562,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3207960819495026254">Dodano do zakładek</translation>
<translation id="3209034400446768650">Strona może powodować naliczanie opłat</translation>
<translation id="3212581601480735796">Twoja aktywność związana z hostem <ph name="HOSTNAME" /> jest monitorowana</translation>
+<translation id="3212623355668894776">Zamknij wszystkie okna w trybie gościa, aby usunąć z tego urządzenia swoją aktywność związaną z przeglądaniem.</translation>
<translation id="3215092763954878852">Nie udało się użyć WebAuthn</translation>
<translation id="3218181027817787318">Względna</translation>
<translation id="3225919329040284222">Serwer przedstawił certyfikat, który nie pasuje do zaprogramowanych oczekiwań. Oczekiwania mają chronić Cię w określonych witrynach o wysokim poziomie zabezpieczeń.</translation>
@@ -698,6 +710,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3784372983762739446">Lista urządzeń</translation>
<translation id="3787705759683870569">Wygasa: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Rozmiar 16</translation>
+<translation id="3789841737615482174">Zainstaluj</translation>
<translation id="3793574014653384240">Liczba i przyczyny niedawnych awarii</translation>
<translation id="3797522431967816232">Prc3 (koperta)</translation>
<translation id="3799805948399000906">Zażądano czcionki</translation>
@@ -748,6 +761,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Klucz „<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (koperta)</translation>
+<translation id="4067669230157909013">Przechwytywanie ekranu zostało wznowione.</translation>
<translation id="4067947977115446013">Dodaj poprawny adres</translation>
<translation id="4072486802667267160">Podczas przetwarzania zamówienia wystąpił błąd. Spróbuj ponownie.</translation>
<translation id="4075732493274867456">Klient i serwer nie obsługują wspólnej wersji protokołu SSL lub mechanizmu szyfrowania.</translation>
@@ -828,6 +842,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4297502707443874121">Miniatura strony <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Rozwiń</translation>
<translation id="4300675098767811073">Wiele otworów z prawej strony</translation>
+<translation id="4302514097724775343">Kliknij dinozaura, by zacząć grać</translation>
<translation id="4302965934281694568">Chou3 (koperta)</translation>
<translation id="4305666528087210886">Nie udało się uzyskać dostępu do pliku</translation>
<translation id="4305817255990598646">Przełącz</translation>
@@ -906,6 +921,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4658638640878098064">Zszywka w lewym górnym rogu</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Rzeczywistość wirtualna</translation>
+<translation id="4675657451653251260">W trybie gościa nie będą widoczne informacje z żadnego profilu Chrome. Aby uzyskać dostęp do informacji ze swojego konta Google, np. haseł czy form płatności, możesz się <ph name="LINK_BEGIN" />zalogować<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa ma błędy. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="4677585247300749148"><ph name="URL" /> chce odpowiadać na zdarzenia dotyczące ułatwień dostępu</translation>
<translation id="467809019005607715">Prezentacje Google</translation>
@@ -933,6 +949,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4761104368405085019">Korzystanie z Twojego mikrofonu</translation>
<translation id="4764776831041365478">Strona internetowa pod adresem <ph name="URL" /> może być tymczasowo niedostępna lub została na stałe przeniesiona pod nowy adres internetowy.</translation>
<translation id="4766713847338118463">Dwie zszywki na dole</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Twoje działania, które zostaną zapisane na tym urządzeniu:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />wszystkie pliki pobrane w tym oknie.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Wystąpił nieznany błąd.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Zablokowano wyskakujące okienko}few{Zablokowano # wyskakujące okienka}many{Zablokowano # wyskakujących okienek}other{Zablokowano # wyskakującego okienka}}</translation>
<translation id="4780366598804516005">Zestaw tac odbiorczych 1</translation>
@@ -1095,11 +1117,13 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5386426401304769735">ÅaÅ„cuch certyfikatów tej witryny zawiera certyfikat podpisany za pomocÄ… SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Zszywanie przy prawej krawędzi</translation>
+<translation id="5398772614898833570">Reklamy zostały zablokowane</translation>
<translation id="5400836586163650660">Szary</translation>
<translation id="540969355065856584">Ten serwer nie może udowodnić, że należy do domeny <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest obecnie ważny. Może to być spowodowane nieprawidłową konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="541416427766103491">Układarka 4</translation>
<translation id="5421136146218899937">Wyczyść dane przeglądania...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> chce wysyłać Ci powiadomienia</translation>
+<translation id="542872847390508405">Przeglądasz jako gość</translation>
<translation id="5430298929874300616">Usuń zakładkę</translation>
<translation id="5439770059721715174">BÅ‚Ä…d podczas sprawdzania poprawnoÅ›ci schematu – „<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Kolejność odwrotna, strona do drukowania skierowana w górę</translation>
@@ -1141,12 +1165,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5571083550517324815">Odbiór spod tego adresu jest niemożliwy. Wybierz inny adres.</translation>
<translation id="5580958916614886209">Sprawdź miesiąc ważności i spróbuj ponownie</translation>
<translation id="5586446728396275693">Brak zapisanych adresów</translation>
+<translation id="5593349413089863479">Połączenie nie jest całkiem bezpieczne</translation>
<translation id="5595485650161345191">Edytuj adres</translation>
<translation id="5598944008576757369">Wybierz formę płatności</translation>
<translation id="560412284261940334">Zarządzanie jest nieobsługiwane</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Ta strona może być fałszywa. Chrome zaleca jej natychmiastowe opuszczenie.</translation>
<translation id="5610142619324316209">Sprawdź połączenie</translation>
<translation id="5610807607761827392">Możesz zarządzać kartami i adresami w <ph name="BEGIN_LINK" />Ustawieniach<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Przetłumacz tę stronę w Tłumaczu Google</translation>
@@ -1218,6 +1242,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5901630391730855834">Żółty</translation>
<translation id="5905445707201418379">Zablokowano zgodnie z zasadami dotyczącymi źródła obowiązującymi w przypadku strony <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (zsynchronizowane)</translation>
+<translation id="5913377024445952699">Przechwytywanie ekranu zostało wstrzymane</translation>
<translation id="59174027418879706">WÅ‚Ä…czony</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">włączono</translation>
@@ -1230,6 +1255,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5963413905009737549">Sekcja</translation>
<translation id="5967592137238574583">Edytuj dane kontaktowe</translation>
<translation id="5967867314010545767">Usuń z historii</translation>
+<translation id="5968793460449681917">Podczas każdej wizyty</translation>
<translation id="5975083100439434680">Pomniejsz</translation>
<translation id="5979084224081478209">Sprawdź hasła</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1385,6 +1411,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6587923378399804057">Skopiowany link</translation>
<translation id="6591833882275308647">Twoje urzÄ…dzenie <ph name="DEVICE_TYPE" /> nie jest zarzÄ…dzane</translation>
<translation id="6596325263575161958">Opcje szyfrowania</translation>
+<translation id="6596892391065203054">Administrator zablokował drukowanie tej zawartości.</translation>
<translation id="6604181099783169992">Czujniki ruchu lub światła</translation>
<translation id="6609880536175561541">Prc7 (koperta)</translation>
<translation id="6612358246767739896">Treść chroniona</translation>
@@ -1444,6 +1471,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6895330447102777224">Karta została potwierdzona</translation>
<translation id="6897140037006041989">Klient</translation>
<translation id="6898699227549475383">Organizacja (O)</translation>
+<translation id="6907293445143367439">Zezwól stronie <ph name="SITE_NAME" /> na:</translation>
<translation id="6910240653697687763"><ph name="URL" /> chce mieć pełny dostęp do sterowania urządzeniami MIDI</translation>
<translation id="6915804003454593391">Użytkownik:</translation>
<translation id="6934672428414710184">To imię i nazwisko pochodzi z Twojego konta Google</translation>
@@ -1555,6 +1583,7 @@ Dodatkowe informacje:
<translation id="7346048084945669753">Jest w tej samej domenie:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Wiersz poleceń</translation>
+<translation id="7359588939039777303">Reklamy zostały zablokowane.</translation>
<translation id="7372973238305370288">wynik wyszukiwania</translation>
<translation id="7374733840632556089">Ten problem pojawia się z powodu certyfikatu zainstalowanego na tym urządzeniu przez Ciebie lub inną osobę. Ten certyfikat jest używany do monitorowania i przechwytywania ruchu sieciowego. Chrome mu nie ufa. Choć w pewnych przypadkach (np. w sieci szkolnej lub firmowej) monitorowanie jest uzasadnione i legalne, Chrome będzie Cię o tym powiadamiać, nawet jeśli nie możesz nic na to poradzić. Monitorowanie może odbywać się w każdej przeglądarce lub aplikacji, która ma dostęp do sieci.</translation>
<translation id="7375818412732305729">Dołączono plik</translation>
@@ -1729,6 +1758,7 @@ Dodatkowe informacje:
<translation id="7976214039405368314">Zbyt wiele żądań</translation>
<translation id="7977538094055660992">Urządzenie wyjściowe</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Aby oglądać treści rzeczywistości rozszerzonej, zainstaluj ARCore</translation>
<translation id="799149739215780103">WiÄ…zanie</translation>
<translation id="7995512525968007366">Nie określono</translation>
<translation id="800218591365569300">Zamknij inne karty lub programy, by zwolnić pamięć.</translation>
@@ -1856,24 +1886,38 @@ Dodatkowe informacje:
<translation id="8507227106804027148">Wiersz poleceń</translation>
<translation id="8508648098325802031">Ikona wyszukiwania</translation>
<translation id="8522552481199248698">Chrome może Ci pomóc w zabezpieczeniu Twojego konta Google i zmianie hasła.</translation>
+<translation id="8525306231823319788">Pełny ekran</translation>
<translation id="8530813470445476232">Wyczyść historię przeglądania, pliki cookie, pamięć podręczną i inne dane w ustawieniach Chrome</translation>
<translation id="8533619373899488139">Wejdź na stronę &lt;strong&gt;chrome://policy&lt;/strong&gt;, by wyświetlić listę zablokowanych adresów URL oraz inne zasady egzekwowane przez administratora systemu.</translation>
<translation id="8541158209346794904">UrzÄ…dzenie Bluetooth</translation>
<translation id="8542014550340843547">Trzy zszywki na dole</translation>
<translation id="8543181531796978784">Możesz <ph name="BEGIN_ERROR_LINK" />zgłosić problem z wykrywaniem<ph name="END_ERROR_LINK" /> lub – jeśli rozumiesz zagrożenie – <ph name="BEGIN_LINK" />wejść na tę niebezpieczną stronę<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Kod CVC znajduje siÄ™ na odwrocie karty.</translation>
+<translation id="8558485628462305855">Aby oglądać treści rzeczywistości rozszerzonej, zaktualizuj ARCore</translation>
<translation id="8559762987265718583">Nie można nawiązać prywatnego połączenia z <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, ponieważ data i godzina (<ph name="DATE_AND_TIME" />) ustawione na urządzeniu są nieprawidłowe.</translation>
<translation id="8564182942834072828">Oddzielne dokumenty / Kopie niesortowane</translation>
<translation id="8564985650692024650">Chromium zaleca zresetowanie hasła, którego używasz w: <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, jeśli zostało użyte na innej stronie.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Działania, które nie zostaną zapisane na tym urządzeniu:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />strony wyświetlane w tym oknie,
+ <ph name="LIST_ITEM" />pliki cookie i dane witryn.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Używaj Touch ID, by szybciej potwierdzać karty</translation>
<translation id="858637041960032120">Dodaj numer telefonu</translation>
<translation id="8589998999637048520">Najlepsza jakość</translation>
+<translation id="8600271352425265729">Tylko tym razem</translation>
<translation id="860043288473659153">ImiÄ™ i nazwisko posiadacza karty</translation>
<translation id="8606726445206553943">Korzystać z urządzeń MIDI</translation>
+<translation id="8612761427948161954">Cześć <ph name="USERNAME" />,
+ <ph name="BR" />
+ przeglądasz jako gość</translation>
<translation id="861775596732816396">Rozmiar 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nie znaleziono pasujących haseł. Pokaż wszystkie zapisane hasła.</translation>
<translation id="8625384913736129811">Zapisz tÄ™ kartÄ™ na tym urzÄ…dzeniu</translation>
+<translation id="8627040765059109009">Przechwytywanie ekranu zostało wznowione</translation>
<translation id="8657078576661269990">Administrator zablokował udostępnianie zawartości z <ph name="ORIGIN_NAME" /> maszynom wirtualnym <ph name="VM_NAME_1" /> i <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Podsumowanie zamówienia, <ph name="TOTAL_LABEL" />, Szczegółowe informacje</translation>
<translation id="867224526087042813">Podpis</translation>
@@ -1936,6 +1980,7 @@ Dodatkowe informacje:
<translation id="8912362522468806198">Konta Google</translation>
<translation id="8913778647360618320">Przycisk zarządzania formami płatności. Naciśnij Enter, by zarządzać informacjami o płatnościach i danymi kart kredytowych w ustawieniach Chrome.</translation>
<translation id="8918231688545606538">Ta strona jest podejrzana</translation>
+<translation id="8922013791253848639">Zawsze zezwalaj na wyświetlanie reklam na tej stronie</translation>
<translation id="892588693504540538">Otwór w prawym górnym rogu</translation>
<translation id="8931333241327730545">Chcesz zapisać tę kartę na swoim koncie Google?</translation>
<translation id="8932102934695377596">Twój zegar się spóźnia</translation>
@@ -2007,6 +2052,7 @@ Dodatkowe informacje:
<translation id="9183302530794969518">Dokumenty Google</translation>
<translation id="9183425211371246419">Serwer <ph name="HOST_NAME" /> używa nieobsługiwanego protokołu.</translation>
<translation id="9191834167571392248">Otwór w lewym dolnym rogu</translation>
+<translation id="9199905725844810519">Drukowanie jest zablokowane</translation>
<translation id="9205078245616868884">Twoje dane są szyfrowane z użyciem hasła synchronizacji. Wpisz je, by rozpocząć synchronizację.</translation>
<translation id="9207861905230894330">Nie udało się dodać artykułu.</translation>
<translation id="9213433120051936369">Dostosuj wyglÄ…d</translation>
@@ -2017,8 +2063,10 @@ Dodatkowe informacje:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Możesz stracić dostęp do swojego konta Google. Chromium zaleca natychmiastową zmianę hasła. Zobaczysz prośbę, by się zalogować.</translation>
<translation id="939736085109172342">Nowy folder</translation>
+<translation id="945522503751344254">Prześlij opinię</translation>
<translation id="945855313015696284">Sprawdź poniższe informacje i usuń karty z błędami</translation>
<translation id="950736567201356821">Trzy otwory u góry</translation>
+<translation id="951941430552851965">Przechwytywanie ekranu zostało wstrzymane przez administratora z powodu wyświetlenia pewnych treści.</translation>
<translation id="961663415146723894">WiÄ…zanie na dole</translation>
<translation id="962484866189421427">Te treści mogą próbować zainstalować wprowadzające w błąd aplikacje, które udają, że są przeznaczone do czegoś innego niż w rzeczywistości, lub zbierają dane, na podstawie których można Cię śledzić. <ph name="BEGIN_LINK" />Pokaż mimo to<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Oficjalna wersja</translation>
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index 1b111fa0f9e..32277f24406 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -80,12 +80,20 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Você informou sua senha em um site que não é gerenciado pela sua organização. Para proteger sua conta, não reutilize sua senha em outros apps e sites.</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Atividades que não serão armazenadas no dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas abertas nesta janela
+ <ph name="LIST_ITEM" />Cookies e dados de sites
+ <ph name="LIST_ITEM" />Informações da conta (<ph name="LINK_BEGIN" />sair<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Método de Retirada</translation>
<translation id="1281476433249504884">Empilhador 1</translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
<translation id="1292701964462482250">"Algum software no seu computador está impedindo o Google Chrome de se conectar com segurança à Web" (somente computadores Windows)</translation>
<translation id="1294154142200295408">Variações de linha de comando</translation>
-<translation id="129553762522093515">Recentemente fechadas</translation>
+<translation id="129553762522093515">Fechadas recentemente</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />Tente limpar os cookies<ph name="END_LINK" /></translation>
<translation id="1301324364792935241">Verifique suas configurações de DNS seguro</translation>
<translation id="1307966114820526988">Recursos obsoletos</translation>
@@ -279,6 +287,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="204357726431741734">Faça login para usar as senhas salvas na sua Conta do Google</translation>
<translation id="2053111141626950936">Páginas em <ph name="LANGUAGE" /> não serão traduzidas.</translation>
<translation id="2053553514270667976">CEP</translation>
+<translation id="2054665754582400095">Sua presença</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}one{# sugestão}other{# sugestões}}</translation>
<translation id="2079545284768500474">Desfazer</translation>
<translation id="20817612488360358">As configurações de proxy do sistema são definidas para serem utilizadas, mas uma configuração explícita de proxy também foi especificada.</translation>
@@ -292,6 +301,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2102495993840063010">Apps Android</translation>
<translation id="2107021941795971877">Compatibilidades de impressão</translation>
<translation id="2108755909498034140">Reiniciar seu computador</translation>
+<translation id="2111166930115883695">Pressione a barra de espaço para jogar</translation>
<translation id="2111256659903765347">Super A</translation>
<translation id="2113977810652731515">Cartão</translation>
<translation id="2114841414352855701">Ignorado porque foi substituído por <ph name="POLICY_NAME" />.</translation>
@@ -303,6 +313,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
<translation id="2148613324460538318">Adicionar Cartão</translation>
+<translation id="2149968176347646218">A conexão não é segura</translation>
<translation id="2154054054215849342">O serviço de sincronização não está disponível para seu domínio</translation>
<translation id="2154484045852737596">Editar cartão</translation>
<translation id="2161656808144014275">Texto</translation>
@@ -313,7 +324,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">Número de telefone</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# endereço}other{# endereços}}</translation>
-<translation id="2187243482123994665">Presença do usuário</translation>
<translation id="2187317261103489799">Detectar (padrão)</translation>
<translation id="2188375229972301266">Perfuração múltipla na parte inferior</translation>
<translation id="2202020181578195191">Informe um ano de validade válido</translation>
@@ -464,6 +474,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2839501879576190149">Site falso</translation>
<translation id="2850739647070081192">Convite (Envelope)</translation>
<translation id="2856444702002559011">Invasores podem estar tentando roubar suas informações de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, senhas, mensagens ou cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Neste site, há exibição de anúncios invasivos ou enganosos</translation>
<translation id="2878197950673342043">Dobra em cruz sanfona</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Posicionamento de janelas</translation>
@@ -502,11 +513,11 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2996674880327704673">Sugestões do Google</translation>
<translation id="3002501248619246229">Verificar mídia de bandeja de entrada</translation>
<translation id="3005723025932146533">Mostrar cópia salva</translation>
-<translation id="3007719053326478567">Seu administrador bloqueou a opção de imprimir este conteúdo</translation>
<translation id="3008447029300691911">Digite o CVC do <ph name="CREDIT_CARD" />. Depois da confirmação, os detalhes do seu cartão serão compartilhados com esse site.</translation>
<translation id="3010559122411665027">Entrada de lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueada automaticamente</translation>
<translation id="3016780570757425217">Saber sua localização</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Pressione "Tab" e depois "Enter" para remover a sugestão.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3037605927509011580">Ah, não!</translation>
@@ -549,6 +560,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3207960819495026254">Adicionado aos favoritos</translation>
<translation id="3209034400446768650">Esta página pode emitir cobranças em dinheiro</translation>
<translation id="3212581601480735796">Sua atividade em <ph name="HOSTNAME" /> está sendo monitorada</translation>
+<translation id="3212623355668894776">Feche todas as janelas de visitante para excluir sua atividade de navegação do dispositivo.</translation>
<translation id="3215092763954878852">Não foi possível usar WebAuthn</translation>
<translation id="3218181027817787318">Relativo</translation>
<translation id="3225919329040284222">O servidor apresentou um certificado que não coincide com as expectativas incorporadas. Estas expectativas são incluídas para determinados websites de alta segurança com a finalidade de oferecer proteção a você.</translation>
@@ -577,7 +589,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3366477098757335611">Ver cartões</translation>
<translation id="3369192424181595722">Erro do relógio</translation>
<translation id="3371076217486966826"><ph name="URL" /> quer:
- • criar um mapa 3D dos seus arredores e acompanhar a posição da câmera;
+ • criar um mapa 3D do ambiente a sua volta e acompanhar a posição da câmera;
• usar a câmera.</translation>
<translation id="337363190475750230">Desprovisionado</translation>
<translation id="3377144306166885718">Versão obsoleta do TLS usada no servidor.</translation>
@@ -619,7 +631,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3487845404393360112">Bandeja 4</translation>
<translation id="3495081129428749620">Encontrar na página
<ph name="PAGE_TITLE" /></translation>
-<translation id="3507936815618196901">Criar um mapa 3D dos seus arredores e acompanhar a posição da câmera</translation>
+<translation id="3507936815618196901">Criar um mapa 3D do ambiente a sua volta e acompanhar a posição da câmera</translation>
<translation id="3512163584740124171">Esta política é ignorada porque outra política do mesmo grupo tem uma prioridade mais alta.</translation>
<translation id="3518941727116570328">Gerenciamento de vários objetos</translation>
<translation id="3528171143076753409">O certificado do servidor não é confiável.</translation>
@@ -696,6 +708,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3784372983762739446">Dispositivos Bluetooth</translation>
<translation id="3787705759683870569">Validade: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamanho 16</translation>
+<translation id="3789841737615482174">Instalar</translation>
<translation id="3793574014653384240">Números e causas das falhas que ocorreram recentemente</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Fonte solicitada</translation>
@@ -746,6 +759,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4056223980640387499">Sépia</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Captura de tela retomada.</translation>
<translation id="4067947977115446013">Adicione um Endereço Válido</translation>
<translation id="4072486802667267160">Ocorreu um erro ao processar seu pedido. Tente novamente.</translation>
<translation id="4075732493274867456">O cliente e o servidor não são compatíveis com uma versão do protocolo SSL comum ou com o pacote de criptografia.</translation>
@@ -826,6 +840,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4297502707443874121">Miniatura da página <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expandir</translation>
<translation id="4300675098767811073">Perfuração múltipla do lado direito</translation>
+<translation id="4302514097724775343">Toque no dinossauro para jogar</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Não foi possível acessar seu arquivo</translation>
<translation id="4305817255990598646">Alternar</translation>
@@ -904,6 +919,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4658638640878098064">Grampo na parte superior direita</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realidade virtual</translation>
+<translation id="4675657451653251260">Você não verá informações de perfis do Chrome no modo visitante. <ph name="LINK_BEGIN" />Faça login<ph name="LINK_END" /> para acessar informações da sua Conta do Google, como senhas e formas de pagamento.</translation>
<translation id="467662567472608290">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança contém erros. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="4677585247300749148"><ph name="URL" /> quer responder a eventos de acessibilidade</translation>
<translation id="467809019005607715">Apresentações Google</translation>
@@ -931,6 +947,12 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4761104368405085019">Usar microfone</translation>
<translation id="4764776831041365478">A página <ph name="URL" /> pode estar temporariamente indisponível ou pode ter sido movida permanentemente para um novo endereço da Web.</translation>
<translation id="4766713847338118463">Dois grampos na parte inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Atividades que serão armazenadas no dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Arquivos transferidos por download nesta janela
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up bloqueado}one{# pop-up bloqueado}other{# pop-ups bloqueados}}</translation>
<translation id="4780366598804516005">Caixa de e-mails 1</translation>
@@ -1093,11 +1115,13 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5386426401304769735">A cadeia de certificados desse site contém um certificado assinado usando SHA-1.</translation>
<translation id="538659543871111977">A4 Tab</translation>
<translation id="5396631636586785122">Costura no lado direito</translation>
+<translation id="5398772614898833570">Anúncios bloqueados</translation>
<translation id="5400836586163650660">Cinza</translation>
<translation id="540969355065856584">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele não é válido no momento. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="541416427766103491">Empilhador 4</translation>
<translation id="5421136146218899937">Limpar dados de navegação...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> quer enviar notificações a você</translation>
+<translation id="542872847390508405">Você está navegando como visitante</translation>
<translation id="5430298929874300616">Remover favorito</translation>
<translation id="5439770059721715174">Erro de validação de esquema em "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordem reversa virada para cima</translation>
@@ -1139,12 +1163,12 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5571083550517324815">Não é possível fazer a retirada nesse endereço. Tente um endereço diferente.</translation>
<translation id="5580958916614886209">Verifique o mês de validade e tente novamente</translation>
<translation id="5586446728396275693">Nenhum endereço salvo</translation>
+<translation id="5593349413089863479">A conexão não é totalmente segura</translation>
<translation id="5595485650161345191">Editar endereço</translation>
<translation id="5598944008576757369">Escolher forma de pagamento</translation>
<translation id="560412284261940334">Gerenciamento não suportado</translation>
<translation id="5605670050355397069">Tabloide</translation>
<translation id="5607240918979444548">Arch C</translation>
-<translation id="5608165884683734521">Este site pode ser falso ou conter fraude. O Chrome recomenda sair imediatamente.</translation>
<translation id="5610142619324316209">Verificar a conexão</translation>
<translation id="5610807607761827392">É possível gerenciar cartões e endereços em <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduza esta página com o Google Tradutor</translation>
@@ -1216,6 +1240,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5901630391730855834">Amarelo</translation>
<translation id="5905445707201418379">Bloqueado de acordo com a política de origem de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizado)</translation>
+<translation id="5913377024445952699">Captura de tela pausada</translation>
<translation id="59174027418879706">Ativado</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ativado</translation>
@@ -1228,6 +1253,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5963413905009737549">Seção</translation>
<translation id="5967592137238574583">Edite as Informações de Contato</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
+<translation id="5968793460449681917">Em todos os acessos</translation>
<translation id="5975083100439434680">Diminuir zoom</translation>
<translation id="5979084224081478209">Verificar senhas</translation>
<translation id="5980920751713728343">76 mm x 127 mm</translation>
@@ -1383,6 +1409,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6587923378399804057">Link que você copiou</translation>
<translation id="6591833882275308647">Seu <ph name="DEVICE_TYPE" /> não é gerenciado</translation>
<translation id="6596325263575161958">Opções de criptografia</translation>
+<translation id="6596892391065203054">Seu administrador bloqueou a opção de imprimir este conteúdo.</translation>
<translation id="6604181099783169992">Sensores de luz ou movimento</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Conteúdo protegido</translation>
@@ -1411,7 +1438,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6710594484020273272">&lt;Digitar termo de pesquisa&gt;</translation>
<translation id="671076103358959139">Token de inscrição:</translation>
<translation id="6711464428925977395">Há algo errado com o servidor proxy, ou o endereço está incorreto.</translation>
-<translation id="6716672519412350405"><ph name="URL" /> quer criar um mapa 3D dos seus arredores e acompanhar a posição da câmera</translation>
+<translation id="6716672519412350405"><ph name="URL" /> quer criar um mapa 3D do ambiente a sua volta e acompanhar a posição da câmera</translation>
<translation id="6718612893943028815">Usar a câmera?</translation>
<translation id="6738516213925468394">Seus dados foram criptografados com sua <ph name="BEGIN_LINK" />senha longa de sincronização<ph name="END_LINK" /> em <ph name="TIME" />. Digite-a para iniciar a sincronização.</translation>
<translation id="674375294223700098">Erro, certificado de servidor desconhecido.</translation>
@@ -1442,6 +1469,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6895330447102777224">Seu cartão foi confirmado</translation>
<translation id="6897140037006041989">Agente do usuário</translation>
<translation id="6898699227549475383">O (Organização)</translation>
+<translation id="6907293445143367439">Permitir que <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> quer ter controle total sobre seus dispositivos MIDI</translation>
<translation id="6915804003454593391">Usuário:</translation>
<translation id="6934672428414710184">Este nome é da sua Conta do Google</translation>
@@ -1553,6 +1581,7 @@ Mais detalhes:
<translation id="7346048084945669753">O usuário é afiliado:</translation>
<translation id="7349430561505560861">A4 Extra</translation>
<translation id="7353601530677266744">Linha de comando</translation>
+<translation id="7359588939039777303">Anúncios bloqueados.</translation>
<translation id="7372973238305370288">resultado da pesquisa</translation>
<translation id="7374733840632556089">Esse problema acontece devido a um certificado que você ou outra pessoa instalou no dispositivo. O certificado é conhecido por ser usado para monitorar e interceptar redes, e o Chrome não o considera confiável. Embora casos legítimos de monitoramento existam, como em redes de escolas ou empresas, o Chrome quer ter certeza de que você está ciente de tudo o que está acontecendo, mesmo que você não possa fazer nada para impedir isso. O monitoramento pode acontecer em qualquer navegador ou aplicativo que acesse a Web.</translation>
<translation id="7375818412732305729">Um arquivo é anexado</translation>
@@ -1721,12 +1750,13 @@ Mais detalhes:
<translation id="7951415247503192394">32 bits</translation>
<translation id="7953569069500808819">Costura na parte superior</translation>
<translation id="7954523986259449736">Como o site está usando uma conexão que não é inteiramente segura, suas informações ficarão visíveis para outras pessoas.</translation>
-<translation id="7956713633345437162">Favoritos de dispositivos móveis</translation>
+<translation id="7956713633345437162">Favoritos nos dispositivos móveis</translation>
<translation id="7961015016161918242">Nunca</translation>
<translation id="7966803981046576691">Tipo de conta da tarefa</translation>
<translation id="7976214039405368314">Excesso de solicitações</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Para ver conteúdo de realidade aumentada, instale o ARCore</translation>
<translation id="799149739215780103">Encadernar</translation>
<translation id="7995512525968007366">Não especificado</translation>
<translation id="800218591365569300">Tente fechar outras guias ou programas para liberar memória.</translation>
@@ -1839,7 +1869,7 @@ Mais detalhes:
<translation id="8438786541497918448">Usar a câmera e o microfone?</translation>
<translation id="8446884382197647889">Saiba mais</translation>
<translation id="8457125768502047971">Indefinida</translation>
-<translation id="8461694314515752532">Criptografar dados sincronizados com sua senha de sincronização</translation>
+<translation id="8461694314515752532">Criptografar dados sincronizados com sua própria senha longa de sincronização</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 cartão de crédito}one{# cartão de crédito}other{# cartões de crédito}}</translation>
<translation id="8473863474539038330">Endereços e mais</translation>
<translation id="8474910779563686872">Mostrar detalhes do desenvolvedor</translation>
@@ -1854,25 +1884,39 @@ Mais detalhes:
<translation id="8507227106804027148">Linha de comando</translation>
<translation id="8508648098325802031">Ãcone de pesquisa</translation>
<translation id="8522552481199248698">No Chrome, você pode receber ajuda para proteger sua Conta do Google e alterar sua senha.</translation>
+<translation id="8525306231823319788">Tela cheia</translation>
<translation id="8530813470445476232">Limpe o histórico de navegação, os cookies, o cache e muito mais nas configurações do Chrome</translation>
<translation id="8533619373899488139">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista de URLs bloqueados e outras políticas aplicadas pelo administrador do seu sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Três grampos na parte inferior</translation>
<translation id="8543181531796978784">Você pode <ph name="BEGIN_ERROR_LINK" />denunciar um problema de detecção<ph name="END_ERROR_LINK" /> ou, se entende os riscos à sua segurança, <ph name="BEGIN_LINK" />acessar este site não seguro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">O CVC está localizado atrás do seu cartão.</translation>
+<translation id="8558485628462305855">Para ver conteúdo de realidade aumentada, atualize o ARCore</translation>
<translation id="8559762987265718583">Não é possível estabelecer uma conexão privada com <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do seu dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas.</translation>
<translation id="8564182942834072828">Documentos separados/Cópias não reunidas</translation>
<translation id="8564985650692024650">O Chromium recomenda redefinir sua senha de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se você a reutilizou em outros sites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Atividades que não serão armazenadas no dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas abertas nesta janela
+ <ph name="LIST_ITEM" />Cookies e dados de sites
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Use o Touch ID para confirmar seus cartões mais rapidamente</translation>
<translation id="858637041960032120">Ad. nº. telefone
</translation>
<translation id="8589998999637048520">Melhor qualidade</translation>
+<translation id="8600271352425265729">Apenas desta vez</translation>
<translation id="860043288473659153">Nome do titular do cartão</translation>
<translation id="8606726445206553943">Usar seus dispositivos MIDI</translation>
+<translation id="8612761427948161954">Olá, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Você está navegando como visitante</translation>
<translation id="861775596732816396">Tamanho 4</translation>
<translation id="8622948367223941507">Legal extra</translation>
<translation id="8623885649813806493">Não achamos uma senha. Mostrar todas as senhas salvas.</translation>
<translation id="8625384913736129811">Salvar este cartão neste dispositivo</translation>
+<translation id="8627040765059109009">Captura de tela retomada</translation>
<translation id="8657078576661269990">O administrador bloqueou o compartilhamento de <ph name="ORIGIN_NAME" /> com <ph name="VM_NAME_1" /> e <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Resumo do pedido, <ph name="TOTAL_LABEL" />, Mais detalhes</translation>
<translation id="867224526087042813">Assinatura</translation>
@@ -1923,7 +1967,7 @@ Mais detalhes:
<translation id="8866481888320382733">Configurações da política de análise de erros</translation>
<translation id="8866928039507595380">Dobrar</translation>
<translation id="886872106311861689">B3</translation>
-<translation id="8870413625673593573">Recentemente fechadas</translation>
+<translation id="8870413625673593573">Fechadas recentemente</translation>
<translation id="8870494189203302833">Mesma ordem virada para baixo</translation>
<translation id="8874824191258364635">Informe um número de cartão válido</translation>
<translation id="8891727572606052622">Modo de proxy inválido.</translation>
@@ -1935,6 +1979,7 @@ Mais detalhes:
<translation id="8912362522468806198">Conta do Google</translation>
<translation id="8913778647360618320">Botão "Gerenciar formas de pagamento". Pressione "Enter" para gerenciar suas informações de pagamento e de cartão de crédito nas configurações do Chrome</translation>
<translation id="8918231688545606538">Esta página é suspeita</translation>
+<translation id="8922013791253848639">Sempre permitir anúncios neste site</translation>
<translation id="892588693504540538">Perfuração na parte superior direita</translation>
<translation id="8931333241327730545">Quer salvar este cartão na sua Conta do Google?</translation>
<translation id="8932102934695377596">Seu relógio está atrasado</translation>
@@ -2007,6 +2052,7 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="9183302530794969518">Documentos Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> usa um protocolo incompatível.</translation>
<translation id="9191834167571392248">Perfuração na parte inferior esquerda</translation>
+<translation id="9199905725844810519">A impressão foi bloqueada</translation>
<translation id="9205078245616868884">Seus dados são criptografados com sua senha longa de sincronização. Informe-a para começar a sincronização.</translation>
<translation id="9207861905230894330">Falha ao adicionar artigo.</translation>
<translation id="9213433120051936369">Personalizar aparência</translation>
@@ -2017,8 +2063,10 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="936474030629450166">Super B</translation>
<translation id="936602727769022409">Você pode perder o acesso à sua Conta do Google. O Chromium recomenda que sua senha seja alterada agora. Solicitaremos que você faça login.</translation>
<translation id="939736085109172342">Nova pasta</translation>
+<translation id="945522503751344254">Enviar comentários</translation>
<translation id="945855313015696284">Verifique as informações abaixo e exclua todos os cartões inválidos</translation>
<translation id="950736567201356821">Perfuração tripla na parte superior</translation>
+<translation id="951941430552851965">A captura de tela foi pausada pelo administrador devido ao conteúdo exibido.</translation>
<translation id="961663415146723894">Encadernação na parte inferior</translation>
<translation id="962484866189421427">Este conteúdo pode tentar instalar apps enganosos que fingem ser outra coisa ou coletam dados que podem ser usados para rastrear você. <ph name="BEGIN_LINK" />Mostrar mesmo assim<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Versão oficial</translation>
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index 0d679846869..29c17140b3b 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -80,6 +80,14 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Introduziu a palavra-passe num site que não é gerido pela sua organização. Para proteger a conta, não reutilize a sua palavra-passe noutras aplicações e sites.</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Atividade que não é mantida neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas que vê nesta janela.
+ <ph name="LIST_ITEM" />Cookies e dados de sites.
+ <ph name="LIST_ITEM" />Informações da conta (<ph name="LINK_BEGIN" />terminar sessão<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Método de recolha</translation>
<translation id="1281476433249504884">Empilhador 1</translation>
<translation id="1285320974508926690">Nunca traduzir este site</translation>
@@ -283,6 +291,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="204357726431741734">Iniciar sessão para utilizar palavras-passe guardadas na sua Conta Google</translation>
<translation id="2053111141626950936">As páginas em <ph name="LANGUAGE" /> não serão traduzidas.</translation>
<translation id="2053553514270667976">Código postal</translation>
+<translation id="2054665754582400095">A sua presença</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}other{# sugestões}}</translation>
<translation id="2079545284768500474">Anular</translation>
<translation id="20817612488360358">As definições de proxy do sistema estão definidas para serem utilizadas, mas também está especificada uma configuração de proxy explícita.</translation>
@@ -296,6 +305,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2102495993840063010">Apps Android</translation>
<translation id="2107021941795971877">Suportes de impressão</translation>
<translation id="2108755909498034140">Reiniciar o computador</translation>
+<translation id="2111166930115883695">Prima a barra de espaço.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Cartão</translation>
<translation id="2114841414352855701">Ignorada porque foi substituída por <ph name="POLICY_NAME" /> .</translation>
@@ -307,6 +317,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
<translation id="2148613324460538318">Adicionar cartão</translation>
+<translation id="2149968176347646218">A ligação não é segura</translation>
<translation id="2154054054215849342">A sincronização não está disponível para o domínio</translation>
<translation id="2154484045852737596">Editar cartão</translation>
<translation id="2161656808144014275">Texto</translation>
@@ -317,7 +328,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">Número de telefone</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}other{# endereços}}</translation>
-<translation id="2187243482123994665">Presença do utilizador</translation>
<translation id="2187317261103489799">Detetar (predefinição)</translation>
<translation id="2188375229972301266">Perfuração múltipla na parte inferior</translation>
<translation id="2202020181578195191">Introduza um ano de expiração válido</translation>
@@ -470,6 +480,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2839501879576190149">O site seguinte é falso</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Os atacantes poderão estar a tentar roubar as suas informações de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, palavras-passe, mensagens ou cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Este site apresenta anúncios intrusivos ou enganadores.</translation>
<translation id="2878197950673342043">Dobra cruzada</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Posicionamento de janelas</translation>
@@ -508,11 +519,11 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2996674880327704673">Sugestões da Google</translation>
<translation id="3002501248619246229">Verificar o suporte do tabuleiro de entrada</translation>
<translation id="3005723025932146533">Mostrar cópia guardada</translation>
-<translation id="3007719053326478567">A impressão deste conteúdo está bloqueada pelo seu administrador.</translation>
<translation id="3008447029300691911">Introduza o Código de Segurança/CVC de <ph name="CREDIT_CARD" />. Ao confirmar, os detalhes do cartão são partilhados com este site.</translation>
<translation id="3010559122411665027">Entrada da lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueada automaticamente</translation>
<translation id="3016780570757425217">Conhecer a sua localização</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, prima Tab e, em seguida Enter para remover a sugestão.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Tipo de política incorreto</translation>
<translation id="3037605927509011580">Ah, bolas!!</translation>
@@ -555,6 +566,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3207960819495026254">Adicionado aos marcadores</translation>
<translation id="3209034400446768650">A página pode efetuar cobranças</translation>
<translation id="3212581601480735796">A sua atividade em <ph name="HOSTNAME" /> está a ser monitorizada</translation>
+<translation id="3212623355668894776">Feche todas as janelas de convidado para que a sua atividade de navegação seja eliminada neste dispositivo.</translation>
<translation id="3215092763954878852">Não foi possível utilizar o WebAuthn</translation>
<translation id="3218181027817787318">Relativa</translation>
<translation id="3225919329040284222">O servidor apresentou um certificado que não corresponde às expectativas existentes. Estas expectativas são incluídas para determinados Web sites de alta segurança para sua proteção.</translation>
@@ -702,6 +714,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3784372983762739446">Dispositivos Bluetooth</translation>
<translation id="3787705759683870569">Expira a <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Tamanho 16</translation>
+<translation id="3789841737615482174">Instalar</translation>
<translation id="3793574014653384240">Números e causas das falhas de sistema que ocorreram recentemente.</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Tipo de letra solicitado</translation>
@@ -753,6 +766,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4056223980640387499">Sépia</translation>
<translation id="4058922952496707368">Chave "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">A captura de ecrã foi retomada.</translation>
<translation id="4067947977115446013">Adicionar endereço válido</translation>
<translation id="4072486802667267160">Ocorreu um erro ao processar a sua encomenda. Tente novamente.</translation>
<translation id="4075732493274867456">O cliente e o servidor não suportam uma versão do protocolo SSL ou um conjunto de cifras comum.</translation>
@@ -837,6 +851,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4297502707443874121">Miniatura da página <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expandir</translation>
<translation id="4300675098767811073">Perfuração múltipla à direita</translation>
+<translation id="4302514097724775343">Toque no dinossauro para jogar.</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Não foi possível aceder ao seu ficheiro</translation>
<translation id="4305817255990598646">Mudar</translation>
@@ -915,6 +930,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4658638640878098064">Agrafar parte superior esquerda</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realidade virtual</translation>
+<translation id="4675657451653251260">Não verá quaisquer informações do perfil do Chrome no modo convidado. Pode <ph name="LINK_BEGIN" />iniciar sessão<ph name="LINK_END" /> para aceder às informações da sua Conta Google, como palavras-passe e métodos de pagamento.</translation>
<translation id="467662567472608290">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o respetivo certificado de segurança contém erros. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="4677585247300749148"><ph name="URL" /> pretende responder a eventos de acessibilidade.</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -942,6 +958,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4761104368405085019">Utilizar o seu microfone</translation>
<translation id="4764776831041365478">A página Web em <ph name="URL" /> poderá estar temporariamente inactiva ou poderá ter sido movida permanentemente para um novo endereço Web.</translation>
<translation id="4766713847338118463">Agrafo duplo na parte inferior</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ A sua atividade que é mantida neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Todos os ficheiros que transferir nesta janela.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up bloqueado}other{# pop-ups bloqueados}}</translation>
<translation id="4780366598804516005">Caixa de correio 1</translation>
@@ -1104,11 +1126,13 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5386426401304769735">A cadeia de certificados inclui um certificado assinado através de SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Coser extremidade direita</translation>
+<translation id="5398772614898833570">Anúncios bloqueados</translation>
<translation id="5400836586163650660">Cinzento</translation>
<translation id="540969355065856584">Este servidor não conseguiu provar que é <ph name="DOMAIN" />; de momento, o respetivo certificado de segurança não é válido. Isto pode ser provocado por uma configuração incorreta ou por um atacante que esteja a intercetar a sua ligação.</translation>
<translation id="541416427766103491">Empilhador 4</translation>
<translation id="5421136146218899937">Limpar dados de navegação...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> pretende enviar-lhe notificações.</translation>
+<translation id="542872847390508405">Está a navegar como Convidado</translation>
<translation id="5430298929874300616">Remover marcador</translation>
<translation id="5439770059721715174">Erro de validação de esquema em "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ordem inversa, com orientação para cima</translation>
@@ -1150,12 +1174,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5571083550517324815">Não é possível recolher a partir deste endereço. Selecione um diferente.</translation>
<translation id="5580958916614886209">Verifique o mês de validade e tente novamente</translation>
<translation id="5586446728396275693">Nenhum endereço guardado</translation>
+<translation id="5593349413089863479">A ligação não é totalmente segura</translation>
<translation id="5595485650161345191">Editar morada</translation>
<translation id="5598944008576757369">Escolher método de pagamento</translation>
<translation id="560412284261940334">Gestão não suportada</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Este site pode ser falso ou fraudulento. O Chrome recomenda que saia agora.</translation>
<translation id="5610142619324316209">Verificar a ligação</translation>
<translation id="5610807607761827392">Pode gerir cartões e endereços nas <ph name="BEGIN_LINK" />Definições<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Traduza esta página com o Google Tradutor</translation>
@@ -1227,6 +1251,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5901630391730855834">Amarelo</translation>
<translation id="5905445707201418379">Bloqueado de acordo com a política de origem de <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizados)</translation>
+<translation id="5913377024445952699">Captura de ecrã em pausa</translation>
<translation id="59174027418879706">Ativada</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Ativado</translation>
@@ -1239,6 +1264,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5963413905009737549">Secção</translation>
<translation id="5967592137238574583">Editar informações de contacto</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
+<translation id="5968793460449681917">Em cada visita</translation>
<translation id="5975083100439434680">Reduzir</translation>
<translation id="5979084224081478209">Verificar palavras-passe</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6587923378399804057">Link copiado por si</translation>
<translation id="6591833882275308647">O seu <ph name="DEVICE_TYPE" /> não é gerido.</translation>
<translation id="6596325263575161958">Opções de encriptação</translation>
+<translation id="6596892391065203054">A impressão deste conteúdo está bloqueada pelo seu administrador.</translation>
<translation id="6604181099783169992">Sensores de movimento ou de luz</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Conteúdo protegido</translation>
@@ -1453,6 +1480,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6895330447102777224">O seu cartão foi confirmado</translation>
<translation id="6897140037006041989">Agente do utilizador</translation>
<translation id="6898699227549475383">Organização (O)</translation>
+<translation id="6907293445143367439">Permitir à app <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> pretende obter o controlo total sobre os seus dispositivos MIDI.</translation>
<translation id="6915804003454593391">Utilizador:</translation>
<translation id="6934672428414710184">Este nome é proveniente da sua Conta Google.</translation>
@@ -1564,6 +1592,7 @@ Detalhes adicionais:
<translation id="7346048084945669753">Está afiliado:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Linha de comandos</translation>
+<translation id="7359588939039777303">Anúncios bloqueados.</translation>
<translation id="7372973238305370288">resultado da pesquisa</translation>
<translation id="7374733840632556089">Este problema ocorre devido a um certificado que o utilizador ou outra pessoa instalou no dispositivo. Sabe-se que o certificado é utilizado para monitorizar e intercetar redes e não é considerado fidedigno pelo Chrome. Embora existam alguns casos legítimos para a monitorização, como numa rede escolar ou da empresa, o Chrome pretende certificar-se de que o utilizador tem conhecimento da situação, mesmo que não seja possível interrompê-la. A monitorização pode ocorrer em qualquer navegador ou aplicação que aceda à Web.</translation>
<translation id="7375818412732305729">É anexado um ficheiro</translation>
@@ -1737,6 +1766,7 @@ Detalhes adicionais:
<translation id="7976214039405368314">Demasiados pedidos</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Para ver conteúdo de realidade aumentada, instale o ARCore.</translation>
<translation id="799149739215780103">Encadernar</translation>
<translation id="7995512525968007366">Não especificado</translation>
<translation id="800218591365569300">Experimente fechar outros separadores ou programas para libertar memória.</translation>
@@ -1864,25 +1894,39 @@ Detalhes adicionais:
<translation id="8507227106804027148">Linha de comandos</translation>
<translation id="8508648098325802031">Ãcone de pesquisa</translation>
<translation id="8522552481199248698">O Chrome pode ajudá-lo a proteger a sua Conta Google e a alterar a palavra-passe.</translation>
+<translation id="8525306231823319788">Ecrã inteiro</translation>
<translation id="8530813470445476232">Limpe o seu histórico de navegação, cookies, cache e muito mais nas definições do Chrome.</translation>
<translation id="8533619373899488139">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista dos URLs bloqueados e outras políticas aplicadas pelo administrador do sistema.</translation>
<translation id="8541158209346794904">Dispositivo Bluetooth</translation>
<translation id="8542014550340843547">Agrafo triplo na parte inferior</translation>
<translation id="8543181531796978784">Pode <ph name="BEGIN_ERROR_LINK" />comunicar um problema de deteção<ph name="END_ERROR_LINK" /> ou, se compreende os riscos para a sua segurança, <ph name="BEGIN_LINK" />aceda a este site não seguro<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">O Código de Segurança/CVC está localizado no verso do cartão.</translation>
+<translation id="8558485628462305855">Para ver conteúdo de realidade aumentada, atualize o ARCore.</translation>
<translation id="8559762987265718583">Não é possível estabelecer uma ligação privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do seu dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas.</translation>
<translation id="8564182942834072828">Documentos separados/Cópias não agrupadas</translation>
<translation id="8564985650692024650">O Chromium recomenda a reposição da palavra-passe da <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se a tiver reutilizado noutros sites.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Atividade que não é mantida neste dispositivo:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Páginas que vê nesta janela.
+ <ph name="LIST_ITEM" />Cookies e dados de sites.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Utilizar o Touch ID para confirmar os cartões mais rapidamente</translation>
<translation id="858637041960032120">Adic. n.º telef.
</translation>
<translation id="8589998999637048520">Qualidade óptima</translation>
+<translation id="8600271352425265729">Apenas desta vez</translation>
<translation id="860043288473659153">Nome do titular do cartão</translation>
<translation id="8606726445206553943">Utilizar os seus dispositivos MIDI</translation>
+<translation id="8612761427948161954">Olá, <ph name="USERNAME" />,
+ <ph name="BR" />
+ Está a navegar como convidado</translation>
<translation id="861775596732816396">Tamanho 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Não existem palavras-passe correspondentes. Mostrar todas as palavras-passe guardadas.</translation>
<translation id="8625384913736129811">Guardar este cartão neste dispositivo</translation>
+<translation id="8627040765059109009">Captura de ecrã retomada</translation>
<translation id="8657078576661269990">O seu administrador bloqueou a partilha de <ph name="ORIGIN_NAME" /> com as VMs <ph name="VM_NAME_1" /> e <ph name="VM_NAME_2" />.</translation>
<translation id="8663226718884576429">Resumo da encomenda, <ph name="TOTAL_LABEL" />, mais detalhes</translation>
<translation id="867224526087042813">Assinatura</translation>
@@ -1945,6 +1989,7 @@ Detalhes adicionais:
<translation id="8912362522468806198">Conta Google</translation>
<translation id="8913778647360618320">Botão Gerir métodos de pagamento; prima Enter para gerir as suas informações de cartões de crédito e pagamentos nas Definições do Chrome.</translation>
<translation id="8918231688545606538">Esta página é suspeita</translation>
+<translation id="8922013791253848639">Permitir sempre anúncios neste site</translation>
<translation id="892588693504540538">Perfurar na parte superior direita</translation>
<translation id="8931333241327730545">Pretende guardar este cartão na sua Conta Google?</translation>
<translation id="8932102934695377596">O seu relógio está atrasado</translation>
@@ -2016,6 +2061,7 @@ Detalhes adicionais:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> utiliza um protocolo não suportado.</translation>
<translation id="9191834167571392248">Perfurar na parte inferior esquerda</translation>
+<translation id="9199905725844810519">A impressão está bloqueada.</translation>
<translation id="9205078245616868884">Os dados estão encriptados com a sua frase de acesso de sincronização. Introduza-a para iniciar a sincronização.</translation>
<translation id="9207861905230894330">Falha ao adicionar o artigo.</translation>
<translation id="9213433120051936369">Personalize o aspeto</translation>
@@ -2026,8 +2072,10 @@ Detalhes adicionais:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Pode perder o acesso à sua Conta Google. O Chromium recomenda que altere a palavra-passe agora. Ser-lhe-á pedido para iniciar sessão.</translation>
<translation id="939736085109172342">Nova pasta</translation>
+<translation id="945522503751344254">Enviar feedback</translation>
<translation id="945855313015696284">Verifique as informações abaixo e elimine os cartões inválidos</translation>
<translation id="950736567201356821">Perfuração tripla na parte superior</translation>
+<translation id="951941430552851965">A captura de ecrã foi colocada em pausa pelo seu administrador devido a conteúdo no ecrã.</translation>
<translation id="961663415146723894">Encadernar parte inferior</translation>
<translation id="962484866189421427">Este conteúdo poderá tentar instalar aplicações fraudulentas que se fazem passar por algo diferente ou que recolhem dados que podem ser utilizados para o monitorizar. <ph name="BEGIN_LINK" />Mostrar, mesmo assim<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Compilação oficial</translation>
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index 6a247ecb75f..9f912ab5560 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ai introdus parola pe un site care nu este gestionat de organizația ta. Pentru a proteja contul, nu folosi aceeași parolă pentru alte aplicații și site-uri.</translation>
<translation id="1263231323834454256">Lista de lectură</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Activități care nu vor fi păstrate pe acest dispozitiv:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />paginile pe care le vezi în această fereastră;
+ <ph name="LIST_ITEM" />cookie-uri și date privind site-urile;
+ <ph name="LIST_ITEM" />informații despre cont (<ph name="LINK_BEGIN" />deconectarea<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Metodă de preluare</translation>
<translation id="1281476433249504884">Receptorul de hârtie 1</translation>
<translation id="1285320974508926690">Nu traduce niciodată acest site</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Conectează-te pentru a folosi parolele salvate în Contul Google</translation>
<translation id="2053111141626950936">Paginile în <ph name="LANGUAGE" /> nu vor fi traduse.</translation>
<translation id="2053553514270667976">Cod zip</translation>
+<translation id="2054665754582400095">Prezența ta</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestie}few{# sugestii}other{# de sugestii}}</translation>
<translation id="2079545284768500474">Anulează</translation>
<translation id="20817612488360358">Setările proxy de sistem sunt setate pentru a fi utilizate, dar o configurație explicită pentru proxy este, de asemenea, specificată.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Aplicații Android</translation>
<translation id="2107021941795971877">Suporturi de printare</translation>
<translation id="2108755909498034140">repornește computerul;</translation>
+<translation id="2111166930115883695">Apasă pe Space pentru a juca</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Politica este ignorată, deoarece a fost înlocuită de <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Anulează plata</translation>
<translation id="2147827593068025794">Sincronizare în fundal</translation>
<translation id="2148613324460538318">Adaugă un card</translation>
+<translation id="2149968176347646218">Conexiunea nu este sigură</translation>
<translation id="2154054054215849342">Sincronizarea nu este disponibilă pentru domeniul tău</translation>
<translation id="2154484045852737596">Editează cardul</translation>
<translation id="2161656808144014275">Text</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Politici</translation>
<translation id="2183608646556468874">Număr de telefon</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresă}few{# adrese}other{# de adrese}}</translation>
-<translation id="2187243482123994665">Prezența utilizatorului</translation>
<translation id="2187317261103489799">Detectează (în mod prestabilit)</translation>
<translation id="2188375229972301266">Perforare multiplă în partea de jos</translation>
<translation id="2202020181578195191">Introdu un an de expirare valid</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">Urmează un site fals</translation>
<translation id="2850739647070081192">Invite (Plic)</translation>
<translation id="2856444702002559011">Atacatorii pot încerca să îți fure informațiile de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (de exemplu, parole, mesaje sau date despre cardurile de credit). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Acest site afișează anunțuri deranjante sau înșelătoare.</translation>
<translation id="2878197950673342043">ÃŽndoire de tip afiÈ™</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Poziționarea ferestrelor</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">Sugestii de la Google</translation>
<translation id="3002501248619246229">Verifică suportul din tava de intrare</translation>
<translation id="3005723025932146533">Afișați o copie salvată</translation>
-<translation id="3007719053326478567">Printarea acestui conținut a fost blocată de administrator</translation>
<translation id="3008447029300691911">Introdu codul CVC pentru <ph name="CREDIT_CARD" />. După ce confirmi, acest site va avea acces la detaliile cardului tău.</translation>
<translation id="3010559122411665027">Intrarea din listă „<ph name="ENTRY_INDEX" />â€: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Blocată automat</translation>
<translation id="3016780570757425217">Afle locația</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, apasă pe Tab, apoi pe Enter pentru a elimina sugestia.</translation>
<translation id="3023071826883856138">You4 (Plic)</translation>
<translation id="3024663005179499861">Tip de politică greșit</translation>
<translation id="3037605927509011580">Of, nu mai merge!</translation>
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">Marcată</translation>
<translation id="3209034400446768650">Pagina poate percepe o taxă</translation>
<translation id="3212581601480735796">Activitatea ta de pe <ph name="HOSTNAME" /> este monitorizată</translation>
+<translation id="3212623355668894776">Închide toate ferestrele pentru invitați pentru ca activitatea ta de navigare să se șteargă de pe acest dispozitiv.</translation>
<translation id="3215092763954878852">Nu s-a putut folosi WebAuthn</translation>
<translation id="3218181027817787318">Relativă</translation>
<translation id="3225919329040284222">Serverul a prezentat un certificat care nu se potrivește cu așteptările încorporate. Aceste așteptări sunt incluse pentru anumite site-uri web, cu un grad sporit de securitate, pentru a vă proteja.</translation>
@@ -700,6 +712,7 @@
<translation id="3784372983762739446">Dispozitive Bluetooth</translation>
<translation id="3787705759683870569">Expiră în <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Mărimea 16</translation>
+<translation id="3789841737615482174">Instalează</translation>
<translation id="3793574014653384240">Numărul și cauzele blocărilor apărute recent</translation>
<translation id="3797522431967816232">Prc3 (Plic)</translation>
<translation id="3799805948399000906">Font solicitat</translation>
@@ -751,6 +764,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Cheie „<ph name="SUBKEY" />â€: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Plic)</translation>
+<translation id="4067669230157909013">Funcția de realizare a capturilor de ecran a fost reluată.</translation>
<translation id="4067947977115446013">Adaugă o adresă validă</translation>
<translation id="4072486802667267160">A apărut o eroare la procesarea comenzii. Încearcă din nou.</translation>
<translation id="4075732493274867456">Clientul și serverul nu acceptă o versiune a protocolului SSL sau o suită de codificare obișnuită.</translation>
@@ -835,6 +849,7 @@
<translation id="4297502707443874121">Miniatură pentru pagina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Extinde</translation>
<translation id="4300675098767811073">Perforare multiplă în dreapta</translation>
+<translation id="4302514097724775343">Atinge dinozaurul ca să joci</translation>
<translation id="4302965934281694568">Chou3 (Plic)</translation>
<translation id="4305666528087210886">Fișierul nu a putut fi accesat</translation>
<translation id="4305817255990598646">Comută</translation>
@@ -913,6 +928,7 @@
<translation id="4658638640878098064">Capsare în stânga sus</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realitate virtuală</translation>
+<translation id="4675657451653251260">În modul pentru invitați, nu vei vedea alte informații ale profilului Chrome. Poți să te <ph name="LINK_BEGIN" />conectezi<ph name="LINK_END" /> pentru a accesa informațiile contului Google, cum ar fi parolele și metodele de plată.</translation>
<translation id="467662567472608290">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate conține erori. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="4677585247300749148"><ph name="URL" /> dorește să răspundă evenimentelor de accesibilitate</translation>
<translation id="467809019005607715">Prezentări Google</translation>
@@ -940,6 +956,12 @@
<translation id="4761104368405085019">Utilizează microfonul</translation>
<translation id="4764776831041365478">Pagina web de la <ph name="URL" /> poate fi temporar nefuncțională sau a fost mutată definitiv la o nouă adresă web.</translation>
<translation id="4766713847338118463">Capsare dublă în partea de jos</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Activități care vor fi păstrate pe acest dispozitiv:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />toate fișierele pe care le descarci în această fereastră.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">A apărut o eroare necunoscută.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Fereastră pop-up blocată}few{# ferestre pop-up blocate}other{# de ferestre pop-up blocate}}</translation>
<translation id="4780366598804516005">Căsuța de e-mail 1</translation>
@@ -1102,11 +1124,13 @@
<translation id="5386426401304769735">Lanțul de certificate pentru acest site conține un certificat semnat folosind SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Broșare pe marginea din dreapta</translation>
+<translation id="5398772614898833570">Anunțurile au fost blocate</translation>
<translation id="5400836586163650660">Gri</translation>
<translation id="540969355065856584">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; momentan, certificatul de securitate nu este valid. Cauza poate fi o configurare greșită sau interceptarea conexiunii de un atacator.</translation>
<translation id="541416427766103491">Receptorul de hârtie 4</translation>
<translation id="5421136146218899937">Șterge datele de navigare...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> dorește să îți trimită notificări</translation>
+<translation id="542872847390508405">Navigați ca invitat</translation>
<translation id="5430298929874300616">Elimină marcajul</translation>
<translation id="5439770059721715174">Eroare de validare a schemei la „<ph name="ERROR_PATH" />â€: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">În ordine inversă, cu fața în sus</translation>
@@ -1148,12 +1172,12 @@
<translation id="5571083550517324815">Nu se poate prelua de la această adresă. Selectează altă adresă.</translation>
<translation id="5580958916614886209">Verifică luna în care expiră și încearcă din nou</translation>
<translation id="5586446728396275693">Nu există adrese salvate</translation>
+<translation id="5593349413089863479">Conexiunea nu este complet sigură</translation>
<translation id="5595485650161345191">Editează adresa</translation>
<translation id="5598944008576757369">Alege metoda de plată</translation>
<translation id="560412284261940334">Gestionarea nu este acceptată</translation>
<translation id="5605670050355397069">Registru</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Acest site poate fi fals sau fraudulos. Chrome îți recomandă să ieși acum.</translation>
<translation id="5610142619324316209">să verifici conexiunea;</translation>
<translation id="5610807607761827392">Poți să gestionezi cardurile și adresele în <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Tradu această pagină cu Google Traducere</translation>
@@ -1225,6 +1249,7 @@
<translation id="5901630391730855834">Galben</translation>
<translation id="5905445707201418379">Blocat conform politicii de origine de la <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizat)</translation>
+<translation id="5913377024445952699">Funcție de realizare a capturilor întreruptă</translation>
<translation id="59174027418879706">Activat</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">activate</translation>
@@ -1237,6 +1262,7 @@
<translation id="5963413905009737549">Secțiune</translation>
<translation id="5967592137238574583">Editează informațiile de contact</translation>
<translation id="5967867314010545767">Eliminați din istoric</translation>
+<translation id="5968793460449681917">La fiecare vizită</translation>
<translation id="5975083100439434680">Micșorează</translation>
<translation id="5979084224081478209">Verifică parolele</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1392,6 +1418,7 @@
<translation id="6587923378399804057">Linkul copiat de tine</translation>
<translation id="6591833882275308647">Dispozitivul <ph name="DEVICE_TYPE" /> nu este gestionat</translation>
<translation id="6596325263575161958">Opțiuni de criptare</translation>
+<translation id="6596892391065203054">Printarea acestui conținut a fost blocată de administrator.</translation>
<translation id="6604181099783169992">Senzori de mișcare sau de lumină</translation>
<translation id="6609880536175561541">Prc7 (Plic)</translation>
<translation id="6612358246767739896">Conținut protejat</translation>
@@ -1451,6 +1478,7 @@
<translation id="6895330447102777224">Cardul tău este confirmat</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6898699227549475383">Organizația (O)</translation>
+<translation id="6907293445143367439">Permite ca <ph name="SITE_NAME" /> să:</translation>
<translation id="6910240653697687763">Adresa <ph name="URL" /> dorește să preia controlul complet asupra dispozitivelor MIDI</translation>
<translation id="6915804003454593391">Utilizator:</translation>
<translation id="6934672428414710184">Acest nume provine din Contul tău Google</translation>
@@ -1562,6 +1590,7 @@ Detalii suplimentare:
<translation id="7346048084945669753">Este afiliat:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Linie de comandă</translation>
+<translation id="7359588939039777303">Anunțurile au fost blocate.</translation>
<translation id="7372973238305370288">rezultat al căutării</translation>
<translation id="7374733840632556089">Această problemă apare din cauza unui certificat pe care tu sau altcineva l-ați instalat pe dispozitiv. Certificatul este folosit pentru a monitoriza și a intercepta rețelele, nefiind autorizat de Chrome. Deși există cazuri legitime pentru monitorizare, de exemplu, într-o rețea de la școală sau de la serviciu, Chrome vrea să se asigure că știi ce se întâmplă, chiar dacă nu poți opri acest lucru. Monitorizarea se poate face în orice browser sau aplicație care intră pe web.</translation>
<translation id="7375818412732305729">Fișierul este atașat</translation>
@@ -1736,6 +1765,7 @@ Detalii suplimentare:
<translation id="7976214039405368314">Prea multe solicitări</translation>
<translation id="7977538094055660992">Dispozitiv de ieșire</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Pentru a vedea conținut din realitatea augmentată, instalează ARCore</translation>
<translation id="799149739215780103">Legare</translation>
<translation id="7995512525968007366">Nespecificată</translation>
<translation id="800218591365569300">Încearcă să închizi celelalte file sau programe pentru a elibera memoria.</translation>
@@ -1863,25 +1893,39 @@ Detalii suplimentare:
<translation id="8507227106804027148">Linie de comandă</translation>
<translation id="8508648098325802031">Pictograma Căutare</translation>
<translation id="8522552481199248698">Chrome te poate ajuta să îți protejezi Contul Google și să îți schimbi parola.</translation>
+<translation id="8525306231823319788">Ecran complet</translation>
<translation id="8530813470445476232">Șterge istoricul de navigare, cookie-urile, memoria cache și altele din setările Chrome</translation>
<translation id="8533619373899488139">Accesează &lt;strong&gt;chrome://policy&lt;/strong&gt; ca să vezi lista de adrese URL blocate și alte politici aplicate de administratorul de sistem.</translation>
<translation id="8541158209346794904">Dispozitivul Bluetooth</translation>
<translation id="8542014550340843547">Capsare triplă în partea de jos</translation>
<translation id="8543181531796978784">Poți să <ph name="BEGIN_ERROR_LINK" />raportezi o problemă privind detectarea<ph name="END_ERROR_LINK" /> sau, dacă îți asumi riscurile de securitate, poți să <ph name="BEGIN_LINK" />accesezi acest site nesigur<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Codul CVC se află pe spatele cardului.</translation>
+<translation id="8558485628462305855">Pentru a vedea conținut din realitatea augmentată, actualizează ARCore</translation>
<translation id="8559762987265718583">O conexiune privată la <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nu poate fi stabilită, deoarece data și ora dispozitivului (<ph name="DATE_AND_TIME" />) sunt incorecte.</translation>
<translation id="8564182942834072828">Documente separate/Copii necolaționate</translation>
<translation id="8564985650692024650">Chromium îți recomandă să resetezi parola pentru <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> dacă ai folosit-o și pe alte site-uri.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Activități care nu vor fi păstrate pe acest dispozitiv:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />paginile pe care le vezi în această fereastră;
+ <ph name="LIST_ITEM" />cookie-uri și date privind site-urile.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Folosește Touch ID ca să confirmi cardurile mai rapid</translation>
<translation id="858637041960032120">Adăugați telefon
</translation>
<translation id="8589998999637048520">Calitate optimă</translation>
+<translation id="8600271352425265729">Doar de data aceasta</translation>
<translation id="860043288473659153">Nume titular de card</translation>
<translation id="8606726445206553943">Folosească dispozitive MIDI</translation>
+<translation id="8612761427948161954">Salut, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Navighezi ca invitat</translation>
<translation id="861775596732816396">Mărimea 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Parolele nu corespund. Afișează toate parolele salvate.</translation>
<translation id="8625384913736129811">Salvează cardul pe acest dispozitiv</translation>
+<translation id="8627040765059109009">Funcție de realizare a capturilor reluată</translation>
<translation id="8657078576661269990">Administratorul a blocat permiterea accesului de pe <ph name="ORIGIN_NAME" /> la <ph name="VM_NAME_1" /> și la <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Rezumatul comenzii, <ph name="TOTAL_LABEL" />, Mai multe detalii</translation>
<translation id="867224526087042813">Semnătura</translation>
@@ -1944,6 +1988,7 @@ Detalii suplimentare:
<translation id="8912362522468806198">Contul Google</translation>
<translation id="8913778647360618320">Butonul Gestionează metodele de plată, apasă pe Enter pentru a gestiona informațiile despre plăți și carduri de credit în setările Chrome</translation>
<translation id="8918231688545606538">Această pagină este suspectă</translation>
+<translation id="8922013791253848639">Permite întotdeauna anunțurile pe acest site</translation>
<translation id="892588693504540538">Perforare în dreapta sus</translation>
<translation id="8931333241327730545">Dorești să salvezi acest card în Contul Google?</translation>
<translation id="8932102934695377596">Ora este setată în trecut</translation>
@@ -2015,6 +2060,7 @@ Detalii suplimentare:
<translation id="9183302530794969518">Documente Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> folosește un protocol neacceptat.</translation>
<translation id="9191834167571392248">Perforare în stânga jos</translation>
+<translation id="9199905725844810519">Printarea este blocată</translation>
<translation id="9205078245616868884">Datele sunt criptate cu expresia de acces pentru sincronizare. Introdu-o pentru a începe sincronizarea.</translation>
<translation id="9207861905230894330">Articolul nu a fost adăugat.</translation>
<translation id="9213433120051936369">Personalizează aspectul</translation>
@@ -2025,8 +2071,10 @@ Detalii suplimentare:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Este posibil să pierzi accesul la Contul Google. Chromium îți recomandă să îți schimbi parola acum. Ți se va cere să te conectezi.</translation>
<translation id="939736085109172342">Dosar nou</translation>
+<translation id="945522503751344254">Trimite feedback</translation>
<translation id="945855313015696284">Verifică informațiile de mai jos și șterge cardurile nevalide</translation>
<translation id="950736567201356821">Perforare triplă în partea de sus</translation>
+<translation id="951941430552851965">Funcția de realizare a capturilor de ecran a fost întreruptă de administrator din cauza conținutului de pe ecran.</translation>
<translation id="961663415146723894">Legare în partea de jos</translation>
<translation id="962484866189421427">Acest conținut poate încerca să instaleze aplicații înșelătoare care pretind a fi altceva sau colectează date care pot fi folosite pentru a te urmări. <ph name="BEGIN_LINK" />Afișează oricum<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Versiune oficială</translation>
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index 3ba26b91127..145a63b2f53 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ð’Ñ‹ ввели пароль на Ñайте, которым не управлÑет ваша организациÑ. Чтобы защитить Ñвой аккаунт, не иÑпользуйте Ñтот пароль Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… приложений и Ñайтов.</translation>
<translation id="1263231323834454256">СпиÑок Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Ðа Ñтом уÑтройÑтве не будут ÑохранÑÑ‚ÑŒÑÑ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраницы, которые вы проÑматриваете в Ñтом окне;
+ <ph name="LIST_ITEM" />файлы cookie и данные Ñайтов;
+ <ph name="LIST_ITEM" />Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± аккаунте (<ph name="LINK_BEGIN" />выйти<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">СпоÑоб получениÑ</translation>
<translation id="1281476433249504884">Укладчик 1</translation>
<translation id="1285320974508926690">Ðикогда не переводить Ñтот Ñайт</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">Войти, чтобы иÑпользовать пароли, Ñохраненные в аккаунте Google</translation>
<translation id="2053111141626950936">Страницы на Ñтом Ñзыке (<ph name="LANGUAGE" />) не будут переводитьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки.</translation>
<translation id="2053553514270667976">Почтовый индекÑ</translation>
+<translation id="2054665754582400095">Ваше приÑутÑтвие</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 вариант}one{# вариант}few{# варианта}many{# вариантов}other{# варианта}}</translation>
<translation id="2079545284768500474">Отмена</translation>
<translation id="20817612488360358">Включены ÑиÑтемные наÑтройки прокÑи-Ñервера, но при Ñтом его ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð´Ð°Ð½Ð° Ñвным образом.</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Android</translation>
<translation id="2107021941795971877">Поддержка печати</translation>
<translation id="2108755909498034140">Перезагрузите компьютер.</translation>
+<translation id="2111166930115883695">Чтобы начать игру, нажмите Пробел.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701">ИгнорируетÑÑ, так как правило <ph name="POLICY_NAME" /> имеет приоритет.</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">Отменить оплату</translation>
<translation id="2147827593068025794">Ð¤Ð¾Ð½Ð¾Ð²Ð°Ñ ÑинхронизациÑ</translation>
<translation id="2148613324460538318">Добавить карту</translation>
+<translation id="2149968176347646218">Подключение не защищено</translation>
<translation id="2154054054215849342">Ð’ вашем домене ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½ÐµÐ´Ð¾Ñтупна</translation>
<translation id="2154484045852737596">Изменение данных карты</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">Правила</translation>
<translation id="2183608646556468874">Ðомер телефона</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑ}one{# адреÑ}few{# адреÑа}many{# адреÑов}other{# адреÑа}}</translation>
-<translation id="2187243482123994665">ПриÑутÑтвие пользователÑ</translation>
<translation id="2187317261103489799">ОпределÑÑ‚ÑŒ (по умолчанию)</translation>
<translation id="2188375229972301266">ÐеÑколько отверÑтий Ñнизу</translation>
<translation id="2202020181578195191">ÐедопуÑтимый формат года.</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">ОÑторожно, поддельный Ñайт!</translation>
<translation id="2850739647070081192">Invite (конверт)</translation>
<translation id="2856444702002559011">Злоумышленники могут пытатьÑÑ Ð¿Ð¾Ñ…Ð¸Ñ‚Ð¸Ñ‚ÑŒ ваши данные Ñ Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например, пароли, ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ номера банковÑких карт). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Этот Ñайт показывает навÑзчивую или вводÑщую в заблуждение рекламу.</translation>
<translation id="2878197950673342043">Ð”Ð²Ð¾Ð¹Ð½Ð°Ñ Ð¿ÐµÑ€Ð¿ÐµÐ½Ð´Ð¸ÐºÑƒÐ»ÑÑ€Ð½Ð°Ñ Ñ„Ð°Ð»ÑŒÑ†Ð¾Ð²ÐºÐ°</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Размещение окон</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Рекомендации от Google</translation>
<translation id="3002501248619246229">Проверить данные входного лотка</translation>
<translation id="3005723025932146533">Открыть Ñохраненную копию</translation>
-<translation id="3007719053326478567">Печать Ñтого контента заблокирована админиÑтратором.</translation>
<translation id="3008447029300691911">Введите CVC-код карты <ph name="CREDIT_CARD" />. ПоÑле Ñтого ее данные будут переданы Ñайту.</translation>
<translation id="3010559122411665027">Элемент ÑпиÑка "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Заблокировано автоматичеÑки</translation>
<translation id="3016780570757425217">доÑтуп к данным о вашем меÑтоположении</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />. Чтобы удалить подÑказку, нажмите Tab, а затем Ввод.</translation>
<translation id="3023071826883856138">You4 (конверт)</translation>
<translation id="3024663005179499861">Ðеверный тип политики</translation>
<translation id="3037605927509011580">Опаньки...</translation>
@@ -548,6 +559,7 @@
<translation id="3207960819495026254">Добавлено в закладки.</translation>
<translation id="3209034400446768650">Ðа Ñтой Ñтранице может взиматьÑÑ Ð¿Ð»Ð°Ñ‚Ð°</translation>
<translation id="3212581601480735796">Ваши дейÑÑ‚Ð²Ð¸Ñ Ð½Ð° Ñайте <ph name="HOSTNAME" /> отÑлеживаютÑÑ</translation>
+<translation id="3212623355668894776">Чтобы удалить Ñ Ñтого уÑтройÑтва данные о Ñвоих дейÑтвиÑÑ… в браузере, закройте окна, открытые в гоÑтевом режиме.</translation>
<translation id="3215092763954878852">Ðе удалоÑÑŒ иÑпользовать WebAuthn</translation>
<translation id="3218181027817787318">ОтноÑительный</translation>
<translation id="3225919329040284222">Сертификат не ÑоответÑтвует вÑтроенным параметрам определенных Ñайтов Ñ Ð²Ñ‹Ñоким уровнем безопаÑноÑти.</translation>
@@ -695,6 +707,7 @@
<translation id="3784372983762739446">УÑтройÑтва Bluetooth</translation>
<translation id="3787705759683870569">Срок дейÑтвиÑ: до <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Размер: 16</translation>
+<translation id="3789841737615482174">УÑтановить</translation>
<translation id="3793574014653384240">КоличеÑтво недавних Ñбоев и их причины</translation>
<translation id="3797522431967816232">Prc3 (конверт)</translation>
<translation id="3799805948399000906">Шрифт запрошен</translation>
@@ -745,6 +758,7 @@
<translation id="4056223980640387499">СепиÑ</translation>
<translation id="4058922952496707368">Ключ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (конверт)</translation>
+<translation id="4067669230157909013">ЗапиÑÑŒ Ñкрана возобновлена.</translation>
<translation id="4067947977115446013">Введите дейÑтвительный адреÑ</translation>
<translation id="4072486802667267160">При обработке заказа произошла ошибка. Повторите попытку.</translation>
<translation id="4075732493274867456">Клиент и Ñервер поддерживают разные верÑии протокола SSL или набора шифров.</translation>
@@ -825,6 +839,7 @@
<translation id="4297502707443874121">Уменьшенное изображение Ñтраницы <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Развернуть</translation>
<translation id="4300675098767811073">ÐеÑколько отверÑтий Ñправа</translation>
+<translation id="4302514097724775343">Чтобы начать игру, нажмите на динозаврика.</translation>
<translation id="4302965934281694568">Chou3 (конверт)</translation>
<translation id="4305666528087210886">Ðе удалоÑÑŒ получить доÑтуп к файлу</translation>
<translation id="4305817255990598646">ПереключитьÑÑ</translation>
@@ -903,6 +918,7 @@
<translation id="4658638640878098064">Скоба в левом верхнем углу</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Ð’Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ñ€ÐµÐ°Ð»ÑŒÐ½Ð¾ÑÑ‚ÑŒ</translation>
+<translation id="4675657451653251260">Ð’ гоÑтевом режиме вы не увидите информацию Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Chrome. Чтобы получить доÑтуп к Ñвоим данным, например паролÑм и ÑпоÑобам оплаты, <ph name="LINK_BEGIN" />войдите в аккаунт Google<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти Ñодержит ошибки. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="4677585247300749148">Сайт <ph name="URL" /> запрашивает доÑтуп к Ñпециальным возможноÑÑ‚Ñм.</translation>
<translation id="467809019005607715">Google Презентации</translation>
@@ -930,6 +946,12 @@
<translation id="4761104368405085019">ИÑпользование микрофона</translation>
<translation id="4764776831041365478">Веб-Ñтраница по адреÑу <ph name="URL" />, возможно, временно недоÑтупна или поÑтоÑнно перемещена по новому адреÑу.</translation>
<translation id="4766713847338118463">Две Ñкобы Ñнизу</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Ðа Ñтом уÑтройÑтве будут Ñохранены:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />файлы, которые вы Ñкачиваете в Ñтом окне.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Произошла неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Ð’Ñплывающее окно заблокировано}one{Заблокировано # вÑплывающее окно}few{Заблокировано # вÑплывающих окна}many{Заблокировано # вÑплывающих окон}other{Заблокировано # вÑплывающ. окна}}</translation>
<translation id="4780366598804516005">Почтовый Ñщик 1</translation>
@@ -1083,7 +1105,7 @@
<translation id="5332219387342487447">СпоÑоб доÑтавки</translation>
<translation id="5334013548165032829">Подробные ÑиÑтемные журналы.</translation>
<translation id="5340250774223869109">Приложение заблокировано</translation>
-<translation id="534295439873310000">УÑтройÑтва Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸ÐµÐ¹ NFC</translation>
+<translation id="534295439873310000">УÑтройÑтва Ñ NFC</translation>
<translation id="5344579389779391559">ЕÑли вы откроете Ñту Ñтраницу, Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ Ñчета могут быть ÑпиÑаны ÑредÑтва</translation>
<translation id="5355557959165512791">Сертификат веб-Ñайта <ph name="SITE" /> отозван. Открыть Ñайт в наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð½ÐµÐ»ÑŒÐ·Ñ. Сбой мог быть вызван Ñетевой ошибкой или дейÑтвиÑми злоумышленников. Скорее вÑего, Ñайт заработает через некоторое времÑ.</translation>
<translation id="536296301121032821">Ðе удалоÑÑŒ Ñохранить наÑтройки политики</translation>
@@ -1092,11 +1114,13 @@
<translation id="5386426401304769735">Ð’ цепочке Ñертификатов Ñтого Ñайта еÑÑ‚ÑŒ Ñертификат, подпиÑанный Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ алгоритма SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Скобы по правому краю</translation>
+<translation id="5398772614898833570">Реклама заблокирована</translation>
<translation id="5400836586163650660">Серый</translation>
<translation id="540969355065856584">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти может быть недейÑтвителен в наÑтоÑщее времÑ. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="541416427766103491">Укладчик 4</translation>
<translation id="5421136146218899937">ОчиÑтить иÑторию...</translation>
<translation id="5426179911063097041">С Ñайта <ph name="SITE" /> поÑтупил Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° отправку уведомлений.</translation>
+<translation id="542872847390508405">Ð’Ñ‹ вошли в гоÑтевом режиме</translation>
<translation id="5430298929874300616">Удалить закладку</translation>
<translation id="5439770059721715174">Ошибка проверки Ñхемы, <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ð’ обратном порÑдке лицевой Ñтороной вверх</translation>
@@ -1138,12 +1162,12 @@
<translation id="5571083550517324815">Этот Ð°Ð´Ñ€ÐµÑ Ð½Ðµ поддерживаетÑÑ. Выберите другой.</translation>
<translation id="5580958916614886209">Проверьте меÑÑц в Ñроке дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹ и повторите попытку</translation>
<translation id="5586446728396275693">Ðет Ñохраненных адреÑов</translation>
+<translation id="5593349413089863479">Подключение недоÑтаточно защищено</translation>
<translation id="5595485650161345191">Изменить адреÑ</translation>
<translation id="5598944008576757369">Выбрать ÑпоÑоб оплаты</translation>
<translation id="560412284261940334">Управление уÑтройÑтвами не поддерживаетÑÑ</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Этот Ñайт может оказатьÑÑ Ð¿Ð¾Ð´Ð´ÐµÐ»ÑŒÐ½Ñ‹Ð¼ или мошенничеÑким. Советуем покинуть его прÑмо ÑейчаÑ.</translation>
<translation id="5610142619324316209">Проверьте подключение к Интернету.</translation>
<translation id="5610807607761827392">Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ картах и адреÑах можно изменить в <ph name="BEGIN_LINK" />наÑтройках<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">ПеревеÑти Ñту Ñтраницу Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Google Переводчика</translation>
@@ -1215,6 +1239,7 @@
<translation id="5901630391730855834">Желтый</translation>
<translation id="5905445707201418379">Заблокировано в ÑоответÑтвии Ñ Ð¿Ð¾Ð»Ð¸Ñ‚Ð¸ÐºÐ¾Ð¹ в отношении иÑточников <ph name="ORIGIN" /></translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (данные ÑинхронизируютÑÑ)</translation>
+<translation id="5913377024445952699">Съемка Ñкрана приоÑтановлена</translation>
<translation id="59174027418879706">Включено</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ВКЛ</translation>
@@ -1227,6 +1252,7 @@
<translation id="5963413905009737549">Раздел</translation>
<translation id="5967592137238574583">Измените контактную информацию</translation>
<translation id="5967867314010545767">Удалить из иÑтории</translation>
+<translation id="5968793460449681917">Ð’Ñегда</translation>
<translation id="5975083100439434680">Уменьшить</translation>
<translation id="5979084224081478209">Проверить пароли</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1382,6 +1408,7 @@
<translation id="6587923378399804057">Ð¡ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ ÑÑылка</translation>
<translation id="6591833882275308647">Это уÑтройÑтво <ph name="DEVICE_TYPE" /> не управлÑетÑÑ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратором.</translation>
<translation id="6596325263575161958">Параметры шифрованиÑ</translation>
+<translation id="6596892391065203054">Печать Ñтого контента заблокирована админиÑтратором.</translation>
<translation id="6604181099783169992">Датчики Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¸ оÑвещенноÑти</translation>
<translation id="6609880536175561541">Prc7 (конверт)</translation>
<translation id="6612358246767739896">Защищенный контент</translation>
@@ -1441,6 +1468,7 @@
<translation id="6895330447102777224">Ваша карта подтверждена</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6898699227549475383">ÐžÑ€Ð³Ð°Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ (O)</translation>
+<translation id="6907293445143367439">ПредоÑтавьте Ñайту <ph name="SITE_NAME" /> Ñледующие разрешениÑ:</translation>
<translation id="6910240653697687763">Сайт <ph name="URL" /> запрашивает полный контроль над MIDI-уÑтройÑтвами.</translation>
<translation id="6915804003454593391">Пользователь:</translation>
<translation id="6934672428414710184">Это Ð¸Ð¼Ñ Ð¸Ð· вашего аккаунта Google</translation>
@@ -1552,6 +1580,7 @@
<translation id="7346048084945669753">Ðффилированный пользователь:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока</translation>
+<translation id="7359588939039777303">Реклама заблокирована.</translation>
<translation id="7372973238305370288">результат поиÑка</translation>
<translation id="7374733840632556089">Эта проблема возникает из-за Ñертификата, который вы или другой пользователь уÑтановили на Ñто уÑтройÑтво. Такой Ñертификат не ÑчитаетÑÑ Ð´Ð¾Ð²ÐµÑ€ÐµÐ½Ð½Ñ‹Ð¼, поÑкольку обычно он иÑпользуетÑÑ Ð´Ð»Ñ Ð¾Ñ‚ÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸ перехвата данных в Ñети. Подобный функционал допуÑтим, когда уÑтройÑтво прикреплено к организации или учебному заведению. Так или иначе, мы хотели бы предупредить Ð²Ð°Ñ Ð¾ ÑущеÑтвовании Ñтого Ñертификата. Обратите внимание, что отÑлеживание дейÑтвий может проиÑходить в любом браузере или приложении Ñ Ð´Ð¾Ñтупом в Интернет.</translation>
<translation id="7375818412732305729">Прикреплен файл</translation>
@@ -1726,6 +1755,7 @@
<translation id="7976214039405368314">Ñлишком много запроÑов</translation>
<translation id="7977538094055660992">УÑтройÑтво вывода</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Чтобы проÑматривать контент в режиме дополненной реальноÑти, уÑтановите приложение ARCore.</translation>
<translation id="799149739215780103">Скрепление</translation>
<translation id="7995512525968007366">Ðе указано</translation>
<translation id="800218591365569300">Закройте другие вкладки и программы, чтобы оÑвободить памÑÑ‚ÑŒ.</translation>
@@ -1853,24 +1883,38 @@
<translation id="8507227106804027148">ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока</translation>
<translation id="8508648098325802031">Значок поиÑка</translation>
<translation id="8522552481199248698">Защитите Ñвой аккаунт Google и Ñмените пароль Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Chrome.</translation>
+<translation id="8525306231823319788">ПолноÑкранный режим</translation>
<translation id="8530813470445476232">Удалить иÑторию браузера, файлы cookie, кеш и другие данные в наÑтройках Chrome</translation>
<translation id="8533619373899488139">Чтобы поÑмотреть ÑпиÑок заблокированных URL и узнать, какие ещё правила заданы ÑиÑтемным админиÑтратором, перейдите на Ñтраницу &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
<translation id="8541158209346794904">УÑтройÑтво Bluetooth</translation>
<translation id="8542014550340843547">Три Ñкобы внизу</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Сообщите о зараженном Ñайте<ph name="END_ERROR_LINK" />. ЕÑли вы готовы подвергнуть риÑку личные данные, то можете <ph name="BEGIN_LINK" />перейти на Ñтраницу<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC-код указан на обратной Ñтороне карты.</translation>
+<translation id="8558485628462305855">Чтобы проÑматривать контент в режиме дополненной реальноÑти, обновите приложение ARCore.</translation>
<translation id="8559762987265718583">Ðе удалоÑÑŒ уÑтановить защищенное Ñоединение Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-за неверных наÑтроек ÑиÑтемных чаÑов и ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">ÐеÑколько документов/без разбора по копиÑм</translation>
<translation id="8564985650692024650">Chromium рекомендует ÑброÑить пароль, иÑпользуемый в подразделении <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, еÑли вы указывали его на других Ñайтах.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Ðа Ñтом уÑтройÑтве не будут ÑохранÑÑ‚ÑŒÑÑ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñтраницы, которые вы проÑматриваете в Ñтом окне;
+ <ph name="LIST_ITEM" />файлы cookie и данные Ñайтов.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ИÑпользовать Touch ID Ð´Ð»Ñ Ð±Ñ‹Ñтрого Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ ÐºÐ°Ñ€Ñ‚</translation>
<translation id="858637041960032120">Добавьте номер</translation>
<translation id="8589998999637048520">Лучшее качеÑтво</translation>
+<translation id="8600271352425265729">Только в Ñтот раз</translation>
<translation id="860043288473659153">Ð˜Ð¼Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†Ð° карты</translation>
<translation id="8606726445206553943">иÑпользование MIDI-уÑтройÑтв</translation>
+<translation id="8612761427948161954">ЗдравÑтвуйте, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Ð’Ñ‹ иÑпользуете гоÑтевой режим.</translation>
<translation id="861775596732816396">Размер: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ðет подходÑщих паролей. Показать вÑе Ñохраненные пароли.</translation>
<translation id="8625384913736129811">Сохранить карту на Ñтом уÑтройÑтве</translation>
+<translation id="8627040765059109009">Съемка Ñкрана возобновлена</translation>
<translation id="8657078576661269990">ВозможноÑÑ‚ÑŒ делитьÑÑ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚Ð¾Ð¼ Ñ Ñайта <ph name="ORIGIN_NAME" /> Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ машинами <ph name="VM_NAME_1" /> и <ph name="VM_NAME_2" /> заблокирована админиÑтратором.</translation>
<translation id="8663226718884576429">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ заказе, <ph name="TOTAL_LABEL" />, дополнительные ÑведениÑ</translation>
<translation id="867224526087042813">ПодпиÑÑŒ</translation>
@@ -1933,6 +1977,7 @@
<translation id="8912362522468806198">Ðккаунт Google</translation>
<translation id="8913778647360618320">Кнопка ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑпоÑобами оплаты. Ðажмите Ввод, чтобы изменить данные о ÑпоÑобах оплаты и банковÑких картах в наÑтройках Chrome.</translation>
<translation id="8918231688545606538">ÐŸÐ¾Ð´Ð¾Ð·Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñтраница</translation>
+<translation id="8922013791253848639">Ð’Ñегда разрешать рекламу на Ñтом Ñайте</translation>
<translation id="892588693504540538">ОтверÑтие в правом верхнем углу</translation>
<translation id="8931333241327730545">Сохранить Ñту карту в аккаунте Google?</translation>
<translation id="8932102934695377596">ЧаÑÑ‹ отÑтают</translation>
@@ -2004,6 +2049,7 @@
<translation id="9183302530794969518">Google Документы</translation>
<translation id="9183425211371246419">Ðа Ñайте <ph name="HOST_NAME" /> иÑпользуетÑÑ Ð½ÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ñ‹Ð¹ протокол.</translation>
<translation id="9191834167571392248">ОтверÑтие в левом нижнем углу</translation>
+<translation id="9199905725844810519">Печать заблокирована</translation>
<translation id="9205078245616868884">Данные зашифрованы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кодовой фразы. Введите ее, чтобы начать Ñинхронизацию.</translation>
<translation id="9207861905230894330">Ðе удалоÑÑŒ добавить Ñтатью</translation>
<translation id="9213433120051936369">ÐаÑтроить вид</translation>
@@ -2014,8 +2060,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Ð’Ñ‹ можете потерÑÑ‚ÑŒ доÑтуп к аккаунту Google. Рекомендуем немедленно Ñменить пароль. ПоÑле Ñтого потребуетÑÑ Ñнова войти в аккаунт.</translation>
<translation id="939736085109172342">ÐÐ¾Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°</translation>
+<translation id="945522503751344254">Отправить отзыв</translation>
<translation id="945855313015696284">Проверьте данные и удалите недейÑтвительные карты.</translation>
<translation id="950736567201356821">Три отверÑÑ‚Ð¸Ñ Ñверху</translation>
+<translation id="951941430552851965">ÐдминиÑтратор приоÑтановил запиÑÑŒ Ñкрана из-за отображаемого контента.</translation>
<translation id="961663415146723894">Скрепление Ñнизу</translation>
<translation id="962484866189421427">Переход на Ñту Ñтраницу может привеÑти к уÑтановке вредоноÑных приложений, маÑкирующихÑÑ Ð¿Ð¾Ð´ безопаÑные программы или Ñобирающих данные, по которым Ð²Ð°Ñ Ð¼Ð¾Ð¶Ð½Ð¾ отÑледить. <ph name="BEGIN_LINK" />Ð’Ñе равно продолжить<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ÐžÑ„Ð¸Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ñборка</translation>
diff --git a/chromium/components/strings/components_strings_si.xtb b/chromium/components/strings/components_strings_si.xtb
index 8c3b45b4e80..f7443fa5fdc 100644
--- a/chromium/components/strings/components_strings_si.xtb
+++ b/chromium/components/strings/components_strings_si.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">ඔබ ඔබේ සංවිධà·à¶±à¶º විසින් කළමනà·à¶šà¶»à¶«à¶º නොකරන ලද වෙබ් අඩවියක ඔබේ මුරපදය ඇතුළු කර ඇත. ඔබේ ගිණුම ආරක්ෂ෠කිරීම සඳහ෠වෙනත් යෙදුම් සහ අඩවි මත ඔබේ මුරපදය නà·à·€à¶­ භà·à·€à·’ත නොකරන්න.</translation>
<translation id="1263231323834454256">කියවීම් ලà·à¶ºà·’ස්තුව</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ මෙම උපà·à¶‚ගයේ නොපවතිනු ඇති ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />මෙම කවුළුව තුළ ඔබ බලන පිටු
+ <ph name="LIST_ITEM" />කුකි සහ අඩවි දත්ත
+ <ph name="LIST_ITEM" />ගිණුම් තොරතුරු (<ph name="LINK_BEGIN" />වරන්න<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">නංව෠ගà·à¶±à·“මේ ක්â€à¶»à¶¸à¶º</translation>
<translation id="1281476433249504884">අට්ටිය 1</translation>
<translation id="1285320974508926690">මෙම අඩවිය කිසිවිට පරිවර්තනය නොකරන්න</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">ඔබේ Google ගිණුම තුළ සුරà·à¶šà·“ ඇති මුරපද භà·à·€à·’ත කිරීමට පුරන්න</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> හි පිටු පරිවර්තන නොකෙරේ</translation>
<translation id="2053553514270667976">ZIP කේතය</translation>
+<translation id="2054665754582400095">ඔබගේ සිටීම</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{යà·à¶¢à¶±à· 1}one{යà·à¶¢à¶±à· #}other{යà·à¶¢à¶±à· #}}</translation>
<translation id="2079545284768500474">පසුගමනය</translation>
<translation id="20817612488360358">පද්ධති ප්â€à¶»à·œà¶šà·Šà·ƒà·’ පසුතල සකස෠ඇත්තේ භà·à·€à·’ත෠කිරීමට වන නමුත් සවිස්තර ප්â€à¶»à·œà¶šà·Šà·ƒà·’ වින්â€à¶ºà·à·ƒà¶šà¶»à¶«à¶ºà¶¯ නිà·à·Šà¶ à·’තව දක්ව෠තිබේ.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android යෙදුම්</translation>
<translation id="2107021941795971877">මුද්â€à¶»à¶« සහය</translation>
<translation id="2108755909498034140">ඔබේ පරිගණකය යළි අරඹන්න</translation>
+<translation id="2111166930115883695">à·€à·à¶¯à¶±à¶º කිරීමට ඉඩ යතුර ඔබන්න</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">කà·à¶©à·Šà¶´à¶­</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> විසින් ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º කළ නිස෠නොතක෠හරින ලදි.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">ගෙවීම අවලංගු කරන්න</translation>
<translation id="2147827593068025794">පසුබිම සමමුහුර්ත කිරීම</translation>
<translation id="2148613324460538318">කà·à¶©à·Šà¶´à¶­ එක් කරන්න</translation>
+<translation id="2149968176347646218">සබà·à¶³à·”ම සුරක්ෂිත නොවේ</translation>
<translation id="2154054054215849342">ඔබගේ වසම සඳහ෠සමමුහුර්ත කිරීම ලබ෠ගත නොහà·à¶šà·’ය</translation>
<translation id="2154484045852737596">කà·à¶©à·Šà¶´à¶­ සංස්කරණය කරන්න</translation>
<translation id="2161656808144014275">පà·à¶¨à¶º</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">ප්â€à¶»à¶­à·’පත්ති</translation>
<translation id="2183608646556468874">දුරකථන අංකය</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{ලිපින 1}one{ලිපින #}other{ලිපින #}}</translation>
-<translation id="2187243482123994665">පරිà·à·“ලකයà·à¶œà·š සිටීම</translation>
<translation id="2187317261103489799">හදුනà·à¶œà¶±à·Šà¶± (පෙරනිමි)</translation>
<translation id="2188375229972301266">පහළට ඇනීම් බොහොමයක්</translation>
<translation id="2202020181578195191">වලංගු කල් ඉකුත් වීමේ වසරක් ඇතුළු කරන්න</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">ව්â€à¶ºà·à¶¢ අඩවියක් ඉදිරියෙනි</translation>
<translation id="2850739647070081192">Invite (ලියුම් කවරය)</translation>
<translation id="2856444702002559011">ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶±à·Š <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> වෙතින් ඔබේ තොරතුරු සොරකම් කිරීමට උත්සà·à·„ කරනව෠විය à·„à·à¶š (උදà·à·„රණ ලෙස, මුරපද, පණිවිඩ, හ෠ණයපත්). <ph name="BEGIN_LEARN_MORE_LINK" />තව දà·à¶± ගන්න<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">මෙම වෙබ් අඩවිය ආක්â€à¶»à¶¸à¶«à·’ක හ෠නොමඟ යවන දà·à¶±à·Šà·€à·“ම් පෙන්වයි.</translation>
<translation id="2878197950673342043">පà·à·ƒà·Šà¶§à¶» නà·à¶¸à·“ම</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">කවුළු තà·à¶¶à·“ම</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">Google වෙතින් යà·à¶¢à¶±à·</translation>
<translation id="3002501248619246229">ආදà·à¶± බඳුන් මà·à¶°à·Šâ€à¶º පරීක්â€à·‚෠කරන්න</translation>
<translation id="3005723025932146533">සුරà·à¶šà·’ පිටපතක් පෙන්වන්න</translation>
-<translation id="3007719053326478567">මෙම අන්තර්ගතය මුද්â€à¶»à¶«à¶º කිරීම ඔබගේ පරිපà·à¶½à¶š විසින් අවහිර කර ඇත</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> සඳහ෠CVC ඇතුළු කරන්න. ඔබ තහවුරු කළ පසු, ඔබේ කà·à¶©à·Šà¶´à¶­à·Š විස්තර මෙම අඩවිය සමග බෙද෠ගනු ඇත.</translation>
<translation id="3010559122411665027">"<ph name="ENTRY_INDEX" />": <ph name="ERROR" /> ලà·à¶ºà·’ස්තුගත කරන්න</translation>
<translation id="301521992641321250">ස්වයංක්â€à¶»à·’යව අවහිර කර ඇත</translation>
<translation id="3016780570757425217">ඔබේ පිහිටීම දà·à¶± ගන්න</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, යà·à¶¢à¶±à·à·€ ඉවත් කිරීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න.</translation>
<translation id="3023071826883856138">You4 (ලියුම් කවරය)</translation>
<translation id="3024663005179499861">à·€à·à¶»à¶¯à·’ ප්â€à¶»à¶­à·’පත්ති වර්ගය</translation>
<translation id="3037605927509011580">අනේ, අපොයි!</translation>
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">පිටුසලකුණු කළ</translation>
<translation id="3209034400446768650">පිටුවට මුදල් අය කළ à·„à·à¶šà·’ය</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> මත ඔබේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸ නිරීක්â€à·‚ණ කෙරේ</translation>
+<translation id="3212623355668894776">ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š මෙම උපà·à¶‚ගයෙන් මà·à¶šà·™à¶± ලෙස සියලු ආගන්තුක කවුළු වසන්න.</translation>
<translation id="3215092763954878852">WebAuthn භà·à·€à·’ත කළ නොහà·à¶šà·’ විය</translation>
<translation id="3218181027817787318">අදà·à·…</translation>
<translation id="3225919329040284222">සේවà·à¶¯à·à¶ºà¶šà¶º සහතිකයක් ඉදිරිපත් කළ නමුත් එය තිළà·à¶½à·’ පොරොත්තු සමඟ නොගà·à¶½à¶´à·š. ඔබේ ආරක්ෂà·à·€ සඳහ෠එම පොරොත්තු ඇතුළත් කර ඇත්තේ නිà·à·Šà¶ à·’ත අධි-ආරක්ෂිත අඩවි පමණි.</translation>
@@ -700,6 +712,7 @@
<translation id="3784372983762739446">බ්ලූටූත් උපà·à¶‚ග</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> කල් ඉකුත් වේ</translation>
<translation id="3789155188480882154">ප්â€à¶»à¶¸à·à¶«à¶º 16</translation>
+<translation id="3789841737615482174">ස්ථà·à¶´à¶±à¶º</translation>
<translation id="3793574014653384240">මෑතදී සිදු වූ බිඳ à·€à·à¶§à·“ම් සංඛ්â€à¶ºà·à·€ සහ හේතු</translation>
<translation id="3797522431967816232">Prc3 (ලියුම් කවරය)</translation>
<translation id="3799805948399000906">අකුරු වර්ගය ඉල්ලුවà·</translation>
@@ -751,6 +764,7 @@
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">යතුර "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ලියුම් කවරය)</translation>
+<translation id="4067669230157909013">තිර ග්â€à¶»à·„ණය නà·à·€à¶­ පටන් ගන්න෠ලදි.</translation>
<translation id="4067947977115446013">වලංගු ලිපිනයක් එක් කරන්න</translation>
<translation id="4072486802667267160">ඔබේ ඇණවුම à·ƒà·à¶šà·ƒà·“මේ දà·à·‚යක් විය. නà·à·€à¶­ උත්සà·à·„ කරන්න.</translation>
<translation id="4075732493274867456">සේවà·à¶½à·à¶·à·’ය෠සහ සේවà·à¶¯à·à¶ºà¶šà¶ºà· පොදු SSL ප්â€à¶»à·œà¶§à·œà¶šà·à¶½ අනුවà·à¶¯à¶ºà¶šà·Š හ෠කේතà·à¶‚ක කට්ටලයක් සඳහ෠සහà·à¶º නොදක්වයි.</translation>
@@ -832,6 +846,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> පිටුව සඳහ෠සිඟිති රුව</translation>
<translation id="42981349822642051">දිගහරින්න</translation>
<translation id="4300675098767811073">දකුණට බොහ෠වරක් අනින්න</translation>
+<translation id="4302514097724775343">à·€à·à¶¯à¶±à¶º කිරීමට ඩයින෠තට්ටු කරන්න</translation>
<translation id="4302965934281694568">Chou3 (ලියුම් කවරය)</translation>
<translation id="4305666528087210886">ඔබගේ ගොනුවට පිවිසීමට නොහà·à¶šà·’ විය.</translation>
<translation id="4305817255990598646">ස්විචය</translation>
@@ -910,6 +925,7 @@
<translation id="4658638640878098064">ඉහළ වම ස්ටේපල් කරන්න</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">අතත්â€à¶º යථà·à¶»à·Šà¶®à¶º</translation>
+<translation id="4675657451653251260">ඔබ ආගන්තුක ප්â€à¶»à¶šà·à¶»à¶º තුළ Chrome පà·à¶­à·’කඩෙහි තතු කිසිවක් නොදකිනු ඇත. මුරපද සහ ගෙවීම් ක්â€à¶»à¶¸ à·€à·à¶±à·’ Google ගිණුම් තතුවලට ප්â€à¶»à·€à·šà· වීමට ඔබට <ph name="LINK_BEGIN" />පිරීමට<ph name="LINK_END" /> à·„à·à¶šà·’ය.</translation>
<translation id="467662567472608290">මෙම සේවà·à¶¯à·à¶ºà¶šà¶ºà¶§ එය <ph name="DOMAIN" /> බව සනà·à¶® කිරීමට නොහà·à¶šà·’ විය; එහි ආරක්ෂණ සහතිකයේ දà·à·‚ අඩංගුය. මෙය à·€à·à¶»à¶¯à·’ වින්â€à¶ºà·à·ƒ කිරීමක් හ෠ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶šà·” ඔබගේ සබà·à¶³à·”මට බà·à¶°à· කිරීමක් නිස෠විය à·„à·à¶šà·’ය.</translation>
<translation id="4677585247300749148"><ph name="URL" /> හට ප්â€à¶»à·€à·šà·à·Šâ€à¶ºà¶­à· සිදුවීම්වලට ප්â€à¶»à¶­à·’චà·à¶» දà·à¶šà·Šà·€à·“මට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -937,6 +953,12 @@
<translation id="4761104368405085019">මයික්â€à¶»à·œà·™à·†à·à¶±à¶º භà·à·€à·’ත෠කරන්න</translation>
<translation id="4764776831041365478"><ph name="URL" /> à·„à·’ වෙබ් පිටුව තà·à·€à¶šà·à¶½à·’කව ක්â€à¶»à·’ය෠නොකරයි නà·à¶­à·„ොත් එය ස්ථිරවම වෙනත් වෙබ් ලිපිනයක් වෙත ගෙනගොස් ඇත.</translation>
<translation id="4766713847338118463">පහළට දෙවරක් ස්ටේපල්</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ මෙම උපà·à¶‚ගයෙහි පවතින ඔබගේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ඔබ මෙම කවුළුවෙහි බà·à¶œà¶±à·Šà¶±à· ඕනෑම ගොනුවක්
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">නොදන්න෠දà·à·‚යක් ඇති විය.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{උත්පතනය අවහිර කරන ලදී}one{උත්පතන #ක් අවහිර කරන ලදී}other{උත්පතන #ක් අවහිර කරන ලදී}}</translation>
<translation id="4780366598804516005">තà·à¶´à·à¶½à·Š පෙට්ටිය 1</translation>
@@ -1099,11 +1121,13 @@
<translation id="5386426401304769735">සහතික දà·à¶¸à¶ºà·™à·„à·’ SHA-1 භà·à·€à·’තයෙන් අත්සන් කළ සහතිකයක් අඩංගුය.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">දකුණු දà·à¶»à¶º මසන්න</translation>
+<translation id="5398772614898833570">වෙළඳ දà·à¶±à·Šà·€à·“ම් අවහිරයි</translation>
<translation id="5400836586163650660">අළු</translation>
<translation id="540969355065856584">මෙම සේවà·à¶¯à·à¶ºà¶šà¶ºà¶§ එය <ph name="DOMAIN" /> බව සනà·à¶® කිරීමට නොහà·à¶šà·’ විය; එහි ආරක්ෂණ සහතිකය මෙම අවස්ථවේ වලංගු නà·à¶­. මෙය à·€à·à¶»à¶¯à·’ වින්â€à¶ºà·à·ƒ කිරීමක් හ෠ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶šà·” ඔබගේ සබà·à¶³à·”මට බà·à¶°à· කිරීමක් නිස෠විය à·„à·à¶šà·’ය.</translation>
<translation id="541416427766103491">අට්ටිය 4</translation>
<translation id="5421136146218899937">පිරික්සුම් දත්ත හිස් කරන්න...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> හට ඔබට දà·à¶±à·”ම්දීම් එවීමට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
+<translation id="542872847390508405">ඔබ අමුත්තෙකු ලෙස ගවේà·à¶±à¶º කරයි</translation>
<translation id="5430298929874300616">පිටු සලකුණ ඉවත් කරන්න</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />": <ph name="ERROR" /> à·„à·’ පරිපà·à¶§à·’ තහවුරු කිâ€à¶»à·“මේ දà·à·‚යකි</translation>
<translation id="5443468954631487277">ප්â€à¶»à¶­à·’වර්තන පිළිවෙළ මුහුණු ඉහළට</translation>
@@ -1145,12 +1169,12 @@
<translation id="5571083550517324815">මෙම ලිපිනයෙන් ලබ෠ගà·à¶±à·“මට නොහà·à¶šà·’ය. වෙනත් ලිපිනයක් තà·à¶»à¶±à·Šà¶±.</translation>
<translation id="5580958916614886209">ඔබේ කල් ඉකුත් වීමේ මà·à·ƒà¶º පරික්ෂ෠කර නà·à·€à¶­ උත්සà·à·„ කරන්න</translation>
<translation id="5586446728396275693">සුරà·à¶šà·– ලිපින නà·à¶­</translation>
+<translation id="5593349413089863479">සබà·à¶³à·”ම පූර්ණ à·€à·à¶ºà·™à¶±à·Š ආරක්ෂිත නà·à¶­</translation>
<translation id="5595485650161345191">ලිපිනය සංස්කරණය</translation>
<translation id="5598944008576757369">ගෙවීමේ ක්â€à¶»à¶¸à¶º තà·à¶»à·à¶œà¶±à·Šà¶±</translation>
<translation id="560412284261940334">කළමනà·à¶šà¶»à¶«à¶º සහà·à¶º නොදක්වයි</translation>
<translation id="5605670050355397069">ලෙජරය</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">මෙම වෙබ් අඩවිය ව්â€à¶ºà·à¶¢ හ෠වංචනික විය à·„à·à¶š. Chrome දà·à¶±à·Š පිට වීම නිර්දේ෠කරයි.</translation>
<translation id="5610142619324316209">සම්බන්ධතà·à·€ පරීක්ෂ෠කරමින්</translation>
<translation id="5610807607761827392">ඔබට කà·à¶©à·Šà¶´à¶­à·Š සහ ලිපින <ph name="BEGIN_LINK" />à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළ කළමනà·à¶šà¶»à¶«à¶º කළ à·„à·à¶šà·’ය.</translation>
<translation id="561165882404867731">Google පරිවර්තනය සමඟ මෙම පිටුව පරිවර්තනය කරන්න</translation>
@@ -1222,6 +1246,7 @@
<translation id="5901630391730855834">කහ</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" />ගේ මූලà·à¶»à¶¸à·Šà¶· ප්â€à¶»à¶­à·’පත්තියට අනුව අවහිර කර ඇත.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (සමමුහුර්තයි)</translation>
+<translation id="5913377024445952699">තිර ග්â€à¶»à·„ණය විරà·à¶¸ කරන ලදි</translation>
<translation id="59174027418879706">සබලයි</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶šà¶ºà·’</translation>
@@ -1234,6 +1259,7 @@
<translation id="5963413905009737549">කොටස</translation>
<translation id="5967592137238574583">සම්බන්ධත෠තතු සංස්කරණය</translation>
<translation id="5967867314010545767">ඉතිහà·à·ƒà¶ºà·™à¶±à·Š මකන්න</translation>
+<translation id="5968793460449681917">සෑම පිවිසීමකදීම</translation>
<translation id="5975083100439434680">විà·à·à¶½à¶±à¶º අඩු කරන්න</translation>
<translation id="5979084224081478209">මුරපද පරීක්â€à·‚෠කරන්න</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1389,6 +1415,7 @@
<translation id="6587923378399804057">ඔබ පිටපත් කළ සබà·à¶³à·’ය</translation>
<translation id="6591833882275308647">ඔබේ <ph name="DEVICE_TYPE" /> කළමන෠නොකෙරේ</translation>
<translation id="6596325263575161958">සංකේතනය කිරීමේ විකල්ප</translation>
+<translation id="6596892391065203054">මෙම අන්තර්ගතය මුද්â€à¶»à¶«à¶º කිරීම ඔබගේ පරිපà·à¶½à¶š විසින් අවහිර කර ඇත.</translation>
<translation id="6604181099783169992">චලිත හ෠ආලà·à¶š සංවේදක</translation>
<translation id="6609880536175561541">Prc7 (ලියුම් කවරය)</translation>
<translation id="6612358246767739896">ආරක්ෂිත අන්තර්ගතය</translation>
@@ -1448,6 +1475,7 @@
<translation id="6895330447102777224">ඔබේ කà·à¶©à·Šà¶´à¶­ තහවුරු කර ඇත</translation>
<translation id="6897140037006041989">භà·à·€à·’ත නියà·à¶¢à·’ත</translation>
<translation id="6898699227549475383">සංවිධà·à¶±à¶º (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> හට මේවà·à¶§ ඉඩ දෙන්න:</translation>
<translation id="6910240653697687763"><ph name="URL" /> හට ඔබේ MIDI උපà·à¶‚ගවල සම්පූර්ණ පà·à¶½à¶±à¶º ලබ෠ගà·à¶±à·“මට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="6915804003454593391">පරිà·à·“ලක</translation>
<translation id="6934672428414710184">මෙම නම ඔබගේ Google ගිණුමෙනි</translation>
@@ -1559,6 +1587,7 @@
<translation id="7346048084945669753">අනුබද්ධ වී ඇත්තේ:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">විධà·à¶± පේළිය</translation>
+<translation id="7359588939039777303">වෙළඳ දà·à¶±à·Šà·€à·“ම් අවහිරයි.</translation>
<translation id="7372973238305370288">සෙවුම් ප්â€à¶»à¶®à·’පල</translation>
<translation id="7374733840632556089">මෙම ගà·à¶§à¶½à·”à·€ සිදු වන්නේ ඔබ හ෠වෙනත් කෙනෙක් ඔබේ උපà·à¶‚ගය මත ස්ථà·à¶´à¶± කර ඇති සහතිකයක් හේතුවෙනි. එම සහතිකය ජà·à¶½ නිරීක්â€à·‚ණ කිරීමටත් අතුරු ඇරීමටත් භà·à·€à·’ත වන බවට දන්න෠අතර, Chrome විසින් විà·à·Šà·€à·à·ƒ නොකෙරේ. පà·à·ƒà¶½à·Š හ෠සමà·à¶œà¶¸à·Š ජà·à¶½à¶ºà¶šà·Š මත à·€à·à¶±à·’ නිරීක්â€à·‚ණ කිරීම සඳහ෠යම් නීත්â€à¶ºà·à¶±à·”කූල සංදර්භ පවතින අතරතුර, ඔබට එය නà·à·€à·à¶­à·Šà·€à·’ය නොහà·à¶šà·’ නමුත් ඔබ එය සිදු වන බවට දà·à¶± සිටීම ගà·à¶± Chrome කà·à¶¸à¶­à·’ වෙයි. වෙබයට ප්â€à¶»à·€à·šà· වන ඕනෑම බ්â€à¶»à·€à·”සරයක් හ෠යෙදුමක් තුළ නිරීක්â€à·‚ණය සිදු විය à·„à·à¶š.</translation>
<translation id="7375818412732305729">ගොනුව අමුණ෠ඇත</translation>
@@ -1733,6 +1762,7 @@
<translation id="7976214039405368314">ඉල්ලීම් ඉත෠වà·à¶©à·’ය</translation>
<translation id="7977538094055660992">ප්â€à¶»à¶­à·’දà·à¶± උපà·à¶‚ගය</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">à·€à·à¶©à·’ දියුණු කළ යතà·à¶»à·Šà¶® අන්තර්ගතය බà·à¶½à·“මට, ARCore ස්ථà·à¶´à¶±à¶º කරන්න</translation>
<translation id="799149739215780103">බඳින්න</translation>
<translation id="7995512525968007366">නියම නොකළ</translation>
<translation id="800218591365569300">මතකය නිදහස් කිරීමට වෙනත් පටිති à·„à· à·€à·à¶©à·ƒà¶§à·„න් à·€à·à·ƒà·“මට උත්සà·à·„ කරන්න.</translation>
@@ -1860,24 +1890,38 @@
<translation id="8507227106804027148">විධà·à¶± පේළිය</translation>
<translation id="8508648098325802031">සෙවීමේ නිරූපකය</translation>
<translation id="8522552481199248698">Chrome ඔබට ඔබේ Google ගිණුම ආරක්â€à·‚෠කිරීමටත් ඔබේ මුරපදය වෙනස් කිරීමටත් ඔබට උදවු කළ à·„à·à¶š.</translation>
+<translation id="8525306231823319788">සම්පුර්ණ තිරය</translation>
<translation id="8530813470445476232">ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ඉතිහà·à·ƒà¶º, කුකි, à·„à·à¶¹à·’ලි සහ තවත් දේ Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ හිස් කරන්න</translation>
<translation id="8533619373899488139">ඔබේ පද්ධති පරිපà·à¶½à¶š විසින් පනවන ලද අවහිර කළ URL සහ වෙනත් ප්â€à¶»à¶­à·’පත්ති බà·à¶½à·“මට &lt;strong&gt;chrome://policy&lt;/strong&gt; වෙත පිවිසෙන්න.</translation>
<translation id="8541158209346794904">බ්ලූටූත් උපà·à¶‚ගය</translation>
<translation id="8542014550340843547">පහළට තුන් වරක් ස්ටේපල් කරන්න</translation>
<translation id="8543181531796978784">ඔබට <ph name="BEGIN_ERROR_LINK" />අනà·à·€à¶»à¶«à¶º කර ගà·à¶±à·“මේ ගà·à¶§à¶½à·”වක් à·€à·à¶»à·Šà¶­à· කිරීමට<ph name="END_ERROR_LINK" /> à·„à·, ඔබට ඔබගේ ආරක්ෂà·à·€ සඳහ෠වන අවදà·à¶±à¶¸ à·€à·à¶§à·„ෙන්නේ නම්, <ph name="BEGIN_LINK" />මෙම අනà·à¶»à¶šà·Šà·‚ිත වෙබ් අඩවිය වෙත පිවිසීමට<ph name="END_LINK" /> à·„à·à¶šà·’ය.</translation>
<translation id="8557066899867184262">CVC ඔබේ කà·à¶©à·Šà¶´à¶­ පිටුපස පිහිට෠ඇත.</translation>
+<translation id="8558485628462305855">à·€à·à¶©à·’ දියුණු කළ යතà·à¶»à·Šà¶® අන්තර්ගතය බà·à¶½à·“මට, ARCore යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්න</translation>
<translation id="8559762987265718583">ඔබගේ උපà·à¶‚ගයේ දිනය සහ වේලà·à·€ (<ph name="DATE_AND_TIME" />) නිවà·à¶»à¶¯à·’ නොවන නිස෠<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> වෙත පෞද්ගලික සම්බන්ධයක් සෑදිය නොහà·à¶šà·’යි.</translation>
<translation id="8564182942834072828">වෙන් වූ ලේඛන/එකතු නොකළ පිටපත්</translation>
<translation id="8564985650692024650">Chromium ඔබේ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> මුරපදය ඔබ වෙනත් අඩවිවල නà·à·€à¶­ භà·à·€à·’ත කර තිබේ නම් යළි à·ƒà·à¶šà·ƒà·“මට නිර්දේ෠කරයි.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ මෙම උපà·à¶‚ගයේ නොපවතිනු ඇති ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />මෙම කවුළුව තුළ ඔබ බලන පිටු
+ <ph name="LIST_ITEM" />කුකි සහ අඩවි දත්ත
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">කà·à¶©à·Šà¶´à¶­à·Š වඩ෠වේගයෙන් තහවුරු කිරීමට ස්පර්෠හà·à¶³à·”නුම භà·à·€à·’ත කරන්න</translation>
<translation id="858637041960032120">දුරකථන අංකය එක් කරන්න</translation>
<translation id="8589998999637048520">ඉහළම ගුණත්වය</translation>
+<translation id="8600271352425265729">මෙම වතà·à·€à·š පමණී</translation>
<translation id="860043288473659153">කà·à¶©à·Šà¶´à¶­à·Š හිමිකරුගේ නම</translation>
<translation id="8606726445206553943">ඔබේ MIDI උපකරණ භà·à·€à·’ත කරන්න</translation>
+<translation id="8612761427948161954">ආයුබà·à·€à¶±à·Š <ph name="USERNAME" />,
+ <ph name="BR" />
+ ඔබ අමුත්තකු ලෙස බ්â€à¶»à·€à·”ස් කරයි</translation>
<translation id="861775596732816396">ප්â€à¶»à¶¸à·à¶«à¶º 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ගà·à·…පෙන මුරපද නà·à¶­. සුරà·à¶šà·’ මුරපද සියල්ල පෙන්වන්න.</translation>
<translation id="8625384913736129811">මෙම උපà·à¶‚ගයට මෙම කà·à¶©à·Šà¶´à¶­ සුරකින්න</translation>
+<translation id="8627040765059109009">තිර ග්â€à¶»à·„ණය නà·à·€à¶­ පටන් ගන්න෠ලදි</translation>
<translation id="8657078576661269990">ඔබගේ පරිපà·à¶½à¶š <ph name="ORIGIN_NAME" /> වෙතින්<ph name="VM_NAME_1" /> සහ <ph name="VM_NAME_2" /> වෙත බෙද෠ගà·à¶±à·“ම අවහිර කර ඇත</translation>
<translation id="8663226718884576429">ඇණවුමේ à·ƒà·à¶»à·à¶‚à·à¶º, <ph name="TOTAL_LABEL" />, තව විස්තර</translation>
<translation id="867224526087042813">අත්සන</translation>
@@ -1940,6 +1984,7 @@
<translation id="8912362522468806198">Google ගිණුම</translation>
<translation id="8913778647360618320">ගෙවීම් ක්â€à¶»à¶¸ කළමනà·à¶šà¶»à¶«à¶º කිරීමේ බොත්තම, Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ඔබගේ ගෙවීම් සහ ණය කà·à¶©à·Šà¶´à¶­à·Š තතු කළමනà·à¶šà¶»à¶«à¶º කිරීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
<translation id="8918231688545606538">මෙම පිටුව à·ƒà·à¶š සහිතයි</translation>
+<translation id="8922013791253848639">මෙම අඩවිය මත වෙළඳ දà·à¶±à·Šà·€à·“ම්වලට à·ƒà·à¶¸ විටම ඉඩ දෙන්න</translation>
<translation id="892588693504540538">ඉහළ දකුණ අනින්න</translation>
<translation id="8931333241327730545">ඔබට ඔබේ Google ගිණුම වෙත මෙම කà·à¶©à·Šà¶´à¶­ සුරà·à¶šà·“මට අවà·à·Šâ€à¶ºà¶¯?</translation>
<translation id="8932102934695377596">ඔබගේ ඔරලà·à·ƒà·”à·€ ඇත්තේ පිටුපසින් ය</translation>
@@ -2011,6 +2056,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> සහà·à¶º නොදක්වන ප්â€à¶»à·œà¶§à·œà¶šà·à¶½à¶ºà¶šà·Š භà·à·€à·’ත කරයි.</translation>
<translation id="9191834167571392248">පහළ වමට අනින්න</translation>
+<translation id="9199905725844810519">මුද්â€à¶»à¶«à¶º කිරීම අවහිර කර ඇත</translation>
<translation id="9205078245616868884">ඔබේ දත්ත ඔබේ සමමුහුර්ත මුරවදන සමඟ සංකේතනය කර ඇත. සමමුහුර්ත කිරීම ආරම්භ කිරීමට ඇතුළු කරන්න.</translation>
<translation id="9207861905230894330">භà·à¶«à·Šà¶©à¶º එකතු කළ නොහà·à¶šà·’ විය.</translation>
<translation id="9213433120051936369">පෙනුම අභිරුචිකරණය කරන්න</translation>
@@ -2021,8 +2067,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">ඔබට ඔබේ Google ගිණුමට ප්â€à¶»à·€à·šà·à¶º අහිමි විය à·„à·à¶š. Chromium දà·à¶±à·Š ඔබේ මුරපදය වෙනස් කිරීම නිර්දේ෠කරයි. පුරන ලෙස ඔබෙන් අසනු ලà·à¶¶à·š.</translation>
<translation id="939736085109172342">නව à·†à·à¶½à·Šà¶©à¶»à¶º</translation>
+<translation id="945522503751344254">අදහස් හ෠යà·à¶¢à¶±à· යවන්න</translation>
<translation id="945855313015696284">පහත තොරතුරු පරීක්â€à·‚෠කර, කිසියම් අවලංගු කà·à¶©à·Šà¶´à¶­à·Š තිබේ නම් මකන්න</translation>
<translation id="950736567201356821">ඉහළ තුන් වරක් අනින්න</translation>
+<translation id="951941430552851965">ඔබගේ තිරයේ අන්තර්ගතය හේතුවෙන් ඔබගේ පරිපà·à¶½à¶š විසින් තිර ග්â€à¶»à·„ණය කිරීම විරà·à¶¸ කරන ලදි.</translation>
<translation id="961663415146723894">පහළ බඳින්න</translation>
<translation id="962484866189421427">වෙනත් දෙයක් බවට පෙන්වීමට උත්සà·à·„ කරන හ෠ඔබට හඹ෠යà·à¶¸à¶§ භà·à·€à·’ත෠කළ à·„à·à¶šà·’ දත්ත එකතු කරන රà·à·€à¶§à·’ලිකà·à¶» යෙදුම් ස්ථà·à¶´à¶±à¶º කිරීමට මෙම අන්තර්ගතය මගින් උත්සà·à·„ කිරීමට à·„à·à¶šà·’ය. <ph name="BEGIN_LINK" />කෙසේ වුවත් පෙන්වන්න<ph name="END_LINK" /></translation>
<translation id="969892804517981540">නිල තà·à¶±à·”ම</translation>
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index c0ae3b63049..0e2cdef9b35 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -80,6 +80,14 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Zadali ste heslo na webe, ktorý nie je spravovaný vaÅ¡ou organizáciou. Ak chcete, aby bol váš úÄet chránený, nepoužívajte dané heslo pre iné aplikácie a weby.</translation>
<translation id="1263231323834454256">Čitateľský zoznam</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivita, ktorá nezostane v tomto zariadení:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stránky zobrazené v tomto okne;
+ <ph name="LIST_ITEM" />súbory cookie a údaje webov;
+ <ph name="LIST_ITEM" />informácie o úÄte (<ph name="LINK_BEGIN" />odhlásiÅ¥ sa<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Spôsob vyzdvihnutia</translation>
<translation id="1281476433249504884">OdkladaÄ Ä. 1</translation>
<translation id="1285320974508926690">Nikdy neprekladať tieto webové stránky</translation>
@@ -279,6 +287,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="204357726431741734">PrihlásiÅ¥ sa a používaÅ¥ heslá uložené vo vaÅ¡om úÄte Google</translation>
<translation id="2053111141626950936">Stránky v jazyku <ph name="LANGUAGE" /> nebudú prekladané.</translation>
<translation id="2053553514270667976">PSČ</translation>
+<translation id="2054665754582400095">Vaša prítomnosť</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 návrh}few{# návrhy}many{# návrhu}other{# návrhov}}</translation>
<translation id="2079545284768500474">Späť</translation>
<translation id="20817612488360358">Používanie systémových nastavení servera proxy je nastavené, avÅ¡ak je urÄená aj explicitná konfigurácia servera proxy.</translation>
@@ -292,6 +301,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2102495993840063010">Aplikácie pre Android</translation>
<translation id="2107021941795971877">Podpory tlaÄe</translation>
<translation id="2108755909498034140">ReÅ¡tartujte poÄítaÄ</translation>
+<translation id="2111166930115883695">Ak chcete hraÅ¥, stlaÄte medzerník</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Ignorované, pretože bolo prepísané pravidlom <ph name="POLICY_NAME" />.</translation>
@@ -303,17 +313,17 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="214556005048008348">Zrušiť platbu</translation>
<translation id="2147827593068025794">Synchronizácia na pozadí</translation>
<translation id="2148613324460538318">Pridať kartu</translation>
+<translation id="2149968176347646218">Pripojenie nie je zabezpeÄené</translation>
<translation id="2154054054215849342">Synchronizácia nie je pre vašu doménu k dispozícii</translation>
<translation id="2154484045852737596">Úprava karty</translation>
<translation id="2161656808144014275">Text</translation>
<translation id="2164510882479075877">Skontrolujte, Äi nie je v názve <ph name="HOST_NAME" /> preklep.</translation>
-<translation id="2166049586286450108">Úplný prístup správcu</translation>
+<translation id="2166049586286450108">Úplný správcovský prístup</translation>
<translation id="2166378884831602661">Tento web nedokáže poskytnúť zabezpeÄené pripojenie</translation>
<translation id="2169984857010174799">Kaku2 (obálka)</translation>
<translation id="2181821976797666341">Pravidlá</translation>
<translation id="2183608646556468874">Telefónne Äíslo</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}few{# adresy}many{# adresy}other{# adries}}</translation>
-<translation id="2187243482123994665">Prítomnosť používateľa</translation>
<translation id="2187317261103489799">Rozpoznávať (predvolené)</translation>
<translation id="2188375229972301266">Viacero dierok dole</translation>
<translation id="2202020181578195191">Zadajte platný rok vypršania platnosti</translation>
@@ -464,6 +474,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2839501879576190149">Falošný web</translation>
<translation id="2850739647070081192">Invite (obálka)</translation>
<translation id="2856444702002559011">ÚtoÄníci sa môžu pokúsiÅ¥ ukradnúť vaÅ¡e informácie z webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (napríklad heslá, správy alebo kreditné karty). <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Tento web zobrazuje obťažujúce alebo zavádzajúce reklamy.</translation>
<translation id="2878197950673342043">Plagátový záhyb</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Umiestnenie okna</translation>
@@ -502,11 +513,11 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2996674880327704673">Návrhy od Googlu</translation>
<translation id="3002501248619246229">Skontrolujte médiá vstupnej priehradky</translation>
<translation id="3005723025932146533">Zobraziť uloženú kópiu</translation>
-<translation id="3007719053326478567">TlaÄ tohto dokumentu je blokovaná vaším správcom</translation>
<translation id="3008447029300691911">Zadajte kód CVC karty <ph name="CREDIT_CARD" />. Po potvrdení budú podrobnosti o karte zdieľané s týmto webom.</translation>
<translation id="3010559122411665027">Položka zoznamu „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automaticky blokované</translation>
<translation id="3016780570757425217">Zistiť vašu polohu</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, návrh odstránite postupným stlaÄením klávesov Tab a Enter.</translation>
<translation id="3023071826883856138">You4 (obálka)</translation>
<translation id="3024663005179499861">Chybný typ pravidla</translation>
<translation id="3037605927509011580">Aj, chyba!</translation>
@@ -546,6 +557,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3207960819495026254">Pridané medzi záložky</translation>
<translation id="3209034400446768650">Stránka môže úÄtovaÅ¥ peniaze</translation>
<translation id="3212581601480735796">Vaša aktivita v zariadení <ph name="HOSTNAME" /> je sledovaná</translation>
+<translation id="3212623355668894776">Zavrite všetky okná hosťovského režimu, aby bola aktivita prehliadania odstránená z tohto zariadenia.</translation>
<translation id="3215092763954878852">WebAuthn sa nepodarilo použiť</translation>
<translation id="3218181027817787318">Relatívne</translation>
<translation id="3225919329040284222">Server sa preukázal certifikátom, ktorý nezodpovedá integrovaným oÄakávaniam. Tieto oÄakávania sú kvôli vaÅ¡ej ochrane zahrnuté pri urÄitých webových stránkach s vysokou úrovňou zabezpeÄenia.</translation>
@@ -692,6 +704,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3784372983762739446">Zariadenia Bluetooth</translation>
<translation id="3787705759683870569">Platnosť vyprší <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Veľkosť 16</translation>
+<translation id="3789841737615482174">Inštalovať</translation>
<translation id="3793574014653384240">PoÄty a príÄiny nedávnych zrútení</translation>
<translation id="3797522431967816232">Prc3 (obálka)</translation>
<translation id="3799805948399000906">Písmo bolo vyžiadané</translation>
@@ -742,6 +755,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4056223980640387499">Sépia</translation>
<translation id="4058922952496707368">KÄ¾ÃºÄ <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (obálka)</translation>
+<translation id="4067669230157909013">Snímanie obrazovky bolo obnovené.</translation>
<translation id="4067947977115446013">Pridanie platnej adresy</translation>
<translation id="4072486802667267160">Pri spracovaní vašej objednávky sa vyskytla chyba. Skúste to znova.</translation>
<translation id="4075732493274867456">Klient a server nepodporujú spoloÄnú verziu protokolu SSL ani Å¡ifrovaciu súpravu.</translation>
@@ -822,6 +836,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4297502707443874121">Miniatúra stránky <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Rozbaliť</translation>
<translation id="4300675098767811073">Viacero dierok vpravo</translation>
+<translation id="4302514097724775343">Ak chcete hrať, klepnite na dinosaura</translation>
<translation id="4302965934281694568">Chou3 (obálka)</translation>
<translation id="4305666528087210886">Súbor sa nepodarilo otvoriť</translation>
<translation id="4305817255990598646">Prepnúť</translation>
@@ -900,6 +915,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4658638640878098064">Predierkovať vľavo hore</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuálna realita</translation>
+<translation id="4675657451653251260">V hosÅ¥ovskom režime neuvidíte žiadne údaje profilu Chromu. Ak chcete získaÅ¥ prístup k údajom svojho úÄtu Google, napríklad k heslám a spôsobom platby, <ph name="LINK_BEGIN" />môžete sa prihlásiÅ¥<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" />, jej bezpeÄnostný certifikát obsahuje chyby. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie zachytil útoÄník.</translation>
<translation id="4677585247300749148"><ph name="URL" /> chce reagovať na udalosti dostupnosti</translation>
<translation id="467809019005607715">Prezentácie Google</translation>
@@ -927,6 +943,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4761104368405085019">Používať váš mikrofón</translation>
<translation id="4764776831041365478">Stránka <ph name="URL" /> je možno doÄasne nedostupná, možno bola natrvalo presunutá na novú webovú adresu.</translation>
<translation id="4766713847338118463">Dve spinky dole</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Vaša aktivita, ktorá zostane v tomto zariadení:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />všetky súbory, ktoré v tomto okne stiahnete.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Vyskytla sa neznáma chyba.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Zablokované vyskakovacie okno}few{Zablokované # vyskakovacie okná}many{# pop-ups blocked}other{Zablokovaných # vyskakovacích okien}}</translation>
<translation id="4780366598804516005">PoÅ¡tová schránka Ä. 1</translation>
@@ -999,7 +1021,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5056549851600133418">Články pre vás</translation>
<translation id="5061227663725596739">Mysleli ste <ph name="LOOKALIKE_DOMAIN" />?</translation>
<translation id="5068524481479508725">A10</translation>
-<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(Používa sa 1)}few{(Používajú sa #)}many{(# in use)}other{(Používa sa #)}}</translation>
+<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(používa sa 1)}few{(používajú sa #)}many{(# in use)}other{(používa sa #)}}</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Skontrolovať adresu proxy servera<ph name="END_LINK" /></translation>
<translation id="507130231501693183">PoÅ¡tová schránka Ä. 4</translation>
<translation id="5087286274860437796">Certifikát servera je momentálne neplatný</translation>
@@ -1089,11 +1111,13 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5386426401304769735">Reťazec certifikátu pre tento web obsahuje certifikát podpísaný pomocou funkcie SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Zošiť hrebeňovou väzbou vpravo</translation>
+<translation id="5398772614898833570">Reklamy sú blokované</translation>
<translation id="5400836586163650660">Sivá</translation>
<translation id="540969355065856584">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" /> – jej bezpeÄnostný certifikát je momentálne neplatný. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie napadol útoÄník.</translation>
<translation id="541416427766103491">OdkladaÄ Ä. 4</translation>
<translation id="5421136146218899937">Vymazať dáta prehliadania…</translation>
<translation id="5426179911063097041">Web <ph name="SITE" /> vám chce posielať upozornenia</translation>
+<translation id="542872847390508405">Prehliadate ako hosť</translation>
<translation id="5430298929874300616">Odstrániť záložku</translation>
<translation id="5439770059721715174">Pri overení schémy sa vyskytla chyba na mieste <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">V opaÄnom poradí lícom nahor</translation>
@@ -1135,12 +1159,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5571083550517324815">Vyzdvihnutie na tejto adrese nie je možné. Vyberte inú adresu.</translation>
<translation id="5580958916614886209">Skontrolujte mesiac vypršania platnosti a skúste to znova</translation>
<translation id="5586446728396275693">Žiadne uložené adresy</translation>
+<translation id="5593349413089863479">Pripojenie nie je úplne zabezpeÄené</translation>
<translation id="5595485650161345191">Upraviť adresu</translation>
<translation id="5598944008576757369">Zvoliť spôsob platby</translation>
<translation id="560412284261940334">Správa nie je podporovaná</translation>
<translation id="5605670050355397069">ÚÄtovná kniha</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Tento web môže byÅ¥ faloÅ¡ný alebo podvodný. Chrome vám odporúÄa okamžite odísÅ¥.</translation>
<translation id="5610142619324316209">Skontrolovať pripojenie</translation>
<translation id="5610807607761827392">Karty a adresy môžete spravovaÅ¥ v Äasti <ph name="BEGIN_LINK" />Nastavenia<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">PreložiÅ¥ túto stránku v PrekladaÄi Google</translation>
@@ -1212,6 +1236,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5901630391730855834">Žltá</translation>
<translation id="5905445707201418379">Blokované pravidlom pre zdroj <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synchronizované)</translation>
+<translation id="5913377024445952699">Snímanie obrazovky bolo pozastavené</translation>
<translation id="59174027418879706">Povolené</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">zapnuté</translation>
@@ -1224,6 +1249,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5963413905009737549">Sekcia</translation>
<translation id="5967592137238574583">Úprava kontaktných informácií</translation>
<translation id="5967867314010545767">Odstrániť z histórie</translation>
+<translation id="5968793460449681917">Pri každej návšteve</translation>
<translation id="5975083100439434680">Oddialiť</translation>
<translation id="5979084224081478209">Skontrolovať heslá</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1378,6 +1404,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6587923378399804057">Skopírovaný odkaz</translation>
<translation id="6591833882275308647">Zariadenie <ph name="DEVICE_TYPE" /> nie je spravované</translation>
<translation id="6596325263575161958">Možnosti šifrovania</translation>
+<translation id="6596892391065203054">TlaÄ tohto obsahu zablokoval správca.</translation>
<translation id="6604181099783169992">Senzory pohybu alebo svetla</translation>
<translation id="6609880536175561541">Prc7 (obálka)</translation>
<translation id="6612358246767739896">Chránený obsah</translation>
@@ -1437,6 +1464,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6895330447102777224">Vaša karta je overená</translation>
<translation id="6897140037006041989">Používateľský agent</translation>
<translation id="6898699227549475383">Organizácia (O)</translation>
+<translation id="6907293445143367439">Povoliť webu <ph name="SITE_NAME" /> tieto akcie:</translation>
<translation id="6910240653697687763">Web <ph name="URL" /> chce získať úplnú kontrolu nad zariadeniami MIDI</translation>
<translation id="6915804003454593391">Používateľ:</translation>
<translation id="6934672428414710184">Meno pochádza z vášho úÄtu Google</translation>
@@ -1465,7 +1493,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7004583254764674281">Potvrdzujte karty rýchlejšie pomocou služby Windows Hello</translation>
<translation id="7006930604109697472">Aj tak odoslať</translation>
<translation id="7012363358306927923">China UnionPay</translation>
-<translation id="7014741021609395734">Úroveň priblíženia alebo oddialenia</translation>
+<translation id="7014741021609395734">Úroveň lupy</translation>
<translation id="7016992613359344582">Tieto poplatky môžu byť jednorazové alebo opakované a nemusia byť predvídateľné.</translation>
<translation id="7029809446516969842">Heslá</translation>
<translation id="7031646650991750659">Ktoré aplikácie Google Play máte nainštalované.</translation>
@@ -1548,6 +1576,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7346048084945669753">Je pridružený/-á</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Príkazový riadok</translation>
+<translation id="7359588939039777303">Reklamy sú blokované.</translation>
<translation id="7372973238305370288">výsledok vyhľadávania</translation>
<translation id="7374733840632556089">Tento problém je spôsobený certifikátom, ktorý bol v zariadení nainÅ¡talovaný vami alebo niekým iným. O tomto certifikáte je známe, že sa pomocou neho sledujú a narúšajú siete. Chrome mu nedôveruje. Niekedy existujú legitímne prípady sledovania, napríklad v školskej alebo firemnej sieti. Chrome sa vÅ¡ak chce uistiÅ¥, Äi viete, že k tomu dochádza (aj keÄ to nemôžete zastaviÅ¥). Sledovanie môže prebiehaÅ¥ v ktoromkoľvek prehliadaÄi alebo aplikácii s prístupom na internet.</translation>
<translation id="7375818412732305729">Priloženie súboru</translation>
@@ -1722,6 +1751,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7976214039405368314">Príliš veľa žiadostí</translation>
<translation id="7977538094055660992">Zariadenie výstupu</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Ak chcete zobraziť obsah v rozšírenej realite, nainštalujte si ARCore</translation>
<translation id="799149739215780103">Zviazať</translation>
<translation id="7995512525968007366">Nie je upresnené</translation>
<translation id="800218591365569300">Skúste zavrieť ostatné karty alebo programy a uvoľniť tak miesto v pamäti.</translation>
@@ -1849,25 +1879,39 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8507227106804027148">Príkazový riadok</translation>
<translation id="8508648098325802031">Ikona vyhľadávania</translation>
<translation id="8522552481199248698">Chrome vám pomôže ochrániÅ¥ úÄet Google a zmeniÅ¥ heslo.</translation>
+<translation id="8525306231823319788">Celá obrazovka</translation>
<translation id="8530813470445476232">VymazaÅ¥ svoju históriu prehliadania, súbory cookie, vyrovnávaciu pamäť a ÄalÅ¡ie položky v nastaveniach Chromu</translation>
<translation id="8533619373899488139">Na stránke &lt;strong&gt;chrome://policy&lt;/strong&gt; nájdete zoznam zakázaných webových adries a ÄalÅ¡ie pravidlá presadzované vaším správcom systému.</translation>
<translation id="8541158209346794904">Zariadenie Bluetooth</translation>
<translation id="8542014550340843547">Tri spinky dole</translation>
<translation id="8543181531796978784">Môžete buÄ <ph name="BEGIN_ERROR_LINK" />nahlásiÅ¥ problém s zisÅ¥ovaním<ph name="END_ERROR_LINK" />, alebo <ph name="BEGIN_LINK" />tieto nebezpeÄné stránky navÅ¡tíviÅ¥<ph name="END_LINK" /> (ak si uvedomujete bezpeÄnostné riziko).</translation>
<translation id="8557066899867184262">Kód CVC nájdete na zadnej strane karty.</translation>
+<translation id="8558485628462305855">Ak chcete zobraziť obsah v rozšírenej realite, aktualizujte ARCore</translation>
<translation id="8559762987265718583">Súkromné pripojenie k doméne <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> sa nedá nadviazaÅ¥, pretože dátum a Äas (<ph name="DATE_AND_TIME" />) vášho zariadenia sú nesprávne.</translation>
<translation id="8564182942834072828">Samostatné dokumenty alebo nezoradené kópie</translation>
<translation id="8564985650692024650">Ak ste heslo organizácie <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili aj na iných weboch, Chromium ho odporúÄa obnoviÅ¥.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivita, ktorá nezostane v tomto zariadení:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />stránky zobrazené v tomto okne;
+ <ph name="LIST_ITEM" />súbory cookie a údaje webov.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Potvrdzujte karty rýchlejšie pomocou funkcie Touch ID</translation>
<translation id="858637041960032120">Pridať telefón
</translation>
<translation id="8589998999637048520">Najlepšia kvalita</translation>
+<translation id="8600271352425265729">Iba tentokrát</translation>
<translation id="860043288473659153">Meno držiteľa karty</translation>
<translation id="8606726445206553943">Používať zariadenia MIDI</translation>
+<translation id="8612761427948161954">Dobrý deň, <ph name="USERNAME" />,
+ <ph name="BR" />
+ prehliadate ako hosť.</translation>
<translation id="861775596732816396">Veľkosť 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Žiadne zhodujúce sa heslá. Zobrazte si všetky uložené heslá.</translation>
<translation id="8625384913736129811">Uložiť túto kartu do tohto zariadenia</translation>
+<translation id="8627040765059109009">Snímanie obrazovky bolo obnovené</translation>
<translation id="8657078576661269990">Váš správca zablokoval zdieľanie zo zdroja <ph name="ORIGIN_NAME" /> do poÄítaÄov <ph name="VM_NAME_1" /> a <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Súhrn objednávky, <ph name="TOTAL_LABEL" />, ÄalÅ¡ie podrobnosti</translation>
<translation id="867224526087042813">Podpis</translation>
@@ -1894,7 +1938,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; webu <ph name="HOST_NAME" /> sa nenašla. Problém sa diagnostikuje.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je kód pre <ph name="ORIGIN" /></translation>
<translation id="874918643257405732">Pridať kartu medzi záložky</translation>
-<translation id="8751426954251315517">Skúste to znova neskôr</translation>
+<translation id="8751426954251315517">Skúste to neskôr</translation>
<translation id="8759274551635299824">Platnosť tejto karty vypršala</translation>
<translation id="87601671197631245">Tento web používa zastaranú konfiguráciu zabezpeÄenia, ktorá môže odhaliÅ¥ vaÅ¡e informácie (napríklad heslá, správy alebo kreditné karty), keÄ ich naň odoÅ¡lete.</translation>
<translation id="8761567432415473239">BezpeÄné prehliadanie Google nedávno <ph name="BEGIN_LINK" />zistilo Å¡kodlivé programy<ph name="END_LINK" /> na webe <ph name="SITE" />.</translation>
@@ -1930,6 +1974,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8912362522468806198">úÄtu Google</translation>
<translation id="8913778647360618320">TlaÄidlo SpravovaÅ¥ spôsob platby. StlaÄením klávesa Enter môžete v nastaveniach Chromu spravovaÅ¥ spôsoby platby a informácie o kreditnej karte.</translation>
<translation id="8918231688545606538">Táto stránka je podozrivá</translation>
+<translation id="8922013791253848639">Vždy povoliť reklamy na tomto webe</translation>
<translation id="892588693504540538">Prederaviť vpravo hore</translation>
<translation id="8931333241327730545">Chcete túto kartu uložiÅ¥ do svojho úÄtu Google?</translation>
<translation id="8932102934695377596">Vaše hodiny idú pozadu</translation>
@@ -2001,6 +2046,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="9183302530794969518">Dokumenty Google</translation>
<translation id="9183425211371246419">Web <ph name="HOST_NAME" /> využíva nepodporovaný protokol.</translation>
<translation id="9191834167571392248">Prederaviť vľavo dolu</translation>
+<translation id="9199905725844810519">TlaÄ je blokovaná</translation>
<translation id="9205078245616868884">Údaje sú Å¡ifrované pomocou vlastnej prístupovej frázy synchronizácie. KeÄ ju zadáte, synchronizácia sa spustí.</translation>
<translation id="9207861905230894330">Článok sa nepodarilo pridať.</translation>
<translation id="9213433120051936369">Prispôsobenie vzhľadu</translation>
@@ -2011,8 +2057,10 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Môžete stratiÅ¥ prístup do úÄtu Google. Chromium odporúÄa, aby ste si ihneÄ zmenili heslo. Zobrazí sa výzva na prihlásenie.</translation>
<translation id="939736085109172342">Nový prieÄinok</translation>
+<translation id="945522503751344254">Odoslať spätnú väzbu</translation>
<translation id="945855313015696284">Skontrolujte informácie nižšie a odstráňte neplatné karty</translation>
<translation id="950736567201356821">Tri dierky hore</translation>
+<translation id="951941430552851965">Snímanie obrazovky bolo pozastavené správcom. Dôvodom bol obsah vašej obrazovky.</translation>
<translation id="961663415146723894">Zviazať dolu</translation>
<translation id="962484866189421427">Tento obsah sa môže pokúsiÅ¥ nainÅ¡talovaÅ¥ klamlivé aplikácie vydávajúce sa za iné aplikácie alebo zhromažÄovaÅ¥ údaje, ktoré sa dajú použiÅ¥ na sledovanie vaÅ¡ej osoby. <ph name="BEGIN_LINK" />Napriek tomu zobraziÅ¥<ph name="END_LINK" /></translation>
<translation id="969892804517981540">oficiálna zostava</translation>
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index 9b514dc858e..872051484ca 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -80,6 +80,14 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Vnesli ste geslo na spletnem mestu, ki ga ne upravlja vaÅ¡a organizacija. Zaradi zaÅ¡Äite raÄuna gesla ne uporabljajte za druge aplikacije in spletna mesta.</translation>
<translation id="1263231323834454256">Bralni seznam</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Dejavnost, ki se ne shrani v tej napravi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />strani, ki si jih ogledate v tem oknu,
+ <ph name="LIST_ITEM" />piškotki in podatki spletnih mest,
+ <ph name="LIST_ITEM" />podatki o raÄunu (<ph name="LINK_BEGIN" />odjava<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">NaÄin prevzema</translation>
<translation id="1281476433249504884">Zlagalnik 1</translation>
<translation id="1285320974508926690">Nikoli ne prevedi tega spletnega mesta</translation>
@@ -283,6 +291,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="204357726431741734">Prijavite se, Äe želite uporabljati gesla, shranjena v raÄunu Google</translation>
<translation id="2053111141626950936">Strani v jeziku <ph name="LANGUAGE" /> ne bodo prevedene.</translation>
<translation id="2053553514270667976">Poštna številka</translation>
+<translation id="2054665754582400095">Vaša prisotnost</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 predlog}one{# predlog}two{# predloga}few{# predlogi}other{# predlogov}}</translation>
<translation id="2079545284768500474">Razveljavi</translation>
<translation id="20817612488360358">Za uporabo so nastavljene sistemske nastavitve strežnika proxy, vendar je navedena tudi izrecna konfiguracija proxyja.</translation>
@@ -296,6 +305,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2102495993840063010">Aplikacije za Android</translation>
<translation id="2107021941795971877">Podpora za tiskanje</translation>
<translation id="2108755909498034140">Znova zaženite raÄunalnik</translation>
+<translation id="2111166930115883695">Pritisnite preslednico, Äe želite igrati.</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kartica</translation>
<translation id="2114841414352855701">Prezrto, ker je to preglasil pravilnik <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="214556005048008348">PrekliÄi plaÄilo</translation>
<translation id="2147827593068025794">Sinhroniziranje v ozadju</translation>
<translation id="2148613324460538318">Dodaj kartico</translation>
+<translation id="2149968176347646218">Povezava ni varna</translation>
<translation id="2154054054215849342">Sinhronizacija ni na voljo za vašo domeno</translation>
<translation id="2154484045852737596">Urejanje kartice</translation>
<translation id="2161656808144014275">Besedilo</translation>
@@ -317,7 +328,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2181821976797666341">Pravilniki</translation>
<translation id="2183608646556468874">Telefonska Å¡tevilka</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 naslov}one{# naslov}two{# naslova}few{# naslovi}other{# naslovov}}</translation>
-<translation id="2187243482123994665">Prisotnost uporabnika</translation>
<translation id="2187317261103489799">Zaznava (privzeto)</translation>
<translation id="2188375229972301266">VeÄkratno luknjanje spodaj</translation>
<translation id="2202020181578195191">Vnesite veljavno leto poteka veljavnosti</translation>
@@ -470,6 +480,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2839501879576190149">Lažno spletno mesto</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Morda poskuÅ¡ajo napadalci ukrasti vaÅ¡e podatke s spletnega mesta <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primer gesla, sporoÄila ali podatke kreditnih kartic). <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">To spletno mesto prikazuje vsiljive ali zavajajoÄe oglase.</translation>
<translation id="2878197950673342043">Prepogibanje v obliki plakata</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Postavitev oken</translation>
@@ -508,11 +519,11 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2996674880327704673">Googlovi predlogi</translation>
<translation id="3002501248619246229">Preverite medije na vhodnem pladnju</translation>
<translation id="3005723025932146533">Pokaži shranjeno kopijo</translation>
-<translation id="3007719053326478567">Tiskanje te vsebine je blokiral skrbnik.</translation>
<translation id="3008447029300691911">Vnesite CVC za <ph name="CREDIT_CARD" />. Ko potrdite, bodo temu spletnemu mestu razkriti podatki o vaši kartici.</translation>
<translation id="3010559122411665027">Vnos na sznamu »<ph name="ENTRY_INDEX" />«: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Samodejno blokirano</translation>
<translation id="3016780570757425217">podatke o vaši lokaciji</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pritisnite tabulatorko, nato Enter, Äe želite odstraniti predlog.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">NapaÄna vrsta pravilnika</translation>
<translation id="3037605927509011580">Ti Å¡ment!</translation>
@@ -555,6 +566,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3207960819495026254">Dodano med zaznamke</translation>
<translation id="3209034400446768650">Stran morda zaraÄunava</translation>
<translation id="3212581601480735796">Vaša dejavnost v gostitelju <ph name="HOSTNAME" /> je nadzorovana</translation>
+<translation id="3212623355668894776">Zaprite vsa okna naÄina za goste, da se bo dejavnost brskanja izbrisala iz te naprave.</translation>
<translation id="3215092763954878852">Ni bilo mogoÄe uporabiti WebAuthn</translation>
<translation id="3218181027817787318">Relativno</translation>
<translation id="3225919329040284222">Strežnik je poslal potrdilo, ki se ne ujema z vgrajenimi priÄakovanji. Ta priÄakovanja so zaradi vaÅ¡e varnosti vkljuÄena za nekatera strogo zavarovana spletna mesta.</translation>
@@ -702,6 +714,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3784372983762739446">Naprave Bluetooth</translation>
<translation id="3787705759683870569">PoteÄe: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Velikost 16</translation>
+<translation id="3789841737615482174">Namesti</translation>
<translation id="3793574014653384240">Številke in vzroki razširitev, do katerih je prišlo nedavno</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Zahtevana pisava</translation>
@@ -753,6 +766,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4056223980640387499">Sepija</translation>
<translation id="4058922952496707368">KljuÄ Â»<ph name="SUBKEY" />«: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Zajem zaslona se je nadaljeval.</translation>
<translation id="4067947977115446013">Dodajanje veljavnega naslova</translation>
<translation id="4072486802667267160">Pri obdelavi naroÄila je priÅ¡lo do napake. Poskusite znova.</translation>
<translation id="4075732493274867456">Odjemalec in strežnik ne podpirata skupne razliÄice protokola SSL ali Å¡ifrirne zbirke.</translation>
@@ -837,6 +851,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4297502707443874121">SliÄica za stran <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Razširi</translation>
<translation id="4300675098767811073">VeÄkratno luknjanje na desni</translation>
+<translation id="4302514097724775343">Če želite igrati, se dotaknite dinozavra.</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Ni bilo mogoÄe dostopati do datoteke</translation>
<translation id="4305817255990598646">Preklopi</translation>
@@ -915,6 +930,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4658638640878098064">Spenjanje zgoraj levo</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Navidezna resniÄnost</translation>
+<translation id="4675657451653251260">V naÄinu za goste ne boste videli podatkov profila v Chromu. ÄŒe želite dostopati do podatkov v raÄunu Google, kot so gesla in plaÄilna sredstva, se lahko <ph name="LINK_BEGIN" />prijavite<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo vsebuje napake. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="4677585247300749148"><ph name="URL" /> se želi odzvati na dogodke funkcij za ljudi s posebnimi potrebami</translation>
<translation id="467809019005607715">Google Predstavitve</translation>
@@ -942,6 +958,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4761104368405085019">Uporabite mikrofon</translation>
<translation id="4764776831041365478">Spletna stran na naslovu <ph name="URL" /> morda zaÄasno ne deluje ali pa je trajno premaknjena na novi spletni naslov.</translation>
<translation id="4766713847338118463">Dvojno spenjanje spodaj</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Vaša dejavnost, ki se shrani v tej napravi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />datoteke, ki jih prenesete v tem oknu.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Prišlo je do neznane napake.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pojavno okno je blokirano}one{# pojavno okno je blokirano}two{# pojavni okni sta blokirani}few{# pojavna okna so blokirana}other{# pojavnih oken je blokiranih}}</translation>
<translation id="4780366598804516005">Nabiralnik 1</translation>
@@ -1104,11 +1126,13 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5386426401304769735">Veriga potrdil za to spletno mesto vsebuje potrdilo, podpisano z algoritmom SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Robni Å¡iv na desni</translation>
+<translation id="5398772614898833570">Oglasi blokirani</translation>
<translation id="5400836586163650660">Siva</translation>
<translation id="540969355065856584">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo trenutno ni veljavno. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="541416427766103491">Zlagalnik 4</translation>
<translation id="5421136146218899937">Izbriši podatke brskanja ...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vam želi pošiljati obvestila</translation>
+<translation id="542872847390508405">Brskate kot gost</translation>
<translation id="5430298929874300616">Odstrani zaznamek</translation>
<translation id="5439770059721715174">Napaka preverjanja sheme pri »<ph name="ERROR_PATH" />«: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">V obratnem vrstnem redu s tiskom na zgornji strani</translation>
@@ -1150,12 +1174,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5571083550517324815">Prevzem na tem naslovu ni mogoÄ. Izberite drugega.</translation>
<translation id="5580958916614886209">Preverite mesec poteka veljavnosti in poskusite znova</translation>
<translation id="5586446728396275693">Ni shranjenih naslovov</translation>
+<translation id="5593349413089863479">Povezava ni povsem varna</translation>
<translation id="5595485650161345191">Uredi naslov</translation>
<translation id="5598944008576757369">Izbira plaÄilnega sredstva</translation>
<translation id="560412284261940334">Upravljanje ni podprto</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">To spletno mesto je lahko lažno ali goljufivo. Chrome predlaga, da ga takoj zapustite.</translation>
<translation id="5610142619324316209">preveriti povezavo</translation>
<translation id="5610807607761827392">Kartice in naslove je mogoÄe upravljati v <ph name="BEGIN_LINK" />nastavitvah<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Prevajanje te strani z Google Prevajalnikom</translation>
@@ -1227,6 +1251,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5901630391730855834">Rumena</translation>
<translation id="5905445707201418379">Blokirano v skladu s pravilnikom izvora za <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinhronizirano)</translation>
+<translation id="5913377024445952699">ZaÄasno zaustavljeno zajemanje slike zaslona</translation>
<translation id="59174027418879706">OmogoÄeno</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Vklopljeno</translation>
@@ -1239,6 +1264,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5963413905009737549">Razdelek</translation>
<translation id="5967592137238574583">Urejanje podatkov o stiku</translation>
<translation id="5967867314010545767">Odstrani iz zgodovine</translation>
+<translation id="5968793460449681917">Ob vsakem obisku</translation>
<translation id="5975083100439434680">Pomanjšaj</translation>
<translation id="5979084224081478209">Preveri gesla</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6587923378399804057">Povezava, ki ste jo kopirali</translation>
<translation id="6591833882275308647">Naprava <ph name="DEVICE_TYPE" /> ni upravljana</translation>
<translation id="6596325263575161958">Možnosti šifriranja</translation>
+<translation id="6596892391065203054">Tiskanje te vsebine je blokiral skrbnik.</translation>
<translation id="6604181099783169992">Tipala za gibanje in svetlobe</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">ZaÅ¡Äitena vsebina</translation>
@@ -1453,6 +1480,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6895330447102777224">Kartica je potrjena.</translation>
<translation id="6897140037006041989">Uporabnikov posrednik</translation>
<translation id="6898699227549475383">Organizacija (O)</translation>
+<translation id="6907293445143367439">Ali spletnemu mestu <ph name="SITE_NAME" /> dovolite, da:</translation>
<translation id="6910240653697687763"><ph name="URL" /> želi pridobiti popolni nadzor nad vašimi napravami MIDI</translation>
<translation id="6915804003454593391">Uporabnik:</translation>
<translation id="6934672428414710184">To ime je iz vaÅ¡ega raÄuna za Google</translation>
@@ -1564,6 +1592,7 @@ Dodatne podrobnosti:
<translation id="7346048084945669753">Je povezan:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Ukazna vrstica</translation>
+<translation id="7359588939039777303">Oglasi blokirani.</translation>
<translation id="7372973238305370288">rezultat iskanja</translation>
<translation id="7374733840632556089">Do te težave pride zaradi potrdila, ki ste ga vi ali nekdo drug namestili v napravo. To potrdilo se je v preteklosti uporabljalo za prestrezanje in nadzor v omrežjih, zato ga Chrome ne obravnava kot zaupanja vrednega. ÄŒeprav obstajajo nekateri legitimni primeri nadzora, denimo v Å¡olah ali omrežjih v podjetjih, se želi Chrome prepriÄati, da se nadzora zavedate, tudi Äe ga ne morete prepreÄiti. Do nadzora lahko pride v katerem koli brskalniku ali aplikaciji, ki dostopa do spleta.</translation>
<translation id="7375818412732305729">Datoteka je priložena</translation>
@@ -1738,6 +1767,7 @@ Dodatne podrobnosti:
<translation id="7976214039405368314">PreveÄ zahtev.</translation>
<translation id="7977538094055660992">Izhodna naprava</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ÄŒe si želite ogledati vsebino v razÅ¡irjeni resniÄnosti, namestite ARCore</translation>
<translation id="799149739215780103">Vezava</translation>
<translation id="7995512525968007366">Ni navedeno</translation>
<translation id="800218591365569300">Poskusite zapreti druge zavihke ali programe, da boste tako sprostili pomnilnik.</translation>
@@ -1865,24 +1895,38 @@ Dodatne podrobnosti:
<translation id="8507227106804027148">Ukazna vrstica</translation>
<translation id="8508648098325802031">Ikona za iskanje</translation>
<translation id="8522552481199248698">Chrome vam lahko pomaga zaÅ¡Äititi raÄun za Google in spremeniti geslo.</translation>
+<translation id="8525306231823319788">Celozaslonsko</translation>
<translation id="8530813470445476232">PoÄistite zgodovino brskanja, piÅ¡kotke, predpomnilnik in drugo v nastavitvah v Chromu</translation>
<translation id="8533619373899488139">Na &lt;strong&gt;chrome://policy&lt;/strong&gt; si lahko ogledate seznam blokiranih URL-jev in drugih pravilnikov, ki jih uveljavlja skrbnik sistema.</translation>
<translation id="8541158209346794904">Naprava Bluetooth</translation>
<translation id="8542014550340843547">Trojno spenjanje spodaj</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Prijavite lahko težavo z zaznavanjem<ph name="END_ERROR_LINK" />, Äe razumete varnostna tveganja, pa lahko <ph name="BEGIN_LINK" />obiÅ¡Äete to spletno mesto, ki ni varno<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC je na zadnji strani kartice.</translation>
+<translation id="8558485628462305855">ÄŒe si želite ogledati vsebino v razÅ¡irjeni resniÄnosti, posodobite ARCore</translation>
<translation id="8559762987265718583">Zasebne povezave z domeno <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ni mogoÄe vzpostaviti, ker sta datum in ura (<ph name="DATE_AND_TIME" />) v napravi nepravilna.</translation>
<translation id="8564182942834072828">LoÄeni dokumenti/nezbrane kopije</translation>
<translation id="8564985650692024650">Chromium priporoÄa, da ponastavite geslo za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Äe ste ga uporabljali tudi na drugih spletnih mestih.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Dejavnost, ki se ne shrani v tej napravi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />strani, ki si jih ogledate v tem oknu,
+ <ph name="LIST_ITEM" />piškotki in podatki spletnih mest.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Uporabite Touch ID za hitrejše potrjevanje kartic</translation>
<translation id="858637041960032120">Dodajte tel. Å¡t. </translation>
<translation id="8589998999637048520">Najboljša kakovost</translation>
+<translation id="8600271352425265729">Samo tokrat</translation>
<translation id="860043288473659153">Ime imetnika kartice</translation>
<translation id="8606726445206553943">Uporaba naprav MIDI</translation>
+<translation id="8612761427948161954">Pozdravljeni, <ph name="USERNAME" />,
+ <ph name="BR" />
+ brskate kot gost.</translation>
<translation id="861775596732816396">Velikost 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ni gesel, ki bi se ujemala. Prikaži vsa shranjena gesla.</translation>
<translation id="8625384913736129811">Shrani to kartico v tej napravi</translation>
+<translation id="8627040765059109009">Nadaljevanje zajemanja slike zaslona</translation>
<translation id="8657078576661269990">Skrbnik je blokiral deljenje vsebine iz vira <ph name="ORIGIN_NAME" /> z navideznima raÄunalnikoma <ph name="VM_NAME_1" /> in <ph name="VM_NAME_2" />.</translation>
<translation id="8663226718884576429">Povzetek naroÄila, <ph name="TOTAL_LABEL" />, veÄ podrobnosti</translation>
<translation id="867224526087042813">Podpis</translation>
@@ -1945,6 +1989,7 @@ Dodatne podrobnosti:
<translation id="8912362522468806198">RaÄun Google</translation>
<translation id="8913778647360618320">Gumb za upravljanje plaÄilnih sredstev, pritisnite Enter, Äe želite upravljati plaÄila in podatke o kreditnih karticah v Chromovih nastavitvah</translation>
<translation id="8918231688545606538">Ta stran je sumljiva</translation>
+<translation id="8922013791253848639">Vedno dovoli oglase na tem spletnem mestu</translation>
<translation id="892588693504540538">Luknjanje zgoraj desno</translation>
<translation id="8931333241327730545">Ali želite to kartico shraniti v Google RaÄun?</translation>
<translation id="8932102934695377596">Ura zaostaja</translation>
@@ -2016,6 +2061,7 @@ Dodatne podrobnosti:
<translation id="9183302530794969518">Google Dokumenti</translation>
<translation id="9183425211371246419">Spletno mesto <ph name="HOST_NAME" /> uporablja nepodprt protokol.</translation>
<translation id="9191834167571392248">Luknjanje spodaj levo</translation>
+<translation id="9199905725844810519">Tiskanje je blokirano</translation>
<translation id="9205078245616868884">Podatki so Å¡ifrirani z vaÅ¡im geslom za sinhronizacijo. Vnesite ga, Äe želite zaÄeti sinhronizacijo.</translation>
<translation id="9207861905230894330">ÄŒlanka ni bilo mogoÄe dodati.</translation>
<translation id="9213433120051936369">Prilagajanje videza</translation>
@@ -2026,8 +2072,10 @@ Dodatne podrobnosti:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Izgubite lahko dostop do Google RaÄuna. Chromium priporoÄa, da spremenite geslo. Pozvani boste, da se prijavite.</translation>
<translation id="939736085109172342">Nova mapa</translation>
+<translation id="945522503751344254">Pošiljanje povratnih informacij</translation>
<translation id="945855313015696284">Preverite spodnje podatke in izbrišite neveljavne kartice</translation>
<translation id="950736567201356821">Trojno luknjanje zgoraj</translation>
+<translation id="951941430552851965">Zajem zaslona je skrbnik zaÄasno zaustavil zaradi vsebine na zaslonu.</translation>
<translation id="961663415146723894">Vezava spodaj</translation>
<translation id="962484866189421427">Ta vsebina lahko poskusi namestiti zavajajoÄe aplikacije, ki se izdajajo za kaj drugega ali zbirajo podatke, s katerimi vas je mogoÄe spremljati. <ph name="BEGIN_LINK" />Vseeno pokaži<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Uradna razliÄica</translation>
diff --git a/chromium/components/strings/components_strings_sq.xtb b/chromium/components/strings/components_strings_sq.xtb
index e76b00d1452..96f24f3ec62 100644
--- a/chromium/components/strings/components_strings_sq.xtb
+++ b/chromium/components/strings/components_strings_sq.xtb
@@ -58,7 +58,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1186201132766001848">Kontrollo fjalëkalimet</translation>
<translation id="1195558154361252544">Njoftimet janë bllokuar automatikisht për të gjitha sajtet përveçse për ato që lejon ti</translation>
<translation id="1197088940767939838">Portokalli</translation>
-<translation id="1201402288615127009">Tjetra</translation>
+<translation id="1201402288615127009">Para</translation>
<translation id="1201895884277373915">Më shumë nga ky sajt</translation>
<translation id="1206967143813997005">Nënshkrimi fillestar i gabuar</translation>
<translation id="1209206284964581585">Fshih për momentin</translation>
@@ -80,6 +80,14 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ke futur fjalëkalimin tënd në një sajt që nuk menaxhohet nga organizata jote. Për të mbrojtur llogarinë tënde, mos e ripërdor fjalëkalimin në aplikacione dhe sajte të tjera.</translation>
<translation id="1263231323834454256">Lista e leximit</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktiviteti që nuk do të ruhet në këtë pajisje:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Faqet që shikon në këtë dritare
+ <ph name="LIST_ITEM" />Kukit dhe të dhënat e sajteve
+ <ph name="LIST_ITEM" />Informacionet e llogarisë (<ph name="LINK_BEGIN" />kur ke dalë<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Mënyra e marrjes</translation>
<translation id="1281476433249504884">Stivuesi 1</translation>
<translation id="1285320974508926690">Asnjëherë mos e përkthe këtë sajt</translation>
@@ -282,6 +290,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="204357726431741734">Identifikohu për të përdorur fjalëkalimet e ruajtura në "Llogarinë tënde të Google"</translation>
<translation id="2053111141626950936">Faqet në <ph name="LANGUAGE" /> nuk do të përkthehen.</translation>
<translation id="2053553514270667976">Kodi postar</translation>
+<translation id="2054665754582400095">Prania jote</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 sugjerim}other{# sugjerime}}</translation>
<translation id="2079545284768500474">Zhbëj</translation>
<translation id="20817612488360358">Cilësimet e përfaqësuesit të sistemit janë caktuar që të përdoren, por është specifikuar po ashtu një konfigurim i qartë i përfaqësuesit.</translation>
@@ -295,6 +304,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2102495993840063010">Aplikacionet e Android</translation>
<translation id="2107021941795971877">Mbështetjet e printimit</translation>
<translation id="2108755909498034140">Rinis kompjuterin</translation>
+<translation id="2111166930115883695">Shtyp hapësirën për të luajtur</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">U shpërfill për shkak se u anulua nga <ph name="POLICY_NAME" />.</translation>
@@ -306,6 +316,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="214556005048008348">Anulo pagesën</translation>
<translation id="2147827593068025794">Sinkronizimi në sfond</translation>
<translation id="2148613324460538318">Shto kartë</translation>
+<translation id="2149968176347646218">Lidhja nuk është e sigurt</translation>
<translation id="2154054054215849342">Sinkronizimi nuk ofrohet për domenin tënd</translation>
<translation id="2154484045852737596">Redakto kartën</translation>
<translation id="2161656808144014275">Teksti</translation>
@@ -316,7 +327,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2181821976797666341">Politikat</translation>
<translation id="2183608646556468874">Numri i telefonit</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresë}other{# adresa}}</translation>
-<translation id="2187243482123994665">Prania e përdoruesit</translation>
<translation id="2187317261103489799">Zbulo (parazgjedhja)</translation>
<translation id="2188375229972301266">Shumë shpime poshtë</translation>
<translation id="2202020181578195191">Fut një vit të vlefshëm skadimi</translation>
@@ -467,6 +477,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2839501879576190149">Sajt i rremë përpara</translation>
<translation id="2850739647070081192">Invite (Zarf)</translation>
<translation id="2856444702002559011">Sulmuesit mund të përpiqen të vjedhin informacionet e tua nga <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (për shembull, fjalëkalimet, mesazhet ose kartat e kreditit). <ph name="BEGIN_LEARN_MORE_LINK" />Mëso më shumë<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ky sajt shfaq reklama ndërhyrëse ose mashtruese.</translation>
<translation id="2878197950673342043">Palosje posteri</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Vendosja e dritareve</translation>
@@ -505,11 +516,11 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2996674880327704673">Sugjerime nga Google</translation>
<translation id="3002501248619246229">Kontrollo median e tabakasë së hyrjes</translation>
<translation id="3005723025932146533">Shfaq një kopje të ruajtur</translation>
-<translation id="3007719053326478567">Printimi i kësaj përmbajtjeje është bllokuar nga administratori yt</translation>
<translation id="3008447029300691911">Shkruaj kodin CVC për <ph name="CREDIT_CARD" />. Pasi të konfirmohet, të dhënat e kartës do të ndahen me këtë sajt.</translation>
<translation id="3010559122411665027">Hyrja e listës "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bllokuar automatikisht</translation>
<translation id="3016780570757425217">Njihu me vendndodhjen tënde</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, shtyp Tab dhe më pas shtyp Enter për të hequr sugjerimin.</translation>
<translation id="3023071826883856138">You4 (Zarf)</translation>
<translation id="3024663005179499861">Lloj i gabuar politike</translation>
<translation id="3037605927509011580">Ndërprerje aksidentale!</translation>
@@ -552,6 +563,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3207960819495026254">Regjistruar në faqeshënues</translation>
<translation id="3209034400446768650">Faqja mund të tarifojë para</translation>
<translation id="3212581601480735796">Aktiviteti yt në <ph name="HOSTNAME" /> po monitorohet</translation>
+<translation id="3212623355668894776">Mbyll të gjitha dritaret e "vizitorit" që aktiviteti yt i shfletimit të fshihet nga kjo pajisje.</translation>
<translation id="3215092763954878852">WebAuthn nuk mund të përdorej</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3225919329040284222">Serveri paraqiti një certifikatë që nuk përputhet me pritshmëritë e integruara. Këto pritshmëri përfshihen për uebsajte të caktuara të sigurisë së lartë, me qëllim që të të mbrojnë.</translation>
@@ -699,6 +711,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3784372983762739446">Pajisjet me Bluetooth</translation>
<translation id="3787705759683870569">Skadon më <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Madhësia 16</translation>
+<translation id="3789841737615482174">Instalo</translation>
<translation id="3793574014653384240">Shifrat dhe shkaqet e përplasjeve që kanë ndodhur së fundi</translation>
<translation id="3797522431967816232">Prc3 (Zarf)</translation>
<translation id="3799805948399000906">Fonti i kërkuar</translation>
@@ -750,6 +763,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Çelësi "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Zarf)</translation>
+<translation id="4067669230157909013">Regjistrimi i ekranit u riaktivizua.</translation>
<translation id="4067947977115446013">Shto adresë të vlefshme</translation>
<translation id="4072486802667267160">Ndodhi një gabim gjatë përpunimit të porosisë. Provo përsëri.</translation>
<translation id="4075732493274867456">Klienti dhe serveri nuk mbështesin një version të zakonshëm të protokollit SSL ose një paketë të shifrimit.</translation>
@@ -832,6 +846,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4297502707443874121">Miniatura për faqen <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Zgjero</translation>
<translation id="4300675098767811073">Shumë shpime djathtas</translation>
+<translation id="4302514097724775343">Trokit te dinozauri për të luajtur</translation>
<translation id="4302965934281694568">Chou3 (Zarf)</translation>
<translation id="4305666528087210886">Qasja te skedari ishte e pamundur</translation>
<translation id="4305817255990598646">Ndërro</translation>
@@ -910,6 +925,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4658638640878098064">Kapje me tel lart majtas</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Realiteti virtual</translation>
+<translation id="4675657451653251260">Në modalitetin e vizitorit, nuk do të shikosh informacione të profilit të Chrome. Mund <ph name="LINK_BEGIN" />të identifikohesh<ph name="LINK_END" /> për t'u qasur tek informacionet e "Llogarisë sate të Google" si fjalëkalimet dhe mënyrat e pagesës.</translation>
<translation id="467662567472608290">Ky server nuk mund të dëshmonte se është <ph name="DOMAIN" />; certifikata e tij e sigurisë përmban gabime. Kjo mund të shkaktohet nga një konfigurim i pasaktë ose nga ndërhyrja e një sulmuesi në lidhjen tënde.</translation>
<translation id="4677585247300749148"><ph name="URL" /> kërkon të reagojë ndaj ngjarjeve të qasshmërisë</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -937,6 +953,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4761104368405085019">Përdor mikrofonin</translation>
<translation id="4764776831041365478">Faqja e internetit në <ph name="URL" /> mund të mos ofrohet përkohësisht ose është zhvendosur përgjithmonë në një adresë të re interneti.</translation>
<translation id="4766713847338118463">Dy kapje me tel në fund</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktiviteti yt që ruhet në këtë pajisje:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Çdo skedar që ti shkarkon në këtë dritare
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ka ndodhur një gabim i panjohur.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Një dritare kërcyese u bllokua}other{# dritare kërcyese u bllokuan}}</translation>
<translation id="4780366598804516005">Kutia postare 1</translation>
@@ -1099,11 +1121,13 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5386426401304769735">Zinxhiri i certifikatës për këtë sajt përmban një certifikatë të nënshkruar me SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Qepje anësore djathtas</translation>
+<translation id="5398772614898833570">Reklamat janë të bllokuara</translation>
<translation id="5400836586163650660">Gri</translation>
<translation id="540969355065856584">Ky server nuk mund të provojë se është <ph name="DOMAIN" />; certifikata e tij e sigurisë është e pavlefshme në këtë moment. Kjo mund të shkaktohet për shkak të konfigurimit të pasaktë ose në rast të ndërhyrjes së ndonjë sulmuesi në lidhjen tënde.</translation>
<translation id="541416427766103491">Stivuesi 4</translation>
<translation id="5421136146218899937">Pastro të dhënat e shfletimit...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> dëshiron të të dërgojë njoftime</translation>
+<translation id="542872847390508405">Po shfleton si vizitor</translation>
<translation id="5430298929874300616">Hiqe faqeshënuesin</translation>
<translation id="5439770059721715174">Gabim i miratimit të skemës në "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Renditja e kundërt e kthyer lart</translation>
@@ -1145,12 +1169,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5571083550517324815">Nuk mund të merret nga kjo adresë. Zgjidh një adresë tjetër.</translation>
<translation id="5580958916614886209">Kontrollo muajin e skadimit dhe provo përsëri</translation>
<translation id="5586446728396275693">Nuk ka adresa të ruajtura</translation>
+<translation id="5593349413089863479">Lidhja nuk është plotësisht e sigurt</translation>
<translation id="5595485650161345191">Redakto adresën</translation>
<translation id="5598944008576757369">Zgjidh mënyrën e pagesës</translation>
<translation id="560412284261940334">Menaxhimi nuk mbështetet</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Ky sajt mund të jetë i rremë ose mashtrues. Chrome rekomandon që të largohesh tani.</translation>
<translation id="5610142619324316209">Të kontrollosh lidhjen</translation>
<translation id="5610807607761827392">Mund t'i menaxhosh kartat dhe adresat te <ph name="BEGIN_LINK" />Cilësimet<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Përktheje këtë faqe me "Përkthe me Google"</translation>
@@ -1222,6 +1246,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5901630391730855834">E verdhë</translation>
<translation id="5905445707201418379">Bllokuar sipas politikës së origjinës së <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinkronizuar)</translation>
+<translation id="5913377024445952699">Regjistrimi i ekranit u vendos në pauzë</translation>
<translation id="59174027418879706">Aktivizuar</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Aktive</translation>
@@ -1234,6 +1259,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5963413905009737549">Seksioni</translation>
<translation id="5967592137238574583">Modifiko informacionet e kontaktit</translation>
<translation id="5967867314010545767">Hiqe nga historiku</translation>
+<translation id="5968793460449681917">Në çdo vizitë</translation>
<translation id="5975083100439434680">Zvogëlo</translation>
<translation id="5979084224081478209">Kontrollo fjalëkalimet</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1388,6 +1414,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6587923378399804057">Lidhja që kopjove</translation>
<translation id="6591833882275308647">Pajisja jote <ph name="DEVICE_TYPE" /> nuk është e menaxhuar</translation>
<translation id="6596325263575161958">Opsionet e enkriptimit</translation>
+<translation id="6596892391065203054">Printimi i kësaj përmbajtjeje është bllokuar nga administratori yt.</translation>
<translation id="6604181099783169992">Sensorët e lëvizjes ose të dritës</translation>
<translation id="6609880536175561541">Prc7 (Zarf)</translation>
<translation id="6612358246767739896">Përmbajtje e mbrojtur</translation>
@@ -1447,6 +1474,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6895330447102777224">Karta jote është konfirmuar</translation>
<translation id="6897140037006041989">Agjenti i përdoruesit</translation>
<translation id="6898699227549475383">Organizata (O)</translation>
+<translation id="6907293445143367439">Lejo <ph name="SITE_NAME" /> te:</translation>
<translation id="6910240653697687763"><ph name="URL" /> kërkon të marrë nën kontroll të plotë pajisjet e tua MIDI</translation>
<translation id="6915804003454593391">Përdoruesi:</translation>
<translation id="6934672428414710184">Ky emër është nga "Llogaria jote e Google"</translation>
@@ -1558,6 +1586,7 @@ Detaje shtesë:
<translation id="7346048084945669753">Është i lidhur:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Linja e komandave</translation>
+<translation id="7359588939039777303">Reklamat janë të bllokuara.</translation>
<translation id="7372973238305370288">rezultati i kërkimit</translation>
<translation id="7374733840632556089">Ky problem ndodh për shkak të një certifikate që instalove ti ose dikush tjetër në pajisjen tënde. Certifikata njihet se është përdorur për të monitoruar dhe ndërhyrë në rrjete dhe nuk është e besuar nga Chrome. Megjithëse ekzistojnë disa raste legjitime për monitorimin, si p.sh. një rrjet shkolle ose kompanie, Chrome dëshiron të sigurohet që je në dijeni se kjo ndodh, edhe nëse nuk arrin ta ndalosh. Monitorimi mund të ndodhë në çdo shfletues ose aplikacion që ka qasje në ueb.</translation>
<translation id="7375818412732305729">Skedari është bashkëngjitur</translation>
@@ -1732,6 +1761,7 @@ Detaje shtesë:
<translation id="7976214039405368314">Ka shumë kërkesa</translation>
<translation id="7977538094055660992">Pajisja e daljes</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Për të parë përmbajtje realiteti të zgjeruar, instalo ARCore</translation>
<translation id="799149739215780103">Lidhje</translation>
<translation id="7995512525968007366">Nuk është specifikuar</translation>
<translation id="800218591365569300">Provo të mbyllësh skedat ose programet e tjera për të liruar memorien.</translation>
@@ -1859,24 +1889,38 @@ Detaje shtesë:
<translation id="8507227106804027148">Rreshti i komandës</translation>
<translation id="8508648098325802031">Ikona e kërkimit</translation>
<translation id="8522552481199248698">Chrome mund të të ndihmojë ta mbrosh "Llogarinë tënde të Google" dhe të ndryshosh fjalëkalimin tënd.</translation>
+<translation id="8525306231823319788">Ekrani i plotë</translation>
<translation id="8530813470445476232">Pastro historikun e shfletimit, kukit, memorien specifike etj. te cilësimet e Chrome</translation>
<translation id="8533619373899488139">Vizito &lt;strong&gt;chrome://policy&lt;/strong&gt; për të parë listën e URL-ve të bllokuara dhe politika të tjera të detyruara nga administratori i sistemit tënd.</translation>
<translation id="8541158209346794904">Pajisje me Bluetooth</translation>
<translation id="8542014550340843547">Tri kapje me tel poshtë</translation>
<translation id="8543181531796978784">Mund <ph name="BEGIN_ERROR_LINK" />të raportosh një problem të zbulimit<ph name="END_ERROR_LINK" /> ose, nëse i kupton rreziqet ndaj sigurisë tënde, <ph name="BEGIN_LINK" />vizito këtë sajt të pasigurt<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">Kodi CVC ndodhet në pjesën e pasme të kartës.</translation>
+<translation id="8558485628462305855">Për të parë përmbajtje realiteti të zgjeruar, përditëso ARCore</translation>
<translation id="8559762987265718583">Nuk mund të vendoset një lidhje private me <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />sepse data dhe ora (<ph name="DATE_AND_TIME" />) e pajisjes tënde nuk janë të sakta.</translation>
<translation id="8564182942834072828">Dokumente të ndara/kopje të parenditura</translation>
<translation id="8564985650692024650">Chromium rekomandon rivendosjen e fjalëkalimit tënd të <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> nëse e ke ripërdorur në sajte të tjera.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktiviteti që nuk do të ruhet në këtë pajisje:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Faqet që shikon në këtë pajisje
+ <ph name="LIST_ITEM" />Kukit dhe të dhënat e sajteve
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Përdor Touch ID për të konfirmuar kartat më shpejt</translation>
<translation id="858637041960032120">Shto numrin e telefonit</translation>
<translation id="8589998999637048520">Cilësia më e mirë</translation>
+<translation id="8600271352425265729">Vetëm këtë herë</translation>
<translation id="860043288473659153">Emri i mbajtësit të kartës</translation>
<translation id="8606726445206553943">Përdor pajisjet e tua MIDI</translation>
+<translation id="8612761427948161954">Përshëndetje <ph name="USERNAME" />,
+ <ph name="BR" />
+ Po shfleton si vizitor</translation>
<translation id="861775596732816396">Madhësia 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nuk ka asnjë fjalëkalim që përputhet. Shfaq të gjitha fjalëkalimet e ruajtura.</translation>
<translation id="8625384913736129811">Ruaje këtë kartë në këtë pajisje</translation>
+<translation id="8627040765059109009">Regjistrimi i ekranit u riaktivizua</translation>
<translation id="8657078576661269990">Administratori yt ka bllokuar ndarjen nga <ph name="ORIGIN_NAME" /> në <ph name="VM_NAME_1" /> dhe <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Përmbledhje e porosisë, <ph name="TOTAL_LABEL" />, detaje të tjera</translation>
<translation id="867224526087042813">Nënshkrimi</translation>
@@ -1939,6 +1983,7 @@ Detaje shtesë:
<translation id="8912362522468806198">Llogaria e Google</translation>
<translation id="8913778647360618320">Butoni "Menaxho mënyrat e pagesës", shtyp "Enter" për të menaxhuar informacionet e pagesave dhe të kartës së kreditit te cilësimet e Chrome</translation>
<translation id="8918231688545606538">Kjo faqe është e dyshimtë</translation>
+<translation id="8922013791253848639">Lejo gjithmonë reklamat në këtë sajt</translation>
<translation id="892588693504540538">Shpim lart djathtas</translation>
<translation id="8931333241327730545">Dëshiron që ta ruash këtë kartë te llogaria jote e Google?</translation>
<translation id="8932102934695377596">Ora ka mbetur prapa</translation>
@@ -2010,6 +2055,7 @@ Detaje shtesë:
<translation id="9183302530794969518">Dokumentet e Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> përdor një protokoll të pambështetur.</translation>
<translation id="9191834167571392248">Shpim poshtë majtas</translation>
+<translation id="9199905725844810519">Printimi është bllokuar</translation>
<translation id="9205078245616868884">Të dhënat e tua janë koduar me frazën e kalimit të sinkronizimit. Fute atë për të nisur sinkronizmin.</translation>
<translation id="9207861905230894330">Dështoi në shtimin e artikullit.</translation>
<translation id="9213433120051936369">Personalizo pamjen</translation>
@@ -2020,8 +2066,10 @@ Detaje shtesë:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Mund të humbësh qasjen në "Llogarinë tënde të Google". Chromium rekomandon që ta ndryshosh fjalëkalimin tani. Do të të kërkohet që të identifikohesh.</translation>
<translation id="939736085109172342">Dosje e re</translation>
+<translation id="945522503751344254">Dërgo komente</translation>
<translation id="945855313015696284">Kontrollo informacionin më poshtë dhe fshi çdo kartë të pavlefshme</translation>
<translation id="950736567201356821">Tri shpime lart</translation>
+<translation id="951941430552851965">Regjistrimi i ekranit u vendos në pauzë nga administratori yt për shkak të përmbajtjes në ekranin tënd.</translation>
<translation id="961663415146723894">Lidhje poshtë</translation>
<translation id="962484866189421427">Kjo përmbajtje mund të përpiqet të instalojë aplikacione mashtruese që pretendojnë se janë diçka tjetër ose që mbledhin të dhëna që mund të përdoren për të të gjurmuar. <ph name="BEGIN_LINK" />Shfaq gjithsesi<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Ndërtimi zyrtar</translation>
diff --git a/chromium/components/strings/components_strings_sr-Latn.xtb b/chromium/components/strings/components_strings_sr-Latn.xtb
index 007045ba80e..d20611c1a7a 100644
--- a/chromium/components/strings/components_strings_sr-Latn.xtb
+++ b/chromium/components/strings/components_strings_sr-Latn.xtb
@@ -80,6 +80,14 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Uneli ste lozinku na sajtu kojim ne upravlja vaša organizacija. Da biste zaštitili nalog, ne koristite lozinku ponovo u drugim aplikacijama ni na drugim sajtovima.</translation>
<translation id="1263231323834454256">Lista za Äitanje</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje ne ostaju na ovom uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Stranice koje pregledate u ovom prozoru
+ <ph name="LIST_ITEM" />KolaÄicÌi i podaci o sajtovima
+ <ph name="LIST_ITEM" />Informacije o nalogu (<ph name="LINK_BEGIN" />odjavite se<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">NaÄin preuzimanja</translation>
<translation id="1281476433249504884">1. pregrada za slaganje</translation>
<translation id="1285320974508926690">Nikad ne prevodi ovaj sajt</translation>
@@ -283,6 +291,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="204357726431741734">Prijavite se da biste koristili lozinke saÄuvane na Google nalogu</translation>
<translation id="2053111141626950936">Stranice na jeziku <ph name="LANGUAGE" /> necÌe biti prevedene.</translation>
<translation id="2053553514270667976">Poštanski broj</translation>
+<translation id="2054665754582400095">Prisustvo</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 predlog}one{# predlog}few{# predloga}other{# predloga}}</translation>
<translation id="2079545284768500474">Opozovi</translation>
<translation id="20817612488360358">Podešeno je da se koriste sistemska podešavanja proksija, ali je navedena eksplicitna konfiguracija proksija.</translation>
@@ -296,6 +305,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2102495993840063010">Android aplikacije</translation>
<translation id="2107021941795971877">Podrška za štampanje</translation>
<translation id="2108755909498034140">Ponovo pokrenite raÄunar</translation>
+<translation id="2111166930115883695">Pritisnite taster za razmak da biste igrali</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kartica</translation>
<translation id="2114841414352855701">Zanemaruju se jer su zamenjene smernicama <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="214556005048008348">Otkaži placÌanje</translation>
<translation id="2147827593068025794">Sinhronizacija u pozadini</translation>
<translation id="2148613324460538318">Dodaj karticu</translation>
+<translation id="2149968176347646218">Veza nije bezbedna</translation>
<translation id="2154054054215849342">Sinhronizacija nije dostupna za domen</translation>
<translation id="2154484045852737596">Izmenite karticu</translation>
<translation id="2161656808144014275">Tekst</translation>
@@ -317,7 +328,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2181821976797666341">Smernice</translation>
<translation id="2183608646556468874">Broj telefona</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adresa}one{# adresa}few{# adrese}other{# adresa}}</translation>
-<translation id="2187243482123994665">Prisustvo korisnika</translation>
<translation id="2187317261103489799">Otkrij (podrazumevano)</translation>
<translation id="2188375229972301266">Višestruko bušenje na dnu</translation>
<translation id="2202020181578195191">Unesite važecÌu godinu isteka</translation>
@@ -470,6 +480,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2839501879576190149">Sajt na koji želite da odete je lažan</translation>
<translation id="2850739647070081192">Invite (koverat)</translation>
<translation id="2856444702002559011">NapadaÄi možda pokuÅ¡avaju da ukradu informacije sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primer, lozinke, poruke ili kreditne kartice). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Ovaj sajt prikazuje oglase koji ometaju aktivnosti ili obmanjujucÌe oglase.</translation>
<translation id="2878197950673342043">Presavijanje u obliku postera</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Postavljanje prozora</translation>
@@ -508,11 +519,11 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2996674880327704673">Google predlozi</translation>
<translation id="3002501248619246229">Proverite medije ulazne fioke</translation>
<translation id="3005723025932146533">Prikaži saÄuvanu kopiju</translation>
-<translation id="3007719053326478567">Administrator je blokirao štampanje ovog sadržaja</translation>
<translation id="3008447029300691911">Unesite CVC za karticu <ph name="CREDIT_CARD" />. Kada budete potvrdili, podaci o kartici cÌe biti poslati ovom sajtu.</translation>
<translation id="3010559122411665027">Unos na listi „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Automatski je blokirano</translation>
<translation id="3016780570757425217">zna vašu lokaciju</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, pritisnite Tab, pa Enter da biste uklonili predlog.</translation>
<translation id="3023071826883856138">You4 (koverat)</translation>
<translation id="3024663005179499861">Pogrešan tip smernica</translation>
<translation id="3037605927509011580">O, ne!</translation>
@@ -555,6 +566,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3207960819495026254">Obeleženo</translation>
<translation id="3209034400446768650">Stranica može da naplacÌuje</translation>
<translation id="3212581601480735796">Vaše aktivnosti na <ph name="HOSTNAME" /> se prate</translation>
+<translation id="3212623355668894776">Zatvorite sve prozore u režimu gosta da bi se aktivnosti pregledanja izbrisale sa ovog uređaja.</translation>
<translation id="3215092763954878852">KoriÅ¡cÌenje veb-standarda WebAuthn nije uspelo</translation>
<translation id="3218181027817787318">Relativno</translation>
<translation id="3225919329040284222">Server je prikazao sertifikat koji se ne podudara sa ugraÄ‘enim oÄekivanjima. Ta oÄekivanja su obuhvacÌena za odreÄ‘ene veb-sajtove sa jakim bezbednosnim merama kako bi vas zaÅ¡titila.</translation>
@@ -702,6 +714,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3784372983762739446">Bluetooth uređaji</translation>
<translation id="3787705759683870569">IstiÄe <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">VeliÄina 16</translation>
+<translation id="3789841737615482174">Instaliraj</translation>
<translation id="3793574014653384240">Broj nedavnih otkazivanja i razlozi</translation>
<translation id="3797522431967816232">Prc3 (koverat)</translation>
<translation id="3799805948399000906">Font je zatražen</translation>
@@ -753,6 +766,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4056223980640387499">Sepija</translation>
<translation id="4058922952496707368">KljuÄ â€ž<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (koverat)</translation>
+<translation id="4067669230157909013">Snimanje ekrana je nastavljeno.</translation>
<translation id="4067947977115446013">Dodajte važecÌu adresu</translation>
<translation id="4072486802667267160">Došlo je do greške pri obradi porudžbine. Probajte ponovo.</translation>
<translation id="4075732493274867456">Klijent i server ne podržavaju istu verziju SSL protokola ili paket za šifrovanje.</translation>
@@ -837,6 +851,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4297502707443874121">SliÄica za <ph name="THUMBNAIL_PAGE" />. stranicu</translation>
<translation id="42981349822642051">Proširite</translation>
<translation id="4300675098767811073">Višestruko bušenje na desnoj strani</translation>
+<translation id="4302514097724775343">Dodirnite dinosaurusa da biste igrali</translation>
<translation id="4302965934281694568">Chou3 (koverat)</translation>
<translation id="4305666528087210886">Pristup datoteci nije uspeo</translation>
<translation id="4305817255990598646">Pređi</translation>
@@ -915,6 +930,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4658638640878098064">Spajanje u gornjem levom uglu</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuelna realnost</translation>
+<translation id="4675657451653251260">U režimu gosta necÌete videti nikakve informacije o Chrome profilu. Možete da se <ph name="LINK_BEGIN" />prijavite<ph name="LINK_END" /> radi pristupa informacijama o Google nalogu, kao Å¡to su lozinke i naÄini placÌanja.</translation>
<translation id="467662567472608290">Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat sadrži greÅ¡ke. Uzrok tome je možda pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vezu.</translation>
<translation id="4677585247300749148"><ph name="URL" /> želi da odgovara na dogaÄ‘aje pristupaÄnosti</translation>
<translation id="467809019005607715">Google prezentacije</translation>
@@ -942,6 +958,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4761104368405085019">KoriÅ¡cÌenje mikrofona</translation>
<translation id="4764776831041365478">MogucÌe je da veb-stranica na adresi <ph name="URL" /> privremeno ne funkcioniÅ¡e ili da je trajno premeÅ¡tena na novu veb adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje na dnu</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje ostaju na ovom uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Svi fajlovi koje preuzmete u ovom prozoru
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Došlo je do nepoznate greške.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{IskaÄucÌi prozor je blokiran}one{# iskaÄucÌi prozor je blokiran}few{# iskaÄucÌa prozora su blokirana}other{# iskaÄucÌih prozora je blokirano}}</translation>
<translation id="4780366598804516005">1. poÅ¡tansko sanduÄe</translation>
@@ -1104,11 +1126,13 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5386426401304769735">Lanac sertifikata za ovaj sajt sadrži sertifikat potpisan pomocÌu algoritma SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Spajanje ivica Å¡avom na desnoj strani</translation>
+<translation id="5398772614898833570">Oglasi su blokirani</translation>
<translation id="5400836586163650660">Siva</translation>
<translation id="540969355065856584">Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat trenutno nije važecÌi. Uzrok tome je možda pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vezu.</translation>
<translation id="541416427766103491">4. pregrada za slaganje</translation>
<translation id="5421136146218899937">Obriši podatke pregledanja...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> želi da vam šalje obaveštenja</translation>
+<translation id="542872847390508405">Pregledate kao gost</translation>
<translation id="5430298929874300616">Uklonite obeleživaÄ</translation>
<translation id="5439770059721715174">Greška u validaciji šeme na „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Obrnutim redosledom sa odštampanom stranom nagore</translation>
@@ -1150,12 +1174,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5571083550517324815">Preuzimanje sa ove adrese nije mogucÌe. Izaberite drugu adresu.</translation>
<translation id="5580958916614886209">Proverite mesec isteka i probajte ponovo</translation>
<translation id="5586446728396275693">Nema saÄuvanih adresa</translation>
+<translation id="5593349413089863479">Veza nije potpuno bezbedna</translation>
<translation id="5595485650161345191">Izmena adrese</translation>
<translation id="5598944008576757369">Odaberite naÄin placÌanja</translation>
<translation id="560412284261940334">Upravljanje nije podržano</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Ovaj sajt je možda lažan ili služi za prevaru. Chrome vam preporuÄuje da ga odmah napustite.</translation>
<translation id="5610142619324316209">da proverite vezu</translation>
<translation id="5610807607761827392">Karticama i adresama možete da upravljate u <ph name="BEGIN_LINK" />Podešavanjima<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Prevedite ovu stranicu pomocÌu Google prevodioca</translation>
@@ -1227,6 +1251,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5901630391730855834">Žuta</translation>
<translation id="5905445707201418379">Blokirano je u skladu sa smernicama za poreklo (<ph name="ORIGIN" />).</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinhronizovano)</translation>
+<translation id="5913377024445952699">Snimanje ekrana je pauzirano</translation>
<translation id="59174027418879706">OmogucÌeno</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">UkljuÄeno</translation>
@@ -1239,6 +1264,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5963413905009737549">Odeljak</translation>
<translation id="5967592137238574583">Izmenite kontakt informacije</translation>
<translation id="5967867314010545767">Ukloni iz istorije</translation>
+<translation id="5968793460449681917">Pri svakoj poseti</translation>
<translation id="5975083100439434680">Umanjivanje</translation>
<translation id="5979084224081478209">Proveri lozinke</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6587923378399804057">Link koji ste kopirali</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" />-om se ne upravlja</translation>
<translation id="6596325263575161958">Opcije Å¡ifrovanja</translation>
+<translation id="6596892391065203054">Administrator je blokirao štampanje ovog sadržaja.</translation>
<translation id="6604181099783169992">Senzori za pokret ili svetlo</translation>
<translation id="6609880536175561541">Prc7 (koverat)</translation>
<translation id="6612358246767739896">ZaÅ¡ticÌeni sadržaj</translation>
@@ -1452,6 +1479,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6895330447102777224">Kartica je potvrđena</translation>
<translation id="6897140037006041989">KorisniÄki agent</translation>
<translation id="6898699227549475383">Organizacija (O)</translation>
+<translation id="6907293445143367439">Dozvolite da <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> želi da u potpunosti kontroliše MIDI uređaje</translation>
<translation id="6915804003454593391">Korisnik:</translation>
<translation id="6934672428414710184">To je ime sa vašeg Google naloga</translation>
@@ -1563,6 +1591,7 @@ Dodatni detalji:
<translation id="7346048084945669753">Povezan je:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Komandna linija</translation>
+<translation id="7359588939039777303">Oglasi su blokirani.</translation>
<translation id="7372973238305370288">rezultat pretrage</translation>
<translation id="7374733840632556089">Ovaj problem se javlja zbog sertifikata koji ste vi ili neko drugi instalirali na ureÄ‘aju. Sertifikat se koristi za nadgledanje i presretanje mreža i Chrome ga ne smatra pouzdanim. Iako postoje pojedini opravdani razlozi za nadgledanje, na primer na Å¡kolskoj ili poslovnoj mreži, Chrome želi da budete svesni da se to dogaÄ‘a, Äak i ako to ne možete da spreÄite. Nadgledanje je mogucÌe u bilo kom pregledaÄu ili aplikaciji koja pristupa vebu.</translation>
<translation id="7375818412732305729">Datoteka je priložena</translation>
@@ -1737,6 +1766,7 @@ Dodatni detalji:
<translation id="7976214039405368314">Previše je zahteva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Da biste videli sadržaj proširene realnosti, instalirajte ARCore</translation>
<translation id="799149739215780103">Povezivanje</translation>
<translation id="7995512525968007366">Nije navedeno</translation>
<translation id="800218591365569300">Probajte da zatvorite druge kartice ili programe da biste oslobodili memoriju.</translation>
@@ -1864,25 +1894,39 @@ Dodatni detalji:
<translation id="8507227106804027148">Komandna linija</translation>
<translation id="8508648098325802031">Ikona Pretraga</translation>
<translation id="8522552481199248698">Chrome može da vam pomogne da zaštitite Google nalog i promenite lozinku.</translation>
+<translation id="8525306231823319788">Ceo ekran</translation>
<translation id="8530813470445476232">ObriÅ¡ite istoriju pregledanja, kolaÄicÌe, keÅ¡ i drugo u podeÅ¡avanjima Chrome-a</translation>
<translation id="8533619373899488139">Posetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste videli listu blokiranih URL-ova i druge smernice koje je odredio administrator sistema.</translation>
<translation id="8541158209346794904">Bluetooth uređaj</translation>
<translation id="8542014550340843547">Trostruko spajanje na dnu</translation>
<translation id="8543181531796978784">Možete da <ph name="BEGIN_ERROR_LINK" />prijavite problem sa otkrivanjem<ph name="END_ERROR_LINK" /> ili, ako shvatate bezbednosne rizike, <ph name="BEGIN_LINK" />posetite ovaj nebezbedan sajt<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC je na poleđini kartice.</translation>
+<translation id="8558485628462305855">Da biste videli sadržaj proširene realnosti, ažurirajte ARCore</translation>
<translation id="8559762987265718583">Nije mogucÌe uspostaviti privatnu vezu sa domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vreme na ureÄ‘aju (<ph name="DATE_AND_TIME" />) nisu taÄni.</translation>
<translation id="8564182942834072828">Odvojeni dokumenti/nesređene kopije</translation>
<translation id="8564985650692024650">Chromium vam preporuÄuje da resetujete lozinku za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je koristili na drugim sajtovima.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivnosti koje ne ostaju na ovom uređaju:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Stranice koje pregledate u ovom prozoru
+ <ph name="LIST_ITEM" />KolaÄicÌi i podaci o sajtovima
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Koristite Touch ID za bržu potvrdu kartica</translation>
<translation id="858637041960032120">Dodaj tel. broj
</translation>
<translation id="8589998999637048520">Najbolji kvalitet</translation>
+<translation id="8600271352425265729">Samo ovaj put</translation>
<translation id="860043288473659153">Ime vlasnika kartice</translation>
<translation id="8606726445206553943">koristi MIDI uređaje</translation>
+<translation id="8612761427948161954">Zdravo <ph name="USERNAME" />,
+ <ph name="BR" />
+ Pregledate kao gost</translation>
<translation id="861775596732816396">VeliÄina 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Nijedna lozinka se ne podudara. Prikaži sve saÄuvane lozinke.</translation>
<translation id="8625384913736129811">SaÄuvaj ovu karticu na ovom ureÄ‘aju</translation>
+<translation id="8627040765059109009">Snimanje ekrana je nastavljeno</translation>
<translation id="8657078576661269990">Administrator je blokirao deljenje sa <ph name="ORIGIN_NAME" /> na <ph name="VM_NAME_1" /> i <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Rezime porudžbine, <ph name="TOTAL_LABEL" />, još detalja</translation>
<translation id="867224526087042813">Potpis</translation>
@@ -1945,6 +1989,7 @@ Dodatni detalji:
<translation id="8912362522468806198">Google naloga</translation>
<translation id="8913778647360618320">Dugme Upravljaj naÄinima placÌanja, pritisnite Enter da biste upravljali placÌanjima i informacijama o kreditnim karticama u podeÅ¡avanjima Chrome-a</translation>
<translation id="8918231688545606538">Ova stranica je sumnjiva</translation>
+<translation id="8922013791253848639">Uvek dozvoljavaj oglase na ovom sajtu</translation>
<translation id="892588693504540538">Bušenje u gornjem desnom uglu</translation>
<translation id="8931333241327730545">Da li želite da saÄuvate ovu karticu na Google nalog?</translation>
<translation id="8932102934695377596">Sat vam kasni</translation>
@@ -2016,6 +2061,7 @@ Dodatni detalji:
<translation id="9183302530794969518">Google dokumenti</translation>
<translation id="9183425211371246419">Host <ph name="HOST_NAME" /> koristi nepodržani protokol.</translation>
<translation id="9191834167571392248">Bušenje u donjem levom uglu</translation>
+<translation id="9199905725844810519">Å tampanje je blokirano</translation>
<translation id="9205078245616868884">Podaci se Å¡ifruju pomocÌu pristupne fraze za sinhronizaciju. Unesite je da biste zapoÄeli sinhronizaciju.</translation>
<translation id="9207861905230894330">Dodavanje Älanka nije uspelo.</translation>
<translation id="9213433120051936369">Prilagodite izgled</translation>
@@ -2026,8 +2072,10 @@ Dodatni detalji:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Mogli biste da izgubite pristup Google nalogu. Chromium preporuÄuje da odmah promenite lozinku. MoracÌete da se prijavite.</translation>
<translation id="939736085109172342">Novi direktorijum</translation>
+<translation id="945522503751344254">Pošalji povratne informacije</translation>
<translation id="945855313015696284">Proverite informacije u nastavku i izbriÅ¡ite sve nevažecÌe kartice</translation>
<translation id="950736567201356821">Trostruko bušenje na vrhu</translation>
+<translation id="951941430552851965">Administrator je pauzirao snimanje ekrana zbog sadržaja na vašem ekranu.</translation>
<translation id="961663415146723894">Povez na dnu</translation>
<translation id="962484866189421427">Ovaj sadržaj možda pokuÅ¡ava da instalira obmanjujucÌe aplikacije koje se pretvaraju da su neÅ¡to drugo ili da prikupljaju podatke koji mogu da se koriste za pracÌenje. <ph name="BEGIN_LINK" />Prikaži<ph name="END_LINK" /></translation>
<translation id="969892804517981540">ZvaniÄna verzija</translation>
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index 6d86dd1302b..b25903eeb93 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Унели Ñте лозинку на Ñајту којим не управља ваша организација. Да биÑте заштитили налог, не кориÑтите лозинку поново у другим апликацијама ни на другим Ñајтовима.</translation>
<translation id="1263231323834454256">ЛиÑта за читање</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ÐктивноÑти које не оÑтају на овом уређају:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Странице које прегледате у овом прозору
+ <ph name="LIST_ITEM" />Колачићи и подаци о Ñајтовима
+ <ph name="LIST_ITEM" />Информације о налогу (<ph name="LINK_BEGIN" />одјавите Ñе<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ðачин преузимања</translation>
<translation id="1281476433249504884">1. преграда за Ñлагање</translation>
<translation id="1285320974508926690">Ðикад не преводи овај Ñајт</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Пријавите Ñе да биÑте кориÑтили лозинке Ñачуване на Google налогу</translation>
<translation id="2053111141626950936">Странице на језику <ph name="LANGUAGE" /> неће бити преведене.</translation>
<translation id="2053553514270667976">ПоштанÑки број</translation>
+<translation id="2054665754582400095">ПриÑуÑтво</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 предлог}one{# предлог}few{# предлога}other{# предлога}}</translation>
<translation id="2079545284768500474">Опозови</translation>
<translation id="20817612488360358">Подешено је да Ñе кориÑте ÑиÑтемÑка подешавања прокÑија, али је наведена екÑплицитна конфигурација прокÑија.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android апликације</translation>
<translation id="2107021941795971877">Подршка за штампање</translation>
<translation id="2108755909498034140">Поново покрените рачунар</translation>
+<translation id="2111166930115883695">ПритиÑните таÑтер за размак да биÑте играли</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Картица</translation>
<translation id="2114841414352855701">Занемарују Ñе јер Ñу замењене Ñмерницама <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">Откажи плаћање</translation>
<translation id="2147827593068025794">Синхронизација у позадини</translation>
<translation id="2148613324460538318">Додај картицу</translation>
+<translation id="2149968176347646218">Веза није безбедна</translation>
<translation id="2154054054215849342">Синхронизација није доÑтупна за домен</translation>
<translation id="2154484045852737596">Измените картицу</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Смернице</translation>
<translation id="2183608646556468874">Број телефона</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑа}one{# адреÑа}few{# адреÑе}other{# адреÑа}}</translation>
-<translation id="2187243482123994665">ПриÑуÑтво кориÑника</translation>
<translation id="2187317261103489799">Откриј (подразумевано)</translation>
<translation id="2188375229972301266">ВишеÑтруко бушење на дну</translation>
<translation id="2202020181578195191">УнеÑите важећу годину иÑтека</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">Сајт на који желите да одете је лажан</translation>
<translation id="2850739647070081192">Invite (коверат)</translation>
<translation id="2856444702002559011">Ðападачи можда покушавају да украду информације Ñа <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (на пример, лозинке, поруке или кредитне картице). <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Овај Ñајт приказује оглаÑе који ометају активноÑти или обмањујуће оглаÑе.</translation>
<translation id="2878197950673342043">ПреÑавијање у облику поÑтера</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ПоÑтављање прозора</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google предлози</translation>
<translation id="3002501248619246229">Проверите медије улазне фиоке</translation>
<translation id="3005723025932146533">Прикажи Ñачувану копију</translation>
-<translation id="3007719053326478567">ÐдминиÑтратор је блокирао штампање овог Ñадржаја</translation>
<translation id="3008447029300691911">УнеÑите CVC за картицу <ph name="CREDIT_CARD" />. Када будете потврдили, подаци о картици ће бити поÑлати овом Ñајту.</translation>
<translation id="3010559122411665027">Ð£Ð½Ð¾Ñ Ð½Ð° лиÑти „<ph name="ENTRY_INDEX" />“: <ph name="ERROR" /></translation>
<translation id="301521992641321250">ÐутоматÑки је блокирано</translation>
<translation id="3016780570757425217">зна вашу локацију</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, притиÑните Tab, па Enter да биÑте уклонили предлог.</translation>
<translation id="3023071826883856138">You4 (коверат)</translation>
<translation id="3024663005179499861">Погрешан тип Ñмерница</translation>
<translation id="3037605927509011580">О, не!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">Обележено</translation>
<translation id="3209034400446768650">Страница може да наплаћује</translation>
<translation id="3212581601480735796">Ваше активноÑти на <ph name="HOSTNAME" /> Ñе прате</translation>
+<translation id="3212623355668894776">Затворите Ñве прозоре у режиму гоÑта да би Ñе активноÑти прегледања избриÑале Ñа овог уређаја.</translation>
<translation id="3215092763954878852">Коришћење веб-Ñтандарда WebAuthn није уÑпело</translation>
<translation id="3218181027817787318">Релативно</translation>
<translation id="3225919329040284222">Сервер је приказао Ñертификат који Ñе не подудара Ñа уграђеним очекивањима. Та очекивања Ñу обухваћена за одређене веб-Ñајтове Ñа јаким безбедноÑним мерама како би Ð²Ð°Ñ Ð·Ð°ÑˆÑ‚Ð¸Ñ‚Ð¸Ð»Ð°.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">Bluetooth уређаји</translation>
<translation id="3787705759683870569">ИÑтиче <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Величина 16</translation>
+<translation id="3789841737615482174">ИнÑталирај</translation>
<translation id="3793574014653384240">Број недавних отказивања и разлози</translation>
<translation id="3797522431967816232">Prc3 (коверат)</translation>
<translation id="3799805948399000906">Фонт је затражен</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">Сепија</translation>
<translation id="4058922952496707368">Кључ „<ph name="SUBKEY" />“: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (коверат)</translation>
+<translation id="4067669230157909013">Снимање екрана је наÑтављено.</translation>
<translation id="4067947977115446013">Додајте важећу адреÑу</translation>
<translation id="4072486802667267160">Дошло је до грешке при обради поруџбине. Пробајте поново.</translation>
<translation id="4075732493274867456">Клијент и Ñервер не подржавају иÑту верзију SSL протокола или пакет за шифровање.</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121">Сличица за <ph name="THUMBNAIL_PAGE" />. Ñтраницу</translation>
<translation id="42981349822642051">Проширите</translation>
<translation id="4300675098767811073">ВишеÑтруко бушење на деÑној Ñтрани</translation>
+<translation id="4302514097724775343">Додирните диноÑауруÑа да биÑте играли</translation>
<translation id="4302965934281694568">Chou3 (коверат)</translation>
<translation id="4305666528087210886">ПриÑтуп датотеци није уÑпео</translation>
<translation id="4305817255990598646">Пређи</translation>
@@ -915,6 +930,7 @@
<translation id="4658638640878098064">Спајање у горњем левом углу</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Виртуелна реалноÑÑ‚</translation>
+<translation id="4675657451653251260">У режиму гоÑта нећете видети никакве информације о Chrome профилу. Можете да Ñе <ph name="LINK_BEGIN" />пријавите<ph name="LINK_END" /> ради приÑтупа информацијама о Google налогу, као што Ñу лозинке и начини плаћања.</translation>
<translation id="467662567472608290">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат Ñадржи грешке. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="4677585247300749148"><ph name="URL" /> жели да одговара на догађаје приÑтупачноÑти</translation>
<translation id="467809019005607715">Google презентације</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">Коришћење микрофона</translation>
<translation id="4764776831041365478">Могуће је да веб-Ñтраница на адреÑи <ph name="URL" /> привремено не функционише или да је трајно премештена на нову веб адреÑу.</translation>
<translation id="4766713847338118463">ДвоÑтруко Ñпајање на дну</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ ÐктивноÑти које оÑтају на овом уређају:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Сви фајлови које преузмете у овом прозору
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Дошло је до непознате грешке.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ИÑкачући прозор је блокиран}one{# иÑкачући прозор је блокиран}few{# иÑкачућа прозора Ñу блокирана}other{# иÑкачућих прозора је блокирано}}</translation>
<translation id="4780366598804516005">1. поштанÑко Ñандуче</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">Ланац Ñертификата за овај Ñајт Ñадржи Ñертификат потпиÑан помоћу алгоритма SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Спајање ивица шавом на деÑној Ñтрани</translation>
+<translation id="5398772614898833570">ОглаÑи Ñу блокирани</translation>
<translation id="5400836586163650660">Сива</translation>
<translation id="540969355065856584">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат тренутно није важећи. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="541416427766103491">4. преграда за Ñлагање</translation>
<translation id="5421136146218899937">Обриши податке прегледања...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> жели да вам шаље обавештења</translation>
+<translation id="542872847390508405">Прегледате као гоÑÑ‚</translation>
<translation id="5430298929874300616">Уклоните обележивач</translation>
<translation id="5439770059721715174">Грешка у валидацији шеме на „<ph name="ERROR_PATH" />“: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Обрнутим редоÑледом Ñа одштампаном Ñтраном нагоре</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">Преузимање Ñа ове адреÑе није могуће. Изаберите другу адреÑу.</translation>
<translation id="5580958916614886209">Проверите меÑец иÑтека и пробајте поново</translation>
<translation id="5586446728396275693">Ðема Ñачуваних адреÑа</translation>
+<translation id="5593349413089863479">Веза није потпуно безбедна</translation>
<translation id="5595485650161345191">Измена адреÑе</translation>
<translation id="5598944008576757369">Одаберите начин плаћања</translation>
<translation id="560412284261940334">Управљање није подржано</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Овај Ñајт је можда лажан или Ñлужи за превару. Chrome вам препоручује да га одмах напуÑтите.</translation>
<translation id="5610142619324316209">да проверите везу</translation>
<translation id="5610807607761827392">Картицама и адреÑама можете да управљате у <ph name="BEGIN_LINK" />Подешавањима<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Преведите ову Ñтраницу помоћу Google преводиоца</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">Жута</translation>
<translation id="5905445707201418379">Блокирано је у Ñкладу Ñа Ñмерницама за порекло (<ph name="ORIGIN" />).</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинхронизовано)</translation>
+<translation id="5913377024445952699">Снимање екрана је паузирано</translation>
<translation id="59174027418879706">Омогућено</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Укључено</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">Одељак</translation>
<translation id="5967592137238574583">Измените контакт информације</translation>
<translation id="5967867314010545767">Уклони из иÑторије</translation>
+<translation id="5968793460449681917">При Ñвакој поÑети</translation>
<translation id="5975083100439434680">Умањивање</translation>
<translation id="5979084224081478209">Провери лозинке</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@
<translation id="6587923378399804057">Линк који Ñте копирали</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" />-ом Ñе не управља</translation>
<translation id="6596325263575161958">Опције шифровања</translation>
+<translation id="6596892391065203054">ÐдминиÑтратор је блокирао штампање овог Ñадржаја.</translation>
<translation id="6604181099783169992">Сензори за покрет или Ñветло</translation>
<translation id="6609880536175561541">Prc7 (коверат)</translation>
<translation id="6612358246767739896">Заштићени Ñадржај</translation>
@@ -1452,6 +1479,7 @@
<translation id="6895330447102777224">Картица је потврђена</translation>
<translation id="6897140037006041989">КориÑнички агент</translation>
<translation id="6898699227549475383">Организација (O)</translation>
+<translation id="6907293445143367439">Дозволите да <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> жели да у потпуноÑти контролише MIDI уређаје</translation>
<translation id="6915804003454593391">КориÑник:</translation>
<translation id="6934672428414710184">То је име Ñа вашег Google налога</translation>
@@ -1563,6 +1591,7 @@
<translation id="7346048084945669753">Повезан је:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Командна линија</translation>
+<translation id="7359588939039777303">ОглаÑи Ñу блокирани.</translation>
<translation id="7372973238305370288">резултат претраге</translation>
<translation id="7374733840632556089">Овај проблем Ñе јавља због Ñертификата који Ñте ви или неко други инÑталирали на уређају. Сертификат Ñе кориÑти за надгледање и преÑретање мрежа и Chrome га не Ñматра поузданим. Иако поÑтоје поједини оправдани разлози за надгледање, на пример на школÑкој или поÑловној мрежи, Chrome жели да будете ÑвеÑни да Ñе то догађа, чак и ако то не можете да Ñпречите. Ðадгледање је могуће у било ком прегледачу или апликацији која приÑтупа вебу.</translation>
<translation id="7375818412732305729">Датотека је приложена</translation>
@@ -1737,6 +1766,7 @@
<translation id="7976214039405368314">Превише је захтева</translation>
<translation id="7977538094055660992">Излазни уређај</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Да биÑте видели Ñадржај проширене реалноÑти, инÑталирајте ARCore</translation>
<translation id="799149739215780103">Повезивање</translation>
<translation id="7995512525968007366">Ðије наведено</translation>
<translation id="800218591365569300">Пробајте да затворите друге картице или програме да биÑте оÑлободили меморију.</translation>
@@ -1864,25 +1894,39 @@
<translation id="8507227106804027148">Командна линија</translation>
<translation id="8508648098325802031">Икона Претрага</translation>
<translation id="8522552481199248698">Chrome може да вам помогне да заштитите Google налог и промените лозинку.</translation>
+<translation id="8525306231823319788">Цео екран</translation>
<translation id="8530813470445476232">Обришите иÑторију прегледања, колачиће, кеш и друго у подешавањима Chrome-а</translation>
<translation id="8533619373899488139">ПоÑетите &lt;strong&gt;chrome://policy&lt;/strong&gt; да биÑте видели лиÑту блокираних URL-ова и друге Ñмернице које је одредио админиÑтратор ÑиÑтема.</translation>
<translation id="8541158209346794904">Bluetooth уређај</translation>
<translation id="8542014550340843547">ТроÑтруко Ñпајање на дну</translation>
<translation id="8543181531796978784">Можете да <ph name="BEGIN_ERROR_LINK" />пријавите проблем Ñа откривањем<ph name="END_ERROR_LINK" /> или, ако Ñхватате безбедноÑне ризике, <ph name="BEGIN_LINK" />поÑетите овај небезбедан Ñајт<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC је на полеђини картице.</translation>
+<translation id="8558485628462305855">Да биÑте видели Ñадржај проширене реалноÑти, ажурирајте ARCore</translation>
<translation id="8559762987265718583">Ðије могуће уÑпоÑтавити приватну везу Ñа доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> јер датум и време на уређају (<ph name="DATE_AND_TIME" />) ниÑу тачни.</translation>
<translation id="8564182942834072828">Одвојени документи/неÑређене копије</translation>
<translation id="8564985650692024650">Chromium вам препоручује да реÑетујете лозинку за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако Ñте је кориÑтили на другим Ñајтовима.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ÐктивноÑти које не оÑтају на овом уређају:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Странице које прегледате у овом прозору
+ <ph name="LIST_ITEM" />Колачићи и подаци о Ñајтовима
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">КориÑтите Touch ID за бржу потврду картица</translation>
<translation id="858637041960032120">Додај тел. број
</translation>
<translation id="8589998999637048520">Ðајбољи квалитет</translation>
+<translation id="8600271352425265729">Само овај пут</translation>
<translation id="860043288473659153">Име влаÑника картице</translation>
<translation id="8606726445206553943">кориÑти MIDI уређаје</translation>
+<translation id="8612761427948161954">Здраво <ph name="USERNAME" />,
+ <ph name="BR" />
+ Прегледате као гоÑÑ‚</translation>
<translation id="861775596732816396">Величина 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Ðиједна лозинка Ñе не подудара. Прикажи Ñве Ñачуване лозинке.</translation>
<translation id="8625384913736129811">Сачувај ову картицу на овом уређају</translation>
+<translation id="8627040765059109009">Снимање екрана је наÑтављено</translation>
<translation id="8657078576661269990">ÐдминиÑтратор је блокирао дељење Ñа <ph name="ORIGIN_NAME" /> на <ph name="VM_NAME_1" /> и <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Резиме поруџбине, <ph name="TOTAL_LABEL" />, још детаља</translation>
<translation id="867224526087042813">ПотпиÑ</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google налога</translation>
<translation id="8913778647360618320">Дугме Управљај начинима плаћања, притиÑните Enter да биÑте управљали плаћањима и информацијама о кредитним картицама у подешавањима Chrome-а</translation>
<translation id="8918231688545606538">Ова Ñтраница је Ñумњива</translation>
+<translation id="8922013791253848639">Увек дозвољавај оглаÑе на овом Ñајту</translation>
<translation id="892588693504540538">Бушење у горњем деÑном углу</translation>
<translation id="8931333241327730545">Да ли желите да Ñачувате ову картицу на Google налог?</translation>
<translation id="8932102934695377596">Сат вам каÑни</translation>
@@ -2016,6 +2061,7 @@
<translation id="9183302530794969518">Google документи</translation>
<translation id="9183425211371246419">ХоÑÑ‚ <ph name="HOST_NAME" /> кориÑти неподржани протокол.</translation>
<translation id="9191834167571392248">Бушење у доњем левом углу</translation>
+<translation id="9199905725844810519">Штампање је блокирано</translation>
<translation id="9205078245616868884">Подаци Ñе шифрују помоћу приÑтупне фразе за Ñинхронизацију. УнеÑите је да биÑте започели Ñинхронизацију.</translation>
<translation id="9207861905230894330">Додавање чланка није уÑпело.</translation>
<translation id="9213433120051936369">Прилагодите изглед</translation>
@@ -2026,8 +2072,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Могли биÑте да изгубите приÑтуп Google налогу. Chromium препоручује да одмах промените лозинку. Мораћете да Ñе пријавите.</translation>
<translation id="939736085109172342">Ðови директоријум</translation>
+<translation id="945522503751344254">Пошаљи повратне информације</translation>
<translation id="945855313015696284">Проверите информације у наÑтавку и избришите Ñве неважеће картице</translation>
<translation id="950736567201356821">ТроÑтруко бушење на врху</translation>
+<translation id="951941430552851965">ÐдминиÑтратор је паузирао Ñнимање екрана због Ñадржаја на вашем екрану.</translation>
<translation id="961663415146723894">Повез на дну</translation>
<translation id="962484866189421427">Овај Ñадржај можда покушава да инÑталира обмањујуће апликације које Ñе претварају да Ñу нешто друго или да прикупљају податке који могу да Ñе кориÑте за праћење. <ph name="BEGIN_LINK" />Прикажи<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Званична верзија</translation>
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index 4b47384971d..5196b35cd45 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -55,7 +55,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="1175875016430184367">Tre häftklamrar till höger</translation>
<translation id="1178581264944972037">Paus</translation>
<translation id="1181037720776840403">Ta bort</translation>
-<translation id="1186201132766001848">Kontrollera lösenorden</translation>
+<translation id="1186201132766001848">Kontrollera lösenord</translation>
<translation id="1195558154361252544">Aviseringar blockeras automatiskt på alla webbplatser utom sådana du tillåter</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Nästa</translation>
@@ -80,6 +80,14 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Du har angett ditt lösenord på en webbplats som inte hanteras av organisationen. Skydda kontot genom att inte återanvända lösenordet för andra appar och webbplatser.</translation>
<translation id="1263231323834454256">Läslista</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Aktivitet som inte sparas på enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sidor du visar i det här fönstret
+ <ph name="LIST_ITEM" />Cookies och webbplatsdata
+ <ph name="LIST_ITEM" />Kontoinformation (<ph name="LINK_BEGIN" />logga ut<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Alternativ för utlämning</translation>
<translation id="1281476433249504884">Utmatningsfack 1</translation>
<translation id="1285320974508926690">Översätt aldrig den här webbplatsen</translation>
@@ -283,6 +291,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="204357726431741734">Logga in om du vill använda lösenord som har sparats i Google-kontot</translation>
<translation id="2053111141626950936">Sidor på <ph name="LANGUAGE" /> översätts inte.</translation>
<translation id="2053553514270667976">ZIP</translation>
+<translation id="2054665754582400095">Din närvaro</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 förslag}other{# förslag}}</translation>
<translation id="2079545284768500474">Ã…ngra</translation>
<translation id="20817612488360358">Datorns proxyinställningar är inställda på att användas, men det finns också en explicit proxykonfiguration.</translation>
@@ -296,6 +305,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="2102495993840063010">Android-appar</translation>
<translation id="2107021941795971877">Skriva ut underlag</translation>
<translation id="2108755909498034140">Starta om datorn</translation>
+<translation id="2111166930115883695">Tryck på blanksteg för att spela</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignoreras eftersom den åsidosätts av <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="214556005048008348">Avbryt betalningen</translation>
<translation id="2147827593068025794">Bakgrundssynkronisering</translation>
<translation id="2148613324460538318">Lägg till kort</translation>
+<translation id="2149968176347646218">Anslutningen är inte säker</translation>
<translation id="2154054054215849342">Synkronisering är inte tillgänglig för din domän</translation>
<translation id="2154484045852737596">Redigera kortet</translation>
<translation id="2161656808144014275">Text</translation>
@@ -317,7 +328,6 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="2181821976797666341">Policyer</translation>
<translation id="2183608646556468874">Telefonnummer</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adress}other{# adresser}}</translation>
-<translation id="2187243482123994665">Användarens närvaro</translation>
<translation id="2187317261103489799">Identifiera (standard)</translation>
<translation id="2188375229972301266">Flera hål längst ned</translation>
<translation id="2202020181578195191">Ange ett giltigt utgångsår</translation>
@@ -470,6 +480,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="2839501879576190149">Webbplatsen som öppnas är en bluff</translation>
<translation id="2850739647070081192">Invite (kuvert)</translation>
<translation id="2856444702002559011">En angripare kan försöka stjäla dina uppgifter från <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (t.ex. lösenord, meddelanden eller kreditkortsuppgifter). <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Påträngande eller vilseledande annonser visas på den här webbplatsen.</translation>
<translation id="2878197950673342043">Korsfalsning</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Fönsterplacering</translation>
@@ -508,11 +519,11 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="2996674880327704673">Förslag från Google</translation>
<translation id="3002501248619246229">Kontrollera inmatningsfack för media</translation>
<translation id="3005723025932146533">Visa sparad kopia</translation>
-<translation id="3007719053326478567">Möjligheten att skriva ut detta innehåll blockeras av administratören</translation>
<translation id="3008447029300691911">Ange CVC-koden för <ph name="CREDIT_CARD" />. När du bekräftar delas kortinformationen med den här webbplatsen.</translation>
<translation id="3010559122411665027">Listposten <ph name="ENTRY_INDEX" />: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Blockerades automatiskt</translation>
<translation id="3016780570757425217">Veta din plats</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, tryck på Tabb och sedan på Retur för att ta bort förslaget.</translation>
<translation id="3023071826883856138">You4 (kuvert)</translation>
<translation id="3024663005179499861">Felaktig policytyp</translation>
<translation id="3037605927509011580">Oj, ett fel har uppstått!</translation>
@@ -555,6 +566,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="3207960819495026254">Bokmärkt</translation>
<translation id="3209034400446768650">Sidan kan vara avgiftsbelagd</translation>
<translation id="3212581601480735796">Din aktivitet på <ph name="HOSTNAME" /> övervakas</translation>
+<translation id="3212623355668894776">Stäng alla gästfönster så raderas din webbaktivitet från enheten.</translation>
<translation id="3215092763954878852">Det gick inte att använda WebAuthn</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3225919329040284222">Ett certifikat som inte överensstämmer med inbyggda förväntningar presenterades på servern. Förväntningarna gäller för webbplatser med hög säkerhet för att skydda dig.</translation>
@@ -702,6 +714,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="3784372983762739446">Bluetooth-enheter</translation>
<translation id="3787705759683870569">Utgångsdatum: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Storlek 16</translation>
+<translation id="3789841737615482174">Installera</translation>
<translation id="3793574014653384240">Antal och orsaker till krascher som har skett nyligen</translation>
<translation id="3797522431967816232">Prc3 (kuvert)</translation>
<translation id="3799805948399000906">Teckensnitt begärt</translation>
@@ -753,6 +766,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Nyckel <ph name="SUBKEY" />: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (kuvert)</translation>
+<translation id="4067669230157909013">Skärmbild/skärminspelning har återupptagits.</translation>
<translation id="4067947977115446013">Lägg till giltig adress</translation>
<translation id="4072486802667267160">Det gick inte att behandla beställningen. Försök igen.</translation>
<translation id="4075732493274867456">Klienten och servern har inte stöd för en gemensam SSL-protokollversion eller chiffersvit.</translation>
@@ -780,7 +794,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="4152318981910038897">{COUNT,plural, =1{Sida 1}other{Sida {COUNT}}}</translation>
<translation id="4154664944169082762">Fingeravtryck</translation>
<translation id="4159784952369912983">Lila</translation>
-<translation id="4165986682804962316">Platsinställningar</translation>
+<translation id="4165986682804962316">Webbplatsinställningar</translation>
<translation id="4171400957073367226">Felaktig verifieringssignatur</translation>
<translation id="4171489848299289778"><ph name="RESULT_MODIFIED_DATE" /> – <ph name="RESULT_OWNER" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="4172051516777682613">Visa alltid</translation>
@@ -837,6 +851,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="4297502707443874121">Miniatyr för sidan <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expandera</translation>
<translation id="4300675098767811073">Flera hål till höger</translation>
+<translation id="4302514097724775343">Tryck på dinon för att spela</translation>
<translation id="4302965934281694568">Chou3 (kuvert)</translation>
<translation id="4305666528087210886">Ingen åtkomst till filen</translation>
<translation id="4305817255990598646">Byt</translation>
@@ -915,6 +930,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="4658638640878098064">Häfta uppe till vänster</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtuell verklighet</translation>
+<translation id="4675657451653251260">I gästläget kan du varken se eller ändra informationen i några Chrome-profiler. Du kan komma åt uppgifter som lösenord och betalningsmetoder i ditt Google-konto genom att <ph name="LINK_BEGIN" />logga in<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat innehåller fel. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="4677585247300749148"><ph name="URL" /> vill svara på tillgänglighetshändelser</translation>
<translation id="467809019005607715">Google Presentationer</translation>
@@ -942,6 +958,12 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="4761104368405085019">Använd mikrofonen</translation>
<translation id="4764776831041365478">Webbsidan på <ph name="URL" /> kan ligga nere för tillfället eller kan ha flyttats permanent till en ny webbadress.</translation>
<translation id="4766713847338118463">Två häftklamrar längst ned</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Aktivitet som sparas på enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Filer du laddar ned i fönstret
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Ett okänt fel uppstod.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Popup-fönster har blockerats}other{# popup-fönster har blockerats}}</translation>
<translation id="4780366598804516005">Postfack 1</translation>
@@ -1104,11 +1126,13 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="5386426401304769735">Certifikatkedjan för den här webbplatsen innehåller ett certifikat som signerades med SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Kanthäftning till höger</translation>
+<translation id="5398772614898833570">Annonser blockeras</translation>
<translation id="5400836586163650660">Grå</translation>
<translation id="540969355065856584">Servern kunde inte bevisa att det är <ph name="DOMAIN" />. Dess säkerhetscertifikat är inte giltigt för närvarande. Detta kan bero på en felaktig konfiguration eller att någon kapat din anslutning.</translation>
<translation id="541416427766103491">Utmatningsfack 4</translation>
<translation id="5421136146218899937">Ta bort webbinformation...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> vill skicka aviseringar</translation>
+<translation id="542872847390508405">Du surfar som gäst</translation>
<translation id="5430298929874300616">Ta bort bokmärke</translation>
<translation id="5439770059721715174">Schemavalideringsfel i <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Omvänd ordning – framsidan uppåt</translation>
@@ -1150,12 +1174,12 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="5571083550517324815">Utlämning erbjuds inte på den här adressen. Välj en annan adress.</translation>
<translation id="5580958916614886209">Kontrollera utgångsmånad och försök igen</translation>
<translation id="5586446728396275693">Inga sparade adresser</translation>
+<translation id="5593349413089863479">Anslutningen är inte helt säker</translation>
<translation id="5595485650161345191">Redigera adress</translation>
<translation id="5598944008576757369">Välj betalningsmetod</translation>
<translation id="560412284261940334">Hantering stöds inte</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Den här webbplatsen kan vara falsk eller bedräglig. Chrome rekommenderar att du lämnar den nu.</translation>
<translation id="5610142619324316209">kontrollera anslutningen</translation>
<translation id="5610807607761827392">Du hanterar kort och adresser under <ph name="BEGIN_LINK" />Inställningar<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Översätt den här sidan med Google Översätt</translation>
@@ -1227,6 +1251,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="5901630391730855834">Gul</translation>
<translation id="5905445707201418379">Blockerad i enlighet med ursprungsprincipen på <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (synkroniserade)</translation>
+<translation id="5913377024445952699">Skärmbild/skärminspelning har pausats</translation>
<translation id="59174027418879706">Aktiverad</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">PÃ¥</translation>
@@ -1239,8 +1264,9 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="5963413905009737549">Avsnitt</translation>
<translation id="5967592137238574583">Redigera kontaktuppgifter</translation>
<translation id="5967867314010545767">Ta bort från historiken</translation>
+<translation id="5968793460449681917">Vid varje besök</translation>
<translation id="5975083100439434680">Zooma ut</translation>
-<translation id="5979084224081478209">Kontrollera lösenorden</translation>
+<translation id="5979084224081478209">Kontrollera lösenord</translation>
<translation id="5980920751713728343">Index-3x5</translation>
<translation id="5984570616552610254">Luftfuktighet i kammare</translation>
<translation id="598637245381783098">Det gick inte att öppna betalningsappen</translation>
@@ -1394,6 +1420,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="6587923378399804057">Länk som du har kopierat</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> hanteras inte</translation>
<translation id="6596325263575161958">Krypteringsalternativ</translation>
+<translation id="6596892391065203054">Möjligheten att skriva ut detta innehåll blockeras av administratören.</translation>
<translation id="6604181099783169992">Rörelse- eller ljussensorer</translation>
<translation id="6609880536175561541">Prc7 (kuvert)</translation>
<translation id="6612358246767739896">Skyddat innehåll</translation>
@@ -1453,6 +1480,7 @@ Annars blockeras detta av sekretessinställningarna. Om du tillåter detta kan i
<translation id="6895330447102777224">Kortet har bekräftats</translation>
<translation id="6897140037006041989">Användaragent</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
+<translation id="6907293445143367439">Tillåt att <ph name="SITE_NAME" /> gör följande:</translation>
<translation id="6910240653697687763"><ph name="URL" /> vill ha fullständig kontroll över dina MIDI-enheter</translation>
<translation id="6915804003454593391">Användare:</translation>
<translation id="6934672428414710184">Det här namnet har hämtats från Google-kontot</translation>
@@ -1564,6 +1592,7 @@ Mer information.
<translation id="7346048084945669753">Är anknuten:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Kommandorad</translation>
+<translation id="7359588939039777303">Annonser blockeras.</translation>
<translation id="7372973238305370288">sökresultat</translation>
<translation id="7374733840632556089">Det här problemet uppstår på grund av ett certifikat som du eller någon annan har installerat på enheten. Certifikatet är känt för att användas för att övervaka och fånga upp nätverkstrafik och är inte betrott i Chrome. Även om det kan vara berättigat med övervakning i vissa fall, t.ex. i ett skol- eller företagsnätverk, vill vi göra dig medveten om vad som pågår även om du inte kan göra något åt det. Alla webbläsare och appar som använder internet omfattas av övervakningen.</translation>
<translation id="7375818412732305729">Fil bifogas</translation>
@@ -1738,6 +1767,7 @@ Mer information.
<translation id="7976214039405368314">För många begäranden</translation>
<translation id="7977538094055660992">Utmatningsenhet</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Installera ARCore om du vill visa innehåll med förstärkt verklighet</translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7995512525968007366">Inte specificerad</translation>
<translation id="800218591365569300">Testa att stänga andra flikar eller program för att frigöra minne.</translation>
@@ -1865,25 +1895,39 @@ Mer information:
<translation id="8507227106804027148">Kommandorad</translation>
<translation id="8508648098325802031">Sökikon</translation>
<translation id="8522552481199248698">Du kan skydda Google-kontot genom att byta lösenord.</translation>
+<translation id="8525306231823319788">Helskärm</translation>
<translation id="8530813470445476232">Rensa webbhistorik, cookies, cache med mera i inställningarna för Chrome</translation>
<translation id="8533619373899488139">Besök &lt;strong&gt;chrome://policy&lt;/strong&gt; om du vill visa listan med blockerade webbadresser och andra policyer som angetts av systemadministratören.</translation>
<translation id="8541158209346794904">Bluetooth-enhet</translation>
<translation id="8542014550340843547">Tre häftklamrar längst ned</translation>
<translation id="8543181531796978784">Du kan <ph name="BEGIN_ERROR_LINK" />rapportera ett identifieringsproblem<ph name="END_ERROR_LINK" /> eller <ph name="BEGIN_LINK" />besöka den här osäkra webbplatsen<ph name="END_LINK" /> om du är medveten om säkerhetsriskerna.</translation>
<translation id="8557066899867184262">CVC-koden finns på baksidan av kortet.</translation>
+<translation id="8558485628462305855">Uppdatera ARCore om du vill visa innehåll med förstärkt verklighet</translation>
<translation id="8559762987265718583">Det gick inte att upprätta en privat anslutning till <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> eftersom enhetens datum och tid (<ph name="DATE_AND_TIME" />) inte stämmer.</translation>
<translation id="8564182942834072828">Separata dokument/kopior grupperade per sida</translation>
<translation id="8564985650692024650">Du rekommenderas att återställa lösenordet för <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> om du har återanvänt det på andra webbplatser.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Aktivitet som inte sparas på enheten:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sidor du visar i det här fönstret
+ <ph name="LIST_ITEM" />Cookies och webbplatsdata
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Verifiera kreditkort snabbare med Touch ID</translation>
<translation id="858637041960032120">Ange telefonnr
</translation>
<translation id="8589998999637048520">Bästa kvalitet</translation>
+<translation id="8600271352425265729">Bara den här gången</translation>
<translation id="860043288473659153">Namn på kortinnehavare</translation>
<translation id="8606726445206553943">Använda MIDI-enheter</translation>
+<translation id="8612761427948161954">Hej <ph name="USERNAME" />!
+ <ph name="BR" />
+ Du surfar som gäst</translation>
<translation id="861775596732816396">Storlek 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Inga matchande lösenord. Visa alla sparade lösenord.</translation>
<translation id="8625384913736129811">Spara kortet på enheten</translation>
+<translation id="8627040765059109009">Skärmbilder/skärminspelningar har återupptagits</translation>
<translation id="8657078576661269990">Administratören har blockerat delning från <ph name="ORIGIN_NAME" /> till <ph name="VM_NAME_1" /> och <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Beställningsöversikt, <ph name="TOTAL_LABEL" />, mer information</translation>
<translation id="867224526087042813">Signatur</translation>
@@ -1946,6 +1990,7 @@ Mer information:
<translation id="8912362522468806198">Google-konto</translation>
<translation id="8913778647360618320">Knappen Hantera betalningsmetoder, tryck på Retur om du vill hantera betalningar och kreditkortsuppgifter i inställningarna för Chrome</translation>
<translation id="8918231688545606538">Sidan är misstänkt</translation>
+<translation id="8922013791253848639">Tillåt alltid annonser på den här webbplatsen</translation>
<translation id="892588693504540538">Hål uppe till höger</translation>
<translation id="8931333241327730545">Vill du spara det här kortet i ditt Google-konto?</translation>
<translation id="8932102934695377596">Klockan går efter</translation>
@@ -2017,6 +2062,7 @@ Mer information:
<translation id="9183302530794969518">Google Dokument</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> använder ett protokoll som inte stöds.</translation>
<translation id="9191834167571392248">Hål nere till vänster</translation>
+<translation id="9199905725844810519">Utskrift har blockerats</translation>
<translation id="9205078245616868884">Din data har krypterats med din lösenfras för synkronisering. Ange den om du vill starta synkroniseringen.</translation>
<translation id="9207861905230894330">Det gick inte att lägga till artikeln.</translation>
<translation id="9213433120051936369">Anpassa utseendet</translation>
@@ -2027,8 +2073,10 @@ Mer information:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Du kan förlora tillgången till Google-kontot. Du rekommenderas att ändra lösenordet nu. Du blir uppmanad att logga in.</translation>
<translation id="939736085109172342">Ny mapp</translation>
+<translation id="945522503751344254">Skicka feedback</translation>
<translation id="945855313015696284">Kontrollera informationen nedan och radera alla ogiltiga kort</translation>
<translation id="950736567201356821">Tre hål högst upp</translation>
+<translation id="951941430552851965">Skärmbild/skärminspelning pausades av administratören på grund av innehåll på skärmen.</translation>
<translation id="961663415146723894">Bindning längst ned</translation>
<translation id="962484866189421427">Bedrägliga appar som inte gör vad de påstås göra eller insamling av data som används för att spåra dig skulle kunna installeras via innehållet. <ph name="BEGIN_LINK" />Visa ändå<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Officiell version</translation>
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index 70b0b6c7f22..3ea86f558e9 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -80,6 +80,14 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Umeweka nenosiri kwenye tovuti ambayo haidhibitiwi na shirika lako. Ili ulinde akaunti yako, usitumie tena nenosiri lako kwenye tovuti na programu zingine.</translation>
<translation id="1263231323834454256">Orodha ya kusoma</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Shughuli ambazo hazitahifadhiwa kwenye kifaa hiki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Kurasa unazoziangalia katika dirisha hili
+ <ph name="LIST_ITEM" />Data ya tovuti na vidakuzi
+ <ph name="LIST_ITEM" />Maelezo ya akaunti (<ph name="LINK_BEGIN" />ondoka katika akaunti<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Mbinu ya Kuchukua</translation>
<translation id="1281476433249504884">Tupio la kutoa la printa la kwanza</translation>
<translation id="1285320974508926690">Kamwe usitafsiri tovuti hii</translation>
@@ -282,6 +290,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="204357726431741734">Ingia katika akaunti ili utumie manenosiri uliyohifadhi kwenye Akaunti yako ya Google</translation>
<translation id="2053111141626950936">Haitatafsiri kurasa za <ph name="LANGUAGE" />.</translation>
<translation id="2053553514270667976">Msimbo wa eneo</translation>
+<translation id="2054665754582400095">Maelezo ya wakati upo mtandaoni</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{Pendekezo 1}other{Mapendekezo #}}</translation>
<translation id="2079545284768500474">Tendua</translation>
<translation id="20817612488360358">Mipangilio ya mfumo ya proksi imewekwa ili kutumiwa lakini usanidi dhahiri wa proksi pia umebainishwa.</translation>
@@ -295,6 +304,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2102495993840063010">Programu za Android</translation>
<translation id="2107021941795971877">Visaidizi vya uchapishaji</translation>
<translation id="2108755909498034140">Zima na uwashe kompyuta yako</translation>
+<translation id="2111166930115883695">Bonyeza kitufe cha nafasi ili ucheze</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kadi</translation>
<translation id="2114841414352855701">Imepuuzwa kwa sababu ilifutwa na <ph name="POLICY_NAME" />.</translation>
@@ -306,6 +316,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="214556005048008348">Ghairi malipo</translation>
<translation id="2147827593068025794">Usawazishaji wa Chini Chini</translation>
<translation id="2148613324460538318">Ongeza Kadi</translation>
+<translation id="2149968176347646218">Muunganisho si salama</translation>
<translation id="2154054054215849342">Huduma ya usawazishaji haipatikani kwa ajili ya kikoa chako</translation>
<translation id="2154484045852737596">Badilisha kadi</translation>
<translation id="2161656808144014275">Maandishi</translation>
@@ -316,7 +327,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2181821976797666341">Sera</translation>
<translation id="2183608646556468874">Nambari ya Simu</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Anwani 1}other{Anwani #}}</translation>
-<translation id="2187243482123994665">Upatikanaji wa mtumiaji</translation>
<translation id="2187317261103489799">Gundua (chaguomsingi)</translation>
<translation id="2188375229972301266">Toboa mara kadhaa chini</translation>
<translation id="2202020181578195191">Andika mwaka sahihi wa kuisha kwa muda wa matumizi</translation>
@@ -469,6 +479,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2839501879576190149">Huenda ni tovuti bandia</translation>
<translation id="2850739647070081192">Invite (Bahasha)</translation>
<translation id="2856444702002559011">Huenda wavamizi wanajaribu kuiba maelezo yako kutoka <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (kwa mfano, manenosiri, ujumbe au kadi za mikopo).<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Tovuti inaonyesha matangazo yanayopotosha au yanayokatiza huduma.</translation>
<translation id="2878197950673342043">Mkunjo wa bango</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Kuonyesha dirisha</translation>
@@ -507,11 +518,11 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2996674880327704673">Mapendekezo kutoka Google</translation>
<translation id="3002501248619246229">Angalia yaliyo kwenye trei ya kuingiza</translation>
<translation id="3005723025932146533">Onyesha nakala iliyohifadhiwa</translation>
-<translation id="3007719053326478567">Kuchapisha maudhui haya kumezuiwa na msimamizi wako</translation>
<translation id="3008447029300691911">Weka CVC ya <ph name="CREDIT_CARD" />. Baada ya kuthibitisha, maelezo ya kadi yako yatashirikiwa na tovuti hii.</translation>
<translation id="3010559122411665027">Ingizo orodha "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Imezuiwa kiotomatiki</translation>
<translation id="3016780570757425217">kujua mahali ulipo</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, bonyeza kitufe cha "Tab" kisha "Enter" ili Uondoe Pendekezo.</translation>
<translation id="3023071826883856138">You4 (Bahasha)</translation>
<translation id="3024663005179499861">Aina mbaya ya sera</translation>
<translation id="3037605927509011580">Lo!</translation>
@@ -554,6 +565,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3207960819495026254">Imealamishwa</translation>
<translation id="3209034400446768650">Huenda ukurasa ukakutoza</translation>
<translation id="3212581601480735796">Shughuli zako kwenye <ph name="HOSTNAME" /> zinafuatiliwa</translation>
+<translation id="3212623355668894776">Funga madirisha yote ya Wageni ili shughuli zako za kuvinjari zifutwe kwenye kifaa hiki.</translation>
<translation id="3215092763954878852">Imeshindwa kutumia WebAuthn</translation>
<translation id="3218181027817787318">Kiwango wastani</translation>
<translation id="3225919329040284222">Seva imewasilisha cheti kisicholingana na matarajio ya kijenzi cha ndani. Matarajio haya yanajumlishwa kwa baadhi ya tovuti za usalama wa juu ili kukulinda.</translation>
@@ -701,6 +713,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3784372983762739446">Vifaa vya Bluetooth</translation>
<translation id="3787705759683870569">Muda wa matumizi utakwisha <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Ukubwa wa 16</translation>
+<translation id="3789841737615482174">Sakinisha</translation>
<translation id="3793574014653384240">Idadi na sababu za matukio ya hivi majuzi ya programu kuacha kufanya kazi</translation>
<translation id="3797522431967816232">Prc3 (Bahasha)</translation>
<translation id="3799805948399000906">Imeomba fonti</translation>
@@ -752,6 +765,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Kitufe "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Bahasha)</translation>
+<translation id="4067669230157909013">Kipengele cha kurekodi skrini kimeanza kutumika tena.</translation>
<translation id="4067947977115446013">Ongeza Anwani Sahihi ya Mahali Bidhaa Itapelekwa</translation>
<translation id="4072486802667267160">Hitilafu imetokea wakati wa kushughulikia agizo lako. Tafadhali jaribu tena.</translation>
<translation id="4075732493274867456">Mteja na seva hazitumii toleo la kawaida la itifaki ya SSL au mipangilio ya kriptografia.</translation>
@@ -836,6 +850,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4297502707443874121">Kijipicha cha ukurasa wa <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Panua</translation>
<translation id="4300675098767811073">Toboa mara kadhaa kulia</translation>
+<translation id="4302514097724775343">Gusa dinosau ili ucheze</translation>
<translation id="4302965934281694568">Chou3 (Bahasha)</translation>
<translation id="4305666528087210886">Imeshindwa kufikia faili yako</translation>
<translation id="4305817255990598646">Badilisha</translation>
@@ -914,6 +929,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4658638640878098064">Toboa juu kushoto</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Uhalisia pepe</translation>
+<translation id="4675657451653251260">Hutaona maelezo ya wasifu wowote kwenye Chrome katika dirisha la Wageni. Unaweza <ph name="LINK_BEGIN" />kuingia katika akaunti<ph name="LINK_END" /> ili uweze kufikia maelezo ya akaunti yako ya Google kama vile manenosiri na njia za kulipa.</translation>
<translation id="467662567472608290">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kina hitilafu. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="4677585247300749148"><ph name="URL" /> inataka kushughulikia matukio ya zana za walio na matatizo ya kuona au kusikia</translation>
<translation id="467809019005607715">Slaidi za Google</translation>
@@ -941,6 +957,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4761104368405085019">Tumia kipazasauti chako</translation>
<translation id="4764776831041365478">Ukurasa wa wavuti ulio <ph name="URL" /> unaweza kuwa haupatikani kwa muda au unaweza kuwa umehamishwa kabisa hadi anwani mpya ya wavuti.</translation>
<translation id="4766713847338118463">Bana mara mbili chini</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Shughuli zako zitakazohifadhiwa kwenye kifaa hiki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Faili zozote unazopakua katika dirisha hili
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Hitilafu isiyojulikana imetokea.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Imezuia dirisha ibukizi}other{Imezuia madirisha # ibukizi}}</translation>
<translation id="4780366598804516005">Kikasha cha barua cha kwanza</translation>
@@ -1103,11 +1125,13 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5386426401304769735">Msururu wa cheti wa tovuti hii una cheti kilichotiwa sahihi kwa kutumia SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Shona ncha ya kulia</translation>
+<translation id="5398772614898833570">Matangazo yamezuiwa</translation>
<translation id="5400836586163650660">Kijivu</translation>
<translation id="540969355065856584">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama si sahihi kwa sasa. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="541416427766103491">Tupio la kutoa la printa la nne</translation>
<translation id="5421136146218899937">Futa data ya kuvinjari...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> inataka kukutumia arifa</translation>
+<translation id="542872847390508405">Unavinjari kama Mgeni</translation>
<translation id="5430298929874300616">Ondoa alamisho</translation>
<translation id="5439770059721715174">Hitilafu katika uhalalishaji wa Skima " <ph name="ERROR_PATH" /> ": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Kinyume cha mpangilio wa kuangalia juu</translation>
@@ -1149,12 +1173,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5571083550517324815">Haiwezi kuchukua kutoka kwenye anwani hii. Chagua anwani tofauti.</translation>
<translation id="5580958916614886209">Angalia mwezi kuisha kwa muda wa matumizi halafu ujajibu tena</translation>
<translation id="5586446728396275693">Hakuna anwani zilizohifadhiwa</translation>
+<translation id="5593349413089863479">Muunganisho si salama kabisa</translation>
<translation id="5595485650161345191">Badilisha anwani</translation>
<translation id="5598944008576757369">Chagua Njia ya Kulipa</translation>
<translation id="560412284261940334">Usimamizi hautumiki</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Huenda tovuti hii ni bandia au laghai. Chrome inapendekeza uifunge sasa.</translation>
<translation id="5610142619324316209">Kuangalia muunganisho</translation>
<translation id="5610807607761827392">Unaweza kudhibiti maelezo ya kadi na anwani katika <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Tafsiri ukurasa huu ukitumia Google Tafsiri</translation>
@@ -1226,6 +1250,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5901630391730855834">Manjano</translation>
<translation id="5905445707201418379">Imezuiwa kulingana na sera ya asili ya <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (imesawazishwa)</translation>
+<translation id="5913377024445952699">Kipengele cha kupiga picha ya skrini kimesitishwa</translation>
<translation id="59174027418879706">Imewezeshwa</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Imewashwa</translation>
@@ -1238,6 +1263,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5963413905009737549">Sehemu</translation>
<translation id="5967592137238574583">Badilisha Maelezo ya Mawasiliano</translation>
<translation id="5967867314010545767">Ondoa kwenye historia</translation>
+<translation id="5968793460449681917">Kila wakati unapoitembelea</translation>
<translation id="5975083100439434680">Fifiza</translation>
<translation id="5979084224081478209">Kagua manenosiri</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1393,6 +1419,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6587923378399804057">Kiungo ulichonakili</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> yako haidhibitiwi</translation>
<translation id="6596325263575161958">Chaguo za usimbaji fiche</translation>
+<translation id="6596892391065203054">Kuchapisha maudhui haya kumezuiwa na msimamizi wako.</translation>
<translation id="6604181099783169992">Vitambuzi vya Mwendo au Mwangaza</translation>
<translation id="6609880536175561541">Prc7 (Bahasha)</translation>
<translation id="6612358246767739896">Maudhui yanayolindwa</translation>
@@ -1452,6 +1479,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6895330447102777224">Kadi yako imethibitishwa</translation>
<translation id="6897140037006041989">Programu ya Mtumiaji</translation>
<translation id="6898699227549475383">Shirika (O)</translation>
+<translation id="6907293445143367439">Ruhusu <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> inataka kupata udhibiti kamili wa vifaa vyako vya MIDI</translation>
<translation id="6915804003454593391">Mtumiaji:</translation>
<translation id="6934672428414710184">Jina hili linatoka kwenye Akaunti yako ya Google</translation>
@@ -1561,6 +1589,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7346048084945669753">Ni mshirika:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Mbinu ya Amri</translation>
+<translation id="7359588939039777303">Matangazo yamezuiwa.</translation>
<translation id="7372973238305370288">matokeo ya utafutaji</translation>
<translation id="7374733840632556089">Tatizo hili hutokea kwa sababu ya cheti ambacho wewe au mtu mwingine amesakinisha kwenye kifaa chako. Cheti kinajulikana kuwa huwa kinatumika kufuatilia na kuvamia mitandao na hakiaminiki na Chrome. Ingawa baadhi ya hali halali za ufuatiliaji zipo, kama vile kwenye mtandao wa shule au kampuni, Chrome ingependa kuhakikisha kuwa unafahamu kwamba jambo hili linafanyika, hata ikiwa huwezi kulisimamisha. Ufuatiliaji unaweza kutokea katika kivinjari chochote au programu inayoweza kufikia wavuti.</translation>
<translation id="7375818412732305729">Faili inapoambatishwa</translation>
@@ -1735,6 +1764,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7976214039405368314">Maombi mengi mno</translation>
<translation id="7977538094055660992">Kifaa cha kutoa maudhui</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Sakinisha ARCore ili uangalie maudhui ya uhalisia ulioboreshwa</translation>
<translation id="799149739215780103">Unganisha</translation>
<translation id="7995512525968007366">Hakijabainishwa</translation>
<translation id="800218591365569300">Jaribu kufunga vichupo au programu nyingine upate nafasi zaidi.</translation>
@@ -1860,25 +1890,39 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8507227106804027148">Mbinu ya amri</translation>
<translation id="8508648098325802031">Aikoni ya Utafutaji</translation>
<translation id="8522552481199248698">Chrome inaweza kukusaidia kulinda Akaunti yako ya Google na kubadilisha nenosiri lako.</translation>
+<translation id="8525306231823319788">Skrini nzima</translation>
<translation id="8530813470445476232">Futa historia yako ya kuvinjari, vidakuzi, akiba na zaidi katika mipangilio ya Chrome</translation>
<translation id="8533619373899488139">Tembelea &lt;strong&gt;chrome://policy&lt;/strong&gt; ili uone orodha ya URL zilizozuiwa na sera zingine zinazotekelezwa na msimamizi wako wa mfumo.</translation>
<translation id="8541158209346794904">Kifaa cha Bluetooth</translation>
<translation id="8542014550340843547">Bana mara tatu chini</translation>
<translation id="8543181531796978784">Unaweza <ph name="BEGIN_ERROR_LINK" />kuripoti tatizo la ugunduzi<ph name="END_ERROR_LINK" /> au, ikiwa unaelewa kiwango cha hatari kinachoweza kutokea, <ph name="BEGIN_LINK" />tembelea tovuti hii isiyo salama<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC inapatikana nyuma ya kadi yako.</translation>
+<translation id="8558485628462305855">Sasisha ARCore ili uangalie maudhui ya uhalisia ulioboreshwa</translation>
<translation id="8559762987265718583">Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hauwezi kupatikana kwa sababu tarehe na wakati wa kifaa chako (<ph name="DATE_AND_TIME" />) si sahihi.</translation>
<translation id="8564182942834072828">Hati zilizotenganishwa/Nakala ambazo hazijapangwa</translation>
<translation id="8564985650692024650">Chromium inapendekeza ubadilishe nenosiri lako la <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ikiwa ulilitumia tena kwenye tovuti zingine.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Shughuli ambazo hazitahifadhiwa kwenye kifaa hiki:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Kurasa unazoziangalia katika dirisha hili
+ <ph name="LIST_ITEM" />Data ya tovuti na vidakuzi
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Tumia Touch ID kuthibitisha kadi kwa haraka zaidi</translation>
<translation id="858637041960032120">Ongeza simu
</translation>
<translation id="8589998999637048520">Ubora wa juu zaidi</translation>
+<translation id="8600271352425265729">Mara hii pekee</translation>
<translation id="860043288473659153">Jina la mmiliki wa kadi</translation>
<translation id="8606726445206553943">Tumia vifaa vyako vya MIDI</translation>
+<translation id="8612761427948161954">Hujambo <ph name="USERNAME" />,
+ <ph name="BR" />
+ Unavinjari katika dirisha la Wageni</translation>
<translation id="861775596732816396">Ukubwa wa 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Hakuna manenosiri yanayolingana. Onyesha manenosiri yote yaliyohifadhiwa.</translation>
<translation id="8625384913736129811">Hifadhi Maelezo ya Kadi Hii kwenye Kifaa Hiki</translation>
+<translation id="8627040765059109009">Kipengele cha kupiga picha ya skrini kimeanza kutumika tena</translation>
<translation id="8657078576661269990">Msimamizi wako amezuia kushiriki kwenye <ph name="VM_NAME_1" /> na <ph name="VM_NAME_2" /> kutoka <ph name="ORIGIN_NAME" /></translation>
<translation id="8663226718884576429">Muhtasari wa Agizo, <ph name="TOTAL_LABEL" />, Maelezo Zaidi</translation>
<translation id="867224526087042813">Sahihi</translation>
@@ -1941,6 +1985,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8912362522468806198">Akaunti ya Google</translation>
<translation id="8913778647360618320">Kitufe cha 'Dhibiti njia za kulipa', bonyeza 'Enter' ili udhibiti maelezo yako ya malipo na ya kadi ya mikopo katika mipangilio ya Chrome</translation>
<translation id="8918231688545606538">Ukurasa huu unatiliwa shaka</translation>
+<translation id="8922013791253848639">Ruhusu matangazo kwenye tovuti hii wakati wote</translation>
<translation id="892588693504540538">Toboa juu kulia</translation>
<translation id="8931333241327730545">Je, ungependa kuhifadhi kadi hii katika Akaunti yako ya Google?</translation>
<translation id="8932102934695377596">Saa yako iko nyuma</translation>
@@ -2012,6 +2057,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="9183302530794969518">Hati za Google</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> hutumia itifaki isiyokubalika.</translation>
<translation id="9191834167571392248">Toboa chini kushoto</translation>
+<translation id="9199905725844810519">Kipengele cha kuchapisha kimezuiwa</translation>
<translation id="9205078245616868884">Data yako imesimbwa kwa njia fiche kwa kauli yako ya siri ya kusawazisha. Iweke ile uanze kusawazisha.</translation>
<translation id="9207861905230894330">Haikufaulu kuongeza makala.</translation>
<translation id="9213433120051936369">Weka mapendeleo ya mwonekano</translation>
@@ -2022,8 +2068,10 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Unaweza kupoteza uwezo wa kufikia Akaunti yako ya Google. Chromium inapendekeza ubadilishe nenosiri lako sasa. Utaombwa uingie katika akaunti.</translation>
<translation id="939736085109172342">Folda mpya</translation>
+<translation id="945522503751344254">Tuma maoni</translation>
<translation id="945855313015696284">Angalia maelezo yaliyo hapa chini na ufute kadi zozote ambazo si sahihi</translation>
<translation id="950736567201356821">Toboa mara tatu juu</translation>
+<translation id="951941430552851965">Kipengele cha kurekodi skrini kimesitishwa na msimamizi wako kwa sababu ya maudhui yaliyo kwenye skrini yako.</translation>
<translation id="961663415146723894">Unganisha chini</translation>
<translation id="962484866189421427">Huenda maudhui haya yakajaribu kusakinisha programu za udanganyifu zinazojifanya kuwa kitu kingine au kukusanya data inayoweza kutumika kukufuatilia. <ph name="BEGIN_LINK" />Onyesha tu<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Muundo Rasmi</translation>
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index 276724b01e9..dd50c1c327d 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">உஙà¯à®•à®³à¯ நிறà¯à®µà®©à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•à®¾à®¤ தளதà¯à®¤à®¿à®²à¯ உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®Ÿà¯€à®°à¯à®•à®³à¯. உஙà¯à®•à®³à¯ கணகà¯à®•à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•, பிற ஆபà¯à®¸à®¿à®²à¯à®®à¯ தளஙà¯à®•à®³à®¿à®²à¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ வேணà¯à®Ÿà®¾à®®à¯.</translation>
<translation id="1263231323834454256">வாசிபà¯à®ªà¯à®ªà¯ படà¯à®Ÿà®¿à®¯à®²à¯</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ பினà¯à®µà®°à¯à®ªà®µà¯ˆ இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />இநà¯à®¤à®šà¯ சாளரதà¯à®¤à®¿à®²à¯ பாரà¯à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à¯
+ <ph name="LIST_ITEM" />கà¯à®•à¯à®•à¯€à®•à®³à¯ &amp; தளதà¯à®¤à®¿à®©à¯ தரவà¯
+ <ph name="LIST_ITEM" />கணகà¯à®•à¯à®¤à¯ தகவலà¯à®•à®³à¯ (<ph name="LINK_BEGIN" />வெளியேறà¯<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">பிகà¯à®…ப௠மà¯à®±à¯ˆ</translation>
<translation id="1281476433249504884">ஸà¯à®Ÿà¯‡à®•à¯à®•à®°à¯ 1</translation>
<translation id="1285320974508926690">இநà¯à®¤ தளதà¯à®¤à¯ˆ எபà¯à®ªà¯‹à®¤à¯à®®à¯ மொழிபெயரà¯à®•à¯à®• வேணà¯à®Ÿà®¾à®®à¯</translation>
@@ -149,7 +157,7 @@
<translation id="1513706915089223971">வரலாறà¯à®±à¯ உளà¯à®³à¯€à®Ÿà¯à®•à®³à®¿à®©à¯ படà¯à®Ÿà®¿à®¯à®²à¯</translation>
<translation id="1517433312004943670">ஃபோன௠எண௠தேவை</translation>
<translation id="1519264250979466059">உரà¯à®µà®¾à®•à¯à®•à®¿à®¯ தேதி</translation>
-<translation id="1521655867290435174">Google விரிதாளà¯</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">இணைபà¯à®ªà®¿à®±à¯à®•à®¾à®•à®•à¯ காதà¯à®¤à®¿à®°à¯à®•à¯à®•à®¿à®±à®¤à¯â€¦</translation>
<translation id="1529521330346880926">10x15 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="1529789484829130889">தடà¯à®Ÿà¯ 8</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ உளà¯à®¨à¯à®´à¯ˆà®•</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> மொழியில௠உளà¯à®³ பகà¯à®•à®™à¯à®•à®³à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯.</translation>
<translation id="2053553514270667976">ஜிப௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
+<translation id="2054665754582400095">எனத௠செயலà¯à®ªà®¾à®Ÿà¯</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 பரிநà¯à®¤à¯à®°à¯ˆ}other{# பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯}}</translation>
<translation id="2079545284768500474">செயலà¯à®¤à®µà®¿à®°à¯</translation>
<translation id="20817612488360358">கணினி பà¯à®°à®¾à®•à¯à®¸à®¿ அமைபà¯à®ªà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. வெளிபà¯à®ªà®Ÿà¯ˆà®¯à®¾à®© பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Android ஆபà¯à®¸à¯</translation>
<translation id="2107021941795971877">உதவித௠தோறà¯à®±à®®à¯ˆà®ªà¯à®ªà¯à®•à®³à¯ˆ அசà¯à®šà®¿à®Ÿà¯à®¤à®²à¯</translation>
<translation id="2108755909498034140">கமà¯à®ªà¯à®¯à¯‚டà¯à®Ÿà®°à¯ˆ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®µà¯à®®à¯</translation>
+<translation id="2111166930115883695">விளையாடத௠தொடஙà¯à®• Space விசையை à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">காரà¯à®Ÿà¯</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ஆல௠கொளà¯à®•à¯ˆ மேலெழà¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à®¾à®²à¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">பேமணà¯à®Ÿà¯à®Ÿà¯ˆ ரதà¯à®¤à¯à®šà¯†à®¯à¯</translation>
<translation id="2147827593068025794">பினà¯à®ªà¯à®² ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯</translation>
<translation id="2148613324460538318">காரà¯à®Ÿà¯ˆà®šà¯ சேரà¯</translation>
+<translation id="2149968176347646218">பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± இணைபà¯à®ªà¯</translation>
<translation id="2154054054215849342">உஙà¯à®•à®³à¯ டொமைனà¯à®•à¯à®•à¯ ஒதà¯à®¤à®¿à®šà¯ˆà®¤à¯à®¤à®²à¯ சேவை à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="2154484045852737596">காரà¯à®Ÿà¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="2161656808144014275">உரை</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">கொளà¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="2183608646556468874">ஃபோன௠எணà¯</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 à®®à¯à®•à®µà®°à®¿}other{# à®®à¯à®•à®µà®°à®¿à®•à®³à¯}}</translation>
-<translation id="2187243482123994665">பயனர௠செயலà¯à®¨à®¿à®²à¯ˆ</translation>
<translation id="2187317261103489799">கணà¯à®Ÿà®±à®¿ (இயலà¯à®ªà¯)</translation>
<translation id="2188375229972301266">மலà¯à®Ÿà®¿à®ªà¯à®ªà®¿à®²à¯ பஞà¯à®šà¯ பாடà¯à®Ÿà®®à¯</translation>
<translation id="2202020181578195191">சரியான காலாவதி ஆணà¯à®Ÿà¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">போலியான தளம௠உளà¯à®³à®¤à¯</translation>
<translation id="2850739647070081192">Invite (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> தளதà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ ஹேகà¯à®•à®°à¯à®•à®³à¯ உஙà¯à®•à®³à¯ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, செயà¯à®¤à®¿à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) திரà¯à®Ÿ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ அலà¯à®²à®¤à¯ தவறாக வழிநடதà¯à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆ இநà¯à®¤à®¤à¯ தளம௠காணà¯à®ªà®¿à®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="2878197950673342043">போஸà¯à®Ÿà®°à¯ ஃபோலà¯à®Ÿà¯</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">சாளரதà¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à®¿à®Ÿà®®à¯</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">Google வழஙà¯à®•à¯à®®à¯ பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯</translation>
<translation id="3002501248619246229">உளà¯à®³à¯€à®Ÿà¯à®Ÿà¯à®¤à¯ தடà¯à®Ÿà®¿à®©à¯ மீடியாவைச௠சரிபாரà¯</translation>
<translation id="3005723025932146533">சேமிதà¯à®¤ நகலைக௠காடà¯à®Ÿà¯</translation>
-<translation id="3007719053326478567">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பிரிணà¯à®Ÿà¯ செயà¯à®µà®¤à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¾à®°à¯</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> இன௠CVC எணà¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯. உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¤ பினà¯à®©à®°à¯, உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à¯à®ªà¯ பகிரபà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="3010559122411665027">படà¯à®Ÿà®¿à®¯à®²à¯ உளà¯à®³à¯€à®Ÿà¯ "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">தானாகத௠தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="3016780570757425217">உஙà¯à®•à®³à¯ இரà¯à®ªà¯à®ªà®¿à®Ÿà®¤à¯à®¤à¯ˆ அறியà¯à®®à¯</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, பரிநà¯à®¤à¯à®°à¯ˆà®¯à¯ˆ அகறà¯à®± Tab விசையை à®…à®´à¯à®¤à¯à®¤à®¿à®¯à®ªà®¿à®±à®•à¯ Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯.</translation>
<translation id="3023071826883856138">You4 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="3024663005179499861">தவறான கொளà¯à®•à¯ˆ வகை</translation>
<translation id="3037605927509011580">அசà¯à®šà®šà¯à®šà¯‹!</translation>
@@ -550,6 +561,7 @@
<translation id="3207960819495026254">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="3209034400446768650">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செனà¯à®±à®¾à®²à¯ கடà¯à®Ÿà®£à®®à¯ விதிகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> இல௠உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
+<translation id="3212623355668894776">உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆ இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ நீகà¯à®•, கெஸà¯à®Ÿà¯ சாளரஙà¯à®•à®³à¯ அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ மூடவà¯à®®à¯.</translation>
<translation id="3215092763954878852">WebAuthnனைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3218181027817787318">சாரà¯à®ªà¯à®Ÿà¯ˆà®¯à®¤à¯</translation>
<translation id="3225919329040284222">உளà¯à®³à®®à¯ˆà®¨à¯à®¤ எதிரà¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯à®Ÿà®©à¯ பொரà¯à®¨à¯à®¤à®¾à®¤ சானà¯à®±à®¿à®¤à®´à¯ˆ சேவையகம௠வழஙà¯à®•à®¿à®¯à®¤à¯. சில உயரà¯-பாதà¯à®•à®¾à®ªà¯à®ªà¯ வலைதà¯à®¤à®³à®™à¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à®µà¯‡ இநà¯à®¤ எதிரà¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯ சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®©.</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">பà¯à®³à¯‚டூத௠சாதனஙà¯à®•à®³à¯</translation>
<translation id="3787705759683870569">காலாவதி: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">அளவà¯: 16</translation>
+<translation id="3789841737615482174">நிறà¯à®µà¯à®•</translation>
<translation id="3793574014653384240">சமீபதà¯à®¤à®¿à®²à¯ நிகழà¯à®¨à¯à®¤ சிதைவà¯à®•à®³à®¿à®©à¯ எணà¯à®£à®¿à®•à¯à®•à¯ˆà®•à®³à¯à®®à¯ காரணஙà¯à®•à®³à¯à®®à¯</translation>
<translation id="3797522431967816232">Prc3 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="3799805948399000906">கோரபà¯à®ªà®Ÿà¯à®Ÿ எழà¯à®¤à¯à®¤à¯à®°à¯</translation>
@@ -747,6 +760,7 @@
<translation id="4056223980640387499">செபியா</translation>
<translation id="4058922952496707368">விசை "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (எனà¯à®µà®²à®ªà¯)</translation>
+<translation id="4067669230157909013">திரையின௠ஸà¯à®•à®¿à®°à¯€à®©à¯à®·à®¾à®Ÿà¯ எடà¯à®ªà¯à®ªà®¤à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="4067947977115446013">சரியான à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®šà¯ சேரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="4072486802667267160">ஆரà¯à®Ÿà®°à¯ˆà®šà¯ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à®¿à®²à¯ பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯. பிறக௠மà¯à®¯à®²à®µà¯à®®à¯.</translation>
<translation id="4075732493274867456">கà¯à®³à¯ˆà®¯à®©à¯à®Ÿà¯à®Ÿà¯à®®à¯ சேவையகமà¯à®®à¯ பொதà¯à®µà®¾à®© SSL நெறிமà¯à®±à¯ˆà®ªà¯ பதிபà¯à®ªà¯ˆà®¯à¯‹ சைஃபர௠பொதியையோ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
@@ -831,6 +845,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ சிற௠படமà¯</translation>
<translation id="42981349822642051">விரி</translation>
<translation id="4300675098767811073">மலà¯à®Ÿà®¿à®ªà¯à®ªà®¿à®²à¯ பஞà¯à®šà¯ ரைடà¯</translation>
+<translation id="4302514097724775343">விளையாட டைனோசரைத௠தடà¯à®Ÿà¯à®™à¯à®•à®³à¯</translation>
<translation id="4302965934281694568">Chou3 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="4305666528087210886">உஙà¯à®•à®³à¯ கோபà¯à®ªà®¿à®©à¯ˆ அணà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="4305817255990598646">மாறà¯</translation>
@@ -909,9 +924,10 @@
<translation id="4658638640878098064">ஸà¯à®Ÿà¯‡à®ªà¯à®ªà®¿à®²à¯ டாப௠லெஃபà¯à®Ÿà¯</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">விரà¯à®šà¯à®šà¯à®µà®²à¯ ரியாலிடà¯à®Ÿà®¿</translation>
+<translation id="4675657451653251260">கெஸà¯à®Ÿà¯ பயனà¯à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ எநà¯à®¤à®µà¯Šà®°à¯ Chrome சà¯à®¯à®µà®¿à®µà®°à®¤à¯à®¤à®¿à®©à¯ தகவலà¯à®®à¯ காடà¯à®Ÿà®ªà¯à®ªà®Ÿà®¾à®¤à¯. கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆà®•à®³à¯ போனà¯à®± உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯à®¤à¯ தகவலை அணà¯à®• <ph name="LINK_BEGIN" />உளà¯à®¨à¯à®´à¯ˆà®¯à®²à®¾à®®à¯<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">இத௠<ph name="DOMAIN" /> தான௠எனà¯à®ªà®¤à¯ˆ இநà¯à®¤à®šà¯ சேவையகம௠உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à®¿à®²à¯ பிழைகள௠உளà¯à®³à®©. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4677585247300749148">அணà¯à®•à®²à¯à®¤à®©à¯à®®à¯ˆ நிகழà¯à®µà¯à®•à®³à¯à®•à¯à®•à¯, <ph name="URL" /> பதிலளிகà¯à®• விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
-<translation id="467809019005607715">Google ஸà¯à®²à¯ˆà®Ÿà¯</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">மோசடி செயà¯à®¯à¯à®®à¯ தளதà¯à®¤à®¿à®²à¯ உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯. இநà¯à®¤à®•à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> ஆகியவறà¯à®±à¯à®•à¯à®•à¯à®®à¯ பிற தளஙà¯à®•à®³à¯à®•à¯à®•à¯à®®à¯ செனà¯à®±à¯ à®…à®™à¯à®•à¯ சேமிதà¯à®¤à¯à®³à¯à®³ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="4690462567478992370">தவறான சானà¯à®±à®¿à®¤à®´à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®µà®¤à¯ˆ நிறà¯à®¤à¯à®¤à¯</translation>
<translation id="4691835149146451662">Architecture-A (எனà¯à®µà®²à®ªà¯)</translation>
@@ -936,6 +952,12 @@
<translation id="4761104368405085019">உஙà¯à®•à®³à¯ மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
<translation id="4764776831041365478"><ph name="URL" /> இல௠உளà¯à®³ வலைபà¯à®ªà®•à¯à®•à®®à®¾à®©à®¤à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®• இயஙà¯à®•à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ அத௠ஒர௠பà¯à®¤à®¿à®¯ வலை à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ நிரநà¯à®¤à®°à®®à®¾à®• நகரà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4766713847338118463">டூயல௠ஸà¯à®Ÿà¯‡à®ªà¯à®ªà®¿à®²à¯ பாடà¯à®Ÿà®®à¯</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ இவை இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />இநà¯à®¤à®šà¯ சாளரதà¯à®¤à®¿à®²à¯ நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à¯à®®à¯ கோபà¯à®ªà¯à®•à®³à¯
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">அறியபà¯à®ªà®Ÿà®¾à®¤ பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{பாபà¯-அப௠தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯}other{# பாபà¯-அபà¯à®•à®³à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©}}</translation>
<translation id="4780366598804516005">அஞà¯à®šà®²à¯ பெடà¯à®Ÿà®¿ 1</translation>
@@ -1098,11 +1120,13 @@
<translation id="5386426401304769735">இநà¯à®¤à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ சஙà¯à®•à®¿à®²à®¿à®¯à®¿à®²à¯, SHA-1à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ கையொபà¯à®ªà®®à®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿ சானà¯à®±à®¿à®¤à®´à¯ உளà¯à®³à®¤à¯.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">எடà¯à®œà¯ ஸà¯à®Ÿà®¿à®Ÿà¯à®šà¯ ரைடà¯</translation>
+<translation id="5398772614898833570">விளமà¯à®ªà®°à®™à¯à®•à®³à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©</translation>
<translation id="5400836586163650660">கிரே</translation>
<translation id="540969355065856584"><ph name="DOMAIN" /> டொமைனை, சேவையகம௠உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; அதறà¯à®•à®¾à®© காரணஙà¯à®•à®³à¯: இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ தறà¯à®ªà¯‹à®¤à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®©à®¤à®²à¯à®². இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¿à®©à®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="541416427766103491">ஸà¯à®Ÿà¯‡à®•à¯à®•à®°à¯ 4</translation>
<translation id="5421136146218899937">உலாவிய தரவை அழி...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> உஙà¯à®•à®³à¯à®•à¯à®•à¯ அறிவிபà¯à®ªà¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ª விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
+<translation id="542872847390508405">கெஸà¯à®Ÿà®¾à®• உலாவà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯</translation>
<translation id="5430298929874300616">பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®¯à¯ˆ அகறà¯à®±à¯</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" திடà¯à®Ÿà®®à¯à®±à¯ˆ சரிபாரà¯à®ªà¯à®ªà¯à®ªà¯ பிழை: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">பினà¯à®©à¯‹à®•à¯à®•à®¿à®¯ வரிசையில௠மேல௠நோகà¯à®•à®¿à®¯ பாணி</translation>
@@ -1144,12 +1168,12 @@
<translation id="5571083550517324815">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ பிகà¯à®…ப௠செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="5580958916614886209">காலாவதி மாததà¯à®¤à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à®µà¯à®®à¯</translation>
<translation id="5586446728396275693">சேமிதà¯à®¤ à®®à¯à®•à®µà®°à®¿à®•à®³à¯ இலà¯à®²à¯ˆ</translation>
+<translation id="5593349413089863479">இணைபà¯à®ªà¯ à®®à¯à®´à¯à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯à®Ÿà®©à¯ இலà¯à®²à¯ˆ</translation>
<translation id="5595485650161345191">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à¯</translation>
<translation id="5598944008576757369">கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆà®¯à¯ˆà®¤à¯ தேரà¯à®µà¯ செயà¯</translation>
<translation id="560412284261940334">நிரà¯à®µà®¾à®•à®®à¯ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">இநà¯à®¤à®¤à¯ தளம௠போலியானதாகவோ மோசடி செயà¯à®¯à®•à¯à®•à¯‚டியதாகவோ இரà¯à®•à¯à®•à¯à®®à¯. இதிலிரà¯à®¨à¯à®¤à¯ இபà¯à®ªà¯‹à®¤à¯‡ வெளியேறà¯à®®à®¾à®±à¯ Chrome பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="5610142619324316209">இணைபà¯à®ªà¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯</translation>
<translation id="5610807607761827392"><ph name="BEGIN_LINK" />அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> காரà¯à®Ÿà¯à®•à®³à¯ˆà®¯à¯à®®à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯ˆà®¯à¯à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="561165882404867731">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ Google Translate மூலம௠மொழிபெயரà¯</translation>
@@ -1221,6 +1245,7 @@
<translation id="5901630391730855834">மஞà¯à®šà®³à¯</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> இன௠அசல௠கொளà¯à®•à¯ˆà®¯à®¿à®©à¯à®ªà®Ÿà®¿ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ஒதà¯à®¤à®¿à®šà¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯)</translation>
+<translation id="5913377024445952699">ஸà¯à®•à®¿à®°à¯€à®©à¯à®·à®¾à®Ÿà¯ எடà¯à®ªà¯à®ªà®¤à¯ இடைநிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="59174027418879706">இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
@@ -1233,6 +1258,7 @@
<translation id="5963413905009737549">பிரிவà¯</translation>
<translation id="5967592137238574583">தொடரà¯à®ªà¯à®¤à¯ தகவலைத௠திரà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="5967867314010545767">வரலாறà¯à®±à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ அகறà¯à®±à¯</translation>
+<translation id="5968793460449681917">ஒவà¯à®µà¯Šà®°à¯ à®®à¯à®±à¯ˆ வரà¯à®®à¯à®ªà¯‹à®¤à¯à®®à¯</translation>
<translation id="5975083100439434680">சிறிதாகà¯à®•à¯</translation>
<translation id="5979084224081478209">கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®šà¯ சோதிதà¯à®¤à¯à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1387,6 +1413,7 @@
<translation id="6587923378399804057">நீஙà¯à®•à®³à¯ நகலெடà¯à®¤à¯à®¤ இணைபà¯à®ªà¯</translation>
<translation id="6591833882275308647">உஙà¯à®•à®³à¯ <ph name="DEVICE_TYPE" /> சாதனம௠நிரà¯à®µà®•à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="6596325263575161958">எனà¯à®•à¯à®°à®¿à®ªà¯à®·à®©à¯ விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯</translation>
+<translation id="6596892391065203054">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பிரிணà¯à®Ÿà¯ செயà¯à®µà®¤à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¾à®°à¯.</translation>
<translation id="6604181099783169992">நகரà¯à®µà¯ அலà¯à®²à®¤à¯ ஒளி உணரà¯à®µà®¿à®•à®³à¯</translation>
<translation id="6609880536175561541">Prc7 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="6612358246767739896">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®®à¯</translation>
@@ -1446,6 +1473,7 @@
<translation id="6895330447102777224">காரà¯à®Ÿà¯ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="6897140037006041989">பயனர௠à®à®œà¯†à®£à¯à®Ÿà¯</translation>
<translation id="6898699227549475383">நிறà¯à®µà®©à®®à¯ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> இவறà¯à®±à¯ˆ அணà¯à®• அனà¯à®®à®¤à®¿à®•à¯à®•à®µà¯à®®à¯:</translation>
<translation id="6910240653697687763"><ph name="URL" /> MIDI சாதனஙà¯à®•à®³à®¿à®©à¯ à®®à¯à®´à¯à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯ˆà®¯à¯à®®à¯ பெற விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="6915804003454593391">பயனரà¯:</translation>
<translation id="6934672428414710184">இநà¯à®¤à®ªà¯ பெயர௠உஙà¯à®•à®³à¯ ‘Google கணகà¯à®•à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯â€™ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
@@ -1465,7 +1493,7 @@
<translation id="6973656660372572881">நிலையான பà¯à®°à®¾à®•à¯à®¸à®¿ சேவையகஙà¯à®•à®³à¯à®®à¯ .pac ஸà¯à®•à®¿à®°à®¿à®ªà¯à®Ÿà¯ URL ஆகிய இரணà¯à®Ÿà¯à®®à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
<translation id="6973932557599545801">மனà¯à®©à®¿à®•à¯à®•à®µà¯à®®à¯, எனà¯à®©à®¾à®²à¯ உதவ இயலவிலà¯à®²à¯ˆ. நீஙà¯à®•à®³à¯‡ செயà¯à®¯à¯à®™à¯à®•à®³à¯.</translation>
<translation id="6975012522936652259">மோசடி செயà¯à®¯à¯à®®à¯ இணையதளதà¯à®¤à®¿à®²à¯ உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯. இநà¯à®¤à®•à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ உளà¯à®¨à¯à®´à¯ˆà®¯à¯à®®à¯ <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> மறà¯à®±à¯à®®à¯ பிற தளஙà¯à®•à®³à¯à®•à¯à®•à¯à®šà¯ செனà¯à®±à¯ இதை இபà¯à®ªà¯‹à®¤à¯‡ மாறà¯à®±à¯à®®à®¾à®±à¯ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
-<translation id="6979158407327259162">Google இயகà¯à®•à®•à®®à¯</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">à®®à¯à®Ÿà®•à¯à®•à¯ (இயலà¯à®ªà¯)</translation>
<translation id="6979983982287291980">நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à¯à®®à¯ கோபà¯à®ªà¯à®•à®³à¯ Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®• வேணà¯à®Ÿà®¿à®¯ தரவோ மாலà¯à®µà¯‡à®°à¯‹ உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அவை ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="6989763994942163495">மேமà¯à®ªà®Ÿà¯à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿...</translation>
@@ -1557,6 +1585,7 @@
<translation id="7346048084945669753">இணைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¾à®°à®¾?:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">கடà¯à®Ÿà®³à¯ˆ வரி</translation>
+<translation id="7359588939039777303">விளமà¯à®ªà®°à®™à¯à®•à®³à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©.</translation>
<translation id="7372973238305370288">தேடல௠மà¯à®Ÿà®¿à®µà¯</translation>
<translation id="7374733840632556089">உஙà¯à®•à®³à®¾à®²à¯‹ வேறொரà¯à®µà®°à®¾à®²à¯‹ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯ நிறà¯à®µà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ சானà¯à®±à®¿à®¤à®´à¯‡ இநà¯à®¤à®šà¯ சிகà¯à®•à®²à¯à®•à¯à®•à¯à®•à¯ காரணம௠ஆகà¯à®®à¯. இத௠நெடà¯à®µà¯Šà®°à¯à®•à¯à®•à¯à®•à®³à¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯à®®à¯ அவறà¯à®±à®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®µà®¤à®±à¯à®•à¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯ சானà¯à®±à®¿à®¤à®´à¯ ஆகà¯à®®à¯, எனவே இதை Chrome நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. பளà¯à®³à®¿ அலà¯à®²à®¤à¯ நிறà¯à®µà®© நெடà¯à®µà¯Šà®°à¯à®•à¯ போனà¯à®±à®¤à¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®• வேணà¯à®Ÿà®¿à®¯ நியாயமான சூழலà¯à®•à®³à¯ இரà¯à®•à¯à®•à¯à®®à¯†à®©à®¿à®©à¯à®®à¯, உஙà¯à®•à®³à®¾à®²à¯ தடà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à®ªà¯‹à®¤à¯à®®à¯ இத௠நிகழà¯à®•à®¿à®±à®¤à¯ எனà¯à®ªà®¤à¯ˆ நீஙà¯à®•à®³à¯ அறிய வேணà¯à®Ÿà¯à®®à¯†à®© Chrome விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯. இணையதà¯à®¤à¯ˆ அணà¯à®•à®•à¯à®•à¯‚டிய எநà¯à®¤ உலாவியà¯à®®à¯ ஆபà¯à®¸à¯à®®à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="7375818412732305729">கோபà¯à®ªà¯ இணைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯</translation>
@@ -1688,7 +1717,7 @@
<translation id="7791011319128895129">வெளியிடபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7791196057686275387">பேலà¯</translation>
<translation id="7791543448312431591">சேரà¯</translation>
-<translation id="7798389633136518089">கிளவà¯à®Ÿà¯ ஆதாரம௠மூலம௠அமைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à®¤à®¾à®²à¯ கொளà¯à®•à¯ˆ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
+<translation id="7798389633136518089">கிளவà¯à®Ÿà¯ ஆதாரம௠மூலம௠அமைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à®¤à®¾à®²à¯ கொளà¯à®•à¯ˆ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="7800304661137206267">செயà¯à®¤à®¿ à®…à®™à¯à®•à¯€à®•à®°à®¿à®ªà¯à®ªà®¿à®±à¯à®•à®¾à®•, <ph name="KX" /> ஠விசைப௠பரிமாறà¯à®± செயலà¯à®®à¯à®±à¯ˆà®¯à®¾à®•à®•à¯ கொணà¯à®Ÿà¯, <ph name="MAC" /> உடன௠<ph name="CIPHER" /> à®à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ இணைபà¯à®ªà®¾à®©à®¤à¯ எனà¯à®•à¯à®°à®¿à®ªà¯à®Ÿà¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="7802523362929240268">தளமானத௠சடà¯à®Ÿà®ªà¯à®ªà¯‚à®°à¯à®µà®®à®¾à®©à®¤à¯</translation>
<translation id="780301667611848630">வேணà¯à®Ÿà®¾à®®à¯</translation>
@@ -1731,6 +1760,7 @@
<translation id="7976214039405368314">அளவà¯à®•à¯à®•à¯ அதிகமான கோரிகà¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="7977538094055660992">அவà¯à®Ÿà¯à®ªà¯à®Ÿà¯ சாதனமà¯</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•, ARCore஠நிறà¯à®µà®µà¯à®®à¯</translation>
<translation id="799149739215780103">பைணà¯à®Ÿà¯</translation>
<translation id="7995512525968007366">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="800218591365569300">பிற தாவலà¯à®•à®³à¯ அலà¯à®²à®¤à¯ நிரலà¯à®•à®³à¯ˆ மூடி, நினைவகதà¯à®¤à¯ˆà®•à¯ காலியாகà¯à®•à®µà¯à®®à¯.</translation>
@@ -1858,24 +1888,38 @@
<translation id="8507227106804027148">கடà¯à®Ÿà®³à¯ˆ வரி</translation>
<translation id="8508648098325802031">தேடல௠à®à®•à®¾à®©à¯</translation>
<translation id="8522552481199248698">உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à®µà¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®µà¯à®®à¯ Chrome உதவà¯à®®à¯.</translation>
+<translation id="8525306231823319788">à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆ</translation>
<translation id="8530813470445476232">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ உலாவல௠வரலாறà¯, கà¯à®•à¯à®•à¯€à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®• சேமிபà¯à®ªà¯ ஆகியவறà¯à®±à¯ˆ அழி</translation>
<translation id="8533619373899488139">தடைசெயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿ URLகளின௠படà¯à®Ÿà®¿à®¯à®²à¯ˆà®¯à¯à®®à¯ உஙà¯à®•à®³à¯ சிஸà¯à®Ÿà®®à¯ நிரà¯à®µà®¾à®•à®¿ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯à¯à®³à¯à®³ பிற கொளà¯à®•à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ பாரà¯à®•à¯à®• &lt;strong&gt;chrome://policy&lt;/strong&gt; எனà¯à®ªà®¤à®±à¯à®•à¯à®šà¯ செலà¯à®²à®µà¯à®®à¯.</translation>
<translation id="8541158209346794904">பà¯à®³à¯‚டூத௠சாதனமà¯</translation>
<translation id="8542014550340843547">டிரிபà¯à®ªà®¿à®²à¯ ஸà¯à®Ÿà¯‡à®ªà¯à®ªà®¿à®²à¯ பாடà¯à®Ÿà®®à¯</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />கணà¯à®Ÿà®±à®¿à®µà®¤à®¿à®²à¯ சிகà¯à®•à®²à¯ இரà¯à®ªà¯à®ªà®¤à¯ˆà®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®•à¯à®•à®²à®¾à®®à¯<ph name="END_ERROR_LINK" /> அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¿à®±à¯à®•à¯ à®à®±à¯à®ªà®Ÿà®•à¯à®•à¯‚டிய ஆபதà¯à®¤à¯à®•à®³à¯ˆà®ªà¯ பà¯à®°à®¿à®¨à¯à®¤à¯à®•à¯Šà®£à¯à®Ÿà®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯, <ph name="BEGIN_LINK" />இநà¯à®¤à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± தளதà¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செலà¯à®²à®²à®¾à®®à¯<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">உஙà¯à®•à®³à¯ காரà¯à®Ÿà®¿à®©à¯ பினà¯à®ªà¯à®±à®¤à¯à®¤à®¿à®²à¯ CVC எண௠இரà¯à®•à¯à®•à¯à®®à¯.</translation>
+<translation id="8558485628462305855">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•, ARCoreà®à®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="8559762987265718583">உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ தேதி மறà¯à®±à¯à®®à¯ நேரம௠(<ph name="DATE_AND_TIME" />) தவறாக உளà¯à®³à®¤à®¾à®²à¯ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> கà¯à®•à®¾à®© தனிபà¯à®ªà®Ÿà¯à®Ÿ இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="8564182942834072828">தனிதà¯à®¤à®©à®¿ ஆவணஙà¯à®•à®³à¯/தொகà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ நகலà¯à®•à®³à¯</translation>
<translation id="8564985650692024650">பிற தளஙà¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯, அதை மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ பினà¯à®µà®°à¯à®ªà®µà¯ˆ இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />இநà¯à®¤à®šà¯ சாளரதà¯à®¤à®¿à®²à¯ பாரà¯à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à¯
+ <ph name="LIST_ITEM" />கà¯à®•à¯à®•à¯€à®•à®³à¯ &amp; தளதà¯à®¤à®¿à®©à¯ தரவà¯
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">காரà¯à®Ÿà¯à®•à®³à¯ˆ மேலà¯à®®à¯ விரைவாக உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤ Touch IDயைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="858637041960032120">ஃபோன௠எணà¯à®£à¯ˆà®šà¯ சேரà¯</translation>
<translation id="8589998999637048520">சிறநà¯à®¤ தரமà¯</translation>
+<translation id="8600271352425265729">இபà¯à®ªà¯‹à®¤à¯ மடà¯à®Ÿà¯à®®à¯</translation>
<translation id="860043288473659153">காரà¯à®Ÿà¯ உரிமையாளரின௠பெயரà¯</translation>
<translation id="8606726445206553943">MIDI சாதனஙà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
+<translation id="8612761427948161954">வணகà¯à®•à®®à¯ <ph name="USERNAME" />,
+ <ph name="BR" />
+ நீஙà¯à®•à®³à¯ கெஸà¯à®Ÿà®¾à®• உலாவà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯</translation>
<translation id="861775596732816396">அளவà¯: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">பொரà¯à®¨à¯à®¤à¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ. சேமிதà¯à®¤ எலà¯à®²à®¾à®•à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®¯à¯à®®à¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="8625384913736129811">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ காரà¯à®Ÿà¯ˆà®šà¯ சேமி</translation>
+<translation id="8627040765059109009">ஸà¯à®•à®¿à®°à¯€à®©à¯à®·à®¾à®Ÿà¯ எடà¯à®ªà¯à®ªà®¤à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="8657078576661269990">கிளிபà¯à®ªà¯‹à®°à¯à®Ÿà®¿à®²à¯à®³à¯à®³ தரவை <ph name="ORIGIN_NAME" /> எனà¯à®ªà®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ <ph name="VM_NAME_1" />, <ph name="VM_NAME_2" /> ஆகியவறà¯à®±à¯à®•à¯à®•à¯à®ªà¯ பகிரà¯à®µà®¤à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¾à®°à¯</translation>
<translation id="8663226718884576429">ஆரà¯à®Ÿà®°à¯ சà¯à®°à¯à®•à¯à®•à®®à¯, <ph name="TOTAL_LABEL" />, மேலà¯à®®à¯ விவரஙà¯à®•à®³à¯</translation>
<translation id="867224526087042813">கையொபà¯à®ªà®®à¯</translation>
@@ -1938,6 +1982,7 @@
<translation id="8912362522468806198">Google கணகà¯à®•à¯</translation>
<translation id="8913778647360618320">’கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆà®•à®³à¯ˆ நிரà¯à®µà®•à®¿â€™ படà¯à®Ÿà®©à¯, Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ பேமெணà¯à®Ÿà¯à®Ÿà¯à®•à®³à¯, கிரெடிட௠காரà¯à®Ÿà¯ ஆகியவை கà¯à®±à®¿à®¤à¯à®¤ தகவலை நிரà¯à®µà®•à®¿à®•à¯à®• Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="8918231688545606538">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ சநà¯à®¤à¯‡à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯à®°à®¿à®¯à®¤à®¾à®• உளà¯à®³à®¤à¯</translation>
+<translation id="8922013791253848639">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ எபà¯à®ªà¯‹à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿</translation>
<translation id="892588693504540538">பஞà¯à®šà¯ டாப௠ரைடà¯</translation>
<translation id="8931333241327730545">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ˆ உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à¯ சேமிகà¯à®• வேணà¯à®Ÿà¯à®®à®¾?</translation>
<translation id="8932102934695377596">உஙà¯à®•à®³à¯ கடிகாரம௠மிகவà¯à®®à¯ பினà¯à®¤à®™à¯à®•à®¿ இரà¯à®•à¯à®•à®¿à®±à®¤à¯</translation>
@@ -2007,21 +2052,24 @@
<translation id="917450738466192189">சேவையகச௠சானà¯à®±à®¿à®¤à®´à¯ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®©à®¤à®²à¯à®².</translation>
<translation id="9174917557437862841">இநà¯à®¤à®¤à¯ தாவலà¯à®•à¯à®•à¯ மாற, ’தாவலà¯â€™ மாறà¯à®± படà¯à®Ÿà®©à¯ˆà®¤à¯ தடà¯à®Ÿà®¿, ‘எணà¯à®Ÿà®°à¯â€™ படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="9179703756951298733">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ பேமெணà¯à®Ÿà¯à®•à®³à¯, கிரெடிட௠காரà¯à®Ÿà¯ கà¯à®±à®¿à®¤à¯à®¤ தகவலை நிரà¯à®µà®•à®¿à®¤à¯à®¤à®²à¯</translation>
-<translation id="9183302530794969518">Google ஆவணமà¯</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ நெறிமà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="9191834167571392248">பஞà¯à®šà¯ பாடà¯à®Ÿà®®à¯ லெஃபà¯à®Ÿà¯</translation>
+<translation id="9199905725844810519">பிரிணà¯à®Ÿà¯ செயà¯à®µà®¤à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="9205078245616868884">உஙà¯à®•à®³à¯ தரவ௠உஙà¯à®•à®³à¯ ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®±à¯Šà®Ÿà®°à¯ˆà®•à¯ கொணà¯à®Ÿà¯ à®®à¯à®±à¯ˆà®®à¯ˆà®¯à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯ˆà®¤à¯ தொடஙà¯à®•, அதை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯.</translation>
<translation id="9207861905230894330">கடà¯à®Ÿà¯à®°à¯ˆà®¯à¯ˆà®šà¯ சேரà¯à®ªà¯à®ªà®¤à®¿à®²à¯ தோலà¯à®µà®¿.</translation>
<translation id="9213433120051936369">தோறà¯à®±à®¤à¯à®¤à¯ˆà®¤à¯ தனிபà¯à®ªà®¯à®©à®¾à®•à¯à®•à¯à®™à¯à®•à®³à¯</translation>
<translation id="9215416866750762878">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯à®Ÿà®©à¯ Chrome பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• இணைவதை, ஆபà¯à®¸à¯ தடà¯à®•à¯à®•à®¿à®±à®¤à¯</translation>
-<translation id="9219103736887031265">படஙà¯à®•à®³à¯</translation>
+<translation id="9219103736887031265">Images</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">படிவதà¯à®¤à¯ˆ அழி</translation>
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®±à¯à®•à®¾à®© அணà¯à®•à®²à¯ˆ நீஙà¯à®•à®³à¯ இழகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯. இபà¯à®ªà¯‹à®¤à¯‡ உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à¯à®®à®¾à®±à¯ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯. அதறà¯à®•à¯ நீஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®¯ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="939736085109172342">பà¯à®¤à®¿à®¯ கோபà¯à®ªà¯à®±à¯ˆ</translation>
+<translation id="945522503751344254">கரà¯à®¤à¯à®¤à¯ˆ அனà¯à®ªà¯à®ªà¯</translation>
<translation id="945855313015696284">கீழà¯à®³à¯à®³ தகவலà¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®¾à®¤ காரà¯à®Ÿà¯à®•à®³à¯ à®à®¤à¯‡à®©à¯à®®à¯ இரà¯à®¨à¯à®¤à®¾à®²à¯ அவறà¯à®±à¯ˆ நீகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="950736567201356821">டிரிபà¯à®ªà®¿à®²à¯ பஞà¯à®šà¯ டாபà¯</translation>
+<translation id="951941430552851965">திரையில௠தோனà¯à®±à¯à®®à¯ உளà¯à®³à®Ÿà®•à¯à®•à®®à¯ காரணமாக ஸà¯à®•à®¿à®°à¯€à®©à¯à®·à®¾à®Ÿà¯ எடà¯à®ªà¯à®ªà®¤à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ இடைநிறà¯à®¤à¯à®¤à®¿à®¯à¯à®³à¯à®³à®¾à®°à¯.</translation>
<translation id="961663415146723894">பைணà¯à®Ÿà¯ பாடà¯à®Ÿà®®à¯</translation>
<translation id="962484866189421427">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®®à¯, வேறொர௠பிரபல ஆபà¯à®¸à¯ போலத௠தோறà¯à®±à®®à®³à®¿à®•à¯à®•à®•à¯à®•à¯‚டிய அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®•à¯à®•à¯‚டிய தரவைச௠சேகரிகà¯à®•à¯à®®à¯ போலியான ஆபà¯à®¸à¯ˆ நிறà¯à®µ à®®à¯à®¯à®²à®²à®¾à®®à¯. <ph name="BEGIN_LINK" />பரவாயிலà¯à®²à¯ˆ, பகà¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà¯<ph name="END_LINK" /></translation>
<translation id="969892804517981540">அதிகாரபà¯à®ªà¯‚à®°à¯à®µ கடà¯à®Ÿà®®à¯ˆà®ªà¯à®ªà¯</translation>
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index 06556addf37..769d77074eb 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">మీ సంసà±à°¥ నిరà±à°µà°¹à°¿à°‚చని à°’à°• సైటà±â€Œà°²à±‹ మీరౠమీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± నమోదౠచేసారà±. మీ ఖాతానౠరకà±à°·à°¿à°‚à°šà°¡à°‚ కోసం, ఇతర యాపà±â€Œà°²à± మరియౠసైటà±â€Œà°²à°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± తిరిగి ఉపయోగించవదà±à°¦à±.</translation>
<translation id="1263231323834454256">పఠన జాబితా</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ à°ˆ పరికరంలో సేవౠఅవà±à°µà°¨à°¿ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />మీరౠఈ విండోలో చూసే పేజీలà±
+ <ph name="LIST_ITEM" />à°•à±à°•à±à°•à±€â€Œà°²à±, సైటౠడేటా
+ <ph name="LIST_ITEM" />ఖాతా సమాచారం (<ph name="LINK_BEGIN" />సైనౠఅవà±à°Ÿà±<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">పికపౠపదà±à°§à°¤à°¿</translation>
<translation id="1281476433249504884">à°¸à±à°Ÿà°¾à°•à°°à± 1</translation>
<translation id="1285320974508926690">à°ˆ సైటà±â€Œà°¨à± à°Žà°ªà±à°ªà°Ÿà°¿à°•à±€ à°…à°¨à±à°µà°¦à°¿à°‚చవదà±à°¦à±</translation>
@@ -129,7 +137,7 @@
<translation id="1413809658975081374">గోపà±à°¯à°¤à°¾ à°Žà°°à±à°°à°°à±</translation>
<translation id="1426410128494586442">à°…à°µà±à°¨à±</translation>
<translation id="1428146450423315676">à°¸à±à°Ÿà°¾à°•à°°à± 7</translation>
-<translation id="1430915738399379752">à°®à±à°¦à±à°°à°¿à°‚à°šà±</translation>
+<translation id="1430915738399379752">à°ªà±à°°à°¿à°‚à°Ÿà±</translation>
<translation id="1442386063175183758">à°•à±à°¡à°¿à°µà±ˆà°ªà± గేటౠఫోలà±à°¡à±</translation>
<translation id="1442987760062738829">à°°à°‚à°§à±à°°à°‚</translation>
<translation id="1447067628680007684">(x86_64)</translation>
@@ -151,7 +159,7 @@
<translation id="1513706915089223971">à°šà°°à°¿à°¤à±à°° నమోదà±à°² జాబితా</translation>
<translation id="1517433312004943670">ఫోనౠనంబరౠఅవసరం</translation>
<translation id="1519264250979466059">బిలà±à°¡à± తేదీ</translation>
-<translation id="1521655867290435174">Google షీటà±â€Œà°²à±</translation>
+<translation id="1521655867290435174">Google Sheets</translation>
<translation id="1527263332363067270">కనెకà±à°·à°¨à± కోసం వేచి ఉనà±à°¨à°¾à°®à±...</translation>
<translation id="1529521330346880926">10x15 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="1529789484829130889">à°Ÿà±à°°à±‡ 8</translation>
@@ -285,6 +293,7 @@
<translation id="204357726431741734">మీ Google ఖాతాలో సేవౠచేయబడిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± ఉపయోగించడానికి సైనౠఇనౠచేయండి</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> భాషలో ఉనà±à°¨ పేజీలౠఅనà±à°µà°¦à°¿à°‚చబడవà±.</translation>
<translation id="2053553514270667976">జిపౠకోడà±</translation>
+<translation id="2054665754582400095">మీ ఉనికి</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 సూచన}other{# సూచనలà±}}</translation>
<translation id="2079545284768500474">à°šà°°à±à°¯ à°°à°¦à±à°¦à±</translation>
<translation id="20817612488360358">సిసà±à°Ÿà°®à± à°ªà±à°°à°¾à°•à±à°¸à±€ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à± ఉపయోగించడానికి సెటౠచేయబడà±à°¡à°¾à°¯à°¿ కానీ à°¸à±à°ªà°·à±à°Ÿà°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠకూడా పేరà±à°•à±Šà°¨à°¬à°¡à°¿à°‚ది.</translation>
@@ -295,9 +304,10 @@
<translation id="2099652385553570808">ఎడమవైపౠటà±à°°à°¿à°ªà±à°²à± à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
<translation id="2101225219012730419">వెరà±à°·à°¨à±:</translation>
<translation id="2102134110707549001">బలమైన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± సూచించà±â€¦</translation>
-<translation id="2102495993840063010">Android à°…à°¨à±à°µà°°à±à°¤à°¨à°¾à°²à±</translation>
+<translation id="2102495993840063010">Android యాపà±â€Œà°²à±</translation>
<translation id="2107021941795971877">à°ªà±à°°à°¿à°‚టౠమదà±à°¦à°¤à±à°²à±</translation>
<translation id="2108755909498034140">మీ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°¨à± à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
+<translation id="2111166930115883695">ఆడటానికి à°¸à±à°ªà±‡à°¸à±â€Œà°¨à± నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="2111256659903765347">సూపరà±-A</translation>
<translation id="2113977810652731515">కారà±à°¡à±</translation>
<translation id="2114841414352855701">ఇది <ph name="POLICY_NAME" /> à°¦à±à°µà°¾à°°à°¾ à°­à°°à±à°¤à±€ చేయబడినందà±à°¨ విసà±à°®à°°à°¿à°‚చబడింది.</translation>
@@ -309,6 +319,7 @@
<translation id="214556005048008348">చెలà±à°²à°¿à°‚à°ªà±à°¨à± à°°à°¦à±à°¦à± చేయి</translation>
<translation id="2147827593068025794">à°¬à±à°¯à°¾à°•à±â€Œà°—à±à°°à±Œà°‚డౠసింకà±</translation>
<translation id="2148613324460538318">కారà±à°¡à±â€Œà°¨à°¿ జోడించà±</translation>
+<translation id="2149968176347646218">కనెకà±à°·à°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ లేదà±</translation>
<translation id="2154054054215849342">సింకà±â€Œ మీ డొమైనà±â€Œà°•à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="2154484045852737596">కారà±à°¡à±â€Œà°¨à± సవరించండి</translation>
<translation id="2161656808144014275">వచనం</translation>
@@ -319,7 +330,6 @@
<translation id="2181821976797666341">విధానాలà±</translation>
<translation id="2183608646556468874">ఫోనౠనంబరà±</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 à°šà°¿à°°à±à°¨à°¾à°®à°¾}other{# à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à±}}</translation>
-<translation id="2187243482123994665">యూజరౠఉనికి</translation>
<translation id="2187317261103489799">à°—à±à°°à±à°¤à°¿à°‚à°šà± (డిఫాలà±à°Ÿà±)</translation>
<translation id="2188375229972301266">దిగà±à°µ భాగంలో అనేక à°°à°‚à°§à±à°°à°¾à°²à±</translation>
<translation id="2202020181578195191">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°—à°¡à±à°µà± à°®à±à°—ింపౠసంవతà±à°¸à°°à°¾à°¨à±à°¨à°¿ నమోదౠచేయండి</translation>
@@ -470,6 +480,7 @@
<translation id="2839501879576190149">à°®à±à°‚à°¦à±à°¨à±à°¨ సైటౠనకిలీది</translation>
<translation id="2850739647070081192">ఆహà±à°µà°¾à°¨à°‚ (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="2856444702002559011">à°¹à±à°¯à°¾à°•à°°à±â€Œà°²à± <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à°¨à±à°‚à°¡à°¿ మీ సమాచారానà±à°¨à°¿ దొంగిలించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±‚ ఉండవచà±à°šà± (ఉదాహరణకà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, సందేశాలౠలేదా à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">à°ˆ సైటౠఅనà±à°šà°¿à°¤à°®à±ˆà°¨ లేదా తపà±à°ªà±à°¦à°¾à°°à°¿ పటà±à°Ÿà°¿à°‚చే à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± చూపà±à°¤à±à°‚ది.</translation>
<translation id="2878197950673342043">పోసà±à°Ÿà°°à± ఫోలà±à°¡à±</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">విండో à°¸à±à°¥à°²à°‚</translation>
@@ -508,11 +519,11 @@
<translation id="2996674880327704673">Google à°¦à±à°µà°¾à°°à°¾ సూచనలà±</translation>
<translation id="3002501248619246229">ఇనà±â€Œà°ªà±à°Ÿà± à°Ÿà±à°°à±‡ మీడియానౠతనిఖీ చేయి</translation>
<translation id="3005723025932146533">సేవౠచేయబడిన కాపీని చూపà±</translation>
-<translation id="3007719053326478567">à°ˆ కంటెంటà±â€Œà°¨à± à°ªà±à°°à°¿à°‚టౠచేయడానà±à°¨à°¿ మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¬à±à°²à°¾à°•à± చేశారà±</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> కారà±à°¡à± CVCని నమోదౠచేయండి. మీరౠనిరà±à°§à°¾à°°à°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤, మీ కారà±à°¡à± వివరాలౠఈ సైటà±â€Œà°¤à±‹ షేరౠచేయబడతాయి.</translation>
<translation id="3010559122411665027">జాబితా నమోదౠ"<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">à°¸à±à°µà°¯à°‚చాలకంగా à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="3016780570757425217">మీ à°¸à±à°¥à°¾à°¨à°¾à°¨à±à°¨à°¿ తెలà±à°¸à±à°•à±‹à°µà°¾à°²à°¨à±à°•à±à°‚టోంది</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, సూచననౠతీసివేయడానికి Tabనౠనొకà±à°•à°¿, ఆపై à°Žà°‚à°Ÿà°°à±â€Œà°¨à± నొకà±à°•à°‚à°¡à°¿.</translation>
<translation id="3023071826883856138">You4 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="3024663005179499861">చెలà±à°²à°¨à°¿ విధాన à°°à°•à°‚</translation>
<translation id="3037605927509011580">ఆవà±, à°¸à±à°¨à°¾à°ªà±!</translation>
@@ -555,6 +566,7 @@
<translation id="3207960819495026254">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à± చేయబడింది</translation>
<translation id="3209034400446768650">పేజీ, నగదà±à°¨à± ఛారà±à°œà± చేయవచà±à°šà±</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />లోని మీ కారà±à°¯à°•à°²à°¾à°ªà°‚ పరà±à°¯à°µà±‡à°•à±à°·à°¿à°‚చబడà±à°¤à±‹à°‚ది</translation>
+<translation id="3212623355668894776">à°…à°¨à±à°¨à°¿ గెసà±à°Ÿà± విండోలనౠమూసివేయండి, తదà±à°µà°¾à°°à°¾ à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ తొలగించబడà±à°¤à±à°‚ది.</translation>
<translation id="3215092763954878852">WebAuthn ఉపయోగించడం సాధà±à°¯à°‚ కాలేదà±</translation>
<translation id="3218181027817787318">సంబంధిత</translation>
<translation id="3225919329040284222">అంతరà±à°—à°¤ అంచనాలకౠసరిపోలని à°’à°• ధృవీకరణ పతà±à°°à°¾à°¨à±à°¨à°¿ సరà±à°µà°°à± సమరà±à°ªà°¿à°‚చింది. మిమà±à°®à°²à±à°¨à°¿ సంరకà±à°·à°¿à°‚చే దిశగా నిరà±à°¦à°¿à°·à±à°Ÿ, ఉనà±à°¨à°¤ à°¸à±à°§à°¾à°¯à°¿ à°­à°¦à±à°°à°¤à°¾ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² కోసం à°ˆ అంచనాలౠచేరà±à°šà°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
@@ -702,6 +714,7 @@
<translation id="3784372983762739446">à°¬à±à°²à±‚టూతౠపరికరాలà±</translation>
<translation id="3787705759683870569">à°—à°¡à±à°µà± à°®à±à°—ింపౠ<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">పరిమాణం 16</translation>
+<translation id="3789841737615482174">ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయి</translation>
<translation id="3793574014653384240">ఇటీవల à°à°°à±à°ªà°¡à°¿à°¨ à°•à±à°°à°¾à°·à±â€Œà°² సంఖà±à°¯à°²à±, వాటికి à°—à°² కారణాలà±</translation>
<translation id="3797522431967816232">Prc3 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="3799805948399000906">à°…à°­à±à°¯à°°à±à°¥à°¿à°‚à°šà°¿à°¨ ఫాంటà±</translation>
@@ -753,6 +766,7 @@
<translation id="4056223980640387499">సెపియా</translation>
<translation id="4058922952496707368">à°•à±€ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
+<translation id="4067669230157909013">à°¸à±à°•à±à°°à±€à°¨à± à°•à±à°¯à°¾à°ªà±à°šà°°à± కొనసాగించబడింది.</translation>
<translation id="4067947977115446013">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± జోడించండి</translation>
<translation id="4072486802667267160">మీ ఆరà±à°¡à°°à±â€Œà°¨à± à°ªà±à°°à°¾à°¸à±†à°¸à± చేసà±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°Žà°°à±à°°à°°à± à°à°°à±à°ªà°¡à°¿à°‚ది. దయచేసి మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="4075732493274867456">à°•à±à°²à°¯à°¿à°‚à°Ÿà±, సరà±à°µà°°à±- ఒకే SSL à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à± సంసà±à°•à°°à°£ లేదా సైఫరౠసూటà±â€Œà°•à± మదà±à°¦à°¤à± ఇవà±à°µà°µà±.</translation>
@@ -764,7 +778,7 @@
<translation id="4098354747657067197">à°®à±à°‚à°¦à±à°¨à±à°¨ సైటౠమోసపూరితమైనది</translation>
<translation id="4101413244023615925">టెకà±à°¸à±à°Ÿà±, à°—à±à°°à°¾à°«à°¿à°•à±à°¸à±</translation>
<translation id="4103249731201008433">పరికరం à°•à±à°°à°® సంఖà±à°¯ చెలà±à°²à°¦à±</translation>
-<translation id="4110652170750985508">మీ చెలà±à°²à°¿à°‚à°ªà±à°¨à± సమీకà±à°·à°¿à°‚à°šà°‚à°¡à°¿</translation>
+<translation id="4110652170750985508">మీ చెలà±à°²à°¿à°‚à°ªà±à°¨à± à°°à°¿à°µà±à°¯à±‚ చేయండి</translation>
<translation id="4112140312785995938">వెనà±à°•à°•à± జరà±à°ªà±</translation>
<translation id="4116663294526079822">à°ˆ సైటà±â€Œà°²à±‹ à°Žà°²à±à°²à°ªà±à°ªà±à°¡à±‚ à°…à°¨à±à°®à°¤à°¿à°‚à°šà±</translation>
<translation id="4116701314593212016">JIS B7</translation>
@@ -837,6 +851,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> పేజీ కోసం థంబà±â€Œà°¨à±†à°¯à°¿à°²à±</translation>
<translation id="42981349822642051">విసà±à°¤à°°à°¿à°‚à°šà±</translation>
<translation id="4300675098767811073">à°•à±à°¡à°¿à°µà±ˆà°ªà± అనేక à°°à°‚à°§à±à°°à°¾à°²à±</translation>
+<translation id="4302514097724775343">ఆడటానికి డైనోసారà±â€Œà°¨à± à°Ÿà±à°¯à°¾à°ªà± చేయండి</translation>
<translation id="4302965934281694568">Chou3 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="4305666528087210886">మీ ఫైలà±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±</translation>
<translation id="4305817255990598646">à°¸à±à°µà°¿à°šà±</translation>
@@ -915,9 +930,10 @@
<translation id="4658638640878098064">ఎడమవైపౠఎగà±à°µ భాగంలో à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">వరà±à°šà±à°µà°²à± రియాలిటీ</translation>
+<translation id="4675657451653251260">గెసà±à°Ÿà± మోడà±â€Œà°²à±‹ మీరౠఎటà±à°µà°‚à°Ÿà°¿ Chrome à°ªà±à°°à±Šà°«à±ˆà°²à± సమాచారానà±à°¨à±€ చూడలేరà±. పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, పేమెంటౠఆపà±à°·à°¨à±â€Œà°² వంటి మీ Google ఖాతా సమాచారానà±à°¨à°¿ యాకà±à°¸à±†à°¸à± చేయడానికి, మీరౠ<ph name="LINK_BEGIN" />సైనౠఇనà±<ph name="LINK_END" /> చేయవచà±à°šà±.</translation>
<translation id="467662567472608290">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚లో లోపాలౠఉనà±à°¨à°¾à°¯à°¿. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±.</translation>
<translation id="4677585247300749148">యాకà±à°¸à±†à°¸à°¿à°¬à°¿à°²à°¿à°Ÿà±€ ఈవెంటà±â€Œà°²à°•à± <ph name="URL" /> à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దించాలని à°…à°¨à±à°•à±à°‚టోంది</translation>
-<translation id="467809019005607715">Google à°¸à±à°²à°¯à°¿à°¡à±â€Œà°²à±</translation>
+<translation id="467809019005607715">Google Slides</translation>
<translation id="4680804919228900307">మీరౠమోసపూరితమైన సైటà±â€Œà°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఎంటరౠచేశారà±. <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" />, ఇతర సైటà±â€Œà°²à°²à±‹ à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ మీరౠఎకà±à°•à°¡à±ˆà°¤à±‡ à°ˆ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఉపయోగిసà±à°¤à°¾à°°à±‹, à°…à°•à±à°•à°¡ మీ సేవౠచేసిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± తనిఖీ చేసà±à°•à±‹à°®à°¨à°¿ Chromium సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
<translation id="4690462567478992370">చెలà±à°²à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ ఉపయోగించడానà±à°¨à°¿ ఆపివేయి</translation>
<translation id="4691835149146451662">ఆరà±à°•à°¿à°Ÿà±†à°•à±à°šà°°à±-A (à°Žà°¨à±à°µà°²à°ªà±)</translation>
@@ -942,6 +958,12 @@
<translation id="4761104368405085019">మీ మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఉపయోగించండి</translation>
<translation id="4764776831041365478"><ph name="URL" /> వదà±à°¦ వెబà±â€Œà°ªà±‡à°œà±€ తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ తెరà±à°šà±à°•à±‹à°µà°Ÿà°‚ లేదౠలేదా అది కొతà±à°¤â€Œ వెబౠచిరà±à°¨à°¾à°®à°¾à°•à± శాశà±à°µà°¤à°‚à°—à°¾ తరలించబడి ఉండవచà±à°šà±.</translation>
<translation id="4766713847338118463">దిగà±à°µ భాగంలో à°¡à±à°¯à±à°¯à°²à± à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ à°ˆ పరికరంలో సేవౠఅయà±à°¯à±‡ మీ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à°ˆ విండోలో మీరౠడౌనà±â€Œà°²à±‹à°¡à± చేసిన à°à°µà±ˆà°¨à°¾ ఫైలà±à°¸à±
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">తెలియని à°Žà°°à±à°°à°°à± à°’à°•à°Ÿà°¿ à°à°°à±à°ªà°¡à°¿à°‚ది.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{పాపà±-అపౠబà±à°²à°¾à°•à± చేయబడింది}other{# పాపà±-à°…à°ªà±â€Œà°²à± à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿}}</translation>
<translation id="4780366598804516005">మెయిలà±â€Œà°¬à°¾à°•à±à°¸à± 1</translation>
@@ -1104,11 +1126,13 @@
<translation id="5386426401304769735">à°ˆ సైటౠసరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± గొలà±à°¸à±à°²à±‹ SHA-1 ఉపయోగించి సంతకం చేసిన సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± ఉంది.</translation>
<translation id="538659543871111977">A4-à°Ÿà±à°¯à°¾à°¬à±</translation>
<translation id="5396631636586785122">à°•à±à°¡à°¿à°µà±ˆà°ªà± à°•à±à°Ÿà±à°Ÿà°¿à°¨ à°…à°‚à°šà±</translation>
+<translation id="5398772614898833570">à°ªà±à°°à°•à°Ÿà°¨à°²à± à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿</translation>
<translation id="5400836586163650660">బూడిద à°°à°‚à°—à±</translation>
<translation id="540969355065856584">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ చెలà±à°²à°¦à±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడి చేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±.</translation>
<translation id="541416427766103491">à°¸à±à°Ÿà°¾à°•à°°à± 4</translation>
<translation id="5421136146218899937">à°¬à±à°°à±Œà°œà°¿à°‚గౠడేటానౠకà±à°²à°¿à°¯à°°à± చేయి...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> మీకౠనోటిఫికేషనà±â€Œà°²à°¨à± పంపాలనà±à°•à±à°‚టోంది</translation>
+<translation id="542872847390508405">మీరౠఅతిథిగా à°¬à±à°°à±Œà°œà± చేసà±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
<translation id="5430298929874300616">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°¨à± తీసివేయండి</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />"లో à°¸à±à°•à±€à°®à°¾ à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ à°Žà°°à±à°°à°°à±: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">à°µà±à°¯à°¤à°¿à°°à±‡à°• à°•à±à°°à°®à°‚లో ఉనà±à°¨ ఫేసౠఅపà±</translation>
@@ -1150,12 +1174,12 @@
<translation id="5571083550517324815">à°ˆ à°šà°¿à°°à±à°¨à°¾à°®à°¾ à°¨à±à°‚à°¡à°¿ పికపౠచేసà±à°•à±‹à°µà°¡à°‚ సాధà±à°¯à°‚ కాదà±. వేరే à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="5580958916614886209">మీ à°—à°¡à±à°µà± à°®à±à°—ింపౠనెలనౠతనిఖీ చేసి, మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="5586446728396275693">సేవౠచేయబడిన à°šà°¿à°°à±à°¨à°¾à°®à°¾à°²à± లేవà±</translation>
+<translation id="5593349413089863479">కనెకà±à°·à°¨à± పూరà±à°¤à°¿à°—à°¾ à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨à°¦à°¿ కాదà±</translation>
<translation id="5595485650161345191">à°šà°¿à°°à±à°¨à°¾à°®à°¾à°¨à± సవరించà±</translation>
<translation id="5598944008576757369">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à°¿à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="560412284261940334">నిరà±à°µà°¹à°£à°•à± మదà±à°¦à°¤à± లేదà±</translation>
<translation id="5605670050355397069">లెడà±à°œà°°à±</translation>
<translation id="5607240918979444548">ఆరà±à°•à°¿à°Ÿà±†à°•à±à°šà°°à±-C</translation>
-<translation id="5608165884683734521">à°ˆ సైటౠనకిలీ లేదా మోసపూరితమైనది కావచà±à°šà±. ఇపà±à°ªà±à°¡à±‡ నిషà±à°•à±à°°à°®à°¿à°‚చమని Chrome సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
<translation id="5610142619324316209">కనెకà±à°·à°¨à±â€Œà°¨à± తనిఖీ చేయడం</translation>
<translation id="5610807607761827392">మీరౠకారà±à°¡à±â€Œà°²à± మరియౠచిరà±à°¨à°¾à°®à°¾à°²à°¨à± <ph name="BEGIN_LINK" />సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో నిరà±à°µà°¹à°¿à°‚చగలరà±.</translation>
<translation id="561165882404867731">Google Translateతో à°ˆ పేజీని à°…à°¨à±à°µà°¦à°¿à°‚à°šà°‚à°¡à°¿</translation>
@@ -1227,6 +1251,7 @@
<translation id="5901630391730855834">పసà±à°ªà±</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> యొకà±à°• ఆరిజినౠఎరà±à°°à°°à± విధానం à°ªà±à°°à°•à°¾à°°à°‚ à°¬à±à°²à°¾à°•à± చేయబడింది.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (సమకాలీకరించబడింది)</translation>
+<translation id="5913377024445952699">à°¸à±à°•à±à°°à±€à°¨à±â€Œà°¨à± à°•à±à°¯à°¾à°ªà±à°šà°°à± చేయడం పాజౠచేయబడింది</translation>
<translation id="59174027418879706">à°ªà±à°°à°¾à°°à°‚భించబడింది</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">ఆనౠచేయబడà±à°¡à°¾à°¯à°¿</translation>
@@ -1239,6 +1264,7 @@
<translation id="5963413905009737549">విభాగం</translation>
<translation id="5967592137238574583">సంపà±à°°à°¦à°¿à°‚పౠసమాచారానà±à°¨à°¿ సవరించండి</translation>
<translation id="5967867314010545767">à°šà°°à°¿à°¤à±à°° à°¨à±à°‚à°¡à°¿ తీసివేయి</translation>
+<translation id="5968793460449681917">à°ªà±à°°à°¤à°¿ సందరà±à°¶à°¨à°²à±‹</translation>
<translation id="5975083100439434680">దూరంగా జూమౠచేయి</translation>
<translation id="5979084224081478209">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± తనిఖీ చేయి</translation>
<translation id="5980920751713728343">సూచిక-3x5</translation>
@@ -1394,6 +1420,7 @@
<translation id="6587923378399804057">మీరౠకాపీ చేసిన లింకà±</translation>
<translation id="6591833882275308647">మీ <ph name="DEVICE_TYPE" /> నిరà±à°µà°¹à°¿à°‚చబడటం లేదà±</translation>
<translation id="6596325263575161958">à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°·à°¨à± ఎంపికలà±</translation>
+<translation id="6596892391065203054">à°ˆ కంటెంటà±â€Œà°¨à± à°ªà±à°°à°¿à°‚టౠచేయడానà±à°¨à°¿ మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¬à±à°²à°¾à°•à± చేశారà±.</translation>
<translation id="6604181099783169992">చలనం లేదా కాంతి సరà±à°¦à±à°¬à°¾à°Ÿà± సెనà±à°¸à°¾à°°à±â€Œà°²à±</translation>
<translation id="6609880536175561541">Prc7 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="6612358246767739896">à°°à°•à±à°·à°¿à°¤ కంటెంటà±</translation>
@@ -1453,6 +1480,7 @@
<translation id="6895330447102777224">మీ కారà±à°¡à± నిరà±à°§à°¾à°°à°¿à°‚చబడింది</translation>
<translation id="6897140037006041989">వినియోగదారౠపà±à°°à°¤à°¿à°¨à°¿à°§à°¿</translation>
<translation id="6898699227549475383">సంసà±à°¥ (O)</translation>
+<translation id="6907293445143367439">దీనికి <ph name="SITE_NAME" />నౠఅనà±à°®à°¤à°¿à°‚à°šà°‚à°¡à°¿:</translation>
<translation id="6910240653697687763"><ph name="URL" /> మీ MIDI పరికరాలకౠపూరà±à°¤à°¿ నియంతà±à°°à°£à°¨à± పొందాలనà±à°•à±à°‚టోంది</translation>
<translation id="6915804003454593391">వినియోగదారà±:</translation>
<translation id="6934672428414710184">ఇది మీ Google ఖాతాలో ఉనà±à°¨ పేరà±</translation>
@@ -1472,7 +1500,7 @@
<translation id="6973656660372572881">రెండౠసà±à°¥à°¿à°° à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±à°²à± మరియౠఒక .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URL పేరà±à°•à±Šà°¨à°¬à°¡à±à°¡à°¾à°¯à°¿.</translation>
<translation id="6973932557599545801">à°•à±à°·à°®à°¿à°‚à°šà°‚à°¡à°¿ నేనౠసహాయం చేయలేకపోయానà±, దయచేసి మీరే à°¸à±à°µà°‚తంగా కొనసాగండి.</translation>
<translation id="6975012522936652259">మీరౠమోసపూరితమైన సైటà±â€Œà°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఎంటరౠచేశారà±. మీరౠఈ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఉపయోగించిన<ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, ఇతర సైటà±â€Œà°²à°•à± ఇపà±à°ªà±à°¡à±‡ వెళà±à°²à°¿, మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± మారà±à°šà°¾à°²à±à°¸à°¿à°‚దిగా Chromium సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
-<translation id="6979158407327259162">Google à°¡à°¿à°¸à±à°•à±</translation>
+<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">à°®à±à°¯à±‚à°Ÿà± (డిఫాలà±à°Ÿà±)</translation>
<translation id="6979983982287291980">మీరౠడౌనà±â€Œà°²à±‹à°¡à± చేసిన ఫైలà±à°¸à± Google à°•à±à°²à±Œà°¡à± లేదా థరà±à°¡à± పారà±à°Ÿà±€à°²à°•à± విశà±à°²à±‡à°·à°£ కోసం పంపబడతాయి. ఉదాహరణకà±, వాటిని à°¸à±à°¨à±à°¨à°¿à°¤à°®à±†à±–à°¨ à°µà±à°¯à°•à±à°¤à°¿à°—à°¤ సమాచారం లేదా మాలà±â€Œà°µà±‡à°°à± కోసం à°¸à±à°•à°¾à°¨à± చేయబడవచà±à°šà±.</translation>
<translation id="6989763994942163495">à°…à°§à±à°¨à°¾à°¤à°¨ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± చూపించà±...</translation>
@@ -1564,6 +1592,7 @@
<translation id="7346048084945669753">à°…à°¨à±à°¬à°‚ధితం:</translation>
<translation id="7349430561505560861">A4-అదనం</translation>
<translation id="7353601530677266744">ఆదేశ పంకà±à°¤à°¿</translation>
+<translation id="7359588939039777303">à°ªà±à°°à°•à°Ÿà°¨à°²à± à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿.</translation>
<translation id="7372973238305370288">శోధన ఫలితం</translation>
<translation id="7374733840632556089">మీ పరికరంలో మీరౠలేదా మరొకరౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేసిన సరà±à°Ÿà°¿à°«à°¿à°•à±‡à°Ÿà± కారణంగా à°ˆ సమసà±à°¯ తలెతà±à°¤à±à°¤à±à°‚ది. నెటà±â€Œà°µà°°à±à°•à±â€Œà°²à°¨à± పరà±à°¯à°µà±‡à°•à±à°·à°¿à°‚చడానికి మరియౠఅడà±à°¡à°—ించడానికి సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± ఉపయోగించబడà±à°¤à±à°‚ది, ఇది Chrome à°¦à±à°µà°¾à°°à°¾ విశà±à°µà°¸à°¿à°‚చబడదà±. పరà±à°¯à°µà±‡à°•à±à°·à°£ కోసం కొనà±à°¨à°¿ à°šà°Ÿà±à°Ÿà°¬à°¦à±à°§à°®à±ˆà°¨ కేసà±à°²à± ఉనà±à°¨à°ªà±à°ªà°Ÿà°¿à°•à±€, పాఠశాల లేదా కంపెనీ నెటà±â€Œà°µà°°à±à°•à±â€Œà°²à±‹ మాదిరిగా, మీరౠదీనà±à°¨à°¿ ఆపలేక పోయినపà±à°ªà°Ÿà°¿à°•à±€, ఇది జరà±à°—à±à°¤à±à°¨à±à°¨à°Ÿà±à°²à± మీకౠతెలà±à°¸à°¨à°¿ Chrome నిరà±à°§à°¾à°°à°¿à°‚à°šà±à°•à±‹à°µà°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°‚ది. వెబà±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేసే à°à°¦à±ˆà°¨à°¾ à°¬à±à°°à±Œà°œà°°à± లేదా యాపà±â€Œà°²à±‹ పరà±à°¯à°µà±‡à°•à±à°·à°£ జరగవచà±à°šà±.</translation>
<translation id="7375818412732305729">ఫైలà±â€Œà°¨à± జోడించినపà±à°ªà±à°¡à±</translation>
@@ -1738,6 +1767,7 @@
<translation id="7976214039405368314">చాలా à°Žà°•à±à°•à±à°µ à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œà°²à±</translation>
<translation id="7977538094055660992">à°…à°µà±à°Ÿà±â€Œà°ªà±à°Ÿà± పరికరం</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">మెరà±à°—ైన వాసà±à°¤à°µà°¿à°• à°…à°¨à±à°­à°µ కంటెంటà±â€Œà°¨à± చూడడానికి, ARCoreని ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయండి</translation>
<translation id="799149739215780103">బైండà±</translation>
<translation id="7995512525968007366">పేరà±à°•à±Šà°¨à°¬à°¡à°²à±‡à°¦à±</translation>
<translation id="800218591365569300">మెమరీని ఖాళీ చేయడానికి ఇతర à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± లేదా à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± మూసివేయడానà±à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
@@ -1865,24 +1895,38 @@
<translation id="8507227106804027148">ఆదేశ పంకà±à°¤à°¿</translation>
<translation id="8508648098325802031">శోధన à°šà°¿à°¹à±à°¨à°‚</translation>
<translation id="8522552481199248698">మీ Google ఖాతానౠసంరకà±à°·à°¿à°‚à°šà±à°•à±‹à°µà°¡à°‚లో, మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± మారà±à°šà°¡à°‚లో Chrome మీకౠసహాయపడగలదà±.</translation>
+<translation id="8525306231823319788">పూరà±à°¤à°¿ à°¸à±à°•à±à°°à±€à°¨à±</translation>
<translation id="8530813470445476232">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€, à°•à±à°•à±à°•à±€à°²à±, కాషౠఇంకా మరినà±à°¨à°¿à°‚టిని à°•à±à°²à°¿à°¯à°°à± చేయండి</translation>
<translation id="8533619373899488139">à°¬à±à°²à°¾à°•à± చేయబడి ఉనà±à°¨ URLà°² లిసà±à°Ÿà±â€Œà°¨à±, మీ సిసà±à°Ÿà°®à± à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¦à±à°µà°¾à°°à°¾ అమలౠచేయబడిన ఇతర పాలసీలనౠచూడటానికి &lt;strong&gt;chrome://policy&lt;/strong&gt;ని సందరà±à°¶à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="8541158209346794904">à°¬à±à°²à±‚టూతౠపరికరం</translation>
<translation id="8542014550340843547">దిగà±à°µ భాగంలో à°Ÿà±à°°à°¿à°ªà±à°²à± à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
<translation id="8543181531796978784">మీరౠ<ph name="BEGIN_ERROR_LINK" />à°—à±à°°à±à°¤à°¿à°‚పౠసమసà±à°¯à°¨à± నివేదించవచà±à°šà±<ph name="END_ERROR_LINK" /> లేదా మీకౠమీ à°­à°¦à±à°°à°¤à°•à± పొంచి ఉనà±à°¨ à°ªà±à°°à°®à°¾à°¦à°¾à°²à± à°…à°°à±à°¥à°‚ à°…à°¯à±à°¯à°¿ ఉంటే, à°®<ph name="BEGIN_LINK" />à°ˆ à°…à°¸à±à°°à°•à±à°·à°¿à°¤ సైటà±â€Œà°¨à± సందరà±à°¶à°¿à°‚à°šà°‚à°¡à°¿<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">మీ కారà±à°¡à± వెనà±à°•à°µà±ˆà°ªà± CVC ఉంటà±à°‚ది.</translation>
+<translation id="8558485628462305855">మెరà±à°—ైన వాసà±à°¤à°µà°¿à°• à°…à°¨à±à°­à°µ కంటెంటà±â€Œà°¨à± చూడడానికి, ARCoreని à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయండి</translation>
<translation id="8559762987265718583">మీ పరికరం తేదీ మరియౠసమయం <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨ (<ph name="DATE_AND_TIME" />)à°•à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కనెకà±à°·à°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయబడదà±.</translation>
<translation id="8564182942834072828">విడి డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œà°²à±/విడి కాపీలà±</translation>
<translation id="8564985650692024650">మీరౠమీ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à°¿ ఇతర సైటà±â€Œà°²à°²à±‹ తిరిగి ఉపయోగించినటà±à°²à°¯à°¿à°¤à±‡ దీనిని రీసెటౠచేయాలà±à°¸à°¿à°‚దిగా Chromium సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ à°ˆ పరికరంలో సేవౠఅవà±à°µà°¨à°¿ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />మీరౠఈ విండోలో చూసే పేజీలà±
+ <ph name="LIST_ITEM" />à°•à±à°•à±à°•à±€â€Œà°²à±, సైటౠడేటా
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">కారà±à°¡à±â€Œà°²à°¨à± వేగంగా నిరà±à°§à°¾à°°à°¿à°‚చడానికి Touch IDని ఉపయోగించండి</translation>
<translation id="858637041960032120">ఫోనౠనం. జోడిం.</translation>
<translation id="8589998999637048520">ఉతà±à°¤à°® నాణà±à°¯à°¤</translation>
+<translation id="8600271352425265729">à°ˆ à°’à°•à±à°•à°¸à°¾à°°à°¿ మాతà±à°°à°®à±‡</translation>
<translation id="860043288473659153">కారà±à°¡à±à°¦à°¾à°°à±à°¨à°¿ పేరà±</translation>
<translation id="8606726445206553943">మీ MIDI పరికరాలనౠఉపయోగించాలనà±à°•à±à°‚టోంది</translation>
+<translation id="8612761427948161954">హాయౠ<ph name="USERNAME" />,
+ <ph name="BR" />
+ మీరౠగెసà±à°Ÿà±â€Œà°²à°¾à°—à°¾ à°¬à±à°°à±Œà°œà± చేసà±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
<translation id="861775596732816396">పరిమాణం 4</translation>
<translation id="8622948367223941507">à°šà°Ÿà±à°Ÿ సంబంధితం-అదనం</translation>
<translation id="8623885649813806493">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à± à°à°µà±€ à°®à±à°¯à°¾à°šà± à°…à°µà±à°µà°²à±‡à°¦à±. సేవౠచేసిన à°…à°¨à±à°¨à°¿ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చూపà±.</translation>
<translation id="8625384913736129811">à°ˆ కారà±à°¡à±â€Œà°¨à± à°ˆ పరికరానికి సేవౠచేయి</translation>
+<translation id="8627040765059109009">à°¸à±à°•à±à°°à±€à°¨à± à°•à±à°¯à°¾à°ªà±à°šà°°à± కొనసాగించబడింది</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> à°¨à±à°‚à°¡à°¿ <ph name="VM_NAME_1" />, <ph name="VM_NAME_2" />లకౠషేరౠచేయడానà±à°¨à°¿ మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¬à±à°²à°¾à°•à± చేశారà±</translation>
<translation id="8663226718884576429">ఆరà±à°¡à°°à± సారాంశం, <ph name="TOTAL_LABEL" />, మరినà±à°¨à°¿ వివరాలà±</translation>
<translation id="867224526087042813">సంతకం</translation>
@@ -1945,6 +1989,7 @@
<translation id="8912362522468806198">Google ఖాతా</translation>
<translation id="8913778647360618320">'పేమెంటౠఆపà±à°·à°¨à±â€Œà°²à°¨à± మేనేజౠచేయి' బటనà±, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ పేమెంటà±â€Œà°²à±, à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à± సమాచారం మేనేజౠచేయడానికి 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="8918231688545606538">à°ˆ పేజీ à°…à°¨à±à°®à°¾à°¨à°¾à°¸à±à°ªà°¦à°‚à°—à°¾ ఉంది</translation>
+<translation id="8922013791253848639">à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± à°ˆ సైటà±â€Œà°²à±‹ à°Žà°ªà±à°ªà±à°¡à±‚ à°…à°¨à±à°®à°¤à°¿à°‚à°šà±</translation>
<translation id="892588693504540538">à°•à±à°¡à°¿à°µà±ˆà°ªà± à°Žà°—à±à°µ భాగంలో à°°à°‚à°§à±à°°à°‚</translation>
<translation id="8931333241327730545">మీరౠఈ కారà±à°¡à±â€Œà°¨à± మీ Google ఖాతాకౠసేవౠచేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="8932102934695377596">మీ గడియారం సమయం గతంలో ఉంది</translation>
@@ -1982,7 +2027,7 @@
<translation id="9050666287014529139">రహసà±à°¯ పదబంధం</translation>
<translation id="9056953843249698117">à°¸à±à°Ÿà±‹à°°à±</translation>
<translation id="9062620674789239642">ఇది తరలించబడి గానీ, ఎడిటౠచేసి గానీ లేదా తొలగించబడి ఉండవచà±à°šà±.</translation>
-<translation id="9065203028668620118">సవరించà±</translation>
+<translation id="9065203028668620118">à°Žà°¡à°¿à°Ÿà±</translation>
<translation id="9065745800631924235">à°šà°°à°¿à°¤à±à°° à°¨à±à°‚à°¡à°¿ <ph name="TEXT" /> శోధన</translation>
<translation id="9069693763241529744">పొడిగింపౠదà±à°µà°¾à°°à°¾ à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="9078964945751709336">మరింత సమాచారం ఆవశà±à°¯à°•à°‚</translation>
@@ -2013,21 +2058,24 @@
<translation id="917450738466192189">సరà±à°µà°°à± యొకà±à°• à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ చెలà±à°²à±à°¬à°¾à°Ÿà± కాదà±.</translation>
<translation id="9174917557437862841">à°Ÿà±à°¯à°¾à°¬à± à°¸à±à°µà°¿à°šà± బటనà±, à°ˆ à°Ÿà±à°¯à°¾à°¬à±â€Œà°•à°¿ మారడానికి à°Žà°‚à°Ÿà°°à±â€Œà°¨à°¿ నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="9179703756951298733">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ పేమెంటà±â€Œà°²à°¨à±, à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à± సమాచారానà±à°¨à°¿ మేనేజౠచేయండి</translation>
-<translation id="9183302530794969518">Google డాకà±à°¸à±</translation>
+<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> మదà±à°¦à°¤à± లేని à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à±â€Œà°¨à± ఉపయోగిసà±à°¤à±‹à°‚ది.</translation>
<translation id="9191834167571392248">ఎడమవైపౠదిగà±à°µ భాగంలో à°°à°‚à°§à±à°°à°‚</translation>
+<translation id="9199905725844810519">à°ªà±à°°à°¿à°‚à°Ÿà°¿à°‚à°—à± à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="9205078245616868884">మీ సింకà±â€Œ రహసà±à°¯ పదబంధంతో మీ డేటా à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయ‌బ‌డింది. సింకà±â€Œà°¨à± à°ªà±à°°à°¾à°°à°‚భించడానికి దీనà±à°¨à°¿ నమోదౠచేయండి.</translation>
<translation id="9207861905230894330">కథనానà±à°¨à°¿ జోడించడంలో విఫలమైంది.</translation>
<translation id="9213433120051936369">కనిపించే తీరà±à°¨à± à°…à°¨à±à°•à±‚లంగా మారà±à°šà°‚à°¡à°¿</translation>
<translation id="9215416866750762878">à°’à°• à°…à°ªà±à°²à°¿à°•à±‡à°·à°¨à± కారణంగా Chrome à°ˆ సైటà±â€Œà°•à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ కనెకà±à°Ÿà± కాలేకపోతోంది</translation>
-<translation id="9219103736887031265">à°šà°¿à°¤à±à°°à°¾à°²à±</translation>
+<translation id="9219103736887031265">ఇమేజà±â€Œà°²à±</translation>
<translation id="933712198907837967">డైనరà±à°¸à± à°•à±à°²à°¬à±</translation>
<translation id="935608979562296692">ఫారమà±â€Œà°¨à± తీసివేయండి</translation>
<translation id="936474030629450166">సూపరà±-B</translation>
<translation id="936602727769022409">మీరౠమీ Google ఖాతాకౠయాకà±à°¸à±†à°¸à±â€Œà°¨à°¿ కోలà±à°ªà±‹à°µà°šà±à°šà±. మీరౠఇపà±à°ªà±à°¡à±‡ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à°¿ మారà±à°šà°¾à°²à±à°¸à°¿à°‚దిగా Chromium సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది. మీరౠసైనౠఇనౠచేయాలà±à°¸à°¿ ఉంటà±à°‚ది.</translation>
<translation id="939736085109172342">à°•à±à°°à±Šà°¤à±à°¤ ఫోలà±à°¡à°°à±</translation>
+<translation id="945522503751344254">ఫీడà±â€Œà°¬à±à°¯à°¾à°•à± పంపండి</translation>
<translation id="945855313015696284">à°ˆ కింది వివరాలనౠఒకà±à°•à°¸à°¾à°°à°¿ పరిశీలించి చెలà±à°²à°¨à°¿ కారà±à°¡à±â€Œà°²à± à°à°®à±ˆà°¨à°¾ ఉంటే తొలగించండి</translation>
<translation id="950736567201356821">à°Žà°—à±à°µ భాగంలో మూడౠరంధà±à°°à°¾à°²à±</translation>
+<translation id="951941430552851965">మీ à°¸à±à°•à±à°°à±€à°¨à±â€Œà°ªà±ˆà°¨ కంటెంటౠకారణంగా మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¦à±à°µà°¾à°°à°¾ à°¸à±à°•à±à°°à±€à°¨à± à°•à±à°¯à°¾à°ªà±à°šà°°à± ఆపివేయబడింది.</translation>
<translation id="961663415146723894">దిగà±à°µ భాగంలో బైండà±</translation>
<translation id="962484866189421427">à°ˆ కంటెంటౠవేరేవాటిలా కనిపించే మోసపూరిత యాపà±â€Œà°²à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చవచà±à°šà± లేదా మిమà±à°®à°²à±à°¨à°¿ à°Ÿà±à°°à°¾à°•à± చేయడానికి ఉపయోగించే డేటాని సేకరించవచà±à°šà±. <ph name="BEGIN_LINK" />అయినపà±à°ªà°Ÿà°¿à°•à±€, చూపించà±<ph name="END_LINK" /></translation>
<translation id="969892804517981540">అధికారిక బిలà±à°¡à±</translation>
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index 9ac3a762bdd..9ab6857733f 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">คุณป้อนรหัสผ่านในเว็บไซต์ที่องค์à¸à¸£à¹„ม่ได้จัดà¸à¸²à¸£ เพื่อปà¸à¸›à¹‰à¸­à¸‡à¸šà¸±à¸à¸Šà¸µ โปรดอย่าใช้รหัสผ่านซ้ำในà¹à¸­à¸›à¹à¸¥à¸°à¹€à¸§à¹‡à¸šà¹„ซต์อื่นๆ</translation>
<translation id="1263231323834454256">เรื่องรออ่าน</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸—ี่จะไม่บันทึà¸à¹„ว้ในอุปà¸à¸£à¸“์นี้ ได้à¹à¸à¹ˆ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />หน้าเว็บที่คุณดูในหน้าต่างนี้
+ <ph name="LIST_ITEM" />คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลเว็บไซต์
+ <ph name="LIST_ITEM" />ข้อมูลบัà¸à¸Šà¸µ (<ph name="LINK_BEGIN" />ออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸š<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">วิธีà¸à¸²à¸£à¸£à¸±à¸šà¸ªà¸´à¸™à¸„้า</translation>
<translation id="1281476433249504884">สà¹à¸•à¹‡à¸à¹€à¸à¸­à¸£à¹Œ 1</translation>
<translation id="1285320974508926690">ไม่ต้องà¹à¸›à¸¥à¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">ลงชื่อเข้าใช้เพื่อใช้รหัสผ่านที่บันทึà¸à¹„ว้ในบัà¸à¸Šà¸µ Google</translation>
<translation id="2053111141626950936">ระบบจะไม่à¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸šà¸ à¸²à¸©à¸²<ph name="LANGUAGE" /></translation>
<translation id="2053553514270667976">รหัสไปรษณีย์</translation>
+<translation id="2054665754582400095">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 คำà¹à¸™à¸°à¸™à¸³}other{# คำà¹à¸™à¸°à¸™à¸³}}</translation>
<translation id="2079545284768500474">เลิà¸à¸—ำ</translation>
<translation id="20817612488360358">มีà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ให้ใช้à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าพร็อà¸à¸‹à¸µà¸£à¸°à¸šà¸š à¹à¸•à¹ˆà¸à¹‡à¸¡à¸µà¸à¸²à¸£à¸£à¸°à¸šà¸¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าพร็อà¸à¸‹à¸µà¸­à¸¢à¹ˆà¸²à¸‡à¸Šà¸±à¸”เจนไว้ด้วยเช่นà¸à¸±à¸™</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">à¹à¸­à¸› Android</translation>
<translation id="2107021941795971877">à¸à¸²à¸£à¸£à¸­à¸‡à¸£à¸±à¸šà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ</translation>
<translation id="2108755909498034140">รีสตาร์ทคอมพิวเตอร์</translation>
+<translation id="2111166930115883695">à¸à¸”à¹à¸›à¹‰à¸™à¹€à¸§à¹‰à¸™à¸§à¸£à¸£à¸„เพื่อเล่น</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">บัตร</translation>
<translation id="2114841414352855701">ไม่สนใจเพราะถูà¸à¹à¸—นที่โดย <ph name="POLICY_NAME" /></translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="2147827593068025794">à¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ในà¹à¸šà¹‡à¸à¸à¸£à¸²à¸§à¸”์</translation>
<translation id="2148613324460538318">เพิ่มบัตร</translation>
+<translation id="2149968176347646218">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹„ม่ปลอดภัย</translation>
<translation id="2154054054215849342">ไม่มีà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์สำหรับโดเมนของคุณ</translation>
<translation id="2154484045852737596">à¹à¸à¹‰à¹„ขบัตร</translation>
<translation id="2161656808144014275">ข้อความ</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">นโยบาย</translation>
<translation id="2183608646556468874">หมายเลขโทรศัพท์</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{ที่อยู่ 1 รายà¸à¸²à¸£}other{ที่อยู่ # รายà¸à¸²à¸£}}</translation>
-<translation id="2187243482123994665">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸­à¸¢à¸¹à¹ˆà¸‚องผู้ใช้</translation>
<translation id="2187317261103489799">ตรวจหา (ค่าเริ่มต้น)</translation>
<translation id="2188375229972301266">เจาะรูด้านล่างหลายรู</translation>
<translation id="2202020181578195191">ป้อนปีที่หมดอายุที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">ระวังเว็บไซต์หลอà¸à¸¥à¸§à¸‡</translation>
<translation id="2850739647070081192">Invite (ซองจดหมาย)</translation>
<translation id="2856444702002559011">ผู้โจมตีอาจพยายามขโมยข้อมูลจาภ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ตัวอย่างเช่น รหัสผ่าน ข้อความ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">เว็บไซต์นี้à¹à¸ªà¸”งโฆษณาที่à¹à¸—รà¸à¸«à¸£à¸·à¸­à¸—ำให้เข้าใจผิด</translation>
<translation id="2878197950673342043">พับà¹à¸šà¸šà¹‚ปสเตอร์</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ตำà¹à¸«à¸™à¹ˆà¸‡à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">คำà¹à¸™à¸°à¸™à¸³à¹‚ดย Google</translation>
<translation id="3002501248619246229">ตรวจสอบสื่อของถาดà¸à¸£à¸°à¸”าษเข้า</translation>
<translation id="3005723025932146533">à¹à¸ªà¸”งสำเนาที่บันทึà¸à¹„ว้</translation>
-<translation id="3007719053326478567">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸¥à¹‡à¸­à¸à¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œà¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸™à¸µà¹‰à¹„ว้</translation>
<translation id="3008447029300691911">ป้อน CVC สำหรับ <ph name="CREDIT_CARD" /> เมื่อยืนยันà¹à¸¥à¹‰à¸§ รายละเอียดบัตรของคุณจะà¹à¸Šà¸£à¹Œà¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
<translation id="3010559122411665027">รายà¸à¸²à¸£à¸—ี่เข้ามา "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ถูà¸à¸šà¸¥à¹‡à¸­à¸à¹‚ดยอัตโนมัติ</translation>
<translation id="3016780570757425217">ทราบตำà¹à¸«à¸™à¹ˆà¸‡à¸‚องคุณ</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> à¸à¸” Tab ตามด้วย Enter เพื่อนำคำà¹à¸™à¸°à¸™à¸³à¸­à¸­à¸</translation>
<translation id="3023071826883856138">You4 (ซองจดหมาย)</translation>
<translation id="3024663005179499861">ประเภทนโยบายไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="3037605927509011580">à¹à¸¢à¹ˆà¸ˆà¸±à¸‡!</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¹à¸¥à¹‰à¸§</translation>
<translation id="3209034400446768650">อาจมีà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¹ƒà¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰</translation>
<translation id="3212581601480735796">มีà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸—ี่คุณทำใน <ph name="HOSTNAME" /></translation>
+<translation id="3212623355668894776">ปิดหน้าต่างโหมดผู้มาเยือนทั้งหมดเพื่อลบà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บออà¸à¸ˆà¸²à¸à¸­à¸¸à¸›à¸à¸£à¸“์นี้</translation>
<translation id="3215092763954878852">ใช้ WebAuthn ไม่ได้</translation>
<translation id="3218181027817787318">Relative</translation>
<translation id="3225919329040284222">เซิร์ฟเวอร์à¹à¸ªà¸”งใบรับรองที่ไม่ตรงà¸à¸±à¸šà¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์ที่มีอยู่ à¸à¸²à¸£à¸„าดà¸à¸²à¸£à¸“์เหล่านี้มีอยู่ในบางเว็บไซต์ที่มีà¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยสูงเพื่อปà¸à¸›à¹‰à¸­à¸‡à¸„ุณ</translation>
@@ -695,6 +707,7 @@
<translation id="3784372983762739446">อุปà¸à¸£à¸“์บลูทูธ</translation>
<translation id="3787705759683870569">หมดอายุ <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">ขนาด 16</translation>
+<translation id="3789841737615482174">ติดตั้ง</translation>
<translation id="3793574014653384240">จำนวนà¹à¸¥à¸°à¸ªà¸²à¹€à¸«à¸•à¸¸à¸‚องà¸à¸²à¸£à¸‚ัดข้องที่เà¸à¸´à¸”ขึ้นเมื่อเร็วๆ นี้</translation>
<translation id="3797522431967816232">Prc3 (ซองจดหมาย)</translation>
<translation id="3799805948399000906">ขอà¹à¸šà¸šà¸­à¸±à¸à¸©à¸£à¹à¸¥à¹‰à¸§</translation>
@@ -745,6 +758,7 @@
<translation id="4056223980640387499">ซีเปีย</translation>
<translation id="4058922952496707368">คีย์ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ซองจดหมาย)</translation>
+<translation id="4067669230157909013">à¸à¸²à¸£à¸ˆà¸±à¸šà¸ à¸²à¸žà¸«à¸™à¹‰à¸²à¸ˆà¸­à¸à¸¥à¸±à¸šà¸¡à¸²à¸—ำงานอีà¸à¸„รั้ง</translation>
<translation id="4067947977115446013">เพิ่มที่อยู่ที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="4072486802667267160">เà¸à¸´à¸”ข้อผิดพลาดในà¸à¸²à¸£à¸›à¸£à¸°à¸¡à¸§à¸¥à¸œà¸¥à¸„ำสั่งซื้อของคุณ โปรดลองอีà¸à¸„รั้ง</translation>
<translation id="4075732493274867456">ไคลเอ็นต์à¹à¸¥à¸°à¹€à¸‹à¸´à¸£à¹Œà¸Ÿà¹€à¸§à¸­à¸£à¹Œà¹„ม่รองรับโปรโตคอล SSL เวอร์ชันทั่วไปหรือชุดà¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
@@ -825,6 +839,7 @@
<translation id="4297502707443874121">ภาพขนาดย่อของหน้า <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">ขยาย</translation>
<translation id="4300675098767811073">เจาะรูด้านขวาหลายรู</translation>
+<translation id="4302514097724775343">à¹à¸•à¸°à¹„ดโนเสาร์เพื่อเล่น</translation>
<translation id="4302965934281694568">Chou3 (ซองจดหมาย)</translation>
<translation id="4305666528087210886">เข้าถึงไฟล์ไม่ได้</translation>
<translation id="4305817255990598646">สลับ</translation>
@@ -903,6 +918,7 @@
<translation id="4658638640878098064">เย็บด้วยลวดเย็บà¸à¸£à¸°à¸”าษด้านซ้ายบน</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual Reality</translation>
+<translation id="4675657451653251260">คุณจะไม่เห็นข้อมูลใดๆ ของโปรไฟล์ Chrome ในโหมดผู้มาเยือน à¹à¸•à¹ˆà¸ªà¸²à¸¡à¸²à¸£à¸–<ph name="LINK_BEGIN" />ลงชื่อเข้าใช้<ph name="LINK_END" />เพื่อดูข้อมูลในบัà¸à¸Šà¸µ Google เช่น รหัสผ่านà¹à¸¥à¸°à¸§à¸´à¸˜à¸µà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="467662567472608290">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยมีข้อผิดพลาด โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้บุà¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="4677585247300749148"><ph name="URL" /> ต้องà¸à¸²à¸£à¸•à¸­à¸šà¸ªà¸™à¸­à¸‡à¸•à¹ˆà¸­à¹€à¸«à¸•à¸¸à¸à¸²à¸£à¸“์à¸à¸²à¸£à¹€à¸‚้าถึงพิเศษ</translation>
<translation id="467809019005607715">Google สไลด์</translation>
@@ -930,6 +946,12 @@
<translation id="4761104368405085019">ใช้ไมโครโฟนของคุณ</translation>
<translation id="4764776831041365478">หน้าเว็บใน <ph name="URL" /> อาจหยุดให้บริà¸à¸²à¸£à¸Šà¸±à¹ˆà¸§à¸„ราวหรืออาจถูà¸à¸¢à¹‰à¸²à¸¢à¹„ปยังที่อยู่เว็บใหม่อย่างถาวร</translation>
<translation id="4766713847338118463">เย็บด้วยลวดเย็บà¸à¸£à¸°à¸”าษด้านล่าง 2 ครั้ง</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸—ี่จะบันทึà¸à¹„ว้ในอุปà¸à¸£à¸“์นี้ ได้à¹à¸à¹ˆ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ไฟล์ใดๆ ที่คุณดาวน์โหลดในหน้าต่างนี้
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">มีข้อผิดพลาดที่ไม่ทราบเà¸à¸´à¸”ขึ้น</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{ป๊อปอัปถูà¸à¸šà¸¥à¹‡à¸­à¸}other{# ป๊อปอัปถูà¸à¸šà¸¥à¹‡à¸­à¸}}</translation>
<translation id="4780366598804516005">à¸à¸¥à¹ˆà¸­à¸‡à¸ˆà¸”หมาย 1</translation>
@@ -1092,11 +1114,13 @@
<translation id="5386426401304769735">à¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้มีใบรับรองที่ลงนามโดยใช้ SHA-1</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">เย็บขอบด้านขวา</translation>
+<translation id="5398772614898833570">บล็อà¸à¹‚ฆษณา</translation>
<translation id="5400836586163650660">สีเทา</translation>
<translation id="540969355065856584">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เนื่องจาà¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸„วามปลอดภัยไม่สามารถใช้ได้ในขณะนี้ ซึ่งอาจเป็นเพราะà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าที่ไม่ถูà¸à¸•à¹‰à¸­à¸‡à¸«à¸£à¸·à¸­à¸¡à¸µà¸œà¸¹à¹‰à¹‚จมตีที่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="541416427766103491">สà¹à¸•à¹‡à¸à¹€à¸à¸­à¸£à¹Œ 4</translation>
<translation id="5421136146218899937">ล้างข้อมูลà¸à¸²à¸£à¸—่องเว็บ...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> ต้องà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¹ƒà¸«à¹‰à¸„ุณ</translation>
+<translation id="542872847390508405">คุณà¸à¸³à¸¥à¸±à¸‡à¹€à¸£à¸µà¸¢à¸à¸”ูในà¸à¸²à¸™à¸°à¸œà¸¹à¹‰à¹€à¸¢à¸µà¹ˆà¸¢à¸¡à¸Šà¸¡</translation>
<translation id="5430298929874300616">นำบุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸­à¸</translation>
<translation id="5439770059721715174">ข้อผิดพลาดในà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸£à¸¹à¸›à¹à¸šà¸šà¸—ี่ "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">ลำดับย้อนà¸à¸¥à¸±à¸šà¸«à¸‡à¸²à¸¢à¸«à¸™à¹‰à¸²à¸‚ึ้น</translation>
@@ -1138,12 +1162,12 @@
<translation id="5571083550517324815">ไม่สามารถรับสินค้าจาà¸à¸—ี่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="5580958916614886209">ตรวจสอบเดือนหมดอายุà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="5586446728396275693">ไม่มีที่อยู่ที่บันทึà¸à¹„ว้</translation>
+<translation id="5593349413089863479">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹„ม่ปลอดภัยอย่างสมบูรณ์</translation>
<translation id="5595485650161345191">à¹à¸à¹‰à¹„ขที่อยู่</translation>
<translation id="5598944008576757369">เลือà¸à¸§à¸´à¸˜à¸µà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="560412284261940334">ไม่สนับสนุนà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">เว็บไซต์นี้อาจเป็นเว็บไซต์ปลอมหรือฉ้อโà¸à¸‡ Chrome à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸„ุณออà¸à¸ˆà¸²à¸à¹€à¸§à¹‡à¸šà¹„ซต์เดี๋ยวนี้</translation>
<translation id="5610142619324316209">ตรวจสอบà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
<translation id="5610807607761827392">คุณสามารถจัดà¸à¸²à¸£à¸šà¸±à¸•à¸£à¹à¸¥à¸°à¸—ี่อยู่ใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า<ph name="END_LINK" /></translation>
<translation id="561165882404867731">à¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¹‚ดยใช้ Google à¹à¸›à¸¥à¸ à¸²à¸©à¸²</translation>
@@ -1215,6 +1239,7 @@
<translation id="5901630391730855834">สีเหลือง</translation>
<translation id="5905445707201418379">ถูà¸à¸šà¸¥à¹‡à¸­à¸à¸•à¸²à¸¡à¸™à¹‚ยบายดั้งเดิมของ <ph name="ORIGIN" /></translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (ซิงค์à¹à¸¥à¹‰à¸§)</translation>
+<translation id="5913377024445952699">à¸à¸²à¸£à¸ˆà¸±à¸šà¸ à¸²à¸žà¸«à¸™à¹‰à¸²à¸ˆà¸­à¸«à¸¢à¸¸à¸”อยู่ชั่วคราว</translation>
<translation id="59174027418879706">เปิดใช้งาน</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">เปิด</translation>
@@ -1227,6 +1252,7 @@
<translation id="5963413905009737549">ส่วน</translation>
<translation id="5967592137238574583">à¹à¸à¹‰à¹„ขข้อมูลติดต่อ</translation>
<translation id="5967867314010545767">ลบจาà¸à¸›à¸£à¸°à¸§à¸±à¸•à¸´à¸à¸²à¸£à¹€à¸‚้าชม</translation>
+<translation id="5968793460449681917">ทุà¸à¸„รั้งที่เข้าชม</translation>
<translation id="5975083100439434680">ย่อ</translation>
<translation id="5979084224081478209">ตรวจสอบรหัสผ่าน</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1382,6 +1408,7 @@
<translation id="6587923378399804057">ลิงà¸à¹Œà¸—ี่คุณคัดลอà¸</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> ของคุณไม่มีà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£</translation>
<translation id="6596325263575161958">ตัวเลือà¸à¸à¸²à¸£à¹€à¸‚้ารหัส</translation>
+<translation id="6596892391065203054">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸¥à¹‡à¸­à¸à¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œà¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸™à¸µà¹‰à¹„ว้</translation>
<translation id="6604181099783169992">เซ็นเซอร์จับความเคลื่อนไหวหรือเซ็นเซอร์à¹à¸ªà¸‡</translation>
<translation id="6609880536175561541">Prc7 (ซองจดหมาย)</translation>
<translation id="6612358246767739896">เนื้อหาที่ได้รับความคุ้มครอง</translation>
@@ -1441,6 +1468,7 @@
<translation id="6895330447102777224">บัตรของคุณได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="6897140037006041989">User agent</translation>
<translation id="6898699227549475383">องค์à¸à¸£ (O)</translation>
+<translation id="6907293445143367439">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="SITE_NAME" /></translation>
<translation id="6910240653697687763"><ph name="URL" /> ต้องà¸à¸²à¸£à¸—ี่จะได้รับสิทธิ์ควบคุมอุปà¸à¸£à¸“์ MIDI เต็มรูปà¹à¸šà¸š</translation>
<translation id="6915804003454593391">ผู้ใช้:</translation>
<translation id="6934672428414710184">ชื่อนี้มาจาà¸à¸šà¸±à¸à¸Šà¸µ Google ของคุณ</translation>
@@ -1552,6 +1580,7 @@
<translation id="7346048084945669753">เป็นพาร์ทเนอร์:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">บรรทัดคำสั่ง </translation>
+<translation id="7359588939039777303">บล็อà¸à¹‚ฆษณา</translation>
<translation id="7372973238305370288">ผลà¸à¸²à¸£à¸„้นหา</translation>
<translation id="7374733840632556089">ปัà¸à¸«à¸²à¸™à¸µà¹‰à¹€à¸à¸´à¸”จาà¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸—ี่คุณหรือคนอื่นติดตั้งไว้ในอุปà¸à¸£à¸“์ เป็นที่ทราบà¸à¸±à¸™à¸§à¹ˆà¸² ใบรับรองนี้ใช้สำหรับà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¹à¸¥à¸°à¸ªà¸à¸±à¸”à¸à¸±à¹‰à¸™à¹€à¸„รือข่าย à¹à¸¥à¸° Chrome ไม่เชื่อถือใบรับรองนี้ à¹à¸¡à¹‰à¸§à¹ˆà¸²à¸ˆà¸°à¸¡à¸µà¸šà¸²à¸‡à¸à¸£à¸“ีที่à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸Šà¸­à¸šà¸”้วยà¸à¸Žà¸«à¸¡à¸²à¸¢ เช่น เครือข่ายของบริษัทหรือโรงเรียน à¹à¸•à¹ˆ Chrome à¸à¹‡à¸¢à¸±à¸‡à¸­à¸¢à¸²à¸à¸ˆà¸°à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸„ุณรับรู้ว่ามีà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸–ึงà¹à¸¡à¹‰à¸ˆà¸°à¸«à¸¢à¸¸à¸”à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸™à¸±à¹‰à¸™à¹„ม่ได้à¸à¹‡à¸•à¸²à¸¡ à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸­à¸²à¸ˆà¹€à¸à¸´à¸”ขึ้นได้ในทุà¸à¹€à¸šà¸£à¸²à¸§à¹Œà¹€à¸‹à¸­à¸£à¹Œà¸«à¸£à¸·à¸­à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันที่เข้าถึงเว็บ</translation>
<translation id="7375818412732305729">มีà¸à¸²à¸£à¹à¸™à¸šà¹„ฟล์</translation>
@@ -1726,6 +1755,7 @@
<translation id="7976214039405368314">มีคำขอมาà¸à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="7977538094055660992">อุปà¸à¸£à¸“์à¸à¸£à¸°à¸”าษออà¸</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">ติดตั้ง ARCore เพื่อดูเนื้อหา Augmented Reality</translation>
<translation id="799149739215780103">เย็บเล่ม</translation>
<translation id="7995512525968007366">ไม่ได้ระบุ</translation>
<translation id="800218591365569300">ลองปิดà¹à¸—็บหรือโปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹† เพื่อเพิ่มหน่วยความจำ</translation>
@@ -1853,25 +1883,39 @@
<translation id="8507227106804027148">บรรทัดคำสั่ง</translation>
<translation id="8508648098325802031">ไอคอนค้นหา</translation>
<translation id="8522552481199248698">Chrome ช่วยคุณปà¸à¸›à¹‰à¸­à¸‡à¸šà¸±à¸à¸Šà¸µ Google à¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¹„ด้</translation>
+<translation id="8525306231823319788">เต็มหน้าจอ</translation>
<translation id="8530813470445476232">ล้างประวัติà¸à¸²à¸£à¸—่องเว็บ คุà¸à¸à¸µà¹‰ à¹à¸„ช à¹à¸¥à¸°à¸­à¸·à¹ˆà¸™à¹† ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="8533619373899488139">ไปที่ &lt;strong&gt;chrome://policy&lt;/strong&gt; เพื่อดูรายà¸à¸²à¸£ URL ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸à¹à¸¥à¸°à¸™à¹‚ยบายอื่นๆ ที่ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸±à¸‡à¸„ับใช้</translation>
<translation id="8541158209346794904">อุปà¸à¸£à¸“์บลูทูธ</translation>
<translation id="8542014550340843547">เย็บด้วยลวดเย็บà¸à¸£à¸°à¸”าษด้านล่าง 3 ครั้ง</translation>
<translation id="8543181531796978784">คุณสามารถ<ph name="BEGIN_ERROR_LINK" />รายงานปัà¸à¸«à¸²à¹ƒà¸™à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸«à¸²<ph name="END_ERROR_LINK" />ได้ หรือหาà¸à¸„ุณเข้าใจถึงความเสี่ยงต่อความปลอดภัยของคุณ คุณสามารถ<ph name="BEGIN_LINK" />เข้าชมเว็บไซต์ที่ไม่ปลอดภัย<ph name="END_LINK" />ได้</translation>
<translation id="8557066899867184262">CVC จะอยู่ที่ด้านหลังบัตร</translation>
+<translation id="8558485628462305855">อัปเดต ARCore เพื่อดูเนื้อหา Augmented Reality</translation>
<translation id="8559762987265718583">ไม่สามารถเริ่มà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¸à¸±à¸š <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ได้เนื่องจาà¸à¸§à¸±à¸™à¸—ี่à¹à¸¥à¸°à¹€à¸§à¸¥à¸²à¸‚องอุปà¸à¸£à¸“์ (<ph name="DATE_AND_TIME" />) ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="8564182942834072828">เอà¸à¸ªà¸²à¸£à¹à¸¢à¸à¸à¸±à¸™/ไม่จัดชุดสำเนา</translation>
<translation id="8564985650692024650">Chromium ขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸£à¸µà¹€à¸‹à¹‡à¸•à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> หาà¸à¸„ุณใช้รหัสผ่านนี้ซ้ำในเว็บไซต์อื่น</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸—ี่จะไม่บันทึà¸à¹„ว้ในอุปà¸à¸£à¸“์นี้ ได้à¹à¸à¹ˆ
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />หน้าเว็บที่คุณดูในหน้าต่างนี้
+ <ph name="LIST_ITEM" />คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลเว็บไซต์
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ใช้ Touch ID เพื่อยืนยันบัตรได้เร็วขึ้น</translation>
<translation id="858637041960032120">เพิ่มเบอร์โทร
</translation>
<translation id="8589998999637048520">คุณภาพดีที่สุด</translation>
+<translation id="8600271352425265729">เฉพาะครั้งนี้</translation>
<translation id="860043288473659153">ชื่อผู้ถือบัตร</translation>
<translation id="8606726445206553943">ใช้อุปà¸à¸£à¸“์ MIDI ของคุณ</translation>
+<translation id="8612761427948161954">สวัสดี คุณ <ph name="USERNAME" />
+ <ph name="BR" />
+ คุณà¸à¸³à¸¥à¸±à¸‡à¸—่องเว็บในà¸à¸²à¸™à¸°à¸œà¸¹à¹‰à¸¡à¸²à¹€à¸¢à¸·à¸­à¸™</translation>
<translation id="861775596732816396">ขนาด 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">ไม่มีรหัสผ่านที่ตรงà¸à¸±à¸™ à¹à¸ªà¸”งรหัสผ่านที่บันทึà¸à¹„ว้ทั้งหมด</translation>
<translation id="8625384913736129811">บันทึà¸à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¸¥à¸‡à¹ƒà¸™à¸­à¸¸à¸›à¸à¸£à¸“์นี้</translation>
+<translation id="8627040765059109009">à¸à¸²à¸£à¸ˆà¸±à¸šà¸ à¸²à¸žà¸«à¸™à¹‰à¸²à¸ˆà¸­à¸à¸¥à¸±à¸šà¸¡à¸²à¸—ำงานอีà¸à¸„รั้งà¹à¸¥à¹‰à¸§</translation>
<translation id="8657078576661269990">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸¥à¹‡à¸­à¸à¸à¸²à¸£à¹à¸Šà¸£à¹Œà¸ˆà¸²à¸ <ph name="ORIGIN_NAME" /> ไปยัง <ph name="VM_NAME_1" /> à¹à¸¥à¸° <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">สรุปคำสั่งซื้อ <ph name="TOTAL_LABEL" /> รายละเอียดเพิ่มเติม</translation>
<translation id="867224526087042813">ลายเซ็น</translation>
@@ -1934,6 +1978,7 @@
<translation id="8912362522468806198">บัà¸à¸Šà¸µ Google</translation>
<translation id="8913778647360618320">ปุ่มจัดà¸à¸²à¸£à¸§à¸´à¸˜à¸µà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™ à¸à¸” Enter เพื่อจัดà¸à¸²à¸£à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¹à¸¥à¸°à¸‚้อมูลบัตรเครดิตในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="8918231688545606538">หน้านี้ดูน่าสงสัย</translation>
+<translation id="8922013791253848639">อนุà¸à¸²à¸•à¹‚ฆษณาในไซต์นี้เสมอ</translation>
<translation id="892588693504540538">เจาะรูด้านขวาบน</translation>
<translation id="8931333241327730545">คุณต้องà¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¹ƒà¸™à¸šà¸±à¸à¸Šà¸µ Google ไหม</translation>
<translation id="8932102934695377596">นาฬิà¸à¸²à¸Šà¹‰à¸²à¹€à¸à¸´à¸™à¹„ป</translation>
@@ -2005,6 +2050,7 @@
<translation id="9183302530794969518">Google เอà¸à¸ªà¸²à¸£</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ใช้โปรโตคอลที่ไม่รองรับ</translation>
<translation id="9191834167571392248">เจาะรูด้านซ้ายล่าง</translation>
+<translation id="9199905725844810519">à¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œà¸–ูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
<translation id="9205078245616868884">ข้อมูลของคุณมีà¸à¸²à¸£à¹€à¸‚้ารหัสด้วยรหัสผ่านà¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ โปรดป้อนรหัสผ่านเพื่อเริ่มซิงค์</translation>
<translation id="9207861905230894330">à¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸šà¸—ความล้มเหลว</translation>
<translation id="9213433120051936369">à¸à¸³à¸«à¸™à¸”ลัà¸à¸©à¸“ะที่ปราà¸à¸</translation>
@@ -2015,8 +2061,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">คุณอาจสูà¸à¹€à¸ªà¸µà¸¢à¸ªà¸´à¸—ธิ์เข้าถึงบัà¸à¸Šà¸µ Google ของคุณ Chromium ขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸—ันที ระบบจะขอให้คุณลงชื่อเข้าใช้</translation>
<translation id="939736085109172342">โฟลเดอร์ใหม่</translation>
+<translation id="945522503751344254">ส่งความคิดเห็น</translation>
<translation id="945855313015696284">ตรวจสอบข้อมูลด้านล่างà¹à¸¥à¸°à¸¥à¸šà¸šà¸±à¸•à¸£à¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="950736567201356821">เจาะรูด้านบน 3 รู</translation>
+<translation id="951941430552851965">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸«à¸¢à¸¸à¸”à¸à¸²à¸£à¸ˆà¸±à¸šà¸ à¸²à¸žà¸«à¸™à¹‰à¸²à¸ˆà¸­à¹„ว้ชั่วคราวเนื่องจาà¸à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸šà¸™à¸«à¸™à¹‰à¸²à¸ˆà¸­à¸‚องคุณ</translation>
<translation id="961663415146723894">เย็บเล่มด้านล่าง</translation>
<translation id="962484866189421427">เนื้อหานี้อาจพยายามติดตั้งà¹à¸­à¸›à¸—ี่หลอà¸à¸¥à¸§à¸‡à¸‹à¸¶à¹ˆà¸‡à¸›à¸¥à¸­à¸¡à¹€à¸›à¹‡à¸™à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸­à¸¢à¹ˆà¸²à¸‡à¸­à¸·à¹ˆà¸™à¸«à¸£à¸·à¸­à¸£à¸§à¸šà¸£à¸§à¸¡à¸‚้อมูลที่อาจนำไปใช้ติดตามคุณ <ph name="BEGIN_LINK" />à¹à¸ªà¸”งเนื้อหา<ph name="END_LINK" /></translation>
<translation id="969892804517981540">รุ่นที่เป็นทางà¸à¸²à¸£</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index 7c3a8e0fdce..65a6c73fdea 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -80,6 +80,14 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Şifrenizi kuruluşunuz tarafından yönetilmeyen bir sitede girdiniz. Hesabınızı korumak için şifrenizi başka uygulama ve sitelerde tekrar kullanmayın.</translation>
<translation id="1263231323834454256">Okuma listesi</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Bu cihazda kalmayacak etkinlikler:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pencerede görüntülediğiniz sayfalar
+ <ph name="LIST_ITEM" />Çerezler ve site verileri
+ <ph name="LIST_ITEM" />Hesap bilgileri (<ph name="LINK_BEGIN" />oturumu kapat<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Alma Yöntemi</translation>
<translation id="1281476433249504884">Yığınlayıcı 1</translation>
<translation id="1285320974508926690">Bu siteyi hiçbir zaman çevirme</translation>
@@ -280,6 +288,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="204357726431741734">Google Hesabınızda kayıtlı şifreleri kullanmak için oturum açın</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> dilindeki sayfalar çevrilmeyecek.</translation>
<translation id="2053553514270667976">Posta kodu</translation>
+<translation id="2054665754582400095">Bir yerde olduÄŸunuza dair bilgi</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 öneri}other{# öneri}}</translation>
<translation id="2079545284768500474">Geri al</translation>
<translation id="20817612488360358">Sistem proxy ayarları kullanılmak üzere ayarlandı, ancak açık bir proxy yapılandırması da belirtildi.</translation>
@@ -293,6 +302,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2102495993840063010">Android uygulamaları</translation>
<translation id="2107021941795971877">Yazdırma destekleri</translation>
<translation id="2108755909498034140">Bilgisayarınızı yeniden başlatın</translation>
+<translation id="2111166930115883695">Oynamak için boşluk tuşuna basın</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Kart</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> tarafından geçersiz kılındığı için yoksayıldı.</translation>
@@ -304,6 +314,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="214556005048008348">Ödemeyi iptal et</translation>
<translation id="2147827593068025794">Arka Plan Senkronizasyonu</translation>
<translation id="2148613324460538318">Kart Ekle</translation>
+<translation id="2149968176347646218">Bağlantı güvenli değil</translation>
<translation id="2154054054215849342">Senkronizasyon alan adınızda kullanılamıyor</translation>
<translation id="2154484045852737596">Kartı düzenle</translation>
<translation id="2161656808144014275">Metin</translation>
@@ -314,7 +325,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2181821976797666341">Politikalar</translation>
<translation id="2183608646556468874">Telefon Numarası</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 adres}other{# adres}}</translation>
-<translation id="2187243482123994665">Kullanıcı etkinliği</translation>
<translation id="2187317261103489799">Algıla (varsayılan)</translation>
<translation id="2188375229972301266">Altta çoklu zımba</translation>
<translation id="2202020181578195191">Geçerli bir son kullanma yılı girin</translation>
@@ -341,7 +351,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2288422996159078444">Yazdığınız her şey, görüntülediğiniz her sayfa ve web'deki diğer tüm etkinlikleriniz izlenir. Sitelerdeki içerik, bilginiz dışında değiştirilebilir.</translation>
<translation id="2289385804009217824">Kırp</translation>
<translation id="2292556288342944218">Ä°nternet eriÅŸiminiz engellendi</translation>
-<translation id="2293443924986248631">Etkinleştirildiğinde, siteler sizi web'de takip eden çerezler kullanamaz. Bazı sitelerdeki özellikler bozulabilir.</translation>
+<translation id="2293443924986248631">Etkinleştirildiğinde, siteler sizi web'de takip eden çerezler kullanamaz. Bazı sitelerdeki özellikler çalışmayabilir.</translation>
<translation id="2295290966866883927">Ziyaret ettiğiniz sayfaların URL'leri analiz amacıyla Google Cloud'a veya üçüncü taraflara gönderilir. Örneğin, güvenli olmayan web sitelerini tespit etmek için taranabilirler.</translation>
<translation id="2297722699537546652">B5 (Zarf)</translation>
<translation id="2300306941146563769">Yüklenmeyenler</translation>
@@ -465,6 +475,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2839501879576190149">Sahte bir siteyi ziyaret etmek üzeresiniz</translation>
<translation id="2850739647070081192">Invite (Zarf)</translation>
<translation id="2856444702002559011">Saldırganlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> üzerinden bilgilerinizi çalmaya çalışıyor olabilir (örneğin, şifreler, mesajlar veya kredi kartları). <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Bu site, araya giren veya yanıltıcı reklamlar gösteriyor.</translation>
<translation id="2878197950673342043">Poster katlama</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Pencere yerleÅŸimi</translation>
@@ -503,11 +514,11 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2996674880327704673">Google Önerileri</translation>
<translation id="3002501248619246229">Giriş tepsisi ortam kontrolü</translation>
<translation id="3005723025932146533">Kaydedilen kopyayı göster</translation>
-<translation id="3007719053326478567">Bu içeriğin yazdırılması yöneticiniz tarafından engellendi</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> numaralı kartın CVC kodunu girin. Onayladığınızda kart ayrıntılarınız bu siteyle paylaşılacaktır.</translation>
<translation id="3010559122411665027">Liste giriÅŸi "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Otomatik olarak engellendi</translation>
<translation id="3016780570757425217">Konumunuzu bilme</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, Öneriyi Kaldırmak için Sekme'ye, sonra Enter tuşuna basın.</translation>
<translation id="3023071826883856138">You4 (Zarf)</translation>
<translation id="3024663005179499861">Yanlış politika türü</translation>
<translation id="3037605927509011580">Hay aksi!</translation>
@@ -550,6 +561,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3207960819495026254">Yer iÅŸareti koyuldu</translation>
<translation id="3209034400446768650">Sayfa sizden ücret alabilir</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> sitesinde etkinliÄŸiniz izleniyor</translation>
+<translation id="3212623355668894776">Tarama etkinliğinizin bu cihazdan silinmesi için tüm Misafir pencerelerini kapatın.</translation>
<translation id="3215092763954878852">WebAuthn kullanılamadı</translation>
<translation id="3218181027817787318">Akraba</translation>
<translation id="3225919329040284222">Sunucu, yerleşik beklentilerle eşleşmeyen bir sertifika sundu. Bu beklentiler sizi korumak amacıyla bazı yüksek güvenlikli web sitelerinde bulunur.</translation>
@@ -697,6 +709,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3784372983762739446">Bluetooth cihazlar</translation>
<translation id="3787705759683870569">Son kullanma tarihi: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Boyut 16</translation>
+<translation id="3789841737615482174">Yükle</translation>
<translation id="3793574014653384240">Son zamanlarda meydana gelen kilitlenmelerin sayısı ve nedenleri</translation>
<translation id="3797522431967816232">Prc3 (Zarf)</translation>
<translation id="3799805948399000906">Yazı tipi istendi</translation>
@@ -747,6 +760,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4056223980640387499">Sepya Tonu</translation>
<translation id="4058922952496707368">"<ph name="SUBKEY" />" anahtarı: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Zarf)</translation>
+<translation id="4067669230157909013">Ekran görüntüsü alma devam ettirildi.</translation>
<translation id="4067947977115446013">Geçerli Adres Ekleyin</translation>
<translation id="4072486802667267160">Ödemeniz işlenirken bir hata oluştu. Lütfen tekrar deneyin.</translation>
<translation id="4075732493274867456">İstemci ve sunucu, ortak bir SSL protokolü sürümünü veya şifre setini desteklemiyor.</translation>
@@ -828,6 +842,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" />. sayfanın küçük resmi</translation>
<translation id="42981349822642051">GeniÅŸlet</translation>
<translation id="4300675098767811073">Sağda çoklu delik</translation>
+<translation id="4302514097724775343">Oynamak için dinozora dokunun</translation>
<translation id="4302965934281694568">Chou3 (Zarf)</translation>
<translation id="4305666528087210886">Dosyanıza erişilemedi</translation>
<translation id="4305817255990598646">Anahtar</translation>
@@ -906,6 +921,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4658638640878098064">Sol üstte tel zımba</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Sanal gerçeklik</translation>
+<translation id="4675657451653251260">Misafir modunda Chrome profilinin hiçbir bilgisini görmezsiniz. Şifreler ve ödeme yöntemleri gibi Google hesabı bilgilerine erişmek için <ph name="LINK_BEGIN" />oturum açabilirsiniz<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikasında hatalar var. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="4677585247300749148"><ph name="URL" />, erişilebilirlikle ilgili etkinliklere yanıt vermek istiyor</translation>
<translation id="467809019005607715">Google Slaytlar</translation>
@@ -933,6 +949,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4761104368405085019">Mikrofonunuzu kullanma</translation>
<translation id="4764776831041365478"><ph name="URL" /> adresindeki web sayfası, geçici olarak kullanılamıyor veya kalıcı olarak yeni bir web adresine taşınmış olabilir.</translation>
<translation id="4766713847338118463">Altta ikili tel zımba</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Bu cihazda kalacak etkinliÄŸiniz:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pencerede indirdiğiniz tüm dosyalar
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Bilinmeyen bir hata oluÅŸtu.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up engellendi}other{# pop-up engellendi}}</translation>
<translation id="4780366598804516005">Posta kutusu 1</translation>
@@ -1095,11 +1117,13 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5386426401304769735">Bu sitenin sertifika zinciri, SHA-1 kullanılarak imzalanmış bir sertifika içeriyor.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">SaÄŸda kenar dikiÅŸi</translation>
+<translation id="5398772614898833570">Reklamlar engellendi</translation>
<translation id="5400836586163650660">Gri</translation>
<translation id="540969355065856584">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası şu anda geçerli değil. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="541416427766103491">Yığınlayıcı 4</translation>
<translation id="5421136146218899937">Tarama verilerini temizle...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> size bildirim göndermek istiyor</translation>
+<translation id="542872847390508405">Misafir olarak göz atıyorsunuz</translation>
<translation id="5430298929874300616">Yer işaretini kaldır</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" üzerinde şema doğrulama hatası: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Ters sırada ön yüz yukarı bakacak şekilde</translation>
@@ -1141,12 +1165,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5571083550517324815">Bu adresten alım yapılamıyor. Farklı bir adres seçin.</translation>
<translation id="5580958916614886209">Son kullanma tarihinin ayını kontrol edip tekrar deneyin</translation>
<translation id="5586446728396275693">KaydedilmiÅŸ adres yok</translation>
+<translation id="5593349413089863479">Bağlantı tam olarak güvenli değil</translation>
<translation id="5595485650161345191">Adresi düzenle</translation>
<translation id="5598944008576757369">Ödeme Yöntemi Seç</translation>
<translation id="560412284261940334">Yönetim desteklenmiyor</translation>
<translation id="5605670050355397069">Ana Defter</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Bu site taklit veya sahte olabilir. Chrome siteden çıkmanızı önerir.</translation>
<translation id="5610142619324316209">Bağlantınızı kontrol etme</translation>
<translation id="5610807607761827392">Kartları ve adresleri <ph name="BEGIN_LINK" />Ayarlar<ph name="END_LINK" />'da yönetebilirsiniz.</translation>
<translation id="561165882404867731">Bu sayfayı Google Çeviri'yle çevirin</translation>
@@ -1218,6 +1242,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5901630391730855834">Sarı</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> sitesinin kaynak politikası uyarınca engellendi.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (senkronize edildi)</translation>
+<translation id="5913377024445952699">Ekran görüntüsü alma duraklatıldı</translation>
<translation id="59174027418879706">Etkin</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Açık</translation>
@@ -1230,6 +1255,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5963413905009737549">Bölüm</translation>
<translation id="5967592137238574583">İletişim Bilgilerini Düzenleyin</translation>
<translation id="5967867314010545767">Geçmişten kaldır.</translation>
+<translation id="5968793460449681917">Her ziyarette</translation>
<translation id="5975083100439434680">Uzaklaştır</translation>
<translation id="5979084224081478209">Åžifreleri kontrol et</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1385,6 +1411,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6587923378399804057">Kopyalanan bağlantı</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> cihazınız yönetilmemektedir</translation>
<translation id="6596325263575161958">Şifreleme seçenekleri</translation>
+<translation id="6596892391065203054">Bu içeriğin yazdırılması yöneticiniz tarafından engellendi.</translation>
<translation id="6604181099783169992">Hareket veya Işık Sensörleri</translation>
<translation id="6609880536175561541">Prc7 (Zarf)</translation>
<translation id="6612358246767739896">Korunan içerik</translation>
@@ -1444,6 +1471,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6895330447102777224">Kartınız onaylandı</translation>
<translation id="6897140037006041989">Kullanıcı Aracısı</translation>
<translation id="6898699227549475383">KuruluÅŸ (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> sitesine şunlar için izin ver:</translation>
<translation id="6910240653697687763"><ph name="URL" />, MIDI cihazlarınız üzerinde tam denetim istiyor</translation>
<translation id="6915804003454593391">Kullanıcı:</translation>
<translation id="6934672428414710184">Bu ad Google Hesabınızdan gelmektedir</translation>
@@ -1555,6 +1583,7 @@ Ek ayrıntılar:
<translation id="7346048084945669753">Ä°liÅŸkili olma durumu:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Komut Satırı</translation>
+<translation id="7359588939039777303">Reklamlar engellendi.</translation>
<translation id="7372973238305370288">arama sonucu</translation>
<translation id="7374733840632556089">Bu sorunun nedeni sizin veya başka birinin cihazınıza yüklediği bir sertifika olabilir. Sertifikanın ağa müdahale etmek ve izlemek amacıyla kullanıldığı bilindiğinden, Chrome bu sertifikaya güvenmez. Okul veya şirket ağı gibi izlemenin meşru olduğu durumlar vardır. İzlemeyi durduramasanız bile Chrome yine de farkında olmanızı sağlamak ister. Web’e erişen her tarayıcı ve uygulamada izleme yapılabilir.</translation>
<translation id="7375818412732305729">Dosya ekleme</translation>
@@ -1729,6 +1758,7 @@ Ek ayrıntılar:
<translation id="7976214039405368314">Çok fazla istek var</translation>
<translation id="7977538094055660992">Çıkış cihazı</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Artırılmış gerçeklik içeriğini görüntülemek için ARCore'u yükleyin</translation>
<translation id="799149739215780103">BaÄŸlama</translation>
<translation id="7995512525968007366">Belirtilmedi</translation>
<translation id="800218591365569300">Bellekte yer açmak için diğer sekmeleri veya programları kapatmayı deneyin.</translation>
@@ -1841,7 +1871,7 @@ Ek ayrıntılar:
<translation id="8438786541497918448">Kamera ve mikrofon kullanılsın mı?</translation>
<translation id="8446884382197647889">Daha Fazla Bilgi Edinin</translation>
<translation id="8457125768502047971">Süresiz</translation>
-<translation id="8461694314515752532">Senkronize edilen verileri senkronizasyon parolanızı kullanarak şifrele</translation>
+<translation id="8461694314515752532">Senkronize edilen verileri kendi senkronizasyon parolanızla şifreleyin</translation>
<translation id="8466379296835108687">{COUNT,plural, =1{1 kredi kartı}other{# kredi kartı}}</translation>
<translation id="8473863474539038330">Adresler ve daha fazlası</translation>
<translation id="8474910779563686872">Geliştirici ayrıntılarını göster</translation>
@@ -1856,25 +1886,39 @@ Ek ayrıntılar:
<translation id="8507227106804027148">Komut satırı</translation>
<translation id="8508648098325802031">Arama simgesi</translation>
<translation id="8522552481199248698">Chrome, Google Hesabınızı korumanıza ve şifrenizi değiştirmenize yardımcı olabilir.</translation>
+<translation id="8525306231823319788">Tam ekran</translation>
<translation id="8530813470445476232">Chrome ayarlarında tarama geçmişinizi, çerezleri, önbelleği ve diğer öğeleri temizleyin</translation>
<translation id="8533619373899488139">Engellenen URL'lerin ve sistem yöneticinizin zorunlu tuttuğu diğer politikaların listesini görmek için &lt;strong&gt;chrome://policy&lt;/strong&gt; adresini ziyaret edin.</translation>
<translation id="8541158209346794904">Bluetooth cihaz</translation>
<translation id="8542014550340843547">Altta üçlü tel zımba</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Bir tespit sorununu bildirebilir<ph name="END_ERROR_LINK" /> veya güvenliğiniz açısından riskleri anlıyorsanız <ph name="BEGIN_LINK" />güvenli olmayan bu siteyi ziyaret edebilirsiniz<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC, kartınızın arkasında bulunur.</translation>
+<translation id="8558485628462305855">Artırılmış gerçeklik içeriğini görüntülemek için ARCore'u güncelleyin</translation>
<translation id="8559762987265718583">Cihazınızın tarih ve saati (<ph name="DATE_AND_TIME" />) yanlış olduğundan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alan adına gizli bir bağlantı kurulamıyor.</translation>
<translation id="8564182942834072828">Ayrı dokümanlar/Harmanlanmamış kopyalar</translation>
<translation id="8564985650692024650">Chromium, <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> şifrenizi başka sitelerde kullandıysanız sıfırlamanızı önerir.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Bu cihazda kalmayacak etkinlikler:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu pencerede görüntülediğiniz sayfalar
+ <ph name="LIST_ITEM" />Çerezler ve site verileri
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Kartları daha hızlı onaylamak için Touch ID'yi kullanın</translation>
<translation id="858637041960032120">Telefon no ekle
</translation>
<translation id="8589998999637048520">En iyi kalite</translation>
+<translation id="8600271352425265729">Yalnız bu sefer</translation>
<translation id="860043288473659153">Kart sahibinin adı</translation>
<translation id="8606726445206553943">MIDI cihazlarınızı kullanma</translation>
+<translation id="8612761427948161954">Merhaba <ph name="USERNAME" />,
+ <ph name="BR" />
+ Misafir olarak göz atıyorsunuz</translation>
<translation id="861775596732816396">Boyut 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Eşleşen şifre yok. Tüm kayıtlı şifreleri göster.</translation>
<translation id="8625384913736129811">Bu Kartı Bu Cihaza Kaydet</translation>
+<translation id="8627040765059109009">Ekran görüntüsü alma devam ettirildi</translation>
<translation id="8657078576661269990">Yöneticiniz, <ph name="ORIGIN_NAME" /> sitesinden <ph name="VM_NAME_1" /> ve <ph name="VM_NAME_2" /> ile paylaşımı engelledi</translation>
<translation id="8663226718884576429">Sipariş Özeti, <ph name="TOTAL_LABEL" />, Daha Fazla Ayrıntı</translation>
<translation id="867224526087042813">Ä°mza</translation>
@@ -1915,7 +1959,7 @@ Ek ayrıntılar:
<translation id="8805819170075074995">Liste girişi "<ph name="LANGUAGE_ID" />": Giriş, SpellcheckLanguage politikasında da yer aldığı için yoksayıldı.</translation>
<translation id="8807160976559152894">Her sayfadan sonra kırp</translation>
<translation id="8816395686387277279"><ph name="UPDATE_CHROME_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarınızdan Chrome'u güncellemek için Sekme'ye, sonra Enter'a basın</translation>
-<translation id="8820817407110198400">Favoriler</translation>
+<translation id="8820817407110198400">Yer iÅŸaretleri</translation>
<translation id="883848425547221593">DiÄŸer Yer Ä°ÅŸaretleri</translation>
<translation id="884264119367021077">Gönderim adresi</translation>
<translation id="884923133447025588">İptal mekanizması bulunamadı.</translation>
@@ -1937,6 +1981,7 @@ Ek ayrıntılar:
<translation id="8912362522468806198">Google Hesabı</translation>
<translation id="8913778647360618320">Ödeme yöntemlerini yönet düğmesi, Chrome ayarlarında ödemelerinizi ve kredi kartı bilgilerinizi yönetmek için Enter'a basın</translation>
<translation id="8918231688545606538">Bu sayfa şüpheli</translation>
+<translation id="8922013791253848639">Bu sitede her zaman reklamlara izin ver</translation>
<translation id="892588693504540538">Sağ üstte delik</translation>
<translation id="8931333241327730545">Bu kartı Google Hesabınıza kaydetmek istiyor musunuz?</translation>
<translation id="8932102934695377596">Saatiniz geri</translation>
@@ -2008,6 +2053,7 @@ Ek ayrıntılar:
<translation id="9183302530794969518">Google Dokümanlar</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> desteklenmeyen bir protokol kullanıyor.</translation>
<translation id="9191834167571392248">Sol altta delik</translation>
+<translation id="9199905725844810519">Yazdırma engellendi</translation>
<translation id="9205078245616868884">Verileriniz senkronizasyon parolanızla şifrelendi. Senkronizasyonu başlatmak için senkronizasyon parolanızı girin.</translation>
<translation id="9207861905230894330">Makale eklenemedi.</translation>
<translation id="9213433120051936369">Görünümü özelleştir</translation>
@@ -2018,8 +2064,10 @@ Ek ayrıntılar:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google Hesabınıza erişimi kaybedebilirsiniz. Chromium, şifrenizi hemen değiştirmenizi önerir. Oturum açmanız istenecektir.</translation>
<translation id="939736085109172342">Yeni klasör</translation>
+<translation id="945522503751344254">Geri bildirim gönder</translation>
<translation id="945855313015696284">Aşağıdaki bilgileri kontrol edin ve geçersiz kartları silin</translation>
<translation id="950736567201356821">Üstte üçlü delik</translation>
+<translation id="951941430552851965">Ekran görüntüsü alma, ekranınızdaki içerik nedeniyle yöneticiniz tarafından duraklatıldı.</translation>
<translation id="961663415146723894">Alttan bağlı</translation>
<translation id="962484866189421427">Bu içerik başka bir şeyi taklit eden aldatıcı uygulamalar yükleyebilir veya sizi izlemek için kullanılabilecek veriler toplayabilir. <ph name="BEGIN_LINK" />Yine de göster<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Resmi Derleme</translation>
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index b9fe654bf7e..ebb7345cf0c 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ви ввели пароль на Ñайті, Ñким не керує ваша організаціÑ. Щоб захиÑтити Ñвій обліковий запиÑ, не викориÑтовуйте цей пароль Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¸Ñ… додатків Ñ– Ñайтів.</translation>
<translation id="1263231323834454256">СпиÑок читаннÑ</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Дії, Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñкі не залишитьÑÑ Ð½Ð° приÑтрої:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñторінки, переглÑнуті в цьому вікні;
+ <ph name="LIST_ITEM" />файли cookie та дані Ñайтів;
+ <ph name="LIST_ITEM" />дані облікового запиÑу (<ph name="LINK_BEGIN" />вийти<ph name="LINK_END" />).
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">СпоÑіб отриманнÑ</translation>
<translation id="1281476433249504884">Ðакопичувач 1</translation>
<translation id="1285320974508926690">Ðіколи не перекладати цей Ñайт</translation>
@@ -283,6 +291,7 @@
<translation id="204357726431741734">Увійдіть, щоб кориÑтуватиÑÑ Ð¿Ð°Ñ€Ð¾Ð»Ñми, збереженими в обліковому запиÑÑ– Google</translation>
<translation id="2053111141626950936">Сторінки цією мовою (<ph name="LANGUAGE" />) не перекладатимутьÑÑ.</translation>
<translation id="2053553514270667976">Поштовий індекÑ</translation>
+<translation id="2054665754582400095">Дані про те, чи ви приÑутні</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 пропозиціÑ}one{# пропозиціÑ}few{# пропозиції}many{# пропозицій}other{# пропозиції}}</translation>
<translation id="2079545284768500474">Відмінити</translation>
<translation id="20817612488360358">СиÑтемні параметри прокÑÑ–-Ñервера налаштовано Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтаннÑ, але чітко вказано Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–-Ñервера.</translation>
@@ -296,6 +305,7 @@
<translation id="2102495993840063010">Додатки Android</translation>
<translation id="2107021941795971877">Підтримка друку</translation>
<translation id="2108755909498034140">Перезавантажте комп’ютер</translation>
+<translation id="2111166930115883695">Щоб почати гру, натиÑніть пробіл</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Картка</translation>
<translation id="2114841414352855701">Правило ігноруєтьÑÑ, оÑкільки його замінено правилом <ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@
<translation id="214556005048008348">СкаÑувати оплату</translation>
<translation id="2147827593068025794">Фонова ÑинхронізаціÑ</translation>
<translation id="2148613324460538318">Додати картку</translation>
+<translation id="2149968176347646218">З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð½ÐµÐ½Ð°Ð´Ñ–Ð¹Ð½Ðµ</translation>
<translation id="2154054054215849342">Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð½ÐµÐ´Ð¾Ñтупна Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ домену</translation>
<translation id="2154484045852737596">Редагувати картку</translation>
<translation id="2161656808144014275">ТекÑÑ‚</translation>
@@ -317,7 +328,6 @@
<translation id="2181821976797666341">Правила</translation>
<translation id="2183608646556468874">Ðомер телефону</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 адреÑа}one{# адреÑа}few{# адреÑи}many{# адреÑ}other{# адреÑи}}</translation>
-<translation id="2187243482123994665">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ приÑутніÑÑ‚ÑŒ</translation>
<translation id="2187317261103489799">Визначати (за умовчаннÑм)</translation>
<translation id="2188375229972301266">Пробити кілька отворів унизу</translation>
<translation id="2202020181578195191">Введіть дійÑний рік Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
@@ -468,6 +478,7 @@
<translation id="2839501879576190149">Ви переходите на фальшивий Ñайт</translation>
<translation id="2850739647070081192">Invite (конверт)</translation>
<translation id="2856444702002559011">ЗловмиÑники можуть намагатиÑÑ Ð²Ð¸ÐºÑ€Ð°Ñти вашу інформацію із Ñайту <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (наприклад, паролі, Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‡Ð¸ дані кредитних карток). <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Цей Ñайт показує нав’Ñзливі чи оманливі оголошеннÑ.</translation>
<translation id="2878197950673342043">Зігнути за типом плаката</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ð Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–ÐºÐ¾Ð½</translation>
@@ -506,11 +517,11 @@
<translation id="2996674880327704673">Пропозиції від Google</translation>
<translation id="3002501248619246229">Перевірте лоток Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¼ÐµÐ´Ñ–Ð°</translation>
<translation id="3005723025932146533">Показати збережену копію</translation>
-<translation id="3007719053326478567">ÐдмініÑтратор заблокував можливіÑÑ‚ÑŒ друкувати цей контент</translation>
<translation id="3008447029300691911">Введіть код CVC картки <ph name="CREDIT_CARD" />. Щойно ви підтвердите дані картки, цей Ñайт отримає доÑтуп до них.</translation>
<translation id="3010559122411665027">Елемент ÑпиÑку "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">БлокуєтьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾</translation>
<translation id="3016780570757425217">Бачити ваше міÑцезнаходженнÑ</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />; натиÑніть Tab, а потім – Enter, щоб видалити підказку.</translation>
<translation id="3023071826883856138">You4 (конверт)</translation>
<translation id="3024663005179499861">Ðеправильний тип правила</translation>
<translation id="3037605927509011580">От халепа!</translation>
@@ -539,7 +550,7 @@
<translation id="3157931365184549694">Відновити</translation>
<translation id="3162559335345991374">Можливо, щоб під’єднатиÑÑ Ð´Ð¾ цієї мережі Wi-Fi, потрібно відвідати Ñ—Ñ— Ñторінку входу.</translation>
<translation id="3167968892399408617">Сторінки, Ñкі ви переглÑдаєте на анонімних вкладках, не реєÑтруютьÑÑ Ð² Ñ–Ñторії веб-переглÑдача чи Ñ–Ñторії пошуку та не залишають файлів cookie, коли ви закриваєте вÑÑ– анонімні вкладки. УÑÑ– завантажені файли чи Ñтворені закладки зберігаютьÑÑ.</translation>
-<translation id="3169472444629675720">Discover</translation>
+<translation id="3169472444629675720">Рекомендації</translation>
<translation id="3174168572213147020">ОÑтрів</translation>
<translation id="3176929007561373547">Перевірте Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñвого прокÑÑ–-Ñервера чи звернітьÑÑ Ð´Ð¾ адмініÑтратора мережі,
щоб переконатиÑÑ, що прокÑÑ–-Ñервер працює. Якщо ви вважаєте, що не потрібно
@@ -553,6 +564,7 @@
<translation id="3207960819495026254">Створено закладку</translation>
<translation id="3209034400446768650">Ðа Ñторінці може ÑÑ‚ÑгуватиÑÑ Ð¿Ð»Ð°Ñ‚Ð°</translation>
<translation id="3212581601480735796">Ваші дії на Ñайті <ph name="HOSTNAME" /> відÑтежуютьÑÑ</translation>
+<translation id="3212623355668894776">Закрийте вÑÑ– вікна в режимі гоÑÑ‚Ñ, щоб видалити Ñ–Ñторію дій у веб-переглÑдачі з приÑтрою.</translation>
<translation id="3215092763954878852">Ðе вдалоÑÑ ÑкориÑтатиÑÑ Ð²ÐµÐ±-автентифікацією</translation>
<translation id="3218181027817787318">ВідноÑна</translation>
<translation id="3225919329040284222">Сервер надав Ñертифікат, Ñкий не відповідає очікуваним вбудованим параметрам. Ці очікувані параметри вÑтановлено Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… веб-Ñайтів із виÑоким рівнем безпеки, щоб захиÑтити ваÑ.</translation>
@@ -700,6 +712,7 @@
<translation id="3784372983762739446">ПриÑтрої Bluetooth</translation>
<translation id="3787705759683870569">Діє до <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Розмір 16</translation>
+<translation id="3789841737615482174">УÑтановити</translation>
<translation id="3793574014653384240">КількіÑÑ‚ÑŒ Ñ– причини оÑтанніх аварійних завершень роботи</translation>
<translation id="3797522431967816232">Prc3 (конверт)</translation>
<translation id="3799805948399000906">Запит на шрифт</translation>
@@ -751,6 +764,7 @@
<translation id="4056223980640387499">СепіÑ</translation>
<translation id="4058922952496707368">Ключ "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (конверт)</translation>
+<translation id="4067669230157909013">Зйомку екрана відновлено.</translation>
<translation id="4067947977115446013">Додайте дійÑну адреÑу</translation>
<translation id="4072486802667267160">Ðе вдалоÑÑŒ обробити ваше замовленнÑ. Повторіть Ñпробу.</translation>
<translation id="4075732493274867456">Клієнт Ñ– Ñервер підтримують різні верÑÑ–Ñ— протоколу SSL або набору шифрів.</translation>
@@ -835,6 +849,7 @@
<translation id="4297502707443874121">ЕÑкіз Ð´Ð»Ñ Ñторінки <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Розгорнути</translation>
<translation id="4300675098767811073">Пробити кілька отворів праворуч</translation>
+<translation id="4302514097724775343">Щоб почати гру, торкнітьÑÑ Ð´Ð¸Ð½Ð¾Ð·Ð°Ð²Ñ€Ð°</translation>
<translation id="4302965934281694568">Chou3 (конверт)</translation>
<translation id="4305666528087210886">Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ доÑтуп до файлу</translation>
<translation id="4305817255990598646">Перейти</translation>
@@ -913,6 +928,7 @@
<translation id="4658638640878098064">Скріпити вгорі ліворуч</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Віртуальна реальніÑÑ‚ÑŒ</translation>
+<translation id="4675657451653251260">У режимі гоÑÑ‚Ñ Ð²Ð¸ не зможете переглÑдати інформацію в профілÑÑ… Chrome. Ви можете <ph name="LINK_BEGIN" />ввійти<ph name="LINK_END" />, щоб отримати доÑтуп до даних в обліковому запиÑÑ– Google (Ñк-от паролі чи ÑпоÑоби оплати).</translation>
<translation id="467662567472608290">Цей Ñервер не зміг довеÑти, що він – домен <ph name="DOMAIN" />. Його Ñертифікат безпеки міÑтить помилки. Імовірні причини: неправильна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð°Ð±Ð¾ хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ.</translation>
<translation id="4677585247300749148">Сайт <ph name="URL" /> хоче реагувати на викориÑÑ‚Ð°Ð½Ð½Ñ Ñпеціальних можливоÑтей</translation>
<translation id="467809019005607715">Google Презентації</translation>
@@ -940,6 +956,12 @@
<translation id="4761104368405085019">ВикориÑтовувати ваш мікрофон</translation>
<translation id="4764776831041365478">Веб-Ñторінка за адреÑою <ph name="URL" /> може бути тимчаÑово недоÑтупною або Ñ—Ñ— назавжди переміщено на нову веб-адреÑу.</translation>
<translation id="4766713847338118463">Двічі Ñкріпити внизу</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Дії, Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñкі залишитьÑÑ Ð½Ð° приÑтрої:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />файли, Ñкі ви завантажуєте в цьому вікні.
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Виникла невідома помилка.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Спливаюче вікно заблоковано}one{# Ñпливаюче вікно заблоковано}few{# Ñпливаючі вікна заблоковано}many{# Ñпливаючих вікон заблоковано}other{# Ñпливаючого вікна заблоковано}}</translation>
<translation id="4780366598804516005">Поштова Ñкринька 1</translation>
@@ -1102,11 +1124,13 @@
<translation id="5386426401304769735">Ланцюжок Ñертифіката цього Ñайту міÑтить Ñертифікат, підпиÑаний за допомогою SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Зшити вздовж правого краю</translation>
+<translation id="5398772614898833570">ÐžÐ³Ð¾Ð»Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾</translation>
<translation id="5400836586163650660">Сірий</translation>
<translation id="540969355065856584">Серверу не вдалоÑÑ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸, що це <ph name="DOMAIN" />. Його Ñертифікат безпеки зараз недійÑний. Можливі причини: неправильна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð°Ð±Ð¾ хтоÑÑŒ перехопив ваше з’єднаннÑ.</translation>
<translation id="541416427766103491">Ðакопичувач 4</translation>
<translation id="5421136146218899937">ОчиÑтити Ñ–Ñторію…</translation>
<translation id="5426179911063097041">Сайт <ph name="SITE" /> хоче надÑилати вам ÑповіщеннÑ</translation>
+<translation id="542872847390508405">Ви переглÑдаєте в гоÑтьовому режимі</translation>
<translation id="5430298929874300616">Видалити закладку</translation>
<translation id="5439770059721715174">Помилка перевірки Ñхеми за адреÑою "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Зворотний порÑдок лицевою Ñтороною вгору</translation>
@@ -1148,12 +1172,12 @@
<translation id="5571083550517324815">ÐдреÑа Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
<translation id="5580958916614886209">Перевірте міÑÑць Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії та повторіть Ñпробу</translation>
<translation id="5586446728396275693">Ðемає збережених адреÑ</translation>
+<translation id="5593349413089863479">З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð½Ðµ повніÑÑ‚ÑŽ захищене</translation>
<translation id="5595485650161345191">Редагувати адреÑу</translation>
<translation id="5598944008576757369">Вибрати ÑпоÑіб оплати</translation>
<translation id="560412284261940334">ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Цей Ñайт може бути підробленим або шахрайÑьким. Chrome радить залишити його.</translation>
<translation id="5610142619324316209">перевірити наÑвніÑÑ‚ÑŒ з’єднаннÑ</translation>
<translation id="5610807607761827392">Ви можете керувати картками й адреÑами в <ph name="BEGIN_LINK" />ÐалаштуваннÑÑ…<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">ПереклаÑти цю Ñторінку за допомогою Google Перекладача</translation>
@@ -1225,6 +1249,7 @@
<translation id="5901630391730855834">Жовтий</translation>
<translation id="5905445707201418379">Заблоковано відповідно до правила джерела <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (Ñинхронізовано)</translation>
+<translation id="5913377024445952699">Зйомку екрана призупинено</translation>
<translation id="59174027418879706">Увімкнено</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Увімкнено</translation>
@@ -1237,6 +1262,7 @@
<translation id="5963413905009737549">Розділ</translation>
<translation id="5967592137238574583">Змініть контактну інформацію</translation>
<translation id="5967867314010545767">Видалити з Ñ–Ñторії</translation>
+<translation id="5968793460449681917">Щоразу</translation>
<translation id="5975083100439434680">Зменшити маÑштаб</translation>
<translation id="5979084224081478209">Перевірити паролі</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1392,6 +1418,7 @@
<translation id="6587923378399804057">Скопійоване поÑиланнÑ</translation>
<translation id="6591833882275308647">ПриÑтроєм <ph name="DEVICE_TYPE" /> не керує адмініÑтратор</translation>
<translation id="6596325263575161958">Параметри шифруваннÑ</translation>
+<translation id="6596892391065203054">ÐдмініÑтратор заблокував можливіÑÑ‚ÑŒ друкувати цей контент.</translation>
<translation id="6604181099783169992">Датчики руху чи Ñвітла</translation>
<translation id="6609880536175561541">Prc7 (конверт)</translation>
<translation id="6612358246767739896">Захищений вміÑÑ‚</translation>
@@ -1451,6 +1478,7 @@
<translation id="6895330447102777224">Дані картки підтверджено</translation>
<translation id="6897140037006041989">Ðгент кориÑтувача</translation>
<translation id="6898699227549475383">ÐžÑ€Ð³Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ (О)</translation>
+<translation id="6907293445143367439">Дозволити Ñайту <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763">Сайт <ph name="URL" /> хоче повніÑÑ‚ÑŽ контролювати ваші приÑтрої MIDI</translation>
<translation id="6915804003454593391">КориÑтувач:</translation>
<translation id="6934672428414710184">Це Ñ–Ð¼â€™Ñ Ð· вашого облікового запиÑу Google</translation>
@@ -1562,6 +1590,7 @@
<translation id="7346048084945669753">Зв'Ñзано:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Командний Ñ€Ñдок</translation>
+<translation id="7359588939039777303">ÐžÐ³Ð¾Ð»Ð¾ÑˆÐµÐ½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾.</translation>
<translation id="7372973238305370288">результат пошуку</translation>
<translation id="7374733840632556089">Ð¦Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð° виникла через Ñертифікат, Ñкий уÑтановили ви або інший кориÑтувач на приÑтрої. Цей Ñертифікат відÑтежує й перехоплює мережу. Chrome не вважає його надійним. Хоча Ñ–Ñнують законні випадки відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ (наприклад, у мережі навчального закладу або компанії), Chrome хоче переконатиÑÑ, що ви знаєте про ці дії, навіть Ñкщо не можете Ñ—Ñ… зупинити. ВідÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¶Ðµ відбуватиÑÑ Ð² будь-Ñкому веб-переглÑдачі або додатку з доÑтупом до Інтернету.</translation>
<translation id="7375818412732305729">Долучено файл</translation>
@@ -1736,6 +1765,7 @@
<translation id="7976214039405368314">Забагато запитів</translation>
<translation id="7977538094055660992">ПриÑтрій виведеннÑ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Щоб переглÑдати вміÑÑ‚ у режимі доповненої реальноÑÑ‚Ñ–, уÑтановіть ARCore</translation>
<translation id="799149739215780103">Зшити</translation>
<translation id="7995512525968007366">Ðе вказано</translation>
<translation id="800218591365569300">Щоб звільнити пам’ÑÑ‚ÑŒ, закрийте інші вкладки та програми.</translation>
@@ -1863,25 +1893,39 @@
<translation id="8507227106804027148">Командний Ñ€Ñдок</translation>
<translation id="8508648098325802031">Значок пошуку</translation>
<translation id="8522552481199248698">Chrome допоможе захиÑтити обліковий Ð·Ð°Ð¿Ð¸Ñ Google Ñ– змінити пароль.</translation>
+<translation id="8525306231823319788">Ðа веÑÑŒ екран</translation>
<translation id="8530813470445476232">ОчиÑтити Ñ–Ñторію веб-переглÑду, файли cookie, кеш та інше в налаштуваннÑÑ… Chrome</translation>
<translation id="8533619373899488139">Перейдіть на Ñторінку &lt;strong&gt;chrome://policy&lt;/strong&gt;, щоб переглÑнути ÑпиÑок заблокованих URL-Ð°Ð´Ñ€ÐµÑ Ñ‚Ð° інші правила, Ñкі ввімкнув ваш ÑиÑтемний адмініÑтратор.</translation>
<translation id="8541158209346794904">ПриÑтрій Bluetooth</translation>
<translation id="8542014550340843547">Тричі Ñкріпити внизу</translation>
<translation id="8543181531796978784">Ви можете <ph name="BEGIN_ERROR_LINK" />повідомити про проблему з пошуком<ph name="END_ERROR_LINK" /> або <ph name="BEGIN_LINK" />перейти на цей незахищений Ñайт<ph name="END_LINK" /> (Ñкщо розумієте, наÑкільки це небезпечно).</translation>
<translation id="8557066899867184262">Код CVC розташований на зворотному боці картки.</translation>
+<translation id="8558485628462305855">Щоб переглÑдати вміÑÑ‚ у режимі доповненої реальноÑÑ‚Ñ–, оновіть ARCore</translation>
<translation id="8559762987265718583">Ðе вдаєтьÑÑ Ð²Ñтановити конфіденційне Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, оÑкільки на приÑтрої вÑтановлено неправильні дату й Ñ‡Ð°Ñ (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Окремі документи/непідібрані копії</translation>
<translation id="8564985650692024650">Chromium радить Ñкинути пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Ñкщо ви заÑтоÑовували його на інших Ñайтах.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Дії, Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñкі не залишитьÑÑ Ð½Ð° приÑтрої:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñторінки, переглÑнуті в цьому вікні;
+ <ph name="LIST_ITEM" />файли cookie та дані Ñайтів.
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">ВикориÑтовувати Touch ID, щоб швидше підтверджувати картки</translation>
<translation id="858637041960032120">Додати тел.номер
</translation>
<translation id="8589998999637048520">Ðайкраща ÑкіÑÑ‚ÑŒ</translation>
+<translation id="8600271352425265729">Лише цього разу</translation>
<translation id="860043288473659153">Ð†Ð¼â€™Ñ Ñ‚Ð° прізвище влаÑника картки</translation>
<translation id="8606726445206553943">ВикориÑтовувати ваші приÑтрої MIDI</translation>
+<translation id="8612761427948161954">Вітаємо, <ph name="USERNAME" />!
+ <ph name="BR" />
+ Ви переглÑдаєте в гоÑтьовому режимі</translation>
<translation id="861775596732816396">Розмір 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Пароль Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñайту не знайдено. Показати вÑÑ– збережені паролі.</translation>
<translation id="8625384913736129811">Зберегти цю картку на приÑтрої</translation>
+<translation id="8627040765059109009">Зйомку екрана відновлено</translation>
<translation id="8657078576661269990">ÐдмініÑтратор заблокував можливіÑÑ‚ÑŒ надавати машинам <ph name="VM_NAME_1" /> Ñ– <ph name="VM_NAME_2" /> доÑтуп до контенту із Ñайту <ph name="ORIGIN_NAME" /></translation>
<translation id="8663226718884576429">ПідÑумок замовленнÑ, <ph name="TOTAL_LABEL" />, докладніше</translation>
<translation id="867224526087042813">ПідпиÑ</translation>
@@ -1944,6 +1988,7 @@
<translation id="8912362522468806198">Обліковий Ð·Ð°Ð¿Ð¸Ñ Google</translation>
<translation id="8913778647360618320">Кнопка "Керувати ÑпоÑобами оплати"; натиÑніть Enter, щоб керувати платежами й даними кредитної картки в налаштуваннÑÑ… Chrome</translation>
<translation id="8918231688545606538">Ð¦Ñ Ñторінка підозріла</translation>
+<translation id="8922013791253848639">Завжди дозволÑти показ реклами на цьому Ñайті</translation>
<translation id="892588693504540538">Пробити отвір угорі праворуч</translation>
<translation id="8931333241327730545">Зберегти цю картку у вашому обліковому запиÑÑ– Google?</translation>
<translation id="8932102934695377596">Ваш годинник запізнюєтьÑÑ</translation>
@@ -2015,6 +2060,7 @@
<translation id="9183302530794969518">Google Документи</translation>
<translation id="9183425211371246419">Протокол, Ñкий викориÑтовує хоÑÑ‚ <ph name="HOST_NAME" />, не підтримуєтьÑÑ.</translation>
<translation id="9191834167571392248">Пробити отвір унизу ліворуч</translation>
+<translation id="9199905725844810519">Друк заблоковано</translation>
<translation id="9205078245616868884">Ваші дані зашифровано за допомогою парольної фрази. Введіть Ñ—Ñ—, щоб почати Ñинхронізацію.</translation>
<translation id="9207861905230894330">Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ Ñтаттю.</translation>
<translation id="9213433120051936369">Ðалаштувати оформленнÑ</translation>
@@ -2025,8 +2071,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Ви можете втратити доÑтуп до облікового запиÑу Google. Chromium радить змінити пароль. Вам буде запропоновано ввійти в обліковий запиÑ.</translation>
<translation id="939736085109172342">Ðова папка</translation>
+<translation id="945522503751344254">ÐадіÑлати відгук</translation>
<translation id="945855313015696284">Перевірте дані нижче й видаліть недійÑні картки.</translation>
<translation id="950736567201356821">Пробити три отвори вгорі</translation>
+<translation id="951941430552851965">ÐдмініÑтратор призупинив зйомку екрана через характер контенту.</translation>
<translation id="961663415146723894">Зшити внизу</translation>
<translation id="962484866189421427">Ð¦Ñ Ñторінка може намагатиÑÑ Ð²Ñтановлювати оманливі додатки, Ñкі видають Ñебе за інший вміÑÑ‚, або збирати дані Ð´Ð»Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð²Ð°ÑˆÐ¸Ñ… дій. <ph name="BEGIN_LINK" />УÑе одно показати<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Розробка</translation>
diff --git a/chromium/components/strings/components_strings_ur.xtb b/chromium/components/strings/components_strings_ur.xtb
index eed93c9ed85..a96edb999df 100644
--- a/chromium/components/strings/components_strings_ur.xtb
+++ b/chromium/components/strings/components_strings_ur.xtb
@@ -29,7 +29,7 @@
<translation id="1080116354587839789">چوڑائی میں ÙÙ¹ کریں</translation>
<translation id="1086953900555227778">Index-5x8</translation>
<translation id="1088860948719068836">کارڈ پر نام شامل کریں</translation>
-<translation id="1089439967362294234">پاسورڈ تبدیل کریں</translation>
+<translation id="1089439967362294234">پاس ورڈ تبدیل کریں</translation>
<translation id="1096545575934602868">اس Ùیلڈ میں <ph name="MAX_ITEMS_LIMIT" /> سے Ø²ÛŒØ§Ø¯Û Ø§Ù†Ø¯Ø±Ø§Ø¬Ø§Øª Ù†Ûیں Ûونے چاÛئیں۔ سبھی مزید اندراجات مسترد کر دیے جائیں Ú¯Û’Û”</translation>
<translation id="1101672080107056897">خرابی کی کارروائی</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> Ú©Ùˆ ÛÙ…ÛŒØ´Û ØªØ±Ø¬Ù…Û Ú©Ø±ÛŒÚº</translation>
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">آپ Ù†Û’ اپنا پاس ورڈ ایک ایسی سائٹ پر درج کیا ÛÛ’ جو آپ Ú©ÛŒ تنظیم Ú©Û’ زیر انتظام Ù†Ûیں ÛÛ’Û” اپنے اکاؤنٹ Ú©Û’ تحÙظ Ú©Û’ لیے، دیگر ایپس اور سائٹس پر اپنا پاس ورڈ Ø¯ÙˆØ¨Ø§Ø±Û Ø§Ø³ØªØ¹Ù…Ø§Ù„ Ù†Û Ú©Ø±ÛŒÚºÛ”</translation>
<translation id="1263231323834454256">Ù¾Ú‘Ú¾Ù†Û’ Ú©ÛŒ ÙÛرست</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ ÙˆÛ Ø³Ø±Ú¯Ø±Ù…ÛŒ جو اس آلے پر برقرار Ù†Ûیں رÛÛ’ Ú¯ÛŒ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÙˆÛ ØµÙحات جنÛیں آپ اس ونڈو میں Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ØªÛ’ Ûیں
+ <ph name="LIST_ITEM" />کوکیز اور سائٹ کا ڈیٹا
+ <ph name="LIST_ITEM" />اکاؤنٹ کی معلومات (<ph name="LINK_BEGIN" />سائن آؤٹ کریں<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Ù¾ÙÚ© اپ کا طریقÛ</translation>
<translation id="1281476433249504884">اسٹیکر 1</translation>
<translation id="1285320974508926690">اس سائٹ کا ØªØ±Ø¬Ù…Û Ú©Ø¨Ú¾ÛŒ Ù†Û Ú©Ø±ÛŒÚº</translation>
@@ -284,6 +292,7 @@
<translation id="204357726431741734">â€Ø§Ù¾Ù†Û’ Google اکاؤنٹ میں محÙوظ Ú©Ø±Ø¯Û Ù¾Ø§Ø³ ورڈز کا استعمال کرنے Ú©Û’ لئے سائن ان کریں</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> Ú©Û’ صÙحات کا ØªØ±Ø¬Ù…Û Ù†Ûیں کیا جائے گا۔</translation>
<translation id="2053553514270667976">زپ کوڈ</translation>
+<translation id="2054665754582400095">آپ کی موجودگی</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 تجویز}other{# تجاویز}}</translation>
<translation id="2079545284768500474">کالعدم کریں</translation>
<translation id="20817612488360358">سسٹم پراکسی Ú©ÛŒ ترتیبات استعمال کیے جانے کیلئے سیٹ Ûیں لیکن ایک واضح پراکسی Ú©Ù†Ùیگریشن بھی متعین Ú©ÛŒ گئی ÛÛ’Û”</translation>
@@ -297,6 +306,7 @@
<translation id="2102495993840063010">â€Android ایپس</translation>
<translation id="2107021941795971877">پرنٹ سپورٹس</translation>
<translation id="2108755909498034140">اپنے کمپیوٹر Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کریں</translation>
+<translation id="2111166930115883695">کھیلنے کے لیے اسپیس دبائیں</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">کارڈ</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> Ú©ÛŒ جانب سے اسے اوور رائڈ کیے جانے Ú©ÛŒ ÙˆØ¬Û Ø³Û’ نظر انداز کر دیا گیا۔</translation>
@@ -308,6 +318,7 @@
<translation id="214556005048008348">ادائیگی منسوخ کریں</translation>
<translation id="2147827593068025794">پس منظر کی مطابقت پذیری</translation>
<translation id="2148613324460538318">کارڈ شامل کریں</translation>
+<translation id="2149968176347646218">کنکشن محÙوظ Ù†Ûیں ÛÛ’</translation>
<translation id="2154054054215849342">مطابقت پذیری آپ Ú©Û’ ڈومین کیلئے دستیاب Ù†Ûیں ÛÛ’</translation>
<translation id="2154484045852737596">کارڈ میں ترمیم کریں</translation>
<translation id="2161656808144014275">متن</translation>
@@ -318,7 +329,6 @@
<translation id="2181821976797666341">پالیسیاں</translation>
<translation id="2183608646556468874">Ùون نمبر</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 پتÛ}other{# پتے}}</translation>
-<translation id="2187243482123994665">صار٠کی موجودگی</translation>
<translation id="2187317261103489799">پتا لگائیں (ÚˆÛŒÙالٹ)</translation>
<translation id="2188375229972301266">نیچے متعدد سوراخ</translation>
<translation id="2202020181578195191">ایک درست سال٠اختتام درج کریں</translation>
@@ -472,6 +482,7 @@
<translation id="2839501879576190149">آگے جعلی سائٹ ÛÛ’</translation>
<translation id="2850739647070081192">Invite ‎(Envelope‎)‎</translation>
<translation id="2856444702002559011">Ø­Ù…Ù„Û Ø¢ÙˆØ± <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> سے آپ Ú©ÛŒ معلومات (مثلاً، پاس ورڈز، پیغامات یا کریڈٹ کارڈز) چوری کرنے Ú©ÛŒ کوشش کر سکتے Ûیں۔ <ph name="BEGIN_LEARN_MORE_LINK" />مزید جانیں<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">ÛŒÛ Ø³Ø§Ø¦Ù¹ دخل انداز یا Ú¯Ù…Ø±Ø§Û Ú©Ù† اشتÛارات دکھاتی ÛÛ’Û”</translation>
<translation id="2878197950673342043">پوسٹر جیسے Ùولڈ</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">ونڈو کا مقام</translation>
@@ -510,11 +521,11 @@
<translation id="2996674880327704673">â€Google Ú©ÛŒ تجاویز</translation>
<translation id="3002501248619246229">ان پٹ ٹرے میڈیا چیک کریں</translation>
<translation id="3005723025932146533">محÙوظ Ú©Ø±Ø¯Û Ú©Ø§Ù¾ÛŒ دکھائیں</translation>
-<translation id="3007719053326478567">آپ Ú©Û’ منتظم Ú©ÛŒ طر٠سے اس مواد Ú©ÛŒ پرنٹنگ مسدود ÛÛ’</translation>
<translation id="3008447029300691911">â€<ph name="CREDIT_CARD" /> کیلئے CVC درج کریں۔ آپ Ú©Û’ توثیق کرنے Ú©Û’ بعد، اس سائٹ Ú©Û’ ساتھ آپ Ú©Û’ کارڈ Ú©ÛŒ تÙصیلات کا اشتراک کیا جائے گا۔</translation>
<translation id="3010559122411665027">ÙÛرست کا اندراج "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">خود کار طور پر مسدود ÛÙˆ گيا</translation>
<translation id="3016780570757425217">اپنا مقام جانیں</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />ØŒ تجویز Ûٹانے Ú©Û’ لیے ٹیب، پھر اینٹر دبائیں۔</translation>
<translation id="3023071826883856138">You4 ‎(Envelope‎)‎</translation>
<translation id="3024663005179499861">پالیسی کی غلط قسم</translation>
<translation id="3037605927509011580">ارے، رکیں!</translation>
@@ -558,6 +569,7 @@
<translation id="3207960819495026254">بÙÚ© مارک بنایا Ûوا</translation>
<translation id="3209034400446768650">صÙØ­Û Ù¾ÛŒØ³Û’ چارج کر سکتا ÛÛ’</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> پر آپ Ú©ÛŒ سرگرمی پر نظر رکھی جا رÛÛŒ ÛÛ’</translation>
+<translation id="3212623355668894776">سبھی Ù…Ûمان ونڈوز Ú©Ùˆ بند کریں ØªØ§Ú©Û Ø§Ù“Ù¾ Ú©ÛŒ براؤزنگ Ú©ÛŒ سرگرمی اس آلے سے حذ٠ÛÙˆ جائے۔</translation>
<translation id="3215092763954878852">â€WebAuthn کا استعمال Ù†Ûیں کیا جا سکا</translation>
<translation id="3218181027817787318">متعلقÛ</translation>
<translation id="3225919329040284222">سرور Ù†Û’ ایک سرٹیÙکیٹ پیش کیا ÛÛ’ جو Ù¾ÛÙ„Û’ سے موجود توقعات سے مماثل Ù†Ûیں ÛÛ’Û” آپ Ú©Û’ تحÙظ کیلئے ÛŒÛ ØªÙˆÙ‚Ø¹Ø§Øª مخصوص، انتÛائی سیکیورٹی والی ویب سائٹس کیلئے شامل Ú©ÛŒ جاتی Ûیں۔</translation>
@@ -705,6 +717,7 @@
<translation id="3784372983762739446">بلوٹوتھ آلات</translation>
<translation id="3787705759683870569"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /> Ú©Ùˆ میعاد ختم ÛÙˆ رÛÛŒ ÛÛ’</translation>
<translation id="3789155188480882154">سائز 16</translation>
+<translation id="3789841737615482174">انسٹال کریں</translation>
<translation id="3793574014653384240">حال ÛÛŒ میں Ûونے والے کریشز Ú©ÛŒ تعداد اور اسباب</translation>
<translation id="3797522431967816232">Prc3 ‎(Envelope‎)‎</translation>
<translation id="3799805948399000906">Ùونٹ Ú©ÛŒ درخواست Ú©ÛŒ گئی</translation>
@@ -756,6 +769,7 @@
<translation id="4056223980640387499">سیپیا</translation>
<translation id="4058922952496707368">کلید "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 ‎(Envelope‎)‎</translation>
+<translation id="4067669230157909013">اسکرین کیپچر Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کر دیا گیا۔</translation>
<translation id="4067947977115446013">درست Ù¾ØªÛ Ø´Ø§Ù…Ù„ کریں</translation>
<translation id="4072486802667267160">آپ Ú©Û’ آرڈر پر کارروائی کرنے میں ایک خرابی پیش آگئی۔ Ø¨Ø±Ø§Û Ú©Ø±Ù… Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں۔</translation>
<translation id="4075732493274867456">â€Ú©Ù„ائنٹ اور سرور عام SSL پروٹوکول ورژن یا سائÙر سوئٹ کا تعاون Ù†Ûیں کرتے Ûیں۔</translation>
@@ -840,6 +854,7 @@
<translation id="4297502707443874121"><ph name="THUMBNAIL_PAGE" /> صÙØ­Û Ú©Ø§ تھمب نیل</translation>
<translation id="42981349822642051">پھیلائیں</translation>
<translation id="4300675098767811073">دائیں طر٠متعدد سوراخ</translation>
+<translation id="4302514097724775343">کھیلنے کے لیے ڈائنوسار گیم کھیلنے پر تھپتھپائیں</translation>
<translation id="4302965934281694568">Chou3 ‎(Envelope‎)‎</translation>
<translation id="4305666528087210886">آپ Ú©ÛŒ Ùائل تک رسائی Ù†Ûیں ÛÙˆ سکی</translation>
<translation id="4305817255990598646">سوئچ کریں</translation>
@@ -918,6 +933,7 @@
<translation id="4658638640878098064">اوپر بائیں طر٠سٹیپل</translation>
<translation id="4668929960204016307">،</translation>
<translation id="4670064810192446073">ورچوئل رئیلٹی</translation>
+<translation id="4675657451653251260">â€Ø¢Ù¾ Ú©Ùˆ Ù…Ûمان وضع میں Chrome پروÙائل Ú©ÛŒ کوئی بھی معلومات نظر Ù†Ûیں آئے گی۔ پاس ورڈز اور ادائیگی Ú©Û’ طریقوں جیسی اپنے Google اکاؤنٹ Ú©ÛŒ معلومات تک رسائی حاصل کرنے Ú©Û’ لیے آپ <ph name="LINK_BEGIN" />سائن ان<ph name="LINK_END" /> کر سکتے Ûیں۔</translation>
<translation id="467662567472608290">ÛŒÛ Ø³Ø±ÙˆØ± ÛŒÛ Ø«Ø§Ø¨Øª Ù†Ûیں کر سکا Ú©Û ÛŒÛ <ph name="DOMAIN" /> ÛÛ’Ø› اس Ú©Û’ سیکیورٹی سرٹیÙکیٹ میں خرابیاں Ûیں۔ ÛŒÛ ØºÙ„Ø· Ú©Ù†Ùیگریشن یا آپ Ú©Û’ کنکشن Ú©Ùˆ قطع کرنے والے کسی Ø­Ù…Ù„Û Ø¢ÙˆØ± Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="4677585247300749148"><ph name="URL" /> ایکسیسبیلٹی Ú©Û’ ایونٹس کا جواب دینا چاÛتا ÛÛ’</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -945,6 +961,12 @@
<translation id="4761104368405085019">اپنا مائیکروÙون استعمال کریں</translation>
<translation id="4764776831041365478"><ph name="URL" /> پر موجود ویب صÙØ­Û Ø¹Ø§Ø±Ø¶ÛŒ طور پر سست ÛÙˆ سکتا ÛÛ’ یا اسے مستقل طور پر ایک نئے ویب پتے پر منتقل کیا گیا ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="4766713847338118463">نیچے دÙÛری سٹیپل</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ آپ Ú©ÛŒ سرگرمی جو اس آلے پر برقرار رÛÛ’ Ú¯ÛŒ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />کوئی بھی Ùائل جسے آپ اس ونڈو میں ڈاؤن لوڈ کرتے Ûیں
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">ایک نامعلوم خرابی پیش آگئی ÛÛ’Û”</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{پاپ اپ مسدود کر دیا گیا}other{# پاپ اپس مسدود کر دیے گئے}}</translation>
<translation id="4780366598804516005">میل باکس 1</translation>
@@ -1107,11 +1129,13 @@
<translation id="5386426401304769735">â€Ø§Ø³ سائٹ کیلئے سرٹیÙکیٹ چین میں SHA-1 کا استعمال کر Ú©Û’ دستخط Ú©Ø±Ø¯Û Ø³Ø±Ù¹ÛŒÙکیٹ شامل ÛÛ’Û”</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">دائیں طر٠کنارے کی سلائی</translation>
+<translation id="5398772614898833570">اشتÛارات مسدود Ûیں</translation>
<translation id="5400836586163650660">خاکستری</translation>
<translation id="540969355065856584">ÛŒÛ Ø³Ø±ÙˆØ± ÛŒÛ Ø«Ø§Ø¨Øª Ù†Ûیں کر سکا Ú©Û ÛŒÛ <ph name="DOMAIN" /> ÛÛ’Ø› اس کا سیکیورٹی سرٹیÙکیٹ اس وقت درست Ù†Ûیں ÛÛ’Û” ÛŒÛ ØºÙ„Ø· Ú©Ù†Ùیگریشن یا آپ Ú©Û’ کنکشن میں مانع بن رÛÛ’ کسی Ø­Ù…Ù„Û Ø¢ÙˆØ± Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="541416427766103491">اسٹیکر 4</translation>
<translation id="5421136146218899937">براؤزنگ ڈیٹا صا٠کریں…</translation>
<translation id="5426179911063097041"><ph name="SITE" /> آپ Ú©Ùˆ اطلاعات بھیجنا چاÛتی ÛÛ’</translation>
+<translation id="542872847390508405">آپ ایک Ù…Ûمان Ú©Û’ بطور براؤز کر رÛÛ’ Ûیں</translation>
<translation id="5430298929874300616">بÙÚ© مارک Ú©Ùˆ Ûٹائیں</translation>
<translation id="5439770059721715174">"<ph name="ERROR_PATH" />" پر سکیما کی توثیق میں خرابی: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">اÙلٹ ترتیب میں، صÙحات کا رÙØ® اوپر Ú©ÛŒ جانب</translation>
@@ -1153,12 +1177,12 @@
<translation id="5571083550517324815">اس پتے سے Ù¾ÙÚ© اپ Ù†Ûیں کر سکتے۔ کوئی Ù…Ø®ØªÙ„Ù Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کریں۔</translation>
<translation id="5580958916614886209">اپنا اختتامی Ù…ÛÛŒÙ†Û Ú†ÛŒÚ© کریں اور Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں</translation>
<translation id="5586446728396275693">کوئي Ù¾ØªÛ Ù…Ø­Ùوظ Ù†Ûیں ÛÛ’</translation>
+<translation id="5593349413089863479">کنکشن مکمل طور پر محÙوظ Ù†Ûیں ÛÛ’</translation>
<translation id="5595485650161345191">پتے میں ترمیم کریں</translation>
<translation id="5598944008576757369">ادائیگی کا Ø·Ø±ÛŒÙ‚Û Ù…Ù†ØªØ®Ø¨ کریں</translation>
<translation id="560412284261940334">مینیجمنٹ تعاون یاÙØªÛ Ù†Ûیں ÛÛ’</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">â€ÛŒÛ سائٹ جعلی یا Ù¾Ùر Ùریب ÛÙˆ سکتی ÛÛ’Û” Chrome سائٹ ابھی Ú†Ú¾ÙˆÚ‘Ù†Û’ Ú©ÛŒ تجویز دیتا ÛÛ’Û”</translation>
<translation id="5610142619324316209">کنکشن چیک کیا جا رÛا ÛÛ’</translation>
<translation id="5610807607761827392">آپ <ph name="BEGIN_LINK" />ترتیبات<ph name="END_LINK" /> میں کارڈز اور پتوں کا نظم کر سکتے Ûیں۔</translation>
<translation id="561165882404867731">â€Ø§Ø³ صÙØ­Û Ú©Ùˆ Google ØªØ±Ø¬Ù…Û Ø§ÛŒÙ¾ Ú©ÛŒ مدد سے ØªØ±Ø¬Ù…Û Ú©Ø±ÛŒÚº</translation>
@@ -1230,6 +1254,7 @@
<translation id="5901630391730855834">پیلا</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> Ú©ÛŒ اصل پالیسی Ú©Û’ مطابق مسدود کردÛÛ”</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (مطابقت پذیری کردÛ)</translation>
+<translation id="5913377024445952699">اسکرین کیپچر روک دیا گیا</translation>
<translation id="59174027418879706">Ùعال</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">آن</translation>
@@ -1242,6 +1267,7 @@
<translation id="5963413905009737549">سیکشن</translation>
<translation id="5967592137238574583">رابطے کی معلومات میں ترمیم کریں</translation>
<translation id="5967867314010545767">سرگزشت سے Ûٹا دیں</translation>
+<translation id="5968793460449681917">Ûر ملاحظے پر</translation>
<translation id="5975083100439434680">زوم آؤٹ کریں</translation>
<translation id="5979084224081478209">پاس ورڈز چیک کریں</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1398,6 +1424,7 @@
<translation id="6587923378399804057">آپ کا کاپی Ú©Ø±Ø¯Û Ù„Ù†Ú©</translation>
<translation id="6591833882275308647">آپ کا <ph name="DEVICE_TYPE" /> زیر انتظام Ù†Ûیں ÛÛ’</translation>
<translation id="6596325263575161958">مرموزکاری کے اختیارات</translation>
+<translation id="6596892391065203054">آپ Ú©Û’ منتظم Ú©ÛŒ طر٠سے اس مواد Ú©ÛŒ پرنٹنگ مسدود ÛÛ’Û”</translation>
<translation id="6604181099783169992">موشن یا لائٹ سینسرز</translation>
<translation id="6609880536175561541">Prc7 ‎(Envelope‎)‎</translation>
<translation id="6612358246767739896">تحÙظ یاÙØªÛ Ù…ÙˆØ§Ø¯</translation>
@@ -1457,6 +1484,7 @@
<translation id="6895330447102777224">آپ Ú©Û’ کارڈ Ú©ÛŒ توثیق ÛÙˆ گئی ÛÛ’</translation>
<translation id="6897140037006041989">صار٠کا ایجنٹ</translation>
<translation id="6898699227549475383">â€ØªÙ†Ø¸ÛŒÙ… (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> کو اس کی اجازت دیں:</translation>
<translation id="6910240653697687763">â€<ph name="URL" /> آپ Ú©Û’ MIDI آلات کا پورا کنٹرول حاصل کرنا چاÛتا ÛÛ’</translation>
<translation id="6915804003454593391">صارÙ:</translation>
<translation id="6934672428414710184">â€ÛŒÛ نام آپ Ú©Û’ Google اکاؤنٹ سے ÛÛ’</translation>
@@ -1568,6 +1596,7 @@
<translation id="7346048084945669753">الحاق یاÙØªÛ ÛÛ’:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">کمانڈ لائن</translation>
+<translation id="7359588939039777303">اشتÛارات مسدود Ûیں۔</translation>
<translation id="7372973238305370288">تلاش کا نتیجÛ</translation>
<translation id="7374733840632556089">â€Ø¢Ù¾ Ú©Û’ Ø¢Ù„Û Ù¾Ø± آپ یا کسی اور Ú©Û’ Ø°Ø±ÛŒØ¹Û Ø§Ù†Ø³Ù¹Ø§Ù„ Ú©Ø±Ø¯Û Ø³Ø±Ù¹ÛŒÙکیٹ Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛŒÛ Ù…Ø³Ø¦Ù„Û Ù¾ÛŒØ´ آتا ÛÛ’Û” اس سرٹیÙکیٹ Ú©Ùˆ نیٹ ورکس مانیٹر کرنے اور منقطع کرنے Ú©Û’ استعمال Ú©Û’ لیے جانا جاتا ÛÛ’ØŒ اور ÛŒÛ Chrome Ú©ÛŒ طر٠سے قابل اعتماد Ù†Ûیں ÛÛ’Û” Ø¬Ø¨Ú©Û Ù…Ø§Ù†ÛŒÙ¹Ø±Ù†Ú¯ Ú©Û’ لئے Ú©Ú†Ú¾ جائز صورتیں موجود Ûیں، جیسے اسکول یا کمپنی Ú©Û’ نیٹ ورک پر، Chrome یقینی بنانا چاÛتا ÛÛ’ Ú©Û Ø¢Ù¾ Ûونے والی چیزوں سے واÙÙ‚ Ûیں، چاÛÛ’ آپ اسے روک Ù†Ûیں سکتے۔ مانیٹرنگ کسی بھی براؤزر یا ایپلیکیشن میں ÛÙˆ سکتی ÛÛ’ جسے ویب تک رسائی حاصل ÛÛ’Û”</translation>
<translation id="7375818412732305729">Ùائل منسلک Ú©ÛŒ جاتی ÛÛ’</translation>
@@ -1716,7 +1745,7 @@
<translation id="7862185352068345852">سائٹ چھوڑیں؟</translation>
<translation id="7865448901209910068">Ø¹Ù…Ø¯Û Ø±Ùتار</translation>
<translation id="7874263914261512992">â€Ø¢Ù¾ Ù†Û’ ابھی ایک Ù¾ÙرÙریب سائٹ پر اپنا پاس ورڈ درج کیا ÛÛ’Û” Chrome <ph name="WEBSITE_1" />ØŒ <ph name="WEBSITE_2" /> اور دیگر ایسی سائٹس Ú©Û’ لیے اپنے محÙوظ Ú©Ø±Ø¯Û Ù¾Ø§Ø³ ورڈز Ú©Ùˆ ابھی چیک کرنے Ú©ÛŒ تجویز کرتا ÛÛ’ جÛاں آپ اس پاس ورڈ کا استعمال کرتے Ûیں۔</translation>
-<translation id="7878562273885520351">لگتا ÛÛ’ کسی Ù†Û’ آپ Ú©Û’ پاسورڈ Ú©Û’ ساتھ چھیڑ چھاڑ Ú©ÛŒ ÛÛ’</translation>
+<translation id="7878562273885520351">لگتا ÛÛ’ کسی Ù†Û’ آپ Ú©Û’ پاس ورڈ Ú©Û’ ساتھ چھیڑ چھاڑ Ú©ÛŒ ÛÛ’</translation>
<translation id="7882421473871500483">بھورا</translation>
<translation id="7887683347370398519">â€Ø§Ù¾Ù†Ø§ CVC چیک کریں اور Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں</translation>
<translation id="7887885240995164102">'تصویر میں تصویر' میں داخل ÛÙˆÚº</translation>
@@ -1742,6 +1771,7 @@
<translation id="7976214039405368314">بÛت Ø²ÛŒØ§Ø¯Û Ø¯Ø±Ø®ÙˆØ§Ø³ØªÛŒÚº</translation>
<translation id="7977538094055660992">آؤٹ پٹ آلÛ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">â€Ø§ÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª کا مواد دیکھنے کیلئے، ARCore Ú©Ùˆ انسٹال کریں</translation>
<translation id="799149739215780103">باندھیں</translation>
<translation id="7995512525968007366">متعین Ù†Ûیں ÛÛ’</translation>
<translation id="800218591365569300">میموری خالی کرنے کیلئے دیگر ٹیبز یا پروگرامز کو بند کرنے کی کوشش کریں۔</translation>
@@ -1869,24 +1899,38 @@
<translation id="8507227106804027148">کمانڈ لائن</translation>
<translation id="8508648098325802031">تلاش کا آئیکن</translation>
<translation id="8522552481199248698">â€Chrome آپ Ú©ÛŒ اپنا Google اکاؤنٹ محÙوظ اور پاس ورڈ تبدیل کرنے میں مدد کر سکتا ÛÛ’Û”</translation>
+<translation id="8525306231823319788">پوری اسکرین</translation>
<translation id="8530813470445476232">â€Chrome ترتیبات میں اپنے براؤزنگ Ú©ÛŒ سرگزشت، کوکیز، کیش اور بÛت Ú©Ú†Ú¾ Ú©Ùˆ صا٠کریں</translation>
<translation id="8533619373899488139">â€Ù…سدود Ú©Ø±Ø¯Û URLs Ú©ÛŒ ÙÛرست اور اپنے سسٹم Ú©Û’ منتظم Ú©Û’ ذریعے ناÙØ° Ú©Ø±Ø¯Û Ø¯ÛŒÚ¯Ø± پالیسیاں دیکھنے Ú©Û’ لیے &lt;strong&gt;chrome://policy&lt;/strong&gt; Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ÛŒÚºÛ”</translation>
<translation id="8541158209346794904">بلوٹوتھ آلÛ</translation>
<translation id="8542014550340843547">نیچے تین سٹیپل</translation>
<translation id="8543181531796978784">آپ <ph name="BEGIN_ERROR_LINK" />پتا لگانے Ú©Û’ Ù…Ø³Ø¦Ù„Û Ú©ÛŒ اطلاع<ph name="END_ERROR_LINK" /> دے سکتے Ûیں یا اگر آپ اپنی سیکیورٹی Ú©Û’ خطروں Ú©Ùˆ سمجھتے ÛÙŠÚº تو آپ <ph name="BEGIN_LINK" />ÛŒÛ ØºÛŒØ± محÙوظ سائٹ ملاحظÛ<ph name="END_LINK" /> کر سکتے Ûیں۔</translation>
<translation id="8557066899867184262">â€CVC آپ Ú©Û’ کارڈ Ú©Û’ پیچھے ÛÛ’Û”</translation>
+<translation id="8558485628462305855">â€Ø§ÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª کا مواد دیکھنے کیلئے، ARCore Ú©Ùˆ اپ ڈیٹ کریں</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> سے ایک نجی کنکشن تشکیل Ù†Ûیں دیا جا سکتا ÛÛ’ Ú©ÛŒÙˆÙ†Ú©Û Ø¢Ù¾ Ú©Û’ آلے Ú©ÛŒ تاریخ اور وقت (<ph name="DATE_AND_TIME" />) غلط Ûیں۔</translation>
<translation id="8564182942834072828">Ø¹Ù„ÛŒØ­Ø¯Û Ø¯Ø³ØªØ§ÙˆÛŒØ²Ø§Øª/بغیر ملائی Ûوئی کاپیاں</translation>
<translation id="8564985650692024650">â€Ø§Ú¯Ø± آپ Ù†Û’ اپنا پاس ورڈ دیگر سائٹس پر Ø¯ÙˆØ¨Ø§Ø±Û Ø§Ø³ØªØ¹Ù…Ø§Ù„ کیا ÛÛ’ تو Chromium آپ Ú©Ùˆ اپنا <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> پاس ورڈ ری سیٹ کرنے Ú©ÛŒ تجویز کرتا ÛÛ’Û”</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ ÙˆÛ Ø³Ø±Ú¯Ø±Ù…ÛŒ جو اس آلے پر برقرار Ù†Ûیں رÛÛ’ Ú¯ÛŒ:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÙˆÛ ØµÙحات جنÛیں آپ اس ونڈو میں Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ØªÛ’ Ûیں
+ <ph name="LIST_ITEM" />کوکیز اور سائٹ کا ڈیٹا
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">â€ØªÛŒØ²ÛŒ سے اپنے کارڈز Ú©ÛŒ تصدیق کرنے Ú©Û’ لیے Touch ID استعمال کریں</translation>
<translation id="858637041960032120">Ùون نمبر شامل کریں</translation>
<translation id="8589998999637048520">بÛترین معیار</translation>
+<translation id="8600271352425265729">صر٠اس وقت</translation>
<translation id="860043288473659153">کارڈ کے حامل کا نام</translation>
<translation id="8606726445206553943">â€Ø§Ù¾Ù†Û’ MIDI آلات استعمال کریں</translation>
+<translation id="8612761427948161954">آداب <ph name="USERNAME" />،
+ <ph name="BR" />
+ آپ ایک Ù…Ûمان Ú©Û’ بطور براؤز کر رÛÛ’ Ûیں</translation>
<translation id="861775596732816396">سائز 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">کوئی مماثل پاس ورڈ Ù†Ûیں۔ سبھی محÙوظ پاس ورڈز دکھائيں</translation>
<translation id="8625384913736129811">اس کارڈ Ú©Ùˆ اس Ø¢Ù„Û Ù…ÛŒÚº محÙوظ کریں</translation>
+<translation id="8627040765059109009">اسکرین کیپچر Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کر دیا گیا</translation>
<translation id="8657078576661269990">آپ Ú©Û’ منتظم Ù†Û’ <ph name="ORIGIN_NAME" /> سے <ph name="VM_NAME_1" /> اور <ph name="VM_NAME_2" /> میں اشتراک کرنا مسدود کر دیا ÛÛ’</translation>
<translation id="8663226718884576429">آرڈر کا خلاصÛØŒ <ph name="TOTAL_LABEL" />ØŒ مزید تÙصیلات</translation>
<translation id="867224526087042813">دستخط</translation>
@@ -1949,6 +1993,7 @@
<translation id="8912362522468806198">â€Google اکاؤنٹ</translation>
<translation id="8913778647360618320">â€'ادائیگی Ú©Û’ طریقوں کا نظم کریں' بٹن، Chrome Ú©ÛŒ ترتیبات میں اپنی ادائیگیوں اور کریڈٹ کارڈ Ú©ÛŒ معلومات کا نظم کرنے Ú©Û’ لیے اینٹر دبائیں</translation>
<translation id="8918231688545606538">ÛŒÛ ØµÙØ­Û Ù…Ø´ØªØ¨Û ÛÛ’</translation>
+<translation id="8922013791253848639">ÛÙ…ÛŒØ´Û Ø§Ø³ سائٹ پر اشتÛارات Ú©ÛŒ اجازت دیں</translation>
<translation id="892588693504540538">اوپر دائیں طر٠سوراخ</translation>
<translation id="8931333241327730545">â€Ú©ÛŒØ§ آپ اس کارڈ Ú©Ùˆ اپنے Google اکاؤنٹ میں محÙوظ کرنا چاÛتے Ûیں؟</translation>
<translation id="8932102934695377596">آپ Ú©ÛŒ Ú¯Ú¾Ú‘ÛŒ پیچھے ÛÛ’</translation>
@@ -2021,6 +2066,7 @@
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> ایک غیر تعاون یاÙØªÛ Ù¾Ø±ÙˆÙ¹ÙˆÚ©ÙˆÙ„ استعمال کرتا ÛÛ’Û”</translation>
<translation id="9191834167571392248">نیچے بائیں طر٠سوراخ</translation>
+<translation id="9199905725844810519">پرنٹنگ مسدود ÛÛ’</translation>
<translation id="9205078245616868884">آپ Ú©Û’ ڈیٹا Ú©ÛŒ آپ Ú©Û’ مطابقت پذیر پاس Ùریز Ú©Û’ ساتھ مرموز کاری Ú©ÛŒ گئی ÛÛ’Û” مطابقت پذیری شروع کرنے کیلئے اسے درج کریں۔</translation>
<translation id="9207861905230894330">مضمون شامل کرنے میں ناکام Ûوگیا۔</translation>
<translation id="9213433120051936369">Ûیئت حسب ضرورت بنائیں</translation>
@@ -2031,8 +2077,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">â€Ø¢Ù¾ اپنے Google اکاؤنٹ تک رسائی سے محروم ÛÙˆ سکتے Ûیں۔ Chromium تجویز کرتا ÛÛ’ Ú©Û Ø¢Ù¾ ابھی اپنا پاس ورڈ تبدیل کریں۔ آپ سے سائن ان کرنے Ú©Ùˆ Ú©Ûا جائے گا۔</translation>
<translation id="939736085109172342">نیا Ùولڈر</translation>
+<translation id="945522503751344254">تاثرات بھیجیں</translation>
<translation id="945855313015696284">Ù…Ù†Ø¯Ø±Ø¬Û Ø°ÛŒÙ„ معلومات چیک کریں اور کسی بھی غلط کارڈ Ú©Ùˆ حذ٠کریں</translation>
<translation id="950736567201356821">اوپر تین بار سوراخ</translation>
+<translation id="951941430552851965">آپ Ú©ÛŒ اسکرین پر موجود مواد Ú©ÛŒ ÙˆØ¬Û Ø³Û’ آپ Ú©Û’ منتظم Ú©ÛŒ جانب سے اسکرین کیپچر روک دیا گیا۔</translation>
<translation id="961663415146723894">نیچے باندھیں</translation>
<translation id="962484866189421427">ÛÙˆ سکتا ÛÛ’ Ú©Û ÛŒÛ Ù…ÙˆØ§Ø¯ ایسی Ù¾Ùر Ùریب ایپس انسٹال کرنے Ú©ÛŒ کوشش کرے جو Ú©Ú†Ú¾ اور Ûونے کا دکھاوا کریں یا آپ Ú©ÛŒ براؤزنگ سرگرمیوں پر نظر رکھنے کیلئے استعمال کیا جانے والا ڈیٹا جمع کریں۔ <ph name="BEGIN_LINK" />مزید جانیں<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Ø¢Ùیشل بلڈ</translation>
diff --git a/chromium/components/strings/components_strings_uz.xtb b/chromium/components/strings/components_strings_uz.xtb
index 7c655ee7fc6..b05f84db4dc 100644
--- a/chromium/components/strings/components_strings_uz.xtb
+++ b/chromium/components/strings/components_strings_uz.xtb
@@ -80,6 +80,14 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Parolingizni tashkilot domenidan tashqaridagi saytda kiritdingiz. Hisobingizni himoyalash uchun tashqi ilova va saytlarda parolingizni qayta kiritmang.</translation>
<translation id="1263231323834454256">Mutolaa ro‘yxati</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Bu qurilmada saqlanib qolmaydigan amallar:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu oynada ochilgan sahifalar
+ <ph name="LIST_ITEM" />Cookie fayllari va sayt maʼlumotlari
+ <ph name="LIST_ITEM" />Hisob axboroti (<ph name="LINK_BEGIN" />chiqish<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Olib ketish usuli</translation>
<translation id="1281476433249504884">Taxlovchi 1</translation>
<translation id="1285320974508926690">Bu sayt hech qachon tarjima qilinmasin</translation>
@@ -282,6 +290,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="204357726431741734">Google hisobingizda saqlangan parollardan foydalanish uchun hisobingizga kiring</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> tilidagi sahifalar tarjima qilinmaydi</translation>
<translation id="2053553514270667976">Pochta indeksi</translation>
+<translation id="2054665754582400095">Faolligingiz</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 ta tavsiya}other{# ta tavsiya}}</translation>
<translation id="2079545284768500474">Bekor qilish</translation>
<translation id="20817612488360358">Tizim proksi-server sozlamalari yoniq, lekin uning sozlamalari aniq belgilangan.</translation>
@@ -295,6 +304,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2102495993840063010">Android ilovalar</translation>
<translation id="2107021941795971877">Chop etish mumkin</translation>
<translation id="2108755909498034140">Kompyuterni o‘chirib yoqing</translation>
+<translation id="2111166930115883695">Boshlash uchun probelni bosing</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Inkor qilindi, chunki <ph name="POLICY_NAME" /> parametri undan ustunroq.</translation>
@@ -306,6 +316,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="214556005048008348">To‘lovni bekor qilish</translation>
<translation id="2147827593068025794">Orqa fonda sinxronlash</translation>
<translation id="2148613324460538318">Yangi karta qo‘shish</translation>
+<translation id="2149968176347646218">Aloqa xavfsiz emas.</translation>
<translation id="2154054054215849342">Domeningizda sinxronizatsiya xizmati o‘chirib qo‘yilgan</translation>
<translation id="2154484045852737596">Karta ma’lumotlarini tahrirlash</translation>
<translation id="2161656808144014275">Matn</translation>
@@ -316,7 +327,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2181821976797666341">Qoidalar</translation>
<translation id="2183608646556468874">Telefon raqami</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ta manzil}other{# ta manzil}}</translation>
-<translation id="2187243482123994665">Foydalanuvchining faolligi</translation>
<translation id="2187317261103489799">Aniqlansin (standart parametr)</translation>
<translation id="2188375229972301266">Quyidan bir nechta teshik ochish</translation>
<translation id="2202020181578195191">Muddati tugaydigan yilni xatosiz kiriting</translation>
@@ -469,6 +479,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2839501879576190149">Bu soxta sayt</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Firibgarlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytidan ma’lumotlaringizni (parol, xabar va kredit karta ma’lumotlari kabilarni) o‘g‘irlashga urinayotgan bo‘lishi mumkin. <ph name="BEGIN_LEARN_MORE_LINK" />Batafsil<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Bu saytda yoqimsiz yoki befoyda reklamalar chiqadi.</translation>
<translation id="2878197950673342043">Poster shaklida taxlash</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Oynani joylashtirish</translation>
@@ -507,11 +518,11 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2996674880327704673">Google tavsiyalari</translation>
<translation id="3002501248619246229">Kiritish tarnovi axborotini tekshirish</translation>
<translation id="3005723025932146533">Saqlangan nusxani ko‘rsatish</translation>
-<translation id="3007719053326478567">Bu kontentni chop etish administrator tomonidan taqiqlangan</translation>
<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> kartasining CVC kodini kiriting. Tasdiqlangandan so‘ng, kartangiz ma’lumotlari bu saytda saqlanib qoladi.</translation>
<translation id="3010559122411665027">“<ph name="ENTRY_INDEX" />†ro‘yxat bandi: <ph name="ERROR" /></translation>
<translation id="301521992641321250">Avtomatik bloklangan</translation>
<translation id="3016780570757425217">Joylashuvingiz haqidagi ma’lumotlar</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, taklifni olib tashlash uchun avval Tab, keyin esa Enter tugmasini bosing.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Qoida turi noto‘g‘ri</translation>
<translation id="3037605927509011580">Ana xolos!</translation>
@@ -552,6 +563,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3207960819495026254">Xatcho‘plarga qo‘shildi</translation>
<translation id="3209034400446768650">Sahifa pul yechib olishi mumkin</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> saytidagi harakatlaringiz kuzatuv ostida</translation>
+<translation id="3212623355668894776">Barcha mehmon oynalarni yopsangiz, bu qurilmadan brauzerdagi faoliyat oʻchiriladi.</translation>
<translation id="3215092763954878852">WebAuthn ishlatib boʻlmadi</translation>
<translation id="3218181027817787318">Aloqador</translation>
<translation id="3225919329040284222">Serverdagi sertifikat ba’zi saytlardagi yuqori darajali havfsizlik ichki parametrlariga mos kelmaydi.</translation>
@@ -697,6 +709,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3784372983762739446">Bluetooth qurilmalar</translation>
<translation id="3787705759683870569">Amal qilish muddati: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Hajmi: 16</translation>
+<translation id="3789841737615482174">O‘rnatish</translation>
<translation id="3793574014653384240">Oxirgi ishdan chiqishlar va ularning sabablari</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Shrift talabi qilindi</translation>
@@ -748,6 +761,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4056223980640387499">Sepiya</translation>
<translation id="4058922952496707368">“<ph name="SUBKEY" />†kaliti: <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Ekranni tasvirga olishda davom etamiz.</translation>
<translation id="4067947977115446013">To‘g‘ri manzilni kiriting</translation>
<translation id="4072486802667267160">To‘lovni amalga oshirishda xatolik yuz berdi. Qayta urinib ko‘ring.</translation>
<translation id="4075732493274867456">Mijoz va server turli xil SSL protokoli versiyasi yoki shifrlar to‘plamidan foydalanmoqda.</translation>
@@ -832,6 +846,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4297502707443874121">Sahifa eskizi: <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Kengaytirish</translation>
<translation id="4300675098767811073">Oʻngdan bir necha teshik ochish</translation>
+<translation id="4302514097724775343">Boshlash uchun dinozavrni bosing</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Fayldan foydalanishga ruxsat berilmadi</translation>
<translation id="4305817255990598646">Almashtirish</translation>
@@ -910,6 +925,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4658638640878098064">Yuqori chapdan steplerlash</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual reallik</translation>
+<translation id="4675657451653251260">Mehmon rejimida hech qanday Chrome profilini koʻra olmaysiz. Parol va toʻlov usullari kabi Google hisobingizdagi maʼlumotlarga kiritish uchun <ph name="LINK_BEGIN" />hisobingizga kiring<ph name="LINK_END" />.</translation>
<translation id="467662567472608290">Bu <ph name="DOMAIN" /> serveri ekanligi tasdiqlanmadi. Uning sertifikati ayni paytda yaroqsiz bo‘lishi mumkin. Balki, server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘rilashga urinayotgan bo‘lishi mumkin.</translation>
<translation id="4677585247300749148"><ph name="URL" /> maxsus imkoniyatlardan foydalanmoqchi</translation>
<translation id="467809019005607715">Google Slides</translation>
@@ -937,6 +953,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4761104368405085019">Mikrofoningizni ishlatish</translation>
<translation id="4764776831041365478"><ph name="URL" /> manzilidagi veb-sahifa vaqtinchalik ishlamayapti yoki boshqa manzilga butunlay ko‘chirilgan.</translation>
<translation id="4766713847338118463">Quyidan ikki marta steplerlash</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Bu qurilmada saqlanib qoladigan amallar:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu oynada yuklab olingan har qanday fayllar
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Noma’lum xatolik yuz berdi.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Qalqib chiquvchi oyna bloklandi}other{# ta qalqib chiquvchi oyna bloklandi}}</translation>
<translation id="4780366598804516005">Pochta qutisi 1</translation>
@@ -1099,11 +1121,13 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5386426401304769735">Bu veb-saytning sertifikatlari zanjiridagi sertifikat SHA-1 algoritmi asosida yozilgan.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Oʻng chekkasini tikish</translation>
+<translation id="5398772614898833570">Reklamalar bloklandi</translation>
<translation id="5400836586163650660">Kulrang</translation>
<translation id="540969355065856584">Bu <ph name="DOMAIN" /> serveri ekanligini tasdiqlab bo‘lmadi. Uning sertifikati ayni paytda yaroqsiz bo‘lishi mumkin. Balki, server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘rilashga urinayotgan bo‘lishi mumkin.</translation>
<translation id="541416427766103491">Taxlovchi 4</translation>
<translation id="5421136146218899937">Brauzer tarixini tozalash...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> sayti bildirishnoma yuborishga ruxsat so‘ramoqda.</translation>
+<translation id="542872847390508405">Siz mehmon rejimida kirdingiz</translation>
<translation id="5430298929874300616">Xatcho‘pni o‘chirish</translation>
<translation id="5439770059721715174">Atributlar tekshiruvida xatolik, <ph name="ERROR_PATH" />: <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Teskari tartibda old tomonida</translation>
@@ -1145,12 +1169,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5571083550517324815">Bu manzildan olib keta olmaymiz. Boshqa manzilni tanlang.</translation>
<translation id="5580958916614886209">Kartangiz muddatining tugash oyini tekshiring va yana urinib ko‘ring.</translation>
<translation id="5586446728396275693">Hech qanday manzil saqlanmagan</translation>
+<translation id="5593349413089863479">Aloqa butunlay xavfsiz emas</translation>
<translation id="5595485650161345191">Manzilni o‘zgartirish</translation>
<translation id="5598944008576757369">To‘lov usulini tanlang</translation>
<translation id="560412284261940334">Qurilmalar boshqaruvi qo‘llab-quvvatlanmaydi</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Bu sayt soxta yoki firibgarlarniki boʻlishi mumkin. Chrome uni hoziroq yopishni tavsiya qiladi.</translation>
<translation id="5610142619324316209">Internet aloqasini tekshiring</translation>
<translation id="5610807607761827392">Karta va manzillarni <ph name="BEGIN_LINK" />Sozlamalar<ph name="END_LINK" /> orqali boshqarish mumkin.</translation>
<translation id="561165882404867731">Bu sahifani Google Tarjimon bilan tarjima qilish</translation>
@@ -1222,6 +1246,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5901630391730855834">Sariq</translation>
<translation id="5905445707201418379"><ph name="ORIGIN" /> manba siyosati asosida bloklandi.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sinxronlandi)</translation>
+<translation id="5913377024445952699">Ekranni tasvirga olish pauza qilindi</translation>
<translation id="59174027418879706">Yoqilgan</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Yoniq</translation>
@@ -1234,6 +1259,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5963413905009737549">Bo‘lim</translation>
<translation id="5967592137238574583">Aloqa ma’lumotini tahrirlang</translation>
<translation id="5967867314010545767">Tarixdan olib tashlash</translation>
+<translation id="5968793460449681917">Har tashrifda</translation>
<translation id="5975083100439434680">Kichiklashtirish</translation>
<translation id="5979084224081478209">Parollarni tekshiring</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1388,6 +1414,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6587923378399804057">Nusxalangan havola</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> qurilmangiz mustaqil</translation>
<translation id="6596325263575161958">Shifrlash parametrlari</translation>
+<translation id="6596892391065203054">Bu kontentni chop etish administrator tomonidan taqiqlangan.</translation>
<translation id="6604181099783169992">Harakat va yorug‘lik sensorlari</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Himoyalangan kontent</translation>
@@ -1447,6 +1474,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6895330447102777224">Kartangiz tasdiqlandi</translation>
<translation id="6897140037006041989">User Agent</translation>
<translation id="6898699227549475383">Tashkilot (O)</translation>
+<translation id="6907293445143367439"><ph name="SITE_NAME" /> uchun ruxsatlar:</translation>
<translation id="6910240653697687763"><ph name="URL" /> sayti MIDI qurilmalaringizni boshqarishga to‘liq ruxsat so‘ramoqda</translation>
<translation id="6915804003454593391">Foydalanuvchi:</translation>
<translation id="6934672428414710184">Bu nom Google hisobingizga biriktirilgan</translation>
@@ -1558,6 +1586,7 @@ Batafsil axborot:
<translation id="7346048084945669753">Tasarrufidami:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Buyruqlar qatori</translation>
+<translation id="7359588939039777303">Reklamalar bloklandi.</translation>
<translation id="7372973238305370288">qidiruv natijasi</translation>
<translation id="7374733840632556089">Bu muammo qurilmangizda oʻrnatilgan sertifikat sababli yuz berishi ham mumkin. Bunday sertifikat ishonchli hisoblanmaydi, chunki u odatda tarmoqdagi maʼlumotlarni kuzatish va olish uchun foydalaniladi. Bunday funksiyadan ish joylarida yoki taʼlim muassasalarida foydalanishadi. Nima boʻlganda ham biz ushbu sertifikat mavjudligi haqida sizni ogohlantirmoqchimiz. Har qanday internetga ulangan brauzer yoki ilovada faoliyatni kuzatish mumkin.</translation>
<translation id="7375818412732305729">Fayl biriktirilishi</translation>
@@ -1732,6 +1761,7 @@ Batafsil axborot:
<translation id="7976214039405368314">Limitdan oshib ketdi</translation>
<translation id="7977538094055660992">Chiqarish qurilmasi</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Virtual reallik kontentini ochish uchun ARCore ilovasini yuklab oling</translation>
<translation id="799149739215780103">Belgilash</translation>
<translation id="7995512525968007366">Ko‘rsatilmagan</translation>
<translation id="800218591365569300">Xotirani bo‘shatish uchun boshqa oyna va dasturlarni yopib ko‘ring</translation>
@@ -1859,24 +1889,38 @@ Batafsil axborot:
<translation id="8507227106804027148">Buyruqlar qatori</translation>
<translation id="8508648098325802031">Qidiruv ikonkasi</translation>
<translation id="8522552481199248698">Chrome Google hisobingizni himoyalash va parolni almashtirish uchun yordam beradi.</translation>
+<translation id="8525306231823319788">To‘liq ekran rejimi</translation>
<translation id="8530813470445476232">Brauzer tarixi, cookie fayllar, kesh va boshqa Chrome sozlamalarini tozalang</translation>
<translation id="8533619373899488139">Administrator tomonidan tuzilgan URL manzillar qora roʻyxati va boshqa parametrlarni &lt;strong&gt;chrome://policy&lt;/strong&gt; sahifasi orqali koʻrish mumkin.</translation>
<translation id="8541158209346794904">Bluetooth qurilma</translation>
<translation id="8542014550340843547">Quyidan 3 marta steplerlash</translation>
<translation id="8543181531796978784">Siz <ph name="BEGIN_ERROR_LINK" />aniqlangan muammo haqida xabar berishingiz<ph name="END_ERROR_LINK" /> yoki shaxsiy ma’lumotlaringizni xavf ostiga qo‘yishga tayyor bo‘lsangiz, <ph name="BEGIN_LINK" />ushbu xavfli saytga kirishingiz mumkin<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC kod kartangizning orqa tomonida joylashgan.</translation>
+<translation id="8558485628462305855">Virtual reallik kontentini ochish uchun ARCore ilovasini yangilang</translation>
<translation id="8559762987265718583">Tizimdagi sana va vaqt sozlamalari (<ph name="DATE_AND_TIME" />) noto‘g‘ri bo‘lganligi sababli <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeni bilan havfsiz aloqa o‘rnatib bo‘lmadi.</translation>
<translation id="8564182942834072828">Bir nechta hujjat/Tartibsiz nusxalarda</translation>
<translation id="8564985650692024650">Parolingizni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> domenidan tashqaridagi saytda kiritgan bo‘lsangiz, uni zudlik bilan almashtirishingizni tavsiya etamiz.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Bu qurilmada saqlanib qolmaydigan amallar:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Bu oynada ochilgan sahifalar
+ <ph name="LIST_ITEM" />Cookie fayllari va sayt maʼlumotlari
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Kartalarni tezda tasdiqlash uchun Touch ID ishlating</translation>
<translation id="858637041960032120">Raqam qo‘shing</translation>
<translation id="8589998999637048520">Eng sifatli</translation>
+<translation id="8600271352425265729">Faqat shu safar</translation>
<translation id="860043288473659153">Karta egasining ismi</translation>
<translation id="8606726445206553943">MIDI qurilmalaridan foydalanish</translation>
+<translation id="8612761427948161954">Salom <ph name="USERNAME" />,
+ <ph name="BR" />
+ Siz mehmon rejimida kirdingiz</translation>
<translation id="861775596732816396">Hajmi: 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Mos parollar mavjud emas. Saqlangan barcha parollar koʻrsatilsin.</translation>
<translation id="8625384913736129811">Kartani bu qurilmaga saqlash</translation>
+<translation id="8627040765059109009">Ekranni tasvirga olish davom ettirildi</translation>
<translation id="8657078576661269990"><ph name="ORIGIN_NAME" /> dan <ph name="VM_NAME_1" /> va <ph name="VM_NAME_2" /> tizimlariga axborot ulashish administrator tomonidan taqiqlangan</translation>
<translation id="8663226718884576429">Buyurtma axboroti, <ph name="TOTAL_LABEL" />, Batafsil</translation>
<translation id="867224526087042813">Imzo</translation>
@@ -1939,6 +1983,7 @@ Batafsil axborot:
<translation id="8912362522468806198">Google hisobi</translation>
<translation id="8913778647360618320">Toʻlov usullarini boshqarish tugmasi, Chrome sozlamalari orqali toʻlov va kredit karta axborotini boshqarish uchun Enter tugmasini bosing</translation>
<translation id="8918231688545606538">Bu sahifa shubhali</translation>
+<translation id="8922013791253848639">Bu saytda har doim reklama ko‘rsatilsin</translation>
<translation id="892588693504540538">Yuqori oʻngdan teshik ochish</translation>
<translation id="8931333241327730545">Ushbu karta Google hisobingizda saqlansinmi?</translation>
<translation id="8932102934695377596">Soatingiz orqada</translation>
@@ -2010,6 +2055,7 @@ Batafsil axborot:
<translation id="9183302530794969518">Google Docs</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> sayti qo‘llab-quvvatlanmaydigan protokoldan foydalanmoqda.</translation>
<translation id="9191834167571392248">Quyi chapdan teshik ochish</translation>
+<translation id="9199905725844810519">Chop etish taqiqlangan</translation>
<translation id="9205078245616868884">Ma’lumotlaringiz kodli ibora bilan shifrlangan. Sinxronlashuvni boshlash uchun uni kiriting.</translation>
<translation id="9207861905230894330">Maqolani qo‘shib bo‘lmadi.</translation>
<translation id="9213433120051936369">Dizaynini moslash</translation>
@@ -2020,8 +2066,10 @@ Batafsil axborot:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Google hisobingiz xavf ostida. Parolingizni yangilashni tavsiya qilamiz. Hisobingizga qayta kirishingiz talab qilinadi.</translation>
<translation id="939736085109172342">Yangi jild</translation>
+<translation id="945522503751344254">Fikr-mulohaza</translation>
<translation id="945855313015696284">Quyidagi axborotni tekshiring va yaroqsiz kartalarni olib tashlang</translation>
<translation id="950736567201356821">Yuqoridan 3 ta teshik ochish</translation>
+<translation id="951941430552851965">Ekrandagi kontent tufayli ekranni tasvirga olish administrator tomonidan pauza qilindi.</translation>
<translation id="961663415146723894">Quyi chekkasini belgilash</translation>
<translation id="962484866189421427">Bu kontent soxta ilovalarni o‘rnatishga urinishi mumkin. Shuningdek, sizni kuzatishi yoki axborot yig‘ishi mumkin. <ph name="BEGIN_LINK" />Baribir ko‘rsatilsin<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Rasmiy versiya</translation>
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index d24d1d4f20f..50d3b371ca4 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -80,6 +80,14 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Bạn đã nhập mật khẩu của mình trên má»™t trang web không thuá»™c quyá»n quản lý của tổ chức bạn. Äể bảo vệ tài khoản, không sá»­ dụng lại mật khẩu của bạn trên các ứng dụng và trang web khác.</translation>
<translation id="1263231323834454256">Danh sách Ä‘á»c</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Hoạt động mà Chrome sẽ không lưu trên thiết bị này:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Các trang bạn xem trong cửa sổ này
+ <ph name="LIST_ITEM" />Cookie và dữ liệu trang web
+ <ph name="LIST_ITEM" />Thông tin tài khoản (<ph name="LINK_BEGIN" />đăng xuất<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Phương thức nhận hàng</translation>
<translation id="1281476433249504884">Khay xếp chồng 1</translation>
<translation id="1285320974508926690">Không bao giỠdịch trang web này</translation>
@@ -283,6 +291,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="204357726431741734">Äăng nhập để sá»­ dụng mật khẩu đã lÆ°u trong Tài khoản Google của bạn</translation>
<translation id="2053111141626950936">Các trang viết bằng <ph name="LANGUAGE" /> sẽ không được dịch.</translation>
<translation id="2053553514270667976">Mã zip</translation>
+<translation id="2054665754582400095">Sự hiện diện của bạn</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 đỠxuất}other{# đỠxuất}}</translation>
<translation id="2079545284768500474">Hoàn tác</translation>
<translation id="20817612488360358">Cài đặt proxy hệ thống được đặt để sử dụng nhưng cấu hình proxy rõ ràng cũng được chỉ định.</translation>
@@ -296,6 +305,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2102495993840063010">Ứng dụng Android</translation>
<translation id="2107021941795971877">Hỗ trợ in</translation>
<translation id="2108755909498034140">Khởi động lại máy tính của bạn</translation>
+<translation id="2111166930115883695">Nhấn phím cách để chơi</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Thẻ</translation>
<translation id="2114841414352855701">BỠqua vì đã bị <ph name="POLICY_NAME" /> ghi đè.</translation>
@@ -307,6 +317,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="214556005048008348">Hủy thanh toán</translation>
<translation id="2147827593068025794">Äồng bá»™ hóa dÆ°á»›i ná»n</translation>
<translation id="2148613324460538318">Thêm thẻ</translation>
+<translation id="2149968176347646218">ÄÆ°á»ng kết nối không an toàn</translation>
<translation id="2154054054215849342">Tính năng đồng bá»™ hóa không khả dụng cho miá»n của bạn</translation>
<translation id="2154484045852737596">Chỉnh sửa thẻ</translation>
<translation id="2161656808144014275">Văn bản</translation>
@@ -317,7 +328,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2181821976797666341">Chính sách</translation>
<translation id="2183608646556468874">Số điện thoại</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 địa chỉ}other{# địa chỉ}}</translation>
-<translation id="2187243482123994665">Hoạt Ä‘á»™ng của ngÆ°á»i dùng</translation>
<translation id="2187317261103489799">Phát hiện (mặc định)</translation>
<translation id="2188375229972301266">Äục nhiá»u lá»— dÆ°á»›i cùng</translation>
<translation id="2202020181578195191">Nhập năm hết hạn hợp lệ</translation>
@@ -470,6 +480,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2839501879576190149">Bạn sắp truy cập vào trang web giả mạo</translation>
<translation id="2850739647070081192">Invite (Phong bì)</translation>
<translation id="2856444702002559011">Những kẻ tấn công có thể đang cố gắng đánh cắp thông tin của bạn từ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ví dụ: mật khẩu, thư hoặc thẻ tín dụng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Trang web này hiển thị quảng cáo xâm nhập hoặc quảng cáo gây hiểu nhầm.</translation>
<translation id="2878197950673342043">Gấp kiểu áp phích</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Vị trí cửa sổ</translation>
@@ -508,11 +519,11 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2996674880327704673">Bài viết do Google đỠxuất</translation>
<translation id="3002501248619246229">Kiểm tra phương tiện khay nạp giấy</translation>
<translation id="3005723025932146533">Hiển thị bản sao đã lưu</translation>
-<translation id="3007719053326478567">Quản trị viên của bạn đã chặn thao tác in nội dung này</translation>
<translation id="3008447029300691911">Nhập CVC cho <ph name="CREDIT_CARD" />. Sau khi bạn xác nhận, chi tiết thẻ của bạn sẽ được chia sẻ với trang web này.</translation>
<translation id="3010559122411665027">Mục nhập danh sách "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Tự động bị chặn</translation>
<translation id="3016780570757425217">Biết vị trí của bạn</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, nhấn phím Tab rồi nhấn phím Enter để loại bỠnội dung đỠxuất.</translation>
<translation id="3023071826883856138">You4 (Phong bì)</translation>
<translation id="3024663005179499861">Loại chính sách sai</translation>
<translation id="3037605927509011580">Ôi, há»ng! </translation>
@@ -555,6 +566,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3207960819495026254">Äã đánh dấu trang</translation>
<translation id="3209034400446768650">Trang này có thể tính phí</translation>
<translation id="3212581601480735796">Hoạt động của bạn trên <ph name="HOSTNAME" /> sẽ bị giám sát</translation>
+<translation id="3212623355668894776">Äóng tất cả cá»­a sổ Khách để xóa hoạt Ä‘á»™ng duyệt web của bạn khá»i thiết bị này.</translation>
<translation id="3215092763954878852">Không thể dùng WebAuthn</translation>
<translation id="3218181027817787318">Tương đối</translation>
<translation id="3225919329040284222">Máy chủ Ä‘Æ°a ra chứng chỉ không khá»›p vá»›i kỳ vá»ng được tích hợp sẵn. Các kỳ vá»ng này có trong má»™t số trang web nhất định, có tính bảo mật cao vá»›i mục đích bảo vệ bạn.</translation>
@@ -702,6 +714,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3784372983762739446">Thiết bị Bluetooth</translation>
<translation id="3787705759683870569">Ngày hết hạn <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Kích thước 16</translation>
+<translation id="3789841737615482174">Cài đặt</translation>
<translation id="3793574014653384240">Số lượng lỗi và nguyên nhân gây ra các lỗi gần đây</translation>
<translation id="3797522431967816232">Prc3 (Phong bì)</translation>
<translation id="3799805948399000906">Phông chữ đã yêu cầu</translation>
@@ -753,6 +766,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4056223980640387499">Màu nâu Ä‘á»</translation>
<translation id="4058922952496707368">Khóa "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Phong bì)</translation>
+<translation id="4067669230157909013">Tính năng chụp ảnh màn hình đã được tiếp tục.</translation>
<translation id="4067947977115446013">Thêm địa chỉ hợp lệ</translation>
<translation id="4072486802667267160">Äã xảy ra lá»—i khi xá»­ lý Ä‘Æ¡n đặt hàng của bạn. Vui lòng thá»­ lại.</translation>
<translation id="4075732493274867456">Ứng dụng và máy chủ không há»— trợ bá»™ mã hóa hoặc phiên bản giao thức SSL thông thÆ°á»ng.</translation>
@@ -837,6 +851,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4297502707443874121">Hình thu nhỠcủa trang <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Mở rộng</translation>
<translation id="4300675098767811073">Äục nhiá»u lá»— bên phải</translation>
+<translation id="4302514097724775343">Nhấn vào hình khủng long để chơi</translation>
<translation id="4302965934281694568">Chou3 (Phong bì)</translation>
<translation id="4305666528087210886">Không thể truy cập vào tệp của bạn</translation>
<translation id="4305817255990598646">Chuyển</translation>
@@ -915,6 +930,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4658638640878098064">Dập ghim trên cùng bên trái</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Thực tế ảo</translation>
+<translation id="4675657451653251260">Bạn sẽ không thấy thông tin nào của hồ sơ Chrome ở chế độ Khách. Bạn có thể <ph name="LINK_BEGIN" />đăng nhập<ph name="LINK_END" /> để xem thông tin Tài khoản Google của mình, chẳng hạn như mật khẩu và phương thức thanh toán.</translation>
<translation id="467662567472608290">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này có lá»—i. Äiá»u này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="4677585247300749148"><ph name="URL" /> muốn phản hồi các sự kiện trợ năng</translation>
<translation id="467809019005607715">Google Trang trình bày</translation>
@@ -942,6 +958,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4761104368405085019">Sử dụng micrô của bạn</translation>
<translation id="4764776831041365478">Trang web tại <ph name="URL" /> có thể tạm thá»i không hoạt Ä‘á»™ng hay được chuyển vÄ©nh viá»…n sang địa chỉ web má»›i.</translation>
<translation id="4766713847338118463">Dập 2 ghim dưới cùng</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Hoạt động mà Chrome sẽ lưu trên thiết bị này:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Má»i tệp mà bạn tải xuống trong cá»­a sổ này
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Xảy ra lỗi chưa biết.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Äã chặn cá»­a sổ bật lên}other{Äã chặn # cá»­a sổ bật lên}}</translation>
<translation id="4780366598804516005">Há»™p thÆ° 1</translation>
@@ -1104,11 +1126,13 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5386426401304769735">Chuỗi chứng chỉ cho trang web này có chứa một chứng chỉ đã ký bằng SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">May viá»n ở bên phải</translation>
+<translation id="5398772614898833570">Äã chặn quảng cáo</translation>
<translation id="5400836586163650660">Màu xám</translation>
<translation id="540969355065856584">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này không hợp lệ tại thá»i Ä‘iểm này. Äiá»u này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="541416427766103491">Khay xếp chồng 4</translation>
<translation id="5421136146218899937">Xóa dữ liệu duyệt web...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> muốn gửi thông báo cho bạn</translation>
+<translation id="542872847390508405">Bạn đang duyệt với tư cách khách</translation>
<translation id="5430298929874300616">Xóa dấu trang</translation>
<translation id="5439770059721715174">Lỗi xác thực lược đồ tại "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">Thứ tự đảo ngược hướng lên</translation>
@@ -1150,12 +1174,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5571083550517324815">Không thể nhận hàng từ địa chỉ này. Chá»n má»™t địa chỉ khác.</translation>
<translation id="5580958916614886209">Kiểm tra tháng hết hạn của bạn và thử lại</translation>
<translation id="5586446728396275693">Không có địa chỉ nào được lưu</translation>
+<translation id="5593349413089863479">ÄÆ°á»ng kết nối không đủ an toàn</translation>
<translation id="5595485650161345191">Chỉnh sửa địa chỉ</translation>
<translation id="5598944008576757369">Chá»n phÆ°Æ¡ng thức thanh toán</translation>
<translation id="560412284261940334">Không hỗ trợ quản lý</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Äây có thể là trang web giả mạo hoặc lừa đảo. Bạn nên thoát khá»i trang web này ngay.</translation>
<translation id="5610142619324316209">Kiểm tra kết nối</translation>
<translation id="5610807607761827392">Bạn có thể quản lý thẻ và địa chỉ trong <ph name="BEGIN_LINK" />Cài đặt<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Dịch trang này bằng Google Dịch</translation>
@@ -1227,6 +1251,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5901630391730855834">Vàng</translation>
<translation id="5905445707201418379">Bị chặn theo chính sách nguồn gốc của <ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (được đồng bộ hóa)</translation>
+<translation id="5913377024445952699">Tính năng chụp ảnh màn hình bị tạm dừng</translation>
<translation id="59174027418879706">Äược kích hoạt</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Äang bật</translation>
@@ -1239,6 +1264,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5963413905009737549">Phần</translation>
<translation id="5967592137238574583">Chỉnh sửa thông tin liên hệ</translation>
<translation id="5967867314010545767">Xóa khá»i lịch sá»­</translation>
+<translation id="5968793460449681917">Vào mỗi lần truy cập</translation>
<translation id="5975083100439434680">Thu nhá»</translation>
<translation id="5979084224081478209">Kiểm tra mật khẩu</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1394,6 +1420,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6587923378399804057">Liên kết bạn đã sao chép</translation>
<translation id="6591833882275308647"><ph name="DEVICE_TYPE" /> của bạn không được quản lý</translation>
<translation id="6596325263575161958">Tùy chá»n mã hóa</translation>
+<translation id="6596892391065203054">Quản trị viên của bạn đã chặn thao tác in nội dung này.</translation>
<translation id="6604181099783169992">Cảm biến chuyển động hoặc ánh sáng</translation>
<translation id="6609880536175561541">Prc7 (Phong bì)</translation>
<translation id="6612358246767739896">Nội dung được bảo vệ</translation>
@@ -1453,6 +1480,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6895330447102777224">Thẻ của bạn đã được xác nhận</translation>
<translation id="6897140037006041989">Tác nhân NgÆ°á»i dùng</translation>
<translation id="6898699227549475383">Tổ chức (O)</translation>
+<translation id="6907293445143367439">Cho phép <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> muốn có quyá»n kiểm soát toàn bá»™ thiết bị MIDI của bạn</translation>
<translation id="6915804003454593391">NgÆ°á»i dùng:</translation>
<translation id="6934672428414710184">Tên này lấy từ Tài khoản Google của bạn</translation>
@@ -1564,6 +1592,7 @@ Thông tin chi tiết bổ sung:
<translation id="7346048084945669753">Äược liên kết:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Dòng Lệnh</translation>
+<translation id="7359588939039777303">Äã chặn quảng cáo.</translation>
<translation id="7372973238305370288">kết quả tìm kiếm</translation>
<translation id="7374733840632556089">Sá»± cố này xảy ra do má»™t chứng chỉ mà bạn hoặc ai đó đã cài đặt trên thiết bị của bạn. Chrome không tin cậy chứng chỉ này vì chứng chỉ được xác định là dùng để chặn và giám sát mạng. Mặc dù có má»™t số trÆ°á»ng hợp trong đó hoạt Ä‘á»™ng giám sát là hợp pháp, chẳng hạn nhÆ° mạng của trÆ°á»ng há»c hay công ty, nhÆ°ng Chrome muốn đảm bảo rằng bạn biết Ä‘iá»u này, ngay cả khi bạn không thể ngăn chặn. Hoạt Ä‘á»™ng giám sát có thể diá»…n ra trong bất kỳ trình duyệt hoặc ứng dụng nào có quyá»n truy cập vào web.</translation>
<translation id="7375818412732305729">Äính kèm tệp</translation>
@@ -1738,6 +1767,7 @@ Thông tin chi tiết bổ sung:
<translation id="7976214039405368314">Quá nhiá»u yêu cầu</translation>
<translation id="7977538094055660992">Thiết bị đầu ra</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Äể xem ná»™i dung thá»±c tế tăng cÆ°á»ng, hãy cài đặt bá»™ công cụ ARCore</translation>
<translation id="799149739215780103">Äóng gáy</translation>
<translation id="7995512525968007366">Không chỉ định</translation>
<translation id="800218591365569300">Thử đóng các thẻ hoặc chương trình khác để giải phóng bộ nhớ.</translation>
@@ -1865,25 +1895,39 @@ Thông tin chi tiết bổ sung:
<translation id="8507227106804027148">Dòng lệnh</translation>
<translation id="8508648098325802031">Biểu tượng Tìm kiếm</translation>
<translation id="8522552481199248698">Chrome có thể giúp bạn bảo vệ Tài khoản Google của mình và đổi mật khẩu.</translation>
+<translation id="8525306231823319788">Toàn màn hình</translation>
<translation id="8530813470445476232">Xóa lịch sử duyệt web, cookie, bộ nhớ đệm và các dữ liệu khác trong phần cài đặt của Chrome</translation>
<translation id="8533619373899488139">Hãy truy cập vào &lt;strong&gt;chrome://policy&lt;/strong&gt; để xem danh sách các URL bị chặn và những chính sách khác do quản trị viên hệ thống thực thi.</translation>
<translation id="8541158209346794904">Thiết bị Bluetooth</translation>
<translation id="8542014550340843547">Dập 3 ghim dưới cùng</translation>
<translation id="8543181531796978784">Bạn có thể <ph name="BEGIN_ERROR_LINK" />báo cáo sự cố đã phát hiện<ph name="END_ERROR_LINK" /> hoặc nếu bạn hiểu rủi ro với bảo mật của mình, hãy <ph name="BEGIN_LINK" />truy cập trang web không an toàn này<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">CVC nằm ở mặt sau thẻ của bạn.</translation>
+<translation id="8558485628462305855">Äể xem ná»™i dung thá»±c tế tăng cÆ°á»ng, hãy cập nhật bá»™ công cụ ARCore</translation>
<translation id="8559762987265718583">Không thể thiết lập kết nối riêng tư với <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vì ngày và giỠ(<ph name="DATE_AND_TIME" />) trên thiết bị của bạn không đúng.</translation>
<translation id="8564182942834072828">Tài liệu riêng biệt/Bản sao chưa đối chiếu</translation>
<translation id="8564985650692024650">Chromium khuyên bạn nên đặt lại mật khẩu <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> của mình nếu đã sử dụng lại mật khẩu này trên các trang web khác.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Hoạt động mà Chrome sẽ không lưu trên thiết bị này:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Các trang bạn xem trong cửa sổ này
+ <ph name="LIST_ITEM" />Cookie và dữ liệu trang web
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Dùng Touch ID để xác nhận các thẻ nhanh hơn</translation>
<translation id="858637041960032120">Thêm số đ.thoại
</translation>
<translation id="8589998999637048520">Chất lượng tốt nhất</translation>
+<translation id="8600271352425265729">Chỉ lần này</translation>
<translation id="860043288473659153">Tên chủ thẻ</translation>
<translation id="8606726445206553943">Sử dụng các thiết bị MIDI của bạn</translation>
+<translation id="8612761427948161954">Chào <ph name="USERNAME" />!
+ <ph name="BR" />
+ Bạn đang duyệt web với tư cách Khách</translation>
<translation id="861775596732816396">Kích thước 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Không có mật khẩu nào khớp. Hiển thị tất cả các mật khẩu đã lưu.</translation>
<translation id="8625384913736129811">Lưu thẻ này vào thiết bị này</translation>
+<translation id="8627040765059109009">Tiếp tục chụp ảnh màn hình</translation>
<translation id="8657078576661269990">Quản trị viên của bạn đã chặn thao tác chia sẻ từ <ph name="ORIGIN_NAME" /> tới <ph name="VM_NAME_1" /> và <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Tóm tắt đơn hàng, <ph name="TOTAL_LABEL" />, chi tiết khác</translation>
<translation id="867224526087042813">Chữ ký</translation>
@@ -1946,6 +1990,7 @@ Thông tin chi tiết bổ sung:
<translation id="8912362522468806198">Tài khoản Google</translation>
<translation id="8913778647360618320">Nút Quản lý phương thức thanh toán, nhấn phím Enter để quản lý thông tin thanh toán và thẻ tín dụng trong phần cài đặt của Chrome</translation>
<translation id="8918231688545606538">Äây là trang đáng ngá»</translation>
+<translation id="8922013791253848639">Luôn cho phép quảng cáo trên trang web này</translation>
<translation id="892588693504540538">Äục lá»— trên cùng bên phải</translation>
<translation id="8931333241327730545">Bạn có muốn lưu thẻ này vào Tài khoản Google của mình không?</translation>
<translation id="8932102934695377596">Äồng hồ của bạn chạy chậm</translation>
@@ -2017,6 +2062,7 @@ Thông tin chi tiết bổ sung:
<translation id="9183302530794969518">Google Tài liệu</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> sử dụng giao thức không được hỗ trợ.</translation>
<translation id="9191834167571392248">Äục lá»— dÆ°á»›i cùng bên trái</translation>
+<translation id="9199905725844810519">Tính năng in đã bị chặn</translation>
<translation id="9205078245616868884">Dữ liệu của bạn đã được mã hóa bằng cụm mật khẩu đồng bộ hóa. Nhập cụm mật khẩu đó để bắt đầu đồng bộ hóa.</translation>
<translation id="9207861905230894330">Không thêm được bài viết.</translation>
<translation id="9213433120051936369">Tùy chỉnh giao diện</translation>
@@ -2027,8 +2073,10 @@ Thông tin chi tiết bổ sung:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Bạn có thể mất quyá»n truy cập vào Tài khoản Google của mình. Chromium khuyên bạn nên đổi mật khẩu ngay bây giá». Bạn sẽ được yêu cầu đăng nhập.</translation>
<translation id="939736085109172342">Thư mục mới</translation>
+<translation id="945522503751344254">Gửi phản hồi</translation>
<translation id="945855313015696284">Kiểm tra thông tin bên dÆ°á»›i và xóa má»i thẻ không hợp lệ</translation>
<translation id="950736567201356821">Äục 3 lá»— trên cùng</translation>
+<translation id="951941430552851965">Quản trị viên đã tạm dừng tính năng chụp ảnh màn hình do có nội dung không được phép chụp hình.</translation>
<translation id="961663415146723894">Äóng gáy dÆ°á»›i cùng</translation>
<translation id="962484866189421427">Nội dung này có thể tìm cách cài đặt ứng dụng lừa đảo giả mạo nội dung khác hoặc thu thập dữ liệu có thể được dùng để theo dõi bạn. <ph name="BEGIN_LINK" />Vẫn hiển thị<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Phiên bản Chính thức</translation>
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index c74fc3687d4..f63a9f88b72 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">您在一个ä¸å—è´µå•ä½ç®¡ç†çš„网站上输入了您的密ç ã€‚为了ä¿æŠ¤æ‚¨çš„å¸å·ï¼Œè¯·ä¸è¦åœ¨å…¶ä»–应用和网站上é‡å¤ä½¿ç”¨æ‚¨çš„密ç ã€‚</translation>
<translation id="1263231323834454256">阅读清å•</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ 系统ä¸ä¼šå°†ä»¥ä¸‹æ´»åŠ¨è®°å½•ä¿å­˜åˆ°æ­¤è®¾å¤‡ä¸Šï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您在该窗å£ä¸­æŸ¥çœ‹çš„网页
+ <ph name="LIST_ITEM" />Cookie 和网站数æ®
+ <ph name="LIST_ITEM" />å¸å·ä¿¡æ¯ï¼ˆ<ph name="LINK_BEGIN" />退出<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">å–货方å¼</translation>
<translation id="1281476433249504884">å †å å‡ºçº¸å™¨ 1</translation>
<translation id="1285320974508926690">一律ä¸ç¿»è¯‘此网站</translation>
@@ -137,7 +145,7 @@
<translation id="1462951478840426066">使用您计算机上的字体,以便您能够创作高ä¿çœŸå†…容</translation>
<translation id="1463543813647160932">5x7</translation>
<translation id="1467432559032391204">å‘å·¦</translation>
-<translation id="1472675084647422956">显示更多</translation>
+<translation id="1472675084647422956">展开</translation>
<translation id="1473183651233018052">JIS B10</translation>
<translation id="147358896496811705">2A0</translation>
<translation id="1476595624592550506">更改您的密ç </translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">登录åŽå³å¯ä½¿ç”¨æ‚¨ Google å¸å·ä¸­ä¿å­˜çš„密ç </translation>
<translation id="2053111141626950936">系统ä¸ä¼šç¿»è¯‘<ph name="LANGUAGE" />网页。</translation>
<translation id="2053553514270667976">邮编</translation>
+<translation id="2054665754582400095">您的状æ€</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 æ¡å»ºè®®}other{# æ¡å»ºè®®}}</translation>
<translation id="2079545284768500474">撤消</translation>
<translation id="20817612488360358">已设置为使用系统代ç†è®¾ç½®ï¼Œä½†åŒæ—¶æŒ‡å®šäº†ä¸€ä¸ªæ˜Žç¡®çš„代ç†é…置。</translation>
@@ -292,17 +301,19 @@
<translation id="2102495993840063010">Android 应用</translation>
<translation id="2107021941795971877">打å°æ–¹é¢çš„支æŒ</translation>
<translation id="2108755909498034140">é‡æ–°å¯åŠ¨è®¡ç®—机</translation>
+<translation id="2111166930115883695">按空格键å³å¯æ’­æ”¾</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">信用å¡</translation>
<translation id="2114841414352855701">由于已被 <ph name="POLICY_NAME" /> 替æ¢ï¼Œè¯¥æ”¿ç­–已忽略。</translation>
<translation id="2119505898009119320">é¢å‘对象:<ph name="ORGANIZATION" /> [<ph name="JURISDICTION" />]</translation>
<translation id="2119867082804433120">打孔(å³ä¸‹è§’)</translation>
-<translation id="2129079103035905234">动æ€ä¼ æ„Ÿå™¨</translation>
+<translation id="2129079103035905234">移动传感器</translation>
<translation id="2130448033692577677">您指定的模æ¿æœªå¿…会被应用,因为 DnsOverHttpsMode 政策未设置。</translation>
<translation id="213826338245044447">移动设备书签</translation>
<translation id="214556005048008348">å–消付款</translation>
<translation id="2147827593068025794">åŽå°åŒæ­¥</translation>
<translation id="2148613324460538318">添加支付å¡</translation>
+<translation id="2149968176347646218">连接ä¸å®‰å…¨</translation>
<translation id="2154054054215849342">您的网域ä¸æ”¯æŒåŒæ­¥</translation>
<translation id="2154484045852737596">修改支付å¡</translation>
<translation id="2161656808144014275">文字</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">政策</translation>
<translation id="2183608646556468874">电è¯å·ç </translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 个地å€}other{# 个地å€}}</translation>
-<translation id="2187243482123994665">用户活跃状æ€</translation>
<translation id="2187317261103489799">检测(默认)</translation>
<translation id="2188375229972301266">多孔(底部)</translation>
<translation id="2202020181578195191">请输入有效的失效年份</translation>
@@ -345,7 +355,7 @@
<translation id="2297722699537546652">B5 (Envelope)</translation>
<translation id="2300306941146563769">未上传</translation>
<translation id="2310021320168182093">Chou2 (Envelope)</translation>
-<translation id="2316887270356262533">释放了ä¸åˆ° 1 MB。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
+<translation id="2316887270356262533">释放ä¸åˆ° 1 MB 空间。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> è¦æ±‚æ供用户å和密ç ã€‚</translation>
<translation id="2330137317877982892"><ph name="CREDIT_CARD" />,到期时间:<ph name="EXPIRATION_DATE_ABBR" /></translation>
<translation id="2337852623177822836">设置由管ç†å‘˜æŽ§åˆ¶</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">您è¦è®¿é—®çš„是虚å‡ç½‘ç«™</translation>
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">攻击者å¯èƒ½ä¼šè¯•å›¾ä»Ž <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 窃å–您的信æ¯ï¼ˆä¾‹å¦‚:密ç ã€é€šè®¯å†…容或信用å¡ä¿¡æ¯ï¼‰ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">此网站展示过侵扰性或误导性广告。</translation>
<translation id="2878197950673342043">海报折</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">窗å£æ”¾ç½®</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google æ供的建议</translation>
<translation id="3002501248619246229">检查进纸匣媒体</translation>
<translation id="3005723025932146533">显示已ä¿å­˜çš„版本</translation>
-<translation id="3007719053326478567">您的管ç†å‘˜å·²ç¦æ­¢æ‰“å°æ­¤å†…容</translation>
<translation id="3008447029300691911">输入“<ph name="CREDIT_CARD" />â€çš„银行å¡éªŒè¯ç  (CVC)。在您确认åŽï¼Œæ‚¨çš„信用å¡è¯¦æƒ…将与此网站共享。</translation>
<translation id="3010559122411665027">列表æ¡ç›®â€œ<ph name="ENTRY_INDEX" />â€ï¼š<ph name="ERROR" /></translation>
<translation id="301521992641321250">已被自动ç¦æ­¢</translation>
<translation id="3016780570757425217">获å–您的ä½ç½®</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯ç§»é™¤å»ºè®®ã€‚</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">策略类型有误</translation>
<translation id="3037605927509011580">喔唷,崩溃啦ï¼</translation>
@@ -547,6 +558,7 @@
<translation id="3207960819495026254">已加书签</translation>
<translation id="3209034400446768650">此网页å¯èƒ½ä¼šæ”¶å–费用</translation>
<translation id="3212581601480735796">您在 <ph name="HOSTNAME" /> 上的活动正被监控</translation>
+<translation id="3212623355668894776">请关闭所有访客窗å£ï¼Œä»¥ä¾¿ä»Žæ­¤è®¾å¤‡ä¸­åˆ é™¤æ‚¨çš„æµè§ˆæ´»åŠ¨è®°å½•ã€‚</translation>
<translation id="3215092763954878852">无法使用 WebAuthn</translation>
<translation id="3218181027817787318">相对</translation>
<translation id="3225919329040284222">æœåŠ¡å™¨æ供的è¯ä¹¦ä¸Žå†…置预期è¯ä¹¦ä¸åŒ¹é…。这些预期è¯ä¹¦æ˜¯é’ˆå¯¹æŸäº›é«˜å®‰å…¨æ€§ç½‘ç«™æ供的,以便为您æä¾›ä¿æŠ¤ã€‚</translation>
@@ -692,6 +704,7 @@
<translation id="3784372983762739446">è“牙设备</translation>
<translation id="3787705759683870569">失效日期:<ph name="EXPIRATION_YEAR" /> 年 <ph name="EXPIRATION_MONTH" /> 月</translation>
<translation id="3789155188480882154">大å°ï¼š16</translation>
+<translation id="3789841737615482174">安装</translation>
<translation id="3793574014653384240">近期å‘生崩溃的次数和原因</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">请求的字体</translation>
@@ -739,9 +752,10 @@
<translation id="4014128326099193693">{COUNT,plural, =1{åŒ…å« {COUNT} 页内容的 PDF 文档}other{åŒ…å« {COUNT} 页内容的 PDF 文档}}</translation>
<translation id="4030383055268325496">撤消添加(&amp;U)</translation>
<translation id="4032320456957708163">您的æµè§ˆå™¨ç”± <ph name="ENROLLMENT_DOMAIN" /> 管ç†</translation>
-<translation id="4056223980640387499">棕色调</translation>
+<translation id="4056223980640387499">棕è¤è‰²è°ƒ</translation>
<translation id="4058922952496707368">“<ph name="SUBKEY" />â€é”®ï¼š<ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">å±å¹•æˆªå–功能已æ¢å¤ã€‚</translation>
<translation id="4067947977115446013">添加有效地å€</translation>
<translation id="4072486802667267160">处ç†æ‚¨çš„订å•æ—¶å‡ºé”™ã€‚请é‡è¯•ã€‚</translation>
<translation id="4075732493274867456">客户端和æœåŠ¡å™¨ä¸æ”¯æŒä¸€èˆ¬ SSL å议版本或加密套件。</translation>
@@ -822,6 +836,7 @@
<translation id="4297502707443874121">第 <ph name="THUMBNAIL_PAGE" /> 页的缩略图</translation>
<translation id="42981349822642051">展开</translation>
<translation id="4300675098767811073">多孔(å³ä¾§ï¼‰</translation>
+<translation id="4302514097724775343">点按æ龙图标å³å¯å¼€å§‹çŽ©è¿™æ¬¾æ¸¸æˆ</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">无法访问您的文件</translation>
<translation id="4305817255990598646">切æ¢</translation>
@@ -900,6 +915,7 @@
<translation id="4658638640878098064">钉装(左上角)</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">虚拟实境</translation>
+<translation id="4675657451653251260">在访客模å¼ä¸‹ï¼Œæ‚¨æ— æ³•æŸ¥çœ‹ä»»ä½• Chrome 个人资料的信æ¯ã€‚您å¯<ph name="LINK_BEGIN" />登录<ph name="LINK_END" />以访问您的 Google å¸å·ä¿¡æ¯ï¼ˆä¾‹å¦‚密ç å’Œä»˜æ¬¾æ–¹å¼ï¼‰ã€‚</translation>
<translation id="467662567472608290">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦æœ‰è¯¯ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="4677585247300749148"><ph name="URL" /> 想对无障ç¢äº‹ä»¶åšå‡ºå“应</translation>
<translation id="467809019005607715">Google å¹»ç¯ç‰‡</translation>
@@ -927,6 +943,12 @@
<translation id="4761104368405085019">使用您的麦克风</translation>
<translation id="4764776831041365478">网å€ä¸º <ph name="URL" /> 的网页å¯èƒ½æš‚时无法连接,或者它已永久性地移动到了新网å€ã€‚</translation>
<translation id="4766713847338118463">åŒé’‰ï¼ˆåº•éƒ¨ï¼‰</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ 系统会将您的以下活动记录ä¿å­˜åˆ°æ­¤è®¾å¤‡ä¸Šï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您在该窗å£ä¸­ä¸‹è½½çš„所有文件
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">å‘生未知错误。</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{已拦截弹出å¼çª—å£}other{已拦截 # 个弹出å¼çª—å£}}</translation>
<translation id="4780366598804516005">ä¿¡ç®± 1</translation>
@@ -1089,11 +1111,13 @@
<translation id="5386426401304769735">此网站的è¯ä¹¦é“¾åŒ…å«ä½¿ç”¨ SHA-1 签署的è¯ä¹¦ã€‚</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">边缘装订(å³ä¾§ï¼‰</translation>
+<translation id="5398772614898833570">广告已被拦截</translation>
<translation id="5400836586163650660">ç°è‰²</translation>
<translation id="540969355065856584">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯ <ph name="DOMAIN" />;其安全è¯ä¹¦ç›®å‰æ— æ•ˆã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="541416427766103491">å †å å‡ºçº¸å™¨ 4</translation>
<translation id="5421136146218899937">清除æµè§ˆæ•°æ®...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> 想å‘您å‘é€é€šçŸ¥</translation>
+<translation id="542872847390508405">您正在以访客身份æµè§ˆ</translation>
<translation id="5430298929874300616">移除书签</translation>
<translation id="5439770059721715174">“<ph name="ERROR_PATH" />â€ä¸­å­˜åœ¨æ¨¡å¼éªŒè¯é”™è¯¯ï¼š<ph name="ERROR" /></translation>
<translation id="5443468954631487277">逆转顺åºï¼Œæ­£é¢æœä¸Š</translation>
@@ -1135,12 +1159,12 @@
<translation id="5571083550517324815">无法从此地å€å–货。请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
<translation id="5580958916614886209">请检查您的信用å¡åˆ°æœŸæœˆä»½ï¼Œç„¶åŽé‡è¯•</translation>
<translation id="5586446728396275693">没有已ä¿å­˜çš„地å€</translation>
+<translation id="5593349413089863479">连接ä¸å¤Ÿå®‰å…¨</translation>
<translation id="5595485650161345191">修改地å€</translation>
<translation id="5598944008576757369">选择付款方å¼</translation>
<translation id="560412284261940334">ä¸æ”¯æŒç®¡ç†</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">此网站å¯èƒ½æ˜¯è™šå‡æˆ–欺诈性网站。Chrome 建议您立å³ç¦»å¼€ã€‚</translation>
<translation id="5610142619324316209">检查网络连接</translation>
<translation id="5610807607761827392">您å¯ä»¥åœ¨<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />中管ç†ä¿¡ç”¨å¡å’Œåœ°å€ä¿¡æ¯ã€‚</translation>
<translation id="561165882404867731">使用“Google 翻译â€æœåŠ¡æ¥ç¿»è¯‘此页é¢</translation>
@@ -1212,6 +1236,7 @@
<translation id="5901630391730855834">黄色</translation>
<translation id="5905445707201418379">å·²æ ¹æ® <ph name="ORIGIN" /> çš„æ¥æºæ”¿ç­–而å±è”½ã€‚</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" />(已åŒæ­¥ï¼‰</translation>
+<translation id="5913377024445952699">å±å¹•æˆªå–功能已暂åœ</translation>
<translation id="59174027418879706">å·²å¯ç”¨</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">已开å¯</translation>
@@ -1224,6 +1249,7 @@
<translation id="5963413905009737549">章节标记</translation>
<translation id="5967592137238574583">修改è”系信æ¯</translation>
<translation id="5967867314010545767">从历å²è®°å½•ä¸­ç§»é™¤</translation>
+<translation id="5968793460449681917">æ¯æ¬¡è®¿é—®æ—¶</translation>
<translation id="5975083100439434680">缩å°</translation>
<translation id="5979084224081478209">检查密ç </translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1318,7 +1344,7 @@
<translation id="6328639280570009161">请å°è¯•åœç”¨ç½‘络è”想查询功能</translation>
<translation id="6328784461820205019">“您的连接ä¸æ˜¯ç§å¯†è¿žæŽ¥â€ã€â€œ&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;â€ã€â€œ&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;â€ã€â€œ&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;â€ã€â€œ&lt;span class="error-code"&gt;ERR_CERT_SYMANTEC_LEGACY&lt;/span&gt;â€æˆ–“SSL è¯ä¹¦é”™è¯¯â€</translation>
<translation id="6328786501058569169">此网站是欺骗性网站</translation>
-<translation id="6337133576188860026">释放了ä¸åˆ° <ph name="SIZE" />。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
+<translation id="6337133576188860026">释放ä¸åˆ° <ph name="SIZE" /> 空间。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
<translation id="6337534724793800597">按å称过滤政策</translation>
<translation id="6353505687280762741">{COUNT,plural, =0{æ— }=1{1 个密ç ï¼ˆç”¨äºŽ <ph name="DOMAIN_LIST" />,已åŒæ­¥ï¼‰}=2{2 个密ç ï¼ˆç”¨äºŽ <ph name="DOMAIN_LIST" />,已åŒæ­¥ï¼‰}other{# 个密ç ï¼ˆç”¨äºŽ <ph name="DOMAIN_LIST" />,已åŒæ­¥ï¼‰}}</translation>
<translation id="6358450015545214790">这分别æ„味ç€ä»€ä¹ˆï¼Ÿ</translation>
@@ -1378,6 +1404,7 @@
<translation id="6587923378399804057">您å¤åˆ¶çš„链接</translation>
<translation id="6591833882275308647">您的 <ph name="DEVICE_TYPE" /> ä¸å—管ç†</translation>
<translation id="6596325263575161958">加密选项</translation>
+<translation id="6596892391065203054">您的管ç†å‘˜å·²ç¦æ­¢æ‰“å°æ­¤å†…容。</translation>
<translation id="6604181099783169992">动æ€ä¼ æ„Ÿå™¨æˆ–光传感器</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">å—ä¿æŠ¤çš„内容</translation>
@@ -1437,6 +1464,7 @@
<translation id="6895330447102777224">已确认您的信用å¡</translation>
<translation id="6897140037006041989">用户代ç†</translation>
<translation id="6898699227549475383">组织 (O)</translation>
+<translation id="6907293445143367439">å…许 <ph name="SITE_NAME" />:</translation>
<translation id="6910240653697687763"><ph name="URL" /> 想完全控制您的 MIDI 设备</translation>
<translation id="6915804003454593391">用户:</translation>
<translation id="6934672428414710184">æ­¤å称æ¥è‡ªæ‚¨çš„ Google å¸å·</translation>
@@ -1548,6 +1576,7 @@
<translation id="7346048084945669753">有无关è”:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">命令行</translation>
+<translation id="7359588939039777303">广告已被拦截。</translation>
<translation id="7372973238305370288">æœç´¢ç»“æžœ</translation>
<translation id="7374733840632556089">此问题是由您或他人在您设备上安装的æŸä¸ªè¯ä¹¦å¯¼è‡´çš„。该è¯ä¹¦å·²çŸ¥è¢«ç”¨äºŽç›‘控和拦截网络,因此ä¸å— Chrome 信任。尽管æŸäº›æƒ…况下的监控确实是åˆç†çš„(例如监控学校网络或公å¸ç½‘络),但 Chrome 想确ä¿æ‚¨çŸ¥é“自己正被监控,å³ä½¿æ‚¨æ— æ³•æ”¹å˜è¿™ä¸€äº‹å®žã€‚监控å¯èƒ½ä¼šå‘生在已è”网的任何æµè§ˆå™¨æˆ–应用中。</translation>
<translation id="7375818412732305729">附加文件</translation>
@@ -1722,6 +1751,7 @@
<translation id="7976214039405368314">请求次数过多</translation>
<translation id="7977538094055660992">输出设备</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">è¦æŸ¥çœ‹å¢žå¼ºçŽ°å®žå†…容,请安装 ARCore</translation>
<translation id="799149739215780103">装订</translation>
<translation id="7995512525968007366">未指定</translation>
<translation id="800218591365569300">请å°è¯•å…³é—­å…¶ä»–标签页或程åºä»¥é‡Šæ”¾å†…存。</translation>
@@ -1849,25 +1879,39 @@
<translation id="8507227106804027148">命令行</translation>
<translation id="8508648098325802031">æœç´¢å›¾æ ‡</translation>
<translation id="8522552481199248698">Chrome å¯ä»¥å¸®åŠ©æ‚¨ä¿æŠ¤æ‚¨çš„ Google å¸å·å’Œæ›´æ”¹å¯†ç ã€‚</translation>
+<translation id="8525306231823319788">å…¨å±</translation>
<translation id="8530813470445476232">请在 Chrome 设置中清除您的æµè§ˆè®°å½•ã€Cookieã€ç¼“å­˜åŠå…¶ä»–æ•°æ®</translation>
<translation id="8533619373899488139">请访问 &lt;strong&gt;chrome://policy&lt;/strong&gt;,查看被å±è”½çš„网å€åˆ—表以åŠæ‚¨çš„系统管ç†å‘˜å¼ºåˆ¶æ‰§è¡Œçš„其他政策。</translation>
<translation id="8541158209346794904">è“牙设备</translation>
<translation id="8542014550340843547">三钉(底部)</translation>
<translation id="8543181531796978784">您å¯ä»¥<ph name="BEGIN_ERROR_LINK" />报告检测问题<ph name="END_ERROR_LINK" />;或者,如果您了解自己将é¢ä¸´çš„安全风险,则å¯ä»¥<ph name="BEGIN_LINK" />访问这个ä¸å®‰å…¨çš„网站<ph name="END_LINK" />。</translation>
<translation id="8557066899867184262">银行å¡éªŒè¯ç  (CVC) ä½äºŽé“¶è¡Œå¡èƒŒé¢ã€‚</translation>
+<translation id="8558485628462305855">è¦æŸ¥çœ‹å¢žå¼ºçŽ°å®žå†…容,请更新 ARCore</translation>
<translation id="8559762987265718583">您设备的日期和时间(<ph name="DATE_AND_TIME" />)ä¸æ­£ç¡®ï¼Œå› æ­¤æ— æ³•ä¸Ž <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§å¯†è¿žæŽ¥ã€‚</translation>
<translation id="8564182942834072828">å•ç‹¬çš„文档/éžé€ä»½æ‰“å°çš„副本</translation>
<translation id="8564985650692024650">如果您在其他网站上é‡å¤ä½¿ç”¨äº†æ‚¨çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密ç ï¼ŒChromium 建议您é‡ç½®è¯¥å¯†ç ã€‚</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ 系统ä¸ä¼šå°†ä»¥ä¸‹æ´»åŠ¨è®°å½•ä¿å­˜åˆ°æ­¤è®¾å¤‡ä¸Šï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您在该窗å£ä¸­æŸ¥çœ‹çš„网页
+ <ph name="LIST_ITEM" />Cookie 和网站数æ®
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">使用 Touch ID 更快地确认银行å¡</translation>
<translation id="858637041960032120">添加电è¯å·ç 
</translation>
<translation id="8589998999637048520">最佳的质é‡</translation>
+<translation id="8600271352425265729">ä»…é™è¿™ä¸€æ¬¡</translation>
<translation id="860043288473659153">æŒå¡äººå§“å</translation>
<translation id="8606726445206553943">使用您的 MIDI 设备</translation>
+<translation id="8612761427948161954">尊敬的<ph name="USERNAME" />:
+ <ph name="BR" />
+ 您好ï¼æ‚¨æ­£åœ¨ä»¥è®¿å®¢èº«ä»½æµè§ˆ</translation>
<translation id="861775596732816396">大å°ï¼š4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">没有匹é…的密ç ã€‚显示所有已ä¿å­˜çš„密ç ã€‚</translation>
<translation id="8625384913736129811">将此å¡çš„ä¿¡æ¯ä¿å­˜åˆ°è¯¥è®¾å¤‡</translation>
+<translation id="8627040765059109009">å±å¹•æˆªå–功能已æ¢å¤</translation>
<translation id="8657078576661269990">您的管ç†å‘˜å·²ç¦æ­¢å°† <ph name="ORIGIN_NAME" /> 的内容共享给 <ph name="VM_NAME_1" /> å’Œ <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">订å•æ‘˜è¦ï¼Œ<ph name="TOTAL_LABEL" />,更多详情</translation>
<translation id="867224526087042813">ç­¾å</translation>
@@ -1930,6 +1974,7 @@
<translation id="8912362522468806198">Google å¸å·</translation>
<translation id="8913778647360618320">“管ç†ä»˜æ¬¾æ–¹å¼â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯åœ¨ Chrome 设置中管ç†æ‚¨çš„付款和信用å¡ä¿¡æ¯</translation>
<translation id="8918231688545606538">此网页å¯ç–‘</translation>
+<translation id="8922013791253848639">在此网站上始终å…许显示广告</translation>
<translation id="892588693504540538">打孔(å³ä¸Šè§’)</translation>
<translation id="8931333241327730545">è¦å°†æ­¤å¡çš„ä¿¡æ¯ä¿å­˜åˆ°æ‚¨çš„ Google å¸å·å—?</translation>
<translation id="8932102934695377596">您的时钟慢了</translation>
@@ -2001,6 +2046,7 @@
<translation id="9183302530794969518">Google 文档</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> 使用了ä¸å—支æŒçš„å议。</translation>
<translation id="9191834167571392248">打孔(左下角)</translation>
+<translation id="9199905725844810519">打å°åŠŸèƒ½å·²è¢«ç¦ç”¨</translation>
<translation id="9205078245616868884">您的数æ®å·²ä½¿ç”¨æ‚¨çš„åŒæ­¥å¯†ç åŠ å¯†ã€‚输入该密ç å³å¯å¼€å§‹åŒæ­¥ã€‚</translation>
<translation id="9207861905230894330">无法添加文章。</translation>
<translation id="9213433120051936369">自定义外观</translation>
@@ -2011,8 +2057,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">您å¯èƒ½ä¼šæ— æ³•å†è®¿é—®è‡ªå·±çš„ Google å¸å·ã€‚Chromium 建议您立å³æ›´æ”¹å¯†ç ã€‚系统会è¦æ±‚您登录。</translation>
<translation id="939736085109172342">新建文件夹</translation>
+<translation id="945522503751344254">å‘é€å馈</translation>
<translation id="945855313015696284">请查看下é¢çš„ä¿¡æ¯ï¼Œå¹¶åˆ é™¤æ‰€æœ‰æ— æ•ˆå¡ç‰‡</translation>
<translation id="950736567201356821">三孔(顶部)</translation>
+<translation id="951941430552851965">为了ä¿æŠ¤æ‚¨å±å¹•ä¸Šçš„内容,管ç†å‘˜å·²æš‚åœå±å¹•æˆªå–功能。</translation>
<translation id="961663415146723894">装订(底部)</translation>
<translation id="962484866189421427">此内容å¯èƒ½ä¼šå°è¯•å®‰è£…欺骗性应用,而这些应用能够冒充其他内容或收集å¯ç”¨äºŽå¯¹æ‚¨è¿›è¡Œè·Ÿè¸ªçš„æ•°æ®ã€‚<ph name="BEGIN_LINK" />ä»ç„¶æ˜¾ç¤º<ph name="END_LINK" /></translation>
<translation id="969892804517981540">æ­£å¼ç‰ˆæœ¬</translation>
diff --git a/chromium/components/strings/components_strings_zh-HK.xtb b/chromium/components/strings/components_strings_zh-HK.xtb
index c2eace87499..f4cb36e6bcb 100644
--- a/chromium/components/strings/components_strings_zh-HK.xtb
+++ b/chromium/components/strings/components_strings_zh-HK.xtb
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">您輸入密碼的網站並éžç”±æ‚¨çš„機構管ç†ã€‚為ä¿è­·æ‚¨çš„帳戶,請勿在其他應用程å¼å’Œç¶²ç«™ä¸Šé‡ç”¨å¯†ç¢¼ã€‚</translation>
<translation id="1263231323834454256">閱讀清單</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ è£ç½®å°‡ä¸æœƒå„²å­˜ä»¥ä¸‹æ´»å‹•ï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您在此視窗ç€è¦½çš„網é 
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />帳戶資料 (<ph name="LINK_BEGIN" />登出<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">å–貨方å¼</translation>
<translation id="1281476433249504884">堆疊器 1</translation>
<translation id="1285320974508926690">æ°¸ä¸ç¿»è­¯æ­¤ç¶²ç«™</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">登入å³å¯ä½¿ç”¨å„²å­˜åœ¨ Google 帳戶中的密碼</translation>
<translation id="2053111141626950936">系統將ä¸æœƒç¿»è­¯<ph name="LANGUAGE" />網é ã€‚</translation>
<translation id="2053553514270667976">郵éžå€è™Ÿ</translation>
+<translation id="2054665754582400095">您的狀態</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 個建議}other{# 個建議}}</translation>
<translation id="2079545284768500474">復原</translation>
<translation id="20817612488360358">雖然系統 Proxy 設定已設為使用,ä¸éŽä¹ŸæŒ‡å®šäº†æ˜Žç¢ºçš„ Proxy 設定。</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android 應用程å¼</translation>
<translation id="2107021941795971877">列å°æ”¯æ´</translation>
<translation id="2108755909498034140">é‡æ–°å•Ÿå‹•æ‚¨çš„電腦</translation>
+<translation id="2111166930115883695">按一下空格éµå³å¯é–‹å§‹éŠæˆ²</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">å¡ç‰‡</translation>
<translation id="2114841414352855701">由於政策已被「<ph name="POLICY_NAME" />ã€è¦†å¯«ï¼Œå› æ­¤è¢«ç•¥éŽã€‚</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">å–消付款</translation>
<translation id="2147827593068025794">背景åŒæ­¥è™•ç†</translation>
<translation id="2148613324460538318">新增付款å¡</translation>
+<translation id="2149968176347646218">連線ä¸å®‰å…¨</translation>
<translation id="2154054054215849342">您的網域無法使用åŒæ­¥è™•ç†åŠŸèƒ½</translation>
<translation id="2154484045852737596">編輯付款信用å¡</translation>
<translation id="2161656808144014275">文字</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">政策</translation>
<translation id="2183608646556468874">電話號碼</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 個地å€}other{# 個地å€}}</translation>
-<translation id="2187243482123994665">使用者狀態</translation>
<translation id="2187317261103489799">åµæ¸¬ (é è¨­)</translation>
<translation id="2188375229972301266">多孔 (底部)</translation>
<translation id="2202020181578195191">請輸入有效的到期年份</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">您將è¦ç€è¦½å‡ç¶²ç«™</translation>
<translation id="2850739647070081192">Invite (ä¿¡å°)</translation>
<translation id="2856444702002559011">攻擊者å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–您的資料 (例如密碼ã€è¨Šæ¯æˆ–信用å¡è³‡æ–™)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">此網站顯示滋擾性或誤導廣告。</translation>
<translation id="2878197950673342043">å字摺</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">放置視窗</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google æ供的建議</translation>
<translation id="3002501248619246229">檢查輸入紙匣媒體</translation>
<translation id="3005723025932146533">顯示儲存的複本</translation>
-<translation id="3007719053326478567">管ç†å“¡å·²ç¦æ­¢åˆ—å°æ­¤å…§å®¹</translation>
<translation id="3008447029300691911">請輸入 <ph name="CREDIT_CARD" /> 的信用å¡é©—證碼 (CVC)。完æˆé©—證後,系統會與這個網站共用您的信用å¡è³‡æ–™ã€‚</translation>
<translation id="3010559122411665027">清單項目「<ph name="ENTRY_INDEX" />ã€ï¼š<ph name="ERROR" /></translation>
<translation id="301521992641321250">已自動å°éŽ–</translation>
<translation id="3016780570757425217">掌æ¡æ‚¨çš„ä½ç½®</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />,按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯ç§»é™¤å»ºè­°ã€‚</translation>
<translation id="3023071826883856138">You4 (ä¿¡å°)</translation>
<translation id="3024663005179499861">政策類型有誤</translation>
<translation id="3037605927509011580">糟糕ï¼</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">已加入書籤</translation>
<translation id="3209034400446768650">網é å¯èƒ½æœƒæ”¶å–費用</translation>
<translation id="3212581601480735796">您在 <ph name="HOSTNAME" /> 上進行的活動正å—監控</translation>
+<translation id="3212623355668894776">åªè¦é—œé–‰æ‰€æœ‰è¨ªå®¢è¦–窗,您的ç€è¦½æ´»å‹•å°±æœƒå¾žæ­¤è£ç½®ä¸­åˆªé™¤ã€‚</translation>
<translation id="3215092763954878852">無法使用 WebAuthn</translation>
<translation id="3218181027817787318">相å°</translation>
<translation id="3225919329040284222">伺æœå™¨æ供的憑證與內置的é æœŸæ¢ä»¶ä¸ç¬¦ã€‚我們在特定高安全性的網站內置了這些é æœŸæ¢ä»¶ï¼Œä»¥ä¿è­·æ‚¨çš„資料安全無虞。</translation>
@@ -695,6 +707,7 @@
<translation id="3784372983762739446">è—牙è£ç½®</translation>
<translation id="3787705759683870569">到期日:<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">粗幼:16</translation>
+<translation id="3789841737615482174">安è£</translation>
<translation id="3793574014653384240">最近發生的當機次數和原因</translation>
<translation id="3797522431967816232">Prc3 (ä¿¡å°)</translation>
<translation id="3799805948399000906">è¦æ±‚çš„å­—åž‹</translation>
@@ -745,6 +758,7 @@
<translation id="4056223980640387499">棕è¤è‰²</translation>
<translation id="4058922952496707368">金鑰「<ph name="SUBKEY" />ã€ï¼š<ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ä¿¡å°)</translation>
+<translation id="4067669230157909013">已繼續擷å–螢幕畫é¢ã€‚</translation>
<translation id="4067947977115446013">新增有效的地å€</translation>
<translation id="4072486802667267160">處ç†æ‚¨çš„訂單時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚</translation>
<translation id="4075732493274867456">用戶端和伺æœå™¨ä¸æ”¯æ´å…±é€š SSL 通訊å”定版本或加密套件。</translation>
@@ -825,6 +839,7 @@
<translation id="4297502707443874121">第 <ph name="THUMBNAIL_PAGE" /> é å˜…縮圖</translation>
<translation id="42981349822642051">展開</translation>
<translation id="4300675098767811073">多孔 (å³å´)</translation>
+<translation id="4302514097724775343">輕按æé¾å³å¯é–‹å§‹éŠæˆ²</translation>
<translation id="4302965934281694568">Chou3 (ä¿¡å°)</translation>
<translation id="4305666528087210886">無法存å–您的檔案</translation>
<translation id="4305817255990598646">切æ›</translation>
@@ -903,6 +918,7 @@
<translation id="4658638640878098064">é‡˜è£ (左上方)</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">虛擬實境</translation>
+<translation id="4675657451653251260">在訪客模å¼ä¸­ï¼Œæ‚¨å°‡ä¸æœƒçœ‹åˆ°ä»»ä½• Chrome 設定檔的資料。您å¯<ph name="LINK_BEGIN" />登入<ph name="LINK_END" />ä»¥å­˜å– Google 帳戶資料,例如密碼和付款方法。</translation>
<translation id="467662567472608290">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;伺æœå™¨çš„安全性憑證å«æœ‰éŒ¯èª¤ã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="4677585247300749148"><ph name="URL" /> 希望回應無障礙功能事件</translation>
<translation id="467809019005607715">Google ç°¡å ±</translation>
@@ -930,6 +946,12 @@
<translation id="4761104368405085019">使用您的麥克風</translation>
<translation id="4764776831041365478"><ph name="URL" /> 的網é å¯èƒ½æš«æ™‚無法使用或被永久移至新網å€ã€‚</translation>
<translation id="4766713847338118463">雙釘 (底部)</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ æ­¤è£ç½®å°‡æœƒå„²å­˜ä»¥ä¸‹æ´»å‹•ï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />在此視窗下載的任何檔案
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">發生ä¸æ˜Žçš„錯誤。</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{å·²å°éŽ–彈出å¼è¦–窗}other{å·²å°éŽ– # 個彈出å¼è¦–窗}}</translation>
<translation id="4780366598804516005">出紙槽 1</translation>
@@ -1092,11 +1114,13 @@
<translation id="5386426401304769735">此網站的憑證éˆå…§åŒ…å«ä½¿ç”¨ SHA-1 簽署的憑證。</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">é‚Šç·£é‡˜è£ (å³å´)</translation>
+<translation id="5398772614898833570">å·²å°éŽ–廣告</translation>
<translation id="5400836586163650660">ç°è‰²</translation>
<translation id="540969355065856584">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證目å‰ç„¡æ•ˆã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="541416427766103491">堆疊器 4</translation>
<translation id="5421136146218899937">清除ç€è¦½æ•¸æ“šâ€¦</translation>
<translation id="5426179911063097041"><ph name="SITE" /> è¦æ±‚傳é€é€šçŸ¥çµ¦æ‚¨</translation>
+<translation id="542872847390508405">您目å‰æ˜¯ä»¥è¨ªå®¢èº«åˆ†ç€è¦½</translation>
<translation id="5430298929874300616">移除書籤</translation>
<translation id="5439770059721715174">「<ph name="ERROR_PATH" />ã€ç™¼ç”Ÿç¶±è¦é©—證錯誤:<ph name="ERROR" /></translation>
<translation id="5443468954631487277">相åé †åº (æ­£é¢æœä¸Š)</translation>
@@ -1138,12 +1162,12 @@
<translation id="5571083550517324815">無法在此地å€å–貨,請é¸å–其他地å€ã€‚</translation>
<translation id="5580958916614886209">請檢查您的到期月份,然後å†è©¦ä¸€æ¬¡</translation>
<translation id="5586446728396275693">沒有已儲存的地å€</translation>
+<translation id="5593349413089863479">連線å¯èƒ½æœ‰å®‰å…¨æ¼æ´ž</translation>
<translation id="5595485650161345191">編輯地å€</translation>
<translation id="5598944008576757369">é¸æ“‡ä»˜æ¬¾æ–¹æ³•</translation>
<translation id="560412284261940334">系統ä¸æ”¯æ´ç®¡ç†</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">這å¯èƒ½æ˜¯å½é€ æˆ–è©é¨™ç¶²ç«™ï¼ŒChrome 建議您立å³é›¢é–‹ã€‚</translation>
<translation id="5610142619324316209">檢查連線狀態</translation>
<translation id="5610807607761827392">您å¯åœ¨ã€Œ<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />ã€ä¸­ç®¡ç†å片和地å€ã€‚</translation>
<translation id="561165882404867731">使用「Google 翻譯ã€ä¾†ç¿»è­¯æ­¤é é¢</translation>
@@ -1215,6 +1239,7 @@
<translation id="5901630391730855834">黃色</translation>
<translation id="5905445707201418379">已根據 <ph name="ORIGIN" /> 的安全政策å°éŽ–。</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (å·²åŒæ­¥)</translation>
+<translation id="5913377024445952699">已暫åœæ“·å–螢幕畫é¢</translation>
<translation id="59174027418879706">已啟用</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">é–‹å•Ÿ</translation>
@@ -1227,6 +1252,7 @@
<translation id="5963413905009737549">å€æ®µ</translation>
<translation id="5967592137238574583">編輯è¯çµ¡äººè³‡æ–™</translation>
<translation id="5967867314010545767">從記錄中移除</translation>
+<translation id="5968793460449681917">æ¯æ¬¡ç€è¦½</translation>
<translation id="5975083100439434680">縮å°</translation>
<translation id="5979084224081478209">檢查密碼</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1382,6 +1408,7 @@
<translation id="6587923378399804057">您複製的連çµ</translation>
<translation id="6591833882275308647">您的 <ph name="DEVICE_TYPE" /> 未å—管ç†</translation>
<translation id="6596325263575161958">加密é¸é …</translation>
+<translation id="6596892391065203054">管ç†å“¡å·²ç¦æ­¢åˆ—å°æ­¤å…§å®¹ã€‚</translation>
<translation id="6604181099783169992">動態或光線感應器</translation>
<translation id="6609880536175561541">Prc7 (ä¿¡å°)</translation>
<translation id="6612358246767739896">å—ä¿è­·å…§å®¹</translation>
@@ -1441,6 +1468,7 @@
<translation id="6895330447102777224">您的信用å¡å·²å®Œæˆé©—è­‰</translation>
<translation id="6897140037006041989">使用者代ç†ç¨‹å¼</translation>
<translation id="6898699227549475383">機構 (O)</translation>
+<translation id="6907293445143367439">å…許 <ph name="SITE_NAME" /> 執行以下æ“作:</translation>
<translation id="6910240653697687763"><ph name="URL" /> è¦æ±‚全權控制 MIDI è£ç½®</translation>
<translation id="6915804003454593391">使用者:</translation>
<translation id="6934672428414710184">æ­¤å稱來自您的 Google 賬戶</translation>
@@ -1552,6 +1580,7 @@
<translation id="7346048084945669753">是å¦å·²å»ºç«‹é—œè¯ï¼š</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">命令列</translation>
+<translation id="7359588939039777303">å·²å°éŽ–廣告。</translation>
<translation id="7372973238305370288">æœå°‹çµæžœ</translation>
<translation id="7374733840632556089">æ­¤å•é¡Œç”±æ‚¨æˆ–其他人在è£ç½®ä¸Šå®‰è£çš„憑證而導致。由於憑證曾用作監控åŠç¶²çµ¡æ””截,因此ä¸ç² Chrome 信任。雖然有些監控ç†ç”±åˆç† (例如學校或公å¸ç¶²çµ¡),且無法åœæ­¢æœ‰é—œç›£æŽ§ï¼Œä½† Chrome ä»å¸Œæœ›å°±æ­¤é€šçŸ¥æ‚¨ã€‚任何使用網絡的ç€è¦½å™¨å’Œæ‡‰ç”¨ç¨‹å¼éƒ½å¯èƒ½å—到監控。</translation>
<translation id="7375818412732305729">已附加檔案</translation>
@@ -1726,6 +1755,7 @@
<translation id="7976214039405368314">è¦æ±‚數é‡éŽå¤š</translation>
<translation id="7977538094055660992">輸出è£ç½®</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">如è¦è§€çœ‹æ“´å¼µå¯¦å¢ƒå…§å®¹ï¼Œè«‹å…ˆå®‰è£ ARCore</translation>
<translation id="799149739215780103">釘è£</translation>
<translation id="7995512525968007366">未指定 </translation>
<translation id="800218591365569300">嘗試關閉其他分é æˆ–應用程å¼ï¼Œä»¥é‡‹å‡ºè¨˜æ†¶é«”。</translation>
@@ -1853,24 +1883,38 @@
<translation id="8507227106804027148">指令列</translation>
<translation id="8508648098325802031">æœå°‹åœ–示</translation>
<translation id="8522552481199248698">Chrome å¯åŠ©æ‚¨ä¿è­· Google 帳戶並變更密碼。</translation>
+<translation id="8525306231823319788">全螢幕</translation>
<translation id="8530813470445476232">清除您的ç€è¦½è¨˜éŒ„ã€Cookieã€å¿«å–以åŠå…¶ä»– Chrome 設定</translation>
<translation id="8533619373899488139">è«‹å‰å¾€ &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看被å°éŽ–的網å€æ¸…單,以åŠç”±ç³»çµ±ç®¡ç†å“¡å¼·åˆ¶åŸ·è¡Œçš„其他政策。</translation>
<translation id="8541158209346794904">è—牙è£ç½®</translation>
<translation id="8542014550340843547">三釘 (底部)</translation>
<translation id="8543181531796978784">您å¯ä»¥<ph name="BEGIN_ERROR_LINK" />報告åµæ¸¬å•é¡Œ<ph name="END_ERROR_LINK" />;或如果您瞭解安全性風險,也å¯ä»¥<ph name="BEGIN_LINK" />ç€è¦½é€™å€‹ä¸å®‰å…¨çš„網站<ph name="END_LINK" />。</translation>
<translation id="8557066899867184262">信用å¡é©—證碼 (CVC) ä½æ–¼ä¿¡ç”¨å¡èƒŒé¢ã€‚</translation>
+<translation id="8558485628462305855">如è¦è§€çœ‹æ“´å¼µå¯¦å¢ƒå…§å®¹ï¼Œè«‹å…ˆæ›´æ–° ARCore</translation>
<translation id="8559762987265718583">您è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•å»ºç«‹ç§äººé€£ç·šè‡³ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />。</translation>
<translation id="8564182942834072828">個別文件/未自動分é çš„副本</translation>
<translation id="8564985650692024650">如果您已在其他網站上é‡ç”¨ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chromium 建議您é‡è¨­å¯†ç¢¼ã€‚</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ æ­¤è£ç½®å°‡ä¸æœƒå„²å­˜ä»¥ä¸‹æ´»å‹•ï¼š
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您在此視窗ç€è¦½çš„網é 
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">使用 Touch ID å³å¯åŠ å¿«ç¢ºèªæ‚¨çš„付款å¡</translation>
<translation id="858637041960032120">新增電話號碼</translation>
<translation id="8589998999637048520">最佳å“質</translation>
+<translation id="8600271352425265729">僅é™é€™æ¬¡</translation>
<translation id="860043288473659153">æŒå¡äººå§“å</translation>
<translation id="8606726445206553943">使用您的 MIDI è£ç½®</translation>
+<translation id="8612761427948161954"><ph name="USERNAME" />,您好,
+ <ph name="BR" />
+ 您目å‰æ˜¯ä»¥è¨ªå®¢èº«åˆ†ç€è¦½</translation>
<translation id="861775596732816396">粗幼:4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">沒有相符的密碼。顯示所有已儲存的密碼。</translation>
<translation id="8625384913736129811">將這張信用å¡å„²å­˜è‡³æ­¤è£ç½®</translation>
+<translation id="8627040765059109009">已繼續擷å–螢幕畫é¢</translation>
<translation id="8657078576661269990">管ç†å“¡å·²ç¦æ­¢å°‡ <ph name="ORIGIN_NAME" /> 的內容分享至 <ph name="VM_NAME_1" /> å’Œ <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">訂單摘è¦ã€<ph name="TOTAL_LABEL" /> åŠæ›´å¤šè©³æƒ…</translation>
<translation id="867224526087042813">ç°½å</translation>
@@ -1933,6 +1977,7 @@
<translation id="8912362522468806198">Google 帳戶</translation>
<translation id="8913778647360618320">管ç†ä»˜æ¬¾æ–¹æ³•æŒ‰éˆ•ï¼Œã©’一下 Enter éµå°±å¯ä»¥å–º Chrome 設定度管ç†ä»˜æ¬¾åŒä¿¡ç”¨å¡è³‡æ–™</translation>
<translation id="8918231688545606538">此網é åŒ…å«å¯ç–‘的內容</translation>
+<translation id="8922013791253848639">一律å…許在此網站中顯示廣告</translation>
<translation id="892588693504540538">打孔 (å³ä¸Šæ–¹)</translation>
<translation id="8931333241327730545">è¦å°‡æ­¤ä¿¡ç”¨å¡å„²å­˜è‡³æ‚¨çš„ Google 帳戶嗎?</translation>
<translation id="8932102934695377596">您時é˜çš„時間éŽæ…¢</translation>
@@ -2004,6 +2049,7 @@
<translation id="9183302530794969518">Google 文件</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> 使用ä¸æ”¯æ´çš„通訊å”定。</translation>
<translation id="9191834167571392248">打孔 (左下方)</translation>
+<translation id="9199905725844810519">å·²å°éŽ–列å°åŠŸèƒ½</translation>
<translation id="9205078245616868884">您已使用åŒæ­¥å¯†ç¢¼çŸ­èªžåŠ å¯†è³‡æ–™ï¼Œè«‹è¼¸å…¥å¯†ç¢¼çŸ­èªžé–‹å§‹åŒæ­¥è³‡æ–™ã€‚</translation>
<translation id="9207861905230894330">無法新增文章。</translation>
<translation id="9213433120051936369">自訂外觀</translation>
@@ -2014,8 +2060,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">您å¯èƒ½æœƒå¤±åŽ» Google 帳戶存å–權。Chromium 建議您立å³è®Šæ›´å¯†ç¢¼ã€‚系統會è¦æ±‚您登入。</translation>
<translation id="939736085109172342">新增資料夾</translation>
+<translation id="945522503751344254">æä¾›æ„見å映</translation>
<translation id="945855313015696284">請查看以下資料,並刪除無效的付款å¡ã€‚</translation>
<translation id="950736567201356821">三孔 (頂端)</translation>
+<translation id="951941430552851965">管ç†å“¡å› ç•«é¢ä¸Šçš„內容,已暫åœæ“·å–螢幕畫é¢ã€‚</translation>
<translation id="961663415146723894">é‡˜è£ (底部)</translation>
<translation id="962484866189421427">此內容å¯èƒ½æœƒå˜—試安è£æ¬ºè©æ‡‰ç”¨ç¨‹å¼ä¾†å†’充其他內容,或收集å¯ç”¨ä¾†è¿½è¹¤æ‚¨çš„資料。<ph name="BEGIN_LINK" />一律顯示<ph name="END_LINK" /></translation>
<translation id="969892804517981540">æ­£å¼ç‰ˆæœ¬</translation>
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index d6207ac84c7..7cd13ecf4dd 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -65,7 +65,7 @@
<translation id="121201262018556460">你嘗試å‰å¾€ <ph name="DOMAIN" />,但伺æœå™¨æ‰€æ供的憑證å«æœ‰é˜²è­·åŠ›è–„弱的金鑰。攻擊者å¯èƒ½å·²ç ´å£žç§å¯†é‡‘鑰,而該伺æœå™¨å¯èƒ½ä¸¦éžä½ çš„目標伺æœå™¨ (你的連線å°è±¡å¯èƒ½æ˜¯æ”»æ“Šè€…的電腦)。</translation>
<translation id="1219129156119358924">系統安全性</translation>
<translation id="1227224963052638717">ä¸æ˜Žæ”¿ç­–。</translation>
-<translation id="1228893227497259893">實體識別碼錯誤</translation>
+<translation id="1228893227497259893">實體 ID 錯誤</translation>
<translation id="1232569758102978740">未命å</translation>
<translation id="1236081509407217141">è¦å…許 VR 嗎?</translation>
<translation id="1240347957665416060">ä½ çš„è£ç½®å稱</translation>
@@ -80,6 +80,14 @@
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">你在ä¸æ˜¯ç”±è²´æ©Ÿæ§‹ç®¡ç†çš„網站上輸入了你的密碼。為確ä¿å¸³æˆ¶å®‰å…¨ï¼Œè«‹å‹¿åœ¨å…¶ä»–應用程å¼å’Œç¶²ç«™ä¸Šé‡è¤‡ä½¿ç”¨ä½ çš„密碼。</translation>
<translation id="1263231323834454256">閱讀清單</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ 這部è£ç½®ä¸æœƒå„²å­˜çš„活動:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />你在這個視窗中ç€è¦½çš„é é¢
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />帳戶資訊 (<ph name="LINK_BEGIN" />登出<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">å–件方å¼</translation>
<translation id="1281476433249504884">堆疊出紙器 1</translation>
<translation id="1285320974508926690">一律ä¸ç¿»è­¯æ­¤ç¶²ç«™</translation>
@@ -279,6 +287,7 @@
<translation id="204357726431741734">登入以使用儲存在 Google 帳戶中的密碼</translation>
<translation id="2053111141626950936">系統ä¸æœƒç¿»è­¯<ph name="LANGUAGE" />網é ã€‚</translation>
<translation id="2053553514270667976">郵éžå€è™Ÿ</translation>
+<translation id="2054665754582400095">你的使用狀態</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 個建議項目}other{# 個建議項目}}</translation>
<translation id="2079545284768500474">復原</translation>
<translation id="20817612488360358">雖然系統 Proxy 設定已設為使用,ä¸éŽä¹ŸæŒ‡å®šäº†æ˜Žç¢º Proxy 設定。</translation>
@@ -292,6 +301,7 @@
<translation id="2102495993840063010">Android 應用程å¼</translation>
<translation id="2107021941795971877">列å°æ”¯æ´</translation>
<translation id="2108755909498034140">é‡æ–°å•Ÿå‹•é›»è…¦</translation>
+<translation id="2111166930115883695">按下空格éµå³å¯é–‹å§‹éŠæˆ²</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">信用å¡</translation>
<translation id="2114841414352855701">由於政策被「<ph name="POLICY_NAME" />ã€è¦†å¯«äº†ï¼Œå› æ­¤é­åˆ°ç•¥éŽã€‚</translation>
@@ -303,6 +313,7 @@
<translation id="214556005048008348">å–消付款</translation>
<translation id="2147827593068025794">背景åŒæ­¥è™•ç†</translation>
<translation id="2148613324460538318">新增å¡ç‰‡</translation>
+<translation id="2149968176347646218">連線ä¸å®‰å…¨</translation>
<translation id="2154054054215849342">你的網域無法使用åŒæ­¥åŠŸèƒ½</translation>
<translation id="2154484045852737596">編輯å¡ç‰‡è³‡è¨Š</translation>
<translation id="2161656808144014275">文字</translation>
@@ -313,7 +324,6 @@
<translation id="2181821976797666341">政策</translation>
<translation id="2183608646556468874">電話號碼</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 個地å€}other{# 個地å€}}</translation>
-<translation id="2187243482123994665">使用者狀態</translation>
<translation id="2187317261103489799">åµæ¸¬ (é è¨­)</translation>
<translation id="2188375229972301266">多孔 (底部)</translation>
<translation id="2202020181578195191">請輸入有效的到期年份</translation>
@@ -464,6 +474,7 @@
<translation id="2839501879576190149">ä½ è¦é€ è¨ªçš„是å½é€ çš„網站</translation>
<translation id="2850739647070081192">Invite (ä¿¡å°)</translation>
<translation id="2856444702002559011">攻擊者å¯èƒ½æœƒè©¦åœ–從 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–你的資訊 (例如密碼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">這個網站會顯示干擾性或誤導性的廣告。</translation>
<translation id="2878197950673342043">å字摺</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">放置視窗</translation>
@@ -502,11 +513,11 @@
<translation id="2996674880327704673">Google 建議的項目</translation>
<translation id="3002501248619246229">檢查輸入紙匣媒體</translation>
<translation id="3005723025932146533">顯示儲存的複本</translation>
-<translation id="3007719053326478567">系統管ç†å“¡å·²ç¦æ­¢åˆ—å°æ­¤å…§å®¹</translation>
<translation id="3008447029300691911">請輸入 <ph name="CREDIT_CARD" /> 的信用å¡é©—證碼。您確èªå¾Œï¼Œé€™å€‹ç¶²ç«™å°±å¯ä»¥å–得您的信用å¡è©³ç´°è³‡è¨Šã€‚</translation>
<translation id="3010559122411665027">清單項目「<ph name="ENTRY_INDEX" />ã€ï¼š<ph name="ERROR" /></translation>
<translation id="301521992641321250">已自動å°éŽ–</translation>
<translation id="3016780570757425217">å­˜å–您的ä½ç½®è³‡è¨Š</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />,按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯ç§»é™¤å»ºè­°é …目。</translation>
<translation id="3023071826883856138">You4 (ä¿¡å°)</translation>
<translation id="3024663005179499861">政策類型有誤</translation>
<translation id="3037605927509011580">糟糕ï¼</translation>
@@ -549,6 +560,7 @@
<translation id="3207960819495026254">已加入書籤</translation>
<translation id="3209034400446768650">這個é é¢å¯èƒ½æœƒç”¢ç”Ÿè²»ç”¨</translation>
<translation id="3212581601480735796">你在 <ph name="HOSTNAME" /> 上進行的活動正é­åˆ°ç›£æŽ§</translation>
+<translation id="3212623355668894776">åªè¦é—œé–‰æ‰€æœ‰è¨ªå®¢è¦–窗,你的ç€è¦½æ´»å‹•å°±æœƒå¾žé€™éƒ¨è£ç½®åˆªé™¤ã€‚</translation>
<translation id="3215092763954878852">無法使用 WebAuthn</translation>
<translation id="3218181027817787318">相å°</translation>
<translation id="3225919329040284222">伺æœå™¨å‘ˆç¾çš„憑證與內建的é æœŸæ¢ä»¶ä¸ç¬¦ã€‚我們在系統中é‡å°ç‰¹å®šé«˜å®‰å…¨æ€§çš„網站內建了這些é æœŸæ¢ä»¶ï¼Œç›®çš„在於ä¿è­·ä½ çš„資料安全無虞。</translation>
@@ -696,6 +708,7 @@
<translation id="3784372983762739446">è—牙è£ç½®</translation>
<translation id="3787705759683870569">到期日:<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">粗細:16</translation>
+<translation id="3789841737615482174">安è£</translation>
<translation id="3793574014653384240">最近發生當機情形的次數和原因</translation>
<translation id="3797522431967816232">Prc3 (ä¿¡å°)</translation>
<translation id="3799805948399000906">è¦æ±‚çš„å­—åž‹</translation>
@@ -710,7 +723,7 @@
<translation id="3832522519263485449">多孔 (å·¦å´)</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3858027520442213535">更新日期和時間</translation>
-<translation id="3884278016824448484">è£ç½®è­˜åˆ¥ç¢¼ç™¼ç”Ÿè¡çª</translation>
+<translation id="3884278016824448484">è£ç½® ID 發生è¡çª</translation>
<translation id="3885155851504623709">æ•™å€</translation>
<translation id="388632593194507180">åµæ¸¬åˆ°ä½ æ­£é­åˆ°ç›£æŽ§</translation>
<translation id="3886948180919384617">堆疊出紙器 3</translation>
@@ -746,6 +759,7 @@
<translation id="4056223980640387499">æ·±è¤è‰²èª¿</translation>
<translation id="4058922952496707368">éµã€Œ<ph name="SUBKEY" />ã€ï¼š<ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (ä¿¡å°)</translation>
+<translation id="4067669230157909013">已繼續擷å–螢幕畫é¢ã€‚</translation>
<translation id="4067947977115446013">新增有效的地å€</translation>
<translation id="4072486802667267160">處ç†ä½ çš„訂單時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚</translation>
<translation id="4075732493274867456">用戶端和伺æœå™¨ä¸æ”¯æ´ä¸€èˆ¬ SSL 通訊å”定版本或加密套件。</translation>
@@ -826,6 +840,7 @@
<translation id="4297502707443874121">第 <ph name="THUMBNAIL_PAGE" /> é çš„縮圖</translation>
<translation id="42981349822642051">展開</translation>
<translation id="4300675098767811073">多孔 (å³å´)</translation>
+<translation id="4302514097724775343">輕觸æé¾å³å¯é–‹å§‹éŠæˆ²</translation>
<translation id="4302965934281694568">Chou3 (ä¿¡å°)</translation>
<translation id="4305666528087210886">無法存å–你的檔案</translation>
<translation id="4305817255990598646">切æ›</translation>
@@ -904,6 +919,7 @@
<translation id="4658638640878098064">é‡˜è£ (左上方)</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">虛擬實境</translation>
+<translation id="4675657451653251260">在訪客模å¼ä¸­ï¼Œä½ ç„¡æ³•æŸ¥çœ‹ä»»ä½• Chrome 設定檔的資訊。你å¯ä»¥<ph name="LINK_BEGIN" />登入<ph name="LINK_END" />帳戶,以存å–自己的 Google 帳戶資訊,例如密碼或付款方å¼ã€‚</translation>
<translation id="467662567472608290">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證å«æœ‰éŒ¯èª¤ã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截你的連線所致。</translation>
<translation id="4677585247300749148"><ph name="URL" /> è¦æ±‚回應無障礙事件</translation>
<translation id="467809019005607715">Google ç°¡å ±</translation>
@@ -931,6 +947,12 @@
<translation id="4761104368405085019">使用你的麥克風</translation>
<translation id="4764776831041365478"><ph name="URL" /> 的網é å¯èƒ½æš«æ™‚離線,或是已經é·ç§»åˆ°å¦ä¸€å€‹ç¶²å€ã€‚</translation>
<translation id="4766713847338118463">雙釘 (底部)</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ 這部è£ç½®æœƒå„²å­˜çš„活動:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />你在這個視窗下載的所有檔案
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">發生ä¸æ˜Žçš„錯誤。</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{å·²å°éŽ–彈出å¼è¦–窗}other{å·²å°éŽ– # 個彈出å¼è¦–窗}}</translation>
<translation id="4780366598804516005">出紙槽 1</translation>
@@ -1093,11 +1115,13 @@
<translation id="5386426401304769735">這個網站的憑證éˆçµåŒ…å«ä½¿ç”¨ SHA-1 進行簽署的憑證。</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">é‚Šç·£è£è¨‚ (å³å´)</translation>
+<translation id="5398772614898833570">å·²å°éŽ–廣告</translation>
<translation id="5400836586163650660">ç°</translation>
<translation id="540969355065856584">這個伺æœå™¨ç„¡æ³•è­‰æ˜Žæ‰€å±¬ç¶²åŸŸç‚º <ph name="DOMAIN" />;其安全性憑證目å‰ç„¡æ•ˆã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–是有攻擊者攔截您的連線所致。</translation>
<translation id="541416427766103491">堆疊出紙器 4</translation>
<translation id="5421136146218899937">清除ç€è¦½è³‡æ–™...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> è¦æ±‚傳é€é€šçŸ¥çµ¦ä½ </translation>
+<translation id="542872847390508405">ä½ ç›®å‰æ˜¯ä»¥è¨ªå®¢èº«åˆ†ç€è¦½</translation>
<translation id="5430298929874300616">移除書籤</translation>
<translation id="5439770059721715174">「<ph name="ERROR_PATH" />ã€ç™¼ç”Ÿæž¶æ§‹é©—證錯誤:<ph name="ERROR" /></translation>
<translation id="5443468954631487277">相åé †åº (æ­£é¢æœä¸Š)</translation>
@@ -1139,12 +1163,12 @@
<translation id="5571083550517324815">無法在這個地å€å–件,請改用其他地å€ã€‚</translation>
<translation id="5580958916614886209">請檢查信用å¡åˆ°æœŸæœˆä»½ï¼Œç„¶å¾Œå†è©¦ä¸€æ¬¡</translation>
<translation id="5586446728396275693">沒有已儲存的地å€</translation>
+<translation id="5593349413089863479">連線å¯èƒ½æœ‰å®‰å…¨æ¼æ´ž</translation>
<translation id="5595485650161345191">編輯地å€</translation>
<translation id="5598944008576757369">é¸æ“‡ä»˜æ¬¾æ–¹å¼</translation>
<translation id="560412284261940334">系統ä¸æ”¯æ´ç®¡ç†</translation>
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">這å¯èƒ½æ˜¯å½é€ çš„網站或è©é¨™ç¶²ç«™ï¼ŒChrome 建議你立å³é›¢é–‹ã€‚</translation>
<translation id="5610142619324316209">檢查連線狀態</translation>
<translation id="5610807607761827392">ä½ å¯ä»¥åœ¨<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />中管ç†ä¿¡ç”¨å¡å’Œåœ°å€è³‡è¨Šã€‚</translation>
<translation id="561165882404867731">使用 Google 翻譯來翻譯這個é é¢</translation>
@@ -1216,6 +1240,7 @@
<translation id="5901630391730855834">黃色</translation>
<translation id="5905445707201418379">已根據「<ph name="ORIGIN" />ã€çš„來æºæ”¿ç­–加以å°éŽ–。</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (å·²åŒæ­¥)</translation>
+<translation id="5913377024445952699">已暫åœæ“·å–螢幕畫é¢</translation>
<translation id="59174027418879706">已啟用</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">é–‹å•Ÿ</translation>
@@ -1228,6 +1253,7 @@
<translation id="5963413905009737549">å€æ®µ</translation>
<translation id="5967592137238574583">編輯è¯çµ¡è³‡è¨Š</translation>
<translation id="5967867314010545767">從記錄中移除</translation>
+<translation id="5968793460449681917">æ¯æ¬¡é€ è¨ª</translation>
<translation id="5975083100439434680">縮å°</translation>
<translation id="5979084224081478209">檢查密碼</translation>
<translation id="5980920751713728343">Index-3x5</translation>
@@ -1383,6 +1409,7 @@
<translation id="6587923378399804057">你複製的連çµ</translation>
<translation id="6591833882275308647">ä½ çš„ <ph name="DEVICE_TYPE" /> 未å—管ç†</translation>
<translation id="6596325263575161958">加密é¸é …</translation>
+<translation id="6596892391065203054">系統管ç†å“¡å·²ç¦æ­¢åˆ—å°æ­¤å…§å®¹ã€‚</translation>
<translation id="6604181099783169992">動作或光æºæ„Ÿæ‡‰å™¨</translation>
<translation id="6609880536175561541">Prc7 (ä¿¡å°)</translation>
<translation id="6612358246767739896">å—ä¿è­·å…§å®¹</translation>
@@ -1442,6 +1469,7 @@
<translation id="6895330447102777224">您的信用å¡å·²é€šéŽé©—è­‰</translation>
<translation id="6897140037006041989">使用者代ç†ç¨‹å¼</translation>
<translation id="6898699227549475383">組織 (O)</translation>
+<translation id="6907293445143367439">å…許 <ph name="SITE_NAME" /> 執行下列æ“作:</translation>
<translation id="6910240653697687763"><ph name="URL" /> è¦æ±‚å–å¾— MIDI è£ç½®çš„完整控制權é™</translation>
<translation id="6915804003454593391">使用者:</translation>
<translation id="6934672428414710184">這是你在 Google 帳戶中設定的å稱</translation>
@@ -1553,6 +1581,7 @@
<translation id="7346048084945669753">是å¦å·²å»ºç«‹é—œè¯ï¼š</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">命令列</translation>
+<translation id="7359588939039777303">å·²å°éŽ–廣告。</translation>
<translation id="7372973238305370288">æœå°‹çµæžœ</translation>
<translation id="7374733840632556089">發生這個å•é¡Œæ˜¯å› ç‚ºä½ æˆ–其他人在è£ç½®ä¸Šå®‰è£äº†å…·æœ‰é¢¨éšªçš„憑證。已知這個憑證是用於監控åŠæ””截網路資訊,且ä¸å— Chrome 信任。雖然有部分監控活動屬於正當行為 (例如學校或公å¸ç¶²è·¯ä¸Šçš„監控機制),Chrome ä»æƒ³ç¢ºä¿ä½ çŸ¥æ›‰æ­¤ä¸€æƒ…æ³ï¼Œå³ä½¿ä½ ç„¡æ³•é˜»æ­¢é€™é¡žç›£æŽ§æ´»å‹•ã€‚任何存å–網路的ç€è¦½å™¨æˆ–應用程å¼éƒ½å¯èƒ½å—到監控。</translation>
<translation id="7375818412732305729">已附加檔案</translation>
@@ -1727,6 +1756,7 @@
<translation id="7976214039405368314">è¦æ±‚數é‡éŽå¤š</translation>
<translation id="7977538094055660992">輸出è£ç½®</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">如è¦æŸ¥çœ‹æ“´å¢žå¯¦å¢ƒå…§å®¹ï¼Œè«‹å®‰è£ ARCore</translation>
<translation id="799149739215780103">è£è¨‚</translation>
<translation id="7995512525968007366">未指定</translation>
<translation id="800218591365569300">嘗試關閉其他分é æˆ–程å¼ï¼Œä»¥é‡‹å‡ºè¨˜æ†¶é«”。</translation>
@@ -1801,7 +1831,7 @@
<translation id="8275952078857499577">ä¸è¦è©¢å•æ˜¯å¦è¦ç¿»è­¯é€™å€‹ç¶²ç«™</translation>
<translation id="8277900682056760511">已開啟付款處ç†å¸¸å¼å·¥ä½œè¡¨</translation>
<translation id="8281084378435768645">Large-Photo</translation>
-<translation id="8282947398454257691">å­˜å–您的專屬è£ç½®è­˜åˆ¥ç¢¼</translation>
+<translation id="8282947398454257691">å­˜å–您的專屬è£ç½® ID</translation>
<translation id="8286036467436129157">登入</translation>
<translation id="8288807391153049143">顯示憑證</translation>
<translation id="8289355894181816810">如果你ä¸ç¢ºå®šé€™ä»£è¡¨ä»€éº¼æ„æ€ï¼Œè«‹èˆ‡ç¶²è·¯ç®¡ç†å“¡è¯çµ¡ã€‚</translation>
@@ -1854,24 +1884,38 @@
<translation id="8507227106804027148">指令列</translation>
<translation id="8508648098325802031">æœå°‹åœ–示</translation>
<translation id="8522552481199248698">Chrome å¯å”助你ä¿è­· Google 帳戶並變更密碼。</translation>
+<translation id="8525306231823319788">全螢幕</translation>
<translation id="8530813470445476232">清除ç€è¦½è¨˜éŒ„ã€Cookieã€å¿«å–以åŠå…¶ä»– Chrome 設定</translation>
<translation id="8533619373899488139">è«‹å‰å¾€ &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看é­åˆ°å°éŽ–的網å€æ¸…單,以åŠç”±ç³»çµ±ç®¡ç†å“¡æ‰€å¼·åˆ¶åŸ·è¡Œçš„其他政策。</translation>
<translation id="8541158209346794904">è—牙è£ç½®</translation>
<translation id="8542014550340843547">三釘 (底部)</translation>
<translation id="8543181531796978784">您å¯ä»¥<ph name="BEGIN_ERROR_LINK" />回報åµæ¸¬å•é¡Œ<ph name="END_ERROR_LINK" />。或者在您瞭解安全性風險後,ä»ç„¶å¯ä»¥<ph name="BEGIN_LINK" />å‰å¾€é€™å€‹ä¸å®‰å…¨çš„網站<ph name="END_LINK" />。</translation>
<translation id="8557066899867184262">信用å¡é©—證碼ä½æ–¼ä¿¡ç”¨å¡èƒŒé¢ã€‚</translation>
+<translation id="8558485628462305855">如è¦æŸ¥çœ‹æ“´å¢žå¯¦å¢ƒå…§å®¹ï¼Œè«‹æ›´æ–° ARCore</translation>
<translation id="8559762987265718583">ä½ è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
<translation id="8564182942834072828">個別文件/未自動分é çš„副本</translation>
<translation id="8564985650692024650">如果你在其他網站上é‡è¤‡ä½¿ç”¨éŽä½ çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chromium 會建議你é‡è¨­å¯†ç¢¼ã€‚</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ 這部è£ç½®ä¸æœƒå„²å­˜çš„活動:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />你在這個視窗中ç€è¦½çš„é é¢
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">使用 Touch ID 加快å¡ç‰‡é©—證速度</translation>
<translation id="858637041960032120">新增電話號碼</translation>
<translation id="8589998999637048520">最佳畫質</translation>
+<translation id="8600271352425265729">僅é™é€™æ¬¡</translation>
<translation id="860043288473659153">æŒå¡äººå§“å</translation>
<translation id="8606726445206553943">使用您的 MIDI è£ç½®</translation>
+<translation id="8612761427948161954"><ph name="USERNAME" />,你好:
+ <ph name="BR" />
+ 你正在以訪客身分ç€è¦½</translation>
<translation id="861775596732816396">粗細:4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">找ä¸åˆ°ç›¸ç¬¦çš„密碼。顯示所有已儲存的密碼。</translation>
<translation id="8625384913736129811">將這張信用å¡å„²å­˜åˆ°é€™å€‹è£ç½®</translation>
+<translation id="8627040765059109009">已繼續擷å–螢幕畫é¢</translation>
<translation id="8657078576661269990">系統管ç†å“¡å·²ç¦æ­¢å°‡è³‡æ–™å¾ž <ph name="ORIGIN_NAME" /> 分享到 <ph name="VM_NAME_1" /> å’Œ <ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">訂單摘è¦ï¼š<ph name="TOTAL_LABEL" />,更多詳細資料</translation>
<translation id="867224526087042813">ç°½å</translation>
@@ -1934,6 +1978,7 @@
<translation id="8912362522468806198">Google 帳戶</translation>
<translation id="8913778647360618320">「管ç†ä»˜æ¬¾æ–¹å¼ã€æŒ‰éˆ•ï¼ŒæŒ‰ä¸‹ Enter éµå³å¯åœ¨ Chrome 設定中管ç†ä»˜æ¬¾å’Œä¿¡ç”¨å¡è³‡è¨Š</translation>
<translation id="8918231688545606538">這個網é åŒ…å«å¯ç–‘的內容</translation>
+<translation id="8922013791253848639">一律å…許在這個網站中顯示廣告</translation>
<translation id="892588693504540538">打孔 (å³ä¸Šæ–¹)</translation>
<translation id="8931333241327730545">您è¦å°‡é€™å¼µå¡ç‰‡çš„資訊儲存到您的 Google 帳戶嗎?</translation>
<translation id="8932102934695377596">你的時é˜æ™‚é–“éŽæ…¢</translation>
@@ -2005,6 +2050,7 @@
<translation id="9183302530794969518">Google 文件</translation>
<translation id="9183425211371246419"><ph name="HOST_NAME" /> 使用了ä¸æ”¯æ´çš„通訊å”定。</translation>
<translation id="9191834167571392248">打孔 (左下方)</translation>
+<translation id="9199905725844810519">列å°åŠŸèƒ½å·²é­å°éŽ–</translation>
<translation id="9205078245616868884">您已使用åŒæ­¥é€šé—œå¯†èªžå°è³‡æ–™é€²è¡ŒåŠ å¯†ï¼Œè«‹è¼¸å…¥é€šé—œå¯†èªžé–‹å§‹é€²è¡ŒåŒæ­¥ã€‚</translation>
<translation id="9207861905230894330">無法新增文章。</translation>
<translation id="9213433120051936369">自訂外觀</translation>
@@ -2015,8 +2061,10 @@
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">為é¿å…失去 Google 帳戶存å–權,Chromium 建議你立å³è®Šæ›´å¯†ç¢¼ã€‚系統會è¦æ±‚你登入帳戶。</translation>
<translation id="939736085109172342">新增資料夾</translation>
+<translation id="945522503751344254">æä¾›æ„見</translation>
<translation id="945855313015696284">查看下方資訊並刪除所有無效的å¡ç‰‡</translation>
<translation id="950736567201356821">三孔 (頂端)</translation>
+<translation id="951941430552851965">系統管ç†å“¡å› ç‚ºèž¢å¹•ä¸Šçš„內容,已暫åœæ“·å–螢幕畫é¢ã€‚</translation>
<translation id="961663415146723894">è£è¨‚ (底部)</translation>
<translation id="962484866189421427">這項內容å¯èƒ½æœƒè©¦åœ–讓你安è£èº«åˆ†ä¸å¯¦çš„欺騙性應用程å¼ï¼Œæˆ–是收集å¯ç”¨æ–¼è¿½è¹¤ä½ çš„資料。<ph name="BEGIN_LINK" />ä»è¦é¡¯ç¤º<ph name="END_LINK" /></translation>
<translation id="969892804517981540">æ­£å¼ç‰ˆæœ¬</translation>
diff --git a/chromium/components/strings/components_strings_zu.xtb b/chromium/components/strings/components_strings_zu.xtb
index a2bff467945..bd5c40052a5 100644
--- a/chromium/components/strings/components_strings_zu.xtb
+++ b/chromium/components/strings/components_strings_zu.xtb
@@ -80,6 +80,14 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
&lt;/ol&gt;</translation>
<translation id="1257286744552378071">Ufake iphasiwedi yakho kusayithi elingaphethwe inhlangano yakho. Ukuze uvikele i-akhawunti yakho, ungaphindi usebenzise iphasiwedi yakho kwezinye izinhlelo zokusebenza namasayithi.</translation>
<translation id="1263231323834454256">Uhlu lokufunda</translation>
+<translation id="1267173982554786072"><ph name="BEGIN_BOLD" />
+ Umsebenzi ongeke uhlale kule divayisi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Amakhasi owabukayo kuleli windi
+ <ph name="LIST_ITEM" />Amakhukhi nedath yesayithi
+ <ph name="LIST_ITEM" />Ulwazi lwe-akhawunti (<ph name="LINK_BEGIN" />phuma ngemvume<ph name="LINK_END" />)
+ <ph name="END_LIST" /></translation>
<translation id="1270502636509132238">Indlela yokulandwa</translation>
<translation id="1281476433249504884">Isitaki esingu-1</translation>
<translation id="1285320974508926690">Ungalokothi uhumushe leli sayithi</translation>
@@ -283,6 +291,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="204357726431741734">Ngena ngemvume ukuze usebenzise amaphasiwedi alondolozwe ku-akhawunti yakho ye-Google</translation>
<translation id="2053111141626950936">Amakhasi angesi-<ph name="LANGUAGE" /> ngeke aze ahunyushwe.</translation>
<translation id="2053553514270667976">Ikhodi ye-Zip</translation>
+<translation id="2054665754582400095">Ubukhona bakho</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 isiphakamiso}one{# iziphakamiso}other{# iziphakamiso}}</translation>
<translation id="2079545284768500474">Hlehlisa</translation>
<translation id="20817612488360358">Izilungiselelo zesistimu yommeleli zisethelwe ukusetshenziswa kodwa ukulungiselelwa kommeleli okubekelwe obala kuphinde kucaciswe.</translation>
@@ -296,6 +305,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2102495993840063010">Izinhlelo zokusebenza ze-Android</translation>
<translation id="2107021941795971877">Izisekeli zokuphrinta</translation>
<translation id="2108755909498034140">Qalisa kabusha ikhompyutha yakho</translation>
+<translation id="2111166930115883695">Cindezela isikhala ukuze udlale</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2113977810652731515">Awamakhadi</translation>
<translation id="2114841414352855701">Izitshiwe ngoba ibhalwe ngaphezulu yi-<ph name="POLICY_NAME" />.</translation>
@@ -307,6 +317,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="214556005048008348">Khansela inkokhelo</translation>
<translation id="2147827593068025794">Ukuvumelanisa Ingemuva</translation>
<translation id="2148613324460538318">Engeza ikhadi</translation>
+<translation id="2149968176347646218">Ukuxhumeka akuvikelekile</translation>
<translation id="2154054054215849342">Ukuvumelanisa akutholakali kusizinda sakho</translation>
<translation id="2154484045852737596">Hlela ikhadi</translation>
<translation id="2161656808144014275">Umbhalo</translation>
@@ -317,7 +328,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2181821976797666341">Izinqubomgomo</translation>
<translation id="2183608646556468874">Inombolo yefoni</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{1 ikheli}one{# amakheli}other{# amakheli}}</translation>
-<translation id="2187243482123994665">Ukuba khona komsebenzisi</translation>
<translation id="2187317261103489799">Thola (okuzenzakalelayo)</translation>
<translation id="2188375229972301266">Ukushaya kaningi phansi</translation>
<translation id="2202020181578195191">Faka unyaka ovumelekile wokuphelelwa isikhathi</translation>
@@ -470,6 +480,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2839501879576190149">Isayithi mbumbulu ngaphambili</translation>
<translation id="2850739647070081192">Mema (Envelope)</translation>
<translation id="2856444702002559011">Abahlaseli bangazama ukutshontsha ulwazi lwakho kusuka ku-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (isibonelo, amaphasiwedi, imilayezo, noma amakhadi esikweletu). <ph name="BEGIN_LEARN_MORE_LINK" />Funda kabanzi<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2859806420264540918">Leli sayithi libonisa izikhangiso ezingathandeki noma ezidukisayo.</translation>
<translation id="2878197950673342043">Ukugoqa iphosta</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Ukubekwa kwewindi</translation>
@@ -508,11 +519,11 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2996674880327704673">Iziphakamiso nge-Google</translation>
<translation id="3002501248619246229">Hlola ithileyi lemidiya yokufakwayo</translation>
<translation id="3005723025932146533">Bonisa ikhophi elondoloziwe</translation>
-<translation id="3007719053326478567">Ukuphrinthwa kwalokhu okuqukethwe kuvinjwe ngumlawuli wakho</translation>
<translation id="3008447029300691911">Faka i-CVC ye-<ph name="CREDIT_CARD" />. Uma usuqinisekile, imininingwane yekhadi lakho izokwabiwa naleli sayithi.</translation>
<translation id="3010559122411665027">Ukufakwa kuhlu kwe-"<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Kuvinjelwe ngokuzenzakalelayo</translation>
<translation id="3016780570757425217">Yazi indawo yakho</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />, cindezela i-Tab bese ku-Enter ukuze Ususe Isiphakamiso.</translation>
<translation id="3023071826883856138">You4 (Envelope)</translation>
<translation id="3024663005179499861">Uhlobo lwenqubomgomo olungalungile</translation>
<translation id="3037605927509011580">Hawu, iphutha!</translation>
@@ -553,6 +564,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3207960819495026254">Kubekwe uphawu lokubekisa</translation>
<translation id="3209034400446768650">Ikhasi lingakhokhisa imali</translation>
<translation id="3212581601480735796">Umsebenzi wakho ku-<ph name="HOSTNAME" /> ugadiwe</translation>
+<translation id="3212623355668894776">Vala wonke amawindi Wesimenywa ukuze umsebenzi wakho wokuphequlula ususwe kusuka kule divayisi.</translation>
<translation id="3215092763954878852">Ayikwazanga ukusebenzisa i-WebAuthn</translation>
<translation id="3218181027817787318">Kuhlobene</translation>
<translation id="3225919329040284222">Iseva iphrezenthe isitifiketi esingafani nokulindelekile okwakhelwe ngaphakathi. Lokhu okulindelekile kuyafakwa kumawebhusayithi athile, anokuvikeleka okuphezulu ukuze kuvikelwe wena.</translation>
@@ -699,6 +711,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3784372983762739446">Amadivaysi e-Bluetooth</translation>
<translation id="3787705759683870569">Iphelelwa isikhathi ngomhla ka-<ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
<translation id="3789155188480882154">Usayizi 16</translation>
+<translation id="3789841737615482174">Faka</translation>
<translation id="3793574014653384240">Izinombolo nezimbangela zokuphahlazeka ezenzeke muva nje</translation>
<translation id="3797522431967816232">Prc3 (Envelope)</translation>
<translation id="3799805948399000906">Ifonti iceliwe</translation>
@@ -750,6 +763,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4056223980640387499">I-Sepia</translation>
<translation id="4058922952496707368">Ukhiye we-"<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Envelope)</translation>
+<translation id="4067669230157909013">Ukuthatha isikrini kuye kwaqhutshekiswa.</translation>
<translation id="4067947977115446013">Engeza ikheli elivumelekile</translation>
<translation id="4072486802667267160">Kube nenkinga ekucubunguleni i-oda lakho. Sicela uzame futhi.</translation>
<translation id="4075732493274867456">Iklayenti neseva azisekeli inguqulo yephrothokholi ejwayelekile ye-SSL noma i-cipher suite.</translation>
@@ -834,6 +848,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4297502707443874121">Isithonjana sekhasi le-<ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Nweba</translation>
<translation id="4300675098767811073">Ukushaya okuningi kwesokudla</translation>
+<translation id="4302514097724775343">Thepha i-dino ukuze udlale</translation>
<translation id="4302965934281694568">Chou3 (Envelope)</translation>
<translation id="4305666528087210886">Ifayela lakho alikwazanga ukufinyelelwa</translation>
<translation id="4305817255990598646">Shintsha</translation>
@@ -912,6 +927,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4658638640878098064">Ukunamathisela phansi kwesokunxele</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Into engekho ngokoqobo</translation>
+<translation id="4675657451653251260">Ngeke ubone noma yiluphi ulwazi lwephrofayela ye-Chrome kumodi Yesivakashi. <ph name="LINK_BEGIN" />Ungangena ngemvume<ph name="LINK_END" /> ukufinyelela ulwazi lwe-akhawunti yakho ye-Google njengamaphasiwedi nezindlela zokukhokha.</translation>
<translation id="467662567472608290">Le seva ayikwazanga ukukhombisa ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikeleka siqukethe amaphutha. Lokhu kungahle kubangelwe ukulungisa okungafanele noma umhlaseli ozama ukufinyelela uxhumo lwakho.</translation>
<translation id="4677585247300749148">I-<ph name="URL" /> ifuna ukuphendula kumicimbi efinyelelekayo</translation>
<translation id="467809019005607715">Google Amaslayidi</translation>
@@ -939,6 +955,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4761104368405085019">Sebenzisa imakrofoni yakho</translation>
<translation id="4764776831041365478">Ikhasi lewebhu ku-<ph name="URL" /> kungenzeka ukuthi liphansi okwesikhashana noma lihanjiswe unaphakade kukheli elisha lewebhu.</translation>
<translation id="4766713847338118463">Ukunamathisela okubili phansi</translation>
+<translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
+ Umsebenzi wakho ohlala kule divayisi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Noma yimaphi amafayela owalanda kuleli windi
+ <ph name="END_LIST" /></translation>
<translation id="4771973620359291008">Kuvele iphutha elingaziwa.</translation>
<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Okwesikhashana kuvinjiwe}one{# okwesikhashana kuvinjiwe}other{# okwesikhashana kuvinjiwe}}</translation>
<translation id="4780366598804516005">Ibhokisi lemeyili elingu-1</translation>
@@ -1101,11 +1123,13 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5386426401304769735">Iketanga lesitifiketi laleli sayithi liqukethe isitifiketi esisayinwe kusetshenziswa i-SHA-1.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Ukuthunga umphetho kwesokudla</translation>
+<translation id="5398772614898833570">Izikhangiso zivinjewe</translation>
<translation id="5400836586163650660">Okumpunga</translation>
<translation id="540969355065856584">Le seva ayikwazanga ukubonisa ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuphepha asivumelekile ngalesi sikhathi. Lokhu kungabangelwa ukungalungiseki kahle noma umhlaseli uhlasela uxhumo lakho.</translation>
<translation id="541416427766103491">Isitaki esingu-4</translation>
<translation id="5421136146218899937">Sula idatha yokudlulisa amehlo...</translation>
<translation id="5426179911063097041">I-<ph name="SITE" /> ifuna ukukuthumelela izaziso</translation>
+<translation id="542872847390508405">Udlulisa amehlo njengesihambeli</translation>
<translation id="5430298929874300616">Susa ibhukhimakhi</translation>
<translation id="5439770059721715174">Iphutha lokuqinisekisa i-schema ku-"<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
<translation id="5443468954631487277">I-oda elingemuva libheke phezulu</translation>
@@ -1147,12 +1171,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5571083550517324815">Ayikwazi ukulanda kusukela kuleli kheli. Khetha ikheli elihlukile.</translation>
<translation id="5580958916614886209">Hlola inyanga yakho yokuphelelwa isikhathi uphinde uzame futhi</translation>
<translation id="5586446728396275693">Awekho amakheli alondoloziwe</translation>
+<translation id="5593349413089863479">Ukuxhuma akuvikelekile ngokuphelele</translation>
<translation id="5595485650161345191">Hlela ikheli</translation>
<translation id="5598944008576757369">Khetha indlela yokukhokha</translation>
<translation id="560412284261940334">Ukuphathwa akusekelwe</translation>
<translation id="5605670050355397069">I-Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
-<translation id="5608165884683734521">Leli sayithi lingaba imbumbulu noma umgunyathi. I-Chrome incoma ukuhamba manje.</translation>
<translation id="5610142619324316209">Ukuhlola uxhumo</translation>
<translation id="5610807607761827392">Ungaphatha amakhadi namakheli <ph name="BEGIN_LINK" />Kuzilungiselelo<ph name="END_LINK" />.</translation>
<translation id="561165882404867731">Humusha leli khasi nge-Google Translate</translation>
@@ -1224,6 +1248,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5901630391730855834">Okuliphuzi</translation>
<translation id="5905445707201418379">Kuvinjelwe ngokuya kwenqubomgomo yoqobo ye-<ph name="ORIGIN" />.</translation>
<translation id="5908541034548427511"><ph name="TYPE_1" /> (kuvumelanisiwe)</translation>
+<translation id="5913377024445952699">Ukuthatha isikrini kuphunyuziwe</translation>
<translation id="59174027418879706">Kunikwe amandla</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5921185718311485855">Vuliwe</translation>
@@ -1236,6 +1261,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5963413905009737549">Isigaba</translation>
<translation id="5967592137238574583">Hlela ulwazi loxhumana naye</translation>
<translation id="5967867314010545767">Susa kusuka kumlando</translation>
+<translation id="5968793460449681917">Kukho konke ukuvakasha</translation>
<translation id="5975083100439434680">Hlehlisa isithombe</translation>
<translation id="5979084224081478209">Hlola amaphasiwedi</translation>
<translation id="5980920751713728343">I-Index-3x5</translation>
@@ -1391,6 +1417,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6587923378399804057">Isixhumanisi osikopishile</translation>
<translation id="6591833882275308647">I-<ph name="DEVICE_TYPE" /> yakho ayiphethwe</translation>
<translation id="6596325263575161958">Izinketho zokubethela</translation>
+<translation id="6596892391065203054">Ukuphrinthwa kwalokhu okuqukethwe kuvinjwe ngumlawuli wakho.</translation>
<translation id="6604181099783169992">Izinzwa zokunyakaza noma zokukhanya</translation>
<translation id="6609880536175561541">Prc7 (Envelope)</translation>
<translation id="6612358246767739896">Okuqukethwe okuvikelekile</translation>
@@ -1450,6 +1477,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6895330447102777224">Ikhadi lakho liqinisekisiwe</translation>
<translation id="6897140037006041989">Umenzeli womsebenzisi</translation>
<translation id="6898699227549475383">Inhlangano (O)</translation>
+<translation id="6907293445143367439">Vumela i-<ph name="SITE_NAME" /> ku-:</translation>
<translation id="6910240653697687763">I-<ph name="URL" /> ifuna ulawulo olugcwele lwamadivayisi akho e-MIDI</translation>
<translation id="6915804003454593391">Umsebenzisi:</translation>
<translation id="6934672428414710184">Leli gama lisuka ku-akhawunti yakho ye-Google</translation>
@@ -1561,6 +1589,7 @@ Imininingwane engeziwe:
<translation id="7346048084945669753">Iyinxusa:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
<translation id="7353601530677266744">Umugqa womyalo</translation>
+<translation id="7359588939039777303">Izikhangiso zivinjewe.</translation>
<translation id="7372973238305370288">umphumela wosesho</translation>
<translation id="7374733840632556089">Le nkinga yenzeka ngenxa yesitifiketi noma othile ufake kudivayisi yakho. Isitifiketi saziwa ngokusetshenziswa ukwengamela amanethiwekhi e-intercept, futhi asithembekile ku-Chrome. Ngenkathi ezinye izimo zokufinyelela zokwengamela zikhona, njengasesikoleni noma inethiwekhi yenkampani, i-Chrome ifuna ukuqinisekisa ukuthi uyaqaphela ukuthi lokhu kuyenzeka, ngisho noma ungeke ukwazi ukukumisa. Ukwengamela kungenzeka kunoma isiphi isiphequluli noma uhlelo lokusebenza olufinyelela iwebhu.</translation>
<translation id="7375818412732305729">Ifayela linamathiselwe</translation>
@@ -1735,6 +1764,7 @@ Imininingwane engeziwe:
<translation id="7976214039405368314">Izicelo eziningi kakhulu</translation>
<translation id="7977538094055660992">Idivaysi yokukhishwayo</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="79859296434321399">Ukuze ubuke okuqukethwe kwe-augmented reality, faka i-ARCore</translation>
<translation id="799149739215780103">Ukubophezela</translation>
<translation id="7995512525968007366">Akucacisiwe</translation>
<translation id="800218591365569300">Zama ukuvala amanye amathebhu noma izinhlelo ukuze ukhulule imemori.</translation>
@@ -1862,24 +1892,38 @@ Imininingwane engeziwe:
<translation id="8507227106804027148">Umugqa womyalo</translation>
<translation id="8508648098325802031">Isithonjana sosesho</translation>
<translation id="8522552481199248698">I-Chrome ingakusiza uvikele i-akhawunti yakho ye-Google uphinde ushintshe iphasiwedi yakho.</translation>
+<translation id="8525306231823319788">Isikrini esigcwele</translation>
<translation id="8530813470445476232">Sula umlando wakho wokuphequlula, amakhukhi, inqolobane, nokuningi kumasethingi we-Chrome</translation>
<translation id="8533619373899488139">Vakashela ku-&lt;strong&gt;chrome://policy&lt;/strong&gt; ukuze ubone uhlu lwama-URL avinjiwe nezinye izinqubomgomo eziphoqwa ngumlawuli wesistimu yakho.</translation>
<translation id="8541158209346794904">Idivayisi ye-bluetooth</translation>
<translation id="8542014550340843547">Ukunamathisela okuthathu phansi</translation>
<translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />Ungabika inkinga yokutholwa<ph name="END_ERROR_LINK" /> noma, uma uqonda izingcuphe zokuvikelwa kwakho, <ph name="BEGIN_LINK" />ungavakashela leli sayithi elingaphephile<ph name="END_LINK" />.</translation>
<translation id="8557066899867184262">I-CVC isemuva kwekhadi lakho.</translation>
+<translation id="8558485628462305855">Ukuze ubuke okuqukethwe kwe-augmented reality, buyekeza i-ARCore</translation>
<translation id="8559762987265718583">Uxhumano oluyimfihlo oluya ku-<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alukwazi ukusungulwa ngoba idethi nesikhathi sedivayisi yakho (<ph name="DATE_AND_TIME" />) azilungile.</translation>
<translation id="8564182942834072828">Amadokhumenti ahlukene/Amakhophi angaqathaniswanga</translation>
<translation id="8564985650692024650">I-Chromium incoma ukusetha kabusha iphasiwedi yakho ye-<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> uma uphinde wayisebenzisa kwamanye amasayithi.</translation>
+<translation id="856887218454489335"><ph name="BEGIN_BOLD" />
+ Umsebenzi ongeke uhlale kule divayisi:
+ <ph name="END_BOLD" />
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Amakhasi owabuka kuleli windi
+ <ph name="LIST_ITEM" />Amakhukhi nedatha yesayithi
+ <ph name="END_LIST" /></translation>
<translation id="8574899947864779331">Sebenzisa i-Touch ID ukuqinisekisa amakhadi ngokushesha</translation>
<translation id="858637041960032120">Engeza inombolo yefoni</translation>
<translation id="8589998999637048520">Ikhwalithi ehamba phambili</translation>
+<translation id="8600271352425265729">Ngalesi sikhathi kuphela</translation>
<translation id="860043288473659153">Igama lomnikazi wekhadi</translation>
<translation id="8606726445206553943">Sebenzisa amadivayisi wakho we-MIDI</translation>
+<translation id="8612761427948161954">Sawubona <ph name="USERNAME" />,
+ <ph name="BR" />
+ Uphequlula njengesimenywa</translation>
<translation id="861775596732816396">Usayizi 4</translation>
<translation id="8622948367223941507">Okungaphezulu kwezomthetho</translation>
<translation id="8623885649813806493">Awekho amaphasiwedi afanayo. Bonisa onke amaphasiwedi alondoloziwe.</translation>
<translation id="8625384913736129811">Londoloza leli khadi kule divayisi</translation>
+<translation id="8627040765059109009">Ukuthatha isikrini kuyaqhubeka</translation>
<translation id="8657078576661269990">Umlawuli wakho uvimbe ukwabelana kusuka ku-<ph name="ORIGIN_NAME" /> kuya ku-<ph name="VM_NAME_1" /> no-<ph name="VM_NAME_2" /></translation>
<translation id="8663226718884576429">Isifinyezo se-oda, <ph name="TOTAL_LABEL" />, Imininingwane eminingi</translation>
<translation id="867224526087042813">Isiginesha</translation>
@@ -1942,6 +1986,7 @@ Imininingwane engeziwe:
<translation id="8912362522468806198">I-Akhawunti ye-Google</translation>
<translation id="8913778647360618320">Inkinobho yokulawula indlela yokukhokha, cindezela u-Enter ukuze uphathe izinkokhelo zakho nolwazi lwekhadi lesikweletu kumasethingi e-Chrome</translation>
<translation id="8918231688545606538">Leli khasi liyasolisa</translation>
+<translation id="8922013791253848639">Njalo vumela izikhangiso kuleli sayithi</translation>
<translation id="892588693504540538">Ukushaya phezulu kwesokudla</translation>
<translation id="8931333241327730545">Ingabe ufuna ukulondoloza leli khadi ku-Akhawunti yakho ye-Google?</translation>
<translation id="8932102934695377596">Iwashi lakho lisemuva</translation>
@@ -2013,6 +2058,7 @@ Imininingwane engeziwe:
<translation id="9183302530794969518">Google Amadokhumenti</translation>
<translation id="9183425211371246419">I-<ph name="HOST_NAME" /> isebenzisa iphrothokholi engasekelwe.</translation>
<translation id="9191834167571392248">Ukushaya phansi kwesokunxele</translation>
+<translation id="9199905725844810519">Ukuphrinta kuvinjelwe</translation>
<translation id="9205078245616868884">Idatha yakho ibethelwe ngomushwana wakho wokungena wokuvumelanisa. Wufake lapha ukuze uqale ukuvumelanisa.</translation>
<translation id="9207861905230894330">Yehlulekile ukungeza i-athikili.</translation>
<translation id="9213433120051936369">Yenza ngokwezifiso ukubukeka</translation>
@@ -2023,8 +2069,10 @@ Imininingwane engeziwe:
<translation id="936474030629450166">Super-B</translation>
<translation id="936602727769022409">Ungalahlekelwa wukufinyelela ku-akhawunti yakho ye-Google. I-Chromium incoma ukuthi ushintshe iphasiwedi yakho manje. Uzocelwa ukuthi ungene ngemvume.</translation>
<translation id="939736085109172342">Ifolda entsha</translation>
+<translation id="945522503751344254">Thumela impendulo</translation>
<translation id="945855313015696284">Hlola ulwazi olungezansi uphinde ususe noma imaphi amakhadi angavumelekile</translation>
<translation id="950736567201356821">Ukushaya kathathu phezulu</translation>
+<translation id="951941430552851965">Ukuthatha isikrini kuye kwaphunyuzwa umlawuli wakho ngenxa yokuqukethwe okukusikrini sakho.</translation>
<translation id="961663415146723894">Ukubophezela phansi</translation>
<translation id="962484866189421427">Lokhu okuqukethwe kungazama ukufaka izinhlelo zokusebenza ezilahlekisayo ezenza ngathi okunye noma ziqoqe idatha engasetshenziswa ukukulandela. <ph name="BEGIN_LINK" />Bonisa noma kunjalo<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Ukwakha okusemthethweni</translation>
diff --git a/chromium/components/subresource_filter/android/BUILD.gn b/chromium/components/subresource_filter/android/BUILD.gn
index c3969bd4f69..4360f5ca4b2 100644
--- a/chromium/components/subresource_filter/android/BUILD.gn
+++ b/chromium/components/subresource_filter/android/BUILD.gn
@@ -5,24 +5,60 @@
import("//build/config/android/rules.gni")
generate_jni("subresource_filter_jni_headers") {
- sources = [ "java/src/org/chromium/components/subresource_filter/SubresourceFilterFeatureList.java" ]
+ sources = [
+ "java/src/org/chromium/components/subresource_filter/AdsBlockedInfoBar.java",
+ "java/src/org/chromium/components/subresource_filter/SubresourceFilterFeatureList.java",
+ ]
}
android_library("java") {
- sources = [ "java/src/org/chromium/components/subresource_filter/SubresourceFilterFeatureList.java" ]
+ sources = [
+ "java/src/org/chromium/components/subresource_filter/AdsBlockedInfoBar.java",
+ "java/src/org/chromium/components/subresource_filter/SubresourceFilterFeatureList.java",
+ ]
deps = [
+ ":java_resources",
":subresource_filter_jni_headers",
"//base:base_java",
"//base:jni_java",
+ "//components/infobars/android:infobar_android_enums_java",
+ "//components/infobars/android:java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_java",
+ "//ui/android:ui_no_recycler_view_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ resources_package = "org.chromium.components.subresource_filter"
}
source_set("android") {
- sources = [ "subresource_filter_feature_list.cc" ]
+ sources = [
+ "ads_blocked_infobar.cc",
+ "ads_blocked_infobar.h",
+ "ads_blocked_infobar_delegate.cc",
+ "ads_blocked_infobar_delegate.h",
+ "subresource_filter_feature_list.cc",
+ ]
deps = [
":subresource_filter_jni_headers",
"//base",
+ "//components/infobars/android",
+ "//components/infobars/content",
+ "//components/infobars/core",
+ "//components/resources:android_resources",
+ "//components/strings:components_strings_grit",
+ "//components/subresource_filter/content/browser",
"//components/subresource_filter/core/browser",
+ "//content/public/browser",
+ "//ui/base",
+ ]
+}
+
+android_resources("java_resources") {
+ sources = [ "java/res/values/ids.xml" ]
+
+ deps = [
+ "//components/browser_ui/strings/android:browser_ui_strings_grd",
+ "//components/browser_ui/styles/android:java_resources",
+ "//components/strings:components_strings_grd",
]
}
diff --git a/chromium/components/subresource_filter/android/DEPS b/chromium/components/subresource_filter/android/DEPS
new file mode 100644
index 00000000000..ff048235361
--- /dev/null
+++ b/chromium/components/subresource_filter/android/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+components/infobars",
+ "+components/resources",
+ "+components/strings",
+ "+components/subresource_filter/content/browser",
+ "+content/public/browser",
+ "+ui/android/java",
+ "+ui/base/l10n",
+]
diff --git a/chromium/components/subresource_filter/android/ads_blocked_infobar.cc b/chromium/components/subresource_filter/android/ads_blocked_infobar.cc
new file mode 100644
index 00000000000..0e97211c23f
--- /dev/null
+++ b/chromium/components/subresource_filter/android/ads_blocked_infobar.cc
@@ -0,0 +1,46 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/android/ads_blocked_infobar.h"
+
+#include <utility>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "components/subresource_filter/android/subresource_filter_jni_headers/AdsBlockedInfoBar_jni.h"
+
+using base::android::JavaParamRef;
+
+namespace subresource_filter {
+
+AdsBlockedInfoBar::AdsBlockedInfoBar(
+ std::unique_ptr<AdsBlockedInfobarDelegate> delegate,
+ const ResourceIdMapper& resource_id_mapper)
+ : infobars::ConfirmInfoBar(std::move(delegate), resource_id_mapper) {}
+
+AdsBlockedInfoBar::~AdsBlockedInfoBar() {}
+
+base::android::ScopedJavaLocalRef<jobject>
+AdsBlockedInfoBar::CreateRenderInfoBar(JNIEnv* env) {
+ using base::android::ConvertUTF16ToJavaString;
+ using base::android::ScopedJavaLocalRef;
+ AdsBlockedInfobarDelegate* ads_blocked_delegate =
+ static_cast<AdsBlockedInfobarDelegate*>(delegate());
+ ScopedJavaLocalRef<jstring> reload_button_text = ConvertUTF16ToJavaString(
+ env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_CANCEL));
+ ScopedJavaLocalRef<jstring> ok_button_text = ConvertUTF16ToJavaString(
+ env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK));
+ ScopedJavaLocalRef<jstring> message_text =
+ ConvertUTF16ToJavaString(env, ads_blocked_delegate->GetMessageText());
+ ScopedJavaLocalRef<jstring> explanation_message =
+ ConvertUTF16ToJavaString(env, ads_blocked_delegate->GetExplanationText());
+
+ ScopedJavaLocalRef<jstring> toggle_text =
+ ConvertUTF16ToJavaString(env, ads_blocked_delegate->GetToggleText());
+ return Java_AdsBlockedInfoBar_show(env, GetJavaIconId(), message_text,
+ ok_button_text, reload_button_text,
+ toggle_text, explanation_message);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/android/ads_blocked_infobar.h b/chromium/components/subresource_filter/android/ads_blocked_infobar.h
new file mode 100644
index 00000000000..f5989ff6308
--- /dev/null
+++ b/chromium/components/subresource_filter/android/ads_blocked_infobar.h
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_H_
+
+#include "base/macros.h"
+#include "components/infobars/android/confirm_infobar.h"
+#include "components/subresource_filter/android/ads_blocked_infobar_delegate.h"
+
+namespace subresource_filter {
+
+class AdsBlockedInfoBar : public infobars::ConfirmInfoBar {
+ public:
+ AdsBlockedInfoBar(std::unique_ptr<AdsBlockedInfobarDelegate> delegate,
+ const ResourceIdMapper& resource_id_mapper);
+
+ ~AdsBlockedInfoBar() override;
+
+ private:
+ // ConfirmInfoBar:
+ base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+ JNIEnv* env) override;
+
+ DISALLOW_COPY_AND_ASSIGN(AdsBlockedInfoBar);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_H_
diff --git a/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.cc b/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.cc
new file mode 100644
index 00000000000..44f621e013f
--- /dev/null
+++ b/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/android/ads_blocked_infobar_delegate.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/infobars/content/content_infobar_manager.h"
+#include "components/infobars/core/infobar.h"
+#include "components/resources/android/theme_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/subresource_filter/android/ads_blocked_infobar.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace subresource_filter {
+
+// static
+void AdsBlockedInfobarDelegate::Create(
+ infobars::ContentInfoBarManager* infobar_manager,
+ const infobars::InfoBarAndroid::ResourceIdMapper& resource_id_mapper) {
+ infobar_manager->AddInfoBar(std::make_unique<AdsBlockedInfoBar>(
+ base::WrapUnique(new AdsBlockedInfobarDelegate()), resource_id_mapper));
+}
+
+AdsBlockedInfobarDelegate::~AdsBlockedInfobarDelegate() = default;
+
+base::string16 AdsBlockedInfobarDelegate::GetExplanationText() const {
+ return l10n_util::GetStringUTF16(IDS_BLOCKED_ADS_PROMPT_EXPLANATION);
+}
+
+base::string16 AdsBlockedInfobarDelegate::GetToggleText() const {
+ return l10n_util::GetStringUTF16(IDS_ALWAYS_ALLOW_ADS);
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AdsBlockedInfobarDelegate::GetIdentifier() const {
+ return ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID;
+}
+
+int AdsBlockedInfobarDelegate::GetIconId() const {
+ return IDR_ANDROID_INFOBAR_BLOCKED_POPUPS;
+}
+
+GURL AdsBlockedInfobarDelegate::GetLinkURL() const {
+ DCHECK(infobar_expanded_);
+ return GURL(subresource_filter::kLearnMoreLink);
+}
+
+bool AdsBlockedInfobarDelegate::LinkClicked(WindowOpenDisposition disposition) {
+ if (infobar_expanded_) {
+ subresource_filter::ContentSubresourceFilterThrottleManager::LogAction(
+ subresource_filter::SubresourceFilterAction::kClickedLearnMore);
+ return ConfirmInfoBarDelegate::LinkClicked(disposition);
+ }
+
+ subresource_filter::ContentSubresourceFilterThrottleManager::LogAction(
+ subresource_filter::SubresourceFilterAction::kDetailsShown);
+ infobar_expanded_ = true;
+ return false;
+}
+
+base::string16 AdsBlockedInfobarDelegate::GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_BLOCKED_ADS_INFOBAR_MESSAGE);
+}
+
+int AdsBlockedInfobarDelegate::GetButtons() const {
+ return BUTTON_OK | BUTTON_CANCEL;
+}
+
+base::string16 AdsBlockedInfobarDelegate::GetButtonLabel(
+ InfoBarButton button) const {
+ return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_OK : IDS_RELOAD);
+}
+
+bool AdsBlockedInfobarDelegate::Cancel() {
+ subresource_filter::ContentSubresourceFilterThrottleManager::FromWebContents(
+ infobars::ContentInfoBarManager::WebContentsFromInfoBar(infobar()))
+ ->OnReloadRequested();
+ return true;
+}
+
+AdsBlockedInfobarDelegate::AdsBlockedInfobarDelegate() = default;
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.h b/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.h
new file mode 100644
index 00000000000..546edeeece7
--- /dev/null
+++ b/chromium/components/subresource_filter/android/ads_blocked_infobar_delegate.h
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_DELEGATE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_DELEGATE_H_
+
+#include "base/macros.h"
+#include "components/infobars/android/infobar_android.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+namespace infobars {
+class ContentInfoBarManager;
+}
+
+namespace subresource_filter {
+
+// This infobar appears when the user proceeds through Safe Browsing warning
+// interstitials to a site with deceptive embedded content. It tells the user
+// ads have been blocked and provides a button to reload the page with the
+// content unblocked.
+//
+// The infobar also appears when the site is known to show intrusive ads.
+class AdsBlockedInfobarDelegate : public ConfirmInfoBarDelegate {
+ public:
+ // Creates a subresource filter infobar and delegate and adds the infobar to
+ // |infobar_manager|.
+ static void Create(
+ infobars::ContentInfoBarManager* infobar_manager,
+ const infobars::InfoBarAndroid::ResourceIdMapper& resource_id_mapper);
+
+ ~AdsBlockedInfobarDelegate() override;
+
+ base::string16 GetExplanationText() const;
+ base::string16 GetToggleText() const;
+
+ // ConfirmInfoBarDelegate:
+ InfoBarIdentifier GetIdentifier() const override;
+ int GetIconId() const override;
+ GURL GetLinkURL() const override;
+ bool LinkClicked(WindowOpenDisposition disposition) override;
+ base::string16 GetMessageText() const override;
+ int GetButtons() const override;
+ base::string16 GetButtonLabel(InfoBarButton button) const override;
+ bool Cancel() override;
+
+ private:
+ AdsBlockedInfobarDelegate();
+
+ // True when the infobar is in the expanded state.
+ bool infobar_expanded_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(AdsBlockedInfobarDelegate);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_ANDROID_ADS_BLOCKED_INFOBAR_DELEGATE_H_
diff --git a/chromium/components/subresource_filter/content/browser/BUILD.gn b/chromium/components/subresource_filter/content/browser/BUILD.gn
index 3923b666bdf..181ade2f7d5 100644
--- a/chromium/components/subresource_filter/content/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/content/browser/BUILD.gn
@@ -6,6 +6,8 @@ static_library("browser") {
sources = [
"activation_state_computing_navigation_throttle.cc",
"activation_state_computing_navigation_throttle.h",
+ "ads_intervention_manager.cc",
+ "ads_intervention_manager.h",
"async_document_subresource_filter.cc",
"async_document_subresource_filter.h",
"content_activation_list_utils.cc",
@@ -26,20 +28,29 @@ static_library("browser") {
"subframe_navigation_filtering_throttle.cc",
"subframe_navigation_filtering_throttle.h",
"subresource_filter_client.h",
+ "subresource_filter_content_settings_manager.cc",
+ "subresource_filter_content_settings_manager.h",
"subresource_filter_observer.h",
"subresource_filter_observer_manager.cc",
"subresource_filter_observer_manager.h",
+ "subresource_filter_profile_context.cc",
+ "subresource_filter_profile_context.h",
"subresource_filter_safe_browsing_activation_throttle.cc",
"subresource_filter_safe_browsing_activation_throttle.h",
"subresource_filter_safe_browsing_client.cc",
"subresource_filter_safe_browsing_client.h",
"subresource_filter_safe_browsing_client_request.cc",
"subresource_filter_safe_browsing_client_request.h",
+ "unindexed_ruleset_stream_generator.cc",
+ "unindexed_ruleset_stream_generator.h",
"verified_ruleset_dealer.cc",
"verified_ruleset_dealer.h",
]
deps = [
"//base",
+ "//components/content_settings/core/browser",
+ "//components/content_settings/core/common",
+ "//components/keyed_service/core",
"//components/prefs:prefs",
"//components/safe_browsing/core/db:database_manager",
"//components/safe_browsing/core/db:util",
@@ -71,11 +82,14 @@ static_library("test_support") {
"subframe_navigation_test_utils.h",
"subresource_filter_observer_test_utils.cc",
"subresource_filter_observer_test_utils.h",
+ "test_ruleset_publisher.cc",
+ "test_ruleset_publisher.h",
]
deps = [
":browser",
"//base/test:test_support",
"//components/subresource_filter/core/common",
+ "//components/subresource_filter/core/common:test_support",
"//content/public/browser",
"//content/test:test_support",
"//net",
@@ -92,6 +106,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"activation_state_computing_navigation_throttle_unittest.cc",
+ "ads_intervention_manager_unittest.cc",
"async_document_subresource_filter_unittest.cc",
"content_activation_list_utils_unittest.cc",
"content_subresource_filter_throttle_manager_unittest.cc",
@@ -99,6 +114,7 @@ source_set("unit_tests") {
"ruleset_publisher_impl_unittest.cc",
"ruleset_service_unittest.cc",
"subframe_navigation_filtering_throttle_unittest.cc",
+ "subresource_filter_content_settings_manager_unittest.cc",
"subresource_filter_safe_browsing_activation_throttle_unittest.cc",
"verified_ruleset_dealer_unittest.cc",
]
@@ -106,6 +122,8 @@ source_set("unit_tests") {
":browser",
":test_support",
"//base/test:test_support",
+ "//components/content_settings/core/browser",
+ "//components/content_settings/core/common",
"//components/prefs:test_support",
"//components/safe_browsing/core/db:database_manager",
"//components/safe_browsing/core/db:util",
@@ -114,12 +132,14 @@ source_set("unit_tests") {
"//components/subresource_filter/core/browser:test_support",
"//components/subresource_filter/core/common",
"//components/subresource_filter/core/common:test_support",
+ "//components/sync_preferences:test_support",
"//components/ukm:test_support",
"//components/ukm/content:content",
"//content/test:test_support",
"//ipc",
"//ipc:test_support",
"//testing/gtest",
+ "//ui/base:test_support",
]
public_deps = [ "//components/subresource_filter/content/mojom" ]
}
diff --git a/chromium/components/subresource_filter/content/browser/DEPS b/chromium/components/subresource_filter/content/browser/DEPS
index e588ec2450a..8fc613d6f99 100644
--- a/chromium/components/subresource_filter/content/browser/DEPS
+++ b/chromium/components/subresource_filter/content/browser/DEPS
@@ -1,10 +1,14 @@
include_rules = [
+ "+components/content_settings/core/browser",
+ "+components/content_settings/core/common",
+ "+components/keyed_service/core",
"+components/safe_browsing/core/db",
+ "+components/sync_preferences",
"+components/ukm",
"+content/public/browser",
"+content/public/test",
"+mojo/public",
"+net/base",
"+services/metrics/public/cpp",
- "+ui/base/page_transition_types.h",
+ "+ui/base",
]
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
index 06e6b7c3792..5e1d7df0d40 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
@@ -8,8 +8,8 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
@@ -33,19 +33,6 @@
namespace subresource_filter {
-namespace {
-
-// Histogram name on thread timers. Please, use |ExpectThreadTimers| for
-// expectation calls corrections.
-constexpr char kActivationCPU[] =
- "SubresourceFilter.DocumentLoad.Activation.CPUDuration";
-
-int ExpectThreadTimers(int expected) {
- return ScopedThreadTimers::IsSupported() ? expected : 0;
-}
-
-} // namespace
-
namespace proto = url_pattern_index::proto;
// The tests are parameterized by a bool which enables speculative main frame
@@ -484,33 +471,26 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, DisabledStatePropagated2) {
EXPECT_TRUE(state.generic_blocking_rules_disabled);
}
-TEST_P(ActivationStateComputingThrottleSubFrameTest, Speculation) {
- // Use the activation performance metric as a proxy for how many times
- // activation computation occurred.
- base::HistogramTester main_histogram_tester;
-
+// TODO(crbug.com/1143730): This test needs to verify that
+// ComputeActivationState was called appropriately. Previously this was done
+// via looking at performance histograms, but those are now obsolete.
+TEST_P(ActivationStateComputingThrottleSubFrameTest, DISABLED_Speculation) {
// Main frames don't do speculative lookups, a navigation commit should only
// trigger a single ruleset lookup.
CreateTestNavigationForMainFrame(GURL("http://example.test/"));
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
- int main_frame_checks = dryrun_speculation() ? 1 : 0;
- main_histogram_tester.ExpectTotalCount(kActivationCPU,
- ExpectThreadTimers(main_frame_checks));
+ // Check that there was one activation decision.
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
- main_frame_checks += dryrun_speculation() ? 1 : 0;
- main_histogram_tester.ExpectTotalCount(kActivationCPU,
- ExpectThreadTimers(main_frame_checks));
+ // Check that there was one additional activation decision.
mojom::ActivationState state;
state.activation_level = mojom::ActivationLevel::kEnabled;
NotifyPageActivation(state);
SimulateCommitAndExpectToProceed();
- main_frame_checks += dryrun_speculation() ? 0 : 1;
- main_histogram_tester.ExpectTotalCount(kActivationCPU,
- ExpectThreadTimers(main_frame_checks));
+ // Check that there was one additional activation decision.
base::HistogramTester sub_histogram_tester;
CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
@@ -519,16 +499,16 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, Speculation) {
// For subframes, do a ruleset lookup at the start and every redirect.
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(1));
+ // Check that there was one additional activation decision.
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
+ // Check that there was one additional activation decision.
// No ruleset lookup required at commit because we've already checked the
// latest URL.
SimulateCommitAndExpectToProceed();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
+ // Check that there were no additional activation decisions.
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
@@ -545,11 +525,9 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
simulator->Start();
EXPECT_FALSE(simulator->IsDeferred());
- main_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
simulator->Redirect(GURL("http://example.test2/"));
EXPECT_FALSE(simulator->IsDeferred());
- main_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
mojom::ActivationState state;
state.activation_level = mojom::ActivationLevel::kEnabled;
@@ -559,17 +537,12 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
EXPECT_TRUE(simulator->IsDeferred());
EXPECT_LT(0u, simple_task_runner()->NumPendingTasks());
simple_task_runner()->RunPendingTasks();
- // If speculation was enabled for this test, will do a lookup at start and
- // redirect.
- main_histogram_tester.ExpectTotalCount(
- kActivationCPU, ExpectThreadTimers(dryrun_speculation() ? 2 : 1));
simulator->Wait();
EXPECT_FALSE(simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
simulator->GetLastThrottleCheckResult());
simulator->Commit();
- base::HistogramTester sub_histogram_tester;
auto subframe_simulator =
content::NavigationSimulator::CreateRendererInitiated(
GURL("http://example.test"),
@@ -582,14 +555,12 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
// navigation until commit time.
subframe_simulator->Start();
EXPECT_FALSE(subframe_simulator->IsDeferred());
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
// Calling redirect should ensure that the throttle does not receive the
// results of the check, but the task to actually perform the check will still
// happen.
subframe_simulator->Redirect(GURL("http://example.test2/"));
EXPECT_FALSE(subframe_simulator->IsDeferred());
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 0);
// Finish the checks dispatched in the start and redirect phase when the
// navigation is ready to commit.
@@ -601,7 +572,6 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
EXPECT_FALSE(subframe_simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
simulator->GetLastThrottleCheckResult());
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
}
INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc
new file mode 100644
index 00000000000..92ef688e69a
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc
@@ -0,0 +1,130 @@
+// Copyright 2020 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/subresource_filter/content/browser/ads_intervention_manager.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "content/public/browser/navigation_handle.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Key into the website settings dict for last active ads violation.
+const char kLastAdsViolationTimeKey[] = "LastAdsViolationTime";
+const char kLastAdsViolationKey[] = "LastAdsViolation";
+
+// Histograms
+const char kAdsInterventionRecordedHistogramName[] =
+ "SubresourceFilter.PageLoad.AdsInterventionTriggered";
+
+const char kTimeSinceAdsInterventionTriggeredHistogramName[] =
+ "SubresourceFilter.PageLoad.TimeSinceLastActiveAdsIntervention";
+
+AdsInterventionStatus GetAdsInterventionStatus(bool activation_status,
+ bool intervention_active) {
+ if (!intervention_active)
+ return AdsInterventionStatus::kExpired;
+
+ return activation_status ? AdsInterventionStatus::kBlocking
+ : AdsInterventionStatus::kWouldBlock;
+}
+
+} // namespace
+
+AdsInterventionManager::AdsInterventionManager(
+ SubresourceFilterContentSettingsManager* settings_manager)
+ : settings_manager_(settings_manager),
+ clock_(base::DefaultClock::GetInstance()) {}
+
+AdsInterventionManager::~AdsInterventionManager() = default;
+
+void AdsInterventionManager::TriggerAdsInterventionForUrlOnSubsequentLoads(
+ const GURL& url,
+ mojom::AdsViolation ads_violation) {
+ std::unique_ptr<base::DictionaryValue> additional_metadata =
+ std::make_unique<base::DictionaryValue>();
+
+ double now = clock_->Now().ToDoubleT();
+ additional_metadata->SetDouble(kLastAdsViolationTimeKey, now);
+ additional_metadata->SetInteger(kLastAdsViolationKey,
+ static_cast<int>(ads_violation));
+
+ bool activated = base::FeatureList::IsEnabled(kAdsInterventionsEnforced);
+ // This is a no-op if the metadata already exists for an active
+ // ads intervention.
+ settings_manager_->SetSiteMetadataBasedOnActivation(
+ url, activated,
+ SubresourceFilterContentSettingsManager::ActivationSource::
+ kAdsIntervention,
+ std::move(additional_metadata));
+
+ UMA_HISTOGRAM_ENUMERATION(kAdsInterventionRecordedHistogramName,
+ ads_violation);
+}
+
+base::Optional<AdsInterventionManager::LastAdsIntervention>
+AdsInterventionManager::GetLastAdsIntervention(const GURL& url) const {
+ int ads_violation;
+ double last_violation_time;
+ // The last active ads intervention is stored in the site metadata.
+ std::unique_ptr<base::DictionaryValue> dict =
+ settings_manager_->GetSiteMetadata(url);
+
+ if (dict && dict->GetInteger(kLastAdsViolationKey, &ads_violation) &&
+ dict->GetDouble(kLastAdsViolationTimeKey, &last_violation_time)) {
+ base::TimeDelta diff =
+ clock_->Now() - base::Time::FromDoubleT(last_violation_time);
+
+ return LastAdsIntervention(
+ {diff, static_cast<mojom::AdsViolation>(ads_violation)});
+ }
+
+ return base::nullopt;
+}
+
+bool AdsInterventionManager::ShouldActivate(
+ content::NavigationHandle* navigation_handle) const {
+ const GURL& url(navigation_handle->GetURL());
+ // TODO(https://crbug.com/1136987): Add new ads intervention
+ // manager function to return struct with all ads intervention
+ // metadata to reduce metadata accesses.
+ base::Optional<AdsInterventionManager::LastAdsIntervention>
+ last_intervention = GetLastAdsIntervention(url);
+
+ // Only activate the subresource filter if we are intervening on
+ // ads.
+ bool current_activation_status =
+ settings_manager_->GetSiteActivationFromMetadata(url);
+ bool has_active_ads_intervention =
+ last_intervention &&
+ last_intervention->duration_since <
+ subresource_filter::kAdsInterventionDuration.Get();
+ if (last_intervention) {
+ UMA_HISTOGRAM_COUNTS_1000(kTimeSinceAdsInterventionTriggeredHistogramName,
+ last_intervention->duration_since.InHours());
+
+ auto* ukm_recorder = ukm::UkmRecorder::Get();
+ ukm::builders::AdsIntervention_LastIntervention builder(
+ ukm::ConvertToSourceId(navigation_handle->GetNavigationId(),
+ ukm::SourceIdType::NAVIGATION_ID));
+ builder
+ .SetInterventionType(static_cast<int>(last_intervention->ads_violation))
+ .SetInterventionStatus(static_cast<int>(GetAdsInterventionStatus(
+ current_activation_status, has_active_ads_intervention)));
+ builder.Record(ukm_recorder->Get());
+ }
+
+ return current_activation_status && has_active_ads_intervention;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/ads_intervention_manager.h b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.h
new file mode 100644
index 00000000000..95fb4d695a1
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.h
@@ -0,0 +1,109 @@
+// Copyright 2020 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_ADS_INTERVENTION_MANAGER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_ADS_INTERVENTION_MANAGER_H_
+
+#include <memory>
+
+#include "base/optional.h"
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+
+class GURL;
+
+namespace base {
+class Clock;
+}
+
+namespace content {
+class NavigationHandle;
+}
+
+// The subresource filter activation status associated with an ads
+// intervention during page load.
+enum class AdsInterventionStatus {
+ // The ads intervention occurred longer than
+ // subresource_filter::kAdsInterventionDuration ago.
+ kExpired,
+ // Ads interventions are in dry run mode and the subresource filter would
+ // have activated due to an active intervention.
+ kWouldBlock,
+ // Ads interventions are activate and there is an active intervention.
+ kBlocking,
+};
+
+namespace subresource_filter {
+
+// This class tracks ads interventions that have occurred on origins and is
+// bound to the user's profile. The ads intervention manager operates in two
+// modes set by the feature flag kAdsInterventionsEnforced:
+// 1. Dry run: Ads are not blocked on sites with ad interventions, however,
+// the ads intervention manager records metrics as if ads were blocked.
+// If the ads intervention manager is asked to intervene on the same URL
+// in the period where we would block ads during enforcement, it will only
+// record the first seen intervention.
+// 2. Enforced: Ads are blocked on sites with ad interventions.
+//
+// The duration of an ad intervention is set by the feature flag
+// kAdsInterventionDuration.
+//
+// This class maintain's metadata for ads interventions in the user's website
+// settings. This is persisted to disk and cleared with browsing history. The
+// content subresource filter manager expires ads intervention metadata after
+// 7 days. As a result, kAdsInterventionDuration should be less than 7 days
+// to prevent expiry from impacting metrics. The metadata is scoped to each
+// url's origin. This API would ideally work with Origins insead of GURLs,
+// however, downstream APIs use GURL's.
+class AdsInterventionManager {
+ public:
+ // Struct representing the last triggered ads intervention.
+ struct LastAdsIntervention {
+ base::TimeDelta duration_since;
+ mojom::AdsViolation ads_violation;
+ };
+
+ // The content_settings_manager should outlive the ads intervention manager.
+ // This is satisfied as the SubresourceFilterContentSettingsManager and the
+ // AdsInterventionManager are both bound to the profile.
+ explicit AdsInterventionManager(
+ SubresourceFilterContentSettingsManager* content_settings_manager);
+ ~AdsInterventionManager();
+ AdsInterventionManager(const AdsInterventionManager&) = delete;
+ AdsInterventionManager& operator=(const AdsInterventionManager&) = delete;
+
+ // The ads intervention manager should trigger an ads intervention on each
+ // subsequent page load to |url| for kAdsInterventionDuration. The active
+ // intervention is recorded in the user's website settings and updates
+ // |url| site metadata with the last active intervention.
+ void TriggerAdsInterventionForUrlOnSubsequentLoads(
+ const GURL& url,
+ mojom::AdsViolation ads_violation);
+
+ // Returns the last active ads intervention written to metadata,
+ // otherwise base::nullopt is returned. When retrieving ads interventions
+ // for a navigation, should_record_metrics should be true to record
+ // per-navigation ads intervention metrics.
+ base::Optional<LastAdsIntervention> GetLastAdsIntervention(
+ const GURL& url) const;
+
+ // Returns whether the subresource filter should activate for
+ // |navigation_handle| based on feature status and current active
+ // intervention. This should only be called once per page to calculate
+ // activation as it records per page intervention information.
+ bool ShouldActivate(content::NavigationHandle* navigation_handle) const;
+
+ void set_clock_for_testing(base::Clock* clock) { clock_ = clock; }
+
+ private:
+ // The SubresourceFilterContentSettingsManager is guaranteed to outlive the
+ // AdsInterventionManager. Both are bound to the profile.
+ SubresourceFilterContentSettingsManager* settings_manager_ = nullptr;
+
+ base::Clock* clock_;
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_ADS_INTERVENTION_MANAGER_H_
diff --git a/chromium/components/subresource_filter/content/browser/ads_intervention_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/ads_intervention_manager_unittest.cc
new file mode 100644
index 00000000000..17ffa249939
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/ads_intervention_manager_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2020 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/subresource_filter/content/browser/ads_intervention_manager.h"
+
+#include <memory>
+
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+class AdsInterventionManagerTest : public testing::Test {
+ public:
+ AdsInterventionManagerTest() = default;
+ AdsInterventionManagerTest(const AdsInterventionManagerTest&) = delete;
+ AdsInterventionManagerTest& operator=(const AdsInterventionManagerTest&) =
+ delete;
+
+ // Creates and configures the AdsInterventionManager instance used by the
+ // tests, first creating the dependencies that need to be supplied to that
+ // instance.
+ void SetUp() override {
+ HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
+ settings_map_ = new HostContentSettingsMap(
+ &prefs_, false /* is_off_the_record */, false /* store_last_modified */,
+ false /* restore_session */);
+ settings_manager_ =
+ std::make_unique<SubresourceFilterContentSettingsManager>(
+ settings_map_.get());
+
+ ads_intervention_manager_ =
+ std::make_unique<AdsInterventionManager>(settings_manager_.get());
+
+ test_clock_ = std::make_unique<base::SimpleTestClock>();
+ ads_intervention_manager_->set_clock_for_testing(test_clock_.get());
+ }
+
+ void TearDown() override { settings_map_->ShutdownOnUIThread(); }
+
+ base::SimpleTestClock* test_clock() { return test_clock_.get(); }
+
+ protected:
+ // Used by the HostContentSettingsMap instance.
+ sync_preferences::TestingPrefServiceSyncable prefs_;
+
+ // Used by the SubresourceFilterContentSettingsManager instance.
+ scoped_refptr<HostContentSettingsMap> settings_map_;
+
+ // Used by the AdsInterventionManager instance.
+ std::unique_ptr<SubresourceFilterContentSettingsManager> settings_manager_;
+
+ // Instance under test.
+ std::unique_ptr<AdsInterventionManager> ads_intervention_manager_;
+
+ private:
+ content::BrowserTaskEnvironment task_environment_;
+
+ std::unique_ptr<base::SimpleTestClock> test_clock_;
+};
+
+TEST_F(AdsInterventionManagerTest,
+ NoIntervention_NoActiveInterventionReturned) {
+ GURL url("https://example.test/");
+
+ base::Optional<AdsInterventionManager::LastAdsIntervention> ads_intervention =
+ ads_intervention_manager_->GetLastAdsIntervention(url);
+ EXPECT_FALSE(ads_intervention.has_value());
+}
+
+TEST_F(AdsInterventionManagerTest, SingleIntervention_TimeSinceMatchesClock) {
+ GURL url("https://example.test/");
+
+ ads_intervention_manager_->TriggerAdsInterventionForUrlOnSubsequentLoads(
+ url, mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
+ test_clock()->Advance(base::TimeDelta::FromHours(1));
+
+ base::Optional<AdsInterventionManager::LastAdsIntervention> ads_intervention =
+ ads_intervention_manager_->GetLastAdsIntervention(url);
+ EXPECT_TRUE(ads_intervention.has_value());
+ EXPECT_EQ(ads_intervention->ads_violation,
+ mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
+ EXPECT_EQ(ads_intervention->duration_since, base::TimeDelta::FromHours(1));
+
+ // Advance the clock by two hours, duration since should now be 3 hours.
+ test_clock()->Advance(base::TimeDelta::FromHours(2));
+ ads_intervention = ads_intervention_manager_->GetLastAdsIntervention(url);
+ EXPECT_TRUE(ads_intervention.has_value());
+ EXPECT_EQ(ads_intervention->ads_violation,
+ mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
+ EXPECT_EQ(ads_intervention->duration_since, base::TimeDelta::FromHours(3));
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
index 0f9fce5364c..c26ed088a84 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/task_runner_util.h"
@@ -26,22 +26,6 @@ mojom::ActivationState ComputeActivationState(
const MemoryMappedRuleset* ruleset) {
DCHECK(ruleset);
- SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
- "SubresourceFilter.DocumentLoad.Activation.WallDuration");
- SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
- "SubresourceFilter.DocumentLoad.Activation.CPUDuration");
-
- auto page_wall_duration_timer = ScopedTimers::StartIf(
- parent_document_origin.opaque(), [](base::TimeDelta delta) {
- UMA_HISTOGRAM_MICRO_TIMES(
- "SubresourceFilter.PageLoad.Activation.WallDuration", delta);
- });
- auto page_cpu_duration_timer = ScopedThreadTimers::StartIf(
- parent_document_origin.opaque(), [](base::TimeDelta delta) {
- UMA_HISTOGRAM_MICRO_TIMES(
- "SubresourceFilter.PageLoad.Activation.CPUDuration", delta);
- });
-
IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length());
mojom::ActivationState activation_state = parent_activation_state;
if (activation_state.filtering_disabled_for_document)
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc
index caea3eae205..066f597efe2 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.cc
@@ -5,7 +5,7 @@
#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
index 26a1535cf87..abda084140f 100644
--- a/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index c042f87b4cf..b8647ea16dd 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -24,6 +24,7 @@
#include "components/subresource_filter/content/common/subresource_filter_utils.h"
#include "components/subresource_filter/content/mojom/subresource_filter_agent.mojom.h"
#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -38,17 +39,99 @@
namespace subresource_filter {
+namespace {
+
+bool ShouldInheritOpenerActivation(content::NavigationHandle* navigation_handle,
+ content::RenderFrameHost* frame_host) {
+ if (!navigation_handle->IsInMainFrame()) {
+ return false;
+ }
+
+ // If this navigation is for a special url that did not go through the network
+ // stack or if the initial (attempted) load wasn't committed, the frame's
+ // activation will not have been set. It should instead be inherited from its
+ // same-origin opener (if any). See ShouldInheritParentActivation() for
+ // subframes.
+ content::RenderFrameHost* opener_rfh =
+ navigation_handle->GetWebContents()->GetOpener();
+ if (!opener_rfh) {
+ return false;
+ }
+
+ if (!frame_host->GetLastCommittedOrigin().IsSameOriginWith(
+ opener_rfh->GetLastCommittedOrigin())) {
+ return false;
+ }
+
+ return ShouldInheritActivation(navigation_handle->GetURL()) ||
+ !navigation_handle->HasCommitted();
+}
+
+bool ShouldInheritParentActivation(
+ content::NavigationHandle* navigation_handle) {
+ if (navigation_handle->IsInMainFrame()) {
+ return false;
+ }
+ DCHECK(navigation_handle->GetParentFrame());
+
+ // As with ShouldInheritSameOriginOpenerActivation() except that we inherit
+ // from the parent frame as we are a subframe.
+ return ShouldInheritActivation(navigation_handle->GetURL()) ||
+ !navigation_handle->HasCommitted();
+}
+
+} // namespace
+
+const char ContentSubresourceFilterThrottleManager::
+ kContentSubresourceFilterThrottleManagerWebContentsUserDataKey[] =
+ "content_subresource_filter_throttle_manager";
+
+// static
+void ContentSubresourceFilterThrottleManager::CreateForWebContents(
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client,
+ VerifiedRulesetDealer::Handle* dealer_handle) {
+ if (!base::FeatureList::IsEnabled(kSafeBrowsingSubresourceFilter))
+ return;
+
+ if (FromWebContents(web_contents))
+ return;
+
+ web_contents->SetUserData(
+ kContentSubresourceFilterThrottleManagerWebContentsUserDataKey,
+ std::make_unique<ContentSubresourceFilterThrottleManager>(
+ std::move(client), dealer_handle, web_contents));
+}
+
+// static
+ContentSubresourceFilterThrottleManager*
+ContentSubresourceFilterThrottleManager::FromWebContents(
+ content::WebContents* web_contents) {
+ return static_cast<ContentSubresourceFilterThrottleManager*>(
+ web_contents->GetUserData(
+ kContentSubresourceFilterThrottleManagerWebContentsUserDataKey));
+}
+
+// static
+const ContentSubresourceFilterThrottleManager*
+ContentSubresourceFilterThrottleManager::FromWebContents(
+ const content::WebContents* web_contents) {
+ return static_cast<const ContentSubresourceFilterThrottleManager*>(
+ web_contents->GetUserData(
+ kContentSubresourceFilterThrottleManagerWebContentsUserDataKey));
+}
+
ContentSubresourceFilterThrottleManager::
ContentSubresourceFilterThrottleManager(
- SubresourceFilterClient* client,
+ std::unique_ptr<SubresourceFilterClient> client,
VerifiedRulesetDealer::Handle* dealer_handle,
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
receiver_(web_contents, this),
dealer_handle_(dealer_handle),
- client_(client) {
+ client_(std::move(client)) {
SubresourceFilterObserverManager::CreateForWebContents(web_contents);
- scoped_observer_.Add(
+ scoped_observation_.Observe(
SubresourceFilterObserverManager::FromWebContents(web_contents));
}
@@ -58,7 +141,7 @@ ContentSubresourceFilterThrottleManager::
void ContentSubresourceFilterThrottleManager::OnSubresourceFilterGoingAway() {
// Stop observing here because the observer manager could be destroyed by the
// time this class is destroyed.
- scoped_observer_.RemoveAll();
+ scoped_observation_.RemoveObservation();
}
void ContentSubresourceFilterThrottleManager::RenderFrameDeleted(
@@ -108,7 +191,8 @@ void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
if (navigation_handle->GetNetErrorCode() != net::OK)
return;
- auto it = ongoing_activation_throttles_.find(navigation_handle);
+ auto it =
+ ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
if (it == ongoing_activation_throttles_.end())
return;
@@ -161,11 +245,13 @@ void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
- // Make sure not to leak throttle pointers.
ActivationStateComputingNavigationThrottle* throttle = nullptr;
- auto throttle_it = ongoing_activation_throttles_.find(navigation_handle);
+ auto throttle_it =
+ ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
if (throttle_it != ongoing_activation_throttles_.end()) {
throttle = throttle_it->second;
+
+ // Make sure not to leak throttle pointers.
ongoing_activation_throttles_.erase(throttle_it);
}
@@ -173,40 +259,29 @@ void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
if (navigation_handle->IsSameDocument()) {
return;
}
- if (!navigation_handle->HasCommitted()) {
- // TODO(crbug.com/1055558): Handle the case of an aborted main frame load.
-
- // If the initial load was aborted, the frame's activation will never have
- // been set and should instead be inherited from its parents. Reuse the
- // previous activation in the case of a non-initial aborted load.
- if (!navigation_handle->IsInMainFrame() &&
- navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) {
- // Cannot get the RFH from navigation_handle due to the aborted load.
- content::RenderFrameHost* frame_host =
- navigation_handle->GetWebContents()->UnsafeFindFrameByFrameTreeNodeId(
- navigation_handle->GetFrameTreeNodeId());
-
- // The RenderFrameHost will still exist as, even if a frame is destroyed,
- // the NavigationHandle is destroyed (resulting in a call to
- // DidFinishNavigation) before the RenderFrameHost is.
- DCHECK(frame_host);
- if (navigated_frames_.insert(frame_host).second) {
- DCHECK(!base::Contains(frame_host_filter_map_, frame_host));
- frame_host_filter_map_[frame_host] = nullptr;
- }
- }
+
+ // Cannot get the RFH from |navigation_handle| if there's no committed load.
+ content::RenderFrameHost* frame_host =
+ navigation_handle->HasCommitted()
+ ? navigation_handle->GetRenderFrameHost()
+ : navigation_handle->GetWebContents()
+ ->UnsafeFindFrameByFrameTreeNodeId(
+ navigation_handle->GetFrameTreeNodeId());
+ if (!frame_host) {
+ DCHECK(!navigation_handle->HasCommitted());
return;
}
- std::unique_ptr<AsyncDocumentSubresourceFilter> filter;
- if (throttle) {
- CHECK_EQ(navigation_handle, throttle->navigation_handle());
- filter = throttle->ReleaseFilter();
+ // Reuse the previous activation if this attempted load was neither the
+ // initial load nor committed.
+ if (!navigated_frames_.insert(frame_host).second &&
+ !navigation_handle->HasCommitted()) {
+ return;
}
- content::RenderFrameHost* frame_host =
- navigation_handle->GetRenderFrameHost();
- navigated_frames_.insert(frame_host);
+ bool did_inherit_opener_activation;
+ AsyncDocumentSubresourceFilter* filter = FilterForFinishedNavigation(
+ navigation_handle, throttle, frame_host, did_inherit_opener_activation);
if (navigation_handle->IsInMainFrame()) {
current_committed_load_has_notified_disallowed_load_ = false;
@@ -222,31 +297,103 @@ void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
kActivationConsoleMessage);
}
}
- mojom::ActivationLevel level =
+ RecordUmaHistogramsForMainFrameNavigation(
+ navigation_handle,
filter ? filter->activation_state().activation_level
- : mojom::ActivationLevel::kDisabled;
- UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationState",
- level);
+ : mojom::ActivationLevel::kDisabled,
+ did_inherit_opener_activation);
+ }
+
+ DestroyRulesetHandleIfNoLongerUsed();
+}
+
+AsyncDocumentSubresourceFilter*
+ContentSubresourceFilterThrottleManager::FilterForFinishedNavigation(
+ content::NavigationHandle* navigation_handle,
+ ActivationStateComputingNavigationThrottle* throttle,
+ content::RenderFrameHost* frame_host,
+ bool& did_inherit_opener_activation) {
+ DCHECK(navigation_handle);
+ DCHECK(frame_host);
+
+ std::unique_ptr<AsyncDocumentSubresourceFilter> filter;
+ did_inherit_opener_activation = false;
+
+ if (navigation_handle->HasCommitted() && throttle) {
+ CHECK_EQ(navigation_handle, throttle->navigation_handle());
+ filter = throttle->ReleaseFilter();
+ }
+
+ // If the frame should inherit its activation then, if it has an activated
+ // opener, construct a filter with the inherited activation state. The
+ // filter's activation state will be available immediately so a throttle is
+ // not required. Instead, we construct the filter synchronously.
+ if (ShouldInheritOpenerActivation(navigation_handle, frame_host)) {
+ content::RenderFrameHost* opener_rfh =
+ navigation_handle->GetWebContents()->GetOpener();
+ base::Optional<mojom::ActivationState> opener_activation;
+ if (auto* opener_throttle_manager =
+ ContentSubresourceFilterThrottleManager::FromWebContents(
+ content::WebContents::FromRenderFrameHost(opener_rfh))) {
+ opener_activation =
+ opener_throttle_manager->GetFrameActivationState(opener_rfh);
+ did_inherit_opener_activation = true;
+ }
+
+ if (opener_activation && opener_activation->activation_level !=
+ mojom::ActivationLevel::kDisabled) {
+ DCHECK(dealer_handle_);
+
+ // This constructs the filter in a way that allows it to be immediately
+ // used. See the AsyncDocumentSubresourceFilter constructor for details.
+ filter = std::make_unique<AsyncDocumentSubresourceFilter>(
+ EnsureRulesetHandle(), frame_host->GetLastCommittedOrigin(),
+ *opener_activation);
+ }
}
// Make sure |frame_host_filter_map_| is updated or cleaned up depending on
// this navigation's activation state.
- if (filter) {
- base::OnceClosure disallowed_callback(base::BindOnce(
- &ContentSubresourceFilterThrottleManager::MaybeShowNotification,
- weak_ptr_factory_.GetWeakPtr()));
- filter->set_first_disallowed_load_callback(std::move(disallowed_callback));
- frame_host_filter_map_[frame_host] = std::move(filter);
- } else {
- frame_host_filter_map_.erase(frame_host);
-
- // If this is for a special url that did not go through the navigation
- // throttles, then based on the parent's activation state, possibly add this
- // to frame_host_filter_map_.
- MaybeActivateSubframeSpecialUrls(navigation_handle);
+ if (!filter) {
+ if (ShouldInheritParentActivation(navigation_handle) &&
+ base::Contains(frame_host_filter_map_,
+ navigation_handle->GetParentFrame())) {
+ // TODO(crbug.com/1134288): Synchronously construct filters for subframes
+ // to inherit activation from their parents, instead of walking up the
+ // frame tree. Once done, consider updating the map in the caller.
+ // |nullptr| indicates a subframe inheriting its activation.
+ frame_host_filter_map_[frame_host] = nullptr;
+ } else {
+ frame_host_filter_map_.erase(frame_host);
+ }
+ return nullptr;
}
- DestroyRulesetHandleIfNoLongerUsed();
+ base::OnceClosure disallowed_callback(base::BindOnce(
+ &ContentSubresourceFilterThrottleManager::MaybeShowNotification,
+ weak_ptr_factory_.GetWeakPtr()));
+ filter->set_first_disallowed_load_callback(std::move(disallowed_callback));
+
+ AsyncDocumentSubresourceFilter* raw_ptr = filter.get();
+ frame_host_filter_map_[frame_host] = std::move(filter);
+
+ return raw_ptr;
+}
+
+void ContentSubresourceFilterThrottleManager::
+ RecordUmaHistogramsForMainFrameNavigation(
+ content::NavigationHandle* navigation_handle,
+ const mojom::ActivationLevel& activation_level,
+ bool did_inherit_opener_activation) {
+ DCHECK(navigation_handle->IsInMainFrame());
+
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationState",
+ activation_level);
+ if (did_inherit_opener_activation) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SubresourceFilter.PageLoad.ActivationState.DidInherit",
+ activation_level);
+ }
}
void ContentSubresourceFilterThrottleManager::DidFinishLoad(
@@ -267,7 +414,8 @@ void ContentSubresourceFilterThrottleManager::OnPageActivationComputed(
DCHECK(navigation_handle->IsInMainFrame());
DCHECK(!navigation_handle->HasCommitted());
- auto it = ongoing_activation_throttles_.find(navigation_handle);
+ auto it =
+ ongoing_activation_throttles_.find(navigation_handle->GetNavigationId());
if (it == ongoing_activation_throttles_.end())
return;
@@ -316,7 +464,8 @@ void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles(
client_->GetSafeBrowsingDatabaseManager()) {
throttles->push_back(
std::make_unique<SubresourceFilterSafeBrowsingActivationThrottle>(
- navigation_handle, client_, content::GetIOThreadTaskRunner({}),
+ navigation_handle, client_.get(),
+ content::GetIOThreadTaskRunner({}),
client_->GetSafeBrowsingDatabaseManager()));
}
@@ -327,10 +476,11 @@ void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles(
throttles->push_back(std::move(filtering_throttle));
}
- DCHECK(!base::Contains(ongoing_activation_throttles_, navigation_handle));
+ DCHECK(!base::Contains(ongoing_activation_throttles_,
+ navigation_handle->GetNavigationId()));
if (auto activation_throttle =
MaybeCreateActivationStateComputingThrottle(navigation_handle)) {
- ongoing_activation_throttles_[navigation_handle] =
+ ongoing_activation_throttles_[navigation_handle->GetNavigationId()] =
activation_throttle.get();
throttles->push_back(std::move(activation_throttle));
}
@@ -363,6 +513,16 @@ ContentSubresourceFilterThrottleManager::LoadPolicyForLastCommittedNavigation(
return base::nullopt;
}
+void ContentSubresourceFilterThrottleManager::OnReloadRequested() {
+ client_->OnReloadRequested();
+}
+
+// static
+void ContentSubresourceFilterThrottleManager::LogAction(
+ SubresourceFilterAction action) {
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.Actions2", action);
+}
+
std::unique_ptr<SubframeNavigationFilteringThrottle>
ContentSubresourceFilterThrottleManager::
MaybeCreateSubframeNavigationFilteringThrottle(
@@ -410,19 +570,33 @@ ContentSubresourceFilterThrottleManager::GetParentFrameFilter(
content::NavigationHandle* child_frame_navigation) {
DCHECK(!child_frame_navigation->IsInMainFrame());
content::RenderFrameHost* parent = child_frame_navigation->GetParentFrame();
- DCHECK(parent);
+ return GetFrameFilter(parent);
+}
+
+const base::Optional<subresource_filter::mojom::ActivationState>
+ContentSubresourceFilterThrottleManager::GetFrameActivationState(
+ content::RenderFrameHost* frame_host) {
+ if (AsyncDocumentSubresourceFilter* filter = GetFrameFilter(frame_host))
+ return filter->activation_state();
+ return base::nullopt;
+}
+
+AsyncDocumentSubresourceFilter*
+ContentSubresourceFilterThrottleManager::GetFrameFilter(
+ content::RenderFrameHost* frame_host) {
+ DCHECK(frame_host);
// Filter will be null for those special url navigations that were added in
- // MaybeActivateSubframeSpecialUrls and for subframes with no committed
- // navigation. Return the filter of the first parent with a non-null filter.
- while (parent) {
- auto it = frame_host_filter_map_.find(parent);
+ // MaybeActivateSubframeSpecialUrls and for subframes with an aborted load.
+ // Return the filter of the first parent with a non-null filter.
+ while (frame_host) {
+ auto it = frame_host_filter_map_.find(frame_host);
if (it == frame_host_filter_map_.end())
return nullptr;
if (it->second)
return it->second.get();
- parent = it->first->GetParent();
+ frame_host = it->first->GetParent();
}
// Since a null filter is only possible for special navigations of iframes and
@@ -497,23 +671,4 @@ void ContentSubresourceFilterThrottleManager::SetDocumentLoadStatistics(
statistics_->OnDocumentLoadStatistics(*statistics);
}
-void ContentSubresourceFilterThrottleManager::MaybeActivateSubframeSpecialUrls(
- content::NavigationHandle* navigation_handle) {
- if (navigation_handle->IsInMainFrame())
- return;
-
- if (!ShouldUseParentActivation(navigation_handle->GetURL()))
- return;
-
- content::RenderFrameHost* frame_host =
- navigation_handle->GetRenderFrameHost();
- if (!frame_host)
- return;
-
- content::RenderFrameHost* parent = navigation_handle->GetParentFrame();
- DCHECK(parent);
- if (base::Contains(frame_host_filter_map_, parent))
- frame_host_filter_map_[frame_host] = nullptr;
-}
-
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
index 779139e7854..1e8687823a7 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -13,8 +13,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/stl_util.h"
+#include "base/supports_user_data.h"
#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
@@ -37,24 +38,70 @@ class ActivationStateComputingNavigationThrottle;
class PageLoadStatistics;
class SubresourceFilterClient;
+// This enum backs a histogram. Make sure new elements are only added to the
+// end. Keep histograms.xml up to date with any changes.
+enum class SubresourceFilterAction {
+ // Standard UI shown. On Desktop this is in the omnibox,
+ // On Android, it is an infobar.
+ kUIShown = 0,
+
+ // The UI was suppressed due to "smart" logic which tries not to spam the UI
+ // on navigations on the same origin within a certain time.
+ kUISuppressed = 1,
+
+ // On Desktop, this is a bubble. On Android it is an
+ // expanded infobar.
+ kDetailsShown = 2,
+
+ kClickedLearnMore = 3,
+
+ // Logged when the user presses "Always allow ads" scoped to a particular
+ // site. Does not count manual changes to content settings.
+ kAllowlistedSite = 4,
+
+ // Logged when a devtools message arrives notifying us to force activation in
+ // this web contents.
+ kForcedActivationEnabled = 5,
+
+ kMaxValue = kForcedActivationEnabled
+};
+
// The ContentSubresourceFilterThrottleManager manages NavigationThrottles in
// order to calculate frame activation states and subframe navigation filtering,
// within a given WebContents. It contains a mapping of all activated
// RenderFrameHosts, along with their associated DocumentSubresourceFilters.
//
-// The class is designed to be used by a SubresourceFilterClient instance that
-// shares lifetime with this class (aka the typical lifetime of a
-// WebContentsObserver). The client will be notified of the first disallowed
-// subresource load for a top level navgation, and has veto power for frame
-// activation.
+// The class is designed to be attached to a WebContents instance by an embedder
+// via CreateForWebContents(), with the embedder passing a
+// SubresourceFilterClient instance customized for that embedder. The client
+// will be notified of the first disallowed subresource load for a top level
+// navgation, and has veto power for frame activation.
class ContentSubresourceFilterThrottleManager
- : public content::WebContentsObserver,
+ : public base::SupportsUserData::Data,
+ public content::WebContentsObserver,
public mojom::SubresourceFilterHost,
public SubresourceFilterObserver,
public SubframeNavigationFilteringThrottle::Delegate {
public:
+ static const char
+ kContentSubresourceFilterThrottleManagerWebContentsUserDataKey[];
+
+ // Creates a ThrottleManager instance from the given parameters and attaches
+ // it as user data of |web_contents|.
+ // NOTE: Short-circuits out if the kSafeBrowsingSubresourceFilter feature is
+ // not enabled.
+ static void CreateForWebContents(
+ content::WebContents* web_contents,
+ std::unique_ptr<SubresourceFilterClient> client,
+ VerifiedRulesetDealer::Handle* dealer_handle);
+
+ static ContentSubresourceFilterThrottleManager* FromWebContents(
+ content::WebContents* web_contents);
+ static const ContentSubresourceFilterThrottleManager* FromWebContents(
+ const content::WebContents* web_contents);
+
ContentSubresourceFilterThrottleManager(
- SubresourceFilterClient* client,
+ std::unique_ptr<SubresourceFilterClient> client,
VerifiedRulesetDealer::Handle* dealer_handle,
content::WebContents* web_contents);
~ContentSubresourceFilterThrottleManager() override;
@@ -74,6 +121,8 @@ class ContentSubresourceFilterThrottleManager
PageLoadStatistics* page_load_statistics() const { return statistics_.get(); }
+ SubresourceFilterClient* client() { return client_.get(); }
+
VerifiedRuleset::Handle* ruleset_handle_for_testing() {
return ruleset_handle_.get();
}
@@ -93,6 +142,12 @@ class ContentSubresourceFilterThrottleManager
base::Optional<LoadPolicy> LoadPolicyForLastCommittedNavigation(
const content::RenderFrameHost* frame_host) const;
+ // Notifies the client that the user has requested a reload of a page with
+ // blocked ads (e.g., via an infobar).
+ void OnReloadRequested();
+
+ static void LogAction(SubresourceFilterAction action);
+
protected:
// content::WebContentsObserver:
void RenderFrameDeleted(content::RenderFrameHost* frame_host) override;
@@ -134,6 +189,16 @@ class ContentSubresourceFilterThrottleManager
AsyncDocumentSubresourceFilter* GetParentFrameFilter(
content::NavigationHandle* child_frame_navigation);
+ // Returns nullptr if the frame is not activated (and therefore has no
+ // subresource filter).
+ AsyncDocumentSubresourceFilter* GetFrameFilter(
+ content::RenderFrameHost* frame_host);
+
+ // Returns the activation state of the frame's filter. If the frame is not
+ // activated (and therefore has no subresource filter), returns base::nullopt.
+ const base::Optional<subresource_filter::mojom::ActivationState>
+ GetFrameActivationState(content::RenderFrameHost* frame_host);
+
// Calls ShowNotification on |client_| at most once per committed,
// non-same-page navigation in the main frame.
void MaybeShowNotification();
@@ -151,12 +216,22 @@ class ContentSubresourceFilterThrottleManager
void SetDocumentLoadStatistics(
mojom::DocumentLoadStatisticsPtr statistics) override;
- // Adds the navigation's RenderFrameHost to activated_frame_hosts_ if it is a
- // special navigation which did not go through navigation throttles and its
- // parent frame is activated as well. The filter for these frames is set
- // to nullptr.
- void MaybeActivateSubframeSpecialUrls(
- content::NavigationHandle* navigation_handle);
+ // Gets a filter for the navigation from |throttle|, creates and returns a new
+ // filter, or returns |nullptr|. Also updates |frame_host_filter_map_| as
+ // appropriate. |frame_host| is provided as |navigation_handle|'s getter
+ // cannot be used when the navigation has not committed.
+ // `did_inherit_opener_activation` will be set according to whether the
+ // activation was inherited from the frame's same-origin opener.
+ AsyncDocumentSubresourceFilter* FilterForFinishedNavigation(
+ content::NavigationHandle* navigation_handle,
+ ActivationStateComputingNavigationThrottle* throttle,
+ content::RenderFrameHost* frame_host,
+ bool& did_inherit_opener_activation);
+
+ void RecordUmaHistogramsForMainFrameNavigation(
+ content::NavigationHandle* navigation_handle,
+ const mojom::ActivationLevel& activation_level,
+ bool did_inherit_opener_activation);
// For each RenderFrameHost where the last committed load has subresource
// filtering activated, owns the corresponding AsyncDocumentSubresourceFilter.
@@ -169,14 +244,14 @@ class ContentSubresourceFilterThrottleManager
frame_host_filter_map_;
// Set of RenderFrameHosts that have had at least one committed or aborted
- // navigation. Main frames with only aborted navigations are not included.
+ // navigation.
std::set<content::RenderFrameHost*> navigated_frames_;
// For each ongoing navigation that requires activation state computation,
// keeps track of the throttle that is carrying out that computation, so that
- // the result can be retrieved when the navigation is ready to commit.
- std::map<content::NavigationHandle*,
- ActivationStateComputingNavigationThrottle*>
+ // the result can be retrieved when the navigation is ready to commit. Keyed
+ // by navigation id.
+ std::map<int64_t, ActivationStateComputingNavigationThrottle*>
ongoing_activation_throttles_;
// Set of RenderFrameHosts that have been identified as ads. An RFH is an ad
@@ -197,8 +272,9 @@ class ContentSubresourceFilterThrottleManager
content::WebContentsFrameReceiverSet<mojom::SubresourceFilterHost> receiver_;
- ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver>
- scoped_observer_{this};
+ base::ScopedObservation<SubresourceFilterObserverManager,
+ SubresourceFilterObserver>
+ scoped_observation_{this};
// Lazily instantiated in EnsureRulesetHandle when the first page level
// activation is triggered. Will go away when there are no more activated
@@ -212,9 +288,10 @@ class ContentSubresourceFilterThrottleManager
// should only be called at most once per main frame load.
bool current_committed_load_has_notified_disallowed_load_ = false;
- // These members outlive this class.
+ // This member outlives this class.
VerifiedRulesetDealer::Handle* dealer_handle_;
- SubresourceFilterClient* client_;
+
+ std::unique_ptr<SubresourceFilterClient> client_;
base::WeakPtrFactory<ContentSubresourceFilterThrottleManager>
weak_ptr_factory_{this};
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
index 4e874edaa0e..7be82a95c4f 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/run_loop.h"
@@ -29,6 +29,7 @@
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
#include "components/subresource_filter/content/mojom/subresource_filter_agent.mojom.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
@@ -175,10 +176,45 @@ class MockPageStateActivationThrottle : public content::NavigationThrottle {
DISALLOW_COPY_AND_ASSIGN(MockPageStateActivationThrottle);
};
+class TestSubresourceFilterClient : public SubresourceFilterClient {
+ public:
+ TestSubresourceFilterClient() = default;
+ ~TestSubresourceFilterClient() override = default;
+
+ // SubresourceFilterClient:
+ void ShowNotification() override { ++disallowed_notification_count_; }
+ mojom::ActivationLevel OnPageActivationComputed(
+ content::NavigationHandle* navigation_handle,
+ mojom::ActivationLevel effective_activation_level,
+ ActivationDecision* decision) override {
+ return effective_activation_level;
+ }
+ void OnAdsViolationTriggered(
+ content::RenderFrameHost* rfh,
+ mojom::AdsViolation triggered_violation) override {}
+ const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
+ GetSafeBrowsingDatabaseManager() override {
+ return database_manager_;
+ }
+ void OnReloadRequested() override {}
+
+ void CreateSafeBrowsingDatabaseManager() {
+ database_manager_ =
+ base::MakeRefCounted<CustomTestSafeBrowsingDatabaseManager>();
+ }
+
+ int disallowed_notification_count() const {
+ return disallowed_notification_count_;
+ }
+
+ private:
+ scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
+ int disallowed_notification_count_ = 0;
+};
+
class ContentSubresourceFilterThrottleManagerTest
: public content::RenderViewHostTestHarness,
public content::WebContentsObserver,
- public SubresourceFilterClient,
public ::testing::WithParamInterface<PageActivationNotificationTiming> {
public:
ContentSubresourceFilterThrottleManagerTest() {}
@@ -211,13 +247,19 @@ class ContentSubresourceFilterThrottleManagerTest
/*expected_checksum=*/0,
base::DoNothing());
+ auto subresource_filter_client =
+ std::make_unique<TestSubresourceFilterClient>();
+ client_ = subresource_filter_client.get();
throttle_manager_ =
std::make_unique<ContentSubresourceFilterThrottleManager>(
- this, dealer_handle_.get(), web_contents);
+ std::move(subresource_filter_client), dealer_handle_.get(),
+ web_contents);
+
Observe(web_contents);
}
void TearDown() override {
+ client_ = nullptr;
throttle_manager_.reset();
dealer_handle_.reset();
base::RunLoop().RunUntilIdle();
@@ -272,7 +314,9 @@ class ContentSubresourceFilterThrottleManagerTest
return throttle_manager_->ruleset_handle_for_testing();
}
- int disallowed_notification_count() { return disallowed_notification_count_; }
+ int disallowed_notification_count() const {
+ return client_->disallowed_notification_count();
+ }
protected:
// content::WebContentsObserver
@@ -321,23 +365,6 @@ class ContentSubresourceFilterThrottleManagerTest
agent_map_[host] = std::move(new_agent);
}
- // SubresourceFilterClient:
- void ShowNotification() override { ++disallowed_notification_count_; }
- mojom::ActivationLevel OnPageActivationComputed(
- content::NavigationHandle* navigation_handle,
- mojom::ActivationLevel effective_activation_level,
- ActivationDecision* decision) override {
- return effective_activation_level;
- }
- void OnAdsViolationTriggered(
- content::RenderFrameHost* rfh,
- mojom::AdsViolation triggered_violation) override {}
-
- const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
- GetSafeBrowsingDatabaseManager() override {
- return database_manager_;
- }
-
ContentSubresourceFilterThrottleManager* throttle_manager() {
return throttle_manager_.get();
}
@@ -347,14 +374,17 @@ class ContentSubresourceFilterThrottleManagerTest
}
void CreateSafeBrowsingDatabaseManager() {
- database_manager_ =
- base::MakeRefCounted<CustomTestSafeBrowsingDatabaseManager>();
+ client_->CreateSafeBrowsingDatabaseManager();
+ }
+
+ VerifiedRulesetDealer::Handle* dealer_handle() {
+ return dealer_handle_.get();
}
private:
testing::TestRulesetCreator test_ruleset_creator_;
testing::TestRulesetPair test_ruleset_pair_;
- scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
+ TestSubresourceFilterClient* client_;
std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
@@ -368,9 +398,6 @@ class ContentSubresourceFilterThrottleManagerTest
bool created_safe_browsing_throttle_for_last_navigation_ = false;
- // Incremented on every OnFirstSubresourceLoadDisallowed call.
- int disallowed_notification_count_ = 0;
-
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterThrottleManagerTest);
};
@@ -814,6 +841,46 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_EQ(0, disallowed_notification_count());
}
+TEST_F(ContentSubresourceFilterThrottleManagerTest, CreateForWebContents) {
+ auto web_contents =
+ content::RenderViewHostTestHarness::CreateTestWebContents();
+ ASSERT_EQ(ContentSubresourceFilterThrottleManager::FromWebContents(
+ web_contents.get()),
+ nullptr);
+
+ {
+ base::test::ScopedFeatureList scoped_feature;
+ scoped_feature.InitAndDisableFeature(kSafeBrowsingSubresourceFilter);
+
+ // CreateForWebContents() should not do anything if the subresource filter
+ // feature is not enabled.
+ ContentSubresourceFilterThrottleManager::CreateForWebContents(
+ web_contents.get(), std::make_unique<TestSubresourceFilterClient>(),
+ dealer_handle());
+ EXPECT_EQ(ContentSubresourceFilterThrottleManager::FromWebContents(
+ web_contents.get()),
+ nullptr);
+ }
+
+ // If the subresource filter feature is enabled (as it is by default),
+ // CreateForWebContents() should create and attach an instance.
+ ContentSubresourceFilterThrottleManager::CreateForWebContents(
+ web_contents.get(), std::make_unique<TestSubresourceFilterClient>(),
+ dealer_handle());
+ auto* throttle_manager =
+ ContentSubresourceFilterThrottleManager::FromWebContents(
+ web_contents.get());
+ EXPECT_NE(throttle_manager, nullptr);
+
+ // A second call should not attach a different instance.
+ ContentSubresourceFilterThrottleManager::CreateForWebContents(
+ web_contents.get(), std::make_unique<TestSubresourceFilterClient>(),
+ dealer_handle());
+ EXPECT_EQ(ContentSubresourceFilterThrottleManager::FromWebContents(
+ web_contents.get()),
+ throttle_manager);
+}
+
TEST_F(ContentSubresourceFilterThrottleManagerTest,
SafeBrowsingThrottleCreation) {
// If no safe browsing database is present, the throttle should not be
@@ -871,13 +938,6 @@ TEST_F(ContentSubresourceFilterThrottleManagerTest, LogActivation) {
ExpectActivationSignalForFrame(subframe1, true /* expect_activation */);
tester.ExpectTotalCount(kActivationStateHistogram, 3);
- // Only those with page level activation do ruleset lookups.
- tester.ExpectTotalCount("SubresourceFilter.PageLoad.Activation.WallDuration",
- 2);
- // The *.CPUDuration histograms are recorded only if base::ThreadTicks is
- // supported.
- tester.ExpectTotalCount("SubresourceFilter.PageLoad.Activation.CPUDuration",
- base::ThreadTicks::IsSupported() ? 2 : 0);
}
// Check to make sure we don't send an IPC with the ad tag bit for ad frames
diff --git a/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc b/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
index 75ad00a4a16..04ad806a6fc 100644
--- a/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
@@ -5,7 +5,7 @@
#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_publisher_impl_unittest.cc b/chromium/components/subresource_filter/content/browser/ruleset_publisher_impl_unittest.cc
index 7cfabb4a4a9..b9922038fa2 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_publisher_impl_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/ruleset_publisher_impl_unittest.cc
@@ -11,8 +11,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_service.cc b/chromium/components/subresource_filter/content/browser/ruleset_service.cc
index 8bda760ee6b..085e713ae6b 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_service.cc
+++ b/chromium/components/subresource_filter/content/browser/ruleset_service.cc
@@ -26,6 +26,7 @@
#include "components/prefs/pref_service.h"
#include "components/subresource_filter/content/browser/ruleset_publisher.h"
#include "components/subresource_filter/content/browser/ruleset_publisher_impl.h"
+#include "components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
#include "components/subresource_filter/core/browser/copying_file_stream.h"
#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
@@ -268,10 +269,10 @@ IndexedRulesetVersion RulesetService::IndexAndWriteRuleset(
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
- base::File unindexed_ruleset_file(
- unindexed_ruleset_info.ruleset_path,
- base::File::FLAG_OPEN | base::File::FLAG_READ);
- if (!unindexed_ruleset_file.IsValid()) {
+ UnindexedRulesetStreamGenerator unindexed_ruleset_stream_generator(
+ unindexed_ruleset_info);
+
+ if (!unindexed_ruleset_stream_generator.ruleset_stream()) {
RecordIndexAndWriteRulesetResult(
IndexAndWriteRulesetResult::FAILED_OPENING_UNINDEXED_RULESET);
return IndexedRulesetVersion();
@@ -309,7 +310,7 @@ IndexedRulesetVersion RulesetService::IndexAndWriteRuleset(
// will prevent this version of the ruleset from ever being indexed again.
RulesetIndexer indexer;
- if (!(*g_index_ruleset_func)(std::move(unindexed_ruleset_file), &indexer)) {
+ if (!(*g_index_ruleset_func)(&unindexed_ruleset_stream_generator, &indexer)) {
RecordIndexAndWriteRulesetResult(
IndexAndWriteRulesetResult::FAILED_PARSING_UNINDEXED_RULESET);
return IndexedRulesetVersion();
@@ -335,19 +336,19 @@ IndexedRulesetVersion RulesetService::IndexAndWriteRuleset(
}
// static
-bool RulesetService::IndexRuleset(base::File unindexed_ruleset_file,
- RulesetIndexer* indexer) {
+bool RulesetService::IndexRuleset(
+ UnindexedRulesetStreamGenerator* unindexed_ruleset_stream_generator,
+ RulesetIndexer* indexer) {
SCOPED_UMA_HISTOGRAM_TIMER("SubresourceFilter.IndexRuleset.WallDuration");
SCOPED_UMA_HISTOGRAM_THREAD_TIMER(
"SubresourceFilter.IndexRuleset.CPUDuration");
- int64_t unindexed_ruleset_size = unindexed_ruleset_file.GetLength();
+ int64_t unindexed_ruleset_size =
+ unindexed_ruleset_stream_generator->ruleset_size();
if (unindexed_ruleset_size < 0)
return false;
- CopyingFileInputStream copying_stream(std::move(unindexed_ruleset_file));
- google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
- &copying_stream, 4096 /* buffer_size */);
- UnindexedRulesetReader reader(&zero_copy_stream_adaptor);
+ UnindexedRulesetReader reader(
+ unindexed_ruleset_stream_generator->ruleset_stream());
size_t num_unsupported_rules = 0;
url_pattern_index::proto::FilteringRules ruleset_chunk;
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_service.h b/chromium/components/subresource_filter/content/browser/ruleset_service.h
index 4cc9eab6ad6..2e9e6dcdd1d 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_service.h
+++ b/chromium/components/subresource_filter/content/browser/ruleset_service.h
@@ -59,6 +59,7 @@ class SequencedTaskRunner;
namespace subresource_filter {
class RulesetIndexer;
+class UnindexedRulesetStreamGenerator;
// Contains all utility functions that govern how files pertaining to indexed
// ruleset version should be organized on disk.
@@ -214,10 +215,11 @@ class RulesetService : public base::SupportsWeakPtr<RulesetService> {
const base::FilePath& indexed_ruleset_base_dir,
const UnindexedRulesetInfo& unindexed_ruleset_info);
- // Reads the rules from the |unindexed_ruleset_file|, and indexes them using
- // |indexer|. Returns whether the entire ruleset could be parsed.
- static bool IndexRuleset(base::File unindexed_ruleset_file,
- RulesetIndexer* indexer);
+ // Reads the rules via the |unindexed_ruleset_stream_generator|, and indexes
+ // them using |indexer|. Returns whether the entire ruleset could be parsed.
+ static bool IndexRuleset(
+ UnindexedRulesetStreamGenerator* unindexed_ruleset_stream_generator,
+ RulesetIndexer* indexer);
// Writes all files comprising the given |indexed_version| of the ruleset
// into the corresponding subdirectory in |indexed_ruleset_base_dir|.
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_service_unittest.cc b/chromium/components/subresource_filter/content/browser/ruleset_service_unittest.cc
index 1bd335c408e..b8272e88a99 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_service_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/ruleset_service_unittest.cc
@@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/environment.h"
+#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
@@ -30,10 +31,13 @@
#include "build/build_config.h"
#include "components/prefs/testing_pref_service.h"
#include "components/subresource_filter/content/browser/ruleset_publisher.h"
+#include "components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/url_pattern_index/proto/rules.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/mock_resource_bundle_delegate.h"
+#include "ui/base/resource/resource_bundle.h"
namespace subresource_filter {
@@ -150,12 +154,14 @@ bool MockFailingReplaceFile(const base::FilePath&,
}
#if GTEST_HAS_DEATH_TEST
-bool MockCrashingIndexRuleset(base::File, RulesetIndexer*) {
+bool MockCrashingIndexRuleset(UnindexedRulesetStreamGenerator*,
+ RulesetIndexer*) {
LOG(FATAL) << "Synthetic crash.";
return false;
}
#else
-bool MockFailingIndexRuleset(base::File, RulesetIndexer*) {
+bool MockFailingIndexRuleset(UnindexedRulesetStreamGenerator*,
+ RulesetIndexer*) {
return false;
}
#endif
@@ -164,8 +170,10 @@ bool MockFailingIndexRuleset(base::File, RulesetIndexer*) {
// Test fixtures --------------------------------------------------------------
-using testing::TestRulesetPair;
+using ::testing::_;
+using ::testing::Return;
using testing::TestRulesetCreator;
+using testing::TestRulesetPair;
class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
public:
@@ -248,6 +256,50 @@ class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
RunBlockingUntilIdle();
}
+ void WaitForIndexAndStoreAndPublishUpdatedRulesetFromResourceBundle(
+ const TestRulesetPair& test_ruleset_pair,
+ const std::string& new_content_version) {
+ int unindexed_ruleset_resource_id = 42;
+ auto unindexed_ruleset_contents = test_ruleset_pair.unindexed.contents;
+ std::string unindexed_ruleset(
+ reinterpret_cast<const char*>(unindexed_ruleset_contents.data()),
+ unindexed_ruleset_contents.size());
+
+ UnindexedRulesetInfo ruleset_info;
+ ruleset_info.resource_id = unindexed_ruleset_resource_id;
+ ruleset_info.content_version = new_content_version;
+
+ // Configure the resource bundle to return |unindexed_ruleset| as the
+ // contents for |unindexed_ruleset_resource_id|.
+ ui::MockResourceBundleDelegate resource_bundle_delegate;
+ EXPECT_CALL(resource_bundle_delegate,
+ LoadDataResourceString(unindexed_ruleset_resource_id))
+ .Times(1)
+ .WillOnce(Return(unindexed_ruleset));
+
+ // Suppress "uninteresting mock function call" warning output that would
+ // occur as part of resource bundle initialization.
+ EXPECT_CALL(resource_bundle_delegate, GetPathForLocalePack(_, _))
+ .WillRepeatedly(Return(base::FilePath()));
+
+ ui::ResourceBundle* orig_resource_bundle =
+ ui::ResourceBundle::SwapSharedInstanceForTesting(nullptr);
+ ui::ResourceBundle::InitSharedInstanceWithLocale(
+ "en-US", &resource_bundle_delegate,
+ ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
+
+ // Now that everything has been set up, do the actual indexing.
+ service()->IndexAndStoreAndPublishRulesetIfNeeded(ruleset_info);
+
+ // Wait for indexing on background task runner.
+ RunBackgroundUntilIdle();
+ // Wait for file to be opened on blocking task runner.
+ RunBlockingUntilIdle();
+
+ ui::ResourceBundle::CleanupSharedInstance();
+ ui::ResourceBundle::SwapSharedInstanceForTesting(orig_resource_bundle);
+ }
+
// Mark the initialization complete and run task queues until all are empty.
void SimulateStartupCompletedAndWaitForTasks() {
DCHECK(mock_publisher());
@@ -620,6 +672,19 @@ TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_Published) {
}
TEST_F(SubresourceFilteringRulesetServiceTest,
+ RulesetFromResourceId_Published) {
+ SimulateStartupCompletedAndWaitForTasks();
+
+ WaitForIndexAndStoreAndPublishUpdatedRulesetFromResourceBundle(
+ test_ruleset_1(), kTestContentVersion1);
+
+ ASSERT_EQ(1u, mock_publisher()->published_rulesets().size());
+ ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+ &mock_publisher()->published_rulesets()[0],
+ test_ruleset_1().indexed.contents));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
NewRulesetWithEmptyVersion_NotPublished) {
SimulateStartupCompletedAndWaitForTasks();
WaitForIndexAndStoreAndPublishUpdatedRuleset(test_ruleset_1(), std::string());
@@ -765,7 +830,8 @@ TEST_F(SubresourceFilteringRulesetServiceTest,
mock_publisher()->RunBestEffortUntilIdle();
UnindexedRulesetInfo ruleset_info;
- ruleset_info.ruleset_path = base::FilePath(); // Non-existent.
+ ruleset_info.ruleset_path =
+ base::FilePath(FILE_PATH_LITERAL("non/existent/path")); // Non-existent.
ruleset_info.content_version = kTestContentVersion1;
service()->IndexAndStoreAndPublishRulesetIfNeeded(ruleset_info);
RunBackgroundUntilIdle();
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_version.cc b/chromium/components/subresource_filter/content/browser/ruleset_version.cc
index 91436742239..3a17850d3cb 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_version.cc
+++ b/chromium/components/subresource_filter/content/browser/ruleset_version.cc
@@ -26,6 +26,10 @@ const char kSubresourceFilterRulesetChecksum[] =
UnindexedRulesetInfo::UnindexedRulesetInfo() = default;
UnindexedRulesetInfo::~UnindexedRulesetInfo() = default;
+UnindexedRulesetInfo::UnindexedRulesetInfo(const UnindexedRulesetInfo&) =
+ default;
+UnindexedRulesetInfo& UnindexedRulesetInfo::operator=(
+ const UnindexedRulesetInfo&) = default;
IndexedRulesetVersion::IndexedRulesetVersion() = default;
IndexedRulesetVersion::IndexedRulesetVersion(const std::string& content_version,
diff --git a/chromium/components/subresource_filter/content/browser/ruleset_version.h b/chromium/components/subresource_filter/content/browser/ruleset_version.h
index 1c7d59ae5db..1da5d49776c 100644
--- a/chromium/components/subresource_filter/content/browser/ruleset_version.h
+++ b/chromium/components/subresource_filter/content/browser/ruleset_version.h
@@ -26,6 +26,8 @@ namespace subresource_filter {
struct UnindexedRulesetInfo {
UnindexedRulesetInfo();
~UnindexedRulesetInfo();
+ UnindexedRulesetInfo(const UnindexedRulesetInfo&);
+ UnindexedRulesetInfo& operator=(const UnindexedRulesetInfo&);
// The version of the ruleset contents. Because the wire format of unindexed
// rules is expected to be stable over time (at least backwards compatible),
@@ -35,9 +37,17 @@ struct UnindexedRulesetInfo {
// There is no ordering defined on versions.
std::string content_version;
- // The path to the file containing the unindexed subresource filtering rules.
+ // The (optional) path to the file containing the unindexed subresource
+ // filtering rules. One (but not both) of |ruleset_path| and |resource_id|
+ // should be set.
base::FilePath ruleset_path;
+ // The (optional) grit resource id containing the unindexed subresource
+ // filtering rules, which if supplied is given to the ResourceBundle to
+ // resolve to a string. One (but not both) of |ruleset_path| and |resource_id|
+ // should be set.
+ int resource_id = 0;
+
// The (optional) path to a file containing the applicable license, which will
// be copied next to the indexed ruleset. For convenience, the lack of license
// can be indicated not only by setting |license_path| to empty, but also by
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
index 1065a37b3f8..686aa9d6af4 100644
--- a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
@@ -8,8 +8,8 @@
#include <sstream>
#include <string>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_client.h b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
index 0614894273f..949c0363b27 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
@@ -53,6 +53,10 @@ class SubresourceFilterClient {
// client, or null if there is no such instance.
virtual const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
GetSafeBrowsingDatabaseManager() = 0;
+
+ // Invoked when the user has requested a reload of a page with blocked ads
+ // (e.g., via an infobar).
+ virtual void OnReloadRequested() = 0;
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc
new file mode 100644
index 00000000000..2ed324f0835
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc
@@ -0,0 +1,235 @@
+// 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.
+
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/time/default_clock.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Key into the website setting dict for the smart UI.
+const char kInfobarLastShownTimeKey[] = "InfobarLastShownTime";
+const char kActivatedKey[] = "Activated";
+const char kNonRenewingExpiryTime[] = "NonRenewingExpiryTime";
+
+bool ShouldUseSmartUI() {
+#if defined(OS_ANDROID)
+ return true;
+#endif
+ return false;
+}
+
+} // namespace
+
+constexpr base::TimeDelta
+ SubresourceFilterContentSettingsManager::kDelayBeforeShowingInfobarAgain;
+
+constexpr base::TimeDelta
+ SubresourceFilterContentSettingsManager::kMaxPersistMetadataDuration;
+
+SubresourceFilterContentSettingsManager::
+ SubresourceFilterContentSettingsManager(
+ HostContentSettingsMap* settings_map)
+ : settings_map_(settings_map),
+ clock_(std::make_unique<base::DefaultClock>(base::DefaultClock())),
+ should_use_smart_ui_(ShouldUseSmartUI()) {
+ DCHECK(settings_map_);
+}
+
+SubresourceFilterContentSettingsManager::
+ ~SubresourceFilterContentSettingsManager() = default;
+
+ContentSetting SubresourceFilterContentSettingsManager::GetSitePermission(
+ const GURL& url) const {
+ return settings_map_->GetContentSetting(url, GURL(),
+ ContentSettingsType::ADS);
+}
+
+void SubresourceFilterContentSettingsManager::AllowlistSite(const GURL& url) {
+ settings_map_->SetContentSettingDefaultScope(
+ url, GURL(), ContentSettingsType::ADS, CONTENT_SETTING_ALLOW);
+}
+
+void SubresourceFilterContentSettingsManager::OnDidShowUI(const GURL& url) {
+ std::unique_ptr<base::DictionaryValue> dict = GetSiteMetadata(url);
+ if (!dict)
+ dict = CreateMetadataDictWithActivation(true /* is_activated */);
+
+ double now = clock_->Now().ToDoubleT();
+ dict->SetDouble(kInfobarLastShownTimeKey, now);
+ SetSiteMetadata(url, std::move(dict));
+}
+
+bool SubresourceFilterContentSettingsManager::ShouldShowUIForSite(
+ const GURL& url) const {
+ if (!should_use_smart_ui())
+ return true;
+
+ std::unique_ptr<base::DictionaryValue> dict = GetSiteMetadata(url);
+ if (!dict)
+ return true;
+
+ double last_shown_time_double = 0;
+ if (dict->GetDouble(kInfobarLastShownTimeKey, &last_shown_time_double)) {
+ base::Time last_shown = base::Time::FromDoubleT(last_shown_time_double);
+ if (clock_->Now() - last_shown < kDelayBeforeShowingInfobarAgain)
+ return false;
+ }
+ return true;
+}
+
+void SubresourceFilterContentSettingsManager::SetSiteMetadataBasedOnActivation(
+ const GURL& url,
+ bool is_activated,
+ ActivationSource activation_source,
+ std::unique_ptr<base::DictionaryValue> additional_data) {
+ std::unique_ptr<base::DictionaryValue> dict = GetSiteMetadata(url);
+
+ if (!is_activated &&
+ ShouldDeleteDataWithNoActivation(dict.get(), activation_source)) {
+ // If we are clearing metadata, there should be no additional_data dict.
+ DCHECK(!additional_data);
+ SetSiteMetadata(url, nullptr);
+ return;
+ }
+
+ // Do not create new metadata if it exists already, it could clobber
+ // existing data.
+ if (!dict)
+ dict = CreateMetadataDictWithActivation(is_activated /* is_activated */);
+ else
+ dict->SetBoolKey(kActivatedKey, is_activated);
+
+ if (additional_data)
+ dict->MergeDictionary(additional_data.get());
+
+ // Ads intervention metadata should not be deleted by changes in activation
+ // during the metrics collection period (kMaxPersistMetadataDuration).
+ // Setting the key kNonRenewingExpiryTime enforces this behavior in
+ // SetSiteMetadata.
+ if (activation_source == ActivationSource::kAdsIntervention) {
+ // If we have an expiry time set, then we are already tracking
+ // an ads intervention. Since we should not be able to trigger a new ads
+ // intervention once we should be blocking ads, do not change the expiry
+ // time or overwrite existing ads intervention metadata,
+ if (dict->FindDoubleKey(kNonRenewingExpiryTime))
+ return;
+ double expiry_time =
+ (clock_->Now() + kMaxPersistMetadataDuration).ToDoubleT();
+ dict->SetDoubleKey(kNonRenewingExpiryTime, expiry_time);
+ }
+
+ SetSiteMetadata(url, std::move(dict));
+}
+
+std::unique_ptr<base::DictionaryValue>
+SubresourceFilterContentSettingsManager::GetSiteMetadata(
+ const GURL& url) const {
+ return base::DictionaryValue::From(settings_map_->GetWebsiteSetting(
+ url, GURL(), ContentSettingsType::ADS_DATA, nullptr));
+}
+
+void SubresourceFilterContentSettingsManager::SetSiteMetadataForTesting(
+ const GURL& url,
+ std::unique_ptr<base::DictionaryValue> dict) {
+ SetSiteMetadata(url, std::move(dict));
+}
+
+void SubresourceFilterContentSettingsManager::SetSiteMetadata(
+ const GURL& url,
+ std::unique_ptr<base::DictionaryValue> dict) {
+ if (url.is_empty())
+ return;
+
+ // Metadata expires after kMaxPersistMetadataDuration by default. If
+ // kNonRenewingExpiryTime was previously set, then we are storing ads
+ // intervention metadata and should not override the expiry time that
+ // was previously set.
+ base::Time expiry_time = base::Time::Now() + kMaxPersistMetadataDuration;
+ if (dict && dict->HasKey(kNonRenewingExpiryTime)) {
+ base::Optional<double> metadata_expiry_time =
+ dict->FindDoubleKey(kNonRenewingExpiryTime);
+ DCHECK(metadata_expiry_time);
+ expiry_time = base::Time::FromDoubleT(*metadata_expiry_time);
+ }
+
+ content_settings::ContentSettingConstraints constraints = {expiry_time};
+ settings_map_->SetWebsiteSettingDefaultScope(
+ url, GURL(), ContentSettingsType::ADS_DATA, std::move(dict), constraints);
+}
+
+std::unique_ptr<base::DictionaryValue>
+SubresourceFilterContentSettingsManager::CreateMetadataDictWithActivation(
+ bool is_activated) {
+ auto dict = std::make_unique<base::DictionaryValue>();
+ dict->SetBoolKey(kActivatedKey, is_activated);
+
+ return dict;
+}
+
+bool SubresourceFilterContentSettingsManager::ShouldDeleteDataWithNoActivation(
+ base::DictionaryValue* dict,
+ ActivationSource activation_source) {
+ // For the ads intervention dry run experiment we want to make sure that
+ // non activated pages get properly tagged for metrics collection. Don't
+ // delete them from storage until their associated intervention _would have_
+ // expired.
+ if (activation_source != ActivationSource::kSafeBrowsing)
+ return false;
+
+ if (!dict)
+ return true;
+
+ base::Optional<double> metadata_expiry_time =
+ dict->FindDoubleKey(kNonRenewingExpiryTime);
+
+ if (!metadata_expiry_time)
+ return true;
+
+ base::Time expiry_time = base::Time::FromDoubleT(*metadata_expiry_time);
+ return clock_->Now() > expiry_time;
+}
+
+bool SubresourceFilterContentSettingsManager::GetSiteActivationFromMetadata(
+ const GURL& url) {
+ std::unique_ptr<base::DictionaryValue> dict = GetSiteMetadata(url);
+
+ // If there is no dict, this is metadata V1, absence of metadata
+ // implies no activation.
+ if (!dict)
+ return false;
+
+ base::Optional<bool> site_activation_status =
+ dict->FindBoolKey(kActivatedKey);
+
+ // If there is no explicit site activation status, it is metadata V1:
+ // use the presence of metadata as indicative of the site activation.
+ // Otherwise it is metadata V2, we return the activation stored in
+ // kActivatedKey.
+ return !site_activation_status || *site_activation_status;
+}
+
+void SubresourceFilterContentSettingsManager::ClearSiteMetadata(
+ const GURL& url) {
+ SetSiteMetadata(url, nullptr);
+}
+
+void SubresourceFilterContentSettingsManager::ClearMetadataForAllSites() {
+ settings_map_->ClearSettingsForOneType(ContentSettingsType::ADS_DATA);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h
new file mode 100644
index 00000000000..eb9e9fccb48
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h
@@ -0,0 +1,159 @@
+// 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.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CONTENT_SETTINGS_MANAGER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CONTENT_SETTINGS_MANAGER_H_
+
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/common/content_settings.h"
+
+class GURL;
+class HostContentSettingsMap;
+
+namespace base {
+class DictionaryValue;
+} // namespace base
+
+namespace subresource_filter {
+
+// This class contains helpers to get/set content and website settings related
+// to subresource filtering.
+//
+// Site metadata is stored in two formats as a base::DictionaryValue:
+// - V1 (or legacy) metadata, which uses the presence of metadata to indicate
+// activation due to safe browsing and may store additional data for
+// the time since UI was shown, see OnDidShowUI. The absence of metadata
+// indicates no activation.
+// TODO(justinmiron): All V1 metadata will be updated to V2 when it is
+// processed, but we should ideally migrate it all at some point to remove
+// this case.
+//
+// - V2 metadata, which explicitly stores the activation status in a key
+// within the metadata dict. This metadata, by default, expires after 1
+// week. However, when metadata is set by an ads intervention, and we
+// and ads interventions are not blocking ads (no activation), the
+// expiration time is explicitly set to match the metadata expiry key in the
+// metadata dict. Additional data may be persisted but will be deleted
+// if there is no activation and the metadata expiry key is not set.
+//
+// Data stored in the metadata for a url:
+// - kInfobarLastShownTimeKey (V1/V2): The last time the info bar was shown for
+// the smart UI.
+// - kActivatedKey (V2): The current activation status of the url.
+// - kNonRenewingExpiryTime (V2): The time that this url's
+// metadata will expire at and be cleared from the website settings.
+// Note, if this is set, there is no code path that should be able to extend
+// the expiry time. This is a "non-renewable" expiry.
+// TODO(https://crbug.com/1113967): This ensures that even safe browsing
+// activation is not persisted for the full expiration if it comes after an
+// ads intervention. This is non-ideal and this behavior should be removed
+// when metrics collection is finished, in M88.
+//
+// TODO(crbug.com/706061): Once observing changes to content settings is robust
+// enough for metrics collection, should collect metrics here too, using a
+// content_settings::Observer. Generally speaking, we want a system where we can
+// easily log metrics if the content setting has changed meaningfully from it's
+// previous value.
+class SubresourceFilterContentSettingsManager {
+ public:
+ explicit SubresourceFilterContentSettingsManager(
+ HostContentSettingsMap* settings_map);
+ ~SubresourceFilterContentSettingsManager();
+
+ ContentSetting GetSitePermission(const GURL& url) const;
+
+ // Only called via direct user action on via the subresource filter UI. Sets
+ // the content setting to turn off the subresource filter.
+ void AllowlistSite(const GURL& url);
+
+ // Public for testing.
+ std::unique_ptr<base::DictionaryValue> GetSiteMetadata(const GURL& url) const;
+
+ // Specific logic for more intelligent UI.
+ void OnDidShowUI(const GURL& url);
+ bool ShouldShowUIForSite(const GURL& url) const;
+ bool should_use_smart_ui() const { return should_use_smart_ui_; }
+ void set_should_use_smart_ui_for_testing(bool should_use_smart_ui) {
+ should_use_smart_ui_ = should_use_smart_ui;
+ }
+
+ // Enumerates the source of setting metadata in
+ // SetSiteMetadataBasedOnActivation.
+ enum class ActivationSource {
+ // The safe browsing component has activated on the site as it
+ // is on one of the safe browsing lists.
+ kSafeBrowsing,
+
+ // An ads intervention has been triggered for the site. Whether
+ // we activate on the site depends on if ad blocking for ads
+ // intervention is currently enabled.
+ kAdsIntervention,
+ };
+
+ // Updates the site metadata based on the state of subresource filter
+ // activation. See class comment for information on metadata data model.
+ void SetSiteMetadataBasedOnActivation(
+ const GURL& url,
+ bool is_activated,
+ ActivationSource activation_source,
+ std::unique_ptr<base::DictionaryValue> additional_metadata = nullptr);
+
+ // Returns the activation status based on the |url|'s site metadata. See
+ // class comment for information on the metadata data model.
+ bool GetSiteActivationFromMetadata(const GURL& url);
+
+ // Clears metadata for |url|.
+ void ClearSiteMetadata(const GURL& url);
+
+ // Clears metadata for all sites.
+ void ClearMetadataForAllSites();
+
+ void set_clock_for_testing(std::unique_ptr<base::Clock> tick_clock) {
+ clock_ = std::move(tick_clock);
+ }
+
+ // Time before showing the UI again on a domain.
+ // TODO(csharrison): Consider setting this via a finch param.
+ static constexpr base::TimeDelta kDelayBeforeShowingInfobarAgain =
+ base::TimeDelta::FromHours(24);
+
+ // Maximum duration to persist metadata for.
+ static constexpr base::TimeDelta kMaxPersistMetadataDuration =
+ base::TimeDelta::FromDays(7);
+
+ // Overwrites existing site metadata for testing.
+ void SetSiteMetadataForTesting(const GURL& url,
+ std::unique_ptr<base::DictionaryValue> dict);
+
+ private:
+ void SetSiteMetadata(const GURL& url,
+ std::unique_ptr<base::DictionaryValue> dict);
+
+ std::unique_ptr<base::DictionaryValue> CreateMetadataDictWithActivation(
+ bool is_activated);
+
+ // Whether the site metadata stored in |dict| is being persisted with an
+ // expiry time set by an ads intervention.
+ bool ShouldDeleteDataWithNoActivation(base::DictionaryValue* dict,
+ ActivationSource activation_source);
+
+ HostContentSettingsMap* settings_map_;
+
+ // A clock is injected into this class so tests can set arbitrary timestamps
+ // in website settings.
+ std::unique_ptr<base::Clock> clock_;
+
+ bool should_use_smart_ui_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterContentSettingsManager);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_CONTENT_SETTINGS_MANAGER_H_
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc
new file mode 100644
index 00000000000..4ed285c2aa6
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc
@@ -0,0 +1,359 @@
+// 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.
+
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace subresource_filter {
+
+namespace {
+
+class SubresourceFilterContentSettingsManagerTest : public testing::Test {
+ public:
+ SubresourceFilterContentSettingsManagerTest() {}
+
+ // Creates and configures the SubresourceFilterContentSettingsManager instance
+ // used by the tests, first creating the dependencies that need to be supplied
+ // to that instance.
+ void SetUp() override {
+ HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
+ settings_map_ = new HostContentSettingsMap(
+ &prefs_, false /* is_off_the_record */, false /* store_last_modified */,
+ false /* restore_session */);
+
+ settings_manager_ =
+ std::make_unique<SubresourceFilterContentSettingsManager>(
+ settings_map_.get());
+
+ settings_manager_->set_should_use_smart_ui_for_testing(true);
+ }
+
+ void TearDown() override { settings_map_->ShutdownOnUIThread(); }
+
+ HostContentSettingsMap* GetSettingsMap() { return settings_map_.get(); }
+
+ const base::HistogramTester& histogram_tester() { return histogram_tester_; }
+
+ SubresourceFilterContentSettingsManager* settings_manager() {
+ return settings_manager_.get();
+ }
+
+ ContentSetting GetContentSettingMatchingUrlWithEmptyPath(const GURL& url) {
+ ContentSettingsForOneType host_settings;
+ GetSettingsMap()->GetSettingsForOneType(ContentSettingsType::ADS,
+ &host_settings);
+ GURL url_with_empty_path = url.GetWithEmptyPath();
+ for (const auto& it : host_settings) {
+ // Need GURL conversion to get rid of unnecessary default ports.
+ if (GURL(it.primary_pattern.ToString()) == url_with_empty_path)
+ return it.GetContentSetting();
+ }
+ return CONTENT_SETTING_DEFAULT;
+ }
+
+ content::BrowserTaskEnvironment* task_environment() {
+ return &task_environment_;
+ }
+
+ private:
+ content::BrowserTaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ base::HistogramTester histogram_tester_;
+
+ // Used by the HostContentSettingsMap instance.
+ sync_preferences::TestingPrefServiceSyncable prefs_;
+
+ // Used by the SubresourceFilterContentSettingsManager instance.
+ scoped_refptr<HostContentSettingsMap> settings_map_;
+
+ // Instance under test.
+ std::unique_ptr<SubresourceFilterContentSettingsManager> settings_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterContentSettingsManagerTest);
+};
+
+TEST_F(SubresourceFilterContentSettingsManagerTest, LogDefaultSetting) {
+ const char kDefaultContentSetting[] =
+ "ContentSettings.DefaultSubresourceFilterSetting";
+ // The histogram should be logged at profile creation.
+ histogram_tester().ExpectTotalCount(kDefaultContentSetting, 1);
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ SetSiteMetadataBasedOnActivation) {
+ GURL url("https://example.test/");
+ EXPECT_FALSE(settings_manager()->GetSiteActivationFromMetadata(url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, false /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+ EXPECT_FALSE(settings_manager()->GetSiteActivationFromMetadata(url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ NoSiteMetadata_SiteActivationFalse) {
+ GURL url("https://example.test/");
+ settings_manager()->SetSiteMetadataForTesting(url, nullptr);
+ EXPECT_FALSE(settings_manager()->GetSiteActivationFromMetadata(url));
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ MetadataExpiryFollowingActivation) {
+ GURL url("https://example.test/");
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+ auto dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+
+ // Advance the clock, metadata is cleared.
+ task_environment()->FastForwardBy(
+ SubresourceFilterContentSettingsManager::kMaxPersistMetadataDuration);
+ dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_EQ(dict, nullptr);
+
+ // Verify once metadata has expired we revert to metadata V1 and do not set
+ // activation using the metadata activation key.
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, false /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+ dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_EQ(dict, nullptr);
+}
+
+// TODO(https://crbug.com/1113967): Remove test once ability to persist metadata
+// is removed from the subresource filter content settings manager.
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ MetadataExpiryFavorsAdsIntervention) {
+ GURL url("https://example.test/");
+
+ // Sets metadata expiry at kMaxPersistMetadataDuration from Time::Now().
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::
+ kAdsIntervention);
+
+ task_environment()->FastForwardBy(
+ SubresourceFilterContentSettingsManager::kMaxPersistMetadataDuration -
+ base::TimeDelta::FromMinutes(1));
+
+ // Setting metadata in safe browsing does not overwrite the existing
+ // expiration set by the ads intervention.
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+
+ auto dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_NE(dict, nullptr);
+
+ // Advance the clock, metadata should be cleared.
+ task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(1));
+
+ dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_EQ(dict, nullptr);
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ AdsInterventionMetadata_ExpiresAfterDuration) {
+ GURL url("https://example.test/");
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::
+ kAdsIntervention);
+ auto dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+
+ // Advance the clock, metadata is cleared.
+ task_environment()->FastForwardBy(
+ SubresourceFilterContentSettingsManager::kMaxPersistMetadataDuration);
+ dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_EQ(dict, nullptr);
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ AdditionalMetadata_SetInMetadata) {
+ GURL url("https://example.test/");
+ const char kTestKey[] = "Test";
+ auto additional_metadata = std::make_unique<base::DictionaryValue>();
+ additional_metadata->SetBoolKey(kTestKey, true);
+
+ // Set activation with additional metadata.
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing,
+ std::move(additional_metadata));
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+
+ // Verify metadata was actually persisted on site activation false.
+ auto dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_TRUE(dict->HasKey(kTestKey));
+}
+
+// TODO(https://crbug.com/1113967): Remove test once ability to persist metadata
+// is removed from the subresource filter content settings manager.
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ AdditionalMetadata_PersistedWithAdsIntervention) {
+ GURL url("https://example.test/");
+ const char kTestKey[] = "Test";
+ auto additional_metadata = std::make_unique<base::DictionaryValue>();
+ additional_metadata->SetBoolKey(kTestKey, true);
+
+ // Set activation with additional metadata.
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, true /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::
+ kAdsIntervention,
+ std::move(additional_metadata));
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+
+ // Verify metadata was actually persisted if another activation source
+ // sets site activation false.
+ settings_manager()->SetSiteMetadataBasedOnActivation(
+ url, false /* is_activated */,
+ SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
+ EXPECT_FALSE(settings_manager()->GetSiteActivationFromMetadata(url));
+ auto dict = settings_manager()->GetSiteMetadata(url);
+ EXPECT_TRUE(dict->HasKey(kTestKey));
+}
+
+// Verifies that the site activation status is True when there is
+// metadata without an explicit site activation status key value
+// pair in the metadata.
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ SiteMetadataWithoutActivationStatus_SiteActivationTrue) {
+ GURL url("https://example.test/");
+ auto dict = std::make_unique<base::DictionaryValue>();
+ settings_manager()->SetSiteMetadataForTesting(url, std::move(dict));
+ EXPECT_TRUE(settings_manager()->GetSiteActivationFromMetadata(url));
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest, SmartUI) {
+ GURL url("https://example.test/");
+ GURL url2("https://example.test/path");
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url2));
+
+ EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+ GetContentSettingMatchingUrlWithEmptyPath(url));
+ settings_manager()->OnDidShowUI(url);
+
+ // Subsequent same-origin navigations should not show UI.
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(url2));
+
+ // Fast forward the clock.
+ task_environment()->FastForwardBy(
+ SubresourceFilterContentSettingsManager::kDelayBeforeShowingInfobarAgain);
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url2));
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest, NoSmartUI) {
+ settings_manager()->set_should_use_smart_ui_for_testing(false);
+
+ GURL url("https://example.test/");
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+
+ EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+ GetContentSettingMatchingUrlWithEmptyPath(url));
+ settings_manager()->OnDidShowUI(url);
+
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(url));
+}
+
+TEST_F(SubresourceFilterContentSettingsManagerTest,
+ DefaultSettingsChange_NoWebsiteMetadata) {
+ GURL url("https://example.test/");
+ EXPECT_FALSE(settings_manager()->GetSiteMetadata(url));
+
+ // Set the setting to the default, should not populate the metadata.
+ GetSettingsMap()->SetContentSettingDefaultScope(
+ url, GURL(), ContentSettingsType::ADS, CONTENT_SETTING_DEFAULT);
+
+ EXPECT_FALSE(settings_manager()->GetSiteMetadata(url));
+}
+
+// Tests that ClearSiteMetadata(origin) will result in clearing metadata for all
+// sites whose origin is |origin|, but will not clear metadata for sites with
+// different origins.
+TEST_F(SubresourceFilterContentSettingsManagerTest, ClearSiteMetadata) {
+ GURL initial_url("https://example.test/1");
+ GURL same_origin_url("https://example.test/2");
+ GURL different_origin_url("https://second_example.test/");
+
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->OnDidShowUI(initial_url);
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->OnDidShowUI(different_origin_url);
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->ClearSiteMetadata(initial_url);
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->ClearSiteMetadata(different_origin_url);
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+}
+
+// Tests that ClearMetadataForAllSites() does indeed clear metadata for all
+// sites.
+TEST_F(SubresourceFilterContentSettingsManagerTest, ClearMetadataForAllSites) {
+ GURL initial_url("https://example.test/1");
+ GURL same_origin_url("https://example.test/2");
+ GURL different_origin_url("https://second_example.test/");
+
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->OnDidShowUI(initial_url);
+ settings_manager()->OnDidShowUI(different_origin_url);
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_FALSE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+
+ settings_manager()->ClearMetadataForAllSites();
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(initial_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(same_origin_url));
+ EXPECT_TRUE(settings_manager()->ShouldShowUIForSite(different_origin_url));
+}
+
+} // namespace
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
index 4b4389bfada..b2a918d24d4 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
@@ -12,19 +12,18 @@
namespace subresource_filter {
TestSubresourceFilterObserver::TestSubresourceFilterObserver(
- content::WebContents* web_contents)
- : scoped_observer_(this) {
+ content::WebContents* web_contents) {
auto* manager =
SubresourceFilterObserverManager::FromWebContents(web_contents);
DCHECK(manager);
- scoped_observer_.Add(manager);
+ scoped_observation_.Observe(manager);
Observe(web_contents);
}
TestSubresourceFilterObserver::~TestSubresourceFilterObserver() {}
void TestSubresourceFilterObserver::OnSubresourceFilterGoingAway() {
- scoped_observer_.RemoveAll();
+ scoped_observation_.RemoveObservation();
}
void TestSubresourceFilterObserver::OnPageActivationComputed(
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
index 6aaa170a0c6..c90d745fdfa 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "components/safe_browsing/core/db/util.h"
#include "components/safe_browsing/core/db/v4_protocol_manager_util.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
@@ -74,8 +74,9 @@ class TestSubresourceFilterObserver : public SubresourceFilterObserver,
pending_activations_;
base::Optional<mojom::ActivationLevel> last_committed_activation_;
- ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver>
- scoped_observer_;
+ base::ScopedObservation<SubresourceFilterObserverManager,
+ SubresourceFilterObserver>
+ scoped_observation_{this};
DISALLOW_COPY_AND_ASSIGN(TestSubresourceFilterObserver);
};
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.cc
new file mode 100644
index 00000000000..e99e8562cf4
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "components/subresource_filter/content/browser/subresource_filter_profile_context.h"
+
+#include "components/subresource_filter/content/browser/ads_intervention_manager.h"
+#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
+
+namespace subresource_filter {
+
+SubresourceFilterProfileContext::SubresourceFilterProfileContext(
+ HostContentSettingsMap* settings_map)
+ : settings_manager_(
+ std::make_unique<SubresourceFilterContentSettingsManager>(
+ settings_map)),
+ ads_intervention_manager_(
+ std::make_unique<AdsInterventionManager>(settings_manager_.get())) {}
+
+SubresourceFilterProfileContext::~SubresourceFilterProfileContext() {}
+
+void SubresourceFilterProfileContext::SetEmbedderData(
+ std::unique_ptr<SubresourceFilterProfileContext::EmbedderData>
+ embedder_data) {
+ DCHECK(!embedder_data_);
+ embedder_data_ = std::move(embedder_data);
+}
+
+void SubresourceFilterProfileContext::Shutdown() {
+ settings_manager_.reset();
+ ads_intervention_manager_.reset();
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.h b/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.h
new file mode 100644
index 00000000000..d8ca401382e
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_profile_context.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class HostContentSettingsMap;
+
+namespace subresource_filter {
+
+class SubresourceFilterContentSettingsManager;
+class AdsInterventionManager;
+
+// This class holds BrowserContext-scoped context for subresource filtering. The
+// embedder should use KeyedServiceFactory to associate instances of this class
+// with instances of (their subclass of) BrowserContext; see //chrome's
+// subresource_filter_profile_context_factory.* for an example.
+class SubresourceFilterProfileContext : public KeyedService {
+ public:
+ // An opaque class that the embedder can use to scope an embedder-level object
+ // to SubresourceFilterProfileContext via SetEmbedderData().
+ class EmbedderData {
+ public:
+ virtual ~EmbedderData() = default;
+ };
+
+ explicit SubresourceFilterProfileContext(
+ HostContentSettingsMap* settings_map);
+ ~SubresourceFilterProfileContext() override;
+
+ SubresourceFilterContentSettingsManager* settings_manager() {
+ return settings_manager_.get();
+ }
+
+ AdsInterventionManager* ads_intervention_manager() {
+ return ads_intervention_manager_.get();
+ }
+
+ // Can be used to attach an embedder-level object to this object. Can only be
+ // invoked once. |embedder_data| will be destroyed before the other objects
+ // owned by this object, and thus it can safely depend on those other objects.
+ void SetEmbedderData(std::unique_ptr<EmbedderData> embedder_data);
+
+ private:
+ // KeyedService:
+ void Shutdown() override;
+
+ std::unique_ptr<SubresourceFilterContentSettingsManager> settings_manager_;
+
+ // Manages ads interventions that have been triggered on previous
+ // navigations.
+ std::unique_ptr<AdsInterventionManager> ads_intervention_manager_;
+
+ // NOTE: Declared after the objects above to ensure that it is destroyed
+ // before them.
+ std::unique_ptr<EmbedderData> embedder_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceFilterProfileContext);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_PROFILE_CONTEXT_H_
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index 7c2590646ed..4d1124f66fb 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -229,12 +229,8 @@ void SubresourceFilterSafeBrowsingActivationThrottle::
builder.SetDryRun(true);
}
- if (auto optional_position = GetEnforcementRedirectPosition(check_results_)) {
- RedirectPosition position = *optional_position;
- UMA_HISTOGRAM_ENUMERATION(
- "SubresourceFilter.PageLoad.Activation.RedirectPosition2.Enforcement",
- position);
- builder.SetEnforcementRedirectPosition(static_cast<int64_t>(position));
+ if (auto position = GetEnforcementRedirectPosition(check_results_)) {
+ builder.SetEnforcementRedirectPosition(static_cast<int64_t>(*position));
}
builder.Record(ukm::UkmRecorder::Get());
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index fa7538e7ad6..a53efc30b0f 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -12,7 +12,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
@@ -94,6 +94,7 @@ class MockSubresourceFilterClient : public SubresourceFilterClient {
MOCK_METHOD0(
GetSafeBrowsingDatabaseManager,
const scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>());
+ MOCK_METHOD0(OnReloadRequested, void());
void AllowlistInCurrentWebContents(const GURL& url) {
ASSERT_TRUE(url.SchemeIsHTTPOrHTTPS());
@@ -167,11 +168,13 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
base::DoNothing());
auto* contents = RenderViewHostTestHarness::web_contents();
- client_ =
+ auto subresource_filter_client =
std::make_unique<::testing::NiceMock<MockSubresourceFilterClient>>();
+ client_ = subresource_filter_client.get();
throttle_manager_ =
std::make_unique<ContentSubresourceFilterThrottleManager>(
- client_.get(), ruleset_dealer_.get(), contents);
+ std::move(subresource_filter_client), ruleset_dealer_.get(),
+ contents);
fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
NavigateAndCommit(GURL("https://test.com"));
Observe(contents);
@@ -331,7 +334,7 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
const base::HistogramTester& tester() const { return tester_; }
- MockSubresourceFilterClient* client() { return client_.get(); }
+ MockSubresourceFilterClient* client() { return client_; }
base::TestMockTimeTaskRunner* test_io_task_runner() const {
return test_io_task_runner_.get();
@@ -353,7 +356,7 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
std::unique_ptr<ContentSubresourceFilterThrottleManager> throttle_manager_;
std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
- std::unique_ptr<MockSubresourceFilterClient> client_;
+ MockSubresourceFilterClient* client_;
std::unique_ptr<TestSubresourceFilterObserver> observer_;
scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
base::HistogramTester tester_;
@@ -906,9 +909,6 @@ struct RedirectSamplesAndResults {
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
RedirectPositionLogged) {
- std::string histogram_string =
- "SubresourceFilter.PageLoad.Activation.RedirectPosition2.Enforcement";
-
// Set up the urls for enforcement.
GURL normal_url("https://example.regular");
GURL bad_url("https://example.bad");
@@ -941,7 +941,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
{{worse_url}, true, RedirectPosition::kOnly},
};
for (const auto& test_case : kTestCases) {
- const base::HistogramTester histograms;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
SimulateStartAndExpectProceed(test_case.urls[0]);
for (size_t index = 1; index < test_case.urls.size(); index++) {
SimulateRedirectAndExpectProceed(test_case.urls[index]);
@@ -955,11 +955,20 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
EXPECT_EQ(mojom::ActivationLevel::kDisabled,
*observer()->GetPageActivationForLastCommittedLoad());
}
+ using SubresourceFilter = ukm::builders::SubresourceFilter;
+ auto entries =
+ test_ukm_recorder.GetEntriesByName(SubresourceFilter::kEntryName);
+ EXPECT_EQ(1u, entries.size());
+ const auto* entry = entries[0];
if (test_case.last_enforcement_position.has_value()) {
- histograms.ExpectUniqueSample(histogram_string,
- *test_case.last_enforcement_position, 1);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, SubresourceFilter::kEnforcementRedirectPositionName,
+ static_cast<int64_t>(*test_case.last_enforcement_position));
} else {
- histograms.ExpectTotalCount(histogram_string, 0);
+ EXPECT_EQ(
+ nullptr,
+ test_ukm_recorder.GetEntryMetric(
+ entry, SubresourceFilter::kEnforcementRedirectPositionName));
}
}
}
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
index 2e8d4b623ae..14bbc1a3b61 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.cc b/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.cc
new file mode 100644
index 00000000000..9b15091bb37
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.cc
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/content/browser/test_ruleset_publisher.h"
+
+#include "base/hash/hash.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/subresource_filter/content/browser/ruleset_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+namespace testing {
+
+namespace {
+
+class RulesetDistributionListener {
+ public:
+ explicit RulesetDistributionListener(RulesetService* service)
+ : service_(service) {
+ service_->SetRulesetPublishedCallbackForTesting(run_loop_.QuitClosure());
+ }
+
+ ~RulesetDistributionListener() {
+ service_->SetRulesetPublishedCallbackForTesting(base::OnceClosure());
+ }
+
+ void AwaitDistribution() { run_loop_.Run(); }
+
+ private:
+ RulesetService* service_;
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(RulesetDistributionListener);
+};
+
+} // namespace
+
+TestRulesetPublisher::TestRulesetPublisher(RulesetService* ruleset_service)
+ : ruleset_service_(ruleset_service) {}
+
+TestRulesetPublisher::~TestRulesetPublisher() = default;
+
+void TestRulesetPublisher::SetRuleset(const TestRuleset& unindexed_ruleset) {
+ const std::string& test_ruleset_content_version(base::NumberToString(
+ base::Hash(std::string(unindexed_ruleset.contents.begin(),
+ unindexed_ruleset.contents.end()))));
+ subresource_filter::UnindexedRulesetInfo unindexed_ruleset_info;
+ unindexed_ruleset_info.content_version = test_ruleset_content_version;
+ unindexed_ruleset_info.ruleset_path = unindexed_ruleset.path;
+ RulesetDistributionListener listener(ruleset_service_);
+ ruleset_service_->IndexAndStoreAndPublishRulesetIfNeeded(
+ unindexed_ruleset_info);
+ listener.AwaitDistribution();
+}
+
+} // namespace testing
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.h b/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.h
new file mode 100644
index 00000000000..8903756ab31
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/test_ruleset_publisher.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_TEST_RULESET_PUBLISHER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_TEST_RULESET_PUBLISHER_H_
+
+#include "base/macros.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+
+namespace subresource_filter {
+
+class RulesetService;
+
+namespace testing {
+
+// Helper class to create testing rulesets during browser tests, as well as to
+// get them indexed and published to renderers by the RulesetService.
+class TestRulesetPublisher {
+ public:
+ explicit TestRulesetPublisher(RulesetService* ruleset_service);
+ ~TestRulesetPublisher();
+
+ // Indexes the |unindexed_ruleset| and publishes it to all renderers
+ // via the RulesetService. Spins a nested run loop until done.
+ void SetRuleset(const TestRuleset& unindexed_ruleset);
+
+ private:
+ RulesetService* ruleset_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestRulesetPublisher);
+};
+
+} // namespace testing
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_TEST_RULESET_PUBLISHER_H_
diff --git a/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.cc b/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.cc
new file mode 100644
index 00000000000..53e844ceac8
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.cc
@@ -0,0 +1,67 @@
+// Copyright 2020 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/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h"
+
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/files/file_path.h"
+#include "components/subresource_filter/content/browser/ruleset_version.h"
+#include "components/subresource_filter/core/browser/copying_file_stream.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace subresource_filter {
+
+UnindexedRulesetStreamGenerator::UnindexedRulesetStreamGenerator(
+ const UnindexedRulesetInfo& ruleset_info) {
+ bool has_ruleset_file = !ruleset_info.ruleset_path.empty();
+
+ DCHECK(has_ruleset_file || ruleset_info.resource_id);
+ DCHECK(!(has_ruleset_file && ruleset_info.resource_id));
+
+ if (has_ruleset_file) {
+ GenerateStreamFromFile(ruleset_info.ruleset_path);
+ } else {
+ GenerateStreamFromResourceId(ruleset_info.resource_id);
+ }
+}
+
+UnindexedRulesetStreamGenerator::~UnindexedRulesetStreamGenerator() = default;
+
+void UnindexedRulesetStreamGenerator::GenerateStreamFromFile(
+ base::FilePath ruleset_path) {
+ DCHECK(!ruleset_stream_);
+ DCHECK(!copying_stream_);
+ DCHECK_EQ(ruleset_size_, -1);
+
+ base::File unindexed_ruleset_file(
+ ruleset_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
+ if (!unindexed_ruleset_file.IsValid()) {
+ return;
+ }
+
+ ruleset_size_ = unindexed_ruleset_file.GetLength();
+
+ copying_stream_ = std::make_unique<CopyingFileInputStream>(
+ std::move(unindexed_ruleset_file));
+ ruleset_stream_ =
+ std::make_unique<google::protobuf::io::CopyingInputStreamAdaptor>(
+ copying_stream_.get(), 4096 /* buffer_size */);
+}
+
+void UnindexedRulesetStreamGenerator::GenerateStreamFromResourceId(
+ int resource_id) {
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ std::string data_as_string = bundle.LoadDataResourceString(resource_id);
+ ruleset_size_ = data_as_string.size();
+
+ string_stream_.str(data_as_string);
+ ruleset_stream_ = std::make_unique<google::protobuf::io::IstreamInputStream>(
+ &string_stream_);
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h b/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h
new file mode 100644
index 00000000000..2969e0c8861
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/unindexed_ruleset_stream_generator.h
@@ -0,0 +1,78 @@
+// Copyright 2020 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_SUBRESOURCE_FILTER_CONTENT_BROWSER_UNINDEXED_RULESET_STREAM_GENERATOR_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_UNINDEXED_RULESET_STREAM_GENERATOR_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <sstream>
+
+namespace base {
+class FilePath;
+}
+
+namespace google {
+namespace protobuf {
+namespace io {
+class ZeroCopyInputStream;
+}
+} // namespace protobuf
+} // namespace google
+
+namespace subresource_filter {
+
+class CopyingFileInputStream;
+struct UnindexedRulesetInfo;
+
+// Processes the on-disk representation of the unindexed ruleset data into a
+// stream via which a client can read this data.
+class UnindexedRulesetStreamGenerator {
+ public:
+ explicit UnindexedRulesetStreamGenerator(
+ const UnindexedRulesetInfo& ruleset_info);
+ ~UnindexedRulesetStreamGenerator();
+
+ UnindexedRulesetStreamGenerator(const UnindexedRulesetStreamGenerator&) =
+ delete;
+ UnindexedRulesetStreamGenerator& operator=(
+ const UnindexedRulesetStreamGenerator&) = delete;
+
+ // Returns a ZeroCopyInputStream* via which the unindexed ruleset data can be
+ // streamed. If the returned pointer is null, the stream is not valid.
+ // NOTE: The returned pointer will be valid only for the lifetime of this
+ // object.
+ google::protobuf::io::ZeroCopyInputStream* ruleset_stream() {
+ return ruleset_stream_.get();
+ }
+
+ // Returns the size of the unindexed ruleset data in bytes.
+ // If the size is < 0, the stream is not valid.
+ int64_t ruleset_size() const { return ruleset_size_; }
+
+ private:
+ // Generates |ruleset_stream_| from the file at |ruleset_path_|.
+ void GenerateStreamFromFile(base::FilePath ruleset_path);
+
+ // Generates |ruleset_stream_| from the contents of the string stored in the
+ // resource bundle at |resource_id|.
+ void GenerateStreamFromResourceId(int resource_id);
+
+ int64_t ruleset_size_ = -1;
+
+ // Used when the stream is generated from a file on disk.
+ std::unique_ptr<CopyingFileInputStream> copying_stream_;
+
+ // Used when the stream is generated from a resource ID.
+ std::istringstream string_stream_;
+
+ // The stream via which a client of this class can read the data of the
+ // unindexed ruleset.
+ std::unique_ptr<google::protobuf::io::ZeroCopyInputStream> ruleset_stream_;
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_UNINDEXED_RULESET_STREAM_GENERATOR_H_
diff --git a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
index 3a33308aacd..0457a7cb7ea 100644
--- a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
+++ b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/files/file.h"
#include "base/location.h"
diff --git a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer_unittest.cc b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer_unittest.cc
index 1c2f1efd17c..df7dcd6caf3 100644
--- a/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/verified_ruleset_dealer_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/file.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc b/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc
index ae1cb5d75c9..9966138963e 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_utils.cc
@@ -8,7 +8,7 @@
namespace subresource_filter {
-bool ShouldUseParentActivation(const GURL& url) {
+bool ShouldInheritActivation(const GURL& url) {
return !content::IsURLHandledByNetworkStack(url);
}
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_utils.h b/chromium/components/subresource_filter/content/common/subresource_filter_utils.h
index 460e16a4383..93e197e41c3 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_utils.h
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_utils.h
@@ -9,10 +9,14 @@ class GURL;
namespace subresource_filter {
-// Subframe navigations matching these URLs/schemes will not trigger
-// ReadyToCommitNavigation in the browser process, so they must be treated
-// specially to maintain activation. Should only be invoked for subframes.
-bool ShouldUseParentActivation(const GURL& url);
+// Subframe navigations and initial mainframe navigations matching these URLs/
+// schemes will not trigger ReadyToCommitNavigation in the browser process, so
+// they must be treated specially to maintain activation. Each should inherit
+// the activation of its parent in the case of a subframe and its opener in the
+// case of a mainframe. This also accounts for the ability of the parent/opener
+// to affect the frame's content more directly, e.g. through document.write(),
+// even though these URLs won't match a filter list rule by themselves.
+bool ShouldInheritActivation(const GURL& url);
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 37fc27a1c23..98e6573eb55 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -46,6 +46,18 @@ SubresourceFilterAgent::SubresourceFilterAgent(
DCHECK(ruleset_dealer);
// |render_frame| can be nullptr in unit tests.
if (render_frame) {
+ // If a mainframe has an activated opener, we activate the initial empty
+ // document, which is created before this constructor. This ensures that a
+ // popup's final document is appropriately activated, even when the the
+ // initial navigation is aborted and there are no further documents created.
+ if (render_frame->IsMainFrame() &&
+ GetInheritedActivationState(render_frame).activation_level !=
+ mojom::ActivationLevel::kDisabled) {
+ const GURL& url = GetDocumentURL();
+ DCHECK(url.is_empty());
+ DCHECK(ShouldInheritActivation(url));
+ ConstructFilter(GetInheritedActivationState(render_frame), url);
+ }
render_frame->GetAssociatedInterfaceRegistry()->AddInterface(
base::BindRepeating(
&SubresourceFilterAgent::OnSubresourceFilterAgentRequest,
@@ -101,16 +113,33 @@ void SubresourceFilterAgent::SetIsAdSubframe(
render_frame()->GetWebFrame()->SetIsAdSubframe(ad_frame_type);
}
-mojom::ActivationState SubresourceFilterAgent::GetParentActivationState(
+// static
+mojom::ActivationState SubresourceFilterAgent::GetInheritedActivationState(
content::RenderFrame* render_frame) {
- blink::WebFrame* parent =
- render_frame ? render_frame->GetWebFrame()->Parent() : nullptr;
- if (parent && parent->IsWebLocalFrame()) {
- auto* agent = SubresourceFilterAgent::Get(
- content::RenderFrame::FromWebFrame(parent->ToWebLocalFrame()));
+ if (!render_frame)
+ return mojom::ActivationState();
+
+ blink::WebFrame* frame_to_inherit_from =
+ render_frame->IsMainFrame() ? render_frame->GetWebFrame()->Opener()
+ : render_frame->GetWebFrame()->Parent();
+
+ if (!frame_to_inherit_from || !frame_to_inherit_from->IsWebLocalFrame())
+ return mojom::ActivationState();
+
+ blink::WebSecurityOrigin render_frame_origin =
+ render_frame->GetWebFrame()->GetSecurityOrigin();
+ blink::WebSecurityOrigin inherited_origin =
+ frame_to_inherit_from->GetSecurityOrigin();
+
+ // Only inherit from same-origin frames.
+ if (render_frame_origin.IsSameOriginWith(inherited_origin)) {
+ auto* agent =
+ SubresourceFilterAgent::Get(content::RenderFrame::FromWebFrame(
+ frame_to_inherit_from->ToWebLocalFrame()));
if (agent && agent->filter_for_last_created_document_)
return agent->filter_for_last_created_document_->activation_state();
}
+
return mojom::ActivationState();
}
@@ -173,8 +202,7 @@ void SubresourceFilterAgent::DidCreateNewDocument() {
const bool should_record_histograms =
!first_document_ &&
!(IsMainFrame() && !url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsFile());
- if (first_document_) {
- first_document_ = false;
+ if (first_document_ && !IsMainFrame()) {
DCHECK(!filter_for_last_created_document_);
// Local subframes will first create an initial empty document (with url
@@ -191,16 +219,11 @@ void SubresourceFilterAgent::DidCreateNewDocument() {
SendFrameIsAdSubframe();
}
}
-
- // Filter may outlive us, so reset the ad tracker.
- if (filter_for_last_created_document_)
- filter_for_last_created_document_->set_ad_resource_tracker(nullptr);
- filter_for_last_created_document_.reset();
+ first_document_ = false;
const mojom::ActivationState activation_state =
- (!IsMainFrame() && ShouldUseParentActivation(url))
- ? GetParentActivationState(render_frame())
- : activation_state_for_next_document_;
+ ShouldInheritActivation(url) ? GetInheritedActivationStateForNewDocument()
+ : activation_state_for_next_document_;
ResetInfoForNextDocument();
@@ -208,6 +231,23 @@ void SubresourceFilterAgent::DidCreateNewDocument() {
RecordHistogramsOnFilterCreation(activation_state);
}
+ ConstructFilter(activation_state, url);
+}
+
+const mojom::ActivationState
+SubresourceFilterAgent::GetInheritedActivationStateForNewDocument() {
+ DCHECK(ShouldInheritActivation(GetDocumentURL()));
+ return GetInheritedActivationState(render_frame());
+}
+
+void SubresourceFilterAgent::ConstructFilter(
+ const mojom::ActivationState activation_state,
+ const GURL& url) {
+ // Filter may outlive us, so reset the ad tracker.
+ if (filter_for_last_created_document_)
+ filter_for_last_created_document_->set_ad_resource_tracker(nullptr);
+ filter_for_last_created_document_.reset();
+
if (activation_state.activation_level == mojom::ActivationLevel::kDisabled ||
!ruleset_dealer_->IsRulesetFileAvailable())
return;
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
index f10243464b2..4fb6ff3bfe4 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -88,15 +88,23 @@ class SubresourceFilterAgent
blink::mojom::AdFrameType ad_frame_type) override;
private:
- // Assumes that the parent will be in a local frame relative to this one, upon
- // construction.
- virtual mojom::ActivationState GetParentActivationState(
+ // Returns the activation state for the `render_frame` to inherit. Main frames
+ // inherit from their opener frames, and subframes inherit from their parent
+ // frames. Assumes that the parent/opener is in a local frame relative to this
+ // one, upon construction.
+ static mojom::ActivationState GetInheritedActivationState(
content::RenderFrame* render_frame);
void RecordHistogramsOnFilterCreation(
const mojom::ActivationState& activation_state);
void ResetInfoForNextDocument();
+ virtual const mojom::ActivationState
+ GetInheritedActivationStateForNewDocument();
+
+ void ConstructFilter(const mojom::ActivationState activation_state,
+ const GURL& url);
+
mojom::SubresourceFilterHost* GetSubresourceFilterHost();
void OnSubresourceFilterAgentRequest(
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index 8937149153c..344da1dbb13 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -82,10 +82,10 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
return std::move(last_injected_filter_);
}
- void SetParentActivationState(mojom::ActivationLevel level) {
+ void SetInheritedActivationStateForNewDocument(mojom::ActivationLevel level) {
mojom::ActivationState state;
state.activation_level = level;
- parent_activation_state_ = state;
+ inherited_activation_state_for_new_document_ = state;
}
void SimulateNonInitialLoad() { SetFirstDocument(false); }
@@ -93,15 +93,15 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
using SubresourceFilterAgent::ActivateForNextCommittedLoad;
private:
- mojom::ActivationState GetParentActivationState(
- content::RenderFrame*) override {
- return parent_activation_state_;
+ const mojom::ActivationState GetInheritedActivationStateForNewDocument()
+ override {
+ return inherited_activation_state_for_new_document_;
}
std::unique_ptr<blink::WebDocumentSubresourceFilter> last_injected_filter_;
bool is_ad_subframe_ = false;
bool is_main_frame_ = true;
- mojom::ActivationState parent_activation_state_;
+ mojom::ActivationState inherited_activation_state_for_new_document_;
DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentUnderTest);
};
@@ -568,9 +568,27 @@ TEST_F(SubresourceFilterAgentTest,
SetTestRulesetToDisallowURLsWithPathSuffix("somethingNotMatched"));
agent()->SetIsMainFrame(false);
- agent()->SetParentActivationState(mojom::ActivationLevel::kEnabled);
+ agent()->SetInheritedActivationStateForNewDocument(
+ mojom::ActivationLevel::kEnabled);
+
+ EXPECT_CALL(*agent(), GetDocumentURL())
+ .WillOnce(::testing::Return(GURL("about:blank")));
+ EXPECT_CALL(*agent(), OnSetSubresourceFilterForCurrentDocumentCalled());
+ StartLoadAndSetActivationState(mojom::ActivationLevel::kEnabled);
+
+ ExpectNoSubresourceFilterGetsInjected();
+ agent_as_rfo()->DidFailProvisionalLoad();
+}
+
+TEST_F(SubresourceFilterAgentTest,
+ FailedInitialMainFrameLoad_FilterInjectedOnInitialDocumentCreation) {
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix("somethingNotMatched"));
+
+ agent()->SetIsMainFrame(true);
+ agent()->SetInheritedActivationStateForNewDocument(
+ mojom::ActivationLevel::kEnabled);
- // ExpectSubresourceFilterGetsInjected();
EXPECT_CALL(*agent(), GetDocumentURL())
.WillOnce(::testing::Return(GURL("about:blank")));
EXPECT_CALL(*agent(), OnSetSubresourceFilterForCurrentDocumentCalled());
@@ -614,6 +632,7 @@ TEST_F(SubresourceFilterAgentTest, DryRun_FrameAlreadyTaggedAsAd) {
TEST_F(SubresourceFilterAgentTest, DryRun_SendsFrameIsAdSubframe) {
agent()->SetIsAdSubframe();
+ agent()->SetIsMainFrame(false);
ExpectSendFrameIsAdSubframe();
// Call DidCreateNewDocument twice and verify that SendFrameIsAdSubframe is
diff --git a/chromium/components/subresource_filter_strings.grdp b/chromium/components/subresource_filter_strings.grdp
new file mode 100644
index 00000000000..86d6ab396cb
--- /dev/null
+++ b/chromium/components/subresource_filter_strings.grdp
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <message name="IDS_ALWAYS_ALLOW_ADS" desc="Explanation associated with a toggle to allow ads after ads have been blocked on the page. To be used on pages where the ad blocking UI is governed by a persistent permissions-based allowlist.">
+ Always allow ads on this site
+ </message>
+ <message name="IDS_BLOCKED_ADS_PROMPT_TITLE" desc="Title of the prompt shown to users in the omnibox or infobar when Chrome has blocked ads on the site because the site tends to show intrusive ads. The title will stand alone next to an icon so there is no need for a period." formatter_data="android_java">
+ Ads blocked
+ </message>
+ <message name="IDS_BLOCKED_ADS_PROMPT_EXPLANATION" desc="A warning that a site has, in the past, shown intrusive or misleading ads. To be shown in an expanded infobar / bubble">
+ This site shows intrusive or misleading ads.
+ </message>
+
+ <if expr="is_android">
+ <message name="IDS_BLOCKED_ADS_INFOBAR_MESSAGE" desc="The mini infobar message shown to users on Android when Chrome has blocked ads on the site because the site tends to show intrusive ads. Will be presented as a sentence, next to a Details link to expand the infobar.">
+ Ads blocked.
+ </message>
+ </if>
+</grit-part>
diff --git a/chromium/components/suggestions/suggestions_service_impl_unittest.cc b/chromium/components/suggestions/suggestions_service_impl_unittest.cc
index 67f3e3b2e1c..60908661d81 100644
--- a/chromium/components/suggestions/suggestions_service_impl_unittest.cc
+++ b/chromium/components/suggestions/suggestions_service_impl_unittest.cc
@@ -14,7 +14,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/suggestions/blocklist_store.h"
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
index 01059c3ee52..e07af0706b0 100644
--- a/chromium/components/sync/BUILD.gn
+++ b/chromium/components/sync/BUILD.gn
@@ -30,23 +30,16 @@ group("test_support") {
# etc, but currently they all depend on each other.
static_library("rest_of_sync") {
sources = [
+ "engine/commit_and_get_updates_types.cc",
+ "engine/commit_and_get_updates_types.h",
"engine/commit_queue.h",
"engine/configure_reason.h",
- "engine/cycle/commit_counters.cc",
- "engine/cycle/commit_counters.h",
"engine/cycle/model_neutral_state.cc",
"engine/cycle/model_neutral_state.h",
- "engine/cycle/status_counters.cc",
- "engine/cycle/status_counters.h",
"engine/cycle/sync_cycle_snapshot.cc",
"engine/cycle/sync_cycle_snapshot.h",
- "engine/cycle/type_debug_info_observer.h",
- "engine/cycle/update_counters.cc",
- "engine/cycle/update_counters.h",
"engine/data_type_activation_response.cc",
"engine/data_type_activation_response.h",
- "engine/data_type_association_stats.cc",
- "engine/data_type_association_stats.h",
"engine/data_type_debug_info_listener.cc",
"engine/data_type_debug_info_listener.h",
"engine/engine_components_factory.h",
@@ -59,8 +52,6 @@ static_library("rest_of_sync") {
"engine/events/protocol_event_observer.h",
"engine/forwarding_model_type_processor.cc",
"engine/forwarding_model_type_processor.h",
- "engine/model_safe_worker.cc",
- "engine/model_safe_worker.h",
"engine/model_type_configurer.cc",
"engine/model_type_configurer.h",
"engine/model_type_connector.h",
@@ -71,17 +62,11 @@ static_library("rest_of_sync") {
"engine/net/http_bridge.h",
"engine/net/http_post_provider_factory.h",
"engine/net/http_post_provider_interface.h",
- "engine/non_blocking_sync_common.cc",
- "engine/non_blocking_sync_common.h",
- "engine/passive_model_worker.cc",
- "engine/passive_model_worker.h",
"engine/polling_constants.cc",
"engine/polling_constants.h",
"engine/shutdown_reason.cc",
"engine/shutdown_reason.h",
"engine/sync_auth_provider.h",
- "engine/sync_backend_registrar.cc",
- "engine/sync_backend_registrar.h",
"engine/sync_credentials.h",
"engine/sync_encryption_handler.h",
"engine/sync_engine.cc",
@@ -104,21 +89,23 @@ static_library("rest_of_sync") {
"engine_impl/backoff_delay_provider.h",
"engine_impl/bookmark_update_preprocessing.cc",
"engine_impl/bookmark_update_preprocessing.h",
+ "engine_impl/cancelation_signal.cc",
+ "engine_impl/cancelation_signal.h",
"engine_impl/commit.cc",
"engine_impl/commit.h",
"engine_impl/commit_contribution.h",
+ "engine_impl/commit_contribution_impl.cc",
+ "engine_impl/commit_contribution_impl.h",
"engine_impl/commit_contributor.h",
"engine_impl/commit_processor.cc",
"engine_impl/commit_processor.h",
"engine_impl/commit_util.cc",
"engine_impl/commit_util.h",
- "engine_impl/cycle/data_type_debug_info_emitter.cc",
- "engine_impl/cycle/data_type_debug_info_emitter.h",
"engine_impl/cycle/data_type_tracker.cc",
"engine_impl/cycle/data_type_tracker.h",
"engine_impl/cycle/debug_info_getter.h",
- "engine_impl/cycle/non_blocking_type_debug_info_emitter.cc",
- "engine_impl/cycle/non_blocking_type_debug_info_emitter.h",
+ "engine_impl/cycle/entity_change_metric_recording.cc",
+ "engine_impl/cycle/entity_change_metric_recording.h",
"engine_impl/cycle/nudge_tracker.cc",
"engine_impl/cycle/nudge_tracker.h",
"engine_impl/cycle/status_controller.cc",
@@ -177,10 +164,7 @@ static_library("rest_of_sync") {
"engine_impl/net/sync_server_connection_manager.h",
"engine_impl/net/url_translator.cc",
"engine_impl/net/url_translator.h",
- "engine_impl/non_blocking_type_commit_contribution.cc",
- "engine_impl/non_blocking_type_commit_contribution.h",
"engine_impl/nudge_handler.h",
- "engine_impl/nudge_source.h",
"engine_impl/sync_cycle_event.cc",
"engine_impl/sync_cycle_event.h",
"engine_impl/sync_engine_event_listener.h",
@@ -234,6 +218,7 @@ static_library("rest_of_sync") {
"model/sync_metadata_store.h",
"model/syncable_service.h",
"model/time.h",
+ "model/type_entities_count.h",
"model_impl/blocking_model_type_store_impl.cc",
"model_impl/blocking_model_type_store_impl.h",
"model_impl/client_tag_based_model_type_processor.cc",
@@ -335,10 +320,6 @@ static_library("test_support_engine") {
"engine/test_engine_components_factory.h",
"engine_impl/cycle/mock_debug_info_getter.cc",
"engine_impl/cycle/mock_debug_info_getter.h",
- "engine_impl/cycle/test_util.cc",
- "engine_impl/cycle/test_util.h",
- "test/engine/fake_model_worker.cc",
- "test/engine/fake_model_worker.h",
"test/engine/fake_sync_scheduler.cc",
"test/engine/fake_sync_scheduler.h",
"test/engine/mock_connection_manager.cc",
@@ -370,30 +351,24 @@ static_library("test_support_engine") {
static_library("test_support_model") {
testonly = true
sources = [
- "model/data_type_error_handler_mock.cc",
- "model/data_type_error_handler_mock.h",
- "model/fake_model_type_change_processor.cc",
- "model/fake_model_type_change_processor.h",
- "model/fake_model_type_controller_delegate.cc",
- "model/fake_model_type_controller_delegate.h",
- "model/fake_model_type_sync_bridge.cc",
- "model/fake_model_type_sync_bridge.h",
- "model/fake_sync_change_processor.cc",
- "model/fake_sync_change_processor.h",
- "model/mock_model_type_change_processor.cc",
- "model/mock_model_type_change_processor.h",
- "model/model_type_store_test_util.cc",
- "model/model_type_store_test_util.h",
- "model/recording_model_type_change_processor.cc",
- "model/recording_model_type_change_processor.h",
- "model/stub_model_type_sync_bridge.cc",
- "model/stub_model_type_sync_bridge.h",
- "model/sync_change_processor_wrapper_for_test.cc",
- "model/sync_change_processor_wrapper_for_test.h",
- "model/sync_error_factory_mock.cc",
- "model/sync_error_factory_mock.h",
- "model/test_model_type_store_service.cc",
- "model/test_model_type_store_service.h",
+ "test/model/fake_model_type_controller_delegate.cc",
+ "test/model/fake_model_type_controller_delegate.h",
+ "test/model/fake_model_type_sync_bridge.cc",
+ "test/model/fake_model_type_sync_bridge.h",
+ "test/model/fake_sync_change_processor.cc",
+ "test/model/fake_sync_change_processor.h",
+ "test/model/mock_model_type_change_processor.cc",
+ "test/model/mock_model_type_change_processor.h",
+ "test/model/model_type_store_test_util.cc",
+ "test/model/model_type_store_test_util.h",
+ "test/model/stub_model_type_sync_bridge.cc",
+ "test/model/stub_model_type_sync_bridge.h",
+ "test/model/sync_change_processor_wrapper_for_test.cc",
+ "test/model/sync_change_processor_wrapper_for_test.h",
+ "test/model/sync_error_factory_mock.cc",
+ "test/model/sync_error_factory_mock.h",
+ "test/model/test_model_type_store_service.cc",
+ "test/model/test_model_type_store_service.h",
]
public_deps = [ "//components/sync/base:test_support" ]
@@ -418,7 +393,6 @@ source_set("unit_tests") {
testonly = true
sources = [
"base/bind_to_task_runner_unittest.cc",
- "base/cancelation_signal_unittest.cc",
"base/client_tag_hash_unittest.cc",
"base/enum_set_unittest.cc",
"base/immutable_unittest.cc",
@@ -430,32 +404,30 @@ source_set("unit_tests") {
"base/sync_util_unittest.cc",
"base/system_encryptor_unittest.cc",
"base/unique_position_unittest.cc",
- "base/user_demographics_unittest.cc",
"base/weak_handle_unittest.cc",
- "driver/about_sync_util_unittest.cc",
"driver/backend_migrator_unittest.cc",
"driver/data_type_manager_impl_unittest.cc",
"driver/glue/sync_engine_impl_unittest.cc",
- "driver/model_association_manager_unittest.cc",
+ "driver/model_load_manager_unittest.cc",
"driver/model_type_controller_unittest.cc",
"driver/passphrase_type_metrics_provider_unittest.cc",
"driver/profile_sync_service_startup_unittest.cc",
"driver/profile_sync_service_unittest.cc",
"driver/startup_controller_unittest.cc",
"driver/sync_auth_manager_unittest.cc",
+ "driver/sync_internals_util_unittest.cc",
"driver/sync_service_crypto_unittest.cc",
"driver/sync_service_utils_unittest.cc",
"driver/sync_session_durations_metrics_recorder_unittest.cc",
"driver/sync_stopped_reporter_unittest.cc",
"driver/sync_user_settings_unittest.cc",
"engine/cycle/sync_cycle_snapshot_unittest.cc",
- "engine/model_safe_worker_unittest.cc",
"engine/net/http_bridge_unittest.cc",
- "engine/sync_backend_registrar_unittest.cc",
"engine_impl/backoff_delay_provider_unittest.cc",
"engine_impl/bookmark_update_preprocessing_unittest.cc",
+ "engine_impl/cancelation_signal_unittest.cc",
+ "engine_impl/commit_contribution_impl_unittest.cc",
"engine_impl/commit_processor_unittest.cc",
- "engine_impl/cycle/data_type_debug_info_emitter_unittest.cc",
"engine_impl/cycle/nudge_tracker_unittest.cc",
"engine_impl/cycle/status_controller_unittest.cc",
"engine_impl/debug_info_event_listener_unittest.cc",
@@ -471,7 +443,6 @@ source_set("unit_tests") {
"engine_impl/model_type_registry_unittest.cc",
"engine_impl/model_type_worker_unittest.cc",
"engine_impl/net/sync_server_connection_manager_unittest.cc",
- "engine_impl/non_blocking_type_commit_contribution_unittest.cc",
"engine_impl/sync_manager_impl_unittest.cc",
"engine_impl/sync_scheduler_impl_unittest.cc",
"engine_impl/syncer_proto_util_unittest.cc",
@@ -507,6 +478,8 @@ source_set("unit_tests") {
"trusted_vault/securebox_unittest.cc",
"trusted_vault/standalone_trusted_vault_backend_unittest.cc",
"trusted_vault/trusted_vault_access_token_fetcher_frontend_unittest.cc",
+ "trusted_vault/trusted_vault_connection_impl_unittest.cc",
+ "trusted_vault/trusted_vault_request_unittest.cc",
]
configs += [ "//build/config:precompiled_headers" ]
@@ -525,9 +498,9 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/gcm_driver:test_support",
"//components/invalidation/impl",
- "//components/metrics",
"//components/os_crypt",
"//components/os_crypt:test_support",
+ "//components/policy/core/common:test_support",
"//components/prefs:test_support",
"//components/signin/public/base:test_support",
"//components/signin/public/identity_manager:test_support",
@@ -535,8 +508,6 @@ source_set("unit_tests") {
"//components/sync/driver:test_support",
"//components/sync/invalidations:test_support",
"//components/sync/js:test_support",
- "//components/sync_preferences",
- "//components/sync_preferences:test_support",
"//components/version_info",
"//components/version_info:generate_version_info",
"//components/version_info:version_string",
diff --git a/chromium/components/sync/base/BUILD.gn b/chromium/components/sync/base/BUILD.gn
index 70a70958ae0..3d6549525b8 100644
--- a/chromium/components/sync/base/BUILD.gn
+++ b/chromium/components/sync/base/BUILD.gn
@@ -12,9 +12,6 @@ declare_args() {
static_library("base") {
sources = [
"bind_to_task_runner.h",
- "cancelation_observer.h",
- "cancelation_signal.cc",
- "cancelation_signal.h",
"client_tag_hash.cc",
"client_tag_hash.h",
"data_type_histogram.cc",
@@ -68,8 +65,6 @@ static_library("base") {
"unique_position.h",
"unrecoverable_error_info.cc",
"unrecoverable_error_info.h",
- "user_demographics.cc",
- "user_demographics.h",
"user_selectable_type.cc",
"user_selectable_type.h",
"weak_handle.cc",
diff --git a/chromium/components/sync/driver/BUILD.gn b/chromium/components/sync/driver/BUILD.gn
index 8476be77b63..584158fe8c6 100644
--- a/chromium/components/sync/driver/BUILD.gn
+++ b/chromium/components/sync/driver/BUILD.gn
@@ -7,8 +7,7 @@ import("//tools/grit/grit_rule.gni")
static_library("driver") {
sources = [
- "about_sync_util.cc",
- "about_sync_util.h",
+ "active_devices_provider.h",
"backend_migrator.cc",
"backend_migrator.h",
"configure_context.h",
@@ -26,8 +25,8 @@ static_library("driver") {
"glue/sync_engine_backend.h",
"glue/sync_engine_impl.cc",
"glue/sync_engine_impl.h",
- "model_association_manager.cc",
- "model_association_manager.h",
+ "model_load_manager.cc",
+ "model_load_manager.h",
"model_type_controller.cc",
"model_type_controller.h",
"non_ui_syncable_service_based_model_type_controller.cc",
@@ -46,6 +45,8 @@ static_library("driver") {
"sync_client.h",
"sync_driver_switches.cc",
"sync_driver_switches.h",
+ "sync_internals_util.cc",
+ "sync_internals_util.h",
"sync_service.cc",
"sync_service.h",
"sync_service_crypto.cc",
@@ -89,6 +90,8 @@ static_library("driver") {
"//components/keyed_service/core",
"//components/metrics",
"//components/os_crypt",
+ "//components/policy:generated",
+ "//components/policy/core/browser",
"//components/prefs",
"//components/signin/public/identity_manager",
"//components/sync/invalidations",
@@ -102,10 +105,6 @@ static_library("driver") {
"sync_policy_handler.cc",
"sync_policy_handler.h",
]
- deps += [
- "//components/policy:generated",
- "//components/policy/core/browser",
- ]
}
if (is_chromeos) {
@@ -123,10 +122,6 @@ grit("resources") {
"sync_driver_resources.pak",
]
output_dir = "$root_gen_dir/components"
- grit_flags = [
- "-E",
- "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
- ]
}
static_library("test_support") {
@@ -159,6 +154,7 @@ static_library("test_support") {
deps = [
"//components/invalidation/impl:test_support",
"//components/pref_registry",
+ "//components/prefs:test_support",
"//components/signin/public/base",
"//components/signin/public/identity_manager:test_support",
"//components/sync",
@@ -166,7 +162,6 @@ static_library("test_support") {
"//components/sync:test_support_model",
"//components/sync/driver",
"//components/sync/invalidations:test_support",
- "//components/sync_preferences:test_support",
"//components/version_info",
"//components/version_info:generate_version_info",
"//google_apis",
diff --git a/chromium/components/sync/driver/resources/BUILD.gn b/chromium/components/sync/driver/resources/BUILD.gn
index ce9d0b41152..26b18025bb3 100644
--- a/chromium/components/sync/driver/resources/BUILD.gn
+++ b/chromium/components/sync/driver/resources/BUILD.gn
@@ -19,9 +19,8 @@ js_type_check("closure_compile") {
#":sync_node_browser",
#":sync_search",
+ ":invalidations",
":traffic_log",
-
- #":types",
":user_events",
]
}
@@ -90,13 +89,13 @@ js_library("traffic_log") {
deps = [ "//ui/webui/resources/js:cr" ]
}
-js_library("types") {
- deps = [ "//ui/webui/resources/js:cr" ]
-}
-
js_library("user_events") {
deps = [
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js:util",
]
}
+
+js_library("invalidations") {
+ deps = [ "//ui/webui/resources/js:cr" ]
+}
diff --git a/chromium/components/sync/protocol/protocol_sources.gni b/chromium/components/sync/protocol/protocol_sources.gni
index 1db5c64365e..39de476ba9d 100644
--- a/chromium/components/sync/protocol/protocol_sources.gni
+++ b/chromium/components/sync/protocol/protocol_sources.gni
@@ -62,6 +62,7 @@ sync_protocol_bases = [
"user_consent_specifics",
"user_consent_types",
"user_event_specifics",
+ "vault",
"web_app_specifics",
"wifi_configuration_specifics",
]
diff --git a/chromium/components/sync/trusted_vault/BUILD.gn b/chromium/components/sync/trusted_vault/BUILD.gn
index d00500b6ecd..84946109957 100644
--- a/chromium/components/sync/trusted_vault/BUILD.gn
+++ b/chromium/components/sync/trusted_vault/BUILD.gn
@@ -18,6 +18,8 @@ static_library("trusted_vault") {
"trusted_vault_connection.h",
"trusted_vault_connection_impl.cc",
"trusted_vault_connection_impl.h",
+ "trusted_vault_request.cc",
+ "trusted_vault_request.h",
]
public_deps = [
"//base",
@@ -29,6 +31,7 @@ static_library("trusted_vault") {
"//components/sync/base",
"//components/sync/protocol",
"//crypto",
+ "//net",
"//services/network/public/cpp:cpp",
"//third_party/boringssl",
]
diff --git a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
index 2fd92ff645a..849ae468c9d 100644
--- a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
+++ b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
@@ -70,7 +70,7 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
data->parent_id = parent_entity->metadata()->server_id();
// TODO(crbug.com/516866): Double check that custom passphrase works well
// with this implementation, because:
- // 1. NonBlockingTypeCommitContribution::AdjustCommitProto() clears the
+ // 1. syncer::CommitContributionImpl::AdjustCommitProto() clears the
// title out.
// 2. Bookmarks (maybe ancient legacy bookmarks only?) use/used |name| to
// encode the title.
diff --git a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.h b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.h
index ee5ededa48e..93802053939 100644
--- a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.h
+++ b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.h
@@ -7,7 +7,7 @@
#include <vector>
-#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync/engine/commit_and_get_updates_types.h"
namespace bookmarks {
class BookmarkModel;
diff --git a/chromium/components/sync_bookmarks/bookmark_model_merger.cc b/chromium/components/sync_bookmarks/bookmark_model_merger.cc
index 463c2c6ae3a..f5487739968 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_merger.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_merger.cc
@@ -242,6 +242,7 @@ void DeduplicateValidUpdatesByGUID(UpdatesPerParentId* updates_per_parent_id) {
++updates_iter) {
const UpdateResponseData& update = *updates_iter;
DCHECK(!update.entity.is_deleted());
+ DCHECK(update.entity.server_defined_unique_tag.empty());
const std::string& guid_in_specifics =
update.entity.specifics.bookmark().guid();
@@ -302,51 +303,71 @@ void DeduplicateValidUpdatesByGUID(UpdatesPerParentId* updates_per_parent_id) {
}
}
-// Groups all valid updates by the server ID of their parent and moves them away
-// from |*updates|. |updates| must not be null.
-UpdatesPerParentId GroupValidUpdatesByParentId(
- UpdateResponseDataList* updates) {
+// Checks that the |update| is valid and returns false otherwise. It is used to
+// verify non-deletion updates. |update| must not be a deletion and a permanent
+// node (they are processed in a different way).
+bool IsValidUpdate(const UpdateResponseData& update) {
+ const EntityData& update_entity = update.entity;
+
+ DCHECK(!update_entity.is_deleted());
+ DCHECK(update_entity.server_defined_unique_tag.empty());
+
+ if (!syncer::UniquePosition::FromProto(update_entity.unique_position)
+ .IsValid()) {
+ // Ignore updates with invalid positions.
+ DLOG(ERROR)
+ << "Remote update with invalid position: "
+ << update_entity.specifics.bookmark().legacy_canonicalized_title();
+ LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidUniquePosition);
+ return false;
+ }
+ if (!IsValidBookmarkSpecifics(update_entity.specifics.bookmark(),
+ update_entity.is_folder)) {
+ // Ignore updates with invalid specifics.
+ DLOG(ERROR) << "Remote update with invalid specifics";
+ LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidSpecifics);
+ return false;
+ }
+ if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(),
+ update_entity.originator_cache_guid,
+ update_entity.originator_client_item_id)) {
+ // Ignore updates with an unexpected GUID.
+ DLOG(ERROR) << "Remote update with unexpected GUID";
+ LogProblematicBookmark(RemoteBookmarkUpdateError::kUnexpectedGuid);
+ return false;
+ }
+ return true;
+}
+
+struct GroupedUpdates {
+ // |updates_per_parent_id| contains all valid updates grouped by their
+ // |parent_id|. Permanent nodes and deletions are filtered out. Permanent
+ // nodes are stored in a dedicated list |permanent_node_updates|.
UpdatesPerParentId updates_per_parent_id;
+ UpdateResponseDataList permanent_node_updates;
+};
- for (UpdateResponseData& update : *updates) {
+// Groups all valid updates by the server ID of their parent. Permanent nodes
+// are grouped in a dedicated |permanent_node_updates| list in a returned value.
+GroupedUpdates GroupValidUpdates(UpdateResponseDataList updates) {
+ GroupedUpdates grouped_updates;
+ for (UpdateResponseData& update : updates) {
const EntityData& update_entity = update.entity;
if (update_entity.is_deleted()) {
continue;
}
- // No need to associate permanent nodes with their parent (the root node).
- // We start merging from the permanent nodes.
if (!update_entity.server_defined_unique_tag.empty()) {
+ grouped_updates.permanent_node_updates.push_back(std::move(update));
continue;
}
- if (!syncer::UniquePosition::FromProto(update_entity.unique_position)
- .IsValid()) {
- // Ignore updates with invalid positions.
- DLOG(ERROR)
- << "Remote update with invalid position: "
- << update_entity.specifics.bookmark().legacy_canonicalized_title();
- LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidUniquePosition);
+ if (!IsValidUpdate(update)) {
continue;
}
- if (!IsValidBookmarkSpecifics(update_entity.specifics.bookmark(),
- update_entity.is_folder)) {
- // Ignore updates with invalid specifics.
- DLOG(ERROR) << "Remote update with invalid specifics";
- LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidSpecifics);
- continue;
- }
- if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(),
- update_entity.originator_cache_guid,
- update_entity.originator_client_item_id)) {
- // Ignore updates with an unexpected GUID.
- DLOG(ERROR) << "Remote update with unexpected GUID";
- LogProblematicBookmark(RemoteBookmarkUpdateError::kUnexpectedGuid);
- continue;
- }
-
- updates_per_parent_id[update_entity.parent_id].push_back(std::move(update));
+ grouped_updates.updates_per_parent_id[update_entity.parent_id].push_back(
+ std::move(update));
}
- return updates_per_parent_id;
+ return grouped_updates;
}
} // namespace
@@ -500,31 +521,30 @@ BookmarkModelMerger::RemoteForest BookmarkModelMerger::BuildRemoteForest(
syncer::UpdateResponseDataList updates) {
// Filter out invalid remote updates and group the valid ones by the server ID
// of their parent.
- UpdatesPerParentId updates_per_parent_id =
- GroupValidUpdatesByParentId(&updates);
+ GroupedUpdates grouped_updates = GroupValidUpdates(std::move(updates));
- DeduplicateValidUpdatesByGUID(&updates_per_parent_id);
+ DeduplicateValidUpdatesByGUID(&grouped_updates.updates_per_parent_id);
// Construct one tree per permanent entity.
RemoteForest update_forest;
- for (UpdateResponseData& update : updates) {
- if (update.entity.server_defined_unique_tag.empty()) {
- continue;
- }
-
+ for (UpdateResponseData& permanent_node_update :
+ grouped_updates.permanent_node_updates) {
// Make a copy of the string to avoid relying on argument evaluation order.
const std::string server_defined_unique_tag =
- update.entity.server_defined_unique_tag;
+ permanent_node_update.entity.server_defined_unique_tag;
+ DCHECK(!server_defined_unique_tag.empty());
update_forest.emplace(
server_defined_unique_tag,
- RemoteTreeNode::BuildTree(std::move(update), kMaxBookmarkTreeDepth,
- &updates_per_parent_id));
+ RemoteTreeNode::BuildTree(std::move(permanent_node_update),
+ kMaxBookmarkTreeDepth,
+ &grouped_updates.updates_per_parent_id));
}
// All remaining entries in |updates_per_parent_id| must be unreachable from
// permanent entities, since otherwise they would have been moved away.
- for (const auto& parent_id_and_updates : updates_per_parent_id) {
+ for (const auto& parent_id_and_updates :
+ grouped_updates.updates_per_parent_id) {
for (const UpdateResponseData& update : parent_id_and_updates.second) {
if (!update.entity.is_deleted() &&
update.entity.specifics.has_bookmark()) {
diff --git a/chromium/components/sync_bookmarks/bookmark_model_merger.h b/chromium/components/sync_bookmarks/bookmark_model_merger.h
index acb1e539d71..ac289daeecc 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_merger.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_merger.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "components/sync/base/unique_position.h"
-#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync/engine/commit_and_get_updates_types.h"
namespace bookmarks {
class BookmarkModel;
diff --git a/chromium/components/sync_bookmarks/bookmark_model_observer_impl.cc b/chromium/components/sync_bookmarks/bookmark_model_observer_impl.cc
index 2d1011c0d27..dc644fdb12c 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_observer_impl.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_observer_impl.cc
@@ -13,7 +13,7 @@
#include "components/sync/base/hash_util.h"
#include "components/sync/base/unique_position.h"
#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync/engine/commit_and_get_updates_types.h"
#include "components/sync_bookmarks/bookmark_specifics_conversions.h"
#include "components/sync_bookmarks/switches.h"
diff --git a/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
index 616c1d157b3..75166e5f149 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -11,7 +11,7 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
index 777be7d1bc3..c4da6382ddf 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -22,9 +22,9 @@
#include "components/sync/base/model_type.h"
#include "components/sync/base/time.h"
#include "components/sync/engine/commit_queue.h"
-#include "components/sync/engine/cycle/status_counters.h"
#include "components/sync/engine/model_type_processor_proxy.h"
#include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
#include "components/sync/protocol/bookmark_model_metadata.pb.h"
#include "components/sync/protocol/proto_value_conversions.h"
#include "components/sync_bookmarks/bookmark_local_changes_builder.h"
@@ -39,47 +39,6 @@ namespace sync_bookmarks {
namespace {
-// Metrics: "Sync.MissingBookmarkPermanentNodes"
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class MissingPermanentNodes {
- kBookmarkBar = 0,
- kOtherBookmarks = 1,
- kMobileBookmarks = 2,
- kBookmarkBarAndOtherBookmarks = 3,
- kBookmarkBarAndMobileBookmarks = 4,
- kOtherBookmarksAndMobileBookmarks = 5,
- kBookmarkBarAndOtherBookmarksAndMobileBookmarks = 6,
-
- kMaxValue = kBookmarkBarAndOtherBookmarksAndMobileBookmarks,
-};
-
-void LogMissingPermanentNodes(
- const SyncedBookmarkTracker::Entity* bookmark_bar,
- const SyncedBookmarkTracker::Entity* other_bookmarks,
- const SyncedBookmarkTracker::Entity* mobile_bookmarks) {
- MissingPermanentNodes missing_nodes;
- if (!bookmark_bar && other_bookmarks && mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kBookmarkBar;
- } else if (bookmark_bar && !other_bookmarks && mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kOtherBookmarks;
- } else if (bookmark_bar && other_bookmarks && !mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kMobileBookmarks;
- } else if (!bookmark_bar && !other_bookmarks && mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kBookmarkBarAndOtherBookmarks;
- } else if (!bookmark_bar && other_bookmarks && !mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kBookmarkBarAndMobileBookmarks;
- } else if (bookmark_bar && !other_bookmarks && !mobile_bookmarks) {
- missing_nodes = MissingPermanentNodes::kOtherBookmarksAndMobileBookmarks;
- } else {
- // All must be missing.
- missing_nodes =
- MissingPermanentNodes::kBookmarkBarAndOtherBookmarksAndMobileBookmarks;
- }
- UMA_HISTOGRAM_ENUMERATION("Sync.MissingBookmarkPermanentNodes",
- missing_nodes);
-}
-
class ScopedRemoteUpdateBookmarks {
public:
// |bookmark_model|, |bookmark_undo_service| and |observer| must not be null
@@ -476,12 +435,6 @@ void BookmarkModelTypeProcessor::OnInitialUpdateReceived(
bookmark_model_->other_node()) ||
!bookmark_tracker_->GetEntityForBookmarkNode(
bookmark_model_->mobile_node())) {
- LogMissingPermanentNodes(bookmark_tracker_->GetEntityForBookmarkNode(
- bookmark_model_->bookmark_bar_node()),
- bookmark_tracker_->GetEntityForBookmarkNode(
- bookmark_model_->other_node()),
- bookmark_tracker_->GetEntityForBookmarkNode(
- bookmark_model_->mobile_node()));
StopTrackingMetadata();
bookmark_tracker_.reset();
error_handler_.Run(
@@ -613,18 +566,16 @@ void BookmarkModelTypeProcessor::AppendNodeAndChildrenForDebugging(
AppendNodeAndChildrenForDebugging(child.get(), i++, all_nodes);
}
-void BookmarkModelTypeProcessor::GetStatusCountersForDebugging(
- StatusCountersCallback callback) {
+void BookmarkModelTypeProcessor::GetTypeEntitiesCountForDebugging(
+ base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- syncer::StatusCounters counters;
+ syncer::TypeEntitiesCount count(syncer::BOOKMARKS);
if (bookmark_tracker_) {
- counters.num_entries =
- bookmark_tracker_->TrackedBookmarksCountForDebugging();
- counters.num_entries_and_tombstones =
- counters.num_entries +
- bookmark_tracker_->TrackedUncommittedTombstonesCountForDebugging();
+ count.non_tombstone_entities = bookmark_tracker_->TrackedBookmarksCount();
+ count.entities = count.non_tombstone_entities +
+ bookmark_tracker_->TrackedUncommittedTombstonesCount();
}
- std::move(callback).Run(syncer::BOOKMARKS, counters);
+ std::move(callback).Run(count);
}
void BookmarkModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
@@ -632,8 +583,7 @@ void BookmarkModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
SyncRecordModelTypeMemoryHistogram(syncer::BOOKMARKS, EstimateMemoryUsage());
if (bookmark_tracker_) {
SyncRecordModelTypeCountHistogram(
- syncer::BOOKMARKS,
- bookmark_tracker_->TrackedBookmarksCountForDebugging());
+ syncer::BOOKMARKS, bookmark_tracker_->TrackedBookmarksCount());
} else {
SyncRecordModelTypeCountHistogram(syncer::BOOKMARKS, 0);
}
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.h b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
index 867448564b0..f6753c7e2d4 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -57,7 +57,9 @@ class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor,
StartCallback start_callback) override;
void OnSyncStopping(syncer::SyncStopMetadataFate metadata_fate) override;
void GetAllNodesForDebugging(AllNodesCallback callback) override;
- void GetStatusCountersForDebugging(StatusCountersCallback callback) override;
+ void GetTypeEntitiesCountForDebugging(
+ base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback)
+ const override;
void RecordMemoryUsageAndCountsHistograms() override;
// Encodes all sync metadata into a string, representing a state that can be
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index ff551d5fcb8..32ef7bc4704 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -8,10 +8,10 @@
#include <string>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/guid.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
@@ -21,6 +21,7 @@
#include "components/sync/base/unique_position.h"
#include "components/sync/engine/commit_queue.h"
#include "components/sync/model/data_type_activation_request.h"
+#include "components/sync/model/type_entities_count.h"
#include "components/sync_bookmarks/switches.h"
#include "components/undo/bookmark_undo_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -98,9 +99,23 @@ sync_pb::ModelTypeState CreateDummyModelTypeState() {
return model_type_state;
}
+// |node| must not be nullptr.
+sync_pb::BookmarkMetadata CreateNodeMetadata(
+ const bookmarks::BookmarkNode* node,
+ const std::string& server_id) {
+ sync_pb::BookmarkMetadata bookmark_metadata;
+ bookmark_metadata.set_id(node->id());
+ bookmark_metadata.mutable_metadata()->set_server_id(server_id);
+ bookmark_metadata.mutable_metadata()->set_client_tag_hash(
+ syncer::ClientTagHash::FromUnhashed(syncer::BOOKMARKS, node->guid())
+ .value());
+ return bookmark_metadata;
+}
+
void AssertState(const BookmarkModelTypeProcessor* processor,
const std::vector<BookmarkInfo>& bookmarks) {
const SyncedBookmarkTracker* tracker = processor->GetTrackerForTest();
+ ASSERT_THAT(tracker, NotNull());
// Make sure the tracker contains all bookmarks in |bookmarks| + the
// 3 permanent nodes.
@@ -153,7 +168,7 @@ void InitWithSyncedBookmarks(const std::vector<BookmarkInfo>& bookmarks,
class MockCommitQueue : public syncer::CommitQueue {
public:
- MOCK_METHOD0(NudgeForCommit, void());
+ MOCK_METHOD(void, NudgeForCommit, (), (override));
};
class ProxyCommitQueue : public syncer::CommitQueue {
@@ -437,9 +452,8 @@ TEST_F(BookmarkModelTypeProcessorTest, ShouldDecodeSyncMetadata) {
bookmark_metadata->mutable_metadata()->set_server_id(kMobileBookmarksId);
// Add an entry for the bookmark node.
- bookmark_metadata = model_metadata.add_bookmarks_metadata();
- bookmark_metadata->set_id(bookmarknode->id());
- bookmark_metadata->mutable_metadata()->set_server_id(kNodeId);
+ *model_metadata.add_bookmarks_metadata() =
+ CreateNodeMetadata(bookmarknode, kNodeId);
// Create a new processor and init it with the metadata str.
BookmarkModelTypeProcessor new_processor(bookmark_undo_service());
@@ -629,16 +643,15 @@ TEST_F(BookmarkModelTypeProcessorTest,
ShouldReportNoCountersWhenModelIsNotLoaded) {
SimulateOnSyncStarting();
ASSERT_THAT(processor()->GetTrackerForTest(), IsNull());
- syncer::StatusCounters status_counters;
- // Assign an arbitrary non-zero number to the |num_entries| to be able to
- // check that actually a 0 has been written to it later.
- status_counters.num_entries = 1000;
- processor()->GetStatusCountersForDebugging(
- base::BindLambdaForTesting([&](syncer::ModelType model_type,
- const syncer::StatusCounters& counters) {
- status_counters = counters;
+ syncer::TypeEntitiesCount count(syncer::BOOKMARKS);
+ // Assign an arbitrary non-zero number of entities to be able to check that
+ // actually a 0 has been written to it later.
+ count.non_tombstone_entities = 1000;
+ processor()->GetTypeEntitiesCountForDebugging(base::BindLambdaForTesting(
+ [&](const syncer::TypeEntitiesCount& returned_count) {
+ count = returned_count;
}));
- EXPECT_EQ(0u, status_counters.num_entries);
+ EXPECT_EQ(0, count.non_tombstone_entities);
}
TEST_F(BookmarkModelTypeProcessorTest,
@@ -677,8 +690,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
// Add an entry for the bookmark node.
bookmark_metadata = model_metadata.add_bookmarks_metadata();
- bookmark_metadata->set_id(node->id());
- bookmark_metadata->mutable_metadata()->set_server_id(kNodeId);
+ *bookmark_metadata = CreateNodeMetadata(node, kNodeId);
// Mark the entity as unsynced.
bookmark_metadata->mutable_metadata()->set_sequence_number(2);
bookmark_metadata->mutable_metadata()->set_acked_sequence_number(1);
@@ -700,7 +712,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
ASSERT_EQ(0u, bookmark_client()->GetTasksCount());
EXPECT_CALL(callback, Run(_));
- processor()->GetLocalChanges(/*max_entities=*/10, callback.Get());
+ processor()->GetLocalChanges(/*max_entries=*/10, callback.Get());
EXPECT_TRUE(callback_result.empty());
EXPECT_TRUE(node->is_favicon_loading());
@@ -708,7 +720,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
GURL(kIconUrl));
ASSERT_TRUE(node->is_favicon_loaded());
EXPECT_CALL(callback, Run(_));
- processor()->GetLocalChanges(/*max_entities=*/10, callback.Get());
+ processor()->GetLocalChanges(/*max_entries=*/10, callback.Get());
EXPECT_FALSE(callback_result.empty());
}
diff --git a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
index 8b501ff27a7..e62e82832ce 100644
--- a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
+++ b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -9,7 +9,7 @@
#include <string>
#include <vector>
-#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync/engine/commit_and_get_updates_types.h"
#include "components/sync_bookmarks/synced_bookmark_tracker.h"
namespace bookmarks {
diff --git a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index 3da13ba40c3..0a43becd29e 100644
--- a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -16,6 +16,7 @@
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/test/test_bookmark_client.h"
#include "components/favicon/core/test/mock_favicon_service.h"
+#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/hash_util.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/unique_position.h"
@@ -66,20 +67,25 @@ enum class ExpectedRemoteBookmarkUpdateError {
kMaxValue = kParentNotFolder,
};
-sync_pb::BookmarkMetadata CreateNodeMetadata(int64_t node_id,
- const std::string& server_id) {
+// |node| must not be nullptr.
+sync_pb::BookmarkMetadata CreateNodeMetadata(
+ const bookmarks::BookmarkNode* node,
+ const std::string& server_id) {
sync_pb::BookmarkMetadata bookmark_metadata;
- bookmark_metadata.set_id(node_id);
+ bookmark_metadata.set_id(node->id());
bookmark_metadata.mutable_metadata()->set_server_id(server_id);
+ bookmark_metadata.mutable_metadata()->set_client_tag_hash(
+ syncer::ClientTagHash::FromUnhashed(syncer::BOOKMARKS, node->guid())
+ .value());
return bookmark_metadata;
}
sync_pb::BookmarkMetadata CreateNodeMetadata(
- int64_t node_id,
+ const bookmarks::BookmarkNode* node,
const std::string& server_id,
const syncer::UniquePosition& unique_position) {
sync_pb::BookmarkMetadata bookmark_metadata =
- CreateNodeMetadata(node_id, server_id);
+ CreateNodeMetadata(node, server_id);
*bookmark_metadata.mutable_metadata()->mutable_unique_position() =
unique_position.ToProto();
return bookmark_metadata;
@@ -103,13 +109,13 @@ sync_pb::BookmarkModelMetadata CreateMetadataForPermanentNodes(
model_metadata.set_bookmarks_full_title_reuploaded(true);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->bookmark_bar_node()->id(),
+ CreateNodeMetadata(bookmark_model->bookmark_bar_node(),
/*server_id=*/kBookmarkBarId);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->mobile_node()->id(),
+ CreateNodeMetadata(bookmark_model->mobile_node(),
/*server_id=*/kMobileBookmarksId);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->other_node()->id(),
+ CreateNodeMetadata(bookmark_model->other_node(),
/*server_id=*/kOtherBookmarksId);
return model_metadata;
@@ -586,7 +592,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
histogram_tester.ExpectBucketCount(
"Sync.ProblematicServerSideBookmarks",
/*sample=*/ExpectedRemoteBookmarkUpdateError::kInvalidSpecifics,
- /*count=*/1);
+ /*expected_count=*/1);
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -620,7 +626,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
histogram_tester.ExpectBucketCount(
"Sync.ProblematicServerSideBookmarks",
/*sample=*/ExpectedRemoteBookmarkUpdateError::kUnexpectedGuid,
- /*count=*/1);
+ /*expected_count=*/1);
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -675,7 +681,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
histogram_tester.ExpectBucketCount(
"Sync.ProblematicServerSideBookmarks",
/*sample=*/ExpectedRemoteBookmarkUpdateError::kUnexpectedGuid,
- /*count=*/0);
+ /*expected_count=*/0);
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -1015,7 +1021,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
histogram_tester.ExpectBucketCount(
"Sync.ProblematicServerSideBookmarks",
/*sample=*/ExpectedRemoteBookmarkUpdateError::kParentNotFolder,
- /*count=*/1);
+ /*expected_count=*/1);
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
@@ -1752,6 +1758,10 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
// past bug (see https://crbug.com/1071061).
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
ShouldProcessUpdateWhileDuplicateEntities) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(
+ kInvalidateBookmarkSyncMetadataIfClientTagMissing);
+
const std::string kTitle = "Title";
const std::string kNewTitle = "New Title";
const GURL kUrl("http://www.url.com");
@@ -1774,7 +1784,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
sync_pb::BookmarkMetadata* node_metadata =
model_metadata.add_bookmarks_metadata();
*node_metadata =
- CreateNodeMetadata(node->id(), kLocalId,
+ CreateNodeMetadata(node, kLocalId,
syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()));
sync_pb::BookmarkMetadata* tombstone_metadata =
@@ -1782,8 +1792,8 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
*tombstone_metadata = CreateTombstoneMetadata(kServerId);
// Be sure that there is not client tag hashes yet.
- ASSERT_FALSE(node_metadata->metadata().has_client_tag_hash());
- ASSERT_FALSE(tombstone_metadata->metadata().has_client_tag_hash());
+ node_metadata->mutable_metadata()->clear_client_tag_hash();
+ tombstone_metadata->mutable_metadata()->clear_client_tag_hash();
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -1826,6 +1836,10 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
// difference is that in this test both entities are tombstones.
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
ShouldProcessUpdateWhileDuplicateTombstones) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(
+ kInvalidateBookmarkSyncMetadataIfClientTagMissing);
+
const std::string kTitle = "Title";
const std::string kNewTitle = "New Title";
const GURL kUrl("http://www.url.com");
@@ -1849,8 +1863,8 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
*tombstone_metadata = CreateTombstoneMetadata(kServerId);
// Be sure that there is not client tag hashes yet.
- ASSERT_FALSE(node_metadata->metadata().has_client_tag_hash());
- ASSERT_FALSE(tombstone_metadata->metadata().has_client_tag_hash());
+ node_metadata->mutable_metadata()->clear_client_tag_hash();
+ tombstone_metadata->mutable_metadata()->clear_client_tag_hash();
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -1896,11 +1910,15 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
/*sample=*/
BookmarkRemoteUpdatesHandler::
DuplicateBookmarkEntityOnRemoteUpdateCondition::kServerIdTombstone,
- /*count=*/1);
+ /*expected_count=*/1);
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
- ShouldProcessRemoveUpdateWhileDuplicateEntities) {
+ ShouldProcessRemoteUpdateWhileDuplicateEntities) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(
+ kInvalidateBookmarkSyncMetadataIfClientTagMissing);
+
const std::string kTitle = "Title";
const std::string kNewTitle = "New Title";
const GURL kUrl("http://www.url.com");
@@ -1923,7 +1941,7 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
sync_pb::BookmarkMetadata* node_metadata =
model_metadata.add_bookmarks_metadata();
*node_metadata =
- CreateNodeMetadata(node->id(), kLocalId,
+ CreateNodeMetadata(node, kLocalId,
syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()));
sync_pb::BookmarkMetadata* tombstone_metadata =
@@ -1931,8 +1949,8 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
*tombstone_metadata = CreateTombstoneMetadata(kServerId);
// Be sure that there is not client tag hashes yet.
- ASSERT_FALSE(node_metadata->metadata().has_client_tag_hash());
- ASSERT_FALSE(tombstone_metadata->metadata().has_client_tag_hash());
+ node_metadata->mutable_metadata()->clear_client_tag_hash();
+ tombstone_metadata->mutable_metadata()->clear_client_tag_hash();
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -2043,10 +2061,9 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
sync_pb::BookmarkMetadata* node_metadata =
model_metadata.add_bookmarks_metadata();
*node_metadata =
- CreateNodeMetadata(node->id(), kFolderId,
+ CreateNodeMetadata(node, kFolderId,
syncer::UniquePosition::InitialPosition(
syncer::UniquePosition::RandomSuffix()));
- ASSERT_FALSE(node_metadata->metadata().has_client_tag_hash());
const int64_t server_version = node_metadata->metadata().server_version();
std::unique_ptr<SyncedBookmarkTracker> tracker =
@@ -2059,7 +2076,6 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
tracker->GetEntityForSyncId(kFolderId);
ASSERT_THAT(entity, NotNull());
ASSERT_FALSE(entity->IsUnsynced());
- ASSERT_FALSE(entity->has_final_guid());
syncer::UpdateResponseDataList updates;
// Create an update with the same server version as local entity has. This
@@ -2134,11 +2150,11 @@ TEST(BookmarkRemoteUpdatesHandlerTest, ShouldComputeRightChildNodeIndex) {
sync_pb::BookmarkModelMetadata model_metadata =
CreateMetadataForPermanentNodes(bookmark_model.get());
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node1->id(), "folder1_id", pos1);
+ CreateNodeMetadata(node1, "folder1_id", pos1);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node2->id(), "folder2_id", pos2);
+ CreateNodeMetadata(node2, "folder2_id", pos2);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node3->id(), "folder3_id", pos3);
+ CreateNodeMetadata(node3, "folder3_id", pos3);
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
index 88e24eb9e47..878cfb985ed 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -31,12 +31,12 @@ const base::Feature kInvalidateBookmarkSyncMetadataIfMismatchingGuid{
"InvalidateBookmarkSyncMetadataIfMismatchingGuid",
base::FEATURE_ENABLED_BY_DEFAULT};
-// TODO(crbug.com/1032052): Enable by default once UMA metric
-// Sync.BookmarkModelMetadataClientTagState suggests that most users have
-// received client tag hashes (final GUIDs).
+// TODO(crbug.com/1032052): Clean up once UMA metric
+// Sync.BookmarksModelMetadataCorruptionReason, bucket MISSING_CLIENT_TAG_HASH,
+// is verified to be small enough.
extern const base::Feature kInvalidateBookmarkSyncMetadataIfClientTagMissing{
"InvalidateBookmarkSyncMetadataIfClientTagMissing",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Soft version of the above: it does treat local sync metadata as obsolete if
// client tags are missing, but only if the local client is in sync with the
// server, for some definition of in-sync (see implementation in
@@ -593,6 +593,10 @@ SyncedBookmarkTracker::InitEntitiesFromModelAndMetadata(
return CorruptionReason::BOOKMARK_ID_IN_TOMBSTONE;
}
+ if (!bookmark_metadata.metadata().has_client_tag_hash()) {
+ bookmark_without_client_tag_found = true;
+ }
+
auto tombstone_entity = std::make_unique<Entity>(
/*node=*/nullptr, std::make_unique<sync_pb::EntityMetadata>(std::move(
*bookmark_metadata.mutable_metadata())));
@@ -879,19 +883,18 @@ size_t SyncedBookmarkTracker::EstimateMemoryUsage() const {
return memory_usage;
}
-size_t SyncedBookmarkTracker::TrackedEntitiesCountForTest() const {
- return sync_id_to_entities_map_.size();
-}
-
-size_t SyncedBookmarkTracker::TrackedBookmarksCountForDebugging() const {
+size_t SyncedBookmarkTracker::TrackedBookmarksCount() const {
return bookmark_node_to_entities_map_.size();
}
-size_t SyncedBookmarkTracker::TrackedUncommittedTombstonesCountForDebugging()
- const {
+size_t SyncedBookmarkTracker::TrackedUncommittedTombstonesCount() const {
return ordered_local_tombstones_.size();
}
+size_t SyncedBookmarkTracker::TrackedEntitiesCountForTest() const {
+ return sync_id_to_entities_map_.size();
+}
+
void SyncedBookmarkTracker::ClearSpecificsHashForTest(const Entity* entity) {
AsMutableEntity(entity)->metadata()->clear_specifics_hash();
}
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.h b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
index d0d209c08e9..0f734f6d933 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -270,15 +270,15 @@ class SyncedBookmarkTracker {
// Returns the estimate of dynamically allocated memory in bytes.
size_t EstimateMemoryUsage() const;
- // Returns number of tracked entities. Used only in test.
- size_t TrackedEntitiesCountForTest() const;
-
// Returns number of tracked bookmarks that aren't deleted.
- size_t TrackedBookmarksCountForDebugging() const;
+ size_t TrackedBookmarksCount() const;
// Returns number of bookmarks that have been deleted but the server hasn't
// confirmed the deletion yet.
- size_t TrackedUncommittedTombstonesCountForDebugging() const;
+ size_t TrackedUncommittedTombstonesCount() const;
+
+ // Returns number of tracked entities. Used only in test.
+ size_t TrackedEntitiesCountForTest() const;
// Clears the specifics hash for |entity|, useful for testing.
void ClearSpecificsHashForTest(const Entity* entity);
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index ed8ce4d746a..63d146f7d9b 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -13,6 +13,7 @@
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/time.h"
#include "components/sync/base/unique_position.h"
#include "components/sync/model/entity_data.h"
@@ -62,20 +63,28 @@ sync_pb::EntitySpecifics GenerateSpecifics(const std::string& title,
return specifics;
}
-sync_pb::BookmarkMetadata CreateNodeMetadata(int64_t node_id,
- const std::string& server_id) {
+// |node| must not be nullptr.
+sync_pb::BookmarkMetadata CreateNodeMetadata(
+ const bookmarks::BookmarkNode* node,
+ const std::string& server_id) {
sync_pb::BookmarkMetadata bookmark_metadata;
- bookmark_metadata.set_id(node_id);
+ bookmark_metadata.set_id(node->id());
bookmark_metadata.mutable_metadata()->set_server_id(server_id);
+ bookmark_metadata.mutable_metadata()->set_client_tag_hash(
+ syncer::ClientTagHash::FromUnhashed(syncer::BOOKMARKS, node->guid())
+ .value());
return bookmark_metadata;
}
sync_pb::BookmarkMetadata CreateTombstoneMetadata(
- const std::string& server_id) {
+ const std::string& server_id,
+ const syncer::ClientTagHash& client_tag_hash) {
sync_pb::BookmarkMetadata bookmark_metadata;
bookmark_metadata.mutable_metadata()->set_server_id(server_id);
bookmark_metadata.mutable_metadata()->set_is_deleted(true);
bookmark_metadata.mutable_metadata()->set_sequence_number(1);
+ bookmark_metadata.mutable_metadata()->set_client_tag_hash(
+ client_tag_hash.value());
return bookmark_metadata;
}
@@ -85,13 +94,13 @@ sync_pb::BookmarkModelMetadata CreateMetadataForPermanentNodes(
model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->bookmark_bar_node()->id(),
+ CreateNodeMetadata(bookmark_model->bookmark_bar_node(),
/*server_id=*/kBookmarkBarId);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->mobile_node()->id(),
+ CreateNodeMetadata(bookmark_model->mobile_node(),
/*server_id=*/kMobileBookmarksId);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(bookmark_model->other_node()->id(),
+ CreateNodeMetadata(bookmark_model->other_node(),
/*server_id=*/kOtherBookmarksId);
CHECK_EQ(kNumPermanentNodes, model_metadata.bookmarks_metadata_size());
@@ -341,15 +350,15 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(bookmark_model.get());
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node0->id(), /*server_id=*/kId0);
- *initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node1->id(), /*server_id=*/kId1);
+ CreateNodeMetadata(node0, /*server_id=*/kId0);
*initial_model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/kId2);
- *initial_model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/kId3);
- *initial_model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/kId4);
+ CreateNodeMetadata(node1, /*server_id=*/kId1);
+ *initial_model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/kId2, syncer::ClientTagHash::FromHashed("clienttaghash2"));
+ *initial_model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/kId3, syncer::ClientTagHash::FromHashed("clienttaghash3"));
+ *initial_model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/kId4, syncer::ClientTagHash::FromHashed("clienttaghash4"));
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -405,15 +414,15 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(bookmark_model.get());
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node0->id(), /*server_id=*/kId0);
+ CreateNodeMetadata(node0, /*server_id=*/kId0);
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node1->id(), /*server_id=*/kId1);
+ CreateNodeMetadata(node1, /*server_id=*/kId1);
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node2->id(), /*server_id=*/kId2);
+ CreateNodeMetadata(node2, /*server_id=*/kId2);
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node3->id(), /*server_id=*/kId3);
+ CreateNodeMetadata(node3, /*server_id=*/kId3);
*initial_model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node4->id(), /*server_id=*/kId4);
+ CreateNodeMetadata(node4, /*server_id=*/kId4);
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -463,20 +472,20 @@ TEST(SyncedBookmarkTrackerTest, ShouldUndeleteTombstone) {
tracker->Add(&node, kSyncId, kServerVersion, kModificationTime,
unique_position, specifics);
- ASSERT_THAT(tracker->TrackedUncommittedTombstonesCountForDebugging(), Eq(0U));
+ ASSERT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(0U));
// Delete the bookmark, leading to a pending deletion (local tombstone).
tracker->MarkDeleted(tracker->GetEntityForSyncId(kSyncId));
ASSERT_THAT(entity->bookmark_node(), IsNull());
ASSERT_TRUE(entity->metadata()->is_deleted());
- ASSERT_THAT(tracker->TrackedUncommittedTombstonesCountForDebugging(), Eq(1U));
+ ASSERT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(1U));
// Undelete it.
tracker->UndeleteTombstoneForBookmarkNode(entity, &node);
EXPECT_THAT(entity->bookmark_node(), NotNull());
EXPECT_FALSE(entity->metadata()->is_deleted());
- EXPECT_THAT(tracker->TrackedUncommittedTombstonesCountForDebugging(), Eq(0U));
+ EXPECT_THAT(tracker->TrackedUncommittedTombstonesCount(), Eq(0U));
}
TEST(SyncedBookmarkTrackerTest,
@@ -512,13 +521,13 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(bookmark_model.get());
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node1->id(), /*server_id=*/kId1);
+ CreateNodeMetadata(node1, /*server_id=*/kId1);
+ *model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/kId3, syncer::ClientTagHash::FromHashed("clienttaghash3"));
*model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/kId3);
+ CreateNodeMetadata(node2, /*server_id=*/kId2);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node2->id(), /*server_id=*/kId2);
- *model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node0->id(), /*server_id=*/kId0);
+ CreateNodeMetadata(node0, /*server_id=*/kId0);
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -558,11 +567,12 @@ TEST(SyncedBookmarkTrackerTest, ShouldNotInvalidateMetadata) {
// Add entry for the managed node.
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node->id(), /*server_id=*/"NodeId");
+ CreateNodeMetadata(node, /*server_id=*/"NodeId");
// Add a tombstone entry.
- *model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/"tombstoneId");
+ *model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/"tombstoneId",
+ syncer::ClientTagHash::FromHashed("clienttaghash"));
base::HistogramTester histogram_tester;
@@ -572,7 +582,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldNotInvalidateMetadata) {
histogram_tester.ExpectUniqueSample(
"Sync.BookmarksModelMetadataCorruptionReason",
- /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1);
+ /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*expected_count=*/1);
}
TEST(SyncedBookmarkTrackerTest, ShouldInvalidateMetadataIfMissingMobileFolder) {
@@ -585,10 +595,10 @@ TEST(SyncedBookmarkTrackerTest, ShouldInvalidateMetadataIfMissingMobileFolder) {
// Add entries for all the permanent nodes except for the Mobile bookmarks
// folder.
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(model->bookmark_bar_node()->id(),
+ CreateNodeMetadata(model->bookmark_bar_node(),
/*server_id=*/kBookmarkBarId);
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(model->other_node()->id(),
+ CreateNodeMetadata(model->other_node(),
/*server_id=*/kOtherBookmarksId);
base::HistogramTester histogram_tester;
@@ -637,7 +647,7 @@ TEST(SyncedBookmarkTrackerTest,
/*parent=*/model->bookmark_bar_node(), /*index=*/0,
base::UTF8ToUTF16("node"));
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node->id(), /*server_id=*/"serverid");
+ CreateNodeMetadata(node, /*server_id=*/"serverid");
// Remove the local bookmark ID.
model_metadata.mutable_bookmarks_metadata()->rbegin()->clear_id();
@@ -661,8 +671,9 @@ TEST(SyncedBookmarkTrackerTest,
sync_pb::BookmarkModelMetadata model_metadata =
CreateMetadataForPermanentNodes(model.get());
- *model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/"serverid");
+ *model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/"serverid",
+ syncer::ClientTagHash::FromHashed("clienttaghash"));
// Add a node ID to the tombstone.
model_metadata.mutable_bookmarks_metadata()->rbegin()->set_id(1234);
@@ -691,7 +702,7 @@ TEST(SyncedBookmarkTrackerTest,
/*parent=*/model->bookmark_bar_node(), /*index=*/0,
base::UTF8ToUTF16("node"));
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node->id(), /*server_id=*/"serverid");
+ CreateNodeMetadata(node, /*server_id=*/"serverid");
// Set an arbitrary local node ID that won't match anything in BookmarkModel.
model_metadata.mutable_bookmarks_metadata()->rbegin()->set_id(123456);
@@ -709,10 +720,6 @@ TEST(SyncedBookmarkTrackerTest,
}
TEST(SyncedBookmarkTrackerTest, ShouldInvalidateMetadataIfGuidMismatch) {
- base::test::ScopedFeatureList override_features;
- override_features.InitAndEnableFeature(
- kInvalidateBookmarkSyncMetadataIfMismatchingGuid);
-
std::unique_ptr<bookmarks::BookmarkModel> model =
bookmarks::TestBookmarkClient::CreateModel();
@@ -724,7 +731,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldInvalidateMetadataIfGuidMismatch) {
CreateMetadataForPermanentNodes(model.get());
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
// Set a mismatching client tag hash.
node0_metadata->mutable_metadata()->set_client_tag_hash("corrupthash");
@@ -753,7 +760,7 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(model.get());
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
const syncer::ClientTagHash client_tag_hash =
syncer::ClientTagHash::FromUnhashed(syncer::BOOKMARKS, node0->guid());
@@ -764,7 +771,8 @@ TEST(SyncedBookmarkTrackerTest,
// hash.
sync_pb::BookmarkMetadata* tombstone_metadata =
model_metadata.add_bookmarks_metadata();
- *tombstone_metadata = CreateTombstoneMetadata("id1");
+ *tombstone_metadata = CreateTombstoneMetadata(
+ "id1", syncer::ClientTagHash::FromHashed("clienttaghash1"));
tombstone_metadata->mutable_metadata()->set_client_tag_hash(
client_tag_hash.value());
@@ -797,7 +805,7 @@ TEST(SyncedBookmarkTrackerTest,
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
node0_metadata->mutable_metadata()->clear_client_tag_hash();
@@ -815,6 +823,10 @@ TEST(SyncedBookmarkTrackerTest,
TEST(
SyncedBookmarkTrackerTest,
ShouldNotInvalidateMetadataDespiteMissingClientTagHashIfLastSyncedLongAgo) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(
+ kInvalidateBookmarkSyncMetadataIfClientTagMissing);
+
std::unique_ptr<bookmarks::BookmarkModel> model =
bookmarks::TestBookmarkClient::CreateModel();
@@ -830,7 +842,7 @@ TEST(
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
node0_metadata->mutable_metadata()->clear_client_tag_hash();
@@ -846,6 +858,10 @@ TEST(
TEST(SyncedBookmarkTrackerTest,
ShouldNotInvalidateMetadataDespiteMissingClientTagIfPendingLocalChanges) {
+ base::test::ScopedFeatureList override_features;
+ override_features.InitAndDisableFeature(
+ kInvalidateBookmarkSyncMetadataIfClientTagMissing);
+
std::unique_ptr<bookmarks::BookmarkModel> model =
bookmarks::TestBookmarkClient::CreateModel();
@@ -859,12 +875,12 @@ TEST(SyncedBookmarkTrackerTest,
// tombstone that prevents sync metadata from being invalidated.
model_metadata.set_last_sync_time(syncer::TimeToProtoTime(
base::Time::Now() - base::TimeDelta::FromHours(1)));
- *model_metadata.add_bookmarks_metadata() =
- CreateTombstoneMetadata(/*server_id=*/"id0");
+ *model_metadata.add_bookmarks_metadata() = CreateTombstoneMetadata(
+ /*server_id=*/"id0", syncer::ClientTagHash::FromHashed("clienttaghash0"));
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id1");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id1");
node0_metadata->mutable_metadata()->clear_client_tag_hash();
@@ -880,10 +896,6 @@ TEST(SyncedBookmarkTrackerTest,
TEST(SyncedBookmarkTrackerTest,
ShouldInvalidateMetadataIfMissingClientTagHash) {
- base::test::ScopedFeatureList override_features;
- override_features.InitAndEnableFeature(
- kInvalidateBookmarkSyncMetadataIfClientTagMissing);
-
std::unique_ptr<bookmarks::BookmarkModel> model =
bookmarks::TestBookmarkClient::CreateModel();
@@ -895,7 +907,7 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(model.get());
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
node0_metadata->mutable_metadata()->clear_client_tag_hash();
@@ -929,7 +941,7 @@ TEST(SyncedBookmarkTrackerTest,
// Add unsyncable node to metadata.
*model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(managed_node->id(),
+ CreateNodeMetadata(managed_node,
/*server_id=*/"server_id");
base::HistogramTester histogram_tester;
@@ -958,7 +970,7 @@ TEST(SyncedBookmarkTrackerTest,
CreateMetadataForPermanentNodes(model.get());
sync_pb::BookmarkMetadata* node0_metadata =
model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0->id(), /*server_id=*/"id0");
+ *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
// Set a mismatching client tag hash.
node0_metadata->mutable_metadata()->set_client_tag_hash("corrupthash");
@@ -1052,8 +1064,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldPopulateFaviconHashUponUpdate) {
CreateMetadataForPermanentNodes(model.get());
// Add entry for the URL node.
- *model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node->id(), kSyncId);
+ *model_metadata.add_bookmarks_metadata() = CreateNodeMetadata(node, kSyncId);
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
@@ -1093,8 +1104,7 @@ TEST(SyncedBookmarkTrackerTest, ShouldPopulateFaviconHashExplicitly) {
CreateMetadataForPermanentNodes(model.get());
// Add entry for the URL node.
- *model_metadata.add_bookmarks_metadata() =
- CreateNodeMetadata(node->id(), kSyncId);
+ *model_metadata.add_bookmarks_metadata() = CreateNodeMetadata(node, kSyncId);
std::unique_ptr<SyncedBookmarkTracker> tracker =
SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
diff --git a/chromium/components/sync_device_info/device_info_prefs.cc b/chromium/components/sync_device_info/device_info_prefs.cc
index 5f02f05600b..d3a47f1e94d 100644
--- a/chromium/components/sync_device_info/device_info_prefs.cc
+++ b/chromium/components/sync_device_info/device_info_prefs.cc
@@ -17,10 +17,6 @@
namespace syncer {
namespace {
-// Name of obsolete preference that stores most recently used past cache
-// GUIDs, most recent first.
-const char kObsoleteDeviceInfoRecentGUIDs[] = "sync.local_device_guids";
-
// Preference name for storing recently used cache GUIDs and their timestamps
// in days since Windows epoch. Most recent first.
const char kDeviceInfoRecentGUIDsWithTimestamps[] =
@@ -54,25 +50,6 @@ bool MatchesGuidInDictionary(const base::Value& dict,
// static
void DeviceInfoPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kDeviceInfoRecentGUIDsWithTimestamps);
- registry->RegisterListPref(kObsoleteDeviceInfoRecentGUIDs);
-}
-
-// static
-void DeviceInfoPrefs::MigrateRecentLocalCacheGuidsPref(
- PrefService* pref_service) {
- base::Value::ConstListView obsolete_cache_guids =
- pref_service->GetList(kObsoleteDeviceInfoRecentGUIDs)->GetList();
- DeviceInfoPrefs prefs(pref_service, base::DefaultClock::GetInstance());
-
- // Iterate in reverse order to maintain original order.
- for (auto it = obsolete_cache_guids.rbegin();
- it != obsolete_cache_guids.rend(); ++it) {
- if (it->is_string()) {
- prefs.AddLocalCacheGuid(it->GetString());
- }
- }
-
- pref_service->ClearPref(kObsoleteDeviceInfoRecentGUIDs);
}
DeviceInfoPrefs::DeviceInfoPrefs(PrefService* pref_service,
diff --git a/chromium/components/sync_device_info/device_info_prefs.h b/chromium/components/sync_device_info/device_info_prefs.h
index 5c5a1128ce9..9c63454e323 100644
--- a/chromium/components/sync_device_info/device_info_prefs.h
+++ b/chromium/components/sync_device_info/device_info_prefs.h
@@ -24,8 +24,6 @@ class DeviceInfoPrefs {
public:
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
- static void MigrateRecentLocalCacheGuidsPref(PrefService* pref_service);
-
// |pref_service| and |clock| must outlive this class and be non null.
DeviceInfoPrefs(PrefService* pref_service, const base::Clock* clock);
~DeviceInfoPrefs();
diff --git a/chromium/components/sync_device_info/device_info_prefs_unittest.cc b/chromium/components/sync_device_info/device_info_prefs_unittest.cc
index 2d040ad1ac9..69d984ba99a 100644
--- a/chromium/components/sync_device_info/device_info_prefs_unittest.cc
+++ b/chromium/components/sync_device_info/device_info_prefs_unittest.cc
@@ -27,26 +27,6 @@ class DeviceInfoPrefsTest : public testing::Test {
TestingPrefServiceSimple pref_service_;
};
-TEST_F(DeviceInfoPrefsTest, ShouldMigrateFromObsoletePref) {
- const char kObsoleteDeviceInfoRecentGUIDs[] = "sync.local_device_guids";
-
- ListPrefUpdate cache_guids_update(&pref_service_,
- kObsoleteDeviceInfoRecentGUIDs);
-
- cache_guids_update->Insert(cache_guids_update->GetList().begin(),
- base::Value("old_guid1"));
- cache_guids_update->Insert(cache_guids_update->GetList().begin(),
- base::Value("old_guid2"));
-
- ASSERT_FALSE(device_info_prefs_.IsRecentLocalCacheGuid("old_guid1"));
- ASSERT_FALSE(device_info_prefs_.IsRecentLocalCacheGuid("old_guid2"));
-
- DeviceInfoPrefs::MigrateRecentLocalCacheGuidsPref(&pref_service_);
-
- EXPECT_TRUE(device_info_prefs_.IsRecentLocalCacheGuid("old_guid1"));
- EXPECT_TRUE(device_info_prefs_.IsRecentLocalCacheGuid("old_guid2"));
-}
-
TEST_F(DeviceInfoPrefsTest, ShouldGarbageCollectExpiredCacheGuids) {
const base::TimeDelta kMaxDaysLocalCacheGuidsStored =
base::TimeDelta::FromDays(10);
diff --git a/chromium/components/sync_device_info/device_info_sync_bridge.cc b/chromium/components/sync_device_info/device_info_sync_bridge.cc
index f6ca59ef445..be551b72676 100644
--- a/chromium/components/sync_device_info/device_info_sync_bridge.cc
+++ b/chromium/components/sync_device_info/device_info_sync_bridge.cc
@@ -12,7 +12,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/strings/string_util.h"
#include "components/sync/base/model_type.h"
@@ -230,7 +230,11 @@ void DeviceInfoSyncBridge::RefreshLocalDeviceInfo(base::OnceClosure callback) {
device_info_synced_callback_list_.push_back(std::move(callback));
}
- SendLocalData();
+ // Device info cannot be synced if the provider is not initialized. When it
+ // gets initialized, local device info will be sent.
+ if (local_device_info_provider_->GetLocalDeviceInfo()) {
+ SendLocalData();
+ }
}
void DeviceInfoSyncBridge::OnSyncStarting(
@@ -621,7 +625,7 @@ void DeviceInfoSyncBridge::SendLocalDataWithBatch(
change_processor()->Put(specifics->cache_guid(), CopyToEntityData(*specifics),
batch->GetMetadataChangeList());
StoreSpecifics(std::move(specifics), batch.get());
- CommitAndNotify(std::move(batch), /*should_notify=*/true);
+ CommitAndNotify(std::move(batch), /*notify_if_restricted=*/true);
pulse_timer_.Start(FROM_HERE, DeviceInfoUtil::GetPulseInterval(),
base::BindOnce(&DeviceInfoSyncBridge::SendLocalData,
@@ -710,7 +714,7 @@ void DeviceInfoSyncBridge::ExpireOldEntries() {
batch->GetMetadataChangeList()->ClearMetadata(cache_guid);
change_processor()->UntrackEntityForStorageKey(cache_guid);
}
- CommitAndNotify(std::move(batch), /*should_notify=*/true);
+ CommitAndNotify(std::move(batch), /*notify_if_restricted=*/true);
}
} // namespace syncer
diff --git a/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc b/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
index 4c6085cc864..dca1bd7509d 100644
--- a/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -9,11 +9,11 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
@@ -21,12 +21,11 @@
#include "components/sync/base/time.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
-#include "components/sync/model/data_type_error_handler_mock.h"
#include "components/sync/model/entity_data.h"
#include "components/sync/model/metadata_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/test_matchers.h"
#include "components/sync_device_info/device_info_prefs.h"
#include "components/sync_device_info/device_info_util.h"
@@ -493,7 +492,7 @@ class DeviceInfoSyncBridgeTest : public testing::Test,
void ForcePulse() { bridge()->ForcePulseForTest(); }
void RefreshLocalDeviceInfo() {
- bridge()->RefreshLocalDeviceInfo(base::OnceClosure());
+ bridge()->RefreshLocalDeviceInfo(base::DoNothing());
}
void CommitToStoreAndWait(std::unique_ptr<WriteBatch> batch) {
diff --git a/chromium/components/sync_device_info/device_info_sync_service.h b/chromium/components/sync_device_info/device_info_sync_service.h
index 064e06e006e..d76c7d4a357 100644
--- a/chromium/components/sync_device_info/device_info_sync_service.h
+++ b/chromium/components/sync_device_info/device_info_sync_service.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -41,7 +42,7 @@ class DeviceInfoSyncService : public KeyedService {
// soon as possible, without waiting for the periodic commits. |callback| will
// be called when device info is synced.
virtual void RefreshLocalDeviceInfo(
- base::OnceClosure callback = base::OnceClosure()) = 0;
+ base::OnceClosure callback = base::DoNothing()) = 0;
};
} // namespace syncer
diff --git a/chromium/components/sync_device_info/device_info_sync_service_impl.cc b/chromium/components/sync_device_info/device_info_sync_service_impl.cc
index 9e1baf26a55..a24ee0ce5c9 100644
--- a/chromium/components/sync_device_info/device_info_sync_service_impl.cc
+++ b/chromium/components/sync_device_info/device_info_sync_service_impl.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/sync/base/report_unrecoverable_error.h"
#include "components/sync/invalidations/sync_invalidations_service.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
diff --git a/chromium/components/sync_device_info/device_info_sync_service_impl.h b/chromium/components/sync_device_info/device_info_sync_service_impl.h
index e538ef4fbfb..66fb365291d 100644
--- a/chromium/components/sync_device_info/device_info_sync_service_impl.h
+++ b/chromium/components/sync_device_info/device_info_sync_service_impl.h
@@ -44,7 +44,7 @@ class DeviceInfoSyncServiceImpl : public DeviceInfoSyncService,
DeviceInfoTracker* GetDeviceInfoTracker() override;
base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegate() override;
void RefreshLocalDeviceInfo(
- base::OnceClosure callback = base::OnceClosure()) override;
+ base::OnceClosure callback = base::DoNothing()) override;
// FCMRegistrationTokenObserver implementation.
void OnFCMRegistrationTokenChanged() override;
diff --git a/chromium/components/sync_device_info/fake_device_info_sync_service.h b/chromium/components/sync_device_info/fake_device_info_sync_service.h
index 884f31adaa5..f1a51b530b0 100644
--- a/chromium/components/sync_device_info/fake_device_info_sync_service.h
+++ b/chromium/components/sync_device_info/fake_device_info_sync_service.h
@@ -6,7 +6,7 @@
#define COMPONENTS_SYNC_DEVICE_INFO_FAKE_DEVICE_INFO_SYNC_SERVICE_H_
#include "base/callback.h"
-#include "components/sync/model/fake_model_type_controller_delegate.h"
+#include "components/sync/test/model/fake_model_type_controller_delegate.h"
#include "components/sync_device_info/device_info_sync_service.h"
#include "components/sync_device_info/fake_device_info_tracker.h"
#include "components/sync_device_info/fake_local_device_info_provider.h"
diff --git a/chromium/components/sync_device_info/local_device_info_provider_impl_unittest.cc b/chromium/components/sync_device_info/local_device_info_provider_impl_unittest.cc
index d8ae8b5a281..68f52076441 100644
--- a/chromium/components/sync_device_info/local_device_info_provider_impl_unittest.cc
+++ b/chromium/components/sync_device_info/local_device_info_provider_impl_unittest.cc
@@ -5,7 +5,6 @@
#include "components/sync_device_info/local_device_info_provider_impl.h"
#include "base/memory/ptr_util.h"
-#include "base/test/scoped_feature_list.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/sync_util.h"
#include "components/sync_device_info/device_info_sync_client.h"
@@ -42,12 +41,14 @@ class MockDeviceInfoSyncClient : public DeviceInfoSyncClient {
MockDeviceInfoSyncClient() = default;
~MockDeviceInfoSyncClient() = default;
- MOCK_CONST_METHOD0(GetSigninScopedDeviceId, std::string());
- MOCK_CONST_METHOD0(GetSendTabToSelfReceivingEnabled, bool());
- MOCK_CONST_METHOD0(GetLocalSharingInfo,
- base::Optional<DeviceInfo::SharingInfo>());
- MOCK_CONST_METHOD0(GetFCMRegistrationToken, std::string());
- MOCK_CONST_METHOD0(GetInterestedDataTypes, ModelTypeSet());
+ MOCK_METHOD(std::string, GetSigninScopedDeviceId, (), (const override));
+ MOCK_METHOD(bool, GetSendTabToSelfReceivingEnabled, (), (const override));
+ MOCK_METHOD(base::Optional<DeviceInfo::SharingInfo>,
+ GetLocalSharingInfo,
+ (),
+ (const override));
+ MOCK_METHOD(std::string, GetFCMRegistrationToken, (), (const override));
+ MOCK_METHOD(ModelTypeSet, GetInterestedDataTypes, (), (const override));
private:
DISALLOW_COPY_AND_ASSIGN(MockDeviceInfoSyncClient);
diff --git a/chromium/components/sync_preferences/pref_service_syncable.cc b/chromium/components/sync_preferences/pref_service_syncable.cc
index 8685a265f63..358bf7ef164 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable.cc
@@ -7,8 +7,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/strings/string_number_conversions.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/default_pref_store.h"
diff --git a/chromium/components/sync_preferences/pref_service_syncable.h b/chromium/components/sync_preferences/pref_service_syncable.h
index b924e4e3b49..30c466792e7 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.h
+++ b/chromium/components/sync_preferences/pref_service_syncable.h
@@ -82,8 +82,6 @@ class PrefServiceSyncable : public PrefService {
void AddObserver(PrefServiceSyncableObserver* observer);
void RemoveObserver(PrefServiceSyncableObserver* observer);
- // TODO(zea): Have PrefServiceSyncable implement
- // syncer::SyncableService directly.
syncer::SyncableService* GetSyncableService(const syncer::ModelType& type);
// Do not call this after having derived an incognito or per tab pref service.
diff --git a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
index 24574cabbca..2f33f272ac5 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -9,7 +9,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
#include "base/json/json_writer.h"
@@ -25,10 +25,10 @@
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_data.h"
-#include "components/sync/model/sync_error_factory_mock.h"
#include "components/sync/model/syncable_service.h"
#include "components/sync/protocol/preference_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/sync_error_factory_mock.h"
#include "components/sync_preferences/pref_model_associator.h"
#include "components/sync_preferences/pref_model_associator_client.h"
#include "components/sync_preferences/synced_pref_observer.h"
diff --git a/chromium/components/sync_sessions/BUILD.gn b/chromium/components/sync_sessions/BUILD.gn
index 42e045828ca..977ed5845c0 100644
--- a/chromium/components/sync_sessions/BUILD.gn
+++ b/chromium/components/sync_sessions/BUILD.gn
@@ -27,6 +27,8 @@ static_library("sync_sessions") {
"session_sync_service_impl.h",
"sessions_global_id_mapper.cc",
"sessions_global_id_mapper.h",
+ "switches.cc",
+ "switches.h",
"sync_sessions_client.cc",
"sync_sessions_client.h",
"synced_session.cc",
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl.cc b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
index 117d3f2712c..9e8a5ea167a 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync_sessions/switches.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/sync_sessions/synced_session_tracker.h"
#include "components/sync_sessions/synced_tab_delegate.h"
@@ -44,8 +45,12 @@ bool IsSessionRestoreInProgress(SyncSessionsClient* sessions_client) {
}
bool IsWindowSyncable(const SyncedWindowDelegate& window_delegate) {
- return window_delegate.ShouldSync() && window_delegate.GetTabCount() &&
- window_delegate.HasWindow();
+ // TODO(crbug.com/1039234): remove the feature toggle once the logic is rolled
+ // out.
+ return window_delegate.ShouldSync() && window_delegate.HasWindow() &&
+ (window_delegate.GetTabCount() ||
+ base::FeatureList::IsEnabled(
+ switches::kSyncConsiderEmptyWindowsSyncable));
}
// On Android, it's possible to not have any tabbed windows when only custom
@@ -157,12 +162,16 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
window_delegate->GetTabCount());
}
- // Make sure the window has tabs and a viewable window. The viewable
- // window check is necessary because, for example, when a browser is
- // closed the destructor is not necessarily run immediately. This means
+ // Make sure the window is viewable and is not about to be closed. The
+ // viewable window check is necessary because, for example, when a browser
+ // is closed the destructor is not necessarily run immediately. This means
// its possible for us to get a handle to a browser that is about to be
- // removed. If the tab count is 0 or the window is null, the browser is
- // about to be deleted, so we ignore it.
+ // removed. If the window is null, the browser is about to be deleted, so we
+ // ignore it. There is no check for having open tabs anymore. This is needed
+ // to handle a case when the last tab is closed (on Andorid it doesn't mean
+ // that the window is about to be removed). Instead, there is a check if the
+ // window is about to be closed. If the window is last for the profile, the
+ // latest state will be kept.
if (!IsWindowSyncable(*window_delegate)) {
continue;
}
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
index 1a898355b19..9e73ed0f96b 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
@@ -58,23 +58,28 @@ const int kTabId3 = 1000006;
class MockWriteBatch : public LocalSessionEventHandlerImpl::WriteBatch {
public:
- MockWriteBatch() {}
- ~MockWriteBatch() override {}
-
- MOCK_METHOD1(Delete, void(int tab_node_id));
- MOCK_METHOD1(Put, void(std::unique_ptr<sync_pb::SessionSpecifics> specifics));
- MOCK_METHOD0(Commit, void());
+ MockWriteBatch() = default;
+ ~MockWriteBatch() override = default;
+ MOCK_METHOD(void, Delete, (int tab_node_id), (override));
+ MOCK_METHOD(void,
+ Put,
+ (std::unique_ptr<sync_pb::SessionSpecifics> specifics),
+ (override));
+ MOCK_METHOD(void, Commit, (), (override));
};
class MockDelegate : public LocalSessionEventHandlerImpl::Delegate {
public:
- ~MockDelegate() override {}
-
- MOCK_METHOD0(CreateLocalSessionWriteBatch,
- std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>());
- MOCK_METHOD1(IsTabNodeUnsynced, bool(int tab_node_id));
- MOCK_METHOD2(TrackLocalNavigationId,
- void(base::Time timestamp, int unique_id));
+ ~MockDelegate() override = default;
+ MOCK_METHOD(std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>,
+ CreateLocalSessionWriteBatch,
+ (),
+ (override));
+ MOCK_METHOD(bool, IsTabNodeUnsynced, (int tab_node_id), (override));
+ MOCK_METHOD(void,
+ TrackLocalNavigationId,
+ (base::Time timestamp, int unique_id),
+ (override));
};
class LocalSessionEventHandlerImplTest : public testing::Test {
diff --git a/chromium/components/sync_sessions/mock_sync_sessions_client.h b/chromium/components/sync_sessions/mock_sync_sessions_client.h
index fa2bd5456b5..52e4f6b89a1 100644
--- a/chromium/components/sync_sessions/mock_sync_sessions_client.h
+++ b/chromium/components/sync_sessions/mock_sync_sessions_client.h
@@ -16,14 +16,21 @@ class MockSyncSessionsClient : public SyncSessionsClient {
// By default, ShouldSyncURL() always returns true.
MockSyncSessionsClient();
~MockSyncSessionsClient() override;
-
- MOCK_METHOD0(GetSessionSyncPrefs, SessionSyncPrefs*());
- MOCK_METHOD0(GetStoreFactory, syncer::RepeatingModelTypeStoreFactory());
- MOCK_METHOD0(ClearAllOnDemandFavicons, void());
- MOCK_CONST_METHOD1(ShouldSyncURL, bool(const GURL& url));
- MOCK_METHOD0(GetSyncedWindowDelegatesGetter, SyncedWindowDelegatesGetter*());
- MOCK_METHOD0(GetLocalSessionEventRouter, LocalSessionEventRouter*());
- MOCK_METHOD0(IsProxyTabsSyncRunning, bool());
+ MOCK_METHOD(SessionSyncPrefs*, GetSessionSyncPrefs, (), (override));
+ MOCK_METHOD(syncer::RepeatingModelTypeStoreFactory,
+ GetStoreFactory,
+ (),
+ (override));
+ MOCK_METHOD(void, ClearAllOnDemandFavicons, (), (override));
+ MOCK_METHOD(bool, ShouldSyncURL, (const GURL& url), (const override));
+ MOCK_METHOD(SyncedWindowDelegatesGetter*,
+ GetSyncedWindowDelegatesGetter,
+ (),
+ (override));
+ MOCK_METHOD(LocalSessionEventRouter*,
+ GetLocalSessionEventRouter,
+ (),
+ (override));
};
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc
index 738cce5b39d..81a04be3eb6 100644
--- a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc
+++ b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc
@@ -6,8 +6,10 @@
#include <utility>
+#include "base/values.h"
#include "components/sync/driver/configure_context.h"
#include "components/sync/engine/model_type_configurer.h"
+#include "components/sync/model/type_entities_count.h"
namespace sync_sessions {
@@ -29,8 +31,8 @@ void ProxyTabsDataTypeController::LoadModels(
model_load_callback.Run(type(), syncer::SyncError());
}
-syncer::DataTypeController::RegisterWithBackendResult
-ProxyTabsDataTypeController::RegisterWithBackend(
+syncer::DataTypeController::ActivateDataTypeResult
+ProxyTabsDataTypeController::ActivateDataType(
syncer::ModelTypeConfigurer* configurer) {
DCHECK(configurer);
DCHECK_EQ(MODEL_LOADED, state_);
@@ -45,7 +47,8 @@ ProxyTabsDataTypeController::RegisterWithBackend(
state_ = RUNNING;
state_changed_cb_.Run(state_);
- return REGISTRATION_IGNORED;
+ // Proxy types don't have any data to download.
+ return TYPE_ALREADY_DOWNLOADED;
}
void ProxyTabsDataTypeController::Stop(syncer::ShutdownReason shutdown_reason,
@@ -59,6 +62,10 @@ syncer::DataTypeController::State ProxyTabsDataTypeController::state() const {
return state_;
}
+bool ProxyTabsDataTypeController::ShouldRunInTransportOnlyMode() const {
+ return false;
+}
+
void ProxyTabsDataTypeController::DeactivateDataType(
syncer::ModelTypeConfigurer* configurer) {
if (state_ == RUNNING) {
@@ -71,10 +78,9 @@ void ProxyTabsDataTypeController::GetAllNodes(AllNodesCallback callback) {
std::move(callback).Run(type(), std::make_unique<base::ListValue>());
}
-void ProxyTabsDataTypeController::GetStatusCounters(
- StatusCountersCallback callback) {
- syncer::StatusCounters counters;
- std::move(callback).Run(type(), counters);
+void ProxyTabsDataTypeController::GetTypeEntitiesCount(
+ base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback) const {
+ std::move(callback).Run(syncer::TypeEntitiesCount(type()));
}
void ProxyTabsDataTypeController::RecordMemoryUsageAndCountsHistograms() {}
diff --git a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h
index aa82a741afa..f44e9ebcf83 100644
--- a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h
+++ b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h
@@ -26,14 +26,17 @@ class ProxyTabsDataTypeController : public syncer::DataTypeController {
// DataTypeController interface.
void LoadModels(const syncer::ConfigureContext& configure_context,
const ModelLoadCallback& model_load_callback) override;
- RegisterWithBackendResult RegisterWithBackend(
+ ActivateDataTypeResult ActivateDataType(
syncer::ModelTypeConfigurer* configurer) override;
void Stop(syncer::ShutdownReason shutdown_reason,
StopCallback callback) override;
State state() const override;
+ bool ShouldRunInTransportOnlyMode() const override;
void DeactivateDataType(syncer::ModelTypeConfigurer* configurer) override;
void GetAllNodes(AllNodesCallback callback) override;
- void GetStatusCounters(StatusCountersCallback callback) override;
+ void GetTypeEntitiesCount(
+ base::OnceCallback<void(const syncer::TypeEntitiesCount&)> callback)
+ const override;
void RecordMemoryUsageAndCountsHistograms() override;
private:
diff --git a/chromium/components/sync_sessions/session_store.cc b/chromium/components/sync_sessions/session_store.cc
index 1e229a09308..8cea1e81ec3 100644
--- a/chromium/components/sync_sessions/session_store.cc
+++ b/chromium/components/sync_sessions/session_store.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
diff --git a/chromium/components/sync_sessions/session_store_unittest.cc b/chromium/components/sync_sessions/session_store_unittest.cc
index ab8b00e7b44..c48e93cc12a 100644
--- a/chromium/components/sync_sessions/session_store_unittest.cc
+++ b/chromium/components/sync_sessions/session_store_unittest.cc
@@ -9,15 +9,15 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/cancelable_callback.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/hash_util.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/test_matchers.h"
#include "components/sync_device_info/local_device_info_util.h"
#include "components/sync_sessions/mock_sync_sessions_client.h"
@@ -57,10 +57,12 @@ const char kCacheGuid[] = "SomeCacheGuid";
// b) conveniently exposes the last instantiated session store.
class MockOpenCallback {
public:
- MOCK_METHOD3(Run,
- void(const base::Optional<syncer::ModelError>& error,
- SessionStore* store,
- MetadataBatch* metadata_batch));
+ MOCK_METHOD(void,
+ Run,
+ (const base::Optional<syncer::ModelError>& error,
+ SessionStore* store,
+ MetadataBatch* metadata_batch),
+ ());
SessionStore::OpenCallback Get() {
return base::BindOnce(
diff --git a/chromium/components/sync_sessions/session_sync_bridge.cc b/chromium/components/sync_sessions/session_sync_bridge.cc
index fe13be36930..e66de1790b1 100644
--- a/chromium/components/sync_sessions/session_sync_bridge.cc
+++ b/chromium/components/sync_sessions/session_sync_bridge.cc
@@ -11,7 +11,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
index 5cc4e622f64..15a8d422b80 100644
--- a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
+++ b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -8,29 +8,29 @@
#include <utility>
#include <vector>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/json/json_writer.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/sync_prefs.h"
-#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync/engine/commit_and_get_updates_types.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/model/metadata_change_list.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/model/model_type_sync_bridge.h"
#include "components/sync/model/sync_metadata_store.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync/protocol/proto_value_conversions.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/test_matchers.h"
#include "components/sync_sessions/mock_sync_sessions_client.h"
#include "components/sync_sessions/session_sync_prefs.h"
diff --git a/chromium/components/sync_sessions/session_sync_service_impl.cc b/chromium/components/sync_sessions/session_sync_service_impl.cc
index d251c8bc6e1..6e532b8aa67 100644
--- a/chromium/components/sync_sessions/session_sync_service_impl.cc
+++ b/chromium/components/sync_sessions/session_sync_service_impl.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/sync/base/report_unrecoverable_error.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
#include "components/sync_sessions/session_sync_bridge.h"
diff --git a/chromium/components/sync_sessions/switches.cc b/chromium/components/sync_sessions/switches.cc
new file mode 100644
index 00000000000..bc1df38d93b
--- /dev/null
+++ b/chromium/components/sync_sessions/switches.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 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/sync_sessions/switches.h"
+
+namespace switches {
+
+// Enables syncing Sessions data type in case when the window doesn't have open
+// tabs anymore.
+const base::Feature kSyncConsiderEmptyWindowsSyncable{
+ "SyncConsiderEmptyWindowsSyncable", base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace switches
diff --git a/chromium/components/sync_sessions/switches.h b/chromium/components/sync_sessions/switches.h
new file mode 100644
index 00000000000..4f15cd98f4c
--- /dev/null
+++ b/chromium/components/sync_sessions/switches.h
@@ -0,0 +1,16 @@
+// Copyright 2020 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_SYNC_SESSIONS_SWITCHES_H_
+#define COMPONENTS_SYNC_SESSIONS_SWITCHES_H_
+
+#include "base/feature_list.h"
+
+namespace switches {
+
+extern const base::Feature kSyncConsiderEmptyWindowsSyncable;
+
+} // namespace switches
+
+#endif // COMPONENTS_SYNC_SESSIONS_SWITCHES_H_
diff --git a/chromium/components/sync_user_events/DEPS b/chromium/components/sync_user_events/DEPS
index 5db0a1ec69c..eab37591260 100644
--- a/chromium/components/sync_user_events/DEPS
+++ b/chromium/components/sync_user_events/DEPS
@@ -4,5 +4,6 @@ include_rules = [
"+components/sync/driver",
"+components/sync/model",
"+components/sync/protocol",
+ "+components/sync/test/model",
"+google_apis/gaia",
]
diff --git a/chromium/components/sync_user_events/fake_user_event_service.cc b/chromium/components/sync_user_events/fake_user_event_service.cc
index cdaddc8b7e5..03fb6b13496 100644
--- a/chromium/components/sync_user_events/fake_user_event_service.cc
+++ b/chromium/components/sync_user_events/fake_user_event_service.cc
@@ -4,14 +4,13 @@
#include "components/sync_user_events/fake_user_event_service.h"
-#include "components/sync/model/fake_model_type_change_processor.h"
using sync_pb::UserEventSpecifics;
namespace syncer {
FakeUserEventService::FakeUserEventService()
- : fake_bridge_(std::make_unique<FakeModelTypeChangeProcessor>()) {}
+ : fake_controller_delegate_(syncer::USER_EVENTS) {}
FakeUserEventService::~FakeUserEventService() {}
@@ -26,8 +25,9 @@ void FakeUserEventService::RecordUserEvent(
recorded_user_events_.push_back(specifics);
}
-ModelTypeSyncBridge* FakeUserEventService::GetSyncBridge() {
- return &fake_bridge_;
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+FakeUserEventService::GetControllerDelegate() {
+ return fake_controller_delegate_.GetWeakPtr();
}
const std::vector<UserEventSpecifics>&
diff --git a/chromium/components/sync_user_events/fake_user_event_service.h b/chromium/components/sync_user_events/fake_user_event_service.h
index f0e7bc9eb9e..7b3bee37497 100644
--- a/chromium/components/sync_user_events/fake_user_event_service.h
+++ b/chromium/components/sync_user_events/fake_user_event_service.h
@@ -10,8 +10,8 @@
#include <vector>
#include "base/macros.h"
-#include "components/sync/model/fake_model_type_sync_bridge.h"
#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/sync/test/model/fake_model_type_controller_delegate.h"
#include "components/sync_user_events/user_event_service.h"
namespace syncer {
@@ -27,18 +27,14 @@ class FakeUserEventService : public UserEventService {
void RecordUserEvent(
std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
- // TODO(crbug.com/895340): This is hard to mock, replace it (in the base
- // class) by GetControllerDelegate(), then we can get rid of |fake_bridge_|.
- // Maybe we can also expose a raw pointer to be consumed by
- // ForwardingModelTypeControllerDelegate and not care about WeakPtrs anymore
- // (but we need a nice solution for SyncClient).
- ModelTypeSyncBridge* GetSyncBridge() override;
+ base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate()
+ override;
const std::vector<sync_pb::UserEventSpecifics>& GetRecordedUserEvents() const;
private:
std::vector<sync_pb::UserEventSpecifics> recorded_user_events_;
- FakeModelTypeSyncBridge fake_bridge_;
+ FakeModelTypeControllerDelegate fake_controller_delegate_;
DISALLOW_COPY_AND_ASSIGN(FakeUserEventService);
};
diff --git a/chromium/components/sync_user_events/no_op_user_event_service.cc b/chromium/components/sync_user_events/no_op_user_event_service.cc
index 78cb011afc0..505d60dc5ff 100644
--- a/chromium/components/sync_user_events/no_op_user_event_service.cc
+++ b/chromium/components/sync_user_events/no_op_user_event_service.cc
@@ -20,7 +20,8 @@ void NoOpUserEventService::RecordUserEvent(
void NoOpUserEventService::RecordUserEvent(
const UserEventSpecifics& specifics) {}
-ModelTypeSyncBridge* NoOpUserEventService::GetSyncBridge() {
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+NoOpUserEventService::GetControllerDelegate() {
return nullptr;
}
diff --git a/chromium/components/sync_user_events/no_op_user_event_service.h b/chromium/components/sync_user_events/no_op_user_event_service.h
index 0ae48ff7ab2..fd69d6fd1f4 100644
--- a/chromium/components/sync_user_events/no_op_user_event_service.h
+++ b/chromium/components/sync_user_events/no_op_user_event_service.h
@@ -13,8 +13,6 @@
namespace syncer {
-class ModelTypeSyncBridge;
-
// This implementation is used when we know event should never be recorded,
// such as in incognito mode.
class NoOpUserEventService : public UserEventService {
@@ -26,7 +24,8 @@ class NoOpUserEventService : public UserEventService {
void RecordUserEvent(
std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
- ModelTypeSyncBridge* GetSyncBridge() override;
+ base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate()
+ override;
private:
DISALLOW_COPY_AND_ASSIGN(NoOpUserEventService);
diff --git a/chromium/components/sync_user_events/user_event_service.h b/chromium/components/sync_user_events/user_event_service.h
index 16017afbb2f..75d6ea43c73 100644
--- a/chromium/components/sync_user_events/user_event_service.h
+++ b/chromium/components/sync_user_events/user_event_service.h
@@ -15,7 +15,7 @@
namespace syncer {
-class ModelTypeSyncBridge;
+class ModelTypeControllerDelegate;
class UserEventService : public KeyedService {
public:
@@ -31,7 +31,8 @@ class UserEventService : public KeyedService {
const sync_pb::UserEventSpecifics& specifics) = 0;
// Returns the underlying Sync integration point.
- virtual ModelTypeSyncBridge* GetSyncBridge() = 0;
+ virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ GetControllerDelegate() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(UserEventService);
diff --git a/chromium/components/sync_user_events/user_event_service_impl.cc b/chromium/components/sync_user_events/user_event_service_impl.cc
index 0dc39bb51ae..2d35370f54e 100644
--- a/chromium/components/sync_user_events/user_event_service_impl.cc
+++ b/chromium/components/sync_user_events/user_event_service_impl.cc
@@ -79,8 +79,9 @@ void UserEventServiceImpl::RecordUserEvent(
RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics));
}
-ModelTypeSyncBridge* UserEventServiceImpl::GetSyncBridge() {
- return bridge_.get();
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+UserEventServiceImpl::GetControllerDelegate() {
+ return bridge_->change_processor()->GetControllerDelegate();
}
bool UserEventServiceImpl::ShouldRecordEvent(
diff --git a/chromium/components/sync_user_events/user_event_service_impl.h b/chromium/components/sync_user_events/user_event_service_impl.h
index 91e61821fca..70ea7636607 100644
--- a/chromium/components/sync_user_events/user_event_service_impl.h
+++ b/chromium/components/sync_user_events/user_event_service_impl.h
@@ -16,7 +16,6 @@
namespace syncer {
-class ModelTypeSyncBridge;
class UserEventSyncBridge;
class UserEventServiceImpl : public UserEventService {
@@ -31,7 +30,8 @@ class UserEventServiceImpl : public UserEventService {
void RecordUserEvent(
std::unique_ptr<sync_pb::UserEventSpecifics> specifics) override;
void RecordUserEvent(const sync_pb::UserEventSpecifics& specifics) override;
- ModelTypeSyncBridge* GetSyncBridge() override;
+ base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate()
+ override;
private:
// Checks dynamic or event specific conditions.
diff --git a/chromium/components/sync_user_events/user_event_service_impl_unittest.cc b/chromium/components/sync_user_events/user_event_service_impl_unittest.cc
index b8a1a49d10e..35d00204018 100644
--- a/chromium/components/sync_user_events/user_event_service_impl_unittest.cc
+++ b/chromium/components/sync_user_events/user_event_service_impl_unittest.cc
@@ -10,9 +10,9 @@
#include "base/test/task_environment.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/test_sync_service.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync_user_events/user_event_sync_bridge.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/sync_user_events/user_event_sync_bridge.cc b/chromium/components/sync_user_events/user_event_sync_bridge.cc
index c11def54e26..91ebc96b9ca 100644
--- a/chromium/components/sync_user_events/user_event_sync_bridge.cc
+++ b/chromium/components/sync_user_events/user_event_sync_bridge.cc
@@ -10,7 +10,7 @@
#include "base/big_endian.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
#include "base/stl_util.h"
diff --git a/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc b/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
index fc6ff248fbc..91323654dcf 100644
--- a/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
+++ b/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
@@ -9,13 +9,13 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "components/sync/model/data_batch.h"
-#include "components/sync/model/mock_model_type_change_processor.h"
-#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/model/mock_model_type_change_processor.h"
+#include "components/sync/test/model/model_type_store_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/system_media_controls/linux/buildflags/buildflags.gni b/chromium/components/system_media_controls/linux/buildflags/buildflags.gni
index cc386dfb06e..4c3bf42b24e 100644
--- a/chromium/components/system_media_controls/linux/buildflags/buildflags.gni
+++ b/chromium/components/system_media_controls/linux/buildflags/buildflags.gni
@@ -7,5 +7,5 @@ import("//build/config/features.gni")
declare_args() {
# Enables Chromium implementation of the MPRIS D-Bus interface for controlling
# media playback. See ../README.md for details.
- use_mpris = is_desktop_linux && use_dbus
+ use_mpris = is_linux && use_dbus
}
diff --git a/chromium/components/system_media_controls/linux/system_media_controls_linux.cc b/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
index c07a7827b15..0d475be5e75 100644
--- a/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
+++ b/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/singleton.h"
#include "base/process/process.h"
#include "base/strings/string_number_conversions.h"
@@ -153,7 +153,7 @@ void SystemMediaControlsLinux::InitializeProperties() {
// org.mpris.MediaPlayer2 interface properties.
auto set_property = [&](const std::string& property_name, auto&& value) {
properties_->SetProperty(kMprisAPIInterfaceName, property_name,
- std::move(value), false);
+ std::forward<decltype(value)>(value), false);
};
set_property("CanQuit", DbusBoolean(false));
set_property("CanRaise", DbusBoolean(false));
@@ -171,7 +171,7 @@ void SystemMediaControlsLinux::InitializeProperties() {
auto set_player_property = [&](const std::string& property_name,
auto&& value) {
properties_->SetProperty(kMprisAPIPlayerInterfaceName, property_name,
- std::move(value), false);
+ std::forward<decltype(value)>(value), false);
};
set_player_property("PlaybackStatus", DbusString("Stopped"));
set_player_property("Rate", DbusDouble(1.0));
diff --git a/chromium/components/thin_webview/internal/compositor_view_impl.cc b/chromium/components/thin_webview/internal/compositor_view_impl.cc
index f4e87c60545..7a4a064c5d4 100644
--- a/chromium/components/thin_webview/internal/compositor_view_impl.cc
+++ b/chromium/components/thin_webview/internal/compositor_view_impl.cc
@@ -24,14 +24,14 @@ namespace {
const int kPixelFormatUnknown = 0;
} // namespace
-jlong JNI_CompositorViewImpl_Init(
- JNIEnv* env,
- const JavaParamRef<jobject>& obj,
- const JavaParamRef<jobject>& jwindow_android) {
+jlong JNI_CompositorViewImpl_Init(JNIEnv* env,
+ const JavaParamRef<jobject>& obj,
+ const JavaParamRef<jobject>& jwindow_android,
+ jint java_background_color) {
ui::WindowAndroid* window_android =
ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android);
- auto compositor_view =
- std::make_unique<CompositorViewImpl>(env, obj, window_android);
+ auto compositor_view = std::make_unique<CompositorViewImpl>(
+ env, obj, window_android, java_background_color);
return reinterpret_cast<intptr_t>(compositor_view.release());
}
@@ -48,13 +48,14 @@ CompositorView* CompositorView::FromJavaObject(
CompositorViewImpl::CompositorViewImpl(JNIEnv* env,
jobject obj,
- ui::WindowAndroid* window_android)
+ ui::WindowAndroid* window_android,
+ int64_t java_background_color)
: obj_(env, obj),
root_layer_(cc::SolidColorLayer::Create()),
current_surface_format_(kPixelFormatUnknown) {
compositor_.reset(content::Compositor::Create(this, window_android));
root_layer_->SetIsDrawable(true);
- root_layer_->SetBackgroundColor(SK_ColorWHITE);
+ root_layer_->SetBackgroundColor(static_cast<SkColor>(java_background_color));
}
CompositorViewImpl::~CompositorViewImpl() = default;
diff --git a/chromium/components/thin_webview/internal/compositor_view_impl.h b/chromium/components/thin_webview/internal/compositor_view_impl.h
index 28a12e52827..509f57a22f4 100644
--- a/chromium/components/thin_webview/internal/compositor_view_impl.h
+++ b/chromium/components/thin_webview/internal/compositor_view_impl.h
@@ -35,7 +35,8 @@ class CompositorViewImpl : public CompositorView,
public:
CompositorViewImpl(JNIEnv* env,
jobject obj,
- ui::WindowAndroid* window_android);
+ ui::WindowAndroid* window_android,
+ int64_t java_background_color);
~CompositorViewImpl() override;
void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& object);
diff --git a/chromium/components/thin_webview/internal/java/src/org/chromium/components/thinwebview/internal/CompositorViewImpl.java b/chromium/components/thin_webview/internal/java/src/org/chromium/components/thinwebview/internal/CompositorViewImpl.java
index f1acb9f37f6..5d208b4a4c6 100644
--- a/chromium/components/thin_webview/internal/java/src/org/chromium/components/thinwebview/internal/CompositorViewImpl.java
+++ b/chromium/components/thin_webview/internal/java/src/org/chromium/components/thinwebview/internal/CompositorViewImpl.java
@@ -45,8 +45,8 @@ public class CompositorViewImpl implements CompositorView {
mContext = context;
mViewConstraints = constraints.clone();
mView = useSurfaceView() ? createSurfaceView() : createTextureView();
- mNativeCompositorViewImpl =
- CompositorViewImplJni.get().init(CompositorViewImpl.this, windowAndroid);
+ mNativeCompositorViewImpl = CompositorViewImplJni.get().init(
+ CompositorViewImpl.this, windowAndroid, constraints.backgroundColor);
}
@Override
@@ -168,7 +168,7 @@ public class CompositorViewImpl implements CompositorView {
@NativeMethods
interface Natives {
- long init(CompositorViewImpl caller, WindowAndroid windowAndroid);
+ long init(CompositorViewImpl caller, WindowAndroid windowAndroid, int backgroundColor);
void destroy(long nativeCompositorViewImpl, CompositorViewImpl caller);
void surfaceCreated(long nativeCompositorViewImpl, CompositorViewImpl caller);
void surfaceDestroyed(long nativeCompositorViewImpl, CompositorViewImpl caller);
diff --git a/chromium/components/thin_webview/java/src/org/chromium/components/thinwebview/ThinWebViewConstraints.java b/chromium/components/thin_webview/java/src/org/chromium/components/thinwebview/ThinWebViewConstraints.java
index d90c27dc07f..6f1cd3aa65f 100644
--- a/chromium/components/thin_webview/java/src/org/chromium/components/thinwebview/ThinWebViewConstraints.java
+++ b/chromium/components/thin_webview/java/src/org/chromium/components/thinwebview/ThinWebViewConstraints.java
@@ -4,6 +4,8 @@
package org.chromium.components.thinwebview;
+import android.graphics.Color;
+
/** Various constraints associated with the thin webview based on the usage. */
public class ThinWebViewConstraints implements Cloneable {
/**
@@ -11,10 +13,16 @@ public class ThinWebViewConstraints implements Cloneable {
*/
public boolean supportsOpacity;
+ /**
+ * Background color of this view.
+ */
+ public int backgroundColor = Color.WHITE;
+
@Override
public ThinWebViewConstraints clone() {
ThinWebViewConstraints clone = new ThinWebViewConstraints();
clone.supportsOpacity = supportsOpacity;
+ clone.backgroundColor = backgroundColor;
return clone;
}
}
diff --git a/chromium/components/timers/alarm_timer_chromeos.cc b/chromium/components/timers/alarm_timer_chromeos.cc
index af98c0650b5..bd3947cd168 100644
--- a/chromium/components/timers/alarm_timer_chromeos.cc
+++ b/chromium/components/timers/alarm_timer_chromeos.cc
@@ -17,6 +17,7 @@
#include "base/memory/ptr_util.h"
#include "base/pending_task.h"
#include "base/task/common/task_annotator.h"
+#include "base/trace_event/task_execution_macros.h"
#include "base/trace_event/trace_event.h"
namespace timers {
diff --git a/chromium/components/timers/alarm_timer_unittest.cc b/chromium/components/timers/alarm_timer_unittest.cc
index c9e681304aa..c8b5224ed42 100644
--- a/chromium/components/timers/alarm_timer_unittest.cc
+++ b/chromium/components/timers/alarm_timer_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/run_loop.h"
diff --git a/chromium/components/tracing/common/trace_startup_config.cc b/chromium/components/tracing/common/trace_startup_config.cc
index 3ad44dc97f1..5da3a216aca 100644
--- a/chromium/components/tracing/common/trace_startup_config.cc
+++ b/chromium/components/tracing/common/trace_startup_config.cc
@@ -66,15 +66,8 @@ TraceStartupConfig* TraceStartupConfig::GetInstance() {
// static
base::trace_event::TraceConfig
TraceStartupConfig::GetDefaultBrowserStartupConfig() {
- base::trace_event::TraceConfig trace_config(
+ return base::trace_event::TraceConfig(
kDefaultStartupCategories, base::trace_event::RECORD_UNTIL_FULL);
- // Filter only browser process events.
- base::trace_event::TraceConfig::ProcessFilterConfig process_config(
- {base::GetCurrentProcId()});
- // First 10k events at start are sufficient to debug startup traces.
- trace_config.SetTraceBufferSizeInEvents(10000);
- trace_config.SetProcessFilterConfig(process_config);
- return trace_config;
}
TraceStartupConfig::TraceStartupConfig() {
diff --git a/chromium/components/translate/core/browser/BUILD.gn b/chromium/components/translate/core/browser/BUILD.gn
index 5198ffb0317..a9c4a78b217 100644
--- a/chromium/components/translate/core/browser/BUILD.gn
+++ b/chromium/components/translate/core/browser/BUILD.gn
@@ -102,6 +102,7 @@ source_set("unit_tests") {
"translate_browser_metrics_unittest.cc",
"translate_language_list_unittest.cc",
"translate_manager_unittest.cc",
+ "translate_metrics_logger_impl_unittest.cc",
"translate_prefs_unittest.cc",
"translate_ranker_impl_unittest.cc",
"translate_script_unittest.cc",
@@ -141,6 +142,8 @@ source_set("test_support") {
"mock_translate_client.h",
"mock_translate_driver.cc",
"mock_translate_driver.h",
+ "mock_translate_metrics_logger.cc",
+ "mock_translate_metrics_logger.h",
"mock_translate_ranker.cc",
"mock_translate_ranker.h",
]
diff --git a/chromium/components/translate/core/common/BUILD.gn b/chromium/components/translate/core/common/BUILD.gn
index 4ca3db7bb0c..b3350b2e28f 100644
--- a/chromium/components/translate/core/common/BUILD.gn
+++ b/chromium/components/translate/core/common/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 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.
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
static_library("common") {
sources = [
@@ -39,3 +42,15 @@ source_set("unit_tests") {
"//url",
]
}
+
+if (is_android) {
+ java_cpp_enum("translate_infobar_event_enum") {
+ sources = [ "translate_constants.h" ]
+ }
+
+ android_library("translate_infobar_event_enum_java") {
+ deps = [ "//third_party/android_deps:androidx_annotation_annotation_java" ]
+
+ srcjar_deps = [ ":translate_infobar_event_enum" ]
+ }
+}
diff --git a/chromium/components/ui_devtools/devtools_server.cc b/chromium/components/ui_devtools/devtools_server.cc
index 6545f64203d..1a97071e313 100644
--- a/chromium/components/ui_devtools/devtools_server.cc
+++ b/chromium/components/ui_devtools/devtools_server.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/components/ui_devtools/tracing_agent.cc b/chromium/components/ui_devtools/tracing_agent.cc
index d843d12f2df..8d32aa59495 100644
--- a/chromium/components/ui_devtools/tracing_agent.cc
+++ b/chromium/components/ui_devtools/tracing_agent.cc
@@ -114,8 +114,7 @@ class TracingAgent::PerfettoTracingSession
on_recording_enabled_callback_ = std::move(on_recording_enabled_callback);
consumer_host_->EnableTracing(
tracing_session_host_.BindNewPipeAndPassReceiver(),
- std::move(tracing_session_client), std::move(perfetto_config),
- tracing::mojom::TracingClientPriority::kUserInitiated);
+ std::move(tracing_session_client), std::move(perfetto_config));
tracing_session_host_.set_disconnect_handler(
base::BindOnce(&PerfettoTracingSession::OnTracingSessionFailed,
@@ -128,10 +127,9 @@ class TracingAgent::PerfettoTracingSession
}
}
- void OnTracingDisabled() override {
+ void OnTracingDisabled(bool) override {
// Since we're converting the tracing data to JSON, we will receive the
// tracing data via ConsumerHost::DisableTracingAndEmitJson().
- return;
}
void DisableTracing(
@@ -201,7 +199,11 @@ class TracingAgent::PerfettoTracingSession
last_config_for_perfetto_ = std::move(processfilter_stripped_config);
#endif
- return tracing::GetDefaultPerfettoConfig(chrome_config);
+ return tracing::GetDefaultPerfettoConfig(
+ chrome_config,
+ /*privacy_filtering_enabled=*/false,
+ /*convert_to_legacy_json=*/false,
+ perfetto::protos::gen::ChromeConfig::USER_INITIATED);
}
void OnTracingSessionFailed() {
diff --git a/chromium/components/ui_devtools/views/element_utility.cc b/chromium/components/ui_devtools/views/element_utility.cc
index d3463b1d945..67813479e02 100644
--- a/chromium/components/ui_devtools/views/element_utility.cc
+++ b/chromium/components/ui_devtools/views/element_utility.cc
@@ -34,6 +34,10 @@ void AppendLayerPropertiesMatchedStyle(
const auto offset = layer->GetSubpixelOffset();
if (!offset.IsZero())
ret->emplace_back("layer-subpixel-offset", offset.ToString());
+ const auto& rounded_corners = layer->rounded_corner_radii();
+ if (!rounded_corners.IsEmpty())
+ ret->emplace_back("layer-rounded-corners", rounded_corners.ToString());
+
const ui::Layer::ShapeRects* alpha_shape_bounds = layer->alpha_shape();
if (alpha_shape_bounds && alpha_shape_bounds->size()) {
gfx::Rect bounding_box;
@@ -41,6 +45,7 @@ void AppendLayerPropertiesMatchedStyle(
bounding_box.Union(shape_bound);
ret->emplace_back("alpha-shape-bounding-box", bounding_box.ToString());
}
+
const cc::Layer* cc_layer = layer->cc_layer_for_testing();
if (cc_layer) {
// Property trees must be updated in order to get valid render surface
diff --git a/chromium/components/ui_devtools/views/view_element.cc b/chromium/components/ui_devtools/views/view_element.cc
index 6115ce97b8e..bee4ca73d46 100644
--- a/chromium/components/ui_devtools/views/view_element.cc
+++ b/chromium/components/ui_devtools/views/view_element.cc
@@ -10,6 +10,7 @@
#include "components/ui_devtools/ui_element_delegate.h"
#include "components/ui_devtools/views/element_utility.h"
#include "ui/gfx/color_utils.h"
+#include "ui/views/metadata/metadata_types.h"
#include "ui/views/widget/widget.h"
namespace ui_devtools {
@@ -119,10 +120,12 @@ ViewElement::GetCustomPropertiesForMatchedStyle() const {
base::UTF16ToUTF8((*member)->GetValueAsString(view_)), &color))
class_properties.emplace_back("--" + (*member)->member_name(),
color_utils::SkColorToRgbaString(color));
- } else
+ } else if (!!((*member)->GetPropertyFlags() &
+ views::metadata::PropertyFlags::kSerializable)) {
class_properties.emplace_back(
(*member)->member_name(),
base::UTF16ToUTF8((*member)->GetValueAsString(view_)));
+ }
if (member.IsLastMember()) {
ret.emplace_back(member.GetCurrentCollectionName(), class_properties);
@@ -187,6 +190,8 @@ bool ViewElement::SetPropertiesFromString(const std::string& text) {
}
}
+ DCHECK(!!(member->GetPropertyFlags() &
+ views::metadata::PropertyFlags::kSerializable));
member->SetValueAsString(view_, base::UTF8ToUTF16(property_value));
property_set = true;
}
diff --git a/chromium/components/ui_devtools/views/view_element_unittest.cc b/chromium/components/ui_devtools/views/view_element_unittest.cc
index accd6492cb3..588080eb21e 100644
--- a/chromium/components/ui_devtools/views/view_element_unittest.cc
+++ b/chromium/components/ui_devtools/views/view_element_unittest.cc
@@ -7,6 +7,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/ui_devtools/Protocol.h"
#include "components/ui_devtools/ui_devtools_unittest_utils.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/test/views_test_base.h"
namespace ui_devtools {
diff --git a/chromium/components/ukm/content/source_url_recorder_test.cc b/chromium/components/ukm/content/source_url_recorder_test.cc
index 475228979bd..04f1a50c73f 100644
--- a/chromium/components/ukm/content/source_url_recorder_test.cc
+++ b/chromium/components/ukm/content/source_url_recorder_test.cc
@@ -10,6 +10,7 @@
#include "content/public/test/test_renderer_host.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/ukm/source.pb.h"
#include "url/gurl.h"
@@ -66,13 +67,13 @@ TEST_F(SourceUrlRecorderWebContentsObserverTest, InitialUrl) {
size_t document_type_source_count = 0;
for (const auto& kv : sources) {
if (ukm::GetSourceIdType(kv.first) ==
- base::UkmSourceId::Type::NAVIGATION_ID) {
+ ukm::SourceIdObj::Type::NAVIGATION_ID) {
// The navigation source has both URLs.
EXPECT_EQ(initial_url, kv.second->urls().front());
EXPECT_EQ(final_url, kv.second->urls().back());
navigation_type_source_count++;
}
- if (ukm::GetSourceIdType(kv.first) == base::UkmSourceId::Type::DEFAULT) {
+ if (ukm::GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::DEFAULT) {
// The document source has the final URL which is one set on the
// committed document.
EXPECT_EQ(final_url, kv.second->urls().front());
@@ -129,8 +130,7 @@ TEST_F(SourceUrlRecorderWebContentsObserverTest, SameDocumentNavigation) {
for (auto& kv : test_ukm_recorder_.GetSources()) {
// Populate protos from the navigation sources.
- if (ukm::GetSourceIdType(kv.first) !=
- base::UkmSourceId::Type::NAVIGATION_ID)
+ if (ukm::GetSourceIdType(kv.first) != ukm::SourceIdObj::Type::NAVIGATION_ID)
continue;
if (kv.second->url() == url1) {
diff --git a/chromium/components/ukm/debug/ukm_internals.html b/chromium/components/ukm/debug/ukm_internals.html
index 7f74dd63429..054c88fd0b5 100644
--- a/chromium/components/ukm/debug/ukm_internals.html
+++ b/chromium/components/ukm/debug/ukm_internals.html
@@ -5,6 +5,7 @@
<html lang="en">
<meta charset="utf-8">
<script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/js/util.js"></script>
<if expr="is_ios">
diff --git a/chromium/components/ukm/observers/history_delete_observer.cc b/chromium/components/ukm/observers/history_delete_observer.cc
index bbc71a09c9a..55dae084cfe 100644
--- a/chromium/components/ukm/observers/history_delete_observer.cc
+++ b/chromium/components/ukm/observers/history_delete_observer.cc
@@ -13,7 +13,7 @@ HistoryDeleteObserver::~HistoryDeleteObserver() {}
void HistoryDeleteObserver::ObserveServiceForDeletions(
history::HistoryService* history_service) {
if (history_service)
- history_observer_.Add(history_service);
+ history_observations_.AddObservation(history_service);
}
void HistoryDeleteObserver::OnURLsDeleted(
@@ -25,7 +25,7 @@ void HistoryDeleteObserver::OnURLsDeleted(
void HistoryDeleteObserver::HistoryServiceBeingDeleted(
history::HistoryService* history_service) {
- history_observer_.Remove(history_service);
+ history_observations_.RemoveObservation(history_service);
}
} // namespace ukm
diff --git a/chromium/components/ukm/observers/history_delete_observer.h b/chromium/components/ukm/observers/history_delete_observer.h
index c27efadf99b..7a96bc380db 100644
--- a/chromium/components/ukm/observers/history_delete_observer.h
+++ b/chromium/components/ukm/observers/history_delete_observer.h
@@ -7,7 +7,7 @@
#include <set>
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
@@ -34,8 +34,9 @@ class HistoryDeleteObserver : public history::HistoryServiceObserver {
private:
// Tracks observed history services, for cleanup.
- ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
- history_observer_{this};
+ base::ScopedMultiSourceObservation<history::HistoryService,
+ history::HistoryServiceObserver>
+ history_observations_{this};
DISALLOW_COPY_AND_ASSIGN(HistoryDeleteObserver);
};
diff --git a/chromium/components/ukm/observers/ukm_consent_state_observer.cc b/chromium/components/ukm/observers/ukm_consent_state_observer.cc
index e67a74bf46f..2c9da4b4d69 100644
--- a/chromium/components/ukm/observers/ukm_consent_state_observer.cc
+++ b/chromium/components/ukm/observers/ukm_consent_state_observer.cc
@@ -18,7 +18,7 @@ using unified_consent::UrlKeyedDataCollectionConsentHelper;
namespace ukm {
-UkmConsentStateObserver::UkmConsentStateObserver() : sync_observer_(this) {}
+UkmConsentStateObserver::UkmConsentStateObserver() = default;
UkmConsentStateObserver::~UkmConsentStateObserver() {
for (const auto& entry : consent_helpers_) {
@@ -55,7 +55,7 @@ void UkmConsentStateObserver::StartObserving(syncer::SyncService* sync_service,
consent_helper->AddObserver(this);
consent_helpers_[sync_service] = std::move(consent_helper);
- sync_observer_.Add(sync_service);
+ sync_observations_.AddObservation(sync_service);
UpdateUkmAllowedForAllProfiles(false);
}
@@ -149,7 +149,8 @@ void UkmConsentStateObserver::OnSyncShutdown(syncer::SyncService* sync) {
found->second->RemoveObserver(this);
consent_helpers_.erase(found);
}
- sync_observer_.Remove(sync);
+ DCHECK(sync_observations_.IsObservingSource(sync));
+ sync_observations_.RemoveObservation(sync);
previous_states_.erase(sync);
UpdateUkmAllowedForAllProfiles(/*must_purge=*/false);
}
diff --git a/chromium/components/ukm/observers/ukm_consent_state_observer.h b/chromium/components/ukm/observers/ukm_consent_state_observer.h
index 4d214765b1c..258f46a85d9 100644
--- a/chromium/components/ukm/observers/ukm_consent_state_observer.h
+++ b/chromium/components/ukm/observers/ukm_consent_state_observer.h
@@ -7,7 +7,7 @@
#include <map>
-#include "base/scoped_observer.h"
+#include "base/scoped_multi_source_observation.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_service_observer.h"
#include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
@@ -69,8 +69,9 @@ class UkmConsentStateObserver
bool CheckPreviousStatesAllowExtensionUkm();
// Tracks observed sync services, for cleanup.
- ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
- sync_observer_;
+ base::ScopedMultiSourceObservation<syncer::SyncService,
+ syncer::SyncServiceObserver>
+ sync_observations_{this};
// State data about profiles that we need to remember.
struct ProfileState {
diff --git a/chromium/components/ukm/ukm_recorder_impl.cc b/chromium/components/ukm/ukm_recorder_impl.cc
index 0cf4bb4ff63..0871b25e50c 100644
--- a/chromium/components/ukm/ukm_recorder_impl.cc
+++ b/chromium/components/ukm/ukm_recorder_impl.cc
@@ -98,6 +98,24 @@ void LogEventHashAsUmaHistogram(const std::string& histogram_name,
event_hash & 0x7fffffff);
}
+// Artificially inflates counts of some event types reported to UMA histogram.
+// TODO(crbug/1137922): remove this artificial inflation of counts after alerts
+// are tested.
+void MaybeInflateHistogramCount(const std::string& histogram_name,
+ uint64_t event_hash) {
+ const static std::map<uint64_t, size_t> event_hash_to_multipliers = {
+ {builders::Media_BasicPlayback::kEntryNameHash, 4},
+ {builders::RendererSchedulerTask::kEntryNameHash, 2},
+ {builders::HistoryNavigation::kEntryNameHash, 99},
+ };
+
+ auto iter = event_hash_to_multipliers.find(event_hash);
+ if (iter != event_hash_to_multipliers.end()) {
+ for (size_t i = 0; i < iter->second; ++i)
+ LogEventHashAsUmaHistogram(histogram_name, event_hash);
+ }
+}
+
enum class DroppedDataReason {
NOT_DROPPED = 0,
RECORDING_DISABLED = 1,
@@ -354,9 +372,9 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
for (const auto& kv : recordings_.sources) {
// Don't keep sources of these types after current report because their
// entries are logged only at source creation time.
- if (GetSourceIdType(kv.first) == base::UkmSourceId::Type::APP_ID ||
- GetSourceIdType(kv.first) == base::UkmSourceId::Type::HISTORY_ID ||
- GetSourceIdType(kv.first) == base::UkmSourceId::Type::WEBAPK_ID ||
+ if (GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::APP_ID ||
+ GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::HISTORY_ID ||
+ GetSourceIdType(kv.first) == ukm::SourceIdObj::Type::WEBAPK_ID ||
GetSourceIdType(kv.first) == SourceIdType::PAYMENT_APP_ID) {
MarkSourceForDeletion(kv.first);
}
@@ -378,7 +396,7 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
if (!base::Contains(source_ids_seen, kv.first)) {
continue;
} else {
- // Source of base::UkmSourceId::Type::DEFAULT type will not be kept
+ // Source of ukm::SourceIdObj::Type::DEFAULT type will not be kept
// after entries are logged.
MarkSourceForDeletion(kv.first);
}
@@ -761,6 +779,8 @@ void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
// entry counts.
LogEventHashAsUmaHistogram("UKM.Entries.Recorded.ByEntryHash",
entry->event_hash);
+ MaybeInflateHistogramCount("UKM.Entries.Recorded.ByEntryHash",
+ entry->event_hash);
recordings_.entries.push_back(std::move(entry));
}
diff --git a/chromium/components/ukm/ukm_recorder_impl_unittest.cc b/chromium/components/ukm/ukm_recorder_impl_unittest.cc
index 15d9f90f31e..187ea182590 100644
--- a/chromium/components/ukm/ukm_recorder_impl_unittest.cc
+++ b/chromium/components/ukm/ukm_recorder_impl_unittest.cc
@@ -6,13 +6,12 @@
#include "base/bind.h"
#include "base/metrics/metrics_hashes.h"
-#include "base/metrics/ukm_source_id.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_entry_builder.h"
#include "services/metrics/public/cpp/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/ukm/report.pb.h"
#include "url/gurl.h"
diff --git a/chromium/components/ukm/ukm_reporting_service.cc b/chromium/components/ukm/ukm_reporting_service.cc
index 8beedce934d..3f32214b6db 100644
--- a/chromium/components/ukm/ukm_reporting_service.cc
+++ b/chromium/components/ukm/ukm_reporting_service.cc
@@ -13,9 +13,10 @@
#include "base/metrics/histogram_macros.h"
#include "components/metrics/metrics_service_client.h"
#include "components/prefs/pref_registry_simple.h"
-#include "components/ukm/unsent_log_store_metrics_impl.h"
#include "components/ukm/ukm_pref_names.h"
#include "components/ukm/ukm_service.h"
+#include "components/ukm/unsent_log_store_metrics_impl.h"
+#include "third_party/zlib/google/compression_utils.h"
namespace ukm {
@@ -106,10 +107,40 @@ void UkmReportingService::LogResponseOrErrorCode(int response_code,
response_code >= 0 ? response_code : error_code);
}
-void UkmReportingService::LogSuccess(size_t log_size) {
+void UkmReportingService::LogSuccessLogSize(size_t log_size) {
UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size / 1024);
}
+void UkmReportingService::LogSuccessMetadata(const std::string& staged_log) {
+ // Recover the report from the compressed staged log.
+ std::string uncompressed_log_data;
+ bool uncompress_successful =
+ compression::GzipUncompress(staged_log, &uncompressed_log_data);
+ DCHECK(uncompress_successful);
+ Report report;
+ report.ParseFromString(uncompressed_log_data);
+
+ // Log the relative size of the report with relevant UKM data omitted. This
+ // helps us to estimate the bandwidth usage of logs upload that is not
+ // directly attributed to UKM data, for example the system profile info.
+ // Note that serialized logs are further compressed before upload, thus the
+ // percentages here are not the exact percentage of bandwidth they ended up
+ // taking.
+ std::string log_without_ukm_data;
+ report.clear_sources();
+ report.clear_source_counts();
+ report.clear_entries();
+ report.clear_aggregates();
+ report.SerializeToString(&log_without_ukm_data);
+
+ int non_ukm_percentage =
+ log_without_ukm_data.length() * 100 / uncompressed_log_data.length();
+ DCHECK_GE(non_ukm_percentage, 0);
+ DCHECK_LE(non_ukm_percentage, 100);
+ base::UmaHistogramPercentage("UKM.ReportSize.NonUkmPercentage",
+ non_ukm_percentage);
+}
+
void UkmReportingService::LogLargeRejection(size_t log_size) {}
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_reporting_service.h b/chromium/components/ukm/ukm_reporting_service.h
index c011f0fe18e..7abd15670fb 100644
--- a/chromium/components/ukm/ukm_reporting_service.h
+++ b/chromium/components/ukm/ukm_reporting_service.h
@@ -12,8 +12,9 @@
#include <string>
#include "base/macros.h"
-#include "components/metrics/unsent_log_store.h"
#include "components/metrics/reporting_service.h"
+#include "components/metrics/unsent_log_store.h"
+#include "third_party/metrics_proto/ukm/report.pb.h"
class PrefService;
class PrefRegistrySimple;
@@ -56,7 +57,8 @@ class UkmReportingService : public metrics::ReportingService {
void LogResponseOrErrorCode(int response_code,
int error_code,
bool was_https) override;
- void LogSuccess(size_t log_size) override;
+ void LogSuccessLogSize(size_t log_size) override;
+ void LogSuccessMetadata(const std::string& staged_log) override;
void LogLargeRejection(size_t log_size) override;
metrics::UnsentLogStore unsent_log_store_;
diff --git a/chromium/components/ukm/ukm_service.cc b/chromium/components/ukm/ukm_service.cc
index 4750e7893f0..cab3d7c51d5 100644
--- a/chromium/components/ukm/ukm_service.cc
+++ b/chromium/components/ukm/ukm_service.cc
@@ -13,6 +13,7 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -153,11 +154,8 @@ void PurgeExtensionDataFromUnsentLogStore(
},
report.entries(), report.mutable_entries());
- std::string reserialized_log_data;
- report.SerializeToString(&reserialized_log_data);
- // This allows catching errors with bad UKM serialization we've seen before
- // that would otherwise only be noticed on the server.
- DCHECK(UkmService::LogCanBeParsed(reserialized_log_data));
+ std::string reserialized_log_data =
+ UkmService::SerializeReportProtoToString(&report);
// Replace the compressed log in the store by its filtered version.
const std::string old_compressed_log_data =
@@ -181,13 +179,23 @@ bool UkmService::LogCanBeParsed(const std::string& serialized_data) {
bool report_parse_successful = report.ParseFromString(serialized_data);
if (!report_parse_successful)
return false;
- // Make sure the reserialzed log from this |report| matches the input
+ // Make sure the reserialized log from this |report| matches the input
// |serialized_data|.
std::string reserialized_from_report;
report.SerializeToString(&reserialized_from_report);
return reserialized_from_report == serialized_data;
}
+std::string UkmService::SerializeReportProtoToString(Report* report) {
+ std::string serialized_full_log;
+ report->SerializeToString(&serialized_full_log);
+
+ // This allows catching errors with bad UKM serialization we've seen before
+ // that would otherwise only be noticed on the server.
+ DCHECK(UkmService::LogCanBeParsed(serialized_full_log));
+ return serialized_full_log;
+}
+
UkmService::UkmService(PrefService* pref_service,
metrics::MetricsServiceClient* client,
std::unique_ptr<metrics::UkmDemographicMetricsProvider>
@@ -354,8 +362,8 @@ void UkmService::RegisterPrefs(PrefRegistrySimple* registry) {
void UkmService::StartInitTask() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(1) << "UkmService::StartInitTask";
- metrics_providers_.AsyncInit(base::Bind(&UkmService::FinishedInitTask,
- self_ptr_factory_.GetWeakPtr()));
+ metrics_providers_.AsyncInit(base::BindOnce(&UkmService::FinishedInitTask,
+ self_ptr_factory_.GetWeakPtr()));
}
void UkmService::FinishedInitTask() {
@@ -418,11 +426,8 @@ void UkmService::BuildAndStoreLog() {
AddSyncedUserNoiseBirthYearAndGenderToReport(&report);
- std::string serialized_log;
- report.SerializeToString(&serialized_log);
- // This allows catching errors with bad UKM serialization we've seen before
- // that would otherwise only be noticed on the server.
- DCHECK(LogCanBeParsed(serialized_log));
+ std::string serialized_log =
+ UkmService::SerializeReportProtoToString(&report);
reporting_service_.ukm_log_store()->StoreLog(serialized_log, base::nullopt);
}
diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h
index 37d6ab19591..3355ddf90a5 100644
--- a/chromium/components/ukm/ukm_service.h
+++ b/chromium/components/ukm/ukm_service.h
@@ -114,12 +114,15 @@ class UkmService : public UkmRecorderImpl {
// Enables adding the synced user's noised birth year and gender to the UKM
// report. For more details, see doc of metrics::DemographicMetricsProvider in
- // components/metrics/demographic_metrics_provider.h.
+ // components/metrics/demographics/demographic_metrics_provider.h.
static const base::Feature kReportUserNoisedUserBirthYearAndGender;
- // Makes sure that the serialized ukm report can be parsed.
+ // Makes sure that the serialized UKM report can be parsed.
static bool LogCanBeParsed(const std::string& serialized_data);
+ // Serializes the input UKM report into a string and validates it.
+ static std::string SerializeReportProtoToString(Report* report);
+
private:
friend ::metrics::UkmBrowserTestBase;
friend ::ukm::UkmTestHelper;
@@ -158,7 +161,7 @@ class UkmService : public UkmRecorderImpl {
// Adds the user's birth year and gender to the UKM |report| only if (1) the
// provider is registered and (2) the feature is enabled. For more details,
// see doc of metrics::DemographicMetricsProvider in
- // components/metrics/demographic_metrics_provider.h.
+ // components/metrics/demographics/demographic_metrics_provider.h.
void AddSyncedUserNoiseBirthYearAndGenderToReport(Report* report);
void SetInitializationCompleteCallbackForTesting(base::OnceClosure callback);
diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc
index 7d90ad8074a..c4e916a68d7 100644
--- a/chromium/components/ukm/ukm_service_unittest.cc
+++ b/chromium/components/ukm/ukm_service_unittest.cc
@@ -38,6 +38,7 @@
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_entry_builder.h"
#include "services/metrics/public/cpp/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/ukm/report.pb.h"
@@ -62,7 +63,7 @@ std::string Entry1And2Whitelist() {
}
SourceId ConvertSourceIdToWhitelistedType(SourceId id, SourceIdType type) {
- return base::UkmSourceId::FromOtherId(id, type).ToInt64();
+ return ukm::SourceIdObj::FromOtherId(id, type).ToInt64();
}
// A small shim exposing UkmRecorder methods to tests.
diff --git a/chromium/components/unified_consent/unified_consent_service.cc b/chromium/components/unified_consent/unified_consent_service.cc
index d5a12a362c9..2a92611ab0a 100644
--- a/chromium/components/unified_consent/unified_consent_service.cc
+++ b/chromium/components/unified_consent/unified_consent_service.cc
@@ -6,7 +6,7 @@
#include "base/check_op.h"
#include "base/metrics/histogram_macros.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chromium/components/update_client/component.cc b/chromium/components/update_client/component.cc
index c014a3011b0..5973357da2a 100644
--- a/chromium/components/update_client/component.cc
+++ b/chromium/components/update_client/component.cc
@@ -8,8 +8,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -386,9 +386,6 @@ void Component::SetUpdateCheckResult(
if (result)
SetParseResult(result.value());
-
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, std::move(update_check_complete_));
}
void Component::NotifyWait() {
@@ -593,6 +590,23 @@ void Component::StateNew::DoHandle() {
auto& component = State::component();
if (component.crx_component()) {
TransitionState(std::make_unique<StateChecking>(&component));
+
+ // Notify that the component is being checked for updates after the
+ // transition to `StateChecking` occurs. This event indicates the start
+ // of the update check. The component receives the update check results when
+ // the update checks completes, and after that, `UpdateEngine` invokes the
+ // function `StateChecking::DoHandle` to transition the component out of
+ // the `StateChecking`. The current design allows for notifying observers
+ // on state transitions but it does not allow such notifications when a
+ // new state is entered. Hence, posting the task below is a workaround for
+ // this design oversight.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ [](Component& component) {
+ component.NotifyObservers(Events::COMPONENT_CHECKING_FOR_UPDATES);
+ },
+ std::ref(component)));
} else {
component.error_code_ = static_cast<int>(Error::CRX_NOT_FOUND);
component.error_category_ = ErrorCategory::kService;
@@ -601,47 +615,37 @@ void Component::StateNew::DoHandle() {
}
Component::StateChecking::StateChecking(Component* component)
- : State(component, ComponentState::kChecking) {}
+ : State(component, ComponentState::kChecking) {
+ component->last_check_ = base::TimeTicks::Now();
+}
Component::StateChecking::~StateChecking() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-// Unlike how other states are handled, this function does not change the
-// state right away. The state transition happens when the UpdateChecker
-// calls Component::UpdateCheckComplete and |update_check_complete_| is invoked.
-// This is an artifact of how multiple components must be checked for updates
-// together but the state machine defines the transitions for one component
-// at a time.
void Component::StateChecking::DoHandle() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto& component = State::component();
DCHECK(component.crx_component());
- component.last_check_ = base::TimeTicks::Now();
- component.update_check_complete_ = base::BindOnce(
- &Component::StateChecking::UpdateCheckComplete, base::Unretained(this));
-
- component.NotifyObservers(Events::COMPONENT_CHECKING_FOR_UPDATES);
-}
+ if (component.error_code_) {
+ TransitionState(std::make_unique<StateUpdateError>(&component));
+ return;
+ }
-void Component::StateChecking::UpdateCheckComplete() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto& component = State::component();
- if (!component.error_code_) {
- if (component.status_ == "ok") {
- TransitionState(std::make_unique<StateCanUpdate>(&component));
- return;
- }
+ if (component.status_ == "ok") {
+ TransitionState(std::make_unique<StateCanUpdate>(&component));
+ return;
+ }
- if (component.status_ == "noupdate") {
- if (component.action_run_.empty())
- TransitionState(std::make_unique<StateUpToDate>(&component));
- else
- TransitionState(std::make_unique<StateRun>(&component));
- return;
+ if (component.status_ == "noupdate") {
+ if (component.action_run_.empty()) {
+ TransitionState(std::make_unique<StateUpToDate>(&component));
+ } else {
+ TransitionState(std::make_unique<StateRun>(&component));
}
+ return;
}
TransitionState(std::make_unique<StateUpdateError>(&component));
diff --git a/chromium/components/update_client/component.h b/chromium/components/update_client/component.h
index 1b371dad2ac..46b38607d87 100644
--- a/chromium/components/update_client/component.h
+++ b/chromium/components/update_client/component.h
@@ -206,8 +206,6 @@ class Component {
private:
// State overrides.
void DoHandle() override;
-
- void UpdateCheckComplete();
};
class StateUpdateError : public State {
@@ -489,8 +487,6 @@ class Component {
std::unique_ptr<State> state_;
const UpdateContext& update_context_;
- base::OnceClosure update_check_complete_;
-
ComponentState previous_state_ = ComponentState::kLastStatus;
// True if this component has reached a final state because all its states
diff --git a/chromium/components/update_client/crx_downloader_unittest.cc b/chromium/components/update_client/crx_downloader_unittest.cc
index b2a98b78027..5ffb3373b07 100644
--- a/chromium/components/update_client/crx_downloader_unittest.cc
+++ b/chromium/components/update_client/crx_downloader_unittest.cc
@@ -12,7 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
diff --git a/chromium/components/update_client/net/url_loader_post_interceptor.cc b/chromium/components/update_client/net/url_loader_post_interceptor.cc
index f6a48340963..778307197b4 100644
--- a/chromium/components/update_client/net/url_loader_post_interceptor.cc
+++ b/chromium/components/update_client/net/url_loader_post_interceptor.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "components/update_client/test_configurator.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
diff --git a/chromium/components/update_client/ping_manager_unittest.cc b/chromium/components/update_client/ping_manager_unittest.cc
index 1d5994c50c3..b38196f9f74 100644
--- a/chromium/components/update_client/ping_manager_unittest.cc
+++ b/chromium/components/update_client/ping_manager_unittest.cc
@@ -103,7 +103,7 @@ void PingManagerTest::PingSentCallback(int error, const std::string& response) {
scoped_refptr<UpdateContext> PingManagerTest::MakeMockUpdateContext() const {
return base::MakeRefCounted<UpdateContext>(
config_, false, std::vector<std::string>(),
- UpdateClient::CrxDataCallback(), UpdateClient::CrxStateChangeCallback(),
+ UpdateClient::CrxStateChangeCallback(),
UpdateEngine::NotifyObserversCallback(), UpdateEngine::Callback(),
nullptr);
}
diff --git a/chromium/components/update_client/request_sender.cc b/chromium/components/update_client/request_sender.cc
index 9e8fee89862..3fc7cf7aea2 100644
--- a/chromium/components/update_client/request_sender.cc
+++ b/chromium/components/update_client/request_sender.cc
@@ -8,7 +8,7 @@
#include "base/base64.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
diff --git a/chromium/components/update_client/update_checker_unittest.cc b/chromium/components/update_client/update_checker_unittest.cc
index 7717154d9ba..8ed5ffb688f 100644
--- a/chromium/components/update_client/update_checker_unittest.cc
+++ b/chromium/components/update_client/update_checker_unittest.cc
@@ -21,7 +21,7 @@
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
@@ -227,7 +227,7 @@ void UpdateCheckerTest::UpdateCheckComplete(
scoped_refptr<UpdateContext> UpdateCheckerTest::MakeMockUpdateContext() const {
return base::MakeRefCounted<UpdateContext>(
config_, false, std::vector<std::string>(),
- UpdateClient::CrxDataCallback(), UpdateClient::CrxStateChangeCallback(),
+ UpdateClient::CrxStateChangeCallback(),
UpdateEngine::NotifyObserversCallback(), UpdateEngine::Callback(),
nullptr);
}
diff --git a/chromium/components/update_client/update_client.h b/chromium/components/update_client/update_client.h
index be4f70211ba..f462b297243 100644
--- a/chromium/components/update_client/update_client.h
+++ b/chromium/components/update_client/update_client.h
@@ -331,6 +331,12 @@ using Callback = base::OnceCallback<void(Error error)>;
// the browser process has gone single-threaded.
class UpdateClient : public base::RefCountedThreadSafe<UpdateClient> {
public:
+ // Returns `CrxComponent` instances corresponding to the component ids
+ // passed as an argument to the callback. The order of components in the input
+ // and output vectors must match. If the instance of the `CrxComponent` is not
+ // available for some reason, implementors of the callback must not skip
+ // skip the component, and instead, they must insert a `nullopt` value in
+ // the output vector.
using CrxDataCallback =
base::OnceCallback<std::vector<base::Optional<CrxComponent>>(
const std::vector<std::string>& ids)>;
diff --git a/chromium/components/update_client/update_client_errors.h b/chromium/components/update_client/update_client_errors.h
index 1cf13a8c05f..61d70b20c91 100644
--- a/chromium/components/update_client/update_client_errors.h
+++ b/chromium/components/update_client/update_client_errors.h
@@ -18,6 +18,7 @@ enum class Error {
UPDATE_CHECK_ERROR = 5,
CRX_NOT_FOUND = 6,
INVALID_ARGUMENT = 7,
+ BAD_CRX_DATA_CALLBACK = 8,
MAX_VALUE,
};
diff --git a/chromium/components/update_client/update_client_unittest.cc b/chromium/components/update_client/update_client_unittest.cc
index 31b6a55c2b2..5907ba967e8 100644
--- a/chromium/components/update_client/update_client_unittest.cc
+++ b/chromium/components/update_client/update_client_unittest.cc
@@ -4587,4 +4587,60 @@ TEST_F(UpdateClientTest, CustomAttributeNoUpdate) {
EXPECT_EQ(1, observer.calls);
}
+
+// Tests the scenario where `CrxDataCallback` returns a vector whose elements
+// don't include a value for one of the component ids specified by the `ids`
+// parameter of the `UpdateClient::Update` function. Expects the completion
+// callback to include a specific error, and no other events and pings be
+// generated, since the update engine rejects the UpdateClient::Update call.
+TEST_F(UpdateClientTest, BadCrxDataCallback) {
+ class CompletionCallbackMock {
+ public:
+ static void Callback(base::OnceClosure quit_closure, Error error) {
+ EXPECT_EQ(Error::BAD_CRX_DATA_CALLBACK, error);
+ std::move(quit_closure).Run();
+ }
+ };
+
+ class MockPingManager : public MockPingManagerImpl {
+ public:
+ explicit MockPingManager(scoped_refptr<Configurator> config)
+ : MockPingManagerImpl(config) {}
+
+ protected:
+ ~MockPingManager() override { EXPECT_TRUE(ping_data().empty()); }
+ };
+
+ scoped_refptr<UpdateClient> update_client =
+ base::MakeRefCounted<UpdateClientImpl>(
+ config(), base::MakeRefCounted<MockPingManager>(config()),
+ UpdateChecker::Factory{});
+
+ MockObserver observer;
+
+ std::vector<CrxUpdateItem> items;
+ auto receiver = base::MakeRefCounted<MockCrxStateChangeReceiver>();
+ EXPECT_CALL(*receiver, Receive(_))
+ .WillRepeatedly(
+ [&items](const CrxUpdateItem& item) { items.push_back(item); });
+
+ update_client->AddObserver(&observer);
+ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
+ "gjpmebpgbhcamgdgjcmnjfhggjpgcimm"};
+ // The `CrxDataCallback` argument only returns a value for the first
+ // component id. This means that its result is ill formed, and the `Update`
+ // call completes with an error.
+ update_client->Update(
+ ids, base::BindOnce([](const std::vector<std::string>& ids) {
+ EXPECT_EQ(ids.size(), size_t{2});
+ return std::vector<base::Optional<CrxComponent>>{base::nullopt};
+ }),
+ base::BindRepeating(&MockCrxStateChangeReceiver::Receive, receiver), true,
+ base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
+ RunThreads();
+
+ EXPECT_TRUE(items.empty());
+ update_client->RemoveObserver(&observer);
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/update_engine.cc b/chromium/components/update_client/update_engine.cc
index 57816ebc2f3..0a4c2d615ea 100644
--- a/chromium/components/update_client/update_engine.cc
+++ b/chromium/components/update_client/update_engine.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/guid.h"
#include "base/location.h"
@@ -32,7 +33,6 @@ UpdateContext::UpdateContext(
scoped_refptr<Configurator> config,
bool is_foreground,
const std::vector<std::string>& ids,
- UpdateClient::CrxDataCallback crx_data_callback,
UpdateClient::CrxStateChangeCallback crx_state_change_callback,
const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
UpdateEngine::Callback callback,
@@ -41,7 +41,6 @@ UpdateContext::UpdateContext(
is_foreground(is_foreground),
enabled_component_updates(config->EnabledComponentUpdates()),
ids(ids),
- crx_data_callback(std::move(crx_data_callback)),
crx_state_change_callback(crx_state_change_callback),
notify_observers_callback(notify_observers_callback),
callback(std::move(callback)),
@@ -93,22 +92,25 @@ void UpdateEngine::Update(
return;
}
+ // Calls out to get the corresponding CrxComponent data for the components.
+ const std::vector<base::Optional<CrxComponent>> crx_components =
+ std::move(crx_data_callback).Run(ids);
+ if (crx_components.size() < ids.size()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), Error::BAD_CRX_DATA_CALLBACK));
+ return;
+ }
+
const auto update_context = base::MakeRefCounted<UpdateContext>(
- config_, is_foreground, ids, std::move(crx_data_callback),
- crx_state_change_callback, notify_observers_callback_,
- std::move(callback), metadata_.get());
+ config_, is_foreground, ids, crx_state_change_callback,
+ notify_observers_callback_, std::move(callback), metadata_.get());
DCHECK(!update_context->session_id.empty());
const auto result = update_contexts_.insert(
std::make_pair(update_context->session_id, update_context));
DCHECK(result.second);
- // Calls out to get the corresponding CrxComponent data for the CRXs in this
- // update context.
- const auto crx_components =
- std::move(update_context->crx_data_callback).Run(update_context->ids);
- DCHECK_EQ(update_context->ids.size(), crx_components.size());
-
for (size_t i = 0; i != update_context->ids.size(); ++i) {
const auto& id = update_context->ids[i];
@@ -139,33 +141,6 @@ void UpdateEngine::Update(
return;
}
- for (const auto& id : update_context->components_to_check_for_updates)
- update_context->components[id]->Handle(
- base::BindOnce(&UpdateEngine::ComponentCheckingForUpdatesStart, this,
- update_context, id));
-}
-
-void UpdateEngine::ComponentCheckingForUpdatesStart(
- scoped_refptr<UpdateContext> update_context,
- const std::string& id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(update_context);
-
- DCHECK_EQ(1u, update_context->components.count(id));
- DCHECK(update_context->components.at(id));
-
- // Handle |kChecking| state.
- auto& component = *update_context->components.at(id);
- component.Handle(
- base::BindOnce(&UpdateEngine::ComponentCheckingForUpdatesComplete, this,
- update_context));
-
- ++update_context->num_components_ready_to_check;
- if (update_context->num_components_ready_to_check <
- update_context->components_to_check_for_updates.size()) {
- return;
- }
-
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&UpdateEngine::DoUpdateCheck, this, update_context));
@@ -175,6 +150,10 @@ void UpdateEngine::DoUpdateCheck(scoped_refptr<UpdateContext> update_context) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(update_context);
+ // Make the components transition from |kNew| to |kChecking| state.
+ for (const auto& id : update_context->components_to_check_for_updates)
+ update_context->components[id]->Handle(base::DoNothing());
+
update_context->update_checker =
update_checker_factory_(config_, metadata_.get());
@@ -221,6 +200,9 @@ void UpdateEngine::UpdateCheckResultsAvailable(
component->SetUpdateCheckResult(base::nullopt,
ErrorCategory::kUpdateCheck, error);
}
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&UpdateEngine::UpdateCheckComplete, this,
+ update_context));
return;
}
@@ -261,18 +243,6 @@ void UpdateEngine::UpdateCheckResultsAvailable(
static_cast<int>(ProtocolError::UPDATE_RESPONSE_NOT_FOUND));
}
}
-}
-
-void UpdateEngine::ComponentCheckingForUpdatesComplete(
- scoped_refptr<UpdateContext> update_context) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(update_context);
-
- ++update_context->num_components_checked;
- if (update_context->num_components_checked <
- update_context->components_to_check_for_updates.size()) {
- return;
- }
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -284,9 +254,17 @@ void UpdateEngine::UpdateCheckComplete(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(update_context);
- for (const auto& id : update_context->components_to_check_for_updates)
+ for (const auto& id : update_context->components_to_check_for_updates) {
update_context->component_queue.push(id);
+ // Handle the |kChecking| state and transition the component to the
+ // next state, depending on the update check results.
+ DCHECK_EQ(1u, update_context->components.count(id));
+ auto& component = update_context->components.at(id);
+ DCHECK_EQ(component->state(), ComponentState::kChecking);
+ component->Handle(base::DoNothing());
+ }
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&UpdateEngine::HandleComponent, this, update_context));
@@ -407,7 +385,7 @@ void UpdateEngine::SendUninstallPing(const std::string& id,
const auto update_context = base::MakeRefCounted<UpdateContext>(
config_, false, std::vector<std::string>{id},
- UpdateClient::CrxDataCallback(), UpdateClient::CrxStateChangeCallback(),
+ UpdateClient::CrxStateChangeCallback(),
UpdateEngine::NotifyObserversCallback(), std::move(callback),
metadata_.get());
DCHECK(!update_context->session_id.empty());
@@ -437,7 +415,7 @@ void UpdateEngine::SendRegistrationPing(const std::string& id,
const auto update_context = base::MakeRefCounted<UpdateContext>(
config_, false, std::vector<std::string>{id},
- UpdateClient::CrxDataCallback(), UpdateClient::CrxStateChangeCallback(),
+ UpdateClient::CrxStateChangeCallback(),
UpdateEngine::NotifyObserversCallback(), std::move(callback),
metadata_.get());
DCHECK(!update_context->session_id.empty());
diff --git a/chromium/components/update_client/update_engine.h b/chromium/components/update_client/update_engine.h
index 6adba5d2620..a6f291cf5f0 100644
--- a/chromium/components/update_client/update_engine.h
+++ b/chromium/components/update_client/update_engine.h
@@ -80,13 +80,6 @@ class UpdateEngine : public base::RefCountedThreadSafe<UpdateEngine> {
void UpdateComplete(scoped_refptr<UpdateContext> update_context, Error error);
- void ComponentCheckingForUpdatesStart(
- scoped_refptr<UpdateContext> update_context,
- const std::string& id);
- void ComponentCheckingForUpdatesComplete(
- scoped_refptr<UpdateContext> update_context);
- void UpdateCheckComplete(scoped_refptr<UpdateContext> update_context);
-
void DoUpdateCheck(scoped_refptr<UpdateContext> update_context);
void UpdateCheckResultsAvailable(
scoped_refptr<UpdateContext> update_context,
@@ -94,6 +87,7 @@ class UpdateEngine : public base::RefCountedThreadSafe<UpdateEngine> {
ErrorCategory error_category,
int error,
int retry_after_sec);
+ void UpdateCheckComplete(scoped_refptr<UpdateContext> update_context);
void HandleComponent(scoped_refptr<UpdateContext> update_context);
void HandleComponentComplete(scoped_refptr<UpdateContext> update_context);
@@ -127,7 +121,6 @@ struct UpdateContext : public base::RefCountedThreadSafe<UpdateContext> {
scoped_refptr<Configurator> config,
bool is_foreground,
const std::vector<std::string>& ids,
- UpdateClient::CrxDataCallback crx_data_callback,
UpdateClient::CrxStateChangeCallback crx_state_change_callback,
const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
UpdateEngine::Callback callback,
@@ -150,9 +143,6 @@ struct UpdateContext : public base::RefCountedThreadSafe<UpdateContext> {
// Contains the map of ids to components for all the CRX in this context.
IdToComponentPtrMap components;
- // Called before an update check, when update metadata is needed.
- UpdateEngine::CrxDataCallback crx_data_callback;
-
// Called when the observable state of the CRX component has changed.
UpdateClient::CrxStateChangeCallback crx_state_change_callback;
@@ -177,9 +167,6 @@ struct UpdateContext : public base::RefCountedThreadSafe<UpdateContext> {
// The error reported by the update checker.
int update_check_error = 0;
- size_t num_components_ready_to_check = 0;
- size_t num_components_checked = 0;
-
// Contains the ids of the components that the state machine must handle.
base::queue<std::string> component_queue;
diff --git a/chromium/components/url_formatter/android/BUILD.gn b/chromium/components/url_formatter/android/BUILD.gn
index 287b881c9ae..fcef32c945d 100644
--- a/chromium/components/url_formatter/android/BUILD.gn
+++ b/chromium/components/url_formatter/android/BUILD.gn
@@ -37,6 +37,7 @@ android_library("url_formatter_javatests") {
"//third_party/android_deps:androidx_test_runner_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit",
+ "//url:gurl_android_test_helper_java",
"//url:gurl_java",
]
}
diff --git a/chromium/components/url_formatter/android/javatests/src/org/chromium/components/url_formatter/UrlFormatterUnitTest.java b/chromium/components/url_formatter/android/javatests/src/org/chromium/components/url_formatter/UrlFormatterUnitTest.java
index 6696a1c4c1a..3040b32668d 100644
--- a/chromium/components/url_formatter/android/javatests/src/org/chromium/components/url_formatter/UrlFormatterUnitTest.java
+++ b/chromium/components/url_formatter/android/javatests/src/org/chromium/components/url_formatter/UrlFormatterUnitTest.java
@@ -4,6 +4,8 @@
package org.chromium.components.url_formatter;
+import static org.junit.Assert.assertEquals;
+
import androidx.test.filters.SmallTest;
import org.junit.Assert;
@@ -11,9 +13,12 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.chromium.base.Function;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
+import org.chromium.url.GURL;
+import org.chromium.url.GURLJavaTestHelper;
/**
* Unit tests for {@link UrlFormatter}.
@@ -27,14 +32,15 @@ public class UrlFormatterUnitTest {
@Before
public void setUp() {
NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
+ GURLJavaTestHelper.nativeInitializeICU();
}
@Test
@SmallTest
public void testFixupUrl() {
- Assert.assertEquals("http://google.com/", UrlFormatter.fixupUrl("google.com").getSpec());
- Assert.assertEquals("chrome://version/", UrlFormatter.fixupUrl("about:").getSpec());
- Assert.assertEquals("file:///mail.google.com:/",
+ assertEquals("http://google.com/", UrlFormatter.fixupUrl("google.com").getSpec());
+ assertEquals("chrome://version/", UrlFormatter.fixupUrl("about:").getSpec());
+ assertEquals("file:///mail.google.com:/",
UrlFormatter.fixupUrl("//mail.google.com:/").getSpec());
Assert.assertFalse(UrlFormatter.fixupUrl("0x100.0").isValid());
}
@@ -42,12 +48,25 @@ public class UrlFormatterUnitTest {
@Test
@SmallTest
public void testFormatUrlForDisplayOmitUsernamePassword() {
- Assert.assertEquals("http://google.com/path",
+ assertEquals("http://google.com/path",
UrlFormatter.formatUrlForDisplayOmitUsernamePassword("http://google.com/path"));
- Assert.assertEquals("http://google.com",
+ assertEquals("http://google.com",
UrlFormatter.formatUrlForDisplayOmitUsernamePassword(
"http://user:pass@google.com"));
- Assert.assertEquals("http://google.com",
+ assertEquals("http://google.com",
UrlFormatter.formatUrlForDisplayOmitUsernamePassword("http://user@google.com"));
}
+
+ @Test
+ @SmallTest
+ public void testFormatUrlForDisplayOmitSchemePathAndTrivialSubdomains() {
+ Function<GURL, String> f =
+ UrlFormatter::formatUrlForDisplayOmitSchemePathAndTrivialSubdomains;
+
+ assertEquals("google.com", f.apply(new GURL("http://user:pass@google.com/path")));
+ assertEquals("chrome://version", f.apply(new GURL("chrome://version")));
+ assertEquals("äää.de", f.apply(new GURL("https://äää.de")));
+ assertEquals("xn--4caaa.com", f.apply(new GURL("https://äää.com")));
+ assertEquals("مثال.إختبار", f.apply(new GURL("https://xn--mgbh0fb.xn--kgbechtv/")));
+ }
}
diff --git a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
index 6d66a7c4db8..d73192b1426 100644
--- a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
+++ b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -368,7 +368,7 @@ IDNSpoofChecker::Result IDNSpoofChecker::SafeToDisplayAsUnicode(
return Result::kICUSpoofChecks;
}
- icu::UnicodeString label_string(FALSE /* isTerminated */, label.data(),
+ icu::UnicodeString label_string(false /* isTerminated */, label.data(),
base::checked_cast<int32_t>(label.size()));
// A punycode label with 'xn--' prefix is not subject to the URL
@@ -711,7 +711,7 @@ bool IDNSpoofChecker::IsWholeScriptConfusableAllowedForTLD(
base::StringPiece tld,
base::StringPiece16 tld_unicode) {
icu::UnicodeString tld_string(
- FALSE /* isTerminated */, tld_unicode.data(),
+ false /* isTerminated */, tld_unicode.data(),
base::checked_cast<int32_t>(tld_unicode.size()));
// Allow if the TLD contains any letter from the script, in which case it's
// likely to be a TLD in that script.
diff --git a/chromium/components/url_formatter/spoof_checks/skeleton_generator.cc b/chromium/components/url_formatter/spoof_checks/skeleton_generator.cc
index 9628626600d..9a779018ebf 100644
--- a/chromium/components/url_formatter/spoof_checks/skeleton_generator.cc
+++ b/chromium/components/url_formatter/spoof_checks/skeleton_generator.cc
@@ -116,7 +116,7 @@ SkeletonGenerator::~SkeletonGenerator() = default;
Skeletons SkeletonGenerator::GetSkeletons(base::StringPiece16 hostname) {
Skeletons skeletons;
size_t hostname_length = hostname.length() - (hostname.back() == '.' ? 1 : 0);
- icu::UnicodeString host(FALSE, hostname.data(), hostname_length);
+ icu::UnicodeString host(false, hostname.data(), hostname_length);
// If input has any characters outside Latin-Greek-Cyrillic and [0-9._-],
// there is no point in getting rid of diacritics because combining marks
// attached to non-LGC characters are already blocked.
diff --git a/chromium/components/url_formatter/url_formatter_android.cc b/chromium/components/url_formatter/url_formatter_android.cc
index 5c394a65282..9a93a0245df 100644
--- a/chromium/components/url_formatter/url_formatter_android.cc
+++ b/chromium/components/url_formatter/url_formatter_android.cc
@@ -118,6 +118,22 @@ JNI_UrlFormatter_FormatUrlForDisplayOmitSchemeOmitTrivialSubdomains(
net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
}
+static ScopedJavaLocalRef<jstring>
+JNI_UrlFormatter_FormatUrlForDisplayOmitSchemePathAndTrivialSubdomains(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& j_gurl) {
+ DCHECK(j_gurl);
+ std::unique_ptr<GURL> gurl = url::GURLAndroid::ToNativeGURL(env, j_gurl);
+ return base::android::ConvertUTF16ToJavaString(
+ env, url_formatter::FormatUrl(
+ *gurl,
+ url_formatter::kFormatUrlOmitDefaults |
+ url_formatter::kFormatUrlTrimAfterHost |
+ url_formatter::kFormatUrlOmitHTTPS |
+ url_formatter::kFormatUrlOmitTrivialSubdomains,
+ net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
+}
+
} // namespace android
} // namespace url_formatter
diff --git a/chromium/components/user_actions_ui/resources/user_actions.html b/chromium/components/user_actions_ui/resources/user_actions.html
index d676d355f38..a57d543ce73 100644
--- a/chromium/components/user_actions_ui/resources/user_actions.html
+++ b/chromium/components/user_actions_ui/resources/user_actions.html
@@ -6,6 +6,7 @@
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<link rel="stylesheet" href="user_actions.css">
<script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="user_actions.js"></script>
</head>
diff --git a/chromium/components/user_manager/fake_user_manager.cc b/chromium/components/user_manager/fake_user_manager.cc
index 875a6583f2f..64177bc8a34 100644
--- a/chromium/components/user_manager/fake_user_manager.cc
+++ b/chromium/components/user_manager/fake_user_manager.cc
@@ -259,17 +259,14 @@ bool FakeUserManager::IsLoggedInAsUserWithGaiaAccount() const {
}
bool FakeUserManager::IsLoggedInAsPublicAccount() const {
- return false;
+ const User* active_user = GetActiveUser();
+ return active_user && active_user->GetType() == USER_TYPE_PUBLIC_ACCOUNT;
}
bool FakeUserManager::IsLoggedInAsGuest() const {
return false;
}
-bool FakeUserManager::IsLoggedInAsSupervisedUser() const {
- return false;
-}
-
bool FakeUserManager::IsLoggedInAsKioskApp() const {
const User* active_user = GetActiveUser();
return active_user ? active_user->GetType() == USER_TYPE_KIOSK_APP : false;
@@ -301,10 +298,6 @@ bool FakeUserManager::IsUserNonCryptohomeDataEphemeral(
return false;
}
-bool FakeUserManager::AreSupervisedUsersAllowed() const {
- return true;
-}
-
bool FakeUserManager::IsGuestSessionAllowed() const {
return true;
}
diff --git a/chromium/components/user_manager/fake_user_manager.h b/chromium/components/user_manager/fake_user_manager.h
index b8995725ee9..974e5846032 100644
--- a/chromium/components/user_manager/fake_user_manager.h
+++ b/chromium/components/user_manager/fake_user_manager.h
@@ -101,7 +101,6 @@ class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
bool IsLoggedInAsUserWithGaiaAccount() const override;
bool IsLoggedInAsPublicAccount() const override;
bool IsLoggedInAsGuest() const override;
- bool IsLoggedInAsSupervisedUser() const override;
bool IsLoggedInAsKioskApp() const override;
bool IsLoggedInAsArcKioskApp() const override;
bool IsLoggedInAsWebKioskApp() const override;
@@ -114,7 +113,6 @@ class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
void AddSessionStateObserver(UserSessionStateObserver* obs) override {}
void RemoveSessionStateObserver(UserSessionStateObserver* obs) override {}
void NotifyLocalStateChanged() override {}
- bool AreSupervisedUsersAllowed() const override;
bool IsGuestSessionAllowed() const override;
bool IsGaiaUserAllowed(const User& user) const override;
bool IsUserAllowed(const User& user) const override;
@@ -138,13 +136,9 @@ class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
void SetEphemeralUsersEnabled(bool enabled) override;
const std::string& GetApplicationLocale() const override;
PrefService* GetLocalState() const override;
- void HandleUserOAuthTokenStatusChange(
- const AccountId& account_id,
- User::OAuthTokenStatus status) const override {}
bool IsEnterpriseManaged() const override;
void LoadDeviceLocalAccounts(
std::set<AccountId>* device_local_accounts_set) override {}
- void PerformPreUserListLoadingActions() override {}
void PerformPostUserListLoadingActions() override {}
void PerformPostUserLoggedInActions(bool browser_restart) override {}
bool IsDemoApp(const AccountId& account_id) const override;
@@ -153,7 +147,6 @@ class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
void DemoAccountLoggedIn() override {}
void KioskAppLoggedIn(User* user) override {}
void PublicAccountUserLoggedIn(User* user) override {}
- void SupervisedUserLoggedIn(const AccountId& account_id) override {}
void OnUserRemoved(const AccountId& account_id) override {}
protected:
diff --git a/chromium/components/user_manager/known_user.cc b/chromium/components/user_manager/known_user.cc
index cb8fc18f4ce..e5fb80b994c 100644
--- a/chromium/components/user_manager/known_user.cc
+++ b/chromium/components/user_manager/known_user.cc
@@ -81,6 +81,10 @@ const char kOfflineSigninLimit[] = "offline_signin_limit";
// Key of the boolean flag telling if user is enterprise managed.
const char kIsEnterpriseManaged[] = "is_enterprise_managed";
+// Key of the name of the entity (either a domain or email address) that manages
+// the policies for this account.
+const char kAccountManager[] = "enterprise_account_manager";
+
// Key of the last input method user used which is suitable for login/lock
// screen.
const char kLastInputMethod[] = "last_input_method";
@@ -112,6 +116,7 @@ const char* kReservedKeys[] = {kCanonicalEmail,
kLastOnlineSignin,
kOfflineSigninLimit,
kIsEnterpriseManaged,
+ kAccountManager,
kLastInputMethod,
kPinAutosubmitLength,
kPinAutosubmitBackfillNeeded,
@@ -678,8 +683,17 @@ bool GetIsEnterpriseManaged(const AccountId& account_id) {
return false;
}
-void SetUserLastInputMethod(const AccountId& account_id,
- const std::string& input_method) {
+void SetAccountManager(const AccountId& account_id,
+ const std::string& manager) {
+ SetStringPref(account_id, kAccountManager, manager);
+}
+
+bool GetAccountManager(const AccountId& account_id, std::string* manager) {
+ return GetStringPref(account_id, kAccountManager, manager);
+}
+
+void SetUserLastLoginInputMethod(const AccountId& account_id,
+ const std::string& input_method) {
SetStringPref(account_id, kLastInputMethod, input_method);
}
diff --git a/chromium/components/user_manager/known_user.h b/chromium/components/user_manager/known_user.h
index 6e367ab6395..73ce319497e 100644
--- a/chromium/components/user_manager/known_user.h
+++ b/chromium/components/user_manager/known_user.h
@@ -232,9 +232,13 @@ void USER_MANAGER_EXPORT SetIsEnterpriseManaged(const AccountId& account_id,
bool USER_MANAGER_EXPORT GetIsEnterpriseManaged(const AccountId& account_id);
+void USER_MANAGER_EXPORT SetAccountManager(const AccountId& account_id,
+ const std::string& manager);
+bool USER_MANAGER_EXPORT GetAccountManager(const AccountId& account_id,
+ std::string* manager);
void USER_MANAGER_EXPORT
-SetUserLastInputMethod(const AccountId& account_id,
- const std::string& input_method);
+SetUserLastLoginInputMethod(const AccountId& account_id,
+ const std::string& input_method);
bool USER_MANAGER_EXPORT GetUserLastInputMethod(const AccountId& account_id,
std::string* input_method);
diff --git a/chromium/components/user_manager/user_manager.h b/chromium/components/user_manager/user_manager.h
index 0b333930a42..2e1e434ec5a 100644
--- a/chromium/components/user_manager/user_manager.h
+++ b/chromium/components/user_manager/user_manager.h
@@ -278,9 +278,6 @@ class USER_MANAGER_EXPORT UserManager {
// Returns true if we're logged in as a Guest.
virtual bool IsLoggedInAsGuest() const = 0;
- // Returns true if we're logged in as a legacy supervised user.
- virtual bool IsLoggedInAsSupervisedUser() const = 0;
-
// Returns true if we're logged in as a kiosk app.
virtual bool IsLoggedInAsKioskApp() const = 0;
@@ -320,9 +317,6 @@ class USER_MANAGER_EXPORT UserManager {
const gfx::ImageSkia& profile_image) = 0;
virtual void NotifyUsersSignInConstraintsChanged() = 0;
- // Returns true if supervised users allowed.
- virtual bool AreSupervisedUsersAllowed() const = 0;
-
// Returns true if guest user is allowed.
virtual bool IsGuestSessionAllowed() const = 0;
@@ -362,6 +356,7 @@ class USER_MANAGER_EXPORT UserManager {
virtual bool IsStubAccountId(const AccountId& account_id) const = 0;
// Returns true if |account_id| is supervised.
+ // TODO(crbug.com/866790): Check it is not used anymore and remove it.
virtual bool IsSupervisedAccountId(const AccountId& account_id) const = 0;
virtual bool IsDeviceLocalAccountMarkedForRemoval(
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index 5e09ae11289..59ea1b806b3 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/format_macros.h"
@@ -88,10 +88,6 @@ UserType GetStoredUserType(const base::DictionaryValue* prefs_user_types,
} // namespace
-// Feature that hides Supervised Users.
-const base::Feature kHideSupervisedUsers{"HideSupervisedUsers",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// static
void UserManagerBase::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kRegularUsersPref);
@@ -199,7 +195,7 @@ void UserManagerBase::UserLoggedIn(const AccountId& account_id,
break;
case USER_TYPE_SUPERVISED:
- SupervisedUserLoggedIn(account_id);
+ NOTREACHED() << "Supervised users are not supported anymore";
break;
case USER_TYPE_KIOSK_APP:
@@ -342,13 +338,6 @@ void UserManagerBase::RemoveUserFromList(const AccountId& account_id) {
// to the account_id in the User object.
DeleteUser(
RemoveRegularOrSupervisedUserFromList(account_id, true /* notify */));
- } else if (user_loading_stage_ == STAGE_LOADING) {
- DCHECK(IsSupervisedAccountId(account_id));
- // Special case, removing partially-constructed supervised user during user
- // list loading.
- ListPrefUpdate users_update(GetLocalState(), kRegularUsersPref);
- users_update->Remove(base::Value(account_id.GetUserEmail()), nullptr);
- OnUserRemoved(account_id);
} else {
NOTREACHED() << "Users are not loaded yet.";
return;
@@ -598,11 +587,6 @@ bool UserManagerBase::IsLoggedInAsGuest() const {
return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_GUEST;
}
-bool UserManagerBase::IsLoggedInAsSupervisedUser() const {
- DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
- return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_SUPERVISED;
-}
-
bool UserManagerBase::IsLoggedInAsKioskApp() const {
DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_KIOSK_APP;
@@ -740,10 +724,8 @@ void UserManagerBase::NotifyUsersSignInConstraintsChanged() {
}
bool UserManagerBase::CanUserBeRemoved(const User* user) const {
- // Only regular and supervised users are allowed to be manually removed.
- if (!user ||
- !(user->HasGaiaAccount() || user->IsSupervised() ||
- user->IsActiveDirectoryUser()))
+ // Only regular users are allowed to be manually removed.
+ if (!user || !(user->HasGaiaAccount() || user->IsActiveDirectoryUser()))
return false;
// Sanity check: we must not remove single user unless it's an enterprise
@@ -800,8 +782,6 @@ void UserManagerBase::EnsureUsersLoaded() {
return;
user_loading_stage_ = STAGE_LOADING;
- PerformPreUserListLoadingActions();
-
PrefService* local_state = GetLocalState();
const base::ListValue* prefs_regular_users =
local_state->GetList(kRegularUsersPref);
@@ -826,15 +806,10 @@ void UserManagerBase::EnsureUsersLoaded() {
&regular_users_set);
for (std::vector<AccountId>::const_iterator it = regular_users.begin();
it != regular_users.end(); ++it) {
- User* user = nullptr;
- if (IsSupervisedAccountId(*it)) {
- if (base::FeatureList::IsEnabled(kHideSupervisedUsers))
- continue;
- user = User::CreateSupervisedUser(*it);
- } else {
- user = User::CreateRegularUser(*it,
- GetStoredUserType(prefs_user_types, *it));
- }
+ if (IsSupervisedAccountId(*it))
+ continue;
+ User* user =
+ User::CreateRegularUser(*it, GetStoredUserType(prefs_user_types, *it));
user->set_oauth_token_status(LoadUserOAuthStatus(*it));
user->set_force_online_signin(LoadForceOnlineSignin(*it));
user->set_using_saml(known_user::IsUsingSAML(*it));
@@ -978,8 +953,6 @@ User::OAuthTokenStatus UserManagerBase::LoadUserOAuthStatus(
account_id.GetUserEmail(), &oauth_token_status)) {
User::OAuthTokenStatus status =
static_cast<User::OAuthTokenStatus>(oauth_token_status);
- HandleUserOAuthTokenStatusChange(account_id, status);
-
return status;
}
return User::OAUTH_TOKEN_STATUS_UNKNOWN;
@@ -1034,8 +1007,7 @@ User* UserManagerBase::RemoveRegularOrSupervisedUserFromList(
user = *it;
it = users_.erase(it);
} else {
- if ((*it)->HasGaiaAccount() || (*it)->IsSupervised() ||
- (*it)->IsActiveDirectoryUser()) {
+ if ((*it)->HasGaiaAccount() || (*it)->IsActiveDirectoryUser()) {
const std::string user_email = (*it)->GetAccountId().GetUserEmail();
prefs_users_update->AppendString(user_email);
}
diff --git a/chromium/components/user_manager/user_manager_base.h b/chromium/components/user_manager/user_manager_base.h
index 6a901df7231..ce03b1bbce9 100644
--- a/chromium/components/user_manager/user_manager_base.h
+++ b/chromium/components/user_manager/user_manager_base.h
@@ -33,9 +33,6 @@ class SingleThreadTaskRunner;
namespace user_manager {
-// Hides all Supervised Users.
-USER_MANAGER_EXPORT extern const base::Feature kHideSupervisedUsers;
-
class RemoveUserDelegate;
// Base implementation of the UserManager interface.
@@ -93,7 +90,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
bool IsLoggedInAsChildUser() const override;
bool IsLoggedInAsPublicAccount() const override;
bool IsLoggedInAsGuest() const override;
- bool IsLoggedInAsSupervisedUser() const override;
bool IsLoggedInAsKioskApp() const override;
bool IsLoggedInAsArcKioskApp() const override;
bool IsLoggedInAsWebKioskApp() const override;
@@ -160,11 +156,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
// Subsequent calls have no effect. Must be called on the UI thread.
virtual void EnsureUsersLoaded();
- // Handle OAuth token |status| change for |account_id|.
- virtual void HandleUserOAuthTokenStatusChange(
- const AccountId& account_id,
- User::OAuthTokenStatus status) const = 0;
-
// Loads device local accounts from the Local state and fills in
// |device_local_accounts_set|.
virtual void LoadDeviceLocalAccounts(
@@ -182,9 +173,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
virtual void NotifyUserAddedToSession(const User* added_user,
bool user_switch_pending);
- // Performs any additional actions before user list is loaded.
- virtual void PerformPreUserListLoadingActions() = 0;
-
// Performs any additional actions after user list is loaded.
virtual void PerformPostUserListLoadingActions() = 0;
@@ -244,9 +232,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
virtual void RegularUserLoggedInAsEphemeral(const AccountId& account_id,
const UserType user_type);
- // Indicates that a supervised user just logged in.
- virtual void SupervisedUserLoggedIn(const AccountId& account_id) = 0;
-
// Should be called when regular user was removed.
virtual void OnUserRemoved(const AccountId& account_id) = 0;
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn
index 31d4615c3a3..4aab93859c9 100644
--- a/chromium/components/variations/BUILD.gn
+++ b/chromium/components/variations/BUILD.gn
@@ -149,6 +149,8 @@ static_library("test_support") {
sources = [
"variations_params_manager.cc",
"variations_params_manager.h",
+ "variations_test_utils.cc",
+ "variations_test_utils.h",
]
public_deps = [
@@ -158,6 +160,7 @@ static_library("test_support") {
deps = [
"field_trial_config:field_trial_config",
+ "proto",
"//base/test:test_support",
]
}
@@ -191,7 +194,9 @@ source_set("unit_tests") {
}
deps = [
+ ":test_support",
":variations",
+ ":variations_features",
":variations_mojom",
"net",
"proto",
diff --git a/chromium/components/variations/active_field_trials.h b/chromium/components/variations/active_field_trials.h
index d9f10a09efe..a1cba302078 100644
--- a/chromium/components/variations/active_field_trials.h
+++ b/chromium/components/variations/active_field_trials.h
@@ -71,6 +71,8 @@ void SetSeedVersion(const std::string& seed_version);
// Gets the version of the seed that the current set of FieldTrials was
// generated from.
+// Only works on the browser process; returns the empty string from other
+// processes.
// TODO(crbug/507665): Move this to field_trials_provider once it moves
// into components/variations
const std::string& GetSeedVersion();
diff --git a/chromium/components/variations/net/variations_http_headers_unittest.cc b/chromium/components/variations/net/variations_http_headers_unittest.cc
index fd3f1d39f45..555ea0c88d5 100644
--- a/chromium/components/variations/net/variations_http_headers_unittest.cc
+++ b/chromium/components/variations/net/variations_http_headers_unittest.cc
@@ -44,7 +44,7 @@ network::ResourceRequest CreateResourceRequest(
return request;
request.trusted_params->isolation_info = net::IsolationInfo::Create(
- net::IsolationInfo::RedirectMode::kUpdateNothing,
+ net::IsolationInfo::RequestType::kOther,
url::Origin::Create(GURL(isolation_info_top_frame_origin_url)),
url::Origin::Create(GURL(isolation_info_frame_origin_url)),
net::SiteForCookies());
diff --git a/chromium/components/variations/platform_field_trials.h b/chromium/components/variations/platform_field_trials.h
index bb010fee9a6..6af65fcae53 100644
--- a/chromium/components/variations/platform_field_trials.h
+++ b/chromium/components/variations/platform_field_trials.h
@@ -24,9 +24,12 @@ class PlatformFieldTrials {
// FeatureList::AssociateReportingFieldTrial. |has_seed| indicates that the
// variations service used a seed to create field trials. This can be used to
// prevent associating a field trial with a feature that you expect to be
- // controlled by the variations seed.
+ // controlled by the variations seed. |low_entropy_provider| can be used as a
+ // parameter to creating a FieldTrial that should be visible to Google web
+ // properties.
virtual void SetupFeatureControllingFieldTrials(
bool has_seed,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list) = 0;
// Register any synthetic field trials. Will be called later than the above
diff --git a/chromium/components/variations/service/generate_ui_string_overrider.gni b/chromium/components/variations/service/generate_ui_string_overrider.gni
index 14497f9ae44..a8ed3f368fb 100644
--- a/chromium/components/variations/service/generate_ui_string_overrider.gni
+++ b/chromium/components/variations/service/generate_ui_string_overrider.gni
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
+
# Runs the resources map generation script other the given header files to
# produce an output file and a source_set to build it.
#
@@ -30,7 +32,8 @@ template("generate_ui_string_overrider") {
source_set_target_name = target_name
gen_action_target_name = target_name + "_gen_sources"
- action(gen_action_target_name) {
+ # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+ python2_action(gen_action_target_name) {
header_filename = "$target_gen_dir/" + invoker.header_filename
source_filename = "$target_gen_dir/" + invoker.source_filename
diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc
index 2388d8788b5..25e56616448 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator.cc
@@ -163,8 +163,7 @@ std::string VariationsFieldTrialCreator::GetLatestCountry() const {
}
bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
- std::unique_ptr<const base::FieldTrial::EntropyProvider>
- low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list,
SafeSeedManager* safe_seed_manager) {
TRACE_EVENT0("startup", "VariationsFieldTrialCreator::CreateTrialsFromSeed");
@@ -206,7 +205,7 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
seed, *client_filterable_state,
base::BindRepeating(&VariationsFieldTrialCreator::OverrideUIString,
base::Unretained(this)),
- low_entropy_provider.get(), feature_list);
+ low_entropy_provider, feature_list);
// Store into the |safe_seed_manager| the combined server and client data used
// to create the field trials. But, as an optimization, skip this step when
@@ -432,7 +431,8 @@ bool VariationsFieldTrialCreator::SetupFieldTrials(
low_entropy_provider,
std::unique_ptr<base::FeatureList> feature_list,
PlatformFieldTrials* platform_field_trials,
- SafeSeedManager* safe_seed_manager) {
+ SafeSeedManager* safe_seed_manager,
+ base::Optional<int> low_entropy_source_value) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnableBenchmarking) ||
@@ -468,11 +468,13 @@ bool VariationsFieldTrialCreator::SetupFieldTrials(
VariationsIdsProvider* http_header_provider =
VariationsIdsProvider::GetInstance();
+ http_header_provider->SetLowEntropySourceValue(low_entropy_source_value);
// Force the variation ids selected in chrome://flags and/or specified using
// the command-line flag.
auto result = http_header_provider->ForceVariationIds(
variation_ids,
command_line->GetSwitchValueASCII(switches::kForceVariationIds));
+
switch (result) {
case VariationsIdsProvider::ForceIdsResult::INVALID_SWITCH_ENTRY:
ExitWithMessage(base::StringPrintf("Invalid --%s list specified.",
@@ -521,12 +523,12 @@ bool VariationsFieldTrialCreator::SetupFieldTrials(
#endif // BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
bool used_seed = false;
if (!used_testing_config) {
- used_seed = CreateTrialsFromSeed(std::move(low_entropy_provider),
- feature_list.get(), safe_seed_manager);
+ used_seed = CreateTrialsFromSeed(*low_entropy_provider, feature_list.get(),
+ safe_seed_manager);
}
- platform_field_trials->SetupFeatureControllingFieldTrials(used_seed,
- feature_list.get());
+ platform_field_trials->SetupFeatureControllingFieldTrials(
+ used_seed, *low_entropy_provider, feature_list.get());
base::FeatureList::SetInstance(std::move(feature_list));
diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h
index 7418755fe34..d1b5f89ee00 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.h
+++ b/chromium/components/variations/service/variations_field_trial_creator.h
@@ -70,6 +70,8 @@ class VariationsFieldTrialCreator {
// |safe_seed_manager| should be notified of the combined server and client
// state that was activated to create the field trials (only when the return
// value is true).
+ // |low_entropy_source_value| contains the low entropy source value that was
+ // used for client-side randomization of variations.
// |extra_overrides| gives a list of feature overrides that should be applied
// after the features explicitly disabled/enabled from the command line via
// --disable-features and --enable-features, but before field trials.
@@ -88,7 +90,8 @@ class VariationsFieldTrialCreator {
low_entropy_provider,
std::unique_ptr<base::FeatureList> feature_list,
PlatformFieldTrials* platform_field_trials,
- SafeSeedManager* safe_seed_manager);
+ SafeSeedManager* safe_seed_manager,
+ base::Optional<int> low_entropy_source_value);
// Returns all of the client state used for filtering studies.
// As a side-effect, may update the stored permanent consistency country.
@@ -151,8 +154,7 @@ class VariationsFieldTrialCreator {
// successfully; and if so, stores the loaded variations state into the
// |safe_seed_manager|.
bool CreateTrialsFromSeed(
- std::unique_ptr<const base::FieldTrial::EntropyProvider>
- low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list,
SafeSeedManager* safe_seed_manager);
diff --git a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
index 6729a080f31..2544b643041 100644
--- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -8,8 +8,8 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@@ -119,6 +119,7 @@ class TestPlatformFieldTrials : public PlatformFieldTrials {
void SetupFieldTrials() override {}
void SetupFeatureControllingFieldTrials(
bool has_seed,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list) override {}
private:
@@ -249,7 +250,7 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
"", "", "", std::vector<std::string>(),
std::vector<base::FeatureList::FeatureOverrideInfo>(), nullptr,
std::make_unique<base::FeatureList>(), &platform_field_trials,
- safe_seed_manager_);
+ safe_seed_manager_, base::nullopt);
}
TestVariationsSeedStore* seed_store() { return &seed_store_; }
@@ -500,7 +501,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) {
"", "", "", std::vector<std::string>(),
std::vector<base::FeatureList::FeatureOverrideInfo>(), nullptr,
std::make_unique<base::FeatureList>(), &platform_field_trials,
- &safe_seed_manager));
+ &safe_seed_manager, base::nullopt));
EXPECT_EQ(kTestSeedExperimentName,
base::FieldTrialList::FindFullName(kTestSeedStudyName));
diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc
index 327e4f183ad..954214411b3 100644
--- a/chromium/components/variations/service/variations_service.cc
+++ b/chromium/components/variations/service/variations_service.cc
@@ -999,7 +999,8 @@ bool VariationsService::SetupFieldTrials(
return field_trial_creator_.SetupFieldTrials(
kEnableGpuBenchmarking, kEnableFeatures, kDisableFeatures, variation_ids,
extra_overrides, CreateLowEntropyProvider(), std::move(feature_list),
- platform_field_trials, &safe_seed_manager_);
+ platform_field_trials, &safe_seed_manager_,
+ state_manager_->GetLowEntropySource());
}
void VariationsService::OverrideCachedUIStrings() {
diff --git a/chromium/components/variations/service/variations_service_unittest.cc b/chromium/components/variations/service/variations_service_unittest.cc
index 83ff3b54b8d..3e63a3a588c 100644
--- a/chromium/components/variations/service/variations_service_unittest.cc
+++ b/chromium/components/variations/service/variations_service_unittest.cc
@@ -20,7 +20,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/version.h"
diff --git a/chromium/components/variations/study_filtering_unittest.cc b/chromium/components/variations/study_filtering_unittest.cc
index 66aec6047be..96d88515fc7 100644
--- a/chromium/components/variations/study_filtering_unittest.cc
+++ b/chromium/components/variations/study_filtering_unittest.cc
@@ -11,7 +11,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
diff --git a/chromium/components/variations/variations_associated_data_unittest.cc b/chromium/components/variations/variations_associated_data_unittest.cc
index cdc6027c7c0..e1ecb180d71 100644
--- a/chromium/components/variations/variations_associated_data_unittest.cc
+++ b/chromium/components/variations/variations_associated_data_unittest.cc
@@ -6,7 +6,6 @@
#include "base/macros.h"
#include "base/metrics/field_trial.h"
-#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace variations {
diff --git a/chromium/components/variations/variations_features.cc b/chromium/components/variations/variations_features.cc
index 3a1127682c1..1c8c1f0df87 100644
--- a/chromium/components/variations/variations_features.cc
+++ b/chromium/components/variations/variations_features.cc
@@ -9,7 +9,7 @@ namespace variations {
namespace internal {
const base::Feature kRestrictGoogleWebVisibility{
- "RestrictGoogleWebVisibility", base::FEATURE_DISABLED_BY_DEFAULT};
+ "RestrictGoogleWebVisibility", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace internal
} // namespace variations
diff --git a/chromium/components/variations/variations_id_collection.cc b/chromium/components/variations/variations_id_collection.cc
index e34e56602df..e48bcfabc22 100644
--- a/chromium/components/variations/variations_id_collection.cc
+++ b/chromium/components/variations/variations_id_collection.cc
@@ -4,7 +4,7 @@
#include "components/variations/variations_id_collection.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/stl_util.h"
diff --git a/chromium/components/variations/variations_ids_provider.cc b/chromium/components/variations/variations_ids_provider.cc
index 32b287c34d8..7237221105b 100644
--- a/chromium/components/variations/variations_ids_provider.cc
+++ b/chromium/components/variations/variations_ids_provider.cc
@@ -18,6 +18,11 @@
namespace variations {
+// Range of low entropy source values (8000) as variation ids for the
+// X-Client-Data header. This range is reserved in cl/333331461 (internal CL).
+const int kLowEntropySourceVariationIdRangeMin = 3320978;
+const int kLowEntropySourceVariationIdRangeMax = 3328977;
+
bool VariationsHeaderKey::operator<(const VariationsHeaderKey& other) const {
if (is_signed_in != other.is_signed_in)
return is_signed_in < other.is_signed_in;
@@ -110,6 +115,18 @@ VariationsIdsProvider::GetVariationsVectorForWebPropertiesKeys() {
return GetVariationsVectorImpl(web_properties_keys);
}
+void VariationsIdsProvider::SetLowEntropySourceValue(
+ base::Optional<int> low_entropy_source_value) {
+ // The low entropy source value is an integer that is between 0 and 7999,
+ // inclusive. See components/metrics/metrics_state_manager.cc for the logic to
+ // generate it.
+ if (low_entropy_source_value) {
+ DCHECK_GE(low_entropy_source_value.value(), 0);
+ DCHECK_LE(low_entropy_source_value.value(), 7999);
+ }
+ low_entropy_source_value_ = low_entropy_source_value;
+}
+
VariationsIdsProvider::ForceIdsResult VariationsIdsProvider::ForceVariationIds(
const std::vector<std::string>& variation_ids,
const std::string& command_line_variation_ids) {
@@ -423,6 +440,27 @@ VariationsIdsProvider::GetAllVariationIds() {
for (const VariationIDEntry& entry : force_disabled_ids_set_) {
all_variation_ids_set.erase(entry);
}
+
+ // Add the low entropy source value, if it exists, which has one of
+ // 8000 possible values (between kLowEntropySourceVariationIdRange[Min/Max],
+ // ~13 bits). This is the value that has been used for deriving the variation
+ // ids included in the X-Client-Data header and therefore does not reveal
+ // additional information about the client when there are more than 13
+ // variations. A typical Chrome client has more than 13 variation ids
+ // reported.
+ //
+ // The entropy source value is used for retrospective A/A tests to validate
+ // that there's no existing bias between two randomized groups of clients for
+ // a later A/B study.
+ if (low_entropy_source_value_) {
+ int source_value = low_entropy_source_value_.value() +
+ kLowEntropySourceVariationIdRangeMin;
+ DCHECK_GE(source_value, kLowEntropySourceVariationIdRangeMin);
+ DCHECK_LE(source_value, kLowEntropySourceVariationIdRangeMax);
+ all_variation_ids_set.insert(
+ VariationIDEntry(source_value, GOOGLE_WEB_PROPERTIES_FIRST_PARTY));
+ }
+
return all_variation_ids_set;
}
diff --git a/chromium/components/variations/variations_ids_provider.h b/chromium/components/variations/variations_ids_provider.h
index 0dbfc807500..2c63f04a937 100644
--- a/chromium/components/variations/variations_ids_provider.h
+++ b/chromium/components/variations/variations_ids_provider.h
@@ -96,6 +96,10 @@ class VariationsIdsProvider : public base::FieldTrialList::Observer,
// related keys.
std::vector<VariationID> GetVariationsVectorForWebPropertiesKeys();
+ // Sets low entropy source value that was used for client-side randomization
+ // of variations.
+ void SetLowEntropySourceValue(base::Optional<int> low_entropy_source_value);
+
// Result of ForceVariationIds() call.
enum class ForceIdsResult {
SUCCESS,
@@ -140,8 +144,12 @@ class VariationsIdsProvider : public base::FieldTrialList::Observer,
ForceDisableVariationIds_ValidCommandLine);
FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
ForceDisableVariationIds_Invalid);
- FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
+ FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
OnFieldTrialGroupFinalized);
+ FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
+ LowEntropySourceValue_Valid);
+ FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTestWithRestrictedVisibility,
+ LowEntropySourceValue_Null);
FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest,
GetGoogleAppVariationsString);
FRIEND_TEST_ALL_PREFIXES(VariationsIdsProviderTest, GetVariationsString);
@@ -218,6 +226,10 @@ class VariationsIdsProvider : public base::FieldTrialList::Observer,
// Guards access to variables below.
base::Lock lock_;
+ // Low entropy source value from client that was used for client-side
+ // randomization of variations.
+ base::Optional<int> low_entropy_source_value_;
+
// Whether or not we've initialized the caches.
bool variation_ids_cache_initialized_;
diff --git a/chromium/components/variations/variations_ids_provider_unittest.cc b/chromium/components/variations/variations_ids_provider_unittest.cc
index d92b08d3201..6112605b44a 100644
--- a/chromium/components/variations/variations_ids_provider_unittest.cc
+++ b/chromium/components/variations/variations_ids_provider_unittest.cc
@@ -7,58 +7,22 @@
#include <string>
#include "base/base64.h"
+#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/variations/entropy_provider.h"
#include "components/variations/proto/client_variations.pb.h"
#include "components/variations/proto/study.pb.h"
#include "components/variations/variations.mojom.h"
#include "components/variations/variations_associated_data.h"
+#include "components/variations/variations_features.h"
+#include "components/variations/variations_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace variations {
-
-namespace {
-
-// Decodes the variations header and extracts the variation ids.
-bool ExtractVariationIds(const std::string& variations,
- std::set<VariationID>* variation_ids,
- std::set<VariationID>* trigger_ids) {
- std::string serialized_proto;
- if (!base::Base64Decode(variations, &serialized_proto))
- return false;
- ClientVariations proto;
- if (!proto.ParseFromString(serialized_proto))
- return false;
- for (int i = 0; i < proto.variation_id_size(); ++i)
- variation_ids->insert(proto.variation_id(i));
- for (int i = 0; i < proto.trigger_variation_id_size(); ++i)
- trigger_ids->insert(proto.trigger_variation_id(i));
- return true;
-}
-
-scoped_refptr<base::FieldTrial> CreateTrialAndAssociateId(
- const std::string& trial_name,
- const std::string& default_group_name,
- IDCollectionKey key,
- VariationID id) {
- AssociateGoogleVariationID(key, trial_name, default_group_name, id);
- scoped_refptr<base::FieldTrial> trial(
- base::FieldTrialList::CreateFieldTrial(trial_name, default_group_name));
- EXPECT_TRUE(trial);
-
- if (trial) {
- // Ensure the trial is registered under the correct key so we can look it
- // up.
- trial->group();
- }
-
- return trial;
-}
-
-} // namespace
-
class VariationsIdsProviderTest : public ::testing::Test {
public:
VariationsIdsProviderTest() {}
@@ -70,6 +34,25 @@ class VariationsIdsProviderTest : public ::testing::Test {
base::test::SingleThreadTaskEnvironment task_environment_;
};
+// Used for testing the kRestrictGoogleWebVisibility feature.
+class VariationsIdsProviderTestWithRestrictedVisibility
+ : public VariationsIdsProviderTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ VariationsIdsProviderTestWithRestrictedVisibility() {
+ if (GetParam()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ internal::kRestrictGoogleWebVisibility);
+ } else {
+ scoped_feature_list_.InitAndDisableFeature(
+ internal::kRestrictGoogleWebVisibility);
+ }
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
TEST_F(VariationsIdsProviderTest, ForceVariationIds_Valid) {
VariationsIdsProvider provider;
@@ -82,7 +65,6 @@ TEST_F(VariationsIdsProviderTest, ForceVariationIds_Valid) {
EXPECT_FALSE(headers->headers_map.empty());
const std::string variations =
headers->headers_map.at(variations::mojom::GoogleWebVisibility::ANY);
-
std::set<VariationID> variation_ids;
std::set<VariationID> trigger_ids;
ASSERT_TRUE(ExtractVariationIds(variations, &variation_ids, &trigger_ids));
@@ -173,7 +155,94 @@ TEST_F(VariationsIdsProviderTest, ForceDisableVariationIds_Invalid) {
EXPECT_TRUE(provider.GetClientDataHeaders(/*is_signed_in=*/false).is_null());
}
-TEST_F(VariationsIdsProviderTest, OnFieldTrialGroupFinalized) {
+INSTANTIATE_TEST_SUITE_P(All,
+ VariationsIdsProviderTestWithRestrictedVisibility,
+ ::testing::Bool());
+
+TEST_P(VariationsIdsProviderTestWithRestrictedVisibility,
+ LowEntropySourceValue_Valid) {
+ VariationsIdsProvider provider;
+
+ base::Optional<int> valid_low_entropy_source_value = 5;
+ provider.SetLowEntropySourceValue(valid_low_entropy_source_value);
+ provider.InitVariationIDsCacheIfNeeded();
+ variations::mojom::VariationsHeadersPtr headers =
+ provider.GetClientDataHeaders(/*is_signed_in=*/false);
+ EXPECT_FALSE(headers->headers_map.empty());
+
+ const std::string variations_header_first_party = headers->headers_map.at(
+ variations::mojom::GoogleWebVisibility::FIRST_PARTY);
+ const std::string variations_header_any_context =
+ headers->headers_map.at(variations::mojom::GoogleWebVisibility::ANY);
+
+ std::set<VariationID> variation_ids_first_party;
+ std::set<VariationID> trigger_ids_first_party;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_first_party,
+ &variation_ids_first_party,
+ &trigger_ids_first_party));
+ std::set<VariationID> variation_ids_any_context;
+ std::set<VariationID> trigger_ids_any_context;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_any_context,
+ &variation_ids_any_context,
+ &trigger_ids_any_context));
+
+ // 3320983 is the offset value of kLowEntropySourceVariationIdRangeMin + 5.
+ EXPECT_TRUE(base::Contains(variation_ids_first_party, 3320983));
+
+ // The value will be omitted from third-party contexts under
+ // kRestrictGoogleWebVisibility.
+ bool value_omitted =
+ base::FeatureList::IsEnabled(internal::kRestrictGoogleWebVisibility);
+ EXPECT_EQ(value_omitted, !base::Contains(variation_ids_any_context, 3320983));
+}
+
+TEST_P(VariationsIdsProviderTestWithRestrictedVisibility,
+ LowEntropySourceValue_Null) {
+ VariationsIdsProvider provider;
+
+ base::Optional<int> null_low_entropy_source_value = base::nullopt;
+ provider.SetLowEntropySourceValue(null_low_entropy_source_value);
+
+ // Valid experiment ids.
+ CreateTrialAndAssociateId("t1", "g1", GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, 12);
+ CreateTrialAndAssociateId("t2", "g2", GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, 456);
+ provider.InitVariationIDsCacheIfNeeded();
+ variations::mojom::VariationsHeadersPtr headers =
+ provider.GetClientDataHeaders(/*is_signed_in=*/false);
+ EXPECT_FALSE(headers->headers_map.empty());
+
+ const std::string variations_header_first_party = headers->headers_map.at(
+ variations::mojom::GoogleWebVisibility::FIRST_PARTY);
+ const std::string variations_header_any_context =
+ headers->headers_map.at(variations::mojom::GoogleWebVisibility::ANY);
+
+ std::set<VariationID> variation_ids_first_party;
+ std::set<VariationID> trigger_ids_first_party;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_first_party,
+ &variation_ids_first_party,
+ &trigger_ids_first_party));
+ std::set<VariationID> variation_ids_any_context;
+ std::set<VariationID> trigger_ids_any_context;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_any_context,
+ &variation_ids_any_context,
+ &trigger_ids_any_context));
+
+ // We test to make sure that only two valid variation IDs are present and that
+ // the low entropy source value is not added to the sets.
+ EXPECT_TRUE(base::Contains(variation_ids_first_party, 12));
+ EXPECT_TRUE(base::Contains(variation_ids_first_party, 456));
+ EXPECT_FALSE(base::Contains(variation_ids_first_party, 3320983));
+ EXPECT_TRUE(base::Contains(variation_ids_any_context, 12));
+ EXPECT_TRUE(base::Contains(variation_ids_any_context, 456));
+ EXPECT_FALSE(base::Contains(variation_ids_any_context, 3320983));
+
+ // Check to make sure that no other variation IDs are present.
+ EXPECT_EQ(2U, variation_ids_first_party.size());
+ EXPECT_EQ(2U, variation_ids_any_context.size());
+}
+
+TEST_P(VariationsIdsProviderTestWithRestrictedVisibility,
+ OnFieldTrialGroupFinalized) {
VariationsIdsProvider provider;
provider.InitVariationIDsCacheIfNeeded();
@@ -191,7 +260,7 @@ TEST_F(VariationsIdsProviderTest, OnFieldTrialGroupFinalized) {
ASSERT_EQ(default_name, trial_3->group_name());
scoped_refptr<base::FieldTrial> trial_4(CreateTrialAndAssociateId(
- "t4", default_name, GOOGLE_WEB_PROPERTIES_TRIGGER_ANY_CONTEXT, 44));
+ "t4", default_name, GOOGLE_WEB_PROPERTIES_TRIGGER_FIRST_PARTY, 44));
ASSERT_EQ(default_name, trial_4->group_name());
scoped_refptr<base::FieldTrial> trial_5(CreateTrialAndAssociateId(
@@ -206,37 +275,99 @@ TEST_F(VariationsIdsProviderTest, OnFieldTrialGroupFinalized) {
{
variations::mojom::VariationsHeadersPtr headers =
provider.GetClientDataHeaders(/*is_signed_in=*/false);
- const std::string variations =
+ const std::string variations_header_first_party = headers->headers_map.at(
+ variations::mojom::GoogleWebVisibility::FIRST_PARTY);
+ const std::string variations_header_any_context =
headers->headers_map.at(variations::mojom::GoogleWebVisibility::ANY);
- std::set<VariationID> variation_ids;
- std::set<VariationID> trigger_ids;
- ASSERT_TRUE(ExtractVariationIds(variations, &variation_ids, &trigger_ids));
- EXPECT_EQ(2U, variation_ids.size());
- EXPECT_TRUE(variation_ids.find(11) != variation_ids.end());
- EXPECT_TRUE(variation_ids.find(22) != variation_ids.end());
- EXPECT_EQ(2U, trigger_ids.size());
- EXPECT_TRUE(trigger_ids.find(33) != trigger_ids.end());
- EXPECT_TRUE(trigger_ids.find(44) != trigger_ids.end());
+ std::set<VariationID> ids_first_party;
+ std::set<VariationID> trigger_ids_first_party;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_first_party,
+ &ids_first_party,
+ &trigger_ids_first_party));
+ std::set<VariationID> ids_any_context;
+ std::set<VariationID> trigger_ids_any_context;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_any_context,
+ &ids_any_context,
+ &trigger_ids_any_context));
+
+ EXPECT_EQ(2U, ids_first_party.size());
+ EXPECT_TRUE(base::Contains(ids_first_party, 11));
+ EXPECT_TRUE(base::Contains(ids_first_party, 22));
+ EXPECT_EQ(2U, trigger_ids_first_party.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_first_party, 33));
+ EXPECT_TRUE(base::Contains(trigger_ids_first_party, 44));
+
+ if (base::FeatureList::IsEnabled(internal::kRestrictGoogleWebVisibility)) {
+ // When the feature is enabled, IDs associated with FIRST_PARTY
+ // IDCollectionKeys should be excluded from the variations header that may
+ // be sent in third-party contexts.
+ EXPECT_EQ(1U, ids_any_context.size());
+ EXPECT_TRUE(base::Contains(ids_any_context, 11));
+ EXPECT_EQ(1U, trigger_ids_any_context.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 33));
+ } else {
+ // When the feature is disabled, IDs associated with FIRST_PARTY
+ // IDCollectionKeys should be included in the variations header that may
+ // be sent in third-party contexts.
+ EXPECT_EQ(2U, ids_any_context.size());
+ EXPECT_TRUE(base::Contains(ids_any_context, 11));
+ EXPECT_TRUE(base::Contains(ids_any_context, 22));
+ EXPECT_EQ(2U, trigger_ids_any_context.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 33));
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 44));
+ }
}
// Now, get signed-in ids.
{
variations::mojom::VariationsHeadersPtr headers =
provider.GetClientDataHeaders(/*is_signed_in=*/true);
- const std::string variations =
+ const std::string variations_header_first_party = headers->headers_map.at(
+ variations::mojom::GoogleWebVisibility::FIRST_PARTY);
+ const std::string variations_header_any_context =
headers->headers_map.at(variations::mojom::GoogleWebVisibility::ANY);
- std::set<VariationID> variation_ids;
- std::set<VariationID> trigger_ids;
- ASSERT_TRUE(ExtractVariationIds(variations, &variation_ids, &trigger_ids));
- EXPECT_EQ(3U, variation_ids.size());
- EXPECT_TRUE(variation_ids.find(11) != variation_ids.end());
- EXPECT_TRUE(variation_ids.find(22) != variation_ids.end());
- EXPECT_TRUE(variation_ids.find(55) != variation_ids.end());
- EXPECT_EQ(2U, trigger_ids.size());
- EXPECT_TRUE(trigger_ids.find(33) != trigger_ids.end());
- EXPECT_TRUE(trigger_ids.find(44) != trigger_ids.end());
+ std::set<VariationID> ids_first_party;
+ std::set<VariationID> trigger_ids_first_party;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_first_party,
+ &ids_first_party,
+ &trigger_ids_first_party));
+ std::set<VariationID> ids_any_context;
+ std::set<VariationID> trigger_ids_any_context;
+ ASSERT_TRUE(ExtractVariationIds(variations_header_any_context,
+ &ids_any_context,
+ &trigger_ids_any_context));
+
+ EXPECT_EQ(3U, ids_first_party.size());
+ EXPECT_TRUE(base::Contains(ids_first_party, 11));
+ EXPECT_TRUE(base::Contains(ids_first_party, 22));
+ EXPECT_TRUE(base::Contains(ids_any_context, 55));
+ EXPECT_EQ(2U, trigger_ids_first_party.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_first_party, 33));
+ EXPECT_TRUE(base::Contains(trigger_ids_first_party, 44));
+
+ if (base::FeatureList::IsEnabled(internal::kRestrictGoogleWebVisibility)) {
+ // When the feature is enabled, IDs associated with FIRST_PARTY
+ // IDCollectionKeys should be excluded from the variations header that may
+ // be sent in third-party contexts.
+ EXPECT_EQ(2U, ids_any_context.size());
+ EXPECT_TRUE(base::Contains(ids_any_context, 11));
+ EXPECT_TRUE(base::Contains(ids_any_context, 55));
+ EXPECT_EQ(1U, trigger_ids_any_context.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 33));
+ } else {
+ // When the feature is disabled, IDs associated with FIRST_PARTY
+ // IDCollectionKeys should be included in the variations header that may
+ // be sent in third-party contexts.
+ EXPECT_EQ(3U, ids_any_context.size());
+ EXPECT_TRUE(base::Contains(ids_any_context, 11));
+ EXPECT_TRUE(base::Contains(ids_any_context, 22));
+ EXPECT_TRUE(base::Contains(ids_any_context, 55));
+ EXPECT_EQ(2U, trigger_ids_any_context.size());
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 33));
+ EXPECT_TRUE(base::Contains(trigger_ids_any_context, 44));
+ }
}
}
diff --git a/chromium/components/variations/variations_request_scheduler_unittest.cc b/chromium/components/variations/variations_request_scheduler_unittest.cc
index 57390ce2678..56f544882f8 100644
--- a/chromium/components/variations/variations_request_scheduler_unittest.cc
+++ b/chromium/components/variations/variations_request_scheduler_unittest.cc
@@ -5,7 +5,7 @@
#include "components/variations/variations_request_scheduler.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/variations/variations_seed_processor.cc b/chromium/components/variations/variations_seed_processor.cc
index 140104c7113..d7f1e95af2f 100644
--- a/chromium/components/variations/variations_seed_processor.cc
+++ b/chromium/components/variations/variations_seed_processor.cc
@@ -197,7 +197,7 @@ void VariationsSeedProcessor::CreateTrialsFromSeed(
const VariationsSeed& seed,
const ClientFilterableState& client_state,
const UIStringOverrideCallback& override_callback,
- const base::FieldTrial::EntropyProvider* low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list) {
std::vector<ProcessedStudy> filtered_studies;
FilterAndValidateStudies(seed, client_state, &filtered_studies);
@@ -225,7 +225,7 @@ bool VariationsSeedProcessor::ShouldStudyUseLowEntropy(const Study& study) {
void VariationsSeedProcessor::CreateTrialFromStudy(
const ProcessedStudy& processed_study,
const UIStringOverrideCallback& override_callback,
- const base::FieldTrial::EntropyProvider* low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list) {
const Study& study = *processed_study.study();
@@ -290,7 +290,7 @@ void VariationsSeedProcessor::CreateTrialFromStudy(
study.name(), processed_study.total_probability(),
processed_study.GetDefaultExperimentName(), randomization_type,
randomization_seed, nullptr,
- ShouldStudyUseLowEntropy(study) ? low_entropy_provider : nullptr));
+ ShouldStudyUseLowEntropy(study) ? &low_entropy_provider : nullptr));
bool has_overrides = false;
bool enables_or_disables_features = false;
diff --git a/chromium/components/variations/variations_seed_processor.h b/chromium/components/variations/variations_seed_processor.h
index 8c3cd73ec07..6a610e70128 100644
--- a/chromium/components/variations/variations_seed_processor.h
+++ b/chromium/components/variations/variations_seed_processor.h
@@ -47,7 +47,7 @@ class VariationsSeedProcessor {
const VariationsSeed& seed,
const ClientFilterableState& client_state,
const UIStringOverrideCallback& override_callback,
- const base::FieldTrial::EntropyProvider* low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list);
// If the given |study| should alwoys use low entropy. This is true for any
@@ -85,7 +85,7 @@ class VariationsSeedProcessor {
void CreateTrialFromStudy(
const ProcessedStudy& processed_study,
const UIStringOverrideCallback& override_callback,
- const base::FieldTrial::EntropyProvider* low_entropy_provider,
+ const base::FieldTrial::EntropyProvider& low_entropy_provider,
base::FeatureList* feature_list);
DISALLOW_COPY_AND_ASSIGN(VariationsSeedProcessor);
diff --git a/chromium/components/variations/variations_seed_processor_unittest.cc b/chromium/components/variations/variations_seed_processor_unittest.cc
index f6f268e5d07..6974a2c3aaa 100644
--- a/chromium/components/variations/variations_seed_processor_unittest.cc
+++ b/chromium/components/variations/variations_seed_processor_unittest.cc
@@ -13,7 +13,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/format_macros.h"
@@ -129,26 +129,28 @@ class VariationsSeedProcessorTest : public ::testing::Test {
}
bool CreateTrialFromStudy(const Study& study) {
+ base::MockEntropyProvider mock_low_entropy_provider(0.9);
return CreateTrialFromStudyWithFeatureListAndEntropyOverride(
- study, nullptr, base::FeatureList::GetInstance());
+ study, mock_low_entropy_provider, base::FeatureList::GetInstance());
}
bool CreateTrialFromStudyWithEntropyOverride(
const Study& study,
- const base::FieldTrial::EntropyProvider* override_entropy_provider) {
+ const base::FieldTrial::EntropyProvider& override_entropy_provider) {
return CreateTrialFromStudyWithFeatureListAndEntropyOverride(
study, override_entropy_provider, base::FeatureList::GetInstance());
}
bool CreateTrialFromStudyWithFeatureList(const Study& study,
base::FeatureList* feature_list) {
- return CreateTrialFromStudyWithFeatureListAndEntropyOverride(study, nullptr,
- feature_list);
+ base::MockEntropyProvider mock_low_entropy_provider(0.9);
+ return CreateTrialFromStudyWithFeatureListAndEntropyOverride(
+ study, mock_low_entropy_provider, feature_list);
}
bool CreateTrialFromStudyWithFeatureListAndEntropyOverride(
const Study& study,
- const base::FieldTrial::EntropyProvider* override_entropy_provider,
+ const base::FieldTrial::EntropyProvider& override_entropy_provider,
base::FeatureList* feature_list) {
ProcessedStudy processed_study;
const bool is_expired = internal::IsStudyExpired(study, base::Time::Now());
@@ -289,9 +291,10 @@ TEST_F(VariationsSeedProcessorTest,
base::FeatureList feature_list;
study1->set_expiry_date(TimeToProtoTime(year_ago));
- seed_processor.CreateTrialsFromSeed(seed, client_state,
- override_callback_.callback(), nullptr,
- &feature_list);
+ base::MockEntropyProvider mock_low_entropy_provider(0.9);
+ seed_processor.CreateTrialsFromSeed(
+ seed, client_state, override_callback_.callback(),
+ mock_low_entropy_provider, &feature_list);
EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
}
@@ -304,9 +307,10 @@ TEST_F(VariationsSeedProcessorTest,
base::FeatureList feature_list;
study1->clear_expiry_date();
study2->set_expiry_date(TimeToProtoTime(year_ago));
- seed_processor.CreateTrialsFromSeed(seed, client_state,
- override_callback_.callback(), nullptr,
- &feature_list);
+ base::MockEntropyProvider mock_low_entropy_provider(0.9);
+ seed_processor.CreateTrialsFromSeed(
+ seed, client_state, override_callback_.callback(),
+ mock_low_entropy_provider, &feature_list);
EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName));
}
}
@@ -560,9 +564,10 @@ TEST_F(VariationsSeedProcessorTest, StartsActive) {
client_state.platform = Study::PLATFORM_ANDROID;
VariationsSeedProcessor seed_processor;
- seed_processor.CreateTrialsFromSeed(seed, client_state,
- override_callback_.callback(), nullptr,
- base::FeatureList::GetInstance());
+ base::MockEntropyProvider mock_low_entropy_provider(0.9);
+ seed_processor.CreateTrialsFromSeed(
+ seed, client_state, override_callback_.callback(),
+ mock_low_entropy_provider, base::FeatureList::GetInstance());
// Non-specified and ACTIVATE_ON_QUERY should not start active, but
// ACTIVATE_ON_STARTUP should.
@@ -979,9 +984,9 @@ TEST_F(VariationsSeedProcessorTest, LowEntropyStudyTest) {
base::MockEntropyProvider mock_low_entropy_provider(0.9);
EXPECT_TRUE(CreateTrialFromStudyWithEntropyOverride(
- *study1, &mock_low_entropy_provider));
+ *study1, mock_low_entropy_provider));
EXPECT_TRUE(CreateTrialFromStudyWithEntropyOverride(
- *study2, &mock_low_entropy_provider));
+ *study2, mock_low_entropy_provider));
// Since no experiment in study1 sends experiment IDs, it will use the high
// entropy provider, which selects the non-default group.
diff --git a/chromium/components/variations/variations_seed_store.cc b/chromium/components/variations/variations_seed_store.cc
index c3567148f8a..7b6ee96b13a 100644
--- a/chromium/components/variations/variations_seed_store.cc
+++ b/chromium/components/variations/variations_seed_store.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/base64.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
diff --git a/chromium/components/variations/variations_seed_store_unittest.cc b/chromium/components/variations/variations_seed_store_unittest.cc
index e0385834493..e97a3461635 100644
--- a/chromium/components/variations/variations_seed_store_unittest.cc
+++ b/chromium/components/variations/variations_seed_store_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/base64.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
diff --git a/chromium/components/variations/variations_test_utils.cc b/chromium/components/variations/variations_test_utils.cc
new file mode 100644
index 00000000000..dd6aaf2acc6
--- /dev/null
+++ b/chromium/components/variations/variations_test_utils.cc
@@ -0,0 +1,52 @@
+// Copyright 2020 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/variations/variations_test_utils.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "components/variations/proto/client_variations.pb.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace variations {
+
+bool ExtractVariationIds(const std::string& variations,
+ std::set<VariationID>* variation_ids,
+ std::set<VariationID>* trigger_ids) {
+ std::string serialized_proto;
+ if (!base::Base64Decode(variations, &serialized_proto))
+ return false;
+ ClientVariations proto;
+ if (!proto.ParseFromString(serialized_proto))
+ return false;
+ for (int i = 0; i < proto.variation_id_size(); ++i)
+ variation_ids->insert(proto.variation_id(i));
+ for (int i = 0; i < proto.trigger_variation_id_size(); ++i)
+ trigger_ids->insert(proto.trigger_variation_id(i));
+ return true;
+}
+
+scoped_refptr<base::FieldTrial> CreateTrialAndAssociateId(
+ const std::string& trial_name,
+ const std::string& default_group_name,
+ IDCollectionKey key,
+ VariationID id) {
+ AssociateGoogleVariationID(key, trial_name, default_group_name, id);
+ scoped_refptr<base::FieldTrial> trial(
+ base::FieldTrialList::CreateFieldTrial(trial_name, default_group_name));
+ DCHECK(trial);
+
+ if (trial) {
+ // Ensure the trial is registered under the correct key so we can look it
+ // up.
+ trial->group();
+ }
+
+ return trial;
+}
+
+} // namespace variations \ No newline at end of file
diff --git a/chromium/components/variations/variations_test_utils.h b/chromium/components/variations/variations_test_utils.h
new file mode 100644
index 00000000000..0fbabd224d2
--- /dev/null
+++ b/chromium/components/variations/variations_test_utils.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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_VARIATIONS_VARIATIONS_TEST_UTILS_H_
+#define COMPONENTS_VARIATIONS_VARIATIONS_TEST_UTILS_H_
+
+#include <set>
+#include <string>
+
+#include "base/metrics/field_trial.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace variations {
+
+// Decodes the variations header and extracts the variation ids.
+bool ExtractVariationIds(const std::string& variations,
+ std::set<VariationID>* variation_ids,
+ std::set<VariationID>* trigger_ids);
+
+// Creates FieldTrial from given |key| and |id|.
+scoped_refptr<base::FieldTrial> CreateTrialAndAssociateId(
+ const std::string& trial_name,
+ const std::string& default_group_name,
+ IDCollectionKey key,
+ VariationID id);
+
+} // namespace variations
+
+#endif // COMPONENTS_VARIATIONS_VARIATIONS_TEST_UTILS_H_
diff --git a/chromium/components/vector_icons/BUILD.gn b/chromium/components/vector_icons/BUILD.gn
index 1b6aa9068d3..c5e534cf089 100644
--- a/chromium/components/vector_icons/BUILD.gn
+++ b/chromium/components/vector_icons/BUILD.gn
@@ -4,7 +4,7 @@
import("//components/vector_icons/vector_icons.gni")
-aggregate_vector_icons2("components_vector_icons") {
+aggregate_vector_icons("components_vector_icons") {
icon_directory = "."
sources = [
diff --git a/chromium/components/vector_icons/vector_icons.gni b/chromium/components/vector_icons/vector_icons.gni
index 0bff996946f..ec13569abe4 100644
--- a/chromium/components/vector_icons/vector_icons.gni
+++ b/chromium/components/vector_icons/vector_icons.gni
@@ -21,50 +21,6 @@
# Example
#
# See BUILD.gn in this directory (//components/vector_icons/) for an example.
-#
-# TODO(estade): rename to aggregate_vector_icons after all clients are updated.
-template("aggregate_vector_icons2") {
- assert(defined(invoker.sources),
- "Need sources in $target_name listing the icon files.")
- assert(
- defined(invoker.icon_directory),
- "Need icon_directory in $target_name where the icons and templates live.")
-
- action(target_name) {
- visibility = [ ":*" ]
-
- script = "//components/vector_icons/aggregate_vector_icons.py"
-
- output_cc = "$target_gen_dir/vector_icons.cc"
- output_h = "$target_gen_dir/vector_icons.h"
-
- templates = [
- "vector_icons.cc.template",
- "vector_icons.h.template",
- ]
- inputs =
- rebase_path(templates + invoker.sources, ".", invoker.icon_directory) +
- [ "//components/vector_icons/aggregate_vector_icons.py" ]
-
- outputs = [
- output_cc,
- output_h,
- ]
-
- response_file_contents =
- rebase_path(invoker.sources, root_build_dir, invoker.icon_directory)
-
- args = [
- "--working_directory=" +
- rebase_path(invoker.icon_directory, root_build_dir),
- "--file_list={{response_file_name}}",
- "--output_cc=" + rebase_path(output_cc, root_build_dir),
- "--output_h=" + rebase_path(output_h, root_build_dir),
- ]
- }
-}
-
-# Deprecated version. TODO(estade): remove when all clients are updated.
template("aggregate_vector_icons") {
assert(defined(invoker.sources),
"Need sources in $target_name listing the icon files.")
diff --git a/chromium/components/version_ui/resources/about_version.html b/chromium/components/version_ui/resources/about_version.html
index 43fb3ad4a49..924a68c7e40 100644
--- a/chromium/components/version_ui/resources/about_version.html
+++ b/chromium/components/version_ui/resources/about_version.html
@@ -7,6 +7,7 @@ about:version template page
<html id="t" dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <meta name="color-scheme" content="light dark">
<title>$i18n{title}</title>
<if expr="not is_android and not is_ios">
<link rel="icon" type="image/png" sizes="32x32"
@@ -26,6 +27,7 @@ about:version template page
<script src="chrome://resources/js/ios/web_ui.js"></script>
</if>
+ <script src="chrome://resources/js/assert.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/js/cr.js"></script>
<script src="chrome://resources/js/load_time_data.js"></script>
@@ -128,11 +130,6 @@ about:version template page
</td>
</tr>
</if>
-<if expr="not is_android and not is_ios">
- <tr><td class="label">$i18n{flash_plugin}</td>
- <td class="version" id="flash_version">$i18n{flash_version}</td>
- </tr>
-</if>
<tr><td class="label">$i18n{user_agent_name}</td>
<td class="version" id="useragent">$i18n{useragent}</td>
</tr>
diff --git a/chromium/components/version_ui/resources/about_version.js b/chromium/components/version_ui/resources/about_version.js
index 027279ca397..24deedd9bb7 100644
--- a/chromium/components/version_ui/resources/about_version.js
+++ b/chromium/components/version_ui/resources/about_version.js
@@ -34,14 +34,6 @@ function handlePathInfo({execPath, profilePath}) {
}
/**
- * Promise resolution handler for the Flash version to display.
- * @param {string} flashVersion The Flash version to display.
- */
-function handlePluginInfo(flashVersion) {
- $('flash_version').textContent = flashVersion;
-}
-
-/**
* Callback from the backend with the OS version to display.
* @param {string} osVersion The OS version to display.
*/
@@ -84,7 +76,6 @@ function onLoadWork() {
const includeVariationsCmd = location.search.includes("show-variations-cmd");
cr.sendWithPromise('requestVariationInfo', includeVariationsCmd)
.then(handleVariationInfo);
- cr.sendWithPromise('requestPluginInfo').then(handlePluginInfo);
cr.sendWithPromise('requestPathInfo').then(handlePathInfo);
if (cr.isChromeOS) {
diff --git a/chromium/components/version_ui/version_ui_constants.cc b/chromium/components/version_ui/version_ui_constants.cc
index 07518278edd..4acf13cf0b2 100644
--- a/chromium/components/version_ui/version_ui_constants.cc
+++ b/chromium/components/version_ui/version_ui_constants.cc
@@ -13,7 +13,6 @@ const char kVersionJS[] = "version.js";
// Message handlers.
const char kRequestVersionInfo[] = "requestVersionInfo";
const char kRequestVariationInfo[] = "requestVariationInfo";
-const char kRequestPluginInfo[] = "requestPluginInfo";
const char kRequestPathInfo[] = "requestPathInfo";
// Named keys used in message handler responses.
@@ -48,10 +47,6 @@ const char kExecutablePathName[] = "executable_path_name";
#if defined(OS_CHROMEOS)
const char kFirmwareVersion[] = "firmware_version";
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-const char kFlashPlugin[] = "flash_plugin";
-const char kFlashVersion[] = "flash_version";
-#endif
#if !defined(OS_IOS)
const char kJSEngine[] = "js_engine";
const char kJSVersion[] = "js_version";
diff --git a/chromium/components/version_ui/version_ui_constants.h b/chromium/components/version_ui/version_ui_constants.h
index a1b671179e9..d8ffef4d080 100644
--- a/chromium/components/version_ui/version_ui_constants.h
+++ b/chromium/components/version_ui/version_ui_constants.h
@@ -18,7 +18,6 @@ extern const char kVersionJS[];
// Must match the constants used in the resource files.
extern const char kRequestVersionInfo[];
extern const char kRequestVariationInfo[];
-extern const char kRequestPluginInfo[];
extern const char kRequestPathInfo[];
extern const char kKeyVariationsList[];
@@ -53,10 +52,6 @@ extern const char kExecutablePathName[];
#if defined(OS_CHROMEOS)
extern const char kFirmwareVersion[];
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
-extern const char kFlashPlugin[];
-extern const char kFlashVersion[];
-#endif
#if !defined(OS_IOS)
extern const char kJSEngine[];
extern const char kJSVersion[];
diff --git a/chromium/components/visitedlink/browser/visitedlink_writer.cc b/chromium/components/visitedlink/browser/visitedlink_writer.cc
index aea3b152c8c..e8af3af2676 100644
--- a/chromium/components/visitedlink/browser/visitedlink_writer.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_writer.cc
@@ -12,7 +12,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/stack_container.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
diff --git a/chromium/components/viz/BUILD.gn b/chromium/components/viz/BUILD.gn
index 7e7c9111715..49ef7f144e8 100644
--- a/chromium/components/viz/BUILD.gn
+++ b/chromium/components/viz/BUILD.gn
@@ -58,3 +58,18 @@ viz_test("viz_perftests") {
"//testing:run_perf_test",
]
}
+
+if (is_android) {
+ java_cpp_features("java_features_srcjar") {
+ # External code should depend on ":viz_java" instead.
+ visibility = [ ":*" ]
+ sources = [ "common/features.cc" ]
+ template = "common/java/src/org/chromium/components/viz/common/VizFeatures.java.tmpl"
+ }
+
+ android_library("viz_java") {
+ # Right now, this only includes the Java features. But if we need more Java
+ # files, they should be added here as necessary.
+ srcjar_deps = [ ":java_features_srcjar" ]
+ }
+}
diff --git a/chromium/components/viz/OWNERS b/chromium/components/viz/OWNERS
index af9a9b17652..b9559dfa244 100644
--- a/chromium/components/viz/OWNERS
+++ b/chromium/components/viz/OWNERS
@@ -45,6 +45,7 @@ flackr@chromium.org
ccameron@chromium.org
dcastagna@chromium.org
khushalsagar@chromium.org
+magchen@chromium.org
# scheduling / begin frames
sunnyps@chromium.org
diff --git a/chromium/components/viz/client/client_resource_provider.cc b/chromium/components/viz/client/client_resource_provider.cc
index ee2871b3f49..e5cc30730f1 100644
--- a/chromium/components/viz/client/client_resource_provider.cc
+++ b/chromium/components/viz/client/client_resource_provider.cc
@@ -20,6 +20,7 @@
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
namespace viz {
@@ -358,13 +359,13 @@ void ClientResourceProvider::ShutdownAndReleaseAllResources() {
}
ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
- GrContext* gr_context,
+ GrDirectContext* gr_context,
sk_sp<SkColorSpace> color_space,
GLuint texture_id,
GLenum texture_target,
const gfx::Size& size,
ResourceFormat format,
- bool can_use_lcd_text,
+ SkSurfaceProps surface_props,
int msaa_sample_count) {
GrGLTextureInfo texture_info;
texture_info.fID = texture_id;
@@ -372,7 +373,6 @@ ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
texture_info.fFormat = TextureStorageFormat(format);
GrBackendTexture backend_texture(size.width(), size.height(),
GrMipMapped::kNo, texture_info);
- SkSurfaceProps surface_props = ComputeSurfaceProps(can_use_lcd_text);
// This type is used only for gpu raster, which implies gpu compositing.
bool gpu_compositing = true;
surface_ = SkSurface::MakeFromBackendTexture(
@@ -386,19 +386,6 @@ ClientResourceProvider::ScopedSkSurface::~ScopedSkSurface() {
surface_->flushAndSubmit();
}
-SkSurfaceProps ClientResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
- bool can_use_lcd_text) {
- uint32_t flags = 0;
- // Use unknown pixel geometry to disable LCD text.
- SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
- if (can_use_lcd_text) {
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- surface_props =
- SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
- }
- return surface_props;
-}
-
void ClientResourceProvider::ValidateResource(ResourceId id) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(id);
diff --git a/chromium/components/viz/client/client_resource_provider.h b/chromium/components/viz/client/client_resource_provider.h
index 6fff0958085..178b09c4e19 100644
--- a/chromium/components/viz/client/client_resource_provider.h
+++ b/chromium/components/viz/client/client_resource_provider.h
@@ -112,20 +112,18 @@ class VIZ_CLIENT_EXPORT ClientResourceProvider {
class VIZ_CLIENT_EXPORT ScopedSkSurface {
public:
- ScopedSkSurface(GrContext* gr_context,
+ ScopedSkSurface(GrDirectContext* gr_context,
sk_sp<SkColorSpace> color_space,
GLuint texture_id,
GLenum texture_target,
const gfx::Size& size,
ResourceFormat format,
- bool can_use_lcd_text,
+ SkSurfaceProps surface_props,
int msaa_sample_count);
~ScopedSkSurface();
SkSurface* surface() const { return surface_.get(); }
- static SkSurfaceProps ComputeSurfaceProps(bool can_use_lcd_text);
-
private:
sk_sp<SkSurface> surface_;
diff --git a/chromium/components/viz/client/client_resource_provider_unittest.cc b/chromium/components/viz/client/client_resource_provider_unittest.cc
index 524564fa89f..ac4e2248c72 100644
--- a/chromium/components/viz/client/client_resource_provider_unittest.cc
+++ b/chromium/components/viz/client/client_resource_provider_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/test/gtest_util.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/resources/single_release_callback.h"
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index f3c258357cc..1f11eb78edf 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -7,13 +7,6 @@ import("//gpu/vulkan/features.gni")
import("//skia/features.gni")
import("//testing/test.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
source_set("resource_format") {
sources = [ "resources/resource_format.h" ]
}
@@ -26,7 +19,6 @@ viz_component("resource_format_utils") {
sources = [
"resources/resource_format_utils.cc",
"resources/resource_format_utils.h",
- "resources/resource_format_utils_mac.mm",
"resources/resource_sizes.h",
"viz_resource_format_export.h",
]
@@ -47,6 +39,9 @@ viz_component("resource_format_utils") {
if (enable_vulkan) {
deps += [ "//third_party/vulkan_headers" ]
}
+ if (is_mac) {
+ sources += [ "resources/resource_format_utils_mac.mm" ]
+ }
}
# TODO(sgilhuly): To reduce link times, merge these context provider components
@@ -290,6 +285,7 @@ viz_component("common") {
deps = [
"//base",
"//build:chromecast_buildflags",
+ "//build:chromeos_buildflags",
# TODO(staraz): cc/base was added because SharedQuadState includes
# cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
@@ -382,6 +378,9 @@ viz_source_set("unit_tests") {
]
}
+ if (enable_vulkan) {
+ sources += [ "gpu/vulkan_in_process_context_provider_unittest.cc" ]
+ }
deps = [
":common",
"//base/test:test_support",
diff --git a/chromium/components/viz/common/DEPS b/chromium/components/viz/common/DEPS
index f40bbfd2a81..7896474f541 100644
--- a/chromium/components/viz/common/DEPS
+++ b/chromium/components/viz/common/DEPS
@@ -36,6 +36,7 @@ specific_include_rules = {
],
"features.cc" : [
"+gpu/config/gpu_finch_features.h",
+ "+gpu/config/gpu_switches.h",
],
"bitmap_allocation.cc" : [
# Only used to pass Mojo handles, not to communicate with the viz service.
diff --git a/chromium/components/viz/common/delegated_ink_metadata.cc b/chromium/components/viz/common/delegated_ink_metadata.cc
index 13c964ae0ee..3215d5c620a 100644
--- a/chromium/components/viz/common/delegated_ink_metadata.cc
+++ b/chromium/components/viz/common/delegated_ink_metadata.cc
@@ -12,10 +12,11 @@ namespace viz {
std::string DelegatedInkMetadata::ToString() const {
std::string str = base::StringPrintf(
"point: %s, diameter: %f, color: %u, timestamp: %" PRId64
- ", presentation_area: %s",
+ ", presentation_area: %s, frame_time: %" PRId64,
point_.ToString().c_str(), diameter_, color_,
timestamp_.since_origin().InMicroseconds(),
- presentation_area_.ToString().c_str());
+ presentation_area_.ToString().c_str(),
+ frame_time_.since_origin().InMicroseconds());
return str;
}
diff --git a/chromium/components/viz/common/delegated_ink_metadata.h b/chromium/components/viz/common/delegated_ink_metadata.h
index 240310eb7d0..4d297f90626 100644
--- a/chromium/components/viz/common/delegated_ink_metadata.h
+++ b/chromium/components/viz/common/delegated_ink_metadata.h
@@ -34,6 +34,18 @@ class VIZ_COMMON_EXPORT DelegatedInkMetadata {
color_(color),
timestamp_(timestamp),
presentation_area_(area) {}
+ DelegatedInkMetadata(const gfx::PointF& pt,
+ double diameter,
+ SkColor color,
+ base::TimeTicks timestamp,
+ const gfx::RectF& area,
+ base::TimeTicks frame_time)
+ : point_(pt),
+ diameter_(diameter),
+ color_(color),
+ timestamp_(timestamp),
+ presentation_area_(area),
+ frame_time_(frame_time) {}
DelegatedInkMetadata(const DelegatedInkMetadata& other) = default;
const gfx::PointF& point() const { return point_; }
@@ -41,6 +53,9 @@ class VIZ_COMMON_EXPORT DelegatedInkMetadata {
SkColor color() const { return color_; }
base::TimeTicks timestamp() const { return timestamp_; }
const gfx::RectF& presentation_area() const { return presentation_area_; }
+ base::TimeTicks frame_time() const { return frame_time_; }
+
+ void set_frame_time(base::TimeTicks frame_time) { frame_time_ = frame_time; }
std::string ToString() const;
@@ -59,6 +74,9 @@ class VIZ_COMMON_EXPORT DelegatedInkMetadata {
// The rect to clip the ink trail to, defaults to the containing viewport.
gfx::RectF presentation_area_;
+
+ // Frame time of the layer tree that this metadata is on.
+ base::TimeTicks frame_time_;
};
} // namespace viz
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index 9139abd3a99..e8a259cb441 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -10,6 +10,7 @@
#include "components/viz/common/switches.h"
#include "components/viz/common/viz_utils.h"
#include "gpu/config/gpu_finch_features.h"
+#include "gpu/config/gpu_switches.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
@@ -21,14 +22,15 @@ const base::Feature kForcePreferredIntervalForVideo{
"ForcePreferredIntervalForVideo", base::FEATURE_DISABLED_BY_DEFAULT};
// Use the SkiaRenderer.
+const base::Feature kUseSkiaRenderer {
+ "UseSkiaRenderer",
#if defined(OS_WIN) || \
(defined(OS_LINUX) && !(defined(OS_CHROMEOS) || BUILDFLAG(IS_CHROMECAST)))
-const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
- base::FEATURE_ENABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT
#else
-const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_DISABLED_BY_DEFAULT
#endif
+};
// Kill-switch to disable de-jelly, even if flags/properties indicate it should
// be enabled.
@@ -42,6 +44,10 @@ const base::Feature kDynamicColorGamut{"DynamicColorGamut",
base::FEATURE_ENABLED_BY_DEFAULT};
#endif
+// Uses glClear to composite solid color quads whenever possible.
+const base::Feature kFastSolidColorDraw{"FastSolidColorDraw",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Viz for WebView architecture.
const base::Feature kVizForWebView{"VizForWebView",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -51,13 +57,14 @@ const base::Feature kVizForWebView{"VizForWebView",
const base::Feature kVizFrameSubmissionForWebView{
"VizFrameSubmissionForWebView", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
const base::Feature kUsePreferredIntervalForVideo{
- "UsePreferredIntervalForVideo", base::FEATURE_DISABLED_BY_DEFAULT};
+ "UsePreferredIntervalForVideo",
+#if defined(OS_ANDROID)
+ base::FEATURE_DISABLED_BY_DEFAULT
#else
-const base::Feature kUsePreferredIntervalForVideo{
- "UsePreferredIntervalForVideo", base::FEATURE_ENABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT
#endif
+};
// Whether we should use the real buffers corresponding to overlay candidates in
// order to do a pageflip test rather than allocating test buffers.
@@ -107,8 +114,17 @@ bool IsUsingSkiaRenderer() {
if (IsUsingVizForWebView())
return true;
+#if BUILDFLAG(IS_ASH)
+ // TODO(https://crbug.com/1145180): SkiaRenderer isn't supported on Chrome
+ // OS boards that still use the legacy video decoder.
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(
+ switches::kPlatformDisallowsChromeOSDirectVideoDecoder))
+ return false;
+#endif
+
return base::FeatureList::IsEnabled(kUseSkiaRenderer) ||
- base::FeatureList::IsEnabled(kVulkan);
+ features::IsUsingVulkan();
}
#if defined(OS_ANDROID)
@@ -122,12 +138,17 @@ bool IsDynamicColorGamutEnabled() {
}
#endif
+bool IsUsingFastPathForSolidColorQuad() {
+ return base::FeatureList::IsEnabled(kFastSolidColorDraw);
+}
+
bool IsUsingVizForWebView() {
// Viz for WebView requires shared images to be enabled.
if (!base::FeatureList::IsEnabled(kEnableSharedImageForWebview))
return false;
- return base::FeatureList::IsEnabled(kVizForWebView);
+ return base::FeatureList::IsEnabled(kVizForWebView) ||
+ features::IsUsingVulkan();
}
bool IsUsingVizFrameSubmissionForWebView() {
diff --git a/chromium/components/viz/common/features.h b/chromium/components/viz/common/features.h
index 72491fe87be..b7c73764ebb 100644
--- a/chromium/components/viz/common/features.h
+++ b/chromium/components/viz/common/features.h
@@ -20,6 +20,7 @@ VIZ_COMMON_EXPORT extern const base::Feature kDisableDeJelly;
#if defined(OS_ANDROID)
VIZ_COMMON_EXPORT extern const base::Feature kDynamicColorGamut;
#endif
+VIZ_COMMON_EXPORT extern const base::Feature kFastSolidColorDraw;
VIZ_COMMON_EXPORT extern const base::Feature kVizForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kVizFrameSubmissionForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kUsePreferredIntervalForVideo;
@@ -38,6 +39,7 @@ VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
#if defined(OS_ANDROID)
VIZ_COMMON_EXPORT bool IsDynamicColorGamutEnabled();
#endif
+VIZ_COMMON_EXPORT bool IsUsingFastPathForSolidColorQuad();
VIZ_COMMON_EXPORT bool IsUsingVizForWebView();
VIZ_COMMON_EXPORT bool IsUsingVizFrameSubmissionForWebView();
VIZ_COMMON_EXPORT bool IsUsingPreferredIntervalForVideo();
diff --git a/chromium/components/viz/common/gl_i420_converter.h b/chromium/components/viz/common/gl_i420_converter.h
index b5be44c5d6f..0f1424e9156 100644
--- a/chromium/components/viz/common/gl_i420_converter.h
+++ b/chromium/components/viz/common/gl_i420_converter.h
@@ -71,7 +71,7 @@ class ContextProvider;
// planar image data is packed into GL_RGBA textures, how the output textures
// should be sized, and why there are alignment requirements when specifying the
// output rect.
-class VIZ_COMMON_EXPORT GLI420Converter : public ContextLostObserver {
+class VIZ_COMMON_EXPORT GLI420Converter final : public ContextLostObserver {
public:
// GLI420Converter uses the exact same parameters as GLScaler.
using Parameters = GLScaler::Parameters;
diff --git a/chromium/components/viz/common/gl_scaler.h b/chromium/components/viz/common/gl_scaler.h
index 9304ba2b0a1..7b7b3199163 100644
--- a/chromium/components/viz/common/gl_scaler.h
+++ b/chromium/components/viz/common/gl_scaler.h
@@ -40,7 +40,7 @@ class ContextProvider;
// can be configured to operate at different quality levels, manages/converts
// color spaces, and optionally re-arranges/formats data in output textures for
// use with more-efficient texture readback pipelines.
-class VIZ_COMMON_EXPORT GLScaler : public ContextLostObserver {
+class VIZ_COMMON_EXPORT GLScaler final : public ContextLostObserver {
public:
struct VIZ_COMMON_EXPORT Parameters {
// Relative scale from/to factors. Both of these must be non-zero.
diff --git a/chromium/components/viz/common/gpu/context_provider.cc b/chromium/components/viz/common/gpu/context_provider.cc
index 8a7abac4791..180c530b622 100644
--- a/chromium/components/viz/common/gpu/context_provider.cc
+++ b/chromium/components/viz/common/gpu/context_provider.cc
@@ -4,6 +4,8 @@
#include "components/viz/common/gpu/context_provider.h"
+#include <utility>
+
namespace viz {
ContextProvider::ScopedContextLock::ScopedContextLock(
@@ -17,12 +19,4 @@ ContextProvider::ScopedContextLock::~ScopedContextLock() {
// Let ContextCacheController know we are no longer busy.
context_provider_->CacheController()->ClientBecameNotBusy(std::move(busy_));
}
-
-gpu::SharedImageManager* ContextProvider::GetSharedImageManager() {
- return nullptr;
-}
-
-gpu::MemoryTracker* ContextProvider::GetMemoryTracker() {
- return nullptr;
-}
} // namespace viz
diff --git a/chromium/components/viz/common/gpu/context_provider.h b/chromium/components/viz/common/gpu/context_provider.h
index a2176ccb3eb..140edc66775 100644
--- a/chromium/components/viz/common/gpu/context_provider.h
+++ b/chromium/components/viz/common/gpu/context_provider.h
@@ -28,9 +28,7 @@ class Lock;
namespace gpu {
class ContextSupport;
struct GpuFeatureInfo;
-class MemoryTracker;
class SharedImageInterface;
-class SharedImageManager;
namespace gles2 {
class GLES2Interface;
@@ -112,12 +110,6 @@ class VIZ_COMMON_EXPORT ContextProvider {
// been successfully bound to a thread before calling this.
virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
- // Returns the SharedImageManager. Only available inside the GPU process.
- virtual gpu::SharedImageManager* GetSharedImageManager();
-
- // Plumbs out the memory tracker to be shared with overlay.
- virtual gpu::MemoryTracker* GetMemoryTracker();
-
protected:
virtual ~ContextProvider() = default;
};
diff --git a/chromium/components/viz/common/gpu/vulkan_context_provider.h b/chromium/components/viz/common/gpu/vulkan_context_provider.h
index fc823ba2cdc..0a09cdc65d6 100644
--- a/chromium/components/viz/common/gpu/vulkan_context_provider.h
+++ b/chromium/components/viz/common/gpu/vulkan_context_provider.h
@@ -12,6 +12,7 @@
#include "components/viz/common/viz_vulkan_context_provider_export.h"
#include "third_party/vulkan_headers/include/vulkan/vulkan.h"
+struct GrContextOptions;
class GrDirectContext;
class GrVkSecondaryCBDrawContext;
@@ -26,6 +27,7 @@ namespace viz {
class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanContextProvider
: public base::RefCountedThreadSafe<VulkanContextProvider> {
public:
+ virtual bool InitializeGrContext(const GrContextOptions& context_options) = 0;
virtual gpu::VulkanImplementation* GetVulkanImplementation() = 0;
virtual gpu::VulkanDeviceQueue* GetDeviceQueue() = 0;
virtual GrDirectContext* GetGrContext() = 0;
@@ -42,6 +44,13 @@ class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanContextProvider
// semphores are submitted.
virtual void EnqueueSecondaryCBPostSubmitTask(base::OnceClosure closure) = 0;
+ // Returns a valid limit in MB if there is a memory limit where GPU work
+ // should be synchronized with the CPU in order to free previously released
+ // memory immediately. In other words, the CPU will wait for GPU work to
+ // complete before proceeding when the current amount of allocated memory
+ // exceeds this limit.
+ virtual base::Optional<uint32_t> GetSyncCpuMemoryLimit() const = 0;
+
protected:
friend class base::RefCountedThreadSafe<VulkanContextProvider>;
virtual ~VulkanContextProvider() {}
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index 0a30603f3c1..bd7ffac4a6d 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -17,31 +17,53 @@
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/vk/GrVkExtensions.h"
+namespace {
+
+// Setting this limit to 0 practically forces sync at every submit.
+constexpr uint32_t kSyncCpuMemoryLimitAtMemoryPressureCritical = 0;
+
+} // namespace
+
namespace viz {
// static
scoped_refptr<VulkanInProcessContextProvider>
VulkanInProcessContextProvider::Create(
gpu::VulkanImplementation* vulkan_implementation,
- const GrContextOptions& options,
- const gpu::GPUInfo* gpu_info) {
+ uint32_t heap_memory_limit,
+ uint32_t sync_cpu_memory_limit,
+ const gpu::GPUInfo* gpu_info,
+ base::TimeDelta cooldown_duration_at_memory_pressure_critical) {
scoped_refptr<VulkanInProcessContextProvider> context_provider(
- new VulkanInProcessContextProvider(vulkan_implementation));
- if (!context_provider->Initialize(options, gpu_info))
+ new VulkanInProcessContextProvider(
+ vulkan_implementation, heap_memory_limit, sync_cpu_memory_limit,
+ cooldown_duration_at_memory_pressure_critical));
+ if (!context_provider->Initialize(gpu_info))
return nullptr;
return context_provider;
}
VulkanInProcessContextProvider::VulkanInProcessContextProvider(
- gpu::VulkanImplementation* vulkan_implementation)
- : vulkan_implementation_(vulkan_implementation) {}
+ gpu::VulkanImplementation* vulkan_implementation,
+ uint32_t heap_memory_limit,
+ uint32_t sync_cpu_memory_limit,
+ base::TimeDelta cooldown_duration_at_memory_pressure_critical)
+ : vulkan_implementation_(vulkan_implementation),
+ heap_memory_limit_(heap_memory_limit),
+ sync_cpu_memory_limit_(sync_cpu_memory_limit),
+ cooldown_duration_at_memory_pressure_critical_(
+ cooldown_duration_at_memory_pressure_critical) {
+ memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
+ FROM_HERE,
+ base::BindRepeating(&VulkanInProcessContextProvider::OnMemoryPressure,
+ base::Unretained(this)));
+}
VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
Destroy();
}
bool VulkanInProcessContextProvider::Initialize(
- const GrContextOptions& context_options,
const gpu::GPUInfo* gpu_info) {
DCHECK(!device_queue_);
@@ -59,11 +81,16 @@ bool VulkanInProcessContextProvider::Initialize(
}
}
- device_queue_ =
- gpu::CreateVulkanDeviceQueue(vulkan_implementation_, flags, gpu_info);
+ device_queue_ = gpu::CreateVulkanDeviceQueue(vulkan_implementation_, flags,
+ gpu_info, heap_memory_limit_);
if (!device_queue_)
return false;
+ return true;
+}
+
+bool VulkanInProcessContextProvider::InitializeGrContext(
+ const GrContextOptions& context_options) {
GrVkBackendContext backend_context;
backend_context.fInstance = device_queue_->GetVulkanInstance();
backend_context.fPhysicalDevice = device_queue_->GetVulkanPhysicalDevice();
@@ -86,6 +113,10 @@ bool VulkanInProcessContextProvider::Initialize(
return vkGetInstanceProcAddr(instance, proc_name);
};
+ const auto& instance_extensions = vulkan_implementation_->GetVulkanInstance()
+ ->vulkan_info()
+ .enabled_instance_extensions;
+
std::vector<const char*> device_extensions;
device_extensions.reserve(device_queue_->enabled_extensions().size());
for (const auto& extension : device_queue_->enabled_extensions())
@@ -158,4 +189,24 @@ void VulkanInProcessContextProvider::EnqueueSecondaryCBPostSubmitTask(
NOTREACHED();
}
+base::Optional<uint32_t> VulkanInProcessContextProvider::GetSyncCpuMemoryLimit()
+ const {
+ // Return false to indicate that there's no limit.
+ if (!sync_cpu_memory_limit_)
+ return base::Optional<uint32_t>();
+ return base::TimeTicks::Now() < critical_memory_pressure_expiration_time_
+ ? base::Optional<uint32_t>(
+ kSyncCpuMemoryLimitAtMemoryPressureCritical)
+ : base::Optional<uint32_t>(sync_cpu_memory_limit_);
+}
+
+void VulkanInProcessContextProvider::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level) {
+ if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL)
+ return;
+
+ critical_memory_pressure_expiration_time_ =
+ base::TimeTicks::Now() + cooldown_duration_at_memory_pressure_critical_;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
index ec6676ee1d6..971b25823cc 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -8,6 +8,8 @@
#include <memory>
#include <vector>
+#include "base/memory/memory_pressure_listener.h"
+#include "base/time/time.h"
#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/viz_vulkan_context_provider_export.h"
#include "gpu/vulkan/buildflags.h"
@@ -28,14 +30,22 @@ namespace viz {
class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanInProcessContextProvider
: public VulkanContextProvider {
public:
+ // if |sync_cpu_memory_limit| is set and greater than zero,
+ // |cooldown_duration_at_memory_pressure_critical| is the duration of applying
+ // zero sync cpu memory limit after CRITICAL memory pressure signal is
+ // received. 15s is default to sync with memory monitor cycles.
static scoped_refptr<VulkanInProcessContextProvider> Create(
gpu::VulkanImplementation* vulkan_implementation,
- const GrContextOptions& context_options = GrContextOptions(),
- const gpu::GPUInfo* gpu_info = nullptr);
+ uint32_t heap_memory_limit = 0,
+ uint32_t sync_cpu_memory_limit = 0,
+ const gpu::GPUInfo* gpu_info = nullptr,
+ base::TimeDelta cooldown_duration_at_memory_pressure_critical =
+ base::TimeDelta::FromSeconds(15));
void Destroy();
// VulkanContextProvider implementation
+ bool InitializeGrContext(const GrContextOptions& context_options) override;
gpu::VulkanImplementation* GetVulkanImplementation() override;
gpu::VulkanDeviceQueue* GetDeviceQueue() override;
GrDirectContext* GetGrContext() override;
@@ -43,21 +53,36 @@ class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanInProcessContextProvider
void EnqueueSecondaryCBSemaphores(
std::vector<VkSemaphore> semaphores) override;
void EnqueueSecondaryCBPostSubmitTask(base::OnceClosure closure) override;
+ base::Optional<uint32_t> GetSyncCpuMemoryLimit() const override;
private:
- explicit VulkanInProcessContextProvider(
- gpu::VulkanImplementation* vulkan_implementation);
+ friend class VulkanInProcessContextProviderTest;
+
+ VulkanInProcessContextProvider(
+ gpu::VulkanImplementation* vulkan_implementation,
+ uint32_t heap_memory_limit,
+ uint32_t sync_cpu_memory_limit,
+ base::TimeDelta cooldown_duration_at_memory_pressure_critical);
~VulkanInProcessContextProvider() override;
- bool Initialize(const GrContextOptions& context_options,
- const gpu::GPUInfo* gpu_info);
+ bool Initialize(const gpu::GPUInfo* gpu_info);
+
+ // Memory pressure handler, called by |memory_pressure_listener_|.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel level);
#if BUILDFLAG(ENABLE_VULKAN)
sk_sp<GrDirectContext> gr_context_;
gpu::VulkanImplementation* vulkan_implementation_;
std::unique_ptr<gpu::VulkanDeviceQueue> device_queue_;
+ const uint32_t heap_memory_limit_;
+ const uint32_t sync_cpu_memory_limit_;
+ const base::TimeDelta cooldown_duration_at_memory_pressure_critical_;
+ base::TimeTicks critical_memory_pressure_expiration_time_;
#endif
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
DISALLOW_COPY_AND_ASSIGN(VulkanInProcessContextProvider);
};
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider_unittest.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider_unittest.cc
new file mode 100644
index 00000000000..c69b31ebf44
--- /dev/null
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider_unittest.cc
@@ -0,0 +1,75 @@
+// Copyright 2021 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/viz/common/gpu/vulkan_in_process_context_provider.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+
+class VulkanInProcessContextProviderTest : public testing::Test {
+ public:
+ void CreateVulkanInProcessContextProvider(
+ uint32_t sync_cpu_memory_limit,
+ const base::TimeDelta& cooldown_duration_at_memory_pressure_critical) {
+ context_provider_ = new VulkanInProcessContextProvider(
+ nullptr, 0, sync_cpu_memory_limit,
+ cooldown_duration_at_memory_pressure_critical);
+ }
+
+ void TearDown() override { context_provider_.reset(); }
+
+ void SendCriticalMemoryPressureSignal() {
+ context_provider_->OnMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ }
+
+ protected:
+ scoped_refptr<VulkanInProcessContextProvider> context_provider_;
+};
+
+TEST_F(VulkanInProcessContextProviderTest,
+ NotifyMemoryPressureChangesSyncCpuMemoryLimit) {
+ const uint32_t kTestSyncCpuMemoryLimit = 1234;
+ CreateVulkanInProcessContextProvider(kTestSyncCpuMemoryLimit,
+ base::TimeDelta::Max());
+
+ auto limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_TRUE(limit.has_value());
+ EXPECT_EQ(kTestSyncCpuMemoryLimit, limit.value());
+
+ SendCriticalMemoryPressureSignal();
+ limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_TRUE(limit.has_value());
+ EXPECT_EQ(0u, limit.value());
+}
+
+TEST_F(VulkanInProcessContextProviderTest,
+ ZeroSyncCpuMemoryLimitDoesNotChange) {
+ CreateVulkanInProcessContextProvider(0, base::TimeDelta::Max());
+
+ auto limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_FALSE(limit.has_value());
+
+ SendCriticalMemoryPressureSignal();
+ limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_FALSE(limit.has_value());
+}
+
+TEST_F(VulkanInProcessContextProviderTest, SyncCpuMemoryResetsAfterCooldown) {
+ const uint32_t kTestSyncCpuMemoryLimit = 1234;
+ CreateVulkanInProcessContextProvider(kTestSyncCpuMemoryLimit,
+ base::TimeDelta::Min());
+
+ auto limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_TRUE(limit.has_value());
+ EXPECT_EQ(kTestSyncCpuMemoryLimit, limit.value());
+
+ SendCriticalMemoryPressureSignal();
+ limit = context_provider_->GetSyncCpuMemoryLimit();
+ EXPECT_TRUE(limit.has_value());
+ EXPECT_EQ(kTestSyncCpuMemoryLimit, limit.value());
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/java/src/org/chromium/components/viz/common/VizFeatures.java.tmpl b/chromium/components/viz/common/java/src/org/chromium/components/viz/common/VizFeatures.java.tmpl
new file mode 100644
index 00000000000..a0d09475f64
--- /dev/null
+++ b/chromium/components/viz/common/java/src/org/chromium/components/viz/common/VizFeatures.java.tmpl
@@ -0,0 +1,16 @@
+// Copyright 2020 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.components.viz.common;
+
+/**
+ * Constants for the names of Viz Features.
+ */
+public final class VizFeatures {{
+
+{NATIVE_FEATURES}
+
+ // Prevent instantiation.
+ private VizFeatures() {{}}
+}}
diff --git a/chromium/components/viz/common/quads/DEPS b/chromium/components/viz/common/quads/DEPS
index 145b8185b7a..0420c1120fa 100644
--- a/chromium/components/viz/common/quads/DEPS
+++ b/chromium/components/viz/common/quads/DEPS
@@ -21,6 +21,6 @@ specific_include_rules = {
"+cc/test",
],
"yuv_video_draw_quad.*": [
- "+ui/gl/hdr_metadata.h",
+ "+ui/gfx/hdr_metadata.h",
],
}
diff --git a/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc b/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
index cda0bebd9d3..720dfd4298d 100644
--- a/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
+++ b/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
@@ -85,7 +85,7 @@ TEST(CompositorRenderPassTest,
// Stick a quad in the pass, this should not get copied.
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -144,7 +144,7 @@ TEST(CompositorRenderPassTest, CopyAllShouldBeIdentical) {
// Two quads using one shared state.
SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* color_quad1 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -160,7 +160,7 @@ TEST(CompositorRenderPassTest, CopyAllShouldBeIdentical) {
// And two quads using another shared state.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* color_quad3 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -201,8 +201,8 @@ TEST(CompositorRenderPassTest, CopyAllShouldBeIdentical) {
SharedQuadState* contrib_shared_state =
contrib->CreateAndAppendSharedQuadState();
contrib_shared_state->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2),
- gfx::Rect(), gfx::RRectF(), gfx::Rect(), false,
- false, 1, SkBlendMode::kSrcOver, 0);
+ gfx::Rect(), gfx::MaskFilterInfo(), gfx::Rect(),
+ false, false, 1, SkBlendMode::kSrcOver, 0);
auto* contrib_quad = contrib->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
contrib_quad->SetNew(contrib->shared_quad_state_list.back(),
@@ -254,7 +254,7 @@ TEST(CompositorRenderPassTest, CopyAllWithCulledQuads) {
// A shared state with a quad.
SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* color_quad1 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -265,19 +265,19 @@ TEST(CompositorRenderPassTest, CopyAllWithCulledQuads) {
// A shared state with no quads, they were culled.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
// A second shared state with no quads.
SharedQuadState* shared_state3 = pass->CreateAndAppendSharedQuadState();
shared_state3->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
// A last shared state with a quad again.
SharedQuadState* shared_state4 = pass->CreateAndAppendSharedQuadState();
shared_state4->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
- gfx::RRectF(), gfx::Rect(), false, false, 1,
+ gfx::MaskFilterInfo(), gfx::Rect(), false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* color_quad2 = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -295,14 +295,25 @@ TEST(CompositorRenderPassTest, CopyAllWithCulledQuads) {
}
TEST(CompositorRenderPassTest, ReplacedQuadsShouldntMove) {
- auto quad_state = std::make_unique<SharedQuadState>();
- QuadList quad_list;
- auto* quad = quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
+ auto pass = CompositorRenderPass::Create();
+ SharedQuadState* quad_state = pass->CreateAndAppendSharedQuadState();
+ auto* quad = pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
+ gfx::Rect quad_rect(1, 2, 3, 4);
+ quad->SetNew(quad_state, quad_rect, quad_rect, SkColor(), false);
+ pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(
+ pass->quad_list.begin());
+ EXPECT_EQ(pass->quad_list.begin()->rect, quad_rect);
+}
+
+TEST(CompositorRenderPassTest, ReplacedQuadsShouldntBeOpaque) {
+ auto pass = CompositorRenderPass::Create();
+ SharedQuadState* quad_state = pass->CreateAndAppendSharedQuadState();
+ auto* quad = pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
gfx::Rect quad_rect(1, 2, 3, 4);
- quad->SetNew(quad_state.get(), quad_rect, quad_rect, SkColor(), false);
- quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(
- quad_list.begin());
- EXPECT_EQ(quad_list.begin()->rect, quad_rect);
+ quad->SetNew(quad_state, quad_rect, quad_rect, SkColor(), false);
+ pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(
+ pass->quad_list.begin());
+ EXPECT_FALSE(pass->quad_list.begin()->shared_quad_state->are_contents_opaque);
}
} // namespace
diff --git a/chromium/components/viz/common/quads/draw_quad.h b/chromium/components/viz/common/quads/draw_quad.h
index 313e208fafc..4900fb67a9b 100644
--- a/chromium/components/viz/common/quads/draw_quad.h
+++ b/chromium/components/viz/common/quads/draw_quad.h
@@ -79,7 +79,7 @@ class VIZ_COMMON_EXPORT DrawQuad {
bool ShouldDrawWithBlending() const {
return needs_blending || shared_quad_state->opacity < 1.0f ||
shared_quad_state->blend_mode != SkBlendMode::kSrcOver ||
- !shared_quad_state->rounded_corner_bounds.IsEmpty();
+ !shared_quad_state->mask_filter_info.IsEmpty();
}
// Is the left edge of this tile aligned with the originating layer's
diff --git a/chromium/components/viz/common/quads/draw_quad_perftest.cc b/chromium/components/viz/common/quads/draw_quad_perftest.cc
index 00f0de92984..3c0d2e6396f 100644
--- a/chromium/components/viz/common/quads/draw_quad_perftest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_perftest.cc
@@ -42,9 +42,9 @@ SharedQuadState* CreateSharedQuadState(CompositorRenderPass* render_pass) {
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
- state->SetAll(quad_transform, content_rect, visible_layer_rect, gfx::RRectF(),
- clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
- sorting_context_id);
+ state->SetAll(quad_transform, content_rect, visible_layer_rect,
+ gfx::MaskFilterInfo(), clip_rect, is_clipped,
+ are_contents_opaque, opacity, blend_mode, sorting_context_id);
return state;
}
diff --git a/chromium/components/viz/common/quads/draw_quad_unittest.cc b/chromium/components/viz/common/quads/draw_quad_unittest.cc
index c40977510fb..11042dad024 100644
--- a/chromium/components/viz/common/quads/draw_quad_unittest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_unittest.cc
@@ -33,8 +33,8 @@
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/transform.h"
-#include "ui/gl/hdr_metadata.h"
namespace viz {
namespace {
@@ -53,9 +53,9 @@ TEST(DrawQuadTest, CopySharedQuadState) {
int sorting_context_id = 65536;
auto state = std::make_unique<SharedQuadState>();
- state->SetAll(quad_transform, layer_rect, visible_layer_rect, gfx::RRectF(),
- clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
- sorting_context_id);
+ state->SetAll(quad_transform, layer_rect, visible_layer_rect,
+ gfx::MaskFilterInfo(), clip_rect, is_clipped,
+ are_contents_opaque, opacity, blend_mode, sorting_context_id);
auto copy = std::make_unique<SharedQuadState>(*state);
EXPECT_EQ(quad_transform, copy->quad_to_target_transform);
@@ -79,9 +79,9 @@ SharedQuadState* CreateSharedQuadState(CompositorRenderPass* render_pass) {
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
- state->SetAll(quad_transform, layer_rect, visible_layer_rect, gfx::RRectF(),
- clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
- sorting_context_id);
+ state->SetAll(quad_transform, layer_rect, visible_layer_rect,
+ gfx::MaskFilterInfo(), clip_rect, is_clipped,
+ are_contents_opaque, opacity, blend_mode, sorting_context_id);
return state;
}
@@ -421,7 +421,7 @@ TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
gfx::ProtectedVideoType protected_video_type =
gfx::ProtectedVideoType::kHardwareProtected;
gfx::ColorSpace video_color_space = gfx::ColorSpace::CreateJpeg();
- gl::HDRMetadata hdr_metadata = gl::HDRMetadata();
+ gfx::HDRMetadata hdr_metadata = gfx::HDRMetadata();
hdr_metadata.max_content_light_level = 1000;
hdr_metadata.max_frame_average_light_level = 100;
@@ -447,7 +447,7 @@ TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
EXPECT_EQ(resource_multiplier, copy_quad->resource_multiplier);
EXPECT_EQ(bits_per_channel, copy_quad->bits_per_channel);
EXPECT_EQ(gfx::ProtectedVideoType::kClear, copy_quad->protected_video_type);
- EXPECT_EQ(gl::HDRMetadata(), copy_quad->hdr_metadata);
+ EXPECT_EQ(gfx::HDRMetadata(), copy_quad->hdr_metadata);
CREATE_QUAD_ALL(YUVVideoDrawQuad, ya_tex_coord_rect, uv_tex_coord_rect,
ya_tex_size, uv_tex_size, y_plane_resource_id,
diff --git a/chromium/components/viz/common/quads/quad_list.cc b/chromium/components/viz/common/quads/quad_list.cc
index ac2b1b8e912..4aab9add56b 100644
--- a/chromium/components/viz/common/quads/quad_list.cc
+++ b/chromium/components/viz/common/quads/quad_list.cc
@@ -34,19 +34,6 @@ QuadList::QuadList(size_t default_size_to_reserve)
LargestDrawQuadSize(),
default_size_to_reserve) {}
-void QuadList::ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at) {
- // In order to fill the backbuffer with transparent black, the replacement
- // solid color quad needs to set |needs_blending| to false, and
- // ShouldDrawWithBlending() returns false so it is drawn without blending.
- const gfx::Rect rect = at->rect;
- bool needs_blending = false;
- const SharedQuadState* shared_quad_state = at->shared_quad_state;
-
- auto* replacement = QuadList::ReplaceExistingElement<SolidColorDrawQuad>(at);
- replacement->SetAll(shared_quad_state, rect, rect /* visible_rect */,
- needs_blending, SK_ColorTRANSPARENT, true);
-}
-
QuadList::Iterator QuadList::InsertCopyBeforeDrawQuad(Iterator at,
size_t count) {
DCHECK(at->shared_quad_state);
diff --git a/chromium/components/viz/common/quads/quad_list.h b/chromium/components/viz/common/quads/quad_list.h
index f551252686b..10ab9abea29 100644
--- a/chromium/components/viz/common/quads/quad_list.h
+++ b/chromium/components/viz/common/quads/quad_list.h
@@ -28,9 +28,6 @@ class VIZ_COMMON_EXPORT QuadList : public cc::ListContainer<DrawQuad> {
inline ConstBackToFrontIterator BackToFrontBegin() const { return rbegin(); }
inline ConstBackToFrontIterator BackToFrontEnd() const { return rend(); }
- // This function is used by overlay algorithm to fill the backbuffer with
- // transparent black.
- void ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at);
Iterator InsertCopyBeforeDrawQuad(Iterator at, size_t count);
};
diff --git a/chromium/components/viz/common/quads/render_pass_internal.cc b/chromium/components/viz/common/quads/render_pass_internal.cc
index 07f6612884a..6c9ac6a426f 100644
--- a/chromium/components/viz/common/quads/render_pass_internal.cc
+++ b/chromium/components/viz/common/quads/render_pass_internal.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "components/viz/common/quads/render_pass_internal.h"
+#include "components/viz/common/quads/solid_color_draw_quad.h"
#include <stddef.h>
@@ -34,4 +35,24 @@ SharedQuadState* RenderPassInternal::CreateAndAppendSharedQuadState() {
return shared_quad_state_list.AllocateAndConstruct<SharedQuadState>();
}
+void RenderPassInternal::ReplaceExistingQuadWithOpaqueTransparentSolidColor(
+ QuadList::Iterator at) {
+ // In order to fill the backbuffer with transparent black, the replacement
+ // solid color quad needs to set |needs_blending| to false, and
+ // ShouldDrawWithBlending() returns false so it is drawn without blending.
+ const gfx::Rect rect = at->rect;
+ bool needs_blending = false;
+ const SharedQuadState* shared_quad_state = at->shared_quad_state;
+ if (shared_quad_state->are_contents_opaque) {
+ auto* new_shared_quad_state =
+ shared_quad_state_list.AllocateAndCopyFrom(shared_quad_state);
+ new_shared_quad_state->are_contents_opaque = false;
+ shared_quad_state = new_shared_quad_state;
+ }
+
+ auto* replacement = quad_list.ReplaceExistingElement<SolidColorDrawQuad>(at);
+ replacement->SetAll(shared_quad_state, rect, rect /* visible_rect */,
+ needs_blending, SK_ColorTRANSPARENT, true);
+}
+
} // namespace viz
diff --git a/chromium/components/viz/common/quads/render_pass_internal.h b/chromium/components/viz/common/quads/render_pass_internal.h
index 6949c19182f..a3a1bbf3401 100644
--- a/chromium/components/viz/common/quads/render_pass_internal.h
+++ b/chromium/components/viz/common/quads/render_pass_internal.h
@@ -31,6 +31,10 @@ class VIZ_COMMON_EXPORT RenderPassInternal {
public:
SharedQuadState* CreateAndAppendSharedQuadState();
+ // Replaces a quad in |quad_list| with a transparent black SolidColorQuad.
+ void ReplaceExistingQuadWithOpaqueTransparentSolidColor(
+ QuadList::Iterator at);
+
// These are in the space of the render pass' physical pixels.
gfx::Rect output_rect;
gfx::Rect damage_rect;
diff --git a/chromium/components/viz/common/quads/render_pass_io.cc b/chromium/components/viz/common/quads/render_pass_io.cc
index f8846e6e184..9903648acd6 100644
--- a/chromium/components/viz/common/quads/render_pass_io.cc
+++ b/chromium/components/viz/common/quads/render_pass_io.cc
@@ -1468,7 +1468,7 @@ bool YUVVideoDrawQuadFromDict(const base::Value& dict,
static_cast<float>(resource_multiplier.value()),
static_cast<uint32_t>(bits_per_channel.value()),
static_cast<gfx::ProtectedVideoType>(protected_video_type_index),
- gl::HDRMetadata());
+ gfx::HDRMetadata());
return true;
}
@@ -1602,7 +1602,8 @@ base::Value SharedQuadStateToDict(const SharedQuadState& sqs) {
dict.SetKey("quad_layer_rect", RectToDict(sqs.quad_layer_rect));
dict.SetKey("visible_quad_layer_rect",
RectToDict(sqs.visible_quad_layer_rect));
- dict.SetKey("rounded_corner_bounds", RRectFToDict(sqs.rounded_corner_bounds));
+ dict.SetKey("rounded_corner_bounds",
+ RRectFToDict(sqs.mask_filter_info.rounded_corner_bounds()));
dict.SetKey("clip_rect", RectToDict(sqs.clip_rect));
dict.SetBoolKey("is_clipped", sqs.is_clipped);
dict.SetBoolKey("are_contents_opaque", sqs.are_contents_opaque);
@@ -1610,10 +1611,6 @@ base::Value SharedQuadStateToDict(const SharedQuadState& sqs) {
dict.SetStringKey("blend_mode", BlendModeToString(sqs.blend_mode));
dict.SetIntKey("sorting_context_id", sqs.sorting_context_id);
dict.SetBoolKey("is_fast_rounded_corner", sqs.is_fast_rounded_corner);
- if (sqs.occluding_damage_rect) {
- dict.SetKey("occluding_damage_rect",
- RectToDict(sqs.occluding_damage_rect.value()));
- }
dict.SetDoubleKey("de_jelly_delta_y", sqs.de_jelly_delta_y);
return dict;
}
@@ -1676,8 +1673,6 @@ bool SharedQuadStateFromDict(const base::Value& dict, SharedQuadState* sqs) {
dict.FindIntKey("sorting_context_id");
base::Optional<bool> is_fast_rounded_corner =
dict.FindBoolKey("is_fast_rounded_corner");
- const base::Value* occluding_damage_rect =
- dict.FindDictKey("occluding_damage_rect");
base::Optional<double> de_jelly_delta_y =
dict.FindDoubleKey("de_jelly_delta_y");
@@ -1703,20 +1698,13 @@ bool SharedQuadStateFromDict(const base::Value& dict, SharedQuadState* sqs) {
if (blend_mode_index < 0)
return false;
SkBlendMode t_blend_mode = static_cast<SkBlendMode>(blend_mode_index);
- gfx::Rect t_occluding_damage_rect;
- if (occluding_damage_rect) {
- if (!RectFromDict(*occluding_damage_rect, &t_occluding_damage_rect))
- return false;
- }
-
+ gfx::MaskFilterInfo mask_filter_info(t_rounded_corner_bounds);
sqs->SetAll(t_quad_to_target_transform, t_quad_layer_rect,
- t_visible_quad_layer_rect, t_rounded_corner_bounds, t_clip_rect,
+ t_visible_quad_layer_rect, mask_filter_info, t_clip_rect,
is_clipped.value(), are_contents_opaque.value(),
static_cast<float>(opacity.value()), t_blend_mode,
sorting_context_id.value());
sqs->is_fast_rounded_corner = is_fast_rounded_corner.value();
- if (occluding_damage_rect)
- sqs->occluding_damage_rect = t_occluding_damage_rect;
sqs->de_jelly_delta_y = static_cast<float>(de_jelly_delta_y.value());
return true;
}
diff --git a/chromium/components/viz/common/quads/render_pass_io_unittest.cc b/chromium/components/viz/common/quads/render_pass_io_unittest.cc
index 75ebce60926..b8fbd52a4c3 100644
--- a/chromium/components/viz/common/quads/render_pass_io_unittest.cc
+++ b/chromium/components/viz/common/quads/render_pass_io_unittest.cc
@@ -121,13 +121,12 @@ TEST(RenderPassIOTest, SharedQuadStateList) {
ASSERT_TRUE(sqs1);
gfx::Transform transform;
transform.MakeIdentity();
- sqs1->SetAll(transform, gfx::Rect(0, 0, 640, 480),
- gfx::Rect(10, 10, 600, 400),
- gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f),
- gfx::Rect(5, 20, 1000, 200), true, false, 0.5f,
- SkBlendMode::kDstOver, 101);
+ sqs1->SetAll(
+ transform, gfx::Rect(0, 0, 640, 480), gfx::Rect(10, 10, 600, 400),
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(2.f, 3.f, 4.f, 5.f), 1.5f)),
+ gfx::Rect(5, 20, 1000, 200), true, false, 0.5f, SkBlendMode::kDstOver,
+ 101);
sqs1->is_fast_rounded_corner = true;
- sqs1->occluding_damage_rect = gfx::Rect(7, 11, 210, 333);
sqs1->de_jelly_delta_y = 0.7f;
}
base::Value dict0 = CompositorRenderPassToDict(*render_pass0);
@@ -142,7 +141,7 @@ TEST(RenderPassIOTest, SharedQuadStateList) {
EXPECT_TRUE(sqs0->quad_to_target_transform.IsIdentity());
EXPECT_EQ(gfx::Rect(), sqs0->quad_layer_rect);
EXPECT_EQ(gfx::Rect(), sqs0->visible_quad_layer_rect);
- EXPECT_TRUE(sqs0->rounded_corner_bounds.IsEmpty());
+ EXPECT_FALSE(sqs0->mask_filter_info.HasRoundedCorners());
EXPECT_EQ(gfx::Rect(), sqs0->clip_rect);
EXPECT_FALSE(sqs0->is_clipped);
EXPECT_TRUE(sqs0->are_contents_opaque);
@@ -150,7 +149,6 @@ TEST(RenderPassIOTest, SharedQuadStateList) {
EXPECT_EQ(SkBlendMode::kSrcOver, sqs0->blend_mode);
EXPECT_EQ(0, sqs0->sorting_context_id);
EXPECT_FALSE(sqs0->is_fast_rounded_corner);
- EXPECT_FALSE(sqs0->occluding_damage_rect.has_value());
EXPECT_EQ(0.0f, sqs0->de_jelly_delta_y);
const SharedQuadState* sqs1 =
@@ -160,10 +158,10 @@ TEST(RenderPassIOTest, SharedQuadStateList) {
EXPECT_EQ(gfx::Rect(0, 0, 640, 480), sqs1->quad_layer_rect);
EXPECT_EQ(gfx::Rect(10, 10, 600, 400), sqs1->visible_quad_layer_rect);
EXPECT_EQ(gfx::RRectF::Type::kSingle,
- sqs1->rounded_corner_bounds.GetType());
- EXPECT_EQ(1.5f, sqs1->rounded_corner_bounds.GetSimpleRadius());
- EXPECT_EQ(gfx::RectF(2.f, 3.f, 4.f, 5.f),
- sqs1->rounded_corner_bounds.rect());
+ sqs1->mask_filter_info.rounded_corner_bounds().GetType());
+ EXPECT_EQ(1.5f,
+ sqs1->mask_filter_info.rounded_corner_bounds().GetSimpleRadius());
+ EXPECT_EQ(gfx::RectF(2.f, 3.f, 4.f, 5.f), sqs1->mask_filter_info.bounds());
EXPECT_EQ(gfx::Rect(5, 20, 1000, 200), sqs1->clip_rect);
EXPECT_TRUE(sqs1->is_clipped);
EXPECT_FALSE(sqs1->are_contents_opaque);
@@ -171,8 +169,6 @@ TEST(RenderPassIOTest, SharedQuadStateList) {
EXPECT_EQ(SkBlendMode::kDstOver, sqs1->blend_mode);
EXPECT_EQ(101, sqs1->sorting_context_id);
EXPECT_TRUE(sqs1->is_fast_rounded_corner);
- EXPECT_TRUE(sqs1->occluding_damage_rect.has_value());
- EXPECT_EQ(gfx::Rect(7, 11, 210, 333), sqs1->occluding_damage_rect.value());
EXPECT_EQ(0.7f, sqs1->de_jelly_delta_y);
}
base::Value dict1 = CompositorRenderPassToDict(*render_pass1);
@@ -246,7 +242,7 @@ TEST(RenderPassIOTest, QuadList) {
gfx::RectF(0.f, 0.f, 0.5f, 0.6f), gfx::RectF(0.1f, 0.2f, 0.7f, 0.8f),
gfx::Size(400, 200), gfx::Size(800, 400), 1u, 2u, 3u, 4u,
gfx::ColorSpace::CreateCustom(primary_matrix, transfer_func), 3.f,
- 1.1f, 12u, gfx::ProtectedVideoType::kClear, gl::HDRMetadata());
+ 1.1f, 12u, gfx::ProtectedVideoType::kClear, gfx::HDRMetadata());
++sqs_index;
++quad_count;
}
diff --git a/chromium/components/viz/common/quads/shared_quad_state.cc b/chromium/components/viz/common/quads/shared_quad_state.cc
index 42cab6ba363..5d7d3b32292 100644
--- a/chromium/components/viz/common/quads/shared_quad_state.cc
+++ b/chromium/components/viz/common/quads/shared_quad_state.cc
@@ -23,7 +23,7 @@ SharedQuadState::~SharedQuadState() {
void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
const gfx::Rect& quad_layer_rect,
const gfx::Rect& visible_quad_layer_rect,
- const gfx::RRectF& rounded_corner_bounds,
+ const gfx::MaskFilterInfo& mask_filter_info,
const gfx::Rect& clip_rect,
bool is_clipped,
bool are_contents_opaque,
@@ -33,7 +33,7 @@ void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
this->quad_to_target_transform = quad_to_target_transform;
this->quad_layer_rect = quad_layer_rect;
this->visible_quad_layer_rect = visible_quad_layer_rect;
- this->rounded_corner_bounds = rounded_corner_bounds;
+ this->mask_filter_info = mask_filter_info;
this->clip_rect = clip_rect;
this->is_clipped = is_clipped;
this->are_contents_opaque = are_contents_opaque;
@@ -47,8 +47,11 @@ void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
cc::MathUtil::AddToTracedValue("layer_content_rect", quad_layer_rect, value);
cc::MathUtil::AddToTracedValue("layer_visible_content_rect",
visible_quad_layer_rect, value);
- cc::MathUtil::AddToTracedValue("rounded_corner_bounds", rounded_corner_bounds,
- value);
+ cc::MathUtil::AddToTracedValue("mask_filter_bounds",
+ mask_filter_info.bounds(), value);
+ cc::MathUtil::AddCornerRadiiToTracedValue(
+ "mask_filter_rounded_corners_radii",
+ mask_filter_info.rounded_corner_bounds(), value);
value->SetBoolean("is_clipped", is_clipped);
cc::MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
diff --git a/chromium/components/viz/common/quads/shared_quad_state.h b/chromium/components/viz/common/quads/shared_quad_state.h
index 96e96962e87..a1694be0054 100644
--- a/chromium/components/viz/common/quads/shared_quad_state.h
+++ b/chromium/components/viz/common/quads/shared_quad_state.h
@@ -11,6 +11,7 @@
#include "components/viz/common/viz_common_export.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/mask_filter_info.h"
#include "ui/gfx/rrect_f.h"
#include "ui/gfx/transform.h"
@@ -34,9 +35,9 @@ class VIZ_COMMON_EXPORT SharedQuadState {
~SharedQuadState();
void SetAll(const gfx::Transform& quad_to_target_transform,
- const gfx::Rect& layer_rect,
+ const gfx::Rect& quad_layer_rect,
const gfx::Rect& visible_layer_rect,
- const gfx::RRectF& rounded_corner_bounds,
+ const gfx::MaskFilterInfo& mask_filter_info,
const gfx::Rect& clip_rect,
bool is_clipped,
bool are_contents_opaque,
@@ -55,9 +56,9 @@ class VIZ_COMMON_EXPORT SharedQuadState {
// The size of the visible area in the quads' originating layer, in the space
// of the quad rects.
gfx::Rect visible_quad_layer_rect;
- // This rect lives in the target content space. It defines the corner radius
- // to clip the quads with.
- gfx::RRectF rounded_corner_bounds;
+ // This mask filter's coordinates is in the target content space. It defines
+ // the corner radius to clip the quads with.
+ gfx::MaskFilterInfo mask_filter_info;
// This rect lives in the target content space.
gfx::Rect clip_rect;
bool is_clipped = false;
@@ -71,11 +72,10 @@ class VIZ_COMMON_EXPORT SharedQuadState {
// render passes as much as possible.
bool is_fast_rounded_corner = false;
// This is for underlay optimization and used only in the SurfaceAggregator
- // and the OverlayProcessor. This damage rect contains union of damage from
- // occluding surfaces and is only for quads that are the only quad in
- // their surface. SetAll() doesn't update this data.
- base::Optional<gfx::Rect> occluding_damage_rect;
-
+ // and the OverlayProcessor. Do not set the value in CompositorRenderPass.
+ // This index points to the damage rect in the surface damage rect list where
+ // the overlay quad belongs to. SetAll() doesn't update this data.
+ base::Optional<size_t> overlay_damage_index;
// The amount to skew quads in this layer. For experimental de-jelly effect.
float de_jelly_delta_y = 0.0f;
diff --git a/chromium/components/viz/common/quads/yuv_video_draw_quad.cc b/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
index 0a4c243deee..8da23761125 100644
--- a/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
+++ b/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
@@ -8,7 +8,7 @@
#include "base/trace_event/traced_value.h"
#include "base/values.h"
#include "cc/base/math_util.h"
-#include "ui/gl/hdr_metadata.h"
+#include "ui/gfx/hdr_metadata.h"
namespace viz {
@@ -68,7 +68,7 @@ void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
float multiplier,
uint32_t bits_per_channel,
gfx::ProtectedVideoType protected_video_type,
- gl::HDRMetadata hdr_metadata) {
+ gfx::HDRMetadata hdr_metadata) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kYuvVideoContent,
rect, visible_rect, needs_blending);
this->ya_tex_coord_rect = ya_tex_coord_rect;
diff --git a/chromium/components/viz/common/quads/yuv_video_draw_quad.h b/chromium/components/viz/common/quads/yuv_video_draw_quad.h
index 027b72c0875..34ebe1d2bf7 100644
--- a/chromium/components/viz/common/quads/yuv_video_draw_quad.h
+++ b/chromium/components/viz/common/quads/yuv_video_draw_quad.h
@@ -14,8 +14,8 @@
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/video_types.h"
-#include "ui/gl/hdr_metadata.h"
namespace viz {
@@ -73,7 +73,7 @@ class VIZ_COMMON_EXPORT YUVVideoDrawQuad : public DrawQuad {
float multiplier,
uint32_t bits_per_channel,
gfx::ProtectedVideoType protected_video_type,
- gl::HDRMetadata hdr_metadata);
+ gfx::HDRMetadata hdr_metadata);
gfx::RectF ya_tex_coord_rect;
gfx::RectF uv_tex_coord_rect;
@@ -86,7 +86,7 @@ class VIZ_COMMON_EXPORT YUVVideoDrawQuad : public DrawQuad {
gfx::ColorSpace video_color_space;
gfx::ProtectedVideoType protected_video_type =
gfx::ProtectedVideoType::kClear;
- gl::HDRMetadata hdr_metadata;
+ gfx::HDRMetadata hdr_metadata;
static const YUVVideoDrawQuad* MaterialCast(const DrawQuad*);
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index 2bfdfd5d2e4..0d8fe9201d4 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -42,6 +42,7 @@ SkColorType ResourceFormatToClosestSkColorType(bool gpu_compositing,
case RGBX_8888:
case ETC1:
return kRGB_888x_SkColorType;
+ case P010:
case RGBA_1010102:
return kRGBA_1010102_SkColorType;
case BGRA_1010102:
@@ -62,8 +63,6 @@ SkColorType ResourceFormatToClosestSkColorType(bool gpu_compositing,
case RG_88:
return kR8G8_unorm_SkColorType;
case BGRX_8888:
- case P010:
- return kN32_SkColorType;
case RGBA_F16:
return kRGBA_F16_SkColorType;
@@ -323,6 +322,7 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
case RGBX_8888:
case ETC1:
return GL_RGB8_OES;
+ case P010:
case RGBA_1010102:
case BGRA_1010102:
return GL_RGB10_A2_EXT;
@@ -331,7 +331,6 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
return GL_RGB8_OES;
case BGR_565:
case BGRX_8888:
- case P010:
break;
}
NOTREACHED();
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
index b05ef1ef2c2..60d9c903dd5 100644
--- a/chromium/components/viz/common/switches.cc
+++ b/chromium/components/viz/common/switches.cc
@@ -42,6 +42,14 @@ const char kEnableVizDevTools[] = "enable-viz-devtools";
// Enables hit-test debug logging.
const char kEnableVizHitTestDebug[] = "enable-viz-hit-test-debug";
+#if BUILDFLAG(IS_ASH)
+// ChromeOS uses one of two VideoDecoder implementations based on SoC/board
+// specific configurations that are signalled via this command line flag.
+// TODO(b/159825227): remove when the "old" video decoder is fully launched.
+const char kPlatformDisallowsChromeOSDirectVideoDecoder[] =
+ "platform-disallows-chromeos-direct-video-decoder";
+#endif
+
// Effectively disables pipelining of compositor frame production stages by
// waiting for each stage to finish before completing a frame.
const char kRunAllCompositorStagesBeforeDraw[] =
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
index a856bacbf9f..250ae5230ce 100644
--- a/chromium/components/viz/common/switches.h
+++ b/chromium/components/viz/common/switches.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/optional.h"
+#include "build/chromeos_buildflags.h"
#include "components/viz/common/viz_common_export.h"
namespace switches {
@@ -22,6 +23,12 @@ VIZ_COMMON_EXPORT extern const char kEnableDeJelly[];
VIZ_COMMON_EXPORT extern const char kEnableHardwareOverlays[];
VIZ_COMMON_EXPORT extern const char kEnableVizDevTools[];
VIZ_COMMON_EXPORT extern const char kEnableVizHitTestDebug[];
+
+#if BUILDFLAG(IS_ASH)
+VIZ_COMMON_EXPORT extern const char
+ kPlatformDisallowsChromeOSDirectVideoDecoder[];
+#endif
+
VIZ_COMMON_EXPORT extern const char kRunAllCompositorStagesBeforeDraw[];
VIZ_COMMON_EXPORT extern const char kShowAggregatedDamage[];
VIZ_COMMON_EXPORT extern const char kShowDCLayerDebugBorders[];
diff --git a/chromium/components/viz/common/yuv_readback_unittest.cc b/chromium/components/viz/common/yuv_readback_unittest.cc
index c1d7f1be9eb..78820f068d3 100644
--- a/chromium/components/viz/common/yuv_readback_unittest.cc
+++ b/chromium/components/viz/common/yuv_readback_unittest.cc
@@ -56,6 +56,9 @@ class YUVReadbackTest : public testing::Test {
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
nullptr, /* image_factory */
+ nullptr, /* gpu::GpuTaskSchedulerHelper */
+ nullptr,
+ /* gpu::DisplayCompositorMemoryAndTaskControllerOnGpu */
base::ThreadTaskRunnerHandle::Get());
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
gl_ = context_->GetImplementation();
diff --git a/chromium/components/viz/demo/BUILD.gn b/chromium/components/viz/demo/BUILD.gn
index f3fe9d9cfae..4688919b34a 100644
--- a/chromium/components/viz/demo/BUILD.gn
+++ b/chromium/components/viz/demo/BUILD.gn
@@ -55,6 +55,7 @@ executable("viz_demo") {
deps = [
"//base",
+ "//base:base_static",
"//base:i18n",
"//build/win:default_exe_manifest",
"//components/viz/demo:host",
diff --git a/chromium/components/viz/demo/client/demo_client.cc b/chromium/components/viz/demo/client/demo_client.cc
index 75e6f8100ca..6f255f94524 100644
--- a/chromium/components/viz/demo/client/demo_client.cc
+++ b/chromium/components/viz/demo/client/demo_client.cc
@@ -102,7 +102,7 @@ viz::CompositorFrame DemoClient::CreateFrame(const viz::BeginFrameArgs& args) {
transform,
/*quad_layer_rect=*/child_bounds,
/*visible_quad_layer_rect=*/child_bounds,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
/*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -127,7 +127,7 @@ viz::CompositorFrame DemoClient::CreateFrame(const viz::BeginFrameArgs& args) {
gfx::Transform(),
/*quad_layer_rect=*/output_rect,
/*visible_quad_layer_rect=*/output_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
/*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
diff --git a/chromium/components/viz/demo/demo_main.cc b/chromium/components/viz/demo/demo_main.cc
index a24f3c36d01..ab1ad2023cd 100644
--- a/chromium/components/viz/demo/demo_main.cc
+++ b/chromium/components/viz/demo/demo_main.cc
@@ -5,6 +5,7 @@
#include <utility>
#include "base/at_exit.h"
+#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/macros.h"
@@ -27,7 +28,9 @@
#include "ui/platform_window/platform_window_init_properties.h"
#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
#endif
#if defined(OS_WIN)
@@ -84,10 +87,6 @@ class InitMojo {
class InitUI {
public:
InitUI() {
-#if defined(USE_X11)
- if (!features::IsUsingOzonePlatform())
- XInitThreads();
-#endif
event_source_ = ui::PlatformEventSource::CreateDefault();
}
@@ -207,12 +206,57 @@ int DemoMain() {
return 0;
}
+#if defined(USE_OZONE)
+std::unique_ptr<ui::OzoneGpuTestHelper> gpu_helper;
+
+static void SetupOzone(base::WaitableEvent* done) {
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ cmd_line->AppendSwitchASCII(switches::kUseGL, gl::kGLImplementationEGLName);
+ ui::OzonePlatform::InitParams params;
+ params.single_process = true;
+ ui::OzonePlatform::InitializeForGPU(params);
+ done->Signal();
+}
+#endif
+
} // namespace
int main(int argc, char** argv) {
+#if defined(USE_OZONE)
+ base::CommandLine command_line(argc, argv);
+ auto feature_list = std::make_unique<base::FeatureList>();
+ feature_list->InitializeFromCommandLine(
+ command_line.GetSwitchValueASCII(switches::kEnableFeatures),
+ command_line.GetSwitchValueASCII(switches::kDisableFeatures));
+ base::FeatureList::SetInstance(std::move(feature_list));
+
+ base::Thread rendering_thread("GLRenderingVEAClientThread");
+#endif
+
InitBase base(argc, argv);
InitMojo mojo;
InitUI ui;
+#if defined(USE_OZONE)
+ if (features::IsUsingOzonePlatform()) {
+ ui::OzonePlatform::InitParams params;
+ params.single_process = true;
+ ui::OzonePlatform::InitializeForUI(params);
+
+ base::Thread::Options options;
+ options.message_pump_type = base::MessagePumpType::UI;
+ CHECK(rendering_thread.StartWithOptions(options));
+ base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ rendering_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&SetupOzone, &done));
+ done.Wait();
+
+ // To create dmabuf through gbm, Ozone needs to be set up.
+ gpu_helper = std::make_unique<ui::OzoneGpuTestHelper>();
+ gpu_helper->Initialize(base::ThreadTaskRunnerHandle::Get());
+ }
+#endif
+
return DemoMain();
}
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.h b/chromium/components/viz/host/client_frame_sink_video_capturer.h
index 471756da8e1..993a2db3b83 100644
--- a/chromium/components/viz/host/client_frame_sink_video_capturer.h
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_HOST_CLIENT_FRAME_SINK_VIDEO_CAPTURER_H_
#define COMPONENTS_VIZ_HOST_CLIENT_FRAME_SINK_VIDEO_CAPTURER_H_
+#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -36,7 +38,8 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
: private mojom::FrameSinkVideoConsumer {
public:
// A re-connectable FrameSinkVideoCaptureOverlay. See CreateOverlay().
- class VIZ_HOST_EXPORT Overlay : public mojom::FrameSinkVideoCaptureOverlay {
+ class VIZ_HOST_EXPORT Overlay final
+ : public mojom::FrameSinkVideoCaptureOverlay {
public:
Overlay(base::WeakPtr<ClientFrameSinkVideoCapturer> client_capturer,
int32_t stacking_index);
diff --git a/chromium/components/viz/host/gpu_host_impl.cc b/chromium/components/viz/host/gpu_host_impl.cc
index 1d65eed655e..2d9d6851655 100644
--- a/chromium/components/viz/host/gpu_host_impl.cc
+++ b/chromium/components/viz/host/gpu_host_impl.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
@@ -17,7 +17,6 @@
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
-#include "gpu/config/gpu_extra_info.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_info.h"
@@ -409,7 +408,7 @@ void GpuHostImpl::DidInitialize(
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
- const gpu::GpuExtraInfo& gpu_extra_info) {
+ const gfx::GpuExtraInfo& gpu_extra_info) {
UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", true);
// Set GPU driver bug workaround flags that are checked on the browser side.
diff --git a/chromium/components/viz/host/gpu_host_impl.h b/chromium/components/viz/host/gpu_host_impl.h
index 7362ab06310..f99e9ee07be 100644
--- a/chromium/components/viz/host/gpu_host_impl.h
+++ b/chromium/components/viz/host/gpu_host_impl.h
@@ -25,7 +25,6 @@
#include "components/viz/host/viz_host_export.h"
#include "gpu/command_buffer/common/activity_flags.h"
#include "gpu/config/gpu_domain_guilt.h"
-#include "gpu/config/gpu_extra_info.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -38,6 +37,7 @@
#include "services/viz/privileged/mojom/gl/gpu_host.mojom.h"
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
#include "services/viz/privileged/mojom/viz_main.mojom.h"
+#include "ui/gfx/gpu_extra_info.h"
#include "url/gurl.h"
#if defined(OS_WIN)
@@ -67,7 +67,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
- const gpu::GpuExtraInfo& gpu_extra_info) = 0;
+ const gfx::GpuExtraInfo& gpu_extra_info) = 0;
virtual void DidFailInitialize() = 0;
virtual void DidCreateContextSuccessfully() = 0;
virtual void MaybeShutdownGpuProcess() = 0;
@@ -220,7 +220,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
- const gpu::GpuExtraInfo& gpu_extra_info) override;
+ const gfx::GpuExtraInfo& gpu_extra_info) override;
void DidFailInitialize() override;
void DidCreateContextSuccessfully() override;
void DidCreateOffscreenContext(const GURL& url) override;
diff --git a/chromium/components/viz/host/host_frame_sink_manager.cc b/chromium/components/viz/host/host_frame_sink_manager.cc
index 260a41ded84..7951886f214 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
diff --git a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index 0decdba3541..495493831f6 100644
--- a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -4,10 +4,12 @@
#include "components/viz/host/host_gpu_memory_buffer_manager.h"
+#include <string>
#include <utility>
+#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/clang_profiling_buildflags.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/run_loop.h"
@@ -163,6 +165,8 @@ class TestGpuService : public mojom::GpuService {
void DisplayRemoved() override {}
+ void DisplayMetricsChanged() override {}
+
void DestroyAllChannels() override {}
void OnBackgroundCleanup() override {}
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index 3d3fc4f5227..92acbc3a25c 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -9,13 +9,6 @@ import("//media/gpu/args.gni")
import("//skia/features.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
config("viz_service_implementation") {
}
@@ -71,6 +64,8 @@ viz_component("service") {
"display/output_surface_frame.h",
"display/overlay_candidate.cc",
"display/overlay_candidate.h",
+ "display/overlay_candidate_temporal_tracker.cc",
+ "display/overlay_candidate_temporal_tracker.h",
"display/overlay_processor_interface.cc",
"display/overlay_processor_interface.h",
"display/overlay_processor_on_gpu.cc",
@@ -113,8 +108,6 @@ viz_component("service") {
"display_embedder/gl_output_surface.h",
"display_embedder/gl_output_surface_buffer_queue.cc",
"display_embedder/gl_output_surface_buffer_queue.h",
- "display_embedder/gl_output_surface_chromeos.cc",
- "display_embedder/gl_output_surface_chromeos.h",
"display_embedder/gl_output_surface_offscreen.cc",
"display_embedder/gl_output_surface_offscreen.h",
"display_embedder/in_process_gpu_memory_buffer_manager.cc",
@@ -211,6 +204,7 @@ viz_component("service") {
"//media/mojo/services",
"//services/tracing/public/cpp:cpp",
"//services/viz/privileged/mojom",
+ "//skia",
"//skia:skcms",
"//third_party/libyuv",
"//ui/display/types",
@@ -225,6 +219,7 @@ viz_component("service") {
"//gpu/command_buffer/client:gles2_interface",
"//services/viz/privileged/mojom/compositing",
"//services/viz/public/mojom",
+ "//ui/base/prediction",
"//ui/gfx",
"//ui/gfx/geometry",
"//ui/latency",
@@ -239,6 +234,10 @@ viz_component("service") {
}
if (is_chromeos) {
+ sources += [
+ "display_embedder/gl_output_surface_chromeos.cc",
+ "display_embedder/gl_output_surface_chromeos.h",
+ ]
deps += [ "//components/arc/video_accelerator" ]
}
@@ -342,6 +341,8 @@ viz_component("service") {
# then this build target will no longer be needed.
viz_source_set("gpu_service_dependencies") {
sources = [
+ "display/display_compositor_memory_and_task_controller.cc",
+ "display/display_compositor_memory_and_task_controller.h",
"display_embedder/image_context_impl.cc",
"display_embedder/image_context_impl.h",
"display_embedder/output_presenter.cc",
@@ -386,6 +387,7 @@ viz_source_set("gpu_service_dependencies") {
deps = [
"//base",
"//gpu/config",
+ "//third_party/libyuv",
]
if (is_win) {
@@ -427,6 +429,8 @@ viz_source_set("gpu_service_dependencies") {
sources += [
"display_embedder/skia_output_device_vulkan.cc",
"display_embedder/skia_output_device_vulkan.h",
+ "display_embedder/skia_output_device_vulkan_secondary_cb.cc",
+ "display_embedder/skia_output_device_vulkan_secondary_cb.h",
]
public_deps += [ "//gpu/vulkan" ]
@@ -474,6 +478,8 @@ viz_source_set("unit_tests") {
sources = [
"display/bsp_tree_unittest.cc",
"display/copy_output_scaling_pixeltest.cc",
+ "display/delegated_ink_point_pixel_test_helper.cc",
+ "display/delegated_ink_point_pixel_test_helper.h",
"display/display_damage_tracker_unittest.cc",
"display/display_resource_provider_unittest.cc",
"display/display_scheduler_unittest.cc",
diff --git a/chromium/components/viz/service/DEPS b/chromium/components/viz/service/DEPS
index 9adce7e5a9f..6b7b2e7f71e 100644
--- a/chromium/components/viz/service/DEPS
+++ b/chromium/components/viz/service/DEPS
@@ -5,11 +5,13 @@ include_rules = [
"-components/viz/common/features.h",
"-components/viz/common/switches.h",
"-components/viz/service",
+ "+components/viz/service/gl/gpu_service_impl.h",
"+components/viz/service/viz_service_export.h",
"+gpu/config/gpu_feature_info.h",
"+gpu/ipc/common/surface_handle.h",
"+services/viz/privileged/mojom",
"+services/viz/public/mojom",
+ "+skia/ext",
"+third_party/skia",
"+ui/latency",
"+ui/ozone/public",
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/BUILD.gn b/chromium/components/viz/service/compositor_frame_fuzzer/BUILD.gn
index 175cc8f52be..5aa76fa6a43 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/BUILD.gn
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
@@ -19,7 +20,8 @@ proto_library("compositor_frame_fuzzer_proto") {
# The messages must be of type RenderPass, as defined in the proto2 file
# compositor_frame_fuzzer.proto (these assumptions are all hardcoded into
# generate_renderpass_binary.py)
-action_foreach("generate_seed_corpus") {
+# TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+python2_action_foreach("generate_seed_corpus") {
script = "generate_renderpass_binary.py"
pyproto_path = "$root_out_dir/pyproto"
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc b/chromium/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
index 6a316432f94..226e84a8923 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
@@ -15,6 +15,7 @@
#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/mask_filter_info.h"
namespace viz {
namespace {
@@ -343,8 +344,8 @@ void FuzzedCompositorFrameBuilder::ConfigureSharedQuadState(
shared_quad_state->SetAll(
GetTransformFromProtobuf(quad_spec.sqs().transform()),
GetRectFromProtobuf(quad_spec.sqs().layer_rect()),
- GetRectFromProtobuf(quad_spec.sqs().visible_rect()), gfx::RRectF(),
- GetRectFromProtobuf(quad_spec.sqs().clip_rect()),
+ GetRectFromProtobuf(quad_spec.sqs().visible_rect()),
+ gfx::MaskFilterInfo(), GetRectFromProtobuf(quad_spec.sqs().clip_rect()),
quad_spec.sqs().is_clipped(), quad_spec.sqs().are_contents_opaque(),
Normalize(quad_spec.sqs().opacity()), SkBlendMode::kSrcOver,
quad_spec.sqs().sorting_context_id());
@@ -360,12 +361,12 @@ void FuzzedCompositorFrameBuilder::ConfigureSharedQuadState(
.transform_to_root_target());
}
- shared_quad_state->SetAll(transform, GetRectFromProtobuf(quad_spec.rect()),
- GetRectFromProtobuf(quad_spec.visible_rect()),
- gfx::RRectF(), gfx::Rect(), /*is_clipped=*/false,
- /*are_contents_opaque=*/true, /*opacity=*/1.0,
- SkBlendMode::kSrcOver,
- /*sorting_context_id=*/0);
+ shared_quad_state->SetAll(
+ transform, GetRectFromProtobuf(quad_spec.rect()),
+ GetRectFromProtobuf(quad_spec.visible_rect()), gfx::MaskFilterInfo(),
+ gfx::Rect(), /*is_clipped=*/false,
+ /*are_contents_opaque=*/true, /*opacity=*/1.0, SkBlendMode::kSrcOver,
+ /*sorting_context_id=*/0);
}
}
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
index 628c046d0a0..de70a88d98e 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_browser_process.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
@@ -130,7 +130,7 @@ CompositorFrame FuzzerBrowserProcess::BuildBrowserUICompositorFrame(
renderer_sqs->SetAll(gfx::Transform(1.0, 0.0, 0.0, 1.0, 0, 80),
gfx::Rect(kRendererFrameSize),
gfx::Rect(kRendererFrameSize),
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
gfx::Rect(kRendererFrameSize), /*is_clipped=*/false,
/*are_contents_opaque=*/false, /*opacity=*/1,
SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -144,7 +144,7 @@ CompositorFrame FuzzerBrowserProcess::BuildBrowserUICompositorFrame(
auto* toolbar_sqs = pass->CreateAndAppendSharedQuadState();
toolbar_sqs->SetAll(
gfx::Transform(), gfx::Rect(kTopBarSize), gfx::Rect(kTopBarSize),
- /*rounded_corner_bounds=*/gfx::RRectF(), gfx::Rect(kTopBarSize),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(), gfx::Rect(kTopBarSize),
/*is_clipped=*/false, /*are_contents_opaque=*/false,
/*opacity=*/1, SkBlendMode::kSrcOver,
/*sorting_context_id=*/0);
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
index 54c45e0a15e..34014e91bd1 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
@@ -86,11 +86,20 @@ FuzzerSoftwareOutputSurfaceProvider::FuzzerSoftwareOutputSurfaceProvider(
FuzzerSoftwareOutputSurfaceProvider::~FuzzerSoftwareOutputSurfaceProvider() =
default;
+std::unique_ptr<DisplayCompositorMemoryAndTaskController>
+FuzzerSoftwareOutputSurfaceProvider::CreateGpuDependency(
+ bool gpu_compositing,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings) {
+ return nullptr;
+}
+
std::unique_ptr<OutputSurface>
FuzzerSoftwareOutputSurfaceProvider::CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
+ DisplayCompositorMemoryAndTaskController* gpu_dependency,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) {
std::unique_ptr<SoftwareOutputDevice> software_output_device =
@@ -99,12 +108,4 @@ FuzzerSoftwareOutputSurfaceProvider::CreateOutputSurface(
return std::make_unique<SoftwareOutputSurface>(
std::move(software_output_device));
}
-
-gpu::SharedImageManager*
-FuzzerSoftwareOutputSurfaceProvider::GetSharedImageManager() {
- // This is used for creating overlay processor. Software compositor does not
- // support overlay.
- return nullptr;
-}
-
} // namespace viz
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
index 9f73b3f59a6..83014ffa9e2 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
@@ -22,15 +22,18 @@ class FuzzerSoftwareOutputSurfaceProvider : public OutputSurfaceProvider {
~FuzzerSoftwareOutputSurfaceProvider() override;
// OutputSurfaceProvider implementation.
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> CreateGpuDependency(
+ bool gpu_compositing,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings) override;
std::unique_ptr<OutputSurface> CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
+ DisplayCompositorMemoryAndTaskController* gpu_dependency,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) override;
- gpu::SharedImageManager* GetSharedImageManager() override;
-
private:
base::Optional<base::FilePath> png_dir_path_;
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index 39bc1e9f6d8..3c36f05697a 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -13,6 +13,7 @@ include_rules = [
"+components/viz/service/display_embedder/overlay_candidate_validator_ozone.h",
"+components/viz/service/display_embedder/overlay_candidate_validator_surface_control.h",
"+components/viz/service/display_embedder/overlay_candidate_validator_win.h",
+ "+components/viz/service/display_embedder/skia_output_surface_dependency.h",
"+components/viz/common",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
@@ -28,18 +29,20 @@ include_rules = [
"+third_party/skia",
"+third_party/perfetto/protos/perfetto/trace/track_event",
"+ui/latency",
+ "+ui/gfx/android/android_surface_control_compat.h",
+ "+ui/gfx/hdr_metadata.h",
"+ui/gfx/video_types.h",
- "+ui/gl/android/android_surface_control_compat.h",
"+ui/gl/ca_renderer_layer_params.h",
"+ui/gl/dc_renderer_layer_params.h",
"+ui/gl/gl_utils.h",
"+ui/gl/gpu_switching_manager.h",
"+ui/gl/gpu_switching_observer.h",
- "+ui/gl/hdr_metadata.h",
"+ui/gl/trace_util.h",
"+gpu/ipc/common/vulkan_ycbcr_info.h",
"+gpu/ipc/gpu_task_scheduler_helper.h",
+ "+gpu/ipc/display_compositor_memory_and_task_controller_on_gpu.h",
"+gpu/ipc/scheduler_sequence.h",
+ "+gpu/ipc/shared_image_interface_in_process.h",
"+gpu/command_buffer/service/shared_image_factory.h",
"+gpu/command_buffer/service/shared_image_manager.h",
"+gpu/config/gpu_driver_bug_workaround_type.h",
diff --git a/chromium/components/viz/service/display/aggregated_frame.h b/chromium/components/viz/service/display/aggregated_frame.h
index abf165a9be7..0da348e048b 100644
--- a/chromium/components/viz/service/display/aggregated_frame.h
+++ b/chromium/components/viz/service/display/aggregated_frame.h
@@ -17,6 +17,8 @@
namespace viz {
+typedef std::vector<gfx::Rect> SurfaceDamageRectList;
+
class VIZ_SERVICE_EXPORT AggregatedFrame {
public:
AggregatedFrame();
@@ -42,11 +44,8 @@ class VIZ_SERVICE_EXPORT AggregatedFrame {
// Indicates whether this frame may contain video.
bool may_contain_video = false;
- // This is the final root damage rect produced in
- // ProcessSurfaceOccludingDamage().
- // TODO(magchen@): This will be replaced by a damage rect list in the follow
- // up CL.
- gfx::Rect occluding_damage_;
+ // A list of surface damage rects in the current frame, used for overlays.
+ SurfaceDamageRectList surface_damage_rect_list_;
// Contains the metadata required for drawing a delegated ink trail onto the
// end of a rendered ink stroke. This should only be present when two
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.cc b/chromium/components/viz/service/display/ca_layer_overlay.cc
index cf09d0dd4dd..724266170ba 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.cc
+++ b/chromium/components/viz/service/display/ca_layer_overlay.cc
@@ -208,10 +208,10 @@ class CALayerOverlayProcessorInternal {
// possible to make rounded corner rects independent of clip rect (by adding
// another CALayer to the tree). Handling non-single border radii is also,
// but requires APIs not supported on all macOS versions.
- if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty()) {
+ if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners()) {
DCHECK(quad->shared_quad_state->is_clipped);
- if (quad->shared_quad_state->rounded_corner_bounds.GetType() >
- gfx::RRectF::Type::kSingle) {
+ if (quad->shared_quad_state->mask_filter_info.rounded_corner_bounds()
+ .GetType() > gfx::RRectF::Type::kSingle) {
return CA_LAYER_FAILED_QUAD_ROUNDED_CORNER_NOT_UNIFORM;
}
}
@@ -238,7 +238,7 @@ class CALayerOverlayProcessorInternal {
most_recent_overlay_shared_state_->clip_rect =
gfx::RectF(quad->shared_quad_state->clip_rect);
most_recent_overlay_shared_state_->rounded_corner_bounds =
- quad->shared_quad_state->rounded_corner_bounds;
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds();
most_recent_overlay_shared_state_->opacity =
quad->shared_quad_state->opacity;
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index a8acfcea671..2544f98298c 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -83,8 +83,6 @@ class VIZ_SERVICE_EXPORT CALayerOverlay {
const AggregatedRenderPassDrawQuad* rpdq = nullptr;
// The DDL for generating render pass overlay buffer with SkiaRenderer.
sk_sp<SkDeferredDisplayList> ddl;
- // The transform for render pass overlay.
- base::Optional<SkMatrix44> transform;
};
typedef std::vector<CALayerOverlay> CALayerOverlayList;
diff --git a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
index f1859b3a973..351e28d9b71 100644
--- a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
+++ b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -175,8 +175,10 @@ class CopyOutputScalingPixelTest
list.back()->copy_requests.push_back(std::move(request));
renderer()->DecideRenderPassAllocationsForFrame(list);
+ SurfaceDamageRectList surface_damage_rect_list;
renderer()->DrawFrame(&list, 1.0f, viewport_size,
- gfx::DisplayColorSpaces());
+ gfx::DisplayColorSpaces(),
+ &surface_damage_rect_list);
// Call SwapBuffersSkipped(), so the renderer can release related
// resources.
renderer()->SwapBuffersSkipped();
diff --git a/chromium/components/viz/service/display/damage_frame_annotator.cc b/chromium/components/viz/service/display/damage_frame_annotator.cc
index a65710d138c..38d85d4e2ac 100644
--- a/chromium/components/viz/service/display/damage_frame_annotator.cc
+++ b/chromium/components/viz/service/display/damage_frame_annotator.cc
@@ -53,7 +53,7 @@ void DamageFrameAnnotator::AnnotateRootRenderPass(
SharedQuadState* new_sqs = render_pass->shared_quad_state_list
.AllocateAndConstruct<SharedQuadState>();
new_sqs->SetAll(annotation.transform, output_rect, output_rect,
- gfx::RRectF(), output_rect, true, false, 1.f,
+ gfx::MaskFilterInfo(), output_rect, true, false, 1.f,
SkBlendMode::kSrcOver, 0);
DebugBorderDrawQuad* new_quad =
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc
index 740c080cdda..46e1180358b 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.cc
+++ b/chromium/components/viz/service/display/dc_layer_overlay.cc
@@ -5,7 +5,9 @@
#include "components/viz/service/display/dc_layer_overlay.h"
#include <limits>
+#include <utility>
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -19,6 +21,7 @@
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_processor_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/config/gpu_finch_features.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -67,11 +70,24 @@ gfx::RectF ClippedQuadRectangle(const DrawQuad* quad) {
return quad_rect;
}
+gfx::RectF GetExpandedRectWithPixelMovingFilter(
+ const AggregatedRenderPassDrawQuad* rpdq,
+ float max_pixel_movement) {
+ const SharedQuadState* shared_quad_state = rpdq->shared_quad_state;
+ gfx::RectF expanded_rect(rpdq->rect);
+ expanded_rect.Inset(-max_pixel_movement, -max_pixel_movement);
+
+ // expanded_rect in the target space
+ return cc::MathUtil::MapClippedRect(
+ shared_quad_state->quad_to_target_transform, expanded_rect);
+}
+
DCLayerResult ValidateYUVQuad(
const YUVVideoDrawQuad* quad,
const std::vector<gfx::Rect>& backdrop_filter_rects,
bool has_overlay_support,
- int current_frame_processed_overlay_count,
+ int allowed_yuv_overlay_count,
+ int processed_yuv_overlay_count,
DisplayResourceProvider* resource_provider) {
// Note: Do not override this value based on base::Feature values. It is the
// result after the GPU blocklist has been consulted.
@@ -97,11 +113,11 @@ DCLayerResult ValidateYUVQuad(
return DC_LAYER_FAILED_COMPLEX_TRANSFORM;
}
- if (current_frame_processed_overlay_count > 0)
+ if (processed_yuv_overlay_count >= allowed_yuv_overlay_count)
return DC_LAYER_FAILED_TOO_MANY_OVERLAYS;
// Rounded corner on overlays are not supported.
- if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+ if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners())
return DC_LAYER_FAILED_ROUNDED_CORNERS;
auto quad_target_rect = gfx::ToEnclosingRect(ClippedQuadRectangle(quad));
@@ -169,7 +185,7 @@ DCLayerResult ValidateTextureQuad(
}
// Rounded corner on overlays are not supported.
- if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+ if (quad->shared_quad_state->mask_filter_info.HasRoundedCorners())
return DC_LAYER_FAILED_ROUNDED_CORNERS;
auto quad_target_rect = gfx::ToEnclosingRect(ClippedQuadRectangle(quad));
@@ -226,9 +242,6 @@ bool IsProtectedVideo(const QuadList::Iterator& it) {
}
DCLayerResult IsUnderlayAllowed(const QuadList::Iterator& it) {
- if (!base::FeatureList::IsEnabled(features::kDirectCompositionUnderlays)) {
- return DC_LAYER_FAILED_OCCLUDED;
- }
if (it->ShouldDrawWithBlending()) {
return DC_LAYER_FAILED_TRANSPARENT;
}
@@ -236,16 +249,38 @@ DCLayerResult IsUnderlayAllowed(const QuadList::Iterator& it) {
}
// Any occluding quads in the quad list on top of the overlay/underlay
-bool HasOccludingQuads(const gfx::RectF& target_quad,
- QuadList::ConstIterator quad_list_begin,
- QuadList::ConstIterator quad_list_end) {
+bool HasOccludingQuads(
+ const gfx::RectF& target_quad,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end,
+ const DCLayerOverlayProcessor::FilterOperationsMap& render_pass_filters) {
for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
++overlap_iter) {
float opacity = overlap_iter->shared_quad_state->opacity;
if (opacity < std::numeric_limits<float>::epsilon())
continue;
+
const DrawQuad* quad = *overlap_iter;
- gfx::RectF overlap_rect = ClippedQuadRectangle(quad);
+ gfx::RectF overlap_rect;
+ // Expand the overlap_rect for the render pass draw quad with pixel moving
+ // foreground filters.
+ bool has_pixel_moving_filter = false;
+ if (!render_pass_filters.empty() &&
+ quad->material == DrawQuad::Material::kAggregatedRenderPass) {
+ const auto* rpdq = AggregatedRenderPassDrawQuad::MaterialCast(quad);
+ auto render_pass_it = render_pass_filters.find(rpdq->render_pass_id);
+ if (render_pass_it != render_pass_filters.end()) {
+ auto* filters = render_pass_it->second;
+ float max_pixel_movement = filters->MaximumPixelMovement();
+ overlap_rect =
+ GetExpandedRectWithPixelMovingFilter(rpdq, max_pixel_movement);
+ has_pixel_moving_filter = true;
+ }
+ }
+
+ if (!has_pixel_moving_filter)
+ overlap_rect = ClippedQuadRectangle(quad);
+
if (quad->material == DrawQuad::Material::kSolidColor) {
SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
@@ -259,6 +294,31 @@ bool HasOccludingQuads(const gfx::RectF& target_quad,
return false;
}
+gfx::Rect CalculateOccludingDamageRect(
+ const SharedQuadState* shared_quad_state,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const gfx::Rect& quad_rect_in_root_target_space) {
+ if (!shared_quad_state->overlay_damage_index.has_value())
+ return quad_rect_in_root_target_space;
+
+ size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value();
+ if (overlay_damage_index >= surface_damage_rect_list->size()) {
+ DCHECK(false);
+ }
+
+ // Damage rects in surface_damage_rect_list are arranged from top to bottom.
+ // (*surface_damage_rect_list)[0] is the one on the very top.
+ // (*surface_damage_rect_list)[overlay_damage_index] is the damage rect of
+ // this overlay surface.
+ gfx::Rect occluding_damage_rect;
+ for (size_t i = 0; i < overlay_damage_index; ++i) {
+ occluding_damage_rect.Union((*surface_damage_rect_list)[i]);
+ }
+ occluding_damage_rect.Intersect(quad_rect_in_root_target_space);
+
+ return occluding_damage_rect;
+}
+
void RecordVideoDCLayerResult(DCLayerResult result,
gfx::ProtectedVideoType protected_video_type) {
switch (protected_video_type) {
@@ -298,17 +358,22 @@ void RecordDCLayerResult(DCLayerResult result, QuadList::Iterator it) {
}
}
-void RecordOverlayHistograms(bool is_overlay,
- const gfx::Rect& occluding_damage_rect,
- gfx::Rect* damage_rect) {
- UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.IsUnderlay", !is_overlay);
+// This function records the damage rect rect of the current frame.
+void RecordOverlayHistograms(DCLayerOverlayList* dc_layer_overlays,
+ bool has_occluding_surface_damage,
+ const gfx::Rect* damage_rect) {
+ // If an underlay is found, we record the damage rect of this frame as an
+ // underlay.
+ bool is_overlay = true;
+ for (const auto& dc_layer : *dc_layer_overlays) {
+ if (dc_layer.z_order != 1) {
+ is_overlay = false;
+ break;
+ }
+ }
- bool has_occluding_surface_damage = !occluding_damage_rect.IsEmpty();
- bool occluding_damage_equal_to_damage_rect =
- occluding_damage_rect == *damage_rect;
OverlayProcessorInterface::RecordOverlayDamageRectHistograms(
- is_overlay, has_occluding_surface_damage, damage_rect->IsEmpty(),
- occluding_damage_equal_to_damage_rect);
+ is_overlay, has_occluding_surface_damage, damage_rect->IsEmpty());
}
} // namespace
@@ -320,8 +385,13 @@ DCLayerOverlay::~DCLayerOverlay() = default;
DCLayerOverlayProcessor::DCLayerOverlayProcessor(
const DebugRendererSettings* debug_settings,
+ int allowed_yuv_overlay_count,
bool skip_initialization_for_testing)
: has_overlay_support_(skip_initialization_for_testing),
+ use_overlay_damage_list_(base::FeatureList::IsEnabled(
+ features::kDirectCompositionUseOverlayDamageList)),
+ allowed_yuv_overlay_count_(
+ use_overlay_damage_list_ ? allowed_yuv_overlay_count : 1),
debug_settings_(debug_settings),
viz_task_runner_(skip_initialization_for_testing
? nullptr
@@ -362,6 +432,89 @@ void DCLayerOverlayProcessor::ClearOverlayState() {
previous_frame_underlay_rect_ = gfx::Rect();
previous_frame_overlay_rect_union_ = gfx::Rect();
previous_frame_processed_overlay_count_ = 0;
+ previous_frame_overlay_rects_.clear();
+}
+
+void DCLayerOverlayProcessor::RemoveOverlayDamageRect(
+ const QuadList::Iterator& it,
+ const gfx::Rect& quad_rectangle,
+ const gfx::Rect& occluding_damage_rect,
+ gfx::Rect* damage_rect) {
+ if (use_overlay_damage_list_) {
+ // This is done by setting the overlay surface damage rect in the
+ // |surface_damage_rect_list_| to zero.
+ if (it->shared_quad_state->overlay_damage_index.has_value()) {
+ size_t overlay_damage_index =
+ it->shared_quad_state->overlay_damage_index.value();
+ if (overlay_damage_index >= surface_damage_rect_list_->size())
+ DCHECK(false);
+ else
+ (*surface_damage_rect_list_)[overlay_damage_index] = gfx::Rect();
+ }
+ } else {
+ // This is done by subtract the overlay rect fromt the root damage rect.
+ damage_rect->Subtract(quad_rectangle);
+ damage_rect->Union(occluding_damage_rect);
+ }
+}
+
+// This is called at the end of Process(). The goal is to get an empty root
+// damage rect if the overlays are the only damages in the frame.
+void DCLayerOverlayProcessor::UpdateRootDamageRect(
+ const gfx::RectF& display_rect,
+ gfx::Rect* damage_rect) {
+ // Check whether the overlay rect union from the previous frame should be
+ // added to the current frame and whether the overlay damages can be removed
+ // from the current damage rect.
+ if (use_overlay_damage_list_) {
+ DCHECK_EQ(static_cast<size_t>(current_frame_processed_overlay_count_),
+ current_frame_overlay_rects_.size());
+ DCHECK_EQ(static_cast<size_t>(previous_frame_processed_overlay_count_),
+ previous_frame_overlay_rects_.size());
+
+ size_t current_frame_overlay_count = current_frame_overlay_rects_.size();
+ if (current_frame_overlay_count > 0 &&
+ current_frame_overlay_count == previous_frame_overlay_rects_.size() &&
+ display_rect == previous_display_rect_) {
+ bool same_overlays = true;
+ for (size_t i = 0; i < current_frame_overlay_count; ++i) {
+ if (previous_frame_overlay_rects_[i] !=
+ current_frame_overlay_rects_[i]) {
+ same_overlays = false;
+ break;
+ }
+ }
+
+ if (same_overlays) {
+ // No need to add back the overlay rect union from the previous frame
+ // if no changes in overlays.
+ previous_frame_overlay_rect_union_ = gfx::Rect();
+
+ // Overlay rects have been previously removed from
+ // |surface_damage_rect_list_|. The union is the result of non-overlay
+ // rects.
+ gfx::Rect root_damage_rect;
+ for (const auto& damage_rect : *surface_damage_rect_list_)
+ root_damage_rect.Union(damage_rect);
+
+ *damage_rect = root_damage_rect;
+ }
+ }
+ } else {
+ // If the current overlay has changed in size/position from the previous
+ // frame, we have to add the overlay quads from the previous frame to the
+ // damage rect for GL compositor. It's hard to optimize multiple overlays.
+ // So always add the overlay rects back in this case.
+ if (current_frame_processed_overlay_count_ == 1 &&
+ previous_frame_processed_overlay_count_ == 1 &&
+ current_frame_overlay_rect_union_ ==
+ previous_frame_overlay_rect_union_) {
+ previous_frame_overlay_rect_union_ = gfx::Rect();
+ }
+ }
+
+ damage_rect->Union(previous_frame_overlay_rect_union_);
+ damage_rect->Intersect(gfx::ToEnclosingRect(display_rect));
}
void DCLayerOverlayProcessor::InsertDebugBorderDrawQuad(
@@ -399,20 +552,40 @@ void DCLayerOverlayProcessor::InsertDebugBorderDrawQuad(
damage_rect->Union(gfx::ToEnclosingRect(display_rect));
}
+bool DCLayerOverlayProcessor::IsPreviousFrameUnderlayRect(
+ const gfx::Rect& quad_rectangle,
+ size_t index) {
+ if (use_overlay_damage_list_) {
+ if (index >= previous_frame_overlay_rects_.size()) {
+ return false;
+ } else {
+ // Although we can loop through the list to find out if there is an
+ // underlay with the same size from the previous frame, checking
+ // _rectx_[index] is the quickest way to do it. If we cannot find a match
+ // with the same index, there is probably a change in the number of
+ // overlays or layout. Then we won't be able to get a zero root damage
+ // rect in this case. Looping through the list won't give better power.
+ return (previous_frame_overlay_rects_[index].rect == quad_rectangle) &&
+ (previous_frame_overlay_rects_[index].is_overlay == false);
+ }
+ } else {
+ return (quad_rectangle == previous_frame_underlay_rect_) && (index == 0);
+ }
+}
+
void DCLayerOverlayProcessor::Process(
DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
+ const FilterOperationsMap& render_pass_filters,
+ const FilterOperationsMap& render_pass_backdrop_filters,
AggregatedRenderPassList* render_pass_list,
gfx::Rect* damage_rect,
+ SurfaceDamageRectList* surface_damage_rect_list,
DCLayerOverlayList* dc_layer_overlays) {
gfx::Rect this_frame_underlay_rect;
-
- // Which render passes have backdrop filters.
- base::flat_set<AggregatedRenderPassId> render_pass_has_backdrop_filters;
- for (const auto& render_pass : *render_pass_list) {
- if (!render_pass->backdrop_filters.IsEmpty())
- render_pass_has_backdrop_filters.insert(render_pass->id);
- }
+ bool this_frame_has_occluding_damage_rect = false;
+ processed_yuv_overlay_count_ = 0;
+ surface_damage_rect_list_ = surface_damage_rect_list;
// Output rects of child render passes that have backdrop filters in target
// space. These rects are used to determine if the overlay rect could be read
@@ -441,7 +614,9 @@ void DCLayerOverlayProcessor::Process(
for (auto it = quad_list->begin(); it != quad_list->end(); ++it, ++index) {
if (it->material == DrawQuad::Material::kAggregatedRenderPass) {
const auto* rpdq = AggregatedRenderPassDrawQuad::MaterialCast(*it);
- if (render_pass_has_backdrop_filters.count(rpdq->render_pass_id)) {
+ auto render_pass_it =
+ render_pass_backdrop_filters.find(rpdq->render_pass_id);
+ if (render_pass_it != render_pass_backdrop_filters.end()) {
backdrop_filter_rects.push_back(
gfx::ToEnclosingRect(ClippedQuadRectangle(rpdq)));
}
@@ -451,11 +626,13 @@ void DCLayerOverlayProcessor::Process(
DCLayerResult result;
switch (it->material) {
case DrawQuad::Material::kYuvVideoContent:
- result =
- ValidateYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
- backdrop_filter_rects, has_overlay_support_,
- candidate_index_list.size(), resource_provider);
+ result = ValidateYUVQuad(
+ YUVVideoDrawQuad::MaterialCast(*it), backdrop_filter_rects,
+ has_overlay_support_, allowed_yuv_overlay_count_,
+ processed_yuv_overlay_count_, resource_provider);
yuv_quads_in_quad_list++;
+ if (result == DC_LAYER_SUCCESS)
+ processed_yuv_overlay_count_++;
break;
case DrawQuad::Material::kTextureContent:
result = ValidateTextureQuad(TextureDrawQuad::MaterialCast(*it),
@@ -483,11 +660,17 @@ void DCLayerOverlayProcessor::Process(
candidate_index_list.push_back(index);
}
+ // A YUV quad might be rejected later due to not allowed as an underlay.
+ // Recount the YUV overlays when they are added to the overlay list
+ // successfully.
+ processed_yuv_overlay_count_ = 0;
+ // TODO(magchen@): Revisit this code if allowed_yuv_overlay_count_ > 1.
// We might not save power if there are more than one videos and only one is
// promoted to overlay. Skip overlays for this frame unless there are
// protected video or texture overlays.
- if (candidate_index_list.size() > 0 && yuv_quads_in_quad_list > 1 &&
+ if (candidate_index_list.size() > 0 &&
+ yuv_quads_in_quad_list > allowed_yuv_overlay_count_ &&
!has_protected_video_or_texture_overlays) {
candidate_index_list.clear();
// In this case, there is only one candidate in the list.
@@ -503,19 +686,22 @@ void DCLayerOverlayProcessor::Process(
gfx::Rect quad_rectangle_in_target_space =
gfx::ToEnclosingRect(ClippedQuadRectangle(*it));
- gfx::Rect occluding_damage_rect =
- it->shared_quad_state->occluding_damage_rect.has_value()
- ? it->shared_quad_state->occluding_damage_rect.value()
- : quad_rectangle_in_target_space;
// Quad is considered an "overlay" if it has no occluders.
- const bool is_overlay = !HasOccludingQuads(
- gfx::RectF(quad_rectangle_in_target_space), quad_list->begin(), it);
+ bool is_overlay =
+ !HasOccludingQuads(gfx::RectF(quad_rectangle_in_target_space),
+ quad_list->begin(), it, render_pass_filters);
// Protected video is always put in an overlay, but texture quads can be
// skipped if they're not underlay compatible.
const bool requires_overlay = IsProtectedVideo(it);
+ // TODO(magchen@): Since we reject underlays here, the max number of YUV
+ // overlays we can promote might not be accurate. We should allow all YUV
+ // quads to be put into candidate_index_list, but only
+ // |allowed_yuv_overlay_count_| YUV quads should be promoted to
+ // overlays/underlays from that list.
+
// Skip quad if it's an underlay and underlays are not allowed.
if (!is_overlay && !requires_overlay) {
DCLayerResult result = IsUnderlayAllowed(it);
@@ -526,6 +712,18 @@ void DCLayerOverlayProcessor::Process(
}
}
+ // Get the occluding damage rect for underlay.
+ gfx::Rect occluding_damage_rect;
+ if (!is_overlay) {
+ occluding_damage_rect = CalculateOccludingDamageRect(
+ it->shared_quad_state, surface_damage_rect_list,
+ quad_rectangle_in_target_space);
+
+ // Used by a histogram.
+ if (!occluding_damage_rect.IsEmpty())
+ this_frame_has_occluding_damage_rect = true;
+ }
+
UpdateDCLayerOverlays(
display_rect, root_render_pass, it, quad_rectangle_in_target_space,
occluding_damage_rect, is_overlay, &prev_it, &prev_index,
@@ -538,17 +736,28 @@ void DCLayerOverlayProcessor::Process(
// the previous frame is missing in the GL composition path. If any overlay is
// found in this frame, the previous overlay rects would have been handled
// above and |previous_frame_overlay_rect_union_| becomes empty.
- damage_rect->Union(previous_frame_overlay_rect_union_);
+ UpdateRootDamageRect(display_rect, damage_rect);
+
previous_frame_overlay_rect_union_ = current_frame_overlay_rect_union_;
current_frame_overlay_rect_union_ = gfx::Rect();
previous_frame_processed_overlay_count_ =
current_frame_processed_overlay_count_;
current_frame_processed_overlay_count_ = 0;
-
- damage_rect->Intersect(gfx::ToEnclosingRect(display_rect));
+ std::swap(previous_frame_overlay_rects_, current_frame_overlay_rects_);
+ current_frame_overlay_rects_.clear();
previous_display_rect_ = display_rect;
previous_frame_underlay_rect_ = this_frame_underlay_rect;
+ if (!dc_layer_overlays->empty()) {
+ base::UmaHistogramExactLinear(
+ "GPU.DirectComposition.DCLayer.YUVOverlayCount",
+ /*sample=*/processed_yuv_overlay_count_,
+ /*value_max=*/10);
+
+ RecordOverlayHistograms(dc_layer_overlays,
+ this_frame_has_occluding_damage_rect, damage_rect);
+ }
+
if (debug_settings_->show_dc_layer_debug_borders &&
dc_layer_overlays->size() > 0) {
InsertDebugBorderDrawQuad(dc_layer_overlays, root_render_pass, display_rect,
@@ -576,6 +785,7 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays(
case DrawQuad::Material::kYuvVideoContent:
FromYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
render_pass->transform_to_root_target, &dc_layer);
+ processed_yuv_overlay_count_++;
break;
case DrawQuad::Material::kTextureContent:
FromTextureQuad(TextureDrawQuad::MaterialCast(*it),
@@ -585,26 +795,9 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays(
NOTREACHED();
}
- // If the current overlay has changed in size/position from the previous
- // frame, we have to add the overlay quads from the previous frame to the
- // damage rect for GL compositor. It's hard to optimize multiple overlays. So
- // always add the overlay rects back in this case. This is only done once at
- // the first overlay/underlay.
- if (current_frame_processed_overlay_count_ == 0 &&
- !previous_frame_overlay_rect_union_.IsEmpty()) {
- if (quad_rectangle_in_target_space != previous_frame_overlay_rect_union_ ||
- previous_frame_processed_overlay_count_ > 1) {
- damage_rect->Union(previous_frame_overlay_rect_union_);
- }
- previous_frame_overlay_rect_union_ = gfx::Rect();
- }
-
// Underlays are less efficient, so attempt regular overlays first. Only
// check root render pass because we can only check for occlusion within a
- // render pass. Only check if an overlay hasn't been processed already since
- // our damage calculations will be wrong otherwise.
- // TODO(sunnyps): Is the above comment correct? We seem to allow multiple
- // overlays for protected video, but don't calculate damage differently.
+ // render pass.
if (is_overlay) {
*new_it =
ProcessForOverlay(display_rect, render_pass,
@@ -612,19 +805,20 @@ void DCLayerOverlayProcessor::UpdateDCLayerOverlays(
(*new_index)++;
} else {
ProcessForUnderlay(display_rect, render_pass,
- quad_rectangle_in_target_space, it, damage_rect,
- this_frame_underlay_rect, &dc_layer);
+ quad_rectangle_in_target_space, occluding_damage_rect,
+ it, damage_rect, this_frame_underlay_rect, &dc_layer);
}
gfx::Rect rect_in_root = cc::MathUtil::MapEnclosingClippedRect(
render_pass->transform_to_root_target, quad_rectangle_in_target_space);
current_frame_overlay_rect_union_.Union(rect_in_root);
-
- RecordOverlayHistograms(is_overlay, occluding_damage_rect, damage_rect);
+ current_frame_overlay_rects_.push_back({rect_in_root, is_overlay});
dc_layer_overlays->push_back(dc_layer);
- // Only allow one overlay unless it's hardware protected video.
+ // Recorded for each overlay.
+ UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.IsUnderlay", !is_overlay);
+
current_frame_processed_overlay_count_++;
}
@@ -641,8 +835,10 @@ QuadList::Iterator DCLayerOverlayProcessor::ProcessForOverlay(
.Preserves2dAxisAlignment();
const bool needs_blending = it->ShouldDrawWithBlending();
- if (is_axis_aligned && !display_rect_changed && !needs_blending)
- damage_rect->Subtract(quad_rectangle);
+ if (is_axis_aligned && !display_rect_changed && !needs_blending) {
+ RemoveOverlayDamageRect(it, quad_rectangle,
+ /*occluding_damage_rect=*/gfx::Rect(), damage_rect);
+ }
return render_pass->quad_list.EraseAndInvalidateAllPointers(it);
}
@@ -651,6 +847,7 @@ void DCLayerOverlayProcessor::ProcessForUnderlay(
const gfx::RectF& display_rect,
AggregatedRenderPass* render_pass,
const gfx::Rect& quad_rectangle,
+ const gfx::Rect& occluding_damage_rect,
const QuadList::Iterator& it,
gfx::Rect* damage_rect,
gfx::Rect* this_frame_underlay_rect,
@@ -676,12 +873,12 @@ void DCLayerOverlayProcessor::ProcessForUnderlay(
// SrcOver_quad uses opacity of source quad (V_alpha)
// SrcOver_premul uses alpha channel and assumes premultipled alpha
bool is_opaque = false;
- SharedQuadState* new_shared_quad_state =
- render_pass->shared_quad_state_list.AllocateAndCopyFrom(
- shared_quad_state);
if (it->ShouldDrawWithBlending() &&
shared_quad_state->blend_mode == SkBlendMode::kSrcOver) {
+ SharedQuadState* new_shared_quad_state =
+ render_pass->shared_quad_state_list.AllocateAndCopyFrom(
+ shared_quad_state);
new_shared_quad_state->blend_mode = SkBlendMode::kDstOut;
auto* replacement =
@@ -691,44 +888,35 @@ void DCLayerOverlayProcessor::ProcessForUnderlay(
replacement->SetAll(new_shared_quad_state, rect, rect, needs_blending,
SK_ColorBLACK, true /* force_anti_aliasing_off */);
} else {
- // Set |are_contents_opaque| true so SkiaRenderer draws the replacement quad
- // with SkBlendMode::kSrc.
- new_shared_quad_state->are_contents_opaque = false;
- it->shared_quad_state = new_shared_quad_state;
-
// When the opacity == 1.0, drawing with transparent will be done without
// blending and will have the proper effect of completely clearing the
// layer.
- render_pass->quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(
- it);
+ render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
is_opaque = true;
}
bool display_rect_changed = (display_rect != previous_display_rect_);
- bool underlay_rect_changed =
- (quad_rectangle != previous_frame_underlay_rect_);
+ bool underlay_rect_unchanged = IsPreviousFrameUnderlayRect(
+ quad_rectangle, current_frame_processed_overlay_count_);
bool is_axis_aligned =
shared_quad_state->quad_to_target_transform.Preserves2dAxisAlignment();
- if (current_frame_processed_overlay_count_ == 0 && is_axis_aligned &&
- is_opaque && !underlay_rect_changed && !display_rect_changed &&
- shared_quad_state->occluding_damage_rect.has_value()) {
- // If this underlay rect is the same as for last frame, subtract its area
+ if (is_axis_aligned && is_opaque && underlay_rect_unchanged &&
+ !display_rect_changed) {
+ // If this underlay rect is the same as for last frame, Remove its area
// from the damage of the main surface, as the cleared area was already
- // cleared last frame. Add back the damage from the occluded area for this
- // frame.
- damage_rect->Subtract(quad_rectangle);
+ // cleared last frame.
// If none of the quads on top give any damage, we can skip compositing
- // these quads when the incoming damage rect is smaller or equal to the
- // video quad. After subtraction, the resulting output damage rect for GL
- // compositor will be empty. If the incoming damage rect is bigger than the
- // video quad, we don't have an oppertunity for power optimization even if
- // no damage on top. The output damage rect will not be empty in this case.
- damage_rect->Union(shared_quad_state->occluding_damage_rect.value());
+ // these quads. The output root damage rect might be empty after we remove
+ // the damage from the video quad. We can save power if the root damage
+ // rect is empty.
+ RemoveOverlayDamageRect(it, quad_rectangle, occluding_damage_rect,
+ damage_rect);
} else {
// Entire replacement quad must be redrawn.
damage_rect->Union(quad_rectangle);
+ surface_damage_rect_list_->push_back(quad_rectangle);
}
// We only compare current frame's first underlay with the previous frame's
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.h b/chromium/components/viz/service/display/dc_layer_overlay.h
index 0db594ec7cb..e8d50921d31 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.h
+++ b/chromium/components/viz/service/display/dc_layer_overlay.h
@@ -11,14 +11,15 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
+#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/video_types.h"
#include "ui/gl/gpu_switching_observer.h"
-#include "ui/gl/hdr_metadata.h"
namespace viz {
struct DebugRendererSettings;
@@ -69,7 +70,7 @@ class VIZ_SERVICE_EXPORT DCLayerOverlay {
gfx::ProtectedVideoType protected_video_type =
gfx::ProtectedVideoType::kClear;
- gl::HDRMetadata hdr_metadata;
+ gfx::HDRMetadata hdr_metadata;
};
typedef std::vector<DCLayerOverlay> DCLayerOverlayList;
@@ -77,18 +78,29 @@ typedef std::vector<DCLayerOverlay> DCLayerOverlayList;
class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
: public ui::GpuSwitchingObserver {
public:
+ using FilterOperationsMap =
+ base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>;
// When |skip_initialization_for_testing| is true, object will be isolated
// for unit tests.
+ // allowed_yuv_overlay_count will be limited to 1 if
+ // |use_overlay_damage_list_| is not supported. This new method produces an
+ // empty root damage rect when the overlay quads are the only damages in the
+ // frames. If |use_overlay_damage_list_| is false, we should not allowed more
+ // than one YUV overlays since non-empty damage rect won't save any power.
explicit DCLayerOverlayProcessor(
const DebugRendererSettings* debug_settings,
+ int allowed_yuv_overlay_count,
bool skip_initialization_for_testing = false);
virtual ~DCLayerOverlayProcessor();
// Virtual for testing.
virtual void Process(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
+ const FilterOperationsMap& render_pass_filters,
+ const FilterOperationsMap& render_pass_backdrop_filters,
AggregatedRenderPassList* render_passes,
gfx::Rect* damage_rect,
+ SurfaceDamageRectList* surface_damage_rect_list,
DCLayerOverlayList* dc_layer_overlays);
void ClearOverlayState();
// This is the damage contribution due to previous frame's overlays which can
@@ -126,17 +138,33 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
void ProcessForUnderlay(const gfx::RectF& display_rect,
AggregatedRenderPass* render_pass,
const gfx::Rect& quad_rectangle,
+ const gfx::Rect& occluding_damage_rect,
const QuadList::Iterator& it,
gfx::Rect* damage_rect,
gfx::Rect* this_frame_underlay_rect,
DCLayerOverlay* dc_layer);
+ void UpdateRootDamageRect(const gfx::RectF& display_rect,
+ gfx::Rect* damage_rect);
+
+ void RemoveOverlayDamageRect(const QuadList::Iterator& it,
+ const gfx::Rect& quad_rectangle,
+ const gfx::Rect& occluding_damage_rect,
+ gfx::Rect* damage_rect);
+
void InsertDebugBorderDrawQuad(const DCLayerOverlayList* dc_layer_overlays,
AggregatedRenderPass* render_pass,
const gfx::RectF& display_rect,
gfx::Rect* damage_rect);
+ bool IsPreviousFrameUnderlayRect(const gfx::Rect& quad_rectangle,
+ size_t index);
bool has_overlay_support_;
+ const bool use_overlay_damage_list_;
+ // TODO(magchen@): We are going to support more than one YUV overlay.
+ const int allowed_yuv_overlay_count_;
+ int processed_yuv_overlay_count_ = 0;
+
// Reference to the global viz singleton.
const DebugRendererSettings* const debug_settings_;
@@ -148,6 +176,18 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
int previous_frame_processed_overlay_count_ = 0;
int current_frame_processed_overlay_count_ = 0;
+ struct OverlayRect {
+ gfx::Rect rect;
+ bool is_overlay; // If false, it's an underlay.
+ bool operator==(const OverlayRect& b) {
+ return rect == b.rect && is_overlay == b.is_overlay;
+ }
+ bool operator!=(const OverlayRect& b) { return !(*this == b); }
+ };
+ std::vector<OverlayRect> previous_frame_overlay_rects_;
+ std::vector<OverlayRect> current_frame_overlay_rects_;
+ SurfaceDamageRectList* surface_damage_rect_list_;
+
scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
DISALLOW_COPY_AND_ASSIGN(DCLayerOverlayProcessor);
diff --git a/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.cc b/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.cc
new file mode 100644
index 00000000000..c1a587c2bfe
--- /dev/null
+++ b/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 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 "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
+
+#include "components/viz/service/display/direct_renderer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace viz {
+
+DelegatedInkPointPixelTestHelper::DelegatedInkPointPixelTestHelper() = default;
+DelegatedInkPointPixelTestHelper::~DelegatedInkPointPixelTestHelper() = default;
+
+DelegatedInkPointPixelTestHelper::DelegatedInkPointPixelTestHelper(
+ DirectRenderer* renderer)
+ : renderer_(renderer) {
+ renderer_->CreateDelegatedInkPointRenderer();
+}
+
+void DelegatedInkPointPixelTestHelper::SetRendererAndCreateInkRenderer(
+ DirectRenderer* renderer) {
+ renderer_ = renderer;
+ renderer_->CreateDelegatedInkPointRenderer();
+}
+
+DelegatedInkPointRendererBase*
+DelegatedInkPointPixelTestHelper::GetInkRenderer() {
+ return renderer_->GetDelegatedInkPointRenderer();
+}
+
+void DelegatedInkPointPixelTestHelper::CreateAndSendMetadata(
+ const gfx::PointF& point,
+ float diameter,
+ SkColor color,
+ const gfx::RectF& presentation_area) {
+ DCHECK(renderer_);
+ metadata_ =
+ DelegatedInkMetadata(point, diameter, color, base::TimeTicks::Now(),
+ presentation_area, base::TimeTicks::Now());
+ GetInkRenderer()->SetDelegatedInkMetadata(
+ std::make_unique<DelegatedInkMetadata>(metadata_));
+}
+
+void DelegatedInkPointPixelTestHelper::CreateAndSendMetadataFromLastPoint() {
+ DCHECK(renderer_);
+ metadata_ = DelegatedInkMetadata(
+ ink_points_.back().point(), metadata_.diameter(), metadata_.color(),
+ ink_points_.back().timestamp(), metadata_.presentation_area(),
+ metadata_.frame_time());
+ GetInkRenderer()->SetDelegatedInkMetadata(
+ std::make_unique<DelegatedInkMetadata>(metadata_));
+}
+
+void DelegatedInkPointPixelTestHelper::CreateAndSendPoint(
+ const gfx::PointF& point,
+ base::TimeTicks timestamp) {
+ DCHECK(renderer_);
+ ink_points_.emplace_back(point, timestamp);
+ GetInkRenderer()->StoreDelegatedInkPoint(ink_points_.back());
+}
+
+void DelegatedInkPointPixelTestHelper::CreateAndSendPointFromMetadata() {
+ CreateAndSendPoint(metadata().point(), metadata().timestamp());
+}
+
+void DelegatedInkPointPixelTestHelper::CreateAndSendPointFromLastPoint(
+ const gfx::PointF& point) {
+ EXPECT_GT(static_cast<int>(ink_points_.size()), 0);
+ CreateAndSendPoint(point, ink_points_.back().timestamp() +
+ base::TimeDelta::FromMicroseconds(10));
+}
+
+gfx::Rect DelegatedInkPointPixelTestHelper::GetDelegatedInkDamageRect() {
+ EXPECT_GT(static_cast<int>(ink_points_.size()), 0);
+ gfx::RectF ink_damage_rect_f =
+ gfx::RectF(ink_points_[0].point(), gfx::SizeF(1, 1));
+ for (uint64_t i = 1; i < ink_points_.size(); ++i) {
+ ink_damage_rect_f.Union(
+ gfx::RectF(ink_points_[i].point(), gfx::SizeF(1, 1)));
+ }
+ ink_damage_rect_f.Inset(-metadata().diameter() / 2.f,
+ -metadata().diameter() / 2.f);
+
+ return gfx::ToEnclosingRect(ink_damage_rect_f);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.h b/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.h
new file mode 100644
index 00000000000..c9003de644b
--- /dev/null
+++ b/chromium/components/viz/service/display/delegated_ink_point_pixel_test_helper.h
@@ -0,0 +1,60 @@
+// Copyright 2020 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_VIZ_SERVICE_DISPLAY_DELEGATED_INK_POINT_PIXEL_TEST_HELPER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_DELEGATED_INK_POINT_PIXEL_TEST_HELPER_H_
+
+#include <vector>
+
+#include "components/viz/common/delegated_ink_metadata.h"
+
+namespace viz {
+
+class DelegatedInkPoint;
+class DelegatedInkPointRendererBase;
+class DirectRenderer;
+
+// Helper class for running pixel tests to flex the delegated ink point
+// renderers. |renderer_| must be supplied, either when constructed or later
+// after cc::PixelTest::SetUp() has run, which creates the renderer. Then it
+// can be used to create and give ink metadata and points to |renderer_|'s
+// delegated ink point renderer. The metadata and points are stored so that the
+// information can be used for future points and metadata (i.e. when a point
+// needs to match the metadata for the first point of a trail) or when
+// determining the damage rect to apply to a render pass.
+class DelegatedInkPointPixelTestHelper {
+ public:
+ DelegatedInkPointPixelTestHelper();
+ ~DelegatedInkPointPixelTestHelper();
+
+ explicit DelegatedInkPointPixelTestHelper(DirectRenderer* renderer);
+ void SetRendererAndCreateInkRenderer(DirectRenderer* renderer);
+ DelegatedInkPointRendererBase* GetInkRenderer();
+
+ void CreateAndSendMetadata(const gfx::PointF& point,
+ float diameter,
+ SkColor color,
+ const gfx::RectF& presentation_area);
+
+ void CreateAndSendMetadataFromLastPoint();
+
+ void CreateAndSendPoint(const gfx::PointF& point, base::TimeTicks timestamp);
+ void CreateAndSendPointFromMetadata();
+ // Used when sending multiple points to be drawn as a single trail, so it uses
+ // the most recently provided point's timestamp to determine the new one.
+ void CreateAndSendPointFromLastPoint(const gfx::PointF& point);
+
+ gfx::Rect GetDelegatedInkDamageRect();
+
+ const DelegatedInkMetadata& metadata() { return metadata_; }
+
+ private:
+ DirectRenderer* renderer_ = nullptr;
+ std::vector<DelegatedInkPoint> ink_points_;
+ DelegatedInkMetadata metadata_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DELEGATED_INK_POINT_PIXEL_TEST_HELPER_H_
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
index a54d732ae2e..76bf1beabb9 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
@@ -6,44 +6,153 @@
#include "base/trace_event/trace_event.h"
#include "components/viz/common/delegated_ink_metadata.h"
+#include "ui/base/prediction/kalman_predictor.h"
namespace viz {
-DelegatedInkPointRendererBase::DelegatedInkPointRendererBase() = default;
+DelegatedInkPointRendererBase::DelegatedInkPointRendererBase()
+ : metrics_handler_("Renderer.DelegatedInkTrail.Prediction") {
+ unsigned int predictor_options =
+ ui::KalmanPredictor::PredictionOptions::kHeuristicsEnabled |
+ ui::KalmanPredictor::PredictionOptions::kDirectionCutOffEnabled;
+ predictor_ = std::make_unique<ui::KalmanPredictor>(predictor_options);
+}
DelegatedInkPointRendererBase::~DelegatedInkPointRendererBase() = default;
void DelegatedInkPointRendererBase::InitMessagePipeline(
mojo::PendingReceiver<mojom::DelegatedInkPointRenderer> receiver) {
+ // The remote end of this pipeline exists on a per-tab basis, so if tab A
+ // is using the feature and then tab B starts trying to use it, a new
+ // PendingReceiver will arrive here while |receiver_| is still bound to the
+ // remote in tab A. In this case, just reset |receiver_| so that tab A's
+ // remote is unbound and bind the new receiver to use the feature in tab B.
+ if (receiver_.is_bound()) {
+ receiver_.reset();
+ metadata_.reset();
+ points_.clear();
+ }
receiver_.Bind(std::move(receiver));
}
-void DelegatedInkPointRendererBase::DrawDelegatedInkTrail() {
- if (!metadata_)
- return;
+void DelegatedInkPointRendererBase::SetDelegatedInkMetadata(
+ std::unique_ptr<DelegatedInkMetadata> metadata) {
+ // Frame time is set later than everything else due to what is available
+ // at time of creation, so confirm that it was actually set.
+ DCHECK_NE(metadata->frame_time(), base::TimeTicks());
+ metadata_ = std::move(metadata);
+}
+
+std::vector<DelegatedInkPoint> DelegatedInkPointRendererBase::FilterPoints() {
+ if (points_.size() == 0)
+ return {};
+
+ DCHECK(metadata_);
+
+ // TODO(1052145): Add additional filtering to prevent points in |points_| from
+ // having a timestamp that is far ahead of |metadata_|'s timestamp. This could
+ // occur if the renderer stalls before sending a metadata while the browser
+ // continues to pump points through to viz. Then when the renderer starts back
+ // up again, the metadata it sends may be significantly older than the points
+ // stored here, resulting in a long possibly incorrect trail if the max
+ // number of points to store was reached.
+
+ // First remove all points from |points_| with timestamps earlier than
+ // |metadata_|, as they have already been rendered by the app and are no
+ // longer useful for a trail.
+ // After that, there are three possible state of |points_|:
+ // 1. The earliest DelegatedInkPoint in |points_| matches |metadata_|'s
+ // timestamp. All the points in |points_| can be used to draw a trail.
+ // 2. |points_| is empty. No DelegatedInkPoints arrived from the browser
+ // process with a timestamp equal to or later than |metadata_|'s, so we
+ // don't have any points to make a trail from.
+ // 3. There are DelegatedInkPoints in |points_|, but the earliest one is
+ // later than |metadata_|. This can happen most often when the API is
+ // first used, as the browser process did not know to send the point
+ // to viz before it was used to make the metadata in the renderer. So
+ // although it didn't send the DelegatedInkPoint matching |metadata_|, it
+ // still may have sent future points before the metadata propagated all
+ // the way here. In this case, we choose not to use the points in
+ // |points_| to draw, as we have no way of confirming that there
+ // shouldn't be any extra points between |metadata_| and the beginning
+ // of |points_|. So instead, just leave everything after |metadata_| in
+ // |points_| so that they may be used in future trails and don't draw
+ // any trail for the current |metadata_|.
+ // So if |points_| contains a timestamp that matches |metadata_|'s timestamp,
+ // add it and every point after it to |points_to_draw| and return it for
+ // drawing. If it doesn't, just return an empty vector and leave any point
+ // with a timestamp later than |metadata_|'s in |points_|.
+ std::vector<DelegatedInkPoint> points_to_draw;
+
+ auto it = points_.begin();
+ while (points_.size() > 0 && it != points_.end()) {
+ if (it->first < metadata_->timestamp()) {
+ // Sanity check to confirm that we always find the points that are before
+ // |metadata_|'s timestamp at the beginning of |points_| since it should
+ // be sorted.
+ DCHECK(it == points_.begin());
+ it = points_.erase(it);
+ } else {
+ if (it->first == metadata_->timestamp() || points_to_draw.size() > 0) {
+ points_to_draw.emplace_back(it->second, it->first);
+ metrics_handler_.AddRealEvent(it->second, it->first,
+ metadata_->frame_time());
+ it++;
+ } else {
+ // If we find a point that is later than |metadata_|'s timestamp before
+ // finding one that matches |metadata_|'s timestamp, that means that
+ // it doesn't exist in |points_|, so return an empty vector as there are
+ // no valid points to draw.
+ break;
+ }
+ }
+ }
+
+ return points_to_draw;
+}
+
+void DelegatedInkPointRendererBase::PredictPoints(
+ std::vector<DelegatedInkPoint>* ink_points_to_draw) {
+ DCHECK(metadata_);
+ int points_predicted = 0;
- DrawDelegatedInkTrailInternal();
+ // |ink_points_to_draw| needs to have at least one point in it already as a
+ // reference to know what timestamp to start predicting points at. This single
+ // point may just match |metadata_|.
+ if (predictor_->HasPrediction() && ink_points_to_draw->size() > 0) {
+ for (int i = 0; i < kNumberOfPointsToPredict; ++i) {
+ base::TimeTicks timestamp =
+ ink_points_to_draw->back().timestamp() +
+ base::TimeDelta::FromMilliseconds(
+ kNumberOfMillisecondsIntoFutureToPredictPerPoint);
+ std::unique_ptr<ui::InputPredictor::InputData> predicted_point =
+ predictor_->GeneratePrediction(timestamp);
+ if (predicted_point) {
+ ink_points_to_draw->emplace_back(predicted_point->pos,
+ predicted_point->time_stamp);
+ metrics_handler_.AddPredictedEvent(predicted_point->pos,
+ predicted_point->time_stamp,
+ metadata_->frame_time());
+ points_predicted++;
+ } else {
+ // HasPrediction() can return true while GeneratePrediction() fails to
+ // produce a prediction if the predicted point would go in to the
+ // opposite direction of most recently stored points. If this happens,
+ // don't continue trying to generate more predicted points.
+ break;
+ }
+ }
+ }
- // Always reset |metadata_| regardless of the outcome of
- // DrawDelegatedInkPathInternal() so that the trail is never incorrectly
- // drawn if the aggregated frame did not contain delegated ink metadata.
- metadata_.reset();
+ TRACE_EVENT_INSTANT1("viz", "DelegatedInkPointRendererBase::PredictPoints",
+ TRACE_EVENT_SCOPE_THREAD, "predicted points",
+ points_predicted);
+
+ metrics_handler_.EvaluatePrediction();
}
-void DelegatedInkPointRendererBase::FilterPoints() {
- if (points_.size() == 0)
- return;
-
- auto first_valid_point = points_.find(metadata_->timestamp());
- // It is possible that this results in |points_| being empty. This occurs when
- // the points being forwarded from the browser process lose the race against
- // the ink metadata arriving in Display, including the point that matches the
- // metadata. There may still be old points in |points_| allowing execution to
- // get here, but none of them match the metadata point, so they are all
- // erased.
- points_.erase(points_.begin(), first_valid_point);
-
- TRACE_EVENT_INSTANT1("viz", "Filtered points for delegated ink trail",
- TRACE_EVENT_SCOPE_THREAD, "points", points_.size());
+void DelegatedInkPointRendererBase::ResetPrediction() {
+ predictor_->Reset();
+ metrics_handler_.Reset();
}
void DelegatedInkPointRendererBase::StoreDelegatedInkPoint(
@@ -52,6 +161,9 @@ void DelegatedInkPointRendererBase::StoreDelegatedInkPoint(
"DelegatedInkPointRendererImpl::StoreDelegatedInkPoint",
TRACE_EVENT_SCOPE_THREAD, "point", point.ToString());
+ predictor_->Update(
+ ui::InputPredictor::InputData(point.point(), point.timestamp()));
+
// Fail-safe to prevent storing excessive points if they are being sent but
// never filtered and used, like if the renderer has stalled during a long
// running script.
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
index a6b962d1208..e91589912b4 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
@@ -8,10 +8,13 @@
#include <map>
#include <memory>
#include <utility>
+#include <vector>
#include "components/viz/service/viz_service_export.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "services/viz/public/mojom/compositing/delegated_ink_point.mojom.h"
+#include "ui/base/prediction/input_predictor.h"
+#include "ui/base/prediction/prediction_metrics_handler.h"
namespace viz {
class DelegatedInkMetadata;
@@ -21,6 +24,14 @@ class DelegatedInkMetadata;
// added.
constexpr int kMaximumDelegatedInkPointsStored = 10;
+// The number of points to predict into the future, when prediction is
+// available.
+constexpr int kNumberOfPointsToPredict = 1;
+
+// The time that each predicted point should be ahead of the previous point,
+// in milliseconds.
+constexpr int kNumberOfMillisecondsIntoFutureToPredictPerPoint = 12;
+
// This is the base class used for rendering delegated ink trails on the end of
// strokes to reduce user perceived latency. On initialization, it binds the
// mojo interface required for receiving delegated ink points that are made and
@@ -41,11 +52,10 @@ class VIZ_SERVICE_EXPORT DelegatedInkPointRendererBase
mojo::PendingReceiver<mojom::DelegatedInkPointRenderer> receiver);
void StoreDelegatedInkPoint(const DelegatedInkPoint& point) override;
- void SetDelegatedInkMetadata(std::unique_ptr<DelegatedInkMetadata> metadata) {
- metadata_ = std::move(metadata);
- }
+ void SetDelegatedInkMetadata(std::unique_ptr<DelegatedInkMetadata> metadata);
- void DrawDelegatedInkTrail();
+ virtual void FinalizePathForDraw() = 0;
+ virtual gfx::Rect GetDamageRect() = 0;
protected:
// |points_| is not emptied each time after the points are drawn, because one
@@ -53,15 +63,15 @@ class VIZ_SERVICE_EXPORT DelegatedInkPointRendererBase
// ink trail. However, if a point has a timestamp that is earlier than the
// timestamp on the metadata, then the point has already been drawn, and
// therefore should be removed from |points_| before drawing.
- void FilterPoints();
+ std::vector<DelegatedInkPoint> FilterPoints();
+
+ void PredictPoints(std::vector<DelegatedInkPoint>* ink_points_to_draw);
+ void ResetPrediction();
std::unique_ptr<DelegatedInkMetadata> metadata_;
- std::map<base::TimeTicks, gfx::PointF> points_;
private:
- FRIEND_TEST_ALL_PREFIXES(DisplayTest, SkiaDelegatedInkRenderer);
-
- void virtual DrawDelegatedInkTrailInternal() = 0;
+ friend class SkiaDelegatedInkRendererTest;
const std::map<base::TimeTicks, gfx::PointF>& GetPointsMapForTest() const {
return points_;
@@ -71,6 +81,19 @@ class VIZ_SERVICE_EXPORT DelegatedInkPointRendererBase
return metadata_.get();
}
+ virtual int GetPathPointCountForTest() const = 0;
+
+ // The points that arrived from the browser process and may be drawn as part
+ // of the ink trail.
+ std::map<base::TimeTicks, gfx::PointF> points_;
+
+ // Kalman predictor that is used for generating predicted points.
+ std::unique_ptr<ui::InputPredictor> predictor_;
+
+ // Handler for calculating useful metrics for evaluating predicted points
+ // and populating the histograms with those metrics.
+ ui::PredictionMetricsHandler metrics_handler_;
+
mojo::Receiver<mojom::DelegatedInkPointRenderer> receiver_{this};
};
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
index cc29133904b..0175f417494 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
@@ -4,28 +4,161 @@
#include "components/viz/service/display/delegated_ink_point_renderer_skia.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
#include "components/viz/common/delegated_ink_metadata.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
namespace viz {
-void DelegatedInkPointRendererSkia::DrawDelegatedInkTrailInternal() {
- // First, filter the delegated ink points so that only ones that have a
- // timestamp that is equal to or later than the metadata still exist.
- FilterPoints();
+void DelegatedInkPointRendererSkia::DrawDelegatedInkTrail(SkCanvas* canvas) {
+ TRACE_EVENT1("viz", "DelegatedInkPointRendererSkia::DrawDelegatedInkTrail",
+ "points", path_.countPoints());
- if (points_.size() == 0)
+ if (!metadata_)
return;
- // Prediction will occur here. The CL to move prediction to ui/base must land
- // first in order for this to happen.
+ if (!path_.isEmpty() && canvas) {
+ SkRect bounds = gfx::RectFToSkRect(metadata_->presentation_area());
+ canvas->saveLayer(SkCanvas::SaveLayerRec(&bounds, nullptr));
- // If there is only one point total between |points_| and predicted points,
- // then it will match the metadata point and therefore doesn't need to be
- // drawn in this way, as it will be rendered normally.
- // TODO(1052145): Early out here if the above condition is met.
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setBlendMode(SkBlendMode::kSrcOver);
+ paint.setColor(metadata_->color());
+ paint.setFilterQuality(kNone_SkFilterQuality);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ paint.setStrokeWidth(SkScalar(metadata_->diameter()));
+ paint.setStyle(SkPaint::kStroke_Style);
- // TODO(1052145): Draw the all remaining points in |points_| with bezier
- // curves between them onto the skia canvas.
+ canvas->drawPath(path_, paint);
+
+ canvas->restore();
+
+ path_.rewind();
+ }
+
+ // Always reset |metadata_| regardless of if the draw occurred or not so that
+ // the trail is never incorrectly drawn if the aggregated frame did not
+ // contain delegated ink metadata.
+ metadata_.reset();
+}
+
+gfx::Rect DelegatedInkPointRendererSkia::GetDamageRect() {
+ if (old_trail_damage_rect_.IsEmpty() && new_trail_damage_rect_.IsEmpty())
+ return gfx::Rect();
+
+ gfx::RectF damage_rect_f = old_trail_damage_rect_;
+
+ damage_rect_f.Union(new_trail_damage_rect_);
+
+ return gfx::ToEnclosingRect(damage_rect_f);
+}
+
+base::TimeDelta GetImprovement(
+ const std::vector<DelegatedInkPoint>* points_to_draw,
+ const DelegatedInkMetadata* metadata) {
+ if (points_to_draw->size() == 0)
+ return base::TimeDelta::FromMilliseconds(0);
+
+ return points_to_draw->back().timestamp() - metadata->timestamp();
+}
+
+std::vector<SkPoint> DelegatedInkPointRendererSkia::GetPointsToDraw() {
+ std::vector<DelegatedInkPoint> ink_points_to_draw = FilterPoints();
+ UMA_HISTOGRAM_TIMES(
+ "Renderer.DelegatedInkTrail.LatencyImprovement.Skia.WithoutPrediction",
+ GetImprovement(&ink_points_to_draw, metadata_.get()));
+
+ PredictPoints(&ink_points_to_draw);
+ UMA_HISTOGRAM_TIMES(
+ "Renderer.DelegatedInkTrail.LatencyImprovement.Skia.WithPrediction",
+ GetImprovement(&ink_points_to_draw, metadata_.get()));
+
+ std::vector<SkPoint> sk_points;
+ for (DelegatedInkPoint ink_point : ink_points_to_draw)
+ sk_points.push_back(gfx::PointFToSkPoint(ink_point.point()));
+
+ return sk_points;
+}
+
+void DelegatedInkPointRendererSkia::FinalizePathForDraw() {
+ // Always rewind the path first so that a path isn't drawn twice.
+ path_.rewind();
+
+ // Setting the damage rect to empty ensures that the damage rect is cleared
+ // when trails are not being drawn so that extra drawing doesn't occur. If
+ // there isn't metadata, that also indicates that the previous trail has
+ // finished so the predictor should be reset as well.
+ if (!metadata_) {
+ SetDamageRect(gfx::RectF());
+ ResetPrediction();
+ return;
+ }
+
+ std::vector<SkPoint> sk_points = GetPointsToDraw();
+
+ TRACE_EVENT_INSTANT1("viz",
+ "Filtered and predicted points for delegated ink trail",
+ TRACE_EVENT_SCOPE_THREAD, "points", sk_points.size());
+
+ // If there is only one point total after filtering and predicting, then it
+ // will match the metadata point and therefore doesn't need to be drawn in
+ // this way, as it will be rendered normally.
+ if (sk_points.size() <= 1) {
+ SetDamageRect(gfx::RectF());
+ return;
+ }
+
+ path_.moveTo(sk_points[0]);
+ switch (sk_points.size()) {
+ case 2:
+ path_.lineTo(sk_points[1]);
+ break;
+ case 3:
+ path_.quadTo(sk_points[1], sk_points[2]);
+ break;
+ case 4:
+ path_.cubicTo(sk_points[1], sk_points[2], sk_points[3]);
+ break;
+ default:
+ // The connection between two cubic bezier curves will be smooth only if
+ // the second control point of the first curve, the end point of the first
+ // curve/first control point of the second curve, and the second control
+ // point of the second curve are colinear. Since this is unlikely to be
+ // the case, connecting all four points via lines should be acceptable.
+ for (uint64_t i = 1; i < sk_points.size(); ++i)
+ path_.lineTo(sk_points[i]);
+ break;
+ }
+
+ // path_.computeTightBounds() returns a rect that contains the points and
+ // curves, but it isn't guaranteed to contain the drawn stroke, resulting in
+ // the stroke sometimes existing outside of the damage_rect. Therefore, expand
+ // it here to ensure that the stroke is included, then intersect with the
+ // presentation area so that is can't extend beyond the drawable area.
+ gfx::RectF damage_rect = gfx::SkRectToRectF(path_.computeTightBounds());
+ const float kRadius = metadata_->diameter() / 2.f;
+ damage_rect.Inset(-kRadius, -kRadius);
+ damage_rect.Intersect(metadata_->presentation_area());
+
+ TRACE_EVENT_INSTANT1(
+ "viz", "DelegatedInkPointRendererSkia::FinalizePathForDraw",
+ TRACE_EVENT_SCOPE_THREAD, "damage_rect", damage_rect.ToString());
+
+ SetDamageRect(damage_rect);
+}
+
+void DelegatedInkPointRendererSkia::SetDamageRect(gfx::RectF damage_rect) {
+ old_trail_damage_rect_ = new_trail_damage_rect_;
+ new_trail_damage_rect_ = damage_rect;
+}
+
+int DelegatedInkPointRendererSkia::GetPathPointCountForTest() const {
+ return path_.countPoints();
}
} // namespace viz
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
index 34f50116cb0..cebaf231d5a 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
@@ -5,8 +5,13 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DELEGATED_INK_POINT_RENDERER_SKIA_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_DELEGATED_INK_POINT_RENDERER_SKIA_H_
+#include <vector>
+
#include "components/viz/service/display/delegated_ink_point_renderer_base.h"
#include "components/viz/service/viz_service_export.h"
+#include "third_party/skia/include/core/SkPath.h"
+
+class SkCanvas;
namespace viz {
@@ -17,6 +22,26 @@ namespace viz {
// renderer, the |current_canvas_|.
// TODO(1052145): Specify exactly how many points are predicted.
//
+// When an ink trail is getting ready to be drawn, after points and metadata
+// have already arrived, the first thing that will be called is
+// FinalizePathForDraw(). This is called when determining the portion of the
+// frame that needs to be redrawn, so that GetDamageRect() can return the union
+// of the bounding box of the previous ink trail that had been drawn (stored in
+// |new_trail_damage_rect_| at this time) and the new ink trail.
+// FinalizePathForDraw() will filter points, predict new ones, and use the
+// result to update |path_| with the new ink trail. It also calls
+// SetDamageRect() with the new trail's damage rect, which moves the rect
+// currently in |new_trail_damage_rect_| to |old_trail_damage_rect_| and the new
+// damage rect goes to |new_trail_damage_rect_|. GetDamageRect() then returns
+// the union of the two for drawing.
+// Then, after everything else in the frame has been drawn,
+// DrawDelegatedInkTrail() will be called to actually draw the |path_| that was
+// determined in FinalizePathForDraw().
+// After drawing and swapping the buffers has completed, the display will call
+// GetDamageRect() in order to update the ink trail damage rect on the surface
+// aggregator, which is used to ensure one more frame will be drawn so that a
+// trail never sticks around for longer than intended.
+//
// For more information on the feature, please see the explainer:
// https://github.com/WICG/ink-enhancement/blob/master/README.md
class VIZ_SERVICE_EXPORT DelegatedInkPointRendererSkia
@@ -27,8 +52,43 @@ class VIZ_SERVICE_EXPORT DelegatedInkPointRendererSkia
DelegatedInkPointRendererSkia& operator=(
const DelegatedInkPointRendererSkia&) = delete;
+ // Set |path_| that will be drawn in the DrawDelegatedInkTrail() call. This is
+ // called before GetDamageRect() when determining what portion of the frame
+ // needs to be redrawn - earlier in the execution than the actual drawing
+ // happens. Finalizing the trail when determining the portion of the frame
+ // that needs to be redrawn is necessary so that the damage rect of the new
+ // trail is known and the new trail can be drawn entirely, while
+ // simultaneously removing the old trail and optimizing the damage rect to be
+ // as small as possible. The alternative is to use |metadata_|'s presentation
+ // area as the damage rect instead - then the path could be finalized directly
+ // before drawing instead. However, this could result in a noticeable
+ // performance hit by drawing much more than necessary.
+ void FinalizePathForDraw() override;
+
+ // Returns the union of |old_trail_damage_rect_| and |new_trail_damage_rect_|.
+ gfx::Rect GetDamageRect() override;
+
+ void DrawDelegatedInkTrail(SkCanvas* canvas);
+
private:
- void DrawDelegatedInkTrailInternal() override;
+ void SetDamageRect(gfx::RectF);
+
+ // First filters the points that are stored to only keep points with a
+ // timestamp equal to or later than |metadata_|'s, then predict points if
+ // possible. Then converts those points into SkPoints and returns them.
+ std::vector<SkPoint> GetPointsToDraw();
+
+ int GetPathPointCountForTest() const override;
+
+ // The path that will be drawn in DrawDelegatedInkTrail(). See class comments
+ // and FinalizePathForDraw() comment to understand when and why this is
+ // updated.
+ SkPath path_;
+
+ // The damage rects for the trail currently on the screen, and the next one
+ // to be drawn, as of the DrawDelegatedInkTrail() call.
+ gfx::RectF old_trail_damage_rect_;
+ gfx::RectF new_trail_damage_rect_;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index e237e4233a4..01a63bb80f3 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -33,46 +33,10 @@
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_util.h"
namespace {
-static gfx::Transform OrthoProjectionMatrix(float left,
- float right,
- float bottom,
- float top) {
- // Use the standard formula to map the clipping frustum to the cube from
- // [-1, -1, -1] to [1, 1, 1].
- float delta_x = right - left;
- float delta_y = top - bottom;
- gfx::Transform proj;
- if (!delta_x || !delta_y)
- return proj;
- proj.matrix().set(0, 0, 2.0f / delta_x);
- proj.matrix().set(0, 3, -(right + left) / delta_x);
- proj.matrix().set(1, 1, 2.0f / delta_y);
- proj.matrix().set(1, 3, -(top + bottom) / delta_y);
-
- // Z component of vertices is always set to zero as we don't use the depth
- // buffer while drawing.
- proj.matrix().set(2, 2, 0);
-
- return proj;
-}
-
-static gfx::Transform window_matrix(int x, int y, int width, int height) {
- gfx::Transform canvas;
-
- // Map to window position and scale up to pixel coordinates.
- canvas.Translate3d(x, y, 0);
- canvas.Scale3d(width, height, 0);
-
- // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1])
- canvas.Translate3d(0.5, 0.5, 0.5);
- canvas.Scale3d(0.5, 0.5, 0.5);
-
- return canvas;
-}
-
// Returns the bounding box that contains the specified rounded corner.
gfx::RectF ComputeRoundedCornerBoundingBox(const gfx::RRectF& rrect,
const gfx::RRectF::Corner corner) {
@@ -169,10 +133,10 @@ void DirectRenderer::InitializeViewport(DrawingFrame* frame,
DCHECK_LE(viewport_rect.bottom(), surface_size.height());
bool flip_y = FlippedFramebuffer();
if (flip_y) {
- frame->projection_matrix = OrthoProjectionMatrix(
+ frame->projection_matrix = gfx::OrthoProjectionMatrix(
draw_rect.x(), draw_rect.right(), draw_rect.bottom(), draw_rect.y());
} else {
- frame->projection_matrix = OrthoProjectionMatrix(
+ frame->projection_matrix = gfx::OrthoProjectionMatrix(
draw_rect.x(), draw_rect.right(), draw_rect.y(), draw_rect.bottom());
}
@@ -180,8 +144,8 @@ void DirectRenderer::InitializeViewport(DrawingFrame* frame,
if (flip_y)
window_rect.set_y(surface_size.height() - viewport_rect.bottom());
frame->window_matrix =
- window_matrix(window_rect.x(), window_rect.y(), window_rect.width(),
- window_rect.height());
+ gfx::WindowMatrix(window_rect.x(), window_rect.y(), window_rect.width(),
+ window_rect.height());
current_draw_rect_ = draw_rect;
current_viewport_rect_ = viewport_rect;
current_surface_size_ = surface_size;
@@ -244,7 +208,8 @@ void DirectRenderer::DrawFrame(
AggregatedRenderPassList* render_passes_in_draw_order,
float device_scale_factor,
const gfx::Size& device_viewport_size,
- const gfx::DisplayColorSpaces& display_color_spaces) {
+ const gfx::DisplayColorSpaces& display_color_spaces,
+ SurfaceDamageRectList* surface_damage_rect_list) {
DCHECK(visible_);
TRACE_EVENT0("viz,benchmark", "DirectRenderer::DrawFrame");
UMA_HISTOGRAM_COUNTS_1M(
@@ -285,6 +250,21 @@ void DirectRenderer::DrawFrame(
current_frame()->root_damage_rect.Union(
overlay_processor_->GetAndResetOverlayDamage());
}
+ if (DelegatedInkPointRendererBase* ink_renderer =
+ GetDelegatedInkPointRenderer()) {
+ // The path must be finalized before GetDamageRect() can return an accurate
+ // rect that will allow the old trail to be removed and the new trail to
+ // be drawn at the same time.
+ ink_renderer->FinalizePathForDraw();
+ gfx::Rect delegated_ink_damage_rect = ink_renderer->GetDamageRect();
+
+ // The viewport could have changed size since the presentation area was
+ // created and propagated, such as if is window was resized. Intersect the
+ // viewport here to ensure the damage rect doesn't extend beyond the current
+ // viewport.
+ delegated_ink_damage_rect.Intersect(gfx::Rect(device_viewport_size));
+ current_frame()->root_damage_rect.Union(delegated_ink_damage_rect);
+ }
current_frame()->root_damage_rect.Intersect(gfx::Rect(device_viewport_size));
current_frame()->device_viewport_size = device_viewport_size;
current_frame()->display_color_spaces = display_color_spaces;
@@ -346,17 +326,18 @@ void DirectRenderer::DrawFrame(
overlay_processor_->ProcessForOverlays(
resource_provider_, render_passes_in_draw_order,
output_surface_->color_matrix(), render_pass_filters_,
- render_pass_backdrop_filters_, primary_plane,
+ render_pass_backdrop_filters_, surface_damage_rect_list, primary_plane,
&current_frame()->overlay_list, &current_frame()->root_damage_rect,
&current_frame()->root_content_bounds);
// If we promote any quad to an underlay then the main plane must support
// alpha.
- // TODO(ccameron): We should update
- // |root_render_pass->has_transparent_background|, |frame_color_space|, and
+ // TODO(ccameron): We should update |frame_color_space|, and
// |frame_buffer_format| based on the change in |frame_has_alpha|.
- if (current_frame()->output_surface_plane)
+ if (current_frame()->output_surface_plane) {
frame_has_alpha |= current_frame()->output_surface_plane->enable_blending;
+ root_render_pass->has_transparent_background = frame_has_alpha;
+ }
overlay_processor_->AdjustOutputSurfaceOverlay(
&(current_frame()->output_surface_plane));
@@ -717,9 +698,6 @@ void DirectRenderer::DrawRenderPass(const AggregatedRenderPass* render_pass) {
DoDrawQuad(&quad, nullptr);
}
- if (is_root_render_pass && delegated_ink_point_renderer_)
- delegated_ink_point_renderer_->DrawDelegatedInkTrail();
-
FlushPolygons(&poly_list, render_pass_scissor_in_draw_space,
render_pass_requires_scissor);
FinishDrawingQuadList();
@@ -906,12 +884,15 @@ bool DirectRenderer::HasAllocatedResourcesForTesting(
bool DirectRenderer::ShouldApplyRoundedCorner(const DrawQuad* quad) const {
const SharedQuadState* sqs = quad->shared_quad_state;
- const gfx::RRectF& rounded_corner_bounds = sqs->rounded_corner_bounds;
+ const gfx::MaskFilterInfo& mask_filter_info = sqs->mask_filter_info;
// There is no rounded corner set.
- if (rounded_corner_bounds.IsEmpty())
+ if (!mask_filter_info.HasRoundedCorners())
return false;
+ const gfx::RRectF& rounded_corner_bounds =
+ mask_filter_info.rounded_corner_bounds();
+
const gfx::RectF target_quad = cc::MathUtil::MapClippedRect(
sqs->quad_to_target_transform, gfx::RectF(quad->visible_rect));
@@ -948,18 +929,19 @@ bool DirectRenderer::CreateDelegatedInkPointRenderer() {
}
DelegatedInkPointRendererBase* DirectRenderer::GetDelegatedInkPointRenderer() {
- if (!delegated_ink_point_renderer_ && !CreateDelegatedInkPointRenderer())
- return nullptr;
-
- return delegated_ink_point_renderer_.get();
+ return nullptr;
}
void DirectRenderer::SetDelegatedInkMetadata(
std::unique_ptr<DelegatedInkMetadata> metadata) {
- if (!delegated_ink_point_renderer_ && !CreateDelegatedInkPointRenderer())
+ if (!GetDelegatedInkPointRenderer() && !CreateDelegatedInkPointRenderer())
return;
- delegated_ink_point_renderer_->SetDelegatedInkMetadata(std::move(metadata));
+ GetDelegatedInkPointRenderer()->SetDelegatedInkMetadata(std::move(metadata));
+}
+
+void DirectRenderer::DrawDelegatedInkTrail() {
+ NOTREACHED();
}
bool DirectRenderer::CompositeTimeTracingEnabled() {
@@ -968,4 +950,11 @@ bool DirectRenderer::CompositeTimeTracingEnabled() {
void DirectRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {}
+gfx::Rect DirectRenderer::GetDelegatedInkTrailDamageRect() {
+ if (!GetDelegatedInkPointRenderer())
+ return gfx::Rect();
+
+ return GetDelegatedInkPointRenderer()->GetDamageRect();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index 89459c6bf9e..c3497e433c5 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -18,6 +18,7 @@
#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/delegated_ink_point_renderer_base.h"
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_candidate.h"
@@ -72,7 +73,8 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
void DrawFrame(AggregatedRenderPassList* render_passes_in_draw_order,
float device_scale_factor,
const gfx::Size& device_viewport_size,
- const gfx::DisplayColorSpaces& display_color_spaces);
+ const gfx::DisplayColorSpaces& display_color_spaces,
+ SurfaceDamageRectList* surface_damage_rect_list);
// The renderer might expand the damage (e.g: HW overlays were used,
// invalidation rects on previous buffers). This function returns a
@@ -139,7 +141,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
return last_root_render_pass_scissor_rect_;
}
- DelegatedInkPointRendererBase* GetDelegatedInkPointRenderer();
+ virtual DelegatedInkPointRendererBase* GetDelegatedInkPointRenderer();
void SetDelegatedInkMetadata(std::unique_ptr<DelegatedInkMetadata> metadata);
// Returns true if composite time tracing is enabled. This measures a detailed
@@ -149,9 +151,13 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
// Puts the draw time wall in trace file relative to the |ready_timestamp|.
virtual void AddCompositeTimeTraces(base::TimeTicks ready_timestamp);
+ // Return the bounding rect of previously drawn delegated ink trail.
+ gfx::Rect GetDelegatedInkTrailDamageRect();
+
protected:
friend class BspWalkActionDrawPolygon;
- FRIEND_TEST_ALL_PREFIXES(DisplayTest, SkiaDelegatedInkRenderer);
+ friend class SkiaDelegatedInkRendererTest;
+ friend class DelegatedInkPointPixelTestHelper;
enum SurfaceInitializationMode {
SURFACE_INITIALIZATION_MODE_PRESERVE,
@@ -331,9 +337,10 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
// actually created or not. If the renderer doesn't support drawing delegated
// ink trails, then the delegated ink renderer won't be created.
virtual bool CreateDelegatedInkPointRenderer();
- std::unique_ptr<DelegatedInkPointRendererBase> delegated_ink_point_renderer_;
private:
+ virtual void DrawDelegatedInkTrail();
+
bool initialized_ = false;
#if DCHECK_IS_ON()
bool overdraw_feedback_support_missing_logged_once_ = false;
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index fd9431302ff..94877489b13 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -52,7 +52,7 @@
#include "ui/gfx/swap_result.h"
#if defined(OS_ANDROID)
-#include "ui/gl/android/android_surface_control_compat.h"
+#include "ui/gfx/android/android_surface_control_compat.h"
#endif
namespace viz {
@@ -245,7 +245,7 @@ bool ReduceComplexity(const cc::Region& region,
bool SupportsSetFrameRate(const OutputSurface* output_surface) {
#if defined(OS_ANDROID)
return output_surface->capabilities().supports_surfaceless &&
- gl::SurfaceControl::SupportsSetFrameRate();
+ gfx::SurfaceControl::SupportsSetFrameRate();
#elif defined(OS_WIN)
return output_surface->capabilities().supports_dc_layers &&
features::ShouldUseSetPresentDuration();
@@ -292,6 +292,7 @@ Display::Display(
const RendererSettings& settings,
const DebugRendererSettings* debug_settings,
const FrameSinkId& frame_sink_id,
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> gpu_dependency,
std::unique_ptr<OutputSurface> output_surface,
std::unique_ptr<OverlayProcessorInterface> overlay_processor,
std::unique_ptr<DisplaySchedulerBase> scheduler,
@@ -300,6 +301,7 @@ Display::Display(
settings_(settings),
debug_settings_(debug_settings),
frame_sink_id_(frame_sink_id),
+ gpu_dependency_(std::move(gpu_dependency)),
output_surface_(std::move(output_surface)),
skia_output_surface_(output_surface_->AsSkiaOutputSurface()),
scheduler_(std::move(scheduler)),
@@ -512,13 +514,16 @@ void Display::SetOutputIsSecure(bool secure) {
}
void Display::InitializeRenderer(bool enable_shared_images) {
- auto mode = output_surface_->context_provider() || skia_output_surface_
- ? DisplayResourceProvider::kGpu
- : DisplayResourceProvider::kSoftware;
+ bool uses_gpu_resources = output_surface_->context_provider() ||
+ skia_output_surface_ ||
+ output_surface_->capabilities().skips_draw;
+
resource_provider_ = std::make_unique<DisplayResourceProvider>(
- mode, output_surface_->context_provider(), bitmap_manager_,
+ uses_gpu_resources ? DisplayResourceProvider::kGpu
+ : DisplayResourceProvider::kSoftware,
+ output_surface_->context_provider(), bitmap_manager_,
enable_shared_images);
- if (settings_.use_skia_renderer && mode == DisplayResourceProvider::kGpu) {
+ if (skia_output_surface_) {
renderer_ = std::make_unique<SkiaRenderer>(
&settings_, debug_settings_, output_surface_.get(),
resource_provider_.get(), overlay_processor_.get(),
@@ -552,7 +557,7 @@ void Display::InitializeRenderer(bool enable_shared_images) {
aggregator_ = std::make_unique<SurfaceAggregator>(
surface_manager_, resource_provider_.get(), output_partial_list,
- overlay_processor_->NeedsSurfaceOccludingDamageRect());
+ overlay_processor_->NeedsSurfaceDamageRectList());
aggregator_->set_output_is_secure(output_is_secure_);
aggregator_->SetDisplayColorSpaces(display_color_spaces_);
@@ -598,11 +603,6 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
return false;
}
- if (output_surface_->capabilities().skips_draw) {
- TRACE_EVENT_INSTANT0("viz", "Skip draw", TRACE_EVENT_SCOPE_THREAD);
- return true;
- }
-
gfx::OverlayTransform current_display_transform = gfx::OVERLAY_TRANSFORM_NONE;
Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id_);
if (surface->HasActiveFrame()) {
@@ -640,6 +640,11 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
if (output_surface_->capabilities().supports_target_damage)
target_damage_bounding_rect = renderer_->GetTargetDamageBoundingRect();
+ // Ensure that the surfaces that were damaged by any delegated ink trail are
+ // aggregated again so that the trail exists for a single frame.
+ target_damage_bounding_rect.Union(
+ renderer_->GetDelegatedInkTrailDamageRect());
+
frame = aggregator_->Aggregate(
current_surface_id_, expected_display_time, current_display_transform,
target_damage_bounding_rect, ++swapped_trace_id_);
@@ -661,6 +666,9 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
renderer_->SetDelegatedInkMetadata(std::move(frame.delegated_ink_metadata));
}
+ UMA_HISTOGRAM_ENUMERATION("Compositing.ColorGamut",
+ frame.content_color_usage);
+
#if defined(OS_ANDROID)
bool wide_color_enabled =
display_color_spaces_.GetOutputColorSpace(
@@ -686,6 +694,14 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
// Run callbacks early to allow pipelining and collect presented callbacks.
damage_tracker_->RunDrawCallbacks();
+ if (output_surface_->capabilities().skips_draw) {
+ TRACE_EVENT_INSTANT0("viz", "Skip draw", TRACE_EVENT_SCOPE_THREAD);
+ // Aggregation needs to happen before generating hit test for the unified
+ // desktop display. After this point skip drawing anything for real.
+ client_->DisplayWillDrawAndSwap(false, &frame.render_pass_list);
+ return true;
+ }
+
frame.latency_info.insert(frame.latency_info.end(),
stored_latency_info_.begin(),
stored_latency_info_.end());
@@ -713,6 +729,7 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
// skip the draw and so that the GL swap won't stretch the output.
last_render_pass.output_rect.set_size(current_surface_size);
last_render_pass.damage_rect = last_render_pass.output_rect;
+ frame.surface_damage_rect_list_.push_back(last_render_pass.damage_rect);
}
surface_size = last_render_pass.output_rect.size();
have_damage = !last_render_pass.damage_rect.size().IsEmpty();
@@ -754,7 +771,8 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
draw_timer.emplace();
renderer_->DecideRenderPassAllocationsForFrame(frame.render_pass_list);
renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_,
- current_surface_size, display_color_spaces_);
+ current_surface_size, display_color_spaces_,
+ &frame.surface_damage_rect_list_);
switch (output_surface_->type()) {
case OutputSurface::Type::kSoftware:
UMA_HISTOGRAM_COUNTS_1M(
@@ -985,10 +1003,10 @@ void Display::DidFinishFrame(const BeginFrameAck& ack) {
for (auto& observer : observers_)
observer.OnDisplayDidFinishFrame(ack);
- // Only used with experimental de-jelly effect. Forces us to produce a new
- // un-skewed frame if the last one had a de-jelly skew applied. This prevents
- // de-jelly skew from staying on screen for more than one frame.
- if (aggregator_->last_frame_had_jelly()) {
+ // Prevent de-jelly skew or a delegated ink trail from staying on the screen
+ // for more than one frame by forcing a new frame to be produced.
+ if (aggregator_->last_frame_had_jelly() ||
+ !renderer_->GetDelegatedInkTrailDamageRect().IsEmpty()) {
scheduler_->SetNeedsOneBeginFrame(true);
}
}
@@ -1099,9 +1117,10 @@ void Display::RemoveOverdrawQuads(AggregatedFrame* frame) {
// If a rounded corner is being applied then the visible rect for the
// sqs is actually even smaller. Reduce the rect size to get a
// rounded corner adjusted occluding region.
- if (!last_sqs->rounded_corner_bounds.IsEmpty()) {
- sqs_rect_in_target.Intersect(gfx::ToEnclosedRect(
- GetOccludingRectForRRectF(last_sqs->rounded_corner_bounds)));
+ if (last_sqs->mask_filter_info.HasRoundedCorners()) {
+ sqs_rect_in_target.Intersect(
+ gfx::ToEnclosedRect(GetOccludingRectForRRectF(
+ last_sqs->mask_filter_info.rounded_corner_bounds())));
}
if (last_sqs->is_clipped)
diff --git a/chromium/components/viz/service/display/display.h b/chromium/components/viz/service/display/display.h
index 45ac81dd09a..a98ab0ff387 100644
--- a/chromium/components/viz/service/display/display.h
+++ b/chromium/components/viz/service/display/display.h
@@ -20,6 +20,7 @@
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/display/frame_rate_decider.h"
@@ -81,14 +82,16 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
// a MessageLoop.
// TODO(penghuang): Remove skia_output_surface when all DirectRenderer
// subclasses are replaced by SkiaRenderer.
- Display(SharedBitmapManager* bitmap_manager,
- const RendererSettings& settings,
- const DebugRendererSettings* debug_settings,
- const FrameSinkId& frame_sink_id,
- std::unique_ptr<OutputSurface> output_surface,
- std::unique_ptr<OverlayProcessorInterface> overlay_processor,
- std::unique_ptr<DisplaySchedulerBase> scheduler,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner);
+ Display(
+ SharedBitmapManager* bitmap_manager,
+ const RendererSettings& settings,
+ const DebugRendererSettings* debug_settings,
+ const FrameSinkId& frame_sink_id,
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> gpu_dependency,
+ std::unique_ptr<OutputSurface> output_surface,
+ std::unique_ptr<OverlayProcessorInterface> overlay_processor,
+ std::unique_ptr<DisplaySchedulerBase> scheduler,
+ scoped_refptr<base::SingleThreadTaskRunner> current_task_runner);
~Display() override;
@@ -253,6 +256,7 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
std::unique_ptr<gpu::ScopedAllowScheduleGpuTask>
allow_schedule_gpu_task_during_destruction_;
#endif
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> gpu_dependency_;
std::unique_ptr<OutputSurface> output_surface_;
SkiaOutputSurface* const skia_output_surface_;
std::unique_ptr<DisplayDamageTracker> damage_tracker_;
diff --git a/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.cc b/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.cc
new file mode 100644
index 00000000000..c546d4879cf
--- /dev/null
+++ b/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.cc
@@ -0,0 +1,114 @@
+// Copyright 2020 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/viz/service/display/display_compositor_memory_and_task_controller.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
+#include "gpu/ipc/scheduler_sequence.h"
+#include "gpu/ipc/shared_image_interface_in_process.h"
+
+namespace viz {
+
+DisplayCompositorMemoryAndTaskController::
+ DisplayCompositorMemoryAndTaskController(
+ std::unique_ptr<SkiaOutputSurfaceDependency> skia_dependency)
+ : skia_dependency_(std::move(skia_dependency)),
+ gpu_task_scheduler_(std::make_unique<gpu::GpuTaskSchedulerHelper>(
+ skia_dependency_->CreateSequence())) {
+ DCHECK(gpu_task_scheduler_);
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ auto callback = base::BindOnce(
+ &DisplayCompositorMemoryAndTaskController::InitializeOnGpuSkia,
+ base::Unretained(this), skia_dependency_.get(), &event);
+ gpu_task_scheduler_->ScheduleGpuTask(std::move(callback), {});
+ event.Wait();
+
+ shared_image_interface_ =
+ std::make_unique<gpu::SharedImageInterfaceInProcess>(
+ gpu_task_scheduler_->GetTaskSequence(), controller_on_gpu_.get(),
+ nullptr /* command_buffer_helper*/);
+}
+
+DisplayCompositorMemoryAndTaskController::
+ DisplayCompositorMemoryAndTaskController(
+ gpu::CommandBufferTaskExecutor* task_executor,
+ gpu::ImageFactory* image_factory)
+ : gpu_task_scheduler_(
+ std::make_unique<gpu::GpuTaskSchedulerHelper>(task_executor)) {
+ DCHECK(gpu_task_scheduler_);
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ auto callback = base::BindOnce(
+ &DisplayCompositorMemoryAndTaskController::InitializeOnGpuGL,
+ base::Unretained(this), task_executor, image_factory, &event);
+ gpu_task_scheduler_->GetTaskSequence()->ScheduleTask(std::move(callback), {});
+ event.Wait();
+
+ // TODO(weiliangc): Move VizProcessContextProvider initialization here to take
+ // ownership of the shared image interface.
+}
+
+DisplayCompositorMemoryAndTaskController::
+ ~DisplayCompositorMemoryAndTaskController() {
+ gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
+ // Make sure to destroy the SharedImageInterfaceInProcess before getting rid
+ // of data structures on the gpu thread.
+ shared_image_interface_.reset();
+
+ // If we have a |gpu_task_scheduler_|, we must have started initializing
+ // a |controller_on_gpu_| on the |gpu_task_scheduler_|.
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ auto callback =
+ base::BindOnce(&DisplayCompositorMemoryAndTaskController::DestroyOnGpu,
+ base::Unretained(this), &event);
+ gpu_task_scheduler_->GetTaskSequence()->ScheduleTask(std::move(callback), {});
+ event.Wait();
+}
+
+void DisplayCompositorMemoryAndTaskController::InitializeOnGpuSkia(
+ SkiaOutputSurfaceDependency* skia_dependency,
+ base::WaitableEvent* event) {
+ DCHECK(event);
+ controller_on_gpu_ =
+ std::make_unique<gpu::DisplayCompositorMemoryAndTaskControllerOnGpu>(
+ skia_dependency->GetSharedContextState(),
+ skia_dependency->GetMailboxManager(),
+ skia_dependency->GetGpuImageFactory(),
+ skia_dependency->GetSharedImageManager(),
+ skia_dependency->GetSyncPointManager(),
+ skia_dependency->GetGpuPreferences(),
+ skia_dependency->GetGpuDriverBugWorkarounds(),
+ skia_dependency->GetGpuFeatureInfo());
+ event->Signal();
+}
+
+void DisplayCompositorMemoryAndTaskController::InitializeOnGpuGL(
+ gpu::CommandBufferTaskExecutor* task_executor,
+ gpu::ImageFactory* image_factory,
+ base::WaitableEvent* event) {
+ DCHECK(event);
+ controller_on_gpu_ =
+ std::make_unique<gpu::DisplayCompositorMemoryAndTaskControllerOnGpu>(
+ task_executor, image_factory);
+ event->Signal();
+}
+
+void DisplayCompositorMemoryAndTaskController::DestroyOnGpu(
+ base::WaitableEvent* event) {
+ DCHECK(event);
+ controller_on_gpu_.reset();
+ event->Signal();
+}
+
+gpu::SharedImageInterface*
+DisplayCompositorMemoryAndTaskController::shared_image_interface() {
+ return shared_image_interface_.get();
+}
+} // namespace viz
diff --git a/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.h b/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.h
new file mode 100644
index 00000000000..da664cdb574
--- /dev/null
+++ b/chromium/components/viz/service/display/display_compositor_memory_and_task_controller.h
@@ -0,0 +1,85 @@
+// Copyright 2020 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_VIZ_SERVICE_DISPLAY_DISPLAY_COMPOSITOR_MEMORY_AND_TASK_CONTROLLER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_COMPOSITOR_MEMORY_AND_TASK_CONTROLLER_H_
+
+#include <memory>
+
+#include "components/viz/service/viz_service_export.h"
+#include "gpu/ipc/display_compositor_memory_and_task_controller_on_gpu.h"
+#include "gpu/ipc/gpu_task_scheduler_helper.h"
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace gpu {
+class ImageFactory;
+class SharedImageInterface;
+class SharedImageInterfaceInProcess;
+}
+
+namespace viz {
+class SkiaOutputSurfaceDependency;
+
+// This class holds onwership of task posting sequence to the gpu thread and
+// memory tracking for the display compositor. This class has a 1:1 relationship
+// to the display compositor class. This class is only used for gpu compositing.
+// TODO(weiliangc): After GLRenderer is removed, this should merge with
+// SkiaOutputSurfaceDependency.
+class VIZ_SERVICE_EXPORT DisplayCompositorMemoryAndTaskController {
+ public:
+ // For SkiaRenderer.
+ explicit DisplayCompositorMemoryAndTaskController(
+ std::unique_ptr<SkiaOutputSurfaceDependency> skia_dependency);
+ // For VizProcessContextProvider that uses InProcessCommandBuffer.
+ DisplayCompositorMemoryAndTaskController(
+ gpu::CommandBufferTaskExecutor* task_executor,
+ gpu::ImageFactory* image_factory);
+ DisplayCompositorMemoryAndTaskController(
+ const DisplayCompositorMemoryAndTaskController&) = delete;
+ DisplayCompositorMemoryAndTaskController& operator=(
+ const DisplayCompositorMemoryAndTaskController&) = delete;
+ ~DisplayCompositorMemoryAndTaskController();
+
+ SkiaOutputSurfaceDependency* skia_dependency() {
+ return skia_dependency_.get();
+ }
+ gpu::GpuTaskSchedulerHelper* gpu_task_scheduler() {
+ return gpu_task_scheduler_.get();
+ }
+
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* controller_on_gpu() {
+ return controller_on_gpu_.get();
+ }
+
+ gpu::SharedImageInterface* shared_image_interface();
+
+ private:
+ void InitializeOnGpuSkia(SkiaOutputSurfaceDependency* skia_dependency,
+ base::WaitableEvent* event);
+ void InitializeOnGpuGL(gpu::CommandBufferTaskExecutor* task_executor,
+ gpu::ImageFactory* image_factory,
+ base::WaitableEvent* event);
+ void DestroyOnGpu(base::WaitableEvent* event);
+
+ // Accessed on viz compositor thread.
+ std::unique_ptr<SkiaOutputSurfaceDependency> skia_dependency_;
+
+ std::unique_ptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_;
+
+ // Accessed on the gpu thread.
+ std::unique_ptr<gpu::DisplayCompositorMemoryAndTaskControllerOnGpu>
+ controller_on_gpu_;
+
+ // Accessed on the compositor thread.
+ // TODO(weiliangc): Move the GLRenderer's SharedImageInterface ownership here
+ // as well.
+ std::unique_ptr<gpu::SharedImageInterfaceInProcess> shared_image_interface_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_COMPOSITOR_MEMORY_AND_TASK_CONTROLLER_H_
diff --git a/chromium/components/viz/service/display/display_perftest.cc b/chromium/components/viz/service/display/display_perftest.cc
index 0d6d2bb2286..59e18d36617 100644
--- a/chromium/components/viz/service/display/display_perftest.cc
+++ b/chromium/components/viz/service/display/display_perftest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits>
#include <vector>
#include "base/bind.h"
@@ -71,10 +72,17 @@ class RemoveOverdrawQuadPerfTest : public testing::Test {
FakeOutputSurface::Create3d();
auto overlay_processor = std::make_unique<OverlayProcessorStub>();
+ // Normally display will need to take ownership of a
+ // gpu::GpuTaskschedulerhelper in order to keep it alive to share between
+ // the output surface and the overlay processor. In this case the overlay
+ // processor is a stub and the output surface is test only as well, so there
+ // is no need to pass in a real gpu::GpuTaskSchedulerHelper.
+ // TODO(weiliangc): Figure out a better way to set up test without passing
+ // in nullptr.
auto display = std::make_unique<Display>(
&bitmap_manager_, RendererSettings(), &debug_settings_, frame_sink_id,
- std::move(output_surface), std::move(overlay_processor),
- std::move(scheduler), task_runner_.get());
+ nullptr /* gpu::GpuTaskSchedulerHelper */, std::move(output_surface),
+ std::move(overlay_processor), std::move(scheduler), task_runner_.get());
return display;
}
@@ -90,7 +98,7 @@ class RemoveOverdrawQuadPerfTest : public testing::Test {
SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
state->SetAll(quad_transform, rect, rect,
- /*rounded_corner_bounds=*/gfx::RRectF(), rect, is_clipped,
+ /*mask_filter_info=*/gfx::MaskFilterInfo(), rect, is_clipped,
are_contents_opaque, opacity, blend_mode, sorting_context_id);
return state;
}
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
index 4078eafe71e..e0c81e19440 100644
--- a/chromium/components/viz/service/display/display_resource_provider.cc
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -586,11 +586,12 @@ GLenum DisplayResourceProvider::BindForSampling(ResourceId resource_id,
ScopedSetActiveTexture scoped_active_tex(gl, unit);
GLenum target = resource->transferable.mailbox_holder.texture_target;
gl->BindTexture(target, resource->gl_id);
- if (filter != resource->filter) {
- gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
- gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
- resource->filter = filter;
- }
+
+ // Texture parameters can be modified by concurrent reads so reset them
+ // before binding the texture. See https://crbug.com/1092080.
+ gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+ gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+ resource->filter = filter;
return target;
}
@@ -966,16 +967,13 @@ DisplayResourceProvider::ScopedReadLockSharedImage::ScopedReadLockSharedImage(
DisplayResourceProvider::ScopedReadLockSharedImage::
~ScopedReadLockSharedImage() {
- if (!resource_provider_)
- return;
- DCHECK(resource_->lock_for_overlay_count);
- resource_->lock_for_overlay_count--;
- resource_provider_->TryReleaseResource(resource_id_, resource_);
+ Reset();
}
DisplayResourceProvider::ScopedReadLockSharedImage&
DisplayResourceProvider::ScopedReadLockSharedImage::operator=(
ScopedReadLockSharedImage&& other) {
+ Reset();
resource_provider_ = other.resource_provider_;
resource_id_ = other.resource_id_;
resource_ = other.resource_;
@@ -985,6 +983,17 @@ DisplayResourceProvider::ScopedReadLockSharedImage::operator=(
return *this;
}
+void DisplayResourceProvider::ScopedReadLockSharedImage::Reset() {
+ if (!resource_provider_)
+ return;
+ DCHECK(resource_->lock_for_overlay_count);
+ resource_->lock_for_overlay_count--;
+ resource_provider_->TryReleaseResource(resource_id_, resource_);
+ resource_provider_ = nullptr;
+ resource_id_ = kInvalidResourceId;
+ resource_ = nullptr;
+}
+
DisplayResourceProvider::LockSetForExternalUse::LockSetForExternalUse(
DisplayResourceProvider* resource_provider,
ExternalUseClient* client)
@@ -1000,7 +1009,8 @@ DisplayResourceProvider::LockSetForExternalUse::~LockSetForExternalUse() {
ExternalUseClient::ImageContext*
DisplayResourceProvider::LockSetForExternalUse::LockResource(
ResourceId id,
- bool use_skia_color_conversion) {
+ bool is_video_plane,
+ const gfx::ColorSpace& color_space) {
auto it = resource_provider_->resources_.find(id);
DCHECK(it != resource_provider_->resources_.end());
@@ -1013,11 +1023,15 @@ DisplayResourceProvider::LockSetForExternalUse::LockResource(
if (!resource.image_context) {
sk_sp<SkColorSpace> image_color_space;
- // Video (YUV with PQ or half float RGBA with linear HDR) color conversion
- // is handled externally in SkiaRenderer using a special color filter, and
- // |use_skia_color_conversion| is false in that case.
- if (use_skia_color_conversion)
- image_color_space = resource.transferable.color_space.ToSkColorSpace();
+ if (!is_video_plane) {
+ // HDR video color conversion is handled externally in SkiaRenderer
+ // using a special color filter and |color_space| is set to destination
+ // color space so that Skia doesn't perform implicit color conversion.
+ image_color_space =
+ color_space.IsValid()
+ ? color_space.ToSkColorSpace()
+ : resource.transferable.color_space.ToSkColorSpace();
+ }
resource.image_context =
resource_provider_->external_use_client_->CreateImageContext(
resource.transferable.mailbox_holder, resource.transferable.size,
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
index a78c1233d10..c85028235a6 100644
--- a/chromium/components/viz/service/display/display_resource_provider.h
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -237,9 +237,11 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
}
private:
- DisplayResourceProvider* resource_provider_;
- ResourceId resource_id_;
- ChildResource* resource_;
+ void Reset();
+
+ DisplayResourceProvider* resource_provider_ = nullptr;
+ ResourceId resource_id_ = kInvalidResourceId;
+ ChildResource* resource_ = nullptr;
};
// Maintains set of resources locked for external use by SkiaRenderer.
@@ -257,11 +259,14 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
delete;
// Lock a resource for external use. The return value was created by
- // |client| at some point in the past. The resource color space will be set
- // on the SkImage if |use_skia_color_conversion| is true.
+ // |client| at some point in the past. The SkImage color space will be set
+ // to |color_space| if valid, otherwise it will be set to the resource's
+ // color space. If |is_video_plane| is true, the image color space will be
+ // set to nullptr (to avoid LOG spam).
ExternalUseClient::ImageContext* LockResource(
ResourceId resource_id,
- bool use_skia_color_conversion);
+ bool is_video_plane = false,
+ const gfx::ColorSpace& color_space = gfx::ColorSpace());
// Unlock all locked resources with a |sync_token|. The |sync_token| should
// be waited on before reusing the resource's backing to ensure that any
diff --git a/chromium/components/viz/service/display/display_resource_provider_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_unittest.cc
index ff4c1f25a6b..c2358c40fec 100644
--- a/chromium/components/viz/service/display/display_resource_provider_unittest.cc
+++ b/chromium/components/viz/service/display/display_resource_provider_unittest.cc
@@ -15,7 +15,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index 938616be59c..b7b5fe60078 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/null_task_runner.h"
#include "cc/base/math_util.h"
@@ -30,7 +30,7 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/aggregated_frame.h"
-#include "components/viz/service/display/delegated_ink_point_renderer_base.h"
+#include "components/viz/service/display/delegated_ink_point_renderer_skia.h"
#include "components/viz/service/display/direct_renderer.h"
#include "components/viz/service/display/display_client.h"
#include "components/viz/service/display/display_scheduler.h"
@@ -201,8 +201,15 @@ class DisplayTest : public testing::Test {
std::unique_ptr<DisplayScheduler> scheduler,
std::unique_ptr<OutputSurface> output_surface) {
auto overlay_processor = std::make_unique<OverlayProcessorStub>();
+ // Normally display will need to take ownership of a
+ // DisplayCompositorMemoryAndTaskController in order to keep it alive to
+ // share between the output surface and the overlay processor. In this case
+ // the overlay processor is a stub and the output surface is test only as
+ // well, so there is no need to pass in a real
+ // DisplayCompositorMemoryAndTaskController.
auto display = std::make_unique<Display>(
&shared_bitmap_manager_, settings, &debug_settings_, frame_sink_id,
+ nullptr /* DisplayCompositorMemoryAndTaskController */,
std::move(output_surface), std::move(overlay_processor),
std::move(scheduler), task_runner_);
display->SetVisible(true);
@@ -766,7 +773,7 @@ TEST_F(DisplayTest, BackdropFilterTest) {
shared_quad_state1->SetAll(
gfx::Transform(), /*quad_layer_rect=*/sub_surface_rect,
/*visible_quad_layer_rect=*/sub_surface_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/sub_surface_rect, /*is_clipped=*/false,
/*are_contents_opaque=*/true, /*opacity=*/1.0f, SkBlendMode::kSrcOver,
/*sorting_context_id=*/0);
@@ -782,7 +789,7 @@ TEST_F(DisplayTest, BackdropFilterTest) {
gfx::Rect rect1(display_size);
shared_quad_state2->SetAll(gfx::Transform(), /*quad_layer_rect=*/rect1,
/*visible_quad_layer_rect=*/rect1,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/rect1, /*is_clipped=*/false,
/*are_contents_opaque=*/true, /*opacity=*/1.0f,
SkBlendMode::kSrcOver,
@@ -922,13 +929,13 @@ TEST_F(DisplayTest, DrawOcclusionWithBlending) {
auto* src_sqs = render_pass->CreateAndAppendSharedQuadState();
src_sqs->SetAll(
- gfx::Transform(), src_rect, src_rect, gfx::RRectF(), src_rect,
+ gfx::Transform(), src_rect, src_rect, gfx::MaskFilterInfo(), src_rect,
is_clipped, are_contents_opaque, opacity,
is_root_render_pass ? SkBlendMode::kSrcOver : SkBlendMode::kSrcIn, 0);
auto* dest_sqs = render_pass->CreateAndAppendSharedQuadState();
dest_sqs->SetAll(
- gfx::Transform(), dest_rect, dest_rect, gfx::RRectF(), dest_rect,
- is_clipped, are_contents_opaque, opacity,
+ gfx::Transform(), dest_rect, dest_rect, gfx::MaskFilterInfo(),
+ dest_rect, is_clipped, are_contents_opaque, opacity,
is_root_render_pass ? SkBlendMode::kSrcOver : SkBlendMode::kDstIn, 0);
auto* src_quad =
render_pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -988,7 +995,7 @@ TEST_F(DisplayTest, DrawOcclusionWithIntersectingBackdropFilter) {
for (int i = 0; i < 3; i++) {
shared_quad_states[i] = root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_states[i]->SetAll(
- gfx::Transform(), rects[i], rects[i], gfx::RRectF(), rects[i],
+ gfx::Transform(), rects[i], rects[i], gfx::MaskFilterInfo(), rects[i],
is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
if (i == 0) { // Backdrop filter quad
@@ -1053,9 +1060,9 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// | |
// +----+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -1078,13 +1085,13 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// +----+ |
// +----+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -1113,13 +1120,13 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// | | | |
// +--+ +--+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -1147,13 +1154,13 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// +----+ +----+
// +--+ +--+
{
- shared_quad_state->SetAll(gfx::Transform(), rect7, rect7, gfx::RRectF(),
- rect7, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect7, rect7, gfx::MaskFilterInfo(), rect7,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect6, rect6, gfx::RRectF(),
- rect6, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect6, rect6, gfx::MaskFilterInfo(), rect6,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect7, rect7, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect6, rect6, SK_ColorBLACK, false);
@@ -1180,13 +1187,13 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// | | +--+
// +----+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
- rect4, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect4, rect4, SK_ColorBLACK, false);
@@ -1212,13 +1219,13 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// +-----+|
// +------+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
- rect5, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect5, rect5, SK_ColorBLACK, false);
@@ -1270,9 +1277,9 @@ TEST_F(DisplayTest, DrawOcclusionWithSingleOverlapBehindDisjointedDrawQuads) {
frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
auto* quad = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
}
@@ -1326,9 +1333,9 @@ TEST_F(DisplayTest, DrawOcclusionWithMultipleOverlapBehindDisjointedDrawQuads) {
frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
auto* quad = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
}
@@ -1385,12 +1392,12 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
// | |
// +-----+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect1, rect1, SK_ColorBLACK, false);
@@ -1410,12 +1417,12 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -1436,12 +1443,12 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -1462,13 +1469,13 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
- rect4, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect4, rect4, SK_ColorBLACK, false);
@@ -1527,11 +1534,11 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(half_scale, rect2, rect2, gfx::RRectF(), rect2,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(half_scale, rect2, rect2, gfx::MaskFilterInfo(),
+ rect2, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1550,11 +1557,11 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(half_scale, rect3, rect3, gfx::RRectF(), rect3,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(half_scale, rect3, rect3, gfx::MaskFilterInfo(),
+ rect3, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1573,12 +1580,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(half_scale, rect4, rect4, gfx::RRectF(), rect4,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state2->SetAll(half_scale, rect4, rect4, gfx::MaskFilterInfo(),
+ rect4, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1596,8 +1603,8 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
}
{
- shared_quad_state->SetAll(double_scale, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(double_scale, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
@@ -1614,13 +1621,13 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(double_scale, rect5, rect5, gfx::RRectF(), rect5,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ double_scale, rect5, rect5, gfx::MaskFilterInfo(), rect5, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect5, rect5, SK_ColorBLACK, false);
@@ -1642,13 +1649,13 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(double_scale, rect6, rect6, gfx::RRectF(), rect6,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ double_scale, rect6, rect6, gfx::MaskFilterInfo(), rect6, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect6, rect6, SK_ColorBLACK, false);
@@ -1671,13 +1678,13 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(double_scale, rect7, rect7, gfx::RRectF(), rect7,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ double_scale, rect7, rect7, gfx::MaskFilterInfo(), rect7, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect7, rect7, SK_ColorBLACK, false);
@@ -1699,13 +1706,13 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(double_scale, rect8, rect8, gfx::RRectF(), rect8,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ double_scale, rect8, rect8, gfx::MaskFilterInfo(), rect8, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect8, rect8, SK_ColorBLACK, false);
@@ -1727,13 +1734,13 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
}
{
- shared_quad_state->SetAll(double_scale, rect10, rect10, gfx::RRectF(),
- rect10, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ double_scale, rect10, rect10, gfx::MaskFilterInfo(), rect10, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(double_scale, rect9, rect9, gfx::RRectF(), rect9,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ double_scale, rect9, rect9, gfx::MaskFilterInfo(), rect9, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect10, rect10, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect9, rect9, SK_ColorBLACK, false);
@@ -1787,11 +1794,11 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
gfx::Transform inverted;
{
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(zero_scale, rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(zero_scale, rect, rect, gfx::MaskFilterInfo(),
+ rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
@@ -1811,11 +1818,11 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(epsilon_scale, rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(epsilon_scale, rect, rect, gfx::MaskFilterInfo(),
+ rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 1);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
@@ -1841,12 +1848,12 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(larger_epsilon_scale, rect, rect, gfx::RRectF(),
- rect, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ larger_epsilon_scale, rect, rect, gfx::MaskFilterInfo(), rect,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1890,12 +1897,12 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
{
negative_scale.Scale3d(-1, 1, 1);
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1922,12 +1929,12 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
{
negative_scale.MakeIdentity();
negative_scale.Scale3d(1, -1, 1);
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -1954,12 +1961,12 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
{
negative_scale.MakeIdentity();
negative_scale.Scale3d(1, 1, -1);
- shared_quad_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(negative_scale, rect, rect, gfx::RRectF(), rect,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ negative_scale, rect, rect, gfx::MaskFilterInfo(), rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect, rect, SK_ColorBLACK, false);
@@ -2016,12 +2023,12 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
// Apply rotation transform on |rect1| only.
- shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2040,11 +2047,11 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
{
// Apply rotation transform on |rect1| and |rect2|.
- shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(rotate, rect2, rect2, gfx::RRectF(), rect2,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state2->SetAll(rotate, rect2, rect2, gfx::MaskFilterInfo(),
+ rect2, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -2062,12 +2069,12 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
{
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2088,11 +2095,11 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
// Since we only support updating |visible_rect| of DrawQuad with scale
// or translation transform and rotation transform applies to quads,
// |visible_rect| of |quad2| should not be changed.
- shared_quad_state->SetAll(rotate, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(rotate, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(rotate, rect3, rect3, gfx::RRectF(), rect3,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state2->SetAll(rotate, rect3, rect3, gfx::MaskFilterInfo(),
+ rect3, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
@@ -2141,12 +2148,12 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) {
auto* quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state->SetAll(perspective, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(perspective, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect1, rect1, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2165,11 +2172,11 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(perspective, rect2, rect2, gfx::RRectF(), rect2,
- is_clipped, are_contents_opaque, opacity,
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(perspective, rect2, rect2, gfx::MaskFilterInfo(),
+ rect2, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
@@ -2211,12 +2218,13 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
auto* quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque,
- opacityLess1, SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, are_contents_opaque, opacity1,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(gfx::Transform(), rect1, rect1,
+ gfx::MaskFilterInfo(), rect1, is_clipped,
+ are_contents_opaque, opacityLess1,
+ SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2233,12 +2241,12 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity1,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, are_contents_opaque, opacity1,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, are_contents_opaque, opacity1, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2275,12 +2283,12 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
auto* quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, transparent_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, transparent_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2297,12 +2305,12 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
}
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2346,12 +2354,12 @@ TEST_F(DisplayTest, CompositorFrameZTranslate) {
// | |
// +-----+
{
- shared_quad_state->SetAll(translate_back, rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 1);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 1);
+ shared_quad_state->SetAll(
+ translate_back, rect1, rect1, gfx::MaskFilterInfo(), rect1, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 1);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 1);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect1, SK_ColorBLACK, false);
@@ -2404,12 +2412,12 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// +----+
// +-+
// +-+
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, transparent_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, transparent_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2433,12 +2441,12 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// +----+ => | +-+ |
// +-+ | +-+ |
// +-+ +-----+
- shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, opaque_content, opacity,
+ shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, opaque_content, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2463,12 +2471,12 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// +---+ +----+
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, opaque_content, opacity,
+ shared_quad_state->SetAll(translate_up, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, opaque_content, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2527,15 +2535,15 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
// | |----+ => | |----+
// +----+ +----+
//
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -2562,9 +2570,9 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
//
quad3 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state3->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
- rect4, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad3->SetNew(shared_quad_state3, rect4, rect4, SK_ColorBLACK, false);
EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
display_->RemoveOverdrawQuads(&frame);
@@ -2591,9 +2599,9 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
// | |----+ => | | |--|-+
// +----+ +-|--+ |
// +-----+
- shared_quad_state3->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
- rect5, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad3->SetNew(shared_quad_state3, rect5, rect5, SK_ColorBLACK, false);
EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
display_->RemoveOverdrawQuads(&frame);
@@ -2641,7 +2649,7 @@ TEST_F(DisplayTest, DrawOcclusionWithMultipleRenderPass) {
quads[i] =
render_pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
shared_quad_states[i]->SetAll(
- gfx::Transform(), rects[i], rects[i], gfx::RRectF(), rects[i],
+ gfx::Transform(), rects[i], rects[i], gfx::MaskFilterInfo(), rects[i],
false /*is_clipped*/, true /*are_contents_opaque*/, 1.f /*opacity*/,
SkBlendMode::kSrcOver, 0 /*sorting_context_id*/);
quads[i]->SetNew(shared_quad_states[i], rects[i], rects[i], SK_ColorBLACK,
@@ -2704,15 +2712,15 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) {
// | |----+ => | |----+
// +----+ +----+
//
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -2777,12 +2785,12 @@ TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) {
// +----+
//
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad1->SetNew(shared_quad_state2, rect1, rect1, render_pass_id,
mask_resource_id, gfx::RectF(), gfx::Size(),
@@ -2838,12 +2846,12 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
// | | ||
// +------+
//
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, non_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, non_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2865,12 +2873,12 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
//
quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- clip_rect, clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, non_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), clip_rect,
+ clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2894,12 +2902,12 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
// | +-+| => +--+++
// +------+
//
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- clip_rect, clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, non_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), clip_rect,
+ clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ non_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect3, rect3, SK_ColorBLACK, false);
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -2943,12 +2951,12 @@ TEST_F(DisplayTest, CompositorFrameWithCopyRequest) {
auto* quad2 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
frame.render_pass_list.front()->copy_requests.push_back(
@@ -3013,18 +3021,18 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// | | | |
// | R1 | | R2 |
// +-------+---+--------+
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state4->SetAll(gfx::Transform(), rect4, rect4, gfx::RRectF(),
- rect4, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state4->SetAll(
+ gfx::Transform(), rect4, rect4, gfx::MaskFilterInfo(), rect4,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
R1->SetNew(shared_quad_state, rect1, rect1, render_pass_id,
mask_resource_id, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3061,18 +3069,18 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// | | |
// | R2 | R1 |
// +-------+-----------+
- shared_quad_state->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
- rect5, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state4->SetAll(gfx::Transform(), rect6, rect6, gfx::RRectF(),
- rect6, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state4->SetAll(
+ gfx::Transform(), rect6, rect6, gfx::MaskFilterInfo(), rect6,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
R1->SetNew(shared_quad_state, rect5, rect5, render_pass_id,
mask_resource_id, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3108,18 +3116,18 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// |-----+ | |
// | R2 | R1 |
// +-----------+-------+
- shared_quad_state->SetAll(gfx::Transform(), rect5, rect5, gfx::RRectF(),
- rect5, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state4->SetAll(gfx::Transform(), rect7, rect7, gfx::RRectF(),
- rect7, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect5, rect5, gfx::MaskFilterInfo(), rect5,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state4->SetAll(
+ gfx::Transform(), rect7, rect7, gfx::MaskFilterInfo(), rect7,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
R1->SetNew(shared_quad_state, rect5, rect5, render_pass_id,
mask_resource_id, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(), false, 1.0f);
@@ -3197,11 +3205,11 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
// +--+--+
// | | |
// +--+--+
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
shared_quad_state2->SetAll(gfx::Transform(), rect_in_rect1, rect_in_rect1,
- gfx::RRectF(), rect_in_rect1, is_clipped,
+ gfx::MaskFilterInfo(), rect_in_rect1, is_clipped,
opaque_content, opacity, SkBlendMode::kSrcOver,
0);
quad1->SetNew(shared_quad_state, rect1_1, rect1_1, SK_ColorBLACK, false);
@@ -3241,8 +3249,8 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
shared_quad_state2->SetAll(
gfx::Transform(), rect_intersects_rect1, rect_intersects_rect1,
- gfx::RRectF(), rect_intersects_rect1, is_clipped, opaque_content,
- opacity, SkBlendMode::kSrcOver, 0);
+ gfx::MaskFilterInfo(), rect_intersects_rect1, is_clipped,
+ opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad5->SetNew(shared_quad_state2, rect_intersects_rect1,
rect_intersects_rect1, SK_ColorBLACK, false);
EXPECT_EQ(5u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -3280,12 +3288,12 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
auto* quad6 = frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
- shared_quad_state->SetAll(gfx::Transform(), rect2, rect2, gfx::RRectF(),
- rect2, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(gfx::Transform(), rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect2, rect2, gfx::MaskFilterInfo(), rect2,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state2->SetAll(
+ gfx::Transform(), rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad1->SetNew(shared_quad_state, rect2_1, rect2_1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state, rect2_2, rect2_2, SK_ColorBLACK, false);
quad3->SetNew(shared_quad_state, rect2_3, rect2_3, SK_ColorBLACK, false);
@@ -3370,15 +3378,15 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
// |quad1| forms an occlusion rect; |quad2| follows a invertible transform
// and is hiding behind quad1; |quad3| follows a non-invertible transform
// and it is not covered by the occlusion rect.
- shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, opaque_content, opacity,
- SkBlendMode::kSrcOver, 0);
- shared_quad_state2->SetAll(invertible, rect2, rect2, gfx::RRectF(), rect2,
- is_clipped, opaque_content, opacity,
+ shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, opaque_content, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(non_invertible, rect3, rect3, gfx::RRectF(),
- rect3, is_clipped, opaque_content, opacity,
+ shared_quad_state2->SetAll(invertible, rect2, rect2, gfx::MaskFilterInfo(),
+ rect2, is_clipped, opaque_content, opacity,
SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ non_invertible, rect3, rect3, gfx::MaskFilterInfo(), rect3, is_clipped,
+ opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad1->SetNew(shared_quad_state1, rect1, rect1, SK_ColorBLACK, false);
quad2->SetNew(shared_quad_state2, rect2, rect2, SK_ColorBLACK, false);
quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -3403,13 +3411,13 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
// | | | |
// +--------+ +--------+
// Verify if draw occlusion can occlude quad with non-invertible
- // transfrom.
- shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::RRectF(), rect1,
- is_clipped, opaque_content, opacity,
+ // transform.
+ shared_quad_state1->SetAll(invertible, rect1, rect1, gfx::MaskFilterInfo(),
+ rect1, is_clipped, opaque_content, opacity,
SkBlendMode::kSrcOver, 0);
- shared_quad_state3->SetAll(non_invertible_miss_z, rect3, rect3,
- gfx::RRectF(), rect3, is_clipped, opaque_content,
- opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state3->SetAll(
+ non_invertible_miss_z, rect3, rect3, gfx::MaskFilterInfo(), rect3,
+ is_clipped, opaque_content, opacity, SkBlendMode::kSrcOver, 0);
quad1->SetNew(shared_quad_state1, rect1, rect1, SK_ColorBLACK, false);
quad3->SetNew(shared_quad_state3, rect3, rect3, SK_ColorBLACK, false);
@@ -3448,9 +3456,9 @@ TEST_F(DisplayTest, DrawOcclusionWithLargeDrawQuad) {
// | |
// +----+
{
- shared_quad_state->SetAll(gfx::Transform(), rect1, rect1, gfx::RRectF(),
- rect1, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), rect1, rect1, gfx::MaskFilterInfo(), rect1,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
@@ -3515,7 +3523,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
shared_quad_state1->SetAll(
gfx::Transform(), rect1 /* quad_layer_rect */,
rect1 /* visible_quad_layer_rect */,
- gfx::RRectF() /* rounded_corner_bounds*/, rect1 /*clip_rect */,
+ gfx::MaskFilterInfo() /* mask_filter_info */, rect1 /*clip_rect */,
false /* is_clipped */, false /* are_contents_opaque */,
0.5f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
auto* quad1 = pass->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -3528,7 +3536,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
shared_quad_state2->SetAll(
gfx::Transform(), rect2 /* quad_layer_rect */,
rect2 /* visible_quad_layer_rect */,
- gfx::RRectF() /* rounded_corner_bounds */, rect2 /*clip_rect */,
+ gfx::MaskFilterInfo() /* mask_filter_info */, rect2 /*clip_rect */,
false /* is_clipped */, true /* are_contents_opaque */,
1.0f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
auto* quad2 = pass->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
@@ -3933,7 +3941,8 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesNotOcclude) {
// The quad with rounded corner does not completely cover the quad below it.
// The corners of the below quad are visiblg through the clipped corners.
gfx::Rect quad_rect(10, 10, 100, 100);
- gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
+ gfx::MaskFilterInfo mask_filter_info(
+ gfx::RRectF(gfx::RectF(quad_rect), 10.f));
bool is_clipped = false;
bool are_contents_opaque = true;
@@ -3951,16 +3960,16 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesNotOcclude) {
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
{
- shared_quad_state_occluded->SetAll(
- gfx::Transform(), quad_rect, quad_rect, gfx::RRectF(), quad_rect,
- is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state_occluded->SetAll(gfx::Transform(), quad_rect, quad_rect,
+ gfx::MaskFilterInfo(), quad_rect,
+ is_clipped, are_contents_opaque, opacity,
+ SkBlendMode::kSrcOver, 0);
occluded_quad->SetNew(shared_quad_state_occluded, quad_rect, quad_rect,
SK_ColorRED, false);
- shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
- rounded_corner_bounds, quad_rect,
- is_clipped, are_contents_opaque,
- opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state_with_rrect->SetAll(
+ gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
quad_rect, SK_ColorBLUE, false);
@@ -3987,8 +3996,9 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesOcclude) {
// The quad with rounded corner completely covers the quad below it.
AggregatedFrame frame = MakeDefaultAggregatedFrame();
gfx::Rect quad_rect(10, 10, 1000, 1000);
- gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
gfx::Rect occluded_quad_rect(13, 13, 994, 994);
+ gfx::MaskFilterInfo mask_filter_info(
+ gfx::RRectF(gfx::RectF(quad_rect), 10.f));
bool is_clipped = false;
bool are_contents_opaque = true;
@@ -4007,16 +4017,15 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesOcclude) {
{
shared_quad_state_occluded->SetAll(
- gfx::Transform(), occluded_quad_rect, occluded_quad_rect, gfx::RRectF(),
- occluded_quad_rect, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ gfx::Transform(), occluded_quad_rect, occluded_quad_rect,
+ gfx::MaskFilterInfo(), occluded_quad_rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
occluded_quad->SetNew(shared_quad_state_occluded, occluded_quad_rect,
occluded_quad_rect, SK_ColorRED, false);
- shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
- rounded_corner_bounds, quad_rect,
- is_clipped, are_contents_opaque,
- opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state_with_rrect->SetAll(
+ gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
quad_rect, SK_ColorBLUE, false);
@@ -4076,16 +4085,16 @@ TEST_F(DisplayTest, DrawOcclusionSplit) {
{
shared_quad_state_occluder->SetAll(
- gfx::Transform(), occluding_rect, occluding_rect, gfx::RRectF(),
+ gfx::Transform(), occluding_rect, occluding_rect, gfx::MaskFilterInfo(),
occluding_rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
quads[0]->SetNew(shared_quad_state_occluder, occluding_rect, occluding_rect,
SK_ColorRED, false);
shared_quad_state_occluded->SetAll(
- gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect, gfx::RRectF(),
- occluded_sqs_rect, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect,
+ gfx::MaskFilterInfo(), occluded_sqs_rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
for (int i = 1; i < 4; i++) {
quads[i]->SetNew(shared_quad_state_occluded, quad_rects[i - 1],
quad_rects[i - 1], SK_ColorRED, false);
@@ -4179,9 +4188,9 @@ TEST_F(DisplayTest, FirstPassVisibleComplexityReduction) {
for (const auto& r : occluding_rects) {
SharedQuadState* shared_quad_state_occluder =
frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
- shared_quad_state_occluder->SetAll(gfx::Transform(), r, r, gfx::RRectF(), r,
- is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state_occluder->SetAll(
+ gfx::Transform(), r, r, gfx::MaskFilterInfo(), r, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* quad =
frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
@@ -4193,7 +4202,7 @@ TEST_F(DisplayTest, FirstPassVisibleComplexityReduction) {
SharedQuadState* shared_quad_state_occluded =
frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
shared_quad_state_occluded->SetAll(
- gfx::Transform(), occluded_rect, occluded_rect, gfx::RRectF(),
+ gfx::Transform(), occluded_rect, occluded_rect, gfx::MaskFilterInfo(),
occluded_rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* occluded_quad =
@@ -4261,7 +4270,7 @@ TEST_F(DisplayTest, DrawOcclusionSplitDeviceScaleFactorFractional) {
frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
shared_quad_state_occluding->SetAll(
- gfx::Transform(), occluding_rect, occluding_rect, gfx::RRectF(),
+ gfx::Transform(), occluding_rect, occluding_rect, gfx::MaskFilterInfo(),
occluding_rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
occluding_quad->SetNew(shared_quad_state_occluding, occluding_rect,
@@ -4274,7 +4283,7 @@ TEST_F(DisplayTest, DrawOcclusionSplitDeviceScaleFactorFractional) {
frame.render_pass_list.front()
->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
shared_quad_state_occluded->SetAll(
- gfx::Transform(), occluded_rect, occluded_rect, gfx::RRectF(),
+ gfx::Transform(), occluded_rect, occluded_rect, gfx::MaskFilterInfo(),
occluded_rect, is_clipped, are_contents_opaque, opacity,
SkBlendMode::kSrcOver, 0);
occluded_quad->SetNew(shared_quad_state_occluded, occluded_rect,
@@ -4310,7 +4319,8 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerPartialOcclude) {
//
// * -> Visible rect for the quads.
gfx::Rect quad_rect(10, 10, 1000, 1000);
- gfx::RRectF rounded_corner_bounds(gfx::RectF(quad_rect), 10.f);
+ gfx::MaskFilterInfo mask_filter_info(
+ gfx::RRectF(gfx::RectF(quad_rect), 10.f));
gfx::Rect occluded_quad_rect_1(0, 20, 600, 490);
gfx::Rect occluded_quad_rect_2(600, 20, 600, 490);
gfx::Rect occluded_quad_rect_3(0, 510, 600, 490);
@@ -4347,9 +4357,9 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerPartialOcclude) {
{
shared_quad_state_occluded->SetAll(
- gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect, gfx::RRectF(),
- occluded_sqs_rect, is_clipped, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, 0);
+ gfx::Transform(), occluded_sqs_rect, occluded_sqs_rect,
+ gfx::MaskFilterInfo(), occluded_sqs_rect, is_clipped,
+ are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
occluded_quad_1->SetNew(shared_quad_state_occluded, occluded_quad_rect_1,
occluded_quad_rect_1, SK_ColorRED, false);
occluded_quad_2->SetNew(shared_quad_state_occluded, occluded_quad_rect_2,
@@ -4359,10 +4369,9 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerPartialOcclude) {
occluded_quad_4->SetNew(shared_quad_state_occluded, occluded_quad_rect_4,
occluded_quad_rect_4, SK_ColorRED, false);
- shared_quad_state_with_rrect->SetAll(gfx::Transform(), quad_rect, quad_rect,
- rounded_corner_bounds, quad_rect,
- is_clipped, are_contents_opaque,
- opacity, SkBlendMode::kSrcOver, 0);
+ shared_quad_state_with_rrect->SetAll(
+ gfx::Transform(), quad_rect, quad_rect, mask_filter_info, quad_rect,
+ is_clipped, are_contents_opaque, opacity, SkBlendMode::kSrcOver, 0);
rounded_corner_quad->SetNew(shared_quad_state_with_rrect, quad_rect,
quad_rect, SK_ColorBLUE, false);
@@ -4508,87 +4517,268 @@ TEST_F(DisplayTest, DisplaySizeMismatch) {
}
}
-// Testing the delegated ink renderer when the skia renderer is in use.
-TEST_F(DisplayTest, SkiaDelegatedInkRenderer) {
- // First set up the display to use the Skia renderer.
- RendererSettings settings;
- settings.use_skia_renderer = true;
- SetUpGpuDisplaySkia(settings);
+class SkiaDelegatedInkRendererTest : public DisplayTest {
+ public:
+ void SetUpRenderers() {
+ // First set up the display to use the Skia renderer.
+ RendererSettings settings;
+ settings.use_skia_renderer = true;
+ SetUpGpuDisplaySkia(settings);
+
+ // Initialize the renderer and create an ink renderer.
+ StubDisplayClient client;
+ display_->Initialize(&client, manager_.surface_manager());
+ display_->renderer_for_testing()->CreateDelegatedInkPointRenderer();
+ }
- // Initialize the renderer and create an ink renderer.
- StubDisplayClient client;
- display_->Initialize(&client, manager_.surface_manager());
- display_->renderer_for_testing()->CreateDelegatedInkPointRenderer();
+ DelegatedInkPointRendererBase* ink_renderer() {
+ return display_->renderer_for_testing()->GetDelegatedInkPointRenderer();
+ }
+
+ const std::map<base::TimeTicks, gfx::PointF>& stored_points() {
+ return ink_renderer()->GetPointsMapForTest();
+ }
+
+ void CreateAndStoreDelegatedInkPoint(const gfx::PointF& point,
+ base::TimeTicks timestamp) {
+ ink_points_.emplace_back(point, timestamp);
+ ink_renderer()->StoreDelegatedInkPoint(ink_points_.back());
+ }
+
+ void StoreAlreadyCreatedDelegatedInkPoints() {
+ for (DelegatedInkPoint ink_point : ink_points_)
+ ink_renderer()->StoreDelegatedInkPoint(ink_point);
+ }
+
+ void SendMetadata(DelegatedInkMetadata metadata) {
+ ink_renderer()->SetDelegatedInkMetadata(
+ std::make_unique<DelegatedInkMetadata>(metadata));
+ }
+
+ DelegatedInkMetadata MakeAndSendMetadataFromStoredInkPoint(
+ int index,
+ float diameter,
+ SkColor color,
+ const gfx::RectF& presentation_area) {
+ EXPECT_GE(index, 0);
+ EXPECT_LT(index, ink_points_size());
+
+ DelegatedInkMetadata metadata(ink_points_[index].point(), diameter, color,
+ ink_points_[index].timestamp(),
+ presentation_area, base::TimeTicks::Now());
+ SendMetadata(metadata);
+ return metadata;
+ }
+
+ void HistogramCheck(const base::HistogramTester& histograms,
+ base::TimeDelta expected_bucket,
+ const char* histogram_name) {
+ if (expected_bucket == base::TimeDelta::Min()) {
+ histograms.ExpectTotalCount(histogram_name, 0);
+ } else {
+ histograms.ExpectTotalCount(histogram_name, 1);
+ histograms.ExpectTimeBucketCount(histogram_name, expected_bucket, 1);
+ }
+ }
+
+ // Either bucket containing base::TimeDelta::Min() is interpreted to mean that
+ // expected total count of the histogram should be 0.
+ void FinalizePathAndCheckHistograms(
+ base::TimeDelta expected_bucket_without_prediction,
+ base::TimeDelta expected_bucket_with_prediction) {
+ base::HistogramTester histograms;
+ ink_renderer()->FinalizePathForDraw();
+ HistogramCheck(
+ histograms, expected_bucket_without_prediction,
+ "Renderer.DelegatedInkTrail.LatencyImprovement.Skia.WithoutPrediction");
+ HistogramCheck(
+ histograms, expected_bucket_with_prediction,
+ "Renderer.DelegatedInkTrail.LatencyImprovement.Skia.WithPrediction");
+
+ // Either both histograms should be populated, or neither. But never just
+ // one of them.
+ if (expected_bucket_without_prediction == base::TimeDelta::Min() ||
+ expected_bucket_with_prediction == base::TimeDelta::Min()) {
+ EXPECT_EQ(expected_bucket_without_prediction,
+ expected_bucket_with_prediction);
+ }
+ }
+
+ void DrawDelegatedInkTrail() {
+ SkCanvas canvas;
+ static_cast<DelegatedInkPointRendererSkia*>(ink_renderer())
+ ->DrawDelegatedInkTrail(&canvas);
+ }
+
+ int GetPathPointCount() { return ink_renderer()->GetPathPointCountForTest(); }
+
+ // Explicitly get the metadata that is stored on the renderer.
+ const DelegatedInkMetadata* GetMetadataFromRenderer() {
+ return ink_renderer()->GetMetadataForTest();
+ }
+
+ const DelegatedInkPoint& ink_point(int index) {
+ EXPECT_GE(index, 0);
+ EXPECT_LT(index, ink_points_size());
+ return ink_points_[index];
+ }
+
+ int ink_points_size() { return ink_points_.size(); }
- std::unique_ptr<DelegatedInkPointRendererBase>& ink_renderer =
- display_->renderer_for_testing()->delegated_ink_point_renderer_;
+ private:
+ std::vector<DelegatedInkPoint> ink_points_;
+};
- const std::map<base::TimeTicks, gfx::PointF>& stored_points =
- ink_renderer->GetPointsMapForTest();
+// Testing filtering points in the the delegated ink renderer when the skia
+// renderer is in use.
+TEST_F(SkiaDelegatedInkRendererTest, SkiaDelegatedInkRendererFilteringPoints) {
+ SetUpRenderers();
// First, a sanity check.
- EXPECT_EQ(0, static_cast<int>(stored_points.size()));
+ EXPECT_EQ(0, static_cast<int>(stored_points().size()));
// Insert 3 arbitrary points into the ink renderer to confirm that they go
// where we expect and are all stored correctly.
+ const int kInitialDelegatedPoints = 3;
base::TimeTicks timestamp = base::TimeTicks::Now();
- std::vector<DelegatedInkPoint> ink_points;
- ink_points.emplace_back(gfx::PointF(10, 10), timestamp);
- ink_points.emplace_back(gfx::PointF(20, 20),
- timestamp + base::TimeDelta::FromMicroseconds(5));
- ink_points.emplace_back(gfx::PointF(30, 30),
- timestamp + base::TimeDelta::FromMicroseconds(10));
- const int initial_delegated_points = 3;
-
- for (DelegatedInkPoint point : ink_points)
- ink_renderer->StoreDelegatedInkPoint(point);
+ gfx::PointF point(10, 10);
+ for (int i = 0; i < kInitialDelegatedPoints; ++i) {
+ CreateAndStoreDelegatedInkPoint(point, timestamp);
+ point.Offset(10, 10);
+ timestamp += base::TimeDelta::FromMilliseconds(5);
+ }
- EXPECT_EQ(initial_delegated_points, static_cast<int>(stored_points.size()));
+ EXPECT_EQ(kInitialDelegatedPoints, static_cast<int>(stored_points().size()));
// No metadata has been provided yet, so filtering shouldn't occur and all
- // points should still exist after a DrawDelegatedInkTrail() call.
- ink_renderer->DrawDelegatedInkTrail();
+ // points should still exist after a FinalizePath() call.
+ FinalizePathAndCheckHistograms(base::TimeDelta::Min(),
+ base::TimeDelta::Min());
- EXPECT_EQ(initial_delegated_points, static_cast<int>(stored_points.size()));
+ EXPECT_EQ(kInitialDelegatedPoints, static_cast<int>(stored_points().size()));
// Now provide metadata with a timestamp matching one of the points to
// confirm that earlier points are removed and later points remain.
- const int ink_point_for_metadata = 1;
- DelegatedInkMetadata metadata(
- ink_points[ink_point_for_metadata].point(), 1, SK_ColorBLACK,
- ink_points[ink_point_for_metadata].timestamp(), gfx::RectF());
- ink_renderer->SetDelegatedInkMetadata(
- std::make_unique<DelegatedInkMetadata>(metadata));
- ink_renderer->DrawDelegatedInkTrail();
-
- EXPECT_EQ(initial_delegated_points - ink_point_for_metadata,
- static_cast<int>(stored_points.size()));
- EXPECT_EQ(metadata.point(), stored_points.begin()->second);
- EXPECT_EQ(ink_points[ink_points.size() - 1].point(),
- stored_points.rbegin()->second);
- EXPECT_FALSE(ink_renderer->GetMetadataForTest());
-
- // Finally, add more points than the maximum that will be stored to confirm
- // only the max is stored and the correct ones are removed first.
- const int points_beyond_max_allowed = 2;
- for (DelegatedInkPoint point : ink_points)
- ink_renderer->StoreDelegatedInkPoint(point);
- while (ink_points.size() <
- kMaximumDelegatedInkPointsStored + points_beyond_max_allowed) {
- gfx::PointF pt = ink_points[ink_points.size() - 1].point();
- pt.Offset(5, 5);
- base::TimeTicks ts = ink_points[ink_points.size() - 1].timestamp() +
- base::TimeDelta::FromMicroseconds(5);
- ink_points.emplace_back(pt, ts);
- ink_renderer->StoreDelegatedInkPoint(ink_points[ink_points.size() - 1]);
+ const int kInkPointForMetadata = 1;
+ const float kDiameter = 1.f;
+ DelegatedInkMetadata metadata = MakeAndSendMetadataFromStoredInkPoint(
+ kInkPointForMetadata, kDiameter, SK_ColorBLACK, gfx::RectF());
+
+ // The histogram should count one in the bucket that is the difference between
+ // the latest point stored and the metadata. No prediction should occur with
+ // 3 provided, points, so the *WithPrediction histogram should count 1 in the
+ // same bucket as the *WithoutPrediction histogram.
+ base::TimeDelta bucket_without_prediction =
+ ink_point(ink_points_size() - 1).timestamp() - metadata.timestamp();
+ FinalizePathAndCheckHistograms(bucket_without_prediction,
+ bucket_without_prediction);
+
+ EXPECT_EQ(kInitialDelegatedPoints - kInkPointForMetadata,
+ static_cast<int>(stored_points().size()));
+ EXPECT_EQ(metadata.point(), stored_points().begin()->second);
+ EXPECT_EQ(ink_point(ink_points_size() - 1).point(),
+ stored_points().rbegin()->second);
+
+ // Confirm that the metadata is cleared when DrawDelegatedInkTrail() is
+ // called.
+ DrawDelegatedInkTrail();
+ EXPECT_FALSE(GetMetadataFromRenderer());
+
+ // Add more points than the maximum that will be stored to confirm only the
+ // max is stored and the correct ones are removed first.
+ const int kPointsBeyondMaxAllowed = 2;
+ StoreAlreadyCreatedDelegatedInkPoints();
+ while (ink_points_size() <
+ kMaximumDelegatedInkPointsStored + kPointsBeyondMaxAllowed) {
+ CreateAndStoreDelegatedInkPoint(point, timestamp);
+ point.Offset(10, 10);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
}
EXPECT_EQ(kMaximumDelegatedInkPointsStored,
- static_cast<int>(stored_points.size()));
- EXPECT_EQ(ink_points[points_beyond_max_allowed].point(),
- stored_points.begin()->second);
- EXPECT_EQ(ink_points[ink_points.size() - 1].point(),
- stored_points.rbegin()->second);
+ static_cast<int>(stored_points().size()));
+ EXPECT_EQ(ink_point(kPointsBeyondMaxAllowed).point(),
+ stored_points().begin()->second);
+ EXPECT_EQ(ink_point(ink_points_size() - 1).point(),
+ stored_points().rbegin()->second);
+
+ // Now send metadata with a timestamp before all of the points that are
+ // currently stored to confirm that no points are filtered out and the number
+ // stored remains the same while both histograms records 0 improvement.
+ const uint64_t kExpectedPoints = stored_points().size();
+ SendMetadata(metadata);
+ FinalizePathAndCheckHistograms(base::TimeDelta::FromMilliseconds(0),
+ base::TimeDelta::FromMilliseconds(0));
+ EXPECT_EQ(kExpectedPoints, stored_points().size());
+}
+
+// Confirm that the delegated ink trail histograms record latency correctly.
+TEST_F(SkiaDelegatedInkRendererTest, LatencyHistograms) {
+ SetUpRenderers();
+
+ // Confirm that nothing is counted in the histograms when there is no metadata
+ // or points to draw.
+ FinalizePathAndCheckHistograms(base::TimeDelta::Min(),
+ base::TimeDelta::Min());
+
+ // Insert 4 arbitrary points into the ink renderer to later draw.
+ base::TimeTicks timestamp = base::TimeTicks::Now();
+ CreateAndStoreDelegatedInkPoint(gfx::PointF(20, 19), timestamp);
+ CreateAndStoreDelegatedInkPoint(
+ gfx::PointF(15, 19), timestamp + base::TimeDelta::FromMilliseconds(8));
+ CreateAndStoreDelegatedInkPoint(
+ gfx::PointF(16, 28), timestamp + base::TimeDelta::FromMilliseconds(16));
+ CreateAndStoreDelegatedInkPoint(
+ gfx::PointF(29, 35), timestamp + base::TimeDelta::FromMilliseconds(24));
+
+ // Provide a metadata so that points can be drawn, based on the first ink
+ // point that was sent.
+ const float kDiameter = 11.99f;
+ MakeAndSendMetadataFromStoredInkPoint(/*index*/ 0, kDiameter, SK_ColorBLACK,
+ gfx::RectF());
+
+ // *WithoutPrediction histogram should have one counted in the 24 ms bucket
+ // because that's the difference between the latest point and the metadata.
+ // *WithPrediction should be able to predict here, so it should contain 1 in
+ // the bucket that is |kNumberOfMillisecondsIntoFutureToPredictPerPoint| *
+ // |kNumberOfPointsToPredict| into the future from 24 ms bucket.
+ base::TimeDelta bucket_without_prediction =
+ base::TimeDelta::FromMilliseconds(24);
+ FinalizePathAndCheckHistograms(
+ bucket_without_prediction,
+ bucket_without_prediction +
+ base::TimeDelta::FromMilliseconds(
+ kNumberOfMillisecondsIntoFutureToPredictPerPoint *
+ kNumberOfPointsToPredict));
+
+ // Now provide metadata that matches the final ink point provided, so that
+ // everything earlier is filtered out. Then the *WithoutPrediction histogram
+ // will count 1 in the 0 ms bucket and the *WithPrediction histogram will
+ // still be able to predict points, so it should have counted one.
+ MakeAndSendMetadataFromStoredInkPoint(/*index*/ 3, kDiameter, SK_ColorBLACK,
+ gfx::RectF());
+ bucket_without_prediction = base::TimeDelta::FromMilliseconds(0);
+ FinalizePathAndCheckHistograms(
+ bucket_without_prediction,
+ base::TimeDelta::FromMilliseconds(
+ kNumberOfMillisecondsIntoFutureToPredictPerPoint *
+ kNumberOfPointsToPredict));
+
+ // DrawDelegatedInkTrail should clear the metadata, so finalizing the path
+ // shouldn't record anything in the histograms.
+ DrawDelegatedInkTrail();
+ FinalizePathAndCheckHistograms(base::TimeDelta::Min(),
+ base::TimeDelta::Min());
+
+ // Send a few more points but no metadata to confirm that nothing is counted.
+ timestamp = base::TimeTicks::Now();
+ CreateAndStoreDelegatedInkPoint(gfx::PointF(85, 56), timestamp);
+ CreateAndStoreDelegatedInkPoint(
+ gfx::PointF(96, 70), timestamp + base::TimeDelta::FromMilliseconds(2));
+ CreateAndStoreDelegatedInkPoint(
+ gfx::PointF(112, 94), timestamp + base::TimeDelta::FromMilliseconds(10));
+ FinalizePathAndCheckHistograms(base::TimeDelta::Min(),
+ base::TimeDelta::Min());
}
} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
index e5179c0e497..be7906b3e02 100644
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -15,7 +15,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
@@ -32,6 +32,7 @@
#include "cc/paint/render_surface_filters.h"
#include "cc/raster/scoped_gpu_raster.h"
#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/quads/compositor_frame.h"
@@ -77,6 +78,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/rrect_f.h"
#include "ui/gfx/skia_util.h"
@@ -218,6 +220,37 @@ class ScopedTimerQuery {
gpu::gles2::GLES2Interface* gl_;
};
+void AccumulateDrawRects(const gfx::Rect& quad_rect,
+ const gfx::Transform& target_transform,
+ std::vector<gfx::Rect>* drawn_rects) {
+ gfx::RectF quad_rect_f(quad_rect);
+
+ // If the transform is not axis aligned then assume the largest possible
+ // bounds the quad can take in the render target. In this case, we take the
+ // sum of 2 sides.
+ if (!target_transform.Preserves2dAxisAlignment()) {
+ // Increase the length of each side to |width + height|.
+ const int total_length = quad_rect.width() + quad_rect.height();
+ quad_rect_f.set_height(total_length);
+ quad_rect_f.set_width(total_length);
+
+ // Ensure that the increase is equally distributed on either sides of the
+ // quad such that the position of the center of the quad does not change.
+ const float delta_x = -(quad_rect.height() / 2.f);
+ const float delta_y = -(quad_rect.width() / 2.f);
+ quad_rect_f.Offset(gfx::Vector2d(delta_x, delta_y));
+
+ // Apply only the scale and translation component.
+ const gfx::Vector2dF& translate = target_transform.To2dTranslation();
+ const gfx::Vector2dF& scale = target_transform.Scale2d();
+ quad_rect_f.Scale(scale.x(), scale.y());
+ quad_rect_f.Offset(translate.x(), translate.y());
+ } else {
+ target_transform.TransformRect(&quad_rect_f);
+ }
+ drawn_rects->push_back(gfx::ToRoundedRect(quad_rect_f));
+}
+
// Smallest unit that impact anti-aliasing output. We use this to
// determine when anti-aliasing is unnecessary.
const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
@@ -420,6 +453,8 @@ GLRenderer::GLRenderer(
prefer_draw_to_copy_ = output_surface_->context_provider()
->GetGpuFeatureInfo()
.IsWorkaroundEnabled(gpu::PREFER_DRAW_TO_COPY);
+ use_fast_path_solid_color_quad_ =
+ features::IsUsingFastPathForSolidColorQuad();
InitializeSharedObjects();
}
@@ -509,6 +544,9 @@ void GLRenderer::PrepareSurfaceForPass(
gl_->GenQueriesEXT(1, &occlusion_query_);
gl_->BeginQueryEXT(GL_SAMPLES_PASSED_ARB, occlusion_query_);
}
+
+ // For each render pass, reset the drawn region.
+ drawn_rects_.clear();
}
void GLRenderer::ClearFramebuffer() {
@@ -1286,6 +1324,10 @@ void GLRenderer::DrawRenderPassQuadInternal(
ChooseRPDQProgram(params, CurrentRenderPassColorSpace());
UpdateRPDQUniforms(params);
DrawRPDQ(*params);
+
+ AccumulateDrawRects(params->quad->visible_rect,
+ params->quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
}
bool GLRenderer::InitializeRPDQParameters(
@@ -1756,9 +1798,9 @@ void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
SetShaderOpacity(params->quad->shared_quad_state->opacity);
if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- params->quad->shared_quad_state->rounded_corner_bounds,
- params->window_matrix * params->projection_matrix);
+ SetShaderRoundedCorner(params->quad->shared_quad_state->mask_filter_info
+ .rounded_corner_bounds(),
+ params->window_matrix * params->projection_matrix);
}
SetShaderQuadF(params->surface_quad);
}
@@ -2120,41 +2162,84 @@ void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
color = color_f.toSkColor();
}
- SetShaderColor(color, opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->rounded_corner_bounds,
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
+ // Try using glClear to draw the solid color quad if possible. This is much
+ // more performant than executing the shader pipeline.
+ if (CanUseFastSolidColorDraw(quad) && !use_aa) {
+ // Pre-multiply the alpha and opacity to get the correct blending in case of
+ // transparent buffers. glClear does not have any alpha blending stage.
+ Float4 result = PremultipliedColor(color, opacity);
+ SkRGBA4f<kPremul_SkAlphaType> color_f_premul;
+ std::copy(result.data, result.data + 4, color_f_premul.vec());
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
+ gfx::RectF quad_rect_in_target_f(quad->visible_rect);
- if (use_aa) {
- gl_->Uniform3fv(current_program_->edge_location(), 8, edge);
- }
+ device_transform.TransformRect(&quad_rect_in_target_f);
+ gfx::Rect quad_rect_in_target = gfx::ToRoundedRect(quad_rect_in_target_f);
- // Enable blending when the quad properties require it or if we decided
- // to use antialiasing.
- SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
- ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
+ // If we are using partial swap, make sure the new scissor rect is within
+ // the partial swap bounds.
+ if (!scissor_rect_.IsEmpty() && is_scissor_enabled_)
+ quad_rect_in_target.Intersect(scissor_rect_);
+
+ gl_->Enable(GL_SCISSOR_TEST);
+ gl_->Scissor(quad_rect_in_target.x(), quad_rect_in_target.y(),
+ quad_rect_in_target.width(), quad_rect_in_target.height());
- // Antialising requires a normalized quad, but this could lead to floating
- // point precision errors, so only normalize when antialising is on.
- if (use_aa) {
- DrawQuadGeometryWithAA(quad, &local_quad, tile_rect);
+ gl_->ClearColor(color_f_premul.fR, color_f_premul.fG, color_f_premul.fB,
+ color_f_premul.fA);
+ gl_->Clear(GL_COLOR_BUFFER_BIT);
+
+ // Restore GL scissor state.
+ if (is_scissor_enabled_)
+ gl_->Enable(GL_SCISSOR_TEST);
+ else
+ gl_->Disable(GL_SCISSOR_TEST);
+
+ gl_->Scissor(scissor_rect_.x(), scissor_rect_.y(), scissor_rect_.width(),
+ scissor_rect_.height());
} else {
- PrepareGeometry(SHARED_BINDING);
- SetShaderQuadF(local_quad);
- SetShaderMatrix(current_frame()->projection_matrix *
- quad->shared_quad_state->quad_to_target_transform);
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
- num_triangles_drawn_ += 2;
+ SetShaderColor(color, opacity);
+ if (current_program_->rounded_corner_rect_location() != -1) {
+ SetShaderRoundedCorner(
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
+ current_frame()->window_matrix * current_frame()->projection_matrix);
+ }
+
+ if (current_program_->tint_color_matrix_location() != -1) {
+ auto matrix =
+ cc::DebugColors::TintCompositedContentColorTransformMatrix();
+ gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
+ false, matrix.data());
+ }
+
+ if (use_aa) {
+ gl_->Uniform3fv(current_program_->edge_location(), 8, edge);
+ }
+
+ // Enable blending when the quad properties require it or if we decided
+ // to use antialiasing.
+ SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
+ ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
+
+ // Antialiasing requires a normalized quad, but this could lead to floating
+ // point precision errors, so only normalize when antialiasing is on.
+ if (use_aa) {
+ DrawQuadGeometryWithAA(quad, &local_quad, tile_rect);
+ } else {
+ PrepareGeometry(SHARED_BINDING);
+ SetShaderQuadF(local_quad);
+ SetShaderMatrix(current_frame()->projection_matrix *
+ quad->shared_quad_state->quad_to_target_transform);
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
+ num_triangles_drawn_ += 2;
+ }
+ RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
}
- RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
+
+ // Add the quad to the region that has been drawn.
+ AccumulateDrawRects(quad->visible_rect,
+ quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
}
void GLRenderer::DrawTileQuad(const TileDrawQuad* quad,
@@ -2193,6 +2278,10 @@ void GLRenderer::DrawContentQuad(const ContentDrawQuadBase* quad,
clip_region);
else
DrawContentQuadNoAA(quad, resource_id, clip_region);
+
+ AccumulateDrawRects(quad->visible_rect,
+ quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
}
void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
@@ -2299,7 +2388,7 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
SetShaderOpacity(quad->shared_quad_state->opacity);
if (current_program_->rounded_corner_rect_location() != -1) {
SetShaderRoundedCorner(
- quad->shared_quad_state->rounded_corner_bounds,
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
current_frame()->window_matrix * current_frame()->projection_matrix);
}
DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
@@ -2399,7 +2488,7 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
SetShaderOpacity(quad->shared_quad_state->opacity);
if (current_program_->rounded_corner_rect_location() != -1) {
SetShaderRoundedCorner(
- quad->shared_quad_state->rounded_corner_bounds,
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
current_frame()->window_matrix * current_frame()->projection_matrix);
}
@@ -2539,7 +2628,7 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
if (current_program_->rounded_corner_rect_location() != -1) {
SetShaderRoundedCorner(
- quad->shared_quad_state->rounded_corner_bounds,
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
current_frame()->window_matrix * current_frame()->projection_matrix);
}
@@ -2633,6 +2722,11 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
quad->shared_quad_state->quad_to_target_transform, tile_rect,
region_quad, uvs);
}
+
+ // Track the region in the current target surface that has been drawn to.
+ AccumulateDrawRects(quad->visible_rect,
+ quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
}
void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
@@ -2678,7 +2772,7 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
SetShaderOpacity(quad->shared_quad_state->opacity);
if (current_program_->rounded_corner_rect_location() != -1) {
SetShaderRoundedCorner(
- quad->shared_quad_state->rounded_corner_bounds,
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
current_frame()->window_matrix * current_frame()->projection_matrix);
}
gfx::Size texture_size = lock.size();
@@ -2708,6 +2802,10 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
quad->shared_quad_state->quad_to_target_transform, tile_rect,
region_quad, uvs);
}
+
+ AccumulateDrawRects(quad->visible_rect,
+ quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
}
void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
@@ -2734,7 +2832,7 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
if (current_program_->rounded_corner_rect_location() != -1) {
SetShaderRoundedCorner(
- draw_cache_.rounded_corner_bounds,
+ draw_cache_.mask_filter_info.rounded_corner_bounds(),
current_frame()->window_matrix * current_frame()->projection_matrix);
}
@@ -2847,8 +2945,8 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
draw_cache_.nearest_neighbor != quad->nearest_neighbor ||
draw_cache_.background_color != quad->background_color ||
- draw_cache_.rounded_corner_bounds !=
- quad->shared_quad_state->rounded_corner_bounds ||
+ draw_cache_.mask_filter_info !=
+ quad->shared_quad_state->mask_filter_info ||
draw_cache_.matrix_data.size() >= max_quads ||
draw_cache_.is_video_frame != quad->is_video_frame) {
FlushTextureQuadCache(SHARED_BINDING);
@@ -2858,8 +2956,7 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
draw_cache_.nearest_neighbor = quad->nearest_neighbor;
draw_cache_.background_color = quad->background_color;
- draw_cache_.rounded_corner_bounds =
- quad->shared_quad_state->rounded_corner_bounds;
+ draw_cache_.mask_filter_info = quad->shared_quad_state->mask_filter_info;
draw_cache_.is_video_frame = quad->is_video_frame;
}
@@ -2905,6 +3002,11 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
quad_rect_matrix.matrix().asColMajorf(m.data);
draw_cache_.matrix_data.push_back(m);
+ // Track the region in the current target surface that has been drawn to.
+ AccumulateDrawRects(quad->visible_rect,
+ quad->shared_quad_state->quad_to_target_transform,
+ &drawn_rects_);
+
if (clip_region) {
DCHECK_EQ(quad->rect, quad->visible_rect);
gfx::QuadF scaled_region;
@@ -3026,9 +3128,12 @@ void GLRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {
// Delete all timer queries for which results have been retrieved.
gl_->DeleteQueriesEXT(count, queries_to_delete.data());
+ base::TimeDelta unique_id_delta = ready_timestamp - start_time_ticks;
+ const int trace_unique_id = unique_id_delta.InMilliseconds() * count;
+
TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(
TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- this, start_time_ticks);
+ TRACE_ID_LOCAL(trace_unique_id), start_time_ticks);
while (!durations.empty()) {
duration = durations.front().first;
@@ -3041,14 +3146,15 @@ void GLRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {
}
TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- this, durations.front().second.c_str(), start_time_ticks);
+ TRACE_ID_LOCAL(trace_unique_id), durations.front().second.c_str(),
+ start_time_ticks);
start_time_ticks += base::TimeDelta::FromNanoseconds(duration);
durations.pop();
}
TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- this, ready_timestamp);
+ TRACE_ID_LOCAL(trace_unique_id), ready_timestamp);
}
void GLRenderer::FinishDrawingQuadList() {
@@ -3076,8 +3182,10 @@ void GLRenderer::GenerateMipmap() {
}
bool GLRenderer::FlippedFramebuffer() const {
+#if defined(OS_APPLE)
if (force_drawing_frame_framebuffer_unflipped_)
return false;
+#endif
if (current_frame()->current_render_pass != current_frame()->root_render_pass)
return true;
return FlippedRootFramebuffer();
@@ -4244,6 +4352,67 @@ bool GLRenderer::HasOutputColorMatrix() const {
return is_root_render_pass && !output_color_matrix.isIdentity();
}
+bool GLRenderer::CanUseFastSolidColorDraw(
+ const SolidColorDrawQuad* quad) const {
+ const SharedQuadState* sqs = quad->shared_quad_state;
+
+ if (!use_fast_path_solid_color_quad_)
+ return false;
+
+ // Mask filters require blending with the background, which is not possible
+ // with the glClear draw method.
+ if (!sqs->mask_filter_info.IsEmpty())
+ return false;
+
+ // 3D transforms need vertex computation in 3D and cannot be handled using
+ // glClear().
+ if (!sqs->quad_to_target_transform.IsFlat())
+ return false;
+
+ // glClear ignores stencil buffer.
+ if (stencil_shadow_)
+ return false;
+
+ // Any non axis aligned transform cannot be handled by glClear.
+ if (!sqs->quad_to_target_transform.Preserves2dAxisAlignment())
+ return false;
+
+ // If no blending is needed for the quad, then fast draw can be safely used.
+ if (!quad->ShouldDrawWithBlending() && SkColorGetA(quad->color) == 255)
+ return true;
+
+ // It is safe to use glClearColor with alpha blending when the render
+ // pass has transparent background because the blending happens against
+ // (0, 0, 0, 0) which is the same as replacing the destination color & alpha.
+ // However, if the render pass does not have a transparent background, using
+ // glClear with a color that has alpha or opacity, would end up punching an
+ // unwanted hole in the frame buffer.
+ if (!current_frame()->current_render_pass->has_transparent_background)
+ return false;
+
+ // If the color has any alpha and blending is needed, ensure the blend mode
+ // allows replacing destination color & alpha.
+ const bool is_translucent =
+ SkColorGetA(quad->color) != 255 || quad->shared_quad_state->opacity < 1.f;
+ if (is_translucent &&
+ !(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc ||
+ quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver)) {
+ return false;
+ }
+
+ gfx::RectF quad_rect_in_target(quad->visible_rect);
+ sqs->quad_to_target_transform.TransformRect(&quad_rect_in_target);
+ const gfx::Rect quad_rect_in_target_rounded =
+ gfx::ToRoundedRect(quad_rect_in_target);
+
+ // If the quad does not intersect with any region that has already been drawn
+ // to, then blending is not an issue and fast draw path can be used.
+ for (const auto& rect : drawn_rects_)
+ if (quad_rect_in_target_rounded.Intersects(rect))
+ return false;
+ return true;
+}
+
void GLRenderer::AllocateRenderPassResourceIfNeeded(
const AggregatedRenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
index 7e3373fe1aa..138392ee266 100644
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -372,6 +372,10 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
bool HasOutputColorMatrix() const;
+ // Returns true if the given solid color draw quad can be safely drawn using
+ // the glClear function call.
+ bool CanUseFastSolidColorDraw(const SolidColorDrawQuad* quad) const;
+
// A map from RenderPass id to the texture used to draw the RenderPass from.
base::flat_map<AggregatedRenderPassId, ScopedRenderPassTexture>
render_pass_textures_;
@@ -454,16 +458,19 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
bool use_timer_query_ = false;
bool use_occlusion_query_ = false;
bool use_swap_with_bounds_ = false;
+ bool use_fast_path_solid_color_quad_ = false;
// If true, tints all the composited content to red.
bool tint_gl_composited_content_ = true;
+#if defined(OS_APPLE)
// The method FlippedFramebuffer determines whether the framebuffer associated
// with a DrawingFrame is flipped. It makes the assumption that the
// DrawingFrame is being used as part of a render pass. If a DrawingFrame is
// not being used as part of a render pass, setting it here forces
// FlippedFramebuffer to return |true|.
bool force_drawing_frame_framebuffer_unflipped_ = false;
+#endif
BoundGeometry bound_geometry_;
@@ -477,6 +484,9 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
// quad type as string.
base::queue<std::pair<unsigned, std::string>> timer_queries_;
+ // Keeps track of areas that have been drawn to in the current render pass.
+ std::vector<gfx::Rect> drawn_rects_;
+
// This may be null if the compositor is run on a thread without a
// MessageLoop.
scoped_refptr<base::SingleThreadTaskRunner> current_task_runner_;
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc
index 115f0535320..4a280f8760d 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier.cc
@@ -122,16 +122,24 @@ void GLRendererCopier::CopyFromTextureOrFramebuffer(
GLuint framebuffer_texture,
const gfx::Size& framebuffer_texture_size,
bool flipped_source,
- const gfx::ColorSpace& color_space) {
+ const gfx::ColorSpace& framebuffer_color_space) {
const gfx::Rect& result_rect = geometry.result_selection;
+ // If we can't convert |color_space| to a SkColorSpace for SkBitmap copy
+ // requests (e.g. PIECEWISE_HDR), fallback to a color transform to sRGB
+ // before returning the copy result.
+ gfx::ColorSpace dest_color_space = framebuffer_color_space;
+ if (!framebuffer_color_space.ToSkColorSpace() &&
+ request->result_format() == ResultFormat::RGBA_BITMAP) {
+ dest_color_space = gfx::ColorSpace::CreateSRGB();
+ }
// Fast-Path: If no transformation is necessary and no new textures need to be
// generated, read-back directly from the currently-bound framebuffer.
if (request->result_format() == ResultFormat::RGBA_BITMAP &&
- !request->is_scaled()) {
+ framebuffer_color_space == dest_color_space && !request->is_scaled()) {
StartReadbackFromFramebuffer(std::move(request), geometry.readback_offset,
flipped_source, false, result_rect,
- color_space);
+ dest_color_space);
return;
}
@@ -195,17 +203,19 @@ void GLRendererCopier::CopyFromTextureOrFramebuffer(
EnsureTextureDefinedWithSize(context_provider_->ContextGL(),
result_rect.size(), &things->result_texture,
&things->result_texture_size);
- RenderResultTexture(*request, flipped_source, color_space, source_texture,
- source_texture_size, sampling_rect, result_rect,
- things->result_texture, things.get());
- StartReadbackFromTexture(std::move(request), result_rect, color_space,
- things.get());
+ RenderResultTexture(*request, flipped_source, framebuffer_color_space,
+ dest_color_space, source_texture, source_texture_size,
+ sampling_rect, result_rect, things->result_texture,
+ things.get());
+ StartReadbackFromTexture(std::move(request), result_rect,
+ dest_color_space, things.get());
break;
case ResultFormat::RGBA_TEXTURE:
- RenderAndSendTextureResult(
- std::move(request), flipped_source, color_space, source_texture,
- source_texture_size, sampling_rect, result_rect, things.get());
+ RenderAndSendTextureResult(std::move(request), flipped_source,
+ framebuffer_color_space, dest_color_space,
+ source_texture, source_texture_size,
+ sampling_rect, result_rect, things.get());
break;
case ResultFormat::I420_PLANES:
@@ -218,7 +228,7 @@ void GLRendererCopier::CopyFromTextureOrFramebuffer(
}
const gfx::Rect aligned_rect = RenderI420Textures(
- *request, flipped_source, color_space, source_texture,
+ *request, flipped_source, framebuffer_color_space, source_texture,
source_texture_size, sampling_rect, result_rect, things.get());
StartI420ReadbackFromTextures(std::move(request), aligned_rect,
result_rect, things.get());
@@ -249,6 +259,7 @@ void GLRendererCopier::RenderResultTexture(
const CopyOutputRequest& request,
bool flipped_source,
const gfx::ColorSpace& source_color_space,
+ const gfx::ColorSpace& dest_color_space,
GLuint source_texture,
const gfx::Size& source_texture_size,
const gfx::Rect& sampling_rect,
@@ -258,7 +269,7 @@ void GLRendererCopier::RenderResultTexture(
DCHECK_NE(request.result_format(), ResultFormat::I420_PLANES);
GLScaler::Parameters params;
- PopulateScalerParameters(request, source_color_space, source_color_space,
+ PopulateScalerParameters(request, source_color_space, dest_color_space,
flipped_source, &params);
if (request.result_format() == ResultFormat::RGBA_BITMAP) {
// Render the result in top-down row order, and swizzle, within the GPU so
@@ -376,7 +387,7 @@ namespace {
// it has been destroyed in the meantime. We use the WeakPtr to the
// GLRendererCopier as an indicator that the GLContext is still alive. If the
// access to the GLContext is lost, we treat the copy output as failed.
-class GLPixelBufferRGBAResult : public CopyOutputResult {
+class GLPixelBufferRGBAResult final : public CopyOutputResult {
public:
GLPixelBufferRGBAResult(const gfx::Rect& result_rect,
const gfx::ColorSpace& color_space,
@@ -579,7 +590,8 @@ void GLRendererCopier::StartReadbackFromFramebuffer(
void GLRendererCopier::RenderAndSendTextureResult(
std::unique_ptr<CopyOutputRequest> request,
bool flipped_source,
- const gfx::ColorSpace& color_space,
+ const gfx::ColorSpace& source_color_space,
+ const gfx::ColorSpace& dest_color_space,
GLuint source_texture,
const gfx::Size& source_texture_size,
const gfx::Rect& sampling_rect,
@@ -589,7 +601,7 @@ void GLRendererCopier::RenderAndSendTextureResult(
auto* sii = context_provider_->SharedImageInterface();
gpu::Mailbox mailbox = sii->CreateSharedImage(
- ResourceFormat::RGBA_8888, result_rect.size(), color_space,
+ ResourceFormat::RGBA_8888, result_rect.size(), dest_color_space,
kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
auto* gl = context_provider_->ContextGL();
@@ -597,9 +609,9 @@ void GLRendererCopier::RenderAndSendTextureResult(
GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
gl->BeginSharedImageAccessDirectCHROMIUM(
texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
- RenderResultTexture(*request, flipped_source, color_space, source_texture,
- source_texture_size, sampling_rect, result_rect, texture,
- things);
+ RenderResultTexture(*request, flipped_source, source_color_space,
+ dest_color_space, source_texture, source_texture_size,
+ sampling_rect, result_rect, texture, things);
gl->EndSharedImageAccessDirectCHROMIUM(texture);
gl->DeleteTextures(1, &texture);
gpu::SyncToken sync_token;
@@ -614,7 +626,7 @@ void GLRendererCopier::RenderAndSendTextureResult(
texture_deleter_->GetReleaseCallback(context_provider_, mailbox);
request->SendResult(std::make_unique<CopyOutputTextureResult>(
- result_rect, mailbox, sync_token, color_space,
+ result_rect, mailbox, sync_token, dest_color_space,
std::move(release_callback)));
}
@@ -624,7 +636,7 @@ namespace {
// pixel buffer object, and automatically deletes the pixel buffer object at
// destruction time. This provides an optimal one-copy data flow, from the pixel
// buffer into client-provided memory.
-class GLPixelBufferI420Result : public CopyOutputResult {
+class GLPixelBufferI420Result final : public CopyOutputResult {
public:
// |aligned_rect| identifies the region of result pixels in the pixel buffer,
// while the |result_rect| is the subregion that is exposed to the client.
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.h b/chromium/components/viz/service/display/gl_renderer_copier.h
index 0f9a904a228..aa457e9a95d 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.h
+++ b/chromium/components/viz/service/display/gl_renderer_copier.h
@@ -191,6 +191,7 @@ class VIZ_SERVICE_EXPORT GLRendererCopier {
void RenderResultTexture(const CopyOutputRequest& request,
bool flipped_source,
const gfx::ColorSpace& source_color_space,
+ const gfx::ColorSpace& dest_color_space,
GLuint source_texture,
const gfx::Size& source_texture_size,
const gfx::Rect& sampling_rect,
@@ -284,7 +285,8 @@ class VIZ_SERVICE_EXPORT GLRendererCopier {
// as the result to the CopyOutputRequest.
void RenderAndSendTextureResult(std::unique_ptr<CopyOutputRequest> request,
bool flipped_source,
- const gfx::ColorSpace& color_space,
+ const gfx::ColorSpace& source_color_space,
+ const gfx::ColorSpace& dest_color_space,
GLuint source_texture,
const gfx::Size& source_texture_size,
const gfx::Rect& sampling_rect,
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
index 13fdca674b8..32ae73e8bb2 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
@@ -11,7 +11,9 @@
#include <utility>
#include "base/bind.h"
+#include "base/run_loop.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
+#include "components/viz/common/frame_sinks/copy_output_util.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -185,4 +187,36 @@ TEST_F(GLRendererCopierTest, FallsBackOnRGBAForReadbackFormat_BadType) {
EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
}
+// Tests that copying from a source with a color space that can't be converted
+// to a SkColorSpace will fallback to a transform to sRGB.
+TEST_F(GLRendererCopierTest, FallsBackToSRGBForInvalidSkColorSpaces) {
+ std::unique_ptr<CopyOutputResult> result;
+ base::RunLoop loop;
+ auto request = std::make_unique<CopyOutputRequest>(
+ CopyOutputRequest::ResultFormat::RGBA_BITMAP,
+ base::BindOnce(
+ [](std::unique_ptr<CopyOutputResult>* result_out,
+ base::OnceClosure quit_closure,
+ std::unique_ptr<CopyOutputResult> result_from_copier) {
+ *result_out = std::move(result_from_copier);
+ std::move(quit_closure).Run();
+ },
+ &result, loop.QuitClosure()));
+ gfx::Rect bounds(50, 50);
+ copy_output::RenderPassGeometry geometry;
+ geometry.result_bounds = bounds;
+ geometry.result_selection = bounds;
+ geometry.sampling_bounds = bounds;
+ gfx::ColorSpace hdr_color_space = gfx::ColorSpace::CreatePiecewiseHDR(
+ gfx::ColorSpace::PrimaryID::BT2020, 0.5, 1.5);
+
+ copier()->CopyFromTextureOrFramebuffer(std::move(request), geometry, GL_RGBA,
+ 0, gfx::Size(50, 50), false, hdr_color_space);
+ loop.Run();
+
+ SkBitmap result_bitmap = result->AsSkBitmap();
+ ASSERT_NE(nullptr, result_bitmap.colorSpace());
+ EXPECT_TRUE(result_bitmap.colorSpace()->isSRGB());
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_draw_cache.h b/chromium/components/viz/service/display/gl_renderer_draw_cache.h
index a637154e134..6abe06cce4f 100644
--- a/chromium/components/viz/service/display/gl_renderer_draw_cache.h
+++ b/chromium/components/viz/service/display/gl_renderer_draw_cache.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "components/viz/service/display/program_binding.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/rrect_f.h"
+#include "ui/gfx/mask_filter_info.h"
namespace viz {
@@ -39,7 +39,7 @@ struct TexturedQuadDrawCache {
bool needs_blending = false;
bool nearest_neighbor = false;
SkColor background_color = 0;
- gfx::RRectF rounded_corner_bounds;
+ gfx::MaskFilterInfo mask_filter_info;
// A cache for the coalesced quad data.
std::vector<Float4> uv_xform_data;
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
index 3dfb5b542e0..a5d550aef67 100644
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -13,7 +13,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
@@ -28,6 +28,7 @@
#include "cc/test/resource_provider_test_utils.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/quads/texture_draw_quad.h"
@@ -99,8 +100,9 @@ class GLRendererTest : public testing::Test {
const gfx::Size& viewport_size,
const gfx::DisplayColorSpaces& display_color_spaces =
gfx::DisplayColorSpaces()) {
+ SurfaceDamageRectList surface_damage_rect_list;
renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size,
- display_color_spaces);
+ display_color_spaces, &surface_damage_rect_list);
}
static const Program* current_program(GLRenderer* renderer) {
@@ -790,7 +792,7 @@ TEST_F(GLRendererWithDefaultHarnessTest, TextureDrawQuadShaderPrecisionHigh) {
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(1023, 1023), gfx::RRectF(),
+ gfx::Rect(1023, 1023), gfx::MaskFilterInfo(),
gfx::Rect(1023, 1023), false, false, 1,
SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(shared_state, gfx::Rect(1023, 1023),
@@ -853,7 +855,7 @@ TEST_F(GLRendererWithDefaultHarnessTest, TextureDrawQuadShaderPrecisionMedium) {
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(1025, 1025), gfx::RRectF(),
+ gfx::Rect(1025, 1025), gfx::MaskFilterInfo(),
gfx::Rect(1025, 1025), false, false, 1,
SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(shared_state, gfx::Rect(1025, 1025),
@@ -911,7 +913,7 @@ class GLRendererTextureDrawQuadHDRTest
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(kTextureSize), gfx::RRectF(),
+ gfx::Rect(kTextureSize), gfx::MaskFilterInfo(),
gfx::Rect(kTextureSize), false, false, 1,
SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(shared_state, gfx::Rect(kTextureSize),
@@ -1376,8 +1378,13 @@ TEST_F(GLRendererTest, ActiveTextureState) {
EXPECT_FILTER_CALL(GL_LINEAR);
EXPECT_CALL(*gl, DrawElements(_, _, _, _));
- // stream video, solid color and debug draw quads
- EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(3);
+ if (features::IsUsingFastPathForSolidColorQuad()) {
+ // stream video and debug draw quads
+ EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(2);
+ } else {
+ // stream video, solid color, and debug draw quads
+ EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(3);
+ }
}
gfx::Size viewport_size(100, 100);
@@ -1443,8 +1450,9 @@ TEST_F(GLRendererTest, DrawYUVVideoDrawQuadWithVisibleRect) {
visible_rect.Inset(10, 20, 30, 40);
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(), rect, gfx::RRectF(), rect,
- false, false, 1, SkBlendMode::kSrcOver, 0);
+ shared_state->SetAll(gfx::Transform(), gfx::Rect(), rect,
+ gfx::MaskFilterInfo(), rect, false, false, 1,
+ SkBlendMode::kSrcOver, 0);
YUVVideoDrawQuad* quad =
root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
@@ -1534,8 +1542,15 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
Expectation first_render_pass =
EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)).Times(1);
- // The second render pass is the root one, clearing should be prevented.
- EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass);
+ if (features::IsUsingFastPathForSolidColorQuad()) {
+ // The second render pass is the root one, clearing should be prevented. The
+ // one call is expected due to the solid color draw quad which uses glClear
+ // to draw the quad.
+ EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(1).After(first_render_pass);
+ } else {
+ // The second render pass is the root one, clearing should be prevented.
+ EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass);
+ }
EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _))
.Times(AnyNumber())
@@ -1553,7 +1568,20 @@ class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface {
public:
ScissorTestOnClearCheckingGLES2Interface() = default;
- void Clear(GLbitfield) override { EXPECT_FALSE(scissor_enabled_); }
+ void ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) override {
+ // RGBA - {0, 0, 0, 0} is used to clear the buffer before drawing onto the
+ // render target. Any other color means a solid color draw quad is being
+ // drawn.
+ if (features::IsUsingFastPathForSolidColorQuad())
+ is_drawing_solid_color_quad_ = !(r == 0 && g == 0 && b == 0 && a == 0);
+ }
+
+ void Clear(GLbitfield bits) override {
+ // GL clear is also used to draw solid color draw quads.
+ if ((bits & GL_COLOR_BUFFER_BIT) && is_drawing_solid_color_quad_)
+ return;
+ EXPECT_FALSE(scissor_enabled_);
+ }
void Enable(GLenum cap) override {
if (cap == GL_SCISSOR_TEST)
@@ -1567,6 +1595,7 @@ class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface {
private:
bool scissor_enabled_ = false;
+ bool is_drawing_solid_color_quad_ = false;
};
TEST_F(GLRendererTest, ScissorTestWhenClearing) {
@@ -1930,7 +1959,10 @@ class GLRendererSkipTest : public GLRendererTest {
}
void DrawBlackFrame(const gfx::Size& viewport_size) {
- EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
+ // The feature enables a faster path to draw solid color quads that does not
+ // use GL draw calls but instead uses glClear.
+ if (!features::IsUsingFastPathForSolidColorQuad())
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
AggregatedRenderPassId root_pass_id{1};
AggregatedRenderPass* root_pass = cc::AddRenderPass(
@@ -1962,6 +1994,7 @@ TEST_F(GLRendererSkipTest, DrawQuad) {
DrawBlackFrame(viewport_size);
EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
+
AggregatedRenderPassId root_pass_id{1};
AggregatedRenderPass* root_pass = cc::AddRenderPass(
&render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
@@ -1969,6 +2002,11 @@ TEST_F(GLRendererSkipTest, DrawQuad) {
root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
cc::AddQuad(root_pass, quad_rect, SK_ColorGREEN);
+ // Add rounded corners to the solid color draw quad so that the fast path
+ // of drawing using glClear is not used.
+ root_pass->shared_quad_state_list.front()->mask_filter_info =
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 2.f));
+
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
DrawFrame(renderer_.get(), viewport_size);
}
@@ -1992,6 +2030,11 @@ TEST_F(GLRendererSkipTest, SkipVisibleRect) {
gfx::Rect(0, 0, 40, 40);
root_pass->quad_list.front()->visible_rect = gfx::Rect(20, 20, 20, 20);
+ // Add rounded corners to the solid color draw quad so that the fast path
+ // of drawing using glClear is not used.
+ root_pass->shared_quad_state_list.front()->mask_filter_info =
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 1.f));
+
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
DrawFrame(renderer_.get(), viewport_size);
// DrawElements should not be called because the visible rect is outside the
@@ -2387,9 +2430,6 @@ class MockOutputSurface : public OutputSurface {
MOCK_METHOD1(SetUpdateVSyncParametersCallback,
void(UpdateVSyncParametersCallback));
MOCK_METHOD1(SetDisplayTransformHint, void(gfx::OverlayTransform));
- MOCK_METHOD0(GetGpuTaskSchedulerHelper,
- scoped_refptr<gpu::GpuTaskSchedulerHelper>());
- MOCK_METHOD0(GetMemoryTracker, gpu::MemoryTracker*());
gfx::OverlayTransform GetDisplayTransform() override {
return gfx::OVERLAY_TRANSFORM_NONE;
@@ -2453,8 +2493,10 @@ class MockOutputSurfaceTest : public GLRendererTest {
renderer_->DecideRenderPassAllocationsForFrame(
render_passes_in_draw_order_);
+ SurfaceDamageRectList surface_damage_rect_list;
renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor,
- viewport_size, gfx::DisplayColorSpaces());
+ viewport_size, gfx::DisplayColorSpaces(),
+ &surface_damage_rect_list);
}
RendererSettings settings_;
@@ -2482,13 +2524,18 @@ TEST_F(MockOutputSurfaceTest, BackbufferDiscard) {
class MockDCLayerOverlayProcessor : public DCLayerOverlayProcessor {
public:
MockDCLayerOverlayProcessor()
- : DCLayerOverlayProcessor(&debug_settings_, true) {}
+ : DCLayerOverlayProcessor(&debug_settings_,
+ /*allowed_yuv_overlay_count=*/1,
+ true) {}
~MockDCLayerOverlayProcessor() override = default;
- MOCK_METHOD5(Process,
+ MOCK_METHOD8(Process,
void(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
+ const FilterOperationsMap& render_pass_filters,
+ const FilterOperationsMap& render_pass_backdrop_filters,
AggregatedRenderPassList* render_passes,
gfx::Rect* damage_rect,
+ SurfaceDamageRectList* surface_damage_rect_list,
DCLayerOverlayList* dc_layer_overlays));
protected:
@@ -2544,13 +2591,14 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
Strategy() = default;
~Strategy() override = default;
- MOCK_METHOD7(
+ MOCK_METHOD8(
Attempt,
bool(const SkMatrix44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const OverlayProcessorInterface::OutputSurfaceOverlayPlane*
primary_surface,
OverlayCandidateList* candidates,
@@ -2574,7 +2622,7 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
return *(static_cast<Strategy*>(strategy));
}
- MOCK_CONST_METHOD0(NeedsSurfaceOccludingDamageRect, bool());
+ MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
explicit TestOverlayProcessor(OutputSurface* output_surface)
: OverlayProcessorUsingStrategy() {
strategies_.push_back(std::make_unique<Strategy>());
@@ -2686,12 +2734,12 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
// any attempt to overlay, which there shouldn't be. We can't use the quad
// list because the render pass is cleaned up by DrawFrame.
#if defined(USE_OZONE) || defined(OS_ANDROID)
- EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)).Times(0);
#elif defined(OS_APPLE)
EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
.Times(0);
#elif defined(OS_WIN)
- EXPECT_CALL(*dc_processor, Process(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(0);
#endif
DrawFrame(&renderer, viewport_size);
#if defined(USE_OZONE) || defined(OS_ANDROID)
@@ -2718,12 +2766,12 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor,
/*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
#if defined(USE_OZONE) || defined(OS_ANDROID)
- EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _)).Times(1);
#elif defined(OS_APPLE)
EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
.Times(1);
#elif defined(OS_WIN)
- EXPECT_CALL(*dc_processor, Process(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(1);
#endif
DrawFrame(&renderer, viewport_size);
@@ -2744,7 +2792,7 @@ class SingleOverlayOnTopProcessor : public OverlayProcessorUsingStrategy {
strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
}
- bool NeedsSurfaceOccludingDamageRect() const override { return true; }
+ bool NeedsSurfaceDamageRectList() const override { return true; }
bool IsOverlaySupported() const override { return true; }
void CheckOverlaySupport(
@@ -2864,7 +2912,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(viewport_size), gfx::RRectF(),
+ gfx::Rect(viewport_size), gfx::MaskFilterInfo(),
gfx::Rect(viewport_size), false, false, 1,
SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
@@ -3046,6 +3094,358 @@ TEST_F(GLRendererTest, GenerateMipmap) {
DrawFrame(&renderer, viewport_size);
}
+class FastSolidColorMockGLES2Interface : public TestGLES2Interface {
+ public:
+ FastSolidColorMockGLES2Interface() = default;
+
+ MOCK_METHOD1(Enable, void(GLenum cap));
+ MOCK_METHOD1(Disable, void(GLenum cap));
+ MOCK_METHOD4(ClearColor,
+ void(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
+ MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
+};
+
+class GLRendererFastSolidColorTest : public GLRendererTest {
+ public:
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(features::kFastSolidColorDraw);
+ GLRendererTest::SetUp();
+
+ auto gl_owned = std::make_unique<FastSolidColorMockGLES2Interface>();
+ gl_owned->set_have_post_sub_buffer(true);
+ gl_ = gl_owned.get();
+
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
+ provider->BindToCurrentThread();
+
+ output_surface_ = FakeOutputSurface::Create3d(std::move(provider));
+ output_surface_->BindToClient(&output_surface_client_);
+
+ resource_provider_ = std::make_unique<DisplayResourceProvider>(
+ DisplayResourceProvider::kGpu, output_surface_->context_provider(),
+ nullptr);
+
+ settings_.partial_swap_enabled = true;
+ settings_.slow_down_compositing_scale_factor = 1;
+ settings_.allow_antialiasing = true;
+
+ fake_renderer_ = std::make_unique<FakeRendererGL>(
+ &settings_, &debug_settings_, output_surface_.get(),
+ resource_provider_.get());
+ fake_renderer_->Initialize();
+ EXPECT_TRUE(fake_renderer_->use_partial_swap());
+ fake_renderer_->SetVisible(true);
+ }
+
+ void TearDown() override {
+ resource_provider_.reset();
+ fake_renderer_.reset();
+ output_surface_.reset();
+ gl_ = nullptr;
+
+ GLRendererTest::TearDown();
+ }
+
+ FastSolidColorMockGLES2Interface* gl_ptr() { return gl_; }
+
+ FakeOutputSurface* output_surface() { return output_surface_.get(); }
+
+ protected:
+ void AddExpectations(bool use_fast_path,
+ const gfx::Rect& scissor_rect,
+ SkColor color = SK_ColorBLACK,
+ bool enable_stencil = false) {
+ auto* gl = gl_ptr();
+
+ InSequence seq;
+
+ // Restore GL state method calls
+ EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST));
+ EXPECT_CALL(*gl, Disable(GL_CULL_FACE));
+ EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST));
+ EXPECT_CALL(*gl, Enable(GL_BLEND));
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+
+ if (!enable_stencil)
+ EXPECT_CALL(*gl, ClearColor(0, 0, 0, 0));
+
+ if (use_fast_path) {
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
+ scissor_rect.width(), scissor_rect.height()));
+
+ SkColor4f color_f = SkColor4f::FromColor(color);
+ EXPECT_CALL(*gl,
+ ClearColor(color_f.fR, color_f.fG, color_f.fB, color_f.fA));
+
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+ }
+
+ if (enable_stencil) {
+ EXPECT_CALL(*gl, Enable(GL_STENCIL_TEST));
+ EXPECT_CALL(*gl, Disable(GL_BLEND));
+ }
+
+ EXPECT_CALL(*gl, Disable(GL_BLEND));
+ }
+
+ void RunTest(const gfx::Size& viewport_size) {
+ fake_renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ DrawFrame(fake_renderer_.get(), viewport_size);
+
+ auto* gl = gl_ptr();
+ ASSERT_TRUE(gl);
+ Mock::VerifyAndClearExpectations(gl);
+ }
+
+ private:
+ FastSolidColorMockGLES2Interface* gl_ = nullptr;
+ std::unique_ptr<FakeRendererGL> fake_renderer_;
+ std::unique_ptr<FakeOutputSurface> output_surface_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ RendererSettings settings_;
+ base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(GLRendererFastSolidColorTest, RoundedCorners) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_output_rect(400, 400);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 50, 100, 100);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPassWithDamage(
+ &render_passes_in_draw_order_, root_pass_id, root_pass_output_rect,
+ root_pass_damage_rect, gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ root_pass->shared_quad_state_list.front()->mask_filter_info =
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 5.f));
+
+ // Fast Solid color draw quads should not be executed.
+ AddExpectations(false /*use_fast_path*/, gfx::Rect());
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, Transform3DSlowPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 50, 100, 100);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ gfx::Transform tm_3d;
+ tm_3d.RotateAboutYAxis(30.0);
+ ASSERT_FALSE(tm_3d.IsFlat());
+
+ root_pass->shared_quad_state_list.front()->quad_to_target_transform = tm_3d;
+
+ AddExpectations(false /*use_fast_path*/, gfx::Rect());
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, NonTransform3DFastPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 0, 200, 200);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ gfx::Transform tm_non_3d;
+ tm_non_3d.Translate(10.f, 10.f);
+ ASSERT_TRUE(tm_non_3d.IsFlat());
+
+ root_pass->shared_quad_state_list.front()->quad_to_target_transform =
+ tm_non_3d;
+
+ AddExpectations(true /*use_fast_path*/, gfx::Rect(10, 290, 200, 200),
+ SK_ColorRED);
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, NonAxisAlignSlowPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 0, 200, 200);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ gfx::Transform tm_non_axis_align;
+ tm_non_axis_align.RotateAboutZAxis(45.0);
+ ASSERT_TRUE(tm_non_axis_align.IsFlat());
+
+ root_pass->shared_quad_state_list.front()->quad_to_target_transform =
+ tm_non_axis_align;
+
+ AddExpectations(false /*use_fast_path*/, gfx::Rect());
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, StencilSlowPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 0, 200, 200);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ root_pass->has_transparent_background = false;
+
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ AddExpectations(false /*use_fast_path*/, gfx::Rect(), SK_ColorRED,
+ true /*enable_stencil*/);
+ output_surface()->set_has_external_stencil_test(true);
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, NeedsBlendingSlowPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(2, 3, 300, 200);
+ gfx::Rect full_quad_rect(0, 0, 50, 50);
+ gfx::Rect quad_rect_1(0, 0, 20, 20);
+ gfx::Rect quad_rect_2(20, 0, 20, 20);
+ gfx::Rect quad_rect_3(0, 20, 20, 20);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+
+ cc::AddQuad(root_pass, quad_rect_1, SK_ColorRED);
+ root_pass->quad_list.back()->needs_blending = true;
+
+ cc::AddQuad(root_pass, quad_rect_2, SK_ColorBLUE);
+ root_pass->shared_quad_state_list.back()->opacity = 0.5f;
+
+ cc::AddQuad(root_pass, quad_rect_3, SK_ColorGREEN);
+ root_pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kDstIn;
+
+ cc::AddQuad(root_pass, full_quad_rect, SK_ColorBLACK);
+
+ // The first solid color quad would use a fast path, but the other quads that
+ // require blending will use the slower method.
+ AddExpectations(true /*use_fast_path*/, gfx::Rect(0, 450, 50, 50),
+ SK_ColorBLACK, false /*enable_stencil*/);
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, NeedsBlendingFastPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(2, 3, 300, 200);
+ gfx::Rect quad_rect_1(0, 0, 20, 20);
+ gfx::Rect quad_rect_2(20, 0, 20, 20);
+ gfx::Rect quad_rect_3(0, 20, 20, 20);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+
+ cc::AddQuad(root_pass, quad_rect_1, SK_ColorRED);
+ root_pass->quad_list.back()->needs_blending = true;
+
+ cc::AddQuad(root_pass, quad_rect_2, SK_ColorBLUE);
+ root_pass->shared_quad_state_list.back()->opacity = 0.5f;
+
+ cc::AddQuad(root_pass, quad_rect_3, SK_ColorGREEN);
+ root_pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kDstIn;
+
+ auto* gl = gl_ptr();
+
+ // The quads here despite having blend requirements can still use fast path
+ // because they do not intersect with any other quad that has already been
+ // drawn onto the render target.
+ InSequence seq;
+
+ // // Restore GL state method calls
+ EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST));
+ EXPECT_CALL(*gl, Disable(GL_CULL_FACE));
+ EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST));
+ EXPECT_CALL(*gl, Enable(GL_BLEND));
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+ EXPECT_CALL(*gl, ClearColor(0, 0, 0, 0));
+
+ // Fast path draw used for green quad.
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 460, 20, 20));
+ EXPECT_CALL(*gl, ClearColor(0, 1, 0, 1));
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+
+ // Fast path draw used for blue quad.
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(20, 480, 20, 20));
+ EXPECT_CALL(*gl, ClearColor(0, 0, 0.5f, 0.5f));
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+
+ // Fast path draw used for red quad.
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 480, 20, 20));
+ EXPECT_CALL(*gl, ClearColor(1, 0, 0, 1));
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+
+ EXPECT_CALL(*gl, Disable(GL_BLEND));
+
+ RunTest(viewport_size);
+}
+
+TEST_F(GLRendererFastSolidColorTest, AntiAliasSlowPath) {
+ gfx::Size viewport_size(500, 500);
+ gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
+ gfx::Rect quad_rect(0, 0, 200, 200);
+
+ AggregatedRenderPassId root_pass_id{1};
+ AggregatedRenderPass* root_pass = cc::AddRenderPass(
+ &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+ gfx::Transform(), cc::FilterOperations());
+ root_pass->damage_rect = root_pass_damage_rect;
+ cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
+
+ gfx::Transform tm_aa;
+ tm_aa.Translate(0.1f, 0.1f);
+ ASSERT_TRUE(tm_aa.IsFlat());
+
+ root_pass->shared_quad_state_list.front()->quad_to_target_transform = tm_aa;
+
+ AddExpectations(false /*use_fast_path*/, gfx::Rect());
+
+ RunTest(viewport_size);
+}
+
class PartialSwapMockGLES2Interface : public TestGLES2Interface {
public:
PartialSwapMockGLES2Interface() = default;
@@ -3057,6 +3457,13 @@ class PartialSwapMockGLES2Interface : public TestGLES2Interface {
};
class GLRendererPartialSwapTest : public GLRendererTest {
+ public:
+ void SetUp() override {
+ // Force enable fast solid color draw path.
+ scoped_feature_list_.InitAndEnableFeature(features::kFastSolidColorDraw);
+ GLRendererTest::SetUp();
+ }
+
protected:
void RunTest(bool partial_swap, bool set_draw_rectangle) {
auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
@@ -3095,15 +3502,30 @@ class GLRendererPartialSwapTest : public GLRendererTest {
EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST)).Times(1);
EXPECT_CALL(*gl, Disable(GL_CULL_FACE)).Times(1);
EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST)).Times(1);
- EXPECT_CALL(*gl, Disable(GL_BLEND)).Times(2);
EXPECT_CALL(*gl, Enable(GL_BLEND)).Times(1);
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST)).Times(1);
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0)).Times(1);
- if (set_draw_rectangle) {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(1);
- EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(1);
+
+ if (output_surface->capabilities().supports_dc_layers) {
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST)).Times(1);
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0)).Times(1);
+
+ // Root render pass requires a scissor if the output surface supports
+ // dc layers.
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(3);
+ EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(3);
+ } else {
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST)).Times(2);
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0)).Times(2);
+ if (set_draw_rectangle) {
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(2);
+ EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(2);
+ } else {
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(1);
+ EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(1);
+ }
}
+ EXPECT_CALL(*gl, Disable(GL_BLEND)).Times(1);
+
AggregatedRenderPassId root_pass_id{1};
AggregatedRenderPass* root_pass = cc::AddRenderPass(
&render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
@@ -3136,19 +3558,34 @@ class GLRendererPartialSwapTest : public GLRendererTest {
gfx::Rect output_rectangle =
partial_swap ? root_pass_damage_rect : gfx::Rect(viewport_size);
+ // The scissor is flipped, so subtract the y coord and height from the
+ // bottom of the GL viewport.
+ gfx::Rect scissor_rect(output_rectangle.x(),
+ viewport_size.height() - output_rectangle.y() -
+ output_rectangle.height(),
+ output_rectangle.width(),
+ output_rectangle.height());
+
+ // Drawing the solid color quad using glClear and scissor rect.
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
+ scissor_rect.width(), scissor_rect.height()));
+
if (partial_swap || set_draw_rectangle) {
EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- // The scissor is flipped, so subtract the y coord and height from the
- // bottom of the GL viewport.
- EXPECT_CALL(
- *gl, Scissor(output_rectangle.x(),
- viewport_size.height() - output_rectangle.y() -
- output_rectangle.height(),
- output_rectangle.width(), output_rectangle.height()));
+ EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
+ scissor_rect.width(), scissor_rect.height()));
}
- // The quad doesn't need blending.
- EXPECT_CALL(*gl, Disable(GL_BLEND));
+ // Restore GL state after solid color draw quad.
+ if (partial_swap || set_draw_rectangle) {
+ EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
+ scissor_rect.width(), scissor_rect.height()));
+ } else {
+ EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
+ EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
+ }
// Blending is disabled at the end of the frame.
EXPECT_CALL(*gl, Disable(GL_BLEND));
@@ -3164,6 +3601,9 @@ class GLRendererPartialSwapTest : public GLRendererTest {
Mock::VerifyAndClearExpectations(gl);
}
}
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(GLRendererPartialSwapTest, PartialSwap) {
@@ -3186,8 +3626,6 @@ TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_NoPartialSwap) {
// Test that SetEnableDCLayersCHROMIUM is properly called when enabling
// and disabling DC layers.
TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
gl_owned->set_have_post_sub_buffer(true);
auto* gl = gl_owned.get();
@@ -3236,7 +3674,8 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
auto processor = std::make_unique<OverlayProcessorWin>(
output_surface.get(),
- std::make_unique<DCLayerOverlayProcessor>(&debug_settings_, true));
+ std::make_unique<DCLayerOverlayProcessor>(
+ &debug_settings_, /*allowed_yuv_overlay_count=*/1, true));
RendererSettings settings;
settings.partial_swap_enabled = true;
@@ -3258,8 +3697,8 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
gfx::RectF tex_coord_rect(0, 0, 1, 1);
SharedQuadState* shared_state =
root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), rect, rect, gfx::RRectF(), rect,
- false, false, 1, SkBlendMode::kSrcOver, 0);
+ shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
+ rect, false, false, 1, SkBlendMode::kSrcOver, 0);
YUVVideoDrawQuad* quad =
root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
quad->SetNew(shared_state, rect, rect, needs_blending, tex_coord_rect,
@@ -3367,6 +3806,7 @@ class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds) override {
@@ -3389,7 +3829,7 @@ class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
Strategy& strategy() { return static_cast<Strategy&>(*strategies_.back()); }
// Empty mock methods since this test set up uses strategies, which are only
// for ozone and android.
- MOCK_CONST_METHOD0(NeedsSurfaceOccludingDamageRect, bool());
+ MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
bool IsOverlaySupported() const override { return true; }
// A list of possible overlay candidates is presented to this function.
@@ -3672,8 +4112,8 @@ TEST_F(CALayerGLRendererTest, CALayerRoundRects) {
sqs->is_clipped = true;
sqs->clip_rect = gfx::Rect(2, 2, 6, 6);
const float radius = 2;
- sqs->rounded_corner_bounds =
- gfx::RRectF(gfx::RectF(sqs->clip_rect), radius);
+ sqs->mask_filter_info =
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(sqs->clip_rect), radius));
switch (subtest) {
case 0:
@@ -3693,8 +4133,11 @@ TEST_F(CALayerGLRendererTest, CALayerRoundRects) {
break;
case 2:
// Subtest 2 has a non-simple rounded rect.
- sqs->rounded_corner_bounds.SetCornerRadii(
- gfx::RRectF::Corner::kUpperLeft, 1, 1);
+ gfx::RRectF rounded_corner_bounds =
+ sqs->mask_filter_info.rounded_corner_bounds();
+ rounded_corner_bounds.SetCornerRadii(gfx::RRectF::Corner::kUpperLeft, 1,
+ 1);
+ sqs->mask_filter_info = gfx::MaskFilterInfo(rounded_corner_bounds);
// Called 2 extra times in order to set up the rounded corner
// parameters in the shader, because the CALayer is not handling
// the rounded corners.
@@ -4656,7 +5099,7 @@ TEST_F(GLRendererWithGpuFenceTest,
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(50, 50), gfx::RRectF(),
+ gfx::Rect(50, 50), gfx::MaskFilterInfo(),
gfx::Rect(viewport_size), false, false, 1,
SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(
diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h
index 35b009a6111..0dc23fa761d 100644
--- a/chromium/components/viz/service/display/output_surface.h
+++ b/chromium/components/viz/service/display/output_surface.h
@@ -116,6 +116,8 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// This is the maximum size for RenderPass textures. No maximum size is
// enforced if zero.
int max_render_target_size = 0;
+ // The root surface is rendered using vulkan secondary command buffer.
+ bool root_is_vulkan_secondary_command_buffer = false;
// SkColorType for all supported buffer formats.
SkColorType sk_color_types[static_cast<int>(gfx::BufferFormat::LAST) + 1] =
@@ -263,14 +265,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
const gfx::SwapResponse& response,
std::vector<ui::LatencyInfo>* latency_info);
- // This is used to share the same method to schedule task on the gpu thread
- // between the output surface and the overlay processor.
- // TODO(weiliangc): Consider making this outside of output surface and pass in
- // instead of passing it out here.
- virtual scoped_refptr<gpu::GpuTaskSchedulerHelper>
- GetGpuTaskSchedulerHelper() = 0;
- virtual gpu::MemoryTracker* GetMemoryTracker() = 0;
-
// Notifies the OutputSurface of rate of content updates in frames per second.
virtual void SetFrameRate(float frame_rate) {}
diff --git a/chromium/components/viz/service/display/overlay_ca_unittest.cc b/chromium/components/viz/service/display/overlay_ca_unittest.cc
index dbe2ea00cd9..3bcc0d3267d 100644
--- a/chromium/components/viz/service/display/overlay_ca_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_ca_unittest.cc
@@ -8,9 +8,8 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
-#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "cc/test/fake_output_surface_client.h"
@@ -85,11 +84,6 @@ class OverlayOutputSurface : public OutputSurface {
gfx::OverlayTransform GetDisplayTransform() override {
return gfx::OVERLAY_TRANSFORM_NONE;
}
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override {
- return nullptr;
- }
- gpu::MemoryTracker* GetMemoryTracker() override { return nullptr; }
unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
@@ -100,8 +94,7 @@ class OverlayOutputSurface : public OutputSurface {
class CATestOverlayProcessor : public OverlayProcessorMac {
public:
CATestOverlayProcessor()
- : OverlayProcessorMac(true /* could_overlay */,
- true /* enable_ca_overlay */) {}
+ : OverlayProcessorMac(true /* enable_ca_overlay */) {}
};
std::unique_ptr<AggregatedRenderPass> CreateRenderPass() {
@@ -274,10 +267,13 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(1U, ca_layer_list.size());
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
@@ -298,10 +294,13 @@ TEST_F(CALayerOverlayTest, ThreeDTransform) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, ca_layer_list.size());
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(kRenderPassOutputRect, overlay_damage);
@@ -326,10 +325,13 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -349,10 +351,13 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_TRUE(ca_layer_list.back().shared_state->is_clipped);
@@ -374,10 +379,13 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -396,10 +404,13 @@ TEST_F(CALayerOverlayTest, SkipNonVisible) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &ca_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect);
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -418,8 +429,9 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
void ProcessForOverlays() {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(),
- render_pass_filters_, render_pass_backdrop_filters_, nullptr,
- &ca_layer_list_, &damage_rect_, &content_bounds_);
+ render_pass_filters_, render_pass_backdrop_filters_,
+ &surface_damage_rect_list_, nullptr, &ca_layer_list_, &damage_rect_,
+ &content_bounds_);
}
AggregatedRenderPassList pass_list_;
AggregatedRenderPass* pass_;
@@ -430,6 +442,7 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
OverlayProcessorInterface::FilterOperationsMap render_pass_filters_;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters_;
CALayerOverlayList ca_layer_list_;
+ SurfaceDamageRectList surface_damage_rect_list_;
};
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadNoFilters) {
diff --git a/chromium/components/viz/service/display/overlay_candidate.cc b/chromium/components/viz/service/display/overlay_candidate.cc
index 9bc7a2caac2..05e7922ca8e 100644
--- a/chromium/components/viz/service/display/overlay_candidate.cc
+++ b/chromium/components/viz/service/display/overlay_candidate.cc
@@ -17,6 +17,7 @@
#include "components/viz/common/quads/video_hole_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/service/display/display_resource_provider.h"
+#include "components/viz/service/display/overlay_processor_interface.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/video_types.h"
@@ -30,7 +31,8 @@ const SkScalar kEpsilon = std::numeric_limits<float>::epsilon();
const gfx::BufferFormat kOverlayFormats[] = {
gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
gfx::BufferFormat::BGRX_8888, gfx::BufferFormat::BGRA_8888,
- gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR};
+ gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR,
+ gfx::BufferFormat::P010};
enum Axis { NONE, AXIS_POS_X, AXIS_NEG_X, AXIS_POS_Y, AXIS_NEG_Y };
@@ -78,6 +80,45 @@ gfx::OverlayTransform GetOverlayTransform(const gfx::Transform& quad_transform,
return gfx::OVERLAY_TRANSFORM_INVALID;
}
+bool HasOccludingDamage(const SharedQuadState* shared_quad_state,
+ SurfaceDamageRectList* surface_damage_rect_list) {
+ if (!shared_quad_state->overlay_damage_index.has_value())
+ return true;
+
+ size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value();
+ // Invalid index.
+ if (overlay_damage_index >= surface_damage_rect_list->size()) {
+ DCHECK(false);
+ return true;
+ }
+
+ // Damage rects in surface_damage_rect_list are arranged from top to bottom.
+ // (*surface_damage_rect_list)[0] is the one on the very top.
+ // (*surface_damage_rect_list)[overlay_damage_index] is the damage rect of
+ // this overlay surface.
+ for (size_t i = 0; i < overlay_damage_index; ++i) {
+ if (!(*surface_damage_rect_list)[i].IsEmpty())
+ return true; // A damaged surface on top is found.
+ }
+
+ return false; // No occluding damges
+}
+
+gfx::Rect GetDamageRect(const SharedQuadState* shared_quad_state,
+ SurfaceDamageRectList* surface_damage_rect_list) {
+ if (!shared_quad_state->overlay_damage_index.has_value())
+ return gfx::Rect();
+
+ size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value();
+ // Invalid index.
+ if (overlay_damage_index >= surface_damage_rect_list->size()) {
+ DCHECK(false);
+ return gfx::Rect();
+ }
+
+ return (*surface_damage_rect_list)[overlay_damage_index];
+}
+
} // namespace
OverlayCandidate::OverlayCandidate()
@@ -92,7 +133,6 @@ OverlayCandidate::OverlayCandidate()
is_backed_by_surface_texture(false),
is_promotable_hint(false),
#endif
- plane_z_order(0),
is_unoccluded(false),
overlay_handled(false),
gpu_fence_id(0) {
@@ -103,10 +143,12 @@ OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default;
OverlayCandidate::~OverlayCandidate() = default;
// static
-bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
- const SkMatrix44& output_color_matrix,
- const DrawQuad* quad,
- OverlayCandidate* candidate) {
+bool OverlayCandidate::FromDrawQuad(
+ DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const SkMatrix44& output_color_matrix,
+ const DrawQuad* quad,
+ OverlayCandidate* candidate) {
// It is currently not possible to set a color conversion matrix on an HW
// overlay plane.
// TODO(https://crbug.com/792757): Remove this check once the bug is resolved.
@@ -116,8 +158,8 @@ bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
// We don't support an opacity value different than one for an overlay plane.
if (quad->shared_quad_state->opacity != 1.f)
return false;
- // We can't support overlays with rounded corner clipping.
- if (!quad->shared_quad_state->rounded_corner_bounds.IsEmpty())
+ // We can't support overlays with mask filter.
+ if (!quad->shared_quad_state->mask_filter_info.IsEmpty())
return false;
// We support only kSrc (no blending) and kSrcOver (blending with premul).
if (!(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc ||
@@ -127,13 +169,14 @@ bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
switch (quad->material) {
case DrawQuad::Material::kTextureContent:
- return FromTextureQuad(resource_provider,
+ return FromTextureQuad(resource_provider, surface_damage_rect_list,
TextureDrawQuad::MaterialCast(quad), candidate);
case DrawQuad::Material::kVideoHole:
- return FromVideoHoleQuad(
- resource_provider, VideoHoleDrawQuad::MaterialCast(quad), candidate);
+ return FromVideoHoleQuad(resource_provider, surface_damage_rect_list,
+ VideoHoleDrawQuad::MaterialCast(quad),
+ candidate);
case DrawQuad::Material::kStreamVideoContent:
- return FromStreamVideoQuad(resource_provider,
+ return FromStreamVideoQuad(resource_provider, surface_damage_rect_list,
StreamVideoDrawQuad::MaterialCast(quad),
candidate);
default:
@@ -171,8 +214,8 @@ bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
overlap_iter->shared_quad_state->quad_to_target_transform,
gfx::RectF(overlap_iter->rect)));
- if (display_rect.Intersects(overlap_rect) &&
- !OverlayCandidate::IsInvisibleQuad(*overlap_iter)) {
+ if (!OverlayCandidate::IsInvisibleQuad(*overlap_iter) &&
+ display_rect.Intersects(overlap_rect)) {
return true;
}
}
@@ -180,6 +223,36 @@ bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
}
// static
+int OverlayCandidate::EstimateVisibleDamage(
+ const DrawQuad* quad,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end) {
+ gfx::Rect quad_damage =
+ GetDamageRect(quad->shared_quad_state, surface_damage_rect_list);
+ int occluded_damage_estimate_total = 0;
+ for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
+ ++overlap_iter) {
+ gfx::Rect overlap_rect = gfx::ToRoundedRect(cc::MathUtil::MapClippedRect(
+ overlap_iter->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(overlap_iter->rect)));
+
+ // Opaque quad that (partially) occludes this candidate.
+ if (!OverlayCandidate::IsInvisibleQuad(*overlap_iter) &&
+ !overlap_iter->ShouldDrawWithBlending()) {
+ overlap_rect.Intersect(quad_damage);
+ occluded_damage_estimate_total += overlap_rect.size().GetArea();
+ }
+ }
+ // In the case of overlapping UI the |occluded_damage_estimate_total| may
+ // exceed the |quad|'s damage rect that is in consideration. This is the
+ // reason why this computation is an estimate and why we have the max clamping
+ // below.
+ return std::max(
+ 0, quad_damage.size().GetArea() - occluded_damage_estimate_total);
+}
+
+// static
bool OverlayCandidate::RequiresOverlay(const DrawQuad* quad) {
switch (quad->material) {
case DrawQuad::Material::kTextureContent:
@@ -223,6 +296,7 @@ bool OverlayCandidate::IsOccludedByFilteredQuad(
// static
bool OverlayCandidate::FromDrawQuadResource(
DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const DrawQuad* quad,
ResourceId resource_id,
bool y_flipped,
@@ -247,15 +321,19 @@ bool OverlayCandidate::FromDrawQuadResource(
candidate->clip_rect = quad->shared_quad_state->clip_rect;
candidate->is_clipped = quad->shared_quad_state->is_clipped;
candidate->is_opaque = !quad->ShouldDrawWithBlending();
- if (quad->shared_quad_state->occluding_damage_rect.has_value()) {
- candidate->no_occluding_damage =
- quad->shared_quad_state->occluding_damage_rect->IsEmpty();
- }
-
+ candidate->no_occluding_damage =
+ !HasOccludingDamage(quad->shared_quad_state, surface_damage_rect_list);
+ // For underlays the function 'EstimateVisibleDamage()' is called to update
+ // |damage_area_estimate| to more accurately reflect the actual visible
+ // damage.
+ candidate->damage_area_estimate =
+ GetDamageRect(quad->shared_quad_state, surface_damage_rect_list)
+ .size()
+ .GetArea();
candidate->resource_id = resource_id;
candidate->transform = overlay_transform;
candidate->mailbox = resource_provider->GetMailbox(resource_id);
-
+ candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
return true;
}
@@ -264,6 +342,7 @@ bool OverlayCandidate::FromDrawQuadResource(
// and put it in the |candidate|.
bool OverlayCandidate::FromVideoHoleQuad(
DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const VideoHoleDrawQuad* quad,
OverlayCandidate* candidate) {
gfx::OverlayTransform overlay_transform = GetOverlayTransform(
@@ -275,25 +354,33 @@ bool OverlayCandidate::FromVideoHoleQuad(
candidate->display_rect = gfx::RectF(quad->rect);
transform.TransformRect(&candidate->display_rect);
candidate->transform = overlay_transform;
- if (quad->shared_quad_state->occluding_damage_rect.has_value()) {
- candidate->no_occluding_damage =
- quad->shared_quad_state->occluding_damage_rect->IsEmpty();
- }
-
+ candidate->no_occluding_damage =
+ !HasOccludingDamage(quad->shared_quad_state, surface_damage_rect_list);
+ // For underlays the function 'EstimateVisibleDamage()' is called to update
+ // |damage_area_estimate| to more accurately reflect the actual visible
+ // damage.
+ candidate->damage_area_estimate =
+ GetDamageRect(quad->shared_quad_state, surface_damage_rect_list)
+ .size()
+ .GetArea();
+ candidate->requires_overlay = OverlayCandidate::RequiresOverlay(quad);
return true;
}
// static
bool OverlayCandidate::FromTextureQuad(
DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const TextureDrawQuad* quad,
OverlayCandidate* candidate) {
+ if (quad->nearest_neighbor)
+ return false;
if (quad->background_color != SK_ColorTRANSPARENT &&
(quad->background_color != SK_ColorBLACK ||
quad->ShouldDrawWithBlending()))
return false;
- if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(),
- quad->y_flipped, candidate)) {
+ if (!FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
+ quad->resource_id(), quad->y_flipped, candidate)) {
return false;
}
candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
@@ -304,10 +391,11 @@ bool OverlayCandidate::FromTextureQuad(
// static
bool OverlayCandidate::FromStreamVideoQuad(
DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const StreamVideoDrawQuad* quad,
OverlayCandidate* candidate) {
- if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), false,
- candidate)) {
+ if (!FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
+ quad->resource_id(), false, candidate)) {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_candidate.h b/chromium/components/viz/service/display/overlay_candidate.h
index 801178b954e..79b10d445a1 100644
--- a/chromium/components/viz/service/display/overlay_candidate.h
+++ b/chromium/components/viz/service/display/overlay_candidate.h
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/buffer_types.h"
@@ -36,6 +37,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Returns true and fills in |candidate| if |draw_quad| is of a known quad
// type and contains an overlayable resource.
static bool FromDrawQuad(DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const SkMatrix44& output_color_matrix,
const DrawQuad* quad,
OverlayCandidate* candidate);
@@ -49,6 +51,17 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
QuadList::ConstIterator quad_list_begin,
QuadList::ConstIterator quad_list_end);
+ // Returns an estimate of this |quad|'s actual visible damage area. This
+ // visible damage is computed by combining from input
+ // |surface_damage_rect_list| with the occluding rects in the quad_list.
+ // This is an estimate since the occluded damage area is calculated on a per
+ // quad basis.
+ static int EstimateVisibleDamage(
+ const DrawQuad* quad,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end);
+
// Returns true if any of the quads in the list given by |quad_list_begin|
// and |quad_list_end| have a filter associated and occlude |candidate|.
static bool IsOccludedByFilteredQuad(
@@ -106,7 +119,8 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Stacking order of the overlay plane relative to the main surface,
// which is 0. Signed to allow for "underlays".
- int plane_z_order;
+ int plane_z_order = 0;
+
// True if the overlay does not have any visible quads on top of it. Set by
// the strategy so the OverlayProcessor can consider subtracting damage caused
// by underlay quads.
@@ -119,19 +133,32 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Gpu fence to wait for before overlay is ready for display.
unsigned gpu_fence_id;
+ // The total area in square pixels of damage for this candidate's quad. This
+ // is an estimate when 'EstimateOccludedDamage' function is used.
+ int damage_area_estimate = 0;
+
+ // Cached result of call to 'RequiresOverlay' function.
+ bool requires_overlay = false;
+
private:
- static bool FromDrawQuadResource(DisplayResourceProvider* resource_provider,
- const DrawQuad* quad,
- ResourceId resource_id,
- bool y_flipped,
- OverlayCandidate* candidate);
+ static bool FromDrawQuadResource(
+ DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const DrawQuad* quad,
+ ResourceId resource_id,
+ bool y_flipped,
+ OverlayCandidate* candidate);
static bool FromTextureQuad(DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const TextureDrawQuad* quad,
OverlayCandidate* candidate);
- static bool FromStreamVideoQuad(DisplayResourceProvider* resource_provider,
- const StreamVideoDrawQuad* quad,
- OverlayCandidate* candidate);
+ static bool FromStreamVideoQuad(
+ DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const StreamVideoDrawQuad* quad,
+ OverlayCandidate* candidate);
static bool FromVideoHoleQuad(DisplayResourceProvider* resource_provider,
+ SurfaceDamageRectList* surface_damage_rect_list,
const VideoHoleDrawQuad* quad,
OverlayCandidate* candidate);
};
diff --git a/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.cc b/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.cc
new file mode 100644
index 00000000000..9e5328e65d4
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.cc
@@ -0,0 +1,133 @@
+// Copyright 2020 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/viz/service/display/overlay_candidate_temporal_tracker.h"
+
+namespace viz {
+
+void OverlayCandidateTemporalTracker::Reset() {
+ fps_category = kFrameRateLow;
+ damage_category = kDamageLow;
+ for (int i = 0; i < kNumRecords; i++) {
+ damage_record[i] = 0.0f;
+ tick_record[i] = base::TimeTicks();
+ }
+}
+
+void OverlayCandidateTemporalTracker::CategorizeDamageRatio(
+ const OverlayCandidateTemporalTracker::Config& config) {
+ // This function uses member state to provide a hysteresis effect.
+ if (damage_category == DamageCategory::kDamageHigh) {
+ if (MeanDamageAreaRatio() < config.damage_low_threshold) {
+ damage_category = DamageCategory::kDamageLow;
+ }
+ } else {
+ if (MeanDamageAreaRatio() > config.damage_high_threshold) {
+ damage_category = DamageCategory::kDamageHigh;
+ }
+ }
+}
+
+void OverlayCandidateTemporalTracker::CategorizeFrameRate(
+ base::TimeTicks curr_tick) {
+ // This function uses member state to provide a hysteresis effect.
+ static constexpr int64_t kEpsilonMs = 2;
+ static constexpr int64_t k60FPSMs = 16;
+ static constexpr int64_t k30FPSMs = 33;
+ static constexpr int64_t k15FPSMs = 66;
+ // Visual depiction of the hysteresis of this function:
+ // * - Go into kFrameRateLow state.
+ // # - Go into kFrameRate30fps state.
+ // & - Go into kFrameRate60fps state.
+ //
+ // Current fps_category:
+ //
+ // kFrameRateLow --&&&&&&&&#################********
+ // kFrameRate30fps --&&&&&&&&####################*****
+ // kFrameRate60fps --&&&&&&&&&&&&&&&&&&&&&&######*****
+ // mean_frame_time |^^^^^^^^^|^^^^^^^^^|^^^ ... ^^^|
+ // 10 20 30 60
+ //
+ auto mean_frame_time = MeanFrameMs();
+ if (fps_category == FrameRateCategory::kFrameRate60fps) {
+ if (mean_frame_time > (k15FPSMs - kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRateLow;
+ } else if (mean_frame_time > (k30FPSMs - kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRate30fps;
+ }
+ } else if (fps_category == FrameRateCategory::kFrameRate30fps) {
+ if (mean_frame_time < (k60FPSMs + kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRate60fps;
+ } else if (mean_frame_time > (k15FPSMs - kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRateLow;
+ }
+ } else {
+ if (mean_frame_time < (k60FPSMs + kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRate60fps;
+ } else if (mean_frame_time < (k30FPSMs + kEpsilonMs)) {
+ fps_category = FrameRateCategory::kFrameRate30fps;
+ }
+ }
+}
+
+bool OverlayCandidateTemporalTracker::IsActivelyChanging(
+ base::TimeTicks curr_tick,
+ const OverlayCandidateTemporalTracker::Config& config) {
+ return LastChangeMs(curr_tick) < config.max_ms_active;
+}
+
+void OverlayCandidateTemporalTracker::AddRecord(
+ base::TimeTicks curr_tick,
+ float damage_area_ratio,
+ unsigned resource_id,
+ const OverlayCandidateTemporalTracker::Config& config) {
+ if (prev_resource_id != resource_id &&
+ tick_record[(next_index + kNumRecords - 1) % kNumRecords] != curr_tick) {
+ tick_record[next_index] = curr_tick;
+ damage_record[next_index] = damage_area_ratio;
+ next_index = (next_index + 1) % kNumRecords;
+ prev_resource_id = resource_id;
+
+ CategorizeFrameRate(curr_tick);
+ CategorizeDamageRatio(config);
+ }
+ absent = false;
+}
+
+float OverlayCandidateTemporalTracker::MeanDamageAreaRatio() const {
+ float sum = 0.0f;
+ for (auto& damage : damage_record) {
+ sum += damage;
+ }
+ return sum / kNumRecords;
+}
+
+int64_t OverlayCandidateTemporalTracker::LastChangeMs(
+ base::TimeTicks curr_tick) const {
+ int64_t diff_now_prev =
+ (curr_tick - tick_record[((next_index - 1) + kNumRecords) % kNumRecords])
+ .InMilliseconds();
+
+ return diff_now_prev;
+}
+
+int64_t OverlayCandidateTemporalTracker::MeanFrameMs() const {
+ int64_t mean_time = 0;
+ for (int i = 0; i < kNumRecords; i++) {
+ if (i != next_index) {
+ mean_time +=
+ (tick_record[i] - tick_record[((i - 1) + kNumRecords) % kNumRecords])
+ .InMilliseconds();
+ }
+ }
+ return mean_time / (kNumRecords - 1);
+}
+
+bool OverlayCandidateTemporalTracker::IsAbsent() {
+ bool ret = absent;
+ absent = true;
+ return ret;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.h b/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.h
new file mode 100644
index 00000000000..6da011ea915
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_candidate_temporal_tracker.h
@@ -0,0 +1,99 @@
+// Copyright 2020 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_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_TEMPORAL_TRACKER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_TEMPORAL_TRACKER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+// Overlay selection is extremely important for optimal power and performance.
+// The |OverlayCandidateTemporalTracker| class provides a way to temporally
+// track overlay candidate properties and to categorize them. This tracker
+// operates on highly opaque input; it only understands resource id (changes)
+// and damage ratios. The hysteresis in categorization is intentional and its
+// purpose is to temporally stabilize the result.
+class VIZ_SERVICE_EXPORT OverlayCandidateTemporalTracker {
+ public:
+ // The |Config| contains values that are derived as part of a heuristic. This
+ // |Config| allows for the potential of platform specific variations or
+ // experiments.
+ class VIZ_SERVICE_EXPORT Config {
+ public:
+ // Mean damage above |kDamageHighThreshold| is considered significant. An
+ // example of this is a youtube video.
+ float damage_high_threshold = 0.3f;
+ // Mean damage below |kDamageLowThreshold| is considered insignificant. An
+ // example of this is a blinking cursor.
+ float damage_low_threshold = 0.1f;
+
+ // |sMaxMsActive| is a millisecond the cutoff for when an unchanging
+ // candidate is considered to be inactive. see 'IsActivelyChanging()'
+ int64_t max_ms_active = 100;
+ };
+
+ enum FrameRateCategory { kFrameRate60fps, kFrameRate30fps, kFrameRateLow };
+ enum DamageCategory { kDamageHigh, kDamageLow };
+
+ // This function returns true when the time since the |resource_id| changed
+ // exceeds a specific threshold.
+ bool IsActivelyChanging(base::TimeTicks curr_tick, const Config& config);
+
+ // This function adds a new record to the tracker if the |resource_id| has
+ // changed since last update.
+ void AddRecord(base::TimeTicks curr_tick,
+ float damage_area_ratio,
+ unsigned resource_id,
+ const Config& config);
+
+ // This function returns true when this tracker's 'AddRecord' was not called
+ // in the previous frame. We require this behavior in order to know when an
+ // overlay candidate is no longer present since we are tracking across frames.
+ bool IsAbsent();
+
+ void Reset();
+
+ FrameRateCategory GetFPSCategory() const { return fps_category; }
+ bool HasSignificantDamage() { return damage_category == kDamageHigh; }
+
+ // The functions and data below are used internally but also can be used for
+ // diagnosis and testing.
+ int64_t MeanFrameMs() const;
+ float MeanDamageAreaRatio() const;
+ int64_t LastChangeMs(base::TimeTicks curr_tick) const;
+
+ // Categorization can happen over a series of |KNumRecords| frames.
+ // The more records the smoother the categorization but the worse the latency.
+ static constexpr int kNumRecords = 6;
+
+ private:
+ void CategorizeFrameRate(base::TimeTicks curr_tick);
+ void CategorizeDamageRatio(const Config& config);
+
+ unsigned prev_resource_id = kInvalidResourceId;
+ FrameRateCategory fps_category = kFrameRateLow;
+ DamageCategory damage_category = kDamageLow;
+ // Next empty slot index
+ int next_index = 0;
+
+ // The state of this absent bool is as follows:
+ // In the normal flow 'IsAbsent()' is tested which sets |absent| = true. Then
+ // the 'AddRecord() sets it false again in the same frame.
+ // When this tracker no longer corresponds to an overlay candidate the
+ // 'IsAbsent()' is tested which sets |absent| = true but on the next frame
+ // 'IsAbsent()' returns true because |absent| was never reset to false. This
+ // indicating this tracker should be removed.
+ bool absent = false;
+ base::TimeTicks tick_record[kNumRecords] = {};
+ float damage_record[kNumRecords] = {};
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_TEMPORAL_TRACKER_H_
diff --git a/chromium/components/viz/service/display/overlay_dc_unittest.cc b/chromium/components/viz/service/display/overlay_dc_unittest.cc
index c466c784235..209c350473f 100644
--- a/chromium/components/viz/service/display/overlay_dc_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_dc_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
@@ -86,11 +86,6 @@ class OverlayOutputSurface : public OutputSurface {
gfx::OverlayTransform GetDisplayTransform() override {
return gfx::OVERLAY_TRANSFORM_NONE;
}
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override {
- return nullptr;
- }
- gpu::MemoryTracker* GetMemoryTracker() override { return nullptr; }
unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
@@ -101,10 +96,11 @@ class OverlayOutputSurface : public OutputSurface {
class DCTestOverlayProcessor : public OverlayProcessorWin {
public:
explicit DCTestOverlayProcessor(OutputSurface* output_surface)
- : OverlayProcessorWin(
- output_surface,
- std::make_unique<DCLayerOverlayProcessor>(&debug_settings_, true)) {
- }
+ : OverlayProcessorWin(output_surface,
+ std::make_unique<DCLayerOverlayProcessor>(
+ &debug_settings_,
+ /*allowed_yuv_overlay_count=*/1,
+ true)) {}
DebugRendererSettings debug_settings_;
};
@@ -210,6 +206,19 @@ YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad(
return overlay_quad;
}
+AggregatedRenderPassDrawQuad* CreateRenderPassDrawQuadAt(
+ AggregatedRenderPass* render_pass,
+ const SharedQuadState* shared_quad_state,
+ const gfx::Rect& rect,
+ AggregatedRenderPassId render_pass_id) {
+ AggregatedRenderPassDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
+ quad->SetNew(shared_quad_state, rect, rect, render_pass_id, 2, gfx::RectF(),
+ gfx::Size(), gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF(),
+ false, 1.f);
+ return quad;
+}
+
SkMatrix44 GetIdentityColorMatrix() {
return SkMatrix44(SkMatrix44::kIdentity_Constructor);
}
@@ -234,6 +243,7 @@ class DCLayerOverlayTest : public testing::Test {
overlay_processor_ =
std::make_unique<DCTestOverlayProcessor>(output_surface_.get());
overlay_processor_->set_using_dc_layers_for_testing(true);
+ overlay_processor_->SetViewportSize(gfx::Size(256, 256));
EXPECT_TRUE(overlay_processor_->IsOverlaySupported());
}
@@ -261,15 +271,17 @@ class DCLayerOverlayTest : public testing::Test {
};
TEST_F(DCLayerOverlayTest, Occluded) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
{
auto pass = CreateRenderPass();
SharedQuadState* first_shared_state = pass->shared_quad_state_list.back();
- first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
+ first_shared_state->overlay_damage_index = 0;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 3, 100, 100), SK_ColorWHITE);
+
+ SharedQuadState* second_shared_state =
+ pass->CreateAndAppendSharedQuadState();
+ second_shared_state->overlay_damage_index = 1;
auto* first_video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -277,9 +289,9 @@ TEST_F(DCLayerOverlayTest, Occluded) {
first_video_quad->protected_video_type =
gfx::ProtectedVideoType::kHardwareProtected;
- SharedQuadState* second_shared_state =
+ SharedQuadState* third_shared_state =
pass->CreateAndAppendSharedQuadState();
- second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
+ third_shared_state->overlay_damage_index = 2;
auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -295,10 +307,14 @@ TEST_F(DCLayerOverlayTest, Occluded) {
damage_rect_ = gfx::Rect(1, 1, 10, 10);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {
+ gfx::Rect(1, 1, 10, 10), gfx::Rect(0, 0, 0, 0), gfx::Rect(0, 0, 0, 0)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(2U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -310,10 +326,14 @@ TEST_F(DCLayerOverlayTest, Occluded) {
{
auto pass = CreateRenderPass();
SharedQuadState* first_shared_state = pass->shared_quad_state_list.back();
- first_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
+ first_shared_state->overlay_damage_index = 0;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(3, 3, 100, 100), SK_ColorWHITE);
+
+ SharedQuadState* second_shared_state =
+ pass->CreateAndAppendSharedQuadState();
+ second_shared_state->overlay_damage_index = 1;
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -321,9 +341,9 @@ TEST_F(DCLayerOverlayTest, Occluded) {
video_quad->protected_video_type =
gfx::ProtectedVideoType::kHardwareProtected;
- SharedQuadState* second_shared_state =
+ SharedQuadState* third_shared_state =
pass->CreateAndAppendSharedQuadState();
- second_shared_state->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
+ third_shared_state->overlay_damage_index = 2;
auto* second_video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -338,10 +358,14 @@ TEST_F(DCLayerOverlayTest, Occluded) {
damage_rect_ = gfx::Rect(1, 1, 10, 10);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {
+ gfx::Rect(1, 1, 10, 10), gfx::Rect(0, 0, 0, 0), gfx::Rect(0, 0, 0, 0)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(2U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -353,19 +377,23 @@ TEST_F(DCLayerOverlayTest, Occluded) {
// This is calculated by carving out the underlay rect size from the
// damage_rect, adding back the quads on top and then the overlay/underlay
- // rects from the previous frame. The damage rect carried over from the
- // revious frame with multiple overlays cannot be skipped.
- EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
+ // rects from the previous frame. The damage rect carried over from the
+ // previous frame with multiple overlays cannot be skipped if
+ // kDirectCompositionUseOverlayDamageList is disabled.
+ if (base::FeatureList::IsEnabled(
+ features::kDirectCompositionUseOverlayDamageList)) {
+ EXPECT_EQ(gfx::Rect(1, 1, 10, 10), damage_rect_);
+ } else {
+ EXPECT_EQ(gfx::Rect(0, 0, 256, 256), damage_rect_);
+ }
}
}
TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
{
auto pass = CreateRenderPass();
SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back();
- shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20);
+ shared_quad_state->overlay_damage_index = 0;
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
@@ -374,7 +402,11 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
+
// Underlay video quad
+ SharedQuadState* second_shared_state =
+ pass->CreateAndAppendSharedQuadState();
+ second_shared_state->overlay_damage_index = 1;
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -388,10 +420,14 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
damage_rect_ = gfx::Rect(210, 210, 20, 20);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {
+ gfx::Rect(210, 210, 20, 20), gfx::Rect(0, 0, 0, 0)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
@@ -401,7 +437,7 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
{
auto pass = CreateRenderPass();
SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back();
- shared_quad_state->occluding_damage_rect = gfx::Rect(210, 210, 20, 20);
+ shared_quad_state->overlay_damage_index = 0;
// Occluding quad fully contained in video rect.
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
@@ -410,7 +446,11 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(210, 210, 20, 20), SK_ColorWHITE);
+
// Underlay video quad
+ SharedQuadState* second_shared_state =
+ pass->CreateAndAppendSharedQuadState();
+ second_shared_state->overlay_damage_index = 1;
auto* video_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -424,10 +464,14 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
damage_rect_ = gfx::Rect(210, 210, 20, 20);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {
+ gfx::Rect(210, 210, 20, 20), gfx::Rect(0, 0, 0, 0)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
@@ -439,22 +483,25 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
TEST_F(DCLayerOverlayTest, DamageRect) {
for (int i = 0; i < 2; i++) {
auto pass = CreateRenderPass();
+ SharedQuadState* shared_quad_state = pass->shared_quad_state_list.back();
+ shared_quad_state->overlay_damage_index = 0;
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
- gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {gfx::Rect(1, 1, 10, 10)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(1, dc_layer_list.back().z_order);
@@ -469,21 +516,21 @@ TEST_F(DCLayerOverlayTest, DamageRect) {
}
TEST_F(DCLayerOverlayTest, ClipRect) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
-
// Process twice. The second time through the overlay list shouldn't change,
// which will allow the damage rect to reflect just the changes in that
// frame.
for (size_t i = 0; i < 2; ++i) {
auto pass = CreateRenderPass();
+ pass->shared_quad_state_list.back()->overlay_damage_index = 0;
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 2, 100, 100), SK_ColorWHITE);
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 3, 100, 100);
+
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
+ shared_state->overlay_damage_index = 1;
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), shared_state, pass.get());
@@ -497,10 +544,14 @@ TEST_F(DCLayerOverlayTest, ClipRect) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
damage_rect_ = gfx::Rect(1, 1, 10, 10);
+ SurfaceDamageRectList surface_damage_rect_list = {gfx::Rect(1, 3, 10, 8),
+ gfx::Rect(1, 1, 10, 2)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
// Because of clip rects the overlay isn't occluded and shouldn't be an
// underlay.
@@ -521,6 +572,7 @@ TEST_F(DCLayerOverlayTest, TransparentOnTop) {
// frame.
for (size_t i = 0; i < 2; ++i) {
auto pass = CreateRenderPass();
+ pass->shared_quad_state_list.back()->overlay_damage_index = 0;
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
@@ -532,10 +584,13 @@ TEST_F(DCLayerOverlayTest, TransparentOnTop) {
damage_rect_ = gfx::Rect(1, 1, 10, 10);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list = {gfx::Rect(1, 1, 10, 10)};
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(1, dc_layer_list.back().z_order);
// Quad isn't opaque, so underlying damage must remain the same.
@@ -544,9 +599,6 @@ TEST_F(DCLayerOverlayTest, TransparentOnTop) {
}
TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
-
for (int i = 0; i < 3; i++) {
auto pass = CreateRenderPass();
// Add a solid color quad on top
@@ -566,17 +618,20 @@ TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
gfx::Rect damage_rect_ = kOverlayRect;
+ shared_state->overlay_damage_index = 1;
// The quad on top does not give damage on the third frame
- if (i == 2)
- shared_state->occluding_damage_rect = gfx::Rect();
- else
- shared_state->occluding_damage_rect = kOverlayBottomRightRect;
+ SurfaceDamageRectList surface_damage_rect_list = {kOverlayBottomRightRect,
+ kOverlayRect};
+ if (i == 2) {
+ surface_damage_rect_list[0] = gfx::Rect();
+ }
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
@@ -622,11 +677,13 @@ TEST_F(DCLayerOverlayTest, MultipleYUVOverlay) {
damage_rect_ = gfx::Rect(0, 0, 220, 220);
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
// Skip overlays.
EXPECT_EQ(0U, dc_layer_list.size());
@@ -658,6 +715,7 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
DCLayerOverlayList dc_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ SurfaceDamageRectList surface_damage_rect_list;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
// There will be full damage and SetEnableDCLayers(true) will be called on
@@ -672,8 +730,9 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -698,6 +757,7 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -715,8 +775,9 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &dc_layer_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0u, dc_layer_list.size());
EXPECT_EQ(0u, output_surface_->bind_framebuffer_count());
@@ -726,5 +787,147 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
}
}
+// Test that the video is forced to underlay if the expanded quad of pixel
+// moving foreground filter is on top.
+TEST_F(DCLayerOverlayTest, PixelMovingForegroundFilter) {
+ AggregatedRenderPassList pass_list;
+
+ // Create a non-root render pass with a pixel-moving foreground filter.
+ AggregatedRenderPassId filter_render_pass_id{2};
+ gfx::Rect filter_rect = gfx::Rect(260, 260, 100, 100);
+ cc::FilterOperations blur_filter;
+ blur_filter.Append(cc::FilterOperation::CreateBlurFilter(10.f));
+ auto filter_pass = std::make_unique<AggregatedRenderPass>();
+ filter_pass->SetNew(filter_render_pass_id, filter_rect, filter_rect,
+ gfx::Transform());
+ filter_pass->filters = blur_filter;
+
+ // Add a solid quad to the non-root pass.
+ SharedQuadState* shared_state_filter =
+ filter_pass->CreateAndAppendSharedQuadState();
+ CreateSolidColorQuadAt(shared_state_filter, SK_ColorRED, filter_pass.get(),
+ filter_rect);
+ shared_state_filter->opacity = 1.f;
+ pass_list.push_back(std::move(filter_pass));
+
+ // Create a root render pass.
+ auto pass = CreateRenderPass();
+ // Add a RenderPassDrawQuad to the root render pass.
+ SharedQuadState* shared_quad_state_rpdq = pass->shared_quad_state_list.back();
+ // The pixel-moving render pass draw quad itself (rpdq->rect) doesn't
+ // intersect with kOverlayRect(0, 0, 256, 256), but the expanded draw quad
+ // (rpdq->rect(260, 260, 100, 100) + MaximumPixelMovement (2 * 10.f) = (240,
+ // 240, 140, 140)) does.
+
+ CreateRenderPassDrawQuadAt(pass.get(), shared_quad_state_rpdq, filter_rect,
+ filter_render_pass_id);
+
+ // Add a video quad to the root render pass.
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 1.f;
+ CreateFullscreenCandidateYUVVideoQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), shared_state, pass.get());
+ // Make the root render pass output rect bigger enough to cover the video
+ // quad kOverlayRect(0, 0, 256, 256) and the render pass draw quad (260, 260,
+ // 100, 100).
+ pass->output_rect = gfx::Rect(0, 0, 512, 512);
+
+ DCLayerOverlayList dc_layer_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ render_pass_filters[filter_render_pass_id] = &blur_filter;
+
+ pass_list.push_back(std::move(pass));
+ // filter_rect + kOverlayRect. Both are damaged.
+ gfx::Rect damage_rect_ = gfx::Rect(0, 0, 360, 360);
+ shared_state->overlay_damage_index = 1;
+
+ SurfaceDamageRectList surface_damage_rect_list = {filter_rect, kOverlayRect};
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
+
+ EXPECT_EQ(1U, dc_layer_list.size());
+ // Make sure the video is in an underlay mode if the overlay quad intersects
+ // with (rpdq->rect + MaximumPixelMovement()).
+ EXPECT_EQ(-1, dc_layer_list.back().z_order);
+ EXPECT_EQ(gfx::Rect(0, 0, 360, 360), damage_rect_);
+}
+
+// Test that the video is not promoted if a quad on top has backdrop filters.
+TEST_F(DCLayerOverlayTest, BackdropFilter) {
+ AggregatedRenderPassList pass_list;
+
+ // Create a non-root render pass with a backdrop filter.
+ AggregatedRenderPassId backdrop_filter_render_pass_id{2};
+ gfx::Rect backdrop_filter_rect = gfx::Rect(200, 200, 100, 100);
+ cc::FilterOperations backdrop_filter;
+ backdrop_filter.Append(cc::FilterOperation::CreateBlurFilter(10.f));
+ auto backdrop_filter_pass = std::make_unique<AggregatedRenderPass>();
+ backdrop_filter_pass->SetNew(backdrop_filter_render_pass_id,
+ backdrop_filter_rect, backdrop_filter_rect,
+ gfx::Transform());
+ backdrop_filter_pass->backdrop_filters = backdrop_filter;
+
+ // Add a transparent solid quad to the non-root pass.
+ SharedQuadState* shared_state_backdrop_filter =
+ backdrop_filter_pass->CreateAndAppendSharedQuadState();
+ CreateSolidColorQuadAt(shared_state_backdrop_filter, SK_ColorGREEN,
+ backdrop_filter_pass.get(), backdrop_filter_rect);
+ shared_state_backdrop_filter->opacity = 0.1f;
+ pass_list.push_back(std::move(backdrop_filter_pass));
+
+ // Create a root render pass.
+ auto pass = CreateRenderPass();
+ // Add a RenderPassDrawQuad to the root render pass, on top of the video.
+ SharedQuadState* shared_quad_state_rpdq = pass->shared_quad_state_list.back();
+ shared_quad_state_rpdq->opacity = 0.1f;
+ // The render pass draw quad rpdq->rect intersects with the overlay quad
+ // kOverlayRect(0, 0, 256, 256).
+ CreateRenderPassDrawQuadAt(pass.get(), shared_quad_state_rpdq,
+ backdrop_filter_rect,
+ backdrop_filter_render_pass_id);
+
+ // Add a video quad to the root render pass.
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 1.f;
+ CreateFullscreenCandidateYUVVideoQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), shared_state, pass.get());
+ // Make the root render pass output rect bigger enough to cover the video
+ // quad kOverlayRect(0, 0, 256, 256) and the render pass draw quad (200, 200,
+ // 100, 100).
+ pass->output_rect = gfx::Rect(0, 0, 512, 512);
+
+ DCLayerOverlayList dc_layer_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ render_pass_backdrop_filters[backdrop_filter_render_pass_id] =
+ &backdrop_filter;
+
+ pass_list.push_back(std::move(pass));
+ // backdrop_filter_rect + kOverlayRect. Both are damaged.
+ gfx::Rect damage_rect_ = gfx::Rect(0, 0, 300, 300);
+ shared_state->overlay_damage_index = 1;
+
+ SurfaceDamageRectList surface_damage_rect_list = {backdrop_filter_rect,
+ kOverlayRect};
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_,
+ &content_bounds_);
+
+ // Make sure the video is not promoted if the overlay quad intersects
+ // with the backdrop filter rpdq->rect.
+ EXPECT_EQ(0U, dc_layer_list.size());
+ EXPECT_EQ(gfx::Rect(0, 0, 300, 300), damage_rect_);
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_android.cc b/chromium/components/viz/service/display/overlay_processor_android.cc
index 44892039793..cdf4ebc8315 100644
--- a/chromium/components/viz/service/display/overlay_processor_android.cc
+++ b/chromium/components/viz/service/display/overlay_processor_android.cc
@@ -4,8 +4,13 @@
#include "components/viz/service/display/overlay_processor_android.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
#include "base/synchronization/waitable_event.h"
#include "components/viz/common/quads/stream_video_draw_quad.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/display/overlay_processor_on_gpu.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/service/display/skia_output_surface.h"
@@ -14,16 +19,9 @@
namespace viz {
OverlayProcessorAndroid::OverlayProcessorAndroid(
- gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker,
- scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler,
- bool enable_overlay)
+ DisplayCompositorMemoryAndTaskController* display_controller)
: OverlayProcessorUsingStrategy(),
- gpu_task_scheduler_(std::move(gpu_task_scheduler)),
- overlay_enabled_(enable_overlay) {
- if (!overlay_enabled_)
- return;
-
+ gpu_task_scheduler_(display_controller->gpu_task_scheduler()) {
// In unittests, we don't have the gpu_task_scheduler_ set up, but still want
// to test ProcessForOverlays functionalities where we are making overlay
// candidates correctly.
@@ -35,7 +33,8 @@ OverlayProcessorAndroid::OverlayProcessorAndroid(
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto callback = base::BindOnce(
&OverlayProcessorAndroid::InitializeOverlayProcessorOnGpu,
- base::Unretained(this), shared_image_manager, memory_tracker, &event);
+ base::Unretained(this), display_controller->controller_on_gpu(),
+ &event);
gpu_task_scheduler_->ScheduleGpuTask(std::move(callback), {});
event.Wait();
}
@@ -69,11 +68,11 @@ OverlayProcessorAndroid::~OverlayProcessorAndroid() {
}
void OverlayProcessorAndroid::InitializeOverlayProcessorOnGpu(
- gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
+ display_controller_on_gpu,
base::WaitableEvent* event) {
- processor_on_gpu_ = std::make_unique<OverlayProcessorOnGpu>(
- shared_image_manager, memory_tracker);
+ processor_on_gpu_ =
+ std::make_unique<OverlayProcessorOnGpu>(display_controller_on_gpu);
DCHECK(event);
event->Signal();
}
@@ -86,10 +85,10 @@ void OverlayProcessorAndroid::DestroyOverlayProcessorOnGpu(
}
bool OverlayProcessorAndroid::IsOverlaySupported() const {
- return overlay_enabled_;
+ return true;
}
-bool OverlayProcessorAndroid::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorAndroid::NeedsSurfaceDamageRectList() const {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_android.h b/chromium/components/viz/service/display/overlay_processor_android.h
index ac5b63d7f43..461b890fbca 100644
--- a/chromium/components/viz/service/display/overlay_processor_android.h
+++ b/chromium/components/viz/service/display/overlay_processor_android.h
@@ -5,6 +5,10 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_ANDROID_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_ANDROID_H_
+#include <map>
+#include <memory>
+#include <vector>
+
#include "base/containers/circular_deque.h"
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
@@ -13,6 +17,10 @@ namespace base {
class WaitableEvent;
}
+namespace gpu {
+class DisplayCompositorMemoryAndTaskControllerOnGpu;
+}
+
namespace viz {
class OverlayProcessorOnGpu;
@@ -28,16 +36,13 @@ class OverlayProcessorOnGpu;
class VIZ_SERVICE_EXPORT OverlayProcessorAndroid
: public OverlayProcessorUsingStrategy {
public:
- OverlayProcessorAndroid(
- gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker,
- scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler,
- bool enable_overlay);
+ explicit OverlayProcessorAndroid(
+ DisplayCompositorMemoryAndTaskController* display_controller);
~OverlayProcessorAndroid() override;
bool IsOverlaySupported() const override;
- bool NeedsSurfaceOccludingDamageRect() const override;
+ bool NeedsSurfaceDamageRectList() const override;
void ScheduleOverlays(
DisplayResourceProvider* display_resource_provider) override;
@@ -58,8 +63,8 @@ class VIZ_SERVICE_EXPORT OverlayProcessorAndroid
// thread. These two methods are scheduled on the gpu thread to setup and
// teardown the gpu side receiver.
void InitializeOverlayProcessorOnGpu(
- gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
+ display_controller_on_gpu,
base::WaitableEvent* event);
void DestroyOverlayProcessorOnGpu(base::WaitableEvent* event);
void TakeOverlayCandidates(CandidateList* candidate_list) override;
@@ -75,8 +80,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorAndroid
// overlay, if one backs them with a SurfaceView.
PromotionHintInfoMap promotion_hint_info_map_;
- scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_;
- const bool overlay_enabled_;
+ gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_;
// This class is created, accessed, and destroyed on the gpu thread.
std::unique_ptr<OverlayProcessorOnGpu> processor_on_gpu_;
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.cc b/chromium/components/viz/service/display/overlay_processor_interface.cc
index 659dfb77ed5..dd3fddf5d78 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.cc
+++ b/chromium/components/viz/service/display/overlay_processor_interface.cc
@@ -5,11 +5,13 @@
#include "components/viz/service/display/overlay_processor_interface.h"
#include <utility>
+#include <vector>
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/features.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/display/overlay_processor_stub.h"
#if defined(OS_APPLE)
@@ -33,7 +35,7 @@ namespace {
enum class UnderlayDamage {
kZeroDamageRect,
kNonOccludingDamageOnly,
- kOccludingDamageOnly,
+ kOccludingDamageOnly, // deprecated
kOccludingAndNonOccludingDamages,
kMaxValue = kOccludingAndNonOccludingDamages,
};
@@ -51,8 +53,7 @@ enum class UnderlayDamage {
void OverlayProcessorInterface::RecordOverlayDamageRectHistograms(
bool is_overlay,
bool has_occluding_surface_damage,
- bool zero_damage_rect,
- bool occluding_damage_equal_to_damage_rect) {
+ bool zero_damage_rect) {
if (is_overlay) {
UMA_HISTOGRAM_BOOLEAN("Viz.DisplayCompositor.RootDamageRect.Overlay",
!zero_damage_rect);
@@ -62,11 +63,7 @@ void OverlayProcessorInterface::RecordOverlayDamageRectHistograms(
underlay_damage = UnderlayDamage::kZeroDamageRect;
} else {
if (has_occluding_surface_damage) {
- if (occluding_damage_equal_to_damage_rect) {
- underlay_damage = UnderlayDamage::kOccludingDamageOnly;
- } else {
- underlay_damage = UnderlayDamage::kOccludingAndNonOccludingDamages;
- }
+ underlay_damage = UnderlayDamage::kOccludingAndNonOccludingDamages;
} else {
underlay_damage = UnderlayDamage::kNonOccludingDamageOnly;
}
@@ -79,52 +76,61 @@ void OverlayProcessorInterface::RecordOverlayDamageRectHistograms(
std::unique_ptr<OverlayProcessorInterface>
OverlayProcessorInterface::CreateOverlayProcessor(
OutputSurface* output_surface,
- gpu::SharedImageManager* shared_image_manager,
+ gpu::SurfaceHandle surface_handle,
+ const OutputSurface::Capabilities& capabilities,
+ DisplayCompositorMemoryAndTaskController* display_controller,
+ gpu::SharedImageInterface* shared_image_interface,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) {
+ // If we are offscreen, we don't have overlay support.
+ // TODO(vasilyt): WebView would have a kNullSurfaceHandle. Make sure when
+ // overlay for WebView is enabled, this check still works.
+ if (surface_handle == gpu::kNullSurfaceHandle)
+ return std::make_unique<OverlayProcessorStub>();
+
#if defined(OS_APPLE)
- bool could_overlay =
- output_surface->GetSurfaceHandle() != gpu::kNullSurfaceHandle;
- could_overlay &= output_surface->capabilities().supports_surfaceless;
- bool enable_ca_overlay = could_overlay && renderer_settings.allow_overlays;
+ DCHECK(capabilities.supports_surfaceless);
- return std::make_unique<OverlayProcessorMac>(could_overlay,
- enable_ca_overlay);
+ return std::make_unique<OverlayProcessorMac>(
+ renderer_settings.allow_overlays);
#elif defined(OS_WIN)
+ if (!capabilities.supports_dc_layers)
+ return std::make_unique<OverlayProcessorStub>();
+
return std::make_unique<OverlayProcessorWin>(
- output_surface,
- std::make_unique<DCLayerOverlayProcessor>(debug_settings));
+ output_surface, std::make_unique<DCLayerOverlayProcessor>(
+ debug_settings, /*allowed_yuv_overlay_count=*/1));
#elif defined(USE_OZONE)
if (!features::IsUsingOzonePlatform())
return std::make_unique<OverlayProcessorStub>();
- bool overlay_enabled =
- output_surface->GetSurfaceHandle() != gpu::kNullSurfaceHandle;
- overlay_enabled &= !renderer_settings.overlay_strategies.empty();
+
+ // In tests and Ozone/X11, we do not expect surfaceless surface support.
+ if (!capabilities.supports_surfaceless)
+ return std::make_unique<OverlayProcessorStub>();
+
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates;
- if (overlay_enabled) {
+ if (!renderer_settings.overlay_strategies.empty()) {
auto* overlay_manager =
ui::OzonePlatform::GetInstance()->GetOverlayManager();
- overlay_candidates = overlay_manager->CreateOverlayCandidates(
- output_surface->GetSurfaceHandle());
+ overlay_candidates =
+ overlay_manager->CreateOverlayCandidates(surface_handle);
}
- gpu::SharedImageInterface* shared_image_interface = nullptr;
- if (overlay_enabled && features::ShouldUseRealBuffersForPageFlipTest()) {
- CHECK(output_surface->context_provider());
- shared_image_interface =
- output_surface->context_provider()->SharedImageInterface();
+ gpu::SharedImageInterface* sii = nullptr;
+ if (features::ShouldUseRealBuffersForPageFlipTest()) {
+ sii = shared_image_interface;
CHECK(shared_image_interface);
}
return std::make_unique<OverlayProcessorOzone>(
- overlay_enabled, std::move(overlay_candidates),
- std::move(renderer_settings.overlay_strategies), shared_image_interface);
+ std::move(overlay_candidates),
+ std::move(renderer_settings.overlay_strategies), sii);
#elif defined(OS_ANDROID)
- bool overlay_enabled =
- output_surface->GetSurfaceHandle() != gpu::kNullSurfaceHandle;
- if (output_surface->capabilities().supports_surfaceless) {
+ DCHECK(display_controller);
+
+ if (capabilities.supports_surfaceless) {
// This is for Android SurfaceControl case.
- return std::make_unique<OverlayProcessorSurfaceControl>(overlay_enabled);
+ return std::make_unique<OverlayProcessorSurfaceControl>();
} else {
// When SurfaceControl is enabled, any resource backed by
// an AHardwareBuffer can be marked as an overlay candidate but it requires
@@ -132,11 +138,10 @@ OverlayProcessorInterface::CreateOverlayProcessor(
// native window backed GLSurface, the overlay processing code will
// incorrectly assume these resources can be overlaid. So we disable all
// overlay processing for this OutputSurface.
- overlay_enabled &=
- !output_surface->capabilities().android_surface_control_feature_enabled;
- return std::make_unique<OverlayProcessorAndroid>(
- shared_image_manager, output_surface->GetMemoryTracker(),
- output_surface->GetGpuTaskSchedulerHelper(), overlay_enabled);
+ if (capabilities.android_surface_control_feature_enabled)
+ return std::make_unique<OverlayProcessorStub>();
+
+ return std::make_unique<OverlayProcessorAndroid>(display_controller);
}
#else // Default
return std::make_unique<OverlayProcessorStub>();
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.h b/chromium/components/viz/service/display/overlay_processor_interface.h
index 81383d0f801..2c7514b5479 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.h
+++ b/chromium/components/viz/service/display/overlay_processor_interface.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
+#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/viz_service_export.h"
@@ -60,8 +61,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
static void RecordOverlayDamageRectHistograms(
bool is_overlay,
bool has_occluding_surface_damage,
- bool zero_damage_rect,
- bool occluding_damage_equal_to_damage_rect);
+ bool zero_damage_rect);
// Data needed to represent |OutputSurface| as an overlay plane. Due to the
// default values for the primary plane, this is a partial list of
@@ -99,11 +99,14 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
static std::unique_ptr<OverlayProcessorInterface> CreateOverlayProcessor(
OutputSurface* output_surface,
- gpu::SharedImageManager* shared_image_manager,
+ gpu::SurfaceHandle surface_handle,
+ const OutputSurface::Capabilities& capabilities,
+ DisplayCompositorMemoryAndTaskController* display_controller,
+ gpu::SharedImageInterface* shared_image_interface,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings);
- virtual ~OverlayProcessorInterface() {}
+ virtual ~OverlayProcessorInterface() = default;
virtual bool IsOverlaySupported() const = 0;
// Returns a bounding rectangle of the last set of overlay planes scheduled.
@@ -115,7 +118,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
// Returns true if the platform supports hw overlays and surface occluding
// damage rect needs to be computed since it will be used by overlay
// processor.
- virtual bool NeedsSurfaceOccludingDamageRect() const = 0;
+ virtual bool NeedsSurfaceDamageRectList() const = 0;
// Attempt to replace quads from the specified root render pass with overlays
// or CALayers. This must be called every frame.
@@ -125,6 +128,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* overlay_candidates,
gfx::Rect* damage_rect,
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.cc b/chromium/components/viz/service/display/overlay_processor_mac.cc
index 53e5de86c6a..222986111ec 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.cc
+++ b/chromium/components/viz/service/display/overlay_processor_mac.cc
@@ -15,17 +15,14 @@
#include "ui/gfx/geometry/rect_conversions.h"
namespace viz {
-OverlayProcessorMac::OverlayProcessorMac(bool could_overlay,
- bool enable_ca_overlay)
- : could_overlay_(could_overlay),
- enable_ca_overlay_(enable_ca_overlay),
+OverlayProcessorMac::OverlayProcessorMac(bool enable_ca_overlay)
+ : enable_ca_overlay_(enable_ca_overlay),
ca_layer_overlay_processor_(std::make_unique<CALayerOverlayProcessor>()) {
}
OverlayProcessorMac::OverlayProcessorMac(
std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor)
- : could_overlay_(true),
- enable_ca_overlay_(true),
+ : enable_ca_overlay_(true),
ca_layer_overlay_processor_(std::move(ca_layer_overlay_processor)) {}
OverlayProcessorMac::~OverlayProcessorMac() = default;
@@ -35,7 +32,7 @@ bool OverlayProcessorMac::DisableSplittingQuads() const {
}
bool OverlayProcessorMac::IsOverlaySupported() const {
- return could_overlay_;
+ return true;
}
gfx::Rect OverlayProcessorMac::GetPreviousFrameOverlaysBoundingRect() const {
@@ -59,6 +56,7 @@ void OverlayProcessorMac::ProcessForOverlays(
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* candidates,
gfx::Rect* damage_rect,
@@ -103,7 +101,7 @@ void OverlayProcessorMac::AdjustOutputSurfaceOverlay(
output_surface_plane->reset();
}
-bool OverlayProcessorMac::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorMac::NeedsSurfaceDamageRectList() const {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.h b/chromium/components/viz/service/display/overlay_processor_mac.h
index ce332361855..5afdb252071 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.h
+++ b/chromium/components/viz/service/display/overlay_processor_mac.h
@@ -27,7 +27,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
public:
using CandidateList = CALayerOverlayList;
- OverlayProcessorMac(bool could_overlay, bool enable_ca_overlay);
+ explicit OverlayProcessorMac(bool enable_ca_overlay);
// For testing.
explicit OverlayProcessorMac(
std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor);
@@ -42,7 +42,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
// Returns true if the platform supports hw overlays and surface occluding
// damage rect needs to be computed since it will be used by overlay
// processor.
- bool NeedsSurfaceOccludingDamageRect() const override;
+ bool NeedsSurfaceDamageRectList() const override;
// Attempt to replace quads from the specified root render pass with overlays
// or CALayers. This must be called every frame.
@@ -52,6 +52,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* overlay_candidates,
gfx::Rect* damage_rect,
@@ -66,7 +67,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
base::Optional<OutputSurfaceOverlayPlane>* output_surface_plane) override;
private:
- const bool could_overlay_;
const bool enable_ca_overlay_;
gfx::Rect ca_overlay_damage_rect_;
gfx::Rect previous_frame_full_bounding_rect_;
diff --git a/chromium/components/viz/service/display/overlay_processor_on_gpu.cc b/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
index 7d41dc47ba2..26ec61096fd 100644
--- a/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
+++ b/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
@@ -5,17 +5,18 @@
#include "components/viz/service/display/overlay_processor_on_gpu.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
+#include "gpu/ipc/display_compositor_memory_and_task_controller_on_gpu.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace viz {
OverlayProcessorOnGpu::OverlayProcessorOnGpu(
- gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker)
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
+ display_controller_on_gpu)
: shared_image_representation_factory_(
std::make_unique<gpu::SharedImageRepresentationFactory>(
- shared_image_manager,
- memory_tracker)) {
+ display_controller_on_gpu->shared_image_manager(),
+ display_controller_on_gpu->memory_tracker())) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
diff --git a/chromium/components/viz/service/display/overlay_processor_on_gpu.h b/chromium/components/viz/service/display/overlay_processor_on_gpu.h
index 86c3f6977ba..46d0f3457ac 100644
--- a/chromium/components/viz/service/display/overlay_processor_on_gpu.h
+++ b/chromium/components/viz/service/display/overlay_processor_on_gpu.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_ON_GPU_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_ON_GPU_H_
+#include <memory>
+
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "components/viz/service/display/overlay_candidate.h"
@@ -19,8 +21,7 @@
#endif
namespace gpu {
-class MemoryTracker;
-class SharedImageManager;
+class DisplayCompositorMemoryAndTaskControllerOnGpu;
class SharedImageRepresentationFactory;
} // namespace gpu
@@ -40,8 +41,9 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOnGpu {
using CandidateList = OverlayCandidateList;
#endif
- OverlayProcessorOnGpu(gpu::SharedImageManager* shared_image_manager,
- gpu::MemoryTracker* memory_tracker);
+ explicit OverlayProcessorOnGpu(
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu*
+ display_controller_on_gpu);
~OverlayProcessorOnGpu();
// This function takes the overlay candidates, and schedule them for
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.cc b/chromium/components/viz/service/display/overlay_processor_ozone.cc
index 9f3e7ef0679..9e7ff966ac8 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.cc
@@ -4,7 +4,12 @@
#include "components/viz/service/display/overlay_processor_ozone.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
#include "base/logging.h"
+#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
@@ -67,37 +72,32 @@ void ReportSharedImageExists(bool exists) {
// |available_strategies| is a list of overlay strategies that should be
// initialized by InitializeStrategies.
OverlayProcessorOzone::OverlayProcessorOzone(
- bool overlay_enabled,
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates,
std::vector<OverlayStrategy> available_strategies,
gpu::SharedImageInterface* shared_image_interface)
: OverlayProcessorUsingStrategy(),
- overlay_enabled_(overlay_enabled),
overlay_candidates_(std::move(overlay_candidates)),
available_strategies_(std::move(available_strategies)),
shared_image_interface_(shared_image_interface) {
- if (overlay_enabled_) {
- for (OverlayStrategy strategy : available_strategies_) {
- switch (strategy) {
- case OverlayStrategy::kFullscreen:
- strategies_.push_back(
- std::make_unique<OverlayStrategyFullscreen>(this));
- break;
- case OverlayStrategy::kSingleOnTop:
- strategies_.push_back(
- std::make_unique<OverlayStrategySingleOnTop>(this));
- break;
- case OverlayStrategy::kUnderlay:
- strategies_.push_back(
- std::make_unique<OverlayStrategyUnderlay>(this));
- break;
- case OverlayStrategy::kUnderlayCast:
- strategies_.push_back(
- std::make_unique<OverlayStrategyUnderlayCast>(this));
- break;
- default:
- NOTREACHED();
- }
+ for (OverlayStrategy strategy : available_strategies_) {
+ switch (strategy) {
+ case OverlayStrategy::kFullscreen:
+ strategies_.push_back(
+ std::make_unique<OverlayStrategyFullscreen>(this));
+ break;
+ case OverlayStrategy::kSingleOnTop:
+ strategies_.push_back(
+ std::make_unique<OverlayStrategySingleOnTop>(this));
+ break;
+ case OverlayStrategy::kUnderlay:
+ strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+ break;
+ case OverlayStrategy::kUnderlayCast:
+ strategies_.push_back(
+ std::make_unique<OverlayStrategyUnderlayCast>(this));
+ break;
+ default:
+ NOTREACHED();
}
}
}
@@ -105,10 +105,10 @@ OverlayProcessorOzone::OverlayProcessorOzone(
OverlayProcessorOzone::~OverlayProcessorOzone() = default;
bool OverlayProcessorOzone::IsOverlaySupported() const {
- return overlay_enabled_;
+ return true;
}
-bool OverlayProcessorOzone::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorOzone::NeedsSurfaceDamageRectList() const {
return true;
}
@@ -132,6 +132,9 @@ void OverlayProcessorOzone::CheckOverlaySupport(
// For ozone-cast, there will not be a primary_plane.
if (primary_plane) {
ConvertToOzoneOverlaySurface(*primary_plane, &(*ozone_surface_iterator));
+ // TODO(crbug.com/1138568): Fuchsia claims support for presenting primary
+ // plane as overlay, but does not provide a mailbox. Handle this case.
+#if !defined(OS_FUCHSIA)
if (shared_image_interface_) {
bool result = SetNativePixmapForCandidate(&(*ozone_surface_iterator),
primary_plane->mailbox);
@@ -144,6 +147,7 @@ void OverlayProcessorOzone::CheckOverlaySupport(
return;
}
}
+#endif
ozone_surface_iterator++;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.h b/chromium/components/viz/service/display/overlay_processor_ozone.h
index 38e2893c2ce..3f0e05586e1 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.h
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_OZONE_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_OZONE_H_
+#include <memory>
+#include <vector>
+
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
@@ -15,7 +18,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOzone
: public OverlayProcessorUsingStrategy {
public:
OverlayProcessorOzone(
- bool overlay_enabled,
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates,
std::vector<OverlayStrategy> available_strategies,
gpu::SharedImageInterface* shared_image_interface);
@@ -23,7 +25,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOzone
bool IsOverlaySupported() const override;
- bool NeedsSurfaceOccludingDamageRect() const override;
+ bool NeedsSurfaceDamageRectList() const override;
// Override OverlayProcessorUsingStrategy.
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
@@ -42,8 +44,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOzone
bool SetNativePixmapForCandidate(ui::OverlaySurfaceCandidate* candidate,
const gpu::Mailbox& mailbox);
- const bool overlay_enabled_;
-
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_;
const std::vector<OverlayStrategy> available_strategies_;
gpu::SharedImageInterface* const shared_image_interface_;
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.cc b/chromium/components/viz/service/display/overlay_processor_stub.cc
index 0be55eec1c4..ad6a26fba3d 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.cc
+++ b/chromium/components/viz/service/display/overlay_processor_stub.cc
@@ -15,7 +15,7 @@ gfx::Rect OverlayProcessorStub::GetPreviousFrameOverlaysBoundingRect() const {
return gfx::Rect();
}
-bool OverlayProcessorStub::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorStub::NeedsSurfaceDamageRectList() const {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.h b/chromium/components/viz/service/display/overlay_processor_stub.h
index 88032cf8354..06747b82b87 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.h
+++ b/chromium/components/viz/service/display/overlay_processor_stub.h
@@ -22,13 +22,14 @@ class VIZ_SERVICE_EXPORT OverlayProcessorStub
bool IsOverlaySupported() const final;
gfx::Rect GetPreviousFrameOverlaysBoundingRect() const final;
gfx::Rect GetAndResetOverlayDamage() final;
- bool NeedsSurfaceOccludingDamageRect() const final;
+ bool NeedsSurfaceDamageRectList() const final;
void ProcessForOverlays(
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_passes,
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* overlay_candidates,
gfx::Rect* damage_rect,
diff --git a/chromium/components/viz/service/display/overlay_processor_surface_control.cc b/chromium/components/viz/service/display/overlay_processor_surface_control.cc
index 187af48cf2d..b285cd8df4e 100644
--- a/chromium/components/viz/service/display/overlay_processor_surface_control.cc
+++ b/chromium/components/viz/service/display/overlay_processor_surface_control.cc
@@ -4,10 +4,12 @@
#include "components/viz/service/display/overlay_processor_surface_control.h"
+#include <memory>
+
#include "components/viz/service/display/overlay_strategy_underlay.h"
+#include "ui/gfx/android/android_surface_control_compat.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/overlay_transform_utils.h"
-#include "ui/gl/android/android_surface_control_compat.h"
namespace viz {
namespace {
@@ -28,22 +30,19 @@ gfx::RectF ClipFromOrigin(gfx::RectF input) {
} // namespace
-OverlayProcessorSurfaceControl::OverlayProcessorSurfaceControl(
- bool enable_overlay)
- : OverlayProcessorUsingStrategy(), overlay_enabled_(enable_overlay) {
- if (overlay_enabled_) {
- strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
- this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
- }
+OverlayProcessorSurfaceControl::OverlayProcessorSurfaceControl()
+ : OverlayProcessorUsingStrategy() {
+ strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(
+ this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
}
OverlayProcessorSurfaceControl::~OverlayProcessorSurfaceControl() {}
bool OverlayProcessorSurfaceControl::IsOverlaySupported() const {
- return overlay_enabled_;
+ return true;
}
-bool OverlayProcessorSurfaceControl::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorSurfaceControl::NeedsSurfaceDamageRectList() const {
return true;
}
@@ -53,7 +52,7 @@ void OverlayProcessorSurfaceControl::CheckOverlaySupport(
DCHECK(!candidates->empty());
for (auto& candidate : *candidates) {
- if (!gl::SurfaceControl::SupportsColorSpace(candidate.color_space)) {
+ if (!gfx::SurfaceControl::SupportsColorSpace(candidate.color_space)) {
candidate.overlay_handled = false;
return;
}
@@ -99,7 +98,7 @@ void OverlayProcessorSurfaceControl::AdjustOutputSurfaceOverlay(
DCHECK(output_surface_plane && output_surface_plane->has_value());
OutputSurfaceOverlayPlane& plane = output_surface_plane->value();
- DCHECK(gl::SurfaceControl::SupportsColorSpace(plane.color_space))
+ DCHECK(gfx::SurfaceControl::SupportsColorSpace(plane.color_space))
<< "The main overlay must only use color space supported by the "
"device";
diff --git a/chromium/components/viz/service/display/overlay_processor_surface_control.h b/chromium/components/viz/service/display/overlay_processor_surface_control.h
index 59be65eb1bf..a265576c5cd 100644
--- a/chromium/components/viz/service/display/overlay_processor_surface_control.h
+++ b/chromium/components/viz/service/display/overlay_processor_surface_control.h
@@ -13,12 +13,12 @@ namespace viz {
class VIZ_SERVICE_EXPORT OverlayProcessorSurfaceControl
: public OverlayProcessorUsingStrategy {
public:
- explicit OverlayProcessorSurfaceControl(bool enable_overlay);
+ OverlayProcessorSurfaceControl();
~OverlayProcessorSurfaceControl() override;
bool IsOverlaySupported() const override;
- bool NeedsSurfaceOccludingDamageRect() const override;
+ bool NeedsSurfaceDamageRectList() const override;
// Override OverlayProcessorUsingStrategy.
void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
@@ -32,7 +32,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorSurfaceControl
const OverlayCandidate& overlay) const override;
private:
- const bool overlay_enabled_;
gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
gfx::Size viewport_size_;
};
diff --git a/chromium/components/viz/service/display/overlay_processor_surface_control_unittest.cc b/chromium/components/viz/service/display/overlay_processor_surface_control_unittest.cc
index 960abca49f3..9f1b80fadca 100644
--- a/chromium/components/viz/service/display/overlay_processor_surface_control_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_processor_surface_control_unittest.cc
@@ -20,7 +20,7 @@ TEST(OverlayCandidateValidatorSurfaceControlTest, NoClipOrNegativeOffset) {
OverlayCandidateList candidates;
candidates.push_back(candidate);
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.CheckOverlaySupport(nullptr, &candidates);
EXPECT_TRUE(candidates.at(0).overlay_handled);
EXPECT_RECTF_EQ(candidates.at(0).display_rect, gfx::RectF(10.f, 10.f));
@@ -37,7 +37,7 @@ TEST(OverlayProcessorSurfaceControlTest, Clipped) {
OverlayCandidateList candidates;
candidates.push_back(candidate);
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.CheckOverlaySupport(nullptr, &candidates);
EXPECT_TRUE(candidates.at(0).overlay_handled);
EXPECT_RECTF_EQ(candidates.at(0).display_rect,
@@ -56,7 +56,7 @@ TEST(OverlayProcessorSurfaceControlTest, NegativeOffset) {
OverlayCandidateList candidates;
candidates.push_back(candidate);
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.CheckOverlaySupport(nullptr, &candidates);
EXPECT_TRUE(candidates.at(0).overlay_handled);
EXPECT_RECTF_EQ(candidates.at(0).display_rect,
@@ -75,7 +75,7 @@ TEST(OverlayProcessorSurfaceControlTest, ClipAndNegativeOffset) {
OverlayCandidateList candidates;
candidates.push_back(candidate);
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.CheckOverlaySupport(nullptr, &candidates);
EXPECT_TRUE(candidates.at(0).overlay_handled);
EXPECT_RECTF_EQ(candidates.at(0).display_rect,
@@ -92,7 +92,7 @@ TEST(OverlayProcessorSurfaceControlTest, DisplayTransformOverlay) {
OverlayCandidateList candidates;
candidates.push_back(candidate);
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.SetViewportSize(gfx::Size(100, 200));
processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90);
@@ -116,7 +116,7 @@ TEST(OverlayProcessorSurfaceControlTest, DisplayTransformOutputSurfaceOverlay) {
base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>
overlay_plane = candidate;
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.SetViewportSize(gfx::Size(100, 200));
processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90);
processor.AdjustOutputSurfaceOverlay(&overlay_plane);
@@ -130,7 +130,7 @@ TEST(OverlayCandidateValidatorTest, OverlayDamageRectForOutputSurface) {
candidate.transform = gfx::OVERLAY_TRANSFORM_ROTATE_90;
candidate.overlay_handled = false;
- OverlayProcessorSurfaceControl processor(true);
+ OverlayProcessorSurfaceControl processor;
processor.SetViewportSize(gfx::Size(100, 200));
processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90);
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
index 5c65096cbc4..02a15efc49b 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -60,6 +60,7 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* candidates,
gfx::Rect* damage_rect,
@@ -85,7 +86,8 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
// Only if that fails, attempt hardware overlay strategies.
bool success = AttemptWithStrategies(
output_color_matrix, render_pass_backdrop_filters, resource_provider,
- render_passes, output_surface_plane, candidates, content_bounds);
+ render_passes, surface_damage_rect_list, output_surface_plane, candidates,
+ content_bounds);
if (success) {
UpdateDamageRect(candidates, previous_frame_underlay_rect_,
@@ -174,10 +176,9 @@ void OverlayProcessorUsingStrategy::UpdateDamageRect(
}
if (overlay.plane_z_order) {
- RecordOverlayDamageRectHistograms(
- (overlay.plane_z_order > 0), !overlay.no_occluding_damage,
- damage_rect->IsEmpty(),
- false /* occluding_damage_equal_to_damage_rect */);
+ RecordOverlayDamageRectHistograms((overlay.plane_z_order > 0),
+ !overlay.no_occluding_damage,
+ damage_rect->IsEmpty());
}
}
@@ -205,14 +206,16 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategies(
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds) {
last_successful_strategy_ = nullptr;
for (const auto& strategy : strategies_) {
if (strategy->Attempt(output_color_matrix, render_pass_backdrop_filters,
- resource_provider, render_pass_list, primary_plane,
- candidates, content_bounds)) {
+ resource_provider, render_pass_list,
+ surface_damage_rect_list, primary_plane, candidates,
+ content_bounds)) {
// This function is used by underlay strategy to mark the primary plane as
// enable_blending.
strategy->AdjustOutputSurfaceOverlay(primary_plane);
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.h b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
index f04b71d83c8..c4821f5a7f2 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
@@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_USING_STRATEGY_H_
#include <memory>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/macros.h"
@@ -45,6 +46,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
const FilterOperationsMap& render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds) = 0;
@@ -81,6 +83,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* overlay_candidates,
gfx::Rect* damage_rect,
@@ -139,6 +142,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds);
diff --git a/chromium/components/viz/service/display/overlay_processor_win.cc b/chromium/components/viz/service/display/overlay_processor_win.cc
index a4259696719..fc34539e346 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.cc
+++ b/chromium/components/viz/service/display/overlay_processor_win.cc
@@ -27,13 +27,14 @@ OverlayProcessorWin::OverlayProcessorWin(
OutputSurface* output_surface,
std::unique_ptr<DCLayerOverlayProcessor> dc_layer_overlay_processor)
: output_surface_(output_surface),
- supports_dc_layers_(output_surface->capabilities().supports_dc_layers),
- dc_layer_overlay_processor_(std::move(dc_layer_overlay_processor)) {}
+ dc_layer_overlay_processor_(std::move(dc_layer_overlay_processor)) {
+ DCHECK(output_surface_->capabilities().supports_dc_layers);
+}
OverlayProcessorWin::~OverlayProcessorWin() = default;
bool OverlayProcessorWin::IsOverlaySupported() const {
- return supports_dc_layers_;
+ return true;
}
gfx::Rect OverlayProcessorWin::GetPreviousFrameOverlaysBoundingRect() const {
@@ -53,6 +54,7 @@ void OverlayProcessorWin::ProcessForOverlays(
const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters,
const OverlayProcessorInterface::FilterOperationsMap&
render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* candidates,
gfx::Rect* damage_rect,
@@ -84,12 +86,10 @@ void OverlayProcessorWin::ProcessForOverlays(
return;
}
- if (!supports_dc_layers_)
- return;
-
dc_layer_overlay_processor_->Process(
resource_provider, gfx::RectF(root_render_pass->output_rect),
- render_passes, damage_rect, candidates);
+ render_pass_filters, render_pass_backdrop_filters, render_passes,
+ damage_rect, surface_damage_rect_list, candidates);
bool was_using_dc_layers = using_dc_layers_;
if (!candidates->empty()) {
@@ -109,7 +109,7 @@ void OverlayProcessorWin::ProcessForOverlays(
}
}
-bool OverlayProcessorWin::NeedsSurfaceOccludingDamageRect() const {
+bool OverlayProcessorWin::NeedsSurfaceDamageRectList() const {
return true;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_win.h b/chromium/components/viz/service/display/overlay_processor_win.h
index 69570bf35de..55f8d36e1f1 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.h
+++ b/chromium/components/viz/service/display/overlay_processor_win.h
@@ -41,7 +41,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorWin
// Returns true if the platform supports hw overlays and surface occluding
// damage rect needs to be computed since it will be used by overlay
// processor.
- bool NeedsSurfaceOccludingDamageRect() const override;
+ bool NeedsSurfaceDamageRectList() const override;
void AdjustOutputSurfaceOverlay(base::Optional<OutputSurfaceOverlayPlane>*
output_surface_plane) override {}
@@ -54,6 +54,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorWin
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_backdrop_filters,
+ SurfaceDamageRectList* surface_damage_rect_list,
OutputSurfaceOverlayPlane* output_surface_plane,
CandidateList* overlay_candidates,
gfx::Rect* damage_rect,
@@ -69,12 +70,11 @@ class VIZ_SERVICE_EXPORT OverlayProcessorWin
private:
OutputSurface* const output_surface_;
- // Whether direct composition layers are supported by the output surface.
- const bool supports_dc_layers_;
// Whether direct composition layers are being used with SetEnableDCLayers().
bool using_dc_layers_ = false;
// Number of frames since the last time direct composition layers were used.
int frames_since_using_dc_layers_ = 0;
+
// TODO(weiliangc): Eventually fold DCLayerOverlayProcessor into this class.
std::unique_ptr<DCLayerOverlayProcessor> dc_layer_overlay_processor_;
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
index 1d6e95a47f5..11d6b348909 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -4,6 +4,8 @@
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
+#include <vector>
+
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -25,6 +27,7 @@ bool OverlayStrategyFullscreen::Attempt(
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
@@ -48,8 +51,9 @@ bool OverlayStrategyFullscreen::Attempt(
return false;
OverlayCandidate candidate;
- if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
- quad, &candidate)) {
+ if (!OverlayCandidate::FromDrawQuad(resource_provider,
+ surface_damage_rect_list,
+ output_color_matrix, quad, &candidate)) {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
index f9cc821fe65..958b6da98f1 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_FULLSCREEN_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_FULLSCREEN_H_
+#include <vector>
+
#include "base/macros.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/viz_service_export.h"
@@ -25,6 +27,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyFullscreen
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
index 3904f26979d..dfbdfb5423c 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -4,6 +4,8 @@
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
+#include <vector>
+
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -23,6 +25,7 @@ bool OverlayStrategySingleOnTop::Attempt(
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
@@ -35,8 +38,9 @@ bool OverlayStrategySingleOnTop::Attempt(
auto best_quad_it = quad_list->end();
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
- *it, &candidate) &&
+ if (OverlayCandidate::FromDrawQuad(resource_provider,
+ surface_damage_rect_list,
+ output_color_matrix, *it, &candidate) &&
!OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
// If the candidate has been promoted previously and has not changed
// (resource ID is the same) for 3 frames, do not use it as Overlay as
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
index 1da1029c520..133faa203b5 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_
+#include <vector>
+
#include "base/macros.h"
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
@@ -24,6 +26,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategySingleOnTop
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.cc b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
index ef87eb478fe..3efb3048951 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
@@ -4,6 +4,8 @@
#include "components/viz/service/display/overlay_strategy_underlay.h"
+#include <vector>
+
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/service/display/display_resource_provider.h"
@@ -25,6 +27,7 @@ bool OverlayStrategyUnderlay::Attempt(
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
@@ -35,8 +38,9 @@ bool OverlayStrategyUnderlay::Attempt(
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
- if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
- *it, &candidate) ||
+ if (!OverlayCandidate::FromDrawQuad(resource_provider,
+ surface_damage_rect_list,
+ output_color_matrix, *it, &candidate) ||
(opaque_mode_ == OpaqueMode::RequireOpaqueCandidates &&
!candidate.is_opaque)) {
continue;
@@ -75,7 +79,8 @@ bool OverlayStrategyUnderlay::Attempt(
if (new_candidate_list.back().overlay_handled) {
new_candidate_list.back().is_unoccluded =
!OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it);
- quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
+
+ render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
candidate_list->swap(new_candidate_list);
return true;
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.h b/chromium/components/viz/service/display/overlay_strategy_underlay.h
index 9170eeeed7b..ac046eec156 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_UNDERLAY_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_UNDERLAY_H_
+#include <vector>
+
#include "base/macros.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/viz_service_export.h"
@@ -39,6 +41,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlay
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
index fa4880d3fe3..93c0743ab90 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -4,6 +4,9 @@
#include "components/viz/service/display/overlay_strategy_underlay_cast.h"
+#include <utility>
+#include <vector>
+
#include "base/containers/adapters.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -51,6 +54,7 @@ bool OverlayStrategyUnderlayCast::Attempt(
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
@@ -79,10 +83,10 @@ bool OverlayStrategyUnderlayCast::Attempt(
// quad is supposed to be to replace it with a transparent quad to allow
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
- is_underlay =
- quad->material == DrawQuad::Material::kVideoHole &&
- OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
- quad, &candidate);
+ is_underlay = quad->material == DrawQuad::Material::kVideoHole &&
+ OverlayCandidate::FromDrawQuad(
+ resource_provider, surface_damage_rect_list,
+ output_color_matrix, quad, &candidate);
found_underlay = is_underlay;
}
@@ -109,7 +113,8 @@ bool OverlayStrategyUnderlayCast::Attempt(
OverlayCandidate candidate;
if (it->material != DrawQuad::Material::kVideoHole ||
!OverlayCandidate::FromDrawQuad(
- resource_provider, output_color_matrix, *it, &candidate)) {
+ resource_provider, surface_damage_rect_list, output_color_matrix,
+ *it, &candidate)) {
continue;
}
@@ -127,8 +132,7 @@ bool OverlayStrategyUnderlayCast::Attempt(
}
#endif
- render_pass->quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(
- it);
+ render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
break;
}
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
index 6f810a329c9..dfdbffd661f 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_STRATEGY_UNDERLAY_CAST_H_
#include <memory>
+#include <vector>
#include "base/callback.h"
#include "base/macros.h"
@@ -33,6 +34,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast
render_pass_backdrop_filters,
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_pass,
+ SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
diff --git a/chromium/components/viz/service/display/overlay_unittest.cc b/chromium/components/viz/service/display/overlay_unittest.cc
index 469a02d10bc..1af80bf1204 100644
--- a/chromium/components/viz/service/display/overlay_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_unittest.cc
@@ -4,13 +4,13 @@
#include <stddef.h>
+#include <unordered_map>
#include <utility>
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
-#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "cc/test/fake_output_surface_client.h"
@@ -30,6 +30,7 @@
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display/overlay_candidate_temporal_tracker.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
@@ -80,7 +81,7 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
~TestOverlayProcessor() override = default;
bool IsOverlaySupported() const override { return true; }
- bool NeedsSurfaceOccludingDamageRect() const override { return false; }
+ bool NeedsSurfaceDamageRectList() const override { return false; }
void CheckOverlaySupport(const PrimaryPlane* primary_plane,
OverlayCandidateList* surfaces) override {}
size_t GetStrategyCount() const { return strategies_.size(); }
@@ -91,7 +92,7 @@ class FullscreenOverlayProcessor : public TestOverlayProcessor {
FullscreenOverlayProcessor() : TestOverlayProcessor() {
strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
}
- bool NeedsSurfaceOccludingDamageRect() const override { return true; }
+ bool NeedsSurfaceDamageRectList() const override { return true; }
void CheckOverlaySupport(const PrimaryPlane* primary_plane,
OverlayCandidateList* surfaces) override {
surfaces->back().overlay_handled = true;
@@ -103,7 +104,7 @@ class DefaultOverlayProcessor : public TestOverlayProcessor {
DefaultOverlayProcessor()
: TestOverlayProcessor(), expected_rects_(1, gfx::RectF(kOverlayRect)) {}
- bool NeedsSurfaceOccludingDamageRect() const override { return true; }
+ bool NeedsSurfaceDamageRectList() const override { return true; }
void CheckOverlaySupport(const PrimaryPlane* primary_plane,
OverlayCandidateList* surfaces) override {
// We have one overlay surface to test. The output surface as primary plane
@@ -214,11 +215,6 @@ class OverlayOutputSurface : public OutputSurface {
gfx::OverlayTransform GetDisplayTransform() override {
return gfx::OVERLAY_TRANSFORM_NONE;
}
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override {
- return nullptr;
- }
- gpu::MemoryTracker* GetMemoryTracker() override { return nullptr; }
void set_is_displayed_as_overlay_plane(bool value) {
is_displayed_as_overlay_plane_ = value;
@@ -566,11 +562,13 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
@@ -602,13 +600,15 @@ TEST_F(FullscreenOverlayTest, FailOnOutputColorMatrix) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
// This is passing a non-identity color matrix which will result in disabling
// overlays since color matrices are not supported yet.
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetNonIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the 2 quads are not gone.
@@ -629,11 +629,13 @@ TEST_F(FullscreenOverlayTest, AlphaFail) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
// Check that all the quads are gone.
EXPECT_EQ(1U, main_pass->quad_list.size());
@@ -655,11 +657,13 @@ TEST_F(FullscreenOverlayTest, SuccessfulResourceSizeInPixels) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the quad is gone.
@@ -685,11 +689,13 @@ TEST_F(FullscreenOverlayTest, OnTopFail) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the 2 quads are not gone.
@@ -712,10 +718,13 @@ TEST_F(FullscreenOverlayTest, NotCoveringFullscreenFail) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
// Check that the quad is not gone.
@@ -744,10 +753,13 @@ TEST_F(FullscreenOverlayTest, RemoveFullscreenQuadFromQuadList) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the fullscreen quad is gone.
@@ -776,10 +788,13 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that the quad is gone.
@@ -825,10 +840,13 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that one quad is gone.
@@ -859,10 +877,13 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_TRUE(damage_rect_.IsEmpty());
}
@@ -882,10 +903,13 @@ TEST_F(SingleOverlayOnTopTest, NoCandidates) {
OverlayCandidateList candidate_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
// There should be nothing new here.
CompareRenderPassLists(pass_list, original_pass_list);
@@ -911,10 +935,13 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
OverlayCandidateList candidate_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
// There should be nothing new here.
CompareRenderPassLists(pass_list, original_pass_list);
@@ -939,10 +966,13 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -959,10 +989,13 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlending) {
damage_rect_ = quad->rect;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
EXPECT_FALSE(damage_rect_.IsEmpty());
gfx::Rect overlay_damage_rect =
@@ -982,10 +1015,13 @@ TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1001,10 +1037,13 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlackBackgroundColor) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1021,10 +1060,13 @@ TEST_F(SingleOverlayOnTopTest, RejectBlackBackgroundColorWithBlending) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1040,10 +1082,13 @@ TEST_F(SingleOverlayOnTopTest, RejectBlendMode) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1059,10 +1104,36 @@ TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectNearestNeighbor) {
+ auto pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
+ static_cast<TextureDrawQuad*>(pass->quad_list.back())->nearest_neighbor =
+ true;
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1079,10 +1150,13 @@ TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1099,10 +1173,13 @@ TEST_F(SingleOverlayOnTopTest, AllowClipped) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1121,10 +1198,13 @@ TEST_F(UnderlayTest, AllowVerticalFlip) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL,
candidate_list.back().transform);
@@ -1146,10 +1226,13 @@ TEST_F(UnderlayTest, AllowHorizontalFlip) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
candidate_list.back().transform);
@@ -1169,10 +1252,13 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1191,10 +1277,13 @@ TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
@@ -1213,10 +1302,13 @@ TEST_F(UnderlayTest, Allow90DegreeRotation) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform);
}
@@ -1236,10 +1328,13 @@ TEST_F(UnderlayTest, Allow180DegreeRotation) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform);
}
@@ -1259,10 +1354,13 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform);
}
@@ -1280,10 +1378,13 @@ TEST_F(UnderlayTest, AllowsOpaqueCandidates) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
@@ -1299,10 +1400,13 @@ TEST_F(UnderlayTest, DisallowsTransparentCandidates) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
}
@@ -1333,10 +1437,13 @@ TEST_F(UnderlayTest, DisallowFilteredQuadOnTop) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(0U, candidate_list.size());
}
@@ -1353,10 +1460,13 @@ TEST_F(TransparentUnderlayTest, AllowsOpaqueCandidates) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
@@ -1372,10 +1482,13 @@ TEST_F(TransparentUnderlayTest, AllowsTransparentCandidates) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
}
@@ -1396,10 +1509,13 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1422,10 +1538,13 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1446,10 +1565,13 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
}
@@ -1470,10 +1592,13 @@ TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1492,10 +1617,13 @@ TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, candidate_list.size());
}
@@ -1545,10 +1673,13 @@ TEST_F(SingleOverlayOnTopTest, DoNotPromoteIfContentsDontChange) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
if (i <= kFramesSkippedBeforeNotPromoting) {
EXPECT_EQ(1U, candidate_list.size());
@@ -1580,10 +1711,13 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(-1, candidate_list[0].plane_z_order);
EXPECT_EQ(2U, main_pass->quad_list.size());
@@ -1611,10 +1745,13 @@ TEST_F(UnderlayTest, AllowOnTop) {
AggregatedRenderPassList pass_list;
AggregatedRenderPass* main_pass = pass.get();
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
EXPECT_EQ(-1, candidate_list[0].plane_z_order);
// The overlay quad should have changed to a SOLID_COLOR quad.
@@ -1640,10 +1777,13 @@ TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(kOverlayRect, damage_rect_);
}
@@ -1668,10 +1808,13 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
}
// The second time the same overlay rect is scheduled it will be subtracted
@@ -1700,10 +1843,13 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(overlay_rects[i], damage_rect_);
}
@@ -1735,10 +1881,13 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
@@ -1766,10 +1915,13 @@ TEST_F(UnderlayTest, DamageSubtractedForOneFrameAfterBecomingUnoccluded) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
// The damage rect should not be subtracted if the underlay is occluded
// (i==0) or it is unoccluded for the first time (i==1).
@@ -1798,10 +1950,13 @@ TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
@@ -1828,10 +1983,13 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
}
EXPECT_TRUE(damage_rect_.IsEmpty());
@@ -1855,6 +2013,7 @@ TEST_F(UnderlayTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
auto output_surface_plane = overlay_processor_->ProcessOutputSurfaceAsOverlay(
kDisplaySize, kDefaultBufferFormat, gfx::ColorSpace(),
@@ -1864,8 +2023,9 @@ TEST_F(UnderlayTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, primary_plane,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, primary_plane, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, candidate_list.size());
ASSERT_EQ(true, output_surface_plane.enable_blending);
@@ -1894,15 +2054,148 @@ TEST_F(UnderlayTest, UpdateDamageWhenChangingUnderlays) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
}
EXPECT_EQ(kOverlayRect, damage_rect_);
}
+TEST_F(UnderlayTest, OverlayCandidateTemporalTracker) {
+ unsigned id_counter = 0;
+ // Function to fake unique resource ids so the system sees them as changing.
+ auto get_id = [&] { return ++id_counter; };
+
+ // Test the default configuration.
+ OverlayCandidateTemporalTracker::Config config;
+ constexpr float kEpsilon = 0.01f;
+ float kBelowLowDamage = config.damage_low_threshold - kEpsilon;
+ float kAboveHighDamage = config.damage_high_threshold + kEpsilon;
+
+ base::TimeTicks tick_start = base::TimeTicks::Now();
+ // This is a helper function to simulate framerates.
+ auto wait_17ms = [&]() {
+ while ((base::TimeTicks::Now() - tick_start).InMilliseconds() < 17) {
+ }
+ tick_start = base::TimeTicks::Now();
+ };
+
+ auto wait_66ms = [&]() {
+ while ((base::TimeTicks::Now() - tick_start).InMilliseconds() < 66) {
+ }
+ tick_start = base::TimeTicks::Now();
+ };
+ OverlayCandidateTemporalTracker tracker;
+
+ // We test internal hysteresis state by running this test twice.
+ for (int j = 0; j < 2; j++) {
+ // First setup a 60fps high damage candidate.
+ for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) {
+ tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(),
+ config);
+ wait_17ms();
+ }
+
+ OverlayCandidateTemporalTracker tracker_not_active_changing = tracker;
+
+ EXPECT_TRUE(tracker.HasSignificantDamage());
+ ASSERT_EQ(tracker.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate60fps);
+
+ // Test the hysteresis by checking that a few 30fps low damage updates do
+ // not change the categorization state.
+ wait_17ms();
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(),
+ config);
+ wait_17ms();
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(),
+ config);
+ EXPECT_TRUE(tracker.HasSignificantDamage());
+ ASSERT_EQ(tracker.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate60fps);
+
+ // Now simulate a overaly candidate with 30fps and low damage.
+ for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) {
+ wait_17ms();
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), kBelowLowDamage, get_id(),
+ config);
+ }
+ // Check that it has reached the applied state.
+ EXPECT_FALSE(tracker.HasSignificantDamage());
+ ASSERT_EQ(tracker.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate30fps);
+
+ OverlayCandidateTemporalTracker tracker_saved_30fps = tracker;
+
+ // Test hysteresis for this new state by adding in a few high damage 60fps
+ // frames.
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(),
+ config);
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), kAboveHighDamage, get_id(),
+ config);
+ EXPECT_FALSE(tracker.HasSignificantDamage());
+ ASSERT_EQ(tracker.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate30fps);
+
+ EXPECT_TRUE(tracker.IsActivelyChanging(base::TimeTicks::Now(), config));
+
+ // Test hysteresis for 30fps to lowfps state by inserting lowfps frames and
+ // asserting that the tracker is still in the 30fps state.
+ wait_66ms();
+ tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kAboveHighDamage,
+ get_id(), config);
+ wait_66ms();
+ tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kAboveHighDamage,
+ get_id(), config);
+ ASSERT_EQ(tracker.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate30fps);
+
+ for (int i = 0; i < OverlayCandidateTemporalTracker::kNumRecords; i++) {
+ wait_66ms();
+ tracker_saved_30fps.AddRecord(base::TimeTicks::Now(), kBelowLowDamage,
+ get_id(), config);
+ }
+ // make sure our we have moved into the |kFrameRateLow| category.
+ ASSERT_EQ(tracker_saved_30fps.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRateLow);
+
+ // The current design only updates frame rate categorization on record
+ // insertion ('AddRecord()'). We test this assumption by asserting that a
+ // tracker that is not actively changing still has its original 60fps
+ // category.
+ EXPECT_FALSE(tracker_not_active_changing.IsActivelyChanging(
+ base::TimeTicks::Now(), config));
+
+ ASSERT_EQ(tracker_not_active_changing.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRate60fps);
+ // Finally we test that the categorization changes on the addition of a new
+ // record of very large time interval.
+ tracker_not_active_changing.AddRecord(base::TimeTicks::Now(),
+ kAboveHighDamage, get_id(), config);
+ ASSERT_EQ(tracker_not_active_changing.GetFPSCategory(),
+ OverlayCandidateTemporalTracker::kFrameRateLow);
+ }
+
+ EXPECT_FALSE(tracker.IsAbsent());
+ // After a many absent calls the 'IncAbsent()' function should eventually
+ // return true; indicating this tracker is no longer active.
+ EXPECT_TRUE(tracker.IsAbsent());
+
+ wait_17ms();
+ tracker.AddRecord(base::TimeTicks::Now(), 0.0f, get_id(), config);
+ EXPECT_FALSE(tracker.IsAbsent());
+}
+
TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
// In the first pass there is an overlay promotion and the expected damage is
// a union of the hole made for the underlay and the incoming damage. In the
@@ -1941,10 +2234,13 @@ TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
render_pass_background_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_background_filters, nullptr,
- &candidate_list, &damage_rect, &content_bounds_);
+ render_pass_filters, render_pass_background_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect,
+ &content_bounds_);
EXPECT_EQ(expected_damages[i], damage_rect);
ASSERT_EQ(expected_candidate_size[i], candidate_list.size());
@@ -1956,6 +2252,7 @@ TEST_F(UnderlayTest, UpdateDamageRectWhenNoPromotion) {
TEST_F(UnderlayTest, CandidateNoDamageWhenQuadSharedStateNoOccludingDamage) {
for (int i = 0; i < 4; ++i) {
auto pass = CreateRenderPass();
+ SurfaceDamageRectList surface_damage_rect_list;
gfx::Rect rect(2, 3);
SharedQuadState* default_damaged_shared_quad_state =
@@ -1963,10 +2260,15 @@ TEST_F(UnderlayTest, CandidateNoDamageWhenQuadSharedStateNoOccludingDamage) {
pass->shared_quad_state_list.back());
if (i == 2) {
auto* sqs = pass->shared_quad_state_list.front();
- sqs->occluding_damage_rect = gfx::Rect();
+ sqs->overlay_damage_index = 0;
+ surface_damage_rect_list.emplace_back(0, 0, 20, 20);
} else if (i == 3) {
auto* sqs = pass->shared_quad_state_list.front();
- sqs->occluding_damage_rect = gfx::Rect(1, 1, 10, 10);
+ // For the solid color quad gfx::Rect(1, 1, 10, 10).
+ surface_damage_rect_list.emplace_back(1, 1, 10, 10);
+ // For the overlay quad gfx::Rect(0, 0, 20, 20).
+ surface_damage_rect_list.emplace_back(0, 0, 20, 20);
+ sqs->overlay_damage_index = 1;
}
CreateSolidColorQuadAt(default_damaged_shared_quad_state, SK_ColorBLACK,
@@ -1984,15 +2286,21 @@ TEST_F(UnderlayTest, CandidateNoDamageWhenQuadSharedStateNoOccludingDamage) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
- if (i == 0 || i == 1 || i == 3)
+ if (i == 0 || i == 1 || i == 3) {
+ EXPECT_FALSE(candidate_list[0].no_occluding_damage);
EXPECT_FALSE(damage_rect_.IsEmpty());
- else if (i == 2)
+
+ } else if (i == 2) {
+ EXPECT_TRUE(candidate_list[0].no_occluding_damage);
EXPECT_TRUE(damage_rect_.IsEmpty());
+ }
}
}
@@ -2008,10 +2316,13 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(0U, content_bounds_.size());
}
@@ -2025,10 +2336,13 @@ TEST_F(UnderlayCastTest, FullScreenOverlayContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -2055,10 +2369,13 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -2077,10 +2394,13 @@ TEST_F(UnderlayCastTest, OverlayOccludedContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayTopLeftRect, content_bounds_[0]);
@@ -2102,10 +2422,13 @@ TEST_F(UnderlayCastTest, OverlayOccludedUnionContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -2132,10 +2455,13 @@ TEST_F(UnderlayCastTest, RoundOverlayContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(gfx::Rect(0, 0, 11, 11), content_bounds_[0]);
@@ -2163,10 +2489,13 @@ TEST_F(UnderlayCastTest, RoundContentBounds) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
EXPECT_EQ(1U, content_bounds_.size());
EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -2184,10 +2513,13 @@ TEST_F(UnderlayCastTest, NoOverlayPromotionWithoutProtectedContent) {
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, nullptr,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_,
+ &content_bounds_);
ASSERT_TRUE(candidate_list.empty());
EXPECT_TRUE(content_bounds_.empty());
@@ -2213,8 +2545,9 @@ TEST_F(UnderlayCastTest, PrimaryPlaneOverlayIsAlwaysTransparent) {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters, &output_surface_plane,
- &candidate_list, &damage_rect_, &content_bounds_);
+ render_pass_filters, render_pass_backdrop_filters,
+ &surface_damage_rect_list, &output_surface_plane, &candidate_list,
+ &damage_rect_, &content_bounds_);
ASSERT_EQ(true, output_surface_plane.enable_blending);
EXPECT_EQ(0U, content_bounds_.size());
@@ -2327,8 +2660,9 @@ class GLRendererWithOverlaysTest : public testing::Test {
void DrawFrame(AggregatedRenderPassList* pass_list,
const gfx::Size& viewport_size) {
+ SurfaceDamageRectList surface_damage_rect_list;
renderer_->DrawFrame(pass_list, 1.f, viewport_size,
- gfx::DisplayColorSpaces());
+ gfx::DisplayColorSpaces(), &surface_damage_rect_list);
}
void SwapBuffers() {
renderer_->SwapBuffers({});
@@ -2884,8 +3218,9 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
void ProcessForOverlays() {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(),
- render_pass_filters_, render_pass_backdrop_filters_, nullity,
- &ca_layer_list_, &damage_rect_, &content_bounds_);
+ render_pass_filters_, render_pass_backdrop_filters_,
+ &surface_damage_rect_list_, nullity, &ca_layer_list_, &damage_rect_,
+ &content_bounds_);
}
AggregatedRenderPassList pass_list_;
AggregatedRenderPass* pass_;
@@ -2896,6 +3231,7 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
OverlayProcessorInterface::FilterOperationsMap render_pass_filters_;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters_;
CALayerOverlayList ca_layer_list_;
+ SurfaceDamageRectList surface_damage_rect_list_;
};
TEST_F(CALayerOverlayRPDQTest, AggregatedRenderPassDrawQuadNoFilters) {
@@ -3013,7 +3349,7 @@ void AddQuad(gfx::Rect quad_rect,
quad_state->SetAll(
/*quad_layer_rect=*/quad_to_target_transform, quad_rect,
/*visible_quad_layer_rect=*/quad_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(), /*clip_rect=*/gfx::Rect(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(), /*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false,
/*are contents opaque=*/true,
/*opacity=*/1.f,
@@ -3097,5 +3433,121 @@ TEST_F(OverlayCandidateTest, IsOccludedScaled) {
render_pass->quad_list.end()));
}
+TEST_F(SingleOverlayOnTopTest, IsOverlayRequiredBasic) {
+ // Add a small quad.
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(0, 0, 16, 16);
+ auto* new_quad = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ SurfaceDamageRectList surface_damage_rect_list;
+ SkMatrix44 default_color = GetIdentityColorMatrix();
+ OverlayCandidate candidate;
+ OverlayCandidate::FromDrawQuad(resource_provider_.get(),
+ &surface_damage_rect_list, default_color,
+ new_quad, &candidate);
+
+ // Verify that a default candidate is not a required overlay.
+ EXPECT_FALSE(candidate.requires_overlay);
+
+ ASSERT_EQ(gfx::ToRoundedRect(candidate.display_rect), kSmallCandidateRect);
+}
+
+TEST_F(UnderlayTest, EstimateOccludedDamage) {
+ // A visual depiction of how this test works.
+ // * - Candidate
+ // # - Occluder
+ //
+ // The first candidate has no quad occlusions.
+ ///
+ // ***********
+ // * *
+ // * *
+ // * *
+ // ***********
+ //
+ // The second candidate has only one quad occlusion.
+ // ######*****************
+ // # # * *
+ // ###### * *
+ // * * *
+ // **********###### *
+ // * # # *
+ // * ###### *
+ // * *
+ // * *
+ // ***********************
+ // Finally the third larger candidate is occluded by both quads.
+ // The |damage_area_estimate| reflects this damage occlusion when
+ // 'EstimateOccludedDamage' is called
+
+ auto pass = CreateRenderPass();
+ gfx::Transform identity;
+ identity.MakeIdentity();
+
+ // These quads will server to occlude some of our test overlay candidates.
+ const int kOccluderWidth = 10;
+ AddQuad(gfx::Rect(100, 100, kOccluderWidth, kOccluderWidth), identity,
+ pass.get());
+ AddQuad(gfx::Rect(150, 150, kOccluderWidth, kOccluderWidth), identity,
+ pass.get());
+
+ const int kCandidateSmallWidth = 50;
+ const int kCandidateLargeWidth = 100;
+ const gfx::Rect kCandidateRects[] = {
+ gfx::Rect(0, 0, kCandidateSmallWidth, kCandidateSmallWidth),
+ gfx::Rect(100, 100, kCandidateSmallWidth, kCandidateSmallWidth),
+ gfx::Rect(100, 100, kCandidateLargeWidth, kCandidateLargeWidth)};
+
+ const int kExpectedDamages[] = {kCandidateSmallWidth * kCandidateSmallWidth,
+ kCandidateSmallWidth * kCandidateSmallWidth -
+ kOccluderWidth * kOccluderWidth,
+ kCandidateLargeWidth * kCandidateLargeWidth -
+ kOccluderWidth * kOccluderWidth * 2};
+ QuadList& quad_list = pass->quad_list;
+ auto occluder_iter_count = quad_list.size();
+
+ for (size_t i = 0; i < base::size(kCandidateRects); ++i) {
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Create fake surface damage for this candidate.
+ SharedQuadState* damaged_shared_quad_state =
+ pass->shared_quad_state_list.AllocateAndCopyFrom(
+ pass->shared_quad_state_list.back());
+ damaged_shared_quad_state->overlay_damage_index = 0;
+ surface_damage_rect_list.emplace_back(kCandidateRects[i]);
+
+ auto* quad_candidate = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), damaged_shared_quad_state, pass.get(),
+ kCandidateRects[i]);
+
+ SkMatrix44 default_color = GetIdentityColorMatrix();
+ OverlayCandidate candidate;
+ OverlayCandidate::FromDrawQuad(resource_provider_.get(),
+ &surface_damage_rect_list, default_color,
+ quad_candidate, &candidate);
+
+ // Before the 'EstimateOccludedDamage' function is called the damage area
+ // will just be whatever comes from the |surface_damage_rect_list|.
+ ASSERT_EQ(kCandidateRects[i].size().GetArea(),
+ candidate.damage_area_estimate);
+
+ // We have to find the occluder end of our list as it changes each
+ // iteration.
+ auto iter_occluder_end = quad_list.begin();
+ for (size_t j = 0; j < occluder_iter_count; j++) {
+ iter_occluder_end++;
+ }
+
+ // Now we test the opaque occlusion provided by 'EstimateOccludedDamage'
+ // function.
+ candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage(
+ quad_candidate, &surface_damage_rect_list, quad_list.begin(),
+ iter_occluder_end);
+ ASSERT_EQ(kExpectedDamages[i], candidate.damage_area_estimate);
+ }
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/renderer_perftest.cc b/chromium/components/viz/service/display/renderer_perftest.cc
index 1d3350bb44a..61b88cc69b3 100644
--- a/chromium/components/viz/service/display/renderer_perftest.cc
+++ b/chromium/components/viz/service/display/renderer_perftest.cc
@@ -143,19 +143,18 @@ SharedQuadState* CreateTestSharedQuadState(
gfx::Transform quad_to_target_transform,
const gfx::Rect& rect,
CompositorRenderPass* render_pass,
- const gfx::RRectF& rrect) {
+ const gfx::MaskFilterInfo& mask_filter_info) {
const gfx::Rect layer_rect = rect;
const gfx::Rect visible_layer_rect = rect;
const gfx::Rect clip_rect = rect;
const bool is_clipped = false;
const bool are_contents_opaque = false;
const float opacity = 1.0f;
- const gfx::RRectF rounded_corner_bounds = rrect;
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
const int sorting_context_id = 0;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
- rounded_corner_bounds, clip_rect, is_clipped,
+ mask_filter_info, clip_rect, is_clipped,
are_contents_opaque, opacity, blend_mode,
sorting_context_id);
return shared_state;
@@ -297,7 +296,8 @@ class RendererPerfTest : public testing::Test {
// Overloaded for concrete RendererType below.
std::unique_ptr<OutputSurface> CreateOutputSurface(
- GpuServiceImpl* gpu_service);
+ GpuServiceImpl* gpu_service,
+ DisplayCompositorMemoryAndTaskController* display_controller);
void SetUp() override {
enable_pixel_output_ = std::make_unique<gl::DisableNullDrawGLBindings>();
@@ -317,21 +317,44 @@ class RendererPerfTest : public testing::Test {
gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
auto* gpu_channel_manager_delegate =
gpu_service->gpu_channel_manager()->delegate();
+ auto child_task_scheduler = std::make_unique<gpu::GpuTaskSchedulerHelper>(
+ TestGpuServiceHolder::GetInstance()->task_executor());
+ child_gpu_dependency_ =
+ std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ TestGpuServiceHolder::GetInstance()->task_executor(),
+ image_factory);
child_context_provider_ = base::MakeRefCounted<VizProcessContextProvider>(
TestGpuServiceHolder::GetInstance()->task_executor(),
gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
- image_factory, gpu_channel_manager_delegate, renderer_settings_);
+ image_factory, gpu_channel_manager_delegate,
+ child_gpu_dependency_.get(), renderer_settings_);
child_context_provider_->BindToCurrentThread();
child_resource_provider_ = std::make_unique<ClientResourceProvider>();
- auto output_surface = CreateOutputSurface(gpu_service);
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController>
+ display_controller;
+ if (renderer_settings_.use_skia_renderer) {
+ auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+ gpu_service, gpu::kNullSurfaceHandle);
+ display_controller =
+ std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ std::move(skia_deps));
+ } else {
+ auto* task_executor =
+ TestGpuServiceHolder::GetInstance()->task_executor();
+ display_controller =
+ std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ task_executor, image_factory);
+ }
+ auto output_surface =
+ CreateOutputSurface(gpu_service, display_controller.get());
// WaitForSwapDisplayClient depends on this.
output_surface->SetNeedsSwapSizeNotifications(true);
auto overlay_processor = std::make_unique<OverlayProcessorStub>();
display_ = std::make_unique<Display>(
&shared_bitmap_manager_, renderer_settings_, &debug_settings_,
- kArbitraryFrameSinkId, std::move(output_surface),
- std::move(overlay_processor),
+ kArbitraryFrameSinkId, std::move(display_controller),
+ std::move(output_surface), std::move(overlay_processor),
/*display_scheduler=*/nullptr, base::ThreadTaskRunnerHandle::Get());
display_->SetVisible(true);
display_->Initialize(&client_, manager_.surface_manager());
@@ -381,6 +404,7 @@ class RendererPerfTest : public testing::Test {
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_.reset();
child_context_provider_.reset();
+ child_gpu_dependency_.reset();
gpu_memory_buffer_manager_.reset();
display_.reset();
@@ -485,7 +509,7 @@ class RendererPerfTest : public testing::Test {
std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
SharedQuadState* shared_state = CreateTestSharedQuadState(
- gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+ gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
CreateTestTextureDrawQuad(resource_list_.back().id, kSurfaceRect,
/*background_color=*/SK_ColorTRANSPARENT,
@@ -520,7 +544,7 @@ class RendererPerfTest : public testing::Test {
do {
std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
SharedQuadState* shared_state = CreateTestSharedQuadState(
- gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+ gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
@@ -557,7 +581,7 @@ class RendererPerfTest : public testing::Test {
do {
std::unique_ptr<CompositorRenderPass> pass = CreateTestRootRenderPass();
SharedQuadState* shared_state = CreateTestSharedQuadState(
- gfx::Transform(), kSurfaceRect, pass.get(), gfx::RRectF());
+ gfx::Transform(), kSurfaceRect, pass.get(), gfx::MaskFilterInfo());
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
@@ -616,7 +640,7 @@ class RendererPerfTest : public testing::Test {
// SharedQuadState
SharedQuadState* shared_state = CreateTestSharedQuadState(
current_transform, gfx::Rect(kSurfaceSize), pass.get(),
- gfx::RRectF());
+ gfx::MaskFilterInfo());
ResourceId resource_id =
share_resources ? resource_list_[0].id : resource_list_[i].id;
CreateTestTileDrawQuad(resource_id, gfx::Rect(kTileSize), kTextureSize,
@@ -686,6 +710,8 @@ class RendererPerfTest : public testing::Test {
RendererSettings renderer_settings_;
DebugRendererSettings debug_settings_;
std::unique_ptr<Display> display_;
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController>
+ child_gpu_dependency_;
scoped_refptr<ContextProvider> child_context_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::vector<TransferableResource> resource_list_;
@@ -698,23 +724,24 @@ class RendererPerfTest : public testing::Test {
template <>
std::unique_ptr<OutputSurface>
RendererPerfTest<SkiaRenderer>::CreateOutputSurface(
- GpuServiceImpl* gpu_service) {
+ GpuServiceImpl* gpu_service,
+ DisplayCompositorMemoryAndTaskController* display_controller) {
return SkiaOutputSurfaceImpl::Create(
- std::make_unique<SkiaOutputSurfaceDependencyImpl>(
- gpu_service, gpu::kNullSurfaceHandle),
- renderer_settings_, &debug_settings_);
+ display_controller, renderer_settings_, &debug_settings_);
}
template <>
std::unique_ptr<OutputSurface>
-RendererPerfTest<GLRenderer>::CreateOutputSurface(GpuServiceImpl* gpu_service) {
+RendererPerfTest<GLRenderer>::CreateOutputSurface(
+ GpuServiceImpl* gpu_service,
+ DisplayCompositorMemoryAndTaskController* display_controller) {
gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
auto* gpu_channel_manager_delegate =
gpu_service->gpu_channel_manager()->delegate();
auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
TestGpuServiceHolder::GetInstance()->task_executor(),
gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(), image_factory,
- gpu_channel_manager_delegate, renderer_settings_);
+ gpu_channel_manager_delegate, display_controller, renderer_settings_);
context_provider->BindToCurrentThread();
return std::make_unique<GLOutputSurfaceOffscreen>(
std::move(context_provider));
diff --git a/chromium/components/viz/service/display/renderer_pixeltest.cc b/chromium/components/viz/service/display/renderer_pixeltest.cc
index eb5ef8dc7f6..303086fd373 100644
--- a/chromium/components/viz/service/display/renderer_pixeltest.cc
+++ b/chromium/components/viz/service/display/renderer_pixeltest.cc
@@ -9,7 +9,7 @@
#include <tuple>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
@@ -29,6 +29,7 @@
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/software_renderer.h"
#include "components/viz/service/display/viz_pixel_test.h"
@@ -150,12 +151,12 @@ SharedQuadState* CreateTestSharedQuadState(
const bool is_clipped = false;
const bool are_contents_opaque = false;
const float opacity = 1.0f;
- const gfx::RRectF rounded_corner_bounds = rrect;
+ const gfx::MaskFilterInfo mask_filter_info(rrect);
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
int sorting_context_id = 0;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
- rounded_corner_bounds, clip_rect, is_clipped,
+ mask_filter_info, clip_rect, is_clipped,
are_contents_opaque, opacity, blend_mode,
sorting_context_id);
return shared_state;
@@ -175,7 +176,7 @@ SharedQuadState* CreateTestSharedQuadStateClipped(
int sorting_context_id = 0;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(), clip_rect,
+ /*mask_filter_info=*/gfx::MaskFilterInfo(), clip_rect,
is_clipped, are_contents_opaque, opacity, blend_mode,
sorting_context_id);
return shared_state;
@@ -3540,7 +3541,7 @@ TEST_P(GPURendererPixelTest, TileDrawQuadForceAntiAliasingOff) {
SkBitmap bitmap;
bitmap.allocN32Pixels(32, 32);
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
canvas.clear(SK_ColorTRANSPARENT);
gfx::Size tile_size(32, 32);
@@ -4005,7 +4006,7 @@ TEST_P(RendererPixelTest, TileDrawQuadNearestNeighbor) {
SkImageInfo info = SkImageInfo::Make(2, 2, ct, kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info);
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
@@ -4060,7 +4061,7 @@ TEST_F(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) {
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
@@ -4112,7 +4113,7 @@ TEST_F(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
{
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
@@ -4458,7 +4459,7 @@ TEST_P(GPURendererPixelTest, TextureQuadBatching) {
SkBitmap bitmap;
bitmap.allocPixels(
SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(4));
@@ -4540,7 +4541,7 @@ TEST_P(GPURendererPixelTest, TileQuadClamping) {
// layer rect red.
SkBitmap bitmap;
bitmap.allocN32Pixels(tile_size.width(), tile_size.height());
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
SkPaint red;
red.setColor(SK_ColorRED);
canvas.drawRect(SkRect::MakeWH(tile_size.width(), tile_size.height()), red);
@@ -4992,12 +4993,11 @@ class ColorTransformPixelTest
}
void Basic() {
- // SkColorSpace doesn't support piecewise transfer functions so skip those
- // with SkiaRenderer.
- if (!is_gl_renderer() &&
- (src_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR ||
+ // Skip piecewise transfer functions because SkColorSpace (needed for
+ // CopyOutputResult::AsSkBitmap) doesn't support them..
+ if ((src_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR ||
dst_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR)) {
- LOG(ERROR) << "Skipping piecewise HDR function with Skia";
+ LOG(ERROR) << "Skipping piecewise HDR function";
return;
}
@@ -5169,6 +5169,227 @@ INSTANTIATE_TEST_SUITE_P(
testing::ValuesIn(dst_color_spaces),
testing::Bool()));
+class DelegatedInkTest : public VizPixelTestWithParam,
+ public DelegatedInkPointPixelTestHelper {
+ public:
+ void SetUp() override {
+ // Partial swap must be enabled or else the test will pass even if the
+ // delegated ink trail damage rect is wrong, because the whole frame is
+ // always redrawn otherwise.
+ renderer_settings_.partial_swap_enabled = true;
+ VizPixelTestWithParam::SetUp();
+ EXPECT_TRUE(VizPixelTestWithParam::renderer_->use_partial_swap());
+
+ SetRendererAndCreateInkRenderer(VizPixelTestWithParam::renderer_.get());
+ }
+
+ std::unique_ptr<AggregatedRenderPass> CreateTestRootRenderPass(
+ AggregatedRenderPassId id,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect) {
+ auto pass = std::make_unique<AggregatedRenderPass>();
+ const gfx::Transform transform_to_root_target;
+ pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
+ return pass;
+ }
+
+ bool DrawAndTestTrail(base::FilePath::StringPieceType file) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ // Minimize the root render pass damage rect so that it has to be expanded
+ // by the delegated ink trail damage rect to confirm that it is the right
+ // size to remove old trails and add new ones.
+ gfx::Rect damage_rect(0, 0, 1, 1);
+ AggregatedRenderPassId id{1};
+ std::unique_ptr<AggregatedRenderPass> pass =
+ CreateTestRootRenderPass(id, rect, damage_rect);
+
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ gfx::Transform(), rect, pass.get(), gfx::RRectF());
+
+ SolidColorDrawQuad* color_quad =
+ pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
+
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ return this->RunPixelTest(&pass_list, base::FilePath(file),
+ cc::FuzzyPixelOffByOneComparator(true));
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+ DelegatedInkTest,
+ testing::ValuesIn(GetRendererTypesSkiaOnly()),
+ testing::PrintToStringParamName());
+
+// Draw a single trail and erase it, making sure that no bits of trail are left
+// behind.
+TEST_P(DelegatedInkTest, DrawOneTrailAndErase) {
+ // First provide the metadata required to draw the trail, numbers arbitrary.
+ CreateAndSendMetadata(gfx::PointF(10, 10), 3.5f, SK_ColorBLACK,
+ gfx::RectF(0, 0, 175, 172));
+
+ // Then provide some points for the trail to draw. Numbers chosen arbitrarily
+ // after the first point, which must match the metadata. This will predict no
+ // points, so a trail made of 3 points will be drawn.
+ CreateAndSendPointFromMetadata();
+ CreateAndSendPointFromLastPoint(gfx::PointF(75, 62));
+ CreateAndSendPointFromLastPoint(gfx::PointF(124, 45));
+
+ // Confirm that the trail was drawn.
+ EXPECT_TRUE(
+ DrawAndTestTrail(FILE_PATH_LITERAL("delegated_ink_one_trail.png")));
+
+ // The metadata should have been cleared after drawing, so confirm that there
+ // is no trail after another draw.
+ EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL("white.png")));
+}
+
+// Confirm that drawing a second trail completely removes the first trail.
+TEST_P(DelegatedInkTest, DrawTwoTrailsAndErase) {
+ // TODO(crbug.com/1021566): Enable this test for SkiaRenderer Dawn.
+ if (renderer_type() == RendererType::kSkiaDawn)
+ return;
+
+ // First provide the metadata required to draw the trail, numbers arbitrary.
+ CreateAndSendMetadata(gfx::PointF(140, 48), 8.2f, SK_ColorMAGENTA,
+ gfx::RectF(0, 0, 200, 200));
+
+ // Then provide some points for the trail to draw. Numbers chosen arbitrarily
+ // after the first point, which must match the metadata. No points will be
+ // predicted, so a trail made of 2 points will be drawn.
+ CreateAndSendPointFromMetadata();
+ CreateAndSendPointFromLastPoint(gfx::PointF(115, 85));
+
+ // Confirm that the trail was drawn correctly.
+ EXPECT_TRUE(DrawAndTestTrail(
+ FILE_PATH_LITERAL("delegated_ink_two_trails_first.png")));
+
+ // Now provide new metadata and points to draw a new trail. Just use the last
+ // point draw above as the starting point for the new trail. One point will
+ // be predicted, so a trail consisting of 4 points will be drawn.
+ CreateAndSendMetadataFromLastPoint();
+ CreateAndSendPointFromLastPoint(gfx::PointF(134, 100));
+ CreateAndSendPointFromLastPoint(gfx::PointF(150, 81.44f));
+
+ // Confirm the first trail is gone and only the second remains.
+ EXPECT_TRUE(DrawAndTestTrail(
+ FILE_PATH_LITERAL("delegated_ink_two_trails_second.png")));
+
+ // Confirm all trails are gone.
+ EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL("white.png")));
+}
+
+// Confirm that the trail can't be drawn beyond the presentation area.
+TEST_P(DelegatedInkTest, TrailExtendsBeyondPresentationArea) {
+ // TODO(crbug.com/1021566): Enable this test for SkiaRenderer Dawn.
+ if (renderer_type() == RendererType::kSkiaDawn)
+ return;
+
+ const gfx::RectF kPresentationArea(30, 30, 100, 100);
+ CreateAndSendMetadata(gfx::PointF(50.2f, 89.999f), 15.22f, SK_ColorCYAN,
+ kPresentationArea);
+
+ // Send points such that some extend beyond the presentation area to confirm
+ // that the trail is clipped correctly. One point will be predicted, so the
+ // trail will be made of 9 points.
+ CreateAndSendPointFromMetadata();
+ CreateAndSendPointFromLastPoint(gfx::PointF(80.7f, 149.6f));
+ CreateAndSendPointFromLastPoint(gfx::PointF(128.999f, 110.01f));
+ CreateAndSendPointFromLastPoint(gfx::PointF(50, 50));
+ CreateAndSendPointFromLastPoint(gfx::PointF(10.1f, 30.3f));
+ CreateAndSendPointFromLastPoint(gfx::PointF(29.98f, 66));
+ CreateAndSendPointFromLastPoint(gfx::PointF(52.3456f, 2.31f));
+ CreateAndSendPointFromLastPoint(gfx::PointF(97, 36.9f));
+ EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL(
+ "delegated_ink_trail_clipped_by_presentation_area.png")));
+}
+
+// Confirm that the trail appears on top of everything, including batched quads
+// that are drawn as part of the call to FinishDrawingQuadList.
+TEST_P(DelegatedInkTest, DelegatedInkTrailAfterBatchedQuads) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ AggregatedRenderPassId id{1};
+ auto pass = CreateTestRootRenderPass(id, rect, rect);
+
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ gfx::Transform(), rect, pass.get(), gfx::RRectF());
+
+ CreateTestTextureDrawQuad(
+ !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(128, 0, 255, 0), // Texel color.
+ SK_ColorTRANSPARENT, // Background color.
+ true, // Premultiplied alpha.
+ shared_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
+
+ auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
+
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ const gfx::RectF kPresentationArea(0, 0, 200, 200);
+ CreateAndSendMetadata(gfx::PointF(34.f, 72.f), 7.77f, SK_ColorDKGRAY,
+ kPresentationArea);
+ CreateAndSendPointFromMetadata();
+ CreateAndSendPointFromLastPoint(gfx::PointF(79, 101));
+ CreateAndSendPointFromLastPoint(gfx::PointF(134, 114));
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(
+ FILE_PATH_LITERAL("delegated_ink_trail_on_batched_quads.png")),
+ cc::FuzzyPixelOffByOneComparator(true)));
+}
+
+// Confirm that delegated ink trails are not drawn on non-root render passes.
+TEST_P(DelegatedInkTest, SimpleTrailNonRootRenderPass) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ AggregatedRenderPassId child_id{2};
+ auto child_pass = CreateTestRenderPass(child_id, rect, gfx::Transform());
+
+ SharedQuadState* child_shared_state = CreateTestSharedQuadState(
+ gfx::Transform(), rect, child_pass.get(), gfx::RRectF());
+
+ auto* color_quad = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false);
+
+ AggregatedRenderPassId root_id{1};
+ auto root_pass = CreateTestRootRenderPass(root_id, rect, rect);
+
+ SharedQuadState* root_shared_state = CreateTestSharedQuadState(
+ gfx::Transform(), rect, root_pass.get(), gfx::RRectF());
+
+ CreateTestRenderPassDrawQuad(root_shared_state, rect, child_id,
+ root_pass.get());
+
+ auto* child_pass_ptr = child_pass.get();
+
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(child_pass));
+ pass_list.push_back(std::move(root_pass));
+
+ // Values for a simple delegated ink trail, numbers chosen arbitrarily.
+ const gfx::RectF kPresentationArea(0, 0, 200, 200);
+ CreateAndSendMetadata(gfx::PointF(156.f, 111.f), 19.177f, SK_ColorRED,
+ kPresentationArea);
+ CreateAndSendPointFromMetadata();
+ CreateAndSendPointFromLastPoint(gfx::PointF(119, 87.23f));
+ CreateAndSendPointFromLastPoint(gfx::PointF(74.222f, 95.4f));
+
+ // This will only check what was drawn in the child pass, which should never
+ // contain a delegated ink trail, so it should be solid green.
+ EXPECT_TRUE(this->RunPixelTestWithReadbackTarget(
+ &pass_list, child_pass_ptr,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ cc::ExactPixelComparator(true)));
+}
#endif // !defined(OS_ANDROID)
} // namespace
diff --git a/chromium/components/viz/service/display/skia_output_surface.h b/chromium/components/viz/service/display/skia_output_surface.h
index 05592eb3588..7cf1706ee1a 100644
--- a/chromium/components/viz/service/display/skia_output_surface.h
+++ b/chromium/components/viz/service/display/skia_output_surface.h
@@ -122,14 +122,11 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// Finish painting the current frame or current render pass, depends on which
// BeginPaint function is called last. This method will schedule a GPU task to
- // play the DDL back on GPU thread on a cached SkSurface. This method returns
- // a sync token which can be waited on in a command buffer to ensure the paint
- // operation is completed. This token is released when the GPU ops from
- // painting the render pass have been seen and processed by the GPU main.
+ // play the DDL back on GPU thread on a cached SkSurface.
// Optionally the caller may specify |on_finished| callback to be called after
// the GPU has finished processing all submitted commands. The callback may be
// called on a different thread.
- virtual gpu::SyncToken SubmitPaint(base::OnceClosure on_finished) = 0;
+ virtual void EndPaint(base::OnceClosure on_finished) = 0;
// Make a promise SkImage from a render pass id. The render pass has been
// painted with BeginPaintRenderPass and FinishPaintRenderPass. The format
@@ -156,8 +153,12 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// Schedule drawing overlays at next SwapBuffers() call. Waits on
// |sync_tokens| for the overlay textures to be ready before scheduling.
+ // Optionally the caller may specify |on_finished| callback to be called after
+ // the GPU has finished processing all submitted commands. The callback may be
+ // called on a different thread.
virtual void ScheduleOverlays(OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens) = 0;
+ std::vector<gpu::SyncToken> sync_tokens,
+ base::OnceClosure on_finished) = 0;
// Add context lost observer.
virtual void AddContextLostObserver(ContextLostObserver* observer) = 0;
@@ -170,6 +171,11 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
base::OnceClosure callback,
std::vector<gpu::SyncToken> sync_tokens) = 0;
+ // Flush pending GPU tasks. This method returns a sync token which can be
+ // waited on in a command buffer to ensure all pending tasks are executed on
+ // the GPU main thread.
+ virtual gpu::SyncToken Flush() = 0;
+
#if defined(OS_APPLE)
virtual SkCanvas* BeginPaintRenderPassOverlay(
const gfx::Size& size,
diff --git a/chromium/components/viz/service/display/skia_readback_pixeltest.cc b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
index e548e78335a..64d15de10e9 100644
--- a/chromium/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
@@ -49,7 +49,7 @@ SharedQuadState* CreateSharedQuadState(AggregatedRenderPass* render_pass,
const gfx::Rect clip_rect = rect;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), layer_rect, visible_layer_rect,
- gfx::RRectF(), clip_rect, /*is_clipped=*/false,
+ gfx::MaskFilterInfo(), clip_rect, /*is_clipped=*/false,
/*are_contents_opaque=*/false, /*opacity=*/1.0f,
SkBlendMode::kSrcOver,
/*sorting_context_id=*/0);
@@ -194,11 +194,12 @@ TEST_P(SkiaReadbackPixelTest, ExecutesCopyRequest) {
pass->copy_requests.push_back(std::move(request));
AggregatedRenderPassList pass_list;
+ SurfaceDamageRectList surface_damage_rect_list;
pass_list.push_back(std::move(pass));
renderer_->DecideRenderPassAllocationsForFrame(pass_list);
- renderer_->DrawFrame(&pass_list, 1.0f, kSourceSize,
- gfx::DisplayColorSpaces());
+ renderer_->DrawFrame(&pass_list, 1.0f, kSourceSize, gfx::DisplayColorSpaces(),
+ &surface_damage_rect_list);
// Call SwapBuffersSkipped(), so the renderer can have a chance to release
// resources.
renderer_->SwapBuffersSkipped();
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index 73620ae3fa4..0472e5a1820 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -7,6 +7,7 @@
#include <string>
#include <utility>
+#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/bits.h"
#include "base/command_line.h"
@@ -68,6 +69,7 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_util.h"
#if defined(USE_OZONE)
#include "ui/base/ui_base_features.h"
@@ -277,27 +279,28 @@ bool IsAAForcedOff(const DrawQuad* quad) {
}
}
-SkFilterQuality GetFilterQuality(const DrawQuad* quad) {
- bool nearest_neighbor;
+bool UseNearestNeighborSampling(const DrawQuad* quad) {
switch (quad->material) {
case DrawQuad::Material::kPictureContent:
- nearest_neighbor = PictureDrawQuad::MaterialCast(quad)->nearest_neighbor;
- break;
+ return PictureDrawQuad::MaterialCast(quad)->nearest_neighbor;
case DrawQuad::Material::kTextureContent:
- nearest_neighbor = TextureDrawQuad::MaterialCast(quad)->nearest_neighbor;
- break;
+ return TextureDrawQuad::MaterialCast(quad)->nearest_neighbor;
case DrawQuad::Material::kTiledContent:
- nearest_neighbor = TileDrawQuad::MaterialCast(quad)->nearest_neighbor;
- break;
+ return TileDrawQuad::MaterialCast(quad)->nearest_neighbor;
default:
- // Other quad types do not expose filter quality, so default to bilinear
- // TODO(penghuang): figure out how to set correct filter quality for YUV
- // and video stream quads.
- nearest_neighbor = false;
- break;
+ // Other quad types do not expose nearest_neighbor.
+ return false;
}
+}
+
+SkFilterQuality GetFilterQuality(const DrawQuad* quad) {
+ if (UseNearestNeighborSampling(quad))
+ return kNone_SkFilterQuality;
- return nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality;
+ // Default to bilinear if the quad doesn't specify nearest_neighbor.
+ // TODO(penghuang): figure out how to set correct filter quality for YUV and
+ // video stream quads.
+ return kLow_SkFilterQuality;
}
// Returns kFast if sampling outside of vis_tex_coords due to AA or bilerp will
@@ -550,7 +553,7 @@ class SkiaRenderer::ScopedSkImageBuilder {
ResourceId resource_id,
SkAlphaType alpha_type = kPremul_SkAlphaType,
GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin,
- bool use_skia_color_conversion = true);
+ bool use_target_color_space = false);
~ScopedSkImageBuilder() = default;
const SkImage* sk_image() const { return sk_image_; }
@@ -566,14 +569,18 @@ SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
ResourceId resource_id,
SkAlphaType alpha_type,
GrSurfaceOrigin origin,
- bool use_skia_color_conversion) {
+ bool use_target_color_space) {
if (!resource_id)
return;
auto* resource_provider = skia_renderer->resource_provider_;
DCHECK(IsTextureResource(resource_provider, resource_id));
+ gfx::ColorSpace color_space;
+ if (use_target_color_space)
+ color_space = skia_renderer->CurrentRenderPassColorSpace();
+
auto* image_context = skia_renderer->lock_set_for_external_use_->LockResource(
- resource_id, use_skia_color_conversion);
+ resource_id, /*is_video_plane=*/false, color_space);
// |ImageContext::image| provides thread safety: (a) this ImageContext is
// only accessed by GPU thread after |image| is set and (b) the fields of
// ImageContext that are accessed by both compositor and GPU thread are no
@@ -612,20 +619,20 @@ class SkiaRenderer::ScopedYUVSkImageBuilder {
// Skia API ignores the color space information on the individual planes.
// Dropping them here avoids some LOG spam.
auto* y_context = skia_renderer->lock_set_for_external_use_->LockResource(
- quad->y_plane_resource_id(), /*use_skia_color_conversion=*/false);
+ quad->y_plane_resource_id(), /*is_video_plane=*/true);
contexts.push_back(std::move(y_context));
auto* u_context = skia_renderer->lock_set_for_external_use_->LockResource(
- quad->u_plane_resource_id(), /*use_skia_color_conversion=*/false);
+ quad->u_plane_resource_id(), /*is_video_plane=*/true);
contexts.push_back(std::move(u_context));
if (is_i420) {
auto* v_context = skia_renderer->lock_set_for_external_use_->LockResource(
- quad->v_plane_resource_id(), /*use_skia_color_conversion=*/false);
+ quad->v_plane_resource_id(), /*is_video_plane=*/true);
contexts.push_back(std::move(v_context));
}
if (has_alpha) {
auto* a_context = skia_renderer->lock_set_for_external_use_->LockResource(
- quad->a_plane_resource_id(), /*use_skia_color_conversion=*/false);
+ quad->a_plane_resource_id(), /*is_video_plane=*/true);
contexts.push_back(std::move(a_context));
}
@@ -646,24 +653,6 @@ class SkiaRenderer::ScopedYUVSkImageBuilder {
DISALLOW_COPY_AND_ASSIGN(ScopedYUVSkImageBuilder);
};
-SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProvider* resource_provider,
- OverlayProcessorInterface* overlay_processor,
- SkiaOutputSurface* skia_output_surface)
- : DirectRenderer(settings,
- debug_settings,
- output_surface,
- resource_provider,
- overlay_processor),
- skia_output_surface_(skia_output_surface) {
- DCHECK(skia_output_surface_);
- lock_set_for_external_use_.emplace(resource_provider, skia_output_surface_);
-}
-
-SkiaRenderer::~SkiaRenderer() = default;
-
class SkiaRenderer::FrameResourceFence : public ResourceFence {
public:
FrameResourceFence() = default;
@@ -686,6 +675,27 @@ class SkiaRenderer::FrameResourceFence : public ResourceFence {
DISALLOW_COPY_AND_ASSIGN(FrameResourceFence);
};
+SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
+ const DebugRendererSettings* debug_settings,
+ OutputSurface* output_surface,
+ DisplayResourceProvider* resource_provider,
+ OverlayProcessorInterface* overlay_processor,
+ SkiaOutputSurface* skia_output_surface)
+ : DirectRenderer(settings,
+ debug_settings,
+ output_surface,
+ resource_provider,
+ overlay_processor),
+ skia_output_surface_(skia_output_surface) {
+ DCHECK(skia_output_surface_);
+ lock_set_for_external_use_.emplace(resource_provider, skia_output_surface_);
+
+ current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
+ resource_provider_->SetReadLockFence(current_frame_resource_fence_.get());
+}
+
+SkiaRenderer::~SkiaRenderer() = default;
+
bool SkiaRenderer::CanPartialSwap() {
return output_surface_->capabilities().supports_post_sub_buffer;
}
@@ -693,10 +703,7 @@ bool SkiaRenderer::CanPartialSwap() {
void SkiaRenderer::BeginDrawingFrame() {
TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame");
- DCHECK(!current_frame_resource_fence_);
-
- current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
- resource_provider_->SetReadLockFence(current_frame_resource_fence_.get());
+ DCHECK(!current_frame_resource_fence_->WasSet());
#if defined(OS_ANDROID)
for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
@@ -710,7 +717,6 @@ void SkiaRenderer::BeginDrawingFrame() {
void SkiaRenderer::FinishDrawingFrame() {
TRACE_EVENT0("viz", "SkiaRenderer::FinishDrawingFrame");
- current_frame_resource_fence_ = nullptr;
current_canvas_ = nullptr;
current_surface_ = nullptr;
@@ -746,14 +752,17 @@ void SkiaRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
skia_output_surface_->SwapBuffers(std::move(output_frame));
swap_buffer_rect_ = gfx::Rect();
+
+ FlushOutputSurface();
}
void SkiaRenderer::SwapBuffersSkipped() {
skia_output_surface_->SwapBuffersSkipped();
+ FlushOutputSurface();
}
void SkiaRenderer::SwapBuffersComplete() {
- // Right now, only macOS needs to return maliboxes of released overlays, so
+ // Right now, only macOS needs to return mailboxes of released overlays, so
// we should not release |committed_overlay_locks_| here. The resources in it
// will be released by DidReceiveReleasedOverlays() later.
#if defined(OS_APPLE)
@@ -1237,8 +1246,8 @@ SkiaRenderer::DrawQuadParams SkiaRenderer::CalculateDrawQuadParams(
if (ShouldApplyRoundedCorner(quad)) {
// Transform by the window and projection matrix to go from target to
// device space, which should always be a scale+translate.
- SkRRect corner_bounds =
- SkRRect(quad->shared_quad_state->rounded_corner_bounds);
+ SkRRect corner_bounds = SkRRect(
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds());
SkMatrix to_device;
gfx::TransformToFlattenedSkMatrix(target_to_device, &to_device);
@@ -1312,6 +1321,12 @@ const DrawQuad* SkiaRenderer::CanPassBeDrawnDirectly(
quad->material == DrawQuad::Material::kPictureContent)
return nullptr;
+ // If the quad specifies nearest-neighbor scaling then there could be two
+ // scaling operations at different quality levels. This requires drawing to an
+ // intermediate render pass. See https://crbug.com/1155338.
+ if (UseNearestNeighborSampling(quad))
+ return nullptr;
+
if (quad->material == DrawQuad::Material::kTextureContent) {
// Per-vertex opacities complicate bypassing the RP and alpha blending the
// texture with image filters, so punt under that rare circumstance.
@@ -1808,7 +1823,7 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
this, quad->resource_id(),
quad->premultiplied_alpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType,
quad->y_flipped ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin,
- /*use_skia_color_conversion=*/!needs_color_conversion_filter);
+ /*use_target_color_space=*/needs_color_conversion_filter);
const SkImage* image = builder.sk_image();
if (!image)
return;
@@ -2058,6 +2073,8 @@ void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad,
}
void SkiaRenderer::ScheduleOverlays() {
+ DCHECK(!current_frame_resource_fence_->WasSet());
+
pending_overlay_locks_.emplace_back();
if (current_frame()->overlay_list.empty())
return;
@@ -2162,8 +2179,17 @@ void SkiaRenderer::ScheduleOverlays() {
NOTREACHED();
#endif // defined(OS_ANDROID)
+ base::OnceClosure on_finished_callback;
+ if (current_frame_resource_fence_->WasSet()) {
+ on_finished_callback = base::BindOnce(
+ &FrameResourceFence::Signal, std::move(current_frame_resource_fence_));
+ current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
+ resource_provider_->SetReadLockFence(current_frame_resource_fence_.get());
+ }
+
skia_output_surface_->ScheduleOverlays(
- std::move(current_frame()->overlay_list), std::move(sync_tokens));
+ std::move(current_frame()->overlay_list), std::move(sync_tokens),
+ std::move(on_finished_callback));
}
sk_sp<SkColorFilter> SkiaRenderer::GetColorSpaceConversionFilter(
@@ -2498,20 +2524,35 @@ void SkiaRenderer::FinishDrawingQuadList() {
if (!batched_quads_.empty())
FlushBatchedQuads();
+ bool is_root_render_pass =
+ current_frame()->current_render_pass == current_frame()->root_render_pass;
+
+ // Drawing the delegated ink trail must happen after the final
+ // FlushBatchedQuads() call so that the trail can always be on top of
+ // everything else that has already been drawn on the page. For the same
+ // reason, it should only happen on the root render pass.
+ if (is_root_render_pass && delegated_ink_point_renderer_)
+ DrawDelegatedInkTrail();
+
base::OnceClosure on_finished_callback;
// Signal |current_frame_resource_fence_| when the root render pass is
// finished.
- if (current_frame_resource_fence_ &&
- current_frame_resource_fence_->WasSet() &&
- current_frame()->current_render_pass ==
- current_frame()->root_render_pass) {
+ if (current_frame_resource_fence_->WasSet()) {
on_finished_callback = base::BindOnce(
&FrameResourceFence::Signal, std::move(current_frame_resource_fence_));
+ current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
+ resource_provider_->SetReadLockFence(current_frame_resource_fence_.get());
}
- gpu::SyncToken sync_token =
- skia_output_surface_->SubmitPaint(std::move(on_finished_callback));
+ skia_output_surface_->EndPaint(std::move(on_finished_callback));
- lock_set_for_external_use_->UnlockResources(sync_token);
+ // Defer flushing drawing task for root render pass, to avoid extra
+ // MakeCurrent() call. It is expensive on GL.
+ // TODO(https://crbug.com/1141008): Consider deferring drawing tasks for
+ // all render passes.
+ if (is_root_render_pass)
+ return;
+
+ FlushOutputSurface();
}
void SkiaRenderer::GenerateMipmap() {
@@ -2575,6 +2616,11 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
color_space, format}));
}
+void SkiaRenderer::FlushOutputSurface() {
+ auto sync_token = skia_output_surface_->Flush();
+ lock_set_for_external_use_->UnlockResources(sync_token);
+}
+
#if defined(OS_APPLE)
void SkiaRenderer::PrepareRenderPassOverlay(CALayerOverlay* overlay) {
DCHECK(!current_canvas_);
@@ -2582,21 +2628,82 @@ void SkiaRenderer::PrepareRenderPassOverlay(CALayerOverlay* overlay) {
DCHECK(overlay->rpdq);
auto* const quad = overlay->rpdq;
+
+ // The overlay will be sent to GPU the thread, so set rpdq to nullptr to avoid
+ // being accessed on the GPU thread.
overlay->rpdq = nullptr;
- gfx::Transform target_to_device =
- current_frame()->window_matrix * current_frame()->projection_matrix;
- const gfx::Rect* scissor = is_scissor_enabled_ ? &scissor_rect_ : nullptr;
+ // The |current_render_pass| could be used for calculating destination
+ // color space or clipping rect for backdrop filters. However
+ // the |current_render_pass| is nullptr during ScheduleOverlays(), since all
+ // overlay quads should be in the |root_render_pass|, before they are promoted
+ // to overlays, so set the |root_render_pass| to the |current_render_pass|.
+ base::AutoReset<const AggregatedRenderPass*> auto_reset_current_render_pass(
+ &current_frame()->current_render_pass, current_frame()->root_render_pass);
+
+ auto* shared_quad_state =
+ const_cast<SharedQuadState*>(quad->shared_quad_state);
+
+ gfx::Transform quad_to_target_transform_inverse(
+ gfx::Transform::kSkipInitialization);
+ if (shared_quad_state->is_clipped ||
+ !shared_quad_state->mask_filter_info.IsEmpty()) {
+ bool result = shared_quad_state->quad_to_target_transform.GetInverse(
+ &quad_to_target_transform_inverse);
+ DCHECK(result) << "quad_to_target_transform.GetInverse() failed";
+ }
+
+ // The |clip_rect| is in the device coordinate and with all transforms
+ // (translation, scaling, rotation, etc), so remove them.
+ base::Optional<base::AutoReset<gfx::Rect>> auto_reset_clip_rect;
+ if (shared_quad_state->is_clipped) {
+ gfx::RectF clip_rect(shared_quad_state->clip_rect);
+ quad_to_target_transform_inverse.TransformRect(&clip_rect);
+ auto_reset_clip_rect.emplace(&shared_quad_state->clip_rect,
+ gfx::ToEnclosedRect(clip_rect));
+ }
+
+ // The |mask_filter_info| is in the device coordinate and with all transforms
+ // (translation, scaling, rotation, etc), so remove them.
+ if (!shared_quad_state->mask_filter_info.IsEmpty()) {
+ auto result = shared_quad_state->mask_filter_info.Transform(
+ quad_to_target_transform_inverse);
+ DCHECK(result) << "shared_quad_state->mask_filter_info.Transform() failed.";
+ }
+
+ // Reset |quad_to_target_transform|, so the quad will be rendered at the
+ // origin (0,0) without all transforms (translation, scaling, rotation, etc)
+ // and then we will use OS compositor to do those transforms.
+ base::AutoReset<gfx::Transform> auto_reset_transform(
+ &shared_quad_state->quad_to_target_transform, gfx::Transform());
+
+ const auto& viewport_size = current_frame()->device_viewport_size;
+ auto projection_matrix = gfx::OrthoProjectionMatrix(
+ /*left=*/0, /*right=*/viewport_size.width(), /*bottom=*/0,
+ /*top=*/viewport_size.height());
+ auto window_matrix =
+ gfx::WindowMatrix(/*x=*/0, /*y=*/0, /*width=*/viewport_size.width(),
+ /*height=*/viewport_size.height());
+
+ gfx::Transform target_to_device = window_matrix * projection_matrix;
+
+ // Use nullptr scissor, so we can always render the whole render pass in an
+ // overlay backing.
+ // TODO(penghuang): reusing overlay backing from previous frame to avoid
+ // reproducing the overlay backing if the render pass content quad properties
+ // and content are not changed.
DrawQuadParams params = CalculateDrawQuadParams(
- target_to_device, scissor, quad, /*draw_region=*/nullptr);
+ target_to_device, /*scissor=*/nullptr, quad, /*draw_region=*/nullptr);
DrawRPDQParams rpdq_params = CalculateRPDQParams(quad, &params);
+ const auto& filter_bounds = rpdq_params.filter_bounds;
+
// |filter_bounds| is the content space bounds that includes any filtered
// extents. If empty, the draw can be skipped.
- if (rpdq_params.filter_bounds.IsEmpty())
+ if (filter_bounds.IsEmpty())
return;
- ResourceFormat buffer_format;
+ ResourceFormat buffer_format{};
gfx::ColorSpace color_space;
RenderPassBacking* backing = nullptr;
@@ -2622,16 +2729,13 @@ void SkiaRenderer::PrepareRenderPassOverlay(CALayerOverlay* overlay) {
color_space = backing->color_space;
}
- auto dst_filter_bounds = gfx::RectF(rpdq_params.filter_bounds);
- params.content_device_transform.TransformRect(&dst_filter_bounds);
- gfx::Size buffer_size = gfx::ToCeiledSize(dst_filter_bounds.size());
// Adjust the overlay |buffer_size| to reduce memory fragmentation. It also
// increases buffer reusing possibilities.
constexpr int kBufferMultiple = 64;
- buffer_size.SetSize(
- cc::MathUtil::CheckedRoundUp(buffer_size.width(), kBufferMultiple),
- cc::MathUtil::CheckedRoundUp(buffer_size.height(), kBufferMultiple));
+ gfx::Size buffer_size(
+ cc::MathUtil::CheckedRoundUp(filter_bounds.width(), kBufferMultiple),
+ cc::MathUtil::CheckedRoundUp(filter_bounds.height(), kBufferMultiple));
current_canvas_ = skia_output_surface_->BeginPaintRenderPassOverlay(
buffer_size, buffer_format, /*mipmap=*/false,
@@ -2641,16 +2745,19 @@ void SkiaRenderer::PrepareRenderPassOverlay(CALayerOverlay* overlay) {
return;
}
- current_canvas_->clear(overlay->background_color);
-
- // Calculate visible_rect's origin in output device coordinates.
- auto dst_visible_rect_origin = params.visible_rect.origin();
- params.content_device_transform.TransformPoint(&dst_visible_rect_origin);
+ // Clear the backing to ARGB(0,0,0,0).
+ current_canvas_->clear(SkColorSetARGB(0, 0, 0, 0));
- // Adjust the content_device_transform to make sure filter extends are drawn
+ // Adjust the |content_device_transform| to make sure filter extends are drawn
// inside of the buffer.
- params.content_device_transform.Translate(-dst_filter_bounds.x(),
- -dst_filter_bounds.y());
+ params.content_device_transform.Translate(-filter_bounds.x(),
+ -filter_bounds.y());
+
+ // Also adjust the |rounded_corner_bounds| to the new location.
+ if (params.rounded_corner_bounds) {
+ params.rounded_corner_bounds->Offset(-filter_bounds.x(),
+ -filter_bounds.y());
+ }
// When Render Pass has a single quad inside we would draw that directly.
if (bypass != render_pass_bypass_quads_.end()) {
@@ -2695,16 +2802,11 @@ void SkiaRenderer::PrepareRenderPassOverlay(CALayerOverlay* overlay) {
// Put overlay related information in CALayerOverlay,
// so SkiaOutputSurfaceImplOnGpu can use the DDL to create overlay buffer and
// play the DDL back to it accordingly.
- overlay->bounds_rect = gfx::RectF(gfx::SizeF(buffer_size));
overlay->ddl = std::move(ddl);
- // Since the overlay may be in different size comparing to the render pass's
- // visible rect due to filter effect extends and buffer size round up, so we
- // have to adjust the overlay transform to put overlay at the right position.
- overlay->transform = overlay->shared_state->transform;
- overlay->transform->preTranslate(
- -dst_visible_rect_origin.x() + dst_filter_bounds.x(),
- -dst_visible_rect_origin.y() + dst_filter_bounds.y(), 0);
+ // Adjust |bounds_rect| to contain the whole buffer and at the right location.
+ overlay->bounds_rect.set_origin(gfx::PointF(filter_bounds.origin()));
+ overlay->bounds_rect.set_size(gfx::SizeF(buffer_size));
}
#endif
@@ -2728,6 +2830,17 @@ bool SkiaRenderer::CreateDelegatedInkPointRenderer() {
return true;
}
+void SkiaRenderer::DrawDelegatedInkTrail() {
+ delegated_ink_point_renderer_->DrawDelegatedInkTrail(current_canvas_);
+}
+
+DelegatedInkPointRendererBase* SkiaRenderer::GetDelegatedInkPointRenderer() {
+ if (!delegated_ink_point_renderer_ && !CreateDelegatedInkPointRenderer())
+ return nullptr;
+
+ return delegated_ink_point_renderer_.get();
+}
+
#if defined(OS_APPLE)
bool SkiaRenderer::ScopedReadLockComparator::operator()(
const DisplayResourceProvider::ScopedReadLockSharedImage& lhs,
diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h
index ad22656c2f5..b5a3d53cadd 100644
--- a/chromium/components/viz/service/display/skia_renderer.h
+++ b/chromium/components/viz/service/display/skia_renderer.h
@@ -25,6 +25,8 @@ class SkRuntimeEffect;
namespace viz {
class AggregatedRenderPassDrawQuad;
class DebugBorderDrawQuad;
+class DelegatedInkPointRendererBase;
+class DelegatedInkPointRendererSkia;
class PictureDrawQuad;
class SkiaOutputSurface;
class SolidColorDrawQuad;
@@ -56,6 +58,8 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
disable_picture_quad_image_filtering_ = disable;
}
+ DelegatedInkPointRendererBase* GetDelegatedInkPointRenderer() override;
+
protected:
bool CanPartialSwap() override;
void UpdateRenderPassTextures(
@@ -88,6 +92,8 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
void GenerateMipmap() override;
bool CreateDelegatedInkPointRenderer() override;
+ std::unique_ptr<DelegatedInkPointRendererSkia> delegated_ink_point_renderer_;
+
private:
enum class BypassMode;
struct DrawQuadParams;
@@ -221,6 +227,8 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
const DrawQuad* CanPassBeDrawnDirectly(
const AggregatedRenderPass* pass) override;
+ void DrawDelegatedInkTrail() override;
+
// Get a color filter that converts from |src| color space to |dst| color
// space using a shader constructed from gfx::ColorTransform. The color
// filters are cached in |color_filter_cache_|. Resource offset and
@@ -234,6 +242,10 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
// Returns the color filter that should be applied to the current canvas.
sk_sp<SkColorFilter> GetContentColorFilter();
+ // Flush SkiaOutputSurface, so all pending GPU tasks in SkiaOutputSurface will
+ // be sent to GPU scheduler.
+ void FlushOutputSurface();
+
#if defined(OS_APPLE)
void PrepareRenderPassOverlay(CALayerOverlay* overlay);
#endif
diff --git a/chromium/components/viz/service/display/software_output_device.cc b/chromium/components/viz/service/display/software_output_device.cc
index 73e22fb8fe8..0ac41068d5f 100644
--- a/chromium/components/viz/service/display/software_output_device.cc
+++ b/chromium/components/viz/service/display/software_output_device.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/check.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/vsync_provider.h"
@@ -38,7 +39,8 @@ void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size,
SkImageInfo::MakeN32(viewport_pixel_size.width(),
viewport_pixel_size.height(), kOpaque_SkAlphaType);
viewport_pixel_size_ = viewport_pixel_size;
- surface_ = SkSurface::MakeRaster(info);
+ SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
+ surface_ = SkSurface::MakeRaster(info, &props);
}
SkCanvas* SoftwareOutputDevice::BeginPaint(const gfx::Rect& damage_rect) {
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index 3aafdbd4fcc..946d678889a 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -30,6 +30,7 @@
#include "components/viz/service/display/renderer_utils.h"
#include "components/viz/service/display/software_output_device.h"
#include "skia/ext/image_operations.h"
+#include "skia/ext/legacy_display_globals.h"
#include "skia/ext/opacity_filter_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -65,8 +66,8 @@ class AnimatedImagesProvider : public cc::ImageProvider {
return ScopedResult(cc::DecodedDrawImage(
paint_image.GetSkImageForFrame(
frame_index, cc::PaintImage::kDefaultGeneratorClientId),
- SkSize::Make(0, 0), SkSize::Make(1.f, 1.f), draw_image.filter_quality(),
- true /* is_budgeted */));
+ nullptr, SkSize::Make(0, 0), SkSize::Make(1.f, 1.f),
+ draw_image.filter_quality()));
}
private:
@@ -146,7 +147,8 @@ void SoftwareRenderer::BindFramebufferToTexture(
DCHECK(it != render_pass_bitmaps_.end());
SkBitmap& bitmap = it->second;
- current_framebuffer_canvas_ = std::make_unique<SkCanvas>(bitmap);
+ current_framebuffer_canvas_ = std::make_unique<SkCanvas>(
+ bitmap, skia::LegacyDisplayGlobals::GetSkSurfaceProps());
current_canvas_ = current_framebuffer_canvas_.get();
}
@@ -257,7 +259,8 @@ void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
}
if (should_apply_rounded_corner)
- SetClipRRect(quad->shared_quad_state->rounded_corner_bounds);
+ SetClipRRect(
+ quad->shared_quad_state->mask_filter_info.rounded_corner_bounds());
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix,
@@ -875,7 +878,7 @@ sk_sp<SkShader> SoftwareRenderer::GetBackdropFilterShader(
if (!bitmap.tryAllocPixels(info))
base::TerminateBecauseOutOfMemory(info.computeMinByteSize());
- SkCanvas canvas(bitmap);
+ SkCanvas canvas(bitmap, skia::LegacyDisplayGlobals::GetSkSurfaceProps());
// Clip the filtered image to the (rounded) bounding box of the element.
if (backdrop_filter_bounds) {
diff --git a/chromium/components/viz/service/display/software_renderer_unittest.cc b/chromium/components/viz/service/display/software_renderer_unittest.cc
index 589fb7cabc3..91e223e0222 100644
--- a/chromium/components/viz/service/display/software_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/software_renderer_unittest.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/run_loop.h"
@@ -109,8 +109,9 @@ class SoftwareRendererTest : public testing::Test {
base::BindOnce(&SoftwareRendererTest::SaveBitmapResult,
base::Unretained(&bitmap_result), loop.QuitClosure())));
+ SurfaceDamageRectList surface_damage_rect_list;
renderer()->DrawFrame(list, device_scale_factor, viewport_size,
- gfx::DisplayColorSpaces());
+ gfx::DisplayColorSpaces(), &surface_damage_rect_list);
loop.Run();
return bitmap_result;
}
@@ -152,7 +153,7 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
- gfx::RRectF(), outer_rect, false, true, 1.0,
+ gfx::MaskFilterInfo(), outer_rect, false, true, 1.0,
SkBlendMode::kSrcOver, 0);
auto* inner_quad =
root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -220,7 +221,7 @@ TEST_F(SoftwareRendererTest, TileQuad) {
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
- gfx::RRectF(), outer_rect, false, true, 1.0,
+ gfx::MaskFilterInfo(), outer_rect, false, true, 1.0,
SkBlendMode::kSrcOver, 0);
auto* inner_quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, needs_blending,
@@ -282,7 +283,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(), tile_rect, tile_rect,
- gfx::RRectF(), tile_rect, false, true, 1.0,
+ gfx::MaskFilterInfo(), tile_rect, false, true, 1.0,
SkBlendMode::kSrcOver, 0);
auto* quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
quad->SetNew(shared_quad_state, tile_rect, tile_rect, needs_blending,
@@ -443,8 +444,8 @@ TEST_F(SoftwareRendererTest, ClipRoundRect) {
SharedQuadState* shared_quad_state =
root_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
- gfx::RRectF(), gfx::Rect(1, 1, 30, 30), true,
- true, 1.0, SkBlendMode::kSrcOver, 0);
+ gfx::MaskFilterInfo(), gfx::Rect(1, 1, 30, 30),
+ true, true, 1.0, SkBlendMode::kSrcOver, 0);
auto* outer_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
outer_quad->SetNew(shared_quad_state, outer_rect, outer_rect, SK_ColorGREEN,
false);
@@ -457,10 +458,10 @@ TEST_F(SoftwareRendererTest, ClipRoundRect) {
SharedQuadState* shared_quad_state =
root_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(gfx::Transform(), inner_rect, inner_rect,
- gfx::RRectF(gfx::RectF(5, 5, 10, 10), 2),
- inner_rect, false, true, 1.0,
- SkBlendMode::kSrcOver, 0);
+ shared_quad_state->SetAll(
+ gfx::Transform(), inner_rect, inner_rect,
+ gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(5, 5, 10, 10), 2)),
+ inner_rect, false, true, 1.0, SkBlendMode::kSrcOver, 0);
auto* inner_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, SK_ColorRED,
false);
@@ -529,6 +530,7 @@ TEST_F(SoftwareRendererTest, PartialSwap) {
// tests.
AggregatedRenderPassList list;
AggregatedRenderPassId root_pass_id{1};
+ SurfaceDamageRectList surface_damage_rect_list;
auto* root_pass =
AddRenderPass(&list, root_pass_id, gfx::Rect(viewport_size),
gfx::Transform(), cc::FilterOperations());
@@ -540,11 +542,12 @@ TEST_F(SoftwareRendererTest, PartialSwap) {
renderer()->DecideRenderPassAllocationsForFrame(list);
renderer()->DrawFrame(&list, device_scale_factor, viewport_size,
- gfx::DisplayColorSpaces());
+ gfx::DisplayColorSpaces(), &surface_damage_rect_list);
}
{
AggregatedRenderPassList list;
AggregatedRenderPassId root_pass_id{1};
+ SurfaceDamageRectList surface_damage_rect_list;
auto* root_pass =
AddRenderPass(&list, root_pass_id, gfx::Rect(viewport_size),
gfx::Transform(), cc::FilterOperations());
@@ -556,7 +559,7 @@ TEST_F(SoftwareRendererTest, PartialSwap) {
renderer()->DecideRenderPassAllocationsForFrame(list);
renderer()->DrawFrame(&list, device_scale_factor, viewport_size,
- gfx::DisplayColorSpaces());
+ gfx::DisplayColorSpaces(), &surface_damage_rect_list);
// The damage rect should be reported to the SoftwareOutputDevice.
EXPECT_EQ(gfx::Rect(2, 2, 3, 3), device->damage_rect_at_start());
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index 4b5d29ec736..2c17f6b2f2b 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -80,6 +80,20 @@ bool CalculateQuadSpaceDamageRect(
return true;
}
+gfx::Rect GetExpandedRectWithPixelMovingForegroundFilter(
+ const CompositorRenderPassDrawQuad* rpdq,
+ const CompositorRenderPass& child_render_pass) {
+ const SharedQuadState* shared_quad_state = rpdq->shared_quad_state;
+ float max_pixel_movement = child_render_pass.filters.MaximumPixelMovement();
+ gfx::RectF rect(rpdq->rect);
+ rect.Inset(-max_pixel_movement, -max_pixel_movement);
+ gfx::Rect expanded_rect = gfx::ToEnclosingRect(rect);
+
+ // expanded_rect in the target space
+ return cc::MathUtil::MapEnclosingClippedRect(
+ shared_quad_state->quad_to_target_transform, expanded_rect);
+}
+
} // namespace
struct SurfaceAggregator::ClipData {
@@ -100,22 +114,20 @@ struct SurfaceAggregator::PrewalkResult {
gfx::ContentColorUsage content_color_usage = gfx::ContentColorUsage::kSRGB;
};
-struct SurfaceAggregator::RoundedCornerInfo {
- RoundedCornerInfo() = default;
-
- // |target_transform| is the transform that maps |bounds_arg| from its current
- // space into the desired target space. It must be an axis aligned transform.
- RoundedCornerInfo(const gfx::RRectF& bounds_arg,
- bool is_fast_rounded_corner,
+struct SurfaceAggregator::MaskFilterInfoExt {
+ MaskFilterInfoExt() = default;
+ MaskFilterInfoExt(const gfx::MaskFilterInfo& mask_filter_info_arg,
+ bool is_fast_rounded_corner_arg,
const gfx::Transform target_transform)
- : bounds(bounds_arg), is_fast_rounded_corner(is_fast_rounded_corner) {
- if (bounds.IsEmpty())
+ : mask_filter_info(mask_filter_info_arg),
+ is_fast_rounded_corner(is_fast_rounded_corner_arg) {
+ if (mask_filter_info.IsEmpty())
return;
- bool success = target_transform.TransformRRectF(&bounds);
+ bool success = mask_filter_info.Transform(target_transform);
DCHECK(success);
}
- gfx::RRectF bounds;
+ gfx::MaskFilterInfo mask_filter_info;
bool is_fast_rounded_corner;
};
@@ -136,11 +148,11 @@ struct SurfaceAggregator::RenderPassMapEntry {
SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
DisplayResourceProvider* provider,
bool aggregate_only_damaged,
- bool needs_surface_occluding_damage_rect)
+ bool needs_surface_damage_rect_list)
: manager_(manager),
provider_(provider),
aggregate_only_damaged_(aggregate_only_damaged),
- needs_surface_occluding_damage_rect_(needs_surface_occluding_damage_rect),
+ needs_surface_damage_rect_list_(needs_surface_damage_rect_list),
de_jelly_enabled_(DeJellyEnabled()) {
DCHECK(manager_);
}
@@ -248,89 +260,113 @@ gfx::Rect SurfaceAggregator::DamageRectForSurface(
return full_rect;
}
-gfx::Rect SurfaceAggregator::CalculateOccludingSurfaceDamageRect(
- const DrawQuad* quad,
- const gfx::Transform& parent_quad_to_root_target_transform) {
- if (damage_rects_union_of_surfaces_on_top_.IsEmpty())
- return gfx::Rect();
+// This function is called at each render pass - CopyQuadsToPass().
+void SurfaceAggregator::AddRenderPassFilterDamageToDamageList(
+ const gfx::Transform& parent_target_transform,
+ const CompositorRenderPass* source_pass,
+ AggregatedRenderPass* dest_pass) {
+ // Add damages from render passes with pixel-moving foreground filters or
+ // backdrop filters to the surface damage list.
+ if (!source_pass->filters.HasFilterThatMovesPixels() &&
+ !source_pass->backdrop_filters.HasFilterThatMovesPixels()) {
+ return;
+ }
- // Transform the quad to the root target space.
- gfx::Rect quad_in_root_target_space;
- if (quad->shared_quad_state->is_clipped) {
- gfx::Rect quad_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
- quad->shared_quad_state->quad_to_target_transform, quad->visible_rect);
- quad_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
- quad_in_root_target_space = cc::MathUtil::MapEnclosingClippedRect(
- parent_quad_to_root_target_transform, quad_in_target_space);
+ gfx::Transform parent_to_root_target_transform = gfx::Transform(
+ dest_pass->transform_to_root_target, parent_target_transform);
- } else {
- gfx::Transform transform(parent_quad_to_root_target_transform,
- quad->shared_quad_state->quad_to_target_transform);
- quad_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect);
+ gfx::Rect damage_rect = source_pass->output_rect;
+ if (source_pass->filters.HasFilterThatMovesPixels()) {
+ float max_pixel_movement = source_pass->filters.MaximumPixelMovement();
+ gfx::RectF damage_rect_f(damage_rect);
+ damage_rect_f.Inset(-max_pixel_movement, -max_pixel_movement);
+ damage_rect = gfx::ToEnclosingRect(damage_rect_f);
}
- // damage_rects_union_of_surfaces_on_top_ is already in the root target
- // space.
- gfx::Rect occluding_damage_rect = damage_rects_union_of_surfaces_on_top_;
- occluding_damage_rect.Intersect(quad_in_root_target_space);
+ gfx::Rect damage_rect_in_root_target_space =
+ cc::MathUtil::MapEnclosingClippedRect(parent_to_root_target_transform,
+ damage_rect);
- return occluding_damage_rect;
+ // The whole render pass rect with pixel-moving foreground filters or
+ // backdrop filters is considered damaged if it intersects with the other
+ // damages.
+ if (damage_rect_in_root_target_space.Intersects(root_damage_rect_)) {
+ // Transform will be performed again in AddSurfaceDamageToDamageList()
+ // Just pass in damage_rect instead of damage_rect_in_root_target_space.
+ AddSurfaceDamageToDamageList(damage_rect, gfx::Transform(), {}, source_pass,
+ dest_pass, /*surface=*/nullptr);
+ }
}
-// In CopyPasses(), surfaces are processed from top to bottom. Therefore, all
-// surfaces on top has been added to damage_rects_union_of_surfaces_on_top_
-// before this.
-void SurfaceAggregator::UnionSurfaceDamageRectsOnTop(
- const gfx::Rect& damage_rect,
- const gfx::Transform& parent_to_root_target_transform,
- const ClipData& clip_rect) {
- DCHECK(!damage_rect.IsEmpty());
+// This is different from the |root_damage_rect_| which is the union of all
+// surface damages. This function records per-surface damage rects to
+// |surface_damage_rect_list_| in a top-to-bottom order.
+// it's called at each surface in the frame.
+void SurfaceAggregator::AddSurfaceDamageToDamageList(
+ const gfx::Rect& default_damage_rect,
+ const gfx::Transform& parent_target_transform,
+ const ClipData& clip_rect,
+ const CompositorRenderPass* source_pass,
+ AggregatedRenderPass* dest_pass,
+ Surface* surface) {
+ gfx::Rect damage_rect;
+ if (!surface) {
+ // When the surface is null, it's either the surface is lost or it comes
+ // from a render pass with filters.
+ damage_rect = default_damage_rect;
+ } else {
+ if (RenderPassNeedsFullDamage(dest_pass->id,
+ dest_pass->cache_render_pass)) {
+ damage_rect = source_pass->output_rect;
+ } else {
+ damage_rect =
+ DamageRectForSurface(surface, *source_pass, source_pass->output_rect);
+ }
+ }
+
+ if (damage_rect.IsEmpty()) {
+ current_zero_damage_rect_is_not_recorded_ = true;
+ return;
+ }
+ current_zero_damage_rect_is_not_recorded_ = false;
+
+ gfx::Transform parent_to_root_target_transform = gfx::Transform(
+ dest_pass->transform_to_root_target, parent_target_transform);
gfx::Rect damage_rect_in_root_target_space =
cc::MathUtil::MapEnclosingClippedRect(parent_to_root_target_transform,
damage_rect);
- if (clip_rect.is_clipped)
- damage_rect_in_root_target_space.Intersect(clip_rect.rect);
+ if (clip_rect.is_clipped) {
+ gfx::Rect root_clip_rect = cc::MathUtil::MapEnclosingClippedRect(
+ dest_pass->transform_to_root_target, clip_rect.rect);
+ damage_rect_in_root_target_space.Intersect(root_clip_rect);
+ }
- damage_rects_union_of_surfaces_on_top_.Union(
- damage_rect_in_root_target_space);
+ surface_damage_rect_list_->push_back(damage_rect_in_root_target_space);
}
-// This is for underlay video power optimization.
-// The purpose of this function is to calculate the occluding damage rect if
-// there are elements on top of underlay. This damage rect is later saved in
-// shared_quad_state->occluding_damage_rect and used by the overlay
-// processor for damage rect optimization. This function is called once
-// for each surface. It adds the damage rects of all surfaces to
-// damage_rects_union_of_surfaces_on_top_. If there is a DrawQuad in the
-// surface to which the optimization can be applied, this function returns
-// that quad and sets the occluding_damage_rect out parameter to the
-// appropriate rectangle.
-const DrawQuad* SurfaceAggregator::ProcessSurfaceOccludingDamage(
+// This function returns the overlay candidate quad ptr which has an
+// overlay_damage_index pointing to the its damage rect in
+// surface_damage_rect_list_. |overlay_damage_index| will be saved in the shared
+// quad state later.
+// This function is called at CopyQuadsToPass().
+const DrawQuad* SurfaceAggregator::FindQuadWithOverlayDamage(
const CompositorRenderPass& source_pass,
AggregatedRenderPass* dest_pass,
const gfx::Transform& parent_target_transform,
const SurfaceId& surface_id,
const ClipData& clip_rect,
- gfx::Rect* occluding_damage_rect) {
- if (!needs_surface_occluding_damage_rect_)
- return nullptr;
-
+ size_t* overlay_damage_index) {
Surface* surface = manager_->GetSurfaceForId(surface_id);
- DCHECK(surface);
- // Only process the damage rect once per surface.
+
+ // Only process the damage rect at the root render pass, once per surface.
const CompositorFrame& frame = surface->GetActiveFrame();
bool is_last_pass_on_src_surface =
&source_pass == frame.render_pass_list.back().get();
if (!is_last_pass_on_src_surface)
return nullptr;
- // Transform from the parent quad space to the root target space.
- gfx::Transform parent_quad_to_root_target_transform = gfx::Transform(
- dest_pass->transform_to_root_target, parent_target_transform);
-
// The occluding damage optimization currently relies on two things - there
// can't be any damage above the quad within the surface, and the quad needs
// its own SQS for the occluding_damage_rect metadata.
@@ -358,35 +394,21 @@ const DrawQuad* SurfaceAggregator::ProcessSurfaceOccludingDamage(
}
}
- if (target_quad) {
- *occluding_damage_rect = CalculateOccludingSurfaceDamageRect(
- target_quad, parent_quad_to_root_target_transform);
- }
+ // No overlay candidate is found.
+ if (!target_quad)
+ return nullptr;
- gfx::Rect surface_damage_rect;
- if (RenderPassNeedsFullDamage(dest_pass->id, dest_pass->cache_render_pass)) {
- surface_damage_rect = source_pass.output_rect;
- } else {
- surface_damage_rect =
- DamageRectForSurface(surface, source_pass, source_pass.output_rect);
- }
-
- // Add the current surface to the damage rect union if there is any damage.
- // This should be done AFTER checking the occluding damage because the surface
- // on top should not include its own surface.
- if (!surface_damage_rect.IsEmpty()) {
- ClipData root_clip_rect;
- if (clip_rect.is_clipped) {
- // root_clip_rect is in the root target space.
- root_clip_rect.rect = cc::MathUtil::MapEnclosingClippedRect(
- dest_pass->transform_to_root_target, clip_rect.rect);
- root_clip_rect.is_clipped = true;
- }
- UnionSurfaceDamageRectsOnTop(surface_damage_rect,
- parent_quad_to_root_target_transform,
- root_clip_rect);
+ // Zero damage is not recorded in the surface_damage_rect_list_.
+ // In this case, add an empty damage rect to the list so
+ // |overlay_damage_index| can save this index.
+ if (current_zero_damage_rect_is_not_recorded_) {
+ current_zero_damage_rect_is_not_recorded_ = false;
+ surface_damage_rect_list_->push_back(gfx::Rect());
}
+ // The latest surface damage rect.
+ *overlay_damage_index = surface_damage_rect_list_->size() - 1;
+
return target_quad;
}
@@ -422,17 +444,32 @@ void SurfaceAggregator::HandleSurfaceQuad(
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
- const RoundedCornerInfo& rounded_corner_info) {
+ const MaskFilterInfoExt& mask_filter_info) {
SurfaceId primary_surface_id = surface_quad->surface_range.end();
+ Surface* latest_surface =
+ manager_->GetLatestInFlightSurface(surface_quad->surface_range);
+
+ // If a new surface is going to be emitted, add the surface_quad rect to
+ // |surface_damage_rect_list_| for overlays. The whole quad is considered
+ // damaged.
+ if (needs_surface_damage_rect_list_ &&
+ (!latest_surface || !latest_surface->HasActiveFrame() ||
+ (latest_surface->surface_id() != primary_surface_id))) {
+ gfx::Transform transform(
+ target_transform,
+ surface_quad->shared_quad_state->quad_to_target_transform);
+
+ AddSurfaceDamageToDamageList(
+ /*default_damage_rect=*/surface_quad->rect, transform, clip_rect,
+ /*source_pass =*/nullptr, dest_pass, /*surface=*/nullptr);
+ }
// If there's no fallback surface ID available, then simply emit a
// SolidColorDrawQuad with the provided default background color. This
// can happen after a Viz process crash.
- Surface* latest_surface =
- manager_->GetLatestInFlightSurface(surface_quad->surface_range);
if (!latest_surface || !latest_surface->HasActiveFrame()) {
EmitDefaultBackgroundColorQuad(surface_quad, target_transform, clip_rect,
- dest_pass, rounded_corner_info);
+ dest_pass, mask_filter_info);
return;
}
@@ -452,23 +489,13 @@ void SurfaceAggregator::HandleSurfaceQuad(
surface_quad->shared_quad_state,
target_transform, clip_rect,
fallback_frame.metadata.root_background_color,
- dest_pass, rounded_corner_info);
- }
-
- if (needs_surface_occluding_damage_rect_ &&
- latest_surface->surface_id() != primary_surface_id) {
- gfx::Transform transform(
- target_transform,
- surface_quad->shared_quad_state->quad_to_target_transform);
- transform.ConcatTransform(dest_pass->transform_to_root_target);
- UnionSurfaceDamageRectsOnTop(surface_quad->rect, target_transform,
- clip_rect);
+ dest_pass, mask_filter_info);
}
EmitSurfaceContent(latest_surface, parent_device_scale_factor, surface_quad,
target_transform, clip_rect, dest_pass, ignore_undamaged,
damage_rect_in_quad_space, damage_rect_in_quad_space_valid,
- rounded_corner_info);
+ mask_filter_info);
}
void SurfaceAggregator::EmitSurfaceContent(
@@ -481,7 +508,7 @@ void SurfaceAggregator::EmitSurfaceContent(
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
- const RoundedCornerInfo& rounded_corner_info) {
+ const MaskFilterInfoExt& mask_filter_info) {
// If this surface's id is already in our referenced set then it creates
// a cycle in the graph and should be dropped.
SurfaceId surface_id = surface->surface_id();
@@ -570,7 +597,28 @@ void SurfaceAggregator::EmitSurfaceContent(
bool merge_pass =
CanPotentiallyMergePass(*surface_quad) && !reflected_and_scaled &&
copy_requests.empty() && combined_transform.Preserves2dAxisAlignment() &&
- CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back());
+ CanMergeMaskFilterInfo(mask_filter_info, *render_pass_list.back());
+
+ ClipData quads_clip;
+ if (merge_pass) {
+ // Intersect the transformed visible rect and the clip rect to create a
+ // smaller cliprect for the quad.
+ ClipData surface_quad_clip_rect = {
+ true, cc::MathUtil::MapEnclosingClippedRect(
+ source_sqs->quad_to_target_transform, source_visible_rect)};
+ if (source_sqs->is_clipped) {
+ surface_quad_clip_rect.rect.Intersect(source_sqs->clip_rect);
+ }
+
+ quads_clip =
+ CalculateClipRect(clip_rect, surface_quad_clip_rect, target_transform);
+ }
+
+ if (needs_surface_damage_rect_list_) {
+ AddSurfaceDamageToDamageList(
+ /*default_damage_rect=*/gfx::Rect(), combined_transform, quads_clip,
+ /*source_pass =*/render_pass_list.back().get(), dest_pass, surface);
+ }
if (frame.metadata.delegated_ink_metadata) {
// The metadata must be taken off of the surface, rather than a copy being
@@ -624,7 +672,7 @@ void SurfaceAggregator::EmitSurfaceContent(
CopyQuadsToPass(source, copy_pass.get(), frame.device_scale_factor(),
child_to_parent_map, gfx::Transform(), {}, surface_id,
- RoundedCornerInfo());
+ MaskFilterInfoExt());
// If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -656,21 +704,9 @@ void SurfaceAggregator::EmitSurfaceContent(
.IsEmpty();
if (merge_pass) {
- // Intersect the transformed visible rect and the clip rect to create a
- // smaller cliprect for the quad.
- ClipData surface_quad_clip_rect = {
- true, cc::MathUtil::MapEnclosingClippedRect(
- source_sqs->quad_to_target_transform, source_visible_rect)};
- if (source_sqs->is_clipped) {
- surface_quad_clip_rect.rect.Intersect(source_sqs->clip_rect);
- }
-
- ClipData quads_clip =
- CalculateClipRect(clip_rect, surface_quad_clip_rect, target_transform);
-
CopyQuadsToPass(last_pass, dest_pass, frame.device_scale_factor(),
child_to_parent_map, combined_transform, quads_clip,
- surface_id, rounded_corner_info);
+ surface_id, mask_filter_info);
} else {
auto* shared_quad_state = CopyAndScaleSharedQuadState(
source_sqs, scaled_quad_to_target_transform, target_transform,
@@ -680,8 +716,7 @@ void SurfaceAggregator::EmitSurfaceContent(
gfx::ScaleToEnclosingRect(source_sqs->visible_quad_layer_rect,
inverse_extra_content_scale_x,
inverse_extra_content_scale_y),
- clip_rect, dest_pass, rounded_corner_info, /*occluding_damage_rect*/
- gfx::Rect(), /* occluding_damage_rect_valid */ false);
+ clip_rect, dest_pass, mask_filter_info);
// At this point, we need to calculate three values in order to construct
// the CompositorRenderPassDrawQuad:
@@ -741,29 +776,19 @@ void SurfaceAggregator::EmitDefaultBackgroundColorQuad(
const gfx::Transform& target_transform,
const ClipData& clip_rect,
AggregatedRenderPass* dest_pass,
- const RoundedCornerInfo& rounded_corner_info) {
+ const MaskFilterInfoExt& mask_filter_info) {
// The primary surface is unavailable and there is no fallback
// surface specified so create a SolidColorDrawQuad with the default
// background color.
SkColor background_color = surface_quad->default_background_color;
auto* shared_quad_state =
CopySharedQuadState(surface_quad->shared_quad_state, target_transform,
- clip_rect, dest_pass, rounded_corner_info,
- /*occluding_damage_rect*/ gfx::Rect(),
- /*occluding_damage_rect_valid*/ false);
+ clip_rect, dest_pass, mask_filter_info);
auto* solid_color_quad =
dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
solid_color_quad->SetNew(shared_quad_state, surface_quad->rect,
surface_quad->visible_rect, background_color, false);
-
- if (needs_surface_occluding_damage_rect_) {
- gfx::Transform transform(
- target_transform,
- surface_quad->shared_quad_state->quad_to_target_transform);
- transform.ConcatTransform(dest_pass->transform_to_root_target);
- UnionSurfaceDamageRectsOnTop(surface_quad->rect, transform, clip_rect);
- }
}
void SurfaceAggregator::EmitGutterQuadsIfNecessary(
@@ -774,7 +799,7 @@ void SurfaceAggregator::EmitGutterQuadsIfNecessary(
const ClipData& clip_rect,
SkColor background_color,
AggregatedRenderPass* dest_pass,
- const RoundedCornerInfo& rounded_corner_info) {
+ const MaskFilterInfoExt& mask_filter_info) {
bool has_transparent_background = background_color == SK_ColorTRANSPARENT;
// If the fallback Surface's active CompositorFrame has a non-transparent
@@ -792,9 +817,7 @@ void SurfaceAggregator::EmitGutterQuadsIfNecessary(
primary_shared_quad_state,
primary_shared_quad_state->quad_to_target_transform, target_transform,
right_gutter_rect, right_gutter_rect, clip_rect, dest_pass,
- rounded_corner_info,
- /*occluding_damage_rect*/ gfx::Rect(),
- /*occluding_damage_rect_valid*/ false);
+ mask_filter_info);
auto* right_gutter =
dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -811,9 +834,7 @@ void SurfaceAggregator::EmitGutterQuadsIfNecessary(
primary_shared_quad_state,
primary_shared_quad_state->quad_to_target_transform, target_transform,
bottom_gutter_rect, bottom_gutter_rect, clip_rect, dest_pass,
- rounded_corner_info,
- /*occluding_damage_rect*/ gfx::Rect(),
- /*occluding_damage_rect_valid*/ false);
+ mask_filter_info);
auto* bottom_gutter =
dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -865,7 +886,7 @@ void SurfaceAggregator::AddColorConversionPass() {
/*quad_to_target_transform=*/gfx::Transform(),
/*quad_layer_rect=*/output_rect,
/*visible_quad_layer_rect=*/output_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
/*blend_mode=*/SkBlendMode::kSrc, /*sorting_context_id=*/0);
@@ -922,7 +943,7 @@ void SurfaceAggregator::AddDisplayTransformPass() {
/*quad_to_target_transform=*/root_surface_transform_,
/*quad_layer_rect=*/output_rect,
/*visible_quad_layer_rect=*/output_rect,
- /*rounded_corner_bounds=*/gfx::RRectF(),
+ /*mask_filter_info=*/gfx::MaskFilterInfo(),
/*clip_rect=*/gfx::Rect(),
/*is_clipped=*/false, are_contents_opaque, /*opacity=*/1.f,
/*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
@@ -942,14 +963,11 @@ SharedQuadState* SurfaceAggregator::CopySharedQuadState(
const gfx::Transform& target_transform,
const ClipData& clip_rect,
AggregatedRenderPass* dest_render_pass,
- const RoundedCornerInfo& rounded_corner_info,
- const gfx::Rect& occluding_damage_rect,
- bool occluding_damage_rect_valid) {
+ const MaskFilterInfoExt& mask_filter_info) {
return CopyAndScaleSharedQuadState(
source_sqs, source_sqs->quad_to_target_transform, target_transform,
source_sqs->quad_layer_rect, source_sqs->visible_quad_layer_rect,
- clip_rect, dest_render_pass, rounded_corner_info, occluding_damage_rect,
- occluding_damage_rect_valid);
+ clip_rect, dest_render_pass, mask_filter_info);
}
SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
@@ -960,9 +978,7 @@ SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
const gfx::Rect& visible_quad_layer_rect,
const ClipData& clip_rect,
AggregatedRenderPass* dest_render_pass,
- const RoundedCornerInfo& rounded_corner_info,
- const gfx::Rect& occluding_damage_rect,
- bool occluding_damage_rect_valid) {
+ const MaskFilterInfoExt& mask_filter_info_ext) {
auto* shared_quad_state = dest_render_pass->CreateAndAppendSharedQuadState();
ClipData new_clip_rect = CalculateClipRect(
clip_rect, {source_sqs->is_clipped, source_sqs->clip_rect},
@@ -979,14 +995,12 @@ SharedQuadState* SurfaceAggregator::CopyAndScaleSharedQuadState(
shared_quad_state->SetAll(
new_transform, quad_layer_rect, visible_quad_layer_rect,
- rounded_corner_info.bounds, new_clip_rect.rect, new_clip_rect.is_clipped,
- source_sqs->are_contents_opaque, source_sqs->opacity,
- source_sqs->blend_mode, source_sqs->sorting_context_id);
+ mask_filter_info_ext.mask_filter_info, new_clip_rect.rect,
+ new_clip_rect.is_clipped, source_sqs->are_contents_opaque,
+ source_sqs->opacity, source_sqs->blend_mode,
+ source_sqs->sorting_context_id);
shared_quad_state->is_fast_rounded_corner =
- rounded_corner_info.is_fast_rounded_corner;
- if (occluding_damage_rect_valid) {
- shared_quad_state->occluding_damage_rect = occluding_damage_rect;
- }
+ mask_filter_info_ext.is_fast_rounded_corner,
shared_quad_state->de_jelly_delta_y = source_sqs->de_jelly_delta_y;
return shared_quad_state;
@@ -1000,7 +1014,7 @@ void SurfaceAggregator::CopyQuadsToPass(
const gfx::Transform& target_transform,
const ClipData& clip_rect,
const SurfaceId& surface_id,
- const RoundedCornerInfo& parent_rounded_corner_info) {
+ const MaskFilterInfoExt& parent_mask_filter_info_ext) {
const QuadList& source_quad_list = source_pass.quad_list;
const SharedQuadState* last_copied_source_shared_quad_state = nullptr;
@@ -1035,18 +1049,22 @@ void SurfaceAggregator::CopyQuadsToPass(
}
#endif
- gfx::Rect occluding_damage_rect;
- const DrawQuad* quad_with_occluding_damage_rect =
- ProcessSurfaceOccludingDamage(source_pass, dest_pass, target_transform,
- surface_id, clip_rect,
- &occluding_damage_rect);
+ size_t overlay_damage_index = 0;
+ const DrawQuad* quad_with_overlay_damage_index = nullptr;
+ if (needs_surface_damage_rect_list_) {
+ AddRenderPassFilterDamageToDamageList(target_transform, &source_pass,
+ dest_pass);
+ quad_with_overlay_damage_index =
+ FindQuadWithOverlayDamage(source_pass, dest_pass, target_transform,
+ surface_id, clip_rect, &overlay_damage_index);
+ }
- RoundedCornerInfo new_rounded_corner_info = parent_rounded_corner_info;
+ MaskFilterInfoExt new_mask_filter_info_ext = parent_mask_filter_info_ext;
for (auto* quad : source_quad_list) {
// Both cannot be set at once. If this happens then a surface is being
// merged when it should not.
- DCHECK(quad->shared_quad_state->rounded_corner_bounds.IsEmpty() ||
- parent_rounded_corner_info.bounds.IsEmpty());
+ DCHECK(quad->shared_quad_state->mask_filter_info.IsEmpty() ||
+ parent_mask_filter_info_ext.mask_filter_info.IsEmpty());
if (quad->material == DrawQuad::Material::kSurfaceContent) {
const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
@@ -1057,28 +1075,30 @@ void SurfaceAggregator::CopyQuadsToPass(
if (!surface_quad->surface_range.end().is_valid())
continue;
- if (parent_rounded_corner_info.bounds.IsEmpty()) {
- new_rounded_corner_info = RoundedCornerInfo(
- quad->shared_quad_state->rounded_corner_bounds,
+ if (parent_mask_filter_info_ext.mask_filter_info.IsEmpty()) {
+ new_mask_filter_info_ext = MaskFilterInfoExt(
+ quad->shared_quad_state->mask_filter_info,
quad->shared_quad_state->is_fast_rounded_corner, target_transform);
}
HandleSurfaceQuad(
surface_quad, parent_device_scale_factor, target_transform, clip_rect,
dest_pass, ignore_undamaged, &damage_rect_in_quad_space,
- &damage_rect_in_quad_space_valid, new_rounded_corner_info);
+ &damage_rect_in_quad_space_valid, new_mask_filter_info_ext);
} else {
if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
- if (parent_rounded_corner_info.bounds.IsEmpty()) {
- new_rounded_corner_info =
- RoundedCornerInfo(quad->shared_quad_state->rounded_corner_bounds,
+ if (parent_mask_filter_info_ext.mask_filter_info.IsEmpty()) {
+ new_mask_filter_info_ext =
+ MaskFilterInfoExt(quad->shared_quad_state->mask_filter_info,
quad->shared_quad_state->is_fast_rounded_corner,
target_transform);
}
- SharedQuadState* dest_shared_quad_state = CopySharedQuadState(
- quad->shared_quad_state, target_transform, clip_rect, dest_pass,
- new_rounded_corner_info, occluding_damage_rect,
- quad == quad_with_occluding_damage_rect);
+ SharedQuadState* dest_shared_quad_state =
+ CopySharedQuadState(quad->shared_quad_state, target_transform,
+ clip_rect, dest_pass, new_mask_filter_info_ext);
+
+ if (quad == quad_with_overlay_damage_index)
+ dest_shared_quad_state->overlay_damage_index = overlay_damage_index;
if (de_jelly_enabled_) {
// If a surface is being drawn for a second time, clear our
@@ -1229,11 +1249,17 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
source.cache_render_pass, source.has_damage_from_contributing_content,
source.generate_mipmap);
+ if (needs_surface_damage_rect_list_ && is_root_pass) {
+ AddSurfaceDamageToDamageList(
+ /*default_damage_rect=*/gfx::Rect(), surface_transform,
+ /*clip_rect=*/{}, &source, copy_pass.get(), surface);
+ }
+
CopyQuadsToPass(source, copy_pass.get(), frame.device_scale_factor(),
child_to_parent_map,
apply_surface_transform_to_root_pass ? surface_transform
: gfx::Transform(),
- {}, surface->surface_id(), RoundedCornerInfo());
+ {}, surface->surface_id(), MaskFilterInfoExt());
// If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -1299,11 +1325,6 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
if (in_moved_pixel_rp)
moved_pixel_passes_.insert(remapped_pass_id);
- gfx::Transform root_to_target_transform(gfx::Transform::kSkipInitialization);
- const bool transform_inverted =
- target_to_root_transform.GetInverse(&root_to_target_transform);
- DCHECK(transform_inverted);
-
const CompositorFrame& frame = surface->GetActiveFrame();
CompositorRenderPass* last_pass = frame.render_pass_list.back().get();
gfx::Rect full_damage = last_pass->output_rect;
@@ -1315,8 +1336,12 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
gfx::Rect surface_root_rp_damage =
DamageRectForSurface(surface, *last_pass, full_damage);
if (!surface_root_rp_damage.IsEmpty()) {
- surface_root_rp_damage = cc::MathUtil::ProjectEnclosingClippedRect(
- root_to_target_transform, surface_root_rp_damage);
+ gfx::Transform root_to_target_transform(
+ gfx::Transform::kSkipInitialization);
+ if (target_to_root_transform.GetInverse(&root_to_target_transform)) {
+ surface_root_rp_damage = cc::MathUtil::ProjectEnclosingClippedRect(
+ root_to_target_transform, surface_root_rp_damage);
+ }
}
gfx::Rect damage_rect;
@@ -1414,8 +1439,13 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
rect_in_target_space.Intersects(damage_rect);
bool intersects_damage_from_parent =
rect_in_target_space.Intersects(damage_from_parent);
+ // The |can_use_backdrop_filter_cache| flag hints if the current quad
+ // intersects any damage from any quads below in the same surface. If the
+ // flag is false, it means the intersecting damage is from quads above it
+ // or from itself.
bool intersects_damage_from_surface =
- rect_in_target_space.Intersects(surface_root_rp_damage);
+ rect_in_target_space.Intersects(surface_root_rp_damage) &&
+ !render_pass_quad->can_use_backdrop_filter_cache;
if (intersects_current_damage || intersects_damage_from_parent ||
intersects_damage_from_surface) {
render_pass_quad->can_use_backdrop_filter_cache = false;
@@ -1437,6 +1467,31 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
}
}
}
+ // For the pixel-moving backdrop filters, all effects are limited to the
+ // size of the RenderPassDrawQuad rect. Therefore when we find the damage
+ // under the quad intersects quad render pass output rect, we extend the
+ // damage rect to include the rpdq->rect.
+
+ // For the pixel-moving foreground filters, all effects can be expanded
+ // outside the RenderPassDrawQuad rect to the size of rect +
+ // filters.MaximumPixelMovement(). Therefore, we have to check if
+ // (rpdq->rect + MaximumPixelMovement()) intersects the damage under it.
+ // Then we extend the damage rect to include the (rpdq->rect +
+ // MaximumPixelMovement()).
+
+ // Expand the damage to cover entire |output_rect| if the |render_pass|
+ // has pixel-moving foreground filter.
+ if (child_render_pass.filters.HasFilterThatMovesPixels()) {
+ gfx::Rect expanded_rect_in_target_space =
+ GetExpandedRectWithPixelMovingForegroundFilter(render_pass_quad,
+ child_render_pass);
+
+ if (expanded_rect_in_target_space.Intersects(damage_rect) ||
+ expanded_rect_in_target_space.Intersects(damage_from_parent) ||
+ expanded_rect_in_target_space.Intersects(surface_root_rp_damage)) {
+ damage_rect.Union(expanded_rect_in_target_space);
+ }
+ }
auto remapped_child_pass_id =
pass_id_remapper_.Remap(child_pass_id, surface->surface_id());
@@ -1475,6 +1530,49 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
return damage_rect;
}
+bool SurfaceAggregator::DeclareResourcesToProvider(
+ Surface* surface,
+ const std::vector<TransferableResource>& resource_list,
+ const CompositorRenderPassList& render_passes) {
+ // |provider_| may be null in tests.
+ if (!provider_)
+ return true;
+
+ int child_id = ChildIdForSurface(surface);
+
+ // Ref the resources in the surface, and let the provider know we've received
+ // new resources from the compositor frame.
+ surface->RefResources(resource_list);
+ provider_->ReceiveFromChild(child_id, resource_list);
+
+ // Figure out which resources are actually used in the render pass.
+ // Note that we first gather them in a vector, since ResourceIdSet (which we
+ // actually need) is a flat_set, which means bulk insertion we do at the end
+ // is more efficient.
+ std::vector<ResourceId> referenced_resources;
+ referenced_resources.reserve(resource_list.size());
+
+ const auto& child_to_parent_map = provider_->GetChildToParentMap(child_id);
+ for (const auto& render_pass : render_passes) {
+ for (auto* quad : render_pass->quad_list) {
+ for (ResourceId resource_id : quad->resources) {
+ // If we're using a resource which was not declared in the
+ // |resource_list| then this is an invalid frame, we can abort.
+ if (!child_to_parent_map.count(resource_id))
+ return false;
+ referenced_resources.push_back(resource_id);
+ }
+ }
+ }
+
+ // Declare the used resources to the provider. This will cause all resources
+ // that were received but not used in the render passes to be unreferenced in
+ // the surface, and returned to the child in the resource provider.
+ ResourceIdSet resource_set(std::move(referenced_resources));
+ provider_->DeclareUsedResourcesFromChild(child_id, resource_set);
+ return true;
+}
+
gfx::Rect SurfaceAggregator::PrewalkSurface(
Surface* surface,
bool in_moved_pixel_rp,
@@ -1497,14 +1595,6 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(
return gfx::Rect();
const CompositorFrame& frame = surface->GetActiveFrame();
- int child_id = 0;
- // TODO(jbauman): hack for unit tests that don't set up rp
- if (provider_) {
- child_id = ChildIdForSurface(surface);
- surface->RefResources(frame.resource_list);
- provider_->ReceiveFromChild(child_id, frame.resource_list);
- }
-
auto remapped_pass_id = pass_id_remapper_.Remap(
frame.render_pass_list.back()->id, surface->surface_id());
if (parent_pass_id)
@@ -1516,33 +1606,12 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(
base::flat_map<CompositorRenderPassId, RenderPassMapEntry> render_pass_map =
GenerateRenderPassMap(frame.render_pass_list, IsRootSurface(surface));
- std::vector<ResourceId> referenced_resources;
- referenced_resources.reserve(frame.resource_list.size());
-
- bool invalid_frame = false;
- if (provider_) {
- const auto& child_to_parent_map = provider_->GetChildToParentMap(child_id);
- for (const auto& render_pass : base::Reversed(frame.render_pass_list)) {
- for (auto* quad : render_pass->quad_list) {
- for (ResourceId resource_id : quad->resources) {
- if (!child_to_parent_map.count(resource_id)) {
- invalid_frame = true;
- break;
- }
- referenced_resources.push_back(resource_id);
- }
- }
- }
- }
-
- if (invalid_frame)
+ bool valid_frame = DeclareResourcesToProvider(surface, frame.resource_list,
+ frame.render_pass_list);
+ if (!valid_frame)
return gfx::Rect();
valid_surfaces_.insert(surface->surface_id());
- ResourceIdSet resource_set(std::move(referenced_resources));
- if (provider_)
- provider_->DeclareUsedResourcesFromChild(child_id, resource_set);
-
CompositorRenderPass* last_pass = frame.render_pass_list.back().get();
gfx::Rect full_damage = last_pass->output_rect;
gfx::Rect damage_rect =
@@ -1682,23 +1751,24 @@ void SurfaceAggregator::PropagateCopyRequestPasses() {
}
}
-bool SurfaceAggregator::CanMergeRoundedCorner(
- const RoundedCornerInfo& rounded_corner_info,
+bool SurfaceAggregator::CanMergeMaskFilterInfo(
+ const MaskFilterInfoExt& mask_filter_info_ext,
const CompositorRenderPass& root_render_pass) {
- // If the quad has no rounded corner, then we do not have to block merging.
- if (rounded_corner_info.bounds.IsEmpty())
+ // If the quad has no mask filter, then we do not have to block merging.
+ if (mask_filter_info_ext.mask_filter_info.IsEmpty())
return true;
// If the quad has rounded corner and it is not a fast rounded corner, we
// cannot merge.
- if (!rounded_corner_info.is_fast_rounded_corner)
+ if (mask_filter_info_ext.mask_filter_info.HasRoundedCorners() &&
+ !mask_filter_info_ext.is_fast_rounded_corner)
return false;
- // If any of the quads in the root render pass has a rounded corner of its
+ // If any of the quads in the root render pass has a mask filter of its
// own, then we cannot merge.
const SharedQuadStateList& sqs_list = root_render_pass.shared_quad_state_list;
for (const auto* sqs : sqs_list) {
- if (!sqs->rounded_corner_bounds.IsEmpty())
+ if (!sqs->mask_filter_info.IsEmpty())
return false;
}
return true;
@@ -1741,6 +1811,7 @@ AggregatedFrame SurfaceAggregator::Aggregate(
root_surface_frame.metadata.top_controls_visible_height;
dest_pass_list_ = &frame.render_pass_list;
+ surface_damage_rect_list_ = &frame.surface_damage_rect_list_;
const gfx::Size viewport_bounds =
root_surface_frame.render_pass_list.back()->output_rect.size();
@@ -1749,6 +1820,7 @@ AggregatedFrame SurfaceAggregator::Aggregate(
// Reset state that couldn't be reset in ResetAfterAggregate().
damage_ranges_.clear();
+
DCHECK(referenced_surfaces_.empty());
PrewalkResult prewalk_result;
@@ -1764,7 +1836,9 @@ AggregatedFrame SurfaceAggregator::Aggregate(
// Changing color usage will cause the renderer to reshape the output surface,
// therefore the renderer might expand the damage to the whole frame. The
// following makes sure SA will produce all the quads to cover the full frame.
- if (root_content_color_usage_ != prewalk_result.content_color_usage) {
+ bool color_usage_changed =
+ root_content_color_usage_ != prewalk_result.content_color_usage;
+ if (color_usage_changed) {
root_damage_rect_ = cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
root_surface_transform_,
gfx::Rect(root_surface_frame.size_in_pixels()));
@@ -1786,7 +1860,6 @@ AggregatedFrame SurfaceAggregator::Aggregate(
CopyPasses(root_surface_frame, surface);
referenced_surfaces_.erase(surface_id);
DCHECK(referenced_surfaces_.empty());
- frame.occluding_damage_ = damage_rects_union_of_surfaces_on_top_;
if (dest_pass_list_->empty()) {
ResetAfterAggregate();
@@ -1796,11 +1869,16 @@ AggregatedFrame SurfaceAggregator::Aggregate(
// The root render pass damage might have been expanded by target_damage (the
// area that might need to be recomposited on the target surface). We restrict
// the damage_rect of the root render pass to the one caused by the source
- // surfaces.
+ // surfaces, except when drawing delegated ink trails.
// The damage on the root render pass should not include the expanded area
- // since Renderer and OverlayProcessor expect the non expanded damage.
+ // since Renderer and OverlayProcessor expect the non expanded damage. The
+ // only exception is when delegated ink trails are being drawn, in which case
+ // the root render pass needs to contain the expanded area, as |target_damage|
+ // also reflects the delegated ink trail damage rect.
auto* last_pass = dest_pass_list_->back().get();
- if (!RenderPassNeedsFullDamage(last_pass->id, last_pass->cache_render_pass))
+
+ if (!color_usage_changed && !last_frame_had_delegated_ink_ &&
+ !RenderPassNeedsFullDamage(last_pass->id, last_pass->cache_render_pass))
dest_pass_list_->back()->damage_rect.Intersect(surfaces_damage_rect);
// Now that we've handled our main surface aggregation, apply de-jelly effect
@@ -1828,7 +1906,12 @@ AggregatedFrame SurfaceAggregator::Aggregate(
}
}
- frame.delegated_ink_metadata = std::move(delegated_ink_metadata_);
+ if (delegated_ink_metadata_) {
+ frame.delegated_ink_metadata = std::move(delegated_ink_metadata_);
+ last_frame_had_delegated_ink_ = true;
+ } else {
+ last_frame_had_delegated_ink_ = false;
+ }
if (frame_annotator_)
frame_annotator_->AnnotateAggregatedFrame(&frame);
@@ -1838,11 +1921,12 @@ AggregatedFrame SurfaceAggregator::Aggregate(
void SurfaceAggregator::ResetAfterAggregate() {
dest_pass_list_ = nullptr;
+ surface_damage_rect_list_ = nullptr;
+ current_zero_damage_rect_is_not_recorded_ = false;
expected_display_time_ = base::TimeTicks();
valid_surfaces_.clear();
has_cached_render_passes_ = false;
has_pixel_moving_backdrop_filter_ = false;
- damage_rects_union_of_surfaces_on_top_ = gfx::Rect();
new_surfaces_.clear();
moved_pixel_passes_.clear();
copy_request_passes_.clear();
@@ -1957,7 +2041,7 @@ void SurfaceAggregator::TransformAndStoreDelegatedInkMetadata(
parent_quad_to_root_target_transform.TransformRect(&area);
delegated_ink_metadata_ = std::make_unique<DelegatedInkMetadata>(
point, metadata->diameter(), metadata->color(), metadata->timestamp(),
- area);
+ area, metadata->frame_time());
TRACE_EVENT_INSTANT2(
"viz", "SurfaceAggregator::TransformAndStoreDelegatedInkMetadata",
@@ -2183,8 +2267,8 @@ void SurfaceAggregator::AppendDeJellyRenderPass(
auto* new_state = root_pass->CreateAndAppendSharedQuadState();
gfx::Transform transform;
new_state->SetAll(transform, render_pass->output_rect,
- render_pass->output_rect, gfx::RRectF(), jelly_clip, true,
- false, opacity, blend_mode, 0);
+ render_pass->output_rect, gfx::MaskFilterInfo(), jelly_clip,
+ true, false, opacity, blend_mode, 0);
auto* quad =
root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
quad->SetNew(new_state, render_pass->output_rect, render_pass->output_rect,
@@ -2233,5 +2317,4 @@ void SurfaceAggregator::SetLastFrameHadJelly(bool had_jelly) {
}
last_frame_had_jelly_ = had_jelly;
}
-
} // namespace viz
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index bbd1b51d5ab..e1e8bb8d6ff 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -21,6 +21,7 @@
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/common/surfaces/surface_range.h"
+#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/render_pass_id_remapper.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/display_color_spaces.h"
@@ -52,7 +53,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
SurfaceAggregator(SurfaceManager* manager,
DisplayResourceProvider* provider,
bool aggregate_only_damaged,
- bool needs_surface_occluding_damage_rect);
+ bool needs_surface_damage_rect_list);
~SurfaceAggregator();
// |target_damage| represents an area on the output surface that might have
@@ -92,9 +93,9 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
private:
struct ClipData;
struct PrewalkResult;
- struct RoundedCornerInfo;
struct ChildSurfaceInfo;
struct RenderPassMapEntry;
+ struct MaskFilterInfoExt;
// Helper function that gets a list of render passes and returns a map from
// render pass ids to render passes.
@@ -114,7 +115,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
- const RoundedCornerInfo& rounded_corner_info);
+ const MaskFilterInfoExt& mask_filter_info_pair);
void EmitSurfaceContent(Surface* surface,
float parent_device_scale_factor,
@@ -125,14 +126,14 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
bool* damage_rect_in_quad_space_valid,
- const RoundedCornerInfo& rounded_corner_info);
+ const MaskFilterInfoExt& mask_filter_info_pair);
void EmitDefaultBackgroundColorQuad(
const SurfaceDrawQuad* surface_quad,
const gfx::Transform& target_transform,
const ClipData& clip_rect,
AggregatedRenderPass* dest_pass,
- const RoundedCornerInfo& rounded_corner_info);
+ const MaskFilterInfoExt& mask_filter_info_pair);
void EmitGutterQuadsIfNecessary(
const gfx::Rect& primary_rect,
@@ -142,16 +143,14 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const ClipData& clip_rect,
SkColor background_color,
AggregatedRenderPass* dest_pass,
- const RoundedCornerInfo& rounded_corner_info);
+ const MaskFilterInfoExt& mask_filter_info_pair);
SharedQuadState* CopySharedQuadState(
const SharedQuadState* source_sqs,
const gfx::Transform& target_transform,
const ClipData& clip_rect,
AggregatedRenderPass* dest_render_pass,
- const RoundedCornerInfo& rounded_corner_info,
- const gfx::Rect& occluding_damage_rect,
- bool occluding_damage_rect_valid);
+ const MaskFilterInfoExt& mask_filter_info_pair);
SharedQuadState* CopyAndScaleSharedQuadState(
const SharedQuadState* source_sqs,
@@ -161,9 +160,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const gfx::Rect& visible_quad_layer_rect,
const ClipData& clip_rect,
AggregatedRenderPass* dest_render_pass,
- const RoundedCornerInfo& rounded_corner_info,
- const gfx::Rect& occluding_damage_rect,
- bool occluding_damage_rect_valid);
+ const MaskFilterInfoExt& mask_filter_info_pair);
void CopyQuadsToPass(
const CompositorRenderPass& source_pass,
@@ -173,7 +170,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const gfx::Transform& target_transform,
const ClipData& clip_rect,
const SurfaceId& surface_id,
- const RoundedCornerInfo& rounded_corner_info);
+ const MaskFilterInfoExt& mask_filter_info_pair);
// Recursively walks through the render pass and updates the
// |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
@@ -224,6 +221,16 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
bool will_draw,
const gfx::Rect& damage_from_parent,
PrewalkResult* result);
+
+ // Declares all of the resources to the resource provider. Also declares
+ // resources that are used in the render_pass_list. Returns true if this seems
+ // to be a valid frame (all resources used in the render pass are present in
+ // the resource list).
+ bool DeclareResourcesToProvider(
+ Surface* surface,
+ const std::vector<TransferableResource>& resource_list,
+ const CompositorRenderPassList& render_pass_list);
+
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
void CopyPasses(const CompositorFrame& frame, Surface* surface);
void AddColorConversionPass();
@@ -238,37 +245,42 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void PropagateCopyRequestPasses();
// Returns true if the quad list from the render pass provided can be merged
- // with its target render pass based on rounded corners.
- bool CanMergeRoundedCorner(const RoundedCornerInfo& rounded_corner_info,
- const CompositorRenderPass& root_render_pass);
+ // with its target render pass based on mask filter info.
+ bool CanMergeMaskFilterInfo(const MaskFilterInfoExt& mask_filter_info_pair,
+ const CompositorRenderPass& root_render_pass);
int ChildIdForSurface(Surface* surface);
bool IsSurfaceFrameIndexSameAsPrevious(const Surface* surface) const;
gfx::Rect DamageRectForSurface(const Surface* surface,
const CompositorRenderPass& source,
const gfx::Rect& full_rect) const;
- gfx::Rect CalculateOccludingSurfaceDamageRect(
- const DrawQuad* quad,
- const gfx::Transform& parent_quad_to_root_target_transform);
// This function adds |damage_rect| to
// |damage_rects_union_of_surfaces_on_top_|. |damage_rect| is in the quad
// content space while both clip_rect and
// |damage_rects_union_of_surfaces_on_top_| are already on the root target
// space.
- void UnionSurfaceDamageRectsOnTop(
+ void AddSurfaceDamageToDamageList(
const gfx::Rect& damage_rect,
- const gfx::Transform& parent_to_root_target_transform,
- const ClipData& clip_rect);
+ const gfx::Transform& parent_target_transform,
+ const ClipData& clip_rect,
+ const CompositorRenderPass* source_pass,
+ AggregatedRenderPass* dest_pass,
+ Surface* surface);
- // Determine the overlay occluding damage.
- const DrawQuad* ProcessSurfaceOccludingDamage(
+ void AddRenderPassFilterDamageToDamageList(
+ const gfx::Transform& parent_target_transform,
+ const CompositorRenderPass* source_pass,
+ AggregatedRenderPass* dest_pass);
+
+ // Determine the overlay damage and location in the surface damage list.
+ const DrawQuad* FindQuadWithOverlayDamage(
const CompositorRenderPass& source_pass,
AggregatedRenderPass* dest_pass,
const gfx::Transform& parent_target_transform,
const SurfaceId& surface_id,
const ClipData& clip_rect,
- gfx::Rect* occluding_damage_rect);
+ size_t* overlay_damage_index);
// Returns true if the render pass with the given id and cache_render_pass
// flag would need full damage.
@@ -337,8 +349,8 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const bool aggregate_only_damaged_;
- // Occluding damage rect will be calculated for qualified candidates
- const bool needs_surface_occluding_damage_rect_;
+ // If true, per-surface damage rect list will be produced.
+ const bool needs_surface_damage_rect_list_;
// Whether de-jelly may be active.
const bool de_jelly_enabled_;
@@ -407,6 +419,10 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// The root damage rect of the currently-aggregating frame.
gfx::Rect root_damage_rect_;
+ // A pointer to the list of surface damage rects from the current
+ // AggregatedFrame, used for overlay optimization.
+ SurfaceDamageRectList* surface_damage_rect_list_;
+
// The aggregate color content usage of the currently-aggregating frame. This
// is computed by the prewalk, and is used to determine the format and color
// space of all render passes. Note that that is more heavy-handed than is
@@ -414,10 +430,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
gfx::ContentColorUsage root_content_color_usage_ =
gfx::ContentColorUsage::kSRGB;
- // This is the union of the damage rects of all surface on top
- // of the current surface.
- gfx::Rect damage_rects_union_of_surfaces_on_top_;
-
// True if the frame that's currently being aggregated has copy requests.
// This is valid during Aggregate after PrewalkSurface is called.
bool has_copy_requests_ = false;
@@ -458,6 +470,16 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// a surface contains delegated ink metadata on its frame, and it is cleared
// after it is placed on the final aggregated frame during aggregation.
std::unique_ptr<DelegatedInkMetadata> delegated_ink_metadata_;
+ // Whether the last aggregated frame contained delegated ink metadata or not.
+ // Used to determine if the root render pass needs to remain expanded by the
+ // target damage or not, because that allows a frame to be drawn after inking
+ // is finished to remove the last drawn ink trail.
+ bool last_frame_had_delegated_ink_ = false;
+
+ // The current surface has zero_damage_rect and is not recorded in
+ // surface_damage_rect_list_ . Set by AddSurfaceDamageToDamageList() and read
+ // by FindQuadWithOverlayDamage().
+ bool current_zero_damage_rect_is_not_recorded_ = false;
// A helper class used to remap render pass IDs from the surface namespace to
// a common space, to avoid collisions.
diff --git a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
index 38621e794a3..96203ed4c9c 100644
--- a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -12,6 +12,7 @@
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/aggregated_frame.h"
+#include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/display/viz_pixel_test.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
@@ -71,7 +72,7 @@ SharedQuadState* CreateAndAppendTestSharedQuadState(
const gfx::Size& size) {
const gfx::Rect layer_rect = gfx::Rect(size);
const gfx::Rect visible_layer_rect = gfx::Rect(size);
- const gfx::RRectF rounded_corner_bounds = gfx::RRectF();
+ const gfx::MaskFilterInfo mask_filter_info;
const gfx::Rect clip_rect = gfx::Rect(size);
bool is_clipped = false;
bool are_contents_opaque = false;
@@ -79,7 +80,7 @@ SharedQuadState* CreateAndAppendTestSharedQuadState(
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
auto* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(transform, layer_rect, visible_layer_rect,
- rounded_corner_bounds, clip_rect, is_clipped,
+ mask_filter_info, clip_rect, is_clipped,
are_contents_opaque, opacity, blend_mode, 0);
return shared_state;
}
@@ -335,6 +336,71 @@ TEST_P(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
pixel_comparator));
}
+// Draw a simple frame with a delegated ink trail on top of it, then confirm
+// that it is erased by the next aggregation.
+TEST_P(SurfaceAggregatorPixelTest, DrawAndEraseDelegatedInkTrail) {
+ // DelegatedInkTrail isn't supported on non-Skia renderers.
+ if (renderer_type() == RendererType::kGL)
+ return;
+
+ DelegatedInkPointPixelTestHelper delegated_ink_helper(renderer_.get());
+
+ // Create and send metadata and points to the renderer that will be drawn.
+ // Points and timestamps are chosen arbitrarily.
+ delegated_ink_helper.CreateAndSendMetadata(
+ gfx::PointF(10, 10), 7.7f, SK_ColorWHITE, gfx::RectF(0, 0, 200, 200));
+ delegated_ink_helper.CreateAndSendPointFromMetadata();
+ delegated_ink_helper.CreateAndSendPointFromLastPoint(gfx::PointF(26, 37));
+ delegated_ink_helper.CreateAndSendPointFromLastPoint(gfx::PointF(45, 87));
+
+ gfx::Rect rect(this->device_viewport_size_);
+ CompositorRenderPassId id{1};
+ auto pass = CompositorRenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
+ this->device_viewport_size_);
+
+ auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ bool force_anti_aliasing_off = false;
+ color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
+ SK_ColorGREEN, force_anti_aliasing_off);
+
+ auto root_frame =
+ CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
+
+ this->root_allocator_.GenerateId();
+ SurfaceId root_surface_id(this->support_->frame_sink_id(),
+ this->root_allocator_.GetCurrentLocalSurfaceId());
+ this->support_->SubmitCompositorFrame(
+ this->root_allocator_.GetCurrentLocalSurfaceId(), std::move(root_frame));
+
+ SurfaceAggregator aggregator(this->manager_.surface_manager(),
+ this->resource_provider_.get(), true, false);
+ auto aggregated_frame = aggregator.Aggregate(
+ root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE);
+
+ bool discard_alpha = false;
+ cc::FuzzyPixelOffByOneComparator pixel_comparator(discard_alpha);
+ auto* pass_list = &aggregated_frame.render_pass_list;
+ EXPECT_TRUE(this->RunPixelTest(
+ pass_list, base::FilePath(FILE_PATH_LITERAL("delegated_ink_trail.png")),
+ pixel_comparator));
+
+ // Providing the damage rect as the target damage ensures that aggregation
+ // occurs and DrawFrame() has something new to draw. If this doesn't cause
+ // anything to be aggregated, a black square is drawn. If it does, the result
+ // should just erase the previously drawn trail completely.
+ aggregated_frame = aggregator.Aggregate(
+ root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE,
+ delegated_ink_helper.GetDelegatedInkDamageRect());
+ pass_list = &aggregated_frame.render_pass_list;
+
+ EXPECT_TRUE(this->RunPixelTest(pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ pixel_comparator));
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index 40dc37ca2d5..27e261f37c6 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -183,7 +183,7 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
float opacity,
const gfx::Transform& transform,
bool stretch_content_to_fill_bounds,
- const gfx::RRectF& rounded_corner_bounds,
+ const gfx::MaskFilterInfo& mask_filter_info,
bool is_fast_rounded_corner) {
Quad quad;
quad.material = DrawQuad::Material::kSurfaceContent;
@@ -193,7 +193,7 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
quad.surface_range = surface_range;
quad.default_background_color = default_background_color;
quad.stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
- quad.rounded_corner_bounds = rounded_corner_bounds;
+ quad.mask_filter_info = mask_filter_info;
quad.is_fast_rounded_corner = is_fast_rounded_corner;
return quad;
}
@@ -218,8 +218,8 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
gfx::Rect primary_surface_rect;
float opacity;
gfx::Transform to_target_transform;
- gfx::RRectF rounded_corner_bounds;
- bool is_fast_rounded_corner;
+ gfx::MaskFilterInfo mask_filter_info;
+ bool is_fast_rounded_corner = false;
bool allow_merge = true;
// Set when material==DrawQuad::Material::kSolidColor.
@@ -279,7 +279,7 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
desc.to_target_transform, desc.surface_range,
desc.default_background_color,
desc.stretch_content_to_fill_bounds,
- desc.rounded_corner_bounds, desc.is_fast_rounded_corner,
+ desc.mask_filter_info, desc.is_fast_rounded_corner,
desc.allow_merge);
break;
case DrawQuad::Material::kCompositorRenderPass:
@@ -371,7 +371,7 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
const SurfaceRange& surface_range,
SkColor default_background_color,
bool stretch_content_to_fill_bounds,
- const gfx::RRectF& rounded_corner_bounds,
+ const gfx::MaskFilterInfo& mask_filter_info,
bool is_fast_rounded_corner,
bool allow_merge) {
gfx::Transform layer_to_target_transform = transform;
@@ -384,9 +384,9 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
auto* shared_quad_state = pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(layer_to_target_transform, layer_bounds,
- visible_layer_rect, rounded_corner_bounds,
- clip_rect, is_clipped, are_contents_opaque,
- opacity, blend_mode, 0);
+ visible_layer_rect, mask_filter_info, clip_rect,
+ is_clipped, are_contents_opaque, opacity,
+ blend_mode, 0);
shared_quad_state->is_fast_rounded_corner = is_fast_rounded_corner;
SurfaceDrawQuad* surface_quad =
@@ -404,9 +404,9 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
bool can_use_backdrop_filter_cache) {
gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5);
auto* shared_state = pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(transform, output_rect, output_rect, gfx::RRectF(),
- output_rect, false, false, 1, SkBlendMode::kSrcOver,
- 0);
+ shared_state->SetAll(transform, output_rect, output_rect,
+ gfx::MaskFilterInfo(), output_rect, false, false, 1,
+ SkBlendMode::kSrcOver, 0);
auto* quad = pass->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
quad->SetAll(
shared_state, output_rect, output_rect, /*needs_blending=*/true,
@@ -419,7 +419,7 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
const gfx::Rect& output_rect) {
auto* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(), output_rect, output_rect,
- gfx::RRectF(), output_rect, false, false, 1,
+ gfx::MaskFilterInfo(), output_rect, false, false, 1,
SkBlendMode::kSrcOver, 0);
auto* quad = pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
quad->SetNew(shared_state, output_rect, output_rect, false,
@@ -553,8 +553,8 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
for (const SurfaceRange& range : ranges) {
quads.push_back(Quad::SurfaceQuad(
range, SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false));
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false));
}
std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
CompositorRenderPassList pass_list;
@@ -579,6 +579,14 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
support->SubmitCompositorFrame(local_surface_id, std::move(child_frame));
}
+ gfx::Rect DamageListUnion(SurfaceDamageRectList& surface_damage_rect_list) {
+ gfx::Rect damage_rect_union;
+ for (auto damage_rect : surface_damage_rect_list)
+ damage_rect_union.Union(damage_rect);
+
+ return damage_rect_union;
+ }
+
protected:
LocalSurfaceId root_local_surface_id_;
Surface* root_surface_;
@@ -653,8 +661,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
std::vector<Quad> quads = {Quad::SurfaceQuad(
SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
gfx::Rect(5, 5), .5f, gfx::Transform(),
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -676,8 +684,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
std::vector<Quad> quads = {Quad::SurfaceQuad(
SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
gfx::Rect(5, 5), .9999f, gfx::Transform(),
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -712,11 +720,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RotatedClip) {
embedded_local_surface_id, device_scale_factor);
gfx::Transform rotate;
rotate.Rotate(30);
- std::vector<Quad> quads = {
- Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
- SK_ColorWHITE, gfx::Rect(5, 5), 1.f, rotate,
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ std::vector<Quad> quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), 1.f, rotate,
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
@@ -2196,14 +2204,14 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
->render_pass_id);
}
-void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
- CompositorRenderPass* pass,
- const SkBlendMode blend_mode,
- const gfx::RRectF& corner_bounds) {
+void AddSolidColorQuadWithBlendMode(
+ const gfx::Size& size,
+ CompositorRenderPass* pass,
+ const SkBlendMode blend_mode,
+ const gfx::MaskFilterInfo& mask_filter_info) {
const gfx::Transform layer_to_target_transform;
const gfx::Rect layer_rect(size);
const gfx::Rect visible_layer_rect(size);
- const gfx::RRectF rounded_corner_bounds = corner_bounds;
const gfx::Rect clip_rect(size);
bool is_clipped = false;
@@ -2214,7 +2222,7 @@ void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
bool force_anti_aliasing_off = false;
auto* sqs = pass->CreateAndAppendSharedQuadState();
sqs->SetAll(layer_to_target_transform, layer_rect, visible_layer_rect,
- rounded_corner_bounds, clip_rect, is_clipped, are_contents_opaque,
+ mask_filter_info, clip_rect, is_clipped, are_contents_opaque,
opacity, blend_mode, 0);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -2283,7 +2291,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
grandchild_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), grandchild_pass.get(),
- blend_modes[2], gfx::RRectF());
+ blend_modes[2], gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(grandchild_pass), grandchild_local_surface_id,
device_scale_factor, grandchild_support.get());
@@ -2297,7 +2305,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
child_one_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
- blend_modes[1], gfx::RRectF());
+ blend_modes[1], gfx::MaskFilterInfo());
auto* grandchild_surface_quad =
child_one_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
grandchild_surface_quad->SetNew(
@@ -2306,7 +2314,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
/*stretch_content_to_fill_bounds=*/false);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
- blend_modes[3], gfx::RRectF());
+ blend_modes[3], gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(child_one_pass), child_one_local_surface_id,
device_scale_factor, child_one_support.get());
@@ -2320,7 +2328,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
child_two_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
- blend_modes[5], gfx::RRectF());
+ blend_modes[5], gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(child_two_pass), child_two_local_surface_id,
device_scale_factor, child_two_support.get());
@@ -2329,7 +2337,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[0],
- gfx::RRectF());
+ gfx::MaskFilterInfo());
auto* child_one_surface_quad =
root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
child_one_surface_quad->SetNew(
@@ -2338,7 +2346,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
SurfaceRange(base::nullopt, child_one_surface_id), SK_ColorWHITE,
/*stretch_content_to_fill_bounds=*/false);
AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[4],
- gfx::RRectF());
+ gfx::MaskFilterInfo());
auto* child_two_surface_quad =
root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
child_two_surface_quad->SetNew(
@@ -2347,7 +2355,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
SurfaceRange(base::nullopt, child_two_surface_id), SK_ColorWHITE,
/*stretch_content_to_fill_bounds=*/false);
AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(), blend_modes[6],
- gfx::RRectF());
+ gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(root_pass), root_local_surface_id_,
device_scale_factor, root_sink_.get());
@@ -2398,8 +2406,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
// quad(d) - rounded corner [2]
TEST_F(SurfaceAggregatorValidSurfaceTest,
AggregateSharedQuadStateRoundedCornerBounds) {
- const gfx::RRectF kFastRoundedCornerBounds = gfx::RRectF(0, 0, 640, 480, 5);
- const gfx::RRectF kRoundedCornerBounds = gfx::RRectF(0, 0, 100, 100, 2);
+ const gfx::MaskFilterInfo kMaskFilterInfoWithFastRoundedCorners(
+ gfx::RRectF(0, 0, 640, 480, 5));
+ const gfx::MaskFilterInfo kMaskFilterInfoWithRoundedCorners(
+ gfx::RRectF(0, 0, 100, 100, 2));
ParentLocalSurfaceIdAllocator child_root_allocator;
ParentLocalSurfaceIdAllocator child_one_allocator;
@@ -2431,7 +2441,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
child_three_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_three_pass.get(),
- SkBlendMode::kSrcOver, gfx::RRectF());
+ SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(child_three_pass), child_three_local_surface_id,
device_scale_factor, child_three_support.get());
@@ -2446,7 +2456,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
child_one_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
- SkBlendMode::kSrcOver, gfx::RRectF());
+ SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
// Add child three surface quad
auto* child_three_surface_sqs =
@@ -2474,9 +2484,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
child_two_pass->SetNew(pass_id, output_rect, damage_rect,
transform_to_root_target);
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
- SkBlendMode::kSrcOver, gfx::RRectF());
+ SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_two_pass.get(),
- SkBlendMode::kSrcOver, kRoundedCornerBounds);
+ SkBlendMode::kSrcOver,
+ kMaskFilterInfoWithRoundedCorners);
QueuePassAsFrame(std::move(child_two_pass), child_two_local_surface_id,
device_scale_factor, child_two_support.get());
@@ -2515,7 +2526,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// Add solid color quad
AddSolidColorQuadWithBlendMode(SurfaceSize(), child_root_pass.get(),
- SkBlendMode::kSrcOver, gfx::RRectF());
+ SkBlendMode::kSrcOver, gfx::MaskFilterInfo());
QueuePassAsFrame(std::move(child_root_pass), child_root_local_surface_id,
device_scale_factor, child_root_support.get());
@@ -2527,7 +2538,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
auto* child_root_surface_quad =
root_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
child_root_surface_sqs->opacity = 1.f;
- child_root_surface_sqs->rounded_corner_bounds = kFastRoundedCornerBounds;
+ child_root_surface_sqs->mask_filter_info =
+ kMaskFilterInfoWithFastRoundedCorners;
child_root_surface_sqs->is_fast_rounded_corner = true;
child_root_surface_quad->SetNew(
child_root_surface_sqs, gfx::Rect(SurfaceSize()),
@@ -2553,17 +2565,17 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
const auto& aggregated_quad_list_of_surface =
aggregated_pass_list[0]->quad_list;
EXPECT_EQ(2u, aggregated_quad_list_of_surface.size());
- EXPECT_EQ(kRoundedCornerBounds,
+ EXPECT_EQ(kMaskFilterInfoWithRoundedCorners,
aggregated_quad_list_of_surface.back()
- ->shared_quad_state->rounded_corner_bounds);
+ ->shared_quad_state->mask_filter_info);
// The root render pass will have all the remaining quads with the rounded
// corner set on them.
const auto& aggregated_quad_list_of_root = aggregated_pass_list[1]->quad_list;
EXPECT_EQ(4u, aggregated_quad_list_of_root.size());
for (const auto* q : aggregated_quad_list_of_root) {
- EXPECT_EQ(q->shared_quad_state->rounded_corner_bounds,
- kFastRoundedCornerBounds);
+ EXPECT_EQ(q->shared_quad_state->mask_filter_info,
+ kMaskFilterInfoWithFastRoundedCorners);
}
}
@@ -3995,18 +4007,17 @@ TEST_P(SurfaceAggregatorValidSurfaceWithMergingPassesTest,
aggregated_pass_list[AllowMerge() ? 2 : 1]->quad_list.front();
const auto* rp_quad =
AggregatedRenderPassDrawQuad::MaterialCast(quad_to_test);
- // 1) Without merging, the |quad_to_test| (or more precisely, the
- // |output_rect| of the render pass referenced by the quad that's used for
- // damage intersection test) (0,0 60x60) has damage below from surface root
- // render pass (0,0 60x60), so its |can_use_backdrop_filter_cache| resets
- // to false.
+ // 1) Without merging, for the first aggregation, the child surface has
+ // damage from its root render pass (0,0 60x60). |quad_to_test| is on the
+ // root render pass of the child surface, so no damage is under it and its
+ // |can_use_backdrop_filter_cache| remains unchanged (true).
// 2) With merging, the |quad_to_test| would be merged to the root pass of
// the root surface. The damage from below (0,0 100x100), which is the total
// of the damage from second surface quad (0,0 80x80) and from root render
// pass (0,0 100x100), is transformed into the local space of the child
// surface as (-20,-30 100x100) and it intersects |quad_to_test|(0,0 60x60),
// so its |can_use_backdrop_filter_cache| resets to false.
- EXPECT_FALSE(rp_quad->can_use_backdrop_filter_cache);
+ EXPECT_EQ(!AllowMerge(), rp_quad->can_use_backdrop_filter_cache);
}
// Resubmit child frame and since there'll be no damage under the RPDQ with
@@ -5097,8 +5108,10 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
ASSERT_EQ(0u, aggregated_pass_list[0]->quad_list.size());
}
- // Root surface has smaller damage rect, but filter on render pass means all
- // of it and its descendant passes should be aggregated.
+ // Render passes with pixel-moving foreground filters will increase the damage
+ // only if the damage of the contents will overlap the expanded render pass
+ // draw quad. Since the root surface damage does not overlap, the render pass
+ // and its descendant passes should not be aggregated.
{
CompositorRenderPassId root_pass_ids[] = {CompositorRenderPassId{1},
CompositorRenderPassId{2},
@@ -5122,15 +5135,84 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
auto* filter_pass = root_pass_list[1].get();
filter_pass->shared_quad_state_list.front()
->quad_to_target_transform.Translate(10, 10);
- auto* root_pass = root_pass_list[2].get();
+ // Create 3 pixel-moving filters with the same max pixel movement.
filter_pass->filters.Append(cc::FilterOperation::CreateBlurFilter(2));
- root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
+ filter_pass->filters.Append(
+ cc::FilterOperation::CreateDropShadowFilter(gfx::Point(0, 0), 2, 0));
+ filter_pass->filters.Append(cc::FilterOperation::CreateZoomFilter(2, 4));
+ auto* root_pass = root_pass_list[2].get();
+ // Set the root damage rect which doesn't intersect with the expanded
+ // filter_pass quad (-4, -4, 13, 13) (filter quad (0, 0, 5, 5) +
+ // MaximumPixelMovement(2 * 3 = 6)), so we don't have to add more damage
+ // from the filter_pass and the first render pass draw quad will not be
+ // drawn.
+ root_pass->damage_rect = gfx::Rect(20, 20, 2, 2);
SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
&root_pass_list, std::move(referenced_surfaces),
device_scale_factor);
+
+ auto aggregated_frame = AggregateFrame(root_surface_id);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+
+ ASSERT_EQ(4u, aggregated_pass_list.size());
+
+ EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[0]->damage_rect);
+ EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[1]->damage_rect);
+ EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[2]->damage_rect);
+ // The filter pass does not intersects with the other damages. The root
+ // damage should not increase.
+ EXPECT_EQ(gfx::Rect(20, 20, 2, 2), aggregated_pass_list[3]->damage_rect);
+ EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
+ EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size());
+ EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size());
+ // First render pass draw quad with filterw is outside damage rect, so
+ // shouldn't be drawn.
+ EXPECT_EQ(0u, aggregated_pass_list[3]->quad_list.size());
}
+ // Render passes with pixel-moving foreground filters will increase the damage
+ // if the damage of the contents will overlap the expanded render pass draw
+ // quad (quad rect + maximum pixel movement). Since the root surface damage
+ // overlaps, the render pass and its descendant passes should be aggregated.
{
+ CompositorRenderPassId root_pass_ids[] = {CompositorRenderPassId{1},
+ CompositorRenderPassId{2},
+ CompositorRenderPassId{3}};
+ std::vector<Quad> root_quads1 = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false)};
+ std::vector<Quad> root_quads2 = {
+ Quad::RenderPassQuad(root_pass_ids[0], gfx::Transform(), false)};
+ std::vector<Quad> root_quads3 = {
+ Quad::RenderPassQuad(root_pass_ids[1], gfx::Transform(), false)};
+ std::vector<Pass> root_passes = {
+ Pass(root_quads1, root_pass_ids[0], SurfaceSize()),
+ Pass(root_quads2, root_pass_ids[1], SurfaceSize()),
+ Pass(root_quads3, root_pass_ids[2], SurfaceSize())};
+
+ CompositorRenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+
+ auto* filter_pass = root_pass_list[1].get();
+ filter_pass->shared_quad_state_list.front()
+ ->quad_to_target_transform.Translate(10, 10);
+ // Create 3 pixel-moving filters with the same max pixel movement.
+ filter_pass->filters.Append(cc::FilterOperation::CreateBlurFilter(10));
+ filter_pass->filters.Append(
+ cc::FilterOperation::CreateDropShadowFilter(gfx::Point(0, 0), 10, 0));
+ filter_pass->filters.Append(cc::FilterOperation::CreateZoomFilter(2, 20));
+ auto* root_pass = root_pass_list[2].get();
+ // Make the root damage rect intersect with the expanded filter_pass
+ // quad (filter quad (0, 0, 5, 5) + MaximumPixelMovement(10 * 3) = (-30,
+ // -30, 65, 65)), but not with filter_pass quad itself (0, 0, 5, 5). The
+ // first render pass will be drawn.
+ root_pass->damage_rect = gfx::Rect(20, 20, 2, 2);
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+
auto aggregated_frame = AggregateFrame(root_surface_id);
const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
@@ -5140,13 +5222,17 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[0]->damage_rect);
EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[1]->damage_rect);
EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list[2]->damage_rect);
- EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[3]->damage_rect);
+ // The filter pass intersects with the root surface damage, the root damage
+ // should increase.
+ // damage_rect = original root damage (0, 0, 5, 5) + MaximumPixelMovement(10
+ // * 3) = (-30, -30, 65, 65). Then intersects with the root output_rect (0,
+ // 0, 100, 100) = (0, 0, 35, 35).
+ EXPECT_EQ(gfx::Rect(0, 0, 35, 35), aggregated_pass_list[3]->damage_rect);
EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size());
EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size());
- // First render pass draw quad is outside damage rect, so shouldn't be
- // drawn.
- EXPECT_EQ(0u, aggregated_pass_list[3]->quad_list.size());
+ // First render pass draw quad is damaged. It should be drawn.
+ EXPECT_EQ(1u, aggregated_pass_list[3]->quad_list.size());
}
// Root surface has smaller damage rect. Opacity filter on render pass
@@ -5201,9 +5287,10 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size());
}
- // Render passes with pixel-moving filters will increase the damage only if
- // the damage of the contents will overlap the render pass. Since one of the
- // render passes has a pixel-moving backdrop filter no quads are ignored.
+ // Render passes with pixel-moving backdrop filters will increase the damage
+ // only if the damage of the contents will overlap the render pass. Since one
+ // of the render passes has a pixel-moving backdrop filter no quads are
+ // ignored.
{
CompositorRenderPassId child_pass_ids[] = {CompositorRenderPassId{1},
CompositorRenderPassId{2}};
@@ -6639,7 +6726,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectWithInvalidChildFrame) {
auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
EXPECT_EQ(gfx::Rect(gfx::Rect(0, 0, 100, 100)),
output_root_pass->damage_rect);
- EXPECT_EQ(output_root_pass->damage_rect, aggregated_frame.occluding_damage_);
+ EXPECT_EQ(output_root_pass->damage_rect,
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
// Frame # 1 - The primary surface of the child frame is not available.
{
@@ -6655,9 +6743,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectWithInvalidChildFrame) {
// available.
EXPECT_EQ(gfx::Rect(gfx::Rect(0, 0, 100, 100)),
output_root_pass->damage_rect);
- // Make sure |occluding_damage_| is correct.
+ // Make sure |surface_damage_rect_list_| is correct.
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
}
// Frame # 2 - The primary surface is available now.
@@ -6688,7 +6776,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectWithInvalidChildFrame) {
EXPECT_EQ(gfx::Rect(gfx::Rect(10, 10, 60, 60)),
output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
}
// Frame # 3 - The primary surface is not available, with a different id.
{
@@ -6718,7 +6806,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DamageRectWithInvalidChildFrame) {
EXPECT_EQ(gfx::Rect(gfx::Rect(0, 0, 100, 100)),
output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
}
}
@@ -6751,12 +6839,12 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// root surface quads
std::vector<Quad> root_surface_quads = {
Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(60, 0, 40, 40)),
- Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
- SK_ColorWHITE,
- /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
- /*opacity*/ 1.f, video_transform,
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ /*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
+ /*opacity*/ 1.f, video_transform,
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> root_passes = {
Pass(root_surface_quads,
@@ -6778,16 +6866,23 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// The damage rect of the very first frame is always the full rect.
auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
EXPECT_EQ(gfx::Rect(0, 0, 200, 200), output_root_pass->damage_rect);
- // Make sure |occluding_damage_| is correct.
- EXPECT_EQ(output_root_pass->damage_rect, aggregated_frame.occluding_damage_);
+ // Make sure |surface_damage_rect_list_| is correct.
+ EXPECT_EQ(output_root_pass->damage_rect,
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
- // Occluding damage of the first frame = the whole surface rect on top
- // intersects the video quad.
- // (0, 0, 200, 200) intersect with video quad (10, 0, 80, 80) == (10, 0, 80,
- // 80).
- EXPECT_EQ(gfx::Rect(10, 0, 80, 80), video_sqs->occluding_damage_rect.value());
+
+ // The whole root surface (0, 0, 200, 200) is damaged.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ aggregated_frame.surface_damage_rect_list_[0]);
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(1U, index);
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
// Frame #1 - Has occluding damage
{
@@ -6811,14 +6906,20 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// 40).
EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
- // The solid quad on top (60, 0, 40, 40) intersects the video quad (10, 0,
- // 80, 80).
- EXPECT_EQ(gfx::Rect(60, 0, 30, 40),
- video_sqs->occluding_damage_rect.value());
+ // The solid quad on top (60, 0, 40, 40) is damaged.
+ EXPECT_EQ(gfx::Rect(60, 0, 40, 40),
+ aggregated_frame.surface_damage_rect_list_[0]);
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(1U, index);
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
}
// Frame #2 - No occluding damage, the quad on top doesn't change
{
@@ -6835,12 +6936,20 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// Only the video quad (10, 0, 80, 80) is damaged.
EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
+
// No occluding damage.
- EXPECT_EQ(gfx::Rect(), video_sqs->occluding_damage_rect.value());
+ // The solid quad on top (60, 0, 40, 40) is not damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(0U, index);
+
+ // Video quad(10, 0, 80, 80) is damaged
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
}
// Frame #3 - The only quad on top is removed
{
@@ -6855,8 +6964,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
/*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
/*opacity*/ 1.f, video_transform,
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> root_passes = {
Pass(root_surface_quads,
@@ -6877,14 +6986,21 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// the solid quad on top (60, 0, 40, 40).
EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
- // The expose damage (60, 0, 40, 40) intersects the video quad (10, 0,
- // 80, 80).
- EXPECT_EQ(gfx::Rect(60, 0, 30, 40),
- video_sqs->occluding_damage_rect.value());
+
+ // The expose damage (60, 0, 40, 40) on top.
+ EXPECT_EQ(gfx::Rect(60, 0, 40, 40),
+ aggregated_frame.surface_damage_rect_list_[0]);
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(1U, index);
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
}
// Frame #4 - Has occluding damage and clipping of the video quad is on
{
@@ -6914,16 +7030,22 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// 40).
EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
- // The solid quad on top (60, 0, 40, 40) intersects the clipped video quad
- // (26, 0, 48, 64).
- EXPECT_EQ(gfx::Rect(60, 0, 14, 40),
- video_sqs->occluding_damage_rect.value());
- }
+ // The damaged solid quad on top (60, 0, 40, 40).
+ EXPECT_EQ(gfx::Rect(60, 0, 40, 40),
+ aggregated_frame.surface_damage_rect_list_[0]);
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(1U, index);
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
+ }
// Frame #5 - Has occluding damage and clipping of surface on top is on
{
CompositorFrame child_surface_frame = MakeEmptyCompositorFrame();
@@ -6940,8 +7062,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
/*primary_surface_rect*/ gfx::Rect(0, 0, 100, 100),
/*opacity*/ 1.f, video_transform,
- /*stretch_content_to_fill_bounds=*/false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ /*stretch_content_to_fill_bounds=*/false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> root_passes = {
Pass(root_surface_quads,
@@ -6967,14 +7089,17 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// solid quad on top (60, 0, 80, 70) where the clip rect (80, 0, 40, 30).
EXPECT_EQ(gfx::Rect(10, 0, 130, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
- // The solid quad damage on top (60, 0, 80, 70) intersects the video quad
- // (10, 0, 80, 80).
- EXPECT_EQ(gfx::Rect(60, 0, 30, 70),
- video_sqs->occluding_damage_rect.value());
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(1U, index);
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
}
// Add a quad on top of video quad.
@@ -7001,13 +7126,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// Only the video quad (10, 0, 80, 80) is damaged.
EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
// The underlay optimization doesn't apply with multiple
// possibly damaged quads.
- EXPECT_FALSE(video_sqs->occluding_damage_rect.has_value());
+ EXPECT_FALSE(video_sqs->overlay_damage_index.has_value());
}
// Frame #7 - Child surface contains an undamaged quad other than the video
{
@@ -7028,12 +7153,18 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
// Only the video quad (10, 0, 80, 80) is damaged.
EXPECT_EQ(gfx::Rect(10, 0, 80, 80), output_root_pass->damage_rect);
EXPECT_EQ(output_root_pass->damage_rect,
- aggregated_frame.occluding_damage_);
+ DamageListUnion(aggregated_frame.surface_damage_rect_list_));
const SharedQuadState* video_sqs =
output_root_pass->quad_list.back()->shared_quad_state;
// No occluding damage.
- EXPECT_EQ(gfx::Rect(), video_sqs->occluding_damage_rect.value());
+ EXPECT_TRUE(video_sqs->overlay_damage_index.has_value());
+ auto index = video_sqs->overlay_damage_index.value();
+ EXPECT_EQ(0U, index);
+
+ // Video quad(10, 0, 80, 80) is damaged.
+ EXPECT_EQ(gfx::Rect(10, 0, 80, 80),
+ aggregated_frame.surface_damage_rect_list_[index]);
}
}
@@ -7256,7 +7387,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformChange) {
child_frame.render_pass_list[0]
->shared_quad_state_list.front()
- ->rounded_corner_bounds = gfx::RRectF(0, 0, 100, 10, 5);
+ ->mask_filter_info = gfx::MaskFilterInfo(gfx::RRectF(0, 0, 100, 10, 5));
child_sink_->SubmitCompositorFrame(child_local_surface_id,
std::move(child_frame));
@@ -7285,8 +7416,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformChange) {
auto* aggregated_first_pass_sqs =
aggregated_frame.render_pass_list[0]->shared_quad_state_list.front();
- EXPECT_EQ(gfx::RRectF(0, 7, 100, 10, 5),
- aggregated_first_pass_sqs->rounded_corner_bounds);
+ EXPECT_EQ(
+ gfx::RRectF(0, 7, 100, 10, 5),
+ aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
}
// Tests that the rounded corner bounds of a surface quad that gets transformed
@@ -7328,11 +7460,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformedSurfaceQuad) {
child_local_surface_id);
{
// Set an opacity in order to prevent merging into the root render pass.
- std::vector<Quad> child_quads = {
- Quad::SurfaceQuad(SurfaceRange(base::nullopt, grandchild_surface_id),
- SK_ColorWHITE, gfx::Rect(5, 5), 0.5f,
- gfx::Transform(), false, gfx::RRectF(0, 0, 96, 10, 5),
- /*is_fast_border_radius*/ false)};
+ std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), 0.5f, gfx::Transform(), false,
+ gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> child_passes = {
Pass(child_quads, CompositorRenderPassId{1}, SurfaceSize())};
@@ -7350,7 +7482,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformedSurfaceQuad) {
surface_transform.Translate(3, 4);
std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
- gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::RRectF(), false)};
+ gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
@@ -7375,8 +7508,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RoundedCornerTransformedSurfaceQuad) {
// Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
// by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
// by a (3, 4) translation followed by a (0, 7) translation.
- EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
- aggregated_first_pass_sqs->rounded_corner_bounds);
+ EXPECT_EQ(
+ gfx::RRectF(3, 11, 192, 20, 10),
+ aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
}
// This is a variant of RoundedCornerTransformedSurfaceQuad that does not
@@ -7415,11 +7549,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
SurfaceId child_surface_id(child_sink_->frame_sink_id(),
child_local_surface_id);
{
- std::vector<Quad> child_quads = {
- Quad::SurfaceQuad(SurfaceRange(base::nullopt, grandchild_surface_id),
- SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
- false, gfx::RRectF(0, 0, 96, 10, 5),
- /*is_fast_border_radius*/ false)};
+ std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), 1.f, gfx::Transform(), false,
+ gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> child_passes = {
Pass(child_quads, CompositorRenderPassId{1}, SurfaceSize())};
@@ -7437,8 +7571,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
surface_transform.Translate(3, 4);
std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
- gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::RRectF(),
- /*is_fast_border_radius*/ false)};
+ gfx::Rect(5, 5), 1.f, surface_transform, false, gfx::MaskFilterInfo(),
+ /*is_fast_rounded_corner=*/false)};
std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
@@ -7463,8 +7597,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// Original rounded rect is (0, 0, 96, 10, 5). This then gets multiplied
// by a device scale factor of 2 to (0, 0, 192, 20, 10), then moved
// by a (3, 4) translation followed by a (0, 7) translation.
- EXPECT_EQ(gfx::RRectF(3, 11, 192, 20, 10),
- aggregated_first_pass_sqs->rounded_corner_bounds);
+ EXPECT_EQ(
+ gfx::RRectF(3, 11, 192, 20, 10),
+ aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
}
TEST_F(SurfaceAggregatorValidSurfaceTest, TransformedRoundedSurfaceQuad) {
@@ -7498,11 +7633,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TransformedRoundedSurfaceQuad) {
// Root surface.
gfx::Transform surface_transform;
surface_transform.Translate(3, 4);
- std::vector<Quad> secondary_quads = {
- Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
- SK_ColorWHITE, gfx::Rect(5, 5), 1.f, surface_transform,
- false, gfx::RRectF(0, 0, 96, 10, 5),
- /* is_fast_border_radius */ true)};
+ std::vector<Quad> secondary_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), 1.f, surface_transform, false,
+ gfx::MaskFilterInfo(gfx::RRectF(0, 0, 96, 10, 5)),
+ /*is_fast_rounded_corner=*/true)};
std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize())};
@@ -7529,8 +7664,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TransformedRoundedSurfaceQuad) {
// The rounded rect on the surface quad is already in the space of the root
// surface, so the (3, 4) translation should not apply to it.
- EXPECT_EQ(gfx::RRectF(0, 0, 96, 10, 5),
- aggregated_first_pass_sqs->rounded_corner_bounds);
+ EXPECT_EQ(
+ gfx::RRectF(0, 0, 96, 10, 5),
+ aggregated_first_pass_sqs->mask_filter_info.rounded_corner_bounds());
}
// Verifies that if a child surface is embedded twice in the root surface,
@@ -8165,6 +8301,7 @@ void ExpectDelegatedInkMetadataIsEqual(const DelegatedInkMetadata& lhs,
rhs.presentation_area().width());
EXPECT_FLOAT_EQ(lhs.presentation_area().height(),
rhs.presentation_area().height());
+ EXPECT_EQ(lhs.frame_time(), rhs.frame_time());
}
// Basic test to confirm that ink metadata on a child surface will be
@@ -8176,9 +8313,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DelegatedInkMetadataTest) {
Pass(child_quads, CompositorRenderPassId{1}, gfx::Size(100, 100))};
CompositorFrame child_frame = MakeEmptyCompositorFrame();
- DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
- base::TimeTicks::Now(),
- gfx::RectF(10, 10, 200, 200));
+ DelegatedInkMetadata metadata(
+ gfx::PointF(100, 100), 1.5, SK_ColorRED, base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200), base::TimeTicks::Now());
child_frame.metadata.delegated_ink_metadata =
std::make_unique<DelegatedInkMetadata>(metadata);
AddPasses(&child_frame.render_pass_list, child_passes,
@@ -8221,8 +8358,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DelegatedInkMetadataTest) {
root_frame.render_pass_list[0]
->shared_quad_state_list.ElementAt(0)
->quad_to_target_transform.TransformRect(&area);
- metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
- metadata.timestamp(), area);
+ metadata =
+ DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area, metadata.frame_time());
root_sink_->SubmitCompositorFrame(root_local_surface_id_,
std::move(root_frame));
@@ -8253,9 +8391,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
std::vector<Pass> greatgrandchild_passes = {Pass(
greatgrandchild_quads, CompositorRenderPassId{1}, gfx::Size(100, 100))};
- DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
- base::TimeTicks::Now(),
- gfx::RectF(10, 10, 200, 200));
+ DelegatedInkMetadata metadata(
+ gfx::PointF(100, 100), 1.5, SK_ColorRED, base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200), base::TimeTicks::Now());
CompositorFrame greatgrandchild_frame = MakeEmptyCompositorFrame();
greatgrandchild_frame.metadata.delegated_ink_metadata =
std::make_unique<DelegatedInkMetadata>(metadata);
@@ -8374,8 +8512,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
root_local_surface_id_);
auto aggregated_frame = AggregateFrame(root_surface_id);
- metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
- metadata.timestamp(), area);
+ metadata =
+ DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area, metadata.frame_time());
std::unique_ptr<DelegatedInkMetadata> actual_metadata =
std::move(aggregated_frame.delegated_ink_metadata);
@@ -8422,7 +8561,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
DelegatedInkMetadata metadata = DelegatedInkMetadata(
gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
- gfx::RectF(50, 50, 300, 300));
+ gfx::RectF(50, 50, 300, 300), base::TimeTicks::Now());
CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
child_2_frame.metadata.delegated_ink_metadata =
std::make_unique<DelegatedInkMetadata>(metadata);
@@ -8505,8 +8644,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
root_local_surface_id_);
auto aggregated_frame = AggregateFrame(root_surface_id);
- metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
- metadata.timestamp(), area);
+ metadata =
+ DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area, metadata.frame_time());
std::unique_ptr<DelegatedInkMetadata> actual_metadata =
std::move(aggregated_frame.delegated_ink_metadata);
@@ -8558,11 +8698,12 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
// issues with both metadatas sometimes having the same time in Release.
DelegatedInkMetadata early_metadata = DelegatedInkMetadata(
gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
- gfx::RectF(50, 50, 300, 300));
+ gfx::RectF(50, 50, 300, 300), base::TimeTicks::Now());
DelegatedInkMetadata later_metadata = DelegatedInkMetadata(
gfx::PointF(92, 35), 0.08, SK_ColorYELLOW,
base::TimeTicks::Now() + base::TimeDelta::FromMicroseconds(50),
- gfx::RectF(35, 55, 128, 256));
+ gfx::RectF(35, 55, 128, 256),
+ base::TimeTicks::Now() + base::TimeDelta::FromMicroseconds(52));
CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
child_2_frame.metadata.delegated_ink_metadata =
@@ -8651,7 +8792,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
DelegatedInkMetadata expected_metadata = DelegatedInkMetadata(
pt, later_metadata.diameter(), later_metadata.color(),
- later_metadata.timestamp(), area);
+ later_metadata.timestamp(), area, later_metadata.frame_time());
std::unique_ptr<DelegatedInkMetadata> actual_metadata =
std::move(aggregated_frame.delegated_ink_metadata);
@@ -8674,9 +8815,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
Pass(child_quads, CompositorRenderPassId{1}, gfx::Size(100, 100))};
CompositorFrame child_frame = MakeEmptyCompositorFrame();
- DelegatedInkMetadata metadata(gfx::PointF(34, 89), 1.597, SK_ColorBLUE,
- base::TimeTicks::Now(),
- gfx::RectF(2.3, 3.2, 177, 212));
+ DelegatedInkMetadata metadata(
+ gfx::PointF(34, 89), 1.597, SK_ColorBLUE, base::TimeTicks::Now(),
+ gfx::RectF(2.3, 3.2, 177, 212), base::TimeTicks::Now());
child_frame.metadata.delegated_ink_metadata =
std::make_unique<DelegatedInkMetadata>(metadata);
AddPasses(&child_frame.render_pass_list, child_passes,
@@ -8740,6 +8881,63 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
EXPECT_FALSE(new_aggregated_frame.delegated_ink_metadata);
}
+// Tests that changing the color usage results in full-frame damage.
+TEST_F(SurfaceAggregatorValidSurfaceTest, ColorUsageChangeFullFrameDamage) {
+ constexpr float device_scale_factor = 1.0f;
+ const gfx::Rect full_damage_rect(SurfaceSize());
+ const gfx::Rect partial_damage_rect(10, 10, 10, 10);
+ std::vector<Quad> quads = {
+ Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(SurfaceSize()))};
+ std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
+ passes[0].damage_rect = partial_damage_rect;
+
+ // First frame has full damage.
+ {
+ SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
+ device_scale_factor);
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ auto aggregated_frame = AggregateFrame(root_surface_id);
+
+ EXPECT_EQ(gfx::ContentColorUsage::kHDR,
+ aggregated_frame.render_pass_list[0]->content_color_usage);
+ EXPECT_EQ(full_damage_rect,
+ aggregated_frame.render_pass_list[0]->damage_rect);
+ }
+ // Second frame has partial damage.
+ {
+ SubmitCompositorFrame(root_sink_.get(), passes, root_local_surface_id_,
+ device_scale_factor);
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ auto aggregated_frame = AggregateFrame(root_surface_id);
+
+ EXPECT_EQ(gfx::ContentColorUsage::kHDR,
+ aggregated_frame.render_pass_list[0]->content_color_usage);
+ EXPECT_EQ(partial_damage_rect,
+ aggregated_frame.render_pass_list[0]->damage_rect);
+ }
+ // Finally, change the content_color_usage from HDR to sRGB. The resulting
+ // frame should have full damage.
+ {
+ CompositorFrame compositor_frame = MakeEmptyCompositorFrame();
+ compositor_frame.metadata.content_color_usage =
+ gfx::ContentColorUsage::kSRGB;
+ AddPasses(&compositor_frame.render_pass_list, passes,
+ &compositor_frame.metadata.referenced_surfaces);
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(compositor_frame));
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ auto aggregated_frame = AggregateFrame(root_surface_id);
+
+ EXPECT_EQ(gfx::ContentColorUsage::kSRGB,
+ aggregated_frame.render_pass_list[0]->content_color_usage);
+ EXPECT_EQ(full_damage_rect,
+ aggregated_frame.render_pass_list[0]->damage_rect);
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(,
SurfaceAggregatorValidSurfaceWithMergingPassesTest,
testing::Bool());
diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS
index 28c8b9f43fb..7351dd57211 100644
--- a/chromium/components/viz/service/display_embedder/DEPS
+++ b/chromium/components/viz/service/display_embedder/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+cc/scheduler",
"+components/viz/common",
"+components/viz/service/display/dc_layer_overlay.h",
+ "+components/viz/service/display/display_compositor_memory_and_task_controller.h",
"+components/viz/service/display/external_use_client.h",
"+components/viz/service/display/output_surface_client.h",
"+components/viz/service/display/output_surface_frame.h",
@@ -33,6 +34,7 @@ include_rules = [
"+third_party/dawn/src/include",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/khronos/GLES2/gl2ext.h",
+ "+third_party/libyuv",
"+third_party/skia",
"+ui/accelerated_widget_mac",
"+ui/display",
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.cc b/chromium/components/viz/service/display_embedder/gl_output_surface.cc
index 7b5ee808913..810af92dd55 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface.cc
@@ -252,15 +252,6 @@ gpu::SurfaceHandle GLOutputSurface::GetSurfaceHandle() const {
return surface_handle_;
}
-scoped_refptr<gpu::GpuTaskSchedulerHelper>
-GLOutputSurface::GetGpuTaskSchedulerHelper() {
- return viz_context_provider_->GetGpuTaskSchedulerHelper();
-}
-
-gpu::MemoryTracker* GLOutputSurface::GetMemoryTracker() {
- return viz_context_provider_->GetMemoryTracker();
-}
-
void GLOutputSurface::SetFrameRate(float frame_rate) {
viz_context_provider_->ContextSupport()->SetFrameRate(frame_rate);
}
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.h b/chromium/components/viz/service/display_embedder/gl_output_surface.h
index efbe38cd1ce..25394e2b353 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface.h
@@ -54,9 +54,6 @@ class GLOutputSurface : public OutputSurface {
base::ScopedClosureRunner GetCacheBackBufferCb() override;
gpu::SurfaceHandle GetSurfaceHandle() const override;
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override;
- gpu::MemoryTracker* GetMemoryTracker() override;
void SetFrameRate(float frame_rate) override;
void SetNeedsMeasureNextDrawLatency() override;
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.cc b/chromium/components/viz/service/display_embedder/output_presenter.cc
index a1ea3f86653..ba55af0a461 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter.cc
@@ -9,6 +9,7 @@
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
@@ -52,9 +53,8 @@ void OutputPresenter::Image::BeginWriteSkia() {
DCHECK(end_semaphores_.empty());
std::vector<GrBackendSemaphore> begin_semaphores;
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- SkSurfaceProps surface_props(0 /* flags */,
- SkSurfaceProps::kLegacyFontHost_InitType);
+ SkSurfaceProps surface_props =
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
// Buffer queue is internal to GPU proc and handles texture initialization,
// so allow uncleared access.
@@ -115,4 +115,14 @@ void OutputPresenter::Image::PreGrContextSubmit() {
}
}
+std::unique_ptr<OutputPresenter::Image>
+OutputPresenter::AllocateBackgroundImage(gfx::ColorSpace color_space,
+ gfx::Size image_size) {
+ return nullptr;
+}
+
+void OutputPresenter::ScheduleBackground(Image* image) {
+ NOTREACHED();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.h b/chromium/components/viz/service/display_embedder/output_presenter.h
index 52b9ed35251..7916c94069e 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter.h
+++ b/chromium/components/viz/service/display_embedder/output_presenter.h
@@ -86,6 +86,9 @@ class VIZ_SERVICE_EXPORT OutputPresenter {
gfx::ColorSpace color_space,
gfx::Size image_size,
size_t num_images) = 0;
+ virtual std::unique_ptr<Image> AllocateBackgroundImage(
+ gfx::ColorSpace color_space,
+ gfx::Size image_size);
virtual void SwapBuffers(SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) = 0;
virtual void PostSubBuffer(const gfx::Rect& rect,
@@ -102,6 +105,7 @@ class VIZ_SERVICE_EXPORT OutputPresenter {
gpu::SharedImageRepresentationOverlay::ScopedReadAccess;
virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) = 0;
+ virtual void ScheduleBackground(Image* image);
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
index 560e22605b7..4bbd5bde549 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
@@ -8,6 +8,7 @@
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/inspect/cpp/component.h>
+#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
@@ -25,6 +26,7 @@
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/ozone/public/platform_window_surface.h"
namespace viz {
@@ -43,6 +45,20 @@ void GrSemaphoresToZxEvents(gpu::VulkanImplementation* vulkan_implementation,
}
}
+// Duplicates the given zx::events and stores in gfx::GpuFences.
+std::vector<gfx::GpuFence> ZxEventsToGpuFences(
+ const std::vector<zx::event>& events) {
+ std::vector<gfx::GpuFence> fences;
+ for (const auto& event : events) {
+ gfx::GpuFenceHandle handle;
+ zx_status_t status =
+ event.duplicate(ZX_RIGHT_SAME_RIGHTS, &handle.owned_event);
+ ZX_DCHECK(status == ZX_OK, status);
+ fences.emplace_back(std::move(handle));
+ }
+ return fences;
+}
+
class PresenterImageFuchsia : public OutputPresenter::Image {
public:
explicit PresenterImageFuchsia(uint32_t image_id);
@@ -112,7 +128,20 @@ void PresenterImageFuchsia::TakeSemaphores(
} // namespace
-OutputPresenterFuchsia::PendingFrame::PendingFrame() = default;
+OutputPresenterFuchsia::PendingOverlay::PendingOverlay(
+ OverlayCandidate candidate,
+ std::vector<gfx::GpuFence> release_fences)
+ : candidate(std::move(candidate)),
+ release_fences(std::move(release_fences)) {}
+OutputPresenterFuchsia::PendingOverlay::~PendingOverlay() = default;
+
+OutputPresenterFuchsia::PendingOverlay::PendingOverlay(PendingOverlay&&) =
+ default;
+OutputPresenterFuchsia::PendingOverlay&
+OutputPresenterFuchsia::PendingOverlay::operator=(PendingOverlay&&) = default;
+
+OutputPresenterFuchsia::PendingFrame::PendingFrame(uint32_t ordinal)
+ : ordinal(ordinal) {}
OutputPresenterFuchsia::PendingFrame::~PendingFrame() = default;
OutputPresenterFuchsia::PendingFrame::PendingFrame(PendingFrame&&) = default;
@@ -181,6 +210,7 @@ void OutputPresenterFuchsia::InitializeCapabilities(
capabilities->output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
capabilities->supports_post_sub_buffer = false;
capabilities->supports_commit_overlay_planes = false;
+ capabilities->supports_surfaceless = true;
capabilities->sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
kRGBA_8888_SkColorType;
@@ -228,11 +258,13 @@ OutputPresenterFuchsia::AllocateImages(gfx::ColorSpace color_space,
// the ImagePipe.
fuchsia::sysmem::BufferCollectionTokenSyncPtr collection_token;
sysmem_allocator_->AllocateSharedCollection(collection_token.NewRequest());
+ collection_token->SetName(100u, "ChromiumOutput");
+ collection_token->SetDebugClientInfo("vulkan", 0u);
- fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
- token_for_scenic;
+ fuchsia::sysmem::BufferCollectionTokenSyncPtr token_for_scenic;
collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
token_for_scenic.NewRequest());
+ token_for_scenic->SetDebugClientInfo("scenic", 0u);
zx_status_t status = collection_token->Sync();
if (status != ZX_OK) {
@@ -328,11 +360,7 @@ void OutputPresenterFuchsia::SwapBuffers(
next_frame_->completion_callback = std::move(completion_callback);
next_frame_->presentation_callback = std::move(presentation_callback);
- pending_frames_.push_back(std::move(next_frame_.value()));
- next_frame_.reset();
-
- if (!present_is_pending_)
- PresentNextFrame();
+ PresentNextFrame();
}
void OutputPresenterFuchsia::PostSubBuffer(
@@ -356,8 +384,9 @@ void OutputPresenterFuchsia::SchedulePrimaryPlane(
bool is_submitted) {
auto* image_fuchsia = static_cast<PresenterImageFuchsia*>(image);
- DCHECK(!next_frame_);
- next_frame_ = PendingFrame();
+ if (!next_frame_)
+ next_frame_ = PendingFrame(next_frame_ordinal_++);
+ DCHECK(!next_frame_->buffer_collection_id);
next_frame_->image_id = image_fuchsia->image_id();
next_frame_->buffer_collection_id = last_buffer_collection_id_;
@@ -384,56 +413,100 @@ void OutputPresenterFuchsia::SchedulePrimaryPlane(
void OutputPresenterFuchsia::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) {
- // Overlays are not supported yet.
- NOTREACHED();
+ if (!next_frame_)
+ next_frame_ = PendingFrame(next_frame_ordinal_++);
+
+ for (size_t i = 0; i < overlays.size(); ++i) {
+ next_frame_->overlays.emplace_back(std::move(overlays[i]),
+ accesses[i]->TakeReleaseFences());
+ // TODO(crbug.com/1144890): Enqueue overlay plane's acquire fences
+ // after |supports_commit_overlay_planes| is supported. Overlay plane might
+ // display the same Image more than once, which can create a fence
+ // dependency that can be broken by a later Image. However, primary plane
+ // implementation allows only one present at a time. In this scenario,
+ // merging fences might cause hangs, see crbug.com/1151042.
+ }
}
void OutputPresenterFuchsia::PresentNextFrame() {
- DCHECK(!present_is_pending_);
- DCHECK(!pending_frames_.empty());
+ DCHECK(next_frame_);
+
+ pending_frames_.push_back(std::move(next_frame_.value()));
+ next_frame_.reset();
+ auto& frame = pending_frames_.back();
TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "OutputPresenterFuchsia::PresentQueue",
TRACE_ID_LOCAL(this), "image_id",
- pending_frames_.front().image_id);
+ frame.image_id);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
"viz", "OutputPresenterFuchsia::PresentFrame", TRACE_ID_LOCAL(this),
- "image_id", pending_frames_.front().image_id);
+ "image_id", frame.image_id);
+
+ for (size_t i = 0; i < frame.overlays.size(); ++i) {
+ auto& overlay = frame.overlays[i].candidate;
+ DCHECK(overlay.mailbox.IsSharedImage());
+ auto pixmap =
+ dependency_->GetSharedImageManager()->GetNativePixmap(overlay.mailbox);
+ if (!pixmap) {
+ LOG(ERROR) << "Cannot access SysmemNativePixmap";
+ continue;
+ }
+ pixmap->ScheduleOverlayPlane(dependency_->GetSurfaceHandle(),
+ overlay.plane_z_order, overlay.transform,
+ gfx::ToRoundedRect(overlay.display_rect),
+ overlay.uv_rect, !overlay.is_opaque,
+ ZxEventsToGpuFences(frame.acquire_fences),
+ std::move(frame.overlays[i].release_fences));
+ }
+
+ auto now = base::TimeTicks::Now();
+
+ auto present_time = now;
+
+ // If we have PresentatonState frame a previously displayed frame then use it
+ // to calculate target timestamp for the new frame.
+ if (presentation_state_) {
+ uint32_t relative_position =
+ frame.ordinal - presentation_state_->presented_frame_ordinal;
+ present_time = presentation_state_->presentation_time +
+ presentation_state_->interval * relative_position -
+ base::TimeDelta::FromMilliseconds(1);
+ present_time = std::max(present_time, now);
+ }
- present_is_pending_ = true;
- uint64_t target_presentation_time = zx_clock_get_monotonic();
image_pipe_->PresentImage(
- pending_frames_.front().image_id, target_presentation_time,
- std::move(pending_frames_.front().acquire_fences),
- std::move(pending_frames_.front().release_fences),
+ frame.image_id, present_time.ToZxTime(), std::move(frame.acquire_fences),
+ std::move(frame.release_fences),
fit::bind_member(this, &OutputPresenterFuchsia::OnPresentComplete));
}
void OutputPresenterFuchsia::OnPresentComplete(
fuchsia::images::PresentationInfo presentation_info) {
- DCHECK(present_is_pending_);
- present_is_pending_ = false;
-
TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "OutputPresenterFuchsia::PresentFrame",
TRACE_ID_LOCAL(this), "image_id",
pending_frames_.front().image_id);
+ auto presentation_time =
+ base::TimeTicks::FromZxTime(presentation_info.presentation_time);
+ auto presentation_interval =
+ base::TimeDelta::FromZxDuration(presentation_info.presentation_interval);
+
std::move(pending_frames_.front().completion_callback)
.Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
std::move(pending_frames_.front().presentation_callback)
- .Run(gfx::PresentationFeedback(
- base::TimeTicks::FromZxTime(presentation_info.presentation_time),
- base::TimeDelta::FromZxDuration(
- presentation_info.presentation_interval),
- gfx::PresentationFeedback::kVSync));
+ .Run(gfx::PresentationFeedback(presentation_time, presentation_interval,
+ gfx::PresentationFeedback::kVSync));
if (pending_frames_.front().remove_buffer_collection) {
image_pipe_->RemoveBufferCollection(
pending_frames_.front().buffer_collection_id);
}
+ presentation_state_ =
+ PresentatonState{pending_frames_.front().ordinal, presentation_time,
+ presentation_interval};
+
pending_frames_.pop_front();
- if (!pending_frames_.empty())
- PresentNextFrame();
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h
index 686a11d2b2f..48435b9cfea 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h
+++ b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h
@@ -63,15 +63,29 @@ class VIZ_SERVICE_EXPORT OutputPresenterFuchsia : public OutputPresenter {
std::vector<ScopedOverlayAccess*> accesses) final;
private:
+ struct PendingOverlay {
+ PendingOverlay(OverlayCandidate candidate,
+ std::vector<gfx::GpuFence> release_fences);
+ ~PendingOverlay();
+
+ PendingOverlay(PendingOverlay&&);
+ PendingOverlay& operator=(PendingOverlay&&);
+
+ OverlayCandidate candidate;
+ std::vector<gfx::GpuFence> release_fences;
+ };
+
struct PendingFrame {
- PendingFrame();
+ explicit PendingFrame(uint32_t ordinal);
~PendingFrame();
PendingFrame(PendingFrame&&);
PendingFrame& operator=(PendingFrame&&);
- uint32_t buffer_collection_id;
- uint32_t image_id;
+ uint32_t ordinal = 0;
+
+ uint32_t buffer_collection_id = 0;
+ uint32_t image_id = 0;
std::vector<zx::event> acquire_fences;
std::vector<zx::event> release_fences;
@@ -82,6 +96,15 @@ class VIZ_SERVICE_EXPORT OutputPresenterFuchsia : public OutputPresenter {
// Indicates that this is the last frame for this buffer collection and that
// the collection can be removed after the frame is presented.
bool remove_buffer_collection = false;
+
+ // Vector of overlays that are associated with this frame.
+ std::vector<PendingOverlay> overlays;
+ };
+
+ struct PresentatonState {
+ int presented_frame_ordinal;
+ base::TimeTicks presentation_time;
+ base::TimeDelta interval;
};
void PresentNextFrame();
@@ -111,7 +134,16 @@ class VIZ_SERVICE_EXPORT OutputPresenterFuchsia : public OutputPresenter {
base::circular_deque<PendingFrame> pending_frames_;
- bool present_is_pending_ = false;
+ // Ordinal that will be assigned to the next frame. Ordinals are used to
+ // calculate frame position relative to the current frame stored in
+ // |presentation_state_|. They will wrap around when reaching 2^32, but the
+ // math used to calculate relative position will still work as expected.
+ uint32_t next_frame_ordinal_ = 0;
+
+ // Presentation information received from ImagePipe after rendering a frame.
+ // Used to calculate target presentation time for the frames presented in the
+ // future.
+ base::Optional<PresentatonState> presentation_state_;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
index d587bf4c56e..3e3de1684fd 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -17,6 +17,7 @@
#include "ui/display/types/display_snapshot.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/overlay_transform.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
@@ -32,6 +33,13 @@ namespace viz {
namespace {
+// Helper function for moving a GpuFence from a vector to a unique_ptr.
+std::unique_ptr<gfx::GpuFence> TakeGpuFence(std::vector<gfx::GpuFence> fences) {
+ DCHECK(fences.empty() || fences.size() == 1u);
+ return fences.empty() ? nullptr
+ : std::make_unique<gfx::GpuFence>(std::move(fences[0]));
+}
+
class PresenterImageGL : public OutputPresenter::Image {
public:
PresenterImageGL() = default;
@@ -135,8 +143,9 @@ int PresenterImageGL::present_count() const {
gl::GLImage* PresenterImageGL::GetGLImage(
std::unique_ptr<gfx::GpuFence>* fence) {
if (scoped_overlay_read_access_) {
- if (fence)
- *fence = scoped_overlay_read_access_->TakeFence();
+ if (fence) {
+ *fence = TakeGpuFence(scoped_overlay_read_access_->TakeAcquireFences());
+ }
return scoped_overlay_read_access_->gl_image();
}
@@ -282,6 +291,20 @@ OutputPresenterGL::AllocateImages(gfx::ColorSpace color_space,
return images;
}
+std::unique_ptr<OutputPresenter::Image>
+OutputPresenterGL::AllocateBackgroundImage(gfx::ColorSpace color_space,
+ gfx::Size image_size) {
+ auto image = std::make_unique<PresenterImageGL>();
+ if (!image->Initialize(shared_image_factory_,
+ shared_image_representation_factory_, image_size,
+ color_space, image_format_, dependency_,
+ shared_image_usage_)) {
+ DLOG(ERROR) << "Failed to initialize image.";
+ return nullptr;
+ }
+ return image;
+}
+
void OutputPresenterGL::SwapBuffers(
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) {
@@ -329,6 +352,22 @@ void OutputPresenterGL::SchedulePrimaryPlane(
plane.enable_blending, std::move(fence));
}
+void OutputPresenterGL::ScheduleBackground(Image* image) {
+ // Background is not seen by user, and is created before buffer queue buffers.
+ // So fence is not needed.
+ auto* gl_image =
+ reinterpret_cast<PresenterImageGL*>(image)->GetGLImage(nullptr);
+
+ // Background is also z-order 0.
+ constexpr int kPlaneZOrder = INT32_MIN;
+ // Background always uses the full texture.
+ constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
+ gl_surface_->ScheduleOverlayPlane(
+ kPlaneZOrder, gfx::OVERLAY_TRANSFORM_NONE, gl_image, gfx::Rect(),
+ /*crop_rect=*/kUVRect,
+ /*enable_blend=*/false, /*gpu_fence=*/nullptr);
+}
+
void OutputPresenterGL::CommitOverlayPlanes(
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) {
@@ -360,7 +399,7 @@ void OutputPresenterGL::ScheduleOverlays(
gl_surface_->ScheduleOverlayPlane(
overlay.plane_z_order, overlay.transform, gl_image,
ToNearestRect(overlay.display_rect), overlay.uv_rect,
- !overlay.is_opaque, accesses[i]->TakeFence());
+ !overlay.is_opaque, TakeGpuFence(accesses[i]->TakeAcquireFences()));
}
#elif defined(OS_APPLE)
gl_surface_->ScheduleCALayer(ui::CARendererLayerParams(
@@ -368,11 +407,10 @@ void OutputPresenterGL::ScheduleOverlays(
gfx::ToEnclosingRect(overlay.shared_state->clip_rect),
overlay.shared_state->rounded_corner_bounds,
overlay.shared_state->sorting_context_id,
- gfx::Transform(overlay.transform ? *overlay.transform
- : overlay.shared_state->transform),
- gl_image, overlay.contents_rect,
- gfx::ToEnclosingRect(overlay.bounds_rect), overlay.background_color,
- overlay.edge_aa_mask, overlay.shared_state->opacity, overlay.filter));
+ gfx::Transform(overlay.shared_state->transform), gl_image,
+ overlay.contents_rect, gfx::ToEnclosingRect(overlay.bounds_rect),
+ overlay.background_color, overlay.edge_aa_mask,
+ overlay.shared_state->opacity, overlay.filter));
#endif
}
#endif // defined(OS_ANDROID) || defined(OS_APPLE) || defined(USE_OZONE)
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.h b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
index 4cb0ef9a875..7bf8c8b7728 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_gl.h
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
@@ -49,6 +49,8 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
gfx::ColorSpace color_space,
gfx::Size image_size,
size_t num_images) final;
+ std::unique_ptr<Image> AllocateBackgroundImage(gfx::ColorSpace color_space,
+ gfx::Size image_size) final;
void SwapBuffers(SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) final;
void PostSubBuffer(const gfx::Rect& rect,
@@ -62,6 +64,7 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
bool is_submitted) final;
void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) final;
+ void ScheduleBackground(Image* image) final;
private:
scoped_refptr<gl::GLSurface> gl_surface_;
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider.h b/chromium/components/viz/service/display_embedder/output_surface_provider.h
index 9739af01003..77d463e683d 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider.h
@@ -7,16 +7,15 @@
#include <memory>
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/gpu_task_scheduler_helper.h"
#include "services/viz/privileged/mojom/compositing/display_private.mojom.h"
-namespace gpu {
-class SharedImageManager;
-}
-
namespace viz {
struct DebugRendererSettings;
+class DisplayCompositorMemoryAndTaskController;
class RendererSettings;
class OutputSurface;
@@ -25,20 +24,22 @@ class OutputSurfaceProvider {
public:
virtual ~OutputSurfaceProvider() {}
+ // Needs to be called before calling the CreateOutputSurface function. Output
+ // of this should feed into the CreateOutputSurface function.
+ virtual std::unique_ptr<DisplayCompositorMemoryAndTaskController>
+ CreateGpuDependency(bool gpu_compositing,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings) = 0;
+
// Creates a new OutputSurface for |surface_handle|. If creating an
// OutputSurface fails this function will return null.
virtual std::unique_ptr<OutputSurface> CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
+ DisplayCompositorMemoryAndTaskController* gpu_dependency,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) = 0;
-
- // TODO(weiliangc): This API is unfortunately located since this is the
- // overlapping place that both GLOutputSurface and SkiaOutputSurface code path
- // has access to SharedImageManager. Refactor so that OverlayProcessor and
- // OutputSurface could be initialized together at appropriate place.
- virtual gpu::SharedImageManager* GetSharedImageManager() = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
index 2da653cc9c3..54686950a28 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -7,7 +7,8 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/sequenced_task_runner.h"
@@ -16,6 +17,7 @@
#include "cc/base/switches.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/display_embedder/gl_output_surface.h"
#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
#include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
@@ -99,10 +101,33 @@ OutputSurfaceProviderImpl::OutputSurfaceProviderImpl(bool headless)
OutputSurfaceProviderImpl::~OutputSurfaceProviderImpl() = default;
+std::unique_ptr<DisplayCompositorMemoryAndTaskController>
+OutputSurfaceProviderImpl::CreateGpuDependency(
+ bool gpu_compositing,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings) {
+ if (!gpu_compositing)
+ return nullptr;
+
+ if (renderer_settings.use_skia_renderer) {
+ gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
+ auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+ gpu_service_impl_, surface_handle);
+ return std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ std::move(skia_deps));
+ } else {
+ DCHECK(task_executor_);
+ gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
+ return std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ task_executor_, image_factory_);
+ }
+}
+
std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
+ DisplayCompositorMemoryAndTaskController* gpu_dependency,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) {
#if defined(OS_CHROMEOS)
@@ -118,12 +143,11 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
} else if (renderer_settings.use_skia_renderer) {
+ DCHECK(gpu_dependency);
{
gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
output_surface = SkiaOutputSurfaceImpl::Create(
- std::make_unique<SkiaOutputSurfaceDependencyImpl>(gpu_service_impl_,
- surface_handle),
- renderer_settings, debug_settings);
+ gpu_dependency, renderer_settings, debug_settings);
}
if (!output_surface) {
#if defined(OS_CHROMEOS) || BUILDFLAG(IS_CHROMECAST)
@@ -138,6 +162,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
}
} else {
DCHECK(task_executor_);
+ DCHECK(gpu_dependency);
scoped_refptr<VizProcessContextProvider> context_provider;
@@ -155,7 +180,8 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
context_provider = base::MakeRefCounted<VizProcessContextProvider>(
task_executor_, surface_handle, gpu_memory_buffer_manager_.get(),
- image_factory_, gpu_channel_manager_delegate_, renderer_settings);
+ image_factory_, gpu_channel_manager_delegate_, gpu_dependency,
+ renderer_settings);
context_result = context_provider->BindToCurrentThread();
#if defined(OS_ANDROID)
@@ -211,13 +237,6 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
return output_surface;
}
-gpu::SharedImageManager* OutputSurfaceProviderImpl::GetSharedImageManager() {
- if (!gpu_service_impl_)
- return nullptr;
-
- return gpu_service_impl_->shared_image_manager();
-}
-
std::unique_ptr<SoftwareOutputDevice>
OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
gpu::SurfaceHandle surface_handle,
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
index fc5ca2c5565..a6bb42cdbc5 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
@@ -49,16 +49,20 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
explicit OutputSurfaceProviderImpl(bool headless);
~OutputSurfaceProviderImpl() override;
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> CreateGpuDependency(
+ bool gpu_compositing,
+ gpu::SurfaceHandle surface_handle,
+ const RendererSettings& renderer_settings) override;
+
// OutputSurfaceProvider implementation.
std::unique_ptr<OutputSurface> CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
mojom::DisplayClient* display_client,
+ DisplayCompositorMemoryAndTaskController* gpu_dependency,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) override;
- gpu::SharedImageManager* GetSharedImageManager() override;
-
private:
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceForPlatform(
gpu::SurfaceHandle surface_handle,
diff --git a/chromium/components/viz/service/display_embedder/output_surface_unified.cc b/chromium/components/viz/service/display_embedder/output_surface_unified.cc
index 43bbac67d9f..f01790c3016 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_unified.cc
+++ b/chromium/components/viz/service/display_embedder/output_surface_unified.cc
@@ -48,13 +48,4 @@ unsigned OutputSurfaceUnified::UpdateGpuFence() {
gfx::OverlayTransform OutputSurfaceUnified::GetDisplayTransform() {
return gfx::OVERLAY_TRANSFORM_NONE;
}
-
-scoped_refptr<gpu::GpuTaskSchedulerHelper>
-OutputSurfaceUnified::GetGpuTaskSchedulerHelper() {
- return nullptr;
-}
-
-gpu::MemoryTracker* OutputSurfaceUnified::GetMemoryTracker() {
- return nullptr;
-}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_surface_unified.h b/chromium/components/viz/service/display_embedder/output_surface_unified.h
index 10d79d5e918..26e07e3905b 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_unified.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_unified.h
@@ -47,9 +47,6 @@ class OutputSurfaceUnified : public OutputSurface {
UpdateVSyncParametersCallback callback) override {}
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
gfx::OverlayTransform GetDisplayTransform() override;
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override;
- gpu::MemoryTracker* GetMemoryTracker() override;
private:
DISALLOW_COPY_AND_ASSIGN(OutputSurfaceUnified);
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device.cc b/chromium/components/viz/service/display_embedder/skia_output_device.cc
index 130f0d1fab5..3ed0b7c5efa 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device.cc
@@ -14,6 +14,8 @@
#include "base/task/thread_pool/thread_pool_instance.h"
#include "components/viz/service/display/dc_layer_overlay.h"
#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/skia_utils.h"
+#include "third_party/skia/include/core/SkDeferredDisplayList.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "ui/gfx/gpu_fence.h"
@@ -46,19 +48,43 @@ void ReportLatency(const gfx::SwapTimings& timings,
} // namespace
SkiaOutputDevice::ScopedPaint::ScopedPaint(SkiaOutputDevice* device)
- : device_(device), sk_surface_(device->BeginPaint(&end_semaphores_)) {
- DCHECK(sk_surface_);
-}
+ : device_(device), sk_surface_(device->BeginPaint(&end_semaphores_)) {}
SkiaOutputDevice::ScopedPaint::~ScopedPaint() {
DCHECK(end_semaphores_.empty());
device_->EndPaint();
}
+SkCanvas* SkiaOutputDevice::ScopedPaint::GetCanvas() {
+ return device_->GetCanvas(sk_surface_);
+}
+
+GrSemaphoresSubmitted SkiaOutputDevice::ScopedPaint::Flush(
+ VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished) {
+ return device_->Flush(sk_surface_, vulkan_context_provider,
+ std::move(end_semaphores), std::move(on_finished));
+}
+
+bool SkiaOutputDevice::ScopedPaint::Wait(
+ int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait) {
+ return device_->Wait(sk_surface_, num_semaphores, wait_semaphores,
+ delete_semaphores_after_wait);
+}
+
+bool SkiaOutputDevice::ScopedPaint::Draw(
+ sk_sp<const SkDeferredDisplayList> ddl) {
+ return device_->Draw(sk_surface_, std::move(ddl));
+}
+
SkiaOutputDevice::SkiaOutputDevice(
GrDirectContext* gr_context,
gpu::MemoryTracker* memory_tracker,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
- : did_swap_buffer_complete_callback_(
+ : gr_context_(gr_context),
+ did_swap_buffer_complete_callback_(
std::move(did_swap_buffer_complete_callback)),
memory_type_tracker_(
std::make_unique<gpu::MemoryTypeTracker>(memory_tracker)),
@@ -73,7 +99,10 @@ SkiaOutputDevice::~SkiaOutputDevice() {
latency_tracker_runner_->DeleteSoon(FROM_HERE, std::move(latency_tracker_));
}
-void SkiaOutputDevice::PreGrContextSubmit() {}
+void SkiaOutputDevice::Submit(bool sync_cpu, base::OnceClosure callback) {
+ gr_context_->submit(sync_cpu);
+ std::move(callback).Run();
+}
void SkiaOutputDevice::CommitOverlayPlanes(
BufferPresentedCallback feedback,
@@ -208,4 +237,36 @@ void SkiaOutputDevice::SwapInfo::CallFeedback() {
}
}
+SkCanvas* SkiaOutputDevice::GetCanvas(SkSurface* sk_surface) {
+ return sk_surface->getCanvas();
+}
+
+GrSemaphoresSubmitted SkiaOutputDevice::Flush(
+ SkSurface* sk_surface,
+ VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished) {
+ GrFlushInfo flush_info = {
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
+ gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider, &flush_info);
+ if (on_finished)
+ gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
+ return sk_surface->flush(flush_info);
+}
+
+bool SkiaOutputDevice::Wait(SkSurface* sk_surface,
+ int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait) {
+ return sk_surface->wait(num_semaphores, wait_semaphores,
+ delete_semaphores_after_wait);
+}
+
+bool SkiaOutputDevice::Draw(SkSurface* sk_surface,
+ sk_sp<const SkDeferredDisplayList> ddl) {
+ return sk_surface->draw(ddl);
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device.h b/chromium/components/viz/service/display_embedder/skia_output_device.h
index 100a32221eb..aa75af56cea 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device.h
@@ -47,6 +47,8 @@ class LatencyTracker;
namespace viz {
+class VulkanContextProvider;
+
class SkiaOutputDevice {
public:
// A helper class for defining a BeginPaint() and EndPaint() scope.
@@ -55,7 +57,16 @@ class SkiaOutputDevice {
explicit ScopedPaint(SkiaOutputDevice* device);
~ScopedPaint();
+ // This can be null.
SkSurface* sk_surface() const { return sk_surface_; }
+ SkCanvas* GetCanvas();
+ GrSemaphoresSubmitted Flush(VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished);
+ bool Wait(int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait);
+ bool Draw(sk_sp<const SkDeferredDisplayList> ddl);
std::vector<GrBackendSemaphore> TakeEndPaintSemaphores() {
std::vector<GrBackendSemaphore> semaphores;
@@ -66,6 +77,7 @@ class SkiaOutputDevice {
private:
std::vector<GrBackendSemaphore> end_semaphores_;
SkiaOutputDevice* const device_;
+ // Null when using vulkan secondary command buffer.
SkSurface* const sk_surface_;
DISALLOW_COPY_AND_ASSIGN(ScopedPaint);
@@ -89,10 +101,11 @@ class SkiaOutputDevice {
gfx::BufferFormat format,
gfx::OverlayTransform transform) = 0;
- // Call before GrDirectContext::submit() for the current frame. The
- // implementation can use this opportunity to insert some work into the
- // GrDirectContext.
- virtual void PreGrContextSubmit();
+ // Submit the GrContext and run |callback| after. Note most but not all
+ // implementations will run |callback| in this call stack.
+ // If the |sync_cpu| flag is true this function will return once the gpu
+ // has finished with all submitted work.
+ virtual void Submit(bool sync_cpu, base::OnceClosure callback);
// Presents the back buffer.
virtual void SwapBuffers(BufferPresentedCallback feedback,
@@ -168,6 +181,20 @@ class SkiaOutputDevice {
// End paint the back buffer.
virtual void EndPaint() = 0;
+ // Overridden by SkiaOutputDeviceVulkanSecondaryCB.
+ virtual SkCanvas* GetCanvas(SkSurface* sk_surface);
+ virtual GrSemaphoresSubmitted Flush(
+ SkSurface* sk_surface,
+ VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished);
+ virtual bool Wait(SkSurface* sk_surface,
+ int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait);
+ virtual bool Draw(SkSurface* sk_surface,
+ sk_sp<const SkDeferredDisplayList> ddl);
+
// Helper method for SwapBuffers() and PostSubBuffer(). It should be called
// at the beginning of SwapBuffers() and PostSubBuffer() implementations
void StartSwapBuffers(BufferPresentedCallback feedback);
@@ -181,6 +208,8 @@ class SkiaOutputDevice {
const base::Optional<gfx::Rect>& damage_area = base::nullopt,
std::vector<gpu::Mailbox> released_overlays = {});
+ GrDirectContext* const gr_context_;
+
OutputSurface::Capabilities capabilities_;
uint64_t swap_id_ = 0;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
index ce698d4641f..c123d51f767 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -102,28 +102,20 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
SkiaOutputSurfaceDependency* deps,
gpu::SharedImageRepresentationFactory* representation_factory,
gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
+ const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+ bool needs_background_image)
: SkiaOutputDevice(deps->GetSharedContextState()->gr_context(),
memory_tracker,
did_swap_buffer_complete_callback),
presenter_(std::move(presenter)),
dependency_(deps),
- representation_factory_(representation_factory) {
+ representation_factory_(representation_factory),
+ needs_background_image_(needs_background_image) {
capabilities_.uses_default_gl_framebuffer = false;
capabilities_.preserve_buffer_content = true;
capabilities_.only_invalidates_damage_rect = false;
capabilities_.number_of_buffers = 3;
capabilities_.orientation_mode = OutputSurface::OrientationMode::kHardware;
-#if defined(OS_ANDROID)
- // With vulkan, if the chrome is launched in landscape mode, the chrome is
- // always blank until chrome window is rotated once. Workaround this problem
- // by using logic rotation mode.
- // TODO(https://crbug.com/1115065): use hardware orientation mode for vulkan,
- if (dependency_->GetSharedContextState()->GrContextIsVulkan() &&
- base::FeatureList::GetFieldTrial(features::kVulkan)) {
- capabilities_.orientation_mode = OutputSurface::OrientationMode::kLogic;
- }
-#endif
// Force the number of max pending frames to one when the switch
// "double-buffer-compositing" is passed.
@@ -193,6 +185,12 @@ bool SkiaOutputDeviceBufferQueue::IsPrimaryPlaneOverlay() const {
void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane(
const base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>&
plane) {
+ if (background_image_ && !background_image_is_scheduled_) {
+ background_image_->BeginPresent();
+ presenter_->ScheduleBackground(background_image_.get());
+ background_image_is_scheduled_ = true;
+ }
+
if (plane) {
// If the current_image_ is nullptr, it means there is no change on the
// primary plane. So we just need to schedule the last submitted image.
@@ -236,16 +234,24 @@ void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
continue;
}
+ // Fuchsia does not provide a GLImage overlay.
+#if defined(OS_FUCHSIA)
+ const bool needs_gl_image = false;
+#else
+ const bool needs_gl_image = true;
+#endif // defined(OS_FUCHSIA)
+
// TODO(penghuang): do not depend on GLImage.
auto shared_image_access =
- shared_image->BeginScopedReadAccess(true /* needs_gl_image */);
+ shared_image->BeginScopedReadAccess(needs_gl_image);
if (!shared_image_access) {
LOG(ERROR) << "Could not access SharedImage for read.";
continue;
}
// TODO(penghuang): do not depend on GLImage.
- DLOG_IF(FATAL, !shared_image_access->gl_image()) << "Cannot get GLImage.";
+ DLOG_IF(FATAL, needs_gl_image && !shared_image_access->gl_image())
+ << "Cannot get GLImage.";
bool result;
std::tie(it, result) = overlays_.emplace(std::move(shared_image),
@@ -263,10 +269,13 @@ void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
presenter_->ScheduleOverlays(std::move(overlays), std::move(accesses));
}
-void SkiaOutputDeviceBufferQueue::PreGrContextSubmit() {
+void SkiaOutputDeviceBufferQueue::Submit(bool sync_cpu,
+ base::OnceClosure callback) {
// The current image may be missing, for example during WebXR presentation.
if (current_image_)
current_image_->PreGrContextSubmit();
+
+ SkiaOutputDevice::Submit(sync_cpu, std::move(callback));
}
void SkiaOutputDeviceBufferQueue::SwapBuffers(
@@ -438,6 +447,12 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size,
overlay_transform_ = transform;
FreeAllSurfaces();
+ if (needs_background_image_ && !background_image_) {
+ background_image_ =
+ presenter_->AllocateBackgroundImage(color_space_, gfx::Size(4, 4));
+ background_image_is_scheduled_ = false;
+ }
+
images_ = presenter_->AllocateImages(color_space_, image_size_,
capabilities_.number_of_buffers);
if (images_.empty())
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
index 402f39c139c..619aa15ba34 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
@@ -30,7 +30,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
SkiaOutputSurfaceDependency* deps,
gpu::SharedImageRepresentationFactory* representation_factory,
gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback);
+ const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+ bool needs_background_image);
~SkiaOutputDeviceBufferQueue() override;
@@ -39,7 +40,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
delete;
// SkiaOutputDevice overrides.
- void PreGrContextSubmit() override;
+ void Submit(bool sync_cpu, base::OnceClosure callback) override;
void SwapBuffers(BufferPresentedCallback feedback,
std::vector<ui::LatencyInfo> latency_info) override;
void PostSubBuffer(const gfx::Rect& rect,
@@ -126,6 +127,13 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
// Set to true if no image is to be used for the primary plane of this frame.
bool current_frame_has_no_primary_plane_ = false;
+ // Whether the platform needs an occluded background image. Wayland needs it
+ // for opaque accelerated widgets and event wiring.
+ bool needs_background_image_ = false;
+ // A 4x4 small image that will be scaled to cover an opaque region.
+ std::unique_ptr<OutputPresenter::Image> background_image_ = nullptr;
+ // Set to true if background has been scheduled in a frame.
+ bool background_image_is_scheduled_ = false;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
index f8a2e2fcf3c..6ea63f39550 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
@@ -10,17 +10,18 @@
#include <set>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "build/build_config.h"
-#include "gpu/command_buffer/service/scheduler.h"
-
+#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/service/display_embedder/output_presenter_gl.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/test_gpu_service_holder.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/shared_image_backing_factory.h"
+#include "gpu/command_buffer/service/test_shared_image_backing.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/types/display_snapshot.h"
@@ -31,6 +32,7 @@ using ::testing::Expectation;
using ::testing::Ne;
using ::testing::Return;
+namespace viz {
namespace {
// These MACRO and TestOnGpu class make it easier to write tests that runs on
@@ -87,7 +89,7 @@ class TestOnGpu : public ::testing::Test {
}
void SetUp() override {
- gpu_service_holder_ = viz::TestGpuServiceHolder::GetInstance();
+ gpu_service_holder_ = TestGpuServiceHolder::GetInstance();
SetUpOnMain();
auto setup = base::BindLambdaForTesting([&]() { this->SetUpOnGpu(); });
@@ -121,12 +123,67 @@ class TestOnGpu : public ::testing::Test {
virtual void TearDownOnGpu() {}
virtual void TestBodyOnGpu() {}
- viz::TestGpuServiceHolder* gpu_service_holder_;
+ TestGpuServiceHolder* gpu_service_holder_;
base::WaitableEvent wait_;
};
// Here starts SkiaOutputDeviceBufferQueue test related code
+class TestSharedImageBackingFactory : public gpu::SharedImageBackingFactory {
+ public:
+ TestSharedImageBackingFactory() = default;
+ ~TestSharedImageBackingFactory() override = default;
+
+ // gpu::SharedImageBackingFactory implementation.
+ std::unique_ptr<gpu::SharedImageBacking> CreateSharedImage(
+ const gpu::Mailbox& mailbox,
+ ResourceFormat format,
+ gpu::SurfaceHandle surface_handle,
+ const gfx::Size& size,
+ const gfx::ColorSpace& color_space,
+ GrSurfaceOrigin surface_origin,
+ SkAlphaType alpha_type,
+ uint32_t usage,
+ bool is_thread_safe) override {
+ size_t estimated_size =
+ ResourceSizes::CheckedSizeInBytes<size_t>(size, format);
+ return std::make_unique<gpu::TestSharedImageBacking>(
+ mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+ estimated_size);
+ }
+ std::unique_ptr<gpu::SharedImageBacking> CreateSharedImage(
+ const gpu::Mailbox& mailbox,
+ ResourceFormat format,
+ const gfx::Size& size,
+ const gfx::ColorSpace& color_space,
+ GrSurfaceOrigin surface_origin,
+ SkAlphaType alpha_type,
+ uint32_t usage,
+ base::span<const uint8_t> pixel_data) override {
+ return std::make_unique<gpu::TestSharedImageBacking>(
+ mailbox, format, size, color_space, surface_origin, alpha_type, usage,
+ pixel_data.size());
+ }
+ std::unique_ptr<gpu::SharedImageBacking> CreateSharedImage(
+ const gpu::Mailbox& mailbox,
+ int client_id,
+ gfx::GpuMemoryBufferHandle handle,
+ gfx::BufferFormat format,
+ gpu::SurfaceHandle surface_handle,
+ const gfx::Size& size,
+ const gfx::ColorSpace& color_space,
+ GrSurfaceOrigin surface_origin,
+ SkAlphaType alpha_type,
+ uint32_t usage) override {
+ NOTREACHED();
+ return nullptr;
+ }
+ bool CanImportGpuMemoryBuffer(
+ gfx::GpuMemoryBufferType memory_buffer_type) override {
+ return false;
+ }
+};
+
class MockGLSurfaceAsync : public gl::GLSurfaceStub {
public:
bool SupportsAsyncSwap() override { return true; }
@@ -198,11 +255,9 @@ class MemoryTrackerStub : public gpu::MemoryTracker {
} // namespace
-namespace viz {
-
class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
public:
- SkiaOutputDeviceBufferQueueTest() {}
+ SkiaOutputDeviceBufferQueueTest() = default;
void SetUpOnMain() override {
gpu::SurfaceHandle surface_handle_ = gpu::kNullSurfaceHandle;
@@ -220,6 +275,8 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
dependency_->GetSharedContextState().get(),
dependency_->GetMailboxManager(), dependency_->GetSharedImageManager(),
dependency_->GetGpuImageFactory(), memory_tracker_.get(), true),
+ shared_image_factory_->RegisterSharedImageBackingFactoryForTesting(
+ &test_backing_factory_);
shared_image_representation_factory_ =
std::make_unique<gpu::SharedImageRepresentationFactory>(
dependency_->GetSharedImageManager(), memory_tracker_.get());
@@ -228,18 +285,12 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
base::DoNothing::Repeatedly<gpu::SwapBuffersCompleteParams,
const gfx::Size&>();
- uint32_t shared_image_usage =
- gpu::SHARED_IMAGE_USAGE_DISPLAY |
- gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
-
- auto onscreen_device = std::make_unique<SkiaOutputDeviceBufferQueue>(
+ output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::make_unique<OutputPresenterGL>(
gl_surface_, dependency_.get(), shared_image_factory_.get(),
- shared_image_representation_factory_.get(), shared_image_usage),
+ shared_image_representation_factory_.get()),
dependency_.get(), shared_image_representation_factory_.get(),
- memory_tracker_.get(), present_callback);
-
- output_device_ = std::move(onscreen_device);
+ memory_tracker_.get(), present_callback, false);
}
void TearDownOnGpu() override {
@@ -345,6 +396,7 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
std::unique_ptr<SkiaOutputSurfaceDependency> dependency_;
scoped_refptr<MockGLSurfaceAsync> gl_surface_;
std::unique_ptr<MemoryTrackerStub> memory_tracker_;
+ TestSharedImageBackingFactory test_backing_factory_;
std::unique_ptr<gpu::SharedImageFactory> shared_image_factory_;
std::unique_ptr<gpu::SharedImageRepresentationFactory>
shared_image_representation_factory_;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
index 8da108410e2..3a6daaab829 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -9,6 +9,7 @@
#include "base/check_op.h"
#include "base/notreached.h"
#include "components/viz/common/gpu/dawn_context_provider.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/dawn/src/include/dawn_native/D3D12Backend.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/vsync_provider.h"
@@ -122,9 +123,8 @@ SkSurface* SkiaOutputDeviceDawn::BeginPaint(
GrBackendRenderTarget backend_target(
size_.width(), size_.height(), /*sampleCnt=*/0, /*stencilBits=*/0, info);
DCHECK(backend_target.isValid());
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- SkSurfaceProps surface_props(/*flags=*/0,
- SkSurfaceProps::kLegacyFontHost_InitType);
+ SkSurfaceProps surface_props =
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
context_provider_->GetGrContext(), backend_target,
capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
index 3dd38d85300..155b3661600 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -4,11 +4,11 @@
#include "components/viz/service/display_embedder/skia_output_device_gl.h"
+#include <tuple>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/debug/alias.h"
-#include "build/build_config.h"
#include "components/viz/common/gpu/context_lost_reason.h"
#include "components/viz/service/display/dc_layer_overlay.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
@@ -19,6 +19,7 @@
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/command_buffer/service/texture_base.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
@@ -49,6 +50,51 @@ NOINLINE void CheckForLoopFailures() {
} // namespace
+// Holds reference needed to keep overlay textures alive. Can either hold a
+// shared image or legacy GL texture.
+// TODO(kylechar): Merge with SkiaOutputDeviceBufferQueue::OverlayData when we
+// dont need to support TexturePassthrough anymore.
+class SkiaOutputDeviceGL::OverlayData {
+ public:
+ // TODO(crbug.com/1011555): Remove ability to hold TexturePassthrough after
+ // all Window video paths use shared image API.
+ explicit OverlayData(scoped_refptr<gpu::gles2::TexturePassthrough> texture)
+ : texture_(std::move(texture)) {}
+
+ OverlayData(
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation,
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_read_access)
+ : representation_(std::move(representation)),
+ scoped_read_access_(std::move(scoped_read_access)) {}
+
+ ~OverlayData() = default;
+ OverlayData(OverlayData&& other) = default;
+ OverlayData& operator=(OverlayData&& other) {
+ texture_ = std::move(other.texture_);
+ // Must happen in the same order as destruction to avoid having
+ // |scoped_read_access_| outlive |representation_|.
+ scoped_read_access_ = std::move(other.scoped_read_access_);
+ representation_ = std::move(other.representation_);
+ return *this;
+ }
+
+ scoped_refptr<gl::GLImage> GetImage() {
+ if (texture_)
+ return texture_->GetLevelImage(texture_->target(), 0);
+
+ DCHECK(scoped_read_access_);
+ return scoped_read_access_->gl_image();
+ }
+
+ private:
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation_;
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_read_access_;
+
+ scoped_refptr<gpu::gles2::TexturePassthrough> texture_;
+};
+
SkiaOutputDeviceGL::SkiaOutputDeviceGL(
gpu::MailboxManager* mailbox_manager,
gpu::SharedImageRepresentationFactory* shared_image_representation_factory,
@@ -69,12 +115,14 @@ SkiaOutputDeviceGL::SkiaOutputDeviceGL(
capabilities_.output_surface_origin = gl_surface_->GetOrigin();
capabilities_.supports_post_sub_buffer = gl_surface_->SupportsPostSubBuffer();
#if defined(OS_WIN)
- if (gl_surface_->SupportsDCLayers() &&
- gl::ShouldForceDirectCompositionRootSurfaceFullDamage()) {
+ if (gl_surface_->SupportsDCLayers()) {
// We need to set this bit to allow viz to track the previous damage rect
// of a backbuffer in a multiple backbuffer system, so backbuffers always
// have valid pixels, even outside the current damage rect.
- capabilities_.preserve_buffer_content = true;
+ capabilities_.preserve_buffer_content =
+ gl::ShouldForceDirectCompositionRootSurfaceFullDamage();
+ capabilities_.number_of_buffers =
+ gl::DirectCompositionRootSurfaceBufferCount();
}
#endif // OS_WIN
if (feature_info->workarounds()
@@ -174,7 +222,7 @@ bool SkiaOutputDeviceGL::Reshape(const gfx::Size& size,
return false;
}
SkSurfaceProps surface_props =
- SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
GrGLFramebufferInfo framebuffer_info;
framebuffer_info.fFBOID = 0;
@@ -247,14 +295,14 @@ void SkiaOutputDeviceGL::SwapBuffers(
gfx::Size(sk_surface_->width(), sk_surface_->height());
if (supports_async_swap_) {
- auto callback = base::BindOnce(&SkiaOutputDeviceGL::DoFinishSwapBuffers,
- weak_ptr_factory_.GetWeakPtr(), surface_size,
- std::move(latency_info));
+ auto callback = base::BindOnce(
+ &SkiaOutputDeviceGL::DoFinishSwapBuffersAsync,
+ weak_ptr_factory_.GetWeakPtr(), surface_size, std::move(latency_info));
gl_surface_->SwapBuffersAsync(std::move(callback), std::move(feedback));
} else {
gfx::SwapResult result = gl_surface_->SwapBuffers(std::move(feedback));
- FinishSwapBuffers(gfx::SwapCompletionResult(result), surface_size,
- std::move(latency_info));
+ DoFinishSwapBuffers(surface_size, std::move(latency_info),
+ gfx::SwapCompletionResult(result));
}
}
@@ -268,17 +316,17 @@ void SkiaOutputDeviceGL::PostSubBuffer(
gfx::Size(sk_surface_->width(), sk_surface_->height());
if (supports_async_swap_) {
- auto callback = base::BindOnce(&SkiaOutputDeviceGL::DoFinishSwapBuffers,
- weak_ptr_factory_.GetWeakPtr(), surface_size,
- std::move(latency_info));
+ auto callback = base::BindOnce(
+ &SkiaOutputDeviceGL::DoFinishSwapBuffersAsync,
+ weak_ptr_factory_.GetWeakPtr(), surface_size, std::move(latency_info));
gl_surface_->PostSubBufferAsync(rect.x(), rect.y(), rect.width(),
rect.height(), std::move(callback),
std::move(feedback));
} else {
gfx::SwapResult result = gl_surface_->PostSubBuffer(
rect.x(), rect.y(), rect.width(), rect.height(), std::move(feedback));
- FinishSwapBuffers(gfx::SwapCompletionResult(result), surface_size,
- std::move(latency_info));
+ DoFinishSwapBuffers(surface_size, std::move(latency_info),
+ gfx::SwapCompletionResult(result));
}
}
@@ -291,24 +339,43 @@ void SkiaOutputDeviceGL::CommitOverlayPlanes(
gfx::Size(sk_surface_->width(), sk_surface_->height());
if (supports_async_swap_) {
- auto callback = base::BindOnce(&SkiaOutputDeviceGL::DoFinishSwapBuffers,
- weak_ptr_factory_.GetWeakPtr(), surface_size,
- std::move(latency_info));
+ auto callback = base::BindOnce(
+ &SkiaOutputDeviceGL::DoFinishSwapBuffersAsync,
+ weak_ptr_factory_.GetWeakPtr(), surface_size, std::move(latency_info));
gl_surface_->CommitOverlayPlanesAsync(std::move(callback),
std::move(feedback));
} else {
- FinishSwapBuffers(
- gfx::SwapCompletionResult(
- gl_surface_->CommitOverlayPlanes(std::move(feedback))),
- surface_size, std::move(latency_info));
+ gfx::SwapResult result =
+ gl_surface_->CommitOverlayPlanes(std::move(feedback));
+ DoFinishSwapBuffers(surface_size, std::move(latency_info),
+ gfx::SwapCompletionResult(result));
}
}
+void SkiaOutputDeviceGL::DoFinishSwapBuffersAsync(
+ const gfx::Size& size,
+ std::vector<ui::LatencyInfo> latency_info,
+ gfx::SwapCompletionResult result) {
+ DCHECK(!result.gpu_fence);
+ FinishSwapBuffers(std::move(result), size, latency_info);
+}
+
void SkiaOutputDeviceGL::DoFinishSwapBuffers(
const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
gfx::SwapCompletionResult result) {
DCHECK(!result.gpu_fence);
+
+ // Remove entries from |overlays_| for textures that weren't scheduled as an
+ // overlay this frame.
+ if (!overlays_.empty()) {
+ base::EraseIf(overlays_, [this](auto& entry) {
+ const gpu::Mailbox& mailbox = entry.first;
+ return !scheduled_overlay_mailboxes_.contains(mailbox);
+ });
+ scheduled_overlay_mailboxes_.clear();
+ }
+
FinishSwapBuffers(std::move(result), size, latency_info);
}
@@ -333,15 +400,17 @@ void SkiaOutputDeviceGL::ScheduleOverlays(
// Get GLImages for DC layer textures.
bool success = true;
for (size_t i = 0; i < DCLayerOverlay::kNumResources; ++i) {
- if (i > 0 && dc_layer.mailbox[i].IsZero())
+ const gpu::Mailbox& mailbox = dc_layer.mailbox[i];
+ if (i > 0 && mailbox.IsZero())
break;
- auto image = GetGLImageForMailbox(dc_layer.mailbox[i]);
+ auto image = GetGLImageForMailbox(mailbox);
if (!image) {
success = false;
break;
}
+ scheduled_overlay_mailboxes_.insert(mailbox);
image->SetColorSpace(dc_layer.color_space);
params.images[i] = std::move(image);
}
@@ -386,38 +455,36 @@ void SkiaOutputDeviceGL::EndPaint() {}
scoped_refptr<gl::GLImage> SkiaOutputDeviceGL::GetGLImageForMailbox(
const gpu::Mailbox& mailbox) {
+ auto it = overlays_.find(mailbox);
+ if (it != overlays_.end())
+ return it->second.GetImage();
+
// TODO(crbug.com/1005306): Stop using MailboxManager for lookup once all
// clients are using SharedImageInterface to create textures.
// For example, the legacy mailbox still uses GL textures (no overlay)
// and is still used.
auto* texture_base = mailbox_manager_->ConsumeTexture(mailbox);
- if (!texture_base) {
- auto overlay =
- shared_image_representation_factory_->ProduceOverlay(mailbox);
- if (!overlay)
- return nullptr;
-
- // Return GLImage since the ScopedReadAccess isn't being held by anyone.
- // TODO(crbug.com/1011555): Have SkiaOutputSurfaceImplOnGpu hold on to the
- // ScopedReadAccess for overlays like it does for PromiseImage based
- // resources.
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- scoped_overlay_read_access =
- overlay->BeginScopedReadAccess(/*need_gl_image=*/true);
- DCHECK(scoped_overlay_read_access);
- return scoped_overlay_read_access->gl_image();
+ if (texture_base) {
+ DCHECK_EQ(texture_base->GetType(), gpu::TextureBase::Type::kPassthrough);
+ std::tie(it, std::ignore) = overlays_.try_emplace(
+ mailbox,
+ base::WrapRefCounted(
+ static_cast<gpu::gles2::TexturePassthrough*>(texture_base)));
+ return it->second.GetImage();
}
- if (texture_base->GetType() == gpu::TextureBase::Type::kPassthrough) {
- gpu::gles2::TexturePassthrough* texture =
- static_cast<gpu::gles2::TexturePassthrough*>(texture_base);
- return texture->GetLevelImage(texture->target(), 0);
- } else {
- DCHECK_EQ(texture_base->GetType(), gpu::TextureBase::Type::kValidated);
- gpu::gles2::Texture* texture =
- static_cast<gpu::gles2::Texture*>(texture_base);
- return texture->GetLevelImage(texture->target(), 0);
- }
+ auto overlay = shared_image_representation_factory_->ProduceOverlay(mailbox);
+ if (!overlay)
+ return nullptr;
+
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_overlay_read_access =
+ overlay->BeginScopedReadAccess(/*need_gl_image=*/true);
+ DCHECK(scoped_overlay_read_access);
+
+ std::tie(it, std::ignore) = overlays_.try_emplace(
+ mailbox, std::move(overlay), std::move(scoped_overlay_read_access));
+ return it->second.GetImage();
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_gl.h b/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
index edd572e0a76..aa3fe9f044f 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
@@ -8,6 +8,8 @@
#include <memory>
#include <vector>
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -67,11 +69,18 @@ class SkiaOutputDeviceGL final : public SkiaOutputDevice {
void EndPaint() override;
private:
- // Used as callback for SwapBuffersAsync and PostSubBufferAsync to finish
- // operation
+ class OverlayData;
+
+ // Use instead of calling FinishSwapBuffers() directly. On Windows this cleans
+ // up old entries in |overlays_|.
void DoFinishSwapBuffers(const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
gfx::SwapCompletionResult result);
+ // Used as callback for SwapBuffersAsync and PostSubBufferAsync to finish
+ // operation
+ void DoFinishSwapBuffersAsync(const gfx::Size& size,
+ std::vector<ui::LatencyInfo> latency_info,
+ gfx::SwapCompletionResult result);
scoped_refptr<gl::GLImage> GetGLImageForMailbox(const gpu::Mailbox& mailbox);
@@ -86,6 +95,12 @@ class SkiaOutputDeviceGL final : public SkiaOutputDevice {
sk_sp<SkSurface> sk_surface_;
+ // Mailboxes of overlays scheduled in the current frame.
+ base::flat_set<gpu::Mailbox> scheduled_overlay_mailboxes_;
+
+ // Holds references to overlay textures so they aren't destroyed while in use.
+ base::flat_map<gpu::Mailbox, OverlayData> overlays_;
+
uint64_t backbuffer_estimated_size_ = 0;
base::WeakPtrFactory<SkiaOutputDeviceGL> weak_ptr_factory_{this};
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index a6948f6a1b0..1c57be3ef42 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "gpu/command_buffer/service/skia_utils.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace viz {
@@ -136,9 +137,8 @@ SkSurface* SkiaOutputDeviceOffscreen::BeginPaint(
std::vector<GrBackendSemaphore>* end_semaphores) {
DCHECK(backend_texture_.isValid());
if (!sk_surface_) {
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- SkSurfaceProps surface_props(0 /* flags */,
- SkSurfaceProps::kLegacyFontHost_InitType);
+ SkSurfaceProps surface_props =
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
sk_surface_ = SkSurface::MakeFromBackendTexture(
context_state_->gr_context(), backend_texture_,
capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index 8122634c109..cb79adb7b4b 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -18,6 +18,7 @@
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_surface.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
@@ -93,7 +94,7 @@ bool SkiaOutputDeviceVulkan::Reshape(const gfx::Size& size,
return RecreateSwapChain(size, color_space.ToSkColorSpace(), transform);
}
-void SkiaOutputDeviceVulkan::PreGrContextSubmit() {
+void SkiaOutputDeviceVulkan::Submit(bool sync_cpu, base::OnceClosure callback) {
if (LIKELY(scoped_write_)) {
auto& sk_surface =
sk_surface_size_pairs_[scoped_write_->image_index()].sk_surface;
@@ -104,6 +105,8 @@ void SkiaOutputDeviceVulkan::PreGrContextSubmit() {
queue_index);
sk_surface->flush({}, &state);
}
+
+ SkiaOutputDevice::Submit(sync_cpu, std::move(callback));
}
void SkiaOutputDeviceVulkan::SwapBuffers(
@@ -191,7 +194,7 @@ SkSurface* SkiaOutputDeviceVulkan::BeginPaint(
if (UNLIKELY(!sk_surface)) {
SkSurfaceProps surface_props =
- SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
const auto surface_format = vulkan_surface_->surface_format().format;
DCHECK(surface_format == VK_FORMAT_B8G8R8A8_UNORM ||
surface_format == VK_FORMAT_R8G8B8A8_UNORM);
@@ -200,6 +203,8 @@ SkSurface* SkiaOutputDeviceVulkan::BeginPaint(
vk_image_info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
vk_image_info.fImageLayout = scoped_write_->image_layout();
vk_image_info.fFormat = surface_format;
+ vk_image_info.fImageUsageFlags = scoped_write_->image_usage();
+ vk_image_info.fSampleCount = 1;
vk_image_info.fLevelCount = 1;
vk_image_info.fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
vk_image_info.fProtected =
@@ -306,7 +311,7 @@ bool SkiaOutputDeviceVulkan::Initialize() {
// always blank until chrome window is rotated once. Workaround this problem
// by using logic rotation mode.
// TODO(https://crbug.com/1115065): use hardware orientation mode for vulkan,
- if (base::FeatureList::GetFieldTrial(features::kVulkan))
+ if (features::IsUsingVulkan())
capabilities_.orientation_mode = OutputSurface::OrientationMode::kLogic;
#endif
// We don't know the number of buffers until the VulkanSwapChain is
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
index 82ea3d80d24..af1c223be37 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
@@ -45,7 +45,7 @@ class SkiaOutputDeviceVulkan final : public SkiaOutputDevice {
gpu::SurfaceHandle GetChildSurfaceHandle();
#endif
// SkiaOutputDevice implementation:
- void PreGrContextSubmit() override;
+ void Submit(bool sync_cpu, base::OnceClosure callback) override;
bool Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc
new file mode 100644
index 00000000000..b70072fdd3f
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.cc
@@ -0,0 +1,135 @@
+// Copyright 2020 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/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h"
+
+#include <utility>
+
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "third_party/skia/include/core/SkDeferredDisplayList.h"
+#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
+#include "third_party/skia/src/gpu/vk/GrVkSecondaryCBDrawContext.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace viz {
+
+SkiaOutputDeviceVulkanSecondaryCB::SkiaOutputDeviceVulkanSecondaryCB(
+ VulkanContextProvider* context_provider,
+ gpu::MemoryTracker* memory_tracker,
+ DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
+ : SkiaOutputDevice(context_provider->GetGrContext(),
+ memory_tracker,
+ std::move(did_swap_buffer_complete_callback)),
+ context_provider_(context_provider) {
+ capabilities_.uses_default_gl_framebuffer = false;
+ capabilities_.max_frames_pending = 1;
+ capabilities_.preserve_buffer_content = false;
+ capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
+ capabilities_.supports_post_sub_buffer = false;
+ capabilities_.orientation_mode = OutputSurface::OrientationMode::kLogic;
+ capabilities_.root_is_vulkan_secondary_command_buffer = true;
+
+ GrVkSecondaryCBDrawContext* secondary_cb_draw_context =
+ context_provider_->GetGrSecondaryCBDrawContext();
+ SkSurfaceCharacterization characterization;
+ VkFormat vkFormat = VK_FORMAT_UNDEFINED;
+ bool result = secondary_cb_draw_context->characterize(&characterization);
+ CHECK(result);
+ characterization.backendFormat().asVkFormat(&vkFormat);
+ auto sk_color_type = vkFormat == VK_FORMAT_R8G8B8A8_UNORM
+ ? kRGBA_8888_SkColorType
+ : kBGRA_8888_SkColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
+ sk_color_type;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] =
+ sk_color_type;
+}
+
+void SkiaOutputDeviceVulkanSecondaryCB::Submit(bool sync_cpu,
+ base::OnceClosure callback) {
+ // Submit the primary command buffer which may render passes.
+ context_provider_->GetGrContext()->submit(sync_cpu);
+ context_provider_->EnqueueSecondaryCBPostSubmitTask(std::move(callback));
+}
+
+bool SkiaOutputDeviceVulkanSecondaryCB::Reshape(
+ const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) {
+ // No-op
+ size_ = size;
+ return true;
+}
+
+void SkiaOutputDeviceVulkanSecondaryCB::SwapBuffers(
+ BufferPresentedCallback feedback,
+ std::vector<ui::LatencyInfo> latency_info) {
+ StartSwapBuffers(std::move(feedback));
+ FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK), size_,
+ std::move(latency_info));
+}
+
+void SkiaOutputDeviceVulkanSecondaryCB::PostSubBuffer(
+ const gfx::Rect& rect,
+ BufferPresentedCallback feedback,
+ std::vector<ui::LatencyInfo> latency_info) {
+ CHECK(false);
+}
+
+SkSurface* SkiaOutputDeviceVulkanSecondaryCB::BeginPaint(
+ std::vector<GrBackendSemaphore>* end_semaphores) {
+ return nullptr;
+}
+
+void SkiaOutputDeviceVulkanSecondaryCB::EndPaint() {}
+
+SkCanvas* SkiaOutputDeviceVulkanSecondaryCB::GetCanvas(SkSurface* sk_surface) {
+ DCHECK(!sk_surface);
+ return context_provider_->GetGrSecondaryCBDrawContext()->getCanvas();
+}
+
+GrSemaphoresSubmitted SkiaOutputDeviceVulkanSecondaryCB::Flush(
+ SkSurface* sk_surface,
+ VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished) {
+ DCHECK(!sk_surface);
+ DCHECK_EQ(context_provider_, vulkan_context_provider);
+
+ std::vector<VkSemaphore> vk_end_semaphores;
+ for (const GrBackendSemaphore& gr_semaphore : end_semaphores) {
+ vk_end_semaphores.push_back(gr_semaphore.vkSemaphore());
+ }
+ vulkan_context_provider->EnqueueSecondaryCBSemaphores(
+ std::move(vk_end_semaphores));
+ if (on_finished) {
+ vulkan_context_provider->EnqueueSecondaryCBPostSubmitTask(
+ std::move(on_finished));
+ }
+ vulkan_context_provider->GetGrSecondaryCBDrawContext()->flush();
+ return GrSemaphoresSubmitted::kYes;
+}
+
+bool SkiaOutputDeviceVulkanSecondaryCB::Wait(
+ SkSurface* sk_surface,
+ int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait) {
+ DCHECK(!sk_surface);
+ return context_provider_->GetGrSecondaryCBDrawContext()->wait(
+ num_semaphores, wait_semaphores, delete_semaphores_after_wait);
+}
+
+bool SkiaOutputDeviceVulkanSecondaryCB::Draw(
+ SkSurface* sk_surface,
+ sk_sp<const SkDeferredDisplayList> ddl) {
+ DCHECK(!sk_surface);
+ return context_provider_->GetGrSecondaryCBDrawContext()->draw(ddl);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h
new file mode 100644
index 00000000000..8207a3b261a
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h
@@ -0,0 +1,58 @@
+// Copyright 2020 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_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/viz/service/display_embedder/skia_output_device.h"
+
+namespace viz {
+
+class VulkanContextProvider;
+
+class SkiaOutputDeviceVulkanSecondaryCB final : public SkiaOutputDevice {
+ public:
+ SkiaOutputDeviceVulkanSecondaryCB(
+ VulkanContextProvider* context_provider,
+ gpu::MemoryTracker* memory_tracker,
+ DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
+
+ void Submit(bool sync_cpu, base::OnceClosure callback) override;
+ bool Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) override;
+ void SwapBuffers(BufferPresentedCallback feedback,
+ std::vector<ui::LatencyInfo> latency_info) override;
+ void PostSubBuffer(const gfx::Rect& rect,
+ BufferPresentedCallback feedback,
+ std::vector<ui::LatencyInfo> latency_info) override;
+ SkSurface* BeginPaint(
+ std::vector<GrBackendSemaphore>* end_semaphores) override;
+ void EndPaint() override;
+
+ SkCanvas* GetCanvas(SkSurface* sk_surface) override;
+ GrSemaphoresSubmitted Flush(SkSurface* sk_surface,
+ VulkanContextProvider* vulkan_context_provider,
+ std::vector<GrBackendSemaphore> end_semaphores,
+ base::OnceClosure on_finished) override;
+ bool Wait(SkSurface* sk_surface,
+ int num_semaphores,
+ const GrBackendSemaphore wait_semaphores[],
+ bool delete_semaphores_after_wait) override;
+ bool Draw(SkSurface* sk_surface,
+ sk_sp<const SkDeferredDisplayList> ddl) override;
+
+ private:
+ VulkanContextProvider* const context_provider_;
+ gfx::Size size_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_H_
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc b/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
index 74f8c335181..a4af3e197cb 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
@@ -9,6 +9,7 @@
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/shared_context_state.h"
+#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gl/gl_bindings.h"
@@ -99,7 +100,7 @@ void SkiaOutputDeviceWebView::InitSkiaSurface(unsigned int fbo) {
last_frame_buffer_object_ = fbo;
SkSurfaceProps surface_props =
- SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
GrGLFramebufferInfo framebuffer_info;
framebuffer_info.fFBOID = fbo;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_x11.h b/chromium/components/viz/service/display_embedder/skia_output_device_x11.h
index 331dad95f2f..bffd788c84c 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_x11.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_x11.h
@@ -11,8 +11,6 @@
#include "components/viz/service/display_embedder/skia_output_device_offscreen.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/x/connection.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto.h"
namespace viz {
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
index a85a0cf5c1c..86be475a729 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
@@ -5,18 +5,22 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_DEPENDENCY_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_DEPENDENCY_H_
+#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "build/build_config.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/service/sequence_id.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/ipc/common/surface_handle.h"
+#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
#include "ui/gl/gl_surface_format.h"
class GURL;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
index 19960f9d5ba..accf893f211 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
@@ -4,11 +4,15 @@
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
+#include <memory>
+#include <utility>
+
#include "base/callback_helpers.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "gpu/command_buffer/service/scheduler.h"
+#include "gpu/ipc/gpu_task_scheduler_helper.h"
#include "gpu/ipc/scheduler_sequence.h"
#include "gpu/ipc/service/image_transport_surface.h"
#include "ui/gl/init/gl_factory.h"
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
index 3174355ca0c..a90153296bd 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_DEPENDENCY_IMPL_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_DEPENDENCY_IMPL_H_
+#include <memory>
+
#include "base/macros.h"
#include "build/build_config.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 2a9ed59a00f..78ac55b4954 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/no_destructor.h"
#include "base/synchronization/waitable_event.h"
@@ -33,6 +32,7 @@
#include "gpu/ipc/single_task_sequence.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
+#include "skia/ext/legacy_display_globals.h"
#include "ui/gfx/skia_util.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_gl_api_implementation.h"
@@ -92,11 +92,14 @@ SkiaOutputSurfaceImpl::ScopedPaint::~ScopedPaint() = default;
// static
std::unique_ptr<SkiaOutputSurface> SkiaOutputSurfaceImpl::Create(
- std::unique_ptr<SkiaOutputSurfaceDependency> deps,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings) {
+ DCHECK(display_controller);
+ DCHECK(display_controller->skia_dependency());
+ DCHECK(display_controller->gpu_task_scheduler());
auto output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
- util::PassKey<SkiaOutputSurfaceImpl>(), std::move(deps),
+ util::PassKey<SkiaOutputSurfaceImpl>(), display_controller,
renderer_settings, debug_settings);
if (!output_surface->Initialize())
output_surface = nullptr;
@@ -105,13 +108,17 @@ std::unique_ptr<SkiaOutputSurface> SkiaOutputSurfaceImpl::Create(
SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl(
util::PassKey<SkiaOutputSurfaceImpl> /* pass_key */,
- std::unique_ptr<SkiaOutputSurfaceDependency> deps,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings)
- : SkiaOutputSurface(GetOutputSurfaceType(deps.get())),
- dependency_(std::move(deps)),
+ : SkiaOutputSurface(
+ GetOutputSurfaceType(display_controller->skia_dependency())),
+ dependency_(display_controller->skia_dependency()),
renderer_settings_(renderer_settings),
- debug_settings_(debug_settings) {
+ debug_settings_(debug_settings),
+ display_compositor_controller_(display_controller),
+ gpu_task_scheduler_(
+ display_compositor_controller_->gpu_task_scheduler()) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
@@ -129,20 +136,14 @@ SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
}
DCHECK(render_pass_image_cache_.empty());
- // Post a task to destroy |impl_on_gpu_| on the GPU thread and block until
- // that is finished.
- base::WaitableEvent event;
+ // Post a task to destroy |impl_on_gpu_| on the GPU thread.
auto task = base::BindOnce(
- [](std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
- base::WaitableEvent* event) {
- impl_on_gpu.reset();
- event->Signal();
- },
- std::move(impl_on_gpu_), &event);
- ScheduleGpuTask(std::move(task), {});
- event.Wait();
-
- gpu_task_scheduler_.reset();
+ [](std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu) {},
+ std::move(impl_on_gpu_));
+ EnqueueGpuTask(std::move(task), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
+ // Flush GPU tasks and block until all tasks are finished.
+ FlushGpuTasks(/*wait_for_finish=*/true);
}
gpu::SurfaceHandle SkiaOutputSurfaceImpl::GetSurfaceHandle() const {
@@ -180,7 +181,8 @@ void SkiaOutputSurfaceImpl::SetEnableDCLayers(bool enable) {
auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetEnableDCLayers,
base::Unretained(impl_on_gpu_.get()), enable);
- ScheduleGpuTask(std::move(task), {});
+ EnqueueGpuTask(std::move(task), {}, /*make_current=*/true,
+ /*need_framebuffer=*/false);
}
void SkiaOutputSurfaceImpl::EnsureBackbuffer() {
@@ -235,7 +237,9 @@ void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
base::Unretained(impl_on_gpu_.get()), size,
device_scale_factor, color_space, format,
use_stencil, GetDisplayTransform());
- ScheduleGpuTask(std::move(task), {});
+ EnqueueGpuTask(std::move(task), {}, /*make_current=*/true,
+ /*need_framebuffer=*/!dependency_->IsOffscreen());
+ FlushGpuTasks(/*wait_for_finish=*/false);
color_space_ = color_space;
is_hdr_ = color_space_.IsHDR();
@@ -389,19 +393,14 @@ gpu::SyncToken SkiaOutputSurfaceImpl::ReleaseImageContexts(
if (image_contexts.empty())
return gpu::SyncToken();
- gpu::SyncToken sync_token(
- gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE,
- impl_on_gpu_->command_buffer_id(), ++sync_fence_release_);
- sync_token.SetVerifyFlush();
-
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
- auto callback =
- base::BindOnce(&SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts,
- base::Unretained(impl_on_gpu_.get()),
- std::move(image_contexts), sync_fence_release_);
- gpu_task_scheduler_->ScheduleGpuTask(std::move(callback), {});
- return sync_token;
+ auto callback = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts,
+ base::Unretained(impl_on_gpu_.get()), std::move(image_contexts));
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/true,
+ /*need_framebuffer=*/false);
+ return Flush();
}
std::unique_ptr<ExternalUseClient::ImageContext>
@@ -453,9 +452,10 @@ void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) {
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SwapBuffers,
base::Unretained(impl_on_gpu_.get()),
- post_task_timestamp, std::move(frame),
- std::move(deferred_framebuffer_draw_closure_));
- ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
+ post_task_timestamp, std::move(frame));
+ EnqueueGpuTask(std::move(callback), std::move(resource_sync_tokens_),
+ /*make_current=*/true,
+ /*need_framebuffer=*/!dependency_->IsOffscreen());
// Recreate |root_recorder_| after SwapBuffers has been scheduled on GPU
// thread to save some time in BeginPaintCurrentFrame
@@ -467,9 +467,9 @@ void SkiaOutputSurfaceImpl::SwapBuffersSkipped() {
// PostTask to the GPU thread to deal with freeing resources and running
// callbacks.
auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped,
- base::Unretained(impl_on_gpu_.get()),
- std::move(deferred_framebuffer_draw_closure_));
- ScheduleGpuTask(std::move(task), std::move(resource_sync_tokens_));
+ base::Unretained(impl_on_gpu_.get()));
+ EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
+ /*make_current=*/false, /*need_framebuffer=*/false);
// TODO(vasilyt): reuse root recorder
RecreateRootRecorder();
@@ -483,7 +483,8 @@ void SkiaOutputSurfaceImpl::ScheduleOutputSurfaceAsOverlay(
auto callback = base::BindOnce(
&SkiaOutputSurfaceImplOnGpu::ScheduleOutputSurfaceAsOverlay,
base::Unretained(impl_on_gpu_.get()), std::move(output_surface_plane));
- ScheduleGpuTask(std::move(callback), {});
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
}
SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
@@ -516,7 +517,6 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPassOverlay(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Make sure there is no unsubmitted PaintFrame or PaintRenderPass.
DCHECK(!current_paint_);
- DCHECK(resource_sync_tokens_.empty());
SkSurfaceCharacterization characterization = CreateSkSurfaceCharacterization(
size, BufferFormat(format), mipmap, std::move(color_space),
@@ -539,21 +539,14 @@ SkiaOutputSurfaceImpl::EndPaintRenderPassOverlay() {
}
#endif // defined(OS_APPLE)
-gpu::SyncToken SkiaOutputSurfaceImpl::SubmitPaint(
- base::OnceClosure on_finished) {
+void SkiaOutputSurfaceImpl::EndPaint(base::OnceClosure on_finished) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(current_paint_);
- DCHECK(!deferred_framebuffer_draw_closure_);
// If current_render_pass_id_ is not null, we are painting a render pass.
// Otherwise we are painting a frame.
bool painting_render_pass = !current_paint_->render_pass_id().is_null();
- gpu::SyncToken sync_token(
- gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE,
- impl_on_gpu_->command_buffer_id(), ++sync_fence_release_);
- sync_token.SetVerifyFlush();
-
auto ddl = current_paint_->recorder()->detach();
// impl_on_gpu_ is released on the GPU thread by a posted task from
@@ -566,7 +559,6 @@ gpu::SyncToken SkiaOutputSurfaceImpl::SubmitPaint(
// MakePromiseSkImageFromRenderPass() is called.
it->second->clear_image();
}
- DCHECK(!on_finished);
base::TimeTicks post_task_timestamp;
if (should_measure_next_post_task_) {
@@ -574,36 +566,37 @@ gpu::SyncToken SkiaOutputSurfaceImpl::SubmitPaint(
post_task_timestamp = base::TimeTicks::Now();
}
- auto closure =
+ auto task =
base::BindOnce(&SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
base::Unretained(impl_on_gpu_.get()),
post_task_timestamp, current_paint_->render_pass_id(),
std::move(ddl), std::move(images_in_current_paint_),
- resource_sync_tokens_, sync_fence_release_);
- ScheduleGpuTask(std::move(closure), std::move(resource_sync_tokens_));
+ resource_sync_tokens_, std::move(on_finished));
+ EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
+ /*make_current=*/true, /*need_framebuffer=*/false);
} else {
// Draw on the root render pass.
current_buffer_modified_ = true;
sk_sp<SkDeferredDisplayList> overdraw_ddl;
- if (debug_settings_->show_overdraw_feedback) {
+ if (overdraw_surface_recorder_) {
overdraw_ddl = overdraw_surface_recorder_->detach();
DCHECK(overdraw_ddl);
overdraw_canvas_.reset();
- nway_canvas_.reset();
overdraw_surface_recorder_.reset();
}
+ nway_canvas_.reset();
- deferred_framebuffer_draw_closure_ = base::BindOnce(
+ auto task = base::BindOnce(
&SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame,
base::Unretained(impl_on_gpu_.get()), std::move(ddl),
std::move(overdraw_ddl), std::move(images_in_current_paint_),
- resource_sync_tokens_, sync_fence_release_, std::move(on_finished),
- draw_rectangle_);
+ resource_sync_tokens_, std::move(on_finished), draw_rectangle_);
+ EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
+ /*make_current=*/true, /*need_framebuffer=*/true);
draw_rectangle_.reset();
}
images_in_current_paint_.clear();
current_paint_.reset();
- return sync_token;
}
sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
@@ -665,7 +658,8 @@ void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
base::BindOnce(&SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource,
base::Unretained(impl_on_gpu_.get()), std::move(ids),
std::move(image_contexts));
- ScheduleGpuTask(std::move(callback), {});
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
}
void SkiaOutputSurfaceImpl::CopyOutput(
@@ -674,45 +668,47 @@ void SkiaOutputSurfaceImpl::CopyOutput(
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // Defer CopyOutput for root render pass with draw framebuffer to
- // SwapBuffers() or SwapBuffersSkipped().
- if (!id) {
- deferred_framebuffer_draw_closure_ = base::BindOnce(
- &SkiaOutputSurfaceImplOnGpu::CopyOutput,
- base::Unretained(impl_on_gpu_.get()), id, geometry, color_space,
- std::move(request), std::move(deferred_framebuffer_draw_closure_));
- } else {
- DCHECK(!deferred_framebuffer_draw_closure_);
- auto callback = base::BindOnce(
- base::IgnoreResult(&SkiaOutputSurfaceImplOnGpu::CopyOutput),
- base::Unretained(impl_on_gpu_.get()), id, geometry, color_space,
- std::move(request), base::OnceCallback<bool()>());
- ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
- }
+ auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::CopyOutput,
+ base::Unretained(impl_on_gpu_.get()), id,
+ geometry, color_space, std::move(request));
+ EnqueueGpuTask(std::move(callback), std::move(resource_sync_tokens_),
+ /*make_current=*/true, /*need_framebuffer=*/!id);
}
void SkiaOutputSurfaceImpl::ScheduleOverlays(
OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens) {
- auto task =
- base::BindOnce(&SkiaOutputSurfaceImplOnGpu::ScheduleOverlays,
- base::Unretained(impl_on_gpu_.get()), std::move(overlays),
- std::move(images_in_current_paint_));
- ScheduleGpuTask(std::move(task), std::move(sync_tokens));
+ std::vector<gpu::SyncToken> sync_tokens,
+ base::OnceClosure on_finished) {
+ auto task = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::ScheduleOverlays,
+ base::Unretained(impl_on_gpu_.get()), std::move(overlays),
+ std::move(images_in_current_paint_), std::move(on_finished));
+#if defined(OS_APPLE)
+ DCHECK_EQ(dependency_->gr_context_type(), gpu::GrContextType::kGL);
+ // If there are render pass overlays, then a gl context is needed for drawing
+ // the overlay render passes to a backing for being scanned out.
+ bool make_current = std::find_if(overlays.begin(), overlays.end(),
+ [](const CALayerOverlay& overlay) {
+ return !!overlay.ddl;
+ }) != overlays.end();
+ // Append |resource_sync_tokens_| which are depended by drawing render passes
+ // to overlay backings.
+ std::move(resource_sync_tokens_.begin(), resource_sync_tokens_.end(),
+ std::back_inserter(sync_tokens));
+ resource_sync_tokens_.clear();
+#else
+ bool make_current = false;
+#endif
+ EnqueueGpuTask(std::move(task), std::move(sync_tokens), make_current,
+ /*need_framebuffer=*/false);
images_in_current_paint_.clear();
}
-gpu::MemoryTracker* SkiaOutputSurfaceImpl::GetMemoryTracker() {
- // Should only be called after initialization.
- DCHECK(impl_on_gpu_);
- return impl_on_gpu_->GetMemoryTracker();
-}
-
void SkiaOutputSurfaceImpl::SetFrameRate(float frame_rate) {
auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetFrameRate,
base::Unretained(impl_on_gpu_.get()), frame_rate);
- ScheduleGpuTask(std::move(task), {});
+ EnqueueGpuTask(std::move(task), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
}
void SkiaOutputSurfaceImpl::SetCapabilitiesForTesting(
@@ -723,28 +719,24 @@ void SkiaOutputSurfaceImpl::SetCapabilitiesForTesting(
auto callback =
base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetCapabilitiesForTesting,
base::Unretained(impl_on_gpu_.get()), capabilities_);
- ScheduleGpuTask(std::move(callback), {});
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/true,
+ /*need_framebuffer=*/false);
}
bool SkiaOutputSurfaceImpl::Initialize() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Before starting to schedule GPU task, set up |gpu_task_scheduler_| that
- // holds a task sequence.
- gpu_task_scheduler_ = base::MakeRefCounted<gpu::GpuTaskSchedulerHelper>(
- dependency_->CreateSequence());
-
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
// This runner could be called from vsync or GPU thread after |this| is
// destroyed. We post directly to display compositor thread to check
// |weak_ptr_| as |dependency_| may have been destroyed.
- GpuVSyncCallback vsync_callback_runner =
#if defined(OS_ANDROID)
- // Callback is never used on Android. Doesn't work with WebView because
- // calling it bypasses SkiaOutputSurfaceDependency.
- base::DoNothing();
+ // Callback is never used on Android. Doesn't work with WebView because
+ // calling it bypasses SkiaOutputSurfaceDependency.
+ GpuVSyncCallback vsync_callback_runner = base::DoNothing();
#else
+ GpuVSyncCallback vsync_callback_runner =
base::BindRepeating(
[](scoped_refptr<base::SingleThreadTaskRunner> runner,
base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr,
@@ -756,13 +748,15 @@ bool SkiaOutputSurfaceImpl::Initialize() {
base::ThreadTaskRunnerHandle::Get(), weak_ptr_);
#endif
- base::WaitableEvent event;
bool result = false;
- auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
- base::Unretained(this), vsync_callback_runner,
- &event, &result);
- ScheduleGpuTask(std::move(callback), {});
- event.Wait();
+ auto callback =
+ base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
+ base::Unretained(this), vsync_callback_runner, &result);
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
+ // |capabilities_| will be initialized in InitializeOnGpuThread(), so have to
+ // wait.
+ FlushGpuTasks(/*wait_for_finish=*/true);
if (capabilities_.preserve_buffer_content &&
capabilities_.supports_post_sub_buffer) {
@@ -783,14 +777,7 @@ bool SkiaOutputSurfaceImpl::Initialize() {
void SkiaOutputSurfaceImpl::InitializeOnGpuThread(
GpuVSyncCallback vsync_callback_runner,
- base::WaitableEvent* event,
bool* result) {
- base::Optional<base::ScopedClosureRunner> scoped_runner;
- if (event) {
- scoped_runner.emplace(
- base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
- }
-
auto did_swap_buffer_complete_callback = base::BindRepeating(
&SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_);
auto buffer_presented_callback =
@@ -799,8 +786,8 @@ void SkiaOutputSurfaceImpl::InitializeOnGpuThread(
base::BindOnce(&SkiaOutputSurfaceImpl::ContextLost, weak_ptr_);
impl_on_gpu_ = SkiaOutputSurfaceImplOnGpu::Create(
- dependency_.get(), renderer_settings_,
- gpu_task_scheduler_->GetSequenceId(),
+ dependency_, renderer_settings_, gpu_task_scheduler_->GetSequenceId(),
+ display_compositor_controller_->controller_on_gpu(),
std::move(did_swap_buffer_complete_callback),
std::move(buffer_presented_callback), std::move(context_lost_callback),
std::move(vsync_callback_runner));
@@ -821,13 +808,14 @@ SkiaOutputSurfaceImpl::CreateSkSurfaceCharacterization(
bool mipmap,
sk_sp<SkColorSpace> color_space,
bool is_root_render_pass) {
- if (!gr_context_thread_safe_)
+ if (!gr_context_thread_safe_) {
+ DLOG(ERROR) << "gr_context_thread_safe_ is null.";
return SkSurfaceCharacterization();
+ }
auto cache_max_resource_bytes = impl_on_gpu_->max_resource_cache_bytes();
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- SkSurfaceProps surface_props(0 /*flags */,
- SkSurfaceProps::kLegacyFontHost_InitType);
+ SkSurfaceProps surface_props =
+ skia::LegacyDisplayGlobals::GetSkSurfaceProps();
if (is_root_render_pass) {
const auto format_index = static_cast<int>(format);
const auto& color_type = capabilities_.sk_color_types[format_index];
@@ -854,7 +842,9 @@ SkiaOutputSurfaceImpl::CreateSkSurfaceCharacterization(
capabilities_.uses_default_gl_framebuffer, false /* isTextureable */,
impl_on_gpu_->GetGpuPreferences().enforce_vulkan_protected_memory
? GrProtected::kYes
- : GrProtected::kNo);
+ : GrProtected::kNo,
+ false /* vkRTSupportsInputAttachment */,
+ capabilities_.root_is_vulkan_secondary_command_buffer);
VkFormat vk_format = VK_FORMAT_UNDEFINED;
LOG_IF(DFATAL, !characterization.isValid())
<< "\n surface_size=" << surface_size.ToString()
@@ -952,20 +942,64 @@ void SkiaOutputSurfaceImpl::OnGpuVSync(base::TimeTicks timebase,
void SkiaOutputSurfaceImpl::ScheduleGpuTaskForTesting(
base::OnceClosure callback,
std::vector<gpu::SyncToken> sync_tokens) {
- ScheduleGpuTask(std::move(callback), std::move(sync_tokens));
-}
+ EnqueueGpuTask(std::move(callback), std::move(sync_tokens),
+ /*make_current=*/false, /*need_framebuffer=*/false);
+ FlushGpuTasks(/*wait_for_finish=*/false);
+}
+
+void SkiaOutputSurfaceImpl::EnqueueGpuTask(
+ GpuTask task,
+ std::vector<gpu::SyncToken> sync_tokens,
+ bool make_current,
+ bool need_framebuffer) {
+ gpu_tasks_.push_back(std::move(task));
+ std::move(sync_tokens.begin(), sync_tokens.end(),
+ std::back_inserter(gpu_task_sync_tokens_));
+
+ // Set |make_current_|, so MakeCurrent() will be called before executing all
+ // enqueued GPU tasks.
+ make_current_ |= make_current;
+ need_framebuffer_ |= need_framebuffer;
+}
+
+void SkiaOutputSurfaceImpl::FlushGpuTasks(bool wait_for_finish) {
+ // If |wait_for_finish| is true, a GPU task will be always scheduled to make
+ // sure all pending tasks are finished on the GPU thread.
+ if (gpu_tasks_.empty() && !wait_for_finish)
+ return;
-void SkiaOutputSurfaceImpl::ScheduleGpuTask(
- base::OnceClosure callback,
- std::vector<gpu::SyncToken> sync_tokens) {
- auto wrapped_closure = base::BindOnce(
- [](base::OnceClosure callback) {
+ auto event =
+ wait_for_finish ? std::make_unique<base::WaitableEvent>() : nullptr;
+
+ auto callback = base::BindOnce(
+ [](std::vector<GpuTask> tasks, base::WaitableEvent* event,
+ SkiaOutputSurfaceImplOnGpu* impl_on_gpu, bool need_framebuffer) {
gpu::ContextUrl::SetActiveUrl(GetActiveUrl());
- std::move(callback).Run();
+ // MakeCurrent() will mark context lost in SkiaOutputSurfaceImplOnGpu,
+ // if it fails.
+ if (impl_on_gpu)
+ impl_on_gpu->MakeCurrent(need_framebuffer);
+ // Each task can check SkiaOutputSurfaceImplOnGpu::contest_is_lost_
+ // to detect errors.
+ for (auto& task : tasks) {
+ std::move(task).Run();
+ }
+ if (event)
+ event->Signal();
},
- std::move(callback));
- gpu_task_scheduler_->ScheduleGpuTask(std::move(wrapped_closure),
- std::move(sync_tokens));
+ std::move(gpu_tasks_), event.get(),
+ make_current_ ? impl_on_gpu_.get() : nullptr, need_framebuffer_);
+
+ gpu_task_scheduler_->ScheduleGpuTask(std::move(callback),
+ std::move(gpu_task_sync_tokens_));
+
+ make_current_ = false;
+ need_framebuffer_ = false;
+ gpu_task_sync_tokens_.clear();
+ gpu_tasks_.clear();
+
+ if (event)
+ event->Wait();
}
GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
@@ -976,7 +1010,8 @@ GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
#if BUILDFLAG(ENABLE_VULKAN)
if (!ycbcr_info) {
// YCbCr info is required for YUV images.
- DCHECK(resource_format != YVU_420 && resource_format != YUV_420_BIPLANAR);
+ DCHECK(resource_format != YVU_420 &&
+ resource_format != YUV_420_BIPLANAR && resource_format != P010);
return GrBackendFormat::MakeVk(ToVkFormat(resource_format));
}
@@ -1059,6 +1094,20 @@ void SkiaOutputSurfaceImpl::RemoveContextLostObserver(
observers_.RemoveObserver(observer);
}
+gpu::SyncToken SkiaOutputSurfaceImpl::Flush() {
+ gpu::SyncToken sync_token(
+ gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE,
+ impl_on_gpu_->command_buffer_id(), ++sync_fence_release_);
+ sync_token.SetVerifyFlush();
+ auto callback = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::ReleaseFenceSyncAndPushTextureUpdates,
+ base::Unretained(impl_on_gpu_.get()), sync_fence_release_);
+ EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
+ /*need_framebuffer=*/false);
+ FlushGpuTasks(/*wait_for_finish=*/false);
+ return sync_token;
+}
+
void SkiaOutputSurfaceImpl::PrepareYUVATextureIndices(
const std::vector<ImageContext*>& contexts,
bool has_alpha,
@@ -1094,16 +1143,12 @@ void SkiaOutputSurfaceImpl::PrepareYUVATextureIndices(
void SkiaOutputSurfaceImpl::ContextLost() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DLOG(ERROR) << "SkiaOutputSurfaceImpl::ContextLost()";
gr_context_thread_safe_.reset();
for (auto& observer : observers_)
observer.OnContextLost();
}
-scoped_refptr<gpu::GpuTaskSchedulerHelper>
-SkiaOutputSurfaceImpl::GetGpuTaskSchedulerHelper() {
- return gpu_task_scheduler_;
-}
-
gfx::Rect SkiaOutputSurfaceImpl::GetCurrentFramebufferDamage() const {
if (use_damage_area_from_skia_output_device_) {
DCHECK(damage_of_current_buffer_);
@@ -1120,4 +1165,5 @@ gfx::Rect SkiaOutputSurfaceImpl::GetCurrentFramebufferDamage() const {
void SkiaOutputSurfaceImpl::SetNeedsMeasureNextDrawLatency() {
should_measure_next_post_task_ = true;
}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
index 563bb85c26b..657c40a516b 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -16,6 +16,7 @@
#include "build/build_config.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "components/viz/service/display/skia_output_surface.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/sync_token.h"
@@ -26,10 +27,6 @@
#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
#include "third_party/skia/include/core/SkYUVAIndex.h"
-namespace base {
-class WaitableEvent;
-}
-
namespace viz {
class ImageContextImpl;
@@ -49,14 +46,15 @@ class SkiaOutputSurfaceImplOnGpu;
class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
public:
static std::unique_ptr<SkiaOutputSurface> Create(
- std::unique_ptr<SkiaOutputSurfaceDependency> deps,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const RendererSettings& renderer_settings,
const DebugRendererSettings* debug_settings);
- SkiaOutputSurfaceImpl(util::PassKey<SkiaOutputSurfaceImpl> pass_key,
- std::unique_ptr<SkiaOutputSurfaceDependency> deps,
- const RendererSettings& renderer_settings,
- const DebugRendererSettings* debug_settings);
+ SkiaOutputSurfaceImpl(
+ util::PassKey<SkiaOutputSurfaceImpl> pass_key,
+ DisplayCompositorMemoryAndTaskController* display_controller,
+ const RendererSettings& renderer_settings,
+ const DebugRendererSettings* debug_settings);
~SkiaOutputSurfaceImpl() override;
// OutputSurface implementation:
@@ -88,8 +86,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
void SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) override;
base::ScopedClosureRunner GetCacheBackBufferCb() override;
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override;
gfx::Rect GetCurrentFramebufferDamage() const override;
void SetFrameRate(float frame_rate) override;
void SetNeedsMeasureNextDrawLatency() override;
@@ -110,7 +106,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) override;
- gpu::SyncToken SubmitPaint(base::OnceClosure on_finished) override;
+ void EndPaint(base::OnceClosure on_finished) override;
void MakePromiseSkImage(ImageContext* image_context) override;
sk_sp<SkImage> MakePromiseSkImageFromRenderPass(
const AggregatedRenderPassId& id,
@@ -122,7 +118,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
void RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids) override;
void ScheduleOverlays(OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens) override;
+ std::vector<gpu::SyncToken> sync_tokens,
+ base::OnceClosure on_finished) override;
void CopyOutput(AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
@@ -130,6 +127,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
std::unique_ptr<CopyOutputRequest> request) override;
void AddContextLostObserver(ContextLostObserver* observer) override;
void RemoveContextLostObserver(ContextLostObserver* observer) override;
+ gpu::SyncToken Flush() override;
#if defined(OS_APPLE)
SkCanvas* BeginPaintRenderPassOverlay(
@@ -150,8 +148,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
sk_sp<SkColorSpace> color_space) override;
- gpu::MemoryTracker* GetMemoryTracker() override;
-
// Set the fields of |capabilities_| and propagates to |impl_on_gpu_|. Should
// be called after BindToClient().
void SetCapabilitiesForTesting(gfx::SurfaceOrigin output_surface_origin);
@@ -164,7 +160,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
private:
bool Initialize();
void InitializeOnGpuThread(GpuVSyncCallback vsync_callback_runner,
- base::WaitableEvent* event,
bool* result);
SkSurfaceCharacterization CreateSkSurfaceCharacterization(
const gfx::Size& surface_size,
@@ -179,8 +174,12 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
// Provided as a callback for the GPU thread.
void OnGpuVSync(base::TimeTicks timebase, base::TimeDelta interval);
- void ScheduleGpuTask(base::OnceClosure callback,
- std::vector<gpu::SyncToken> sync_tokens);
+ using GpuTask = base::OnceClosure;
+ void EnqueueGpuTask(GpuTask task,
+ std::vector<gpu::SyncToken> sync_tokens,
+ bool make_current,
+ bool need_framebuffer);
+ void FlushGpuTasks(bool wait_for_finish);
GrBackendFormat GetGrBackendFormatForTexture(
ResourceFormat resource_format,
uint32_t gl_texture_target,
@@ -204,7 +203,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
base::ObserverList<ContextLostObserver>::Unchecked observers_;
uint64_t sync_fence_release_ = 0;
- std::unique_ptr<SkiaOutputSurfaceDependency> dependency_;
+ SkiaOutputSurfaceDependency* dependency_;
UpdateVSyncParametersCallback update_vsync_parameters_callback_;
GpuVSyncCallback gpu_vsync_callback_;
bool is_displayed_as_overlay_ = false;
@@ -263,17 +262,24 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
// Points to the viz-global singleton.
const DebugRendererSettings* const debug_settings_;
- // The display transform relative to the hardware natural orientation,
- // applied to the frame content. The transform can be rotations in 90 degree
- // increments or flips.
- gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
+ // For testing cases we would need to setup a SkiaOutputSurface without
+ // OverlayProcessor and Display. For those cases, we hold the gpu task
+ // scheduler inside this class by having a unique_ptr.
+ // TODO(weiliangc): After changing to proper initialization order for Android
+ // WebView, remove this holder.
+ DisplayCompositorMemoryAndTaskController* display_compositor_controller_;
// |gpu_task_scheduler_| holds a gpu::SingleTaskSequence, and helps schedule
// tasks on GPU as a single sequence. It is shared with OverlayProcessor so
// compositing and overlay processing are in order. A gpu::SingleTaskSequence
// in regular Viz is implemented by SchedulerSequence. In Android WebView
// gpu::SingleTaskSequence is implemented on top of WebView's task queue.
- scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_;
+ gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_;
+
+ // The display transform relative to the hardware natural orientation,
+ // applied to the frame content. The transform can be rotations in 90 degree
+ // increments or flips.
+ gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
// |impl_on_gpu| is created and destroyed on the GPU thread.
std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_;
@@ -285,9 +291,14 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
bool should_measure_next_post_task_ = false;
- // We defer the draw to the framebuffer until SwapBuffers or CopyOutput
- // to avoid the expense of posting a task and calling MakeCurrent.
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure_;
+ // GPU tasks pending for flush.
+ std::vector<GpuTask> gpu_tasks_;
+ // GPU sync tokens which are depended by |gpu_tasks_|.
+ std::vector<gpu::SyncToken> gpu_task_sync_tokens_;
+ // True if _any_ of |gpu_tasks_| need a GL context.
+ bool make_current_ = false;
+ // True if _any_ of |gpu_tasks_| need to access the framebuffer.
+ bool need_framebuffer_ = false;
bool use_damage_area_from_skia_output_device_ = false;
// Damage area of the current buffer. Differ to the last submit buffer.
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 30a8812bba6..c8046a401c1 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -6,7 +6,6 @@
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/optional.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -14,6 +13,7 @@
#include "base/trace_event/trace_event.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
+#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/skia_helper.h"
#include "components/viz/common/viz_utils.h"
@@ -36,12 +36,12 @@
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/command_buffer/service/skia_utils.h"
#include "gpu/config/gpu_preferences.h"
-#include "gpu/ipc/common/command_buffer_id.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/common/gpu_peak_memory.h"
#include "gpu/ipc/common/gpu_surface_lookup.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
+#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/skia/include/core/SkDeferredDisplayList.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -49,6 +49,7 @@
#if BUILDFLAG(ENABLE_VULKAN)
#include "components/viz/service/display_embedder/skia_output_device_vulkan.h"
+#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h"
#include "gpu/vulkan/vulkan_util.h"
#endif
@@ -134,21 +135,15 @@ class CopyOutputResultYUV : public CopyOutputResult {
int u_out_stride,
uint8_t* v_out,
int v_out_stride) const override {
- const auto CopyPlane = [](const uint8_t* src, int src_stride, int width,
- int height, uint8_t* out, int out_stride) {
- for (int i = 0; i < height; ++i, src += src_stride, out += out_stride) {
- memcpy(out, src, width);
- }
- };
auto* data0 = static_cast<const uint8_t*>(result_->data(0));
auto* data1 = static_cast<const uint8_t*>(result_->data(1));
auto* data2 = static_cast<const uint8_t*>(result_->data(2));
- CopyPlane(data0, result_->rowBytes(0), width(0), height(0), y_out,
- y_out_stride);
- CopyPlane(data1, result_->rowBytes(1), width(1), height(1), u_out,
- u_out_stride);
- CopyPlane(data2, result_->rowBytes(2), width(2), height(2), v_out,
- v_out_stride);
+ libyuv::CopyPlane(data0, result_->rowBytes(0), y_out, y_out_stride,
+ width(0), height(0));
+ libyuv::CopyPlane(data1, result_->rowBytes(1), u_out, u_out_stride,
+ width(1), height(1));
+ libyuv::CopyPlane(data2, result_->rowBytes(2), v_out, v_out_stride,
+ width(2), height(2));
return true;
}
@@ -240,11 +235,14 @@ void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::BeginAccess(
std::vector<ImageContextImpl*> image_contexts,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) {
- DCHECK(begin_semaphores);
- DCHECK(end_semaphores);
- begin_semaphores->reserve(image_contexts.size());
- // We may need one more space for the swap buffer semaphore.
- end_semaphores->reserve(image_contexts.size() + 1);
+ // GL doesn't need semaphores.
+ if (!impl_on_gpu_->context_state_->GrContextIsGL()) {
+ DCHECK(begin_semaphores);
+ DCHECK(end_semaphores);
+ begin_semaphores->reserve(image_contexts.size());
+ // We may need one more space for the swap buffer semaphore.
+ end_semaphores->reserve(image_contexts.size() + 1);
+ }
image_contexts_.reserve(image_contexts.size() + image_contexts_.size());
image_contexts_.insert(image_contexts.begin(), image_contexts.end());
impl_on_gpu_->BeginAccessImages(std::move(image_contexts), begin_semaphores,
@@ -258,13 +256,10 @@ void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::EndAccess() {
namespace {
-base::AtomicSequenceNumber g_next_command_buffer_id;
-
scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState(
SkiaOutputSurfaceDependency* deps,
+ gpu::CommandBufferId command_buffer_id,
gpu::SequenceId sequence_id) {
- auto command_buffer_id = gpu::CommandBufferId::FromUnsafeValue(
- g_next_command_buffer_id.GetNext() + 1);
return deps->GetSyncPointManager()->CreateSyncPointClientState(
gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE, command_buffer_id,
sequence_id);
@@ -365,6 +360,7 @@ std::unique_ptr<SkiaOutputSurfaceImplOnGpu> SkiaOutputSurfaceImplOnGpu::Create(
SkiaOutputSurfaceDependency* deps,
const RendererSettings& renderer_settings,
const gpu::SequenceId sequence_id,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
BufferPresentedCallback buffer_presented_callback,
ContextLostCallback context_lost_callback,
@@ -388,7 +384,7 @@ std::unique_ptr<SkiaOutputSurfaceImplOnGpu> SkiaOutputSurfaceImplOnGpu::Create(
auto impl_on_gpu = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
util::PassKey<SkiaOutputSurfaceImplOnGpu>(), deps,
context_state->feature_info(), renderer_settings, sequence_id,
- std::move(did_swap_buffer_complete_callback),
+ shared_gpu_deps, std::move(did_swap_buffer_complete_callback),
std::move(buffer_presented_callback), std::move(context_lost_callback),
std::move(gpu_vsync_callback));
if (!impl_on_gpu->Initialize())
@@ -403,19 +399,25 @@ SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
const RendererSettings& renderer_settings,
const gpu::SequenceId sequence_id,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
BufferPresentedCallback buffer_presented_callback,
ContextLostCallback context_lost_callback,
GpuVSyncCallback gpu_vsync_callback)
: dependency_(std::move(deps)),
+ shared_gpu_deps_(shared_gpu_deps),
feature_info_(std::move(feature_info)),
sync_point_client_state_(
- CreateSyncPointClientState(dependency_, sequence_id)),
- memory_tracker_(dependency_->GetSharedContextState()->memory_tracker()),
+ CreateSyncPointClientState(dependency_,
+ shared_gpu_deps_->command_buffer_id(),
+ sequence_id)),
shared_image_factory_(
- CreateSharedImageFactory(dependency_, memory_tracker_)),
+ CreateSharedImageFactory(dependency_,
+ shared_gpu_deps_->memory_tracker())),
shared_image_representation_factory_(
- CreateSharedImageRepresentationFactory(dependency_, memory_tracker_)),
+ CreateSharedImageRepresentationFactory(
+ dependency_,
+ shared_gpu_deps_->memory_tracker())),
vulkan_context_provider_(dependency_->GetVulkanContextProvider()),
dawn_context_provider_(dependency_->GetDawnContextProvider()),
renderer_settings_(renderer_settings),
@@ -448,7 +450,7 @@ SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
// |context_provider_| and clients want either the context to be lost or
// made current on destruction.
- if (MakeCurrent(false /* need_fbo0 */)) {
+ if (MakeCurrent(/*need_framebuffer=*/false)) {
// This ensures any outstanding callbacks for promise images are
// performed.
gr_context()->flushAndSubmit();
@@ -469,7 +471,7 @@ void SkiaOutputSurfaceImplOnGpu::Reshape(const gfx::Size& size,
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(gr_context());
- if (!MakeCurrent(!dependency_->IsOffscreen() /* need_fbo0 */))
+ if (context_is_lost_)
return;
size_ = size;
@@ -477,36 +479,33 @@ void SkiaOutputSurfaceImplOnGpu::Reshape(const gfx::Size& size,
if (!output_device_->Reshape(size_, device_scale_factor, color_space, format,
transform)) {
MarkContextLost(CONTEXT_LOST_RESHAPE_FAILED);
- return;
}
}
-bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
+void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
sk_sp<SkDeferredDisplayList> ddl,
sk_sp<SkDeferredDisplayList> overdraw_ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
- uint64_t sync_fence_release,
base::OnceClosure on_finished,
base::Optional<gfx::Rect> draw_rectangle) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!scoped_output_device_paint_);
- bool need_fbo0 = gl_surface_ && !gl_surface_->IsSurfaceless();
- if (!MakeCurrent(need_fbo0))
- return false;
+ if (context_is_lost_)
+ return;
if (!ddl) {
MarkContextLost(CONTEXT_LOST_UNKNOWN);
- return false;
+ return;
}
if (draw_rectangle) {
if (!output_device_->SetDrawRectangle(*draw_rectangle)) {
MarkContextLost(
ContextLostReason::CONTEXT_LOST_SET_DRAW_RECTANGLE_FAILED);
- return false;
+ return;
}
}
@@ -514,7 +513,7 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
// SwapBuffers() is called, because we may need access to output_sk_surface()
// for CopyOutput().
scoped_output_device_paint_.emplace(output_device_.get());
- DCHECK(output_sk_surface());
+ DCHECK(scoped_output_device_paint_);
dependency_->ScheduleGrContextCleanup();
@@ -532,14 +531,14 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
promise_image_access_helper_.BeginAccess(
std::move(image_contexts), &begin_semaphores, &end_semaphores);
if (!begin_semaphores.empty()) {
- auto result = output_sk_surface()->wait(
+ auto result = scoped_output_device_paint_->Wait(
begin_semaphores.size(), begin_semaphores.data(),
/*deleteSemaphoresAfterWait=*/false);
DCHECK(result);
}
// Draw will only fail if the SkSurface and SkDDL are incompatible.
- bool draw_success = output_sk_surface()->draw(ddl);
+ bool draw_success = scoped_output_device_paint_->Draw(ddl);
DCHECK(draw_success);
destroy_after_swap_.emplace_back(std::move(ddl));
@@ -556,8 +555,8 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
sk_sp<SkColorFilter> colorFilter = SkiaHelper::MakeOverdrawColorFilter();
paint.setColorFilter(colorFilter);
// TODO(xing.xu): move below to the thread where skia record happens.
- output_sk_surface()->getCanvas()->drawImage(overdraw_image.get(), 0, 0,
- &paint);
+ scoped_output_device_paint_->GetCanvas()->drawImage(overdraw_image.get(),
+ 0, 0, &paint);
}
auto end_paint_semaphores =
@@ -565,27 +564,17 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
end_semaphores.insert(end_semaphores.end(), end_paint_semaphores.begin(),
end_paint_semaphores.end());
- GrFlushInfo flush_info = {
- .fNumSemaphores = end_semaphores.size(),
- .fSignalSemaphores = end_semaphores.data(),
- };
-
- gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
- &flush_info);
- if (on_finished)
- gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
-
- auto result = output_sk_surface()->flush(flush_info);
+ auto result = scoped_output_device_paint_->Flush(vulkan_context_provider_,
+ std::move(end_semaphores),
+ std::move(on_finished));
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
DLOG(ERROR) << "output_sk_surface()->flush() failed.";
- return false;
+ return;
}
}
- ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
- return true;
}
void SkiaOutputSurfaceImplOnGpu::ScheduleOutputSurfaceAsOverlay(
@@ -597,8 +586,7 @@ void SkiaOutputSurfaceImplOnGpu::ScheduleOutputSurfaceAsOverlay(
void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
base::TimeTicks post_task_timestamp,
- OutputSurfaceFrame frame,
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure) {
+ OutputSurfaceFrame frame) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::SwapBuffers");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -606,13 +594,12 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
output_device_->SetDrawTimings(post_task_timestamp, base::TimeTicks::Now());
}
- SwapBuffersInternal(std::move(deferred_framebuffer_draw_closure), &frame);
+ SwapBuffersInternal(std::move(frame));
}
-void SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped(
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure) {
+void SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- SwapBuffersInternal(std::move(deferred_framebuffer_draw_closure));
+ SwapBuffersInternal(base::nullopt);
}
void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
@@ -621,7 +608,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
sk_sp<SkDeferredDisplayList> ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
- uint64_t sync_fence_release) {
+ base::OnceClosure on_finished) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(ddl);
@@ -630,7 +617,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
output_device_->SetDrawTimings(post_task_timestamp, base::TimeTicks::Now());
}
- if (!MakeCurrent(false /* need_fbo0 */))
+ if (context_is_lost_)
return;
if (!ddl) {
@@ -672,6 +659,8 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
};
gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
&flush_info);
+ if (on_finished)
+ gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
auto result = offscreen.surface()->flush(flush_info);
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
@@ -679,8 +668,12 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
DLOG(ERROR) << "offscreen.surface()->flush() failed.";
return;
}
+ bool sync_cpu =
+ gpu::ShouldVulkanSyncCpuForSkiaSubmit(vulkan_context_provider_);
+ if (sync_cpu) {
+ gr_context()->submit(true);
+ }
}
- ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
}
void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource(
@@ -712,38 +705,35 @@ static void PostTaskFromMainToImplThread(
FROM_HERE, base::BindOnce(std::move(callback), sync_token, is_lost));
}
-bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
+void SkiaOutputSurfaceImplOnGpu::CopyOutput(
AggregatedRenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
- std::unique_ptr<CopyOutputRequest> request,
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure) {
+ std::unique_ptr<CopyOutputRequest> request) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::CopyOutput");
// TODO(crbug.com/898595): Do this on the GPU instead of CPU with Vulkan.
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (deferred_framebuffer_draw_closure) {
- // returns false if context not set to current, i.e lost
- if (!std::move(deferred_framebuffer_draw_closure).Run())
- return false;
- DCHECK(context_state_->IsCurrent(nullptr /* surface */));
- } else {
- if (!MakeCurrent(true /* need_fbo0 */))
- return false;
- }
+ if (context_is_lost_)
+ return;
- bool from_fbo0 = !id;
- DCHECK(scoped_output_device_paint_ || !from_fbo0);
+ bool from_framebuffer = !id;
+ DCHECK(scoped_output_device_paint_ || !from_framebuffer);
- DCHECK(from_fbo0 ||
+ DCHECK(from_framebuffer ||
offscreen_surfaces_.find(id) != offscreen_surfaces_.end());
- auto* surface =
- from_fbo0 ? output_sk_surface() : offscreen_surfaces_[id].surface();
+ SkSurface* surface = from_framebuffer
+ ? scoped_output_device_paint_->sk_surface()
+ : offscreen_surfaces_[id].surface();
+ // Do not support reading back from vulkan secondary command buffer.
+ if (!surface)
+ return;
// If a platform doesn't support RGBX_8888 format, we will use RGBA_8888
// instead. In this case, we need discard alpha channel (modify the alpha
// value to 0xff, but keep other channel not changed).
- bool need_discard_alpha = from_fbo0 && (output_device_->is_emulated_rgbx());
+ bool need_discard_alpha =
+ from_framebuffer && (output_device_->is_emulated_rgbx());
if (need_discard_alpha) {
base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
if (dependency_->GetGrShaderCache()) {
@@ -813,14 +803,22 @@ bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
CopyOutputRequest::ResultFormat::RGBA_BITMAP) {
// Perform swizzle during readback.
const bool skbitmap_is_bgra = (kN32_SkColorType == kBGRA_8888_SkColorType);
+ // If we can't convert |color_space| to a SkColorSpace
+ // (e.g. PIECEWISE_HDR), request a sRGB destination color space for the
+ // copy result instead.
+ gfx::ColorSpace dest_color_space = color_space;
+ sk_sp<SkColorSpace> sk_color_space = color_space.ToSkColorSpace();
+ if (!sk_color_space) {
+ dest_color_space = gfx::ColorSpace::CreateSRGB();
+ }
SkImageInfo dst_info = SkImageInfo::Make(
geometry.result_selection.width(), geometry.result_selection.height(),
skbitmap_is_bgra ? kBGRA_8888_SkColorType : kRGBA_8888_SkColorType,
- kPremul_SkAlphaType);
+ kPremul_SkAlphaType, sk_color_space);
std::unique_ptr<ReadPixelsContext> context =
std::make_unique<ReadPixelsContext>(std::move(request),
geometry.result_selection,
- color_space, weak_ptr_);
+ dest_color_space, weak_ptr_);
// Skia readback could be synchronous. Incremement counter in case
// ReadbackCompleted is called immediately.
num_readbacks_pending_++;
@@ -842,7 +840,7 @@ bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
gpu::kNullSurfaceHandle, kUsage);
if (!result) {
DLOG(ERROR) << "Failed to create shared image.";
- return false;
+ return;
}
auto representation = dependency_->GetSharedImageManager()->ProduceSkia(
@@ -885,7 +883,7 @@ bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
DLOG(ERROR) << "dest_surface->flush() failed.";
- return false;
+ return;
}
auto release_callback = base::BindOnce(
&SkiaOutputSurfaceImplOnGpu::DestroySharedImageOnImplThread,
@@ -901,7 +899,6 @@ bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
NOTREACHED();
}
ScheduleCheckReadbackCompletion();
- return true;
}
void SkiaOutputSurfaceImplOnGpu::DestroySharedImageOnImplThread(
@@ -919,6 +916,9 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
std::vector<GrBackendSemaphore>* end_semaphores) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::BeginAccessImages");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ bool is_gl = gpu_preferences_.gr_context_type == gpu::GrContextType::kGL;
+
for (auto* context : image_contexts) {
// Prepare for accessing render pass.
if (context->render_pass_id()) {
@@ -938,6 +938,16 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
dependency_->GetMailboxManager(), begin_semaphores, end_semaphores);
if (context->end_access_state())
image_contexts_with_end_access_state_.emplace(context);
+
+ // Texture parameters can be modified by concurrent reads so reset them
+ // before compositing from the texture. See https://crbug.com/1092080.
+ if (is_gl) {
+ auto* promise_texture = context->promise_image_texture();
+ if (promise_texture) {
+ GrBackendTexture backend_texture = promise_texture->backendTexture();
+ backend_texture.glTextureParametersModified();
+ }
+ }
}
}
}
@@ -970,43 +980,40 @@ SkiaOutputSurfaceImplOnGpu::GetGrContextThreadSafeProxy() {
void SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts(
std::vector<std::unique_ptr<ExternalUseClient::ImageContext>>
- image_contexts,
- uint64_t sync_fence_release) {
+ image_contexts) {
DCHECK(!image_contexts.empty());
// The window could be destroyed already, and the MakeCurrent will fail with
// an destroyed window, so MakeCurrent without requiring the fbo0.
- if (!MakeCurrent(false /* need_fbo0 */)) {
+ if (context_is_lost_) {
for (const auto& context : image_contexts)
context->OnContextLost();
}
image_contexts.clear();
- ReleaseFenceSyncAndPushTextureUpdates(sync_fence_release);
}
void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays,
- std::vector<ImageContextImpl*> image_contexts) {
+ std::vector<ImageContextImpl*> image_contexts,
+ base::OnceClosure on_finished) {
#if defined(OS_APPLE)
- std::vector<GrBackendSemaphore> begin_semaphores;
- std::vector<GrBackendSemaphore> end_semaphores;
- promise_image_access_helper_.BeginAccess(std::move(image_contexts),
- &begin_semaphores, &end_semaphores);
+ if (context_is_lost_)
+ return;
+
// GL is used on MacOS and GL doesn't need semaphores.
- DCHECK(begin_semaphores.empty());
- DCHECK(end_semaphores.empty());
+ promise_image_access_helper_.BeginAccess(std::move(image_contexts),
+ /*begin_semaphores=*/nullptr,
+ /*end_semaphores=*/nullptr);
+ using ScopedWriteAccess =
+ std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedWriteAccess>;
+ std::vector<ScopedWriteAccess> scoped_write_accesses;
for (auto& overlay : overlays) {
if (!overlay.ddl)
continue;
-
- base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
- if (dependency_->GetGrShaderCache()) {
- cache_use.emplace(dependency_->GetGrShaderCache(),
- gpu::kDisplayCompositorClientId);
- }
-
const auto& characterization = overlay.ddl->characterization();
auto backing = GetOrCreateRenderPassOverlayBacking(characterization);
+ if (!backing)
+ break;
DCHECK(overlay.mailbox.IsZero());
overlay.mailbox = backing->mailbox();
auto scoped_access = backing->BeginScopedWriteAccess(
@@ -1016,18 +1023,27 @@ void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
bool result = scoped_access->surface()->draw(overlay.ddl);
DCHECK(result);
- context_state_->gr_context()->flushAndSubmit();
- scoped_access.reset();
+ scoped_write_accesses.push_back(std::move(scoped_access));
backing->SetCleared();
in_flight_render_pass_overlay_backings_.insert(std::move(backing));
}
+
+ if (!scoped_write_accesses.empty()) {
+ base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
+ if (dependency_->GetGrShaderCache()) {
+ cache_use.emplace(dependency_->GetGrShaderCache(),
+ gpu::kDisplayCompositorClientId);
+ }
+
+ GrFlushInfo flush_info = {};
+ if (on_finished)
+ gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
+ context_state_->gr_context()->flush(flush_info);
+ context_state_->gr_context()->submit();
+ scoped_write_accesses.clear();
+ }
promise_image_access_helper_.EndAccess();
output_device_->ScheduleOverlays(std::move(overlays));
-
- // Release any backings which are not reused by the current frame, probably
- // because the properties of render passes are changed or render passes are
- // removed.
- available_render_pass_overlay_backings_.clear();
#else
DCHECK(image_contexts.empty());
output_device_->ScheduleOverlays(std::move(overlays));
@@ -1035,7 +1051,7 @@ void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
}
void SkiaOutputSurfaceImplOnGpu::SetEnableDCLayers(bool enable) {
- if (!MakeCurrent(false /* need_fbo0 */))
+ if (context_is_lost_)
return;
output_device_->SetEnableDCLayers(enable);
}
@@ -1051,13 +1067,12 @@ void SkiaOutputSurfaceImplOnGpu::SetFrameRate(float frame_rate) {
void SkiaOutputSurfaceImplOnGpu::SetCapabilitiesForTesting(
const OutputSurface::Capabilities& capabilities) {
- MakeCurrent(false /* need_fbo0 */);
// Check that we're using an offscreen surface.
DCHECK(dependency_->IsOffscreen());
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, capabilities.output_surface_origin,
- renderer_settings_.requires_alpha_channel, memory_tracker_,
- GetDidSwapBuffersCompleteCallback());
+ renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback());
}
bool SkiaOutputSurfaceImplOnGpu::Initialize() {
@@ -1115,7 +1130,8 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kTopLeft,
- renderer_settings_.requires_alpha_channel, memory_tracker_,
+ renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
} else {
gl_surface_ =
@@ -1124,28 +1140,39 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
if (!gl_surface_)
return false;
- if (MakeCurrent(true /* need_fbo0 */)) {
+ if (MakeCurrent(/*need_framebuffer=*/true)) {
if (gl_surface_->IsSurfaceless()) {
+#if defined(USE_OZONE)
+ bool needs_background_image = ui::OzonePlatform::GetInstance()
+ ->GetPlatformProperties()
+ .needs_background_image;
+#else // defined(USE_OZONE)
+ bool needs_background_image = false;
+#endif // !defined(USE_OZONE)
+
#if !defined(OS_WIN)
output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::make_unique<OutputPresenterGL>(
gl_surface_, dependency_, shared_image_factory_.get(),
shared_image_representation_factory_.get()),
dependency_, shared_image_representation_factory_.get(),
- memory_tracker_, GetDidSwapBuffersCompleteCallback());
-#else
+ shared_gpu_deps_->memory_tracker(),
+ GetDidSwapBuffersCompleteCallback(), needs_background_image);
+#else // !defined(OS_WIN)
NOTIMPLEMENTED();
-#endif
+ (void)needs_background_image;
+#endif // defined(OS_WIN)
} else {
if (dependency_->NeedsSupportForExternalStencil()) {
output_device_ = std::make_unique<SkiaOutputDeviceWebView>(
- context_state_.get(), gl_surface_, memory_tracker_,
+ context_state_.get(), gl_surface_,
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
} else {
output_device_ = std::make_unique<SkiaOutputDeviceGL>(
dependency_->GetMailboxManager(),
shared_image_representation_factory_.get(), context_state_.get(),
- gl_surface_, feature_info_, memory_tracker_,
+ gl_surface_, feature_info_, shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
}
}
@@ -1165,7 +1192,8 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
if (dependency_->IsOffscreen()) {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kBottomLeft,
- renderer_settings_.requires_alpha_channel, memory_tracker_,
+ renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
return true;
}
@@ -1175,11 +1203,13 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
if (!gpu_preferences_.disable_vulkan_surface) {
output_device_ = SkiaOutputDeviceVulkan::Create(
vulkan_context_provider_, dependency_->GetSurfaceHandle(),
- memory_tracker_, GetDidSwapBuffersCompleteCallback());
+ shared_gpu_deps_->memory_tracker(),
+ GetDidSwapBuffersCompleteCallback());
}
if (!output_device_) {
output_device_ = std::make_unique<SkiaOutputDeviceX11>(
- context_state_, dependency_->GetSurfaceHandle(), memory_tracker_,
+ context_state_, dependency_->GetSurfaceHandle(),
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
}
if (output_device_)
@@ -1187,6 +1217,14 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
}
#endif // defined(USE_X11)
+#if defined(USE_OZONE)
+ bool needs_background_image = ui::OzonePlatform::GetInstance()
+ ->GetPlatformProperties()
+ .needs_background_image;
+#else // defined(USE_OZONE)
+ bool needs_background_image = false;
+#endif // !defined(USE_OZONE)
+
#if !defined(OS_WIN)
#if defined(OS_FUCHSIA)
auto output_presenter = OutputPresenterFuchsia::Create(
@@ -1204,15 +1242,23 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
if (output_presenter) {
output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::move(output_presenter), dependency_,
- shared_image_representation_factory_.get(), memory_tracker_,
- GetDidSwapBuffersCompleteCallback());
+ shared_image_representation_factory_.get(),
+ shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback(),
+ needs_background_image);
return true;
}
#endif // !defined(OS_WIN)
+ (void)needs_background_image;
+ if (vulkan_context_provider_->GetGrSecondaryCBDrawContext()) {
+ output_device_ = std::make_unique<SkiaOutputDeviceVulkanSecondaryCB>(
+ vulkan_context_provider_, shared_gpu_deps_->memory_tracker(),
+ GetDidSwapBuffersCompleteCallback());
+ return true;
+ }
auto output_device = SkiaOutputDeviceVulkan::Create(
vulkan_context_provider_, dependency_->GetSurfaceHandle(),
- memory_tracker_, GetDidSwapBuffersCompleteCallback());
+ shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback());
if (!output_device)
return false;
@@ -1235,7 +1281,8 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
if (dependency_->IsOffscreen()) {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kBottomLeft,
- renderer_settings_.requires_alpha_channel, memory_tracker_,
+ renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
} else {
#if defined(USE_X11)
@@ -1243,7 +1290,8 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
// SkiaOutputDeviceDawn.
if (!features::IsUsingOzonePlatform()) {
output_device_ = std::make_unique<SkiaOutputDeviceX11>(
- context_state_, dependency_->GetSurfaceHandle(), memory_tracker_,
+ context_state_, dependency_->GetSurfaceHandle(),
+ shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
} else {
return false;
@@ -1252,7 +1300,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
std::unique_ptr<SkiaOutputDeviceDawn> output_device =
std::make_unique<SkiaOutputDeviceDawn>(
dawn_context_provider_, dependency_->GetSurfaceHandle(),
- gfx::SurfaceOrigin::kTopLeft, memory_tracker_,
+ gfx::SurfaceOrigin::kTopLeft, shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
const gpu::SurfaceHandle child_surface_handle =
output_device->GetChildSurfaceHandle();
@@ -1268,9 +1316,15 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
return true;
}
-bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) {
+bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_framebuffer) {
+ // If GL is not being used or GLSurface is not surfaceless, we can ignore
+ // making current the GLSurface for better performance.
+ bool need_fbo0 = need_framebuffer && context_state_->GrContextIsGL() &&
+ gl_surface_ && !gl_surface_->IsSurfaceless();
+
// need_fbo0 implies need_gl too.
bool need_gl = need_fbo0;
+
// Only make current with |gl_surface_|, if following operations will use
// fbo0.
auto* gl_surface = need_fbo0 ? gl_surface_.get() : nullptr;
@@ -1283,6 +1337,13 @@ bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) {
gpu::error::kLostContext, *context_state_->context_lost_reason()));
return false;
}
+
+ // Some GLSurface implements OnMakeCurrent() to tracing current GLContext,
+ // even if framebuffer is not needed, we still call OnMakeCurrent() so
+ // GLSurface implementation will know the current GLContext.
+ if (gl_surface_ && !need_fbo0)
+ gl_surface_->OnMakeCurrent(context_state_->context());
+
context_state_->set_need_context_state_reset(true);
return true;
}
@@ -1321,24 +1382,31 @@ void SkiaOutputSurfaceImplOnGpu::ReleaseFenceSyncAndPushTextureUpdates(
}
void SkiaOutputSurfaceImplOnGpu::SwapBuffersInternal(
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure,
- OutputSurfaceFrame* frame) {
+ base::Optional<OutputSurfaceFrame> frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(output_device_);
- if (deferred_framebuffer_draw_closure) {
- // Returns false if context not set to current, i.e lost
- if (!std::move(deferred_framebuffer_draw_closure).Run())
- return;
- DCHECK(context_state_->IsCurrent(nullptr /* surface */));
- } else {
- if (!MakeCurrent(!dependency_->IsOffscreen() /* need_fbo0 */))
- return;
- }
+#if defined(OS_APPLE)
+ // Release any backings which are not reused by the current frame, probably
+ // because the properties of render passes are changed or render passes are
+ // removed.
+ available_render_pass_overlay_backings_.clear();
+#endif
+
+ if (context_is_lost_)
+ return;
+
+ bool sync_cpu =
+ gpu::ShouldVulkanSyncCpuForSkiaSubmit(vulkan_context_provider_);
ResetStateOfImages();
- output_device_->PreGrContextSubmit();
- gr_context()->submit();
+ output_device_->Submit(
+ sync_cpu, base::BindOnce(&SkiaOutputSurfaceImplOnGpu::PostSubmit,
+ base::Unretained(this), std::move(frame)));
+}
+
+void SkiaOutputSurfaceImplOnGpu::PostSubmit(
+ base::Optional<OutputSurfaceFrame> frame) {
promise_image_access_helper_.EndAccess();
scoped_output_device_paint_.reset();
@@ -1437,7 +1505,7 @@ void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
#if defined(OS_APPLE)
// |available_render_pass_overlay_backings_| are used or released in
- // ScheduleOverlays() for every frames.
+ // SwapBuffers() for every frames.
DCHECK(available_render_pass_overlay_backings_.empty());
// Erase mailboxes of render pass overlays from |params.released_overlays| and
@@ -1498,7 +1566,7 @@ void SkiaOutputSurfaceImplOnGpu::CheckReadbackCompletion() {
// If there are no pending readback requests or we can't make the context
// current then exit. There is no thing to do here.
- if (num_readbacks_pending_ == 0 || !MakeCurrent(/*need_fbo0=*/false))
+ if (num_readbacks_pending_ == 0 || !MakeCurrent(/*need_framebuffer=*/false))
return;
gr_context()->checkAsyncWorkCompletion();
@@ -1558,6 +1626,7 @@ SkiaOutputSurfaceImplOnGpu::GetOrCreateRenderPassOverlayBacking(
kOverlayUsage);
if (!result) {
LOG(ERROR) << "CreateSharedImage() failed.";
+ MarkContextLost(CONTEXT_LOST_OUT_OF_MEMORY);
return nullptr;
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 1123185608f..c8a24455015 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -85,6 +85,7 @@ class SkiaOutputSurfaceImplOnGpu
SkiaOutputSurfaceDependency* deps,
const RendererSettings& renderer_settings,
const gpu::SequenceId sequence_id,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
BufferPresentedCallback buffer_presented_callback,
ContextLostCallback context_lost_callback,
@@ -96,6 +97,7 @@ class SkiaOutputSurfaceImplOnGpu
scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
const RendererSettings& renderer_settings,
const gpu::SequenceId sequence_id,
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
BufferPresentedCallback buffer_presented_callback,
ContextLostCallback context_lost_callback,
@@ -103,8 +105,9 @@ class SkiaOutputSurfaceImplOnGpu
~SkiaOutputSurfaceImplOnGpu() override;
gpu::CommandBufferId command_buffer_id() const {
- return sync_point_client_state_->command_buffer_id();
+ return shared_gpu_deps_->command_buffer_id();
}
+
const OutputSurface::Capabilities capabilities() const {
return output_device_->capabilities();
}
@@ -119,24 +122,20 @@ class SkiaOutputSurfaceImplOnGpu
gfx::BufferFormat format,
bool use_stencil,
gfx::OverlayTransform transform);
- bool FinishPaintCurrentFrame(sk_sp<SkDeferredDisplayList> ddl,
+ void FinishPaintCurrentFrame(sk_sp<SkDeferredDisplayList> ddl,
sk_sp<SkDeferredDisplayList> overdraw_ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
- uint64_t sync_fence_release,
base::OnceClosure on_finished,
base::Optional<gfx::Rect> draw_rectangle);
void ScheduleOutputSurfaceAsOverlay(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane&
output_surface_plane);
- void SwapBuffers(
- base::TimeTicks post_task_timestamp,
- OutputSurfaceFrame frame,
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure);
+ void SwapBuffers(base::TimeTicks post_task_timestamp,
+ OutputSurfaceFrame frame);
// Runs |deferred_framebuffer_draw_closure| when SwapBuffers() or CopyOutput()
// will not.
- void SwapBuffersSkipped(
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure);
+ void SwapBuffersSkipped();
void EnsureBackbuffer() { output_device_->EnsureBackbuffer(); }
void DiscardBackbuffer() { output_device_->DiscardBackbuffer(); }
void FinishPaintRenderPass(base::TimeTicks post_task_timestamp,
@@ -144,17 +143,16 @@ class SkiaOutputSurfaceImplOnGpu
sk_sp<SkDeferredDisplayList> ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
- uint64_t sync_fence_release);
+ base::OnceClosure on_finished);
// Deletes resources for RenderPasses in |ids|. Also takes ownership of
// |images_contexts| and destroys them on GPU thread.
void RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids,
std::vector<std::unique_ptr<ImageContextImpl>> image_contexts);
- bool CopyOutput(AggregatedRenderPassId id,
+ void CopyOutput(AggregatedRenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
- std::unique_ptr<CopyOutputRequest> request,
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure);
+ std::unique_ptr<CopyOutputRequest> request);
void BeginAccessImages(const std::vector<ImageContextImpl*>& image_contexts,
std::vector<GrBackendSemaphore>* begin_semaphores,
@@ -166,10 +164,10 @@ class SkiaOutputSurfaceImplOnGpu
size_t max_resource_cache_bytes() const { return max_resource_cache_bytes_; }
void ReleaseImageContexts(
std::vector<std::unique_ptr<ExternalUseClient::ImageContext>>
- image_contexts,
- uint64_t sync_fence_release);
+ image_contexts);
void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
- std::vector<ImageContextImpl*> image_contexts);
+ std::vector<ImageContextImpl*> image_contexts,
+ base::OnceClosure on_finished);
void SetEnableDCLayers(bool enable);
void SetGpuVSyncEnabled(bool enabled);
@@ -207,7 +205,11 @@ class SkiaOutputSurfaceImplOnGpu
num_readbacks_pending_--;
}
- gpu::MemoryTracker* GetMemoryTracker() { return memory_tracker_; }
+ // Make context current for GL, and return false if the context is lost.
+ // It will do nothing when Vulkan is used.
+ bool MakeCurrent(bool need_framebuffer);
+
+ void ReleaseFenceSyncAndPushTextureUpdates(uint64_t sync_fence_release);
private:
class OffscreenSurface;
@@ -224,9 +226,6 @@ class SkiaOutputSurfaceImplOnGpu
DidSwapBufferCompleteCallback GetDidSwapBuffersCompleteCallback();
- // Make context current for GL, and return false if the context is lost.
- // It will do nothing when Vulkan is used.
- bool MakeCurrent(bool need_fbo0);
void MarkContextLost(ContextLostReason reason);
void DestroySharedImageOnImplThread(
@@ -237,11 +236,8 @@ class SkiaOutputSurfaceImplOnGpu
void PullTextureUpdates(std::vector<gpu::SyncToken> sync_token);
- void ReleaseFenceSyncAndPushTextureUpdates(uint64_t sync_fence_release);
-
- void SwapBuffersInternal(
- base::OnceCallback<bool()> deferred_framebuffer_draw_closure,
- OutputSurfaceFrame* frame = nullptr);
+ void SwapBuffersInternal(base::Optional<OutputSurfaceFrame> frame);
+ void PostSubmit(base::Optional<OutputSurfaceFrame> frame);
GrDirectContext* gr_context() { return context_state_->gr_context(); }
@@ -254,10 +250,6 @@ class SkiaOutputSurfaceImplOnGpu
gpu_preferences_.gr_context_type == gpu::GrContextType::kDawn;
}
- SkSurface* output_sk_surface() const {
- return scoped_output_device_paint_->sk_surface();
- }
-
// Schedules a task to check if any skia readback requests have completed
// after a short delay. Will not schedule a task if there is already a
// scheduled task or no readback requests are pending.
@@ -290,9 +282,9 @@ class SkiaOutputSurfaceImplOnGpu
base::Optional<ReleaseCurrent> release_current_last_;
SkiaOutputSurfaceDependency* const dependency_;
+ gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps_;
scoped_refptr<gpu::gles2::FeatureInfo> feature_info_;
scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
- gpu::MemoryTracker* const memory_tracker_;
std::unique_ptr<gpu::SharedImageFactory> shared_image_factory_;
std::unique_ptr<gpu::SharedImageRepresentationFactory>
shared_image_representation_factory_;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
index 3b09f6fc2d4..be92590160b 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -58,6 +58,7 @@ class SkiaOutputSurfaceImplTest : public testing::Test {
protected:
DebugRendererSettings debug_settings_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
+ std::unique_ptr<DisplayCompositorMemoryAndTaskController> display_controller_;
std::unique_ptr<SkiaOutputSurface> output_surface_;
cc::FakeOutputSurfaceClient output_surface_client_;
base::WaitableEvent wait_;
@@ -76,10 +77,13 @@ SkiaOutputSurfaceImplTest::~SkiaOutputSurfaceImplTest() {
void SkiaOutputSurfaceImplTest::SetUpSkiaOutputSurfaceImpl() {
RendererSettings settings;
settings.use_skia_renderer = true;
- output_surface_ = SkiaOutputSurfaceImpl::Create(
- std::make_unique<SkiaOutputSurfaceDependencyImpl>(
- GetGpuService(), gpu::kNullSurfaceHandle),
- settings, &debug_settings_);
+ auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+ GetGpuService(), gpu::kNullSurfaceHandle);
+ display_controller_ =
+ std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ std::move(skia_deps));
+ output_surface_ = SkiaOutputSurfaceImpl::Create(display_controller_.get(),
+ settings, &debug_settings_);
output_surface_->BindToClient(&output_surface_client_);
}
@@ -91,7 +95,8 @@ gpu::SyncToken SkiaOutputSurfaceImplTest::PaintRootRenderPass(
SkCanvas* root_canvas = output_surface_->BeginPaintCurrentFrame();
root_canvas->drawRect(
SkRect::MakeXYWH(rect.x(), rect.y(), rect.height(), rect.width()), paint);
- return output_surface_->SubmitPaint(std::move(closure));
+ output_surface_->EndPaint(std::move(closure));
+ return output_surface_->Flush();
}
void SkiaOutputSurfaceImplTest::BlockMainThread() {
@@ -129,7 +134,7 @@ void SkiaOutputSurfaceImplTest::CopyRequestCallbackOnGpuThread(
UnblockMainThread();
}
-TEST_F(SkiaOutputSurfaceImplTest, SubmitPaint) {
+TEST_F(SkiaOutputSurfaceImplTest, EndPaint) {
output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
constexpr gfx::Rect output_rect(0, 0, 10, 10);
@@ -159,9 +164,10 @@ TEST_F(SkiaOutputSurfaceImplTest, SubmitPaint) {
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request));
output_surface_->SwapBuffersSkipped();
+ output_surface_->Flush();
BlockMainThread();
- // SubmitPaint draw is deferred until CopyOutput.
+ // EndPaint draw is deferred until CopyOutput.
base::OnceClosure closure =
base::BindOnce(&SkiaOutputSurfaceImplTest::CheckSyncTokenOnGpuThread,
base::Unretained(this), sync_token);
@@ -191,4 +197,82 @@ TEST_F(SkiaOutputSurfaceImplTest, SupportsColorSpaceChange) {
}
}
+// Tests that the destination color space is preserved across a CopyOutput for
+// ColorSpaces supported by SkColorSpace.
+TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapSupportedColorSpace) {
+ output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
+ gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
+
+ constexpr gfx::Rect output_rect(0, 0, 10, 10);
+ const gfx::ColorSpace color_space = gfx::ColorSpace(
+ gfx::ColorSpace::PrimaryID::BT709, gfx::ColorSpace::TransferID::LINEAR);
+ base::RunLoop run_loop;
+ std::unique_ptr<CopyOutputResult> result;
+ auto request = std::make_unique<CopyOutputRequest>(
+ CopyOutputRequest::ResultFormat::RGBA_BITMAP,
+ base::BindOnce(
+ [](std::unique_ptr<CopyOutputResult>* result_out,
+ base::OnceClosure quit_closure,
+ std::unique_ptr<CopyOutputResult> tmp_result) {
+ *result_out = std::move(tmp_result);
+ std::move(quit_closure).Run();
+ },
+ &result, run_loop.QuitClosure()));
+ request->set_result_task_runner(
+ TestGpuServiceHolder::GetInstance()->gpu_thread_task_runner());
+ copy_output::RenderPassGeometry geometry;
+ geometry.result_bounds = output_rect;
+ geometry.result_selection = output_rect;
+ geometry.sampling_bounds = output_rect;
+ geometry.readback_offset = gfx::Vector2d(0, 0);
+
+ PaintRootRenderPass(kSurfaceRect, base::DoNothing::Once());
+ output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
+ std::move(request));
+ output_surface_->SwapBuffersSkipped();
+ output_surface_->Flush();
+ run_loop.Run();
+
+ EXPECT_EQ(color_space, result->GetRGBAColorSpace());
+}
+
+// Tests that copying from a source with a color space that can't be converted
+// to a SkColorSpace will fallback to a transform to sRGB.
+TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapUnsupportedColorSpace) {
+ output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
+ gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
+
+ constexpr gfx::Rect output_rect(0, 0, 10, 10);
+ const gfx::ColorSpace color_space = gfx::ColorSpace::CreatePiecewiseHDR(
+ gfx::ColorSpace::PrimaryID::BT2020, 0.5, 1.5);
+ base::RunLoop run_loop;
+ std::unique_ptr<CopyOutputResult> result;
+ auto request = std::make_unique<CopyOutputRequest>(
+ CopyOutputRequest::ResultFormat::RGBA_BITMAP,
+ base::BindOnce(
+ [](std::unique_ptr<CopyOutputResult>* result_out,
+ base::OnceClosure quit_closure,
+ std::unique_ptr<CopyOutputResult> tmp_result) {
+ *result_out = std::move(tmp_result);
+ std::move(quit_closure).Run();
+ },
+ &result, run_loop.QuitClosure()));
+ request->set_result_task_runner(
+ TestGpuServiceHolder::GetInstance()->gpu_thread_task_runner());
+ copy_output::RenderPassGeometry geometry;
+ geometry.result_bounds = output_rect;
+ geometry.result_selection = output_rect;
+ geometry.sampling_bounds = output_rect;
+ geometry.readback_offset = gfx::Vector2d(0, 0);
+
+ PaintRootRenderPass(kSurfaceRect, base::DoNothing::Once());
+ output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
+ std::move(request));
+ output_surface_->SwapBuffersSkipped();
+ output_surface_->Flush();
+ run_loop.Run();
+
+ EXPECT_EQ(gfx::ColorSpace::CreateSRGB(), result->GetRGBAColorSpace());
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_x11.cc b/chromium/components/viz/service/display_embedder/software_output_device_x11.cc
index 8c0e1d2cf49..23ec5cdd181 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_x11.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_device_x11.cc
@@ -16,9 +16,6 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/base/x/x11_shm_image_pool.h"
#include "ui/base/x/x11_util.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/gfx/x/x11_error_tracker.h"
-#include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto_types.h"
namespace viz {
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_x11.h b/chromium/components/viz/service/display_embedder/software_output_device_x11.h
index caa0ed81bce..9277ece1ab1 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_x11.h
+++ b/chromium/components/viz/service/display_embedder/software_output_device_x11.h
@@ -12,8 +12,6 @@
#include "components/viz/service/viz_service_export.h"
#include "ui/base/x/x11_software_bitmap_presenter.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/x/x11.h"
-#include "ui/gfx/x/x11_types.h"
namespace viz {
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.cc b/chromium/components/viz/service/display_embedder/software_output_surface.cc
index 8b0cfcd0955..a00ed94229e 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.cc
@@ -147,13 +147,4 @@ void SoftwareOutputSurface::SetNeedsSwapSizeNotifications(
needs_swap_size_notifications_ = needs_swap_size_notifications;
}
#endif
-
-scoped_refptr<gpu::GpuTaskSchedulerHelper>
-SoftwareOutputSurface::GetGpuTaskSchedulerHelper() {
- return nullptr;
-}
-
-gpu::MemoryTracker* SoftwareOutputSurface::GetMemoryTracker() {
- return nullptr;
-}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.h b/chromium/components/viz/service/display_embedder/software_output_surface.h
index e9420f8ff1e..c48f40471ce 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.h
@@ -52,9 +52,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
void SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) override;
#endif
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper()
- override;
- gpu::MemoryTracker* GetMemoryTracker() override;
private:
void SwapBuffersCallback(base::TimeTicks swap_time,
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface_unittest.cc b/chromium/components/viz/service/display_embedder/software_output_surface_unittest.cc
index d83f1f327f7..c6ff42bcc58 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_surface_unittest.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "cc/test/fake_output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
index bb1e572d4f1..c623fc05fba 100644
--- a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -21,6 +21,7 @@
#include "components/viz/common/gpu/context_lost_reason.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/viz_utils.h"
+#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_cmd_helper.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
@@ -113,12 +114,13 @@ VizProcessContextProvider::VizProcessContextProvider(
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const RendererSettings& renderer_settings)
: attributes_(CreateAttributes(renderer_settings.requires_alpha_channel,
renderer_settings)) {
InitializeContext(std::move(task_executor), surface_handle,
gpu_memory_buffer_manager, image_factory,
- gpu_channel_manager_delegate,
+ gpu_channel_manager_delegate, display_controller,
SharedMemoryLimitsForRendererSettings(renderer_settings));
if (context_result_ == gpu::ContextResult::kSuccess) {
@@ -242,11 +244,12 @@ void VizProcessContextProvider::InitializeContext(
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const gpu::SharedMemoryLimits& mem_limits) {
const bool is_offscreen = surface_handle == gpu::kNullSurfaceHandle;
+ DCHECK(display_controller);
+ gpu_task_scheduler_helper_ = display_controller->gpu_task_scheduler();
- gpu_task_scheduler_helper_ =
- base::MakeRefCounted<gpu::GpuTaskSchedulerHelper>(task_executor);
command_buffer_ = std::make_unique<gpu::InProcessCommandBuffer>(
task_executor,
GURL("chrome://gpu/VizProcessContextProvider::InitializeContext"));
@@ -254,7 +257,8 @@ void VizProcessContextProvider::InitializeContext(
/*surface=*/nullptr, is_offscreen, surface_handle, attributes_,
gpu_memory_buffer_manager, image_factory, gpu_channel_manager_delegate,
base::ThreadTaskRunnerHandle::Get(),
- gpu_task_scheduler_helper_->GetTaskSequence(), nullptr, nullptr);
+ gpu_task_scheduler_helper_->GetTaskSequence(),
+ display_controller->controller_on_gpu(), nullptr, nullptr);
if (context_result_ != gpu::ContextResult::kSuccess) {
DLOG(ERROR) << "Failed to initialize InProcessCommmandBuffer";
return;
@@ -269,7 +273,8 @@ void VizProcessContextProvider::InitializeContext(
return;
}
- gpu_task_scheduler_helper_->Initialize(gles2_helper_.get());
+ if (gpu_task_scheduler_helper_)
+ gpu_task_scheduler_helper_->Initialize(gles2_helper_.get());
transfer_buffer_ = std::make_unique<gpu::TransferBuffer>(gles2_helper_.get());
@@ -334,19 +339,6 @@ base::ScopedClosureRunner VizProcessContextProvider::GetCacheBackBufferCb() {
return command_buffer_->GetCacheBackBufferCb();
}
-scoped_refptr<gpu::GpuTaskSchedulerHelper>
-VizProcessContextProvider::GetGpuTaskSchedulerHelper() {
- return gpu_task_scheduler_helper_;
-}
-
-gpu::SharedImageManager* VizProcessContextProvider::GetSharedImageManager() {
- return command_buffer_->GetSharedImageManager();
-}
-
-gpu::MemoryTracker* VizProcessContextProvider::GetMemoryTracker() {
- return command_buffer_->GetMemoryTracker();
-}
-
void VizProcessContextProvider::SetNeedsMeasureNextDrawLatency() {
return command_buffer_->SetNeedsMeasureNextDrawLatency();
}
diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.h b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
index 63982bcf300..065ec673b0d 100644
--- a/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
+++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
@@ -44,6 +44,7 @@ class GrContextForGLES2Interface;
namespace viz {
class ContextLostObserver;
+class DisplayCompositorMemoryAndTaskController;
class GpuTaskSchedulerHelper;
class RendererSettings;
@@ -60,6 +61,7 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const RendererSettings& renderer_settings);
// ContextProvider implementation.
@@ -76,8 +78,6 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
void AddObserver(ContextLostObserver* obs) override;
void RemoveObserver(ContextLostObserver* obs) override;
- gpu::SharedImageManager* GetSharedImageManager() override;
- gpu::MemoryTracker* GetMemoryTracker() override;
virtual void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback);
@@ -91,8 +91,6 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
virtual base::ScopedClosureRunner GetCacheBackBufferCb();
- scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper();
-
void SetNeedsMeasureNextDrawLatency();
protected:
@@ -107,6 +105,7 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
+ DisplayCompositorMemoryAndTaskController* display_controller,
const gpu::SharedMemoryLimits& mem_limits);
void OnContextLost();
@@ -118,7 +117,7 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
// The |gpu_task_scheduler_helper_| has 1:1 relationship with the Display
// compositor.
- scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_helper_;
+ gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_helper_;
std::unique_ptr<gpu::InProcessCommandBuffer> command_buffer_;
std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
index 085ce1e8c98..39b59f406e5 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "ui/gfx/overlay_transform.h"
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 7e10b2b6e5a..e677ecec15c 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -5,6 +5,7 @@
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include <algorithm>
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -26,26 +27,8 @@
namespace viz {
namespace {
-// These values are logged to UMA. Entries should not be renumbered and numeric
-// values should never be reused. Please keep in sync with
-// "SendBeginFrameResult" in src/tools/metrics/histograms/enums.xml.
-enum class SendBeginFrameResult {
- kSendFrameTiming = 0,
- kStopNotRequest = 1,
- kStopUnresponsiveClient = 2,
- kThrottleUnresponsiveClient = 3,
- kSendNoActiveSurface = 4,
- kSendBlockedEmbedded = 5,
- kThrottleUndrawnFrames = 6,
- kSendDefault = 7,
- kThrottleAsRequested = 8,
- kMaxValue = kThrottleAsRequested
-};
-
-void RecordShouldSendBeginFrame(SendBeginFrameResult result) {
- TRACE_EVENT1("viz", "ShouldNotSendBeginFrame", "reason", result);
- UMA_HISTOGRAM_ENUMERATION(
- "Compositing.CompositorFrameSinkSupport.ShouldSendBeginFrame", result);
+void RecordShouldSendBeginFrame(const std::string& reason) {
+ TRACE_EVENT1("viz", "ShouldNotSendBeginFrame", "reason", reason);
}
void AdjustPresentationFeedback(gfx::PresentationFeedback* feedback,
@@ -704,6 +687,10 @@ void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) {
last_begin_frame_args_ = args;
BeginFrameArgs copy_args = args;
+ // Force full frame if surface not yet activated to ensure surface creation.
+ if (!last_activated_surface_id_.is_valid())
+ copy_args.animate_only = false;
+
copy_args.trace_id = ComputeTraceId();
TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
TRACE_ID_GLOBAL(copy_args.trace_id),
@@ -853,43 +840,42 @@ bool CompositorFrameSinkSupport::ShouldSendBeginFrame(
// If there are pending timing details from the previous frame(s),
// then the client needs to receive the begin-frame.
if (!frame_timing_details_.empty() && !should_throttle_as_requested) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kSendFrameTiming);
+ RecordShouldSendBeginFrame("SendFrameTiming");
return true;
}
if (!client_needs_begin_frame_) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kStopNotRequest);
+ RecordShouldSendBeginFrame("StopNotRequested");
return false;
}
// Stop sending BeginFrames to clients that are totally unresponsive.
if (begin_frame_tracker_.ShouldStopBeginFrame()) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kStopUnresponsiveClient);
+ RecordShouldSendBeginFrame("StopUnresponsiveClient");
return false;
}
// Throttle clients that are unresponsive.
if (can_throttle_if_unresponsive_or_excessive &&
begin_frame_tracker_.ShouldThrottleBeginFrame()) {
- RecordShouldSendBeginFrame(
- SendBeginFrameResult::kThrottleUnresponsiveClient);
+ RecordShouldSendBeginFrame("ThrottleUnresponsiveClient");
return false;
}
if (!last_activated_surface_id_.is_valid()) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kSendNoActiveSurface);
+ RecordShouldSendBeginFrame("SendNoActiveSurface");
return true;
}
// We should never throttle BeginFrames if there is another client waiting for
// this client to submit a frame.
if (surface_manager_->HasBlockedEmbedder(frame_sink_id_)) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kSendBlockedEmbedded);
+ RecordShouldSendBeginFrame("SendBlockedEmbedded");
return true;
}
if (should_throttle_as_requested) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kThrottleAsRequested);
+ RecordShouldSendBeginFrame("ThrottleRequested");
return false;
}
@@ -910,12 +896,12 @@ bool CompositorFrameSinkSupport::ShouldSendBeginFrame(
uint64_t num_undrawn_frames = active_frame_index - last_drawn_frame_index_;
if (can_throttle_if_unresponsive_or_excessive &&
num_undrawn_frames > kUndrawnFrameLimit) {
- RecordShouldSendBeginFrame(SendBeginFrameResult::kThrottleUndrawnFrames);
+ RecordShouldSendBeginFrame("ThrottleUndrawnFrames");
return false;
}
// No other conditions apply so send the begin frame.
- RecordShouldSendBeginFrame(SendBeginFrameResult::kSendDefault);
+ RecordShouldSendBeginFrame("SendDefault");
return true;
}
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 4b39b205b77..62b75548a3c 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -4,6 +4,8 @@
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/test/simple_test_tick_clock.h"
@@ -1505,4 +1507,32 @@ TEST_F(CompositorFrameSinkSupportTest, BeginFrameInterval) {
EXPECT_EQ(sent_frames, 10);
support->SetNeedsBeginFrame(false);
}
+
+TEST_F(CompositorFrameSinkSupportTest, ForceFullFrameToActivateSurface) {
+ FakeExternalBeginFrameSource begin_frame_source(0.f, false);
+ testing::NiceMock<MockCompositorFrameSinkClient> mock_client;
+ auto support = std::make_unique<CompositorFrameSinkSupport>(
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, /*is_root=*/true);
+ SurfaceId id(kAnotherArbitraryFrameSinkId, local_surface_id_);
+ support->SetBeginFrameSource(&begin_frame_source);
+ support->SetNeedsBeginFrame(true);
+ const base::TimeTicks frame_time;
+ const int64_t sequence_number = 1;
+
+ // ComposterFrameSink hasn't had a surface activate yet.
+ EXPECT_FALSE(support->last_activated_surface_id().is_valid());
+
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 0, sequence_number, frame_time);
+ EXPECT_FALSE(args.animate_only);
+ BeginFrameArgs args_animate_only = args;
+ args_animate_only.animate_only = true;
+ // Verify |animate_only| is toggled back to false before sending to client.
+ EXPECT_CALL(mock_client,
+ OnBeginFrame(testing::Field(&BeginFrameArgs::animate_only,
+ testing::IsFalse()),
+ _));
+ begin_frame_source.TestOnBeginFrame(args_animate_only);
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
index 911e1f03a48..d0d355874d9 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
@@ -4,6 +4,8 @@
#include "components/viz/service/frame_sinks/external_begin_frame_source_mojo.h"
+#include <utility>
+
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
namespace viz {
@@ -89,6 +91,10 @@ void ExternalBeginFrameSourceMojo::MaybeProduceFrameCallback() {
BeginFrameAck nak(last_begin_frame_args_.frame_id.source_id,
last_begin_frame_args_.frame_id.sequence_number,
/*has_damage=*/false);
+ // Prevent missing begin frames from being sent to sinks that came late,
+ // as this may result in two overlapping frames being sent, which is not
+ // supported with full pipeline mode.
+ last_begin_frame_args_ = BeginFrameArgs();
std::move(pending_frame_callback_).Run(nak);
}
@@ -97,6 +103,10 @@ void ExternalBeginFrameSourceMojo::OnDisplayDidFinishFrame(
if (!pending_frame_callback_)
return;
std::move(pending_frame_callback_).Run(ack);
+ // If there are pending copy output requests that have not been fulfilled,
+ // cancel them, as they won't be served till the next frame. This prevents
+ // the client for waiting for them indefinitely.
+ frame_sink_manager_->DiscardPendingCopyOfOutputRequests(this);
}
void ExternalBeginFrameSourceMojo::OnDisplayDestroyed() {
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index e08fb708be0..892734af816 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -41,9 +41,11 @@ RootCompositorFrameSinkImpl::Create(
// First create an output surface.
mojo::Remote<mojom::DisplayClient> display_client(
std::move(params->display_client));
+ auto display_controller = output_surface_provider->CreateGpuDependency(
+ params->gpu_compositing, params->widget, params->renderer_settings);
auto output_surface = output_surface_provider->CreateOutputSurface(
params->widget, params->gpu_compositing, display_client.get(),
- params->renderer_settings, debug_settings);
+ display_controller.get(), params->renderer_settings, debug_settings);
// Creating output surface failed. The host can send a new request, possibly
// with a different compositing mode.
@@ -127,16 +129,22 @@ RootCompositorFrameSinkImpl::Create(
#if !defined(OS_APPLE)
auto* output_surface_ptr = output_surface.get();
#endif
+ gpu::SharedImageInterface* sii = nullptr;
+ if (output_surface->context_provider())
+ sii = output_surface->context_provider()->SharedImageInterface();
+ else if (display_controller)
+ sii = display_controller->shared_image_interface();
auto overlay_processor = OverlayProcessorInterface::CreateOverlayProcessor(
- output_surface.get(), output_surface_provider->GetSharedImageManager(),
- params->renderer_settings, debug_settings);
+ output_surface.get(), output_surface->GetSurfaceHandle(),
+ output_surface->capabilities(),
+ display_controller.get(), sii, params->renderer_settings, debug_settings);
auto display = std::make_unique<Display>(
frame_sink_manager->shared_bitmap_manager(), params->renderer_settings,
- debug_settings, params->frame_sink_id, std::move(output_surface),
- std::move(overlay_processor), std::move(scheduler),
- std::move(task_runner));
+ debug_settings, params->frame_sink_id, std::move(display_controller),
+ std::move(output_surface), std::move(overlay_processor),
+ std::move(scheduler), std::move(task_runner));
if (external_begin_frame_source_mojo)
external_begin_frame_source_mojo->SetDisplay(display.get());
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 037d3cbea16..d5a57391ff8 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -9,8 +9,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h b/chromium/components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h
index 6aa989ffe01..bd8a65704e8 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h
@@ -15,7 +15,7 @@ namespace viz {
// Represents an in-flight frame delivery to the consumer. Its main purpose is
// to proxy callbacks from the consumer back to the relevant capturer
// components owned and operated by FrameSinkVideoCapturerImpl.
-class VIZ_SERVICE_EXPORT InFlightFrameDelivery
+class VIZ_SERVICE_EXPORT InFlightFrameDelivery final
: public mojom::FrameSinkVideoConsumerFrameCallbacks {
public:
InFlightFrameDelivery(
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
index 419d97d9f39..2b12ce9a955 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
using media::VideoFrame;
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
index e88e371f266..62e34785048 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
@@ -47,7 +47,7 @@ namespace viz {
//
// The blit algorithm uses naive linear blending. Thus, the use of non-linear
// color spaces will cause loses in color accuracy.
-class VIZ_SERVICE_EXPORT VideoCaptureOverlay
+class VIZ_SERVICE_EXPORT VideoCaptureOverlay final
: public mojom::FrameSinkVideoCaptureOverlay {
public:
// Interface for notifying the frame source when changes to the overlay's
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
index 3f288ed5969..33a1f3fb10a 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
@@ -98,7 +98,7 @@ class VideoCaptureOverlayTest : public testing::Test {
kTestImageSize.width(), kTestImageSize.height(),
GetLinearSRGB().ToSkColorSpace());
CHECK(result.tryAllocPixels(info, info.minRowBytes()));
- SkCanvas canvas(result);
+ SkCanvas canvas(result, SkSurfaceProps{});
canvas.drawColor(kTestImageBackground);
for (size_t i = 0; i < base::size(kTestImageColors); ++i) {
const size_t idx = (i + cycle) % base::size(kTestImageColors);
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
index 18ca4eb45ed..be829266a98 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -325,7 +325,7 @@ GpuServiceImpl::GpuServiceImpl(
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
- const gpu::GpuExtraInfo& gpu_extra_info,
+ const gfx::GpuExtraInfo& gpu_extra_info,
gpu::VulkanImplementation* vulkan_implementation,
base::OnceCallback<void(base::Optional<ExitCode>)> exit_callback)
: main_runner_(base::ThreadTaskRunnerHandle::Get()),
@@ -368,7 +368,8 @@ GpuServiceImpl::GpuServiceImpl(
// If GL is using a real GPU, the gpu_info will be passed in and vulkan will
// use the same GPU.
vulkan_context_provider_ = VulkanInProcessContextProvider::Create(
- vulkan_implementation_, context_options,
+ vulkan_implementation_, gpu_preferences_.vulkan_heap_memory_limit,
+ gpu_preferences_.vulkan_sync_cpu_memory_limit,
(is_native_vulkan && is_native_gl) ? &gpu_info : nullptr);
if (vulkan_context_provider_) {
// If Vulkan is supported, then OOP-R is supported.
@@ -394,10 +395,10 @@ GpuServiceImpl::GpuServiceImpl(
}
#endif
-#if BUILDFLAG(USE_VAAPI)
+#if BUILDFLAG(USE_VAAPI_IMAGE_CODECS)
image_decode_accelerator_worker_ =
media::VaapiImageDecodeAcceleratorWorker::Create();
-#endif
+#endif // BUILDFLAG(USE_VAAPI_IMAGE_CODECS)
#if defined(OS_APPLE)
if (gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_METAL] ==
@@ -1018,6 +1019,19 @@ void GpuServiceImpl::DisplayRemoved() {
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayRemoved();
}
+void GpuServiceImpl::DisplayMetricsChanged() {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&GpuServiceImpl::DisplayMetricsChanged, weak_ptr_));
+ return;
+ }
+ DVLOG(1) << "GPU: Display Metrics changed";
+
+ if (!in_host_process())
+ ui::GpuSwitchingManager::GetInstance()->NotifyDisplayMetricsChanged();
+}
+
void GpuServiceImpl::DestroyAllChannels() {
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
index 3e3a6e93e5d..d861c8a98e3 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -23,7 +23,6 @@
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/command_buffer/common/activity_flags.h"
#include "gpu/command_buffer/service/sequence_id.h"
-#include "gpu/config/gpu_extra_info.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/ipc/common/surface_handle.h"
@@ -41,6 +40,7 @@
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
#include "skia/buildflags.h"
#include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/gpu_extra_info.h"
#include "ui/gfx/native_widget_types.h"
#if defined(OS_CHROMEOS)
@@ -95,7 +95,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
const base::Optional<gpu::GpuFeatureInfo>&
gpu_feature_info_for_hardware_gpu,
- const gpu::GpuExtraInfo& gpu_extra_info,
+ const gfx::GpuExtraInfo& gpu_extra_info,
gpu::VulkanImplementation* vulkan_implementation,
base::OnceCallback<void(base::Optional<ExitCode>)> exit_callback);
@@ -175,6 +175,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
void DisplayAdded() override;
void DisplayRemoved() override;
+ void DisplayMetricsChanged() override;
void DestroyAllChannels() override;
void OnBackgroundCleanup() override;
void OnBackgrounded() override;
@@ -372,7 +373,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
base::Optional<gpu::GpuFeatureInfo> gpu_feature_info_for_hardware_gpu_;
// Information about the GPU process populated on creation.
- gpu::GpuExtraInfo gpu_extra_info_;
+ gfx::GpuExtraInfo gpu_extra_info_;
mojo::SharedRemote<mojom::GpuHost> gpu_host_;
std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
diff --git a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
index 72ec7d5d9f2..b156a42c1e1 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -5,10 +5,11 @@
#include "components/viz/service/gl/gpu_service_impl.h"
#include <memory>
+#include <utility>
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
@@ -72,7 +73,7 @@ class GpuServiceTest : public testing::Test {
gpu_service_ = std::make_unique<GpuServiceImpl>(
gpu_info, /*watchdog_thread=*/nullptr, io_thread_.task_runner(),
gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(),
- gpu::GpuFeatureInfo(), gpu::GpuExtraInfo(),
+ gpu::GpuFeatureInfo(), gfx::GpuExtraInfo(),
/*vulkan_implementation=*/nullptr,
/*exit_callback=*/base::DoNothing());
}
diff --git a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
index f72d981d39c..90c31ab7673 100644
--- a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
@@ -61,8 +61,6 @@ void InfoCollectionGpuServiceImpl::
DCHECK(main_runner_->BelongsToCurrentThread());
uint32_t d3d12_feature_level = gpu::GetGpuSupportedD3D12Version();
- gpu::RecordGpuSupportedDx12VersionHistograms(d3d12_feature_level);
-
io_runner_->PostTask(FROM_HERE,
base::BindOnce(std::move(callback), d3d12_feature_level,
device_perf_info_));
diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc
index 9db285f4657..ab67d65ffa8 100644
--- a/chromium/components/viz/service/main/viz_main_impl.cc
+++ b/chromium/components/viz/service/main/viz_main_impl.cc
@@ -23,7 +23,7 @@
#include "media/gpu/buildflags.h"
#include "services/metrics/public/cpp/delegating_ukm_recorder.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
-#include "third_party/skia/include/core/SkFontLCDConfig.h"
+#include "skia/ext/legacy_display_globals.h"
namespace {
@@ -159,18 +159,15 @@ void VizMainImpl::CreateGpuService(
if (!gpu_init_->gpu_info().in_process_gpu) {
// If the GPU is running in the browser process, discardable memory manager
// has already been initialized.
- discardable_shared_memory_manager_ = std::make_unique<
+ discardable_shared_memory_manager_ = base::MakeRefCounted<
discardable_memory::ClientDiscardableSharedMemoryManager>(
std::move(discardable_memory_manager), io_task_runner());
base::DiscardableMemoryAllocator::SetInstance(
discardable_shared_memory_manager_.get());
}
- SkFontLCDConfig::SetSubpixelOrder(
- gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrder(
- subpixel_rendering));
- SkFontLCDConfig::SetSubpixelOrientation(
- gfx::FontRenderParams::SubpixelRenderingToSkiaLCDOrientation(
+ skia::LegacyDisplayGlobals::SetCachedPixelGeometry(
+ gfx::FontRenderParams::SubpixelRenderingToSkiaPixelGeometry(
subpixel_rendering));
gpu_service_->Bind(std::move(pending_receiver));
diff --git a/chromium/components/viz/service/main/viz_main_impl.h b/chromium/components/viz/service/main/viz_main_impl.h
index a0ab8317e86..429ce855725 100644
--- a/chromium/components/viz/service/main/viz_main_impl.h
+++ b/chromium/components/viz/service/main/viz_main_impl.h
@@ -190,7 +190,7 @@ class VizMainImpl : public mojom::VizMain,
mojo::AssociatedReceiver<mojom::VizMain> receiver_{this};
- std::unique_ptr<discardable_memory::ClientDiscardableSharedMemoryManager>
+ scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
discardable_shared_memory_manager_;
DISALLOW_COPY_AND_ASSIGN(VizMainImpl);
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
index ee714008b28..e193c56283c 100644
--- a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
+++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -4,7 +4,6 @@
#include "components/viz/service/surfaces/surface_dependency_deadline.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/tick_clock.h"
#include "components/viz/common/quads/frame_deadline.h"
@@ -38,12 +37,7 @@ base::Optional<base::TimeDelta> SurfaceDependencyDeadline::Cancel() {
deadline_.reset();
- base::TimeDelta duration = tick_clock_->NowTicks() - start_time_;
-
- UMA_HISTOGRAM_TIMES("Compositing.SurfaceDependencyDeadline.Duration",
- duration);
-
- return duration;
+ return tick_clock_->NowTicks() - start_time_;
}
bool SurfaceDependencyDeadline::operator==(
diff --git a/chromium/components/viz/service/surfaces/surface_manager.cc b/chromium/components/viz/service/surfaces/surface_manager.cc
index 322850335ed..df98c598915 100644
--- a/chromium/components/viz/service/surfaces/surface_manager.cc
+++ b/chromium/components/viz/service/surfaces/surface_manager.cc
@@ -13,7 +13,6 @@
#include "base/containers/adapters.h"
#include "base/containers/queue.h"
#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
@@ -30,8 +29,6 @@
namespace viz {
namespace {
-const char kUmaAliveSurfaces[] = "Compositing.SurfaceManager.AliveSurfaces";
-
constexpr base::TimeDelta kExpireInterval = base::TimeDelta::FromSeconds(10);
} // namespace
@@ -185,11 +182,6 @@ void SurfaceManager::GarbageCollectSurfaces() {
}
SurfaceIdSet reachable_surfaces = GetLiveSurfaces();
-
- // Log the number of reachable surfaces after a garbage collection.
- UMA_HISTOGRAM_CUSTOM_COUNTS(kUmaAliveSurfaces, reachable_surfaces.size(), 1,
- 200, 50);
-
std::vector<SurfaceId> surfaces_to_delete;
// Delete all destroyed and unreachable surfaces.
diff --git a/chromium/components/web_package/mojom/web_bundle_parser.mojom b/chromium/components/web_package/mojom/web_bundle_parser.mojom
index ce98234a92e..de205988c29 100644
--- a/chromium/components/web_package/mojom/web_bundle_parser.mojom
+++ b/chromium/components/web_package/mojom/web_bundle_parser.mojom
@@ -4,7 +4,7 @@
module web_package.mojom;
-import "mojo/public/mojom/base/file.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
import "url/mojom/url.mojom";
// Factory interface to create WebBundleParser for the passed |file|
@@ -12,7 +12,7 @@ import "url/mojom/url.mojom";
interface WebBundleParserFactory {
// Constructs a parser for the passed |file|.
GetParserForFile(pending_receiver<WebBundleParser> receiver,
- mojo_base.mojom.File file);
+ mojo_base.mojom.ReadOnlyFile file);
// Constructs a parser for the passed |data_source|.
GetParserForDataSource(pending_receiver<WebBundleParser> receiver,
diff --git a/chromium/components/web_package/web_bundle_parser.cc b/chromium/components/web_package/web_bundle_parser.cc
index 66fcc324bba..3fa0edd1fad 100644
--- a/chromium/components/web_package/web_bundle_parser.cc
+++ b/chromium/components/web_package/web_bundle_parser.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include "base/big_endian.h"
-#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/containers/span.h"
#include "base/memory/weak_ptr.h"
#include "base/numerics/checked_math.h"
diff --git a/chromium/components/web_package/web_bundle_parser_factory.cc b/chromium/components/web_package/web_bundle_parser_factory.cc
index 8041050f976..1a1a276e27d 100644
--- a/chromium/components/web_package/web_bundle_parser_factory.cc
+++ b/chromium/components/web_package/web_bundle_parser_factory.cc
@@ -4,7 +4,7 @@
#include "components/web_package/web_bundle_parser_factory.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "components/web_package/web_bundle_parser.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/http_util.h"
diff --git a/chromium/components/web_package/web_bundle_parser_factory_unittest.cc b/chromium/components/web_package/web_bundle_parser_factory_unittest.cc
index d16db82ad95..9a0d3fd507f 100644
--- a/chromium/components/web_package/web_bundle_parser_factory_unittest.cc
+++ b/chromium/components/web_package/web_bundle_parser_factory_unittest.cc
@@ -9,7 +9,7 @@
#include "base/optional.h"
#include "base/path_service.h"
#include "base/run_loop.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/chromium/components/web_package/web_bundle_parser_unittest.cc b/chromium/components/web_package/web_bundle_parser_unittest.cc
index 1af812773b1..d73fa039645 100644
--- a/chromium/components/web_package/web_bundle_parser_unittest.cc
+++ b/chromium/components/web_package/web_bundle_parser_unittest.cc
@@ -8,7 +8,7 @@
#include "base/files/file_util.h"
#include "base/optional.h"
#include "base/path_service.h"
-#include "base/test/bind_test_util.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/cbor/writer.h"
#include "components/web_package/test_support/web_bundle_builder.h"
diff --git a/chromium/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java b/chromium/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
index ae8dd111ebc..ec25a7c5204 100644
--- a/chromium/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
+++ b/chromium/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
@@ -177,10 +177,16 @@ public class WebApkValidator {
*/
@SuppressLint("PackageManagerGetSignatures")
public static boolean isValidWebApk(Context context, String webappPackageName) {
+ if (sOverrideValidationForTesting) {
+ if (DEBUG) {
+ Log.d(TAG, "WebApk validation is disabled for testing.");
+ }
+ return true;
+ }
if (sExpectedSignature == null || sCommentSignedPublicKeyBytes == null) {
Log.wtf(TAG,
- "WebApk validation failure - expected signature not set."
- + "missing call to WebApkValidator.initWithBrowserHostSignature");
+ "WebApk validation failure - expected signature not set - "
+ + "missing call to WebApkValidator.init");
return false;
}
PackageInfo packageInfo;
@@ -194,12 +200,6 @@ public class WebApkValidator {
}
return false;
}
- if (sOverrideValidationForTesting) {
- if (DEBUG) {
- Log.d(TAG, "WebApk validation is disabled for testing.");
- }
- return true;
- }
if (isNotWebApkQuick(packageInfo)) {
return false;
}
@@ -364,6 +364,7 @@ public class WebApkValidator {
* @param manifestUrl The URL of the manifest that was used to generate the WebAPK.
* @return The WebAPK's package name if installed, or null otherwise.
*/
+ @SuppressWarnings("QueryPermissionsNeeded")
public static @Nullable String queryBoundWebApkForManifestUrl(
Context context, String manifestUrl) {
assert manifestUrl != null;
diff --git a/chromium/components/webcrypto/OWNERS b/chromium/components/webcrypto/OWNERS
index c37bd553cc6..36ea0ea81a3 100644
--- a/chromium/components/webcrypto/OWNERS
+++ b/chromium/components/webcrypto/OWNERS
@@ -1,4 +1,3 @@
-eroman@chromium.org
rsleevi@chromium.org
# COMPONENT: Blink>WebCrypto
diff --git a/chromium/components/webcrypto/jwk.cc b/chromium/components/webcrypto/jwk.cc
index 5abc8308e0b..a7700982622 100644
--- a/chromium/components/webcrypto/jwk.cc
+++ b/chromium/components/webcrypto/jwk.cc
@@ -37,11 +37,19 @@ namespace webcrypto {
namespace {
-// Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
+// |kJwkEncUsage| and |kJwkSigUsage| are a superset of the possible meanings of
+// JWK's {"use":"enc"}, and {"use":"sig"} respectively.
+//
+// TODO(https://crbug.com/1136147): Remove these masks,
+// as they are not consistent with the Web Crypto
+// processing model for JWK. In particular,
+// intersecting the usages after processing the JWK
+// means Chrome can fail with a Syntax error in cases
+// where the spec describes a Data error.
const blink::WebCryptoKeyUsageMask kJwkEncUsage =
blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt |
- blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey;
-// Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
+ blink::kWebCryptoKeyUsageWrapKey | blink::kWebCryptoKeyUsageUnwrapKey |
+ blink::kWebCryptoKeyUsageDeriveKey | blink::kWebCryptoKeyUsageDeriveBits;
const blink::WebCryptoKeyUsageMask kJwkSigUsage =
blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify;
diff --git a/chromium/components/webdata/common/web_database.cc b/chromium/components/webdata/common/web_database.cc
index 06fa771a610..bc2eb0ce750 100644
--- a/chromium/components/webdata/common/web_database.cc
+++ b/chromium/components/webdata/common/web_database.cc
@@ -48,7 +48,18 @@ sql::InitStatus FailedMigrationTo(int version_num) {
} // namespace
-WebDatabase::WebDatabase() {}
+WebDatabase::WebDatabase()
+ : db_({// Run the database in exclusive mode. Nobody else should be
+ // accessing the database while we're running, and this will give
+ // somewhat improved perf.
+ .exclusive_locking = true,
+ // We don't store that much data in the tables so use a small page
+ // size. This provides a large benefit for empty tables (which is
+ // very likely with the tables we create).
+ .page_size = 2048,
+ // We shouldn't have much data and what access we currently have is
+ // quite infrequent. So we go with a small cache size.
+ .cache_size = 32}) {}
WebDatabase::~WebDatabase() {}
@@ -80,19 +91,6 @@ sql::Database* WebDatabase::GetSQLConnection() {
sql::InitStatus WebDatabase::Init(const base::FilePath& db_name) {
db_.set_histogram_tag("Web");
- // We don't store that much data in the tables so use a small page size.
- // This provides a large benefit for empty tables (which is very likely with
- // the tables we create).
- db_.set_page_size(2048);
-
- // We shouldn't have much data and what access we currently have is quite
- // infrequent. So we go with a small cache size.
- db_.set_cache_size(32);
-
- // Run the database in exclusive mode. Nobody else should be accessing the
- // database while we're running, and this will give somewhat improved perf.
- db_.set_exclusive_locking();
-
if ((db_name.value() == kInMemoryPath) ? !db_.OpenInMemory()
: !db_.Open(db_name)) {
return sql::INIT_FAILURE;
diff --git a/chromium/components/webdata_services/web_data_service_wrapper_unittest.cc b/chromium/components/webdata_services/web_data_service_wrapper_unittest.cc
index 77a6422ddee..4047bde2f73 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper_unittest.cc
+++ b/chromium/components/webdata_services/web_data_service_wrapper_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
diff --git a/chromium/components/webrtc/media_stream_devices_controller.cc b/chromium/components/webrtc/media_stream_devices_controller.cc
index 7f1528bc117..c08c125c3de 100644
--- a/chromium/components/webrtc/media_stream_devices_controller.cc
+++ b/chromium/components/webrtc/media_stream_devices_controller.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/bind.h"
-#include "base/metrics/histogram_functions.h"
#include "components/permissions/permission_manager.h"
#include "components/permissions/permission_result.h"
#include "components/permissions/permissions_client.h"
@@ -113,15 +112,13 @@ void MediaStreamDevicesController::RequestPermissions(
will_prompt_for_video =
permission_status.content_setting == CONTENT_SETTING_ASK;
- bool has_pan_tilt_zoom_camera = controller->HasAvailableDevices(
- ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
- request.requested_video_device_id);
- base::UmaHistogramBoolean("WebRTC.MediaStreamDevices.HasPanTiltZoomCamera",
- has_pan_tilt_zoom_camera);
- // Request CAMERA_PAN_TILT_ZOOM only if the the website requested
- // the pan-tilt-zoom permission and there are suitable PTZ capable devices
+ // Request CAMERA_PAN_TILT_ZOOM only if the website requested the
+ // pan-tilt-zoom permission and there are suitable PTZ capable devices
// available.
- if (request.request_pan_tilt_zoom_permission && has_pan_tilt_zoom_camera) {
+ if (request.request_pan_tilt_zoom_permission &&
+ controller->HasAvailableDevices(
+ ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
+ request.requested_video_device_id)) {
permissions::PermissionResult permission_status =
permission_manager->GetPermissionStatusForFrame(
ContentSettingsType::CAMERA_PAN_TILT_ZOOM, rfh,
diff --git a/chromium/components/webxr/OWNERS b/chromium/components/webxr/OWNERS
index 0890a7e8601..ef5e6260ba2 100644
--- a/chromium/components/webxr/OWNERS
+++ b/chromium/components/webxr/OWNERS
@@ -2,4 +2,4 @@ alcooper@chromium.org
bialpio@chromium.org
# TEAM: xr-dev@chromium.org
-# COMPONENT: Blink>WebXR
+# COMPONENT: Internals>XR
diff --git a/chromium/components/webxr/android/BUILD.gn b/chromium/components/webxr/android/BUILD.gn
new file mode 100644
index 00000000000..b97b8db0d14
--- /dev/null
+++ b/chromium/components/webxr/android/BUILD.gn
@@ -0,0 +1,127 @@
+# Copyright 2020 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("//build/config/android/rules.gni")
+import("//device/vr/buildflags/buildflags.gni")
+
+source_set("android_utils") {
+ sources = [
+ "webxr_utils.cc",
+ "webxr_utils.h",
+ ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ ]
+}
+
+source_set("android") {
+ sources = [
+ "ar_compositor_delegate_provider.cc",
+ "ar_compositor_delegate_provider.h",
+ "xr_install_helper_delegate.h",
+ "xr_install_infobar.cc",
+ "xr_install_infobar.h",
+ ]
+
+ if (enable_arcore) {
+ sources += [
+ "arcore_install_helper.cc",
+ "arcore_install_helper.h",
+ "arcore_java_utils.cc",
+ "arcore_java_utils.h",
+ ]
+ }
+
+ deps = [
+ ":android_utils",
+ "//base",
+ "//components/infobars/core",
+ "//components/resources:android_resources",
+ "//components/strings",
+ "//content/public/browser",
+ "//ui/base",
+ ]
+
+ if (enable_arcore) {
+ deps += [
+ ":ar_jni_headers",
+ "//device/vr/android/arcore:arcore",
+ ]
+ }
+
+ libs = [ "android" ]
+}
+
+android_library("ar_java_interfaces") {
+ sources = [
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCompositorDelegate.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCompositorDelegateProvider.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArDelegate.java",
+ ]
+
+ deps = [
+ "//content/public/android:content_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ ]
+}
+
+android_library("ar_java_base") {
+ deps = [
+ ":ar_java_base_resources",
+ ":ar_java_interfaces",
+ ":webxr_android_enums_java",
+ "//base:base_java",
+ "//base:jni_java",
+ "//content/public/android:content_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
+ "//ui/android:ui_java",
+ ]
+
+ sources = [
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreInstallUtils.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreJavaUtils.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreShim.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArImmersiveOverlay.java",
+ ]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ resources_package = "org.chromium.components.webxr"
+}
+
+android_resources("ar_java_base_resources") {
+ deps = [ "//components/browser_ui/strings/android:browser_ui_strings_grd" ]
+}
+
+android_library("ar_java") {
+ deps = [
+ ":ar_java_base",
+ ":webxr_android_enums_java",
+ "//base:base_java",
+ "//third_party/arcore-android-sdk-client:com_google_ar_core_java",
+ ]
+
+ sources = [ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreShimImpl.java" ]
+}
+
+if (enable_arcore) {
+ generate_jni("ar_jni_headers") {
+ sources = [
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreInstallUtils.java",
+ "//components/webxr/android/java/src/org/chromium/components/webxr/ArCoreJavaUtils.java",
+ ]
+ }
+}
+
+java_cpp_enum("webxr_android_enums") {
+ sources = [ "arcore_install_helper.h" ]
+}
+
+android_library("webxr_android_enums_java") {
+ deps = [ "//third_party/android_deps:androidx_annotation_annotation_java" ]
+
+ srcjar_deps = [ ":webxr_android_enums" ]
+}
diff --git a/chromium/components/webxr/android/DEPS b/chromium/components/webxr/android/DEPS
new file mode 100644
index 00000000000..456c6841f3a
--- /dev/null
+++ b/chromium/components/webxr/android/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+components/infobars",
+ "+components/resources/android/theme_resources.h",
+ "+components/strings/grit/components_strings.h",
+ "+content/public/android/java/src/org/chromium/content_public",
+ "+device/vr/android/arcore",
+ "+ui/android",
+ "+ui/base",
+]
diff --git a/chromium/components/webxr/android/ar_compositor_delegate_provider.cc b/chromium/components/webxr/android/ar_compositor_delegate_provider.cc
new file mode 100644
index 00000000000..2d6df965bfe
--- /dev/null
+++ b/chromium/components/webxr/android/ar_compositor_delegate_provider.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 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/webxr/android/ar_compositor_delegate_provider.h"
+
+namespace webxr {
+
+ArCompositorDelegateProvider::ArCompositorDelegateProvider(
+ base::android::JavaRef<jobject>&& j_compositor_delegate_provider)
+ : j_compositor_delegate_provider_(
+ std::move(j_compositor_delegate_provider)) {}
+
+ArCompositorDelegateProvider::~ArCompositorDelegateProvider() = default;
+
+ArCompositorDelegateProvider::ArCompositorDelegateProvider(
+ const ArCompositorDelegateProvider& other) = default;
+ArCompositorDelegateProvider& ArCompositorDelegateProvider::operator=(
+ const ArCompositorDelegateProvider& other) = default;
+
+base::android::ScopedJavaLocalRef<jobject>
+ArCompositorDelegateProvider::GetJavaObject() const {
+ return base::android::ScopedJavaLocalRef<jobject>(
+ j_compositor_delegate_provider_);
+}
+
+} // namespace webxr
diff --git a/chromium/components/webxr/android/ar_compositor_delegate_provider.h b/chromium/components/webxr/android/ar_compositor_delegate_provider.h
new file mode 100644
index 00000000000..b2d26b1b541
--- /dev/null
+++ b/chromium/components/webxr/android/ar_compositor_delegate_provider.h
@@ -0,0 +1,32 @@
+// Copyright 2020 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_WEBXR_ANDROID_AR_COMPOSITOR_DELEGATE_PROVIDER_H_
+#define COMPONENTS_WEBXR_ANDROID_AR_COMPOSITOR_DELEGATE_PROVIDER_H_
+
+#include "base/android/scoped_java_ref.h"
+
+namespace webxr {
+
+// Wrapper around Java object that implements ArCompositorDelegateProvider
+// interface (see ArCompositorDelegateProvider.java).
+class ArCompositorDelegateProvider {
+ public:
+ explicit ArCompositorDelegateProvider(
+ base::android::JavaRef<jobject>&& j_compositor_delegate_provider);
+ ~ArCompositorDelegateProvider();
+
+ ArCompositorDelegateProvider(const ArCompositorDelegateProvider& other);
+ ArCompositorDelegateProvider& operator=(
+ const ArCompositorDelegateProvider& other);
+
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const;
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> j_compositor_delegate_provider_;
+};
+
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_AR_COMPOSITOR_DELEGATE_PROVIDER_H_
diff --git a/chromium/components/webxr/android/arcore_install_helper.cc b/chromium/components/webxr/android/arcore_install_helper.cc
new file mode 100644
index 00000000000..99f16347a84
--- /dev/null
+++ b/chromium/components/webxr/android/arcore_install_helper.cc
@@ -0,0 +1,166 @@
+// 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 "components/webxr/android/arcore_install_helper.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "components/infobars/core/infobar_manager.h"
+#include "components/resources/android/theme_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "components/webxr/android/ar_jni_headers/ArCoreInstallUtils_jni.h"
+#include "components/webxr/android/webxr_utils.h"
+#include "components/webxr/android/xr_install_helper_delegate.h"
+#include "components/webxr/android/xr_install_infobar.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+using base::android::AttachCurrentThread;
+
+namespace webxr {
+
+ArCoreInstallHelper::ArCoreInstallHelper(
+ std::unique_ptr<XrInstallHelperDelegate> install_delegate)
+ : install_delegate_(std::move(install_delegate)) {
+ DCHECK(install_delegate_);
+
+ // As per documentation, it's recommended to issue a call to
+ // ArCoreApk.checkAvailability() early in application lifecycle & ignore the
+ // result so that subsequent calls can return cached result:
+ // https://developers.google.com/ar/develop/java/enable-arcore
+ // In the event that a remote call is required, it will not block on that
+ // remote call per:
+ // https://developers.google.com/ar/reference/java/arcore/reference/com/google/ar/core/ArCoreApk#checkAvailability
+ Java_ArCoreInstallUtils_shouldRequestInstallSupportedArCore(
+ AttachCurrentThread());
+
+ java_install_utils_ = Java_ArCoreInstallUtils_create(
+ AttachCurrentThread(), reinterpret_cast<jlong>(this));
+}
+
+ArCoreInstallHelper::~ArCoreInstallHelper() {
+ if (!java_install_utils_.is_null()) {
+ Java_ArCoreInstallUtils_onNativeDestroy(AttachCurrentThread(),
+ java_install_utils_);
+ }
+
+ RunInstallFinishedCallback(false);
+}
+
+void ArCoreInstallHelper::EnsureInstalled(
+ int render_process_id,
+ int render_frame_id,
+ base::OnceCallback<void(bool)> install_callback) {
+ DCHECK(!install_finished_callback_);
+ install_finished_callback_ = std::move(install_callback);
+
+ if (java_install_utils_.is_null()) {
+ RunInstallFinishedCallback(false);
+ return;
+ }
+
+ // ARCore is not installed or requires an update.
+ if (Java_ArCoreInstallUtils_shouldRequestInstallSupportedArCore(
+ AttachCurrentThread())) {
+ ShowInfoBar(render_process_id, render_frame_id);
+ return;
+ }
+
+ // ARCore did not need to be installed/updated so mock out that its
+ // installation succeeded.
+ OnRequestInstallSupportedArCoreResult(nullptr, true);
+}
+
+void ArCoreInstallHelper::ShowInfoBar(int render_process_id,
+ int render_frame_id) {
+ infobars::InfoBarManager* infobar_manager =
+ install_delegate_->GetInfoBarManager(
+ GetWebContents(render_process_id, render_frame_id));
+
+ // We can't show an infobar without an |infobar_manager|, so if it's null,
+ // report that we are not installed and stop processing.
+ if (!infobar_manager) {
+ RunInstallFinishedCallback(false);
+ return;
+ }
+
+ ArCoreAvailability availability = static_cast<ArCoreAvailability>(
+ Java_ArCoreInstallUtils_getArCoreInstallStatus(AttachCurrentThread()));
+ int message_text = -1;
+ int button_text = -1;
+ switch (availability) {
+ case ArCoreAvailability::kUnsupportedDeviceNotCapable: {
+ RunInstallFinishedCallback(false);
+ return; // No need to process further
+ }
+ case ArCoreAvailability::kUnknownChecking:
+ case ArCoreAvailability::kUnknownError:
+ case ArCoreAvailability::kUnknownTimedOut:
+ case ArCoreAvailability::kSupportedNotInstalled: {
+ message_text = IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT;
+ button_text = IDS_INSTALL;
+ break;
+ }
+ case ArCoreAvailability::kSupportedApkTooOld: {
+ message_text = IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT;
+ button_text = IDS_UPDATE;
+ break;
+ }
+ case ArCoreAvailability::kSupportedInstalled:
+ NOTREACHED();
+ break;
+ }
+
+ DCHECK_NE(-1, message_text);
+ DCHECK_NE(-1, button_text);
+
+ // Binding ourself as a weak ref is okay, since our destructor will still
+ // guarantee that the callback is run if we are destroyed while waiting for
+ // the callback from the infobar.
+ // TODO(ijamardo, https://crbug.com/838833): Add icon for AR info bar.
+ auto delegate = std::make_unique<XrInstallInfoBar>(
+ infobars::InfoBarDelegate::InfoBarIdentifier::AR_CORE_UPGRADE_ANDROID,
+ IDR_ANDROID_AR_CORE_INSALL_ICON, message_text, button_text,
+ base::BindOnce(&ArCoreInstallHelper::OnInfoBarResponse,
+ weak_ptr_factory_.GetWeakPtr(), render_process_id,
+ render_frame_id));
+
+ infobar_manager->AddInfoBar(
+ infobar_manager->CreateConfirmInfoBar(std::move(delegate)));
+}
+
+void ArCoreInstallHelper::OnInfoBarResponse(int render_process_id,
+ int render_frame_id,
+ bool try_install) {
+ if (!try_install) {
+ OnRequestInstallSupportedArCoreResult(nullptr, false);
+ return;
+ }
+
+ // When completed, java will call: OnRequestInstallSupportedArCoreResult
+ Java_ArCoreInstallUtils_requestInstallSupportedArCore(
+ AttachCurrentThread(), java_install_utils_,
+ GetJavaWebContents(render_process_id, render_frame_id));
+}
+
+void ArCoreInstallHelper::OnRequestInstallSupportedArCoreResult(JNIEnv* env,
+ bool success) {
+ DVLOG(1) << __func__;
+
+ // Nothing else to do, simply call the deferred callback.
+ RunInstallFinishedCallback(success);
+}
+
+void ArCoreInstallHelper::RunInstallFinishedCallback(bool succeeded) {
+ if (install_finished_callback_) {
+ std::move(install_finished_callback_).Run(succeeded);
+ }
+}
+
+} // namespace webxr
diff --git a/chromium/components/webxr/android/arcore_install_helper.h b/chromium/components/webxr/android/arcore_install_helper.h
new file mode 100644
index 00000000000..0813df3454c
--- /dev/null
+++ b/chromium/components/webxr/android/arcore_install_helper.h
@@ -0,0 +1,72 @@
+// 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 COMPONENTS_WEBXR_ANDROID_ARCORE_INSTALL_HELPER_H_
+#define COMPONENTS_WEBXR_ANDROID_ARCORE_INSTALL_HELPER_H_
+
+#include <memory>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/xr_install_helper.h"
+
+namespace webxr {
+class XrInstallHelperDelegate;
+
+// Equivalent of ArCoreApk.Availability enum.
+// For detailed description, please see:
+// https://developers.google.com/ar/reference/java/arcore/reference/com/google/ar/core/ArCoreApk.Availability
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.webxr
+enum class ArCoreAvailability : int {
+ kSupportedApkTooOld = 0,
+ kSupportedInstalled = 1,
+ kSupportedNotInstalled = 2,
+ kUnknownChecking = 3,
+ kUnknownError = 4,
+ kUnknownTimedOut = 5,
+ kUnsupportedDeviceNotCapable = 6,
+};
+
+// Helper class to ensure that ArCore has been properly installed from the
+// store, per the ArCore Apk's installation implementation. Inherits from
+// content::XrInstallHelper so that it may be returned by the
+// XrIntegrationClient.
+class ArCoreInstallHelper : public content::XrInstallHelper {
+ public:
+ explicit ArCoreInstallHelper(
+ std::unique_ptr<XrInstallHelperDelegate> install_delegate);
+ ~ArCoreInstallHelper() override;
+
+ ArCoreInstallHelper(const ArCoreInstallHelper&) = delete;
+ ArCoreInstallHelper& operator=(const ArCoreInstallHelper&) = delete;
+
+ // content::XrInstallHelper implementation.
+ void EnsureInstalled(
+ int render_process_id,
+ int render_frame_id,
+ base::OnceCallback<void(bool)> install_callback) override;
+
+ // Called from Java end.
+ void OnRequestInstallSupportedArCoreResult(JNIEnv* env, bool success);
+
+ private:
+ void ShowInfoBar(int render_process_id, int render_frame_id);
+ void OnInfoBarResponse(int render_process_id,
+ int render_frame_id,
+ bool try_install);
+ void RunInstallFinishedCallback(bool succeeded);
+
+ base::OnceCallback<void(bool)> install_finished_callback_;
+ base::android::ScopedJavaGlobalRef<jobject> java_install_utils_;
+ std::unique_ptr<XrInstallHelperDelegate> install_delegate_;
+
+ // Must be last.
+ base::WeakPtrFactory<ArCoreInstallHelper> weak_ptr_factory_{this};
+};
+
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_ARCORE_INSTALL_HELPER_H_
diff --git a/chromium/components/webxr/android/arcore_java_utils.cc b/chromium/components/webxr/android/arcore_java_utils.cc
new file mode 100644
index 00000000000..bd634b43930
--- /dev/null
+++ b/chromium/components/webxr/android/arcore_java_utils.cc
@@ -0,0 +1,136 @@
+// Copyright 2018 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/webxr/android/arcore_java_utils.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/android/jni_string.h"
+#include "components/webxr/android/ar_jni_headers/ArCoreJavaUtils_jni.h"
+#include "components/webxr/android/webxr_utils.h"
+#include "device/vr/android/arcore/arcore_shim.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace webxr {
+
+ArCoreJavaUtils::ArCoreJavaUtils(
+ webxr::ArCompositorDelegateProvider compositor_delegate_provider)
+ : compositor_delegate_provider_(compositor_delegate_provider) {
+ JNIEnv* env = AttachCurrentThread();
+ if (!env)
+ return;
+ ScopedJavaLocalRef<jobject> j_arcore_java_utils =
+ Java_ArCoreJavaUtils_create(env, (jlong)this);
+ if (j_arcore_java_utils.is_null())
+ return;
+ j_arcore_java_utils_.Reset(j_arcore_java_utils);
+}
+
+ArCoreJavaUtils::~ArCoreJavaUtils() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_ArCoreJavaUtils_onNativeDestroy(env, j_arcore_java_utils_);
+}
+
+void ArCoreJavaUtils::RequestArSession(
+ int render_process_id,
+ int render_frame_id,
+ bool use_overlay,
+ vr::SurfaceReadyCallback ready_callback,
+ vr::SurfaceTouchCallback touch_callback,
+ vr::SurfaceDestroyedCallback destroyed_callback) {
+ DVLOG(1) << __func__;
+ JNIEnv* env = AttachCurrentThread();
+
+ surface_ready_callback_ = std::move(ready_callback);
+ surface_touch_callback_ = std::move(touch_callback);
+ surface_destroyed_callback_ = std::move(destroyed_callback);
+
+ Java_ArCoreJavaUtils_startSession(
+ env, j_arcore_java_utils_, compositor_delegate_provider_.GetJavaObject(),
+ webxr::GetJavaWebContents(render_process_id, render_frame_id),
+ use_overlay);
+}
+
+void ArCoreJavaUtils::EndSession() {
+ DVLOG(1) << __func__;
+ JNIEnv* env = AttachCurrentThread();
+
+ Java_ArCoreJavaUtils_endSession(env, j_arcore_java_utils_);
+}
+
+void ArCoreJavaUtils::OnDrawingSurfaceReady(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jobject>& surface,
+ int rotation,
+ int width,
+ int height) {
+ DVLOG(1) << __func__ << ": width=" << width << " height=" << height
+ << " rotation=" << rotation;
+ gfx::AcceleratedWidget window =
+ ANativeWindow_fromSurface(base::android::AttachCurrentThread(), surface);
+ display::Display::Rotation display_rotation =
+ static_cast<display::Display::Rotation>(rotation);
+ surface_ready_callback_.Run(window, display_rotation, {width, height});
+}
+
+void ArCoreJavaUtils::OnDrawingSurfaceTouch(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ bool primary,
+ bool touching,
+ int32_t pointer_id,
+ float x,
+ float y) {
+ DVLOG(3) << __func__ << ": pointer_id=" << pointer_id
+ << " primary=" << primary << " touching=" << touching;
+ surface_touch_callback_.Run(primary, touching, pointer_id, {x, y});
+}
+
+void ArCoreJavaUtils::OnDrawingSurfaceDestroyed(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj) {
+ DVLOG(1) << __func__ << ":::";
+ if (surface_destroyed_callback_) {
+ std::move(surface_destroyed_callback_).Run();
+ }
+}
+
+bool ArCoreJavaUtils::EnsureLoaded() {
+ DCHECK(vr::IsArCoreSupported());
+
+ JNIEnv* env = AttachCurrentThread();
+
+ // TODO(crbug.com/884780): Allow loading the ARCore shim by name instead of by
+ // absolute path.
+ ScopedJavaLocalRef<jstring> java_path =
+ Java_ArCoreJavaUtils_getArCoreShimLibraryPath(env);
+
+ // Crash in debug builds if `java_path` is a null pointer but handle this
+ // situation in release builds. This is done by design - the `java_path` will
+ // be null only if there was a regression introduced to our gn/gni files w/o
+ // causing a build break. In release builds, this approach will result in the
+ // site not being able to request an AR session.
+ DCHECK(java_path)
+ << "Unable to find path to ARCore SDK library - please ensure that "
+ "loadable_modules and secondary_abi_loadable_modules are set "
+ "correctly when building";
+ if (!java_path) {
+ LOG(ERROR) << "Unable to find path to ARCore SDK library";
+ return false;
+ }
+
+ return vr::LoadArCoreSdk(
+ base::android::ConvertJavaStringToUTF8(env, java_path));
+}
+
+ScopedJavaLocalRef<jobject> ArCoreJavaUtils::GetApplicationContext() {
+ JNIEnv* env = AttachCurrentThread();
+ return Java_ArCoreJavaUtils_getApplicationContext(env);
+}
+
+} // namespace webxr
diff --git a/chromium/components/webxr/android/arcore_java_utils.h b/chromium/components/webxr/android/arcore_java_utils.h
new file mode 100644
index 00000000000..afdac71a454
--- /dev/null
+++ b/chromium/components/webxr/android/arcore_java_utils.h
@@ -0,0 +1,68 @@
+// Copyright 2018 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_WEBXR_ANDROID_ARCORE_JAVA_UTILS_H_
+#define COMPONENTS_WEBXR_ANDROID_ARCORE_JAVA_UTILS_H_
+
+#include <android/native_window_jni.h>
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "components/webxr/android/ar_compositor_delegate_provider.h"
+#include "device/vr/android/arcore/arcore_session_utils.h"
+
+namespace webxr {
+
+class ArCoreJavaUtils : public vr::ArCoreSessionUtils {
+ public:
+ explicit ArCoreJavaUtils(
+ webxr::ArCompositorDelegateProvider compositor_delegate_provider);
+ ~ArCoreJavaUtils() override;
+
+ // ArCoreSessionUtils:
+ void RequestArSession(
+ int render_process_id,
+ int render_frame_id,
+ bool use_overlay,
+ vr::SurfaceReadyCallback ready_callback,
+ vr::SurfaceTouchCallback touch_callback,
+ vr::SurfaceDestroyedCallback destroyed_callback) override;
+ void EndSession() override;
+ bool EnsureLoaded() override;
+ base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() override;
+
+ // Methods called from the Java side.
+ void OnDrawingSurfaceReady(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jobject>& surface,
+ int rotation,
+ int width,
+ int height);
+ void OnDrawingSurfaceTouch(JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ bool primary,
+ bool touching,
+ int32_t pointer_id,
+ float x,
+ float y);
+ void OnDrawingSurfaceDestroyed(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj);
+
+ private:
+ base::android::ScopedJavaGlobalRef<jobject> j_arcore_java_utils_;
+
+ webxr::ArCompositorDelegateProvider compositor_delegate_provider_;
+
+ vr::SurfaceReadyCallback surface_ready_callback_;
+ vr::SurfaceTouchCallback surface_touch_callback_;
+ vr::SurfaceDestroyedCallback surface_destroyed_callback_;
+};
+
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_ARCORE_JAVA_UTILS_H_
diff --git a/chromium/components/webxr/android/webxr_utils.cc b/chromium/components/webxr/android/webxr_utils.cc
new file mode 100644
index 00000000000..ed3080106d6
--- /dev/null
+++ b/chromium/components/webxr/android/webxr_utils.cc
@@ -0,0 +1,32 @@
+// 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.
+
+#include "components/webxr/android/webxr_utils.h"
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace webxr {
+
+content::WebContents* GetWebContents(int render_process_id,
+ int render_frame_id) {
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ DCHECK(render_frame_host);
+
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ DCHECK(web_contents);
+
+ return web_contents;
+}
+
+base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents(
+ int render_process_id,
+ int render_frame_id) {
+ return GetWebContents(render_process_id, render_frame_id)
+ ->GetJavaWebContents();
+}
+
+} // namespace webxr
diff --git a/chromium/components/webxr/android/webxr_utils.h b/chromium/components/webxr/android/webxr_utils.h
new file mode 100644
index 00000000000..762a3091a01
--- /dev/null
+++ b/chromium/components/webxr/android/webxr_utils.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef COMPONENTS_WEBXR_ANDROID_WEBXR_UTILS_H_
+#define COMPONENTS_WEBXR_ANDROID_WEBXR_UTILS_H_
+
+#include "base/android/jni_android.h"
+
+namespace content {
+class WebContents;
+}
+
+// Functions in this file are currently GVR/ArCore specific functions. If other
+// platforms need the same function here, please move it to
+// components/webxr/*util.cc|h
+namespace webxr {
+
+content::WebContents* GetWebContents(int render_process_id,
+ int render_frame_id);
+
+base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents(
+ int render_process_id,
+ int render_frame_id);
+
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_WEBXR_UTILS_H_
diff --git a/chromium/components/webxr/android/xr_install_helper_delegate.h b/chromium/components/webxr/android/xr_install_helper_delegate.h
new file mode 100644
index 00000000000..4df3bc21c9a
--- /dev/null
+++ b/chromium/components/webxr/android/xr_install_helper_delegate.h
@@ -0,0 +1,42 @@
+// Copyright 2020 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_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
+#define COMPONENTS_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
+
+namespace content {
+class WebContents;
+}
+
+namespace infobars {
+class InfoBarManager;
+}
+
+namespace webxr {
+
+// Helper class for InstallHelpers to gain access to other components. Since the
+// InstallHelpers are intended to be plumbed through content/public's
+// XrIntegrationClient, they may not contain direct references to other
+// component types. This provides a means for embedders to pass accessors for
+// other component types to the InstallHelpers.
+class XrInstallHelperDelegate {
+ public:
+ virtual ~XrInstallHelperDelegate() = default;
+
+ XrInstallHelperDelegate(const XrInstallHelperDelegate&) = delete;
+ XrInstallHelperDelegate& operator=(const XrInstallHelperDelegate&) = delete;
+
+ // Gets the InfoBarManager for the provided web_contents, which can be used to
+ // display the installation confirmation message. It is acceptable to return
+ // a null InfoBarManager, but installation may fail after doing so.
+ virtual infobars::InfoBarManager* GetInfoBarManager(
+ content::WebContents* web_contents) = 0;
+
+ protected:
+ XrInstallHelperDelegate() = default;
+};
+
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
diff --git a/chromium/components/webxr/android/xr_install_infobar.cc b/chromium/components/webxr/android/xr_install_infobar.cc
new file mode 100644
index 00000000000..475d0b21905
--- /dev/null
+++ b/chromium/components/webxr/android/xr_install_infobar.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2020 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/webxr/android/xr_install_infobar.h"
+
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace webxr {
+
+XrInstallInfoBar::XrInstallInfoBar(
+ InfoBarIdentifier identifier,
+ int icon_id,
+ int message_id,
+ int ok_button_id,
+ base::OnceCallback<void(bool)> install_callback)
+ : identifier_(identifier),
+ icon_id_(icon_id),
+ message_id_(message_id),
+ ok_button_id_(ok_button_id),
+ install_callback_(std::move(install_callback)) {}
+
+XrInstallInfoBar::~XrInstallInfoBar() = default;
+
+infobars::InfoBarDelegate::InfoBarIdentifier XrInstallInfoBar::GetIdentifier()
+ const {
+ return identifier_;
+}
+
+int XrInstallInfoBar::GetIconId() const {
+ return icon_id_;
+}
+
+int XrInstallInfoBar::GetButtons() const {
+ return BUTTON_OK;
+}
+
+base::string16 XrInstallInfoBar::GetButtonLabel(InfoBarButton button) const {
+ DCHECK_EQ(BUTTON_OK, button);
+ return l10n_util::GetStringUTF16(ok_button_id_);
+}
+
+base::string16 XrInstallInfoBar::GetMessageText() const {
+ return l10n_util::GetStringUTF16(message_id_);
+}
+
+bool XrInstallInfoBar::Accept() {
+ std::move(install_callback_).Run(true);
+ return true;
+}
+
+bool XrInstallInfoBar::Cancel() {
+ std::move(install_callback_).Run(false);
+ return true;
+}
+
+void XrInstallInfoBar::InfoBarDismissed() {
+ std::move(install_callback_).Run(false);
+}
+} // namespace webxr
diff --git a/chromium/components/webxr/android/xr_install_infobar.h b/chromium/components/webxr/android/xr_install_infobar.h
new file mode 100644
index 00000000000..631bd86439c
--- /dev/null
+++ b/chromium/components/webxr/android/xr_install_infobar.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2020 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_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
+#define COMPONENTS_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
+
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "components/infobars/core/infobar_delegate.h"
+
+namespace webxr {
+
+// An interface derived from InfoBarDelegate implemented by objects wishing to
+// control a ConfirmInfoBar.
+class XrInstallInfoBar : public ConfirmInfoBarDelegate {
+ public:
+ // Constructor for XrInstallInfoBar, the callback is guaranteed to be called,
+ // if the InfoBar is accepted, cancelled, or dismissed. The Callback will be
+ // passed a bool indicating whether the result of the InfoBar was "accepted."
+ XrInstallInfoBar(InfoBarIdentifier identifier,
+ int icon_id,
+ int message_id,
+ int ok_button_id,
+ base::OnceCallback<void(bool)> install_callback);
+ ~XrInstallInfoBar() override;
+
+ infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+ int GetIconId() const override;
+ base::string16 GetMessageText() const override;
+ int GetButtons() const override;
+ base::string16 GetButtonLabel(InfoBarButton button) const override;
+
+ private:
+ // Called when the OK button is pressed. If this function returns true, the
+ // infobar is then immediately closed. Subclasses MUST NOT return true if in
+ // handling this call something triggers the infobar to begin closing.
+ bool Accept() override;
+
+ // Called when the Cancel button is pressed. If this function returns true,
+ // the infobar is then immediately closed. Subclasses MUST NOT return true if
+ // in handling this call something triggers the infobar to begin closing.
+ bool Cancel() override;
+
+ // Called when the user clicks on the close button to dismiss the infobar.
+ void InfoBarDismissed() override;
+
+ const infobars::InfoBarDelegate::InfoBarIdentifier identifier_;
+ const int icon_id_;
+ const int message_id_;
+ const int ok_button_id_;
+ base::OnceCallback<void(bool)> install_callback_;
+};
+} // namespace webxr
+
+#endif // COMPONENTS_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
diff --git a/chromium/components/webxr/mailbox_to_surface_bridge_impl.cc b/chromium/components/webxr/mailbox_to_surface_bridge_impl.cc
index b6991bcc64c..8b8a70eb3f4 100644
--- a/chromium/components/webxr/mailbox_to_surface_bridge_impl.cc
+++ b/chromium/components/webxr/mailbox_to_surface_bridge_impl.cc
@@ -28,6 +28,7 @@
#include "gpu/ipc/common/gpu_surface_tracker.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/gfx/color_space.h"
+#include "ui/gfx/transform.h"
#include "ui/gl/android/surface_texture.h"
#include <android/native_window_jni.h>
@@ -43,8 +44,10 @@ const char kQuadCopyVertex[] = SHADER(
attribute vec4 a_Position;
attribute vec2 a_TexCoordinate;
varying highp vec2 v_TexCoordinate;
+ uniform mat4 u_UvTransform;
void main() {
- v_TexCoordinate = a_TexCoordinate;
+ highp vec4 uv_in = vec4(a_TexCoordinate.x, a_TexCoordinate.y, 0, 1);
+ v_TexCoordinate = (u_UvTransform * uv_in).xy;
gl_Position = a_Position;
}
);
@@ -219,7 +222,7 @@ void MailboxToSurfaceBridgeImpl::CreateSurface(
surface_ = std::make_unique<gl::ScopedJavaSurface>(surface_texture);
surface_handle_ =
tracker->AddSurfaceForNativeWidget(gpu::GpuSurfaceTracker::SurfaceRecord(
- window, surface_->j_surface().obj(),
+ window, surface_->j_surface(),
false /* can_be_used_with_surface_control */));
// Unregistering happens in the destructor.
ANativeWindow_release(window);
@@ -291,6 +294,12 @@ void MailboxToSurfaceBridgeImpl::ResizeSurface(int width, int height) {
bool MailboxToSurfaceBridgeImpl::CopyMailboxToSurfaceAndSwap(
const gpu::MailboxHolder& mailbox) {
+ return CopyMailboxToSurfaceAndSwap(mailbox, gfx::Transform());
+}
+
+bool MailboxToSurfaceBridgeImpl::CopyMailboxToSurfaceAndSwap(
+ const gpu::MailboxHolder& mailbox,
+ const gfx::Transform& uv_transform) {
if (!IsConnected()) {
// We may not have a context yet, i.e. due to surface initialization
// being incomplete. This is not an error, but we obviously can't draw
@@ -316,7 +325,7 @@ bool MailboxToSurfaceBridgeImpl::CopyMailboxToSurfaceAndSwap(
GLuint sourceTexture = ConsumeTexture(gl_, mailbox);
gl_->BeginSharedImageAccessDirectCHROMIUM(
sourceTexture, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
- DrawQuad(sourceTexture);
+ DrawQuad(sourceTexture, uv_transform);
gl_->EndSharedImageAccessDirectCHROMIUM(sourceTexture);
gl_->DeleteTextures(1, &sourceTexture);
gl_->SwapBuffers(swap_id_++);
@@ -423,6 +432,8 @@ void MailboxToSurfaceBridgeImpl::InitializeRenderer() {
gl_->GetAttribLocation(program_handle, "a_TexCoordinate");
GLuint texUniform_handle =
gl_->GetUniformLocation(program_handle, "u_Texture");
+ uniform_uv_transform_handle_ =
+ gl_->GetUniformLocation(program_handle, "u_UvTransform");
GLuint vertexBuffer = 0;
gl_->GenBuffers(1, &vertexBuffer);
@@ -466,7 +477,8 @@ void MailboxToSurfaceBridgeImpl::InitializeRenderer() {
gl_->Uniform1i(texUniform_handle, 0);
}
-void MailboxToSurfaceBridgeImpl::DrawQuad(unsigned int texture_handle) {
+void MailboxToSurfaceBridgeImpl::DrawQuad(unsigned int texture_handle,
+ const gfx::Transform& uv_transform) {
DCHECK(IsConnected());
// We're redrawing over the entire viewport, but it's generally more
@@ -477,6 +489,11 @@ void MailboxToSurfaceBridgeImpl::DrawQuad(unsigned int texture_handle) {
// it's not supported on older devices such as Nexus 5X.
gl_->Clear(GL_COLOR_BUFFER_BIT);
+ float uv_transform_floats[16];
+ uv_transform.matrix().asColMajorf(uv_transform_floats);
+ gl_->UniformMatrix4fv(uniform_uv_transform_handle_, 1, GL_FALSE,
+ &uv_transform_floats[0]);
+
// Configure texture. This is a 1:1 pixel copy since the surface
// size is resized to match the source canvas, so we can use
// GL_NEAREST.
@@ -484,7 +501,11 @@ void MailboxToSurfaceBridgeImpl::DrawQuad(unsigned int texture_handle) {
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ if (uv_transform.IsIdentity()) {
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ } else {
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
gl_->DrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
diff --git a/chromium/components/webxr/mailbox_to_surface_bridge_impl.h b/chromium/components/webxr/mailbox_to_surface_bridge_impl.h
index 0df15b13d52..d611c65aace 100644
--- a/chromium/components/webxr/mailbox_to_surface_bridge_impl.h
+++ b/chromium/components/webxr/mailbox_to_surface_bridge_impl.h
@@ -54,6 +54,9 @@ class MailboxToSurfaceBridgeImpl : public device::MailboxToSurfaceBridge {
bool CopyMailboxToSurfaceAndSwap(const gpu::MailboxHolder& mailbox) override;
+ bool CopyMailboxToSurfaceAndSwap(const gpu::MailboxHolder& mailbox,
+ const gfx::Transform& uv_transform) override;
+
void GenSyncToken(gpu::SyncToken* out_sync_token) override;
void WaitSyncToken(const gpu::SyncToken& sync_token) override;
@@ -77,7 +80,7 @@ class MailboxToSurfaceBridgeImpl : public device::MailboxToSurfaceBridge {
scoped_refptr<viz::ContextProvider> provider);
void InitializeRenderer();
void DestroyContext();
- void DrawQuad(unsigned int textureHandle);
+ void DrawQuad(unsigned int textureHandle, const gfx::Transform& uv_transform);
scoped_refptr<viz::ContextProvider> context_provider_;
std::unique_ptr<gl::ScopedJavaSurface> surface_;
@@ -98,6 +101,9 @@ class MailboxToSurfaceBridgeImpl : public device::MailboxToSurfaceBridge {
// A swap ID which is passed to GL swap. Incremented each call.
uint64_t swap_id_ = 0;
+ // Uniform handle for the UV transform used by DrawQuad.
+ uint32_t uniform_uv_transform_handle_ = 0;
+
// A task runner for the GL thread
scoped_refptr<base::SingleThreadTaskRunner> gl_thread_task_runner_;
diff --git a/chromium/components/webxr_strings.grdp b/chromium/components/webxr_strings.grdp
new file mode 100644
index 00000000000..5b4e1404f48
--- /dev/null
+++ b/chromium/components/webxr_strings.grdp
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- WebXR specific strings (included from components_strings.grd). -->
+<grit-part>
+ <if expr="enable_arcore">
+ <!-- ARCore check infobar -->
+ <message name="IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT" desc="Text to be displayed in the ARCore check infobar. When a WebXR page is loaded, if ARCore is needed to display AR content and it is not installed, an infobar will be shown to the user prompting them to install ARCore.">
+ To view augmented reality content, install ARCore
+ </message>
+ <message name="IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT" desc="Text to be displayed in the ARCore check infobar. When a WebXR page is loaded, if ARCore is needed to display AR content and the installed ARCore is not up to date to the version needed by the implementation, an infobar will be shown to the user prompting them to update ARCore.">
+ To view augmented reality content, update ARCore
+ </message>
+ </if>
+</grit-part>
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1
new file mode 100644
index 00000000000..61e6968626a
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1
@@ -0,0 +1 @@
+53e9d9669c1b11a5768ff5a4134ccdf097c8de42 \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1
new file mode 100644
index 00000000000..7d5e071f241
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1
@@ -0,0 +1 @@
+c2cf80e15c7b64119f4cb102448080a1d25829cf \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/OWNERS b/chromium/components/webxr_strings_grdp/OWNERS
new file mode 100644
index 00000000000..8c91bd77017
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/OWNERS
@@ -0,0 +1,2 @@
+file://components/webxr/OWNERS
+# COMPONENT: Internals>XR
diff --git a/chromium/components/webxr_strings_grdp/README.md b/chromium/components/webxr_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/wifi/BUILD.gn b/chromium/components/wifi/BUILD.gn
index 74b5c277ef0..a5f1d3d07e5 100644
--- a/chromium/components/wifi/BUILD.gn
+++ b/chromium/components/wifi/BUILD.gn
@@ -2,13 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# This file depends on the legacy global sources assignment filter. It should
-# be converted to check target platform before assigning source files to the
-# sources variable. Remove this import and set_sources_assignment_filter call
-# when the file has been converted. See https://crbug.com/1018739 for details.
-import("//build/config/deprecated_default_sources_assignment_filter.gni")
-set_sources_assignment_filter(deprecated_default_sources_assignment_filter)
-
component("wifi") {
sources = [
"network_properties.cc",
@@ -16,8 +9,6 @@ component("wifi") {
"wifi_export.h",
"wifi_service.cc",
"wifi_service.h",
- "wifi_service_mac.mm",
- "wifi_service_win.cc",
]
defines = [ "WIFI_IMPLEMENTATION" ]
@@ -29,6 +20,7 @@ component("wifi") {
]
if (is_win) {
+ sources += [ "wifi_service_win.cc" ]
libs = [ "iphlpapi.lib" ]
deps += [
"//third_party/libxml:xml_reader", # Safe, data come from system.
@@ -37,6 +29,7 @@ component("wifi") {
}
if (is_mac) {
+ sources += [ "wifi_service_mac.mm" ]
frameworks = [
"CoreWLAN.framework",
"Foundation.framework",
diff --git a/chromium/components/zoom/zoom_controller.cc b/chromium/components/zoom/zoom_controller.cc
index f98dfb218b1..260640a3703 100644
--- a/chromium/components/zoom/zoom_controller.cc
+++ b/chromium/components/zoom/zoom_controller.cc
@@ -112,7 +112,7 @@ bool ZoomController::SetZoomLevelByClient(
// Cannot zoom in disabled mode. Also, don't allow changing zoom level on
// a crashed tab, an error page or an interstitial page.
if (zoom_mode_ == ZOOM_MODE_DISABLED ||
- !web_contents()->GetRenderViewHost()->IsRenderViewLive())
+ !web_contents()->GetMainFrame()->GetRenderViewHost()->IsRenderViewLive())
return false;
// Store client data so the |client| can be attributed when the zoom
@@ -157,8 +157,13 @@ bool ZoomController::SetZoomLevelByClient(
event_data_.reset(new ZoomChangedEventData(web_contents(), GetZoomLevel(),
zoom_level, zoom_mode_,
false /* can_show_bubble */));
- int process_id = web_contents()->GetRenderViewHost()->GetProcess()->GetID();
- int view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ int process_id = web_contents()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetProcess()
+ ->GetID();
+ int view_id =
+ web_contents()->GetMainFrame()->GetRenderViewHost()->GetRoutingID();
if (zoom_mode_ == ZOOM_MODE_ISOLATED ||
zoom_map->UsesTemporaryZoomLevel(process_id, view_id)) {
zoom_map->SetTemporaryZoomLevel(process_id, view_id, zoom_level);
@@ -188,8 +193,13 @@ void ZoomController::SetZoomMode(ZoomMode new_mode) {
content::HostZoomMap* zoom_map =
content::HostZoomMap::GetForWebContents(web_contents());
DCHECK(zoom_map);
- int process_id = web_contents()->GetRenderViewHost()->GetProcess()->GetID();
- int view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ int process_id = web_contents()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetProcess()
+ ->GetID();
+ int view_id =
+ web_contents()->GetMainFrame()->GetRenderViewHost()->GetRoutingID();
double original_zoom_level = GetZoomLevel();
DCHECK(!event_data_);
@@ -279,8 +289,13 @@ void ZoomController::ResetZoomModeOnNavigationIfNeeded(const GURL& url) {
if (zoom_mode_ != ZOOM_MODE_ISOLATED && zoom_mode_ != ZOOM_MODE_MANUAL)
return;
- int process_id = web_contents()->GetRenderViewHost()->GetProcess()->GetID();
- int view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ int process_id = web_contents()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetProcess()
+ ->GetID();
+ int view_id =
+ web_contents()->GetMainFrame()->GetRenderViewHost()->GetRoutingID();
content::HostZoomMap* zoom_map =
content::HostZoomMap::GetForWebContents(web_contents());
zoom_level_ = zoom_map->GetDefaultZoomLevel();
@@ -390,8 +405,13 @@ void ZoomController::UpdateState(const std::string& host) {
}
void ZoomController::SetPageScaleFactorIsOneForTesting(bool is_one) {
- int process_id = web_contents()->GetRenderViewHost()->GetProcess()->GetID();
- int view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ int process_id = web_contents()
+ ->GetMainFrame()
+ ->GetRenderViewHost()
+ ->GetProcess()
+ ->GetID();
+ int view_id =
+ web_contents()->GetMainFrame()->GetRenderViewHost()->GetRoutingID();
host_zoom_map_->SetPageScaleFactorIsOneForView(process_id, view_id, is_one);
}
diff --git a/chromium/components/zucchini/fuzzers/BUILD.gn b/chromium/components/zucchini/fuzzers/BUILD.gn
index 90c436e8aca..613ac99add2 100644
--- a/chromium/components/zucchini/fuzzers/BUILD.gn
+++ b/chromium/components/zucchini/fuzzers/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/python.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
@@ -71,7 +72,8 @@ proto_library("zucchini_file_pair_proto") {
# Disabled on Windows due to crbug/844826.
if (current_toolchain == host_toolchain && !is_win) {
# Raw Apply Fuzzer Seed:
- action("zucchini_raw_apply_seed") {
+ # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+ python2_action("zucchini_raw_apply_seed") {
script = "generate_fuzzer_data.py"
args = [
@@ -107,7 +109,8 @@ if (current_toolchain == host_toolchain && !is_win) {
}
# ZTF Apply Fuzzer Seed:
- action("zucchini_ztf_apply_seed") {
+ # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
+ python2_action("zucchini_ztf_apply_seed") {
script = "generate_fuzzer_data.py"
# *.ztf files are expected to be valid ZTF format.
diff --git a/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc b/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc
index f3bb2771c3b..85f1016447c 100644
--- a/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc
+++ b/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc
@@ -12,7 +12,7 @@
#include "components/zucchini/imposed_ensemble_matcher.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/optional.h"
#include "components/zucchini/buffer_view.h"